Index: trunk/psphot/src/psphotAddNoise.c
===================================================================
--- trunk/psphot/src/psphotAddNoise.c	(revision 20451)
+++ trunk/psphot/src/psphotAddNoise.c	(revision 20453)
@@ -20,5 +20,5 @@
     PS_ASSERT (readout->parent->concepts, false);
 
-    psTimerStart ("psphot");
+    psTimerStart ("psphot.noise");
 
     // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
@@ -93,7 +93,7 @@
     }
     if (add) {
-        psLogMsg ("psphot.noise", PS_LOG_INFO, "add noise for %ld objects: %f sec\n", sources->n, psTimerMark ("psphot"));
+        psLogMsg ("psphot.noise", PS_LOG_INFO, "add noise for %ld objects: %f sec\n", sources->n, psTimerMark ("psphot.noise"));
     } else {
-        psLogMsg ("psphot.noise", PS_LOG_INFO, "sub noise for %ld objects: %f sec\n", sources->n, psTimerMark ("psphot"));
+        psLogMsg ("psphot.noise", PS_LOG_INFO, "sub noise for %ld objects: %f sec\n", sources->n, psTimerMark ("psphot.noise"));
     }
     return true;
Index: trunk/psphot/src/psphotApResid.c
===================================================================
--- trunk/psphot/src/psphotApResid.c	(revision 20451)
+++ trunk/psphot/src/psphotApResid.c	(revision 20453)
@@ -18,5 +18,5 @@
     PS_ASSERT_PTR_NON_NULL(recipe, false);
 
-    psTimerStart ("psphot");
+    psTimerStart ("psphot.apresid");
 
     bool measureAptrend = psMetadataLookupBool (&status, recipe, "MEASURE.APTREND");
@@ -218,6 +218,6 @@
     psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", psf->nApResid);
 
-    // psLogMsg ("psphot.apresid", PS_LOG_INFO, "measure full-frame aperture residuals for %d of %d objects: %f sec\n", Nkeep, Npsf, psTimerMark ("psphot"));
     psLogMsg ("psphot.apresid", PS_LOG_DETAIL, "aperture residual: %f +/- %f\n", psf->ApResid, psf->dApResid);
+    psLogMsg ("psphot.apresid", PS_LOG_INFO, "measure full-frame aperture residuals for: %f sec\n", psTimerMark ("psphot.apresid"));
 
     psFree (mag);
Index: trunk/psphot/src/psphotBasicDeblend.c
===================================================================
--- trunk/psphot/src/psphotBasicDeblend.c	(revision 20451)
+++ trunk/psphot/src/psphotBasicDeblend.c	(revision 20453)
@@ -10,5 +10,5 @@
     int Nblend = 0;
 
-    psTimerStart ("psphot");
+    psTimerStart ("psphot.deblend.basic");
 
     float FRACTION = psMetadataLookupF32 (&status, recipe, "DEBLEND_PEAK_FRACTION");
@@ -122,5 +122,5 @@
         psFree (contour);
     }
-    psLogMsg ("psphot.deblend", PS_LOG_INFO, "identified %d blended objects: %f sec\n", Nblend, psTimerMark ("psphot"));
+    psLogMsg ("psphot.deblend", PS_LOG_INFO, "identified %d blended objects: %f sec\n", Nblend, psTimerMark ("psphot.deblend.basic"));
 
     psFree (SN);
Index: trunk/psphot/src/psphotBlendFit.c
===================================================================
--- trunk/psphot/src/psphotBlendFit.c	(revision 20451)
+++ trunk/psphot/src/psphotBlendFit.c	(revision 20453)
@@ -10,5 +10,5 @@
     bool status;
 
-    psTimerStart ("psphot");
+    psTimerStart ("psphot.fit.nonlinear");
 
     // bit-masks to test for good/bad pixels
@@ -119,5 +119,5 @@
     }
 
-    psLogMsg ("psphot.psphotBlendFit", PS_LOG_INFO, "fit models: %f sec for %d objects (%d psf, %d ext, %d failed, %ld skipped)\n", psTimerMark ("psphot"), Nfit, Npsf, Next, Nfail, sources->n - Nfit);
+    psLogMsg ("psphot.psphotBlendFit", PS_LOG_INFO, "fit models: %f sec for %d objects (%d psf, %d ext, %d failed, %ld skipped)\n", psTimerMark ("psphot.fit.nonlinear"), Nfit, Npsf, Next, Nfail, sources->n - Nfit);
 
     psphotVisualShowResidualImage (readout);
Index: trunk/psphot/src/psphotChoosePSF.c
===================================================================
--- trunk/psphot/src/psphotChoosePSF.c	(revision 20451)
+++ trunk/psphot/src/psphotChoosePSF.c	(revision 20453)
@@ -21,5 +21,5 @@
     bool status;
 
-    psTimerStart ("psphot");
+    psTimerStart ("psphot.choose.psf");
 
     // bit-masks to test for good/bad pixels
@@ -308,5 +308,5 @@
 
     char *modelName = pmModelClassGetName (psf->type);
-    psLogMsg ("psphot.pspsf", PS_LOG_INFO, "select psf model: %f sec\n", psTimerMark ("psphot"));
+    psLogMsg ("psphot.pspsf", PS_LOG_INFO, "select psf model: %f sec\n", psTimerMark ("psphot.choose.psf"));
     psLogMsg ("psphot.pspsf", PS_LOG_INFO, "psf model %s, ApResid: %f +/- %f\n", modelName, psf->ApResid, psf->dApResid);
 
Index: trunk/psphot/src/psphotDeblendSatstars.c
===================================================================
--- trunk/psphot/src/psphotDeblendSatstars.c	(revision 20451)
+++ trunk/psphot/src/psphotDeblendSatstars.c	(revision 20453)
@@ -6,5 +6,5 @@
     pmSource *source;
 
-    psTimerStart ("psphot");
+    psTimerStart ("psphot.deblend.sat");
 
     int Nblend = 0;
@@ -155,5 +155,5 @@
     psFree (index);
 
