Index: /trunk/psModules/src/concepts/pmConcepts.c
===================================================================
--- /trunk/psModules/src/concepts/pmConcepts.c	(revision 12284)
+++ /trunk/psModules/src/concepts/pmConcepts.c	(revision 12285)
@@ -8,4 +8,5 @@
 #include <assert.h>
 #include <pslib.h>
+#include <string.h>
 
 #include "pmConcepts.h"
@@ -20,4 +21,20 @@
 static psMetadata *conceptsCell = NULL; // Known concepts for cell
 
+// Return the appropriate concepts metadata, given the level
+static psMetadata *conceptsFromLevel(pmFPALevel level)
+{
+    switch (level) {
+    case PM_FPA_LEVEL_FPA:
+        return conceptsFPA;
+    case PM_FPA_LEVEL_CHIP:
+        return conceptsChip;
+    case PM_FPA_LEVEL_CELL:
+        return conceptsCell;
+    default:
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Invalid concept level provided: %d\n", level);
+        return NULL;
+    }
+}
+
 // Free a concept
 static void conceptSpecFree(pmConceptSpec *spec)
@@ -27,5 +44,5 @@
 
 pmConceptSpec *pmConceptSpecAlloc(psMetadataItem *blank, pmConceptParseFunc parse,
-                                  pmConceptFormatFunc format)
+                                  pmConceptFormatFunc format, bool required)
 {
     pmConceptSpec *spec = psAlloc(sizeof(pmConceptSpec));
@@ -35,4 +52,5 @@
     spec->parse = parse;
     spec->format = format;
+    spec->required = required;
 
     return spec;
@@ -46,17 +64,7 @@
 
     // Get the appropriate concepts
-    psMetadata *concepts = NULL;        // Metadata of concepts specs
-    switch (level) {
-    case PM_FPA_LEVEL_FPA:
-        concepts = conceptsFPA;
-        break;
-    case PM_FPA_LEVEL_CHIP:
-        concepts = conceptsChip;
-        break;
-    case PM_FPA_LEVEL_CELL:
-        concepts = conceptsCell;
-        break;
-    default:
-        psError(PS_ERR_IO, true, "Invalid concept level provided: %d\n", level);
+    psMetadata *concepts = conceptsFromLevel(level); // Metadata of concepts specs
+    if (!concepts) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Invalid concept level provided: %d\n", level);
         return NULL;
     }
@@ -73,46 +81,64 @@
 }
 
