Index: trunk/ppSim/src/ppSimUtils.c
===================================================================
--- trunk/ppSim/src/ppSimUtils.c	(revision 17557)
+++ trunk/ppSim/src/ppSimUtils.c	(revision 18011)
@@ -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,139 @@
     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
+bool ppSimArgToRecipeBool(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;
+    bool value = psMetadataLookupS32(&myStatus, arguments, argName); // Value of interest
+    if (status) { *status = myStatus; }
+
+    psMetadataAddBool(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;
+}
+
+psArray *ppSimSelectSources (pmConfig *config, const pmFPAview *view, const char *filename) {
+
+    pmReadout *readout = pmFPAfileThisReadout (config->files, view, filename);
+    PS_ASSERT_PTR_NON_NULL (readout, NULL);
+
+    psArray *sources = psMetadataLookupPtr (NULL, readout->analysis, "PSPHOT.SOURCES");
+    return sources;
+}
+
+bool ppSimDefinePixels (psArray *sources, pmReadout *readout, psMetadata *recipe) {
+
+    bool status;
+
+    float OUTER = psMetadataLookupF32 (&status, recipe, "SKY_OUTER_RADIUS");
+    if (!status) return NULL;
+
+    for (int i = 0; i < sources->n; i++) {
+	pmSource *source = sources->data[i];
+
+        // allocate image, weight, mask arrays for each peak (square of radius OUTER)
+        pmSourceDefinePixels (source, readout, source->peak->x, source->peak->y, OUTER);
+    }
+    return true;
+}
+
