Index: /branches/eam_branches/ipp-20100621/psphot/src/psphot.h
===================================================================
--- /branches/eam_branches/ipp-20100621/psphot/src/psphot.h	(revision 28910)
+++ /branches/eam_branches/ipp-20100621/psphot/src/psphot.h	(revision 28911)
@@ -106,4 +106,5 @@
 bool            psphotExtendedSourceFits (pmConfig *config, const pmFPAview *view, const char *filerule);
 bool            psphotExtendedSourceFitsReadout (pmConfig *config, const pmFPAview *view, const char *filerule, int index, psMetadata *recipe);
+bool            psphotExtendedSourceFits_Threaded (psThreadJob *job);
 
 bool            psphotApResid (pmConfig *config, const pmFPAview *view, const char *filerule);
Index: /branches/eam_branches/ipp-20100621/psphot/src/psphotExtendedSourceFits.c
===================================================================
--- /branches/eam_branches/ipp-20100621/psphot/src/psphotExtendedSourceFits.c	(revision 28910)
+++ /branches/eam_branches/ipp-20100621/psphot/src/psphotExtendedSourceFits.c	(revision 28911)
@@ -31,4 +31,186 @@
 // non-linear model fitting for extended sources
 bool psphotExtendedSourceFitsReadout (pmConfig *config, const pmFPAview *view, const char *filerule, int index, psMetadata *recipe) {
+
+    bool status;
+    int Next = 0;
+    int Nconvolve = 0;
+    int NconvolvePass = 0;
+    int Nplain = 0;
+    int NplainPass = 0;
+
+    psTimerStart ("psphot.extended");
+
+    // find the currently selected readout
+    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filerule, index); // File of interest
+    psAssert (file, "missing file?");
+
+    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
+    psAssert (readout, "missing readout?");
+
+    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
+    psAssert (detections, "missing detections?");
+
+    psArray *sources = detections->allSources;
+    psAssert (sources, "missing sources?");
+
+    if (!sources->n) {
+	psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping source size");
+	return true;
+    }
+
+    // determine the number of allowed threads
+    int nThreads = psMetadataLookupS32(&status, config->arguments, "NTHREADS"); // Number of threads
+    if (!status) {
+        nThreads = 0;
+    }
+
+    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
+    psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
+    assert (maskVal);
+
+    psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT"); // Mask value for bad pixels
+    assert (markVal);
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
+
+    // select the collection of desired models
+    psMetadata *models = psMetadataLookupMetadata (&status, recipe, "EXTENDED_SOURCE_MODELS");
+    if (!status) {
+        psWarning ("extended source model fits requested but model model is missing (EXTENDED_SOURCE_MODELS)\n");
+        return true;
+    }
+    if (models->list->n == 0) {
+        psWarning ("extended source model fits requested but no models are specified\n");
+        return true;
+    }
+
+    // validate the model entries
+    psMetadataIterator *iter = psMetadataIteratorAlloc (models, PS_LIST_HEAD, NULL);
+    psMetadataItem *item = NULL;
+    while ((item = psMetadataGetAndIncrement (iter)) != NULL) {
+
+      if (item->type != PS_DATA_METADATA) {
+        psAbort ("Invalid type for EXTENDED_SOURCE_MODEL entry %s, not a metadata folder", item->name);
+        // XXX we could cull the bad entries or build a validated model folder
+      }
+
+      psMetadata *model = (psMetadata *) item->data.md;
+
+      // check on the model type
+      char *modelName = psMetadataLookupStr (&status, model, "MODEL");
+      int modelType = pmModelClassGetType (modelName);
+      if (modelType < 0) {
+        psAbort ("Unknown model class for EXTENDED_SOURCE_MODEL entry %s: %s", item->name, modelName);
+      }
+      psMetadataAddS32 (model, PS_LIST_TAIL, "MODEL_TYPE", PS_META_REPLACE, "", modelType);
+
+      // check on the SNLIM, set a float value
+      char *SNword = psMetadataLookupStr (&status, model, "SNLIM");
+      if (!status) {
+        psAbort("SNLIM not defined for extended source model %s\n", item->name);
+      }
+      float SNlim = atof (SNword);
+      psMetadataAddF32 (model, PS_LIST_TAIL, "SNLIM_VALUE", PS_META_REPLACE, "", SNlim);
+
+      // check on the PSF-Convolution status
+      char *convolvedWord = psMetadataLookupStr (&status, model, "PSF_CONVOLVED");
+      if (!status || (strcasecmp (convolvedWord, "true") && strcasecmp (convolvedWord, "false"))) {
+        psAbort ("PSF_CONVOLVED entry invalid or missing for EXTENDED_SOURCE_MODEL entry %s", item->name);
+      }
+      bool convolved = !strcasecmp (convolvedWord, "true");
+      psMetadataAddBool (model, PS_LIST_TAIL, "PSF_CONVOLVED_VALUE", PS_META_REPLACE, "", convolved);
+    }
+    psFree (iter);
+
+    // option to limit analysis to a specific region
+    char *region = psMetadataLookupStr (&status, recipe, "ANALYSIS_REGION");
+    psRegion *AnalysisRegion = psRegionAlloc(0,0,0,0);
+    *AnalysisRegion = psRegionForImage(readout->image, psRegionFromString (region));
+    if (psRegionIsNaN (*AnalysisRegion)) psAbort("analysis region mis-defined");
+
+    // what fraction of the PSF is used? (radius in pixels : 2 -> 5x5 box)
+    int psfSize = psMetadataLookupS32 (&status, recipe, "PCM_BOX_SIZE");
+    assert (status);
+
+    // source analysis is done in S/N order (brightest first)
+    sources = psArraySort (sources, pmSourceSortBySN);
+
+    // choose Cx, Cy (see psphotThreadTools.c for overview of the concepts)
+    int Cx = 1, Cy = 1;
+    psphotChooseCellSizes (&Cx, &Cy, readout, nThreads);
+
+    psArray *cellGroups = psphotAssignSources (Cx, Cy, sources);
+
+    for (int i = 0; i < cellGroups->n; i++) {
+
+        psArray *cells = cellGroups->data[i];
+
+        for (int j = 0; j < cells->n; j++) {
+
+            // allocate a job -- if threads are not defined, this just runs the job
+            psThreadJob *job = psThreadJobAlloc ("PSPHOT_EXTENDED_FIT");
+
+            psArrayAdd(job->args, 1, readout);
+            psArrayAdd(job->args, 1, cells->data[j]); // sources
+            psArrayAdd(job->args, 1, models);
+            psArrayAdd(job->args, 1, AnalysisRegion); // XXX make a pointer
+
+            PS_ARRAY_ADD_SCALAR(job->args, psfSize, PS_TYPE_S32);
+            PS_ARRAY_ADD_SCALAR(job->args, maskVal, PS_TYPE_IMAGE_MASK);
+            PS_ARRAY_ADD_SCALAR(job->args, markVal, PS_TYPE_IMAGE_MASK);
+
+            PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Next
+            PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nconvolve
+            PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for NconvolvePass
+            PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nplain
+            PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for NplainPass
+
+            if (!psThreadJobAddPending(job)) {
+                psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
+		psFree(AnalysisRegion);
+                return false;
+            }
+        }
+
+        // wait for the threads to finish and manage results
+        if (!psThreadPoolWait (false)) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
+	    psFree(AnalysisRegion);
+            return false;
+        }
+
+        // we have only supplied one type of job, so we can assume the types here
+        psThreadJob *job = NULL;
+        while ((job = psThreadJobGetDone()) != NULL) {
+            if (job->args->n < 1) {
+                fprintf (stderr, "error with job\n");
+            } else {
+                psScalar *scalar = NULL;
+                scalar = job->args->data[7];
+                Next += scalar->data.S32;
+                scalar = job->args->data[8];
+                Nconvolve += scalar->data.S32;
+                scalar = job->args->data[9];
+                NconvolvePass += scalar->data.S32;
+                scalar = job->args->data[10];
+                Nplain += scalar->data.S32;
+                scalar = job->args->data[11];
+                NplainPass += scalar->data.S32;
+            }
+            psFree(job);
+            }
+    }
+    psFree (cellGroups);
+    psFree(AnalysisRegion);
+
+    psLogMsg ("psphot", PS_LOG_INFO, "extended source analysis: %f sec for %d objects\n", psTimerMark ("psphot.extended"), Next);
+    psLogMsg ("psphot", PS_LOG_INFO, "  %d convolved models (%d passed)\n", Nconvolve, NconvolvePass);
+    psLogMsg ("psphot", PS_LOG_INFO, "  %d plain models (%d passed)\n", Nplain, NplainPass);
+    return true;
+}
+
+// non-linear model fitting for extended sources
+bool psphotExtendedSourceFits_Threaded (psThreadJob *job) {
 
     bool status;
@@ -40,93 +222,14 @@
     bool savePics = false;
     float radius;
-
-    // find the currently selected readout
-    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filerule, index); // File of interest
-    psAssert (file, "missing file?");
-
-    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
-    psAssert (readout, "missing readout?");
-
-    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
-    psAssert (detections, "missing detections?");
-
-    psArray *sources = detections->allSources;
-    psAssert (sources, "missing sources?");
-
-    if (!sources->n) {
-	psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping source size");
-	return true;
-    }
-
-    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
-    psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
-    assert (maskVal);
-
-    psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT"); // Mask value for bad pixels
-    assert (markVal);
-
-    // maskVal is used to test for rejected pixels, and must include markVal
-    maskVal |= markVal;
-
-    // select the collection of desired models
-    psMetadata *models = psMetadataLookupMetadata (&status, recipe, "EXTENDED_SOURCE_MODELS");
-    if (!status) {
-        psWarning ("extended source model fits requested but model model is missing (EXTENDED_SOURCE_MODELS)\n");
-        return true;
-    }
-    if (models->list->n == 0) {
-        psWarning ("extended source model fits requested but no models are specified\n");
-        return true;
-    }
-
-    // validate the model entries
-    psMetadataIterator *iter = psMetadataIteratorAlloc (models, PS_LIST_HEAD, NULL);
-    psMetadataItem *item = NULL;
-    while ((item = psMetadataGetAndIncrement (iter)) != NULL) {
-
-      if (item->type != PS_DATA_METADATA) {
-        psAbort ("Invalid type for EXTENDED_SOURCE_MODEL entry %s, not a metadata folder", item->name);
-        // XXX we could cull the bad entries or build a validated model folder
-      }
-
-      psMetadata *model = (psMetadata *) item->data.md;
-
-      // check on the model type
-      char *modelName = psMetadataLookupStr (&status, model, "MODEL");
-      int modelType = pmModelClassGetType (modelName);
-      if (modelType < 0) {
-        psAbort ("Unknown model class for EXTENDED_SOURCE_MODEL entry %s: %s", item->name, modelName);
-      }
-      psMetadataAddS32 (model, PS_LIST_TAIL, "MODEL_TYPE", PS_META_REPLACE, "", modelType);
-
-      // check on the SNLIM, set a float value
-      char *SNword = psMetadataLookupStr (&status, model, "SNLIM");
-      if (!status) {
-        psAbort("SNLIM not defined for extended source model %s\n", item->name);
-      }
-      float SNlim = atof (SNword);
-      psMetadataAddF32 (model, PS_LIST_TAIL, "SNLIM_VALUE", PS_META_REPLACE, "", SNlim);
-
-      // check on the PSF-Convolution status
-      char *convolvedWord = psMetadataLookupStr (&status, model, "PSF_CONVOLVED");
-      if (!status || (strcasecmp (convolvedWord, "true") && strcasecmp (convolvedWord, "false"))) {
-        psAbort ("PSF_CONVOLVED entry invalid or missing for EXTENDED_SOURCE_MODEL entry %s", item->name);
-      }
-      bool convolved = !strcasecmp (convolvedWord, "true");
-      psMetadataAddBool (model, PS_LIST_TAIL, "PSF_CONVOLVED_VALUE", PS_META_REPLACE, "", convolved);
-    }
-    psFree (iter);
-
-    // option to limit analysis to a specific region
-    char *region = psMetadataLookupStr (&status, recipe, "ANALYSIS_REGION");
-    psRegion AnalysisRegion = psRegionForImage (readout->image, psRegionFromString (region));
-    if (psRegionIsNaN (AnalysisRegion)) psAbort("analysis region mis-defined");
-
-    // what fraction of the PSF is used? (radius in pixels : 2 -> 5x5 box)
-    int psfSize = psMetadataLookupS32 (&status, recipe, "PCM_BOX_SIZE");
-    assert (status);
-
-    // source analysis is done in S/N order (brightest first)
-    sources = psArraySort (sources, pmSourceSortBySN);
+    psScalar *scalar = NULL;
+
+    // arguments: readout, sources, models, region, psfSize, maskVal, markVal
+    pmReadout *readout      = job->args->data[0];
+    psArray *sources        = job->args->data[1];
+    psMetadata *models      = job->args->data[2];
+    psRegion *region        = job->args->data[3];
+    int psfSize             = PS_SCALAR_VALUE(job->args->data[4],PS_TYPE_IMAGE_MASK_DATA);
+    psImageMaskType maskVal = PS_SCALAR_VALUE(job->args->data[5],PS_TYPE_IMAGE_MASK_DATA);
+    psImageMaskType markVal = PS_SCALAR_VALUE(job->args->data[6],PS_TYPE_IMAGE_MASK_DATA);
 
     // Define source fitting parameters for extended source fits
