Index: trunk/psModules/src/camera/pmFPA.c
===================================================================
--- trunk/psModules/src/camera/pmFPA.c	(revision 26651)
+++ trunk/psModules/src/camera/pmFPA.c	(revision 26893)
@@ -105,5 +105,5 @@
     psFree(fpa->concepts);
     psFree(fpa->analysis);
-    psFree((void *)fpa->camera);
+    psFree(fpa->camera);
     psFree(fpa->hdu);
 
Index: trunk/psModules/src/camera/pmFPAMaskWeight.c
===================================================================
--- trunk/psModules/src/camera/pmFPAMaskWeight.c	(revision 26651)
+++ trunk/psModules/src/camera/pmFPAMaskWeight.c	(revision 26893)
@@ -370,8 +370,34 @@
 
     psImage *image = readout->image, *mask = readout->mask, *variance = readout->variance; // Readout parts
-
     int numCols = image->numCols, numRows = image->numRows; // Size of image
-    int numPix = numCols * numRows;                         // Number of pixels
-    int num = PS_MAX(sample, numPix);                       // Number we care about
+
+    int xMin, xMax, yMin, yMax;         // Bounds of image
+    if (mask) {
+        xMin = numCols;
+        xMax = 0;
+        yMin = numRows;
+        yMax = 0;
+        for (int y = 0; y < numRows; y++) {
+            for (int x = 0; x < numCols; x++) {
+                if (mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) {
+                    continue;
+                }
+                xMin = PS_MIN(xMin, x);
+                xMax = PS_MAX(xMax, x);
+                yMin = PS_MIN(yMin, y);
+                yMax = PS_MAX(yMax, y);
+            }
+        }
+    } else {
+        xMin = 0;
+        xMax = numCols;
+        yMin = 0;
+        yMax = numRows;
+    }
+
+    int xNum = xMax - xMin, yNum = yMax - yMin; // Number of pixels
+
+    int numPix = xNum * yNum;                                  // Number of pixels
+    int num = PS_MIN(sample, numPix);                          // Number we care about
     psVector *signoise = psVectorAllocEmpty(num, PS_TYPE_F32);   // Signal-to-noise values
 
@@ -379,6 +405,6 @@
         // We have an image smaller than Nsubset, so just loop over the image pixels
         int index = 0;                  // Index for vector
