Index: /branches/eam_rel9_p0/psModules/src/astrom/pmFPAConceptsGet.c
===================================================================
--- /branches/eam_rel9_p0/psModules/src/astrom/pmFPAConceptsGet.c	(revision 5938)
+++ /branches/eam_rel9_p0/psModules/src/astrom/pmFPAConceptsGet.c	(revision 5939)
@@ -1,4 +1,5 @@
 #include <stdio.h>
 #include <strings.h>
+#include <assert.h>
 #include "pslib.h"
 
@@ -1059,2 +1060,138 @@
     return item;                        // item is either NULL or is what we want.
 }
+
+
+// Set up concepts for blank image
+bool pmFPABlankConcepts(pmFPA *fpa      // The FPA
+                       )
+{
+    assert(fpa);
+
+    // FPA-level concepts
+    if (! fpa->concepts) {
+        fpa->concepts = psMetadataAlloc();
+    }
+    psMetadataAddStr(fpa->concepts, PS_LIST_TAIL, "FPA.NAME", PS_META_REPLACE, "Name of FPA", "");
+    psMetadataAddF32(fpa->concepts, PS_LIST_TAIL, "FPA.AIRMASS", PS_META_REPLACE,
+                     "Airmass at boresight", NAN);
+    psMetadataAddStr(fpa->concepts, PS_LIST_TAIL, "FPA.FILTER", PS_META_REPLACE, "Filter used", "");
+    psMetadataAddF32(fpa->concepts, PS_LIST_TAIL, "FPA.POSANGLE", PS_META_REPLACE,
+                     "Position angle for instrument", NAN);
+    psMetadataAddStr(fpa->concepts, PS_LIST_TAIL, "FPA.RADECSYS", PS_META_REPLACE,
+                     "Celestial coordinate system", "");
+    psMetadataAddF64(fpa->concepts, PS_LIST_TAIL, "FPA.RA", PS_META_REPLACE,
+                     "Right Ascension of the boresight (radians)", NAN);
+    psMetadataAddF64(fpa->concepts, PS_LIST_TAIL, "FPA.DEC", PS_META_REPLACE,
+                     "Declination of the boresight (radians)", NAN);
+
+    // Iterate through the chips
+    psArray *chips = fpa->chips;        // Array of chips
+    for (int i = 0; i < chips->n; i++) {
+        pmChip *chip = chips->data[i];  // The chip of interest
+        if (! chip) {
+            continue;
+        }
+
+        // Chip-level concepts
+        if (! chip->concepts) {
+            chip->concepts = psMetadataAlloc();
+        }
+        // CHIP.NAME *should* have been added by pmFPAConstruct --- make sure
+        psMetadataItem *chipNameItem = psMetadataLookup(chip->concepts, "CHIP.NAME");
+        if (! chipNameItem) {
+            psMetadataAddStr(fpa->concepts, PS_LIST_TAIL, "CHIP.NAME", PS_META_REPLACE, "Name of Chip", "");
+        }
+
+        // Iterate through the cells
+        psArray *cells = chip->cells;   // Array of cells
+        for (int j = 0; j < cells->n; j++) {
+            pmCell *cell = cells->data[i]; // The cell of interest
+            if (! cell) {
+                continue;
+            }
+
+            // Cell-level concepts
+            if (! cell->concepts) {
+                cell->concepts = psMetadataAlloc();
+            }
+            // CELL.NAME *should* have been added by pmFPAConstruct --- make sure
+            psMetadataItem *cellNameItem = psMetadataLookup(cell->concepts, "CELL.NAME");
+            if (!cellNameItem) {
+                psMetadataAddStr(fpa->concepts, PS_LIST_TAIL, "CELL.NAME", PS_META_REPLACE,
+                                 "Name of Cell", "");
+            }
+            psMetadataAddF32(cell->concepts, PS_LIST_TAIL, "CELL.GAIN", PS_META_REPLACE, "CCD gain (e/count)", NAN);
+            psMetadataAddF32(cell->concepts, PS_LIST_TAIL, "CELL.READNOISE", PS_META_REPLACE, "CCD read noise (e)", NAN);
+            psMetadataAddF32(cell->concepts, PS_LIST_TAIL, "CELL.SATURATION", PS_META_REPLACE, "Saturation level (ADU)", NAN);
+            psMetadataAddF32(cell->concepts, PS_LIST_TAIL, "CELL.BAD", PS_META_REPLACE, "Bad level (ADU)", NAN);
+            psMetadataAddF32(cell->concepts, PS_LIST_TAIL, "CELL.XPARITY", PS_META_REPLACE, "Orientation in x compared to the rest of the FPA", NAN);
+            psMetadataAddF32(cell->concepts, PS_LIST_TAIL, "CELL.YPARITY", PS_META_REPLACE, "Orientation in x compared to the rest of the FPA", NAN);
+            psMetadataAddF32(cell->concepts, PS_LIST_TAIL, "CELL.READDIR", PS_META_REPLACE, "Read direction: 1=row, 2=col", NAN);
+            psMetadataAddF32(cell->concepts, PS_LIST_TAIL, "CELL.EXPOSURE", PS_META_REPLACE, "Exposure time (sec)", NAN);
+            psMetadataAddF32(cell->concepts, PS_LIST_TAIL, "CELL.DARKTIME", PS_META_REPLACE, "Time since CCD flush (sec)", NAN);
+            psMetadataAddS32(cell->concepts, PS_LIST_TAIL, "CELL.XBIN", PS_META_REPLACE, "Binning in x", 0);
+            psMetadataAddS32(cell->concepts, PS_LIST_TAIL, "CELL.YBIN", PS_META_REPLACE, "Binning in y", 0);
+            psMetadataAddS32(cell->concepts, PS_LIST_TAIL, "CELL.X0", PS_META_REPLACE, "Position of (0,0) on the chip", 0);
+            psMetadataAddS32(cell->concepts, PS_LIST_TAIL, "CELL.Y0", PS_META_REPLACE, "Position of (0,0) on the chip", 0);
+
+            psRegion *trimsec = psAlloc(sizeof(psRegion)); // Dummy region
+            trimsec->x0 = NAN;
+            trimsec->x1 = NAN;
+            trimsec->y0 = NAN;
+            trimsec->y1 = NAN;
+            psMetadataAddPtr(cell->concepts, PS_LIST_TAIL, "CELL.TRIMSEC", PS_META_REPLACE, "Trim section", trimsec);
+            psList *biassecs = psListAlloc(NULL); // Dummy list
+            psMetadataAddPtr(cell->concepts, PS_LIST_TAIL, "CELL.BIASSEC", PS_META_REPLACE, "Bias section", biassecs);
+            psTime *time = psTimeAlloc(PS_TIME_TAI); // Dummy time
+            psMetadataAddPtr(cell->concepts, PS_LIST_TAIL, "CELL.TIME", PS_META_REPLACE, "Time of exposure", time);
+            psMetadataAddS32(cell->concepts, PS_LIST_TAIL, "CELL.TIMESYS", PS_META_REPLACE, "Time system", PS_TIME_TAI);
+        }
+    }
+
+    return true;
+}
+
+// Copy concepts from one FPA to another
+bool pmFPACopyConcepts(pmFPA *target,   // The target FPA
+                       pmFPA *source    // The target FPA
+                      )
+{
+    // Copy FPA concepts
+    target->concepts = pap_psMetadataCopy(target->concepts, source->concepts);
+
+    // 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 (%d) and source (%d) 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;
+        }
+        targetChip->concepts = pap_psMetadataCopy(targetChip->concepts, sourceChip->concepts);
+
+        // 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 (%d) and source (%d) 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;
+            }
+            targetCell->concepts = pap_psMetadataCopy(targetCell->concepts, sourceCell->concepts);
+        }
+    }
+
+    return true;
+}
Index: /branches/eam_rel9_p0/psModules/src/astrom/pmFPAConceptsGet.h
===================================================================
--- /branches/eam_rel9_p0/psModules/src/astrom/pmFPAConceptsGet.h	(revision 5938)
+++ /branches/eam_rel9_p0/psModules/src/astrom/pmFPAConceptsGet.h	(revision 5939)
@@ -86,4 +86,13 @@
                          );
 
+// Set up concepts for blank image
+bool pmFPABlankConcepts(pmFPA *fpa      // The FPA
+                       );
+
+// Copy concepts from one FPA to another
+bool pmFPACopyConcepts(pmFPA *target,   // The target FPA
+                       pmFPA *source    // The target FPA
+                      );
+
 // Retrieve a concept
 psMetadataItem *pmCellGetConcept(pmCell *cell, // The cell
Index: /branches/eam_rel9_p0/psModules/src/astrom/pmFPAConstruct.c
===================================================================
--- /branches/eam_rel9_p0/psModules/src/astrom/pmFPAConstruct.c	(revision 5938)
+++ /branches/eam_rel9_p0/psModules/src/astrom/pmFPAConstruct.c	(revision 5939)
@@ -6,4 +6,5 @@
 #include "pmFPAConstruct.h"
 #include "psAdditionals.h"
+#include "pmFPAConceptsGet.h"
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -265,4 +266,7 @@
     }
 
+    // Initialise with dummy concepts, until the real ones can be read.
+    pmFPABlankConcepts(fpa);
+
     return fpa;
 }