@@ -150,8 +253,8 @@
 
         // XXX this should use peak?
-        if (source->peak->x < AnalysisRegion.x0) continue;
-        if (source->peak->y < AnalysisRegion.y0) continue;
-        if (source->peak->x > AnalysisRegion.x1) continue;
-        if (source->peak->y > AnalysisRegion.y1) continue;
+        if (source->peak->x < region->x0) continue;
+        if (source->peak->y < region->y0) continue;
+        if (source->peak->x > region->x1) continue;
+        if (source->peak->y > region->y1) continue;
 
         // if model is NULL, we don't have a starting guess
@@ -166,5 +269,8 @@
 
 	// set the radius based on the footprint (also sets the mask pixels)
-	if (!psphotSetRadiusFootprint(&radius, readout, source, markVal, 1.0)) return false;
+	if (!psphotSetRadiusFootprint(&radius, readout, source, markVal, 1.0)) {
+	    psFree (fitOptions)
+	    return false;
+	}
 
 	// XXX note that this changes the source moments that are published...
@@ -339,7 +445,20 @@
     psFree (fitOptions);
 
-    psLogMsg ("psphot", PS_LOG_INFO, "extended source analysis: %f sec for %d objects\n", psTimerMark ("psphot"), Next);
-    psLogMsg ("psphot", PS_LOG_INFO, "  %d convolved models (%d passed)\n", Nconvolve, NconvolvePass);
-    psLogMsg ("psphot", PS_LOG_INFO, "  %d plain models (%d passed)\n", Nplain, NplainPass);
+    // change the value of a scalar on the array (wrap this and put it in psArray.h)
+    scalar = job->args->data[7];
+    scalar->data.S32 = Next;
+
+    scalar = job->args->data[8];
+    scalar->data.S32 = Nconvolve;
+
+    scalar = job->args->data[9];
+    scalar->data.S32 = NconvolvePass;
+
+    scalar = job->args->data[10];
+    scalar->data.S32 = Nplain;
+
+    scalar = job->args->data[11];
+    scalar->data.S32 = NplainPass;
+
     return true;
 }
