Index: trunk/psModules/src/camera/pmFPAWrite.c
===================================================================
--- trunk/psModules/src/camera/pmFPAWrite.c	(revision 9983)
+++ trunk/psModules/src/camera/pmFPAWrite.c	(revision 10081)
@@ -14,4 +14,229 @@
 
 #include "pmFPAWrite.h"
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Definitions
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Specify what to read
+typedef enum {
+    FPA_WRITE_TYPE_IMAGE,               // Write image
+    FPA_WRITE_TYPE_MASK,                // Write mask
+    FPA_WRITE_TYPE_WEIGHT               // Write weight map
+} fpaWriteType;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// File-static (private) functions
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Return the appropriate image array for the given type
+static psArray **appropriateImageArray(pmHDU *hdu, // HDU containing the image arrays
+                                       fpaWriteType type // Type to write
+                                      )
+{
+    switch (type) {
+    case FPA_WRITE_TYPE_IMAGE:
+        return &hdu->images;
+    case FPA_WRITE_TYPE_MASK:
+        return &hdu->masks;
+    case FPA_WRITE_TYPE_WEIGHT:
+        return &hdu->weights;
+    default:
+        psAbort(__func__, "Unknown write type: %x\n", type);
+    }
+    return NULL;
+}
+
+// Run the appropriate HDU write function
+static bool appropriateWriteFunc(pmHDU *hdu, // HDU to write
+                                 psFits *fits, // FITS file to which to write
+                                 fpaWriteType type // Type to write
+                                )
+{
+    switch (type) {
+    case FPA_WRITE_TYPE_IMAGE:
+        return pmHDUWrite(hdu, fits);
+    case FPA_WRITE_TYPE_MASK:
+        return pmHDUWriteMask(hdu, fits);
+    case FPA_WRITE_TYPE_WEIGHT:
+        return pmHDUWriteWeight(hdu, fits);
+    default:
+        psAbort(__func__, "Unknown write type: %x\n", type);
+    }
+    return false;
+}
+
+// Write a cell image/mask/weight
+static bool cellWrite(pmCell *cell,     // Cell to write
+                      psFits *fits,     // FITS file to which to write
+                      psDB *db,         // Database handle for "concepts" update
+                      bool blank,       // Write a blank PHU?
+                      fpaWriteType type // Type to write
+                     )
+{
+    assert(cell);
+    assert(fits);
+
+    psTrace ("pmFPAWrite", 5, "writing to Cell (%d)\n", blank);
+
+    pmHDU *hdu = cell->hdu;             // The HDU
+    if (!hdu) {
+        return true;                    // We wrote every HDU that exists
+    }
+
+    psArray **imageArray = appropriateImageArray(hdu, type); // Array of images in the HDU
+
+    // Generate the HDU if needed --- this is required after a pmFPACopy, or similar, which does not
+    // generate the HDU, but only copies the structure.
+    if (!hdu->blankPHU && !*imageArray && (!pmHDUGenerateForCell(cell) || !*imageArray)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to generate HDU for cell --- likely programming error.\n");
+        return false;
+    }
+
+    // We only write out a blank PHU if it's specifically requested.
+    bool writeBlank = blank && hdu->blankPHU && !*imageArray; // Write a blank PHU?
+    bool writeImage = !blank && !hdu->blankPHU && *imageArray; // Write an image?
+
+    if (writeBlank || writeImage) {
+        pmConceptSource source = PM_CONCEPT_SOURCE_HEADER | PM_CONCEPT_SOURCE_CELLS |
+                                 PM_CONCEPT_SOURCE_DEFAULTS;
+        if (!pmConceptsWriteCell(cell, source, false, NULL)) {
+            psError(PS_ERR_IO, false, "Unable to write concepts for cell.\n");
+            return false;
+        }
+        if (!appropriateWriteFunc(hdu, fits, type)) {
+            psError(PS_ERR_IO, false, "Unable to write HDU for cell.\n");
+            return false;
+        }
+    }
+    // No lower levels to which to recurse
+
+    return true;
+}
+
+// Write a chip image/mask/weight
+static bool chipWrite(pmChip *chip,     // Chip to write
+                      psFits *fits,     // FITS file to which to write
+                      psDB *db,         // Database handle for "concepts" update
+                      bool blank,       // Write a blank PHU?
+                      bool recurse,     // Recurse to lower levels?
+                      fpaWriteType type // Type to write
+                     )
+{
+    assert(chip);
+    assert(fits);
+
+    pmHDU *hdu = chip->hdu;             // The HDU
+
+    psTrace ("pmFPAWrite", 5, "writing to Chip (%d, %d)\n", blank, recurse);
+
+    // If we have data at this level, try to write it out
+    if (hdu) {
+        psArray **imageArray = appropriateImageArray(hdu, type); // Array of images in HDU
+
+        // Generate the HDU if needed --- this is required after a pmFPACopy, or similar, which does not
+        // generate the HDU, but only copies the structure.
+        if (!blank && !hdu->blankPHU && !*imageArray && (!pmHDUGenerateForChip(chip) || !*imageArray)) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to generate HDU for chip --- likely programming error.\n");
+            return false;
+        }
+
+        // We only write out a blank PHU if it's specifically requested.
+        bool writeBlank = blank && hdu->blankPHU && !*imageArray; // Write a blank HDU?
+        bool writeImage = !blank && !hdu->blankPHU && *imageArray; // Write an image?
+
+        if (writeBlank || writeImage) {
+            pmConceptSource source = PM_CONCEPT_SOURCE_HEADER | PM_CONCEPT_SOURCE_CELLS |
+                                     PM_CONCEPT_SOURCE_DEFAULTS;
+            if (!pmConceptsWriteChip(chip, source, false, true, NULL)) {
+                psError(PS_ERR_IO, false, "Unable to write concepts for chip.\n");
+                return false;
+            }
+            if (!appropriateWriteFunc(hdu, fits, type)) {
+                psError(PS_ERR_IO, false, "Unable to write HDU for chip.\n");
+                return false;
+            }
+        }
+    }
+
+    // Recurse to lower level if specifically requested.
+    // XXX recursion implies blank == false (must be called on correct level?)
+    if (recurse) {
+        psArray *cells = chip->cells;       // Array of cells
+        for (int i = 0; i < cells->n; i++) {
+            pmCell *cell = cells->data[i];  // The cell of interest
+            if (!cellWrite(cell, fits, db, false, type)) {
+                psError(PS_ERR_IO, false, "Unable to write Chip.\n");
+                return false;
+            }
+        }
+    }
+
+    return true;
+}
+
+// Write an FPA image/mask/weight
+static bool fpaWrite(pmFPA *fpa,        // FPA to write
+                     psFits *fits,      // FITS file to which to write
+                     psDB *db,          // Database handle for "concepts" update
+                     bool blank,        // Write a blank PHU?
+                     bool recurse,      // Recurse to lower levels?
+                     fpaWriteType type  // Type to write
+                    )
+{
+    assert(fpa);
+    assert(fits);
+
+    pmHDU *hdu = fpa->hdu;              // The HDU
+
+    psTrace ("pmFPAWrite", 5, "writing to FPA (%d, %d)\n", blank, recurse);
+
+    // If we have data at this level, try to write it out
+    if (hdu) {
+        psArray **imageArray = appropriateImageArray(hdu, type); // Array of images in HDU
+
+        // Generate the HDU if needed --- this is required after a pmFPACopy, or similar, which does not
+        // generate the HDU, but only copies the structure.
+        if (!blank && !hdu->blankPHU && !*imageArray && (!pmHDUGenerateForFPA(fpa) || !*imageArray)) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to generate HDU for FPA --- likely programming error.\n");
+            return false;
+        }
+
+        // We only write out a blank PHU if it's specifically requested.
+        bool writeBlank = blank && hdu->blankPHU && !*imageArray; // Write a blank PHU?
+        bool writeImage = !blank && !hdu->blankPHU && *imageArray; // Write an image?
+
+        if (writeBlank || writeImage) {
+            pmConceptSource source = PM_CONCEPT_SOURCE_HEADER | PM_CONCEPT_SOURCE_CELLS |
+                                     PM_CONCEPT_SOURCE_DEFAULTS;
+            if (!pmConceptsWriteFPA(fpa, source, true, NULL)) {
+                psError(PS_ERR_IO, false, "Unable to write concepts for FPA.\n");
+                return false;
+            }
+            if (!appropriateWriteFunc(hdu, fits, type))  {
+                psError(PS_ERR_IO, false, "Unable to write HDU for FPA.\n");
+                return false;
+            }
+        }
+    }
+
+    // Recurse to lower levels if requested
+    if (recurse) {
+        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 (!chipWrite(chip, fits, db, false, true, type)) {
+                psError(PS_ERR_IO, false, "Unable to write FPA.\n");
+                return false;
+            }
+        }
+    }
+
+    return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Public functions
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 bool pmReadoutWriteNext(pmReadout *readout, psFits *fits, int z)
@@ -82,51 +307,10 @@
 
 
-
-
-bool pmCellWrite(pmCell *cell,          // Cell to write
-                 psFits *fits,          // FITS file to which to write
-                 psDB *db,              // Database handle for "concepts" update
-                 bool blank             // Write a blank PHU?
-                )
+bool pmCellWrite(pmCell *cell, psFits *fits, psDB *db, bool blank)
 {
     PS_ASSERT_PTR_NON_NULL(cell, false);
     PS_ASSERT_PTR_NON_NULL(fits, false);
-
-    psTrace ("pmFPAWrite", 5, "writing to Cell (%d)\n", blank);
-
-    pmHDU *hdu = cell->hdu;             // The HDU
-    if (!hdu) {
-        return true;                    // We wrote every HDU that exists
-    }
-
-    // Generate the HDU if needed --- this is required after a pmFPACopy, or similar, which does not
-    // generate the HDU, but only copies the structure.
-    if (!hdu->blankPHU && !hdu->images) {
-        if (!pmHDUGenerateForCell(cell) || !hdu->images) {
-            psAbort(__func__, "Unable to generate HDU for cell --- likely programming error.\n");
-        }
-    }
-
-    // We only write out a blank PHU if it's specifically requested.
-    bool writeBlank = blank && hdu->blankPHU && !hdu->images; // Write a blank PHU?
-    bool writeImage = !blank && !hdu->blankPHU && hdu->images; // Write an image?
-
-    if (writeBlank || writeImage) {
-        pmConceptSource source = PM_CONCEPT_SOURCE_HEADER | PM_CONCEPT_SOURCE_CELLS |
-                                 PM_CONCEPT_SOURCE_DEFAULTS;
-        if (!pmConceptsWriteCell(cell, source, false, NULL)) {
-            psError(PS_ERR_IO, false, "Unable to write concepts for cell.\n");
-            return false;
-        }
-        if (!pmHDUWrite(hdu, fits)) {
-            psError(PS_ERR_IO, false, "Unable to write HDU for cell.\n");
-            return false;
-        }
-    }
-    // No lower levels to which to recurse
-
-    return true;
-}
-
+    return cellWrite(cell, fits, db, blank, FPA_WRITE_TYPE_IMAGE);
+}
 
 bool pmChipWrite(pmChip *chip, psFits *fits, psDB *db, bool blank, bool recurse)