-    psLogMsg ("psphot", PS_LOG_INFO, "found %d satstar blend peaks, leaving %ld sources: %f sec\n", Nblend, sources->n, psTimerMark ("psphot"));
+    psLogMsg ("psphot", PS_LOG_INFO, "found %d satstar blend peaks, leaving %ld sources: %f sec\n", Nblend, sources->n, psTimerMark ("psphot.deblend.sat"));
     return true;
 }
Index: trunk/psphot/src/psphotFindDetections.c
===================================================================
--- trunk/psphot/src/psphotFindDetections.c	(revision 20451)
+++ trunk/psphot/src/psphotFindDetections.c	(revision 20453)
@@ -8,6 +8,4 @@
     float NSIGMA_PEAK = 25.0;
     int NMAX = 0;
-
-    psTimerStart ("psphot");
 
     // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
Index: trunk/psphot/src/psphotFindFootprints.c
===================================================================
--- trunk/psphot/src/psphotFindFootprints.c	(revision 20451)
+++ trunk/psphot/src/psphotFindFootprints.c	(revision 20453)
@@ -5,5 +5,5 @@
     bool status;
 
-    psTimerStart ("footprints");
+    psTimerStart ("psphot.footprints");
 
     int npixMin = psMetadataLookupS32(&status, recipe, "FOOTPRINT_NPIXMIN");
@@ -40,10 +40,10 @@
     psFree (detections->peaks); 
 
-    psLogMsg ("psphot", PS_LOG_DETAIL, "found %ld footprints: %f sec\n", footprints->n, psTimerMark ("footprints"));
+    psLogMsg ("psphot", PS_LOG_MINUTIA, "found %ld footprints: %f sec\n", footprints->n, psTimerMark ("psphot.footprints"));
 
     // optionally grow footprints isotropically by growRadius pixels
     if (growRadius > 0) {
 	psArray *tmp = pmFootprintArrayGrow(footprints, growRadius);
-	psLogMsg ("psphot", PS_LOG_DETAIL, "grow footprint coverage by %d pixels, %ld footprints become %ld footprints: %f sec\n", growRadius, footprints->n, tmp->n, psTimerMark ("footprints"));
+	psLogMsg ("psphot", PS_LOG_MINUTIA, "grow footprint coverage by %d pixels, %ld footprints become %ld footprints: %f sec\n", growRadius, footprints->n, tmp->n, psTimerMark ("psphot.footprints"));
 	psFree(footprints);
 	footprints = tmp;
@@ -57,5 +57,5 @@
 
 	psArray *mergedFootprints = pmFootprintArraysMerge(detections->footprints, footprints, includePeaks);
-	psLogMsg ("psphot", PS_LOG_DETAIL, "merged %ld new footprints with %ld existing ones: %f sec\n", footprints->n, detections->footprints->n, psTimerMark ("footprints"));
+	psLogMsg ("psphot", PS_LOG_MINUTIA, "merged %ld new footprints with %ld existing ones: %f sec\n", footprints->n, detections->footprints->n, psTimerMark ("psphot.footprints"));
 
 	psFree(footprints);
@@ -68,5 +68,5 @@
     psphotCullPeaks(readout->image, readout->weight, recipe, detections->footprints);
     detections->peaks = pmFootprintArrayToPeaks(detections->footprints);
-    psLogMsg ("psphot", PS_LOG_INFO, "%ld peaks, %ld total footprints: %f sec\n", detections->peaks->n, detections->footprints->n, psTimerMark ("footprints"));
+    psLogMsg ("psphot", PS_LOG_INFO, "%ld peaks, %ld total footprints: %f sec\n", detections->peaks->n, detections->footprints->n, psTimerMark ("psphot.footprints"));
 
     return detections;
Index: trunk/psphot/src/psphotFindPeaks.c
===================================================================
--- trunk/psphot/src/psphotFindPeaks.c	(revision 20451)
+++ trunk/psphot/src/psphotFindPeaks.c	(revision 20453)
@@ -8,5 +8,5 @@
     bool status = false;
 
-    psTimerStart ("peaks");
+    psTimerStart ("psphot.peaks");
 
     // find the peaks in the smoothed image
@@ -48,5 +48,5 @@
         pmPeaksWriteText (peaks, output);
     }
-    psLogMsg ("psphot", PS_LOG_INFO, "%ld peaks: %f sec\n", peaks->n, psTimerMark ("peaks"));
+    psLogMsg ("psphot", PS_LOG_INFO, "%ld peaks: %f sec\n", peaks->n, psTimerMark ("psphot.peaks"));
 
     return peaks;
Index: trunk/psphot/src/psphotFitSourcesLinear.c
===================================================================
--- trunk/psphot/src/psphotFitSourcesLinear.c	(revision 20451)
+++ trunk/psphot/src/psphotFitSourcesLinear.c	(revision 20453)
@@ -20,5 +20,5 @@
     // float r;
 
-    psTimerStart ("psphot");
+    psTimerStart ("psphot.linear");
 
     // bit-masks to test for good/bad pixels
@@ -93,5 +93,5 @@
         psArrayAdd (fitSources, 100, source);
     }
-    psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "built fitSources: %f (%ld objects)\n", psTimerMark ("psphot"), sources->n);
+    psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "built fitSources: %f sec (%ld objects)\n", psTimerMark ("psphot.linear"), sources->n);
 
     // vectors to store stats for each object
@@ -163,9 +163,8 @@
 
     psSparseResort (sparse);
-    psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "built matrix: %f (%d elements)\n", psTimerMark ("psphot"), sparse->Nelem);
+    psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "built matrix: %f sec (%d elements)\n", psTimerMark ("psphot.linear"), sparse->Nelem);
 
     // set the sky, sky_x, sky_y components of border matrix
     SetBorderMatrixElements (border, readout, fitSources, CONSTANT_PHOTOMETRIC_WEIGHTS, SKY_FIT_ORDER, markVal);
-    psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "set border: %f (%d elements)\n", psTimerMark ("psphot"), sparse->Nelem);
 
     psSparseConstraint constraint;
