Index: /trunk/psModules/src/camera/pmFPARead.c
===================================================================
--- /trunk/psModules/src/camera/pmFPARead.c	(revision 7554)
+++ /trunk/psModules/src/camera/pmFPARead.c	(revision 7555)
@@ -21,4 +21,5 @@
 // Carve a readout from the image pixels
 static bool readoutCarve(pmReadout *readout, // Readout to be carved up
+                         psImage **target, // Target pointer for the carved image
                          psImage *image, // Image that will be carved
                          const psRegion *trimsec, // Trim section
@@ -47,5 +48,5 @@
         psFree(readout->image);         // Make way!
     }
-    readout->image = psMemIncrRefCounter(psImageSubset(image, region));
+    *target = psMemIncrRefCounter(psImageSubset(image, region));
 
     // Get the list of overscans
@@ -346,12 +347,15 @@
         }
 
-        pmReadout *readout = pmReadoutAlloc(cell);
-        if (!readoutCarve(readout, image, trimsec, biassecs)) {
+        pmReadout *readout;             // Readout into which to read
+        if (cell->readouts->n > i && cell->readouts->data[i]) {
+            readout = psMemIncrRefCounter(cell->readouts->data[i]);
+        } else {
+            readout = pmReadoutAlloc(cell);
+        }
+        if (!readoutCarve(readout, &readout->image, image, trimsec, biassecs)) {
             psError(PS_ERR_UNEXPECTED_NULL, false,
                     "Unable to carve readout into image and bias sections for %d the plane.", i);
             return NULL;
         }
-        readout->mask = NULL;
-        readout->weight = NULL;
         psFree(readout);                // Drop reference
     }
