Index: trunk/ippconfig/gpc1/ppImage.config
===================================================================
--- trunk/ippconfig/gpc1/ppImage.config	(revision 33589)
+++ trunk/ippconfig/gpc1/ppImage.config	(revision 33590)
@@ -227,5 +227,6 @@
   MASK.BURNTOOL      BOOL    TRUE            # Mask potential burntool trails
   PATTERN.ROW        BOOL    TRUE            # Row pattern correction
-  PATTERN.CELL	     BOOL    TRUE	     # Cell pattern correction
+  PATTERN.CELL	     BOOL    FALSE	     # Cell pattern correction
+  PATTERN.CONTINUITY BOOL    TRUE
   FRINGE             BOOL    TRUE            # Fringe subtraction
   BIN1.FITS          BOOL    TRUE            # Save 1st binned chip image?
@@ -1030,4 +1031,40 @@
     END
   END   
+END
+
+PPIMAGE_NOISEMAP     METADATA
+  BASE.FITS        BOOL    TRUE            # Save base image?
+  BASE.MASK.FITS   BOOL    TRUE            # Save base detrended image?
+  BASE.VARIANCE.FITS BOOL  TRUE            # Save base detrended image?
+  CHIP.FITS        BOOL    FALSE           # Save chip-mosaic-ed image? 
+  CHIP.MASK.FITS   BOOL    FALSE           # Save chip-mosaic-ed image? 
+  CHIP.VARIANCE.FITS BOOL  FALSE           # Save chip-mosaic-ed image? 
+  OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
+  BIAS             BOOL    FALSE            # Bias subtraction
+  DARK             BOOL    FALSE            # Dark subtraction
+  SHUTTER          BOOL    FALSE           # Shutter correction
+  FLAT             BOOL    FALSE           # Flat-field normalisation
+  MASK             BOOL    FALSE           # Mask bad pixels
+  MASK.BUILD       BOOL    FALSE 	   # Build internal mask?
+  FRINGE           BOOL    FALSE           # Fringe subtraction
+  PHOTOM           BOOL    FALSE           # Source identification and photometry
+  ASTROM.CHIP      BOOL    FALSE           # Astrometry per chip?
+  ASTROM.MOSAIC    BOOL    FALSE           # Astrometry for mosaic?
+  BIN1.FITS        BOOL    TRUE            # Save 1st binned chip image?
+  BIN2.FITS        BOOL    TRUE            # Save 2nd binned chip image?
+  CHECK.CTE        BOOL    FALSE            # measure CTE errors?
+  CHECK.NOISE      BOOL    TRUE            # measure cell level noise.
+
+#   DETREND.CONSTRAINTS  METADATA
+#     DARK METADATA
+#       DETTYPE STR DARK_PREMASK
+#       EXPTIME STR FPA.EXPOSURE
+#     END
+#     FLAT METADATA
+#       DETTYPE STR FLAT_PREMASK
+#       FILTER  STR FPA.FILTERID
+#     END
+#   END   
 END
 
Index: trunk/ippconfig/recipes/ppImage.config
===================================================================
--- trunk/ippconfig/recipes/ppImage.config	(revision 33589)
+++ trunk/ippconfig/recipes/ppImage.config	(revision 33590)
@@ -36,4 +36,5 @@
 BACKGROUND         BOOL    FALSE           # Subtract model background?
 CHECK.CTE          BOOL    FALSE           # measure CTE errors?
+CHECK.NOISE        BOOL    FALSE         
 USE.DEBURNED.IMAGE BOOL    FALSE           # use burntool-repaired image?
 USE.BEST.BURNTOOL  BOOL    FALSE           # require the best burntooled data
@@ -110,5 +111,5 @@
 PATTERN.ROW.MEAN       STR     SAMPLE_MEAN     # Statistic for mean for row pattern
 PATTERN.ROW.STDEV      STR     SAMPLE_STDEV    # Statistic for standard deviation for row pattern
-PATTERN.CELL.BG	       STR     ROBUST_MEDIAN   # Statistic for background for cell pattern
+PATTERN.CELL.BG	       STR     FITTED_MEAN     # Statistic for background for cell pattern
 PATTERN.CELL.MEAN      STR     SAMPLE_MEDIAN   # Statistic for mean for cell pattern
 
@@ -130,4 +131,7 @@
 CTE.XBIN                S32     20
 CTE.YBIN                S32     20
