Index: /branches/eam_branches/ipp-20110213/ppImage/src/ppImageDetrendPattern.c
===================================================================
--- /branches/eam_branches/ipp-20110213/ppImage/src/ppImageDetrendPattern.c	(revision 31085)
+++ /branches/eam_branches/ipp-20110213/ppImage/src/ppImageDetrendPattern.c	(revision 31086)
@@ -23,17 +23,35 @@
     assert(inputView->readout == -1);
 
+    // PATTERN.ROW is selected by the recipe.  If it is selected, we search for the table
+    // PATTERN.ROW.SUBSET.  If this is found in our format file, we use that version;
+    // otherwise, we use the table provided in the recipe file "ppImage.config".  Within that
+    // table, we select the entry that matches our CHIP.NAME.  This will be either a boolean or
+    // a string of bits.  If it is a boolean, it specified whether or not to correct the entire
+    // chip; if it is a string, the bits specify which cells to correct (sequence is order of
+    // CELLS in the format:CHIPS metadata table)
+
+    // We also check the chip header for the boolean 'PTRN_ROW' : if this is true, we have
+    // already applied this correct to this data, so we simply skip the correction for this
+    // chip.
+
     if (options->doPatternRow) {
         bool status;
-        pmFPAfile *input = psMetadataLookupPtr(&status, config->files, "PPIMAGE.INPUT");
-        pmFPAview *view = pmFPAviewAlloc(0); // View for local processing
-        *view = *inputView;
-        while ((cell = pmFPAviewNextCell(view, input->fpa, 1)) != NULL) {
+	pmHDU *hdu = pmHDUFromChip(chip);
+	if (psMetadataLookupBool(NULL,hdu->header,"PTRN_ROW")) {
+	  psLogMsg("ppImage", PS_LOG_INFO, "Not performing row pattern correction as it has already been done.");
+	  goto pattern_cell;
+	}
+
+	pmFPAfile *input = psMetadataLookupPtr(&status, config->files, "PPIMAGE.INPUT");
+	pmFPAview *view = pmFPAviewAlloc(0); // View for local processing
+	*view = *inputView;
+	while ((cell = pmFPAviewNextCell(view, input->fpa, 1)) != NULL) {
             if (!cell->process || !cell->file_exists) {
-                continue;
+		continue;
             }
             if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
-              ESCAPE(false, "load failure for Cell");
+		ESCAPE(false, "load failure for Cell");
             }
-
+	    
             if (!cell->data_exists) {
                 continue;
@@ -51,8 +69,8 @@
             if (!doPattern) continue;
 
+	    // A very detailed log message. 
             const char *chipName = psMetadataLookupStr(NULL, chip->concepts, "CHIP.NAME");
             const char *cellName = psMetadataLookupStr(NULL, cell->concepts, "CELL.NAME");
-            psLogMsg("ppImage", PS_LOG_INFO, "Performing row pattern correction for %s, %s\n",
-                     chipName, cellName);
+            psLogMsg("ppImage", PS_LOG_INFO, "Performing row pattern correction for %s, %s\n", chipName, cellName);
 
             // process each of the readouts
@@ -74,7 +92,13 @@
                 }
             }
-        }
-        psFree(view);
+
+	}
+	psMetadataAddBool(hdu->header, PS_LIST_TAIL, "PTRN_ROW",PS_META_REPLACE,"PATTERN.ROW correction applied",true);
+	psFree(view);
     }