@@ -184,5 +183,5 @@
         skyfit = NULL;
     }
-    psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "solve matrix: %f (%d elements)\n", psTimerMark ("psphot"), sparse->Nelem);
+    psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "solve matrix: %f sec (%d elements)\n", psTimerMark ("psphot.linear"), sparse->Nelem);
 
     // adjust I0 for fitSources and subtract
@@ -203,5 +202,5 @@
         source->mode |= PM_SOURCE_MODE_SUBTRACTED;
     }
-    psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "sub models: %f (%d elements)\n", psTimerMark ("psphot"), sparse->Nelem);
+    psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "sub models: %f sec (%d elements)\n", psTimerMark ("psphot.linear"), sparse->Nelem);
 
     // measure chisq for each source
@@ -211,5 +210,5 @@
         pmSourceChisq (model, source->pixels, source->maskObj, source->weight, maskVal);
     }
-    psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "get chisqs: %f (%d elements)\n", psTimerMark ("psphot"), sparse->Nelem);
+    psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "get chisqs: %f sec (%d elements)\n", psTimerMark ("psphot.linear"), sparse->Nelem);
 
     // psFree (index);
@@ -221,5 +220,5 @@
     psFree (border);
 
-    psLogMsg ("psphot.ensemble", PS_LOG_INFO, "measure ensemble of PSFs: %f sec\n", psTimerMark ("psphot"));
+    psLogMsg ("psphot.ensemble", PS_LOG_INFO, "measure ensemble of PSFs: %f sec\n", psTimerMark ("psphot.linear"));
 
     psphotVisualShowResidualImage (readout);
@@ -241,5 +240,4 @@
     fullArray = psRegionForImage (readout->mask, fullArray);
     psImageMaskRegion (readout->mask, fullArray, "OR", markVal);
-    psLogMsg ("psphot.ensemble", PS_LOG_INFO, "step 1: %f sec\n", psTimerMark ("psphot"));
 
     // turn off MARK for all object pixels
@@ -252,5 +250,4 @@
         psImageMaskCircle (source->maskView, x, y, model->radiusFit, "AND", PS_NOT_U8(markVal));
     }
-    psLogMsg ("psphot.ensemble", PS_LOG_INFO, "step 2: %f sec\n", psTimerMark ("psphot"));
 
     // accumulate the image statistics from the masked regions
@@ -289,9 +286,7 @@
         }
     }
-    psLogMsg ("psphot.ensemble", PS_LOG_INFO, "step 3: %f sec\n", psTimerMark ("psphot"));
 
     // turn off MARK for all image pixels
     psImageMaskRegion (readout->mask, fullArray, "AND", PS_NOT_U8(markVal));
-    psLogMsg ("psphot.ensemble", PS_LOG_INFO, "step 4: %f sec\n", psTimerMark ("psphot"));
 
     // set the Border T elements
@@ -310,5 +305,4 @@
         psSparseBorderElementT (border, 2, 2, y2);
     }
-    psLogMsg ("psphot.ensemble", PS_LOG_INFO, "step 5: %f sec\n", psTimerMark ("psphot"));
 
     return true;
Index: trunk/psphot/src/psphotGuessModels.c
===================================================================
--- trunk/psphot/src/psphotGuessModels.c	(revision 20451)
+++ trunk/psphot/src/psphotGuessModels.c	(revision 20453)
@@ -27,5 +27,5 @@
     bool status;
 
-    psTimerStart ("psphot");
+    psTimerStart ("psphot.models");
 
     // select the appropriate recipe information
@@ -142,5 +142,5 @@
     }
     
-    psLogMsg ("psphot.models", 4, "built models for %ld objects: %f sec\n", sources->n, psTimerMark ("psphot"));
+    psLogMsg ("psphot.models", 4, "built models for %ld objects: %f sec\n", sources->n, psTimerMark ("psphot.models"));
     return true;
 }