+
+NOISE.XBIN		S32     20
+NOISE.YBIN		S32	20
 
 PPIMAGE.JPEG1  METADATA
@@ -1871,4 +1875,40 @@
     END
   END   
+END
+
+PPIMAGE_NOISEMAP     METADATA
+  BASE.FITS        BOOL    TRUE            # Save base image?
+  BASE.MASK.FITS   BOOL    TRUE            # Save base detrended image?
+  BASE.VARIANCE.FITS BOOL  TRUE            # Save base detrended image?
+  CHIP.FITS        BOOL    FALSE           # Save chip-mosaic-ed image? 
+  CHIP.MASK.FITS   BOOL    FALSE           # Save chip-mosaic-ed image? 
+  CHIP.VARIANCE.FITS BOOL  FALSE           # Save chip-mosaic-ed image? 
+  OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
+  BIAS             BOOL    TRUE            # Bias subtraction
+  DARK             BOOL    FALSE            # Dark subtraction
+  SHUTTER          BOOL    FALSE           # Shutter correction
+  FLAT             BOOL    FALSE           # Flat-field normalisation
+  MASK             BOOL    FALSE           # Mask bad pixels
+  MASK.BUILD       BOOL    FALSE 	   # Build internal mask?
+  FRINGE           BOOL    FALSE           # Fringe subtraction
+  PHOTOM           BOOL    FALSE           # Source identification and photometry
+  ASTROM.CHIP      BOOL    FALSE           # Astrometry per chip?
+  ASTROM.MOSAIC    BOOL    FALSE           # Astrometry for mosaic?
+  BIN1.FITS        BOOL    TRUE            # Save 1st binned chip image?
+  BIN2.FITS        BOOL    TRUE            # Save 2nd binned chip image?
+  CHECK.CTE        BOOL    FALSE            # measure CTE errors?
+  CHECK.NOISE      BOOL    TRUE            # measure cell level noise.
+
+#   DETREND.CONSTRAINTS  METADATA
+#     DARK METADATA
+#       DETTYPE STR DARK_PREMASK
+#       EXPTIME STR FPA.EXPOSURE
+#     END
+#     FLAT METADATA
+#       DETTYPE STR FLAT_PREMASK
+#       FILTER  STR FPA.FILTERID
+#     END
+#   END   
 END
 
Index: trunk/ppImage/src/Makefile.am
===================================================================
--- trunk/ppImage/src/Makefile.am	(revision 33589)
+++ trunk/ppImage/src/Makefile.am	(revision 33590)
@@ -59,4 +59,5 @@
 	ppImageParityFlip.c \
 	ppImageCheckCTE.c \
+	ppImageCheckNoise.c \
 	ppImageFileCheck.c \
 	ppImageVersion.c \
Index: trunk/ppImage/src/ppImage.h
===================================================================
--- trunk/ppImage/src/ppImage.h	(revision 33589)
+++ trunk/ppImage/src/ppImage.h	(revision 33590)
@@ -48,4 +48,5 @@
     bool doStats;                       // call ppStats on the image
     bool checkCTE;                      // measure pixel-based variance
+    bool checkNoise;                    // measure cell-level variance
     bool applyParity;                   // Apply Cell parities
 
@@ -172,4 +173,6 @@
 bool ppImageCheckCTE(pmConfig *config, ppImageOptions *options, pmFPAview *view);
 
+bool ppImageCheckNoise(pmConfig *config, ppImageOptions *options, pmFPAview *view);
+
 bool ppImageBurntoolMask(pmConfig *config, ppImageOptions *options, pmFPAview *view, pmReadout *mask);
 
