Index: /trunk/psModules/src/objects/pmSourceIO.c
===================================================================
--- /trunk/psModules/src/objects/pmSourceIO.c	(revision 13772)
+++ /trunk/psModules/src/objects/pmSourceIO.c	(revision 13773)
@@ -3,6 +3,6 @@
  *  @author EAM, IfA
  *
- *  @version $Revision: 1.42 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2007-06-06 02:23:33 $
+ *  @version $Revision: 1.43 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2007-06-13 03:27:11 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -40,4 +40,8 @@
 #include "pmSourceIO.h"
 
+
+#define BLANK_HEADERS "BLANK.HEADERS"   // Name of metadata in camera configuration containing header names
+                                        // for putting values into a blank PHU
+
 // translations between psphot object types and dophot object types
 int pmSourceGetDophotType (pmSource *source)
@@ -164,10 +168,15 @@
     *thisView = *view;
 
+    if (!pmConceptsWriteFPA(fpa, PM_CONCEPT_SOURCE_HEADER, true, NULL)) {
+        psError(PS_ERR_IO, false, "Unable to write concepts for fpa");
+        psFree(thisView);
+        return false;
+    }
     for (int i = 0; i < fpa->chips->n; i++) {
         pmChip *chip = fpa->chips->data[i];
-	thisView->chip = i;
+        thisView->chip = i;
         if (!pmChipWriteObjects (chip, thisView, file, config)) {
             psError(PS_ERR_IO, false, "Failed to write %dth chip", i);
-	    psFree (thisView);
+            psFree (thisView);
             return false;
         }
@@ -183,11 +192,15 @@
     *thisView = *view;
 
+    if (!pmConceptsWriteChip(chip, PM_CONCEPT_SOURCE_HEADER, true, true, NULL)) {
+        psError(PS_ERR_IO, false, "Unable to write concepts for chip");
+        psFree(thisView);
+        return false;
+    }
     for (int i = 0; i < chip->cells->n; i++) {
-
         pmCell *cell = chip->cells->data[i];
-	thisView->cell = i;
+        thisView->cell = i;
         if (!pmCellWriteObjects (cell, thisView, file, config)) {
             psError(PS_ERR_IO, false, "Failed to write %dth cell", i);
-	    psFree (thisView);
+            psFree (thisView);
             return false;
         }
@@ -203,11 +216,15 @@
     *thisView = *view;
 
+    if (!pmConceptsWriteCell(cell, PM_CONCEPT_SOURCE_HEADER, true, NULL)) {
+        psError(PS_ERR_IO, false, "Unable to write concepts for cell");
+        psFree(thisView);
+        return false;
+    }
     for (int i = 0; i < cell->readouts->n; i++) {
-
         pmReadout *readout = cell->readouts->data[i];
-	thisView->readout = i;
+        thisView->readout = i;
         if (!pmReadoutWriteObjects (readout, thisView, file, config)) {
             psError(PS_ERR_IO, false, "Failed to write %dth readout", i);
-	    psFree (thisView);
+            psFree (thisView);
             return false;
         }
@@ -309,4 +326,62 @@
                     psMetadataAddStr(outhead, PS_LIST_TAIL, fpaNameHdr, PS_META_REPLACE, "FPA name", fpaName);
                 }
+
+                // We need to get some FPA-level concepts in there
+                // This is a hack, not very pretty.  But then, so is writing the FPA in this manner without
+                // using the pmFPAMosaic functions....
+
+                psMetadata *headers = psMetadataLookupMetadata(NULL, file->fpa->camera,
+                                                               BLANK_HEADERS); // Header names
+                if (!headers) {
+                    psError(PS_ERR_UNEXPECTED_NULL, false,
+                            "Unable to find %s metadata within camera configuration", BLANK_HEADERS);
+                    psFree(outhead);
+                    return false;
+                }
+
+                {
+                    const char *mjdName = psMetadataLookupStr(NULL, headers, "FPA.TIME"); // Header name
+                    if (!mjdName || strlen(mjdName) == 0) {
+                        psError(PS_ERR_UNEXPECTED_NULL, false,
+                                "Unable to find FPA.TIME in %s within camera configuration.", BLANK_HEADERS);
+                        psFree(outhead);
+                        return false;
+                    }
+                    psTime *time = psMetadataLookupTime(NULL, file->fpa->concepts,
+                                                        "FPA.TIME"); // Time of observation
+                    double mjd = psTimeToMJD(time); // The MJD of observation
+                    psMetadataAddF64(outhead, PS_LIST_TAIL, mjdName, PS_META_REPLACE,
+                                     "Time of observation", mjd);
+                }
+
+                {
+                    const char *expName = psMetadataLookupStr(NULL, headers, "FPA.EXPOSURE"); // Header name
+                    if (!expName || strlen(expName) == 0) {
+                        psError(PS_ERR_UNEXPECTED_NULL, false,
+                                "Unable to find FPA.EXPOSURE in %s within camera configuration.",
+                                BLANK_HEADERS);
+                        psFree(outhead);
+                        return false;
+                    }
+                    float exptime = psMetadataLookupF32(NULL, file->fpa->concepts,
+                                                        "FPA.EXPOSURE"); // Exposure time
+                    psMetadataAddF32(outhead, PS_LIST_TAIL, expName, PS_META_REPLACE,
+                                     "Exposure time (sec)", exptime);
+                }
+
+                {
+                    const char *amName = psMetadataLookupStr(NULL, headers, "FPA.AIRMASS"); // Header name
+                    if (!amName || strlen(amName) == 0) {
+                        psError(PS_ERR_UNEXPECTED_NULL, false,
+                                "Unable to find FPA.AIRMASS in %s within camera configuration.",
+                                BLANK_HEADERS);
+                        psFree(outhead);
+                        return false;
+                    }
+                    float airmass = psMetadataLookupF32(NULL, file->fpa->concepts, "FPA.AIRMASS"); // Airmass
+                    psMetadataAddF32(outhead, PS_LIST_TAIL, amName, PS_META_REPLACE,
+                                     "Observation airmass", airmass);
+                }
+
             }
 
@@ -324,99 +399,99 @@
         }
 