Index: trunk/psphot/src/psphotImageMedian.c
===================================================================
--- trunk/psphot/src/psphotImageMedian.c	(revision 20451)
+++ 	(revision )
@@ -1,392 +1,0 @@
-# include "psphotInternal.h"
-static int npass = 0;
-
-// generate the median in NxN boxes, clipping heavily
-// linear interpolation to generate full-scale model
-bool psphotImageMedian (pmConfig *config, const pmFPAview *view, psMaskType maskVal)
-{
-    bool status = true;
-    static char *defaultStatsName = "FITTED_MEAN";
-
-    pmReadout *readout = NULL;
-    pmReadout *background = NULL;
-    pmReadout *backSub = NULL;
-
-    psTimerStart ("psphot");
-
-    // select the appropriate recipe information
-    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
-
-    // user supplied seed, if available
-    unsigned long seed = psMetadataLookupS32 (&status, recipe, "IMSTATS_SEED");
-    if (!status) {
-        seed = 0;
-    }
-    psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS, seed);
-
-    // subtract this amount extra from the sky
-    float SKY_BIAS = psMetadataLookupF32 (&status, recipe, "SKY_BIAS");
-    if (!status) {
-        SKY_BIAS = 0;
-    }
-
-    // supply the sky background statistics options
-    char *statsName = psMetadataLookupStr (&status, recipe, "SKY_STAT");
-    if (statsName == NULL) {
-        statsName = defaultStatsName;
-    }
-    psStatsOptions statsOptionLocation = psStatsOptionFromString(statsName);
-    if (!(statsOptionLocation & (PS_STAT_SAMPLE_MEAN |
-                                 PS_STAT_SAMPLE_MEDIAN |
-                                 PS_STAT_ROBUST_MEDIAN |
-                                 PS_STAT_ROBUST_QUARTILE |
-                                 PS_STAT_CLIPPED_MEAN |
-                                 PS_STAT_FITTED_MEAN |
-                                 PS_STAT_FITTED_MEAN_V2 |
-                                 PS_STAT_FITTED_MEAN_V3 |
-                                 PS_STAT_FITTED_MEAN_V4))) {
-        statsOptionLocation = PS_STAT_FITTED_MEAN;
-    }
-
-    psStatsOptions statsOptionWidth = PS_STAT_NONE;
-    if (statsOptionLocation & (PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_MEDIAN)) {
-        statsOptionWidth = PS_STAT_SAMPLE_STDEV;
-    } else if (statsOptionLocation & (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_QUARTILE)) {
-#if 1
-        statsOptionWidth = PS_STAT_ROBUST_STDEV; // not set; => NaN
-#else
-        statsOptionWidth = PS_STAT_FITTED_STDEV;
-#endif
-    } else if (statsOptionLocation & PS_STAT_FITTED_MEAN) {
-        statsOptionWidth = PS_STAT_FITTED_STDEV;
-    } else if (statsOptionLocation & PS_STAT_CLIPPED_MEAN) {
-        statsOptionWidth = PS_STAT_CLIPPED_STDEV;
-    } else if (statsOptionLocation & PS_STAT_FITTED_MEAN_V2) {
-        statsOptionWidth = PS_STAT_FITTED_STDEV_V2;
-    } else if (statsOptionLocation & PS_STAT_FITTED_MEAN_V3) {
-        statsOptionWidth = PS_STAT_FITTED_STDEV_V3;
-    } else if (statsOptionLocation & PS_STAT_FITTED_MEAN_V4) {
-        statsOptionWidth = PS_STAT_FITTED_STDEV_V4;
-    } else {
-        psAbort("Unable to estimate variance of selected statsOptionLocations 0x%x", statsOptionLocation);
-    }
-
-    const psStatsOptions statsOption = statsOptionLocation | statsOptionWidth;
-    psStats *stats = psStatsAlloc (statsOption);
-
-    // set range for old-version of sky statistic
-    if (statsOptionLocation & PS_STAT_ROBUST_QUARTILE) {
-        stats->min = 0.25;
-        stats->max = 0.75;
-    }
-
-    // set user-option for number of pixels per region
-    stats->nSubsample = psMetadataLookupF32 (&status, recipe, "IMSTATS_NPIX");
-    if (!status) {
-        stats->nSubsample = 1000;
-    }
-
-    // optionally set the binsize
-    stats->binsize = psMetadataLookupF32 (&status, recipe, "SKY_HISTOGRAM_BINS");
-    if (status) {
-        stats->options |= PS_STAT_USE_BINSIZE;
-    }
-
-    // optionally set the sigma clipping
-    stats->clipSigma = psMetadataLookupF32 (&status, recipe, "SKY_CLIP_SIGMA");
-    if (!status) {
-        if ((stats->options & PS_STAT_FITTED_MEAN) || (stats->options & PS_STAT_FITTED_MEAN_V2)) {
-            stats->clipSigma = 1.0;
-        } else {
-            stats->clipSigma = 3.0;
-        }
-    }
-
-    // stats is not initialized by psStats???  use this to save the input options
-    // XXX re-work this to use the new psStatsInit function
-    psStats *statsDefaults = psStatsAlloc (statsOption);
-    *statsDefaults = *stats;
-
-    // find the currently selected readout
-    pmFPAfile *file = psMetadataLookupPtr (&status, config->files, "PSPHOT.INPUT");
-    pmFPA *inFPA = file->fpa;
-    readout = pmFPAviewThisReadout (view, inFPA);
-
-    psImage *image = readout->image;
-    psImage *mask  = readout->mask;
-
-    // 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, "BACKGROUND.XBIN");
-    binning->nYbin  = psMetadataLookupS32 (&status, recipe, "BACKGROUND.YBIN");
-
-    psImageBinningSetRuffSize(binning, PS_IMAGE_BINNING_CENTER);
-    psImageBinningSetSkip(binning, image);
-    status = psMetadataAddPtr(recipe, PS_LIST_TAIL, "PSPHOT.BACKGROUND.BINNING", PS_DATA_UNKNOWN | PS_META_REPLACE, "Background binning", binning);
-    PS_ASSERT (status, false);
-
-    // we save the binning structure for use in psphotMagnitudes
-    pmReadout *model      = pmFPAGenerateReadout (config, view, "PSPHOT.BACKMDL",       inFPA, binning);
-    pmReadout *modelStdev = pmFPAGenerateReadout (config, view, "PSPHOT.BACKMDL.STDEV", inFPA, binning);
-
-    psF32 **modelData = model->image->data.F32;
-    psF32 **modelStdevData = modelStdev->image->data.F32;
-
-    // measure clipped median for subimages
-    psRegion ruffRegion = {0,0,0,0};
-    psRegion fineRegion = {0,0,0,0};
-    for (int iy = 0; iy < model->image->numRows; iy++) {
-        for (int ix = 0; ix < model->image->numCols; ix++) {
-
-            // convert the ruff grid cell to the equivalent fine grid cell
-            // XXX we need to watch out for row0,col0
-            ruffRegion = psRegionSet (ix, ix + 2, iy, iy + 2);
-            fineRegion = psImageBinningSetFineRegion (binning, ruffRegion);
-            fineRegion = psRegionForImage (image, fineRegion);
-
-            psImage *subset  = psImageSubset (image, fineRegion);
-            if (!subset->numCols || !subset->numRows) {
-                psFree (subset);
-                continue;
-            }
-            psImage *submask = psImageSubset (mask, fineRegion);
-
-            // reset the default values
-            *stats = *statsDefaults;
-
-            // Use the selected background statistic for the first pass
-            // If it fails, fall back on the "ROBUST_MEDIAN" version
-            // If both fail, set the pixel to NAN and (below) interpolate
-            // XXX psImageBackground will probably be renamed psImageStats
-            // XXX don't bother trying if there are no valid pixels...
-
-	    psVector *sample = NULL;
-
-	    // turn on stats tracing in desired cells
-	    # if (0)
-	    psMetadata *plots = psMetadataLookupPtr (&status, recipe, "DIAGNOSTIC.PLOTS");
-	    assert (plots);
-	    
-	    int xPlot = psMetadataLookupS32 (&status, plots, "IMAGE.BACKGROUND.CELL.HISTOGRAM.X");
-	    assert (status);
-	    int yPlot = psMetadataLookupS32 (&status, plots, "IMAGE.BACKGROUND.CELL.HISTOGRAM.Y");
-	    assert (status);
-
-	    bool gotX = (xPlot < 0) || (xPlot == ix);
-	    bool gotY = (yPlot < 0) || (yPlot == iy);
-
-	    if (gotX && gotY) {
-		psTraceSetLevel ("psLib.math.vectorFittedStats_v4", 6);
-		psTraceSetLevel ("psLib.math.vectorRobustStats", 6);
-	    } else {
-		psTraceSetLevel ("psLib.math.vectorFittedStats_v4", 0);
-		psTraceSetLevel ("psLib.math.vectorRobustStats", 0);
-	    }	    
-	    # endif
-
-            if (psImageBackground(stats, &sample, subset, submask, maskVal, rng)) {
-                if (stats->options & PS_STAT_ROBUST_QUARTILE) {
-                    modelData[iy][ix] = stats->robustMedian;
-                } else {
-                    modelData[iy][ix] = psStatsGetValue(stats, statsOptionLocation);
-                }
-                modelStdevData[iy][ix] = psStatsGetValue(stats, statsOptionWidth);
-
-		// supply sample to plotting routing
-		psphotDiagnosticPlots (config, "IMAGE.BACKGROUND.CELL.HISTOGRAM", ix, iy, modelData[iy][ix], modelStdevData[iy][ix], sample);
-		psFree (sample);
-            } else {
-                psStatsOptions currentOptions = stats->options;
-                stats->options = PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV;
-                if (!psImageBackground(stats, &sample, subset, submask, maskVal, rng)) {
-                    psLogMsg ("psphot", PS_LOG_DETAIL, "Failed to estimate background using ROBUST_MEDIAN for "
-                               "(%dx%d, (row0,col0) = (%d,%d)",
-                               subset->numRows, subset->numCols, subset->row0, subset->col0);
-                    modelData[iy][ix] = modelStdevData[iy][ix] = NAN;
-                } else {
-                    modelData[iy][ix] = psStatsGetValue (stats, PS_STAT_ROBUST_MEDIAN);
-                    modelStdevData[iy][ix] = psStatsGetValue(stats, PS_STAT_ROBUST_STDEV);
-
-		    // supply sample to plotting routing
-		    psphotDiagnosticPlots (config, "IMAGE.BACKGROUND.CELL.HISTOGRAM", ix, iy, modelData[iy][ix], modelStdevData[iy][ix], sample);
-		    psFree (sample);
-                }
-                // drop errors caused by psImageBackground failures
-                // XXX we probably should trap and exit on serious failures
-                psErrorClear();
-                stats->options = currentOptions;
-            }
-            modelData[iy][ix] += SKY_BIAS;
-            psFree (subset);
-            psFree (submask);
-        }
-    }
-
-    if (psTraceGetLevel("psphot") > 5) {
-        char name[256];
-        sprintf (name, "backraw.%02d.fits", npass);
-        psphotSaveImage (NULL, model->image, name);
-    }
-
-    // patch over bad regions (use average of 8 possible neighbor pixels)
-    // XXX consider testing all pixels against the 8 neighbors and replacing outliers...
-    double Count = 0;                   // number of good pixels
-    double Value = 0;                   // sum of good pixel's value
-    double ValueStdev = 0;              // sum of good pixel's standard deviations
-    for (int iy = 0; iy < model->image->numRows; iy++) {
-        for (int ix = 0; ix < model->image->numCols; ix++) {
-            if (!isnan(modelData[iy][ix])) {
-                Value += modelData[iy][ix];
-                ValueStdev += modelStdevData[iy][ix];
-                Count++;
-                continue;
-            }
-
-            double value = 0;
-            double count = 0;
-            for (int jy = iy - 1; jy <= iy + 1; jy++) {
-                if (jy <   0) continue;
-                if (jy >= model->image->numRows) continue;
-                for (int jx = ix - 1; jx <= ix + 1; jx++) {
-                    if (!jx && !jy) continue;
-                    if (jx   <   0) continue;
-                    if (jx   >= model->image->numCols) continue;
-                    value += modelData[jy][jx];
-                    count += 1.0;
-                }
-            }
-            if (count > 0) modelData[iy][ix] = value / count;
-        }
-    }
-    if (Count == 0) {
-        psError (PSPHOT_ERR_DATA, true, "failed to build background image");
-	psFree(stats);
-	psFree(statsDefaults);
-	psFree(binning);
-	psFree(rng);
-        return false;
-    }
-
-    Value /= Count;
-    ValueStdev /= Count;
-
-    // patch over remaining bad regions (use global average)
-    for (int iy = 0; iy < model->image->numRows; iy++) {
-        for (int ix = 0; ix < model->image->numCols; ix++) {
-            if (!isnan(modelData[iy][ix])) continue;
-            modelData[iy][ix] = Value;
-            modelStdevData[iy][ix] = ValueStdev;
-        }
-    }
-
-    psLogMsg ("psphot", PS_LOG_MINUTIA, "build median image: %f sec\n", psTimerMark ("psphot"));
-
-    psMetadataAddF32(recipe, PS_LIST_TAIL, "SKY_MEAN", PS_META_REPLACE, "sky mean", Value);
-    psMetadataAddF32(recipe, PS_LIST_TAIL, "SKY_STDEV", PS_META_REPLACE, "sky stdev", ValueStdev);
-    psLogMsg ("psphot", PS_LOG_INFO, "image sky : mean %f stdev %f", Value, ValueStdev);
-
-    // measure image and background stats and save for later output
-    psStats *statsBck = psStatsAlloc (PS_STAT_SAMPLE_MEAN |
-                                      PS_STAT_SAMPLE_STDEV |
-                                      PS_STAT_MIN |
-                                      PS_STAT_MAX);
-    psImageStats (statsBck, model->image, NULL, 0);
-    psMetadataAddF32 (recipe, PS_LIST_TAIL, "MSKY_MN",
-                      PS_META_REPLACE, "sky model mean",          statsBck->sampleMean);
-    psMetadataAddF32 (recipe, PS_LIST_TAIL, "MSKY_SIG",
-                      PS_META_REPLACE, "sky model stdev",         statsBck->sampleStdev);
-    psMetadataAddF32 (recipe, PS_LIST_TAIL, "MSKY_MAX",
-                      PS_META_REPLACE, "sky model maximum value", statsBck->max);
-    psMetadataAddF32 (recipe, PS_LIST_TAIL, "MSKY_MIN",
-                      PS_META_REPLACE, "sky model minimum value", statsBck->min);
-    psMetadataAddS32 (recipe, PS_LIST_TAIL, "MSKY_NX",
-                      PS_META_REPLACE, "sky model size (x)",      model->image->numCols);
-    psMetadataAddS32 (recipe, PS_LIST_TAIL, "MSKY_NY",
-                      PS_META_REPLACE, "sky model size (y)",      model->image->numRows);
-    psLogMsg ("psphot", PS_LOG_INFO, "background sky : min %f mean %f max %f stdev %f",
-              statsBck->min, statsBck->sampleMean, statsBck->max, statsBck->sampleStdev);
-    psFree (statsBck);
-
-    // select background pixels, from output background file, or create
-    file = psMetadataLookupPtr (&status, config->files, "PSPHOT.BACKGND");
-    if (file) {
-        // we are using PSPHOT.BACKGND as an I/O file: select readout or create
-        if (file->mode == PM_FPA_MODE_INTERNAL) {
-            background = file->readout;
-        } else {
-            background = pmFPAviewThisReadout (view, file->fpa);
-        }
-        if (background == NULL) {
-            // readout does not yet exist: create from input
-            pmFPAfileCopyStructureView (file->fpa, inFPA, 1, 1, view);
-            background = pmFPAviewThisReadout (view, file->fpa);
-            if ((image->numCols != background->image->numCols) || (image->numRows != background->image->numRows)) {
-                psError (PSPHOT_ERR_PROG, true, "inconsistent sizes for background dimensions");
-                return false;
-            }
-        }
-    } else {
-        background = pmFPAfileDefineInternal (config->files, "PSPHOT.BACKGND", image->numCols, image->numRows, PS_TYPE_F32);
-    }
-    psF32 **backData = background->image->data.F32;
-
-    // linear interpolation to full-scale
-    if (!psImageUnbin (background->image, model->image, binning)) {
-        psError (PSPHOT_ERR_PROG, true, "inconsistent sizes for unbinning");
-        return false;
-    }
-
-    psLogMsg ("psphot", PS_LOG_MINUTIA, "build resampled image: %f sec\n", psTimerMark ("psphot"));
-
-    // back-sub image pixels, from output background file (don't create if not requested)
-    file = psMetadataLookupPtr (&status, config->files, "PSPHOT.BACKSUB");
-    if (file) {
-        // we are using PSPHOT.BACKSUB as an I/O file: select readout or create
-        backSub = pmFPAviewThisReadout (view, file->fpa);
-        if (backSub == NULL) {
-            // readout does not yet exist: create from input
-            pmFPAfileCopyStructureView (file->fpa, inFPA, 1, 1, view);
-            backSub = pmFPAviewThisReadout (view, file->fpa);
-        }
-    }
-
-    if (psTraceGetLevel("psphot") > 5) {
-        char name[256];
-        sprintf (name, "image.%02d.fits", npass);
-        psphotSaveImage (NULL, image, name);
-        sprintf (name, "back.%02d.fits", npass);
-        psphotSaveImage (NULL, background->image, name);
-        sprintf (name, "mask.%02d.fits", npass);
-        psphotSaveImage (NULL, mask, name);
-        sprintf (name, "backmdl.%02d.fits", npass);
-        psphotSaveImage (NULL, model->image, name);
-    }
-
-    // subtract the background model (save in backSub, if requested)
-    for (int j = 0; j < image->numRows; j++) {
-        for (int i = 0; i < image->numCols; i++) {
-            image->data.F32[j][i] -= backData[j][i];
-            if (backSub) {
-                backSub->image->data.F32[j][i] = image->data.F32[j][i];
-            }
-        }
-    }
-
-    if (psTraceGetLevel("psphot") > 5) {
-        char name[256];
-        sprintf (name, "backsub.%02d.fits", npass);
-        psphotSaveImage (NULL, image, name);
-    }
-    npass ++;
-
-    psLogMsg ("psphot", PS_LOG_INFO, "subtracted background model: %f sec\n", psTimerMark ("psphot"));
-    psFree(stats);
-    psFree(statsDefaults);
-    psFree(binning);
-    psFree(rng);
-
-    // the pmReadout selected in this function are all view on entries in config->files
-    return true;
-}
Index: trunk/psphot/src/psphotMagnitudes.c
===================================================================
--- trunk/psphot/src/psphotMagnitudes.c	(revision 20451)
+++ trunk/psphot/src/psphotMagnitudes.c	(revision 20453)
@@ -6,5 +6,5 @@
     int Nap = 0;
 