Index: trunk/ppImage/src/ppImageCheckNoise.c
===================================================================
--- trunk/ppImage/src/ppImageCheckNoise.c	(revision 33590)
+++ trunk/ppImage/src/ppImageCheckNoise.c	(revision 33590)
@@ -0,0 +1,109 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ppImage.h"
+
+// XXX I originally coded this to create a new pmFPAfile, but in retrospect it makes more sense
+// to treat this function as an operation on the input image
+
+// XXX make the choice of stats optional
+bool ppImageCheckNoise(pmConfig *config, ppImageOptions *options, pmFPAview *view)
+{
+    bool status;
+
+    // this step is complete optional.
+    if (!options->checkNoise) {
+        return true;
+    }
+
+    // add recipe options supplied on command line
+    psMetadata *recipe  = psMetadataLookupPtr(&status, config->recipes, RECIPE_NAME);
+
+    // find the currently selected readout
+    pmReadout *inReadout = pmFPAfileThisReadout(config->files, view, "PPIMAGE.INPUT");
+
+    psImage *image    = inReadout->image;
+    psImage *mask     = inReadout->mask;
+    // psImage *variance = inReadout->variance;
+
+    // I have the fine image size, I know the binning factor, determine the ruff image size
+    psImageBinning *binning = psImageBinningAlloc();
+    binning->nXfine = image->numCols;
+    binning->nYfine = image->numRows;
+    binning->nXbin  = psMetadataLookupS32 (&status, recipe, "NOISE.XBIN");
+    binning->nYbin  = psMetadataLookupS32 (&status, recipe, "NOISE.YBIN");
+
+    psImageBinningSetRuffSize(binning, PS_IMAGE_BINNING_CENTER);
+    psImageBinningSetSkip(binning, image);
+
+    psStats *stats = psStatsAlloc (PS_STAT_ROBUST_MEDIAN);
+    psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS);
+    psImageBackground (stats, NULL, image, mask, 0xffff, rng);
+    //    float cellMedian = stats->robustMedian;
+    psFree (stats);
+
+    // stats = psStatsAlloc (PS_STAT_SAMPLE_STDEV);
+    // psStats *statsDefaults = psStatsAlloc (PS_STAT_SAMPLE_STDEV);
+
+    stats = psStatsAlloc (PS_STAT_ROBUST_STDEV);
+    psStats *statsDefaults = psStatsAlloc (PS_STAT_ROBUST_STDEV);
+
+    // measure median and variance for subimages
+    psRegion ruffRegion = {0,0,0,0};
+    psRegion fineRegion = {0,0,0,0};
+    for (int iy = 0; iy < binning->nYruff; iy++) {
+        for (int ix = 0; ix < binning->nXruff; ix++) {
+
+            // convert the ruff grid cell to the equivalent fine grid cell
+            ruffRegion = psRegionSet (ix, ix + 1, iy, iy + 1);
+            fineRegion = psImageBinningSetFineRegion (binning, ruffRegion);
+            fineRegion = psRegionForImage (image, fineRegion);
+            if (fineRegion.x0 >= image->numCols) continue;
+	    if (fineRegion.y0 >= image->numRows) continue;
+
+            psImage *subset  = psImageSubset (image, fineRegion);
+            if (!subset->numCols || !subset->numRows) {
+                psFree (subset);
+                continue;
+            }
+            psImage *submask = NULL;
+            if (mask) {
+                submask = psImageSubset (mask, fineRegion);
+            }
+
+            // reset the default values
+            statsDefaults->tmpData = stats->tmpData; // XXX this is fairly hackish: tmpData is internal storage for stats; the assign drops the reference...
+            *stats = *statsDefaults;
+            statsDefaults->tmpData = NULL;
+
+            psImageStats (stats, subset, submask, 0xffff);
+
+	    // XXX need to apply the gain as well
+	    float normVariance = stats->robustStdev;
+	    // float normVariance = PS_SQR(stats->sampleStdev) / cellMedian;
+	    // if (!isfinite(normVariance)) fprintf (stderr, "** normVariance is nan **\n");
+
+	    // apply resulting value to the input pixels
+	    for (int jy = fineRegion.y0; jy < fineRegion.y1; jy++) {
+	      if (jy < 0) continue;
+	      if (jy >= image->numRows) continue;
+	      for (int jx = fineRegion.x0; jx < fineRegion.x1; jx++) {
+		if (jx < 0) continue;
+		if (jx >= image->numCols) continue;
+		image->data.F32[jy][jx] = normVariance;
+	      }
+	    }
+
+            psFree (subset);
+            psFree (submask);
+        }
+    }
+
+    psFree (rng);
+    psFree (binning);
+    psFree (stats);
+    psFree (statsDefaults);
+
+    return true;
+}
Index: trunk/ppImage/src/ppImageDetrendReadout.c
===================================================================
--- trunk/ppImage/src/ppImageDetrendReadout.c	(revision 33589)
+++ trunk/ppImage/src/ppImageDetrendReadout.c	(revision 33590)
@@ -110,4 +110,6 @@
             // offset information, we are not really getting exactly the right mapping from the
             // original file.
