Index: trunk/ppSub/src/ppSubReadout.c
===================================================================
--- trunk/ppSub/src/ppSubReadout.c	(revision 18612)
+++ trunk/ppSub/src/ppSubReadout.c	(revision 18920)
@@ -58,37 +58,49 @@
     PS_ASSERT_IMAGES_SIZE_EQUAL(input, reference, false);
 
-    // Look up appropriate values
+    // Look up recipe values
+    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSUB_RECIPE); // Recipe for ppSim
+    psAssert(recipe, "We checked this earlier, so it should be here.");
+
+    const char *typeStr = psMetadataLookupStr(NULL, recipe, "KERNEL.TYPE"); // Kernel type
+    psAssert(typeStr, "We put it here in ppSubArguments.c");
+    pmSubtractionKernelsType type = pmSubtractionKernelsTypeFromString(typeStr); // Type of kernel
+    if (type == PM_SUBTRACTION_KERNEL_NONE) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unrecognised kernel type: %s", typeStr);
+        psFree(inConv);
+        psFree(refConv);
+        psFree(outRO);
+        return false;
+    }
+
     bool mdok;                          // Status of MD lookup
-    int size = psMetadataLookupS32(NULL, config->arguments, "KERNEL.SIZE"); // Kernel half-size
-    int order = psMetadataLookupS32(NULL, config->arguments, "SPATIAL.ORDER"); // Spatial polynomial order
-    float regionSize = psMetadataLookupF32(NULL, config->arguments, "REGION.SIZE"); // Size of iso-kernel regs
-    float spacing = psMetadataLookupF32(NULL, config->arguments, "STAMP.SPACING"); // Typical stamp spacing
-    int footprint = psMetadataLookupS32(NULL, config->arguments, "STAMP.FOOTPRINT"); // Stamp half-size
-    float threshold = psMetadataLookupF32(NULL, config->arguments, "STAMP.THRESHOLD"); // Threshold for stmps
-    int iter = psMetadataLookupS32(NULL, config->arguments, "ITER"); // Rejection iterations
-    float rej = psMetadataLookupF32(NULL, config->arguments, "REJ"); // Rejection threshold
-    pmSubtractionKernelsType type = psMetadataLookupS32(NULL, config->arguments,
-                                                        "KERNEL.TYPE"); // Kernel type
+    int size = psMetadataLookupS32(NULL, recipe, "KERNEL.SIZE"); // Kernel half-size
+    int order = psMetadataLookupS32(NULL, recipe, "SPATIAL.ORDER"); // Spatial polynomial order
+    float regionSize = psMetadataLookupF32(NULL, recipe, "REGION.SIZE"); // Size of iso-kernel regs
+    float spacing = psMetadataLookupF32(NULL, recipe, "STAMP.SPACING"); // Typical stamp spacing
+    int footprint = psMetadataLookupS32(NULL, recipe, "STAMP.FOOTPRINT"); // Stamp half-size
+    float threshold = psMetadataLookupF32(NULL, recipe, "STAMP.THRESHOLD"); // Threshold for stmps
+    int iter = psMetadataLookupS32(NULL, recipe, "ITER"); // Rejection iterations
+    float rej = psMetadataLookupF32(NULL, recipe, "REJ"); // Rejection threshold
     bool reverse = psMetadataLookupBool(NULL, config->arguments, "REVERSE"); // Reverse sense of subtraction?
-    psVector *widths = psMetadataLookupPtr(NULL, config->arguments, "ISIS.WIDTHS"); // ISIS Gaussian widths
-    psVector *orders = psMetadataLookupPtr(NULL, config->arguments, "ISIS.ORDERS"); // ISIS Polynomial orders
-    int inner = psMetadataLookupS32(NULL, config->arguments, "INNER"); // Inner radius
-    int ringsOrder = psMetadataLookupS32(NULL, config->arguments, "RINGS.ORDER"); // RINGS polynomial order
-    int binning = psMetadataLookupS32(NULL, config->arguments, "SPAM.BINNING"); // Binning for SPAM kernel
-    float penalty = psMetadataLookupF32(NULL, config->arguments, "PENALTY"); // Penalty for wideness
+    psVector *widths = psMetadataLookupPtr(NULL, recipe, "ISIS.WIDTHS"); // ISIS Gaussian widths
+    psVector *orders = psMetadataLookupPtr(NULL, recipe, "ISIS.ORDERS"); // ISIS Polynomial orders
+    int inner = psMetadataLookupS32(NULL, recipe, "INNER"); // Inner radius
+    int ringsOrder = psMetadataLookupS32(NULL, recipe, "RINGS.ORDER"); // RINGS polynomial order
+    int binning = psMetadataLookupS32(NULL, recipe, "SPAM.BINNING"); // Binning for SPAM kernel
+    float penalty = psMetadataLookupF32(NULL, recipe, "PENALTY"); // Penalty for wideness
     psMaskType maskIn = pmConfigMaskGet("MASK.VALUE", config); // Bits to mask going in to pmSubtractionMatch
     psMaskType maskOut = pmConfigMaskGet("BLANK", config); // Bits to mask after pmSubtractionMatch