-    psTimerStart ("psphot");
+    psTimerStart ("psphot.mags");
 
     pmReadout *backModel = psphotSelectBackground (config, view);
@@ -60,5 +60,5 @@
     }
 
-    psLogMsg ("psphot.magnitudes", PS_LOG_DETAIL, "measure magnitudes : %f sec for %ld objects (%d with apertures)\n", psTimerMark ("psphot"), sources->n, Nap);
+    psLogMsg ("psphot.magnitudes", PS_LOG_DETAIL, "measure magnitudes : %f sec for %ld objects (%d with apertures)\n", psTimerMark ("psphot.mags"), sources->n, Nap);
     return true;
 }
Index: trunk/psphot/src/psphotMakeFluxScale.c
===================================================================
--- trunk/psphot/src/psphotMakeFluxScale.c	(revision 20451)
+++ trunk/psphot/src/psphotMakeFluxScale.c	(revision 20453)
@@ -5,5 +5,5 @@
     bool status = false;
 
-    psTimerStart ("residuals");
+    psTimerStart ("psphot.fluxscale");
 
     int Nx = psMetadataLookupS32(&status, recipe, "PSF.FLUXSCALE.NX");
@@ -72,4 +72,6 @@
     psFree(trend);
 
+    psLogMsg ("psphot", PS_LOG_MINUTIA, "built flux scale: %f sec\n", psTimerMark ("psphot.fluxscale"));
+
     return success;
 }
