Index: branches/pap/ppMerge/src/ppMergeLoop.c
===================================================================
--- branches/pap/ppMerge/src/ppMergeLoop.c	(revision 23948)
+++ branches/pap/ppMerge/src/ppMergeLoop.c	(revision 25027)
@@ -36,4 +36,5 @@
     bool mdok;                          ///< Status of MD lookup
     bool haveMasks = psMetadataLookupBool(&mdok, arguments, "INPUTS.MASKS"); // Do we have masks?
+    bool useMasks = psMetadataLookupBool(&mdok, arguments, "INPUTS.MASKS.USE"); // Do we have masks?
     bool haveVariances = psMetadataLookupBool(&mdok, arguments, "INPUTS.VARIANCES"); // Do we have variances?
 
@@ -64,4 +65,6 @@
     int fringeSmoothX = psMetadataLookupS32(NULL, arguments, "FRINGE.XSMOOTH"); // Smoothing regions in x
     int fringeSmoothY = psMetadataLookupS32(NULL, arguments, "FRINGE.YSMOOTH"); // Smoothing regions in y
+    bool fringeSmooth = psMetadataLookupBool(NULL, arguments, "FRINGE.SMOOTH"); // Smooth the output image?
+    float fringeSmoothSigma = psMetadataLookupF32(NULL, arguments, "FRINGE.SMOOTH.SIGMA"); // Smooth the output image?
 
     // set the mask and mark bit values based on the named masks
@@ -73,5 +76,5 @@
 
     pmCombineParams *combination = pmCombineParamsAlloc(combineStat); ///< Combination parameters
-    combination->maskVal = maskVal;
+    combination->maskVal = useMasks ? maskVal : 0;
     combination->blank = pmConfigMaskGet("BLANK", config);
     combination->nKeep = nKeep;
@@ -93,11 +96,14 @@
     psVector *scales = NULL, *zeros = NULL; ///< Scale and zeroes for combination
     psArray *shutters = NULL;           ///< Shutter correction data
