Index: /branches/eam_branches/20091201/ippconfig/recipes/filerules-split.mdc
===================================================================
--- /branches/eam_branches/20091201/ippconfig/recipes/filerules-split.mdc	(revision 26846)
+++ /branches/eam_branches/20091201/ippconfig/recipes/filerules-split.mdc	(revision 26847)
@@ -285,4 +285,5 @@
 PPVIZPSF.OUTPUT		OUTPUT {OUTPUT}.{CHIP.NAME}.fits         IMAGE     NONE       CHIP       TRUE      NONE
 PPVIZPATTERN.OUTPUT	OUTPUT {OUTPUT}.{CHIP.NAME}.fits	 IMAGE	   NONE	      CHIP	 TRUE	   NONE
+PPVIZPATTERN.CHIP	OUTPUT {OUTPUT}.{CHIP.NAME}.ch.fits	 IMAGE	   NONE	      CHIP	 TRUE	   NONE
 
 # {FPA.OBS}
Index: /branches/eam_branches/20091201/ppViz/src/ppVizPattern/ppVizPatternCamera.c
===================================================================
--- /branches/eam_branches/20091201/ppViz/src/ppVizPattern/ppVizPatternCamera.c	(revision 26846)
+++ /branches/eam_branches/20091201/ppViz/src/ppVizPattern/ppVizPatternCamera.c	(revision 26847)
@@ -42,8 +42,16 @@
     pmFPAfile *output = pmFPAfileDefineOutput(data->config, input->fpa, "PPVIZPATTERN.OUTPUT");
     if (!output) {
-        psError(psErrorCodeLast(), false, "Unable to define output.");
+        psError(psErrorCodeLast(), false, "Unable to define file PPVIZPATTERN.OUTPUT");
         return false;
     }
     output->save = true;
+
+    pmFPAfile *outChip = pmFPAfileDefineChipMosaic(data->config, input->fpa, "PPVIZPATTERN.CHIP");
+    if (!outChip) {
+        psError(psErrorCodeLast(), false, "Unable to define file PPVIZPATTERN.CHIP");
+        return false;
+    }
+    outChip->save = true;
+
 
 #if 0
Index: /branches/eam_branches/20091201/ppViz/src/ppVizPattern/ppVizPatternLoop.c
===================================================================
--- /branches/eam_branches/20091201/ppViz/src/ppVizPattern/ppVizPatternLoop.c	(revision 26846)
+++ /branches/eam_branches/20091201/ppViz/src/ppVizPattern/ppVizPatternLoop.c	(revision 26847)
@@ -15,5 +15,6 @@
 {
     pmConfig *config = data->config;                                        // Configuration data
-    pmFPAfile *input = pmFPAfileSelectSingle(config->files, "PPVIZPATTERN.INPUT", 0); // File with PSF
+    pmFPAfile *input = pmFPAfileSelectSingle(config->files, "PPVIZPATTERN.INPUT", 0); // Input file
+    pmFPAfile *output = pmFPAfileSelectSingle(config->files, "PPVIZPATTERN.CHIP", 0); // Output file
 
     pmFPAview *view = pmFPAviewAlloc(0); // Pointer into FPA hierarchy
@@ -48,5 +49,7 @@
                     return false;
                 }
-                if (!readout->data_exists) {
+                // Need to generate an image even if there's nothing in this readout, so chip-mosaicked image
+                // is filled in.
+                if (!readout->data_exists && !cell->data_exists && !chip->data_exists) {
                     continue;
                 }
@@ -100,4 +103,9 @@
                     return false;
                 }
+
+                // Blow away bias sections to prevent warnings
+                psMetadataItem *biassec = psMetadataLookup(cell->concepts, "CELL.BIASSEC"); // Bias section
+                psFree(biassec->data.list);
+                biassec->data.list = psListAlloc(NULL);
             }
             // Cell
@@ -107,4 +115,15 @@
             }
         }
+
+        pmChip *outChip = pmFPAfileThisChip(config->files, view, "PPVIZPATTERN.CHIP");
+        if (!outChip->hdu && !outChip->parent->hdu) {
+            const char *name = psMetadataLookupStr(NULL, chip->parent->concepts, "FPA.OBS"); // Name of FPA
+            pmFPAAddSourceFromView(outChip->parent, name, view, output->format);
+        }
+        if (!pmChipMosaic(outChip, chip, true, MASK_BAD)) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to mosaic chip.");
+            return false;
+        }
+
         // Chip
         if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
Index: /branches/eam_branches/20091201/psModules/src/detrend/pmPattern.c
===================================================================
--- /branches/eam_branches/20091201/psModules/src/detrend/pmPattern.c	(revision 26846)
+++ /branches/eam_branches/20091201/psModules/src/detrend/pmPattern.c	(revision 26847)
@@ -87,4 +87,5 @@
 
     psImage *corr = psImageAlloc(order + 1, numRows, PS_TYPE_F64); // Corrections applied
+    psImageInit(corr, NAN);
 
     for (int y = 0; y < numRows; y++) {
@@ -113,7 +114,6 @@
         }
 
+        poly->coeff[0] -= background;
         memcpy(corr->data.F64[y], poly->coeff, (order + 1) * PSELEMTYPE_SIZEOF(PS_TYPE_F64));