@@ -415,2 +419,229 @@
 }
 
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Reading the mask
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Read the mask into the cell, and allocate the readouts
+bool pmCellReadMask(pmCell *cell,           // Cell to read into
+                    psFits *fits,           // FITS file from which to read
+                    psDB *db                // Database handle, for "concepts" ingest
+                   )
+{
+    PS_ASSERT_PTR_NON_NULL(cell, false);
+    PS_ASSERT_PTR_NON_NULL(fits, false);
+
+    pmHDU *hdu = pmHDUFromCell(cell);   // The HDU
+    if (!hdu) {
+        return false;                    // Nothing to see here; move along
+    }
+    if (!hdu->images && !pmHDURead(hdu, fits)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to read HDU for cell.\n");
+        return false;
+    }
+
+    if (!pmConceptsReadCell(cell, PM_CONCEPT_SOURCE_HEADER, true, NULL)) {
+        psError(PS_ERR_UNKNOWN, false, "Failed to read concepts for cell");
+        return false;
+    }
+
+    // Having read the cell, we now have to cut it up
+    psRegion *trimsec = psMetadataLookupPtr(NULL, cell->concepts, "CELL.TRIMSEC");
+
+    // Iterate over each of the image planes
+    for (int i = 0; i < hdu->images->n; i++) {
+        psImage *image = hdu->images->data[i]; // The i-th plane
+
+        if (image->type.type != PS_TYPE_U8) {
+            psImage *temp = psImageCopy(NULL, image, PS_TYPE_U8); // Temporary image
+            psFree(hdu->images->data[i]);
+            hdu->images->data[i] = temp;
+            image = temp;
+        }
+
+        pmReadout *readout;             // Readout into which to read
+        if (cell->readouts->n > i && cell->readouts->data[i]) {
+            readout = psMemIncrRefCounter(cell->readouts->data[i]);
+        } else {
+            readout = pmReadoutAlloc(cell);
+        }
+        if (!readoutCarve(readout, &readout->mask, image, trimsec, NULL)) {
+            psError(PS_ERR_UNEXPECTED_NULL, false,
+                    "Unable to carve readout into image and bias sections for %d the plane.", i);
+            return NULL;
+        }
+        psFree(readout);                // Drop reference
+    }
+
+    pmCellSetDataStatus(cell, true);
+    return true;
+}
+
+// Read the mask into the component cells
+bool pmChipReadMask(pmChip *chip,           // Chip to read into
+                    psFits *fits,           // FITS file from which to read
+                    psDB *db                // Database handle, for "concepts" ingest
+                   )
+{
+    PS_ASSERT_PTR_NON_NULL(chip, false);
+    PS_ASSERT_PTR_NON_NULL(fits, false);
+
+    bool success = false;               // Were we able to read at least one HDU?
+    psArray *cells = chip->cells;       // Array of cells
+    for (int i = 0; i < cells->n; i++) {
+        pmCell *cell = cells->data[i];  // The cell of interest
+        success |= pmCellReadMask(cell, fits, db);
+    }
+    if (success) {
+        if (!pmConceptsReadChip(chip, PM_CONCEPT_SOURCE_HEADER, true, true, NULL)) {
+            psError(PS_ERR_IO, false, "Failed to read concepts for FPA.\n");
+            return false;
+        }
+        // XXX probably could just use chip->data_exists
+        pmChipSetDataStatus(chip, true);
+    }
+
+    return success;
+}
+
+// Read the mask into the component chips
+bool pmFPAReadMask(pmFPA *fpa,              // FPA to read into
+                   psFits *fits,            // FITS file from which to read
+                   psDB *db                 // Database handle, for "concepts" ingest
+                  )
+{
+    PS_ASSERT_PTR_NON_NULL(fpa, false);
+    PS_ASSERT_PTR_NON_NULL(fits, false);
+
+    bool success = false;               // Were we able to read at least one HDU?
+    psArray *chips = fpa->chips;        // Array of chips
+    for (int i = 0; i < chips->n; i++) {
+        pmChip *chip = chips->data[i];  // The cell of interest
+        success |= pmChipReadMask(chip, fits, db);
+    }
+    if (success) {
+        if (!pmConceptsReadFPA(fpa, PM_CONCEPT_SOURCE_HEADER, true, NULL)) {
+            psError(PS_ERR_IO, false, "Failed to read concepts for FPA.\n");
+            return false;
+        }
+    } else {
+        psError(PS_ERR_UNKNOWN, false, "Unable to read any chips in FPA");
+    }
+
+    return success;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Reading the weight map
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Read the weight map into the cell, and allocate the readouts
+bool pmCellReadWeight(pmCell *cell,           // Cell to read into
+                      psFits *fits,           // FITS file from which to read
+                      psDB *db                // Database handle, for "concepts" ingest
+                     )
+{
+    PS_ASSERT_PTR_NON_NULL(cell, false);
+    PS_ASSERT_PTR_NON_NULL(fits, false);
+
+    pmHDU *hdu = pmHDUFromCell(cell);   // The HDU
+    if (!hdu) {
+        return false;                    // Nothing to see here; move along
+    }
+    if (!hdu->images && !pmHDURead(hdu, fits)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to read HDU for cell.\n");
+        return false;
+    }
+
+    if (!pmConceptsReadCell(cell, PM_CONCEPT_SOURCE_HEADER, true, NULL)) {
+        psError(PS_ERR_UNKNOWN, false, "Failed to read concepts for cell");
+        return false;
+    }
+
+    // Having read the cell, we now have to cut it up
+    psRegion *trimsec = psMetadataLookupPtr(NULL, cell->concepts, "CELL.TRIMSEC");
+
+    // Iterate over each of the image planes
+    for (int i = 0; i < hdu->images->n; i++) {
+        psImage *image = hdu->images->data[i]; // The i-th plane
+
+        if (image->type.type != PS_TYPE_F32) {
+            psImage *temp = psImageCopy(NULL, image, PS_TYPE_F32); // Temporary image
+            psFree(hdu->images->data[i]);
+            hdu->images->data[i] = temp;
+            image = temp;
+        }
+
+        pmReadout *readout;             // Readout into which to read
+        if (cell->readouts->n > i && cell->readouts->data[i]) {
+            readout = psMemIncrRefCounter(cell->readouts->data[i]);
+        } else {
+            readout = pmReadoutAlloc(cell);
+        }
+        if (!readoutCarve(readout, &readout->weight, image, trimsec, NULL)) {
+            psError(PS_ERR_UNEXPECTED_NULL, false,
+                    "Unable to carve readout into image and bias sections for %d the plane.", i);
+            return NULL;
+        }
+        psFree(readout);                // Drop reference
+    }
+
+    pmCellSetDataStatus(cell, true);
+    return true;
+}
+
+// Read the weight map into the component cells
+bool pmChipReadWeight(pmChip *chip,           // Chip to read into
+                      psFits *fits,           // FITS file from which to read
+                      psDB *db                // Database handle, for "concepts" ingest
+                     )
+{
+    PS_ASSERT_PTR_NON_NULL(chip, false);
+    PS_ASSERT_PTR_NON_NULL(fits, false);
+
+    bool success = false;               // Were we able to read at least one HDU?
+    psArray *cells = chip->cells;       // Array of cells
+    for (int i = 0; i < cells->n; i++) {
+        pmCell *cell = cells->data[i];  // The cell of interest
+        success |= pmCellReadWeight(cell, fits, db);
+    }
+    if (success) {
+        if (!pmConceptsReadChip(chip, PM_CONCEPT_SOURCE_HEADER, true, true, NULL)) {
+            psError(PS_ERR_IO, false, "Failed to read concepts for FPA.\n");
+            return false;
+        }
+        // XXX probably could just use chip->data_exists
+        pmChipSetDataStatus(chip, true);
+    }
+
+    return success;
+}
+
+// Read the weight map into the component chips
+bool pmFPAReadWeight(pmFPA *fpa,              // FPA to read into
+                     psFits *fits,            // FITS file from which to read
+                     psDB *db                 // Database handle, for "concepts" ingest
+                    )
+{
+    PS_ASSERT_PTR_NON_NULL(fpa, false);
+    PS_ASSERT_PTR_NON_NULL(fits, false);
+
+    bool success = false;               // Were we able to read at least one HDU?
+    psArray *chips = fpa->chips;        // Array of chips
+    for (int i = 0; i < chips->n; i++) {
+        pmChip *chip = chips->data[i];  // The cell of interest
+        success |= pmChipReadWeight(chip, fits, db);
+    }
+    if (success) {
+        if (!pmConceptsReadFPA(fpa, PM_CONCEPT_SOURCE_HEADER, true, NULL)) {
+            psError(PS_ERR_IO, false, "Failed to read concepts for FPA.\n");
+            return false;
+        }
+    } else {
+        psError(PS_ERR_UNKNOWN, false, "Unable to read any chips in FPA");
+    }
+
+    return success;
+}
+
Index: /trunk/psModules/src/camera/pmFPARead.h
===================================================================
--- /trunk/psModules/src/camera/pmFPARead.h	(revision 7554)
+++ /trunk/psModules/src/camera/pmFPARead.h	(revision 7555)
@@ -25,4 +25,34 @@
                psDB *db                 // Database handle, for "concepts" ingest
               );