@@ -134,54 +318,6 @@
     PS_ASSERT_PTR_NON_NULL(chip, false);
     PS_ASSERT_PTR_NON_NULL(fits, false);
-
-    pmHDU *hdu = chip->hdu;             // The HDU
-
-    psTrace ("pmFPAWrite", 5, "writing to Chip (%d, %d)\n", blank, recurse);
-
-    // If we have data at this level, try to write it out
-    if (hdu) {
-        // Generate the HDU if needed --- this is required after a pmFPACopy, or similar, which does not
-        // generate the HDU, but only copies the structure.
-        if (!blank && !hdu->blankPHU && !hdu->images) {
-            if (!pmHDUGenerateForChip(chip) || !hdu->images) {
-                psAbort (__func__, "Unable to generate HDU for chip --- likely programming error.\n");
-            }
-        }
-
-        // We only write out a blank PHU if it's specifically requested.
-        bool writeBlank = blank && hdu->blankPHU && !hdu->images; // Write a blank HDU?
-        bool writeImage = !blank && !hdu->blankPHU && hdu->images; // Write an image?
-
-        if (writeBlank || writeImage) {
-            pmConceptSource source = PM_CONCEPT_SOURCE_HEADER | PM_CONCEPT_SOURCE_CELLS |
-                                     PM_CONCEPT_SOURCE_DEFAULTS;
-            if (!pmConceptsWriteChip(chip, source, false, true, NULL)) {
-                psError(PS_ERR_IO, false, "Unable to write concepts for chip.\n");
-                return false;
-            }
-            if (!pmHDUWrite(hdu, fits)) {
-                psError(PS_ERR_IO, false, "Unable to write HDU for chip.\n");
-                return false;
-            }
-        }
-    }
-
-    // Recurse to lower level if specifically requested.
-    // XXX recursion implies blank == false (must be called on correct level?)
-    if (recurse) {
-        psArray *cells = chip->cells;       // Array of cells
-        for (int i = 0; i < cells->n; i++) {
-            pmCell *cell = cells->data[i];  // The cell of interest
-            if (!pmCellWrite(cell, fits, db, false)) {
-                psError(PS_ERR_IO, false, "Unable to write Chip.\n");
-                return false;
-            }
-        }
-    }
-
-    return true;
-}
-
-
+    return chipWrite(chip, fits, db, blank, recurse, FPA_WRITE_TYPE_IMAGE);
+}
 
 bool pmFPAWrite(pmFPA *fpa, psFits *fits, psDB *db, bool blank, bool recurse)