+	    // CZW 2012-03-21: I do not believe this is true anymore.  In any case, this seems to be what
+	    //                 ppImageReplaceBackground does to do sky subtraction.
             psImageBinning *binning = psImageBinningAlloc();
             binning->nXruff = noiseMap->image->numCols;
@@ -119,4 +121,39 @@
             psImageUnbin (noiseImage, noiseMap->image, binning);
             psFree (binning);
+	    // Stolen from pmSkySubtract.c
+	    // CZW: Unneeded, as psImageUnbin does the bilinear interpolation?  It still looks blocky. 
+/* 	    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, RECIPE_NAME); // Recipe */
+/* 	    psAssert(recipe, "Should be there!"); */
+
+/* 	    psS32 xBinFactor = psMetadataLookupS32(NULL,recipe,"NOISE.XBIN"); */
+/* 	    psS32 yBinFactor = psMetadataLookupS32(NULL,recipe,"NOISE.YBIN"); */
+/* 	    psImageInterpolateOptions *interp = psImageInterpolateOptionsAlloc(PS_INTERPOLATE_BILINEAR, */
+/* 									       noiseMap->image, */
+/* 									       NULL, NULL, */
+/* 									       0, 0.0, 0.0, 0, 0, 0.0); */
+/* 	    for (psS32 row = 0; row < input->image->numRows; row++) { */
+/* 	      for (psS32 col = 0; col < input->image->numCols; col++) { */
+/* 		// We calculate the F32 value of the pixel coordinates in the */
+/* 		// binned image and then use a pixel interpolation routine to */
+/* 		// determine the value of the pixel at that location. */
+/* 		psF32 binRowF64 = ((psF32) row) / ((psF32) yBinFactor); */
+/* 		psF32 binColF64 = ((psF32) col) / ((psF32) xBinFactor); */
+/* 		// We add 0.5 to the pixel locations since the pixel */
+/* 		// interpolation routine defines the location of pixel */
+/* 		// (i, j) as (i+0.5, j+0.5). */
+/* 		binRowF64+= 0.5; */
+/* 		binColF64+= 0.5; */
+
+/* 		double binPixel; */
+/* 		if (!psImagePixelInterpolate(&binPixel, NULL, NULL, binColF64, binRowF64, interp)) { */
+/* 		  psError(PS_ERR_UNKNOWN, false, "Unable to interpolate image."); */
+/* 		  psFree(interp); */
+/* 		  psFree(noiseImage); */
+/* 		  return NULL; */
+/* 		} */
+/* 		noiseImage->data.F32[row][col] = binPixel; */
+/* 	      } */
+/* 	    } */
+/* 	    psFree(interp); */
         }
 
Index: trunk/ppImage/src/ppImageLoop.c
===================================================================
--- trunk/ppImage/src/ppImageLoop.c	(revision 33589)
+++ trunk/ppImage/src/ppImageLoop.c	(revision 33590)
@@ -126,4 +126,8 @@
                 }
 
+		if (!ppImageCheckNoise (config, options, view)) {
+		    ESCAPE("Unable to generate noisemap");
+		}
+		
 		// optionally degrade a MD image to 3pi exposure times
 		if (!ppImageAddNoise(config, options, view, input->fpa)){
Index: trunk/ppImage/src/ppImageOptions.c
===================================================================
--- trunk/ppImage/src/ppImageOptions.c	(revision 33589)
+++ trunk/ppImage/src/ppImageOptions.c	(revision 33590)
@@ -41,4 +41,5 @@
     options->doStats         = false;   // Measure and save image statistics
     options->checkCTE        = false;   // Measure pixel-based variance
+    options->checkNoise      = false;   // Measure cell-level variances.
     options->applyParity     = false;   // Apply Cell parities
     options->doMaskStats     = false;   // Calculate mask fractions
@@ -319,4 +320,5 @@
 
     options->checkCTE       = psMetadataLookupBool(NULL, recipe, "CHECK.CTE");
+    options->checkNoise     = psMetadataLookupBool(NULL, recipe, "CHECK.NOISE");
 
     /* doMaskBuild : there are some cases where we require a mask, so we force doMaskBuild to be set even if the user specified 'FALSE'
