Index: /trunk/ppImage/src/Makefile.am
===================================================================
--- /trunk/ppImage/src/Makefile.am	(revision 5975)
+++ /trunk/ppImage/src/Makefile.am	(revision 5976)
@@ -9,4 +9,5 @@
 	ppDetrendNonLinear.c \
 	ppDetrendPedestal.c \
+	ppFile.c \
 	ppImage.c \
 	ppImageConfig.c \
Index: /trunk/ppImage/src/ppImage.c
===================================================================
--- /trunk/ppImage/src/ppImage.c	(revision 5975)
+++ /trunk/ppImage/src/ppImage.c	(revision 5976)
@@ -1,5 +1,6 @@
-# include "ppImage.h"
+#include "ppImage.h"
 
-int main (int argc, char **argv) {
+int main(int argc, char **argv)
+{
 
     ppData data;
@@ -7,26 +8,26 @@
     ppOptions options;
 
-    psTimerStart("phase2");
+    psTimerStart(TIMERNAME);
 
     // Parse the configuration and arguments
-    ppImageConfig (&config, argc, argv);
+    ppImageConfig(&config, argc, argv);
 
     // Open the input image, output image, output mask
     // Get camera configuration from header if not already defined
     // Construct camera in preparation for reading
-    ppImageParseCamera (&data, &config);
+    ppImageParseCamera(&data, &config);
 
     // Set various tasks (define optional operations)
-    ppImageOptions (&data, &options, &config);
+    ppImageOptions(&data, &options, &config);
 
     // open detrend images, load headers, optionally load pixels
-    ppImageParseDetrend (&data, &options, &config);
+    ppImageParseDetrend(&data, &options, &config);
 
     // Image Arithmetic Loop
-    ppImageLoop (&data, &options, &config);
+    ppImageLoop(&data, &options, &config);
 
     // output options
-    // ppImageOutput (&data, &options, &config);
+    // ppImageOutput(&data, &options, &config);
 
-    exit (0);
+    exit(EXIT_SUCCESS);
 }
Index: /trunk/ppImage/src/ppImage.h
===================================================================
--- /trunk/ppImage/src/ppImage.h	(revision 5975)
+++ /trunk/ppImage/src/ppImage.h	(revision 5976)
@@ -1,2 +1,5 @@
+#ifndef PP_IMAGE_H
+#define PP_IMAGE_H
+
 #include <stdio.h>
 #include <strings.h>
@@ -22,87 +25,129 @@
 
 #define RECIPE "PHASE2"                 // Name of the recipe to use
+#define TIMERNAME "ppImage"             // Name of timer
 
+// How much of the FPA to load at a time
 typedef enum {
-    PP_LOAD_NONE,
-    PP_LOAD_FPA,
-    PP_LOAD_CHIP,
-    PP_LOAD_CELL,
+    PP_LOAD_NONE,                       // Don't load anything
+    PP_LOAD_FPA,                        // Load the entire FPA at once
+    PP_LOAD_CHIP,                       // Load by chip
+    PP_LOAD_CELL,                       // Load by cell
 } ppImageLoadDepth;
 
+// Configuration data
 typedef struct {
-    psMetadata *site;
-    psMetadata *camera;
-    psMetadata *recipe;
-    psMetadata *arguments;
-    psDB       *database;
+    psMetadata *site;                   // The site configuration
+    psMetadata *camera;                 // The camera configuration
+    psMetadata *recipe;                 // The recipe (i.e., specific setups)
+    psMetadata *arguments;              // The command-line arguments
+    psDB       *database;               // Database handle
 } ppConfig;
 
+// Options
 typedef struct {
-    bool doMask;			// Mask bad pixles
-    bool doBias;			// Bias subtraction
-    bool doDark;			// Dark subtraction
-    bool doFlat;			// Flat-field normalisation
-    bool doFringe;			// Fringe subtraction
-    bool doSource;			// Source identification and photometry
-    bool doAstrom;			// Astrometry
+    bool doMask;                        // Mask bad pixels
+    bool doBias;                        // Bias subtraction
+    bool doDark;                        // Dark subtraction
+    bool doFlat;                        // Flat-field normalisation
+    bool doFringe;                      // Fringe subtraction
+    bool doSource;                      // Source identification and photometry
+    bool doAstrom;                      // Astrometry
 
-    bool doOverscan;			// Overscan subtraction
-    int overscanBins;			// Number of pixels per bin for overscan
-    psStats *overscanStats;		// Statistics for overscan
-    void *overscanFit;			// Overscan fit (polynomial or spline)
-    pmFit overscanFitType;		// Fit type for overscan
-    pmOverscanAxis overscanMode;	// Axis for overscan
+    bool doOverscan;                    // Overscan subtraction
+    int overscanBins;                   // Number of pixels per bin for overscan
+    psStats *overscanStats;             // Statistics for overscan
+    void *overscanFit;                  // Overscan fit (polynomial or spline)
+    pmFit overscanFitType;              // Fit type for overscan
+    pmOverscanAxis overscanMode;        // Axis for overscan
 
-    bool doNonLin;			// Non-linearity correction
+    bool doNonLin;                      // Non-linearity correction
     psDataType nonLinearType;
     psMetadataItem *nonLinearData;
     void *nonLinearSource;
 
-    ppImageLoadDepth imageLoadDepth;
+    ppImageLoadDepth imageLoadDepth;    // How much of the FPA to load at once
 } ppOptions;
 
+// A file to process
 typedef struct {
-    char *filename;
-    pmFPA *fpa;
-    psFits *fits;
-    psMetadata *header;
-} ppFPA; 
+    char *filename;                     // File name
+    psFits *fits;                       // The FITS file handle
+    psMetadata *phu;                    // The FITS header
+    pmFPA *fpa;                         // The FPA, with pixels and extensions
+} ppFile;
 