+
+ pattern_cell:
+
+    // see the comment for PATTERN.ROW; the same rules apply for PATTERN.CELL
 
     if (options->doPatternCell) {
@@ -83,8 +107,16 @@
         pmFPAview *view = pmFPAviewAlloc(0); // View for local processing
         *view = *inputView;
-        for (int i = 0; i < chip->cells->n; i++) {
+
+	pmHDU *hdu = pmHDUFromChip(chip);
+	if (psMetadataLookupBool(NULL,hdu->header,"PTRN_CEL")) {
+	  psLogMsg("ppImage", PS_LOG_INFO, "Not performing cell pattern correction as it has already been done.");
+	  goto pattern_done;
+	}
+
+	for (int i = 0; i < chip->cells->n; i++) {
             view->cell = i;
 
             pmCell *cell = chip->cells->data[i]; // Cell of interest
+
             if (cell->readouts->n > 1) {
                 psLogMsg("ppImage", PS_LOG_INFO, "Not performing cell pattern correction on video cell.");
@@ -99,17 +131,21 @@
                 tweak->data.U8[i] = 0xFF;
             }
-        }
 
-        // Tweak the cells
-        if (!pmPatternCell(chip, tweak, options->patternCellBG, options->patternCellMean,
-                           options->maskValue, options->darkMask)) {
-            psFree(tweak);
-            psFree(view);
-            return false;
-        }
-        psFree(tweak);
-        psFree(view);
+	}
+
+	// Tweak the cells
+	if (!pmPatternCell(chip, tweak, options->patternCellBG, options->patternCellMean,
+			   options->maskValue, options->darkMask)) {
+	    psFree(tweak);
+	    psFree(view);
+	    return false;
+	}
+	psFree(tweak);
+	psFree(view);
+
+	psMetadataAddBool(hdu->header, PS_LIST_TAIL, "PTRN_CEL",PS_META_REPLACE,"PATTERN.CELL correction applied",true);
     }
 
+ pattern_done:
     return(true);
 }
@@ -119,5 +155,8 @@
     *doit = false;
 
-    psMetadataItem *doPattern = pmConfigRecipeValueByView(config, recipeName, recipeValue, chip->parent, view);
+    psMetadataItem *doPattern;
+
+    doPattern = pmConfigRecipeValueByView(config, recipeName, recipeValue, chip->parent, view);
+    
     if (!doPattern) {
         psError(PS_ERR_UNKNOWN, false, "Unable to determine whether row pattern matching should be applied.");
Index: /branches/eam_branches/ipp-20110213/ppImage/src/ppImageOptions.c
===================================================================
--- /branches/eam_branches/ipp-20110213/ppImage/src/ppImageOptions.c	(revision 31085)
+++ /branches/eam_branches/ipp-20110213/ppImage/src/ppImageOptions.c	(revision 31086)
@@ -126,5 +126,6 @@
         exit(EXIT_FAILURE);
     }
