Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/.cvsignore
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/.cvsignore	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/.cvsignore	(revision 22348)
@@ -0,0 +1,13 @@
+bin
+aclocal.m4
+autom4te.cache
+compile
+config.log
+config.status
+configure
+depcomp
+install-sh
+Makefile.in
+missing
+Makefile
+config.cache
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/Makefile.am
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/Makefile.am	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/Makefile.am	(revision 22348)
@@ -0,0 +1,3 @@
+SUBDIRS = src
+
+CLEANFILES = *~ core core.*
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/autogen.sh
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/autogen.sh	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/autogen.sh	(revision 22348)
@@ -0,0 +1,103 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+ORIGDIR=`pwd`
+cd $srcdir
+
+PROJECT=ppImage
+TEST_TYPE=-f
+# change this to be a unique filename in the top level dir
+FILE=autogen.sh
+
+DIE=0
+
+LIBTOOLIZE=libtoolize
+ACLOCAL=aclocal
+AUTOHEADER=autoheader
+AUTOMAKE=automake
+AUTOCONF=autoconf
+
+#($LIBTOOLIZE --version) < /dev/null > /dev/null 2>&1 || {
+#        echo
+#        echo "You must have $LIBTOOlIZE installed to compile $PROJECT."
+#        echo "Download the appropriate package for your distribution,"
+#        echo "or get the source tarball at http://ftp.gnu.org/gnu/libtool/"
+#        DIE=1
+#}
+
+($ACLOCAL --version) < /dev/null > /dev/null 2>&1 || {
+        echo
+        echo "You must have $ACLOCAL installed to compile $PROJECT."
+        echo "Download the appropriate package for your distribution,"
+        echo "or get the source tarball at http://ftp.gnu.org/gnu/automake/"
+        DIE=1
+}
+
+#($AUTOHEADER --version) < /dev/null > /dev/null 2>&1 || {
+#        echo
+#        echo "You must have $AUTOHEADER installed to compile $PROJECT."
+#        echo "Download the appropriate package for your distribution,"
+#        echo "or get the source tarball at http://ftp.gnu.org/gnu/autoconf/"
+#        DIE=1
+#}
+
+($AUTOMAKE --version) < /dev/null > /dev/null 2>&1 || {
+        echo
+        echo "You must have $AUTOMAKE installed to compile $PROJECT."
+        echo "Download the appropriate package for your distribution,"
+        echo "or get the source tarball at http://ftp.gnu.org/gnu/automake/"
+        DIE=1
+}
+
+($AUTOCONF --version) < /dev/null > /dev/null 2>&1 || {
+        echo
+        echo "You must have $AUTOCONF installed to compile $PROJECT."
+        echo "Download the appropriate package for your distribution,"
+        echo "or get the source tarball at http://ftp.gnu.org/gnu/autoconf/"
+        DIE=1
+}
+
+if test "$DIE" -eq 1; then
+        exit 1
+fi
+
+test $TEST_TYPE $FILE || {
+        echo "You must run this script in the top-level $PROJECT directory"
+        exit 1
+}
+
+if test -z "$*"; then
+        echo "I am going to run ./configure with no arguments - if you wish "
+        echo "to pass any to it, please specify them on the $0 command line."
+fi
+
+#$LIBTOOLIZE --copy --force || echo "$LIBTOOlIZE failed"
+$ACLOCAL || echo "$ACLOCAL failed"
+#$AUTOHEADER || echo "$AUTOHEADER failed"
+$AUTOMAKE --add-missing --force-missing --copy || echo "$AUTOMAKE failed"
+$AUTOCONF || echo "$AUTOCONF failed"
+
+cd $ORIGDIR
+
+run_configure=true
+for arg in $*; do
+    case $arg in
+        --no-configure)
+            run_configure=false
+            ;;
+        *)
+            ;;
+    esac
+done
+
+if $run_configure; then
+    $srcdir/configure --enable-maintainer-mode "$@"
+    echo
+    echo "Now type 'make' to compile $PROJECT."
+else
+    echo
+    echo "Now run 'configure' and 'make' to compile $PROJECT."
+fi
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/configure.ac
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/configure.ac	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/configure.ac	(revision 22348)
@@ -0,0 +1,35 @@
+AC_PREREQ(2.59)
+
+AC_INIT([ppImage], [0.0.1], [price@ifa.hawaii.edu])
+AC_CONFIG_SRCDIR([src])
+
+AM_INIT_AUTOMAKE([1.6 foreign dist-bzip2])
+dnl AM_CONFIG_HEADER([config.h])
+AM_MAINTAINER_MODE
+
+AC_LANG(C)
+AC_GNU_SOURCE
+AC_PROG_CC
+AC_PROG_INSTALL
+dnl AC_PROG_LIBTOOL
+
+dnl handle debug building
+AC_ARG_ENABLE(optimize,
+  [AS_HELP_STRING(--enable-optimize,enable compiler optimization)],
+  [AC_MSG_RESULT(compile optimization enabled)
+   CFLAGS="${CFLAGS=} -O2"],
+  [AC_MSG_RESULT([compile optimization disabled])
+   CFLAGS="${CFLAGS=} -O0 -g"]
+)
+
+PKG_CHECK_MODULES([PSLIB], [pslib >= 0.9.0]) 
+PKG_CHECK_MODULES([PSMODULE], [psmodule >= 0.0.0]) 
+
+ppImage_CFLAGS="-Wall -Werror -std=c99"
+AC_SUBST([ppImage_CFLAGS])
+
+AC_CONFIG_FILES([
+  Makefile
+  src/Makefile
+])
+AC_OUTPUT
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/.cvsignore
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/.cvsignore	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/.cvsignore	(revision 22348)
@@ -0,0 +1,4 @@
+ppImage
+Makefile
+Makefile.in
+.deps
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/Makefile.am
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/Makefile.am	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/Makefile.am	(revision 22348)
@@ -0,0 +1,46 @@
+bin_PROGRAMS = ppImage ppTest
+
+noinst_HEADERS = \
+	ppFile.h \
+	ppImage.h \
+	ppImageData.h \
+	ppImageDetrend.h \
+	ppImageOptions.h \
+	ppMem.h
+
+ppImage_CPPFLAGS = $(PSLIB_CFLAGS) $(PSMODULE_CFLAGS) $(ppImage_CFLAGS)
+ppImage_LDFLAGS = $(PSLIB_LIBS) $(PSMODULE_LIBS)
+ppImage_SOURCES = \
+	ppFile.c \
+	ppImage.c \
+	ppImageConfig.c \
+	ppImageData.c \
+	ppImageDetrendBias.c \
+	ppImageDetrendCell.c \
+	ppImageDetrendMask.c \
+	ppImageDetrendNonLinear.c \
+	ppImageLoop.c \
+	ppImageOptions.c \
+	ppImageParseCamera.c \
+	ppImageWeights.c \
+	ppMem.c
+#	ppImageLoadPixels.c
+#	ppDetrendFlat.c
+#	ppImageOutput.c
+#	ppImageDetrendPedestal.c
+#	ppImageOutput.c
+#	ppImagePhot.c
+
+ppTest_CPPFLAGS = $(PSLIB_CFLAGS) $(PSMODULE_CFLAGS) $(ppImage_CFLAGS)
+ppTest_LDFLAGS = $(PSLIB_LIBS) $(PSMODULE_LIBS)
+ppTest_SOURCES = \
+	ppTest.c \
+	ppMem.c
+
+
+
+clean-local:
+	-rm -f TAGS
+# Tags for emacs
+tags:
+	etags `find . -name \*.[ch] -print`
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppConfig.c
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppConfig.c	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppConfig.c	(revision 22348)
@@ -0,0 +1,27 @@
+#include <stdio.h>
+#include "pslib.h"
+#include "ppConfig.h"
+
+static void configFree(ppConfig *config)
+{
+    psFree(config->site);
+    psFree(config->camera);
+    psFree(config->recipe);
+    psFree(config->arguments);
+    psFree(config->database);
+}
+
+ppConfig *ppConfigAlloc(void)
+{
+    ppConfig *config = psAlloc(sizeof(ppConfig));
+    psMemSetDeallocator(config, (psFreeFunc)configFree);
+
+    config->site = NULL;
+    config->camera = NULL;
+    config->recipe = NULL;
+    config->arguments = NULL;
+    config->database = NULL;
+
+    return config;
+}
+
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppConfig.h
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppConfig.h	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppConfig.h	(revision 22348)
@@ -0,0 +1,16 @@
+#ifndef PP_CONFIG_H
+#define PP_CONFIG_H
+
+#include "pslib.h"
+
+typedef struct {
+    psMetadata *site;                   // Site configuration
+    psMetadata *camera;                 // Camera specification
+    psMetadata *recipe;                 // Recipe for processing
+    psMetadata *arguments;              // Command-line arguments
+    psDB *database;                     // Database handle
+} ppConfig;
+
+ppConfig *ppConfigAlloc(void);
+
+#endif
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppFile.c
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppFile.c	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppFile.c	(revision 22348)
@@ -0,0 +1,52 @@
+#include <stdio.h>
+#include "pslib.h"
+#include "ppFile.h"
+
+// Free a ppFile
+static void fileFree(ppFile *file)
+{
+    psFree(file->filename);
+    psFree(file->fpa);
+    psFree(file->phu);
+    if (file->fits) {
+        psFitsClose(file->fits);
+    }
+    psFree(file->view);
+    return;
+}
+
+ppFile *ppFileAlloc(void)
+{
+
+    ppFile *file = psAlloc(sizeof(ppFile));
+    psMemSetDeallocator(file, (psFreeFunc)fileFree);
+
+    file->filename = NULL;
+    file->fpa = NULL;
+    file->fits = NULL;
+    file->phu = NULL;
+    file->view = NULL;
+
+    return file;
+}
+
+
+bool ppFileOpen(ppFile *file, const char *name, pmConfig *config, psMetadata *camera, psMetadata *format)
+{
+    file->fpa = pmFPAConstruct(camera);
+    psString filename = psMetadataLookupStr(NULL, config->arguments, name);
+    if (strlen(filename) == 0) {
+        return false;
+    }
+    file->filename = psMemIncrRefCounter(filename);
+    file->fits = psFitsOpen(filename, "r");
+    file->phu = psFitsReadHeader(NULL, file->fits);
+    if (!pmConfigValidateCameraFormat(format, file->phu)) {
+        psLogMsg(__func__, PS_LOG_WARN, "File %s doesn't match camera format --- ignored.\n", filename);
+        psFitsClose(file->fits);
+        return false;
+    }
+    file->view = pmFPAAddSource(file->fpa, file->phu, format);
+    return true;
+}
+
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppFile.h
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppFile.h	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppFile.h	(revision 22348)
@@ -0,0 +1,22 @@
+#ifndef PP_FILE_H
+#define PP_FILE_H
+
+#include "pslib.h"
+#include "psmodules.h"
+
+// A file to process
+typedef struct {
+    char *filename;                     // File name
+    psFits *fits;                       // The FITS file handle
+    psMetadata *phu;                    // The FITS header
+    pmFPA *fpa;                         // The FPA, with pixels and extensions
+    pmFPAview *view;                    // The view
+} ppFile;
+
+
+// Allocator
+ppFile *ppFileAlloc(void);
+
+bool ppFileOpen(ppFile *file, const char *name, pmConfig *config, psMetadata *camera, psMetadata *format);
+
+#endif
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImage.c
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImage.c	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImage.c	(revision 22348)
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include "pslib.h"
+#include "psmodules.h"
+#include "ppImage.h"
+#include "ppMem.h"
+
+int main(int argc, char **argv)
+{
+//    psErrorRegister(NULL, -1);
+
+    ppImageData *data = ppImageDataAlloc();
+    ppImageOptions *options = ppImageOptionsAlloc();
+
+    psTimerStart(TIMERNAME);
+
+    // Parse the configuration and arguments
+    pmConfig *config = ppImageConfig(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);
+
+    // Set various tasks (define optional operations)
+    ppImageOptionsParse(data, options, config);
+
+#if 0
+    // XXX I think we do this in ppImageParseCamera
+
+    // open detrend images, load headers, optionally load pixels
+    ppImageParseDetrend(data, options, config);
+#endif
+
+    // Image Arithmetic Loop
+    ppImageLoop(data, options, config);
+
+    // Cleaning up
+    psFree(data);
+    psFree(options);
+    psFree(config);
+    psTimerStop();
+    psTraceReset();
+    pmConceptsDone();
+    ppMemCheck();
+
+    return EXIT_SUCCESS;
+}
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImage.h
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImage.h	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImage.h	(revision 22348)
@@ -0,0 +1,44 @@
+#ifndef PP_IMAGE_H
+#define PP_IMAGE_H
+
+#include "pslib.h"
+#include "psmodules.h"
+
+#include "ppImageData.h"
+#include "ppImageOptions.h"
+
+#define RECIPE_NAME "PHASE2"            // Name of the recipe to use
+#define TIMERNAME "ppImage"             // Name of timer
+
+// Get the configuration
+pmConfig *ppImageConfig(int argc, char **argv);
+
+// Determine what type of camera, and initialise
+bool ppImageParseCamera(ppImageData *data,   // The data to be processed
+                        pmConfig *config // Configuration
+                        );
+
+
+// Loop over the input
+bool ppImageLoop(ppImageData *data, ppImageOptions *options, pmConfig *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(ppImageData *data, ppImageOptions *options, pmConfig *config);
+
+bool ppReadoutWeights(pmReadout *readout);
+
+#if 0
+// These functions are not implemented, or not needed
+pmReadout* ppDetrendPedestal(pmReadout *pedestal, pmCell *input, pmReadout *bias, pmReadout *dark, float darkTime, ppImageOptions *options);
+bool ppImageOutput(ppImageData *data, pmConfig *config);
+bool ppImagePhot(ppImageData *data, ppImageOptions *options, pmConfig *config);
+bool ppFileOpen(ppFile *fpa, char *name, bool doThis);
+#endif
+
+#endif // Pau.
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageConfig.c
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageConfig.c	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageConfig.c	(revision 22348)
@@ -0,0 +1,42 @@
+#include <stdio.h>
+#include "pslib.h"
+#include "psmodules.h"
+#include "ppImage.h"
+
+pmConfig *ppImageConfig(int argc, char **argv)
+{
+    pmConfig *config = pmConfigRead(&argc, argv);
+    if (! config) {
+        psErrorStackPrint(stderr, "Can't find site configuration!\n");
+        exit(EXIT_FAILURE);
+    }
+
+    // Parse other command-line arguments
+    config->arguments = psMetadataAlloc(); // The arguments, with default values
+    psMetadataAddStr(config->arguments, PS_LIST_TAIL, "-key", 0, "exposure ID", "");
+    psMetadataAddStr(config->arguments, PS_LIST_TAIL, "-bias", 0, "Name of the bias image", "");
+    psMetadataAddStr(config->arguments, PS_LIST_TAIL, "-dark", 0, "Name of the dark image", "");
+    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);
+
+    if (! psArgumentParse(config->arguments, &argc, argv) || argc != 3) {
+        printf("\nPan-STARRS Phase 2 processing\n\n");
+        printf("Usage: %s INPUT.fits OUTPUT.fits\n\n", argv[0]);
+        psArgumentHelp(config->arguments);
+        psFree(config->arguments);
+        exit(EXIT_FAILURE);
+    }
+
+    // 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
+#if 0
+    config->database = pmConfigDB(config->site);
+#endif
+
+    return config;
+}
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageData.c
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageData.c	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageData.c	(revision 22348)
@@ -0,0 +1,32 @@
+#include <stdio.h>
+#include "pslib.h"
+#include "ppImageData.h"
+
+static void imageDataFree(ppImageData *data)
+{
+    psFree(data->input);
+    psFree(data->mask);
+    psFree(data->bias);
+    psFree(data->dark);
+    psFree(data->flat);
+    psFree(data->fringe);
+    if (data->output) {
+        psFitsClose(data->output);
+    }
+}
+
+ppImageData *ppImageDataAlloc(void)
+{
+    ppImageData *data = psAlloc(sizeof(ppImageData));
+    psMemSetDeallocator(data, (psFreeFunc)imageDataFree);
+
+    data->input = NULL;
+    data->mask = NULL;
+    data->bias = NULL;
+    data->dark = NULL;
+    data->flat = NULL;
+    data->fringe = NULL;
+    data->output = NULL;
+
+    return data;
+}
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageData.h
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageData.h	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageData.h	(revision 22348)
@@ -0,0 +1,19 @@
+#ifndef PP_IMAGE_DATA_H
+#define PP_IMAGE_DATA_H
+
+#include "ppFile.h"
+
+// The data to be processed
+typedef struct {
+    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
+    psFits *output;                     // The output file
+} ppImageData;
+
+ppImageData *ppImageDataAlloc(void);
+
+#endif
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageDetrend.h
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageDetrend.h	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageDetrend.h	(revision 22348)
@@ -0,0 +1,27 @@
+#ifndef PP_IMAGE_DETREND_H
+#define PP_IMAGE_DETREND_H
+
+#include "pslib.h"
+#include "psmodules.h"
+#include "ppImageOptions.h"
+
+// Cells to be used in the detrend
+typedef struct {
+    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
+} ppImageDetrend;
+
+
+bool ppImageDetrendCell(ppImageDetrend *detrend, ppImageOptions *options, pmConfig *config);
+bool ppImageDetrendMask(pmCell *cell, pmReadout *input, pmReadout *mask);
+bool ppImageDetrendNonLinear(pmCell *cell, pmReadout *input, ppImageOptions *options);
+bool ppImageDetrendNonLinearLookup(pmReadout *input, psMetadataItem *dataItem);
+bool ppImageDetrendNonLinearPolynomial(pmReadout *input, psMetadataItem *dataItem);
+bool ppImageDetrendBias(pmReadout *inputReadout, pmReadout *bias, pmReadout *dark, ppImageOptions *options);
+pmReadout* ppImageDetrendSelectFirst(pmCell *cell, char *name, bool doThis);
+
+
+#endif
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageDetrendBias.c
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageDetrendBias.c	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageDetrendBias.c	(revision 22348)
@@ -0,0 +1,60 @@
+#include <stdio.h>
+#include "pslib.h"
+#include "psmodules.h"
+#include "ppImageOptions.h"
+#include "ppImageDetrend.h"
+
+bool ppImageDetrendBias(pmReadout *inputReadout, pmReadout *bias, pmReadout *dark, ppImageOptions *options)
+{
+    psTrace(__func__, 1, "Commencing bias processing....\n");
+//    psMetadataPrint(inputReadout->parent->concepts, 7);
+
+    pmSubtractBias(inputReadout, options->overscan, bias, dark);
+
+    // Output overscan fit results, if required
+    if (! options->doOverscan || ! options->overscan) {
+        return true;
+    }
+
+    if (!options->overscan->poly && !options->overscan->spline) {
+        psLogMsg("ppImage", PS_LOG_WARN, "No fit generated!\n");
+        return true;
+    }
+
+    switch (options->overscan->fitType) {
+      case PM_FIT_POLY_ORD:
+      case PM_FIT_POLY_CHEBY:
+        {
+            psPolynomial1D *poly = options->overscan->poly; // The polynomial
+            psString coeffs = NULL;     // String containing the coefficients
+            for (int i = 0; i < poly->nX; i++) {
+                psStringAppend(&coeffs, "%e ", poly->coeff[i]);
+            }
+            psLogMsg("phase2", PS_LOG_INFO, "Overscan polynomial coefficients:\n%s\n", coeffs);
+            psFree(coeffs);
+            break;
+        }
+      case PM_FIT_SPLINE:
+        {
+            psSpline1D *spline = options->overscan->spline; // The spline
+            psString coeffs = NULL;     // String containing the coefficients
+            for (int i = 0; i < spline->n; i++) {
+                psPolynomial1D *poly = spline->spline[i]; // i-th polynomial
+                psStringAppend(&coeffs, "%d: ", i);
+                for (int j = 0; j < poly->nX; j++) {
+                    psStringAppend(&coeffs, "%e ", poly->coeff[i]);
+                }
+                psStringAppend(&coeffs, "\n");
+            }
+            psLogMsg("phase2", PS_LOG_INFO, "Overscan spline coefficients:\n%s\n", coeffs);
+            psFree(coeffs);
+            break;
+        }
+      case PM_FIT_NONE:
+        break;
+      default:
+        psAbort(__func__, "Should never get here!!!\n");
+    }
+
+    return true;
+}
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageDetrendCell.c
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageDetrendCell.c	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageDetrendCell.c	(revision 22348)
@@ -0,0 +1,63 @@
+#include <stdio.h>
+#include "pslib.h"
+#include "psmodules.h"
+#include "ppImageDetrend.h"
+#include "ppImageOptions.h"
+
+// mask, bias, dark, flat are defined per Cell
+
+pmReadout *ppImageDetrendSelectFirst(pmCell *cell, char *name, bool doThis)
+{
+    if (!doThis) {
+        return NULL;
+    }
+
+    if (cell->readouts->n > 1) {
+        psLogMsg("phase2", PS_LOG_WARN, "%s contains multiple readouts: only the first will be used.", name);
+    }
+
+    pmReadout *readout = cell->readouts->data[0]; // Readout of interest in this cell
+
+    return readout;
+}
+
+bool ppImageDetrendCell(ppImageDetrend *detrend, ppImageOptions *options, pmConfig *config)
+{
+#if 0
+    pmCellSetWeights(detrend->input);
+#endif
+
+    pmReadout *mask = ppImageDetrendSelectFirst(detrend->mask, "mask", options->doMask);
+    pmReadout *bias = ppImageDetrendSelectFirst(detrend->bias, "bias", options->doBias);
+    pmReadout *dark = ppImageDetrendSelectFirst(detrend->dark, "dark", options->doDark);
+    pmReadout *flat = ppImageDetrendSelectFirst(detrend->flat, "flat", options->doFlat);
+
+#if 0
+    printf("Flat type: %x\n", flat->image->type.type);
+    printf("Flat value: %f\n", flat->image->data.F32[flat->image->numRows/2][flat->image->numCols/2]);
+#endif
+
+    for (int k = 0; k < detrend->input->readouts->n; k++) {
+
+        pmReadout *input = detrend->input->readouts->data[k]; // Readout of interest in input image
+
+        // Mask bad pixels
+        if (options->doMask) {
+            ppImageDetrendMask(detrend->input, input, mask);
+        }
+
+        // Non-linearity correction
+        if (options->doNonLin) {
+            ppImageDetrendNonLinear(detrend->input, input, options);
+        }
+
+        // Bias, dark and overscan subtraction are all merged.
+        ppImageDetrendBias(input, bias, dark, options);
+
+        // Flat-field correction (no options used?)
+        if (options->doFlat) {
+            pmFlatField(input, flat);
+        }
+    }
+    return true;
+}
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageDetrendFlat.c
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageDetrendFlat.c	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageDetrendFlat.c	(revision 22348)
@@ -0,0 +1,23 @@
+#include <stdio.h>
+#include "pslib.h"
+#include "psmodules.h"
+#include "ppImage.h"
+
+// why does this use the flat pmReadout?
+
+bool ppDetrendFlat (pmReadout *inputReadout, pmReadout *flat, ppOptions *options) {
+
+    psLogMsg("phase2", PS_LOG_INFO, "Performing flat field.\n");
+
+
+
+#ifndef PRODUCTION
+    psImage *dummyImage = psImageAlloc(inputReadout->image->numCols,
+                                       inputReadout->image->numRows,
+                                       PS_TYPE_U8);
+    pmReadout *dummyMask = pmReadoutAlloc(NULL);
+    dummyMask->image = dummyImage;
+    (void)pmFlatField(inputReadout, dummyMask, flatReadout);
+    psFree(dummyMask);
+    psFree(dummyImage);
+#endif
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageDetrendMask.c
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageDetrendMask.c	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageDetrendMask.c	(revision 22348)
@@ -0,0 +1,19 @@
+#include <stdio.h>
+#include "psmodules.h"
+#include "ppImageDetrend.h"
+
+# define MASK_MODE (PM_MASK_TRAP | PM_MASK_BADCOL | PM_MASK_SAT)
+
+// XXX pass 'concepts' not 'cell' to this function?
+
+bool ppImageDetrendMask(pmCell *cell, pmReadout *input, pmReadout *mask) {
+
+    float saturation = psMetadataLookupF32(NULL, cell->concepts, "CELL.SATURATION");
+
+    // Need to change this later to grow the mask by the size of the convolution kernel
+    // XXX does this function respect the mask / image cell region information?
+    // XXX should probably take pmRegion *mask
+    pmMaskBadPixels(input, mask->image, MASK_MODE, saturation, PM_MASK_TRAP, 0);
+
+    return true;
+}
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageDetrendNonLinear.c
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageDetrendNonLinear.c	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageDetrendNonLinear.c	(revision 22348)
@@ -0,0 +1,112 @@
+#include <stdio.h>
+#include "pslib.h"
+#include "psmodules.h"
+#include "ppImageDetrend.h"
+
+bool ppImageDetrendNonLinearPolynomial(pmReadout *input, psMetadataItem *dataItem) {
+
+    // These are the polynomial coefficients
+    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;
+    }
+    psPolynomial1D *correction = psPolynomial1DAlloc(coeff->n - 1, PS_POLYNOMIAL_ORD);
+    psFree(correction->coeff);
+    correction->coeff = psMemIncrRefCounter(coeff->data.F64);
+    pmNonLinearityPolynomial(input, correction);
+    psFree(coeff);
+    psFree(correction);
+    return true;
+}
+
+bool ppImageDetrendNonLinearLookup(pmReadout *input, psMetadataItem *dataItem) {
+
+    // This is a filename: lookup table
+    char *name = dataItem->data.V;       // Filename
+    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;
+    }
+#ifdef PRODUCTION
+    pmNonLinearityLookup(input, table);
+#else
+    psVector *influx = table->values->data[0];
+    psVector *outflux = table->values->data[1];
+    pmNonLinearityLookup(input, influx, outflux);
+#endif
+    psFree(table);
+    return true;
+}
+
+bool ppImageDetrendNonLinear(pmCell *cell, pmReadout *input, ppImageOptions *options) {
+
+    psMetadataItem *concept;
+
+    switch (options->nonLinearType) {
+      case PS_DATA_VECTOR:
+        ppImageDetrendNonLinearPolynomial (input, options->nonLinearData);
+        return true;
+
+      case PS_DATA_STRING:
+        ppImageDetrendNonLinearLookup (input, options->nonLinearData);
+        return true;
+
+      case PS_DATA_METADATA:
+        // XXX EAM: this is somewhat confusing : let's wrap in a function when i understand it
+
+        // 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;
+                }
+            }
+        }
+
+        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:
+            ppImageDetrendNonLinearPolynomial (input, optionItem);
+            return true;
+          case PS_DATA_STRING:
+            ppImageDetrendNonLinearLookup (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");
+    }
+    return true;
+}
+
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageDetrendPedestal.c
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageDetrendPedestal.c	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageDetrendPedestal.c	(revision 22348)
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include "pslib.h"
+#include "psmodules.h"
+#include "ppImage.h"
+
+// XXX check on image overlaps, as well as image sizes
+// XXX what constraints do we put on the detrend images?
+// XXX this function is much easier if we can assume all detrend images
+//     should have the same size and represent the same pixels...
+
+pmReadout *ppDetrendPedestal (pmReadout *pedestal, pmCell *input, pmReadout *bias, pmReadout *dark, float darkTime, ppOptions *options) {
+
+#ifdef PRODUCTION
+    static float lastExptime = 0.0;
+    bool reusePedestal = true;
+
+    if (options->doDark) {
+        // Dark time for input image
+        float inputTime = psMetadataLookupF32(NULL, input->concepts, "CELL.DARKTIME");
+        if (inputTime <= 0) {
+            psErrorStackPrint(stderr, "DARKTIME for input image (%f) is non-positive.\n",
+                              inputTime);
+            exit(EXIT_FAILURE);
+        }
+
+        if (inputTime != lastExptime) {
+            // this will create a new pedestal if the input one is NULL
+            // XXX EAM : this function had darkTime * inputTime, which is wrong, yes?
+            if (pedestal == NULL) {
+                pedestal = pmReadoutAlloc (NULL);
+            }
+            pedestal->col0    = dark->col0;
+            pedestal->row0    = dark->row0;
+            pedestal->colBins = dark->colBins;
+            pedestal->rowBins = dark->rowBins;
+
+            pedestal->image   = (psImage *) psBinaryOp(pedestal->image, dark->image, "*", psScalarAlloc(inputTime / darkTime, PS_TYPE_F32));
+            reusePedestal = false;
+            lastExptime = inputTime
+        }
+    }
+
+    // no bias image, return dark pedestal or NULL
+    if (!options->doBias) {
+        return pedestal;
+    }
+
+    // no dark image, return bias pedestal, or reuse
+    if (!options->doDark) {
+        if (!pedestal) {
+            pedestal = psMemIncrRefCounter(bias);
+        }
+        return pedestal;
+    }
+
+    if (reusePedestal) {
+        return pedestal;
+    }
+
+    if (bias->image->numRows != dark->image->numRows ||
+        bias->image->numCols != dark->image->numCols) {
+        psError(PS_ERR_IO, true, "Bias and dark images have different dimensions: %dx%d vs %dx%d\n",
+                bias->image->numCols, bias->image->numRows,
+                dark->image->numCols, dark->image->numRows);
+        exit(EXIT_FAILURE);
+    }
+
+    psBinaryOp(pedestal->image, pedestal->image, "+", bias->image);
+    return pedestal;
+#else
+    return NULL;
+#endif
+}
+
+// creates a new pedestal image for this readout
+// if the current exptime is the same as the last exptime,
+// reuses the supplied pedestal
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageLoadPixels.c
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageLoadPixels.c	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageLoadPixels.c	(revision 22348)
@@ -0,0 +1,69 @@
+#include <stdio.h>
+#include "pslib.h"
+#include "psmodules.h"
+#include "ppImage.h"
+
+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 (input->fits == NULL) {
+        return false;
+    }
+
+    psTrace(__func__, 1, "Loading %d,%d for %s\n", chipNum, cellNum, input->filename);
+
+    pmFPA *fpa = input->fpa;            // The entire focal plane array
+    psArray *chips = fpa->chips;        // The array of chips
+    if (chipNum >= 0 && chipNum < chips->n) {
+        loadCells(chips->data[chipNum]);
+        if (! chip->exists && chip->process) {
+            loadCells(chip, cellNum);
+        }
+    } else {
+        for (int i = 0; i < chips->n; i++) {
+            pmChip *chip = chips->data[i];
+        }
+
+    // set input:valid flags according to process and chipNum/cellNum
+    for (int i = 0; i < input->fpa->chips->n; i++) {
+        pmChip *chip = input->fpa->chips->data[i]; // Chip in input image
+        chip->process = (! chip->exists && ((chipNum == i) || (chipNum == -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->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 *chip = input->fpa->chips->data[i];
+        chip->process = true;
+        for (int j = 0; j < chip->cells->n; j++) {
+
+            pmCell *cell = chip->cells->data[j];
+            cell->process = true;
+        }
+    }
+#endif
+
+    return true;
+}
+
+// XXX this is not very efficient with fseeks : each pmFPARead is randomly accessing the file
+// XXX does this handle multi-file data?
+// XXX this does NOT preserve the state of the input valid flags
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageLoop.c
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageLoop.c	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageLoop.c	(revision 22348)
@@ -0,0 +1,135 @@
+#include <stdio.h>
+#include "pslib.h"
+#include "psmodules.h"
+#include "ppImageDetrend.h"
+#include "ppImage.h"
+#include "ppMem.h"
+
+#define MEM_LEAKS 1
+
+// Read the entire FPA
+void readFPA(ppFile *file,              // File to read
+             pmConfig *config           // Configuration, containing the DB handle
+    )
+{
+    if (file->fpa && file->fits) {
+        pmFPARead(file->fpa, file->fits, config->database);
+    }
+}
+
+// Read a specified chip only
+void readChip(ppFile *file,             // File to read
+              pmConfig *config,         // Configuration
+              int chipNum               // Chip number to read
+    )
+{
+    pmFPA *fpa = file->fpa;             // The FPA
+    if (fpa && file->fits) {
+        pmChip *chip = fpa->chips->data[chipNum]; // The chip
+        pmChipRead(chip, file->fits, config->database);
+    }
+}
+
+
+void readCell(ppFile *file, pmConfig *config, int chipNum, int cellNum)
+{
+    pmFPA *fpa = file->fpa;             // The FPA
+    if (fpa && file->fits) {
+        pmChip *chip = fpa->chips->data[chipNum]; // The chip
+        if (chip) {
+            pmCell *cell = chip->cells->data[cellNum]; // The cell
+            pmCellRead(cell, file->fits, config->database);
+        }
+    }
+}
+
+
+bool ppImageLoop(ppImageData *data, ppImageOptions *options, pmConfig *config)
+{
+    ppImageDetrend detrend;
+
+    int processChip = psMetadataLookupS32(NULL, config->arguments, "-chip"); // Chip number to process or -1
+
+    // Load at FPA level if requested
+    if (processChip < 0 && options->imageLoadDepth == PP_LOAD_FPA) {
+        psTrace(__func__, 1, "Loading pixels for FPA...\n");
+        readFPA(data->input, config);
+        readFPA(data->bias,  config);
+        readFPA(data->dark,  config);
+        readFPA(data->mask,  config);
+        readFPA(data->flat,  config);
+    }
+
+    psArray *chips = data->input->fpa->chips; // Component chips
+    for (int i = 0; i < chips->n; i++) {
+
+        if (processChip >= 0 && i != processChip) {
+            continue;
+        }
+        if (options->imageLoadDepth == PP_LOAD_CHIP) {
+            psTrace(__func__, 1, "Loading pixels for chip %d...\n", i);
+            readChip(data->input, config, i);
+            readChip(data->bias,  config, i);
+            readChip(data->dark,  config, i);
+            readChip(data->mask,  config, i);
+            readChip(data->flat,  config, i);
+        }
+
+        pmChip *inputChip = chips->data[i];
+        pmChip *biasChip  = data->bias->fpa->chips->data[i];
+        pmChip *darkChip  = data->dark->fpa->chips->data[i];
+        pmChip *maskChip  = data->mask->fpa->chips->data[i];
+        pmChip *flatChip  = data->flat->fpa->chips->data[i];
+
+        psArray *cells = inputChip->cells;
+        for (int j = 0; j < cells->n; j++) {
+            detrend.input = inputChip->cells->data[j]; // Cell of interest in input image
+            detrend.bias  = biasChip->cells->data[j];  // Cell of interest in bias image
+            detrend.dark  = darkChip->cells->data[j];  // Cell of interest in dark imag
+            detrend.mask  = maskChip->cells->data[j];  // Cell of interest in mask image
+            detrend.flat  = flatChip->cells->data[j];  // Cell of interest in flat image
+
+            if (! detrend.input->process) { continue; }
+
+            if (options->imageLoadDepth == PP_LOAD_CELL) {
+                psTrace(__func__, 1, "Loading pixels for chip %d, cell %d...\n", i, j);
+                readCell(data->input, config, i, j);
+                readCell(data->bias,  config, i, j);
+                readCell(data->dark,  config, i, j);
+                readCell(data->mask,  config, i, j);
+                readCell(data->flat,  config, i, j);
+            }
+
+            ppImageDetrendCell(&detrend, options, config);
+
+            // Need to free detrend cells here so we have enough memory to do other stuff
+            psFree(detrend.bias);
+            psFree(detrend.dark);
+            psFree(detrend.mask);
+            psFree(detrend.flat);
+        }
+
+#if 0
+        int numMosaicked = pmChipMosaic(inputChip, 1, 1); // Number of cells mosaicked together
+        psLogMsg(__func__, PS_LOG_INFO, "%d cells mosaicked.\n", numMosaicked);
+
+        // XXX A kludge to get the write to behave w.r.t. the concepts --- we've changed the camera format, so
+        // the concepts don't know what on earth to do.
+        const psMetadata *camera = data->input->fpa->camera;
+        data->input->fpa->camera = NULL;
+#endif
+
+        // XXX Photometry goes here!
+
+        pmChipWrite(inputChip, data->output, config->database);
+
+#if 0
+        data->input->fpa->camera = camera;
+#endif
+
+        // Now I can blow away the mosaic so I can then read more.
+        psFree(inputChip);
+    }
+
+    return true;
+}
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageOptions.c
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageOptions.c	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageOptions.c	(revision 22348)
@@ -0,0 +1,212 @@
+#include <stdio.h>
+#include "pslib.h"
+#include "ppImage.h"
+#include "ppImageData.h"
+#include "ppImageOptions.h"
+
+static void imageOptionsFree(ppImageOptions *options)
+{
+    psFree(options->overscan);
+    psFree(options->nonLinearData);
+    psFree(options->nonLinearSource);
+}
+
+ppImageOptions *ppImageOptionsAlloc(void)
+{
+    ppImageOptions *options = psAlloc(sizeof(ppImageOptions));
+    psMemSetDeallocator(options, (psFreeFunc)imageOptionsFree);
+
+    // Initialise options
+    options->overscan = NULL;
+    options->nonLinearData = NULL;
+    options->nonLinearSource = NULL;
+
+    return options;
+}
+
+
+// XXX EAM : this needs signficant work to choose the detrend images based on the detrend database
+
+bool ppImageOptionsParse(ppImageData *data, ppImageOptions *options, pmConfig *config)
+{
+
+    // 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->overscan = NULL;           // Overscan options
+    bool overscanSingle = false;        // A single value for entire overscan?
+    pmFit overscanFit = PM_FIT_NONE;    // Fit type for overscan
+    int overscanOrder = 0;              // Order for overscan fit
+    psStats *overscanStats = NULL;      // Statistics 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
+
+
+    bool mdStatus = false;              // Result of MD lookup
+    psMetadata *recipe = psMetadataLookupMD(&mdStatus, config->recipes, RECIPE_NAME);
+    if (! mdStatus || !recipe) {
+        psLogMsg("ppImage", PS_LOG_ERROR, "Can't find recipe %s in the RECIPES.\n", RECIPE_NAME);
+        exit(EXIT_FAILURE);
+    }
+
+    const char *depth = psMetadataLookupStr(&mdStatus, 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;
+    } 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 %s is not FPA, CHIP or CELL.", RECIPE_NAME);
+        exit(EXIT_FAILURE);
+    }
+
+    // Mask recipe options
+    if (psMetadataLookupBool(NULL, recipe, "MASK")) {
+        data->mask->filename = psMetadataLookupStr(NULL, config->arguments, "-mask");
+        if (data->mask->filename && strlen(data->mask->filename) > 0) {
+            options->doMask = true;
+        } else {
+            psLogMsg(__func__, PS_LOG_WARN, "Masking is desired, but no mask was supplied"
+                     " --- no masking will be performed.\n");
+        }
+    }
+
+    // Non-linearity recipe options
+    if (psMetadataLookupBool(NULL, recipe, "NONLIN")) {
+        psMetadataItem *dataItem = psMetadataLookup(recipe, "NONLIN.DATA");
+        if (! dataItem) {
+            psLogMsg(__func__, PS_LOG_ERROR, "Non-linearity correction desired, but unable to "
+                     "find NONLIN.DATA in recipe %s.", RECIPE_NAME);
+            exit(EXIT_FAILURE);
+        }
+
+        options->doNonLin = true;
+        options->nonLinearType = dataItem->type;
+        options->nonLinearData = dataItem;
+
+        switch (dataItem->type) {
+            // No immediate action required
+          case PS_DATA_VECTOR:
+          case PS_DATA_STRING:
+            break;
+
+            // This is a menu; we need the key
+          case PS_DATA_METADATA:
+            {
+                bool status;
+                options->nonLinearSource = psMetadataLookupStr(&status, recipe, "NONLIN.SOURCE");
+                if (! status || ! options->nonLinearSource) {
+                    psLogMsg(__func__, PS_LOG_ERROR, "Non-linearity correction desired, but unable to "
+                            "find NONLIN.SOURCE in recipe %s.", RECIPE_NAME);
+                    exit(EXIT_FAILURE);
+                }
+            }
+            break;
+          default:
+            psLogMsg(__func__, PS_LOG_ERROR, "Non-linearity correction desired, but "
+                    "NONLIN.DATA is of invalid type in recipe %s.", RECIPE_NAME);
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    // Bias recipe options
+    if (psMetadataLookupBool(NULL, recipe, "BIAS")) {
+        data->bias->filename = psMetadataLookupStr(NULL, config->arguments, "-bias");
+        if (data->bias->filename && strlen(data->bias->filename) > 0) {
+            options->doBias = true;
+        } else {
+            psLogMsg(__func__, PS_LOG_WARN, "Bias subtraction is desired in recipe %s, but no bias was "
+                     "supplied --- no bias subtraction will be performed.\n", RECIPE_NAME);
+        }
+    }
+
+    // Dark recipe options
+    if (psMetadataLookupBool(NULL, recipe, "DARK")) {
+        data->dark->filename = psMetadataLookupStr(NULL, config->arguments, "-dark");
+        if (data->dark->filename && strlen(data->dark->filename) > 0) {
+            options->doDark = true;
+        } else {
+            psLogMsg(__func__, PS_LOG_WARN, "Dark subtraction is desired in recipe %s, but no dark was "
+                     "supplied --- no dark subtraction will be performed.\n", RECIPE_NAME);
+        }
+    }
+
+    // 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, recipe, "OVERSCAN")) {
+        options->doOverscan = true;
+
+        // Do the overscan as a single value?
+        overscanSingle = psMetadataLookupBool(NULL, recipe, "OVERSCAN.SINGLE");
+
+        // How do we fit it?
+        psString fit = psMetadataLookupStr(NULL, recipe, "OVERSCAN.FIT");
+        if (! strcasecmp(fit, "POLYNOMIAL")) {
+            overscanFit = PM_FIT_POLY_ORD;
+            overscanOrder = psMetadataLookupS32(NULL, recipe, "OVERSCAN.ORDER");
+        } else if (! strcasecmp(fit, "CHEBYSHEV")) {
+            overscanFit = PM_FIT_POLY_CHEBY;
+            overscanOrder = psMetadataLookupS32(NULL, recipe, "OVERSCAN.ORDER");
+        } else if (! strcasecmp(fit, "SPLINE")) {
+            overscanFit = PM_FIT_SPLINE;
+        } else if (strcasecmp(fit, "NONE")) {
+            psLogMsg(__func__, PS_LOG_WARN, "OVERSCAN.FIT (%s) in recipe %s is not one of NONE, "
+                     "POLYNOMIAL, or SPLINE: assuming NONE.\n", fit, RECIPE_NAME);
+        }
+
+        psString stat = psMetadataLookupStr(NULL, recipe, "OVERSCAN.STAT");
+        if (! strcasecmp(stat, "MEAN")) {
+            overscanStats = psStatsAlloc(PS_STAT_SAMPLE_MEAN);
+        } else if (! strcasecmp(stat, "MEDIAN")) {
+            overscanStats = psStatsAlloc(PS_STAT_SAMPLE_MEDIAN);
+        } else {
+            psErrorStackPrint(stderr, "OVERSCAN.STAT (%s) in recipe %s is not one of MEAN, MEDIAN: "
+                              "assuming MEAN\n", stat, RECIPE_NAME);
+            overscanStats = psStatsAlloc(PS_STAT_SAMPLE_MEAN);
+        }
+
+        // Fill in the options
+        options->overscan = pmOverscanOptionsAlloc(overscanSingle, overscanFit, overscanOrder, overscanStats);
+        psFree(overscanStats);
+    }
+
+    // flat-field - recipe options
+    if (psMetadataLookupBool(NULL, recipe, "FLAT")) {
+        data->flat->filename = psMetadataLookupStr(NULL, config->arguments, "-flat");
+        if (strlen(data->flat->filename) > 0) {
+            options->doFlat = true;
+        } else {
+            psLogMsg(__func__, PS_LOG_WARN, "Flat-fielding is desired in recipe %s, but no flat was "
+                     "supplied --- no flat-fielding will be performed.\n", RECIPE_NAME);
+        }
+    }
+
+    // XXX need to add the following:
+
+    // fringe - recipe options
+
+    // photom - recipe options
+
+    // astrom - recipe options
+
+    return true;
+}
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageOptions.h
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageOptions.h	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageOptions.h	(revision 22348)
@@ -0,0 +1,43 @@
+#ifndef PP_IMAGE_OPTIONS_H
+#define PP_IMAGE_OPTIONS_H
+
+#include "pslib.h"
+#include "psmodules.h"
+#include "ppImageData.h"
+#include "ppConfig.h"
+
+// How much of the FPA to load at a time
+typedef enum {
+    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;
+
+// Options for ppImage processing
+typedef struct {
+    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
+    pmOverscanOptions *overscan;        // Overscan options
+    bool doNonLin;                      // Non-linearity correction
+    psDataType nonLinearType;
+    psMetadataItem *nonLinearData;
+    void *nonLinearSource;
+    ppImageLoadDepth imageLoadDepth;    // How much of the FPA to load at once
+} ppImageOptions;
+
+ppImageOptions *ppImageOptionsAlloc(void);
+
+// Determine the processing options
+bool ppImageOptionsParse(ppImageData *data, // The data to be processed
+                         ppImageOptions *options, // Processing options
+                         pmConfig *config    // Configuration
+    );
+
+#endif
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageOutput.c
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageOutput.c	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageOutput.c	(revision 22348)
@@ -0,0 +1,22 @@
+#include <stdio.h>
+#include "pslib.h"
+#include "psmodules.h"
+#include "ppImage.h"
+
+bool ppImageOutput(ppData *data, pmConfig *config)
+{
+    const char *outname = psMetadataLookupStr(NULL, config->arguments, "-output"); // Name of output file
+    psFits *outFile = psFitsOpen(outname, "a"); // File for writing
+
+    // Write the output
+    pmFPAWrite(outFile, data->input->fpa, config->database);
+#if 0
+    pmFPAWriteMask(input, outputFile);
+    pmFPAWriteWeight(input, outputFile);
+#endif
+
+    psFitsClose(outFile);
+    psLogMsg("ppImage", PS_LOG_INFO, "Output completed after %f sec.\n", psTimerMark("ppImage"));
+
+    return true;
+}
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageParseCamera.c
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageParseCamera.c	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageParseCamera.c	(revision 22348)
@@ -0,0 +1,66 @@
+#include <stdio.h>
+#include "pslib.h"
+#include "psmodules.h"
+#include "ppImage.h"
+
+bool ppImageParseCamera(ppImageData *data, pmConfig *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();
+
+    data->input->filename = psMemIncrRefCounter(psMetadataLookupStr(NULL, config->arguments, "-input"));
+
+    // Open the input image
+    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) {
+        // We can't open the input
+        psErrorStackPrint(stderr, "Can't open input image: %s\n", data->input->filename);
+        exit(EXIT_FAILURE);
+    }
+    data->input->phu = psFitsReadHeader(NULL, data->input->fits); // FITS header
+
+    // Get camera configuration from header if not already defined
+    psMetadata *cameraFormat = NULL;    // Camera format description
+    if (! config->camera) {
+        cameraFormat = pmConfigCameraFormatFromHeader(config, 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 (! pmConfigValidateCameraFormat(config->camera, data->input->phu)) {
+        // 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);
+    }
+
+    // Construct cameras in preparation for reading
+    data->input->fpa  = pmFPAConstruct(config->camera);
+    data->input->view = pmFPAAddSource(data->input->fpa, data->input->phu, cameraFormat);
+
+    ppFileOpen(data->mask, "-mask", config, config->camera, cameraFormat);
+    ppFileOpen(data->bias, "-bias", config, config->camera, cameraFormat);
+    ppFileOpen(data->dark, "-dark", config, config->camera, cameraFormat);
+    ppFileOpen(data->flat, "-flat", config, config->camera, cameraFormat);
+    ppFileOpen(data->fringe, "-fringe", config, config->camera, cameraFormat);
+
+    psFree(cameraFormat);
+
+    // Open output file
+    const char *outname = psMetadataLookupStr(NULL, config->arguments, "-output"); // Name of output file
+    data->output = psFitsOpen(outname, "w"); // File for writing
+    if (! data->output) {
+        psError(PS_ERR_IO, false, "Unable to open output file %s.\n", data->output);
+        exit(EXIT_FAILURE);
+    }
+
+    return true;
+}
+
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageParseDetrend.c
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageParseDetrend.c	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageParseDetrend.c	(revision 22348)
@@ -0,0 +1,23 @@
+#include <stdio.h>
+#include "pslib.h"
+#include "psmodules.h"
+#include "ppFile.h"
+#include "ppImageData.h"
+#include "ppImageOptions.h"
+#include "ppImage.h"
+
+// open all needed detrend files
+// read in primary headers
+// validate camera for each detrend image
+
+// XXX : keep the primary headers in data?
+// XXX : add fringe frame
+
+bool ppImageParseDetrend(ppImageData *data, ppImageOptions *options, pmConfig *config)
+{
+    ppFileOpen(data->mask, "mask", options->doMask);
+    ppFileOpen(data->bias, "bias", options->doBias);
+    ppFileOpen(data->dark, "dark", options->doDark);
+    ppFileOpen(data->flat, "flat", options->doFlat);
+    return true;
+}
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImagePhot.c
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImagePhot.c	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImagePhot.c	(revision 22348)
@@ -0,0 +1,35 @@
+#include <stdio.h>
+#include "pslib.h"
+#include "psmodules.h"
+#include "ppImage.h"
+
+bool ppImagePhot(ppData *data, ppOptions *options, pmConfig *config)
+{
+    ppFile *input = data->input;        // The input file information
+    pmFPA *fpa = input->fpa;       // The input FPA
+
+    int numMosaicked = pmFPAMosaicCells(fpa, 1, 1); // Number of chips mosaicked together
+    psLogMsg(__func__, PS_LOG_INFO, "%d chips mosaicked.\n", numMosaicked);
+
+#if 1
+    // Write out the mosaicked chip, just to see; this wouldn't normally happen
+    psFits *mosaicFile = psFitsOpen("mosaic.fits", "w");
+    psArray *chips = fpa->chips;
+    for (int i = 0; i < chips->n; i++) {
+        pmChip *chip = chips->data[i];
+        if (! chip || ! chip->exists || ! chip->process) {
+            continue;
+        }
+        psArray *cells = chip->cells;
+        pmCell *cell = cells->data[0];
+        psArray *readouts = cell->readouts;
+        pmReadout *readout = readouts->data[0];
+        psImage *image = readout->image;
+        psFitsWriteImage(mosaicFile, NULL, image, 0);
+    }
+#endif
+
+    // XXX EAM: Insert psphot stuff here
+
+    return true;
+}
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageWeights.c
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageWeights.c	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppImageWeights.c	(revision 22348)
@@ -0,0 +1,32 @@
+#include <stdio.h>
+#include "pslib.h"
+#include "psmodules.h"
+#include "ppImage.h"
+
+bool ppReadoutWeights (pmReadout *readout) {
+
+    psImage *image  = readout->image;
+    readout->mask   = psImageAlloc(image->numCols, image->numRows, PS_TYPE_U8);
+    readout->weight = psImageAlloc(image->numCols, image->numRows, PS_TYPE_F32);
+
+    // XXX : we need to determine rdnoise and gain from the appropriate location
+    float rdnoise = 5.0;  // in electrons
+    float gain = 2.0;     // in e/ADU
+
+    float rgain = 1.0 / gain;
+    float rnoise = PS_SQR (rdnoise / gain);
+
+    psF32 **vI = readout->image->data.F32;
+    psU8  **vM = readout->mask->data.U8;
+    psF32 **vW = readout->weight->data.F32;
+
+    for (int j = 0; j < image->numRows; j++) {
+        for (int i = 0; i < image->numCols; i++) {
+            vM[j][i] = 0;
+            vW[j][i] = PS_MAX (rgain * vI[j][i] + rnoise, 0.0);
+        }
+    }
+    return true;
+}
+
+// XXX : I am defining the 'weight' to be the variance, not the stdev
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppMem.c
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppMem.c	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppMem.c	(revision 22348)
@@ -0,0 +1,85 @@
+#include <stdio.h>
+#include "pslib.h"
+#include "ppMem.h"
+
+#define LEAKS "leaks.dat"               // File to record leaks
+
+psMemId ppMemAlloc(const psMemBlock *ptr)
+{
+    fprintf(stderr, "Allocated ");
+    ppMemPrint(ptr);
+    return 0;
+}
+
+// Same as ppMemAlloc, except it says "Freed", and it subtracts one from the reference counter, because
+// psMemory.c doesn't do that until after the callback.
+psMemId ppMemFree(const psMemBlock *ptr)
+{
+    fprintf(stderr, "Freeing ");
+    ppMemPrint(ptr);
+    return 0;
+}
+
+void ppMemProblem(const psMemBlock *ptr)
+{
+    fprintf(stderr, "Problem with ");
+    ppMemPrint(ptr);
+}
+
+// Simply print a memory block
+void ppMemPrint(const psMemBlock *ptr)
+{
+    fprintf(stderr,
+            "Memory block %ld: %ld references\n"
+             "\tFile %s, line %d, size %zd\n"
+             "\tPosts: %zx %zx %zx\n",
+             ptr->id, ptr->refCounter, ptr->file, ptr->lineno, ptr->userMemorySize, (size_t)ptr->startblock,
+             (size_t)ptr->endblock, (size_t)*(void**)((int8_t *)(ptr + 1) + ptr->userMemorySize));
+}
+
+
+// Check for memory problems
+void ppMemCheck(void)
+{
+    fprintf(stderr, "Checking for memory problems....\n");
+
+    (void)psMemProblemCallbackSet((psMemProblemCallback)ppMemProblem); // Set callback for corruption
+
+    FILE *leakFile = fopen(LEAKS, "w"); // File to write leaks to
+    if (leakFile == NULL) {
+        fprintf(stderr, "Unable to open leaks file, %s\n", LEAKS);
+        return;
+    }
+
+    psMemBlock **leaks = NULL;          // List of leaks
+    int nLeaks = psMemCheckLeaks(0, &leaks, leakFile, true); // Number of leaks
+    fprintf(stderr, "%d leaks found:\n", nLeaks);
+    for (int i = nLeaks - 1; i >= 0; i--) {
+        ppMemPrint(leaks[i]);
+    }
+
+    int nCorrupted;                     // Number of corrupted memory blocks
+    nCorrupted = psMemCheckCorruption(false);
+    fprintf(stderr, "%d memory blocks corrupted.\n", nCorrupted);
+}
+
+void ppMemUsed(void)
+{
+    psMemBlock **leaks = NULL;          // List of leaks
+    int nLeaks = psMemCheckLeaks(0, &leaks, NULL, true); // Number of leaks
+    size_t total = 0;                   // Total size
+    size_t largest = 0;                 // Largest block size
+    psMemId index = -1;                 // Id number of largest block
+    for (int i = nLeaks - 1; i >= 0; i--) {
+        psMemBlock *mb = leaks[i];
+        if (mb->userMemorySize >= largest) {
+            largest = mb->userMemorySize;
+            index = mb->id;
+        }
+        total += mb->userMemorySize;
+    }
+    psFree(leaks);
+
+    psLogMsg(__func__, PS_LOG_INFO, "Memory used: %ld\nLargest id: %ld (%ld bytes)", total, index, largest);
+
+}
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppMem.h
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppMem.h	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppMem.h	(revision 22348)
@@ -0,0 +1,12 @@
+#ifndef PP_MEM_H
+#define PP_MEM_H
+
+#include "pslib.h"
+
+psMemId ppMemAlloc(const psMemBlock *ptr);
+psMemId ppMemFree(const psMemBlock *ptr);
+void ppMemPrint(const psMemBlock *ptr);
+void ppMemCheck(void);
+void ppMemUsed(void);
+
+#endif
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppTest.c
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppTest.c	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/src/ppTest.c	(revision 22348)
@@ -0,0 +1,127 @@
+#include <stdio.h>
+
+#include "pslib.h"
+#include "psmodules.h"
+#include "ppMem.h"
+
+int main(int argc, char *argv[])
+{
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// ppImageConfig.c
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    pmConfig *config = pmConfigRead(&argc, argv);
+    if (! config) {
+        psErrorStackPrint(stderr, "Can't find site configuration!\n");
+        exit(EXIT_FAILURE);
+    }
+
+    // Parse other command-line arguments
+    config->arguments = psMetadataAlloc(); // The arguments, with default values
+    psMetadataAddStr(config->arguments, PS_LIST_TAIL, "-key", 0, "exposure ID", "");
+    psMetadataAddStr(config->arguments, PS_LIST_TAIL, "-bias", 0, "Name of the bias image", "");
+    psMetadataAddStr(config->arguments, PS_LIST_TAIL, "-dark", 0, "Name of the dark image", "");
+    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);
+
+    if (! psArgumentParse(config->arguments, &argc, argv) || argc != 3) {
+        printf("\nPan-STARRS Phase 2 processing\n\n");
+        printf("Usage: %s INPUT.fits OUTPUT.fits\n\n", argv[0]);
+        psArgumentHelp(config->arguments);
+        psFree(config->arguments);
+        exit(EXIT_FAILURE);
+    }
+
+    // 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
+#if 0
+    config->database = pmConfigDB(config->site);
+#endif
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// ppImageParseCamera.c extract with some alterations
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+    const char *inName = psMetadataLookupStr(NULL, config->arguments, "-input");
+    psLogMsg("ppImage", PS_LOG_INFO, "Opening input image: %s\n", inName);
+    psFits *inFile = psFitsOpen(inName, "r"); // File handle for FITS file
+    if (! inFile) {
+        // There's no point in continuing if we can't open the input
+        psErrorStackPrint(stderr, "Can't open input image: %s\n", inName);
+        exit(EXIT_FAILURE);
+    }
+    psMetadata *phu = psFitsReadHeader(NULL, inFile); // FITS primary header
+
+    psMetadata *cameraFormat = pmConfigCameraFormatFromHeader(config, phu);
+    if (! config->camera) {
+        cameraFormat = pmConfigCameraFormatFromHeader(config, 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);
+        }
+    }
+    // Determine the correct recipe to use
+    if (! config->recipes && !pmConfigReadRecipes(config)) {
+        // There's no point in continuing if we can't work out what recipes to use
+        psErrorStackPrint(stderr, "Can't find recipe configuration!\n");
+        exit(EXIT_FAILURE);
+    }
+
+    const char *outName = psMetadataLookupStr(NULL, config->arguments, "-output");
+    psLogMsg("ppImage", PS_LOG_INFO, "Opening output image: %s\n", outName);
+    psFits *outFile = psFitsOpen(outName, "w");
+    if (!outFile) {
+        // There's no point in continuing if we can't open the output
+        psErrorStackPrint(stderr, "Can't open output image: %s\n", outName);
+        exit(EXIT_FAILURE);
+    }
+
+    // Construct camera in preparation for reading
+    pmFPA *fpa = pmFPAConstruct(config->camera);
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// NEW
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+    // Add in a source file
+    pmFPAview *view = pmFPAAddSource(fpa, phu, cameraFormat);
+    printf("View chip: %d\n", view->chip);
+    printf("View cell: %d\n", view->cell);
+
+    // Read the FPA
+    pmFPARead(fpa, inFile, NULL);
+    // Copy to new camera format
+    pmFPA *newFPA = pmFPAConstruct(config->camera);
+    psMetadata *newFormat = psMetadataConfigParse(NULL, NULL, "mcshort_splice.config", true);
+    pmConfigConformHeader(phu, newFormat);
+    pmFPAview *newView = pmFPAAddSource(newFPA, phu, newFormat);
+    printf("View chip: %d\n", newView->chip);
+    printf("View cell: %d\n", newView->cell);
+    pmFPACopy(newFPA, fpa);
+    pmFPAWrite(newFPA, outFile, NULL);
+    pmFPAPrint(newFPA, false, true);
+
+    psFree(newView);
+    psFree(newFormat);
+    psFree(newFPA);
+    psFree(view);
+    psFree(fpa);
+    psFree(config);
+    psFitsClose(inFile);
+    psFitsClose(outFile);
+    psFree(phu);
+    psFree(cameraFormat);
+
+    psTimerStop();
+    psTraceReset();
+    pmConceptsDone();
+    ppMemCheck();
+
+    // Pau.
+}
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/test/.cvsignore
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/test/.cvsignore	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/test/.cvsignore	(revision 22348)
@@ -0,0 +1,3 @@
+.gdb_history
+*.fits
+leaks.dat
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/test/gpc1.config
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/test/gpc1.config	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/test/gpc1.config	(revision 22348)
@@ -0,0 +1,82 @@
+# Camera configuration file for GPC1: describes the camera
+
+# File formats that we know about
+FORMATS		METADATA
+	RAW	STR	gpc1_raw.config
+END
+
+
+# Description of camera --- all the chips and the cells that comprise them
+FPA	METADATA
+	64	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY01	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY02	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY03	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY04	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY05	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY06	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY07	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY10	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY11	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY12	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY13	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY14	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY15	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY16	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY17	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY20	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY21	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY22	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY23	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY24	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY25	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY26	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY27	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY30	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY31	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY32	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY33	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY34	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY35	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY36	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY37	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY40	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY41	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY42	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY43	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY44	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY45	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY46	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY47	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY50	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY51	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY52	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY53	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY54	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY55	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY56	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY57	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY60	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY61	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY62	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY63	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY64	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY65	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY66	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY67	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY70	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY71	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY72	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY73	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY74	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY75	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY76	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+#	XY77	STR	xy00 xy01 xy02 xy03 xy04 xy05 xy06 xy07 xy10 xy11 xy12 xy13 xy14 xy15 xy16 xy17 xy20 xy21 xy22 xy23 xy24 xy25 xy26 xy27 xy30 xy31 xy32 xy33 xy34 xy35 xy36 xy37 xy40 xy41 xy42 xy43 xy44 xy45 xy46 xy47 xy50 xy51 xy52 xy53 xy54 xy55 xy56 xy57 xy60 xy61 xy62 xy63 xy64 xy65 xy66 xy67 xy70 xy71 xy72 xy73 xy74 xy75 xy76 xy77
+END	   
+
+
+# Recipe options
+RECIPES		METADATA
+	PHASE2		STR	phase2.config		# Phase 2 recipe details
+#	PSPHOT		STR	psphot.config		# psphot details
+END
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/test/gpc1_raw.config
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/test/gpc1_raw.config	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/test/gpc1_raw.config	(revision 22348)
@@ -0,0 +1,176 @@
+# The raw GPC data comes off the telescope with each of the chips stored in separate files
+
+# How to identify this type
+RULE	METADATA
+#	TELESCOP	STR	PS1
+#	DETECTOR	STR	GPC1
+	EXTEND		BOOL	T
+	NEXTEND		S32	64
+	NAMPS		S32	64
+END
+
+# How to read this data
+FORMAT	METADATA
+	PHU		STR	CHIP	# The FITS file represents a single chip
+	EXTENSIONS	STR	CELL	# The extensions represent cells
+	FPA.NAME	STR	NAMPS	# A PHU keyword for unique identifier within the hierarchy level
+	CHIP.NAME	STR	NAMPS	# An extension keyword for unique identifier
+END
+
+# What's in the FITS file?
+CONTENTS	METADATA
+	# Extension name, type
+	xy00	STR	xy00:pitch10u
+	xy01	STR	xy01:pitch10u
+	xy02	STR	xy02:pitch10u
+	xy03	STR	xy03:pitch10u
+	xy04	STR	xy04:pitch10u
+	xy05	STR	xy05:pitch10u
+	xy06	STR	xy06:pitch10u
+	xy07	STR	xy07:pitch10u
+	xy10	STR	xy10:pitch10u
+	xy11	STR	xy11:pitch10u
+	xy12	STR	xy12:pitch10u
+	xy13	STR	xy13:pitch10u
+	xy14	STR	xy14:pitch10u
+	xy15	STR	xy15:pitch10u
+	xy16	STR	xy16:pitch10u
+	xy17	STR	xy17:pitch10u
+	xy20	STR	xy20:pitch10u
+	xy21	STR	xy21:pitch10u
+	xy22	STR	xy22:pitch10u
+	xy23	STR	xy23:pitch10u
+	xy24	STR	xy24:pitch10u
+	xy25	STR	xy25:pitch10u
+	xy26	STR	xy26:pitch10u
+	xy27	STR	xy27:pitch10u
+	xy30	STR	xy30:pitch10u
+	xy31	STR	xy31:pitch10u
+	xy32	STR	xy32:pitch10u
+	xy33	STR	xy33:pitch10u
+	xy34	STR	xy34:pitch10u
+	xy35	STR	xy35:pitch10u
+	xy36	STR	xy36:pitch10u
+	xy37	STR	xy37:pitch10u
+	xy40	STR	xy40:pitch10u
+	xy41	STR	xy41:pitch10u
+	xy42	STR	xy42:pitch10u
+	xy43	STR	xy43:pitch10u
+	xy44	STR	xy44:pitch10u
+	xy45	STR	xy45:pitch10u
+	xy46	STR	xy46:pitch10u
+	xy47	STR	xy47:pitch10u
+	xy50	STR	xy50:pitch10u
+	xy51	STR	xy51:pitch10u
+	xy52	STR	xy52:pitch10u
+	xy53	STR	xy53:pitch10u
+	xy54	STR	xy54:pitch10u
+	xy55	STR	xy55:pitch10u
+	xy56	STR	xy56:pitch10u
+	xy57	STR	xy57:pitch10u
+	xy60	STR	xy60:pitch10u
+	xy61	STR	xy61:pitch10u
+	xy62	STR	xy62:pitch10u
+	xy63	STR	xy63:pitch10u
+	xy64	STR	xy64:pitch10u
+	xy65	STR	xy65:pitch10u
+	xy66	STR	xy66:pitch10u
+	xy67	STR	xy67:pitch10u
+	xy70	STR	xy70:pitch10u
+	xy71	STR	xy71:pitch10u
+	xy72	STR	xy72:pitch10u
+	xy73	STR	xy73:pitch10u
+	xy74	STR	xy74:pitch10u
+	xy75	STR	xy75:pitch10u
+	xy76	STR	xy76:pitch10u
+	xy77	STR	xy77:pitch10u
+END
+
+# Specify the cell data
+CELLS	METADATA
+	pitch10u	METADATA
+		CELL.BIASSEC.SOURCE	STR	VALUE
+		CELL.TRIMSEC.SOURCE	STR	VALUE
+		CELL.BIASSEC		STR	[575:606,1:594]
+		CELL.TRIMSEC		STR	[1:574,1:594]
+	#	CELL.BIASSEC		STR	BIASSEC
+	#	CELL.TRIMSEC		STR	DATASEC
+	END
+
+	# This is just in here for fun
+	pitch12u	METADATA
+		CELL.BIASSEC.SOURCE	STR	VALUE
+		CELL.TRIMSEC.SOURCE	STR	VALUE
+		CELL.BIASSEC		STR	[1:10,1:512];[523:574,1:512]
+		CELL.TRIMSEC		STR	[11:522,1:512]
+	#	CELL.BIASSEC		STR	BIASSEC
+	#	CELL.TRIMSEC		STR	TRIMSEC
+	END
+END
+
+
+# How to translate PS concepts into FITS headers
+TRANSLATION	METADATA
+	CELL.XBIN	STR	CCDSUM
+	CELL.YBIN	STR	CCDSUM
+	CELL.X0		STR	IMNPIX1
+	CELL.Y0		STR	IMNPIX2
+ 	CELL.XPARITY	STR	LTM1_1
+	CELL.YPARITY	STR	LTM2_2
+	CELL.SATURATION	STR	SATURATE
+END
+
+# Default PS concepts that may be specified by value
+DEFAULTS	METADATA
+	FPA.AIRMASS	F32	0.0
+	FPA.FILTER	STR	NONE
+	FPA.POSANGLE	F32	0.0
+	FPA.RA		STR	0:0:0
+	FPA.DEC		STR	0:0:0
+	FPA.RADECSYS	STR	ICRS
+	FPA.NAME	S32	12345
+	CELL.EXPOSURE	F32	0.0
+	CELL.DARKTIME	F32	0.0
+	CELL.GAIN	F32	1.0
+	CELL.READNOISE	F32	0.0
+	CELL.READDIR	S32	2
+	CELL.BAD	S32	0
+	CELL.TIMESYS	STR	UTC
+	CELL.TIME	STR	2005-11-23T12:34:56.78
+END
+
+# How to translation PS concepts into database lookups
+DATABASE	METADATA
+	TYPE		dbEntry		TABLE		COLUMN		GIVENDBCOL	GIVENPS
+#	CELL.GAIN	dbEntry		Camera		gain		chipId,cellId	CHIP,CELL
+#	CELL.READNOISE	dbEntry		Camera		readNoise	chipId,cellId	CHIP,CELL
+
+# A database entry refers to a particular column (COLUMN) in a
+# particular table (TABLE), given certain PS concepts (GIVENPS) that
+# match certain database columns (GIVENDBCOL).
+
+END
+
+
+# Where there might be some ambiguity, specify the format
+FORMATS		METADATA
+	FPA.RA		STR	HOURS
+	FPA.DEC		STR	DEGREES
+	CELL.TIME	STR	ISO
+	CELL.BINNING	STR	TOGETHER
+	CELL.X0		STR	FORTRAN
+	CELL.Y0		STR	FORTRAN
+END
+ 
+# Recipe options
+RECIPES		METADATA
+	PHASE2		STR	phase2.config		# Phase 2 recipe details
+END
+ 
+# How to get the supplementary stuff: mask and weight
+SUPPLEMENTARY	METADATA
+	MASK.SOURCE	STR	FILE		# Source type for mask: EXT | FILE
+	MASK.NAME	STR	%a_mask.fits	# Name for mask extension or filename
+	WEIGHT.SOURCE	STR	FILE		# Source type for weight: EXT | FILE
+	WEIGHT.NAME	STR	%a_weight.fits	# Name for weight extension or filename
+END
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/test/ipprc.config
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/test/ipprc.config	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/test/ipprc.config	(revision 22348)
@@ -0,0 +1,34 @@
+### Example .ipprc file
+
+### Database configuration
+DBSERVER	STR	ippdb.ifa.hawaii.edu	# Database host name (for psDBInit)
+DBUSER		STR	ipp			# Database user name (for psDBInit)
+DBPASSWORD	STR	password		# Database password (for psDBInit)
+
+### Setups for each camera system
+CAMERAS		METADATA
+	MEGACAM		STR	megacam.config
+	GPC1		STR	gpc1.config
+#	LRIS_BLUE	STR	lris_blue.config
+#	LRIS_RED	STR	lris_red.config
+END
+
+### psLib setup
+#TIME		STR	/home/mithrandir/price/pan-starrs/jhroot/i686-pc-linux-gnu/etc/pslib/psTime.config	# Time configuration file
+LOGLEVEL	S32	9			# Logging level; 3=INFO
+LOGFORMAT	STR	THLNM			# Log format
+LOGDEST	STR	STDOUT				# Log destination
+TRACE		METADATA			# Trace levels
+	ppImageLoop		S32	10
+	pmFPAPrint		S32	10
+#	ppImageLoadPixels	S32	10
+#	pmFPAWrite		S32	10
+#	pmFPARead		S32	10
+#	pmSubtractBias		S32	10
+#	ppDetrendBias		S32	10
+#	psModule.concepts	S32	10
+#	pmConfigRead		S32	10
+#	pmFPAWriteMask		S32	10
+#	pmFPAWriteWeight	S32	10
+#	pmChipMosaic		S32	10
+END
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/test/lris_blue.config
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/test/lris_blue.config	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/test/lris_blue.config	(revision 22348)
@@ -0,0 +1,13 @@
+# Camera configuration file for LRIS Blue: describes the camera
+
+# File formats that we know about
+FORMATS         METADATA
+	RAW	STR	lris_blue_raw.config
+END
+                                                                                
+                                                                                
+# Description of camera --- all the chips and the cells that comprise them
+FPA     METADATA
+        LeftChip	STR	left right
+        RightChip	STR	left right
+END
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/test/lris_blue_raw.config
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/test/lris_blue_raw.config	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/test/lris_blue_raw.config	(revision 22348)
@@ -0,0 +1,96 @@
+# The Low Resolution Imager and Spectrograph (LRIS) blue side
+
+# We have no choice but to hard-code the various regions, because Keck
+# only stores them as:
+# WINDOW  = '1,0,0,2048,4096'
+# PREPIX  =                   51
+# POSTPIX =                   80
+# BINNING = '1,1     '
+# AMPPSIZE= '[1:1024,1:4096]'
+
+# I don't know how we would get the IPP to react to changes in the
+# windowing on the fly --- we have no mechanism for setting the region
+# sizes on the basis of the above keywords.  Therefore, we hard-code
+# the regions and assert on our assumptions in the RULE.
+
+
+# How to identify this type
+RULE	METADATA
+	TELESCOP	STR	Keck I
+	INSTRUME	STR	LRISBLUE
+	AMPLIST		STR	1,4,0,0
+	WINDOW		STR	1,0,0,2048,4096
+	PREPIX		S32	51
+	POSTPIX		S32	80
+	BINNING		STR	1,1
+	AMPPSIZE	STR	[1:1024,1:4096]
+	NAXIS1		S32	4620
+	NAXIS2		S32	4096
+END
+
+# How to read this data
+FORMAT	METADATA
+	PHU		STR	FPA	# The FITS file represents an entire FPA
+	EXTENSIONS	STR	NONE	# There are no extensions
+	FPA.NAME	STR	OBSNUM	# A PHU keyword for unique identifier within the hierarchy level
+        CHIP.NAME	STR	INSTRUME# An extension keyword for unique identifier
+END
+
+# What's in the FITS file?
+CONTENTS	METADATA
+	LRISBLUE	STR	LeftChip:amp1 LeftChip:amp2 RightChip:amp3 RightChip:amp4
+END
+
+# Specify the cell data
+CELLS	METADATA
+	amp1		METADATA
+		CELL.NAME	STR	left
+		CELL.BIASSEC	STR	VALUE:[1:51,1:4096];[4301:4380,1:4096]
+		CELL.TRIMSEC	STR	VALUE:[205:1228,1:4096]
+		CELL.GAIN	STR	VALUE:1.2
+		CELL.READNOISE	STR	VALUE:5.6
+	END
+
+	amp2	METADATA
+		CELL.NAME	STR	right
+		CELL.BIASSEC	STR	VALUE:[52:102,1:4096];[4381:4460,1:4096]
+		CELL.TRIMSEC	STR	VALUE:[1229:2252,1:4096]
+		CELL.GAIN	STR	VALUE:1.3
+		CELL.READNOISE	STR	VALUE:6.7
+	END
+
+	amp3		METADATA
+		CELL.NAME	STR	left
+		CELL.BIASSEC	STR	VALUE:[103:153,1:4096];[4461:4540,1:4096]
+		CELL.TRIMSEC	STR	VALUE:[2253:3276,1:4096]
+		CELL.GAIN	STR	VALUE:1.4
+		CELL.READNOISE	STR	VALUE:7.8
+	END
+
+	amp4	METADATA
+		CELL.NAME	STR	right
+		CELL.BIASSEC	STR	VALUE:[154:204,1:4096];[4541:4620,1:4096]
+		CELL.TRIMSEC	STR	VALUE:[3277:4300,1:4096]
+		CELL.GAIN	STR	VALUE:1.5
+		CELL.READNOISE	STR	VALUE:8.9
+	END
+END
+
+# How to translate PS concepts into FITS headers
+TRANSLATION	METADATA
+	FPA.AIRMASS	STR	AIRMASS
+	FPA.FILTER	STR	BLUFILT
+	FPA.POSANGLE	STR	ROTPOSN
+	FPA.RA		STR	RA
+	FPA.DEC		STR	DEC
+	CELL.EXPOSURE	STR	EXPOSURE
+	CELL.DARKTIME	STR	EXPOSURE	// No special darktime header; use exposure time
+	CELL.DATE	STR	DATE		// NOTE: There are TWO keywords called "DATE" (creation, exp)!
+	CELL.TIME	STR	UT
+END
+
+# Default PS concepts that may be specified by value
+DEFAULTS	METADATA
+	FPA.RADECSYS	STR	ICRS
+END
+
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/test/lris_red.config
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/test/lris_red.config	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/test/lris_red.config	(revision 22348)
@@ -0,0 +1,14 @@
+# Camera configuration file for LRIS-Red: describes the camera
+
+# File formats that we know about
+FORMATS         METADATA
+        RAW     STR     lris_red_raw.config
+END
+ 
+ 
+# Description of camera --- all the chips and the cells that comprise them
+FPA     METADATA
+        RedChip		STR	LeftSide RightSide
+END
+
+
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/test/lris_red_raw.config
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/test/lris_red_raw.config	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/test/lris_red_raw.config	(revision 22348)
@@ -0,0 +1,82 @@
+# The Low Resolution Imager and Spectrograph (LRIS) red side
+
+# We have no choice but to hard-code the various regions, because Keck
+# only stores them as:
+# WINDOW  = '0,0,0,2048,2048'
+# PREPIX  =                   20
+# POSTPIX =                   80
+# BINNING = '1,1     '
+# AMPPSIZE= '[1:1024,1:4096]'
+
+# I don't know how we would get the IPP to react to changes in the
+# windowing on the fly --- we have no mechanism for setting the region
+# sizes on the basis of the above keywords.  Therefore, we hard-code
+# the regions and assert on our assumptions in the RULE.
+
+
+# How to identify this type
+RULE	METADATA
+	TELESCOP	STR	Keck I
+	INSTRUME	STR	LRIS
+	AMPLIST		STR	2,1,0,0
+	WINDOW		STR	0,0,0,2048,2048
+	PREPIX		S32	20
+	POSTPIX		S32	80
+	BINNING		STR	1, 1
+	CCDPSIZE	STR	[1:2048,1:2048]
+	NAXIS1		S32	2248
+	NAXIS2		S32	2048
+	IMTYPE		STR	TWOAMPTOP
+END
+
+# How to read this data
+FORMAT	METADATA
+	PHU		STR	CHIP	# The FITS file represents a single chip
+	EXTENSIONS	STR	NONE	# There are no extensions
+	FPA.NAME	STR	OBSNUM	# A PHU keyword for unique identifier within the hierarchy level
+	CHIP.NAME	STR	INSTRUME	# An extension keyword for unique identifier
+END
+
+# What's in the FITS file?
+CONTENTS	METADATA
+	# chip identifier, chip name: component cells
+	LRIS		STR	RedChip:left RedChip:right
+END
+
+# Specify the cell data
+CELLS	METADATA
+	left	METADATA
+		CELL.NAME	STR	LeftSide
+		CELL.BIASSEC	STR	VALUE:[1:20,1:2048];[2089:2168,1:2048]
+		CELL.TRIMSEC	STR	VALUE:[41:1064,1:2048]
+		CELL.GAIN	STR	VALUE:1.2
+		CELL.READNOISE	STR	VALUE:5.6
+	END
+
+	right	METADATA
+		CELL.NAME	STR	RightSide
+		CELL.BIASSEC	STR	VALUE:[21:40,1:2048];[2169:2248,1:2048]
+		CELL.TRIMSEC	STR	VALUE:[1065:2088,1:2048]
+		CELL.GAIN	STR	VALUE:1.3
+		CELL.READNOISE	STR	VALUE:6.5
+	END
+END
+
+# How to translate PS concepts into FITS headers
+TRANSLATION	METADATA
+	FPA.AIRMASS	STR	AIRMASS
+	FPA.FILTER	STR	FILTER
+	FPA.POSANGLE	STR	POSANG
+	FPA.RA		STR	OBJ-RA
+	FPA.DEC		STR	OBJ-DEC
+	CELL.EXPOSURE	STR	EXPTIME
+	CELL.DARKTIME	STR	DARKTIME
+	CELL.DATE	STR	DATE-OBS
+	CELL.TIME	STR	TIME-OBS
+END
+
+# Default PS concepts that may be specified by value
+DEFAULTS	METADATA
+	FPA.RADECSYS	STR	ICRS
+END
+
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/test/megacam.config
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/test/megacam.config	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/test/megacam.config	(revision 22348)
@@ -0,0 +1,56 @@
+# Camera configuration file for MegaCam: describes the camera
+
+# File formats that we know about
+FORMATS		METADATA
+	RAW	STR	megacam_raw.config
+	SPLICE	STR	megacam_splice.config
+	SPLIT	STR	megacam_split.config
+END
+
+
+# Description of camera --- all the chips and the cells that comprise them
+FPA	METADATA
+	ccd00	STR	left right
+	ccd01	STR	left right
+	ccd02	STR	left right
+	ccd03	STR	left right
+	ccd04	STR	left right
+	ccd05	STR	left right
+	ccd06	STR	left right
+	ccd07	STR	left right
+	ccd08	STR	left right
+	ccd09	STR	left right
+	ccd10	STR	left right
+	ccd11	STR	left right
+	ccd12	STR	left right
+	ccd13	STR	left right
+	ccd14	STR	left right
+	ccd15	STR	left right
+	ccd16	STR	left right
+	ccd17	STR	left right
+	ccd18	STR	left right
+	ccd19	STR	left right
+	ccd20	STR	left right
+	ccd21	STR	left right
+	ccd22	STR	left right
+	ccd23	STR	left right
+	ccd24	STR	left right
+	ccd25	STR	left right
+	ccd26	STR	left right
+	ccd27	STR	left right
+	ccd28	STR	left right
+	ccd29	STR	left right
+	ccd30	STR	left right
+	ccd31	STR	left right
+	ccd32	STR	left right
+	ccd33	STR	left right
+	ccd34	STR	left right
+	ccd35	STR	left right
+END
+
+
+# Recipe options
+RECIPES		METADATA
+	PHASE2		STR	phase2.config		# Phase 2 recipe details
+#	PSPHOT		STR	psphot.config		# psphot details
+END
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/test/megacam_raw.config
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/test/megacam_raw.config	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/test/megacam_raw.config	(revision 22348)
@@ -0,0 +1,183 @@
+# The raw MegaCam data comes off the telescope with each of the chips stored in extensions of a MEF file.
+
+# How to identify this type
+RULE	METADATA
+	TELESCOP	STR	CFHT 3.6m
+	DETECTOR	STR	MegaCam
+	EXTEND		BOOL	T
+	NEXTEND		S32	72
+END
+
+# How to read this data
+FORMAT	METADATA
+	PHU		STR	FPA	# The FITS file represents an entire FPA
+	EXTENSIONS	STR	CELL	# The extensions represent cells
+	FPA.NAME	STR	EXPNUM	# A PHU keyword for unique identifier within the hierarchy level
+END
+
+# What's in the FITS file?
+CONTENTS	METADATA
+	# Extension name, chip name:type
+	amp00		STR	ccd00:left
+	amp01		STR	ccd00:right
+	amp02		STR	ccd01:left
+	amp03		STR	ccd01:right
+	amp04		STR	ccd02:left
+	amp05		STR	ccd02:right
+	amp06		STR	ccd03:left
+	amp07		STR	ccd03:right
+	amp08		STR	ccd04:left
+	amp09		STR	ccd04:right
+	amp10		STR	ccd05:left
+	amp11		STR	ccd05:right
+	amp12		STR	ccd06:left
+	amp13		STR	ccd06:right
+	amp14		STR	ccd07:left
+	amp15		STR	ccd07:right
+	amp16		STR	ccd08:left
+	amp17		STR	ccd08:right
+	amp18		STR	ccd09:left
+	amp19		STR	ccd09:right
+	amp20		STR	ccd10:left
+	amp21		STR	ccd10:right
+	amp22		STR	ccd11:left
+	amp23		STR	ccd11:right
+	amp24		STR	ccd12:left
+	amp25		STR	ccd12:right
+	amp26		STR	ccd13:left
+	amp27		STR	ccd13:right
+	amp28		STR	ccd14:left
+	amp29		STR	ccd14:right
+	amp30		STR	ccd15:left
+	amp31		STR	ccd15:right
+	amp32		STR	ccd16:left
+	amp33		STR	ccd16:right
+	amp34		STR	ccd17:left
+	amp35		STR	ccd17:right
+	amp36		STR	ccd18:left
+	amp37		STR	ccd18:right
+	amp38		STR	ccd19:left
+	amp39		STR	ccd19:right
+	amp40		STR	ccd20:left
+	amp41		STR	ccd20:right
+	amp42		STR	ccd21:left
+	amp43		STR	ccd21:right
+	amp44		STR	ccd22:left
+	amp45		STR	ccd22:right
+	amp46		STR	ccd23:left
+	amp47		STR	ccd23:right
+	amp48		STR	ccd24:left
+	amp49		STR	ccd24:right
+	amp50		STR	ccd25:left
+	amp51		STR	ccd25:right
+	amp52		STR	ccd26:left
+	amp53		STR	ccd26:right
+	amp54		STR	ccd27:left
+	amp55		STR	ccd27:right
+	amp56		STR	ccd28:left
+	amp57		STR	ccd28:right
+	amp58		STR	ccd29:left
+	amp59		STR	ccd29:right
+	amp60		STR	ccd30:left
+	amp61		STR	ccd30:right
+	amp62		STR	ccd31:left
+	amp63		STR	ccd31:right
+	amp64		STR	ccd32:left
+	amp65		STR	ccd32:right
+	amp66		STR	ccd33:left
+	amp67		STR	ccd33:right
+	amp68		STR	ccd34:left
+	amp69		STR	ccd34:right
+	amp70		STR	ccd35:left
+	amp71		STR	ccd35:right
+END
+
+# Specify the cell data
+CELLS	METADATA
+	left	METADATA	# Left amplifier
+		CELL.NAME		STR	LeftSide
+		CELL.BIASSEC.SOURCE	STR	HEADER
+		CELL.TRIMSEC.SOURCE	STR	HEADER
+		CELL.BIASSEC		STR	BIASSEC
+		CELL.TRIMSEC		STR	DATASEC
+		CELL.XPARITY		S32	1 # We could have specified this as a DEFAULT, but this works
+		CELL.X0			S32	1
+		CELL.Y0			S32	1
+	END
+	right	METADATA	# Right amplifier
+		CELL.NAME		STR	RightSide
+		CELL.BIASSEC.SOURCE	STR	HEADER
+		CELL.TRIMSEC.SOURCE	STR	HEADER
+		CELL.BIASSEC		STR	BIASSEC
+		CELL.TRIMSEC		STR	DATASEC
+		CELL.XPARITY		S32	-1 # This cell is read out in the opposite direction
+		CELL.X0			S32	2048
+		CELL.Y0			S32	1
+	END
+END
+
+# How to translate PS concepts into FITS headers
+TRANSLATION	METADATA
+	FPA.NAME		STR	EXPNUM
+	FPA.AIRMASS		STR	AIRMASS
+	FPA.FILTER		STR	FILTER
+	FPA.POSANGLE		STR	ROTANGLE
+	FPA.RA			STR	RA
+	FPA.DEC			STR	DEC
+	FPA.RADECSYS		STR	RADECSYS
+	CELL.EXPOSURE		STR	EXPTIME
+	CELL.DARKTIME		STR	DARKTIME
+	CELL.GAIN		STR	GAIN
+	CELL.READNOISE		STR	RDNOISE
+	CELL.SATURATION		STR	SATURATE
+	CELL.TIME		STR	MJD-OBS
+	CELL.XBIN		STR	CCDBIN1
+	CELL.YBIN		STR	CCDBIN2
+END
+
+# Default PS concepts that may be specified by value
+DEFAULTS	METADATA
+	CELL.READDIR		S32	1		# Cell is read in x direction
+	CELL.BAD		S32	0
+	CELL.TIMESYS		STR	UTC
+	CELL.YPARITY		S32	1
+END
+
+# How to translation PS concepts into database lookups
+DATABASE	METADATA
+	TYPE		dbEntry		TABLE		COLUMN		GIVENDBCOL	GIVENPS
+#	FPA.BIAS	METADATA
+#		TABLE	STR	Camera
+#		COLUMN	STR	gain
+#		chipId	STR	{CHIP.NAME}
+#		cellId	STR	{CELL.NAME}
+#		time	STR	{CELL.TIME}
+#	END
+#	CELL.GAIN	dbEntry		Camera		gain		chipId,cellId	CHIP.NAME,CELL.NAME
+#	CELL.READNOISE	dbEntry		Camera		readNoise	chipId,cellId	CHIP.NAME,CELL.NAME
+
+# A database entry refers to a particular column (COLUMN) in a
+# particular table (TABLE), given certain PS concepts (GIVENPS) that
+# match certain database columns (GIVENDBCOL).
+END
+
+
+# Where there might be some ambiguity, specify the format
+FORMATS		METADATA
+	FPA.RA		STR	HOURS
+	FPA.DEC		STR	DEGREES
+	CELL.TIME	STR	MJD
+#	CELL.BINNING	STR	SEPARATE
+	CELL.X0		STR	FORTRAN
+	CELL.Y0		STR	FORTRAN
+END
+
+
+
+# How to get the supplementary stuff: mask and weight
+SUPPLEMENTARY	METADATA
+	MASK.SOURCE	STR	FILE		# Source type for mask: EXT | FILE
+	MASK.NAME	STR	%a_mask.fits	# Name for mask extension or filename
+	WEIGHT.SOURCE	STR	FILE		# Source type for weight: EXT | FILE
+	WEIGHT.NAME	STR	%a_weight.fits	# Name for weight extension or filename
+END
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/test/megacam_splice.config
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/test/megacam_splice.config	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/test/megacam_splice.config	(revision 22348)
@@ -0,0 +1,143 @@
+# The spliced MecaCam data is stored in single extensions for each chip
+
+# How to recognise this type
+RULE	METADATA
+	TELESCOP	STR	CFHT 3.6m
+	DETECTOR	STR	MegaCam
+	EXTEND		BOOL	T
+	NEXTEND		S32	36
+END
+
+FORMAT	METADATA
+	# How to read this data
+	PHU		STR	FPA	# The FITS file represents an entire FPA
+	EXTENSIONS	STR	CHIP	# The extensions represent chips
+	FPA.NAME	STR	EXPNUM	# A PHU keyword for unique identifier
+	CHIP.NAME	STR	EXTNAME	# An extension keyword for unique identifie
+END
+
+# What's in the FITS file?
+CONTENTS	METADATA
+	# Extension name, chip name:component cell
+	ccd00		STR	ccd00:left ccd00:right
+	ccd01		STR	ccd01:left ccd01:right
+	ccd02		STR	ccd02:left ccd02:right
+	ccd03		STR	ccd03:left ccd03:right
+	ccd04		STR	ccd04:left ccd04:right
+	ccd05		STR	ccd05:left ccd05:right
+	ccd06		STR	ccd06:left ccd06:right
+	ccd07		STR	ccd07:left ccd07:right
+	ccd08		STR	ccd08:left ccd08:right
+	ccd09		STR	ccd09:left ccd09:right
+	ccd10		STR	ccd10:left ccd10:right
+	ccd11		STR	ccd11:left ccd11:right
+	ccd12		STR	ccd12:left ccd12:right
+	ccd13		STR	ccd13:left ccd13:right
+	ccd14		STR	ccd14:left ccd14:right
+	ccd15		STR	ccd15:left ccd15:right
+	ccd16		STR	ccd16:left ccd16:right
+	ccd17		STR	ccd17:left ccd17:right
+	ccd18		STR	ccd18:left ccd18:right
+	ccd19		STR	ccd19:left ccd19:right
+	ccd20		STR	ccd20:left ccd20:right
+	ccd21		STR	ccd21:left ccd21:right
+	ccd22		STR	ccd22:left ccd22:right
+	ccd23		STR	ccd23:left ccd23:right
+	ccd24		STR	ccd24:left ccd24:right
+	ccd25		STR	ccd25:left ccd25:right
+	ccd26		STR	ccd26:left ccd26:right
+	ccd27		STR	ccd27:left ccd27:right
+	ccd28		STR	ccd28:left ccd28:right
+	ccd29		STR	ccd29:left ccd29:right
+	ccd30		STR	ccd30:left ccd30:right
+	ccd31		STR	ccd31:left ccd31:right
+	ccd32		STR	ccd32:left ccd32:right
+	ccd33		STR	ccd33:left ccd33:right
+	ccd34		STR	ccd34:left ccd34:right
+	ccd35		STR	ccd35:left ccd35:right
+END
+
+# Specify the cells
+CELLS		METADATA
+	left		METADATA
+		CELL.NAME		STR	LeftSide
+		CELL.BIASSEC.SOURCE	STR	HEADER
+		CELL.TRIMSEC.SOURCE	STR	HEADER
+		CELL.BIASSEC		STR	BSECA
+		CELL.TRIMSEC		STR	TSECA
+		CELL.X0			S32	0
+	END
+
+	right		METADATA
+		CELL.NAME		STR	RightSide
+		CELL.BIASSEC.SOURCE	STR	HEADER
+		CELL.TRIMSEC.SOURCE	STR	HEADER
+		CELL.BIASSEC		STR	BSECB
+		CELL.TRIMSEC		STR	TSECB
+		CELL.X0			S32	1024
+	END
+END
+
+# How to translate PS concepts into FITS headers
+TRANSLATION	METADATA
+        FPA.NAME        STR     EXPNUM
+        FPA.AIRMASS     STR     AIRMASS
+        FPA.FILTER      STR     FILTER
+        FPA.POSANGLE    STR     ROTANGLE
+        FPA.RA          STR     RA
+        FPA.DEC         STR     DEC
+        FPA.RADECSYS    STR     RADECSYS
+        CELL.EXPOSURE   STR     EXPTIME
+        CELL.DARKTIME   STR     DARKTIME
+        CELL.GAIN       STR     GAIN
+        CELL.READNOISE  STR     RDNOISE
+        CELL.SATURATION STR     SATURATE
+	CELL.TIME	STR	MJD-OBS
+        CELL.XBIN       STR     CCDBIN1
+        CELL.YBIN       STR     CCDBIN2
+END
+
+# Default PS concepts that may be specified by value
+DEFAULTS        METADATA
+	CELL.READDIR		S32	1		# Cell is read in x direction
+        CELL.BAD                S32     0
+	CELL.TIMESYS		STR	UTC
+	CELL.XPARITY		S32	1
+	CELL.YPARITY		S32	1
+	CELL.Y0			S32	0
+END
+
+
+# How to translation PS concepts into database lookups
+DATABASE	METADATA
+	TYPE		dbEntry		TABLE		COLUMN		GIVENDBCOL	GIVENPS
+#	CELL.GAIN	dbEntry		Camera		gain		chipId,cellId	CHIP.NAME,CELL.NAME
+#	CELL.READNOISE	dbEntry		Camera		readNoise	chipId,cellId	CHIP.NAME,CELL.NAME
+
+# A database entry refers to a particular column (COLUMN) in a
+# particular table (TABLE), given certain PS concepts (GIVENPS) that
+# match certain database columns (GIVENDBCOL).
+END		
+
+
+# Where there might be some ambiguity, specify the format
+FORMATS		METADATA
+	FPA.RA		STR	HOURS
+	FPA.DEC		STR	DEGREES
+	CELL.TIME	STR	MJD
+END
+ 
+# Recipe options
+RECIPES		METADATA
+	PHASE2		STR	phase2.config		# Phase 2 recipe details
+END
+ 
+
+# How to get the supplementary stuff: mask and weight
+SUPPLEMENTARY	METADATA
+	MASK.SOURCE	STR	FILE		# Source type for mask: EXT | FILE
+	MASK.NAME	STR	%a_mask.fits	# Name for mask extension or filename
+	WEIGHT.SOURCE	STR	FILE		# Source type for weight: EXT | FILE
+	WEIGHT.NAME	STR	%a_weight.fits	# Name for weight extension or filename
+END
+
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/test/megacam_split.config
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/test/megacam_split.config	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/test/megacam_split.config	(revision 22348)
@@ -0,0 +1,141 @@
+# The split MecaCam data is stored in single file for each chip
+
+# How to recognise this type
+RULE	METADATA
+	TELESCOP	STR	CFHT 3.6m
+	DETECTOR	STR	MegaCam
+END
+
+# How to read this dataF
+FORMAT	METADATA
+	PHU		STR	CHIP	# The FITS file represents an entire FPA
+	EXTENSIONS	STR	NONE	# The extensions represent chips
+	FPA.NAME	STR	EXPNUM	# A PHU keyword for unique identifier within the hierarchy level
+	CHIP.NAME	STR	EXTNAME	# An extension keyword for unique identifier
+END
+
+# What's in the FITS file?
+CONTENTS	METADATA
+	# Chip name, components
+	ccd00		STR	ccd00:left ccd00:right
+	ccd01		STR	ccd01:left ccd01:right
+	ccd02		STR	ccd02:left ccd02:right
+	ccd03		STR	ccd03:left ccd03:right
+	ccd04		STR	ccd04:left ccd04:right
+	ccd05		STR	ccd05:left ccd05:right
+	ccd06		STR	ccd06:left ccd06:right
+	ccd07		STR	ccd07:left ccd07:right
+	ccd08		STR	ccd08:left ccd08:right
+	ccd09		STR	ccd09:left ccd09:right
+	ccd10		STR	ccd10:left ccd10:right
+	ccd11		STR	ccd11:left ccd11:right
+	ccd12		STR	ccd12:left ccd12:right
+	ccd13		STR	ccd13:left ccd13:right
+	ccd14		STR	ccd14:left ccd14:right
+	ccd15		STR	ccd15:left ccd15:right
+	ccd16		STR	ccd16:left ccd16:right
+	ccd17		STR	ccd17:left ccd17:right
+	ccd18		STR	ccd18:left ccd18:right
+	ccd19		STR	ccd19:left ccd19:right
+	ccd20		STR	ccd20:left ccd20:right
+	ccd21		STR	ccd21:left ccd21:right
+	ccd22		STR	ccd22:left ccd22:right
+	ccd23		STR	ccd23:left ccd23:right
+	ccd24		STR	ccd24:left ccd24:right
+	ccd25		STR	ccd25:left ccd25:right
+	ccd26		STR	ccd26:left ccd26:right
+	ccd27		STR	ccd27:left ccd27:right
+	ccd28		STR	ccd28:left ccd28:right
+	ccd29		STR	ccd29:left ccd29:right
+	ccd30		STR	ccd30:left ccd30:right
+	ccd31		STR	ccd31:left ccd31:right
+	ccd32		STR	ccd32:left ccd32:right
+	ccd33		STR	ccd33:left ccd33:right
+	ccd34		STR	ccd34:left ccd34:right
+	ccd35		STR	ccd35:left ccd35:right
+END
+
+# Specify the cells
+CELLS		METADATA
+	left		METADATA
+		CELL.NAME		STR	LeftSide
+		CELL.BIASSEC.SOURCE	STR	HEADER
+		CELL.TRIMSEC.SOURCE	STR	HEADER
+		CELL.BIASSEC		STR	BSECA
+		CELL.TRIMSEC		STR	TSECA
+		CELL.X0			S32	0
+	END
+
+	right		METADATA
+		CELL.NAME		STR	RightSide
+		CELL.BIASSEC.SOURCE	STR	HEADER
+		CELL.TRIMSEC.SOURCE	STR	HEADER
+		CELL.BIASSEC		STR	BSECB
+		CELL.TRIMSEC		STR	TSECB
+		CELL.X0			S32	1024
+	END
+END
+
+# How to translate PS concepts into FITS headers
+TRANSLATION	METADATA
+        FPA.NAME        STR     EXPNUM
+        FPA.AIRMASS     STR     AIRMASS
+        FPA.FILTER      STR     FILTER
+        FPA.POSANGLE    STR     ROTANGLE
+        FPA.RA          STR     RA
+        FPA.DEC         STR     DEC
+        FPA.RADECSYS    STR     RADECSYS
+        CELL.EXPOSURE   STR     EXPTIME
+        CELL.DARKTIME   STR     DARKTIME
+        CELL.GAIN       STR     GAIN
+        CELL.READNOISE  STR     RDNOISE
+        CELL.SATURATION STR     SATURATE
+	CELL.TIME	STR	MJD-OBS
+        CELL.XBIN       STR     CCDBIN1
+        CELL.YBIN       STR     CCDBIN2
+END
+
+# Default PS concepts that may be specified by value
+DEFAULTS        METADATA
+	CELL.READDIR		S32	1		# Cell is read in x direction
+        CELL.BAD                S32     0
+	CELL.TIMESYS		STR	UTC
+	CELL.XPARITY		S32	1
+	CELL.YPARITY		S32	1
+	CELL.Y0			S32	0
+END
+
+
+# How to translation PS concepts into database lookups
+DATABASE	METADATA
+	TYPE		dbEntry		TABLE		COLUMN		GIVENDBCOL	GIVENPS
+#	CELL.GAIN	dbEntry		Camera		gain		chipId,cellId	CHIP.NAME,CELL.NAME
+#	CELL.READNOISE	dbEntry		Camera		readNoise	chipId,cellId	CHIP.NAME,CELL.NAME
+
+# A database entry refers to a particular column (COLUMN) in a
+# particular table (TABLE), given certain PS concepts (GIVENPS) that
+# match certain database columns (GIVENDBCOL).
+END		
+
+
+# Where there might be some ambiguity, specify the format
+FORMATS		METADATA
+	FPA.RA		STR	HOURS
+	FPA.DEC		STR	DEGREES
+	CELL.TIME	STR	MJD
+END
+ 
+# Recipe options
+RECIPES		METADATA
+	PHASE2		STR	phase2.config		# Phase 2 recipe details
+END
+ 
+
+# How to get the supplementary stuff: mask and weight
+SUPPLEMENTARY	METADATA
+	MASK.SOURCE	STR	FILE		# Source type for mask: EXT | FILE
+	MASK.NAME	STR	%a_mask.fits	# Name for mask extension or filename
+	WEIGHT.SOURCE	STR	FILE		# Source type for weight: EXT | FILE
+	WEIGHT.NAME	STR	%a_weight.fits	# Name for weight extension or filename
+END
+
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/test/nonlin.dat
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/test/nonlin.dat	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/test/nonlin.dat	(revision 22348)
@@ -0,0 +1,106 @@
+# Non-linearity correction lookup table
+# Col 1: Input value
+# Col 2: Corrected value
+0	0
+100	1
+200	2
+300	3
+400	4
+500	5
+600	6
+700	7
+800	8
+900	9
+1000	10
+1100	11
+1200	12
+1300	13
+1400	14
+1500	15
+1600	16
+1700	17
+1800	18
+1900	19
+2000	20
+2100	21
+2200	22
+2300	23
+2400	24
+2500	25
+2600	26
+2700	27
+2800	28
+2900	29
+3000	30
+3100	31
+3200	32
+3300	33
+3400	34
+3500	35
+3600	36
+3700	37
+3800	38
+3900	39
+4000	40
+4100	41
+4200	42
+4300	43
+4400	44
+4500	45
+4600	46
+4700	47
+4800	48
+4900	49
+5000	50
+5100	51
+5200	52
+5300	53
+5400	54
+5500	55
+5600	56
+5700	57
+5800	58
+5900	59
+6000	60
+6100	61
+6200	62
+6300	63
+6400	64
+6500	65
+6600	66
+6700	67
+6800	68
+6900	69
+7000	70
+7100	71
+7200	72
+7300	73
+7400	74
+7500	75
+7600	76
+7700	77
+7800	78
+7900	79
+8000	80
+8100	81
+8200	82
+8300	83
+8400	84
+8500	85
+8600	86
+8700	87
+8800	88
+8900	89
+9000	90
+9100	91
+9200	92
+9300	93
+9400	94
+9500	95
+9600	96
+9700	97
+9800	98
+9900	99
+10000	100
+10001	100
+1e6	100
Index: /tags/ipp-1-X/ppimage_dev_01/ppImage/test/phase2.config
===================================================================
--- /tags/ipp-1-X/ppimage_dev_01/ppImage/test/phase2.config	(revision 22348)
+++ /tags/ipp-1-X/ppimage_dev_01/ppImage/test/phase2.config	(revision 22348)
@@ -0,0 +1,69 @@
+### Phase 2 recipe configuration file
+
+# List of tasks to perform
+MASK		BOOL	FALSE		# Mask bad pixels
+NONLIN		BOOL	FALSE		# Non-linearity correction
+OVERSCAN	BOOL	TRUE		# Overscan subtraction
+BIAS		BOOL	FALSE		# Bias subtraction
+DARK		BOOL	FALSE		# Dark subtraction
+FLAT		BOOL	FALSE		# Flat-field normalisation
+FRINGE		BOOL	FALSE		# Fringe subtraction
+SOURCE		BOOL	FALSE		# Source identification and photometry
+ASTROM		BOOL	FALSE		# Astrometry
+
+
+# Loading issues
+LOAD.DEPTH		STR	CHIP		# Depth at which to load pixels
+
+
+# Non-linearity correction
+NONLIN.SOURCE		STR	CHIP.NAME	# How to determine the source
+#@NONLIN.DATA		F32	0.0 1.001 0.001	# A polynomial
+NONLIN.DATA		STR	nonlin.dat	# Filename for lookup table
+#NONLIN.DATA		METADATA		# Source of non-linearity data
+#	ccd00		STR	nonlin00.dat	# A lookup table 
+#	@ccd01		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd02		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd03		F32	1.2345 		# A polynomial
+#	@ccd04		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd05		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd06		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd07		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd08		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd09		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd10		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd11		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd12		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd13		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd14		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd15		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd16		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd17		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd18		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd19		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd10		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd21		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd22		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd23		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd24		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd25		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd26		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd27		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd28		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd29		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd30		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd31		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd32		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd33		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd34		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd35		F32	0.0 1.001 0.001	# A polynomial
+#	@ccd36		F32	0.0 1.001 0.001	# A polynomial
+#END
+
+# Overscan subtraction
+OVERSCAN.SINGLE		BOOL	FALSE		# Reduce overscan to a single value?
+#OVERSCAN.FIT		STR	SPLINE		# NONE | POLYNOMIAL | SPLINE
+OVERSCAN.FIT		STR	POLYNOMIAL	# NONE | POLYNOMIAL | SPLINE
+OVERSCAN.ORDER		S32	5		# Order of polynomial fit
+OVERSCAN.STAT		STR	MEAN		# MEAN | MEDIAN
+