+// The data to be processed
 typedef struct {
-    ppFPA *input;
-    ppFPA *mask;
-    ppFPA *bias;
-    ppFPA *dark;
-    ppFPA *flat;
-    ppFPA *fringe;
-    ppFPA *process;
+    ppFile *input;                      // The input, to be operated upon
+    ppFile *mask;                       // The bad pixel mask image
+    ppFile *bias;                       // The bias correction image
+    ppFile *dark;                       // The dark correction image
+    ppFile *flat;                       // The flat-field correction image
+    ppFile *fringe;                     // The fringe correction image
+#if 0
+    ppFile *process;                    // A dummy file pointing out what needs to be processed
+#endif
 } ppData;
 
+// Cells to be used in the detrend
 typedef struct {
-    pmCell *input;
-    pmCell *mask;
-    pmCell *bias;
-    pmCell *dark;
-    pmCell *flat;
+    pmCell *input;                      // The input cell, to be operated upon
+    pmCell *mask;                       // The bad pixel mask
+    pmCell *bias;                       // The bias correction
+    pmCell *dark;                       // The dark correction
+    pmCell *flat;                       // The flat-field correction
 } ppDetrend;
 
-bool ppImageConfig (ppConfig *config, int argc, char **argv);
-bool ppImageLoadPixels (ppFPA *input, ppFPA *process, psDB *db, int nChip, int nCell);
-bool ppImageLoop (ppData *data, ppOptions *options, ppConfig *config);
-bool ppImageOptions (ppData *data, ppOptions *options, ppConfig *config);
-bool ppImageParseCamera (ppData *data, ppConfig *config);
-bool ppImageParseDetrend (ppData *data, ppOptions *options, ppConfig *config);
 
-bool ppReadoutWeights (pmReadout *readout);
+// Allocators
+ppFile *ppFileAlloc(void);
 
-bool ppDetrendCell (ppDetrend *detrend, ppOptions *options, ppConfig *config);
 
-bool ppDetrendMask (pmCell *cell, pmReadout *input, pmReadout *mask);
-bool ppDetrendNonLinear (pmCell *cell, pmReadout *input, ppOptions *options);
-bool ppDetrendNonLinearLookup (pmReadout *input, psMetadataItem *dataItem);
-bool ppDetrendNonLinearPolynomial (pmReadout *input, psMetadataItem *dataItem);
-bool ppDetrendBias (pmCell *inputCell, pmReadout *inputReadout, pmReadout *pedestal, ppOptions *options);
-pmReadout* ppDetrendPedestal (pmReadout *pedestal, pmCell *input, pmReadout *bias, pmReadout *dark, float darkTime, ppOptions *options);
-pmReadout* ppDetrendSelectFirst (pmCell *cell, char *name, bool doThis);
 
-bool ppFPAOpen (ppFPA *fpa, psMetadata *camera, char *name, bool doThis);
+// Parse the site configuration (and camera and recipe if specified); read the command-line arguments
+bool ppImageConfig(ppConfig *config,   // The configuration(output)
+                   int argc, char **argv // Command-line arguments
+                   );
+
+// Determine what type of camera, and initialise
+bool ppImageParseCamera(ppData *data,   // The data to be processed
+                        ppConfig *config // Configuration
+                        );
+
+// Determine the procession options
+bool ppImageOptions(ppData *data,       // The data to be processed
+                    ppOptions *options, // Processing options
+                    ppConfig *config    // Configuration
+                    );
+
+
+// Loop over the
+bool ppImageLoop(ppData *data, ppOptions *options, ppConfig *config);
+
+// Load the pixels for the given file
+bool ppImageLoadPixels(ppFile *input,   // File for which to load the pixels
+                       psDB *db,        // Database handle (for reading concepts)
+                       int nChip,       // Chip number to load
+                       int nCell        // Cell number to load
+                       );
+
+bool ppImageParseDetrend(ppData *data, ppOptions *options, ppConfig *config);
+
+bool ppReadoutWeights(pmReadout *readout);
+
+bool ppDetrendCell(ppDetrend *detrend, ppOptions *options, ppConfig *config);
+
+bool ppDetrendMask(pmCell *cell, pmReadout *input, pmReadout *mask);
+bool ppDetrendNonLinear(pmCell *cell, pmReadout *input, ppOptions *options);
+bool ppDetrendNonLinearLookup(pmReadout *input, psMetadataItem *dataItem);
+bool ppDetrendNonLinearPolynomial(pmReadout *input, psMetadataItem *dataItem);
+bool ppDetrendBias(pmCell *inputCell, pmReadout *inputReadout, pmReadout *pedestal, ppOptions *options);
+pmReadout* ppDetrendPedestal(pmReadout *pedestal, pmCell *input, pmReadout *bias, pmReadout *dark, float darkTime, ppOptions *options);
+pmReadout* ppDetrendSelectFirst(pmCell *cell, char *name, bool doThis);
+
+#if 0
+bool ppFileOpen(ppFile *fpa, psMetadata *camera, char *name, bool doThis);
+#endif
+
+
+#endif // Pau.
Index: /trunk/ppImage/src/ppImageConfig.c
===================================================================
--- /trunk/ppImage/src/ppImageConfig.c	(revision 5975)
+++ /trunk/ppImage/src/ppImageConfig.c	(revision 5976)
@@ -1,13 +1,15 @@
-# include "ppImage.h"
+#include "ppImage.h"
 
