Index: trunk/psModules/src/concepts/pmConcepts.c
===================================================================
--- trunk/psModules/src/concepts/pmConcepts.c	(revision 20951)
+++ trunk/psModules/src/concepts/pmConcepts.c	(revision 22699)
@@ -19,5 +19,4 @@
 #include "pmConceptsWrite.h"
 #include "pmConceptsStandard.h"
-#include "pmConceptsUpdate.h"
 
 static bool conceptsInitialised = false;// Have concepts been read?
@@ -49,5 +48,6 @@
 
 pmConceptSpec *pmConceptSpecAlloc(psMetadataItem *blank, pmConceptParseFunc parse,
-                                  pmConceptFormatFunc format, bool required)
+                                  pmConceptFormatFunc format, pmConceptCopyFunc copy,
+                                  bool required)
 {
     pmConceptSpec *spec = psAlloc(sizeof(pmConceptSpec));
@@ -57,4 +57,5 @@
     spec->parse = parse;
     spec->format = format;
+    spec->copy = copy;
     spec->required = required;
 
@@ -86,4 +87,20 @@
 }
 
+psMetadata *pmConceptsSpecs(pmFPALevel level)
+{
+    if (!conceptsInitialised) {
+        pmConceptsInit();
+    }
+
+    // Get the appropriate concepts
+    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;
+    }
+
+    return concepts;
+}
+
 bool pmConceptGetRequired(const char *name, pmFPALevel level)
 {
@@ -129,5 +146,6 @@
 
 bool pmConceptRegister(psMetadataItem *blank, pmConceptParseFunc parse,
-                        pmConceptFormatFunc format, bool required, pmFPALevel level)
+                       pmConceptFormatFunc format, pmConceptCopyFunc copy,
+                       bool required, pmFPALevel level)
 {
     PS_ASSERT_PTR_NON_NULL(blank, false);
@@ -144,5 +162,5 @@
     }
 
-    pmConceptSpec *spec = pmConceptSpecAlloc(blank, parse, format, required); // The concept specification
+    pmConceptSpec *spec = pmConceptSpecAlloc(blank, parse, format, copy, required); // Concept specification
     psMetadataAdd(target, PS_LIST_TAIL, blank->name, PS_DATA_UNKNOWN | PS_META_REPLACE,
                   "Concepts specification", spec);