Index: /branches/eam_branches/ipp-20100621/psphot/src/psphotLoadSRCTEXT.c
===================================================================
--- /branches/eam_branches/ipp-20100621/psphot/src/psphotLoadSRCTEXT.c	(revision 28910)
+++ /branches/eam_branches/ipp-20100621/psphot/src/psphotLoadSRCTEXT.c	(revision 28911)
@@ -84,5 +84,6 @@
 	    source->peak->yf   = PAR[PM_PAR_YPOS]; // but we know the pixel coordinate
 
-	    source->pixWeight = 1.0;
+	    source->pixWeightNotBad = 1.0;
+	    source->pixWeightNotPoor = 1.0;
 	    source->crNsigma  = 0.0;
 	    source->extNsigma = 0.0;
Index: /branches/eam_branches/ipp-20100621/psphot/src/psphotMagnitudes.c
===================================================================
--- /branches/eam_branches/ipp-20100621/psphot/src/psphotMagnitudes.c	(revision 28910)
+++ /branches/eam_branches/ipp-20100621/psphot/src/psphotMagnitudes.c	(revision 28911)
@@ -259,4 +259,5 @@
             psArrayAdd(job->args, 1, cells->data[j]); // sources
             PS_ARRAY_ADD_SCALAR(job->args, maskVal,  PS_TYPE_IMAGE_MASK);