-bool ppImageConfig (ppConfig *config, int argc, char **argv) {
+bool ppImageConfig(ppConfig *config, int argc, char **argv)
+{
+    // Initialise the configuration
+    config->site = NULL;                // Site configuration
+    config->camera = NULL;              // Camera configuration
+    config->recipe = NULL;              // Recipe configuration
+    config->arguments = NULL;           // The command-line arguments
+    config->database = NULL;            // Database handle
 
-    // Parse the configurations
-    config->site = NULL;            // Site configuration
-    config->camera = NULL;          // Camera configuration
-    config->recipe = NULL;          // Recipe configuration
-
-    // XXX - this should be split into a function to parse argc,argv 
-    //       and a second to read the config files.  
+    // XXX - this should be split into a function to parse argc,argv
+    //       and a second to read the config files.
     //       all argc,argv should be interpretted before work is done.
     if (! pmConfigRead(&config->site, &config->camera, &config->recipe, &argc, argv, RECIPE)) {
@@ -23,4 +25,5 @@
     psMetadataAddStr(config->arguments, PS_LIST_TAIL, "-flat", 0, "Name of the flat-field image", "");
     psMetadataAddStr(config->arguments, PS_LIST_TAIL, "-mask", 0, "Name of the mask image", "");
+    psMetadataAddStr(config->arguments, PS_LIST_TAIL, "-fringe", 0, "Name of the fringe image", "");
     psMetadataAddS32(config->arguments, PS_LIST_TAIL, "-chip", 0, "Chip number to process (if positive)", -1);
 
@@ -33,10 +36,13 @@
     }
 
-    // add the input and output images to the arguments list
-    psMetadataAddStr (config->arguments, PS_LIST_TAIL, "-input",  0, "Name of the input image",  argv[1]);
-    psMetadataAddStr (config->arguments, PS_LIST_TAIL, "-output", 0, "Name of the output image", argv[2]);
+    // Add the input and output images (which remain on the command-line) to the arguments list
+    psMetadataAddStr(config->arguments, PS_LIST_TAIL, "-input",  0, "Name of the input image",  argv[1]);
+    psMetadataAddStr(config->arguments, PS_LIST_TAIL, "-output", 0, "Name of the output image", argv[2]);
 
-    // define Database handle, if used
+    // Define database handle, if used
+#if 0
     config->database = pmConfigDB(config->site);
+#endif
+
     return true;
-} 
+}
Index: /trunk/ppImage/src/ppImageDetrendNonLinear.c
===================================================================
--- /trunk/ppImage/src/ppImageDetrendNonLinear.c	(revision 5975)
+++ /trunk/ppImage/src/ppImageDetrendNonLinear.c	(revision 5976)
@@ -6,7 +6,7 @@
     psVector *coeff = dataItem->data.V; // The coefficient vector
     if (coeff->type.type != PS_TYPE_F64) {
-	psVector *temp = psVectorCopy(NULL, coeff, PS_TYPE_F64); // F64 version
-	psFree (coeff);
-	coeff = temp;
+        psVector *temp = psVectorCopy(NULL, coeff, PS_TYPE_F64); // F64 version
+        psFree (coeff);
+        coeff = temp;
     }
     psPolynomial1D *correction = psPolynomial1DAlloc(coeff->n - 1, PS_POLYNOMIAL_ORD);
@@ -17,5 +17,5 @@
     psFree(correction);
     return true;
-}    
+}
 
 bool ppDetrendNonLinearLookup (pmReadout *input, psMetadataItem *dataItem) {
@@ -25,8 +25,8 @@
     psLookupTable *table = psLookupTableAlloc(name, "%f %f", 0);
     if (psLookupTableRead(table) <= 0) {
-	psErrorStackPrint(stderr, "Unable to read non-linearity correction file "
-			  "%s --- ignored\n", name);
-	return false;
-    } 
+        psErrorStackPrint(stderr, "Unable to read non-linearity correction file "
+                          "%s --- ignored\n", name);
+        return false;
+    }
 #ifdef PRODUCTION
     pmNonLinearityLookup(input, table);
@@ -38,5 +38,5 @@
     psFree(table);
     return true;