@@ -188,154 +206,4 @@
 
 
-
-// Read all registered concepts for the specified level
-static bool conceptsRead(psMetadata **specs, // One of the concepts specifications
-                         pmFPA *fpa,    // The FPA
-                         pmChip *chip,  // The chip
-                         pmCell *cell, // The cell
-                         unsigned int *read,     // What's already been read
-                         pmConceptSource source, // The source of the concepts to read
-                         pmConfig *config, // Configuration
-                         psMetadata *target // Place into which to read the concepts
-                        )
-{
-    assert(specs);
-    assert(read);
-    assert(target);
-
-    if (!conceptsInitialised) {
-        pmConceptsInit();
-    }
-
-    // At least one HDU is required for the reading functions
-    pmHDU *hduLow = pmHDUGetLowest(fpa, chip, cell); // Lowest HDU.
-    if (!hduLow) {
-        // Can't do anything --- don't record any success, but don't return an error either
-        return true;
-    }
-    pmHDU *hduHigh = pmHDUGetHighest(fpa, chip, cell); // Highest HDU
-
-    if (cell && (cell->conceptsRead == PM_CONCEPT_SOURCE_NONE)) {
-        pmConceptsBlankCell(cell);
-        cell->conceptsRead = PM_CONCEPT_SOURCE_BLANK;
-    }
-    if (chip && (chip->conceptsRead == PM_CONCEPT_SOURCE_NONE)) {
-        pmConceptsBlankChip(chip);
-        chip->conceptsRead = PM_CONCEPT_SOURCE_BLANK;
-    }
-    if (fpa && (fpa->conceptsRead == PM_CONCEPT_SOURCE_NONE)) {
-        pmConceptsBlankFPA(fpa);
-        fpa->conceptsRead = PM_CONCEPT_SOURCE_BLANK;
-    }
-
-    bool success = true;                // Success in reading concepts?
-    if (source & PM_CONCEPT_SOURCE_CELLS && !(*read & PM_CONCEPT_SOURCE_CELLS) && cell) {
-        if (p_pmConceptsReadFromCells(target, *specs, cell)) {
-            *read |= PM_CONCEPT_SOURCE_CELLS;
-        } else {
-            psError(PS_ERR_UNKNOWN, false, "Error reading concepts from camera configuration.\n");
-            success = false;
-        }
-    }
-
-    if (source & PM_CONCEPT_SOURCE_DEFAULTS && !(*read & PM_CONCEPT_SOURCE_DEFAULTS)) {
-        if (p_pmConceptsReadFromDefaults(target, *specs, fpa, chip, cell)) {
-            *read |= PM_CONCEPT_SOURCE_DEFAULTS;
-        } else {
-            psError(PS_ERR_UNKNOWN, false, "Error reading concepts from defaults.\n");
-            success = false;
-        }
-    }
-
-    if (source & PM_CONCEPT_SOURCE_PHU && !(*read & PM_CONCEPT_SOURCE_PHU) && hduHigh->header) {
-        if (p_pmConceptsReadFromHeader(target, *specs, fpa, chip, cell)) {
-            *read |= PM_CONCEPT_SOURCE_PHU;
-        } else {
-            psError(PS_ERR_UNKNOWN, false, "Error reading concepts from PHU.\n");
-            success = false;
-        }
-    }
-
-    // If there are multiple HDUs, then it may be that one of them hasn't been read yet (hdu->header not set)
-    if (source & PM_CONCEPT_SOURCE_HEADER && !(*read & PM_CONCEPT_SOURCE_HEADER) &&
-        hduLow != hduHigh && hduLow->header) {
-        if (p_pmConceptsReadFromHeader(target, *specs, fpa, chip, cell)) {
-            *read |= PM_CONCEPT_SOURCE_HEADER;
-        } else {
-            psError(PS_ERR_UNKNOWN, false, "Error reading concepts from header.\n");
-            success = false;
-        }
-    }
-
-    #ifdef HAVE_PSDB
-    if (source & PM_CONCEPT_SOURCE_DATABASE && !(*read & PM_CONCEPT_SOURCE_DATABASE)) {
-        if (p_pmConceptsReadFromDatabase(target, *specs, fpa, chip, cell, config)) {
-            *read |= PM_CONCEPT_SOURCE_DATABASE;
-        } else {
-            psError(PS_ERR_UNKNOWN, false, "Error reading concepts from database.\n");
-            success = false;
-        }
-    }
-    #endif
-
-    pmConceptsUpdate(fpa, chip, cell);
-
-    return success;
-}
-
-// Write all registered concepts for the specified level
-static bool conceptsWrite(psMetadata **specs, // One of the concepts specifications
-                          const pmFPA *fpa,   // The FPA
-                          const pmChip *chip, // The chip
-                          const pmCell *cell, // The cell
-                          pmConceptSource source, // The source of the concepts to write
-                          pmConfig *config, // Configuration
-                          const psMetadata *concepts // The concepts to write out
-                         )
-{
-    assert(specs);
-    assert(concepts);
-
-    if (!conceptsInitialised) {
-        pmConceptsInit();
-    }
-
-    psTrace("psModules.concepts", 3, "Writing concepts (%p %p %p): %d\n", fpa, chip, cell, source);
-
-    if (source & PM_CONCEPT_SOURCE_CELLS) {
-        p_pmConceptsWriteToCells(*specs, cell, concepts);
-    }
-    if (source & PM_CONCEPT_SOURCE_DEFAULTS) {
-        p_pmConceptsWriteToDefaults(*specs, fpa, chip, cell, concepts);
-    }
-    if (source & (PM_CONCEPT_SOURCE_PHU | PM_CONCEPT_SOURCE_HEADER)) {
-        p_pmConceptsWriteToHeader(*specs, fpa, chip, cell, concepts);
-    }
-    if (source & PM_CONCEPT_SOURCE_DATABASE) {
-        p_pmConceptsWriteToDatabase(*specs, fpa, chip, cell, config, concepts);
-    }
-
-    return true;
-}
-
-
-bool pmConceptsRead(pmFPA *fpa, pmChip *chip, pmCell *cell, pmConceptSource source, pmConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(fpa, false);
-    bool success = conceptsRead(&conceptsFPA, fpa, chip, cell, &fpa->conceptsRead, source,
-                                config, fpa->concepts);
-    if (chip) {
-        success &= conceptsRead(&conceptsChip, fpa, chip, cell, &chip->conceptsRead, source,
-                                config, chip->concepts);
-    }
-    if (cell) {
-        success &= conceptsRead(&conceptsCell, fpa, chip, cell, &cell->conceptsRead, source,
-                                config, cell->concepts);
-    }
-
-    return success;
-}
-
-
 bool pmConceptsBlankFPA(pmFPA *fpa)
 {
@@ -345,41 +213,4 @@
 }
 
-
-bool pmConceptsReadFPA(pmFPA *fpa, pmConceptSource source, bool propagateDown, pmConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(fpa, false);
-    psTrace("psModules.concepts", 5, "Reading FPA concepts: %p %p\n", conceptsFPA, fpa->concepts);
-    bool success = conceptsRead(&conceptsFPA, fpa, NULL, NULL, &fpa->conceptsRead, source,
-                                config, fpa->concepts);
-    if (propagateDown) {
-        psArray *chips = fpa->chips;    // Array of chips
-        for (long i = 0; i < chips->n; i++) {
-            pmChip *chip = chips->data[i]; // Chip of interest
-            if (chip) {
-                success &= pmConceptsReadChip(chip, source, false, true, config);
-            }
-        }
-    }
-
-    return success;
-}
-
-bool pmConceptsWriteFPA(const pmFPA *fpa, pmConceptSource source, bool propagateDown, pmConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(fpa, false);
-    psTrace("psModules.concepts", 5, "Writing FPA concepts: %p %p\n", conceptsFPA, fpa->concepts);
-    bool success = conceptsWrite(&conceptsFPA, fpa, NULL, NULL, source, config, fpa->concepts);
-    if (propagateDown) {
-        psArray *chips = fpa->chips;        // Array of chips
-        for (long i = 0; i < chips->n; i++) {
-            pmChip *chip = chips->data[i];  // Chip of interest
-            if (chip && !chip->hdu) {
-                success &= pmConceptsWriteChip(chip, source, false, true, config);
-            }
-        }
-    }
-    return success;
-}
-
 bool pmConceptsBlankChip(pmChip *chip)
 {
@@ -389,50 +220,4 @@
 }
 