Index: trunk/psphot/src/psphotMakeGrowthCurve.c
===================================================================
--- trunk/psphot/src/psphotMakeGrowthCurve.c	(revision 20451)
+++ trunk/psphot/src/psphotMakeGrowthCurve.c	(revision 20453)
@@ -5,5 +5,5 @@
     bool status;
 
-    psTimerStart ("growth");
+    psTimerStart ("psphot.growth");
 
     // set limits on the aperture magnitudes
@@ -34,5 +34,5 @@
     }
 
-    psLogMsg ("psphot", PS_LOG_INFO, "built growth curve: %f sec\n", psTimerMark ("growth"));
+    psLogMsg ("psphot", PS_LOG_MINUTIA, "built growth curve: %f sec\n", psTimerMark ("psphot.growth"));
 
     return true;
Index: trunk/psphot/src/psphotMakeResiduals.c
===================================================================
--- trunk/psphot/src/psphotMakeResiduals.c	(revision 20451)
+++ trunk/psphot/src/psphotMakeResiduals.c	(revision 20453)
@@ -7,5 +7,5 @@
     psU8 mflux;
 
-    psTimerStart ("residuals");
+    psTimerStart ("psphot.residuals");
 
     if (!psMetadataLookupBool(&status, recipe, "PSF.RESIDUALS")) return true;
