Index: /branches/eam_branch_20080511/ppSim/configure.ac
===================================================================
--- /branches/eam_branch_20080511/ppSim/configure.ac	(revision 17671)
+++ /branches/eam_branch_20080511/ppSim/configure.ac	(revision 17672)
@@ -17,7 +17,8 @@
 AC_SYS_LARGEFILE
 
-PKG_CHECK_MODULES([PSLIB], [pslib >= 1.0.0])
+PKG_CHECK_MODULES([PSLIB],    [pslib >= 1.0.0])
 PKG_CHECK_MODULES([PSMODULE], [psmodules >= 1.0.0])
-PKG_CHECK_MODULES([PSASTRO], [psastro >= 0.9.0])
+PKG_CHECK_MODULES([PSPHOT],   [psphot >= 0.8.0]) 
+PKG_CHECK_MODULES([PSASTRO],  [psastro >= 0.9.0])
 
 IPP_STDOPTS
Index: /branches/eam_branch_20080511/ppSim/src/Makefile.am
===================================================================
--- /branches/eam_branch_20080511/ppSim/src/Makefile.am	(revision 17671)
+++ /branches/eam_branch_20080511/ppSim/src/Makefile.am	(revision 17672)
@@ -1,6 +1,6 @@
 bin_PROGRAMS = ppSim ppSimSequence
 
-ppSim_CPPFLAGS = $(PSLIB_CFLAGS) $(PSMODULE_CFLAGS) $(PSASTRO_CFLAGS) $(ppSim_CFLAGS)
-ppSim_LDFLAGS = $(PSLIB_LIBS) $(PSMODULE_LIBS) $(PSASTRO_LIBS)
+ppSim_CPPFLAGS = $(PSLIB_CFLAGS) $(PSMODULE_CFLAGS) $(PSPHOT_CFLAGS) $(PSASTRO_CFLAGS) $(ppSim_CFLAGS)
+ppSim_LDFLAGS = $(PSLIB_LIBS) $(PSMODULE_LIBS) $(PSPHOT_LIBS) $(PSASTRO_LIBS)
 ppSim_SOURCES = \
 	ppSim.c			\
Index: /branches/eam_branch_20080511/ppSim/src/ppSim.c
===================================================================
--- /branches/eam_branch_20080511/ppSim/src/ppSim.c	(revision 17671)
+++ /branches/eam_branch_20080511/ppSim/src/ppSim.c	(revision 17672)
@@ -1,3 +1,11 @@
 # include "ppSim.h"
+
+int failure (pmConfig *config, psExit status, char *message) { 
+    psErrorStackPrint(stderr, message);
+    psFree(config);
+    pmModelClassCleanup();
+    psLibFinalize();
+    exit (status);
+}
 
 int main(int argc, char *argv[])
@@ -8,20 +16,17 @@
     pmConfig *config = pmConfigRead(&argc, argv, PPSIM_RECIPE); // Configuration
     if (!config) {
-        psErrorStackPrint(stderr, "Unable to read configurations.");
-        exit(PS_EXIT_CONFIG_ERROR);
+	failure (config, PS_EXIT_CONFIG_ERROR, "Unable to read configurations.");
     }
 
-    ppSimArguments(argc, argv, config);
+    if (!ppSimArguments(argc, argv, config)) {
+	failure (config, PS_EXIT_CONFIG_ERROR, "Error parsing command-line arguments");
+    }
 
     if (!ppSimCreate(config)) {
-        psErrorStackPrint(stderr, "Unable to create output file.");
-        psFree(config);
-        exit(PS_EXIT_CONFIG_ERROR);
+	failure (config, PS_EXIT_CONFIG_ERROR, "Unable to create output file.");
     }
 
     if (!ppSimLoop(config)) {
-        psErrorStackPrint(stderr, "Unable to generate data.");
-        psFree(config);
-        exit(PS_EXIT_SYS_ERROR);
+	failure (config, PS_EXIT_SYS_ERROR, "Unable to generate data.");
     }
 
@@ -32,4 +37,4 @@
     psLibFinalize();
 
-    return PS_EXIT_SUCCESS;
+    exit (PS_EXIT_SUCCESS);
 }
Index: /branches/eam_branch_20080511/ppSim/src/ppSim.h
===================================================================
--- /branches/eam_branch_20080511/ppSim/src/ppSim.h	(revision 17671)
+++ /branches/eam_branch_20080511/ppSim/src/ppSim.h	(revision 17672)
@@ -13,4 +13,5 @@
 #include <psmodules.h>
 #include <psastro.h>
+#include <psphot.h>
 
 #define PPSIM_RECIPE "PPSIM"
@@ -18,7 +19,7 @@
 
 // Compare a value with minimum and maximum values, replacing where required.
-#define COMPARE(VALUE,MIN,MAX) { \
-        if (VALUE < MIN) { MIN = VALUE; } \
-        if (VALUE > MAX) { MAX = VALUE; } \
+#define COMPARE(VALUE,MIN,MAX) {		\
+        if (VALUE < MIN) { MIN = VALUE; }	\
+        if (VALUE > MAX) { MAX = VALUE; }	\
     }
 
@@ -70,7 +71,7 @@
 
 /// Parse command-line arguments
-void ppSimArguments(int argc, char *argv[], ///< Command-line arguments
+bool ppSimArguments(int argc, char **argv, ///< Command-line arguments
                     pmConfig *config ///< Configuration
-                    );
+    );
 
 /// Create output file
@@ -78,18 +79,18 @@
 /// Returns a borrowed pointer to the FPA file.
 pmFPAfile *ppSimCreate(pmConfig *config ///< Configuration
-                       );
+    );
 
 // Return bounds of a chip, based on the concepts
 psRegion *ppSimChipBounds(const pmChip *chip, // Chip for which to determine size
                           pmFPAview *view // View for chip
-                          );
+    );
 
 // Return bounds of an FPA, based on the concepts
 psRegion *ppSimFPABounds(const pmFPA *fpa       // FPA for which to determine size
-                         );
+    );
 
 /// Loop over the output file, generating simulated data
 bool ppSimLoop(pmConfig *config ///< Configuration
-                 );
+    );
 
 psVector *ppSimMakeBiassec (pmCell *cell, pmConfig *config);
@@ -98,5 +99,5 @@
 bool ppSimMakeSky (pmReadout *readout, psImage *expCorr, ppSimType type, pmConfig *config);
 
-psArray *ppSimLoadSpots (pmFPA *fpa, pmConfig *config);
+bool ppSimLoadSpots (pmFPA *fpa, pmConfig *config);
 
 bool ppSimLoadStars (psArray *stars, pmFPA *fpa, pmConfig *config);
@@ -147,3 +148,29 @@
 float ppSimMagToFlux (float mag, float zp);
 
+float ppSimArgToRecipeF32(bool *status, 
+			  psMetadata *options,    // Target to which to add value
+			  const char *recipeName, // Name for value in the recipe
+			  psMetadata *arguments,  // Command-line arguments
+			  const char *argName	 // Argument name in the command-line arguments
+    );
+
+int ppSimArgToRecipeS32(bool *status,
+			psMetadata *options,    // Target to which to add value
+			const char *recipeName, // Name for value in the recipe
+			psMetadata *arguments,  // Command-line arguments
+			const char *argName	 // Argument name in the command-line arguments
+    );
+
+char *ppSimArgToRecipeStr(bool *status,
+			  psMetadata *options,    // Target to which to add value
+			  const char *recipeName, // Name for value in the recipe
+			  psMetadata *arguments,  // Command-line arguments
+			  const char *argName	 // Argument name in the command-line arguments
+    );
+
+ppSimType ppSimTypeFromString (char *typeStr);
+char *ppSimTypeToString (ppSimType type);
+
+float ppSimGetZeroPoint (psMetadata *recipe, char *filter);
+
 #endif