+            PS_ARRAY_ADD_SCALAR(job->args, markVal,  PS_TYPE_IMAGE_MASK);
 
             if (!psThreadJobAddPending(job)) {
@@ -295,4 +296,5 @@
     psArray *sources                = job->args->data[0];
     psImageMaskType maskVal         = PS_SCALAR_VALUE(job->args->data[1],PS_TYPE_IMAGE_MASK_DATA);
+    psImageMaskType markVal         = PS_SCALAR_VALUE(job->args->data[2],PS_TYPE_IMAGE_MASK_DATA);
 
     for (int i = 0; i < sources->n; i++) {
@@ -303,12 +305,14 @@
         if (model == NULL) {
           psTrace ("psphot", 3, "fail mag : no valid model");
-          source->pixWeight = NAN;
+          source->pixWeightNotBad = NAN;
+          source->pixWeightNotPoor = NAN;
           continue;
         }
 
-        status = pmSourcePixelWeight (&source->pixWeight, model, source->maskObj, maskVal);
+        status = pmSourcePixelWeight (&source->pixWeightNotBad, &source->pixWeightNotPoor, model, source->maskObj, maskVal, markVal);
         if (!status) {
           psTrace ("psphot", 3, "fail to measure pixel weight");
-          source->pixWeight = NAN;
+          source->pixWeightNotBad = NAN;
+          source->pixWeightNotPoor = NAN;
           continue;
         }
Index: /branches/eam_branches/ipp-20100621/psphot/src/psphotSetThreads.c
===================================================================
--- /branches/eam_branches/ipp-20100621/psphot/src/psphotSetThreads.c	(revision 28910)
+++ /branches/eam_branches/ipp-20100621/psphot/src/psphotSetThreads.c	(revision 28911)
@@ -15,5 +15,5 @@
     psFree(task);
 
-    task = psThreadTaskAlloc("PSPHOT_PSF_WEIGHTS", 2);
+    task = psThreadTaskAlloc("PSPHOT_PSF_WEIGHTS", 3);
     task->function = &psphotPSFWeights_Threaded;
     psThreadTaskAdd(task);
@@ -35,4 +35,9 @@
     psFree(task);
 
+    task = psThreadTaskAlloc("PSPHOT_EXTENDED_FIT", 12);
+    task->function = &psphotExtendedSourceFits_Threaded;
+    psThreadTaskAdd(task);
+    psFree(task);
+
     return true;
 }
Index: /branches/eam_branches/ipp-20100621/psphot/src/psphotSourceSize.c
===================================================================
--- /branches/eam_branches/ipp-20100621/psphot/src/psphotSourceSize.c	(revision 28910)
+++ /branches/eam_branches/ipp-20100621/psphot/src/psphotSourceSize.c	(revision 28911)
@@ -370,7 +370,10 @@
 		 source->psfMag, apMag, dMag, source->errMag, nSigmaMAG, nSigmaMXX, nSigmaMYY);
 
-        // partially-masked sources are more likely to be mis-measured PSFs
+        // XXX double check on ths stuff!! partially-masked sources are more likely to be mis-measured PSFs
         float sizeBias = 1.0;
-        if (source->pixWeight < 0.9) {
+        if (source->pixWeightNotBad < 0.9) {
+            sizeBias = 3.0;
+        }
+        if (source->pixWeightNotPoor < 0.9) {
             sizeBias = 3.0;
         }
@@ -407,5 +410,5 @@
         if (isCR) {
             psTrace("psphotSourceClassRegion.CR",4,"CLASS: %g %g %f\t%g %g  %g %g  %g %g\t%g %g\t%g CR\t%g %g\n",
-                    source->peak->xf,source->peak->yf,source->pixWeight,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG,
+                    source->peak->xf,source->peak->yf,source->pixWeightNotBad,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG,
                     options->nSigmaApResid,sizeBias*options->nSigmaMoments);
             source->mode |= PM_SOURCE_MODE_DEFECT;
