Index: /trunk/psphot/src/Makefile.am
===================================================================
--- /trunk/psphot/src/Makefile.am	(revision 34257)
+++ /trunk/psphot/src/Makefile.am	(revision 34258)
@@ -25,5 +25,5 @@
 libpsphot_la_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
 
-bin_PROGRAMS = psphot psphotForced psphotMakePSF psphotStack psphotModelTest
+bin_PROGRAMS = psphot psphotForced psphotMinimal psphotMakePSF psphotStack psphotModelTest
 # bin_PROGRAMS = psphotPetrosianStudy psphotTest psphotMomentsStudy 
 
@@ -35,4 +35,8 @@
 psphotForced_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
 psphotForced_LDADD = libpsphot.la
+
+psphotMinimal_CFLAGS = $(PSPHOT_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
+psphotMinimal_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
+psphotMinimal_LDADD = libpsphot.la
 
 psphotMakePSF_CFLAGS = $(PSPHOT_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
@@ -73,4 +77,13 @@
         psphotForced.c             \
 	psphotForcedArguments.c	   \
+	psphotParseCamera.c        \
+	psphotImageLoop.c	   \
+	psphotMosaicChip.c	   \
+	psphotCleanup.c
+
+# forced photometry of specified positions given a specified psf
+psphotMinimal_SOURCES = \
+        psphotMinimal.c            \
+	psphotMinimalArguments.c	   \
 	psphotParseCamera.c        \
 	psphotImageLoop.c	   \
Index: /trunk/psphot/src/psphot.h
===================================================================
--- /trunk/psphot/src/psphot.h	(revision 34257)
+++ /trunk/psphot/src/psphot.h	(revision 34258)
@@ -20,4 +20,5 @@
     PSPHOT_MAKE_PSF,
     PSPHOT_MODEL_TEST,
+    PSPHOT_MINIMAL,
 } psphotImageLoopMode;
 
@@ -332,4 +333,7 @@
 bool psphotForcedReadout(pmConfig *config, const pmFPAview *view, const char *filerule);
 
+pmConfig *psphotMinimalArguments(int argc, char **argv);
+bool psphotReadoutMinimal(pmConfig *config, const pmFPAview *view, const char *filerule);
+
 pmConfig *psphotMakePSFArguments(int argc, char **argv);
 bool psphotMakePSFReadout(pmConfig *config, const pmFPAview *view, const char *filerule);
Index: /trunk/psphot/src/psphotBlendFit.c
===================================================================
--- /trunk/psphot/src/psphotBlendFit.c	(revision 34257)
+++ /trunk/psphot/src/psphotBlendFit.c	(revision 34258)
@@ -61,4 +61,9 @@
     if (!status) {
         nThreads = 0;
+    }
+
+    // do not thread if we are trying to study the fitting process
+    if (psTraceGetLevel ("psphot.psphotFitEXT") >= 6) {
+      nThreads = 0;
     }
 
Index: /trunk/psphot/src/psphotExtendedSourceFits.c
===================================================================
--- /trunk/psphot/src/psphotExtendedSourceFits.c	(revision 34257)
+++ /trunk/psphot/src/psphotExtendedSourceFits.c	(revision 34258)
@@ -77,4 +77,8 @@
     if (!status) {
         nThreads = 0;
+    }
+    // do not thread if we are trying to study the fitting process
+    if (psTraceGetLevel ("psphot.psphotFitEXT") >= 6) {
+      nThreads = 0;
     }
 
@@ -468,4 +472,7 @@
         psFree (source->modelEXT);
         source->modelEXT = psMemIncrRefCounter (source->modelFits->data[minModel]);
+	source->type = PM_SOURCE_TYPE_EXTENDED;
+	source->mode |= PM_SOURCE_MODE_EXTMODEL;
+	source->mode |= PM_SOURCE_MODE_NONLINEAR_FIT;
 
 	// adjust the window so the subtraction covers the faint wings
Index: /trunk/psphot/src/psphotForced.c
===================================================================
--- /trunk/psphot/src/psphotForced.c	(revision 34257)
+++ /trunk/psphot/src/psphotForced.c	(revision 34258)
@@ -1,4 +1,3 @@
 # include "psphotStandAlone.h"
-# define FORCED_PHOTOMETRY 1
 
 int main (int argc, char **argv) {
Index: /trunk/psphot/src/psphotImageLoop.c
===================================================================
--- /trunk/psphot/src/psphotImageLoop.c	(revision 34257)
+++ /trunk/psphot/src/psphotImageLoop.c	(revision 34258)
@@ -118,4 +118,11 @@
 		    }
 		    break;
+		  case PSPHOT_MINIMAL:
+		    if (!psphotReadoutMinimal (config, view, "PSPHOT.INPUT")) {
+			psError(psErrorCodeLast(), false, "failure in psphotReadout for chip %d, cell %d, readout %d\n", view->chip, view->cell, view->readout);
+			psFree (view);
+			return false;
+		    }
+		    break;
 		  case PSPHOT_FORCED:
 		    if (!psphotForcedReadout (config, view, "PSPHOT.INPUT")) {
Index: /trunk/psphot/src/psphotMinimal.c
===================================================================
--- /trunk/psphot/src/psphotMinimal.c	(revision 34258)
+++ /trunk/psphot/src/psphotMinimal.c	(revision 34258)
@@ -0,0 +1,36 @@
+# include "psphotStandAlone.h"
+
+int main (int argc, char **argv) {
+
+    psMemInit();	      // needed if USE_SPINLOCK is set in psMemory.c
+    psTimerStart ("complete");
+    pmErrorRegister();                  // register psModule's error codes/messages
+    psphotInit();
+
+    // load command-line arguments, options, and system config data
+    pmConfig *config = psphotMinimalArguments (argc, argv);
+    assert(config);
+
+    psphotVersionPrint();
+
+    // load input data (config and images (signal, noise, mask)
+    if (!psphotParseCamera (config)) {
+        psErrorStackPrint(stderr, "Error setting up the camera\n");
+        exit (psphotGetExitStatus());
+    }
+
+    // call psphot for each readout
+    if (!psphotImageLoop (config, PSPHOT_MINIMAL)) {
+        psErrorStackPrint(stderr, "Error in the psphot image loop\n");
+        exit (psphotGetExitStatus());
+    }
+
+    psLogMsg ("psphot", PS_LOG_WARN, "complete psphot run: %f sec\n", psTimerMark ("complete"));
+
+    psErrorCode exit_status = psphotGetExitStatus();
+    psphotCleanup (config);
+    exit (exit_status);
+}
+
+// all functions which return to this level must raise one of the top-level error codes if they
+// exit with an error.  these error codes are used to specify the program exit status
Index: /trunk/psphot/src/psphotMinimalArguments.c
===================================================================
--- /trunk/psphot/src/psphotMinimalArguments.c	(revision 34258)
+++ /trunk/psphot/src/psphotMinimalArguments.c	(revision 34258)
@@ -0,0 +1,200 @@
+# include "psphotStandAlone.h"
+
+static void writeHelpInfo(const char* program, pmConfig* config, FILE* ofile)
+{
+  fprintf(ofile,
+	  "Usage: one of the following\n"
+	  "%s -file fname1[,fname2,...] -mask maskfile1[,maskfile2,...]\n"
+	  "     -variance varfile1[,varfile2,...] OutFileBaseName\n"
+	  "\n"
+	  "%s -list FileNameList [-masklist MaskFileNameList] \n"
+	  "     -variancelist VarFileNameList OutFileBaseName\n"
+	  "\n"
+	  "%s -help\n"
+	  "\n"
+	  "%s -version\n"
+	  "\n"
+	  "where:\n"
+	  "  FileNameList is a text file containing filenames, one per line\n"
+	  "  MaskFileNameList is a text file of mask filenames, one per line\n"
+	  "  VarFileNameList is a text file of variance filenames, one per line\n"
+	  "  OutFileBaseName is the 'root name' for output files\n"
+	  "\n"
+	  "additional options:\n"
+	  "  -modeltest xObj yObj [-model DEFAULT|ModelName] \n"
+	  "        [-fitmode DEFAULT|PSF|CONV] [-fitset FitFileName]\n"
+	  "     Test fit for object at the given coordinates.  ModelName\n"
+	  "     is one of PS_MODEL_GAUSS, PS_MODEL_PGAUSS, PS_MODEL_QGAUSS,\n"
+	  "     PS_MODEL_RGAUSS, PS_MODEL_PS1_V1, or PS_MODEL_SERSIC.\n"
+	  "     FitFileName is a file of x,y,Io triples.\n"
+	  "  -psf PsfFile1[,PsfFile2,...] or -psflist PsfFileNameList\n"
+	  "     specify PSF rather than letting %s estimate it\n"
+	  "  -src SrcFile1[,SrcFile2,...] or -srclist SrcFileNameList\n"
+	  "     specify additional sources for PSF generation\n"
+	  "  -chip nn[,nn,...]\n"
+	  "     select detector chips to process; default is all.\n"
+	  "     Indices correspond to zero-based offset in the FPA metadata table.\n"
+	  "  -photcode PhotoCodeName\n"
+	  "     specify photocode\n"
+	  "  -region RegionString\n"
+	  "     specify analysis region.  String is of form '[x0:x1,y0:y1]'\n"
+	  "     To use this option you must define a default in psphot.config\n"
+	  "  -visual\n"
+	  "     turns on interactive display mode\n"
+	  "  -dumpconfig CfgFileName\n"
+          "     causes config info to be dumped to the named file.\n"
+	  "  -break NOTHING|BACKMDL|PEAKS|MOMENTS|PSFMODEL|ENSEMBLE|PASS1\n"
+	  "     choose a point at which to exit processing early\n"
+	  "  -nthreads n\n"
+	  "     set number of parallel threads of execution\n"
+	  "  -F OldFileRule ReplacementFileRule\n"
+	  "     change file naming rule; e.g. '-F PSPHOT.OUTPUT PSPHOT.OUT.CMF.MEF'\n"
+	  "  -D name stringval\n"
+	  "     set a string-valued config parameter\n"
+	  "  -Di name intval\n"
+	  "     set an integer-valued config parameter\n"
+	  "  -Df name fval\n"
+	  "     set a float-valued config parameter\n"
+	  "  -Db name boolval\n"
+	  "     set a boolean-valued config parameter\n"
+	  "  -v, -vv, -vvv\n"
+	  "     set increasing levels of verbosity\n"
+	  "  -logfmt FormatString\n"
+	  "     set format string used for log messages\n"
+	  "  -trace Fac Lvl\n"
+	  "     set tracing for facility Fac to integer Lvl, e.g. '-trace err 10'\n"
+	  "  -trace-levels\n"
+	  "     print current trace levels\n",
+	  program,program,program,program,program);
+    psFree(config);
+    pmConfigDone();
+    psLibFinalize();
+    exit(PS_EXIT_SUCCESS);
+}
+
+static void usage(const char *program,  // Name of the program
+                  psMetadata *arguments, // Command-line arguments
+                  pmConfig *config,      // Configuration
+		  int exitCode
+		  ) 
+{
+  fprintf(stderr,
+	  "Usage: one of the following\n"
+	  "%s -file fname1[,fname2,...] -mask maskfile1[,maskfile2,...]\n"
+	  "     -variance varfile1[,varfile2,...] OutFileBaseName\n"
+	  "\n"
+	  "%s -list FileNameList [-masklist MaskFileNameList] \n"
+	  "     -variancelist VarFileNameList OutFileBaseName\n"
+	  "\n"
+	  "Try '%s -help' for more options and explanation\n",
+	  program,program,program);
+    if (exitCode != PS_EXIT_SUCCESS)
+      psErrorStackPrint(stderr, "Error reading arguments\n");
+    psFree(config);
+    pmConfigDone();
+    psLibFinalize();
+    exit(exitCode);
+}
+
+pmConfig *psphotMinimalArguments(int argc, char **argv) {
+
+    int N;
+    bool status;
+
+    // load config data from default locations
+    pmConfig *config = pmConfigRead(&argc, argv, PSPHOT_RECIPE);
+    if (config == NULL) {
+      psErrorStackPrint(stderr, "Can't read site configuration");
+	exit(PS_EXIT_CONFIG_ERROR);
+    }
+
+    // generic arguments (version, dumpconfig)
+    PS_ARGUMENTS_GENERIC( psphot, config, argc, argv );
+
+    // thread arguments
+    PS_ARGUMENTS_THREADS( psphot, config, argc, argv )
+
+    // save the following additional recipe values based on command-line options
+    // these options override the PSPHOT recipe values loaded from recipe files
+    psMetadata *options = pmConfigRecipeOptions (config, PSPHOT_RECIPE);
+
+    // photcode : used in output to supplement header data (argument or recipe?)
+    if ((N = psArgumentGet (argc, argv, "-photcode"))) {
+        if (argc<=N+1) {
+	  psErrorStackPrint(stderr, "Expected to see 1 more argument; saw %d", argc - 1);
+	  exit(PS_EXIT_CONFIG_ERROR);
+	}
+        psArgumentRemove (N, &argc, argv);
+        psMetadataAddStr (options, PS_LIST_TAIL, "PHOTCODE", PS_META_REPLACE, "", argv[N]);
+        psArgumentRemove (N, &argc, argv);
+    }
+
+    // break : used from recipe throughout psphotReadout
+    if ((N = psArgumentGet (argc, argv, "-break"))) {
+	if (argc<=N+1) {
+	  psErrorStackPrint(stderr, "Expected to see 1 more argument; saw %d", argc - 1);
+	  exit(PS_EXIT_CONFIG_ERROR);
+	}
+        psArgumentRemove (N, &argc, argv);
+        psMetadataAddStr (options, PS_LIST_TAIL, "BREAK_POINT", PS_META_REPLACE, "", argv[N]);
+        psArgumentRemove (N, &argc, argv);
+    }
+
+    // analysis region : overrides recipe value, used in psphotReadout/psphotEnsemblePSF
+    if ((N = psArgumentGet (argc, argv, "-region"))) {
+	if (argc<=N+1) {
+	  psErrorStackPrint(stderr, "Expected to see 1 more argument; saw %d", argc - 1);
+	  exit(PS_EXIT_CONFIG_ERROR);
+	}
+        psArgumentRemove (N, &argc, argv);
+        psMetadataAddStr (options, PS_LIST_TAIL, "ANALYSIS_REGION", 0, "", argv[N]);
+        psArgumentRemove (N, &argc, argv);
+    }
+
+    // chip selection is used to limit chips to be processed
+    if ((N = psArgumentGet (argc, argv, "-chip"))) {
+	if (argc<=N+1) {
+	  psErrorStackPrint(stderr, "Expected to see 1 more argument; saw %d", argc - 1);
+	  exit(PS_EXIT_CONFIG_ERROR);
+	}
+        psArgumentRemove (N, &argc, argv);
+        psMetadataAddStr (config->arguments, PS_LIST_TAIL, "CHIP_SELECTIONS", PS_DATA_STRING, "", argv[N]);
+        psArgumentRemove (N, &argc, argv);
+    }
+
+    // if these command-line options are supplied, load the file name lists into config->arguments
+    // override any configuration-specified source for these files
+    //
+    pmConfigFileSetsMD (config->arguments, &argc, argv, "MASK",       "-mask",     "-masklist");
+    pmConfigFileSetsMD (config->arguments, &argc, argv, "VARIANCE",   "-variance", "-variancelist");
+    pmConfigFileSetsMD (config->arguments, &argc, argv, "PSPHOT.PSF", "-psf",      "-psflist");
+    pmConfigFileSetsMD (config->arguments, &argc, argv, "SRC",        "-src",      "-srclist");
+    pmConfigFileSetsMD (config->arguments, &argc, argv, "EXPNUM",     "-expnum",   "-expnumlist");
+
+    if (argc == 1) {
+        psError(PSPHOT_ERR_ARGUMENTS, true, "Too few arguments: %d", argc);
+	usage(argv[0], config->arguments, config, PS_EXIT_CONFIG_ERROR);
+    }
+
+    if (psArgumentGet(argc, argv, "-help") ||
+	psArgumentGet(argc, argv, "-h"))
+      writeHelpInfo(argv[0], config, stdout);
+      
+    // the input file is a required argument; if not found, we will exit
+    status = pmConfigFileSetsMD (config->arguments, &argc, argv, "INPUT", "-file", "-list");
+    if (!status) {
+        psError(PSPHOT_ERR_ARGUMENTS, false, "pmConfigFileSetsMD failed to parse arguments");
+	usage(argv[0], config->arguments, config, PS_EXIT_CONFIG_ERROR);
+    }
+
+    if (argc != 2) {
+        psError(PSPHOT_ERR_ARGUMENTS, true, "Expected to see one more argument; saw %d", argc - 1);
+	usage(argv[0], config->arguments, config, PS_EXIT_CONFIG_ERROR);
+    }
+
+    // output position is fixed
+    psMetadataAddStr (config->arguments, PS_LIST_TAIL, "OUTPUT", 0, "", argv[1]);
+
+    psTrace("psphot", 1, "Done with psphotArguments...\n");
+    return (config);
+}
Index: /trunk/psphot/src/psphotReadoutMinimal.c
===================================================================
--- /trunk/psphot/src/psphotReadoutMinimal.c	(revision 34257)
+++ /trunk/psphot/src/psphotReadoutMinimal.c	(revision 34258)
@@ -25,4 +25,16 @@
     // Generate the mask and weight images, including the user-defined analysis region of interest
     psphotSetMaskAndVariance (config, view, filerule);
+
+    // only subtract background if needed?
+    // activate this for a clean test with psphotMinimal. (add to recipe!)
+    if (0) {
+      // generate a background model (median, smoothed image)
+      if (!psphotModelBackground (config, view, filerule)) {
+        return psphotReadoutCleanup (config, view, filerule);
+      }
+      if (!psphotSubtractBackground (config, view, filerule)) {
+        return psphotReadoutCleanup (config, view, filerule);
+      }
+    }
 
     // load the psf model, if suppled.  FWHM_X,FWHM_Y,etc are saved on readout->analysis
@@ -72,13 +84,18 @@
     psphotFitSourcesLinear (config, view, filerule, false, false);
 
-// XXX eventually, add the extended source fits here
-# if (0)
+    // measure the radial profiles to the sky
+    psphotRadialProfileWings (config, view, filerule);
+
+    // re-measure the kron mags with models subtracted and more appropriate windows
+    psphotKronIterate(config, view, filerule);
+
     // measure source size for the remaining sources
-    psphotSourceSize (config, view, filerule);
+    psphotSourceSize (config, view, filerule, false);
 
-    psphotExtendedSourceAnalysis (config, view, filerule);
+    // NOTE: Petrosian and Isophotal mags are not relevant at this time
+    // psphotExtendedSourceAnalysis (config, view, filerule);
 
+    // in ppSub context, this is used to fit TRAILs (and maybe EXP for comets)
     psphotExtendedSourceFits (config, view, filerule);
-# endif
 
     // calculate source magnitudes
Index: /trunk/psphot/src/psphotSourceFits.c
===================================================================
--- /trunk/psphot/src/psphotSourceFits.c	(revision 34257)
+++ /trunk/psphot/src/psphotSourceFits.c	(revision 34258)
@@ -463,4 +463,34 @@
     }
 
+# if (PS_TRACE_ON) 
+    if (psTraceGetLevel ("psphot") >= 6) {
+
+      // Moments-based shapes parameters
+      psEllipseMoments moments;
+      moments.x2 = source->moments->Mxx;
+      moments.xy = source->moments->Mxy;
+      moments.y2 = source->moments->Myy;
+      // force the axis ratio to be < 20.0
+      psEllipseAxes axes = psEllipseMomentsToAxes (moments, 20.0);
+
+      // PSF shape parameters
+      psEllipseShape psfShape;
+      psfShape.sx  = source->modelPSF->params->data.F32[PM_PAR_SXX] / M_SQRT2;
+      psfShape.sxy = source->modelPSF->params->data.F32[PM_PAR_SXY];
+      psfShape.sy  = source->modelPSF->params->data.F32[PM_PAR_SYY] / M_SQRT2;
+      psEllipseAxes psfAxes = psEllipseShapeToAxes (psfShape, 20.0);
+
+      fprintf (stderr, "--- guess values ---\n");
+      fprintf (stderr, "(x,y): %f, %f  Mxx: %f, Myy: %f, Mxy: %f -> major: %f, minor: %f, theta: %f (%f deg)\n", source->peak->xf, source->peak->yf, source->moments->Mxx, source->moments->Myy, source->moments->Mxy, axes.major, axes.minor, axes.theta, axes.theta*PS_DEG_RAD);
+      fprintf (stderr, "psf: major: %f, minor: %f, theta: %f (%f deg)\n", psfAxes.major, psfAxes.minor, psfAxes.theta, psfAxes.theta*PS_DEG_RAD);
+      for (int i = 0; i < model->params->n; i++) {
+	fprintf (stderr, "par %d: %f\n", i, model->params->data.F32[i]);
+      }
+    }
+    if (psTraceGetLevel ("psphot") >= 7) {
+      psTraceSetLevel("psLib.math.psMinimizeLMChi2", 5);
+    }
+# endif
+
     // for sersic models, use a grid search to choose an index, then float the params there
     if (modelType == pmModelClassGetType("PS_MODEL_SERSIC")) {
@@ -468,14 +498,26 @@
     }
 
+    options.mode = PM_SOURCE_FIT_EXT;
     if (modelType == pmModelClassGetType("PS_MODEL_SERSIC")) {
 	options.mode = PM_SOURCE_FIT_NO_INDEX;
-    } else {
-	options.mode = PM_SOURCE_FIT_EXT;
-    }
-
-    // psTraceSetLevel("psLib.math.psMinimizeLMChi2", 5);
+    }
+    if (modelType == pmModelClassGetType("PS_MODEL_TRAIL")) {
+	options.mode = PM_SOURCE_FIT_TRAIL;
+    }
+
     pmSourceFitModel (source, model, &options, maskVal);