-
-psList *psMetadataKeys(psMetadata *md)
-{
-    psList *list = psListAlloc(NULL);   // List with the keys
-    psMetadataIterator *iter = psMetadataIteratorAlloc(md, PS_LIST_HEAD, false);
-    psMetadataItem *item;               // Item from iteration
-    while ((item = psMetadataGetAndIncrement(iter))) {
-        psListAdd(list, PS_LIST_TAIL, item->name);
-    }
-    return list;
-}
-
-
-
-bool pmConceptRegister(psMetadataItem *blank, pmConceptParseFunc parse,
-                       pmConceptFormatFunc format, pmFPALevel level)
-{
-    PS_ASSERT_PTR_NON_NULL(blank, false);
-
+bool pmConceptGetRequired(const char *name, pmFPALevel level)
+{
+    PS_ASSERT_STRING_NON_EMPTY(name, false);
     if (!conceptsInitialised) {
         pmConceptsInit();
     }
 
-    pmConceptSpec *spec = pmConceptSpecAlloc(blank, parse, format); // The concept specification
-    psMetadata **target = NULL;         // The metadata of known concepts to write to
-    switch (level) {
-    case PM_FPA_LEVEL_FPA:
-        target = &conceptsFPA;
-        break;
-    case PM_FPA_LEVEL_CHIP:
-        target = &conceptsChip;
-        break;
-    case PM_FPA_LEVEL_CELL:
-        target = &conceptsCell;
-        break;
-    default:
-        psError(PS_ERR_IO, true, "Invalid concept level provided: %d\n", level);
-        psFree(spec);
+    psMetadata *concepts = conceptsFromLevel(level); // The metadata of known concepts
+
+    bool mdok;                          // Status of MD lookup
+    pmConceptSpec *spec = psMetadataLookupPtr(&mdok, concepts, name); // The specification
+    if (!spec) {
+        // Won't throw an error, because we can't distinguish an error from the desired result.
+        // However, that doesn't really matter, because if we can't find it, then it can't be required!
         return false;
     }
 
-    psMetadataAdd(*target, PS_LIST_TAIL, blank->name, PS_DATA_UNKNOWN | PS_META_REPLACE,
+    return spec->required;
+}
+
+bool pmConceptSetRequired(const char *name, pmFPALevel level, bool required)
+{
+    PS_ASSERT_STRING_NON_EMPTY(name, false);
+
+    if (!conceptsInitialised) {
+        pmConceptsInit();
+    }
+
+    psMetadata *concepts = conceptsFromLevel(level); // The metadata of known concepts
+
+    bool mdok;                          // Status of MD lookup
+    pmConceptSpec *spec = psMetadataLookupPtr(&mdok, concepts, name); // The specification
+    if (!spec) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unable to find defined concept %s in level %d.",
+                name, level);
+        return false;
+    }
+    spec->required = required;
+
+    return true;
+}
+
+bool pmConceptRegister(psMetadataItem *blank, pmConceptParseFunc parse,
+                        pmConceptFormatFunc format, bool required, pmFPALevel level)
+{
+    PS_ASSERT_PTR_NON_NULL(blank, false);
+
+    if (!conceptsInitialised) {
+        pmConceptsInit();
+    }
+
+    psMetadata *target = conceptsFromLevel(level); // The metadata of known concepts to write to
+    if (!target) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                "Unable to register concept at invalid concept level.");
+        return false;
+    }
+
+    pmConceptSpec *spec = pmConceptSpecAlloc(blank, parse, format, required); // The concept specification
+    psMetadataAdd(target, PS_LIST_TAIL, blank->name, PS_DATA_UNKNOWN | PS_META_REPLACE,
                   "Concepts specification", spec);
     psFree(spec);                       // Drop reference
@@ -434,17 +460,8 @@
         // Install the standard concepts
 
-        #if 0
-        // FPA.NAME
-        {
-            psMetadataItem *fpaName = psMetadataItemAllocStr("FPA.NAME", "Name of FPA", "");
-            pmConceptRegister(fpaName, NULL, NULL, PM_FPA_LEVEL_FPA);
-            psFree(fpaName);
-        }
-        #endif
-
         // FPA.TELESCOPE
         {
             psMetadataItem *fpaTelescope = psMetadataItemAllocStr("FPA.TELESCOPE", "Camera used", "");
-            pmConceptRegister(fpaTelescope, NULL, NULL, PM_FPA_LEVEL_FPA);
+            pmConceptRegister(fpaTelescope, NULL, NULL, false, PM_FPA_LEVEL_FPA);
             psFree(fpaTelescope);
         }
@@ -453,5 +470,5 @@
         {
             psMetadataItem *fpaInstrument = psMetadataItemAllocStr("FPA.INSTRUMENT", "Camera used", "");
-            pmConceptRegister(fpaInstrument, NULL, NULL, PM_FPA_LEVEL_FPA);
+            pmConceptRegister(fpaInstrument, NULL, NULL, false, PM_FPA_LEVEL_FPA);
             psFree(fpaInstrument);
         }
@@ -460,5 +477,5 @@
         {
             psMetadataItem *fpaDetector = psMetadataItemAllocStr("FPA.DETECTOR", "Detector used", "");
-            pmConceptRegister(fpaDetector, NULL, NULL, PM_FPA_LEVEL_FPA);
+            pmConceptRegister(fpaDetector, NULL, NULL, false, PM_FPA_LEVEL_FPA);
             psFree(fpaDetector);
         }