-
+    psMetadata *format = config->format;
+    
     // Non-linearity recipe options
     if (psMetadataLookupBool(NULL, recipe, "NONLIN")) {
@@ -237,6 +238,20 @@
     options->doFringe = psMetadataLookupBool(NULL, recipe, "FRINGE");
     options->doShutter = psMetadataLookupBool(NULL, recipe, "SHUTTER");
+
+    // PATTERN.ROW is selected by the recipe.  If it is selected, we search for the table
+    // PATTERN.ROW.SUBSET.  If this is found in our format file, we use that version;
+    // otherwise, we use the table provided in the recipe file "ppImage.config".  Within that
+    // table, we select the entry that matches our CHIP.NAME.  This will be either a boolean or
+    // a string of bits.  If it is a boolean, it specified whether or not to correct the entire
+    // chip; if it is a string, the bits specify which cells to correct (sequence is order of
+    // CELLS in the format:CHIPS metadata table)
+
+    // We also check the chip header for the boolean 'PTRN_ROW' : if this is true, we have
+    // already applied this correct to this data, so we simply skip the correction for this
+    // chip.
+
     options->doPatternRow = psMetadataLookupBool(NULL, recipe, "PATTERN.ROW");
     options->doPatternCell = psMetadataLookupBool(NULL, recipe, "PATTERN.CELL");
+
     options->doMaskStats = psMetadataLookupBool(NULL, recipe, "MASK.STATS");
     options->addNoise = psMetadataLookupBool(NULL, recipe, "ADDNOISE");
@@ -344,12 +359,53 @@
 
     // Pattern correction
-    options->patternRowOrder = psMetadataLookupS32(NULL, recipe, "PATTERN.ROW.ORDER");
-    options->patternRowIter = psMetadataLookupS32(NULL, recipe, "PATTERN.ROW.ITER");
-    options->patternRowRej = psMetadataLookupF32(NULL, recipe, "PATTERN.ROW.REJ");
-    options->patternRowThresh = psMetadataLookupF32(NULL, recipe, "PATTERN.ROW.THRESH");
-    options->patternRowMean = psStatsOptionFromString(psMetadataLookupStr(NULL, recipe, "PATTERN.ROW.MEAN"));
-    options->patternRowStdev = psStatsOptionFromString(psMetadataLookupStr(NULL, recipe, "PATTERN.ROW.STDEV"));
-    options->patternCellBG = psStatsOptionFromString(psMetadataLookupStr(NULL, recipe, "PATTERN.CELL.BG"));
-    options->patternCellMean = psStatsOptionFromString(psMetadataLookupStr(NULL, recipe, "PATTERN.CELL.MEAN"));
+    if (psMetadataLookup(format, "PATTERN.ROW.ORDER")) {
+      options->patternRowOrder = psMetadataLookupS32(NULL, format, "PATTERN.ROW.ORDER");
+    }
+    else {
+      options->patternRowOrder = psMetadataLookupS32(NULL, recipe, "PATTERN.ROW.ORDER");
+    }
+    if (psMetadataLookup(format, "PATTERN.ROW.ITER")) {
+      options->patternRowIter = psMetadataLookupS32(NULL, format, "PATTERN.ROW.ITER");
+    }
+    else {
+      options->patternRowIter = psMetadataLookupS32(NULL, recipe, "PATTERN.ROW.ITER");
+    }
+    if (psMetadataLookup(format, "PATTERN.ROW.REJ")) {
+      options->patternRowRej = psMetadataLookupF32(NULL, format, "PATTERN.ROW.REJ");
+    }
+    else {
+      options->patternRowRej = psMetadataLookupF32(NULL, recipe, "PATTERN.ROW.REJ");
+    }
+    if (psMetadataLookup(format, "PATTERN.ROW.THRESH")) {
+      options->patternRowThresh = psMetadataLookupF32(NULL, format, "PATTERN.ROW.THRESH");
+    }
+    else {
+      options->patternRowThresh = psMetadataLookupF32(NULL, recipe, "PATTERN.ROW.THRESH");
+    }
+    if (psMetadataLookup(format, "PATTERN.ROW.MEAN")) {
+      options->patternRowMean = psStatsOptionFromString(psMetadataLookupStr(NULL, format, "PATTERN.ROW.MEAN"));
+    }
+    else {
+      options->patternRowMean = psStatsOptionFromString(psMetadataLookupStr(NULL, recipe, "PATTERN.ROW.MEAN"));
+    }
+    if (psMetadataLookup(format, "PATTERN.ROW.STDEV")) {
+      options->patternRowStdev = psStatsOptionFromString(psMetadataLookupStr(NULL, format, "PATTERN.ROW.STDEV"));
+    }
+    else {
+      options->patternRowStdev = psStatsOptionFromString(psMetadataLookupStr(NULL, recipe, "PATTERN.ROW.STDEV"));
+    }
+    if (psMetadataLookup(format, "PATTERN.CELL.BG")) {
+      options->patternCellBG = psStatsOptionFromString(psMetadataLookupStr(NULL, format, "PATTERN.CELL.BG"));
+    }
+    else {
+      options->patternCellBG = psStatsOptionFromString(psMetadataLookupStr(NULL, recipe, "PATTERN.CELL.BG"));
+    }
+    if (psMetadataLookup(format, "PATTERN.CELL.MEAN")) {
+      options->patternCellMean = psStatsOptionFromString(psMetadataLookupStr(NULL, format, "PATTERN.CELL.MEAN"));
+    }
+    else {
+      options->patternCellMean = psStatsOptionFromString(psMetadataLookupStr(NULL, recipe, "PATTERN.CELL.MEAN"));
+    }
+
 
     // Remnance options