-        for (int y = 0; y < numRows; y++) {
-            for (int x = 0; x < numCols; x++) {
+        for (int y = yMin; y < yMax; y++) {
+            for (int x = xMin; x < xMax; x++) {
                 if ((mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) ||
                     !isfinite(image->data.F32[y][x]) || !isfinite(variance->data.F32[y][x])) {
@@ -397,6 +423,6 @@
             // Pixel coordinates
             int pixel = numPix * psRandomUniform(rng);
-            int x = pixel % numCols;
-            int y = pixel / numCols;
+            int x = xMin + pixel % xNum;
+            int y = yMin + pixel / xNum;
 
             if ((mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) ||
@@ -428,10 +454,12 @@
     // Check valid range of correction factor
     if ((isfinite(minValid) && correction < minValid) || (isfinite(maxValid) && correction > maxValid)) {
-        psWarning("Variance renormalisation is outside valid range: %f vs %f:%f --- no correction made",
-                  correction, minValid, maxValid);
-        return true;
-    }
-
-    psBinaryOp(variance, variance, "*", psScalarAlloc(PS_SQR(correction), PS_TYPE_F32));
+	psError(PS_ERR_UNKNOWN, true, "Variance renormalisation is outside valid range: %f vs %f:%f --- no correction made", correction, minValid, maxValid);
+	psMetadataAddF32(readout->analysis, PS_LIST_TAIL, PM_READOUT_ANALYSIS_RENORM, 0, "Renormalisation of variance", PS_SQR(correction));
+        return false;
+    }
+
+    psImage *subImage = psImageSubset(variance, psRegionSet(xMin, xMax, yMin, yMax)); // Smaller image
+    psBinaryOp(subImage, subImage, "*", psScalarAlloc(PS_SQR(correction), PS_TYPE_F32));
+    psFree(subImage);
 
     pmHDU *hdu = pmHDUFromReadout(readout); // HDU for readout
Index: trunk/psModules/src/camera/pmFPAMosaic.c
===================================================================
--- trunk/psModules/src/camera/pmFPAMosaic.c	(revision 26651)
+++ trunk/psModules/src/camera/pmFPAMosaic.c	(revision 26893)
@@ -626,16 +626,20 @@
     bool good = true;                   // Is everything good?
 
+    const char *cellName = psMetadataLookupStr(NULL, cell->concepts, "CELL.NAME"); // Name of cell
+    const char *chipName = psMetadataLookupStr(NULL, cell->parent->concepts, "CHIP.NAME"); // Name of chip
+
     // Offset of the cell on the chip
     int x0Cell = psMetadataLookupS32(&mdok, cell->concepts, "CELL.X0");
     if (!mdok) {
-        psError(PS_ERR_UNKNOWN, true, "CELL.X0 for cell is not set.\n");
+        psError(PS_ERR_UNKNOWN, true, "CELL.X0 for cell %s,%s is not set.\n", chipName, cellName);
         good = false;
     }
     int y0Cell = psMetadataLookupS32(&mdok, cell->concepts, "CELL.Y0");
     if (!mdok) {
-        psError(PS_ERR_UNKNOWN, true, "CELL.Y0 for cell is not set.\n");
+        psError(PS_ERR_UNKNOWN, true, "CELL.Y0 for cell %s,%s is not set.\n", chipName, cellName);
         good = false;
     }
-    psTrace("psModules.camera", 5, "Cell %ld: x0=%d y0=%d\n", index, x0Cell, y0Cell);
+    psTrace("psModules.camera", 5, "Cell %s,%s (%ld): x0=%d y0=%d\n",
+            chipName, cellName, index, x0Cell, y0Cell);
 
     // Offset of the chip on the FPA
@@ -649,10 +653,10 @@
         x0Chip = psMetadataLookupS32(&mdok, chip->concepts, "CHIP.X0");
         if (!mdok) {
-            psError(PS_ERR_UNKNOWN, true, "CHIP.X0 for chip is not set.\n");
+            psError(PS_ERR_UNKNOWN, true, "CHIP.X0 for chip %s is not set.\n", chipName);
             good = false;
         }
         y0Chip = psMetadataLookupS32(&mdok, chip->concepts, "CHIP.Y0");
         if (!mdok) {
-            psError(PS_ERR_UNKNOWN, true, "CHIP.Y0 for chip is not set.\n");
+            psError(PS_ERR_UNKNOWN, true, "CHIP.Y0 for chip %s is not set.\n", chipName);
             good = false;
         }
@@ -662,5 +666,5 @@
     xBin->data.S32[index] = psMetadataLookupS32(&mdok, cell->concepts, "CELL.XBIN");
     if (!mdok || xBin->data.S32[index] == 0) {
-        psError(PS_ERR_UNKNOWN, true, "CELL.XBIN for cell is not set.\n");
+        psError(PS_ERR_UNKNOWN, true, "CELL.XBIN for cell %s,%s is not set.\n", chipName, cellName);
         return false;
     } else if (xBin->data.S32[index] < *xBinMin) {
@@ -669,5 +673,5 @@
     yBin->data.S32[index] = psMetadataLookupS32(&mdok, cell->concepts, "CELL.YBIN");
     if (!mdok || yBin->data.S32[index] == 0) {
-        psError(PS_ERR_UNKNOWN, true, "CELL.YBIN for cell is not set.\n");
+        psError(PS_ERR_UNKNOWN, true, "CELL.YBIN for cell %s,%s is not set.\n", chipName, cellName);
         return false;
     } else if (yBin->data.S32[index] < *yBinMin) {
@@ -678,10 +682,10 @@
     int xParityCell = psMetadataLookupS32(&mdok, cell->concepts, "CELL.XPARITY");
     if (!mdok || (xParityCell != 1 && xParityCell != -1)) {
-        psError(PS_ERR_UNKNOWN, true, "CELL.XPARITY for cell is not set.\n");
+        psError(PS_ERR_UNKNOWN, true, "CELL.XPARITY for cell %s,%s is not set.\n", chipName, cellName);
         return false;
     }
     int yParityCell = psMetadataLookupS32(&mdok, cell->concepts, "CELL.YPARITY");
     if (!mdok || (yParityCell != 1 && yParityCell != -1)) {
-        psError(PS_ERR_UNKNOWN, true, "CELL.YPARITY for cell is not set.\n");
+        psError(PS_ERR_UNKNOWN, true, "CELL.YPARITY for cell %s,%s is not set.\n", chipName, cellName);
         return false;
     }
@@ -693,10 +697,10 @@
         xParityChip = psMetadataLookupS32(&mdok, chip->concepts, "CHIP.XPARITY");
         if (!mdok || (xParityChip != 1 && xParityChip != -1)) {
-            psError(PS_ERR_UNKNOWN, true, "CHIP.XPARITY for chip is not set.\n");
+            psError(PS_ERR_UNKNOWN, true, "CHIP.XPARITY for chip %s is not set.\n", chipName);
             return false;
         }
         yParityChip = psMetadataLookupS32(&mdok, chip->concepts, "CHIP.YPARITY");
         if (!mdok || (yParityChip != 1 && yParityChip != -1)) {
-            psError(PS_ERR_UNKNOWN, true, "CHIP.YPARITY for chip is not set.\n");
+            psError(PS_ERR_UNKNOWN, true, "CHIP.YPARITY for chip %s is not set.\n", chipName);
             return false;
         }
Index: trunk/psModules/src/camera/pmFPAfile.c
===================================================================
--- trunk/psModules/src/camera/pmFPAfile.c	(revision 26651)
+++ trunk/psModules/src/camera/pmFPAfile.c	(revision 26893)
@@ -519,4 +519,7 @@
     if (!strcasecmp(type, "SUBKERNEL"))     {
         return PM_FPA_FILE_SUBKERNEL;
+    }
+    if (!strcasecmp(type, "PATTERN")) {
+        return PM_FPA_FILE_PATTERN;
     }
 
@@ -563,4 +566,6 @@
       case PM_FPA_FILE_SUBKERNEL:
         return ("SUBKERNEL");
+      case PM_FPA_FILE_PATTERN:
+        return "PATTERN";
       default:
         return ("NONE");
Index: trunk/psModules/src/camera/pmFPAfile.h
===================================================================
--- trunk/psModules/src/camera/pmFPAfile.h	(revision 26651)
+++ trunk/psModules/src/camera/pmFPAfile.h	(revision 26893)
@@ -49,4 +49,5 @@
     PM_FPA_FILE_SUBKERNEL,
     PM_FPA_FILE_SRCTEXT,
+    PM_FPA_FILE_PATTERN,
 } pmFPAfileType;
 
Index: trunk/psModules/src/camera/pmFPAfileIO.c
===================================================================
--- trunk/psModules/src/camera/pmFPAfileIO.c	(revision 26651)
+++ trunk/psModules/src/camera/pmFPAfileIO.c	(revision 26893)
@@ -43,4 +43,5 @@
 #include "pmFPAConstruct.h"
 #include "pmSubtractionIO.h"
+#include "pmPatternIO.h"
 #include "pmConcepts.h"
 #include "pmConfigRun.h"
@@ -66,5 +67,5 @@
 
         switch (place) {
-	  case PM_FPA_BEFORE:
+          case PM_FPA_BEFORE:
             if (!pmFPAfileRead (file, view, config)) {
                 psError(PS_ERR_IO, false, "failed READ in FPA_BEFORE block for %s", file->name);
@@ -76,6 +77,6 @@
             }
             break;
-	  case PM_FPA_AFTER:
-	    if (!pmFPAfileWrite (file, view, config)) {
+          case PM_FPA_AFTER:
+            if (!pmFPAfileWrite (file, view, config)) {
                 psError(PS_ERR_IO, false, "failed WRITE in FPA_AFTER block for %s", file->name);
                 goto failure;
@@ -86,5 +87,5 @@
             }
             break;
-	  default:
+          default:
             psAbort("You can't get here");
         }
@@ -202,4 +203,7 @@
         status = pmSubtractionReadKernels(view, file, config);
         break;
+      case PM_FPA_FILE_PATTERN:
+        status = pmPatternRead(view, file, config);
+        break;
       case PM_FPA_FILE_SX:
       case PM_FPA_FILE_RAW:
@@ -273,23 +277,25 @@
       case PM_FPA_FILE_VARIANCE:
       case PM_FPA_FILE_FRINGE:
-      case PM_FPA_FILE_DARK: {
-          // create FPA structure component based on view
-          psMetadata *format = file->format; // Camera format configuration
-          if (!format) {
-              format = config->format;
-          }
-
-          pmFPA *nameSource = file->src; // Source of FPA.OBS
-          if (!nameSource) {
-              nameSource = file->fpa;
-          }
-          bool mdok;                  // Status of MD lookup
-          const char *fpaObs = psMetadataLookupStr(&mdok, nameSource->concepts, "FPA.OBS"); // Obs. id
-
-          pmFPAAddSourceFromView(file->fpa, fpaObs, view, format);
-          psTrace ("psModules.camera", 5, "created fpa data elements for %s (%s) (%d:%d:%d)\n",
-                   file->name, file->name, view->chip, view->cell, view->readout);
-          break;
-      }
+      case PM_FPA_FILE_DARK:
+      case PM_FPA_FILE_PATTERN:
+        {
+            // create FPA structure component based on view
+            psMetadata *format = file->format; // Camera format configuration
+            if (!format) {
+                format = config->format;
+            }
+
+            pmFPA *nameSource = file->src; // Source of FPA.OBS
+            if (!nameSource) {
+                nameSource = file->fpa;
+            }
+            bool mdok;                  // Status of MD lookup
+            const char *fpaObs = psMetadataLookupStr(&mdok, nameSource->concepts, "FPA.OBS"); // Obs. id
+
+            pmFPAAddSourceFromView(file->fpa, fpaObs, view, format);
+            psTrace ("psModules.camera", 5, "created fpa data elements for %s (%s) (%d:%d:%d)\n",
+                     file->name, file->name, view->chip, view->cell, view->readout);
+            break;
+        }
       case PM_FPA_FILE_HEADER:
         psAbort ("Create not defined for HEADER");
@@ -462,4 +468,7 @@
         status = pmSubtractionWriteKernels(view, file, config);
         break;
+      case PM_FPA_FILE_PATTERN:
+        status = pmPatternWrite(view, file, config);
+        break;
       case PM_FPA_FILE_SX:
       case PM_FPA_FILE_RAW:
@@ -543,4 +552,5 @@
       case PM_FPA_FILE_DARK:
       case PM_FPA_FILE_SUBKERNEL:
+      case PM_FPA_FILE_PATTERN:
       case PM_FPA_FILE_CMF:
       case PM_FPA_FILE_WCS:
@@ -610,4 +620,5 @@
         break;
       case PM_FPA_FILE_SUBKERNEL:
+      case PM_FPA_FILE_PATTERN:
       case PM_FPA_FILE_SX:
       case PM_FPA_FILE_RAW:
@@ -771,4 +782,5 @@
       case PM_FPA_FILE_DARK:
       case PM_FPA_FILE_SUBKERNEL:
+      case PM_FPA_FILE_PATTERN:
       case PM_FPA_FILE_CMF:
       case PM_FPA_FILE_WCS:
@@ -962,4 +974,8 @@
       case PM_FPA_FILE_SUBKERNEL:
         status = pmSubtractionWritePHU(view, file, config);
+        break;
+      case PM_FPA_FILE_PATTERN:
+        status = pmPatternWritePHU(view, file, config);
+        break;
       case PM_FPA_FILE_CMF:
         status = pmSource_CMF_WritePHU (view, file, config);