@@ -273,5 +273,5 @@
     psFree (B);
 
-    psLogMsg ("psphot.pspsf", PS_LOG_INFO, "generate residuals for %ld objects: %f sec\n", input->n, psTimerMark ("residuals"));
+    psLogMsg ("psphot.pspsf", PS_LOG_MINUTIA, "generate residuals for %ld objects: %f sec\n", input->n, psTimerMark ("psphot.residuals"));
 
     psFree (xC);
Index: trunk/psphot/src/psphotModelBackground.c
===================================================================
--- trunk/psphot/src/psphotModelBackground.c	(revision 20451)
+++ trunk/psphot/src/psphotModelBackground.c	(revision 20453)
@@ -9,5 +9,5 @@
     static char *defaultStatsName = "FITTED_MEAN";
 
-    psTimerStart ("psphot");
+    psTimerStart ("psphot.background");
 
     // find the currently selected readout
@@ -283,5 +283,5 @@
     }
 
-    psLogMsg ("psphot", PS_LOG_MINUTIA, "build median image: %f sec\n", psTimerMark ("psphot"));
+    psLogMsg ("psphot", PS_LOG_INFO, "built background image: %f sec\n", psTimerMark ("psphot.background"));
 
     psMetadataAddF32(recipe, PS_LIST_TAIL, "SKY_MEAN", PS_META_REPLACE, "sky mean", Value);
Index: trunk/psphot/src/psphotReplaceUnfit.c
===================================================================
--- trunk/psphot/src/psphotReplaceUnfit.c	(revision 20451)
+++ trunk/psphot/src/psphotReplaceUnfit.c	(revision 20453)
@@ -6,5 +6,5 @@
     pmSource *source;
 
-    psTimerStart ("psphot");
+    psTimerStart ("psphot.replace");
 
     for (int i = 0; i < sources->n; i++) {
@@ -19,5 +19,5 @@
         source->mode &= ~PM_SOURCE_MODE_SUBTRACTED;
     }
-    psLogMsg ("psphot.replace", 3, "replace unfitted models: %f sec (%ld objects)\n", psTimerMark ("psphot"), sources->n);
+    psLogMsg ("psphot.replace", 3, "replace unfitted models: %f sec (%ld objects)\n", psTimerMark ("psphot.replace"), sources->n);
     return true;
 }
@@ -28,5 +28,5 @@
     pmSource *source;
 
-    psTimerStart ("psphot");
+    psTimerStart ("psphot.replace");
 
     // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
@@ -43,5 +43,5 @@
       source->mode &= ~PM_SOURCE_MODE_SUBTRACTED;
     }
-    psLogMsg ("psphot.replace", PS_LOG_INFO, "replaced models for %ld objects: %f sec\n", sources->n, psTimerMark ("psphot"));
+    psLogMsg ("psphot.replace", PS_LOG_INFO, "replaced models for %ld objects: %f sec\n", sources->n, psTimerMark ("psphot.replace"));
     return true;
 }
@@ -52,5 +52,5 @@
     pmSource *source;
 
-    psTimerStart ("psphot");
+    psTimerStart ("psphot.replace");
 
     // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
@@ -67,5 +67,5 @@
       source->mode |= PM_SOURCE_MODE_SUBTRACTED;
     }
-    psLogMsg ("psphot.replace", PS_LOG_INFO, "replaced models for %ld objects: %f sec\n", sources->n, psTimerMark ("psphot"));
+    psLogMsg ("psphot.replace", PS_LOG_INFO, "replaced models for %ld objects: %f sec\n", sources->n, psTimerMark ("psphot.replace"));
     return true;
 }
Index: trunk/psphot/src/psphotRoughClass.c
===================================================================
--- trunk/psphot/src/psphotRoughClass.c	(revision 20451)
+++ trunk/psphot/src/psphotRoughClass.c	(revision 20453)
@@ -14,5 +14,5 @@
     bool status;
 
-    psTimerStart ("psphot");
+    psTimerStart ("psphot.rough");
 
     // we make this measurement on a NxM grid of regions across the readout
@@ -41,5 +41,5 @@
     psphotDumpMoments (recipe, sources);
 
-    psLogMsg ("psphot.roughclass", PS_LOG_INFO, "rough classification: %f sec\n", psTimerMark ("psphot"));
+    psLogMsg ("psphot.roughclass", PS_LOG_INFO, "rough classification: %f sec\n", psTimerMark ("psphot.rough"));
 
     psphotVisualPlotMoments (recipe, sources);
