Index: trunk/psphot/src/psphotStackObjects.c
===================================================================
--- trunk/psphot/src/psphotStackObjects.c	(revision 28013)
+++ trunk/psphot/src/psphotStackObjects.c	(revision 32348)
@@ -47,2 +47,96 @@
     return true;
 }
+
+// mark good vs bad objects
+bool psphotStackObjectsSelectForAnalysis (pmConfig *config, const pmFPAview *view, const char *filerule, psArray *objects) {
+
+    bool status = false;
+
+    // find the currently selected readout
+    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filerule, 0); // use the 0-index image to represent the image area
+    psAssert (file, "missing file?");
+
+    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
+    psAssert (readout, "missing readout?");
+
+    // select the appropriate recipe information
+    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
+    psAssert (recipe, "missing recipe?");
+
+    // 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");
+
+    // S/N limit to perform full non-linear fits
+    float SN_LIM = psMetadataLookupF32 (&status, recipe, "EXTENDED_SOURCE_SN_LIM");
+
+    bool doPetroStars   = psMetadataLookupBool (&status, recipe, "PETROSIAN_FOR_STARS");
+
+    for (int i = 0; i < objects->n; i++) {
+        pmPhotObj *object = objects->data[i];
+	if (!object) continue;
+	if (!object->sources) continue;
+
+	// we check each source for an object and keep the object if any source is valid
+
+	bool keepObject = false;
+	for (int j = 0; j < object->sources->n; j++) {
+
+	    pmSource *source = object->sources->data[j];
+	    if (!source) continue;
+	    if (!source->peak) continue;
+
+	    // skip PSF-like and non-astronomical objects
+	    if (source->type == PM_SOURCE_TYPE_DEFECT) continue;
+	    if (source->type == PM_SOURCE_TYPE_SATURATED) continue;
+	    if (source->mode & PM_SOURCE_MODE_DEFECT) continue;
+	    if (source->mode & PM_SOURCE_MODE_SATSTAR) continue;
+	    
+	// optionally allow non-extended objects to get petrosians as well
+	if (!doPetroStars) {
+	    if (!(source->mode & PM_SOURCE_MODE_EXT_LIMIT)) continue;
+	    if (source->type == PM_SOURCE_TYPE_STAR) continue;
+	}
+
+	    // limit selection to some SN limit
+	    // assert (source->peak); // how can a source not have a peak?
+	    // limit selection to some SN limit
+	    bool skipSource = false;
+	    if (source->mode & PM_SOURCE_MODE_EXT_LIMIT) {
+		skipSource = (source->moments->KronFlux < SN_LIM * source->moments->KronFluxErr);
+	    } else {
+		skipSource = (sqrt(source->peak->detValue) < SN_LIM);
+	    }
+	    if (skipSource) continue;
+
+	    // limit selection by analysis region (this automatically apply
+	    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;
+	    
+	    keepObject = true;
+	}
+
+	for (int j = 0; j < object->sources->n; j++) {
+	    pmSource *source = object->sources->data[j];
+	    if (!source) continue;
+	    if (!source->peak) continue;
+
+	    // we have to set a bit in either case to tell psphotExtendedSourceAnalysis to
+	    // avoid the single-detection tests
+
+	    if (keepObject) {
+		source->tmpFlags |=  PM_SOURCE_TMPF_STACK_KEEP;
+		source->tmpFlags &= ~PM_SOURCE_TMPF_STACK_SKIP;
+	    } else {
+		source->tmpFlags |=  PM_SOURCE_TMPF_STACK_SKIP;
+		source->tmpFlags &= ~PM_SOURCE_TMPF_STACK_KEEP;
+	    }	    
+	}
+    }
+
+    psLogMsg ("psphot", PS_LOG_INFO, "marked good vs bad objects\n");
+    return true;
+}