-	// define the EXTNAME values for the different data segments:
-	{
-	    // lookup the EXTNAME values used for table data and image header segments
-	    char *rule = NULL;
-
-	    // Menu of EXTNAME rules
-	    psMetadata *menu = psMetadataLookupMetadata(&status, file->camera, "EXTNAME.RULES");
-	    if (!menu) {
-		psError(PS_ERR_UNKNOWN, true, "missing EXTNAME.RULES in camera.config");
-		return false;
-	    }
-
-	    // EXTNAME for image header
-	    rule = psMetadataLookupStr(&status, menu, "CMF.HEAD");
-	    if (!rule) {
-		psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.HEAD in EXTNAME.RULES in camera.config");
-		return false;
-	    }
-	    headname = pmFPAfileNameFromRule (rule, file, view);
-
-	    // EXTNAME for table data
-	    rule = psMetadataLookupStr(&status, menu, "CMF.DATA");
-	    if (!rule) {
-		psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.DATA in EXTNAME.RULES in camera.config");
-		return false;
-	    }
-	    dataname = pmFPAfileNameFromRule (rule, file, view);
-	}
-
-	// write out the IMAGE header segment
-	{
-	    // this header block is new, write it to disk
-	    if (hdu->header != file->header) {
-		// add EXTNAME, EXTHEAD, EXTTYPE to header
-		psMetadataAddStr (hdu->header, PS_LIST_TAIL, "EXTDATA", PS_META_REPLACE, "name of table extension", dataname);
-		psMetadataAddStr (hdu->header, PS_LIST_TAIL, "EXTTYPE", PS_META_REPLACE, "extension type", "IMAGE");
-		if (!file->phu) {
-		    // this hdu->header acts as the PHU: set EXTEND to be true
-		    psMetadataAddBool (hdu->header, PS_LIST_TAIL, "EXTEND", PS_META_REPLACE, "this file has extensions", true);
-		}
-
-		// save psphot and psastro metadata in the image and table headers
-		updates = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.HEADER");
-		if (updates) {
-		    psMetadataCopy (hdu->header, updates);
-		}
-		updates = psMetadataLookupPtr (&status, readout->analysis, "PSASTRO.HEADER");
-		if (updates) {
-		    psMetadataCopy (hdu->header, updates);
-		}
-
-		psFitsWriteBlank (file->fits, hdu->header, headname);
-		psTrace ("pmFPAfile", 5, "wrote ext head %s (type: %d)\n", file->filename, file->type);
-		file->header = hdu->header;
-	    }
-	}
-
-	// write out the TABLE data segment
-	{
-	    // create a header to hold the output data
-	    outhead = psMetadataAlloc ();
-
-	    // determine the output table format
-	    psMetadata *recipe = psMetadataLookupMetadata(&status, config->recipes, "PSPHOT");
-	    if (!status) {
-		psError(PS_ERR_UNKNOWN, true, "missing recipe PSPHOT in config data");
-		return false;
-	    }
-	    exttype = psMemIncrRefCounter (psMetadataLookupStr(&status, recipe, "OUTPUT.FORMAT"));
-	    if (!exttype) {
-		exttype = psStringCopy ("SMPDATA");
-	    }
-
-	    // write the links to the image header
-	    psMetadataAddStr (outhead, PS_LIST_TAIL, "EXTHEAD", PS_META_REPLACE, "name of image extension w/", headname);
-	    psMetadataAddStr (outhead, PS_LIST_TAIL, "EXTTYPE", PS_META_REPLACE, "extension type", exttype);
-	    psFree (exttype);
-
-	    // XXX these are case-sensitive since the EXTYPE is case-sensitive
-	    status = false;
-	    if (!strcmp (exttype, "SMPDATA")) {
-		status = pmSourcesWrite_SMPDATA (file->fits, sources, file->header, outhead, dataname);
-	    }
-	    if (!strcmp (exttype, "PS1_DEV_0")) {
-		status = pmSourcesWrite_PS1_DEV_0 (file->fits, sources, file->header, outhead, dataname);
-	    }
-
-	    if (!status) {
-		psError(PS_ERR_IO, false, "writing CMF data to %s with format %s\n", file->filename, exttype);
-		psFree (headname);
-		psFree (dataname);
-		psFree (outhead);
-		return false;
-	    }
-	}
+        // define the EXTNAME values for the different data segments:
+        {
+            // lookup the EXTNAME values used for table data and image header segments
+            char *rule = NULL;
+
+            // Menu of EXTNAME rules
+            psMetadata *menu = psMetadataLookupMetadata(&status, file->camera, "EXTNAME.RULES");
+            if (!menu) {
+                psError(PS_ERR_UNKNOWN, true, "missing EXTNAME.RULES in camera.config");
+                return false;
+            }
+
+            // EXTNAME for image header
+            rule = psMetadataLookupStr(&status, menu, "CMF.HEAD");
+            if (!rule) {
+                psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.HEAD in EXTNAME.RULES in camera.config");
+                return false;
+            }
+            headname = pmFPAfileNameFromRule (rule, file, view);
+
+            // EXTNAME for table data
+            rule = psMetadataLookupStr(&status, menu, "CMF.DATA");
+            if (!rule) {
+                psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.DATA in EXTNAME.RULES in camera.config");
+                return false;
+            }
+            dataname = pmFPAfileNameFromRule (rule, file, view);
+        }
+
+        // write out the IMAGE header segment
+        {
+            // this header block is new, write it to disk
+            if (hdu->header != file->header) {
+                // add EXTNAME, EXTHEAD, EXTTYPE to header
+                psMetadataAddStr (hdu->header, PS_LIST_TAIL, "EXTDATA", PS_META_REPLACE, "name of table extension", dataname);
+                psMetadataAddStr (hdu->header, PS_LIST_TAIL, "EXTTYPE", PS_META_REPLACE, "extension type", "IMAGE");
+                if (!file->phu) {
+                    // this hdu->header acts as the PHU: set EXTEND to be true
+                    psMetadataAddBool (hdu->header, PS_LIST_TAIL, "EXTEND", PS_META_REPLACE, "this file has extensions", true);
+                }
+
+                // save psphot and psastro metadata in the image and table headers
+                updates = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.HEADER");
+                if (updates) {
+                    psMetadataCopy (hdu->header, updates);
+                }
+                updates = psMetadataLookupPtr (&status, readout->analysis, "PSASTRO.HEADER");
+                if (updates) {
+                    psMetadataCopy (hdu->header, updates);
+                }
+
+                psFitsWriteBlank (file->fits, hdu->header, headname);
+                psTrace ("pmFPAfile", 5, "wrote ext head %s (type: %d)\n", file->filename, file->type);
+                file->header = hdu->header;
+            }
+        }
+
+        // write out the TABLE data segment
+        {
+            // create a header to hold the output data
+            outhead = psMetadataAlloc ();
+
+            // determine the output table format
+            psMetadata *recipe = psMetadataLookupMetadata(&status, config->recipes, "PSPHOT");
+            if (!status) {
+                psError(PS_ERR_UNKNOWN, true, "missing recipe PSPHOT in config data");
+                return false;
+            }
+            exttype = psMemIncrRefCounter (psMetadataLookupStr(&status, recipe, "OUTPUT.FORMAT"));
+            if (!exttype) {
+                exttype = psStringCopy ("SMPDATA");
+            }
+
+            // write the links to the image header
+            psMetadataAddStr (outhead, PS_LIST_TAIL, "EXTHEAD", PS_META_REPLACE, "name of image extension w/", headname);
+            psMetadataAddStr (outhead, PS_LIST_TAIL, "EXTTYPE", PS_META_REPLACE, "extension type", exttype);
+            psFree (exttype);
+
+            // XXX these are case-sensitive since the EXTYPE is case-sensitive
+            status = false;
+            if (!strcmp (exttype, "SMPDATA")) {
+                status = pmSourcesWrite_SMPDATA (file->fits, sources, file->header, outhead, dataname);
+            }
+            if (!strcmp (exttype, "PS1_DEV_0")) {
+                status = pmSourcesWrite_PS1_DEV_0 (file->fits, sources, file->header, outhead, dataname);
+            }
+
+            if (!status) {
+                psError(PS_ERR_IO, false, "writing CMF data to %s with format %s\n", file->filename, exttype);
+                psFree (headname);
+                psFree (dataname);
+                psFree (outhead);
+                return false;
+            }
+        }
 
         psTrace ("pmFPAfile", 5, "wrote ext data %s (type: %d)\n", file->filename, file->type);