+
+bool pmCellReadMask(pmCell *cell,           // Cell to read into
+                    psFits *fits,           // FITS file from which to read
+                    psDB *db                // Database handle, for "concepts" ingest
+                   );
+
+bool pmChipReadMask(pmChip *chip,           // Chip to read into
+                    psFits *fits,           // FITS file from which to read
+                    psDB *db                // Database handle, for "concepts" ingest
+                   );
+
+bool pmFPAReadMask(pmFPA *fpa,              // FPA to read into
+                   psFits *fits,            // FITS file from which to read
+                   psDB *db                 // Database handle, for "concepts" ingest
+                  );
+
+bool pmCellReadWeight(pmCell *cell,           // Cell to read into
+                      psFits *fits,           // FITS file from which to read
+                      psDB *db                // Database handle, for "concepts" ingest
+                     );
+
+bool pmChipReadWeight(pmChip *chip,           // Chip to read into
+                      psFits *fits,           // FITS file from which to read
+                      psDB *db                // Database handle, for "concepts" ingest
+                     );
+
+bool pmFPAReadWeight(pmFPA *fpa,              // FPA to read into
+                     psFits *fits,            // FITS file from which to read
+                     psDB *db                 // Database handle, for "concepts" ingest
+                    );
 
 bool pmCellReadPHU(pmCell *cell,        // Cell to read into