@@ -468,5 +485,5 @@
         {
             psMetadataItem *fpaCamera = psMetadataItemAllocStr("FPA.CAMERA", "Camera used", "");
-            pmConceptRegister(fpaCamera, NULL, NULL, PM_FPA_LEVEL_FPA);
+            pmConceptRegister(fpaCamera, NULL, NULL, false, PM_FPA_LEVEL_FPA);
             psFree(fpaCamera);
         }
@@ -475,5 +492,5 @@
         {
             psMetadataItem *fpaFocus = psMetadataItemAllocF32("FPA.FOCUS", "Telescope focus", NAN);
-            pmConceptRegister(fpaFocus, NULL, NULL, PM_FPA_LEVEL_FPA);
+            pmConceptRegister(fpaFocus, NULL, NULL, false, PM_FPA_LEVEL_FPA);
             psFree(fpaFocus);
         }
@@ -482,5 +499,5 @@
         {
             psMetadataItem *fpaAirmass = psMetadataItemAllocF32("FPA.AIRMASS", "Airmass at boresight", NAN);
-            pmConceptRegister(fpaAirmass, NULL, NULL, PM_FPA_LEVEL_FPA);
+            pmConceptRegister(fpaAirmass, NULL, NULL, false, PM_FPA_LEVEL_FPA);
             psFree(fpaAirmass);
         }
@@ -491,5 +508,5 @@
                                                                  "Filter used (parsed, abstract name) ", "");
             pmConceptRegister(fpaFilterid, (pmConceptParseFunc)p_pmConceptParse_FPA_FILTER,
-                              (pmConceptFormatFunc)p_pmConceptFormat_FPA_FILTER, PM_FPA_LEVEL_FPA);
+                              (pmConceptFormatFunc)p_pmConceptFormat_FPA_FILTER, false, PM_FPA_LEVEL_FPA);
             psFree(fpaFilterid);
         }
@@ -498,5 +515,5 @@
         {
             psMetadataItem *fpaFilter = psMetadataItemAllocStr("FPA.FILTER", "Filter used", "");
-            pmConceptRegister(fpaFilter, NULL, NULL, PM_FPA_LEVEL_FPA);
+            pmConceptRegister(fpaFilter, NULL, NULL, false, PM_FPA_LEVEL_FPA);
             psFree(fpaFilter);
         }
@@ -506,5 +523,5 @@
             psMetadataItem *fpaPosangle = psMetadataItemAllocF32("FPA.POSANGLE",
                                           "Position angle of instrument", NAN);
-            pmConceptRegister(fpaPosangle, NULL, NULL, PM_FPA_LEVEL_FPA);
+            pmConceptRegister(fpaPosangle, NULL, NULL, false, PM_FPA_LEVEL_FPA);
             psFree(fpaPosangle);
         }
@@ -514,5 +531,5 @@
             psMetadataItem *fpaRadecsys = psMetadataItemAllocStr("FPA.RADECSYS",
                                           "Celestial coordinate system", "");
-            pmConceptRegister(fpaRadecsys, NULL, NULL, PM_FPA_LEVEL_FPA);
+            pmConceptRegister(fpaRadecsys, NULL, NULL, false, PM_FPA_LEVEL_FPA);
             psFree(fpaRadecsys);
         }
@@ -522,5 +539,5 @@
             psMetadataItem *fpaRa = psMetadataItemAllocF64("FPA.RA", "Right Ascension of boresight", NAN);
             pmConceptRegister(fpaRa, (pmConceptParseFunc)p_pmConceptParse_FPA_Coords,
-                              (pmConceptFormatFunc)p_pmConceptFormat_FPA_Coords, PM_FPA_LEVEL_FPA);
+                              (pmConceptFormatFunc)p_pmConceptFormat_FPA_Coords, false, PM_FPA_LEVEL_FPA);
             psFree(fpaRa);
         }