-    float badFrac = psMetadataLookupF32(NULL, config->arguments, "BADFRAC"); // Maximum bad fraction
+    float badFrac = psMetadataLookupF32(NULL, recipe, "BADFRAC"); // Maximum bad fraction
     const char *stampsName = psMetadataLookupStr(&mdok, config->arguments, "STAMPS"); // Filename for stamps
 
-    bool optimum = psMetadataLookupBool(&mdok, config->arguments, "OPTIMUM"); // Derive optimum parameters?
-    float optMin = psMetadataLookupF32(&mdok, config->arguments, "OPTIMUM.MIN"); // Minimum width for search
-    float optMax = psMetadataLookupF32(&mdok, config->arguments, "OPTIMUM.MAX"); // Maximum width for search
-    float optStep = psMetadataLookupF32(&mdok, config->arguments, "OPTIMUM.STEP"); // Step for search
-    float optThresh = psMetadataLookupF32(&mdok, config->arguments, "OPTIMUM.TOL"); // Tolerance for search
-    int optOrder = psMetadataLookupS32(&mdok, config->arguments, "OPTIMUM.ORDER"); // Order for search
-    bool dual = psMetadataLookupBool(&mdok, config->arguments, "DUAL"); // Dual convolution?
-    bool renorm = psMetadataLookupBool(&mdok, config->arguments, "RENORM"); // Renormalise weights?
-    int renormWidth = psMetadataLookupS32(&mdok, config->arguments, "RENORM.WIDTH"); // Width for renormalise
+    bool optimum = psMetadataLookupBool(&mdok, recipe, "OPTIMUM"); // Derive optimum parameters?
+    float optMin = psMetadataLookupF32(&mdok, recipe, "OPTIMUM.MIN"); // Minimum width for search
+    float optMax = psMetadataLookupF32(&mdok, recipe, "OPTIMUM.MAX"); // Maximum width for search
+    float optStep = psMetadataLookupF32(&mdok, recipe, "OPTIMUM.STEP"); // Step for search
+    float optThresh = psMetadataLookupF32(&mdok, recipe, "OPTIMUM.TOL"); // Tolerance for search
+    int optOrder = psMetadataLookupS32(&mdok, recipe, "OPTIMUM.ORDER"); // Order for search
+    bool dual = psMetadataLookupBool(&mdok, recipe, "DUAL"); // Dual convolution?
+    bool renorm = psMetadataLookupBool(&mdok, recipe, "RENORM"); // Renormalise weights?
+    int renormWidth = psMetadataLookupS32(&mdok, recipe, "RENORM.WIDTH"); // Width for renormalise
 
     pmSubtractionMode mode = dual ? PM_SUBTRACTION_MODE_DUAL : PM_SUBTRACTION_MODE_UNSURE; // Subtraction mode
@@ -97,5 +109,5 @@
     int numCols = input->numCols, numRows = input->numRows; // Image dimensions
     if (!inRO->mask) {
-        if (psMetadataLookupBool(NULL, config->arguments, "MASK.GENERATE")) {
+        if (psMetadataLookupBool(NULL, recipe, "MASK.GENERATE")) {
             pmReadoutSetMask(inRO, pmConfigMaskGet("SAT", config), pmConfigMaskGet("BAD", config));
         } else {
@@ -105,5 +117,5 @@
     }
     if (!refRO->mask) {
-        if (psMetadataLookupBool(NULL, config->arguments, "MASK.GENERATE")) {
+        if (psMetadataLookupBool(NULL, recipe, "MASK.GENERATE")) {
             pmReadoutSetMask(refRO, pmConfigMaskGet("SAT", config), pmConfigMaskGet("BAD", config));
         } else {
@@ -220,5 +232,5 @@
     // Photometry stage 1: measure the PSF
     pmPSF *psf = NULL;                  // PSF for photometry
-    if (psMetadataLookupBool(NULL, config->arguments, "PHOTOMETRY")) {
+    if (psMetadataLookupBool(NULL, recipe, "PHOTOMETRY")) {
         outRO->image = psImageCopy(outRO->image, minuend->image, PS_TYPE_F32);
         if (minuend->weight) {
@@ -319,5 +331,5 @@
 
     // QA: photometry of known sources with measured PSF
-    if (sourcesRO && psMetadataLookupBool(NULL, config->arguments, "PHOTOMETRY")) {
+    if (sourcesRO && psMetadataLookupBool(NULL, recipe, "PHOTOMETRY")) {
         sources = psMetadataLookupPtr(&mdok, sourcesRO->analysis, "PSPHOT.SOURCES");
 
@@ -374,5 +386,5 @@
 
     // Photometry stage 2: find and measure sources on the subtracted image
-    if (psMetadataLookupBool(NULL, config->arguments, "PHOTOMETRY")) {
+    if (psMetadataLookupBool(NULL, recipe, "PHOTOMETRY")) {
         // The PSF should already be stored for the readout
         pmFPAfile *photFile = psMetadataLookupPtr(NULL, config->files, "PSPHOT.INPUT");