-bool pmConceptsReadChip(pmChip *chip, pmConceptSource source, bool propagateUp,
-                        bool propagateDown, pmConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(chip, false);
-    psTrace("psModules.concepts", 5, "Reading chip concepts: %p %p\n", conceptsChip, chip->concepts);
-    pmFPA *fpa = chip->parent;          // FPA to which the chip belongs
-    bool success = conceptsRead(&conceptsChip, fpa, chip, NULL, &chip->conceptsRead, source, config,
-                                chip->concepts);
-    if (propagateUp) {
-        success &= conceptsRead(&conceptsFPA, fpa, chip, NULL, &fpa->conceptsRead, source,
-                                config, fpa->concepts);
-    }
-    if (propagateDown) {
-        psArray *cells = chip->cells;        // Array of cells
-        for (long i = 0; i < cells->n; i++) {
-            pmCell *cell = cells->data[i];  // Cell of interest
-            if (cell) {
-                success &= pmConceptsReadCell(cell, source, false, config);
-            }
-        }
-    }
-    return success;
-}
-
-bool pmConceptsWriteChip(const pmChip *chip, pmConceptSource source, bool propagateUp,
-                         bool propagateDown, pmConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(chip, false);
-    psTrace("psModules.concepts", 5, "Writing chip concepts: %p %p\n", conceptsChip, chip->concepts);
-    pmFPA *fpa = chip->parent;          // FPA to which the chip belongs
-    bool success = conceptsWrite(&conceptsChip, fpa, chip, NULL, source, config, chip->concepts);
-    if (propagateUp && !fpa->hdu) {
-        success &= conceptsWrite(&conceptsFPA, fpa, chip, NULL, source, config, fpa->concepts);
-    }
-    if (propagateDown) {
-        psArray *cells = chip->cells;        // Array of cells
-        for (long i = 0; i < cells->n; i++) {
-            pmCell *cell = cells->data[i];  // Cell of interest
-            if (cell && !cell->hdu) {
-                success &= pmConceptsWriteCell(cell, source, false, config);
-            }
-        }
-    }
-    return success;
-}
-
 bool pmConceptsBlankCell(pmCell *cell)
 {
@@ -440,43 +225,4 @@
     psTrace("psModules.concepts", 5, "Blanking cell concepts: %p %p\n", conceptsCell, cell->concepts);
     return conceptsBlank(&conceptsCell, cell->concepts);
-}
-
-bool pmConceptsReadCell(pmCell *cell, pmConceptSource source, bool propagateUp, pmConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(cell, false);
-    psTrace("psModules.concepts", 5, "Reading cell concepts: %p %p\n", conceptsCell, cell->concepts);
-    pmChip *chip = cell->parent;        // Chip to which the cell belongs
-    pmFPA *fpa = chip->parent;          // FPA to which the chip belongs
-
-    bool success = conceptsRead(&conceptsCell, fpa, chip, cell, &cell->conceptsRead, source, config,
-                                cell->concepts);
-    if (propagateUp) {
-        success &= conceptsRead(&conceptsChip, fpa, chip, cell, &chip->conceptsRead, source, config,
-                                chip->concepts);
-        success &= conceptsRead(&conceptsFPA, fpa, chip, cell, &fpa->conceptsRead, source, config,
-                                fpa->concepts);
-    }
-
-    return success;
-}
-
-bool pmConceptsWriteCell(const pmCell *cell, pmConceptSource source, bool propagateUp, pmConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(cell, false);
-    psTrace("psModules.concepts", 5, "Writing cell concepts: %p %p\n", conceptsCell, cell->concepts);
-    pmChip *chip = cell->parent;        // Chip to which the cell belongs
-    pmFPA *fpa = chip->parent;          // FPA to which the chip belongs
-
-    bool success = conceptsWrite(&conceptsCell, fpa, chip, cell, source, config, cell->concepts);
-    if (propagateUp) {
-        if (!chip->hdu) {
-            success &= conceptsWrite(&conceptsChip, fpa, chip, cell, source, config, chip->concepts);
-            if (!fpa->hdu) {
-                success &= conceptsWrite(&conceptsFPA, fpa, chip, cell, source, config, fpa->concepts);
-            }
-        }
-    }
-
-    return success;
 }
 
@@ -485,6 +231,7 @@
 static void conceptRegister##SUFFIX(const char *name, /* Name of concept */ \
                                     const char *comment, /* Comment for concept */ \
-                                    pmConceptParseFunc parse, /* Parsing function */ \
-                                    pmConceptFormatFunc format, /* Formatting function */ \
+                                    pmConceptParseFunc parse, /* Parsing function, or NULL */ \
+                                    pmConceptFormatFunc format, /* Formatting function, or NULL */ \
+                                    pmConceptCopyFunc copy, /* Copying function, or NULL */ \
                                     bool required, /* Required concept? */ \
                                     pmFPALevel level /* Level at which concept applies */ \
@@ -492,5 +239,5 @@
 { \
     psMetadataItem *item = psMetadataItemAlloc##TYPENAME(name, comment, DEFAULT); /* Item to add */ \
-    pmConceptRegister(item, parse, format, required, level); \
+    pmConceptRegister(item, parse, format, copy, required, level); \
     psFree(item); \
     return; \
@@ -515,5 +262,5 @@
     psMetadataItem *item = psMetadataItemAlloc(name, PS_DATA_TIME, comment, time);
     psFree(time);
-    pmConceptRegister(item, p_pmConceptParse_TIME, p_pmConceptFormat_TIME, required, level);
+    pmConceptRegister(item, p_pmConceptParse_TIME, p_pmConceptFormat_TIME, NULL, required, level);
     psFree(item);
 }