@@ -530,5 +547,5 @@
             psMetadataItem *fpaDec = psMetadataItemAllocF64("FPA.DEC", "Declination of boresight", NAN);
             pmConceptRegister(fpaDec, (pmConceptParseFunc)p_pmConceptParse_FPA_Coords,
-                              (pmConceptFormatFunc)p_pmConceptFormat_FPA_Coords, PM_FPA_LEVEL_FPA);
+                              (pmConceptFormatFunc)p_pmConceptFormat_FPA_Coords, false, PM_FPA_LEVEL_FPA);
             psFree(fpaDec);
         }
@@ -537,5 +554,5 @@
         {
             psMetadataItem *fpaObstype = psMetadataItemAllocStr("FPA.OBSTYPE", "Type of observation", "");
-            pmConceptRegister(fpaObstype, NULL, NULL, PM_FPA_LEVEL_FPA);
+            pmConceptRegister(fpaObstype, NULL, NULL, false, PM_FPA_LEVEL_FPA);
             psFree(fpaObstype);
         }
@@ -544,5 +561,5 @@
         {
             psMetadataItem *fpaObject = psMetadataItemAllocStr("FPA.OBJECT", "Object of observation", "");
-            pmConceptRegister(fpaObject, NULL, NULL, PM_FPA_LEVEL_FPA);
+            pmConceptRegister(fpaObject, NULL, NULL, false, PM_FPA_LEVEL_FPA);
             psFree(fpaObject);
         }
@@ -551,5 +568,5 @@
         {
             psMetadataItem *fpaAlt = psMetadataItemAllocF64("FPA.ALT", "Altitude of telescope", NAN);
-            pmConceptRegister(fpaAlt, NULL, NULL, PM_FPA_LEVEL_FPA);
+            pmConceptRegister(fpaAlt, NULL, NULL, false, PM_FPA_LEVEL_FPA);
             psFree(fpaAlt);
         }
@@ -558,5 +575,5 @@
         {
             psMetadataItem *fpaAz = psMetadataItemAllocF64("FPA.AZ", "Azimuth of telescope", NAN);
-            pmConceptRegister(fpaAz, NULL, NULL, PM_FPA_LEVEL_FPA);
+            pmConceptRegister(fpaAz, NULL, NULL, false, PM_FPA_LEVEL_FPA);
             psFree(fpaAz);
         }
@@ -566,5 +583,5 @@
             psMetadataItem *fpaTimesys = psMetadataItemAllocS32("FPA.TIMESYS", "Time system", -1);
             pmConceptRegister(fpaTimesys, (pmConceptParseFunc)p_pmConceptParse_TIMESYS,
-                              (pmConceptFormatFunc)p_pmConceptFormat_TIMESYS, PM_FPA_LEVEL_FPA);
+                              (pmConceptFormatFunc)p_pmConceptFormat_TIMESYS, false, PM_FPA_LEVEL_FPA);
             psFree(fpaTimesys);
         }
@@ -580,5 +597,5 @@
             psFree(time);
             pmConceptRegister(fpaTime, (pmConceptParseFunc)p_pmConceptParse_TIME,
-                              (pmConceptFormatFunc)p_pmConceptFormat_TIME, PM_FPA_LEVEL_FPA);
+                              (pmConceptFormatFunc)p_pmConceptFormat_TIME, false, PM_FPA_LEVEL_FPA);
             psFree(fpaTime);
         }
@@ -587,5 +604,5 @@
         {
             psMetadataItem *fpaTemp = psMetadataItemAllocF32("FPA.TEMP", "Temperature of focal plane", NAN);
-            pmConceptRegister(fpaTemp, NULL, NULL, PM_FPA_LEVEL_FPA);
+            pmConceptRegister(fpaTemp, NULL, NULL, false, PM_FPA_LEVEL_FPA);
             psFree(fpaTemp);
         }
@@ -595,5 +612,5 @@
             psMetadataItem *fpaExposure = psMetadataItemAllocF32("FPA.EXPOSURE",
                                           "Exposure time (sec)", NAN);
