Index: trunk/ppSub/src/ppSubArguments.c
===================================================================
--- trunk/ppSub/src/ppSubArguments.c	(revision 23402)
+++ trunk/ppSub/src/ppSubArguments.c	(revision 23740)
@@ -41,136 +41,4 @@
 }
 
-// Get a float-point value from the command-line or recipe, and add it to the arguments
-#define VALUE_ARG_RECIPE_FLOAT(ARGNAME, RECIPENAME, TYPE) { \
-    ps##TYPE value = psMetadataLookup##TYPE(NULL, config->arguments, ARGNAME); \
-    if (isnan(value)) { \
-        bool mdok; \
-        value = psMetadataLookup##TYPE(&mdok, recipe, RECIPENAME); \
-        if (!mdok) { \
-            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unable to find %s in recipe %s", \
-                RECIPENAME, PPSUB_RECIPE); \
-            goto ERROR; \
-        } \
-    } \
-    psMetadataAdd##TYPE(recipe, PS_LIST_TAIL, RECIPENAME, PS_META_REPLACE, NULL, value); \
-}
-
-// Get an integer value from the command-line or recipe, and add it to the arguments
-#define VALUE_ARG_RECIPE_INT(ARGNAME, RECIPENAME, TYPE, UNSET) { \
-    ps##TYPE value = psMetadataLookup##TYPE(NULL, config->arguments, ARGNAME); \
-    if (value == UNSET) { \
-        bool mdok; \
-        value = psMetadataLookup##TYPE(&mdok, recipe, RECIPENAME); \
-        if (!mdok) { \
-            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unable to find %s in recipe %s", \
-                RECIPENAME, PPSUB_RECIPE); \
-            goto ERROR; \
-        } \
-    } \
-    psMetadataAdd##TYPE(recipe, PS_LIST_TAIL, RECIPENAME, PS_META_REPLACE, NULL, value); \
-}
-
-/**
- * Get a string value from the command-line and add it to the target
- */
-static bool valueArgStr(psMetadata *arguments, // Command-line arguments
-                        const char *argName, // Argument name in the command-line arguments
-                        const char *mdName, // Name for value in the metadata
-                        psMetadata *target // Target metadata to which to add value
-                        )
-{
-    psString value = psMetadataLookupStr(NULL, arguments, argName); // Value of interest
-    if (value && strlen(value) > 0) {
-        return psMetadataAddStr(target, PS_LIST_TAIL, mdName, PS_META_REPLACE, NULL, value);
-    }
-    return false;
-}
-
-/**
- * Get a string value from the command-line or recipe and add it to the target
- */
-static bool valueArgRecipeStr(psMetadata *arguments, // Command-line arguments
-                              psMetadata *recipe, // Recipe
-                              const char *argName, // Argument name in the command-line arguments
-                              const char *mdName, // Name for value in the metadata and recipe
-                              psMetadata *target // Target metadata to which to add value
-                              )
-{
-    bool mdok;                          // Status of MD lookup
-    psString value = psMetadataLookupStr(&mdok, arguments, argName); // Value of interest
-    if (!value) {
-        value = psMetadataLookupStr(&mdok, recipe, mdName);
-        if (!value) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unable to find %s in recipe %s",
-                    mdName, PPSUB_RECIPE);
-            return false;
-        }
-    }
-    return psMetadataAddStr(target, PS_LIST_TAIL, mdName, PS_META_REPLACE, NULL, value);
-}
-
-/**
- * Get a vector from the command-line or recipe, and add it to the target
- */
-static bool vectorArgRecipe(psMetadata *arguments, // Command-line arguments
-                            const char *argName, // Argument name in the command-line arguments
-                            const psMetadata *recipe, // Recipe
-                            const char *recipeName, // Name for value in the recipe
-                            psMetadata *target, // Target to which to add value
-                            psElemType type // Type for vector
-    )
-{
-    psVector *vector;                   // Vector
-    psString string = psMetadataLookupStr(NULL, arguments, argName); // String from arguments
-    if (string) {
-        psArray *array = psStringSplitArray(string, ", ", false); // Array of strings
-        vector = psVectorAlloc(array->n, type);
-        for (int i = 0; i < array->n; i++) {
-            const char *subString = array->data[i]; // String with a value
-            char *end;                  // Ptr to end of string parsed
-
-            switch (type) {
-              case PS_TYPE_F32:
-                vector->data.F32[i] = strtof(subString, &end);
-                break;
-              case PS_TYPE_S32: {
-                  long value = strtol(subString, &end, 10);
-                  if (value > PS_MAX_S32 || value < PS_MIN_S32) {
-                      psError(PS_ERR_BAD_PARAMETER_VALUE, true,
-                              "%s list includes value beyond S32 representation: %s",
-                              argName, string);
-                      psFree(vector);
-                      return false;
-                  }
-                  vector->data.S32[i] = value;
-                  break;
-              }
-              default:
-                psAbort("Unsupported type: %x\n", type);
-            }
-            if (end == subString) {
-                psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unable to decipher %s list: %s",
-                        argName, string);
-                psFree(vector);
-                return false;
-            }
-        }
-        psFree(array);
-    } else {
-        vector = psMetadataLookupPtr(NULL, recipe, recipeName);
-        if (!psMemCheckVector(vector) || vector->type.type != type) {
-            psError(PS_ERR_BAD_PARAMETER_TYPE, false, "%s in recipe %s is not a vector of type F32.",
-                    recipeName, PPSUB_RECIPE);
-            return false;
-        }
-        psMemIncrRefCounter(vector);
-    }
-
-    psMetadataAddVector(target, PS_LIST_TAIL, recipeName, PS_META_REPLACE, NULL, vector);
-    psFree(vector);                     // Drop reference
-
-    return true;
-}
-
 /**
  * Add a single filename to the arguments as an array, so that it can be used with pmFPAfileBindFromArgs, etc
@@ -189,15 +57,7 @@
 }
 
-bool ppSubArgumentsSetup(int argc, char *argv[], pmConfig *config)
+bool ppSubArguments(int argc, char *argv[], pmConfig *config, ppSubData *data)
 {
-    //    int argnum;                         // Argument Number
     assert(config);
-
-    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSUB_RECIPE); // Recipe for ppSim
-    if (!recipe) {
-        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find recipe %s", PPSUB_RECIPE);
-        return false;
-    }
-
 
     psMetadata *arguments = config->arguments; // Command-line arguments
@@ -212,46 +72,9 @@
     psMetadataAddStr(arguments, PS_LIST_TAIL, "-kernel", 0, "Precalculated kernel to apply", NULL);
     psMetadataAddStr(arguments, PS_LIST_TAIL, "-stats", 0, "Statistics file", NULL);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-region", 0, "Size of iso-kernel region", NAN);
-    psMetadataAddS32(arguments, PS_LIST_TAIL, "-size", 0, "Kernel half-size (pixels)", 0);
-    psMetadataAddS32(arguments, PS_LIST_TAIL, "-order", 0, "Spatial polynomial order", -1);
-    psMetadataAddStr(arguments, PS_LIST_TAIL, "-type", 0,
-                     "Kernel type (ISIS|POIS|SPAM|FRIES|GUNK|RINGS)", NULL);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-penalty", 0, "Penalty for wideness", NAN);
-    psMetadataAddStr(arguments, PS_LIST_TAIL, "-isis-widths", 0,
-                     "ISIS Gaussian FWHMs (comma-separated)", NULL);
-    psMetadataAddStr(arguments, PS_LIST_TAIL, "-isis-orders", 0,
-                     "ISIS polynomial orders (comma-separated)", NULL);
-    psMetadataAddS32(arguments, PS_LIST_TAIL, "-rings-order", 0, "RINGS polynomial order", -1);
-    psMetadataAddS32(arguments, PS_LIST_TAIL, "-inner", 0, "SPAM and FRIES inner radius", -1);
-    psMetadataAddS32(arguments, PS_LIST_TAIL, "-spam-binning", 0, "SPAM kernel binning", 0);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-spacing", 0, "Typical stamp spacing (pixels)", NAN);
-    psMetadataAddS32(arguments, PS_LIST_TAIL, "-footprint", 0, "Stamp footprint half-size (pixels)", -1);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-source-radius", 0, "Source matching radius (pixels)", NAN);
-    psMetadataAddS32(arguments, PS_LIST_TAIL, "-stride", 0, "Size of convolution patches (pixels)", -1);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-threshold", 0, "Minimum threshold for stamps (ADU)", NAN);
-    psMetadataAddS32(arguments, PS_LIST_TAIL, "-iter", 0, "Number of rejection iterations", -1);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-rej", 0, "Rejection thresold (sigma)", NAN);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-sys", 0, "Relative systematic error in kernel", NAN);
-    psMetadataAddImageMask(arguments,  PS_LIST_TAIL, "-mask-bad", 0, "Mask value for bad pixels", 0);
-    psMetadataAddImageMask(arguments,  PS_LIST_TAIL, "-mask-poor", 0, "Mask value for poor pixels", 0);
-    psMetadataAddF32(arguments,  PS_LIST_TAIL, "-poor-frac", 0, "Fraction of variance for poor pixels", NAN);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-badfrac", 0, "Maximum fraction of bad pixels to accept", 1.0);
-    psMetadataAddBool(arguments,  PS_LIST_TAIL, "-reverse", 0, "Reverse sense of subtraction?", false);
-    psMetadataAddBool(arguments,  PS_LIST_TAIL, "-generate-mask", 0, "Generate mask if not supplied?", false);
-    psMetadataAddStr(arguments,  PS_LIST_TAIL, "-stamps", 0,
-                     "Stamps filename; file has x,y on each line", NULL);
-    psMetadataAddBool(arguments, PS_LIST_TAIL, "-opt", 0,
-                      "Derive optimum parameters for ISIS kernels?", false);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-opt-min", 0, "Minimum value for optimum kernel search", NAN);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-opt-max", 0, "Minimum value for optimum kernel search", NAN);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-opt-step", 0, "Step value for optimum kernel search", NAN);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-opt-tol", 0, "Tolerance for optimum kernel search", NAN);
-    psMetadataAddS32(arguments, PS_LIST_TAIL, "-opt-order", 0, "Maximum order for optimum kernel search", -1);
-    psMetadataAddBool(arguments, PS_LIST_TAIL, "-dual", 0, "Dual convolution", false);
-    psMetadataAddBool(arguments, PS_LIST_TAIL, "-photometry", 0, "Perform photometry?", false);
+    psMetadataAddStr(arguments,  PS_LIST_TAIL, "-stamps", 0, "Stamps filename; x,y on each line", NULL);
     psMetadataAddS32(arguments, PS_LIST_TAIL, "-threads", 0, "Number of threads", 0);
-    psMetadataAddS32(arguments, PS_LIST_TAIL, "-bin1", 0, "Binning factor for first level", 0);
-    psMetadataAddS32(arguments, PS_LIST_TAIL, "-bin2", 0, "Binning factor for second level", 0);
     psMetadataAddStr(arguments, PS_LIST_TAIL, "-dumpconfig", 0, "file to dump configuration to", NULL);
+    psMetadataAddBool(arguments, PS_LIST_TAIL, "-photometry", 0, "Perform photometry?", NULL);
+    psMetadataAddBool(arguments, PS_LIST_TAIL, "-inverse", 0, "Generate inverse subtractions?", NULL);
     psMetadataAddBool(arguments, PS_LIST_TAIL, "-visual", 0, "Show diagnostic plots", NULL);
 
@@ -302,80 +125,16 @@
     }
 
-    if (psMetadataLookupBool(NULL, arguments, "-photometry")) {
-        psMetadataAddBool(recipe, PS_LIST_TAIL, "PHOTOMETRY", PS_META_REPLACE, "Perform photometry?", true);
-    }
+    data->stamps = psMemIncrRefCounter(psMetadataLookupStr(NULL, arguments, "-stamps"));
 
-    return true;
-}
-
-bool ppSubArgumentsParse(pmConfig *config)
-{
-    assert(config);
-
-    psMetadata *arguments = config->arguments; // Command-line arguments
-
-    valueArgStr(arguments, "-stats",  "STATS",  arguments);
-    valueArgStr(arguments, "-stamps", "STAMPS", arguments);
-
-    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSUB_RECIPE); // Recipe for ppSim
-    if (!recipe) {
-        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find recipe %s", PPSUB_RECIPE);
-        goto ERROR;
-    }
-
-    VALUE_ARG_RECIPE_FLOAT("-region",        "REGION.SIZE",     F32);
-    VALUE_ARG_RECIPE_INT("-size",            "KERNEL.SIZE",     S32, 0);
-    VALUE_ARG_RECIPE_INT("-order",           "SPATIAL.ORDER",   S32, -1);
-    VALUE_ARG_RECIPE_FLOAT("-spacing",       "STAMP.SPACING",   F32);
-    VALUE_ARG_RECIPE_INT("-rings-order",     "RINGS.ORDER",     S32, -1);
-    VALUE_ARG_RECIPE_INT("-inner",           "INNER",           S32, -1);
-    VALUE_ARG_RECIPE_INT("-spam-binning",    "SPAM.BINNING",    S32, 0);
-    VALUE_ARG_RECIPE_INT("-footprint",       "STAMP.FOOTPRINT", S32, -1);
-    VALUE_ARG_RECIPE_FLOAT("-source-radius", "SOURCE.RADIUS",   F32);
-    VALUE_ARG_RECIPE_INT("-stride",          "STRIDE",          S32, -1);
-    VALUE_ARG_RECIPE_FLOAT("-threshold",     "STAMP.THRESHOLD", F32);
-    VALUE_ARG_RECIPE_INT("-iter",            "ITER",            S32, -1);
-    VALUE_ARG_RECIPE_FLOAT("-rej",           "REJ",             F32);
-    VALUE_ARG_RECIPE_FLOAT("-sys",           "SYS",             F32);
-    VALUE_ARG_RECIPE_FLOAT("-badfrac",       "BADFRAC",         F32);
-    VALUE_ARG_RECIPE_FLOAT("-penalty",       "PENALTY",         F32);
-    VALUE_ARG_RECIPE_FLOAT("-poor-frac",     "POOR.FRACTION",   F32);
-    VALUE_ARG_RECIPE_INT("-bin1",            "BIN1",            S32, 0);
-    VALUE_ARG_RECIPE_INT("-bin2",            "BIN2",            S32, 0);
-
-    valueArgRecipeStr(arguments, recipe, "-mask-in",   "MASK.IN",  recipe);
-    valueArgRecipeStr(arguments, recipe, "-mask-bad",  "MASK.BAD",  recipe);
-    valueArgRecipeStr(arguments, recipe, "-mask-poor", "MASK.POOR", recipe);
-
-    vectorArgRecipe(arguments, "-isis-widths", recipe, "ISIS.WIDTHS", recipe, PS_TYPE_F32);
-    vectorArgRecipe(arguments, "-isis-orders", recipe, "ISIS.ORDERS", recipe, PS_TYPE_S32);
-
-    psVector *widths = psMetadataLookupPtr(NULL, recipe, "ISIS.WIDTHS"); // ISIS Gaussian widths
-    psVector *orders = psMetadataLookupPtr(NULL, recipe, "ISIS.ORDERS"); // ISIS Polynomial orders
-    if (widths->n != orders->n) {
-        psError(PS_ERR_BAD_PARAMETER_SIZE, true, "Size of vectors for ISIS widths and orders do not match.");
-        goto ERROR;
-    }
-
-    if (psMetadataLookupBool(NULL, arguments, "-opt") || psMetadataLookupBool(NULL, recipe, "OPTIMUM")) {
-        psMetadataAddBool(recipe, PS_LIST_TAIL, "OPTIMUM", PS_META_REPLACE,
-                          "Derive optimum parameters for ISIS kernels?", true);
-        VALUE_ARG_RECIPE_FLOAT("-opt-min", "OPTIMUM.MIN",   F32);
-        VALUE_ARG_RECIPE_FLOAT("-opt-max", "OPTIMUM.MAX",   F32);
-        VALUE_ARG_RECIPE_FLOAT("-opt-step","OPTIMUM.STEP",  F32);
-        VALUE_ARG_RECIPE_FLOAT("-opt-tol", "OPTIMUM.TOL",   F32);
-        VALUE_ARG_RECIPE_INT("-opt-order", "OPTIMUM.ORDER", S32, -1);
-    }
-
-    psMetadataAddBool(arguments, PS_LIST_TAIL, "REVERSE", 0, "Reverse sense of subtraction",
-                      psMetadataLookupBool(NULL, arguments, "-reverse"));
-    psMetadataAddBool(recipe, PS_LIST_TAIL, "MASK.GENERATE", PS_META_REPLACE, "Generate mask if not supplied",
-                      psMetadataLookupBool(NULL, arguments, "-generate-mask"));
-    psMetadataAddBool(recipe, PS_LIST_TAIL, "DUAL", PS_META_REPLACE, "Dual convolution?",
-                      psMetadataLookupBool(NULL, arguments, "-dual"));
-
-    // Need to update this because it could have been overwritten by the camera's own recipe
-    if (psMetadataLookupBool(NULL, arguments, "-photometry")) {
-        psMetadataAddBool(recipe, PS_LIST_TAIL, "PHOTOMETRY", PS_META_REPLACE, "Perform photometry?", true);
+    const char *statsName = psMetadataLookupStr(NULL, arguments, "-stats"); // Filename for statistics
+    if (statsName && strlen(statsName) > 0) {
+        psString resolved = pmConfigConvertFilename(statsName, config, true, true); // Resolved filename
+        data->statsFile = fopen(resolved, "w");
+        if (!data->statsFile) {
+            psError(PS_ERR_IO, true, "Unable to open statistics file %s for writing.\n", resolved);
+            psFree(resolved);
+            return false;
+        }
+        psFree(resolved);
     }
 
@@ -384,19 +143,5 @@
     }
 
-    // Translate the kernel type
-    psString type = psMetadataLookupStr(NULL, arguments, "-type"); // Name of kernel type
-    if (!type || strlen(type) == 0) {
-        type = psMetadataLookupStr(NULL, recipe, "KERNEL.TYPE");
-        if (!type || strlen(type) == 0) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Unable to find KERNEL.TYPE specified.");
-            goto ERROR;
-        }
-    }
-    psMetadataAddStr(recipe, PS_LIST_TAIL, "KERNEL.TYPE", PS_META_REPLACE, "Type of kernel", type);
-
-    psTrace("ppSub", 1, "Done reading command-line arguments\n");
-
-    // XXX move this to ppSubArguments
-    int threads = psMetadataLookupS32(NULL, config->arguments, "-threads"); // Number of threads
+    int threads = psMetadataLookupS32(NULL, arguments, "-threads"); // Number of threads
     if (threads > 0) {
         if (!psThreadPoolInit(threads)) {
@@ -406,7 +151,6 @@
     }
 
+    psTrace("ppSub", 1, "Done reading command-line arguments\n");
+
     return true;
-
-ERROR:
-    return false;
 }