@@ -483,8 +558,14 @@
     for (int i = 0; i < fpa->chips->n; i++) {
         pmChip *chip = fpa->chips->data[i];
-	thisView->chip = i;
+        thisView->chip = i;
         pmChipReadObjects (chip, thisView, file, config);
     }
     psFree (thisView);
+
+    if (!pmConceptsReadFPA(fpa, PM_CONCEPT_SOURCE_HEADER, true, NULL)) {
+        psError(PS_ERR_IO, false, "Failed to read concepts for fpa.\n");
+        return false;
+    }
+
     return true;
 }
@@ -499,5 +580,5 @@
     for (int i = 0; i < chip->cells->n; i++) {
         pmCell *cell = chip->cells->data[i];
-	thisView->cell = i;
+        thisView->cell = i;
         pmCellReadObjects (cell, thisView, file, config);
         if (!cell->data_exists) continue;
@@ -505,4 +586,10 @@
     }
     psFree (thisView);
+
+    if (!pmConceptsReadChip(chip, PM_CONCEPT_SOURCE_HEADER, true, true, NULL)) {
+        psError(PS_ERR_IO, false, "Failed to read concepts for chip.\n");
+        return false;
+    }
+
     return true;
 }
@@ -524,5 +611,5 @@
     for (int i = 0; i < cell->readouts->n; i++) {
         pmReadout *readout = cell->readouts->data[i];
-	thisView->readout = i;
+        thisView->readout = i;
         pmReadoutReadObjects (readout, thisView, file, config);
         if (!readout->data_exists) {
@@ -539,4 +626,11 @@
     }
     psFree (thisView);
+
+    if (!pmConceptsReadCell(cell, PM_CONCEPT_SOURCE_HEADER, true, NULL)) {
+        //psError(PS_ERR_UNKNOWN, false, "Failed to read concepts for cell");
+        //return false;
+        psWarning("Difficulty reading concepts for cell; attempting to proceed.");
+    }
+
     return true;
 }