-    // fprintf (stderr, "chisq: %f, nIter: %d, radius: %f, npix: %d\n", model->chisqNorm, model->nIter, model->fitRadius, model->nPix);
-    // psTraceSetLevel("psLib.math.psMinimizeLMChi2", 0);
+
+# if (PS_TRACE_ON) 
+    if (psTraceGetLevel ("psphot") >= 5) {
+      if (psTraceGetLevel ("psphot") >= 6) {
+	fprintf (stderr, "chisq: %f, nIter: %d, radius: %f, npix: %d\n", model->chisqNorm, model->nIter, model->fitRadius, model->nPix);
+      }
+      fprintf (stderr, "--- fitted values ---\n");
+      for (int i = 0; i < model->params->n; i++) {
+	fprintf (stderr, "par %d: %f\n", i, model->params->data.F32[i]);
+      }
+      psTraceSetLevel("psLib.math.psMinimizeLMChi2", 0);
+    }
+# endif
 
     return (model);
Index: /trunk/psphot/src/psphotSourceSize.c
===================================================================
--- /trunk/psphot/src/psphotSourceSize.c	(revision 34257)
+++ /trunk/psphot/src/psphotSourceSize.c	(revision 34258)
@@ -462,4 +462,14 @@
     psImageMaskType maskVal = options->maskVal | options->markVal;
 
+    // in the ppSub context, do we get sensible values for ApResid?
+    float ApResidPSF = options->ApResid;
+    if (!isfinite(ApResidPSF)) {
+      ApResidPSF = 0.0;
+    }
+    float ApSysErrPSF = options->ApSysErr;
+    if (!isfinite(ApSysErrPSF)) {
+      ApSysErrPSF = 0.0;
+    }
+
     for (psS32 i = 0 ; i < sources->n ; i++) {
 
@@ -529,5 +539,5 @@
         // set nSigmaMAG to include both systematic and poisson error terms.  we include a hard
 	// floor on the Ap Sys Err (to be a bit generous).  XXX put the floor in the recipe...
-        float nSigmaMAG = (dMag - options->ApResid) / hypot(source->psfMagErr, hypot(options->ApSysErr, 0.02));
+        float nSigmaMAG = (dMag - ApResidPSF) / hypot(source->psfMagErr, hypot(ApSysErrPSF, 0.02));
         source->extNsigma = nSigmaMAG;
 