Index: trunk/psphot/src/psphotSignificanceImage.c
===================================================================
--- trunk/psphot/src/psphotSignificanceImage.c	(revision 20451)
+++ trunk/psphot/src/psphotSignificanceImage.c	(revision 20453)
@@ -11,5 +11,5 @@
 
     // smooth the image and weight map
-    psTimerStart ("smooth");
+    psTimerStart ("psphot.smooth");
 
     // XXX we can a) choose fft to convolve if needed and b) multithread fftw
@@ -45,5 +45,5 @@
     psImage *smooth_im = psImageCopy(NULL, readout->image, PS_TYPE_F32);
     psImageSmoothMask(smooth_im, smooth_im, readout->mask, maskVal, SIGMA_SMTH, NSIGMA_SMTH, minGauss);
-    psLogMsg("psphot", PS_LOG_MINUTIA, "smooth image: %f sec\n", psTimerMark("smooth"));
+    psLogMsg("psphot", PS_LOG_MINUTIA, "smooth image: %f sec\n", psTimerMark("psphot.smooth"));
 
     // Smooth the weight, applying the mask as we go.  The variance is smoothed by the PSF^2,
@@ -57,5 +57,5 @@
     psImageSmoothMask(smooth_wt, smooth_wt, readout->mask, maskVal, SIGMA_SMTH * M_SQRT1_2,
                       NSIGMA_SMTH, minGauss);
-    psLogMsg("psphot", PS_LOG_MINUTIA, "smooth weight: %f sec\n", psTimerMark("smooth"));
+    psLogMsg("psphot", PS_LOG_MINUTIA, "smooth weight: %f sec\n", psTimerMark("psphot.smooth"));
 
     psImage *mask = readout->mask;
@@ -116,5 +116,5 @@
         }
     }
-    psLogMsg ("psphot", PS_LOG_INFO, "built smoothed signficance image: %f sec\n", psTimerMark("smooth"));
+    psLogMsg ("psphot", PS_LOG_INFO, "built smoothed signficance image: %f sec\n", psTimerMark("psphot.smooth"));
 
     // optionally save example images under trace
Index: trunk/psphot/src/psphotSkyReplace.c
===================================================================
--- trunk/psphot/src/psphotSkyReplace.c	(revision 20451)
+++ trunk/psphot/src/psphotSkyReplace.c	(revision 20453)
@@ -5,5 +5,5 @@
 bool psphotSkyReplace (pmConfig *config, const pmFPAview *view) {
 
-    psTimerStart ("psphot");
+    psTimerStart ("psphot.skyreplace");
 
     // find the currently selected readout
@@ -28,5 +28,5 @@
         }
     }
-    psLogMsg ("psphot.sky", PS_LOG_DETAIL, "replace background flux : %f sec\n", psTimerMark ("psphot"));
+    psLogMsg ("psphot.sky", PS_LOG_DETAIL, "replace background flux : %f sec\n", psTimerMark ("psphot.skyreplace"));
     return true;
 }
Index: trunk/psphot/src/psphotSourceSize.c
===================================================================
--- trunk/psphot/src/psphotSourceSize.c	(revision 20451)
+++ trunk/psphot/src/psphotSourceSize.c	(revision 20453)
@@ -15,5 +15,5 @@
     bool status;
 
-    psTimerStart ("psphot");
+    psTimerStart ("psphot.size");
 
     // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
@@ -228,5 +228,5 @@
 
     psLogMsg ("psphot.size", PS_LOG_INFO, "measure source sizes for %ld sources: %f sec\n",
-              sources->n - first, psTimerMark ("psphot"));
+              sources->n - first, psTimerMark ("psphot.size"));
 
     psphotVisualPlotSourceSize (sources);
Index: trunk/psphot/src/psphotSourceStats.c
===================================================================
--- trunk/psphot/src/psphotSourceStats.c	(revision 20451)
+++ trunk/psphot/src/psphotSourceStats.c	(revision 20453)
@@ -7,5 +7,5 @@
     float BIG_RADIUS;
 
-    psTimerStart ("psphot");
+    psTimerStart ("psphot.stats");
 
     // bit-masks to test for good/bad pixels
@@ -119,5 +119,5 @@
     }
 
-    psLogMsg ("psphot", PS_LOG_INFO, "%ld sources, %d moments, %d failed: %f sec\n", sources->n, Nmoments, Nfail, psTimerMark ("psphot"));
+    psLogMsg ("psphot", PS_LOG_INFO, "%ld sources, %d moments, %d failed: %f sec\n", sources->n, Nmoments, Nfail, psTimerMark ("psphot.stats"));
 
     psphotVisualShowMoments (sources);
Index: trunk/psphot/src/psphotSubtractBackground.c
===================================================================
--- trunk/psphot/src/psphotSubtractBackground.c	(revision 20451)
+++ trunk/psphot/src/psphotSubtractBackground.c	(revision 20453)
@@ -10,5 +10,5 @@
     pmReadout *backSub = NULL;
 
-    psTimerStart ("psphot");
+    psTimerStart ("psphot.background");
 
     // find the currently selected readout
@@ -63,5 +63,5 @@
     }
 
-    psLogMsg ("psphot", PS_LOG_MINUTIA, "build resampled image: %f sec\n", psTimerMark ("psphot"));
+    psLogMsg ("psphot", PS_LOG_MINUTIA, "build resampled image: %f sec\n", psTimerMark ("psphot.background"));
 
     // back-sub image pixels, from output background file (don't create if not requested)
@@ -105,5 +105,5 @@
         psphotSaveImage (NULL, image, name);
     }
-    psLogMsg ("psphot", PS_LOG_INFO, "subtracted background model: %f sec\n", psTimerMark ("psphot"));
+    psLogMsg ("psphot", PS_LOG_INFO, "subtracted background model: %f sec\n", psTimerMark ("psphot.background"));
 
     // the pmReadout selected in this function are all view on entries in config->files