Index: /branches/eam_branch_20080511/ppSim/src/ppSimArguments.c
===================================================================
--- /branches/eam_branch_20080511/ppSim/src/ppSimArguments.c	(revision 17671)
+++ /branches/eam_branch_20080511/ppSim/src/ppSimArguments.c	(revision 17672)
@@ -1,3 +1,3 @@
-#include "ppSim.h"
+# include "ppSim.h"
 
 // Print usage information and die
@@ -18,26 +18,15 @@
 }
 
-// Get a value from the command-line arguments and add it to recipe options
-bool valueArgRecipe(psMetadata *options,    // Target to which to add value
-                    const char *recipeName, // Name for value in the recipe
-		    psMetadata *arguments,  // Command-line arguments
-                    const char *argName	    // Argument name in the command-line arguments
-    )
+// this function supplements the RECIPE:OPTIONS folder with command-line options
+bool ppSimArguments(int argc, char **argv, pmConfig *config)
 {
-    bool status;						    // Status of MD lookup
-    float value = psMetadataLookupF32(&status, arguments, argName); // Value of interest
-    if (isnan(value)) return true;
-    status = psMetadataAddF32(options, PS_LIST_TAIL, recipeName, 0, NULL, value);
-    return status;
-}
-
-// this function supplements the RECIPE:OPTIONS folder with command-line options
-void ppSimArguments(int argc, char *argv[], pmConfig *config)
-{
+    bool status;
     bool mdok;                          // Status of MD lookup
 
     assert(config);
 
-    // save the following command-line options in the arguments structure
+    // save the following command-line options in the arguments structure.  these will later be
+    // parsed and moved to the config->recipes:PPSIM_RECIPE folder
+
     psMetadata *arguments = psMetadataAlloc(); // Command-line arguments
     psMetadataAddStr(arguments, PS_LIST_TAIL, "-format", 0, "Camera format name", NULL);
@@ -71,19 +60,67 @@
 
     pmConfigFileSetsMD (config->arguments, &argc, argv, "PSPHOT.PSF", "-psf", "-psflist");
-
-    // only one of -camera and -file is needed
-    bool status = pmConfigFileSetsMD (config->arguments, &argc, argv, "INPUT", "-file", "-list");
-    if (!config->camera && !status) {
-        psErrorStackPrint(stderr, "A camera name (-camera NAME) or an image (-file NAME) must be specified");
-	exit(PS_EXIT_CONFIG_ERROR);
+    if (psErrorCodeLast () != PS_ERR_NONE) { psAbort ("problem with PSPHOT.PSF option"); }
+
+    // Only one of -camera and -file is needed or allowed.  The -camera option would have been
+    // already parsed by pmConfigRead in ppSim.c and resulted in a value for config->camera
+    bool loadImage = pmConfigFileSetsMD (config->arguments, &argc, argv, "INPUT", "-file", "-list");
+    if (!config->camera && !loadImage) {
+	psError(PS_ERR_IO, true, "A camera name (-camera NAME) or an image (-file NAME) must be specified");
+        psFree(arguments);
+	return false;
+    }
+    if (config->camera && loadImage) {
+        psError(PS_ERR_IO, true, "Only one of (-camera NAME) and (-file NAME) may be specified");
+        psFree(arguments);
+	return false;
     }
 
     if (!psArgumentParse(arguments, &argc, argv)) { 
-	exit(PS_EXIT_CONFIG_ERROR);
+        psError(PS_ERR_IO, false, "error in command-line arguments");
+        psFree(arguments);
+	return false;
     }
 
     if (argc != 2) { 
-        psErrorStackPrint(stderr, "Missing output filename");
-	exit(PS_EXIT_CONFIG_ERROR);
+	psError(PS_ERR_IO, true, "Missing output filename");
+        psFree(arguments);
+	return false;
+    }
+
+    // output filename
+    psMetadataAddStr(config->arguments, PS_LIST_TAIL, "OUTPUT", 0, "Name of the output image", argv[1]);
+
+    // save the additional recipe values based on command-line options. These options override
+    // the PPSIM recipe values loaded from recipe files
+    psMetadata *options = pmConfigRecipeOptions (config, PPSIM_RECIPE);
+    if (!options) {
+        psError(PS_ERR_IO, false, "Unable to find recipe options for %s", PPSIM_RECIPE);
+        psFree(arguments);
+	return false;
+    }
+
+    // these arguments may be used whether the input image is created or loaded
+    ppSimArgToRecipeF32(&status, options, "STARS.LUM",     arguments, "-starslum");
+    ppSimArgToRecipeF32(&status, options, "STARS.MAG",     arguments, "-starsmag");
+    ppSimArgToRecipeF32(&status, options, "STARS.DENSITY", arguments, "-starsdensity");
+
+    // if we are loading the input image (not creating it), then we can skip the remaining arguments
+    if (loadImage) {
+	// if we are supplying an input image, it is so we may supply fake stars; force it to
+	// be treated as an OBJECT image. 
+	psMetadataAddStr(options, PS_LIST_TAIL, "IMAGE.TYPE", 0, "Exposure type", "OBJECT");
+
+	// check for these options as well
+        ppSimArgToRecipeStr(&status, options, "PSF.MODEL",    arguments, "-psfclass"); // PSF model class
+        ppSimArgToRecipeStr(&status, options, "GALAXY.MODEL", arguments, "-galmodel"); // Galaxy model name
+
+	// 'seeing' is not required: we can load a psf-model instead; but if not, it is allowed
+        ppSimArgToRecipeF32(&status, options, "SEEING", arguments, "-seeing"); // seeing (FWHM in arcsec)
+
+	// 'scale' is not required: we can use the WCS instead; but if not, it is allowed
+        ppSimArgToRecipeF32(&status, options, "PIXEL.SCALE", arguments, "-scale"); // Plate scale
+
+	psFree (arguments);
+	return true;
     }
 
@@ -96,95 +133,50 @@
         psMetadata *formats = psMetadataLookupMetadata(NULL, config->camera, "FORMATS"); // The camera formats
         if (!formats) {
-            psErrorStackPrint(stderr, "Unable to find FORMATS in camera configuration.");
+	    psError(PS_ERR_IO, false, "Unable to find FORMATS in camera configuration.");
             psFree(arguments);
-            psFree(config);
-            exit(PS_EXIT_CONFIG_ERROR);
+	    return false;
         }
         psMetadata *format = psMetadataLookupMetadata(NULL, formats, formatName); // Format of interest
         if (!format) {
-            psErrorStackPrint(stderr, "Unable to find format %s in camera FORMATS.", formatName);
+	    psError(PS_ERR_IO, false, "Unable to find format %s in camera FORMATS.", formatName);
             psFree(arguments);
-            psFree(config);
-            exit(PS_EXIT_CONFIG_ERROR);
+	    return false;
         }
         config->format = psMemIncrRefCounter(format);
     }
 
-    // specify the type of simulated image to produce
-    // XXX this should not be required if we supplied INPUT
-    const char *typeStr = psMetadataLookupStr(NULL, arguments, "-type"); // Exposure type
-    if (!typeStr) {
-        psErrorStackPrint(stderr, "An exposure type must be specified using -type");
-	exit(PS_EXIT_CONFIG_ERROR);
-    }
-    ppSimType type = PPSIM_TYPE_NONE;   // Type to simulate
-    if (strcasecmp(typeStr, "BIAS") == 0) {
-        type = PPSIM_TYPE_BIAS;
-    } else if (strcasecmp(typeStr, "DARK") == 0) {
-        type = PPSIM_TYPE_DARK;
-    } else if (strcasecmp(typeStr, "FLAT") == 0) {
-        type = PPSIM_TYPE_FLAT;
-    } else if (strcasecmp(typeStr, "OBJECT") == 0) {
-        type = PPSIM_TYPE_OBJECT;
+    char *typeStr = ppSimArgToRecipeStr (&status, options, "IMAGE.TYPE", arguments, "-type"); // Requested exposure type
+    if (!status) {
+	psError(PS_ERR_IO, false, "An exposure type must be specified using -type");
+        psFree(arguments);
+	return false;
+    }
+    ppSimType type = ppSimTypeFromString (typeStr);
+
+    char *filter = ppSimArgToRecipeStr(&status, options, "FILTER", arguments, "-filter"); // Filter name
+
+    // set the exposure time 
+    if (type == PPSIM_TYPE_BIAS) {
+	psMetadataAddF32(options, PS_LIST_TAIL, "EXPTIME", 0, "Exposure time (s)", 0.0);
     } else {
-        psErrorStackPrint(stderr, "Unrecognised exposure type: %s", typeStr);
-	exit(PS_EXIT_CONFIG_ERROR);
-    }
-    assert(type != PPSIM_TYPE_NONE);
-    psMetadataAddS32(config->arguments, PS_LIST_TAIL, "TYPE", 0, "Exposure type", type);
-
-    const char *filter = psMetadataLookupStr(NULL, arguments, "-filter"); // Filter name
-    psMetadataAddStr(config->arguments, PS_LIST_TAIL, "FILTER", 0, "Filter name", filter);
-
-    // save the following additional recipe values based on command-line options
-    // these options override the PPSIM recipe values loaded from recipe files
-    psMetadata *options = pmConfigRecipeOptions (config, PPSIM_RECIPE);
-    if (!options) {
-        psErrorStackPrint(stderr, "Unable to find recipe options for %s", PPSIM_RECIPE);
-        psFree(arguments);
-        psFree(config);
-        exit(PS_EXIT_CONFIG_ERROR);
-    }
-
-    float expTime;
-    if (type == PPSIM_TYPE_BIAS) {
-        expTime = 0.0;
-    } else {
-        expTime = psMetadataLookupF32(NULL, arguments, "-exptime"); // Exposure time
-        if (isnan(expTime)) {
-            psErrorStackPrint(stderr, "The exposure time must be specified using -exptime");
-	    exit(PS_EXIT_CONFIG_ERROR);
-        }
-    }
-    psMetadataAddF32(options, PS_LIST_TAIL, "EXPTIME", 0, "Exposure time (s)", expTime);
+	ppSimArgToRecipeF32(&status, options, "EXPTIME", arguments, "-exptime");
+	if (!status) {
+	    psError(PS_ERR_IO, false, "The exposure time must be specified using -exptime");
+	    psFree(arguments);
+	    return false;
+        }
+    }
 
     // these values all get moved from arguments to RECIPE:OPTIONS
-    valueArgRecipe(options, "BIAS.LEVEL",    arguments, "-biaslevel");
-    valueArgRecipe(options, "BIAS.RANGE",    arguments, "-biasrange");
-    valueArgRecipe(options, "DARK.RATE",     arguments, "-darkrate");
-    valueArgRecipe(options, "FLAT.SIGMA",    arguments, "-flatsigma");
-    valueArgRecipe(options, "FLAT.RATE",     arguments, "-flatrate");
-    valueArgRecipe(options, "SHUTTER.TIME",  arguments, "-shuttertime");
-    valueArgRecipe(options, "SKY.RATE",      arguments, "-skyrate");
-    valueArgRecipe(options, "STARS.LUM",     arguments, "-starslum");
-    valueArgRecipe(options, "STARS.MAG",     arguments, "-starsmag");
-    valueArgRecipe(options, "STARS.DENSITY", arguments, "-starsdensity");
+    ppSimArgToRecipeF32(&status, options, "BIAS.LEVEL",    arguments, "-biaslevel");
+    ppSimArgToRecipeF32(&status, options, "BIAS.RANGE",    arguments, "-biasrange");
+    ppSimArgToRecipeF32(&status, options, "DARK.RATE",     arguments, "-darkrate");
+    ppSimArgToRecipeF32(&status, options, "FLAT.SIGMA",    arguments, "-flatsigma");
+    ppSimArgToRecipeF32(&status, options, "FLAT.RATE",     arguments, "-flatrate");
+    ppSimArgToRecipeF32(&status, options, "SHUTTER.TIME",  arguments, "-shuttertime");
+    ppSimArgToRecipeF32(&status, options, "SKY.RATE",      arguments, "-skyrate");
+    ppSimArgToRecipeS32(&status, options, "BINNING",       arguments, "-bin");
 
     psMetadata *recipe = psMetadataLookupMetadata(&mdok, config->recipes, PPSIM_RECIPE); // Recipe
-
-    int biasOrder = psMetadataLookupS32(&mdok, recipe, "BIAS.ORDER"); // Overscan polynomial order
-    if (!mdok) {
-        psWarning("BIAS.ORDER(S32) is not set in the recipe %s --- assuming %d", PPSIM_RECIPE, biasOrder);
-    }
-    psMetadataAddS32(options, PS_LIST_TAIL, "BIAS.ORDER", 0, "Overscan polynomial order", biasOrder);
-
-    int binning = psMetadataLookupS32(NULL, arguments, "-bin"); // Binning in x and y
-    if (binning <= 0) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Binning (%d) is non-positive.", binning);
-	exit(PS_EXIT_CONFIG_ERROR);
-    }
-    psMetadataAddS32(config->arguments, PS_LIST_TAIL, "BINNING", 0, "Binning in x and y", binning);
-
-    psMetadataAddStr(config->arguments, PS_LIST_TAIL, "OUTPUT", 0, "Name of the output image", argv[1]);
 
     if (type == PPSIM_TYPE_OBJECT) {
@@ -197,63 +189,31 @@
 	// XXX scale and zp should be supplied by the config file (allow override, but this is camera-dependent)
         if (isnan(ra0) || isnan(dec0) || isnan(pa) || isnan(seeing)) {
-            psErrorStackPrint(stderr, "-ra, -dec, -pa, -scale, -zp, -seeing must be specified for OBJECT type");
-	    exit(PS_EXIT_CONFIG_ERROR);
-        }
-
-        float zp = psMetadataLookupF32(NULL, arguments, "-zp"); // Zero point
-	if (isnan(zp)) {
-	    // use the filter to get the zeropoint from the recipe
-	    psMetadataItem *zpItem = psMetadataLookup (recipe, "ZEROPTS");
-	    // check that item is multi...
-	    
-	    psArray *entries = psListToArray (zpItem->data.list);
-	  
-	    // search for matching filter
-	    for (int i = 0; i < entries->n; i++) {
-		psMetadataItem *item = entries->data[i];
-		psMetadata *entry = item->data.V;
-
-		char *filterName = psMetadataLookupStr (&status, entry, "FILTER");
-		assert (filterName);
-
-		if (strcmp(filterName, filter)) continue;
-
-		zp = psMetadataLookupF32 (&status, entry, "ZERO_PT");
-		assert (status);
-		break;
-            }
-	    psFree (entries);
-	}
-
-        float scale   = psMetadataLookupF32(NULL, arguments, "-scale"); // Plate scale
-	if (isnan(scale)) {
-	    scale = psMetadataLookupF32 (&status, recipe, "PIXEL.SCALE");
-	}
-
-        float skymags = psMetadataLookupF32(NULL, arguments, "-skymags"); // Position angle
-	if (isnan(skymags)) {
-	    skymags = psMetadataLookupF32 (&status, recipe, "SKY.MAGS");
-	}
-
+	    psError(PS_ERR_IO, false, "-ra, -dec, -pa, -scale, -zp, -seeing must be specified for OBJECT type");
+	    psFree(arguments);
+	    return false;
+        }
+
+        float scale = ppSimArgToRecipeF32(&status, options, "PIXEL.SCALE", arguments, "-scale"); // Plate scale
+        ppSimArgToRecipeF32(&status, options, "SKY.MAGS", arguments, "-skymags"); // Plate scale
+        ppSimArgToRecipeStr(&status, options, "PSF.MODEL",    arguments, "-psfclass"); // PSF model class
+        ppSimArgToRecipeStr(&status, options, "GALAXY.MODEL", arguments, "-galmodel"); // Galaxy model name
+
+	// the user supplies FWHM in arcsec; here we convert to Sigma in pixels
+        psMetadataAddF32(options, PS_LIST_TAIL, "SEEING", 0, "Seeing SIGMA (pixels)", seeing / 2.0 / sqrt(2.0 * log(2.0)) / scale);
         psMetadataAddF32(options, PS_LIST_TAIL, "RA", 0, "Boresight RA (radians)", ra0 * M_PI / 180.0);
         psMetadataAddF32(options, PS_LIST_TAIL, "DEC", 0, "Boresight Declination (radians)", dec0 * M_PI / 180.0);
         psMetadataAddF32(options, PS_LIST_TAIL, "PA", 0, "Boresight position angle (radians)",pa * M_PI / 180.0);
 