-}    
+}
 
 bool ppDetrendNonLinear (pmCell *cell, pmReadout *input, ppOptions *options) {
@@ -46,51 +46,62 @@
     switch (options->nonLinearType) {
       case PS_DATA_VECTOR:
-	ppDetrendNonLinearPolynomial (input, options->nonLinearData);
-	return true;
+        ppDetrendNonLinearPolynomial (input, options->nonLinearData);
+        return true;
 
       case PS_DATA_STRING:
-	ppDetrendNonLinearLookup (input, options->nonLinearData);
-	return true;
+        ppDetrendNonLinearLookup (input, options->nonLinearData);
+        return true;
 
       case PS_DATA_METADATA:
-	// XXX this is somewhat confusing : let's wrap in a function when i understand it
-	concept = pmCellGetConcept(cell, options->nonLinearSource);
-	if (! concept) {
-	    psLogMsg("phase2", PS_LOG_WARN, "Unable to find value of concept %s "
-		     "for non-linearity correction --- ignored.\n", options->nonLinearSource);
-	    return false;
-	} 
-	if (concept->type != PS_DATA_STRING) {
-	    psLogMsg("phase2", PS_LOG_WARN, "Type for concept %s isn't STRING, as"
-		     " expected for non-linearity correction --- ignored.\n",
-		     concept);
-	    return false;
-	} 
+        // XXX EAM: this is somewhat confusing : let's wrap in a function when i understand it
 
-	// Get the value of the concept
-	psString conceptValue = concept->data.V;
-	psMetadata *folder = (psMetadata *)options->nonLinearData->data.V;
-	psMetadataItem *optionItem = psMetadataLookup(folder, conceptValue);
-	if (!optionItem) {
-	    psLogMsg("phase2", PS_LOG_WARN, "Unable to find %s in NONLIN.DATA"
-		     " --- ignored.\n", conceptValue);
-	    return false;
-	} 
+        // Go looking for the value in the hierarchy
+        concept = psMetadataLookup(cell->concepts, options->nonLinearSource);
+        if (! concept) {
+            pmChip *chip = cell->parent;// Parent chip
+            concept = psMetadataLookup(chip->concepts, options->nonLinearSource);
+            if (! concept) {
+                pmFPA *fpa = chip->parent; // Parent FPA
+                concept = psMetadataLookup(fpa->concepts, options->nonLinearSource);
+                if (! concept) {
+                    psLogMsg("phase2", PS_LOG_WARN, "Unable to find value of concept %s "
+                             "for non-linearity correction --- ignored.\n", options->nonLinearSource);
+                    return false;
+                }
+            }
+        }
 
-	switch (optionItem->type) {
-	  case PS_DATA_VECTOR:
-	    ppDetrendNonLinearPolynomial (input, optionItem);
-	    return true;
-	  case PS_DATA_STRING:
-	    ppDetrendNonLinearLookup (input, optionItem);
-	    return true;
-	  default:
-	    psLogMsg("phase2", PS_LOG_WARN, "Non-linearity correction "
-		     "desired but unable to interpret NONLIN.DATA for %s"
-		     " --- ignored\n", conceptValue);
-	    return false;
-	}
+        if (concept->type != PS_DATA_STRING) {
+            psLogMsg("phase2", PS_LOG_WARN, "Type for concept %s isn't STRING, as"
+                     " expected for non-linearity correction --- ignored.\n",
+                     concept);
+            return false;
+        }
+
+        // Get the value of the concept
+        psString conceptValue = concept->data.V;
+        psMetadata *folder = (psMetadata *)options->nonLinearData->data.V;
+        psMetadataItem *optionItem = psMetadataLookup(folder, conceptValue);
+        if (!optionItem) {
+            psLogMsg("phase2", PS_LOG_WARN, "Unable to find %s in NONLIN.DATA"
+                     " --- ignored.\n", conceptValue);
+            return false;
+        }
+
+        switch (optionItem->type) {
+          case PS_DATA_VECTOR:
+            ppDetrendNonLinearPolynomial (input, optionItem);
+            return true;
+          case PS_DATA_STRING:
+            ppDetrendNonLinearLookup (input, optionItem);
+            return true;
+          default:
+            psLogMsg("phase2", PS_LOG_WARN, "Non-linearity correction "
+                     "desired but unable to interpret NONLIN.DATA for %s"
+                     " --- ignored\n", conceptValue);
+            return false;
+        }
       default:
-	psAbort("phase2", "Invalid options->nonLinearType");
+        psAbort("phase2", "Invalid options->nonLinearType");
     }
     return true;
Index: /trunk/ppImage/src/ppImageLoadPixels.c
===================================================================
--- /trunk/ppImage/src/ppImageLoadPixels.c	(revision 5975)
+++ /trunk/ppImage/src/ppImageLoadPixels.c	(revision 5976)
@@ -1,52 +1,51 @@
-# include "ppImage.h"
+// XXX PAP: Need to look this over some more
 
-bool ppImageLoadPixels (ppFPA *input, ppFPA *process, psDB *db, int nChip, int nCell) {
+#include "ppImage.h"
 
-    // an input chip is valid if:
-    // (((nChip == i) || (nChip == -1)) && process.valid)
+bool ppImageLoadPixels(ppFile *input, psDB *db, int chipNum, int cellNum)
+{
+    // an input chip is valid for processing if:
+    // (((chipNum == i) || (chipNum == -1)) && chip.process)
 
-    // if we have not opened the file, skip it
+    // If we have not opened the file, skip it
     if (input->fits == NULL) {
-	return false;
+        return false;
     }
 
-    fprintf (stderr, "loading %d,%d for %s\n", nChip, nCell, input->filename);
+    psTrace(__func__, 1, "Loading %d,%d for %s\n", chipNum, cellNum, input->filename);
 
-    // set input:valid flags according to process and nChip/nCell
+    // set input:valid flags according to process and chipNum/cellNum
     for (int i = 0; i < input->fpa->chips->n; i++) {
-	pmChip *pChip = process->fpa->chips->data[i];
-	pmChip *iChip = input->fpa->chips->data[i];
+        pmChip *chip = input->fpa->chips->data[i]; // Chip in input image
+        chip->process = (! chip->exists && ((chipNum == i) || (chipNum == -1)));
 
-	iChip->valid = pChip->valid;
-	iChip->valid &= (nChip == i) || (nChip == -1);
-
-        for (int j = 0; j < iChip->cells->n; j++) {
-
-	    pmCell *pCell = pChip->cells->data[j];
-	    pmCell *iCell = iChip->cells->data[j];
-
-	    iCell->valid =  pCell->valid;
-	    iCell->valid &= iChip->valid;
-	    iCell->valid &= (nCell == i) || (nCell == -1);
-	}
+        for (int j = 0; j < chip->cells->n; j++) {
+            pmCell *cell = chip->cells->data[j]; // Cell in input image
+            cell->process &= chip->process;
+            cell->process = (! cell->exists && ((cellNum == i) || (cellNum == -1)));
+        }
     }
 
     // Read in the input pixels
-    if (! pmFPARead(input->fpa, input->fits, input->header, db)) {
+    if (! pmFPARead(input->fpa, input->fits, input->phu, db)) {
         psErrorStackPrint(stderr, "Unable to populate camera from input FITS file\n");
         exit(EXIT_FAILURE);
     }
 
+#if 0
+    // XXX PAP: Not sure this is required any more.
+
     // reset input:valid flags to true
     for (int i = 0; i < input->fpa->chips->n; i++) {
 
-	pmChip *iChip = input->fpa->chips->data[i];
-	iChip->valid = true;
-        for (int j = 0; j < iChip->cells->n; j++) {
+        pmChip *chip = input->fpa->chips->data[i];
+        chip->process = true;
+        for (int j = 0; j < chip->cells->n; j++) {
 
-	    pmCell *iCell = iChip->cells->data[j];
-	    iCell->valid =  true;
-	}
+            pmCell *cell = chip->cells->data[j];
+            cell->process = true;
+        }
     }
+#endif
 
     return true;
Index: /trunk/ppImage/src/ppImageLoop.c
===================================================================
--- /trunk/ppImage/src/ppImageLoop.c	(revision 5975)
+++ /trunk/ppImage/src/ppImageLoop.c	(revision 5976)
@@ -1,15 +1,17 @@
 # include "ppImage.h"
 
-bool ppImageLoop (ppData *data, ppOptions *options, ppConfig *config) {
-
+bool ppImageLoop(ppData *data, ppOptions *options, ppConfig *config)
+{
     ppDetrend detrend;
 
     if (options->imageLoadDepth == PP_LOAD_FPA) {
-	ppImageLoadPixels (data->input, data->process, config->database, -1, -1);
-	ppImageLoadPixels (data->bias, 	data->process, config->database, -1, -1);
-	ppImageLoadPixels (data->dark, 	data->process, config->database, -1, -1);
-	ppImageLoadPixels (data->mask, 	data->process, config->database, -1, -1);
-	ppImageLoadPixels (data->flat, 	data->process, config->database, -1, -1);
+        psTrace(__func__, 1, "Loading pixels for FPA...\n");
+        ppImageLoadPixels(data->input, config->database, -1, -1);
+        ppImageLoadPixels(data->bias,  config->database, -1, -1);
+        ppImageLoadPixels(data->dark,  config->database, -1, -1);
+        ppImageLoadPixels(data->mask,  config->database, -1, -1);
+        ppImageLoadPixels(data->flat,  config->database, -1, -1);
     }
+
     for (int i = 0; i < data->input->fpa->chips->n; i++) {
         pmChip *inputChip = data->input->fpa->chips->data[i]; // Chip of interest in input image
@@ -19,13 +21,16 @@
         pmChip *flatChip  = data->flat->fpa->chips->data[i];  // Chip of interest in flat image
 
-        if (! inputChip->valid) { continue; }
+        printf("Chip %d: %x %x\n", i, inputChip->exists, inputChip->process);
+        if (! inputChip->process) { continue; }
 
-	if (options->imageLoadDepth == PP_LOAD_CHIP) {
-	    ppImageLoadPixels (data->input, data->process, config->database, i, -1);
-	    ppImageLoadPixels (data->bias,  data->process, config->database, i, -1);
-	    ppImageLoadPixels (data->dark,  data->process, config->database, i, -1);
-	    ppImageLoadPixels (data->mask,  data->process, config->database, i, -1);
-	    ppImageLoadPixels (data->flat,  data->process, config->database, i, -1);
-	}
+        if (options->imageLoadDepth == PP_LOAD_CHIP) {
+            psTrace(__func__, 1, "Loading pixels for chip %d...\n", i);
+            ppImageLoadPixels(data->input, config->database, i, -1);
+            ppImageLoadPixels(data->bias,  config->database, i, -1);
+            ppImageLoadPixels(data->dark,  config->database, i, -1);
+            ppImageLoadPixels(data->mask,  config->database, i, -1);
+            ppImageLoadPixels(data->flat,  config->database, i, -1);
+        }
+
         for (int j = 0; j < inputChip->cells->n; j++) {
             detrend.input = inputChip->cells->data[j]; // Cell of interest in input image
@@ -35,15 +40,18 @@
             detrend.flat  = flatChip->cells->data[j];  // Cell of interest in flat image
 
-            if (! detrend.input->valid) { continue; }
+            printf ("\tCell %d: %x %x\n", j, detrend.input->exists, detrend.input->process);
+            if (! detrend.input->process) { continue; }
 
-	    if (options->imageLoadDepth == PP_LOAD_CELL) {
-		ppImageLoadPixels (data->input, data->process, config->database, i, j);
-		ppImageLoadPixels (data->bias,  data->process, config->database, i, j);
-		ppImageLoadPixels (data->dark,  data->process, config->database, i, j);
-		ppImageLoadPixels (data->mask,  data->process, config->database, i, j);
-		ppImageLoadPixels (data->flat,  data->process, config->database, i, j);
-	    }
-	    ppDetrendCell (&detrend, options, config);
-	}
+            if (options->imageLoadDepth == PP_LOAD_CELL) {
+                psTrace(__func__, 1, "Loading pixels for chip %d, cell %d...\n", i, j);
+                ppImageLoadPixels(data->input, config->database, i, j);
+                ppImageLoadPixels(data->bias,  config->database, i, j);
+                ppImageLoadPixels(data->dark,  config->database, i, j);
+                ppImageLoadPixels(data->mask,  config->database, i, j);
+                ppImageLoadPixels(data->flat,  config->database, i, j);
+            }
+
+            ppDetrendCell (&detrend, options, config);
+        }
     }
     return true;
Index: /trunk/ppImage/src/ppImageOptions.c
===================================================================
--- /trunk/ppImage/src/ppImageOptions.c	(revision 5975)
+++ /trunk/ppImage/src/ppImageOptions.c	(revision 5976)
@@ -1,119 +1,126 @@
-# include "ppImage.h"
+#include "ppImage.h"
 
 // XXX EAM : this needs signficant work to choose the detrend images based on the detrend database
 
-bool ppImageOptions (ppData *data, ppOptions *options, ppConfig *config) {
+bool ppImageOptions(ppData *data, ppOptions *options, ppConfig *config)
+{
 
-    bool status;
-
-    // default initial values
-    options->doMask = false;		// Mask bad pixels
-    options->doNonLin = false;		// Non-linearity correction
-    options->doBias = false;		// Bias subtraction
-    options->doDark = false;		// Dark subtraction
-    options->doOverscan = false;	// Overscan subtraction
-    options->doFlat = false;		// Flat-field normalisation
-    options->doFringe = false;		// Fringe subtraction
-    options->doSource = false;		// Source identification and photometry
-    options->doAstrom = false;		// Astrometry
-    options->overscanBins = 1;		// Number of pixels per bin for overscan
+    // Flags for various activities
+    options->doMask = false;            // Mask bad pixels
+    options->doNonLin = false;          // Non-linearity correction
+    options->doBias = false;            // Bias subtraction
+    options->doDark = false;            // Dark subtraction
+    options->doOverscan = false;        // Overscan subtraction
+    options->doFlat = false;            // Flat-field normalisation
+    options->doFringe = false;          // Fringe subtraction
+    options->doSource = false;          // Source identification and photometry
+    options->doAstrom = false;          // Astrometry
+    // Overscan options
+    options->overscanBins = 1;          // Number of pixels per bin for overscan
     options->overscanStats = NULL;      // Statistics for overscan
-    options->overscanFit = NULL;	// Overscan fit (polynomial or spline)
+    options->overscanFit = NULL;        // Overscan fit (polynomial or spline)
     options->overscanFitType = PM_FIT_NONE; // Fit type for overscan
     options->overscanMode = PM_OVERSCAN_NONE; // Axis for overscan
+    // Non-linearity options
+    options->nonLinearType = 0;         // Type of non-linearity data (vector, string or metadata)
+    options->nonLinearData = NULL;      // The non-linearity data
+    options->nonLinearSource = NULL;    // If the non-linearity data is a menu, this provides the key
+    // Various others
+    options->imageLoadDepth = PP_LOAD_NONE; // No load depth specified yet
 
-    options->doNonLin = false;
-    options->nonLinearType = false;
-    options->nonLinearData = NULL;
-    options->nonLinearSource = NULL;
-
-    options->imageLoadDepth = PP_LOAD_NONE;
-    char *depth = psMetadataLookupPtr(NULL, config->recipe, "LOAD.DEPTH");
-    if (depth == NULL) {
-	psAbort ("phase2", "load depth not specified");
+    bool mdStatus = false;              // Result of MD lookup
+    const char *depth = psMetadataLookupStr(&mdStatus, config->recipe, "LOAD.DEPTH");
+    if (! mdStatus || ! depth || strlen(depth) == 0) {
+        psLogMsg("ppImage", PS_LOG_ERROR, "LOAD.DEPTH not specified in recipe.");
+        exit(EXIT_FAILURE);
     }
     if (!strcasecmp(depth, "FPA")) {
-	options->imageLoadDepth = PP_LOAD_FPA;
-    }
-    if (!strcasecmp(depth, "CHIP")) {
-	options->imageLoadDepth = PP_LOAD_CHIP;
-    }
-    if (!strcasecmp(depth, "CELL")) {
-	options->imageLoadDepth = PP_LOAD_CELL;
-    }
-    if (options->imageLoadDepth == PP_LOAD_NONE) {
-	psAbort ("phase2", "load depth not specified");
+        options->imageLoadDepth = PP_LOAD_FPA;
+    } else if (!strcasecmp(depth, "CHIP")) {
+        options->imageLoadDepth = PP_LOAD_CHIP;
+    } else if (!strcasecmp(depth, "CELL")) {
+        options->imageLoadDepth = PP_LOAD_CELL;
+    } else {
+        psLogMsg(__func__, PS_LOG_ERROR, "LOAD.DEPTH in recipe is not FPA, CHIP or CELL.");
+        exit(EXIT_FAILURE);
     }
 
-    // mask - recipe options
+    // Mask recipe options
     if (psMetadataLookupBool(NULL, config->recipe, "MASK")) {
-	data->mask->filename = psMetadataLookupStr(NULL, config->arguments, "-mask");
-        if (strlen(data->mask->filename) > 0) {
+        data->mask->filename = psMetadataLookupStr(NULL, config->arguments, "-mask");
+        if (data->mask->filename && strlen(data->mask->filename) > 0) {
             options->doMask = true;
         } else {
-            psLogMsg("phase2", PS_LOG_WARN, "Masking is desired, but no mask was supplied"
-		     " --- no masking will be performed.\n");
+            psLogMsg(__func__, PS_LOG_WARN, "Masking is desired, but no mask was supplied"
+                     " --- no masking will be performed.\n");
         }
     }
 
-    // non-linear - recipe options
+    // Non-linearity recipe options
     if (psMetadataLookupBool(NULL, config->recipe, "NONLIN")) {
-	psMetadataItem *dataItem = psMetadataLookup(config->recipe, "NONLIN.DATA");
-	if (! dataItem) {
-	    psAbort("phase2", "Non-linearity correction desired, but unable to "
-		     "find NONLIN.DATA in recipe");
-	} 
+        psMetadataItem *dataItem = psMetadataLookup(config->recipe, "NONLIN.DATA");
+        if (! dataItem) {
+            psLogMsg(__func__, PS_LOG_ERROR, "Non-linearity correction desired, but unable to "
+                     "find NONLIN.DATA in recipe.");
+            exit(EXIT_FAILURE);
+        }
 
         options->doNonLin = true;
-	options->nonLinearType = dataItem->type;
-	options->nonLinearData = dataItem;
+        options->nonLinearType = dataItem->type;
+        options->nonLinearData = dataItem;
 
-	switch (dataItem->type) {
-	  case PS_DATA_VECTOR:
-	  case PS_DATA_STRING:
-	    break;
+        switch (dataItem->type) {
+            // No immediate action required
+          case PS_DATA_VECTOR:
+          case PS_DATA_STRING:
+            break;
 
-	  case PS_DATA_METADATA:
-	    // This is a menu
-	    options->nonLinearSource = psMetadataLookupStr(&status, config->recipe, "NONLIN.SOURCE");
-	    if (! status || ! options->nonLinearSource) {
-		psAbort("phase2", "Non-linearity correction desired, but unable to "
-			 "find NONLIN.SOURCE in recipe");
-	    } 
-	    break;
-
-	  default:
-	    psAbort("phase2", "Non-linearity correction desired, but "
-		    "NONLIN.DATA is of invalid type.");
-	}
-
+            // This is a menu; we need the key
+          case PS_DATA_METADATA:
+            {
+                bool status;
+                options->nonLinearSource = psMetadataLookupStr(&status, config->recipe, "NONLIN.SOURCE");
+                if (! status || ! options->nonLinearSource) {
+                    psLogMsg(__func__, PS_LOG_ERROR, "Non-linearity correction desired, but unable to "
+                            "find NONLIN.SOURCE in recipe");
+                    exit(EXIT_FAILURE);
+                }
+            }
+            break;
+          default:
+            psLogMsg(__func__, PS_LOG_ERROR, "Non-linearity correction desired, but "
+                    "NONLIN.DATA is of invalid type.");
+            exit(EXIT_FAILURE);
+        }
     }
 
-    // bias - recipe options
+    // Bias recipe options
     if (psMetadataLookupBool(NULL, config->recipe, "BIAS")) {
-	data->bias->filename = psMetadataLookupStr(NULL, config->arguments, "-bias");
-        if (strlen(data->bias->filename) > 0) {
+        data->bias->filename = psMetadataLookupStr(NULL, config->arguments, "-bias");
+        if (data->bias->filename && strlen(data->bias->filename) > 0) {
             options->doBias = true;
         } else {
-            psLogMsg("phase2", PS_LOG_WARN, "Bias subtraction is desired, but no bias was supplied --- "
+            psLogMsg(__func__, PS_LOG_WARN, "Bias subtraction is desired, but no bias was supplied --- "
                      "no bias subtraction will be performed.\n");
         }
     }
 
-    // dark - recipe options
+    // Dark recipe options
     if (psMetadataLookupBool(NULL, config->recipe, "DARK")) {
-	data->dark->filename = psMetadataLookupStr(NULL, config->arguments, "-dark");
-        if (strlen(data->dark->filename) > 0) {
+        data->dark->filename = psMetadataLookupStr(NULL, config->arguments, "-dark");
+        if (data->dark->filename && strlen(data->dark->filename) > 0) {
             options->doDark = true;
         } else {
-            psLogMsg("phase2", PS_LOG_WARN, "Dark subtraction is desired, but no dark was supplied --- "
+            psLogMsg(__func__, PS_LOG_WARN, "Dark subtraction is desired, but no dark was supplied --- "
                      "no dark subtraction will be performed.\n");
         }
     }
 
-    // overscan - recipe options
+    // XXX PAP: The overscan stuff needs to be updated following the reworked API
+
+    // Overscan recipe options
     // XXX EAM : we should abort on invalid options. default options?
     if (psMetadataLookupBool(NULL, config->recipe, "OVERSCAN")) {
-	// XXX EAM : does 'overscanMode = NONE' mean doOverscan = false?
+        // XXX EAM : does 'overscanMode = NONE' mean doOverscan = false?
         options->doOverscan = true;
         psString mode = psMetadataLookupStr(NULL, config->recipe, "OVERSCAN.MODE");
@@ -123,5 +130,5 @@
             options->overscanMode = PM_OVERSCAN_ALL;
         } else if (strcasecmp(mode, "NONE")) {
-            psLogMsg("phase2", PS_LOG_WARN, "OVERSCAN.MODE (%s) is not one of NONE, INDIVIDUAL, or ALL:"
+            psLogMsg(__func__, PS_LOG_WARN, "OVERSCAN.MODE (%s) is not one of NONE, INDIVIDUAL, or ALL:"
                      " assuming NONE.\n", mode);
         }
@@ -135,7 +142,7 @@
             options->overscanFitType = PM_FIT_SPLINE;
             // int order = psMetadataLookupS32(NULL, config->recipe, "OVERSCAN.ORDER"); // Order of polynomial fit
-	    // XXX : not in psLib yet : options->overscanFit = psSpline1DAlloc();
+            // XXX : not in psLib yet : options->overscanFit = psSpline1DAlloc();
         } else if (strcasecmp(fit, "NONE")) {
-            psLogMsg("phase2", PS_LOG_WARN, "OVERSCAN.FIT (%s) is not one of NONE, POLYNOMIAL, or SPLINE:"
+            psLogMsg(__func__, PS_LOG_WARN, "OVERSCAN.FIT (%s) is not one of NONE, POLYNOMIAL, or SPLINE:"
                      " assuming NONE.\n", fit);
         }
@@ -158,9 +165,9 @@
     // flat-field - recipe options
     if (psMetadataLookupBool(NULL, config->recipe, "FLAT")) {
-	data->flat->filename = psMetadataLookupStr(NULL, config->arguments, "-flat");
+        data->flat->filename = psMetadataLookupStr(NULL, config->arguments, "-flat");
         if (strlen(data->flat->filename) > 0) {
             options->doFlat = true;
         } else {
-            psLogMsg("phase2", PS_LOG_WARN, "Flat-fielding is desired, but no flat was supplied --- "
+            psLogMsg(__func__, PS_LOG_WARN, "Flat-fielding is desired, but no flat was supplied --- "
                      "no flat-fielding will be performed.\n");
         }
Index: /trunk/ppImage/src/ppImageParseCamera.c
===================================================================
--- /trunk/ppImage/src/ppImageParseCamera.c	(revision 5975)
+++ /trunk/ppImage/src/ppImageParseCamera.c	(revision 5976)
@@ -1,63 +1,52 @@
-# include "ppImage.h"
+#include "ppImage.h"
 
-static void ppFPA_Free (ppFPA *fpa) {
-    return;
-}
+bool ppImageParseCamera(ppData *data, ppConfig *config)
+{
+    // Initialise the containers where the files will go
+    data->input   = ppFileAlloc();
+    data->mask    = ppFileAlloc();
+    data->bias    = ppFileAlloc();
+    data->dark    = ppFileAlloc();
+    data->flat    = ppFileAlloc();
+    data->fringe  = ppFileAlloc();
+#if 0
+    data->process = ppFileAlloc();
+#endif
 
-ppFPA *ppFPA_Alloc (void) {
-
-    ppFPA *fpa = psAlloc (sizeof(ppFPA));
-    psMemSetDeallocator(fpa, (psFreeFunc) ppFPA_Free);
-
-    fpa->filename = NULL;
-    fpa->fpa = NULL;
-    fpa->fits = NULL;
-    fpa->header = NULL;
-
-    return fpa;
-}
-
-bool ppImageParseCamera (ppData *data, ppConfig *config) {
-    
-    bool status;
-
-    data->input   = ppFPA_Alloc ();
-    data->mask 	  = ppFPA_Alloc ();
-    data->bias 	  = ppFPA_Alloc ();
-    data->dark 	  = ppFPA_Alloc ();
-    data->flat 	  = ppFPA_Alloc ();
-    data->fringe  = ppFPA_Alloc ();
-    data->process = ppFPA_Alloc ();
-    
-    data->input->filename = psMetadataLookupPtr (NULL, config->arguments, "-input");
+    data->input->filename = psMemIncrRefCounter(psMetadataLookupStr(NULL, config->arguments, "-input"));
 
     // Open the input image
-    psLogMsg("phase2", PS_LOG_INFO, "Opening input image: %s\n", data->input->filename);
+    psLogMsg("ppImage", PS_LOG_INFO, "Opening input image: %s\n", data->input->filename);
     data->input->fits = psFitsOpen(data->input->filename, "r"); // File handle for FITS file
     if (! data->input->fits) {
+        // There's no point in continuing if we can't open the input
         psErrorStackPrint(stderr, "Can't open input image: %s\n", data->input->filename);
         exit(EXIT_FAILURE);
     }
-    data->input->header = psFitsReadHeader(NULL, data->input->fits); // FITS header
+    data->input->phu = psFitsReadHeader(NULL, data->input->fits); // FITS header
 
     // Get camera configuration from header if not already defined
     if (! config->camera) {
-        config->camera = pmConfigCameraFromHeader(config->site, data->input->header);
+        config->camera = pmConfigCameraFromHeader(config->site, data->input->phu);
         if (! config->camera) {
+             // There's no point in continuing if we can't recognise what we've got
             psErrorStackPrint(stderr, "Can't find camera configuration!\n");
             exit(EXIT_FAILURE);
         }
-   } else if (! pmConfigValidateCamera(config->camera, data->input->header)) {
-        psError(PS_ERR_IO, true, "%s does not seem to be from the camera.\n", data->input->filename);
+   } else if (! pmConfigValidateCamera(config->camera, data->input->phu)) {
+       // There's no point in continuing if what we've got doesn't match what we've been told
+        psError(PS_ERR_IO, true, "%s does not seem to be from the specified camera.\n",
+                data->input->filename);
         exit(EXIT_FAILURE);
     }
 
-    // determine the correct recipe to use
+    // Determine the correct recipe to use
     if (! config->recipe && !(config->recipe = pmConfigRecipeFromCamera(config->camera, RECIPE))) {
+        // There's no point in continuing if we can't work out what recipe to use
         psErrorStackPrint(stderr, "Can't find recipe configuration!\n");
         exit(EXIT_FAILURE);
     }
 
-    // Construct camera in preparation for reading
+    // Construct cameras in preparation for reading
     data->input->fpa   = pmFPAConstruct(config->camera);
     data->mask->fpa    = pmFPAConstruct(config->camera);
@@ -66,16 +55,17 @@
     data->flat->fpa    = pmFPAConstruct(config->camera);
     data->fringe->fpa  = pmFPAConstruct(config->camera);
+#if 0
     data->process->fpa = pmFPAConstruct(config->camera);
+#endif
 
     // XXX EAM : extend this to allow an array of selected chips by name
     // Chip selection: if we are using a single chip, select it for each FPA
-    // data->process acts as a process mask for the full FPA
-    int chipNum = psMetadataLookupS32(&status, config->arguments, "-chip"); // Chip number to work on
+    int chipNum = psMetadataLookupS32(NULL, config->arguments, "-chip"); // Chip number to work on
     if (chipNum >= 0) {
-        if (! pmFPASelectChip(data->process->fpa, chipNum)) {
+        if (! pmFPASelectChip(data->input->fpa, chipNum)) {
             psErrorStackPrint(stderr, "Chip number %d doesn't exist in camera.\n", chipNum);
             exit(EXIT_FAILURE);
         }
-        psLogMsg("phase2", PS_LOG_INFO, "Operating only on chip %d\n", chipNum);
+        psLogMsg("ppImage", PS_LOG_INFO, "Operating only on chip %d\n", chipNum);
     }
     return true;
@@ -84,4 +74,4 @@
 // XXX EAM : I dropped the pre-open of the output files; replace with a stats test of output permissions
 
-// XXX : for split data (data spread across multiple files), this step is only operating on a component 
+// XXX : for split data (data spread across multiple files), this step is only operating on a component
 //       of the FPA.  the other components should be set to 'invalid' in this case?
Index: /trunk/ppImage/src/ppImageParseDetrend.c
===================================================================
--- /trunk/ppImage/src/ppImageParseDetrend.c	(revision 5975)
+++ /trunk/ppImage/src/ppImageParseDetrend.c	(revision 5976)
@@ -8,16 +8,17 @@
 // XXX : add fringe frame
 
-bool ppFPAOpen (ppFPA *fpa, psMetadata *camera, char *name, bool doThis) {
+bool ppFileOpen(ppFile *file, psMetadata *camera, char *name, bool doThis) {
 
     if (!doThis) {
-	return false;
+        return false;
     }
 
-    psLogMsg("phase2", PS_LOG_INFO, "Opening %s image: %s\n", name, fpa->filename);
-    fpa->fits = psFitsOpen(fpa->filename, "r"); // File handle
-    fpa->header = psFitsReadHeader(NULL, fpa->fits); // primary header
-    if (! pmConfigValidateCamera(camera, fpa->header)) {
-	psError(PS_ERR_IO, true, "%s (%s) does not seem to be from the correct camera.\n", name, fpa->filename);
-	exit(EXIT_FAILURE);
+    psLogMsg("phase2", PS_LOG_INFO, "Opening %s image: %s\n", name, file->filename);
+    file->fits = psFitsOpen(file->filename, "r"); // File handle
+    file->phu = psFitsReadHeader(NULL, file->fits); // primary header
+    if (! pmConfigValidateCamera(camera, file->phu)) {
+        psError(PS_ERR_IO, true, "%s (%s) does not seem to be from the correct camera.\n", name,
+                file->filename);
+        exit(EXIT_FAILURE);
     }
     return true;
@@ -26,8 +27,8 @@
 bool ppImageParseDetrend (ppData *data, ppOptions *options, ppConfig *config) {
 
-    ppFPAOpen (data->mask, config->camera, "mask", options->doMask);
-    ppFPAOpen (data->bias, config->camera, "bias", options->doBias);
-    ppFPAOpen (data->dark, config->camera, "dark", options->doDark);
-    ppFPAOpen (data->flat, config->camera, "flat", options->doFlat);
+    ppFileOpen(data->mask, config->camera, "mask", options->doMask);
+    ppFileOpen(data->bias, config->camera, "bias", options->doBias);
+    ppFileOpen(data->dark, config->camera, "dark", options->doDark);
+    ppFileOpen(data->flat, config->camera, "flat", options->doFlat);
     return true;
 }