-            pmConceptRegister(fpaExposure, NULL, NULL, PM_FPA_LEVEL_FPA);
+            pmConceptRegister(fpaExposure, NULL, NULL, false, PM_FPA_LEVEL_FPA);
             psFree(fpaExposure);
         }
@@ -611,5 +628,5 @@
             psMetadataItem *chipXparity = psMetadataItemAllocS32("CHIP.XPARITY",
                                           "Orientation in x compared to the rest of the FPA", 0);
-            pmConceptRegister(chipXparity, NULL, NULL, PM_FPA_LEVEL_CHIP);
+            pmConceptRegister(chipXparity, NULL, NULL, true, PM_FPA_LEVEL_CHIP);
             psFree(chipXparity);
         }
@@ -619,5 +636,5 @@
             psMetadataItem *chipYparity = psMetadataItemAllocS32("CHIP.YPARITY",
                                           "Orientation in y compared to the rest of the FPA", 0);
-            pmConceptRegister(chipYparity, NULL, NULL, PM_FPA_LEVEL_CHIP);
+            pmConceptRegister(chipYparity, NULL, NULL, true, PM_FPA_LEVEL_CHIP);
             psFree(chipYparity);
         }
@@ -627,5 +644,5 @@
             psMetadataItem *chipX0 = psMetadataItemAllocS32("CHIP.X0", "Position of (0,0) on the FPA", 0);
             pmConceptRegister(chipX0, (pmConceptParseFunc)p_pmConceptParse_Positions,
-                              (pmConceptFormatFunc)p_pmConceptFormat_Positions, PM_FPA_LEVEL_CHIP);
+                              (pmConceptFormatFunc)p_pmConceptFormat_Positions, true, PM_FPA_LEVEL_CHIP);
             psFree(chipX0);
         }
@@ -635,5 +652,5 @@
             psMetadataItem *chipY0 = psMetadataItemAllocS32("CHIP.Y0", "Position of (0,0) on the FPA", 0);
             pmConceptRegister(chipY0, (pmConceptParseFunc)p_pmConceptParse_Positions,
-                              (pmConceptFormatFunc)p_pmConceptFormat_Positions, PM_FPA_LEVEL_CHIP);
+                              (pmConceptFormatFunc)p_pmConceptFormat_Positions, true, PM_FPA_LEVEL_CHIP);
             psFree(chipY0);
         }
@@ -642,5 +659,5 @@
         {
             psMetadataItem *chipXsize = psMetadataItemAllocS32("CHIP.XSIZE", "Size of chip (pixels)", 0);
-            pmConceptRegister(chipXsize, NULL, NULL, PM_FPA_LEVEL_CHIP);
+            pmConceptRegister(chipXsize, NULL, NULL, true, PM_FPA_LEVEL_CHIP);
             psFree(chipXsize);
         }
@@ -649,5 +666,5 @@
         {
             psMetadataItem *chipYsize = psMetadataItemAllocS32("CHIP.YSIZE", "Size of chip (pixels)", 0);
-            pmConceptRegister(chipYsize, NULL, NULL, PM_FPA_LEVEL_CHIP);
+            pmConceptRegister(chipYsize, NULL, NULL, true, PM_FPA_LEVEL_CHIP);
             psFree(chipYsize);
         }
@@ -656,5 +673,5 @@
         {
             psMetadataItem *chipTemp = psMetadataItemAllocF32("CHIP.TEMP", "Temperature of chip", NAN);
-            pmConceptRegister(chipTemp, NULL, NULL, PM_FPA_LEVEL_CHIP);
+            pmConceptRegister(chipTemp, NULL, NULL, false, PM_FPA_LEVEL_CHIP);
             psFree(chipTemp);
         }
@@ -671,5 +688,5 @@
         {
             psMetadataItem *cellGain = psMetadataItemAllocF32("CELL.GAIN", "CCD gain (e/count)", NAN);
-            pmConceptRegister(cellGain, NULL, NULL, PM_FPA_LEVEL_CELL);
+            pmConceptRegister(cellGain, NULL, NULL, true, PM_FPA_LEVEL_CELL);
             psFree(cellGain);
         }