-	// the user supplies FWHM in arcsec; here we convert to Sigma in pixels
-        psMetadataAddF32(options, PS_LIST_TAIL, "SEEING", 0, "Seeing SIGMA (pixels)", seeing / 2.0 / sqrt(2.0 * log(2.0)) / scale);
-
-        psMetadataAddF32(options, PS_LIST_TAIL, "SCALE", 0, "Plate scale (arcsec/pix)", scale);
-        psMetadataAddF32(options, PS_LIST_TAIL, "ZEROPOINT", 0, "Photometric zeropoint", zp);
-        psMetadataAddF32(options, PS_LIST_TAIL, "SKY.MAGS", 0, "sky surface brightness", skymags);
-
-        const char *psfClass = psMetadataLookupStr(NULL, arguments, "-psfclass"); // PSF model class
-        psMetadataAddStr(config->arguments, PS_LIST_TAIL, "PSF.MODEL", 0, "PSF model class", psfClass);
-
-        const char *galModel = psMetadataLookupStr(NULL, arguments, "-galmodel"); // Galaxy model name
-        psMetadataAddStr(config->arguments, PS_LIST_TAIL, "GALAXY.MODEL", 0, "Galaxy model", galModel);
+	assert (filter != NULL);
+
+        ppSimArgToRecipeF32(&status, options, "ZEROPOINT", arguments, "-zp"); // Zero point
+	if (!status) {
+	    float zp = ppSimGetZeroPoint (recipe, filter);
+	    psMetadataAddF32(options, PS_LIST_TAIL, "ZEROPOINT", 0, "Photometric zeropoint", zp);
+	}
     }
 
     psFree(arguments);
