Index: trunk/ppImage/src/ppImage.h
===================================================================
--- trunk/ppImage/src/ppImage.h	(revision 42781)
+++ trunk/ppImage/src/ppImage.h	(revision 42890)
@@ -100,4 +100,7 @@
     // options for the analysis
     pmOverscanOptions *overscan;        // Overscan options
+    pmOverscanStatOptions *primary;        // Overscan primary options
+    pmOverscanStatOptions *secondary;      // Overscan secondary options
+    
     int burntoolTrails;
     // binning parameters
@@ -188,4 +191,5 @@
 
 bool ppImageDetrendFree(pmConfig *config, pmFPAview *view);
+bool ppImageDoPatternForView(bool *doit, const pmConfig *config, const pmChip *chip, const pmFPAview *view, const char *recipeName, const char *recipeValue);
 bool ppImageFringeFree(pmConfig *config, pmFPAview *view);
 
Index: trunk/ppImage/src/ppImageDetrendPattern.c
===================================================================
--- trunk/ppImage/src/ppImageDetrendPattern.c	(revision 42781)
+++ trunk/ppImage/src/ppImageDetrendPattern.c	(revision 42890)
@@ -11,5 +11,5 @@
     }
 
-static bool doPatternForView (bool *doit, const pmConfig *config, const pmChip *chip, const pmFPAview *view, const char *recipename, const char *recipevalue);
+bool ppImageDoPatternForView(bool *doit, const pmConfig *config, const pmChip *chip, const pmFPAview *view, const char *recipename, const char *recipevalue);
 
 bool ppImageDetrendPatternRowApply(pmConfig *config, pmChip *chip, const pmFPAview *inputView, ppImageOptions *options);
@@ -131,5 +131,5 @@
 
 	bool doPattern = false;