@@ -679,5 +696,5 @@
             psMetadataItem *cellReadnoise = psMetadataItemAllocF32("CELL.READNOISE",
                                             "CCD read noise (e)", NAN);
-            pmConceptRegister(cellReadnoise, NULL, NULL, PM_FPA_LEVEL_CELL);
+            pmConceptRegister(cellReadnoise, NULL, NULL, true, PM_FPA_LEVEL_CELL);
             psFree(cellReadnoise);
         }
@@ -687,5 +704,5 @@
             psMetadataItem *cellSaturation = psMetadataItemAllocF32("CELL.SATURATION",
                                              "Saturation level (counts)", NAN);
-            pmConceptRegister(cellSaturation, NULL, NULL, PM_FPA_LEVEL_CELL);
+            pmConceptRegister(cellSaturation, NULL, NULL, true, PM_FPA_LEVEL_CELL);
             psFree(cellSaturation);
         }
@@ -694,5 +711,5 @@
         {
             psMetadataItem *cellBad = psMetadataItemAllocF32("CELL.BAD", "Bad level (counts)", NAN);
-            pmConceptRegister(cellBad, NULL, NULL, PM_FPA_LEVEL_CELL);
+            pmConceptRegister(cellBad, NULL, NULL, true, PM_FPA_LEVEL_CELL);
             psFree(cellBad);
         }
@@ -702,5 +719,5 @@
             psMetadataItem *cellXparity = psMetadataItemAllocS32("CELL.XPARITY",
                                           "Orientation in x compared to the rest of the chip", 0);
-            pmConceptRegister(cellXparity, NULL, NULL, PM_FPA_LEVEL_CELL);
+            pmConceptRegister(cellXparity, NULL, NULL, true, PM_FPA_LEVEL_CELL);
             psFree(cellXparity);
         }
@@ -710,5 +727,5 @@
             psMetadataItem *cellYparity = psMetadataItemAllocS32("CELL.YPARITY",
                                           "Orientation in y compared to the rest of the chip", 0);
-            pmConceptRegister(cellYparity, NULL, NULL, PM_FPA_LEVEL_CELL);
+            pmConceptRegister(cellYparity, NULL, NULL, true, PM_FPA_LEVEL_CELL);
             psFree(cellYparity);
         }
@@ -718,5 +735,5 @@
             psMetadataItem *cellReaddir = psMetadataItemAllocS32("CELL.READDIR",
                                           "Read direction, rows=1, cols=2", 0);
-            pmConceptRegister(cellReaddir, NULL, NULL, PM_FPA_LEVEL_CELL);
+            pmConceptRegister(cellReaddir, NULL, NULL, true, PM_FPA_LEVEL_CELL);
             psFree(cellReaddir);
         }
@@ -733,5 +750,5 @@
             psMetadataItem *cellExposure = psMetadataItemAllocF32("CELL.EXPOSURE",
                                            "Exposure time (sec)", NAN);
-            pmConceptRegister(cellExposure, NULL, NULL, PM_FPA_LEVEL_CELL);
+            pmConceptRegister(cellExposure, NULL, NULL, false, PM_FPA_LEVEL_CELL);
             psFree(cellExposure);
         }
@@ -741,5 +758,5 @@
             psMetadataItem *cellDarktime = psMetadataItemAllocF32("CELL.DARKTIME",
                                            "Time since flush (sec)", NAN);
-            pmConceptRegister(cellDarktime, NULL, NULL, PM_FPA_LEVEL_CELL);
+            pmConceptRegister(cellDarktime, NULL, NULL, false, PM_FPA_LEVEL_CELL);
             psFree(cellDarktime);
         }
@@ -753,5 +770,5 @@
             psFree(trimsec);
             pmConceptRegister(cellTrimsec, (pmConceptParseFunc)p_pmConceptParse_CELL_TRIMSEC,
-                              (pmConceptFormatFunc)p_pmConceptFormat_CELL_TRIMSEC, PM_FPA_LEVEL_CELL);
+                              (pmConceptFormatFunc)p_pmConceptFormat_CELL_TRIMSEC, true, PM_FPA_LEVEL_CELL);
             psFree(cellTrimsec);
         }