@@ -521,4 +268,8 @@
 bool pmConceptsInit(void)
 {
+    if (conceptsInitialised) {
+        return true;
+    }
+
     conceptsInitialised = true;
 
@@ -527,84 +278,84 @@
     bool init = false;                  // Did we initialise anything?
 
-    if (! conceptsFPA) {
+    if (!conceptsFPA) {
         conceptsFPA = psMetadataAlloc();
         init = true;
 
         // Install the standard concepts
-        conceptRegisterStr("FPA.TELESCOPE", "Telescope of origin", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterStr("FPA.INSTRUMENT", "Instrument name (according to the instrument)", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterStr("FPA.DETECTOR", "Detector name", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterStr("FPA.COMMENT", "Observation comment", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterStr("FPA.OBS.MODE", "Observation mode (eg, survey id)", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterStr("FPA.OBS.GROUP", "Observation group (eg, associated images)", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.FOCUS", "Telescope focus", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.AIRMASS", "Airmass at boresight", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterStr("FPA.FILTERID", "Filter used (parsed, abstract name)", p_pmConceptParse_FPA_FILTER, p_pmConceptFormat_FPA_FILTER, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterStr("FPA.FILTER", "Filter used (instrument name)", false, NULL, NULL, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.POSANGLE", "Position angle of instrument", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.ROTANGLE", "Rotator angle of instrument", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterStr("FPA.RADECSYS", "Celestial coordinate system", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF64("FPA.RA", "Right Ascension of boresight", p_pmConceptParse_FPA_Coords, p_pmConceptFormat_FPA_Coords, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF64("FPA.DEC", "Declination of boresight", p_pmConceptParse_FPA_Coords, p_pmConceptFormat_FPA_Coords, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF64("FPA.LONGITUDE", "West longitude of observatory", p_pmConceptParse_FPA_Coords, p_pmConceptFormat_FPA_Coords, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF64("FPA.LATITUDE", "Latitude of observatory", p_pmConceptParse_FPA_Coords, p_pmConceptFormat_FPA_Coords, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.ELEVATION", "Elevation of observatory (metres)", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterStr("FPA.OBSTYPE", "Type of observation", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterStr("FPA.OBJECT", "Object of observation", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF64("FPA.ALT", "Altitude of boresight", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF64("FPA.AZ", "Azimuth of boresight", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterEnum("FPA.TIMESYS", "Time system", p_pmConceptParse_TIMESYS, p_pmConceptFormat_TIMESYS, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterStr("FPA.TELESCOPE", "Telescope of origin", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterStr("FPA.INSTRUMENT", "Instrument name (according to the instrument)", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterStr("FPA.DETECTOR", "Detector name", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterStr("FPA.COMMENT", "Observation comment", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterStr("FPA.OBS.MODE", "Observation mode (eg, survey id)", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterStr("FPA.OBS.GROUP", "Observation group (eg, associated images)", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.FOCUS", "Telescope focus", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.AIRMASS", "Airmass at boresight", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterStr("FPA.FILTERID", "Filter used (parsed, abstract name)", p_pmConceptParse_FPA_FILTER, p_pmConceptFormat_FPA_FILTER, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterStr("FPA.FILTER", "Filter used (instrument name)", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.POSANGLE", "Position angle of instrument", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.ROTANGLE", "Rotator angle of instrument", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterStr("FPA.RADECSYS", "Celestial coordinate system", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF64("FPA.RA", "Right Ascension of boresight", p_pmConceptParse_FPA_Coords, p_pmConceptFormat_FPA_Coords, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF64("FPA.DEC", "Declination of boresight", p_pmConceptParse_FPA_Coords, p_pmConceptFormat_FPA_Coords, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF64("FPA.LONGITUDE", "West longitude of observatory", p_pmConceptParse_FPA_Coords, p_pmConceptFormat_FPA_Coords, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF64("FPA.LATITUDE", "Latitude of observatory", p_pmConceptParse_FPA_Coords, p_pmConceptFormat_FPA_Coords, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.ELEVATION", "Elevation of observatory (metres)", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterStr("FPA.OBSTYPE", "Type of observation", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterStr("FPA.OBJECT", "Object of observation", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF64("FPA.ALT", "Altitude of boresight", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF64("FPA.AZ", "Azimuth of boresight", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterEnum("FPA.TIMESYS", "Time system", p_pmConceptParse_TIMESYS, p_pmConceptFormat_TIMESYS, p_pmConceptCopy_TIMESYS, false, PM_FPA_LEVEL_FPA);
         conceptRegisterTime("FPA.TIME", "Time of exposure", false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.TEMP", "Temperature of focal plane", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.M1X", "Primary Mirror X Position", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.M1Y", "Primary Mirror Y Position", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.M1Z", "Primary Mirror Z Position", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.M1TIP", "Primary Mirror TIP", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.M1TILT", "Primary Mirror TILT", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.M2X", "Primary Mirror X Position", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.M2Y", "Primary Mirror Y Position", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.M2Z", "Primary Mirror Z Position", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.M2TIP", "Primary Mirror TIP", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.M2TILT", "Primary Mirror TILT", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.ENV.TEMP", "Environment: Temperature", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.ENV.HUMID", "Environment: Humidity", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.ENV.WIND", "Environment: Wind speed", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.ENV.DIR", "Environment: Wind direction", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.TELTEMP.M1", "Telescope Temperatures: M1", p_pmConceptParse_TELTEMPS, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.TELTEMP.M1CELL", "Telescope Temperatures: M1 cell", p_pmConceptParse_TELTEMPS, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.TELTEMP.M2", "Telescope Temperatures: M2", p_pmConceptParse_TELTEMPS, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.TELTEMP.SPIDER", "Telescope Temperatures: spider", p_pmConceptParse_TELTEMPS, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.TELTEMP.TRUSS", "Telescope Temperatures: truss", p_pmConceptParse_TELTEMPS, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.TELTEMP.EXTRA", "Telescope Temperatures: extra", p_pmConceptParse_TELTEMPS, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.PON.TIME", "Power On Time", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-        conceptRegisterF32("FPA.EXPOSURE", "Exposure time (sec)", NULL, NULL, false, PM_FPA_LEVEL_FPA);
-    }
-    if (! conceptsChip) {
+        conceptRegisterF32("FPA.TEMP", "Temperature of focal plane", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.M1X", "Primary Mirror X Position", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.M1Y", "Primary Mirror Y Position", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.M1Z", "Primary Mirror Z Position", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.M1TIP", "Primary Mirror TIP", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.M1TILT", "Primary Mirror TILT", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.M2X", "Primary Mirror X Position", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.M2Y", "Primary Mirror Y Position", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.M2Z", "Primary Mirror Z Position", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.M2TIP", "Primary Mirror TIP", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.M2TILT", "Primary Mirror TILT", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.ENV.TEMP", "Environment: Temperature", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.ENV.HUMID", "Environment: Humidity", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.ENV.WIND", "Environment: Wind speed", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.ENV.DIR", "Environment: Wind direction", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.TELTEMP.M1", "Telescope Temperatures: M1", p_pmConceptParse_TELTEMPS, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.TELTEMP.M1CELL", "Telescope Temperatures: M1 cell", p_pmConceptParse_TELTEMPS, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.TELTEMP.M2", "Telescope Temperatures: M2", p_pmConceptParse_TELTEMPS, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.TELTEMP.SPIDER", "Telescope Temperatures: spider", p_pmConceptParse_TELTEMPS, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.TELTEMP.TRUSS", "Telescope Temperatures: truss", p_pmConceptParse_TELTEMPS, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.TELTEMP.EXTRA", "Telescope Temperatures: extra", p_pmConceptParse_TELTEMPS, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.PON.TIME", "Power On Time", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.EXPOSURE", "Exposure time (sec)", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+    }
+    if (!conceptsChip) {
         conceptsChip = psMetadataAlloc();
         init = true;
 
         // Install the standard concepts
-        conceptRegisterS32("CHIP.XPARITY", "Orientation in x compared to the rest of the FPA", NULL, NULL, true, PM_FPA_LEVEL_CHIP);
-        conceptRegisterS32("CHIP.YPARITY", "Orientation in y compared to the rest of the FPA", NULL, NULL, true, PM_FPA_LEVEL_CHIP);
-        conceptRegisterS32("CHIP.X0", "Position of (0,0) on the FPA",p_pmConceptParse_Positions,p_pmConceptFormat_Positions, true, PM_FPA_LEVEL_CHIP);
-        conceptRegisterS32("CHIP.Y0", "Position of (0,0) on the FPA",p_pmConceptParse_Positions,p_pmConceptFormat_Positions, true, PM_FPA_LEVEL_CHIP);
-        conceptRegisterS32("CHIP.XSIZE", "Size of chip (pixels)", NULL, NULL, true, PM_FPA_LEVEL_CHIP);
-        conceptRegisterS32("CHIP.YSIZE", "Size of chip (pixels)", NULL, NULL, true, PM_FPA_LEVEL_CHIP);
-        conceptRegisterF32("CHIP.TEMP", "Temperature of chip", NULL, NULL, false, PM_FPA_LEVEL_CHIP);
-        conceptRegisterStr("CHIP.ID", "Chip identifier", NULL, NULL, false, PM_FPA_LEVEL_CHIP);
-    }
-
-    if (! conceptsCell) {
+        conceptRegisterS32("CHIP.XPARITY", "Orientation in x compared to the rest of the FPA", NULL, NULL, NULL, true, PM_FPA_LEVEL_CHIP);
+        conceptRegisterS32("CHIP.YPARITY", "Orientation in y compared to the rest of the FPA", NULL, NULL, NULL, true, PM_FPA_LEVEL_CHIP);
+        conceptRegisterS32("CHIP.X0", "Position of (0,0) on the FPA",p_pmConceptParse_Positions,p_pmConceptFormat_Positions, NULL, true, PM_FPA_LEVEL_CHIP);
+        conceptRegisterS32("CHIP.Y0", "Position of (0,0) on the FPA",p_pmConceptParse_Positions,p_pmConceptFormat_Positions, NULL, true, PM_FPA_LEVEL_CHIP);
+        conceptRegisterS32("CHIP.XSIZE", "Size of chip (pixels)", NULL, NULL, NULL, true, PM_FPA_LEVEL_CHIP);
+        conceptRegisterS32("CHIP.YSIZE", "Size of chip (pixels)", NULL, NULL, NULL, true, PM_FPA_LEVEL_CHIP);
+        conceptRegisterF32("CHIP.TEMP", "Temperature of chip", NULL, NULL, NULL, false, PM_FPA_LEVEL_CHIP);
+        conceptRegisterStr("CHIP.ID", "Chip identifier", NULL, NULL, NULL, false, PM_FPA_LEVEL_CHIP);
+    }
+
+    if (!conceptsCell) {
         conceptsCell = psMetadataAlloc();
         init = true;
 
         // Install the standard concepts
-        conceptRegisterF32("CELL.GAIN", "CCD gain (e/count)", NULL, NULL, true, PM_FPA_LEVEL_CELL);
-        conceptRegisterF32("CELL.READNOISE", "CCD read noise (e)", p_pmConceptParse_CELL_READNOISE, p_pmConceptFormat_CELL_READNOISE, true, PM_FPA_LEVEL_CELL);
-        conceptRegisterF32("CELL.SATURATION", "Saturation level (counts)", NULL, NULL, true, PM_FPA_LEVEL_CELL);
-        conceptRegisterF32("CELL.BAD", "Bad level (counts)", NULL, NULL, true, PM_FPA_LEVEL_CELL);
-        conceptRegisterS32("CELL.XPARITY", "Orientation in x compared to the rest of the chip", NULL, NULL, true, PM_FPA_LEVEL_CELL);
-        conceptRegisterS32("CELL.YPARITY", "Orientation in y compared to the rest of the chip", NULL, NULL, true, PM_FPA_LEVEL_CELL);
-        conceptRegisterS32("CELL.READDIR", "Read direction, rows=1, cols=2", NULL, NULL, true, PM_FPA_LEVEL_CELL);
+        conceptRegisterF32("CELL.GAIN", "CCD gain (e/count)", NULL, NULL, NULL, true, PM_FPA_LEVEL_CELL);
+        conceptRegisterF32("CELL.READNOISE", "CCD read noise (e)", p_pmConceptParse_CELL_READNOISE, p_pmConceptFormat_CELL_READNOISE, NULL, true, PM_FPA_LEVEL_CELL);
+        conceptRegisterF32("CELL.SATURATION", "Saturation level (counts)", NULL, NULL, NULL, true, PM_FPA_LEVEL_CELL);
+        conceptRegisterF32("CELL.BAD", "Bad level (counts)", NULL, NULL, NULL, true, PM_FPA_LEVEL_CELL);
+        conceptRegisterS32("CELL.XPARITY", "Orientation in x compared to the rest of the chip", NULL, NULL, NULL, true, PM_FPA_LEVEL_CELL);
+        conceptRegisterS32("CELL.YPARITY", "Orientation in y compared to the rest of the chip", NULL, NULL, NULL, true, PM_FPA_LEVEL_CELL);
+        conceptRegisterS32("CELL.READDIR", "Read direction, rows=1, cols=2", NULL, NULL, NULL, true, PM_FPA_LEVEL_CELL);
 
         // These (CELL.EXPOSURE and CELL.DARKTIME) used to be READOUT.EXPOSURE and READOUT.DARKTIME, but that
@@ -613,18 +364,18 @@
         // readout is a plane in a 3D image.  We'll have to dream up some additional suffix to specify these,
         // but for now....
-        conceptRegisterF32("CELL.EXPOSURE", "Exposure time (sec)", NULL, NULL, false, PM_FPA_LEVEL_CELL);
-        conceptRegisterF32("CELL.DARKTIME", "Time since flush (sec)", NULL, NULL, false, PM_FPA_LEVEL_CELL);
-
-        conceptRegisterS32("CELL.XBIN", "Binning in x", p_pmConceptParse_CELL_Binning,p_pmConceptFormat_CELL_XBIN, true, PM_FPA_LEVEL_CELL);
-        conceptRegisterS32("CELL.YBIN", "Binning in y",p_pmConceptParse_CELL_Binning,p_pmConceptFormat_CELL_YBIN, true, PM_FPA_LEVEL_CELL);
-        conceptRegisterEnum("CELL.TIMESYS", "Time system", p_pmConceptParse_TIMESYS,p_pmConceptFormat_TIMESYS, false, PM_FPA_LEVEL_CELL);
+        conceptRegisterF32("CELL.EXPOSURE", "Exposure time (sec)", NULL, NULL, NULL, false, PM_FPA_LEVEL_CELL);
+        conceptRegisterF32("CELL.DARKTIME", "Time since flush (sec)", NULL, NULL, NULL, false, PM_FPA_LEVEL_CELL);
+
+        conceptRegisterS32("CELL.XBIN", "Binning in x", p_pmConceptParse_CELL_Binning,p_pmConceptFormat_CELL_XBIN, NULL, true, PM_FPA_LEVEL_CELL);
+        conceptRegisterS32("CELL.YBIN", "Binning in y",p_pmConceptParse_CELL_Binning,p_pmConceptFormat_CELL_YBIN, NULL, true, PM_FPA_LEVEL_CELL);
+        conceptRegisterEnum("CELL.TIMESYS", "Time system", p_pmConceptParse_TIMESYS,p_pmConceptFormat_TIMESYS, p_pmConceptCopy_TIMESYS, false, PM_FPA_LEVEL_CELL);
         conceptRegisterTime("CELL.TIME", "Time of exposure", false, PM_FPA_LEVEL_CELL);
-        conceptRegisterS32("CELL.X0", "Position of (0,0) on the chip",p_pmConceptParse_Positions,p_pmConceptFormat_Positions, true, PM_FPA_LEVEL_CELL);
-        conceptRegisterS32("CELL.Y0", "Position of (0,0) on the chip",p_pmConceptParse_Positions,p_pmConceptFormat_Positions, true, PM_FPA_LEVEL_CELL);
-        conceptRegisterS32("CELL.XSIZE", "Size of cell (pixels)", NULL, NULL, true, PM_FPA_LEVEL_CELL);
-        conceptRegisterS32("CELL.YSIZE", "Size of cell (pixels)", NULL, NULL, true, PM_FPA_LEVEL_CELL);
-        conceptRegisterS32("CELL.XWINDOW", "Start of cell window (pixels)",p_pmConceptParse_Positions,p_pmConceptFormat_Positions, true, PM_FPA_LEVEL_CELL);
-        conceptRegisterS32("CELL.YWINDOW", "Start of cell window (pixels)",p_pmConceptParse_Positions,p_pmConceptFormat_Positions, true, PM_FPA_LEVEL_CELL);
-        conceptRegisterF32("CELL.VARFACTOR", "Variance factor for conversion from large to small scales", NULL, NULL, true, PM_FPA_LEVEL_CELL);
+        conceptRegisterS32("CELL.X0", "Position of (0,0) on the chip",p_pmConceptParse_Positions,p_pmConceptFormat_Positions, NULL, true, PM_FPA_LEVEL_CELL);
+        conceptRegisterS32("CELL.Y0", "Position of (0,0) on the chip",p_pmConceptParse_Positions,p_pmConceptFormat_Positions, NULL, true, PM_FPA_LEVEL_CELL);
+        conceptRegisterS32("CELL.XSIZE", "Size of cell (pixels)", NULL, NULL, NULL, true, PM_FPA_LEVEL_CELL);
+        conceptRegisterS32("CELL.YSIZE", "Size of cell (pixels)", NULL, NULL, NULL, true, PM_FPA_LEVEL_CELL);
+        conceptRegisterS32("CELL.XWINDOW", "Start of cell window (pixels)",p_pmConceptParse_Positions,p_pmConceptFormat_Positions, NULL, true, PM_FPA_LEVEL_CELL);
+        conceptRegisterS32("CELL.YWINDOW", "Start of cell window (pixels)",p_pmConceptParse_Positions,p_pmConceptFormat_Positions, NULL, true, PM_FPA_LEVEL_CELL);
+        conceptRegisterF32("CELL.VARFACTOR", "Variance factor for conversion from large to small scales", NULL, NULL, NULL, true, PM_FPA_LEVEL_CELL);
 
         // CELL.TRIMSEC
@@ -635,5 +386,5 @@
                                           "Trim section", trimsec);
             psFree(trimsec);
-            pmConceptRegister(cellTrimsec, p_pmConceptParse_CELL_TRIMSEC,p_pmConceptFormat_CELL_TRIMSEC, true, PM_FPA_LEVEL_CELL);
+            pmConceptRegister(cellTrimsec, p_pmConceptParse_CELL_TRIMSEC,p_pmConceptFormat_CELL_TRIMSEC, NULL, true, PM_FPA_LEVEL_CELL);
             psFree(cellTrimsec);
         }
@@ -645,5 +396,5 @@
                                           "Bias sections", biassecs);
             psFree(biassecs);
-            pmConceptRegister(cellBiassec, p_pmConceptParse_CELL_BIASSEC, p_pmConceptFormat_CELL_BIASSEC, true, PM_FPA_LEVEL_CELL);
+            pmConceptRegister(cellBiassec, p_pmConceptParse_CELL_BIASSEC, p_pmConceptFormat_CELL_BIASSEC, NULL, true, PM_FPA_LEVEL_CELL);
             psFree(cellBiassec);
         }
@@ -666,169 +417,4 @@
 
     conceptsInitialised = false;
-}
-
-
-// List of concepts not to copy, for each level.
-// Must be NULL-terminated
-static const char *dontCopyConceptsFPA[] = { "FPA.OBS", "FPA.NAME", "FPA.CAMERA", 0 };
-static const char *dontCopyConceptsChip[] = { "CHIP.NAME", 0 };
-static const char *dontCopyConceptsCell[] = { "CELL.NAME", "CELL.TRIMSEC", "CELL.BIASSEC", 0 };
-
-// Copy concepts from a source container to a target container, avoiding certain entries
-static void copyConcepts(psMetadata *target, // Target metadata container
-                         psMetadata *source, // Source metadata container
-                         const char *dontCopyConcepts[] // Don't copy these concepts
-                         )
-{
-    assert(target);
-    assert(source);
-    assert(dontCopyConcepts);
-
-    psMetadataIterator *iter = psMetadataIteratorAlloc(source, PS_LIST_HEAD, NULL);
-    psMetadataItem *item;               // Item from iteration
-    while ((item = psMetadataGetAndIncrement(iter))) {
-        const char *name = item->name;  // Name of concept
-        bool copyOK = true;            // OK to copy
-        for (int i = 0; dontCopyConcepts[i] && copyOK; i++) {
-            if (!strcmp(name, dontCopyConcepts[i])) {
-                copyOK = false;
-            }
-        }
-        if (!copyOK) {
-            continue;
-        }
-        psMetadataItem *new = psMetadataItemCopy(item); // New item, a copy of the old
-        psMetadataAddItem(target, new, PS_LIST_TAIL, PS_META_REPLACE);
-        psFree(new);                    // Drop reference
-    }
-    psFree(iter);
-
-    return;
-}
-
-
-bool pmFPACopyConcepts(pmFPA *target, const pmFPA *source)
-{
-    PS_ASSERT_PTR_NON_NULL(target, false);
-    PS_ASSERT_PTR_NON_NULL(source, false);
-
-    // Copy FPA concepts
-    copyConcepts(target->concepts, source->concepts, dontCopyConceptsFPA);
-
-    // Copy chip concepts
-    psArray *targetChips = target->chips; // Chips in target
-    psArray *sourceChips = source->chips; // Chips in source
-    if (targetChips->n != sourceChips->n) {
-        psError(PS_ERR_IO, true, "Number of chips in target (%ld) and source (%ld) differ --- unable to copy "
-                "concepts.\n", targetChips->n, sourceChips->n);
-        return false;
-    }
-    for (int i = 0; i < targetChips->n; i++) {
-        pmChip *targetChip = targetChips->data[i]; // Target chip of interest
-        pmChip *sourceChip = sourceChips->data[i]; // Source chip of interest
-        if (! targetChip || ! sourceChip) {
-            continue;
-        }
-
-        copyConcepts(targetChip->concepts, sourceChip->concepts, dontCopyConceptsChip);
-
-        // Copy cell concepts
-        psArray *targetCells = targetChip->cells; // Cells in target
-        psArray *sourceCells = sourceChip->cells; // Cells in source
-        if (targetCells->n != sourceCells->n) {
-            psError(PS_ERR_IO, true, "Number of cells in target (%ld) and source (%ld) differ for chip %d ---"
-                    " unable to copy concepts.\n", targetCells->n, sourceCells->n, i);
-            return false;
-        }
-        for (int j = 0; j < targetCells->n; j++) {
-            pmCell *targetCell = targetCells->data[j]; // Target chip of interest
-            pmCell *sourceCell = sourceCells->data[j]; // Source chip of interest
-            if (! targetCell || ! sourceCell) {
-                continue;
-            }
-
-            copyConcepts(targetCell->concepts, sourceCell->concepts, dontCopyConceptsCell);
-        }
-    }
-
-    return true;
-}
-
-
-bool pmConceptsCopyFPA(pmFPA *target, const pmFPA *source, bool chips, bool cells)
-{
-    PS_ASSERT_PTR_NON_NULL(target, false);
-    PS_ASSERT_PTR_NON_NULL(source, false);
-
-    // Copy FPA concepts
-    copyConcepts(target->concepts, source->concepts, dontCopyConceptsFPA);
-
-    // Copy chip concepts
-    bool status = true;                 // Status of chips
-    if (chips) {
-        psArray *targetChips = target->chips; // Chips in target
-        psArray *sourceChips = source->chips; // Chips in source
-        if (targetChips->n != sourceChips->n) {
-            psError(PS_ERR_IO, true,
-                    "Number of chips in target (%ld) and source (%ld) differ --- unable to copy concepts.",
-                    targetChips->n, sourceChips->n);
-            return false;
-        }
-        for (int i = 0; i < targetChips->n; i++) {
-            pmChip *targetChip = targetChips->data[i]; // Target chip of interest
-            pmChip *sourceChip = sourceChips->data[i]; // Source chip of interest
-            if (! targetChip || ! sourceChip) {
-                continue;
-            }
-
-            status &= pmConceptsCopyChip(targetChip, sourceChip, cells);
-        }
-    }
-
-    return status;
-}
-
-bool pmConceptsCopyChip(pmChip *target, const pmChip *source, bool cells)
-{
-    PS_ASSERT_PTR_NON_NULL(target, false);
-    PS_ASSERT_PTR_NON_NULL(source, false);
-
-    // Copy chip concepts
-    copyConcepts(target->concepts, source->concepts, dontCopyConceptsChip);
-
-    // Copy cell concepts
-    bool status = true;                 // Status of cells
-    if (cells) {
-        psArray *targetCells = target->cells; // Cells in target
-        psArray *sourceCells = source->cells; // Cells in source
-        if (targetCells->n != sourceCells->n) {
-            psError(PS_ERR_IO, true,
-                    "Number of cells in target (%ld) and source (%ld) differ --- unable to copy concepts.",
-                    targetCells->n, sourceCells->n);
-            return false;
-        }
-        for (int j = 0; j < targetCells->n; j++) {
-            pmCell *targetCell = targetCells->data[j]; // Target chip of interest
-            pmCell *sourceCell = sourceCells->data[j]; // Source chip of interest
-            if (! targetCell || ! sourceCell) {
-                continue;
-            }
-
-            status &= pmConceptsCopyCell(targetCell, sourceCell);
-        }
-    }
-
-    return status;
-}
-
-
-bool pmConceptsCopyCell(pmCell *target, const pmCell *source)
-{
-    PS_ASSERT_PTR_NON_NULL(target, false);
-    PS_ASSERT_PTR_NON_NULL(source, false);
-
-    copyConcepts(target->concepts, source->concepts, dontCopyConceptsCell);
-
-    return true;
 }
 