-	if (!doPatternForView(&doPattern, config, chip, view, RECIPE_NAME, "PATTERN.ROW.SUBSET")) {
+	if (!ppImageDoPatternForView(&doPattern, config, chip, view, RECIPE_NAME, "PATTERN.ROW.SUBSET")) {
 	    ESCAPE(false, "Unable to determine whether row pattern matching should be applied.");
 	}
@@ -213,5 +213,5 @@
 
 	bool doPattern = false;
-	if (!doPatternForView(&doPattern, config, chip, view, RECIPE_NAME, "PATTERN.CONTINUITY.SUBSET")) {
+	if (!ppImageDoPatternForView(&doPattern, config, chip, view, RECIPE_NAME, "PATTERN.CONTINUITY.SUBSET")) {
 	    ESCAPE(false, "Unable to determine whether row pattern matching should be applied.");
 	}
@@ -271,5 +271,5 @@
 
 	bool doPattern = false;
-	if (!doPatternForView(&doPattern, config, chip, view, RECIPE_NAME, "PATTERN.CELL.SUBSET")) {
+	if (!ppImageDoPatternForView(&doPattern, config, chip, view, RECIPE_NAME, "PATTERN.CELL.SUBSET")) {
 	    ESCAPE(false, "Unable to determine whether row pattern matching should be applied.");
 	}
@@ -449,5 +449,5 @@
 }
 
-static bool doPatternForView (bool *doit, const pmConfig *config, const pmChip *chip, const pmFPAview *view, const char *recipeName, const char *recipeValue) {
+bool ppImageDoPatternForView (bool *doit, const pmConfig *config, const pmChip *chip, const pmFPAview *view, const char *recipeName, const char *recipeValue) {
 
     *doit = false;
Index: trunk/ppImage/src/ppImageDetrendReadout.c
===================================================================
--- trunk/ppImage/src/ppImageDetrendReadout.c	(revision 42781)
+++ trunk/ppImage/src/ppImageDetrendReadout.c	(revision 42890)
@@ -4,4 +4,11 @@
 
 #include "ppImage.h"
+
+#define ESCAPE(STATUS, ...)                           \
+    {                                                 \
+        psError(PS_ERR_UNKNOWN, STATUS, __VA_ARGS__); \
+        psFree(view);                                 \
+        return false;                                 \
+    }
 
 bool ppImageDetrendReadout(pmConfig *config, ppImageOptions *options, pmFPAview *view)
@@ -117,10 +124,25 @@
     // Subtract the overscan
     if (options->doOverscan) {
-      if (!pmOverscanSubtract (input, options->overscan)) {
-	psError(PS_ERR_UNKNOWN, false, "Unable to subtract overscan.");
-	psFree(detview);
-	return false;
-      }
-      // psLogMsg ("ppImage", 6, "subtract overscan: %f sec\n", psTimerMark ("detrend.readout"));
+        bool doTwoDOverscan = false;
+        if (options->overscan->TwoD) {
+            pmChip *chip = pmFPAfileThisChip(config->files, view, "PPIMAGE.INPUT");
+            if (!ppImageDoPatternForView(&doTwoDOverscan, config, chip, view, RECIPE_NAME, "OVERSCAN.2D.SUBSET"))
+            {
+                ESCAPE(false, "Unable to determine whether 2D Overscan subtraction should be applied.");
+            }
+            // set doTwoDOverscan to False if the cell background is larger than 500 ADU or smaller than zero (peculiar)
+            if (doTwoDOverscan) {
+                float backest = psMetadataLookupF32(NULL, input->parent->concepts, "CELL.BACKEST");
+                if (!isfinite(backest) || backest > 500 || backest < 0) {
+                    doTwoDOverscan = false;
+                }
+            }
+        }
+        if (!pmOverscanSubtract(input, options->overscan, doTwoDOverscan)) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to subtract overscan.");
+            psFree(detview);
+            return false;
+        }
+        // psLogMsg ("ppImage", 6, "subtract overscan: %f sec\n", psTimerMark ("detrend.readout"));
     }
 
Index: trunk/ppImage/src/ppImageOptions.c
===================================================================
--- trunk/ppImage/src/ppImageOptions.c	(revision 42781)
+++ trunk/ppImage/src/ppImageOptions.c	(revision 42890)
@@ -187,21 +187,34 @@
     // XXX EAM : we should abort on invalid options. default options?
     if (psMetadataLookupBool(NULL, recipe, "OVERSCAN")) {
+	bool mdok;
+
         options->doOverscan = true;
 
-        // Do the overscan as a single value?
-        bool overscanSingle = psMetadataLookupBool(NULL, recipe, "OVERSCAN.SINGLE");
+        // Fill in the options
+        options->overscan = pmOverscanOptionsAlloc();
+
+	// these options apply to the overscan regardless of layout
+        options->overscan->single   = psMetadataLookupBool(NULL, recipe, "OVERSCAN.SINGLE");
+        options->overscan->constant = psMetadataLookupBool(NULL, recipe, "OVERSCAN.CONSTANT");
+        options->overscan->value    = psMetadataLookupF32(NULL, recipe, "OVERSCAN.VALUE");
+        options->overscan->minValid = psMetadataLookupF32(&mdok, recipe, "OVERSCAN.MIN.VALID");
+	if (!mdok) { options->overscan->minValid = 0.0; }
+        options->overscan->maxValid = psMetadataLookupF32(&mdok, recipe, "OVERSCAN.MAX.VALID");
+	if (!mdok) { options->overscan->maxValid = (float) 0x10000; }
+        options->overscan->maskVal  = 0x0001;
+
+        // statistics for the primary region
+        options->overscan->primary = pmOverscanStatOptionsAlloc();
 
         // How do we fit it?
-        pmFit overscanFit = PM_FIT_NONE; // Fit type for overscan
-        int overscanOrder = 0;          // Order for overscan fit
         psString fit = psMetadataLookupStr(NULL, recipe, "OVERSCAN.FIT");
         if (! strcasecmp(fit, "POLYNOMIAL")) {
-            overscanFit = PM_FIT_POLY_ORD;
-            overscanOrder = psMetadataLookupS32(NULL, recipe, "OVERSCAN.ORDER");
+	    options->overscan->primary->fitType = PM_FIT_POLY_ORD;
+            options->overscan->primary->order   = psMetadataLookupS32(NULL, recipe, "OVERSCAN.ORDER");
         } else if (! strcasecmp(fit, "CHEBYSHEV")) {
-            overscanFit = PM_FIT_POLY_CHEBY;
-            overscanOrder = psMetadataLookupS32(NULL, recipe, "OVERSCAN.ORDER");
+	    options->overscan->primary->fitType = PM_FIT_POLY_CHEBY;
+            options->overscan->primary->order   = psMetadataLookupS32(NULL, recipe, "OVERSCAN.ORDER");
         } else if (! strcasecmp(fit, "SPLINE")) {
-            overscanFit = PM_FIT_SPLINE;
+	    options->overscan->primary->fitType = PM_FIT_SPLINE;
         } else if (strcasecmp(fit, "NONE")) {
             psLogMsg(__func__, PS_LOG_WARN,
@@ -213,37 +226,63 @@
         // What method do we use to measure the overscan statistics?
         // XXX allow user to specify psStats types by name
-        psStats *overscanStats = NULL;  // Statistics for overscan
         psString stat = psMetadataLookupStr(NULL, recipe, "OVERSCAN.STAT");
         if (! strcasecmp(stat, "MEAN")) {
-            // overscanStats = psStatsAlloc(PS_STAT_SAMPLE_MEAN);
-            overscanStats = psStatsAlloc(PS_STAT_SAMPLE_MEAN);
+            options->overscan->primary->stat = psStatsAlloc(PS_STAT_SAMPLE_MEAN);
         } else if (! strcasecmp(stat, "MEDIAN")) {
-            overscanStats = psStatsAlloc(PS_STAT_SAMPLE_MEDIAN);
+            options->overscan->primary->stat = psStatsAlloc(PS_STAT_SAMPLE_MEDIAN);
         } else {
-            psErrorStackPrint(stderr, "OVERSCAN.STAT (%s) in recipe %s is not one of MEAN or MEDIAN",
-                              stat, RECIPE_NAME);
+            psErrorStackPrint(stderr, "OVERSCAN.STAT (%s) in recipe %s is not one of MEAN or MEDIAN", stat, RECIPE_NAME);
             exit(EXIT_FAILURE);
         }
 
-	bool mdok;
-        int boxcar = psMetadataLookupS32(NULL, recipe, "OVERSCAN.BOXCAR");
-        float gauss = psMetadataLookupF32(NULL, recipe, "OVERSCAN.GAUSS");
-        float minValid = psMetadataLookupF32(&mdok, recipe, "OVERSCAN.MIN.VALID");
-	if (!mdok) { minValid = 0.0; }
-
-        float maxValid = psMetadataLookupF32(&mdok, recipe, "OVERSCAN.MAX.VALID");
-	if (!mdok) { maxValid = (float) 0x10000; }
-
-        // Fill in the options
-        options->overscan = pmOverscanOptionsAlloc(overscanSingle, overscanFit, overscanOrder,
-                                                   overscanStats, boxcar, gauss);
-
-        options->overscan->constant = psMetadataLookupBool(NULL, recipe, "OVERSCAN.CONSTANT");
-        options->overscan->value = psMetadataLookupF32(NULL, recipe, "OVERSCAN.VALUE");
-        options->overscan->minValid = minValid;
-        options->overscan->maxValid = maxValid;
-        options->overscan->maskVal  = 0x0001;
-
-        psFree(overscanStats);
+        options->overscan->primary->boxcar = psMetadataLookupS32(NULL, recipe, "OVERSCAN.BOXCAR");
+        options->overscan->primary->gauss  = psMetadataLookupF32(NULL, recipe, "OVERSCAN.GAUSS");
+
+        // Do the overscan as a single value?
+        options->overscan->TwoD = psMetadataLookupBool(NULL, recipe, "OVERSCAN.2D");
+	if (options->overscan->TwoD) {
+
+	    // statistics for the secondary region
+	    options->overscan->secondary = pmOverscanStatOptionsAlloc();
+
+	    // How do we fit it?
+	    psString fit = psMetadataLookupStr(NULL, recipe, "OVERSCAN.2D.FIT");
+	    if (! strcasecmp(fit, "POLYNOMIAL")) {
+		options->overscan->secondary->fitType = PM_FIT_POLY_ORD;
+		options->overscan->secondary->order   = psMetadataLookupS32(NULL, recipe, "OVERSCAN.2D.ORDER");
+	    } else if (! strcasecmp(fit, "CHEBYSHEV")) {
+		options->overscan->secondary->fitType = PM_FIT_POLY_CHEBY;
+		options->overscan->secondary->order   = psMetadataLookupS32(NULL, recipe, "OVERSCAN.2D.ORDER");
+	    } else if (! strcasecmp(fit, "SPLINE")) {
+		options->overscan->secondary->fitType = PM_FIT_SPLINE;
+	    } else if (strcasecmp(fit, "NONE")) {
+		psLogMsg(__func__, PS_LOG_WARN,
+			 "OVERSCAN.2D.FIT (%s) in recipe %s is not one of NONE, POLYNOMIAL, or SPLINE",
+			 fit, RECIPE_NAME);
+		exit(EXIT_FAILURE);
+	    }
+
+	    // What method do we use to measure the overscan statistics?
+	    // XXX allow user to specify psStats types by name
+	    psString stat = psMetadataLookupStr(NULL, recipe, "OVERSCAN.2D.STAT");
+	    if (! strcasecmp(stat, "MEAN")) {
+		options->overscan->secondary->stat = psStatsAlloc(PS_STAT_SAMPLE_MEAN);
+	    } else if (! strcasecmp(stat, "MEDIAN")) {
+		options->overscan->secondary->stat = psStatsAlloc(PS_STAT_SAMPLE_MEDIAN);
+	    } else {
+		psErrorStackPrint(stderr, "OVERSCAN.2D.STAT (%s) in recipe %s is not one of MEAN or MEDIAN", stat, RECIPE_NAME);
+		exit(EXIT_FAILURE);
+	    }
+
+            //Read the 2D overscan BIASSEC regions
+	    psString biassecslow = psMetadataLookupStr(NULL, recipe, "OVERSCAN.2D.BIASSECSLOW");
+	    options->overscan->secondary->biassecslow = psRegionFromString(biassecslow);
+	    
+	    psString biassecfast = psMetadataLookupStr(NULL, recipe, "OVERSCAN.2D.BIASSECFAST");
+	    options->overscan->secondary->biassecfast = psRegionFromString(biassecfast);
+	    
+	    options->overscan->secondary->boxcar = psMetadataLookupS32(NULL, recipe, "OVERSCAN.2D.BOXCAR");
+	    options->overscan->secondary->gauss  = psMetadataLookupF32(NULL, recipe, "OVERSCAN.2D.GAUSS");
+	}
     }
 