@@ -764,5 +781,5 @@
             psFree(biassecs);
             pmConceptRegister(cellBiassec, (pmConceptParseFunc)p_pmConceptParse_CELL_BIASSEC,
-                              (pmConceptFormatFunc)p_pmConceptFormat_CELL_BIASSEC, PM_FPA_LEVEL_CELL);
+                              (pmConceptFormatFunc)p_pmConceptFormat_CELL_BIASSEC, true, PM_FPA_LEVEL_CELL);
             psFree(cellBiassec);
         }
@@ -772,5 +789,5 @@
             psMetadataItem *cellXbin = psMetadataItemAllocS32("CELL.XBIN", "Binning in x", 0);
             pmConceptRegister(cellXbin, (pmConceptParseFunc)p_pmConceptParse_CELL_Binning,
-                              (pmConceptFormatFunc)p_pmConceptFormat_CELL_XBIN, PM_FPA_LEVEL_CELL);
+                              (pmConceptFormatFunc)p_pmConceptFormat_CELL_XBIN, true, PM_FPA_LEVEL_CELL);
             psFree(cellXbin);
         }
@@ -780,5 +797,5 @@
             psMetadataItem *cellYbin = psMetadataItemAllocS32("CELL.YBIN", "Binning in y", 0);
             pmConceptRegister(cellYbin, (pmConceptParseFunc)p_pmConceptParse_CELL_Binning,
-                              (pmConceptFormatFunc)p_pmConceptFormat_CELL_YBIN, PM_FPA_LEVEL_CELL);
+                              (pmConceptFormatFunc)p_pmConceptFormat_CELL_YBIN, true, PM_FPA_LEVEL_CELL);
             psFree(cellYbin);
         }
@@ -788,5 +805,5 @@
             psMetadataItem *cellTimesys = psMetadataItemAllocS32("CELL.TIMESYS", "Time system", -1);
             pmConceptRegister(cellTimesys, (pmConceptParseFunc)p_pmConceptParse_TIMESYS,
-                              (pmConceptFormatFunc)p_pmConceptFormat_TIMESYS, PM_FPA_LEVEL_CELL);
+                              (pmConceptFormatFunc)p_pmConceptFormat_TIMESYS, false, PM_FPA_LEVEL_CELL);
             psFree(cellTimesys);
         }
@@ -802,5 +819,5 @@
             psFree(time);
             pmConceptRegister(cellTime, (pmConceptParseFunc)p_pmConceptParse_TIME,
-                              (pmConceptFormatFunc)p_pmConceptFormat_TIME, PM_FPA_LEVEL_CELL);
+                              (pmConceptFormatFunc)p_pmConceptFormat_TIME, false, PM_FPA_LEVEL_CELL);
             psFree(cellTime);
         }
@@ -810,5 +827,5 @@
             psMetadataItem *cellX0 = psMetadataItemAllocS32("CELL.X0", "Position of (0,0) on the chip", 0);
             pmConceptRegister(cellX0, (pmConceptParseFunc)p_pmConceptParse_Positions,
-                              (pmConceptFormatFunc)p_pmConceptFormat_Positions, PM_FPA_LEVEL_CELL);
+                              (pmConceptFormatFunc)p_pmConceptFormat_Positions, true, PM_FPA_LEVEL_CELL);
             psFree(cellX0);
         }
@@ -818,5 +835,5 @@
             psMetadataItem *cellY0 = psMetadataItemAllocS32("CELL.Y0", "Position of (0,0) on the chip", 0);
             pmConceptRegister(cellY0, (pmConceptParseFunc)p_pmConceptParse_Positions,
-                              (pmConceptFormatFunc)p_pmConceptFormat_Positions, PM_FPA_LEVEL_CELL);
+                              (pmConceptFormatFunc)p_pmConceptFormat_Positions, true, PM_FPA_LEVEL_CELL);
             psFree(cellY0);
         }