-    return;
+    return true;
 }
 
@@ -262,12 +222,6 @@
    PSPHOT.PSF
    INPUT
-   TYPE
-   FILTER
-   BIAS.ORDER
-   BINNING
    OUTPUT
-   PSF.MODEL
-   GALAXY.MODEL
-
-   all othr values should come from the recipe
+
+   all other values should come from the recipe
 */
Index: /branches/eam_branch_20080511/ppSim/src/ppSimCreate.c
===================================================================
--- /branches/eam_branch_20080511/ppSim/src/ppSimCreate.c	(revision 17671)
+++ /branches/eam_branch_20080511/ppSim/src/ppSimCreate.c	(revision 17672)
@@ -1,9 +1,3 @@
 # include "ppSim.h"
-
-// XXX this function forces us to define the camera (on the command line) and format (via the
-// PPSIM.OUTPUT entry).  In this case, we need to set config->format,formatName based on these
-// values.  This will be a problem when we want to load an input image (in order to add fake
-// stars).  We will need to add some logic in ppSimArguments to distinguish the cases of 1)
-// input image and 2) specified camera
 
 pmFPAfile *ppSimCreate(pmConfig *config)
@@ -30,5 +24,4 @@
 	    return NULL;
 	}
-	
     } else {
 	simImage = false;
@@ -37,29 +30,31 @@
 	    return NULL;
 	}
-	fpa = input->fpa;
+	fpa = psMemIncrRefCounter (input->fpa);
     }
 
     // define the output image file -- this is the basis for the ppSimLoop
-    pmFPAfile *file = pmFPAfileDefineOutput(config, fpa, OUTPUT_FILE);
-    if (!file) {
+    pmFPAfile *output = pmFPAfileDefineOutput(config, fpa, OUTPUT_FILE);
+    if (!output) {
         psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to create output file from %s.  "
                 "Did you forget to specify the format?", OUTPUT_FILE);
         return NULL;
     }