+    psImage *zeroSet = NULL;
     switch (type) {
       case PPMERGE_TYPE_FRINGE:
-        zeros = psMetadataLookupPtr(NULL, arguments, "ZEROS");
-        if (!zeros) {
+        zeroSet = psMetadataLookupPtr(NULL, arguments, "ZEROS");
+        if (!zeroSet) {
             psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find ZEROS");
             goto ERROR;
         }
+	// the zeros vector is passed to pmReadoutCombine for each set of inputs per cell
+	zeros = psVectorAlloc(zeroSet->numRows, PS_TYPE_F32);
         // Flow through
       case PPMERGE_TYPE_FLAT:
@@ -139,4 +145,5 @@
     pmFPA *outFPA = output->fpa;        ///< Output FPA
     pmHDU *lastHDU = NULL;              // Last HDU that was updated
+
     int cellNum = 0;                    ///< Index of cell
     if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
@@ -145,9 +152,19 @@
     pmChip *outChip;                    ///< Chip of interest
     while ((outChip = pmFPAviewNextChip(view, outFPA, 1))) {
+        if (!outChip->process || !outChip->file_exists) {
+            continue;
+        }
         if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
             goto ERROR;
         }
         pmCell *outCell;                ///< Cell of interest
+
+	// XXX TEST : force a single loop
+        // outCell = pmFPAviewNextCell(view, outFPA, 1); {
+
         while ((outCell = pmFPAviewNextCell(view, outFPA, 1))) {
+	    if (!outCell->process || !outCell->file_exists) {
+		continue;
+	    }
             if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
                 goto ERROR;
@@ -189,4 +206,16 @@
             }
 
+	    if (zeroSet) {
+	      for (int i = 0; i < zeroSet->numRows; i++) {
+		zeros->data.F32[i] = zeroSet->data.F32[i][cellNum];
+	      }
+	    }
+
+	    int rows = psMetadataLookupS32(NULL, config->arguments, "ROWS"); // Number of rows to read per chunk
+	    if (!rows && nThreads) {
+	      psError(PS_ERR_UNKNOWN, false, "Invalid combination of threads > 0 and ROWS == 0 (ie, multiple threads working on the full array...)");
+	      goto ERROR;
+	    }
+
             ppMergeFileGroup *fileGroup = NULL;
             psArray *fileGroups = psArrayAlloc(nThreads + 1);
@@ -198,5 +227,7 @@
                     pmFPAfile *input = pmFPAfileSelectSingle(config->files, "PPMERGE.INPUT", j);
                     pmCell *inCell = pmFPAviewThisCell(view, input->fpa); ///< Input cell
-                    readouts->data[j] = pmReadoutAlloc(inCell);
+		    pmReadout *readout = pmReadoutAlloc(inCell);
+		    readout->process = true; // until proven otherwise, attempt to process this readout
+                    readouts->data[j] = readout;
                 }
 
@@ -232,5 +263,5 @@
                 psAssert (fileGroups->n > 0, "no valid file groups defined");
                 fileGroup = fileGroups->data[0];
-                if (!pmShutterCorrectionGeneratePrepare(outRO, pattern, fileGroup->readouts, maskVal)) {
+                if (!pmShutterCorrectionGeneratePrepare(outRO, pattern, fileGroup->readouts, combination->maskVal)) {
                     goto ERROR;
                 }
@@ -330,4 +361,5 @@
 
             psFree(fileGroups);
+	    psFree(zeros);
 
             // XXX eventually need to keep both the shutter and the pattern, as we do with dark
@@ -392,6 +424,15 @@
             // Put the new readout into the cell after the existing readouts.
             if (type == PPMERGE_TYPE_FRINGE && outRO) {
-                pmFringeRegions *regions = pmFringeRegionsAlloc(fringeNum, fringeSize, fringeSize,
-                                                                fringeSmoothX, fringeSmoothY);
+		if (fringeSmooth) {
+		    if (outRO->mask) {
+			psImage *smoothed = psImageSmoothMask (NULL, outRO->image, outRO->mask, maskVal, fringeSmoothSigma, 3, 0.2);
+			psFree (outRO->image);
+			outRO->image = smoothed;
+		    } else {
+			psImageSmooth (outRO->image, fringeSmoothSigma, 3);
+		    }
+		}
+
+                pmFringeRegions *regions = pmFringeRegionsAlloc(fringeNum, fringeSize, fringeSize, fringeSmoothX, fringeSmoothY);
                 pmFringeStats *fringe = pmFringeStatsMeasure(regions, outRO, maskVal);
                 psFree(regions);
@@ -405,5 +446,9 @@
                 fringes->data[0] = fringe;
 
-                pmFringesFormat(outCell, NULL, fringes);
+                // XXX replaced this : pmFringesFormat(outCell, NULL, fringes);
+		if (!psMetadataAdd(outCell->analysis, PS_LIST_TAIL, "FRINGE.MEASUREMENTS", PS_DATA_ARRAY, "Fringes", fringes)) {
+		    psError(PS_ERR_UNKNOWN, false, "Unable to add fringe to analysis metadata\n");
+		    goto ERROR;
+		}
                 psFree(fringes);        // Drop reference
             }
@@ -426,4 +471,15 @@
                 char *cteMaskName = psMetadataLookupStr (&mdok, config->arguments, "MASK.SET.VALUE");
                 psImageMaskType cteMaskValue = pmConfigMaskGet(cteMaskName, config);
+
+		if (0) {
+		  psFits *fits = NULL;
+		  fits = psFitsOpen ("combine.fits", "w");
+		  psFitsWriteImage (fits, NULL, outRO->image, 0, NULL);
+		  psFitsClose (fits);
+
+		  fits = psFitsOpen ("inmask.fits", "w");
+		  psFitsWriteImage (fits, NULL, outRO->mask, 0, NULL);
+		  psFitsClose (fits);
+		}
 
                 psF32 **outputImage = outRO->image->data.F32;
@@ -436,4 +492,12 @@
                     }
                 }
+
+		if (0) {
+		  psFits *fits = NULL;
+		  fits = psFitsOpen ("otmask.fits", "w");
+		  psFitsWriteImage (fits, NULL, outRO->mask, 0, NULL);
+		  psFitsClose (fits);
+		}
+
             }
 