@@ -825,5 +842,5 @@
         {
             psMetadataItem *cellXsize = psMetadataItemAllocS32("CELL.XSIZE", "Size of cell (pixels)", 0);
-            pmConceptRegister(cellXsize, NULL, NULL, PM_FPA_LEVEL_CELL);
+            pmConceptRegister(cellXsize, NULL, NULL, true, PM_FPA_LEVEL_CELL);
             psFree(cellXsize);
         }
@@ -832,5 +849,5 @@
         {
             psMetadataItem *cellYsize = psMetadataItemAllocS32("CELL.YSIZE", "Size of cell (pixels)", 0);
-            pmConceptRegister(cellYsize, NULL, NULL, PM_FPA_LEVEL_CELL);
+            pmConceptRegister(cellYsize, NULL, NULL, true, PM_FPA_LEVEL_CELL);
             psFree(cellYsize);
         }
Index: /trunk/psModules/src/concepts/pmConcepts.h
===================================================================
--- /trunk/psModules/src/concepts/pmConcepts.h	(revision 12284)
+++ /trunk/psModules/src/concepts/pmConcepts.h	(revision 12285)
@@ -4,6 +4,6 @@
  * @author Paul Price, IfA
  *
- * @version $Revision: 1.12 $ $Name: not supported by cvs2svn $
- * @date $Date: 2007-02-12 22:22:15 $
+ * @version $Revision: 1.13 $ $Name: not supported by cvs2svn $
+ * @date $Date: 2007-03-07 00:10:36 $
  * Copyright 2005-2006 Institute for Astronomy, University of Hawaii
  */
@@ -62,4 +62,5 @@
     pmConceptParseFunc parse;           ///< Function to call to read the concept
     pmConceptFormatFunc format;         ///< Function to call to write the concept
+    bool required;                      ///< Is concept required (throw an error on problems)?
 }
 pmConceptSpec;
@@ -68,6 +69,18 @@
 pmConceptSpec *pmConceptSpecAlloc(psMetadataItem *blank, ///< Blank value; contains the name
                                   pmConceptParseFunc parse, ///< Function to call to parse the concept
-                                  pmConceptFormatFunc format ///< Function to call to format the concept
+                                  pmConceptFormatFunc format, ///< Function to call to format the concept
+                                  bool required ///< Is concept required?
                                  );
+
+/// Get whether a particular concept is required
+bool pmConceptGetRequired(const char *name, ///< Name of concept
+                          pmFPALevel level ///< Level at which concept resides
+    );
+
+/// Set whether a particular concept is required
+bool pmConceptSetRequired(const char *name, ///< Name of concept
+                          pmFPALevel level, ///< Level at which concept resides
+                          bool required ///< Whether concept is required or not
+    );
 
 /// Register a new concept for parsing and formatting
@@ -80,4 +93,5 @@
                        pmConceptParseFunc parse, ///< Function to call to parse the concept, or NULL
                        pmConceptFormatFunc format, ///< Function to call to format the concept, or NULL
+                       bool required,   ///< Is concept required?
                        pmFPALevel level ///< Level at which to store concept in the FPA hierarchy
                       );
Index: /trunk/psModules/src/concepts/pmConceptsRead.c
===================================================================
--- /trunk/psModules/src/concepts/pmConceptsRead.c	(revision 12284)
+++ /trunk/psModules/src/concepts/pmConceptsRead.c	(revision 12285)
@@ -76,6 +76,11 @@
     }
     if (!parsed) {
-        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to parse concept %s\n", spec->blank->name);
-        return false;
+        if (spec->required) {
+            psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to parse concept %s\n", spec->blank->name);
+            return false;
+        } else {
+            psWarning("Unable to parse concept %s, but concept not marked as required.\n", spec->blank->name);
+            psErrorClear();
+        }
     }
 