-    if (file->type != PM_FPA_FILE_IMAGE) {
+    if (output->type != PM_FPA_FILE_IMAGE) {
         psError(PS_ERR_BAD_PARAMETER_TYPE, true, "%s type is not IMAGE", OUTPUT_FILE);
 	psFree(fpa);
-        psFree(file);
         return NULL;
     }
     // XXX we should not require the output image to be written
-    file->save = true;
+    output->save = true;
 
-    config->format = psMemIncrRefCounter (file->format);
-    config->formatName = psStringCopy (file->formatName);
+    config->format = psMemIncrRefCounter (output->format);
+    config->formatName = psStringCopy (output->formatName);
+
+    psMetadata *recipe = psMetadataLookupMetadata(&status, config->recipes, PPSIM_RECIPE); // Recipe
 
     // For photometry, we operate on the chip-mosaicked image.  we create a copy of the mosaicked
     // image for psphot so we can write out a clean image
-    if (options->doPhotom) {
+    bool doPhotom = psMetadataLookupBool(&status, recipe, "PHOTOM"); // Density of fakes
+    if (doPhotom) {
 
 	// we need a chip image if we perform photometry (is it necessary to build it if we don't use it?)
@@ -67,10 +62,10 @@
 	if (!chipImage) {
 	    psError(PS_ERR_IO, false, _("Unable to generate new file from PPSIM.CHIP"));
-	    psFree(options);
+	    psFree(fpa);
 	    return NULL;
 	}
 	if (chipImage->type != PM_FPA_FILE_IMAGE) {
 	    psError(PS_ERR_IO, true, "PPSIM.CHIP is not of type IMAGE");
-	    psFree(options);
+	    psFree(fpa);
 	    return NULL;
 	}
@@ -84,5 +79,6 @@
         if (!psphotDefineFiles (config, psphotInput)) {
             psError(PSPHOT_ERR_CONFIG, false, "Trouble defining the additional input/output files for psphot");
-            return false;
+	    psFree(fpa);
+            return NULL;
         }
     } else {
@@ -92,9 +88,8 @@
 	if (psMetadataLookupPtr(NULL, config->arguments, "PSPHOT.PSF")) {
 	    // tie the psf file to the chipMosaic 
-	    pmFPAfileBindFromArgs(&status, file, config, "PSPHOT.PSF.LOAD", "PSPHOT.PSF");
+	    pmFPAfileBindFromArgs(&status, output, config, "PSPHOT.PSF.LOAD", "PSPHOT.PSF");
 	    if (!status) {
 		psError(PS_ERR_UNKNOWN, false, "Failed to find/build PSPHOT.PSF.LOAD");
 		psFree(fpa);
-		psFree(file);
 		return NULL;
 	    }
@@ -104,5 +99,5 @@
     // PPSIM.SOURCES carries the constructed, fake sources with their true parameters
     // XXX only invoke this code for OBJECT types of images
-    pmFPAfile *simSources = pmFPAfileDefineOutput (config, file->fpa, "PPSIM.SOURCES");
+    pmFPAfile *simSources = pmFPAfileDefineOutput (config, output->fpa, "PPSIM.SOURCES");
     if (!simSources) {
         psError(PS_ERR_UNKNOWN, false, "Cannot find a rule for PPSIM.SOURCES");
@@ -113,17 +108,27 @@
     // if we have loaded an input image, we do not need to populate the fpa
     if (!simImage) {
-	return file;
+	// we need to extract certain metadata from the image and populate the recipe.
+	// or else we need to set the fpa concepts based on the recipe options...
+
+	psMetadata *recipe = psMetadataLookupMetadata(&status, config->recipes, PPSIM_RECIPE); // Recipe
+
+	ppSimArgToRecipeF32(&status, recipe, "EXPTIME", fpa->concepts, "FPA.EXPOSURE");
+	char *filter = ppSimArgToRecipeStr(&status, recipe, "FILTER", fpa->concepts, "FPA.FILTER");
+
+	float zp = ppSimGetZeroPoint (recipe, filter);
+        psMetadataAddF32(recipe, PS_LIST_TAIL, "ZEROPOINT", PS_META_REPLACE, "Photometric zeropoint", zp);
+
+	return output;
     }
 
-    pmFPALevel phuLevel = pmFPAPHULevel(file->format); // Level at which PHU goes
+    pmFPALevel phuLevel = pmFPAPHULevel(output->format); // Level at which PHU goes
 
     pmFPAview *view = pmFPAviewAlloc(0);// View for current level
 
     if (phuLevel == PM_FPA_LEVEL_FPA) {
-        if (!pmFPAAddSourceFromView(fpa, "Simulation", view, file->format)) {
+        if (!pmFPAAddSourceFromView(fpa, "Simulation", view, output->format)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to add PHU to FPA.");
             psFree(fpa);
             psFree(view);
-	    psFree(file);
             return NULL;
         }
@@ -133,9 +138,8 @@
     while ((chip = pmFPAviewNextChip(view, fpa, 1))) {
         if (phuLevel == PM_FPA_LEVEL_CHIP) {
-            if (!pmFPAAddSourceFromView(fpa, "Simulation", view, file->format)) {
+            if (!pmFPAAddSourceFromView(fpa, "Simulation", view, output->format)) {
                 psError(PS_ERR_UNKNOWN, false, "Unable to add PHU to FPA.");
                 psFree(fpa);
                 psFree(view);
-		psFree(file);
                 return NULL;
             }
@@ -145,9 +149,8 @@
         while ((cell = pmFPAviewNextCell(view, fpa, 1))) {
             if (phuLevel == PM_FPA_LEVEL_CELL) {
-                if (!pmFPAAddSourceFromView(fpa, "Simulation", view, file->format)) {
+                if (!pmFPAAddSourceFromView(fpa, "Simulation", view, output->format)) {
                     psError(PS_ERR_UNKNOWN, false, "Unable to add PHU to FPA.");
                     psFree(fpa);
                     psFree(view);
-		    psFree(file);
                     return NULL;
                 }
@@ -159,4 +162,4 @@
     psFree(view);
 
-    return file;
+    return output;
 }
Index: /branches/eam_branch_20080511/ppSim/src/ppSimInsertGalaxies.c
===================================================================
--- /branches/eam_branch_20080511/ppSim/src/ppSimInsertGalaxies.c	(revision 17671)
+++ /branches/eam_branch_20080511/ppSim/src/ppSimInsertGalaxies.c	(revision 17672)
@@ -10,7 +10,4 @@
     
     if (!galaxies->n) { return true; }
-
-    // XXX is this needed?
-    // pmFPAfile *simSources = psMetadataLookupPtr(NULL, config->files, "PPSIM.SOURCES"); // Output sources
 
     pmCell *cell = readout->parent;
@@ -38,5 +35,5 @@
     if (isnan(skyRate)) {
 	float zp      = psMetadataLookupF32(&mdok, recipe, "ZEROPOINT"); assert (mdok);
-	float scale   = psMetadataLookupF32(&mdok, recipe, "SCALE");     assert (mdok);
+	float scale   = psMetadataLookupF32(&mdok, recipe, "PIXEL.SCALE"); assert (mdok);
 	float skyMags = psMetadataLookupF32(&mdok, recipe, "SKY.MAGS");  assert (mdok);
 	skyRate = scale * scale * ppSimMagToFlux (skyMags, zp);
@@ -56,8 +53,8 @@
     int yParityCell = psMetadataLookupS32(NULL, cell->concepts, "CELL.YPARITY");
 
-    int binning = psMetadataLookupS32(NULL, config->arguments, "BINNING"); // Binning in x and y
+    int binning = psMetadataLookupS32(NULL, recipe, "BINNING"); // Binning in x and y
 
     // determine the galaxy model
-    char *modelName = psMetadataLookupStr(&mdok, config->arguments, "GALAXY.MODEL"); // galaxy model name
+    char *modelName = psMetadataLookupStr(&mdok, recipe, "GALAXY.MODEL"); // galaxy model name
     if (modelName == NULL) {
 	modelName = defaultModel;
Index: /branches/eam_branch_20080511/ppSim/src/ppSimInsertStars.c
===================================================================
--- /branches/eam_branch_20080511/ppSim/src/ppSimInsertStars.c	(revision 17671)
+++ /branches/eam_branch_20080511/ppSim/src/ppSimInsertStars.c	(revision 17672)
@@ -43,5 +43,5 @@
     if (isnan(skyRate)) {
 	float zp      = psMetadataLookupF32(&mdok, recipe, "ZEROPOINT"); assert (mdok);
-	float scale   = psMetadataLookupF32(&mdok, recipe, "SCALE");     assert (mdok);
+	float scale   = psMetadataLookupF32(&mdok, recipe, "PIXEL.SCALE");     assert (mdok);
 	float skyMags = psMetadataLookupF32(&mdok, recipe, "SKY.MAGS");  assert (mdok);
         skyRate = scale * scale * ppSimMagToFlux (skyMags, zp);
@@ -61,5 +61,5 @@
     int yParityCell = psMetadataLookupS32(NULL, cell->concepts, "CELL.YPARITY");
 
-    int binning = psMetadataLookupS32(NULL, config->arguments, "BINNING"); // Binning in x and y
+    int binning = psMetadataLookupS32(NULL, recipe, "BINNING"); // Binning in x and y
 
     pmPSF *psf = psMetadataLookupPtr (&mdok, chip->analysis, "PSPHOT.PSF");
Index: /branches/eam_branch_20080511/ppSim/src/ppSimLoadSpots.c
===================================================================
--- /branches/eam_branch_20080511/ppSim/src/ppSimLoadSpots.c	(revision 17671)
+++ /branches/eam_branch_20080511/ppSim/src/ppSimLoadSpots.c	(revision 17672)
@@ -2,4 +2,6 @@
 
 bool ppSimLoadSpots (pmFPA *fpa, pmConfig *config) {
+
+# if (0)
 
     bool mdok;
@@ -64,4 +66,6 @@
     }
 
+# endif
+
     // XXX these need to be saved on PSPHOT.INPUT.CMF
     return true;
Index: /branches/eam_branch_20080511/ppSim/src/ppSimLoadStars.c
===================================================================
--- /branches/eam_branch_20080511/ppSim/src/ppSimLoadStars.c	(revision 17671)
+++ /branches/eam_branch_20080511/ppSim/src/ppSimLoadStars.c	(revision 17672)
@@ -1,3 +1,3 @@
-#include "ppSim.h"
+# include "ppSim.h"
 
 bool ppSimLoadStars (psArray *stars, pmFPA *fpa, pmConfig *config) {
@@ -24,5 +24,5 @@
     float pa      = psMetadataLookupF32(NULL, recipe, "PA");        // Position angle (radians)
     float seeing  = psMetadataLookupF32(NULL, recipe, "SEEING");    // Seeing SIGMA (pixels)
-    float scale   = psMetadataLookupF32(NULL, recipe, "SCALE") * M_PI / 3600.0 / 180.0; // Plate scale (radians/pixel)
+    float scale   = psMetadataLookupF32(NULL, recipe, "PIXEL.SCALE") * M_PI / 3600.0 / 180.0; // Plate scale (radians/pixel)
     float expTime = psMetadataLookupF32(NULL, recipe, "EXPTIME");   // Exposure time (sec)
 
@@ -40,5 +40,5 @@
     psMetadataAdd(astroRecipe, PS_LIST_TAIL, "DEC_MAX", PS_DATA_F32 | PS_META_REPLACE, "", dec0 + radius);
     psArray *refStars = psastroLoadRefstars(config);
-    if (!refStars || refStars->n == 0) {
+    if (!refStars) {
         psError(PS_ERR_UNKNOWN, false, "Unable to find reference stars.");
         psFree(refStars);
Index: /branches/eam_branch_20080511/ppSim/src/ppSimLoop.c
===================================================================
--- /branches/eam_branch_20080511/ppSim/src/ppSimLoop.c	(revision 17671)
+++ /branches/eam_branch_20080511/ppSim/src/ppSimLoop.c	(revision 17672)
@@ -1,3 +1,8 @@
 #include "ppSim.h"
+
+# define ESCAPE(CODE,MSG) { \
+  psError(CODE, false, MSG); \
+  psFree (rng); \
+  return false; }
 
 bool ppSimLoop(pmConfig *config)
@@ -8,33 +13,30 @@
     pmFPAfile *file = psMetadataLookupPtr(NULL, config->files, OUTPUT_FILE); // Output file
     assert(file);
+
     pmFPA *fpa = file->fpa;             // FPA for file
     assert(fpa);
 
-    ppSimType type = psMetadataLookupS32(NULL, config->arguments, "TYPE"); // Type of image to simulate
+    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSIM_RECIPE); // Recipe
 
     psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS, 0); // Random number generator
 
-    int binning = psMetadataLookupS32(NULL, config->arguments, "BINNING"); // Binning in x and y
-
-    // Load forced-photometry positions
-    if (type == PPSIM_TYPE_OBJECT) {
-      psArray *spots = ppSimLoadSpots (fpa, config);
-    }
-
-    // Load catalogue stars
+    char *typeStr = psMetadataLookupStr(NULL, recipe, "IMAGE.TYPE"); // Type of image to simulate
+    ppSimType type = ppSimTypeFromString (typeStr); // Type of image to simulate
+    int binning = psMetadataLookupS32(NULL, recipe, "BINNING"); // Binning in x and y
+
     psArray *stars = psArrayAllocEmpty (1);
-    if (type == PPSIM_TYPE_OBJECT) {
-        ppSimLoadStars (stars, fpa, config);
-    }
-
-    // Add random stars
-    if (type == PPSIM_TYPE_OBJECT) {
-        ppSimMakeStars (stars, fpa, config, rng);
-    }
-
-    // Add random galaxies
     psArray *galaxies = psArrayAllocEmpty (1);
     if (type == PPSIM_TYPE_OBJECT) {
-        ppSimMakeGalaxies (galaxies, fpa, config, rng);
+	// Load forced-photometry positions
+	if (!ppSimLoadSpots (fpa, config)) ESCAPE (PS_ERR_UNKNOWN, "failed to load forced-photometry spots");
+
+	// Load catalogue stars
+        if (!ppSimLoadStars (stars, fpa, config)) ESCAPE (PS_ERR_UNKNOWN, "failed to load catalog stars");
+
+	// Add random stars
+        if (!ppSimMakeStars (stars, fpa, config, rng)) ESCAPE (PS_ERR_UNKNOWN, "failed to make random stars");
+
+	// Add random galaxies
+        if (!ppSimMakeGalaxies (galaxies, fpa, config, rng)) ESCAPE (PS_ERR_UNKNOWN, "failed to make random galaxies");
     }
 
@@ -176,6 +178,4 @@
         }
 
-        ppSimMosaicChip(config, blankMask, view, "PPSIM.CHIP", "PPSIM.OUTPUT");
-
         // we perform photometry on the readouts of this chip in the output
 	ppSimPhotom (config, view);
Index: /branches/eam_branch_20080511/ppSim/src/ppSimMakeBias.c
===================================================================
--- /branches/eam_branch_20080511/ppSim/src/ppSimMakeBias.c	(revision 17671)
+++ /branches/eam_branch_20080511/ppSim/src/ppSimMakeBias.c	(revision 17672)
@@ -8,4 +8,7 @@
 
     psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSIM_RECIPE); // Recipe
+
+    bool bias = psMetadataLookupBool(&status, recipe, "BIAS"); // Generate a Bias?
+    if (!bias) return true;
 
     float biasLevel = psMetadataLookupF32(NULL, recipe, "BIAS.LEVEL"); // Bias level
Index: /branches/eam_branch_20080511/ppSim/src/ppSimMakeDark.c
===================================================================
--- /branches/eam_branch_20080511/ppSim/src/ppSimMakeDark.c	(revision 17671)
+++ /branches/eam_branch_20080511/ppSim/src/ppSimMakeDark.c	(revision 17672)
@@ -10,4 +10,7 @@
 
     psMetadata *recipe = psMetadataLookupMetadata(&mdok, config->recipes, PPSIM_RECIPE); // Recipe
+
+    bool dark = psMetadataLookupBool(&status, recipe, "DARK"); // Generate a DARK?
+    if (!dark) return true;
 
     float darkRate = psMetadataLookupF32(NULL, recipe, "DARK.RATE"); // Dark rate
Index: /branches/eam_branch_20080511/ppSim/src/ppSimMakeGalaxies.c
===================================================================
--- /branches/eam_branch_20080511/ppSim/src/ppSimMakeGalaxies.c	(revision 17671)
+++ /branches/eam_branch_20080511/ppSim/src/ppSimMakeGalaxies.c	(revision 17672)
@@ -9,5 +9,5 @@
 
     bool galaxyFake = psMetadataLookupBool(&mdok, recipe, "GALAXY.FAKE"); // Density of fakes
-    if (!galaxyFake) return NULL;
+    if (!galaxyFake) return true;
 
     float galaxyLum       = psMetadataLookupF32(&mdok, recipe, "GALAXY.LUM"); // Galaxy luminosity func slope
@@ -35,5 +35,5 @@
     float zp       	  = psMetadataLookupF32(&mdok, recipe, "ZEROPOINT"); // Photometric zero point
     float seeing   	  = psMetadataLookupF32(&mdok, recipe, "SEEING"); // Seeing sigma (pix)
-    float scale    	  = psMetadataLookupF32(&mdok, recipe, "SCALE") * M_PI / 3600.0 / 180.0; // Plate scale (radians/pixel)
+    float scale    	  = psMetadataLookupF32(&mdok, recipe, "PIXEL.SCALE") * M_PI / 3600.0 / 180.0; // Plate scale (radians/pixel)
     float skyRate  	  = psMetadataLookupF32(&mdok, recipe, "SKY.RATE"); // Sky rate
     if (isnan(skyRate)) {
@@ -42,5 +42,5 @@
     }
 
-    if (galaxyDensity <= 0) return NULL;
+    if (galaxyDensity <= 0) return true;
 
     // Size of FPA
@@ -66,5 +66,5 @@
 	psLogMsg("ppSim", PS_LOG_INFO,
 		 "Image noise is above brightest random galaxy --- no random galaxy added.");
-	return NULL;
+	return true;
     }
 
@@ -138,4 +138,4 @@
 	}
     }
-    return galaxies;
+    return true;
 }
Index: /branches/eam_branch_20080511/ppSim/src/ppSimMakeSky.c
===================================================================
--- /branches/eam_branch_20080511/ppSim/src/ppSimMakeSky.c	(revision 17671)
+++ /branches/eam_branch_20080511/ppSim/src/ppSimMakeSky.c	(revision 17672)
@@ -15,4 +15,7 @@
     psMetadata *recipe = psMetadataLookupMetadata(&status, config->recipes, PPSIM_RECIPE); // Recipe
 
+    bool sky = psMetadataLookupBool(&status, recipe, "SKY"); // Generate a SKY flux?
+    if (!sky) return true;
+ 
     float expTime     = psMetadataLookupF32(&status, recipe, "EXPTIME"); // Exposure time
     float flatSigma   = psMetadataLookupF32(&status, recipe, "FLAT.SIGMA"); // Flat-field coefficient
@@ -22,5 +25,5 @@
     if (isnan(skyRate)) {
 	float zp      = psMetadataLookupF32(&status, recipe, "ZEROPOINT"); assert (status);
-	float scale   = psMetadataLookupF32(&status, recipe, "SCALE");     assert (status);
+	float scale   = psMetadataLookupF32(&status, recipe, "PIXEL.SCALE"); assert (status);
 	float skyMags = psMetadataLookupF32(&status, recipe, "SKY.MAGS");  assert (status);
 	skyRate = scale * scale * ppSimMagToFlux (skyMags, zp);
@@ -37,5 +40,5 @@
     int yParityCell   = psMetadataLookupS32(&status, cell->concepts, "CELL.YPARITY");
 
-    int binning = psMetadataLookupS32(NULL, config->arguments, "BINNING"); // Binning in x and y
+    int binning = psMetadataLookupS32(NULL, recipe, "BINNING"); // Binning in x and y
 
     // Size of FPA
Index: /branches/eam_branch_20080511/ppSim/src/ppSimMakeStars.c
===================================================================
--- /branches/eam_branch_20080511/ppSim/src/ppSimMakeStars.c	(revision 17671)
+++ /branches/eam_branch_20080511/ppSim/src/ppSimMakeStars.c	(revision 17672)
@@ -1,3 +1,7 @@
 # include "ppSim.h"
+
+# define ESCAPE(MSG) { \
+  psError(PS_ERR_BAD_PARAMETER_VALUE, true, MSG); \
+  return false; }
 
 bool ppSimMakeStars(psArray *stars, pmFPA *fpa, pmConfig *config, const psRandom *rng) {
@@ -23,5 +27,11 @@
     float zp           = psMetadataLookupF32(&status, recipe, "ZEROPOINT"); // Photometric zero point
     float seeing       = psMetadataLookupF32(&status, recipe, "SEEING"); // Seeing SIGMA (pixels)
-    float scale        = psMetadataLookupF32(&status, recipe, "SCALE") * M_PI / 3600.0 / 180.0; // Plate scale (radians/pixel)
+    float scale        = psMetadataLookupF32(&status, recipe, "PIXEL.SCALE") * M_PI / 3600.0 / 180.0; // Plate scale (radians/pixel)
+
+    if (isnan(darkRate)) darkRate = 0.0;
+    if (isnan(expTime))  ESCAPE("EXPTIME is not defined");
+    if (isnan(zp))       ESCAPE("ZEROPOINT is not defined");
+    if (isnan(seeing))   ESCAPE("SEEING is not defined");
+    if (isnan(scale))    ESCAPE("PIXEL.SCALE is not defined");
 
     bool flatLum       = psMetadataLookupBool(&status,recipe, "STARS.FLAT.LUM"); // were real stars generated?
@@ -47,5 +57,10 @@
 	refMag = psMetadataLookupF32(&status, fpa->concepts, "STARS.REAL.MAG.PEAK"); // Star brightest magnitude
 	refSum = psMetadataLookupF32(&status, fpa->concepts, "STARS.REAL.SUM.PEAK"); // Star brightest magnitude
-	assert (status);
+
+	// if we tried and failed to load reference stars, set more artificial limits
+	if (!status) {
+	    refMag = brightMag;
+	    refSum = 1;
+	}
     } else {
 	refMag = brightMag;
Index: /branches/eam_branch_20080511/ppSim/src/ppSimPhotom.c
===================================================================
--- /branches/eam_branch_20080511/ppSim/src/ppSimPhotom.c	(revision 17671)
+++ /branches/eam_branch_20080511/ppSim/src/ppSimPhotom.c	(revision 17672)
@@ -8,5 +8,13 @@
     pmReadout *readout;
 
+    psMetadata *recipe = psMetadataLookupMetadata(&status, config->recipes, PPSIM_RECIPE); // Recipe
+
+    bool doPhotom = psMetadataLookupBool(&status, recipe, "PHOTOM"); // Density of fakes
+    if (!doPhotom) return true;
+    
     psphotModelClassInit ();
+
+    int blankMask = 0;		// XXX not sure what this should be set to...
+    ppSimMosaicChip(config, blankMask, view, "PPSIM.CHIP", "PPSIM.OUTPUT");
 
     // find or define a pmFPAfile PSPHOT.INPUT
Index: /branches/eam_branch_20080511/ppSim/src/ppSimSetPSF.c
===================================================================
--- /branches/eam_branch_20080511/ppSim/src/ppSimSetPSF.c	(revision 17671)
+++ /branches/eam_branch_20080511/ppSim/src/ppSimSetPSF.c	(revision 17672)
@@ -21,5 +21,5 @@
     float seeing   = psMetadataLookupF32(&status, recipe, "SEEING"); // Seeing SIGMA (pixels)
 
-    char *psfModelName = psMetadataLookupStr(&status, config->arguments, "PSF.MODEL"); // Name of PSF model
+    char *psfModelName = psMetadataLookupStr(&status, recipe, "PSF.MODEL"); // Name of PSF model
     if (psfModelName == NULL) {
         psfModelName = defaultModel;
Index: /branches/eam_branch_20080511/ppSim/src/ppSimUtils.c
===================================================================
--- /branches/eam_branch_20080511/ppSim/src/ppSimUtils.c	(revision 17671)
+++ /branches/eam_branch_20080511/ppSim/src/ppSimUtils.c	(revision 17672)
@@ -15,8 +15,8 @@
     float dec0  = psMetadataLookupF32(NULL, recipe, "DEC"); // Boresight Dec (radians)
     float pa    = psMetadataLookupF32(NULL, recipe, "PA");  // Position angle (radians)
-    float scale = psMetadataLookupF32(NULL, recipe, "SCALE"); // plate scale in arcsec / pixel
+    float scale = psMetadataLookupF32(NULL, recipe, "PIXEL.SCALE"); // plate scale in arcsec / pixel
     scale *= M_PI / 3600.0 / 180.0; // convert plate scale to radians/pixel
 
-    int binning = psMetadataLookupS32(NULL, config->arguments, "BINNING"); // Binning in x and y
+    int binning = psMetadataLookupS32(NULL, recipe, "BINNING"); // Binning in x and y
 
     float x0 = 0.0, y0 = 0.0;
@@ -95,4 +95,28 @@
 }
 
+char *ppSimTypeToString (ppSimType type) {
+
+    char *typeStr;
+
+    switch (type) {
+      case PPSIM_TYPE_BIAS:   typeStr = psStringCopy ("BIAS");   break;
+      case PPSIM_TYPE_DARK:   typeStr = psStringCopy ("DARK");   break;
+      case PPSIM_TYPE_FLAT:   typeStr = psStringCopy ("FLAT");   break;
+      case PPSIM_TYPE_OBJECT: typeStr = psStringCopy ("OBJECT"); break;
+      default:
+        psAbort("Should never get here.");
+    }
+    return (typeStr);
+}
+
+ppSimType ppSimTypeFromString (char *typeStr) {
+
+    if (!strcasecmp (typeStr, "BIAS")) 	 return PPSIM_TYPE_BIAS;
+    if (!strcasecmp (typeStr, "DARK")) 	 return PPSIM_TYPE_DARK;
+    if (!strcasecmp (typeStr, "FLAT")) 	 return PPSIM_TYPE_FLAT;
+    if (!strcasecmp (typeStr, "OBJECT")) return PPSIM_TYPE_OBJECT;
+    psAbort("Should never get here.");
+}
+
 bool ppSimUpdateConceptsFPA (pmFPA *fpa, pmConfig *config) {
 
@@ -103,28 +127,14 @@
     float expTime = psMetadataLookupF32(NULL, recipe, "EXPTIME"); // Exposure time
 
-    const char *filter = psMetadataLookupStr(NULL, config->arguments, "FILTER"); // Filter name
+    const char *filter = psMetadataLookupStr(NULL, recipe, "FILTER"); // Filter name
     if (!filter) {
         filter = "NONE";
     }
 
-    ppSimType type = psMetadataLookupS32(NULL, config->arguments, "TYPE"); // Type of image to simulate
-
-    // Update FPA concepts
-    const char *typeStr;                // Exposure type String
-    switch (type) {
-      case PPSIM_TYPE_BIAS:   typeStr = "BIAS";   break;
-      case PPSIM_TYPE_DARK:   typeStr = "DARK";   break;
-      case PPSIM_TYPE_FLAT:   typeStr = "FLAT";   break;
-      case PPSIM_TYPE_OBJECT: typeStr = "OBJECT"; break;
-      default:
-        psAbort("Should never get here.");
-    }
-
-    psMetadataAddStr(fpa->concepts, PS_LIST_TAIL, "FPA.OBSTYPE", PS_META_REPLACE,
-                     "Observation type", typeStr);
-    psMetadataAddStr(fpa->concepts, PS_LIST_TAIL, "FPA.OBJECT", PS_META_REPLACE,
-                     "Observation name", typeStr);
-    psMetadataAddF32(fpa->concepts, PS_LIST_TAIL, "FPA.EXPTIME", PS_META_REPLACE,
-                     "Exposure time (sec)", expTime);
+    char *typeStr = psMetadataLookupStr(NULL, recipe, "IMAGE.TYPE"); // Type of image to simulate
+
+    psMetadataAddStr(fpa->concepts, PS_LIST_TAIL, "FPA.OBSTYPE", PS_META_REPLACE, "Observation type", typeStr);
+    psMetadataAddStr(fpa->concepts, PS_LIST_TAIL, "FPA.OBJECT", PS_META_REPLACE, "Observation name", typeStr);
+    psMetadataAddF32(fpa->concepts, PS_LIST_TAIL, "FPA.EXPOSURE", PS_META_REPLACE, "Exposure time (sec)", expTime);
     psMetadataAddStr(fpa->concepts, PS_LIST_TAIL, "FPA.FILTERID", PS_META_REPLACE, "Filter name", filter);
     psMetadataAddStr(fpa->concepts, PS_LIST_TAIL, "FPA.FILTER", PS_META_REPLACE, "Filter name", filter);
@@ -139,5 +149,5 @@
     psMetadata *recipe = psMetadataLookupMetadata(&mdok, config->recipes, PPSIM_RECIPE); // Recipe
 
-    int binning = psMetadataLookupS32(NULL, config->arguments, "BINNING"); // Binning in x and y
+    int binning = psMetadataLookupS32(NULL, recipe, "BINNING"); // Binning in x and y
     float expTime = psMetadataLookupF32(NULL, recipe, "EXPTIME"); // Exposure time
 
@@ -153,2 +163,97 @@
     return true;
 }
+
+bool ppSimRecipeValidation (pmConfig *config) {
+
+    bool status;
+
+    psMetadata *recipe = psMetadataLookupMetadata(&status, config->recipes, PPSIM_RECIPE); // Recipe
+
+    int binning = psMetadataLookupS32(&status, recipe, "BINNING"); // Binning in x and y
+    if (binning <= 0) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Binning (%d) is non-positive.", binning);
+	exit(PS_EXIT_CONFIG_ERROR);
+    }
+    return true;
+}
+
+// Get a value from the command-line arguments and add it to recipe options
+float ppSimArgToRecipeF32(bool *status,
+			  psMetadata *options,    // Target to which to add value
+			  const char *recipeName, // Name for value in the recipe
+			  psMetadata *arguments,  // Command-line arguments
+			  const char *argName	    // Argument name in the command-line arguments
+    )
+{
+    bool myStatus;
+    float value = psMetadataLookupF32(&myStatus, arguments, argName); // Value of interest
+    if (status) { *status = myStatus; }
+    if (isnan(value)) return value;
+
+    psMetadataAddF32(options, PS_LIST_TAIL, recipeName, PS_META_REPLACE, NULL, value);
+    return value;
+}
+
+// Get a value from the command-line arguments and add it to recipe options
+int ppSimArgToRecipeS32(bool *status,
+			psMetadata *options,    // Target to which to add value
+			const char *recipeName, // Name for value in the recipe
+			psMetadata *arguments,  // Command-line arguments
+			const char *argName	    // Argument name in the command-line arguments
+    )
+{
+    bool myStatus;
+    int value = psMetadataLookupS32(&myStatus, arguments, argName); // Value of interest
+    if (status) { *status = myStatus; }
+
+    psMetadataAddS32(options, PS_LIST_TAIL, recipeName, PS_META_REPLACE, NULL, value);
+    return value;
+}
+
+// Get a value from the command-line arguments and add it to recipe options
+char *ppSimArgToRecipeStr(bool *status,
+			  psMetadata *options,    // Target to which to add value
+			  const char *recipeName, // Name for value in the recipe
+			  psMetadata *arguments,  // Command-line arguments
+			  const char *argName	    // Argument name in the command-line arguments
+    )
+{
+    bool myStatus;
+
+    char *value = psMetadataLookupStr(&myStatus, arguments, argName); // Value of interest
+    if (status) {
+	*status = myStatus;
+    }
+    psMetadataAddStr(options, PS_LIST_TAIL, recipeName, PS_META_REPLACE, NULL, value);
+    return value;
+}
+
+float ppSimGetZeroPoint (psMetadata *recipe, char *filter) {
+
+    bool mdok;
+    float zp;
+
+    // use the filter to get the zeropoint from the recipe
+    psMetadataItem *zpItem = psMetadataLookup (recipe, "ZEROPTS");
+    // check that item is multi...
+	    
+    psArray *entries = psListToArray (zpItem->data.list);
+	  
+    // search for matching filter
+    for (int i = 0; i < entries->n; i++) {
+	psMetadataItem *item = entries->data[i];
+	psMetadata *entry = item->data.V;
+
+	char *filterName = psMetadataLookupStr (&mdok, entry, "FILTER");
+	assert (filterName);
+
+	if (strcmp(filterName, filter)) continue;
+
+	zp = psMetadataLookupF32 (&mdok, entry, "ZERO_PT");
+	assert (mdok);
+	psFree (entries);
+	return zp;
+    }
+    psFree (entries);
+    return NAN;
+}