@@ -189,165 +325,50 @@
     PS_ASSERT_PTR_NON_NULL(fpa, false);
     PS_ASSERT_PTR_NON_NULL(fits, false);
-
-    pmHDU *hdu = fpa->hdu;              // The HDU
-
-    psTrace ("pmFPAWrite", 5, "writing to FPA (%d, %d)\n", blank, recurse);
-
-    // If we have data at this level, try to write it out
-    if (hdu) {
-        // Generate the HDU if needed --- this is required after a pmFPACopy, or similar, which does not
-        // generate the HDU, but only copies the structure.
-        if (!blank && !hdu->blankPHU && !hdu->images) {
-            if (!pmHDUGenerateForFPA(fpa)) {
-                psAbort("pmFPAWrite", "error generating HDU");
-            }
-            if (!hdu->images) {
-                psAbort("pmFPAWrite", "programming error: failure generating HDU");
-            }
-        }
-
-        // We only write out a blank PHU if it's specifically requested.
-        bool writeBlank = blank && hdu->blankPHU && !hdu->images; // Write a blank PHU?
-        bool writeImage = !blank && !hdu->blankPHU && hdu->images; // Write an image?
-
-        if (writeBlank || writeImage) {
-            pmConceptSource source = PM_CONCEPT_SOURCE_HEADER | PM_CONCEPT_SOURCE_CELLS |
-                                     PM_CONCEPT_SOURCE_DEFAULTS;
-            if (!pmConceptsWriteFPA(fpa, source, true, NULL)) {
-                psError(PS_ERR_IO, false, "Unable to write concepts for FPA.\n");
-                return false;
-            }
-            if (!pmHDUWrite(hdu, fits))  {
-                psError(PS_ERR_IO, false, "Unable to write HDU for FPA.\n");
-                return false;
-            }
-        }
-    }
-
-    // Recurse to lower levels if requested
-    if (recurse) {
-        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 (!pmChipWrite(chip, fits, db, false, true)) {
-                psError(PS_ERR_IO, false, "Unable to write FPA.\n");
-                return false;
-            }
-        }
-    }
-
-    return true;
-}
-
-
-
-bool pmCellWriteMask(pmCell *cell,          // Cell to write
-                     psFits *fits,          // FITS file to which to write
-                     psDB *db           // Database handle for "concepts" update
-                    )
+    return fpaWrite(fpa, fits, db, blank, recurse, FPA_WRITE_TYPE_IMAGE);
+}
+
+
+bool pmCellWriteMask(pmCell *cell, psFits *fits, psDB *db, bool blank)
 {
     PS_ASSERT_PTR_NON_NULL(cell, false);
     PS_ASSERT_PTR_NON_NULL(fits, false);
-
-    pmHDU *hdu = cell->hdu;             // The HDU
-    if (!hdu) {
-        return true;                    // We wrote every HDU that exists
-    }
-
-    psTrace ("pmFPAWrite", 5, "writing mask to Cell\n");
-
-    // Generate the HDU if needed --- this is required after a pmFPACopy, or similar, which does not
-    // generate the HDU, but only copies the structure.
-    if (!hdu->blankPHU && !hdu->masks) {
-        if (!pmHDUGenerateForCell(cell) || !hdu->masks) {
-            psError(PS_ERR_UNKNOWN, false, "Unable to generate HDU for cell --- likely programming error.\n");
-            return false;
-        }
-    }
-
-    pmConceptSource source = PM_CONCEPT_SOURCE_HEADER | PM_CONCEPT_SOURCE_CELLS | PM_CONCEPT_SOURCE_DEFAULTS;
-    if (!pmConceptsWriteCell(cell, source, false, NULL)) {
-        psError(PS_ERR_IO, false, "Unable to write concepts for cell.\n");
-        return false;
-    }
-    if (!pmHDUWriteMask(hdu, fits)) {
-        psError(PS_ERR_IO, false, "Unable to write HDU for cell.\n");
-        return false;
-    }
-
-    return true;
-}
-
-
-bool pmChipWriteMask(pmChip *chip, psFits *fits, psDB *db)
+    return cellWrite(cell, fits, db, blank, FPA_WRITE_TYPE_IMAGE);
+}
+
+bool pmChipWriteMask(pmChip *chip, psFits *fits, psDB *db, bool blank, bool recurse)
 {
     PS_ASSERT_PTR_NON_NULL(chip, false);
     PS_ASSERT_PTR_NON_NULL(fits, false);
-
-    pmHDU *hdu = chip->hdu;             // The HDU
-    if (!hdu) {
-        return true;                    // We wrote every HDU that exists
-    }
-
-    psTrace ("pmFPAWrite", 5, "writing mask to Chip\n");
-
-    // Generate the HDU if needed --- this is required after a pmFPACopy, or similar, which does not
-    // generate the HDU, but only copies the structure.
-    if (!hdu->blankPHU && !hdu->masks) {
-        if (!pmHDUGenerateForChip(chip) || !hdu->masks) {
-            psError(PS_ERR_UNKNOWN, false, "Unable to generate HDU for chip --- likely programming error.\n");
-            return false;
-        }
-    }
-
-    pmConceptSource source = PM_CONCEPT_SOURCE_HEADER | PM_CONCEPT_SOURCE_CELLS | PM_CONCEPT_SOURCE_DEFAULTS;
-    if (!pmConceptsWriteChip(chip, source, false, true, NULL)) {
-        psError(PS_ERR_IO, false, "Unable to write concepts for chip.\n");
-        return false;
-    }
-    if (!pmHDUWriteMask(hdu, fits)) {
-        psError(PS_ERR_IO, false, "Unable to write HDU for chip.\n");
-        return false;
-    }
-
-    return true;
-}
-
-
-
-bool pmFPAWriteMask(pmFPA *fpa, psFits *fits, psDB *db)
+    return chipWrite(chip, fits, db, blank, recurse, FPA_WRITE_TYPE_MASK);
+}
+
+bool pmFPAWriteMask(pmFPA *fpa, psFits *fits, psDB *db, bool blank, bool recurse)
 {
     PS_ASSERT_PTR_NON_NULL(fpa, false);
     PS_ASSERT_PTR_NON_NULL(fits, false);
-
-    pmHDU *hdu = fpa->hdu;              // The HDU
-    if (!hdu) {
-        return true;                    // We wrote every HDU that exists
-    }
-
-    psTrace ("pmFPAWrite", 5, "writing mask to FPA\n");
-
-    // Generate the HDU if needed --- this is required after a pmFPACopy, or similar, which does not
-    // generate the HDU, but only copies the structure.
-    if (!hdu->blankPHU && !hdu->masks) {
-        if (!pmHDUGenerateForFPA(fpa) || !hdu->masks) {
-            psError(PS_ERR_UNKNOWN, false, "Unable to generate HDU for chip --- likely programming error.\n");
-            return false;
-        }
-    }
-
-    pmConceptSource source = PM_CONCEPT_SOURCE_HEADER | PM_CONCEPT_SOURCE_CELLS | PM_CONCEPT_SOURCE_DEFAULTS;
-    if (!pmConceptsWriteFPA(fpa, source, true, NULL)) {
-        psError(PS_ERR_IO, false, "Unable to write concepts for FPA.\n");
-        return false;
-    }
-    if (!pmHDUWriteMask(hdu, fits))  {
-        psError(PS_ERR_IO, false, "Unable to write HDU for FPA.\n");
-        return false;
-    }
-
-    return true;
-}
-
+    return fpaWrite(fpa, fits, db, blank, recurse, FPA_WRITE_TYPE_MASK);
+}
+
+
+bool pmCellWriteWeight(pmCell *cell, psFits *fits, psDB *db, bool blank)
+{
+    PS_ASSERT_PTR_NON_NULL(cell, false);
+    PS_ASSERT_PTR_NON_NULL(fits, false);
+    return cellWrite(cell, fits, db, blank, FPA_WRITE_TYPE_WEIGHT);
+}
+
+bool pmChipWriteWeight(pmChip *chip, psFits *fits, psDB *db, bool blank, bool recurse)
+{
+    PS_ASSERT_PTR_NON_NULL(chip, false);
+    PS_ASSERT_PTR_NON_NULL(fits, false);
+    return chipWrite(chip, fits, db, blank, recurse, FPA_WRITE_TYPE_WEIGHT);
+}
+
+bool pmFPAWriteWeight(pmFPA *fpa, psFits *fits, psDB *db, bool blank, bool recurse)
+{
+    PS_ASSERT_PTR_NON_NULL(fpa, false);
+    PS_ASSERT_PTR_NON_NULL(fits, false);
+    return fpaWrite(fpa, fits, db, blank, recurse, FPA_WRITE_TYPE_WEIGHT);
+}
 
 