-        corr->data.F64[y][0] -= background;
-
         psVector *solution = psPolynomial1DEvalVector(poly, indices); // Solution vector
         if (!solution) {
@@ -125,5 +125,5 @@
 
         for (int x = 0; x < numCols; x++) {
-            image->data.F32[y][x] += (background - solution->data.F32[x]);
+            image->data.F32[y][x] -= solution->data.F32[x];
         }
         psFree(solution);
@@ -174,5 +174,5 @@
 
     for (int y = 0; y < numRows; y++) {
-        memcpy(poly->coeff, corr->data.F64[y], order * PSELEMTYPE_SIZEOF(PS_TYPE_F64));
+        memcpy(poly->coeff, corr->data.F64[y], (order + 1) * PSELEMTYPE_SIZEOF(PS_TYPE_F64));
         psVector *solution = psPolynomial1DEvalVector(poly, indices); // Solution vector
         if (!solution) {
Index: /branches/eam_branches/20091201/psModules/src/detrend/pmPatternIO.c
===================================================================
--- /branches/eam_branches/20091201/psModules/src/detrend/pmPatternIO.c	(revision 26846)
+++ /branches/eam_branches/20091201/psModules/src/detrend/pmPatternIO.c	(revision 26847)
@@ -9,5 +9,7 @@
 #include "pmFPAfile.h"
 #include "pmFPAfileFitsIO.h"
+#include "pmFPAHeader.h"
 #include "pmConceptsRead.h"
+#include "pmConceptsWrite.h"
 
 #include "pmPattern.h"
@@ -24,8 +26,4 @@
     psImage *rowCorr = psMetadataLookupPtr(&gotRow, ro->analysis, PM_PATTERN_ROW_CORRECTION); // Row correction
     float cellCorr = psMetadataLookupF32(&gotCell, ro->analysis, PM_PATTERN_CELL_CORRECTION); // Cell corr.
-    if (!gotRow && !gotCell) {
-        // Nothing to write
-        return true;
-    }
 
     pmCell *cell = ro->parent;          // Cell of interest
@@ -73,4 +71,9 @@
     PS_ASSERT_PTR_NON_NULL(cell->readouts, false);
     PS_ASSERT_PTR_NON_NULL(view, false);
+
+    if (!pmConceptsWriteCell(cell, true, config)) {
+        psError(PS_ERR_IO, false, "Unable to write concepts for cell.");
+        return false;
+    }
 
     pmFPAview *thisView = pmFPAviewAlloc(view->nRows); // Copy of input view
@@ -97,4 +100,9 @@
     PS_ASSERT_PTR_NON_NULL(view, false);
 
+    if (!pmConceptsWriteChip(chip, true, true, config)) {
+        psError(PS_ERR_IO, false, "Unable to write concepts for chip.\n");
+        return false;
+    }
+
     pmFPAview *thisView = pmFPAviewAlloc(view->nRows); // Copy of input view
     *thisView = *view;
@@ -120,4 +128,9 @@
     PS_ASSERT_PTR_NON_NULL(fpa->chips, false);
 
+    if (!pmConceptsWriteFPA(fpa, true, config)) {
+        psError(PS_ERR_IO, false, "Unable to write concepts for FPA.\n");
+        return false;
+    }
+
     pmFPAview *thisView = pmFPAviewAlloc(view->nRows); // Copy of input view
     *thisView = *view;
@@ -168,5 +181,5 @@
     }
 
-    bool data = false;                  // Did we find any data?
+    bool data = true;                  // Did we find any data?
 
     psMetadataItem *cellCorr = psMetadataLookup(header, PM_PATTERN_CELL_CORRECTION); // Cell pattern correction
@@ -216,18 +229,20 @@
         pmReadout *readout = cell->readouts->data[i];
         thisView->readout = i;
-        pmReadoutReadPattern(readout, file->fits);
-        if (!readout->data_exists) {
-            continue;
-        }
-#if 0
-        // load in the concept information for this cell
-        if (!pmConceptsReadCell(cell, PM_CONCEPT_SOURCE_HEADER, true, NULL)) {
-            psErrorClear();
-            psWarning("Difficulty reading concepts for cell; attempting to proceed.");
-        }
-#endif
-        cell->data_exists = true;
-    }
-    psFree(thisView);
+        if (!pmReadoutReadPattern(readout, file->fits)) {
+            psError(PS_ERR_IO, false, "Unable to read pattern correction.");
+            return false;
+        }
+    }
+    psFree(thisView);
+
+    if (!pmCellReadHeader(cell, file->fits, config)) {
+        psError(PS_ERR_IO, false, "Unable to read header for cell.");
+        return false;
+    }
+    // load in the concept information for this cell
+    if (!pmConceptsReadCell(cell, PM_CONCEPT_SOURCE_HEADER, true, NULL)) {
+        psErrorClear();
+        psWarning("Difficulty reading concepts for cell; attempting to proceed.");
+    }
 
     return true;
@@ -256,10 +271,12 @@
     psFree(thisView);
 
-#if 0
+    if (!pmChipReadHeader(chip, file->fits, config)) {
+        psError(PS_ERR_IO, false, "Unable to read header for cell.");
+        return false;
+    }
     if (!pmConceptsReadChip(chip, PM_CONCEPT_SOURCE_HEADER, true, true, NULL)) {
         psError(PS_ERR_IO, false, "Failed to read concepts for chip.\n");
         return false;
     }
-#endif
 
     return true;
@@ -284,10 +301,12 @@
     psFree(thisView);
 
-#if 0
+    if (!pmFPAReadHeader(fpa, file->fits, config)) {
+        psError(PS_ERR_IO, false, "Unable to read header for cell.");
+        return false;
+    }
     if (!pmConceptsReadFPA(fpa, PM_CONCEPT_SOURCE_HEADER, true, NULL)) {
         psError(PS_ERR_IO, false, "Failed to read concepts for fpa.\n");
         return false;
     }
-#endif
 
     return true;
