Index: trunk/ippToPsps/perl/ippToPsps/Batch.pm
===================================================================
--- trunk/ippToPsps/perl/ippToPsps/Batch.pm	(revision 30146)
+++ trunk/ippToPsps/perl/ippToPsps/Batch.pm	(revision 30147)
@@ -126,8 +126,4 @@
     $self->{_surveyType} = $self->getSurveyTypeFromDistGroup();
 
-    # can we run ippToPsps?
-    $self->{_ippToPsps} = can_run('ippToPsps') or
-        (warn "Can't find 'ippToPsps' program" and exit($PS_EXIT_CONFIG_ERROR));
-
     # set up batch output paths
     $self->init();
@@ -139,4 +135,17 @@
 
     return $self;
+}
+
+########################################################################################
+# 
+# Sets to program and checks we can run it
+# 
+########################################################################################
+sub setProgram {
+    my ($self, $program) = @_;
+
+    # can we run ippToPsps?
+    $self->{program} = can_run($program) or
+        (warn "Can't find '$program' program" and exit($PS_EXIT_CONFIG_ERROR));
 }
 
@@ -197,21 +206,6 @@
     my ($self, $input, $resultsFilePath) = @_;
 
-    # build command
-    my $command = "$self->{_ippToPsps}";
-    $command .= " -input $input";
-    $command .= " -output $self->{_batchDir}";
-    if (defined $self->{_dvoPath} ) {$command .= " -D CATDIR $self->{_dvoPath}";}
-    $command .= " -config ../config"; # TODO
-        $command .= " -id $self->{_expId}";
-    $command .= " -expname $self->{_expName}";
-    $command .= " -survey $self->{_surveyType}";
-    $command .= " -batch $self->{_type}";
-    $command .= " -results $resultsFilePath";
-
-    # run command
-    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf )
-        = run(command => $command, verbose => $self->{_verbose});
-
-    return $success;
+    my $thisFunction = (caller(0))[3];
+    print "* ERROR: '$thisFunction' not implemented\n";
 }
 
Index: trunk/ippToPsps/perl/ippToPsps/DetectionBatch.pm
===================================================================
--- trunk/ippToPsps/perl/ippToPsps/DetectionBatch.pm	(revision 30146)
+++ trunk/ippToPsps/perl/ippToPsps/DetectionBatch.pm	(revision 30147)
@@ -8,4 +8,5 @@
 use File::Temp qw(tempfile);
 use XML::LibXML;
+use IPC::Cmd 0.36 qw( can_run run );
 
 use ippToPsps::Batch;
@@ -63,4 +64,6 @@
             );
 
+    $self->setProgram("detectionbatch");
+
     bless $self, $class;
     $self->process();
@@ -105,4 +108,31 @@
 #######################################################################################
 #
+# runs the ippToPsps program
+#
+#######################################################################################
+sub runProgram {
+    my ($self, $input, $resultsFilePath) = @_;
+
+    # build command
+    my $command = "$self->{program}";
+    $command .= " -input $input";
+    $command .= " -output $self->{_batchDir}";
+    if (defined $self->{_dvoPath} ) {$command .= " -D CATDIR $self->{_dvoPath}";}
+    $command .= " -config ../config"; # TODO
+    $command .= " -survey $self->{_surveyType}";
+    $command .= " -results $resultsFilePath";
+    $command .= " -expid $self->{_expId}";
+    $command .= " -expname $self->{_expName}";
+
+    # run command
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf )
+        = run(command => $command, verbose => $self->{_verbose});
+
+    return $success;
+}
+
+
+#######################################################################################
+#
 # - Reads results from processing (min/max obj ID etc)
 # - writes to Db
Index: trunk/ippToPsps/perl/ippToPsps/InitBatch.pm
===================================================================
--- trunk/ippToPsps/perl/ippToPsps/InitBatch.pm	(revision 30146)
+++ trunk/ippToPsps/perl/ippToPsps/InitBatch.pm	(revision 30147)
@@ -8,4 +8,5 @@
 use File::Temp qw(tempfile);
 use XML::LibXML;
+use IPC::Cmd 0.36 qw( can_run run );
 
 use ippToPsps::Batch;
@@ -37,4 +38,6 @@
             $_[7]);    # save_temps
 
+    $self->setProgram("initbatch");
+
     bless $self, $class;
     $self->process();
@@ -52,4 +55,26 @@
     return "NULL";
 }
+
+#######################################################################################
+#
+# runs the ippToPsps program
+#
+#######################################################################################
+sub runProgram {
+    my ($self, $input, $resultsFilePath) = @_;
+
+    # build command
+    my $command = "$self->{program}";
+    $command .= " -output $self->{_batchDir}";
+    $command .= " -config ../config"; # TODO
+    $command .= " -results $resultsFilePath";
+
+    # run command
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf )
+        = run(command => $command, verbose => $self->{_verbose});
+
+    return $success;
+}
+
 
 #######################################################################################
Index: trunk/ippToPsps/perl/ippToPsps/StackBatch.pm
===================================================================
--- trunk/ippToPsps/perl/ippToPsps/StackBatch.pm	(revision 30146)
+++ trunk/ippToPsps/perl/ippToPsps/StackBatch.pm	(revision 30147)
@@ -8,4 +8,5 @@
 use File::Temp qw(tempfile);
 use XML::LibXML;
+use IPC::Cmd 0.36 qw( can_run run );
 
 use ippToPsps::Batch;
@@ -62,5 +63,6 @@
             $_[11]  # save_temps
             );
-
+    
+    $self->setProgram("stackbatch");
 
     $self->{_skyId} = $_[1]; 
@@ -78,4 +80,9 @@
 sub createInputFileList {
     my ($self, $inputFile) = @_;
+
+  # TODO hardcode demo file for now
+        print $inputFile "/data/ippc18.0/home/rhenders/psphotstack.v3.001.cmf\n";
+            return 1;
+
 
     my ($nebPath, $numInputs);
@@ -98,4 +105,30 @@
     return 1;
 }
+
+#######################################################################################
+#
+# runs the ippToPsps program
+#
+#######################################################################################
+sub runProgram {
+    my ($self, $input, $resultsFilePath) = @_;
+
+    # build command
+    my $command = "$self->{program}";
+    $command .= " -input $input";
+    $command .= " -output $self->{_batchDir}";
+    if (defined $self->{_dvoPath} ) {$command .= " -D CATDIR $self->{_dvoPath}";}
+    $command .= " -config ../config"; # TODO
+    $command .= " -survey $self->{_surveyType}";
+    $command .= " -results $resultsFilePath";
+    $command .= " -skycellid $self->{_expId}";
+
+    # run command
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf )
+        = run(command => $command, verbose => $self->{_verbose});
+
+    return $success;
+}
+
 
 #######################################################################################
Index: trunk/ippToPsps/perl/pspsSchema2xml.pl
===================================================================
--- trunk/ippToPsps/perl/pspsSchema2xml.pl	(revision 30146)
+++ trunk/ippToPsps/perl/pspsSchema2xml.pl	(revision 30147)
@@ -30,6 +30,6 @@
 pod2usage(
         -msg => "\n   Required options:\n\n".
-        "--schema <path to PSPS schema>\n".
-        "--type <init|det|diff|stack|object>\n".
+        "-s   <path to PSPS schema>\n".
+        "-t   <init|detection|diff|stack|object>\n".
         -exitval => 3
         ) unless
@@ -37,5 +37,10 @@
 defined $type;
 
-if ($type ne "init" && $type ne "det" && $type ne "diff" && $type ne "stack" && $type ne "object" ) {
+if (
+        $type ne "init" && 
+        $type ne "detection" && 
+        $type ne "diff" && 
+        $type ne "stack" && 
+        $type ne "object" ) {
 
     print "Don't understand type '$type'\n"; 
@@ -43,5 +48,5 @@
 }
 
-my $enumsHeader = "ippToPsps".ucfirst($type)."Enums";
+my $enumsHeader = ucfirst($type)."BatchEnums";
 open(OUT, ">".$enumsHeader.".h") or die("Error");
 
@@ -61,5 +66,5 @@
 
 if ($type eq "init") {createInit();}
-elsif ($type eq "det") {createDetections();}
+elsif ($type eq "detection") {createDetections();}
 elsif ($type eq "diff") {createDiffs();}
 elsif ($type eq "stack") {createStacks();}
Index: trunk/ippToPsps/src/Batch.c
===================================================================
--- trunk/ippToPsps/src/Batch.c	(revision 30147)
+++ trunk/ippToPsps/src/Batch.c	(revision 30147)
@@ -0,0 +1,371 @@
+/** @file ippToPsps.c
+ *
+ *  @ingroup ippToPsps
+ *
+ *  @author IfA
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/stat.h>
+
+#include <pslib.h>
+#include <psmodules.h>
+#include "Batch.h"
+
+// private class members
+static bool haveResultsPath = false;
+static bool haveFitsInPath = false;
+static bool haveFitsOutPath = false;
+static bool haveConfig = false;
+static bool haveSurveyType = false;
+
+
+static bool gotResultsPath() {return haveResultsPath;}
+static bool gotFitsInPath() {return haveFitsInPath;}
+static bool gotFitsOutPath() {return haveFitsOutPath;}
+static bool gotConfig() {return haveConfig;}
+static bool gotSurveyType() {return haveSurveyType;}
+
+/**
+  Gets uncalibrated instrumental flux from magnitude
+  */
+__inline bool getFlux(const float exposureTime, const float magnitude, float* flux, const float magnitudeErr, float* fluxErr) {
+
+    *flux = powf(10.0, -0.4*magnitude) / exposureTime;
+    if (!isfinite(*flux) || *flux < 0.000001) return false;
+    if (fluxErr) *fluxErr = fabsf((magnitudeErr * *flux)/1.085736);
+//      if (fluxErr)    printf("Mag = %03.03f, Flux = %03.03f, Mag err = %03.03f, Flux Err = %03.03f\n", magnitude, *flux, magnitudeErr, *fluxErr);
+
+    return true;
+}
+
+/**
+  Destructor
+  */
+static void destroy(Batch* this) {
+
+    // if we created an output file...
+    if (this->fitsOut) {
+
+        // if unsuccessful, then delete FITS file
+        if (this->exitCode != PS_EXIT_SUCCESS) {
+
+            psError(PS_ERR_UNKNOWN, false, "Failed, so deleting %s", this->fitsOutPath);
+
+            // if process failed, we need to delete that FITS file
+            if (remove(this->fitsOutPath) == -1) {
+
+                psError(PS_ERR_UNKNOWN, false, "Unable to delete %s", this->fitsOutPath);
+            }
+        }
+        // ...otherwise, close file
+        else {
+
+            int status = 0;
+            if (fits_close_file(this->fitsOut, &status)) {
+
+                psError(PS_ERR_IO, false, "Unable to close FITS file %s", this->fitsOutPath);
+                fits_report_error(stderr, status);
+            }
+        }
+    }
+
+    // save XML document for results
+    if (this->resultsXmlDoc) {
+
+        xmlSaveFormatFileEnc(this->resultsPath, this->resultsXmlDoc, "UTF-8", 1);
+
+        xmlFreeDoc(this->resultsXmlDoc);
+        xmlCleanupParser();
+        xmlMemoryDump();
+    }
+
+    psFree(this->pmconfig);
+
+
+    for(uint32_t i=0; i<this->numOfInputFiles; i++) free(this->inputFiles[i]);
+    free(this->inputFiles);
+
+    if (this->dvoConfig != NULL) dvoConfigFree(this->dvoConfig);
+
+    ippToPspsConfig_Destructor(this->config);
+
+    pmConfigDone();
+
+    return;
+}
+
+/**
+  Reads file-input file and populate array of paths
+  */
+static bool readInputFilePaths(Batch* this) {
+
+    FILE* file = fopen (this->fitsInPath, "r");
+
+    if (file == NULL) {
+
+        psError(PS_ERR_UNKNOWN, false, "Unable to open file at %s", this->fitsInPath);
+        return false;
+    }
+
+    this->numOfInputFiles = 0;
+    char line[1000];
+    while (fgets(line, 1000, file) != NULL) this->numOfInputFiles++;
+
+    printf ("Number of input files %d\n", this->numOfInputFiles);
+
+    if (this->numOfInputFiles < 1) return false;
+
+    this->inputFiles = (char**)calloc(this->numOfInputFiles, sizeof(char*));
+    for(uint32_t i=0; i<this->numOfInputFiles; i++)
+        this->inputFiles[i] = (char*)calloc(1000, 1);
+
+    rewind(file);
+    uint16_t i = 0;
+    while (fgets(line, 1000, file) != NULL) {
+
+        sprintf(this->inputFiles[i], "%s", line);
+
+        // remove newline
+        for(uint16_t j=0;j<strlen(this->inputFiles[i]);j++)
+            if (this->inputFiles[i][j] == '\n') this->inputFiles[i][j] = '\0';
+        i++;
+    }
+
+    fclose(file);
+
+    return true;
+}
+
+/**
+  Sets-up and reads command-line arguments
+*/
+static bool parseArguments(Batch* this, int argc, char **argv) {
+
+    // first deal with DVO database
+    bool haveDvo = false;
+    for (int i=0;i<argc; i++) {
+
+        if (strcmp(argv[i], "CATDIR") == 0) {haveDvo = true; break;}
+    }
+    if (haveDvo) this->dvoConfig = dvoConfigRead(&argc, argv);
+    else this->dvoConfig = NULL;
+
+    // setup pmconfig
+    this->pmconfig = pmConfigRead(&argc, argv, NULL);
+    if (!this->pmconfig) {
+
+        psError(PS_ERR_UNKNOWN, false, "Unable to read configuration.");
+        this->exitCode = PS_EXIT_CONFIG_ERROR;
+        return false;
+    }
+    assert(this->pmconfig);
+
+    haveResultsPath = false;
+    haveFitsInPath = false;
+    haveFitsOutPath = false;
+    haveConfig = false;
+    haveSurveyType = false;
+
+    // decode arguments
+    int32_t optind = 1;
+    while( ( optind < argc ) ) {
+
+        char * sw = argv[optind];
+
+        if( argv[optind][0] == '-' ) {
+
+            if(strcmp(sw, "-input") == 0 ) {
+                optind++; if( optind > ( argc-1 ) ) break;
+                strcpy(this->fitsInPath, argv[optind]);
+                haveFitsInPath = true;
+            }
+            else if(strcmp(sw, "-output") == 0 ) {
+                optind++; if( optind > ( argc-1 ) ) break;
+                strcpy(this->fitsOutPath, argv[optind]);
+                haveFitsOutPath = true;
+            }
+            else if(strcmp(sw, "-results") == 0 ) {
+                optind++; if( optind > ( argc-1 ) ) break;
+                strcpy(this->resultsPath, argv[optind]);
+                haveResultsPath = true;
+            }
+            else if(strcmp(sw, "-config") == 0 ) {
+                optind++; if( optind > ( argc-1 ) ) break;
+                strcpy(this->configsDir, argv[optind]);
+                haveConfig = true;
+            }
+            else if(strcmp(sw, "-survey") == 0 ) {
+                optind++; if( optind > ( argc-1 ) ) break;
+                strcpy(this->surveyType, argv[optind]);
+                haveSurveyType = true;
+            }
+        }
+
+        optind++;
+    }
+
+
+    // setup command line arguments
+    //psMetadataAddStr(this->arguments, PS_LIST_TAIL, "-survey", 0, "Survey type", NULL);
+
+
+    // now check rest of arguments
+    //if (argc < 2 || !psArgumentParse(this->arguments, &argc, argv)) {
+
+      //  usage(this, argv[0]);
+        //this->exitCode = PS_EXIT_CONFIG_ERROR;
+        //return false;
+   // }
+
+    //this->surveyType = psMemIncrRefCounter(psMetadataLookupStr(NULL, this->arguments, "-survey"));
+
+    if (haveFitsInPath && !readInputFilePaths(this)) {
+
+        this->exitCode = PS_EXIT_DATA_ERROR;
+        return false;
+    }
+
+    return true;
+}
+
+/**
+  Initialises file paths, creates FITS file etc
+  */
+bool init(Batch* this) {
+
+    // create a config object
+    this->config = ippToPspsConfig_Constructor(this->configsDir);
+    if (this->config == NULL) {
+
+        this->exitCode = PS_EXIT_CONFIG_ERROR;
+        return false;
+    }
+
+    // get survey ID using config object
+    if (strlen(this->surveyType) > 0 && !ippToPspsConfig_getSurveyId(this->config, this->surveyType, &this->surveyID)) {
+
+        this->exitCode = PS_EXIT_CONFIG_ERROR;
+        return false;
+    }
+    // create full FITS out path
+    sprintf (this->fitsOutPath, "%s/%s", this->fitsOutPath, this->fitsOutFile);
+
+    // create an output FITS file
+    int status=0;
+    if (fits_create_file(&this->fitsOut, this->fitsOutPath, &status)) {
+        fits_report_error(stderr, status);
+        psError(PS_ERR_IO, false, "Unable to create file at: '%s'", this->fitsOutPath);
+        this->exitCode = PS_EXIT_SYS_ERROR;
+        this->fitsOut = NULL;
+        return false;
+    }
+
+    // create XML document for results 
+    if (this->resultsPath) {
+
+        this->resultsXmlDoc = xmlNewDoc(BAD_CAST "1.0");
+        xmlNodePtr rootNode = xmlNewNode(NULL, BAD_CAST "ippToPsps_Results");
+        xmlDocSetRootElement(this->resultsXmlDoc, rootNode);
+        xmlNewChild(rootNode, NULL, BAD_CAST "filename", BAD_CAST this->fitsOutFile);
+    }
+
+    return true;
+}
+
+/**
+  Print-out of this class
+  */
+static void print(Batch* this) {
+
+    printf("\n");
+    printf("* surveyType      : '%s'\n", this->surveyType);
+    printf("* surveyID        : %d\n", this->surveyID);
+    printf("* resultsPath     : '%s'\n", this->resultsPath);
+    printf("* numOfInputFiles : %d\n", this->numOfInputFiles);
+    printf("* fitsInPath      : '%s'\n", this->fitsInPath);
+    printf("* fitsOutFile     : '%s'\n", this->fitsOutFile);
+    printf("* fitsOutPath     : '%s'\n", this->fitsOutPath);
+    printf("* configsDir      : '%s'\n", this->configsDir);
+}
+
+
+
+#if 0
+psDB *dbh = psMemIncrRefCounter(pmConfigDB(this->pmconfig));
+if (!dbh) {
+    psError(PS_ERR_UNKNOWN, false, "Can't configure database");
+    ret = false;;
+}
+
+
+
+psString query = psStringCopy("SELECT * FROM camMask");
+
+if (!p_psDBRunQuery(dbh, query)) {
+    psError(PS_ERR_UNKNOWN, false, "database error");
+    psFree(query);
+    return false;
+}
+psFree(query);
+
+psArray *output = p_psDBFetchResult(dbh);
+if (!output) {
+    psError(PS_ERR_UNKNOWN, false, "database error");
+    return false;
+}
+if (!psArrayLength(output)) {
+    psTrace("camtool", PS_LOG_INFO, "no rows found");
+    psFree(output);
+    return true;
+}
+
+psError(PS_ERR_UNKNOWN, false, "FOUND %ld rows\n", psArrayLength(output));
+
+
+psFree(output);
+
+#endif
+
+
+/**
+  Constructor
+  */
+bool new_Batch(Batch *this) {
+
+    this->surveyID = -1;
+    this->resultsXmlDoc = NULL;
+    this->numOfInputFiles = 0;
+    this->inputFiles = NULL;
+    this->fitsOut = NULL;
+    this->config = NULL;
+    this->pmconfig = NULL;
+    this->exitCode = PS_EXIT_SUCCESS;
+
+    this->parseArguments = parseArguments;
+    this->init = init;
+    this->print = print;
+    this->destroy = destroy;
+
+    this->gotResultsPath = gotResultsPath;
+    this->gotFitsInPath = gotFitsInPath;
+    this->gotFitsOutPath = gotFitsOutPath;
+    this->gotConfig = gotConfig;
+    this->gotSurveyType = gotSurveyType;
+
+    assert(this);
+
+    // sort out current time
+    time_t now = time(NULL);;
+    struct tm *ts = gmtime(&now); // TODO should be UTC
+    strftime(this->todaysDate, sizeof(this->todaysDate), "%Y-%m-%d", ts);
+
+    return true;
+}
+
+
Index: trunk/ippToPsps/src/Batch.h
===================================================================
--- trunk/ippToPsps/src/Batch.h	(revision 30147)
+++ trunk/ippToPsps/src/Batch.h	(revision 30147)
@@ -0,0 +1,69 @@
+/** @file ippToPsps.h
+ *
+ *  @brief Batch
+ *
+ *  @ingroup ippToPsps
+ *
+ *  @author IfA
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+#ifndef IPPTOPSPS_BATCH_H
+#define IPPTOPSPS_BATCH_H
+
+#include <psmodules.h>
+#include <dvo_util.h>
+#include "ippToPspsConfig.h"
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+/**
+  Base class for all batches
+  */
+typedef struct Batch {
+
+    // fields
+    char surveyType[10];        // the survey type, eg 3PI, MD01, STS, SSS
+    int8_t surveyID;            // survey ID
+    char fitsInPath[1000];      // path to FITS input
+    char resultsPath[1000];     // path to results file
+    xmlDocPtr resultsXmlDoc;    // pointer to XML document for results
+    uint16_t numOfInputFiles;   // number of input files
+    char** inputFiles;          // array of input file names
+    char fitsOutFile[100];      // FITS output filename
+    char fitsOutPath[1000];     // path to FITS output
+    fitsfile *fitsOut;          // output FITS file
+    char configsDir[500];       // path to IPP/PSPS mapping file
+    pmConfig* pmconfig;         // pmConfig
+    dvoConfig* dvoConfig;       // dvo database
+    IppToPspsConfig* config;    // config structure
+    char todaysDate[20];        // today's date
+    int exitCode;               // ps exit code
+
+    // methods
+    bool (*parseArguments)();
+    bool (*init)();
+    int (*run)();
+    void (*print)();
+    bool (*gotResultsPath)(); 
+    bool (*gotFitsInPath)();
+    bool (*gotFitsOutPath)();
+    bool (*gotConfig)();
+    bool (*gotSurveyType)(); 
+    void (*destroy)();
+
+} Batch;
+
+// public functions
+bool new_Batch(Batch *this);
+
+void ippToPsps_VersionPrint(void);
+
+bool getFlux(
+        const float exposureTime, 
+        const float magnitude, 
+        float* flux, 
+        const float magnitudeErr, 
+        float* fluxErr);
+
+# endif // IPPTOPSPS_BATCH_H 
Index: trunk/ippToPsps/src/Config.c
===================================================================
--- trunk/ippToPsps/src/Config.c	(revision 30147)
+++ trunk/ippToPsps/src/Config.c	(revision 30147)
@@ -0,0 +1,948 @@
+/** @file ippToPspsConfig.c
+ *
+ *  @ingroup ippToPsps
+ *
+ *  @author IfA
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+#include "ippToPspsConfig.h"
+#include <ctype.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+// Gets PS type from string
+static int ippToPsps_GetDataType(char *typename) {
+
+    if (!strncmp(typename, "TBYTE", 5))  return TBYTE;
+    if (!strncmp(typename, "TSHORT", 6)) return TSHORT;
+    if (!strncmp(typename, "TLONGLONG", 9)) return TLONGLONG;
+    if (!strncmp(typename, "TLONG", 5)) return TLONG;
+    if (!strncmp(typename, "TFLOAT", 6)) return TFLOAT;
+    if (!strncmp(typename, "TDOUBLE", 7)) return TDOUBLE;
+    if (!strncmp(typename, "TSTRING", 7)) return TSTRING;
+
+    psError(PS_ERR_IO, false, "Don't understand type '%s'", typename);
+
+    return 0;
+}
+
+// finds a column within this table
+static IppToPspsConfig_Column* ippToPspsConfig_findColumn(IppToPspsConfig_Table* table, const char* name) {
+
+    IppToPspsConfig_Column* column = NULL;
+
+    for (uint32_t i=0; i<table->numOfColumns; i++) {
+
+        if (strcmp(table->columns[i].pspsName, name) == 0) {
+            column = table->columns+i;
+            break;
+        }
+    }
+
+    if (!column) psError(PS_ERR_IO, false, "Could not find column '%s' in table '%s'", name, table->name);
+
+    return column;
+}
+
+// finds a table from the array of tables
+static IppToPspsConfig_Table* ippToPspsConfig_findTable(IppToPspsConfig* this, const char* name) {
+
+    IppToPspsConfig_Table* table = NULL;
+
+    for (uint32_t i=0; i<this->numOfTables; i++) {
+
+        if (strcmp(this->tables[i].name, name) == 0) {
+            table = this->tables+i;
+            break;
+        }
+    }
+
+    if (!table) psError(PS_ERR_IO, false, "Could not find table '%s'", name);
+
+    return table;
+}
+
+// gets an attribute value from XML node
+static bool ippToPspsConfig_getAttribute(xmlNode* node, const char* attName, char* _value) {
+
+    xmlChar* value = xmlGetProp(node, (const xmlChar*)attName);
+    if (!value) return false;
+    sprintf(_value, "%s", value);
+    xmlFree(value);
+
+    return true;
+}
+
+// creates a FITS binary table and populates it with defaults based on definition in schema XML
+static bool ippToPspsConfig_createTable(IppToPspsConfig_Table* table, fitsfile* fitsOut, const long nRows) {
+
+    if (!table) return false;
+    if (nRows < 1) return false;
+
+    long nCols = table->numOfColumns;
+
+    char** colNames = (char**)calloc(nCols, sizeof(char*));
+    char** colTypes = (char**)calloc(nCols, sizeof(char*));
+
+    uint32_t i = 0;
+    for (i=0;i<nCols;i++) colTypes[i] = (char*)calloc(5,sizeof(char));
+
+    i = 0;
+    for (uint32_t m=0; m<table->numOfColumns; m++) {
+
+        colNames[i] = table->columns[i].pspsName;
+
+        //        sprintf(colNames[i], table->columns[i].pspsName);
+
+        switch (table->columns[i].pspsType) {
+
+            case TBYTE:
+                sprintf(colTypes[i],"1B");
+                break;
+            case TSHORT:
+                sprintf(colTypes[i],"1I");
+                break;
+            case TLONG:
+                sprintf(colTypes[i],"1J"); // TODO
+                break;
+            case TLONGLONG:
+                sprintf(colTypes[i],"1K");
+                break;
+            case TFLOAT:
+                sprintf(colTypes[i],"1E");
+                break;
+            case TDOUBLE:
+                sprintf(colTypes[i],"1D");
+                break;
+            case TSTRING:
+                sprintf(colTypes[i],"32A"); // TODO width?
+                break;
+
+            default:
+                break;
+        }
+
+        i++;
+    }
+
+    int status = 0;
+    if (fits_create_tbl(fitsOut, BINARY_TBL, nRows, nCols, colNames, colTypes, NULL, table->name, &status)) {
+
+        fits_report_error(stderr, status);
+        psError(PS_ERR_IO,"Unable to create table: %s", table->name);
+    }
+
+    for (i=0;i<nCols;i++) free(colTypes[i]);
+    free(colTypes);
+    free(colNames);
+
+    // now insert defaults
+    int8_t* int8col = (int8_t*)calloc(nRows, sizeof(int8_t));
+    int16_t* int16col = (int16_t*)calloc(nRows, sizeof(int16_t));
+    long* longcol = (long*)calloc(nRows, sizeof(long));
+    float* floatcol = (float*)calloc(nRows, sizeof(float));
+    double* doublecol = (double*)calloc(nRows, sizeof(double));
+    char** strcol = (char**)calloc(nRows, sizeof(char**));
+    for (uint32_t i=0; i<nRows;i++)
+        strcol[i] = (char*)calloc(20,sizeof(char)); // TODO 20? size issue
+
+    uint32_t j;
+    int64_t tempLong;
+    double tempDouble;
+    char tempStr[20];
+
+    int col;
+    for (uint32_t i=0; i<table->numOfColumns; i++) {
+
+        col = i+1;
+
+        strcpy(tempStr,table->columns[i].defaultValue);
+        tempLong = atol(tempStr);
+        tempDouble = atof(tempStr);
+
+        switch (table->columns[i].pspsType) {
+
+            case TBYTE:
+                for(j=0;j<nRows;j++) int8col[j] = (int8_t)tempLong;
+                fits_write_col(fitsOut, TBYTE, col, 1, 1, nRows, int8col, &status);
+                break;
+            case TSHORT:
+                for(j=0;j<nRows;j++) int16col[j] = (int16_t)tempLong;
+                fits_write_col(fitsOut, TSHORT, col, 1, 1, nRows, int16col, &status);
+                break;
+            case TLONG:
+                for(j=0;j<nRows;j++) longcol[j] = (long)tempLong;
+                fits_write_col(fitsOut, TLONG, col, 1, 1, nRows, longcol, &status);
+                break;
+
+            case TLONGLONG:
+                for(j=0;j<nRows;j++) longcol[j] = tempLong;
+                fits_write_col(fitsOut, TLONGLONG, col, 1, 1, nRows, longcol, &status);
+                break;
+
+            case TFLOAT:
+                for(j=0;j<nRows;j++) floatcol[j] = (float)tempDouble;
+                fits_write_col(fitsOut, TFLOAT, col, 1, 1, nRows, floatcol, &status);
+                break;
+
+            case TDOUBLE:
+                for(j=0;j<nRows;j++) doublecol[j] = tempDouble;
+                fits_write_col(fitsOut, TDOUBLE, col, 1, 1, nRows, doublecol, &status);
+                break;
+
+            case TSTRING:
+                for(j=0;j<nRows;j++) strcpy(strcol[j], tempStr);
+                fits_write_col(fitsOut, TSTRING, col, 1, 1, nRows, strcol, &status);
+                break;
+
+            default:
+                break;
+
+        }
+    }
+
+    free(int8col);
+    free(int16col);
+    free(longcol);
+    free(floatcol);
+    free(doublecol);
+    for (uint32_t i=0; i<nRows;i++) free(strcol[i]);
+    free(strcol);
+
+    return true;
+}
+
+// count number of children with the provided name
+static int ippToPspsConfig_countChildren(xmlNode* rootNode, const char* name) {
+
+    int count = 0;
+    xmlNode* node = NULL;
+
+    for (node = rootNode->children; node; node = node->next) {
+
+        if (strcmp((const char*)node->name, name)==0) count++;
+    } 
+
+    return count;
+}
+
+// searches through this table and finds attribute value for a provided key
+static bool ippToPspsConfig_getRowAttribute(IppToPspsConfig* this, xmlNode* tableNode, 
+        const char* keyName, const char* keyValue, 
+        const char* attName, char* attValue) {
+
+    xmlNode* node = NULL;
+
+    char buffer[100];
+
+    // loop round all available rows for this table
+    for (node = tableNode->children; node; node = node->next) {
+        if (node->type == XML_ELEMENT_NODE) {
+            //psLogMsg("ippToPsps", PS_LOG_INFO, "Node name '%s'",  (const char*)node->name );
+
+            if (strcmp((const char*)node->name, "row")==0) {
+            //psLogMsg("ippToPsps", PS_LOG_INFO, " Looking for key '%s'",  keyName );
+
+                if (!ippToPspsConfig_getAttribute(node, keyName, buffer)) continue;
+            //psLogMsg("ippToPsps", PS_LOG_INFO, "Found key '%s' value '%s'",  keyName, buffer );
+
+                if (strcmp(buffer, keyValue) != 0) continue;
+                ippToPspsConfig_getAttribute(node, attName, attValue);
+                //printf("FOUND %s %s %s %s \n", keyName, buffer, attName, attValue );
+                return true;
+
+            }
+        }
+    }
+
+    psLogMsg("ippToPsps", PS_LOG_INFO, "Could not find value for '%s' for '%s' with value '%s'", attName, keyName, keyValue );
+    return false;
+}
+
+// opens an XML file and returns the document
+static xmlDoc* ippToPspsConfig_openXmlFile(const char* path) {
+
+    xmlDoc* doc = xmlReadFile(path, NULL, 0);
+    if (doc == NULL) psError(PS_ERR_IO, false, "Unable to open XML file at %s", path);
+    return doc;
+}
+
+// closes an XML file 
+static bool ippToPspsConfig_closeXmlFile(xmlDoc* doc) {
+
+    xmlFreeDoc(doc);
+    xmlCleanupParser();
+
+    return true;
+}
+
+// gets filter ID for this filter name from 'init' data 
+static bool ippToPspsConfig_getInitValue(
+        IppToPspsConfig* this, 
+        const char* tableName,
+        const char* keyName, const char* keyValue,
+        const char* attName, char* attValue) {
+
+    bool ret = true;
+
+    psString path = NULL;
+    psStringAppend(&path, "%s/../init/data.xml", this->configsPath); // TODO nasty
+
+    xmlDoc* doc = ippToPspsConfig_openXmlFile(path);
+
+    if (doc == NULL) {
+        psFree(path);
+        return false;
+    }
+    psFree(path);
+
+    xmlNode* rootElement = xmlDocGetRootElement(doc);
+
+    if (strcmp((const char*)rootElement->name, "tabledata")!=0) {
+        psError(PS_ERR_IO, false, "Root node of XML is not 'tabledata', as it should be");
+        return false;
+    }
+
+    xmlNode* node = NULL;
+    char tempStr[100];
+
+    // loop round all available tables
+    for (node = rootElement->children; node; node = node->next) {
+        if (node->type == XML_ELEMENT_NODE) {
+
+            if (strcmp((const char*)node->name, "table")!=0) continue;
+            if (!ippToPspsConfig_getAttribute(node, "name", tempStr)) continue;
+            if (strcmp(tempStr, tableName)!=0) continue;
+
+            ret = ippToPspsConfig_getRowAttribute(this, node, keyName, keyValue, attName, attValue);
+            break;
+        }
+
+    }
+
+    ippToPspsConfig_closeXmlFile(doc);
+
+    return ret;
+}
+
+// gets survey ID from survey name
+bool ippToPspsConfig_getSurveyId(IppToPspsConfig* this, const char* surveyType, int8_t* surveyId) {
+
+    char buffer[10];
+    if (!ippToPspsConfig_getInitValue(this, "Survey", "name", surveyType, "surveyID", buffer)) {
+
+        *surveyId = -1;
+        return false;
+    }
+
+    *surveyId = atoi(buffer);
+    return true;
+}
+
+// gets filter ID from filter type
+bool ippToPspsConfig_getFilterId(IppToPspsConfig* this, const char* filterType, int8_t* filterId) {
+
+    char tmp[2];
+    strncpy(tmp,filterType,1);
+    tmp[1] = '\0';
+    char buffer[10];
+    if (!ippToPspsConfig_getInitValue(this, "Filter", "filterType", tmp, "filterID", buffer)) {
+
+        *filterId = -1;
+        return false;
+    }
+
+    *filterId = atoi(buffer);
+    return true;
+}
+
+// populate the provided table with data from XML
+static bool ippToPspsConfig_populateTable(IppToPspsConfig_Table* table, xmlNode* rootElement, fitsfile *fitsOut) {
+
+    char tempStr[100];
+    xmlNode* node = NULL;
+    xmlNode* tableNode = NULL;
+
+    // first check we have data for this table in XML file
+    for (node = rootElement->children; node; node = node->next) {
+        if (node->type == XML_ELEMENT_NODE) {
+
+            if (strcmp((const char*)node->name, "table")!=0) continue;
+            if (!ippToPspsConfig_getAttribute(node, "name", tempStr)) continue;
+            if (strcmp(tempStr, table->name)==0) {tableNode = node; break;}
+        }
+    }
+
+    if(!tableNode) {
+
+        psError(PS_ERR_IO,"Could not find table: %s", table->name);
+        return false;
+    }
+
+    // now count the number of rows
+    int nRows = ippToPspsConfig_countChildren(tableNode, "row");
+    if (nRows < 1) return false;
+    if (!ippToPspsConfig_createTable(table, fitsOut, nRows)) return false;
+
+    int rows=0;
+    int status;
+    char** strcol = (char**)calloc(1, sizeof(char**));
+    strcol[0] = (char*)calloc(32,sizeof(char)); // TODO 20? size issue
+
+    int8_t* bytecol = calloc(1, sizeof(uint8_t));
+    int16_t* shortcol = calloc(1, sizeof(uint16_t));
+    long* longcol = calloc(1, sizeof(long));
+    double* doublecol = calloc(1, sizeof(double));
+    float* floatcol = calloc(1, sizeof(float));
+
+    int col;
+
+    // now get rows
+    for (node = tableNode->children; node; node = node->next) {
+
+        if (strcmp((const char*)node->name, "row")!=0) continue;
+
+        rows++;
+
+        // get column data for this row
+        for (int i=0;i<table->numOfColumns;i++) {
+
+            col = i+1;
+
+            if (!ippToPspsConfig_getAttribute(node, table->columns[i].pspsName, tempStr)) continue;
+
+            strncpy(strcol[0], tempStr, 32);
+            status=0;
+            //psLogMsg("ippToPsps", PS_LOG_INFO, "Values %s - %ld - %f - %d", strcol[0], longcol[0], doublecol[0], bytecol[0]);
+            switch (table->columns[i].pspsType) {
+
+                case TBYTE:
+                    bytecol[0] = atoi(tempStr);
+                    fits_write_col(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, bytecol, &status); 
+                    break;
+                case TSHORT:
+                    shortcol[0] = atoi(tempStr);
+                    fits_write_col(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, shortcol, &status); 
+                    break;
+                case TLONG:
+                case TLONGLONG:
+                    longcol[0] = atol(tempStr);
+                    fits_write_col(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, longcol, &status); 
+                    break;
+                case TFLOAT:
+                    floatcol[0] = atof(tempStr);
+                    fits_write_col(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, floatcol, &status);
+                    break;
+                case TDOUBLE:
+                    doublecol[0] = atof(tempStr);
+                    fits_write_col(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, doublecol, &status);
+                    break;
+                case TSTRING:
+                    fits_write_col(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, strcol, &status); 
+                    break;
+
+            }
+            if (status) psError(PS_ERR_IO, false, "Unable to write value of %s to column %s in table %s", 
+                    tempStr, table->columns[i].pspsName, table->name);
+        }
+    }
+
+    free(bytecol);
+    free(shortcol);
+    free(longcol);
+    free(floatcol);
+    free(doublecol);
+    free(strcol[0]);
+    free(strcol);
+
+    return true;
+}
+
+// loads a table description from XML
+static bool ippToPspsConfig_loadTableDescription(IppToPspsConfig_Table* table, xmlNode* tableNode) {
+
+    bool ret = true;
+    char tableName[100];
+    ippToPspsConfig_getAttribute(tableNode, "name", tableName);
+    strcpy(table->name, tableName);
+
+    // count how many columns we have coming in and allocate memory for them
+    table->numOfColumns = ippToPspsConfig_countChildren(tableNode, "column");
+    table->columns = calloc(table->numOfColumns, sizeof(IppToPspsConfig_Column));
+    //    psLogMsg("ippToPsps", PS_LOG_INFO, " Found '%d' columns", table->numOfColumns);
+
+    char buffer[200];
+    xmlNode* node;
+    int columnNum = 0;
+
+    for (node = tableNode->children; node; node = node->next) {
+
+        if (strcmp((const char*)node->name, "column") != 0) continue;
+
+        table->columns[columnNum].usingDefault = true;
+
+        // column name
+        ippToPspsConfig_getAttribute(node, "name", buffer);
+        sprintf(table->columns[columnNum].pspsName, buffer);
+
+        // column type
+        ippToPspsConfig_getAttribute(node, "type", buffer);
+        table->columns[columnNum].pspsType = ippToPsps_GetDataType(buffer);
+
+        // default value
+        ippToPspsConfig_getAttribute(node, "default", buffer);
+        sprintf(table->columns[columnNum].defaultValue, buffer);
+
+        // comment
+        ippToPspsConfig_getAttribute(node, "comment", buffer);
+        sprintf(table->columns[columnNum].comment, buffer);
+
+        # if 0
+        psLogMsg("ippToPsps", PS_LOG_INFO, "'%s'  name='%s' type='%d'  default='%s' comment='%s'", 
+                table->name,
+                table->columns[columnNum].pspsName, 
+                table->columns[columnNum].pspsType, 
+                table->columns[columnNum].defaultValue, 
+                table->columns[columnNum].comment);
+# endif
+        columnNum++;
+    }   
+
+
+    if (columnNum < 1) {
+
+        psError(PS_ERR_IO, false, "Found no columns for table '%s'", tableName);
+        ret = false;
+    }
+
+    if (columnNum != table->numOfColumns)
+        psError(PS_ERR_IO, false, "Mismatch between number of columns expected (%d) and those found (%d)", table->numOfColumns, columnNum);
+
+    return ret;
+}
+
+// read table shapes from XML file
+bool ippToPspsConfig_loadTableDescriptions(IppToPspsConfig* this) {
+
+    bool ret = true;
+
+    psString path = NULL;
+    psStringAppend(&path, "%s/tables.xml", this->configsPath);
+
+    xmlDoc* doc = ippToPspsConfig_openXmlFile(path);
+
+    if (doc == NULL) {
+
+        psFree(path);
+        return false;
+    }
+    psFree(path);
+
+    xmlNode* rootElement = xmlDocGetRootElement(doc);
+
+    if (strcmp((const char*)rootElement->name, "tableDescriptions")!=0) {
+
+        psError(PS_ERR_IO, false, "Root node of XML is not 'tableDescriptions', as it should be");
+        return false;
+    }
+
+    // count how many tables we have coming in and allocate memory for them
+    this->numOfTables = ippToPspsConfig_countChildren(rootElement, "table");
+    this->tables = calloc(this->numOfTables, sizeof(IppToPspsConfig_Table));
+    //    psLogMsg("ippToPsps", PS_LOG_INFO, " Found '%d' tables", this->numOfTables);
+
+    xmlNode* node = NULL;
+    IppToPspsConfig_Table* table = NULL;
+
+    int tableNum = 0;
+    // loop round all available table descriptions
+    for (node = rootElement->children; node; node = node->next) {
+        if (node->type == XML_ELEMENT_NODE) {
+
+            if (strcmp((const char*)node->name, "table")==0) {
+
+                table = this->tables+tableNum;
+
+                if (!ippToPspsConfig_loadTableDescription(table, node)) ret = false;
+                else tableNum++;
+            }
+        }
+    }
+
+    if (tableNum != this->numOfTables)
+        psError(PS_ERR_IO, false, "Mismatch between number of tables expected (%d) and those found (%d)", this->numOfTables, tableNum);
+
+    ippToPspsConfig_closeXmlFile(doc);
+
+    return ret;
+}
+
+// loads mappings from XML for a particular table
+static bool ippToPspsConfig_loadTableMappings(IppToPspsConfig* this, xmlNode* tableNode) {
+
+    bool ret = false;
+
+    xmlNode* node = NULL;
+
+    char tableName[100];
+    ippToPspsConfig_getAttribute(tableNode, "name", tableName);
+
+    IppToPspsConfig_Table* table = ippToPspsConfig_findTable(this, tableName);
+    IppToPspsConfig_Column* column = NULL;
+    if (!table) return false;
+
+    char buffer[100];
+    //psLogMsg("ippToPsps", PS_LOG_INFO, "Table '%s'", tableName);
+
+    // loop round all available mappings for this table
+    for (node = tableNode->children; node; node = node->next) {
+        if (node->type == XML_ELEMENT_NODE) {
+
+            if (strcmp((const char*)node->name, "map")==0) {
+
+                // column type
+                ippToPspsConfig_getAttribute(node, "pspsName", buffer);
+                column = ippToPspsConfig_findColumn(table, buffer);
+
+                if (!column) continue;
+
+                // IPP name
+                ippToPspsConfig_getAttribute(node, "ippName", buffer);
+                strcpy(column->ippName, buffer);
+
+                // IPP type
+                ippToPspsConfig_getAttribute(node, "ippType", buffer);
+                column->ippType = ippToPsps_GetDataType(buffer); 
+
+                column->usingDefault = false;
+
+                //psLogMsg("ippToPsps", PS_LOG_INFO, "...mapping PSPS:'%s' to '%s' '%d'", column->pspsName, column->ippName, column->ippColNum );
+            }
+        }
+    }
+
+    return ret;
+}
+
+// reads table mappings from XML file
+static bool ippToPspsConfig_loadMappings(IppToPspsConfig* this) {
+
+    bool ret = true;
+
+    psString path = NULL;
+    psStringAppend(&path, "%s/map.xml", this->configsPath);
+
+    xmlDoc* doc = ippToPspsConfig_openXmlFile(path);
+
+    if (doc == NULL) {
+        psFree(path);
+        return false;
+    }
+    psFree(path);
+
+    xmlNode* rootElement = xmlDocGetRootElement(doc);
+
+    if (strcmp((const char*)rootElement->name, "tabledata")!=0) {
+        psError(PS_ERR_IO, false, "Root node of XML is not 'tabledata', as it should be");
+        return false;
+    }
+
+    xmlNode* node = NULL;
+
+    // loop round all available tables
+    for (node = rootElement->children; node; node = node->next) {
+        if (node->type == XML_ELEMENT_NODE) {
+
+            if (strcmp((const char*)node->name, "table")==0) {
+
+                if (!ippToPspsConfig_loadTableMappings(this, node)) ret = false;
+            }
+        }
+    }
+
+    ippToPspsConfig_closeXmlFile(doc);
+
+    return ret;
+}
+
+// populate the provided table with data from XML
+bool ippToPspsConfig_populateFromFile(IppToPspsConfig* this, fitsfile *fitsOut) {
+
+    bool ret = true;
+    psString path = NULL;
+    psStringAppend(&path, "%s/data.xml", this->configsPath);
+
+    xmlDoc* doc = ippToPspsConfig_openXmlFile(path);
+
+    if (doc == NULL) {
+        psFree(path);
+        return false;
+    }
+    psFree(path);
+
+    xmlNode* rootElement = xmlDocGetRootElement(doc);
+
+    if (strcmp((const char*)rootElement->name, "tabledata")!=0) {
+        psError(PS_ERR_IO, false, "Root node of XML is not 'tabledata', as it should be");
+        return false;
+    }
+
+    for (uint32_t i=0; i<this->numOfTables; i++) {
+        if (!ippToPspsConfig_populateTable(this->tables+i, rootElement, fitsOut)) {
+            ret = false;
+        }
+    }
+
+    ippToPspsConfig_closeXmlFile(doc);
+
+    return ret;
+}
+
+// gets the contents of a FITS column vector
+bool ippToPspsConfig_getColumnVector(
+        int col,
+        long row,
+        int type,
+        int repeat,
+        float* vector,
+        fitsfile *fitsIn) {
+
+    int status = 0;
+    int anynull = 0;  
+
+    fits_read_col(fitsIn, type, col, row, 1, repeat, NULL, vector, &anynull, &status);
+
+    if (status) {
+        psError(PS_ERR_IO, false, "Failed to read vector column %d row %ld", col, row);
+        return false;
+    }
+
+    int i;
+    for(i=0; i<repeat; i++) printf("JJJ %f\n", vector[i]);
+
+    return true;
+}
+
+// gets metadata about a column 
+bool ippToPspsConfig_getFitsColumnMeta(
+        char* name,
+        int* colNum,
+        int* type,
+        long* repeat,
+        fitsfile *fitsIn) {
+
+    int status = 0;
+    fits_get_colnum(fitsIn, CASESEN, name, colNum, &status);
+    if (status) {
+        psError(PS_ERR_IO, false, "Unable to read col '%s'", name);
+        return false;
+    }
+
+    status = 0;
+    fits_get_eqcoltype(fitsIn, *colNum, type, repeat, NULL, &status);
+    if (status) {
+        psError(PS_ERR_IO, false, "Unable to read type info for '%s'", name);
+        return false;
+    }
+
+    return true;
+}
+
+// populate with data from another FITS table into this one
+static bool ippToPspsConfig_populateTableFromFits(
+        IppToPspsConfig_Table* table,
+        fitsfile *fitsIn, 
+        fitsfile *fitsOut,
+        const long nRows, 
+        const bool fromHeader) {
+
+    if (!table) return false;
+    if (!fitsIn) return false;
+
+    int8_t* int8col = (int8_t*)calloc(nRows, sizeof(int8_t));
+    int16_t* int16col = (int16_t*)calloc(nRows, sizeof(int16_t));
+    long* longcol = (long*)calloc(nRows, sizeof(long));
+    float* floatcol = (float*)calloc(nRows, sizeof(float));
+    double* doublecol = (double*)calloc(nRows, sizeof(double));
+    char** strcol = (char**)calloc(nRows, sizeof(char**));
+    for (uint32_t i=0; i<nRows;i++)
+        strcol[i] = (char*)calloc(50,sizeof(char)); // TODO 20? size issue
+
+    int8_t int8null = -99;
+    int16_t int16null = -999;
+    long longnull = -999;
+    float floatnull = -999.0;
+    double doublenull = -999.0;
+
+    int anynull = 0;
+    int readStatus = 0;
+    int writeStatus = 0;
+
+    // first loop round all columns and get IPP col numbers for provided column names TODO only do once, first time in
+    if(!fromHeader) {
+
+        for (uint32_t i=0; i<table->numOfColumns; i++) {
+
+            if (strlen(table->columns[i].ippName) < 1) continue;
+
+int dummy;
+
+            if (!ippToPspsConfig_getFitsColumnMeta(
+                        table->columns[i].ippName,
+                        &table->columns[i].ippColNum,
+          //              &table->columns[i].ippType,  TODO getting wrong type for some reason
+                        &dummy,
+                        &table->columns[i].ippRepeat,
+                        fitsIn)) {return false;}
+        }
+    }
+
+    int col;
+    for (uint32_t i=0; i<table->numOfColumns; i++) {
+
+        readStatus = 0;
+        writeStatus = 0;
+
+        if (!table->columns[i].usingDefault) {
+
+            col = i+1;
+
+            switch (table->columns[i].ippType) {
+
+                case TBYTE:
+                    if (fromHeader) {
+                        fits_read_key(fitsIn, TBYTE, table->columns[i].ippName, &int8col[0], NULL, &readStatus);
+                        if (!isfinite(int8col[0])) int8col[0] = int8null;
+                    }
+                    else fits_read_col(fitsIn, TBYTE, table->columns[i].ippColNum, 1, 1, nRows, &int8null, int8col, &anynull, &readStatus);
+                    fits_write_col(fitsOut, TBYTE, col, 1, 1, nRows, int8col, &writeStatus);
+                    break;
+                case TSHORT:
+                    if (fromHeader) {
+                        fits_read_key(fitsIn, TSHORT, table->columns[i].ippName, &int16col[0], NULL, &readStatus);
+                        if (!isfinite(int16col[0])) int16col[0] = int16null;
+                    }
+                    else fits_read_col(fitsIn, TSHORT, table->columns[i].ippColNum, 1, 1, nRows, &int16null, int16col, &anynull, &readStatus);
+                    fits_write_col(fitsOut, TSHORT, col, 1, 1, nRows, int16col, &writeStatus);
+                    break;
+                case TLONG:
+                    if (fromHeader) {
+                        fits_read_key(fitsIn, TLONG, table->columns[i].ippName, &longcol[0], NULL, &readStatus);
+                        if (!isfinite(longcol[0])) longcol[0] = longnull;
+                    }
+                    else fits_read_col(fitsIn, TLONG, table->columns[i].ippColNum, 1, 1, nRows, &longnull, longcol, &anynull, &readStatus);
+                    fits_write_col(fitsOut, TLONG, col, 1, 1, nRows, longcol, &writeStatus);
+                    break;
+                case TLONGLONG:
+                    if (fromHeader) {
+                        fits_read_key(fitsIn, TLONGLONG, table->columns[i].ippName, &longcol[0], NULL, &readStatus);
+                        if (!isfinite(longcol[0])) longcol[0] = longnull;
+                    }
+                    else fits_read_col(fitsIn, TLONGLONG, table->columns[i].ippColNum, 1, 1, nRows, &longnull, longcol, &anynull, &readStatus);
+                    fits_write_col(fitsOut, TLONGLONG, col, 1, 1, nRows, longcol, &writeStatus);
+                    break;
+                case TFLOAT:
+                    if (fromHeader) {
+                        fits_read_key(fitsIn, TFLOAT, table->columns[i].ippName,&floatcol[0], NULL, &readStatus); 
+                        if (!isfinite(floatcol[0])) floatcol[0] = floatnull;
+                    }
+                    else fits_read_col(fitsIn, TFLOAT, table->columns[i].ippColNum, 1, 1, nRows, &floatnull, floatcol, &anynull, &readStatus);
+                    fits_write_col(fitsOut, TFLOAT, col, 1, 1, nRows, floatcol, &writeStatus);
+                    break;
+                case TDOUBLE:
+                    if (fromHeader) {
+                        fits_read_key(fitsIn, TDOUBLE, table->columns[i].ippName, &doublecol[0], NULL, &readStatus);
+                        if (!isfinite(doublecol[0])) doublecol[0] = doublenull;
+                    }
+                    else fits_read_col(fitsIn, TDOUBLE, table->columns[i].ippColNum, 1, 1, nRows, &doublenull, doublecol, &anynull, &readStatus);
+                    fits_write_col(fitsOut, TDOUBLE, col, 1, 1, nRows, doublecol, &writeStatus);
+                    break;
+                case TSTRING:
+                    if (fromHeader) fits_read_key(fitsIn, TSTRING, table->columns[i].ippName, strcol[0], NULL, &readStatus);
+                    else fits_read_col(fitsIn, TSTRING, table->columns[i].ippColNum, 1, 1, nRows, " ", strcol, &anynull, &readStatus);
+                    fits_write_col(fitsOut, TSTRING, col, 1, 1, nRows, strcol, &writeStatus);
+                    break;
+
+                default:
+                    psError(PS_ERR_IO, false, "Don't know IPP type (%d) for mapping from  '%d'  '%s' to '%s'", table->columns[i].ippType,
+                            table->columns[i].ippColNum, table->columns[i].ippName, table->columns[i].pspsName);
+                    break;
+            }
+
+            // TODO need these errors, but strange error handling runs out of memory
+            //if (readStatus) {
+            //    psError(PS_ERR_IO, false, "Unable to read col num '%d' col name '%s', type %d", 
+            //        table->columns[i].ippColNum, table->columns[i].ippName, table->columns[i].ippType);
+            //    fits_report_error(stderr, readStatus);
+            //}
+            //if (writeStatus) {
+            //    psError(PS_ERR_IO, false, "Unable to write col '%s'", table->columns[i].pspsName );
+            //    fits_report_error(stderr, writeStatus);
+            //}
+        }
+    }
+
+    free(int8col);
+    free(int16col);
+    free(longcol);
+    free(floatcol);
+    free(doublecol);
+    for (uint32_t i=0; i<nRows;i++) free(strcol[i]);
+    free(strcol);
+
+    return true;
+}
+
+// creates and populates a table
+bool ippToPspsConfig_writeTable(
+        IppToPspsConfig* this, 
+        fitsfile* fitsIn,
+        fitsfile* fitsOut,
+        const long nRows,
+        const char* tableName,
+        const bool fromHeader) {
+
+
+    IppToPspsConfig_Table* table = ippToPspsConfig_findTable(this, tableName);
+    if (!table) return false;
+
+    if(!ippToPspsConfig_createTable(table, fitsOut, nRows)) return false;
+    return ippToPspsConfig_populateTableFromFits(table, fitsIn, fitsOut, nRows, fromHeader);
+}
+
+// Destructor.
+void ippToPspsConfig_Destructor(IppToPspsConfig* this) {
+
+    if (this != NULL ) {
+
+        // TODO check logic here
+        for (int i=0;i<this->numOfTables;i++)
+            free(this->tables[i].columns);
+
+        free(this->tables);
+        psFree(this->configsPath);
+        free(this);
+    }
+}
+
+// Constructor. Loads IPP -> PSPS mappings from a csv
+IppToPspsConfig* ippToPspsConfig_Constructor(const char* path) {
+
+    IppToPspsConfig* this = NULL;
+
+    this = malloc(sizeof(IppToPspsConfig));
+
+    this->configsPath = NULL;
+    psStringAppend(&this->configsPath, path);
+
+    // load tables descriptions from XML
+    if (ippToPspsConfig_loadTableDescriptions(this)) {
+
+        // load any mappings we may have from XML        
+        ippToPspsConfig_loadMappings(this);
+    }
+
+    return this;
+}
+
Index: trunk/ippToPsps/src/Config.h
===================================================================
--- trunk/ippToPsps/src/Config.h	(revision 30147)
+++ trunk/ippToPsps/src/Config.h	(revision 30147)
@@ -0,0 +1,82 @@
+/** @file ippToPspsConfig.h
+ *
+ *  @brief ippToPsps
+ *
+ *  @ingroup ippToPsps
+ *
+ *  @author IfA
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+#ifndef IPPTOPSPSCONFIG_H
+#define IPPTOPSPSCONFIG_H
+
+#include <psmodules.h>
+
+// column class
+typedef struct {
+
+    int ippColNum;
+    char ippName[100];
+    int ippType;
+    long ippRepeat;
+    char pspsName[100]; // TODO change to 'name'
+    int pspsType;
+    bool usingDefault;
+    char defaultValue[100];
+    char comment[300];
+
+} IppToPspsConfig_Column;
+
+// table class
+typedef struct {
+
+    char name[32];
+    IppToPspsConfig_Column* columns;
+    int numOfColumns;
+
+} IppToPspsConfig_Table;
+
+//  
+typedef struct {
+
+    psString configsPath;
+    IppToPspsConfig_Table* tables;
+    int numOfTables;
+
+} IppToPspsConfig; 
+
+IppToPspsConfig* ippToPspsConfig_Constructor(const char* filePath);
+bool ippToPspsConfig_populateFromFile(IppToPspsConfig* this, fitsfile *fitsOut); // TODO remove
+void ippToPspsConfig_Destructor();
+bool ippToPspsConfig_writeTable(
+        IppToPspsConfig* this,
+        fitsfile* fitsIn,
+        fitsfile* fitsOut,
+        const long nRows,
+        const char* tableName, 
+        const bool fromHeader);
+
+// getters
+bool ippToPspsConfig_getFilterId(IppToPspsConfig* this, const char* filterType, int8_t* filterId);
+bool ippToPspsConfig_getSurveyId(IppToPspsConfig* this, const char* surveyType, int8_t* surveyId);
+bool ippToPspsConfig_getFitsColumnMeta(
+        char* name,
+        int* colNum,
+        int* type,
+        long* repeat,
+        fitsfile *fitsIn);
+
+bool ippToPspsConfig_getColumnVector(
+        int col,
+        long row,
+        int type,
+        int repeat,
+        float* vector,
+        fitsfile *fitsIn);
+
+
+
+
+#endif // IPPTOPSPSCONFIG_H
+
Index: trunk/ippToPsps/src/DetectionBatch.c
===================================================================
--- trunk/ippToPsps/src/DetectionBatch.c	(revision 30147)
+++ trunk/ippToPsps/src/DetectionBatch.c	(revision 30147)
@@ -0,0 +1,553 @@
+#include "DetectionBatch.h"
+#include "DetectionBatchEnums.h"
+
+/**
+  Destructor
+  */
+static void destroy(DetectionBatch* this) {
+
+    // call superclass destructor
+    this->base.destroy(&this->base);
+    free (this->expName);
+    free (this);
+}
+
+/**
+  Does the work.
+  */
+static int run(DetectionBatch* this) {
+
+    if (this->base.exitCode != PS_EXIT_SUCCESS) return this->base.exitCode;
+
+    int status = 0;
+    fitsfile *fitsIn;
+
+    if (fits_open_file(&fitsIn, this->base.inputFiles[0], READONLY, &status)) {
+
+        fits_report_error(stderr, status);
+        return PS_EXIT_SYS_ERROR;
+    }
+
+    // get primary header and pull stuff out for later
+    int nKeys;
+    fits_get_hdrspace(fitsIn, &nKeys, NULL, &status);
+
+    float zptObs, exposureTime;
+    char filterType[20];
+    double obsTime;
+    double expStart;
+    double expTime;
+    status=0; fits_read_key(fitsIn, TFLOAT, "ZPT_OBS", &zptObs, NULL, &status);
+    status=0; fits_read_key(fitsIn, TFLOAT, "EXPREQ", &exposureTime, NULL, &status);
+    status=0; fits_read_key(fitsIn, TSTRING, "FILTERID", filterType, NULL, &status);
+    status=0; fits_read_key(fitsIn, TDOUBLE, "MJD-OBS", &expStart, NULL, &status);
+    status=0; fits_read_key(fitsIn, TDOUBLE, "EXPTIME", &expTime, NULL, &status);
+    obsTime = expStart + (expTime/172800.0); // exp start plus half exp time (converted from secs to days)
+
+    ippToPspsConfig_writeTable(this->base.config, fitsIn, this->base.fitsOut, 1, "FrameMeta", true);
+
+    // FrameMeta values
+    fits_write_col(this->base.fitsOut, TLONG, FRAMEMETA_FRAMEID, 1, 1, 1, &this->expId, &status);
+    fits_write_col(this->base.fitsOut, TSTRING, FRAMEMETA_FRAMENAME, 1, 1, 1, &(this->expName), &status);
+    fits_write_col(this->base.fitsOut, TBYTE, FRAMEMETA_SURVEYID, 1, 1, 1, &this->base.surveyID, &status);
+
+    int8_t filterID = -1;
+    if (!ippToPspsConfig_getFilterId(this->base.config, filterType, &filterID)) {
+    
+        this->base.exitCode = PS_EXIT_DATA_ERROR;
+        return this->base.exitCode;
+    }
+
+    fits_write_col(this->base.fitsOut, TBYTE, FRAMEMETA_FILTERID, 1, 1, 1, &filterID, &status);
+
+    int16_t cameraID = 1; // TODO
+    fits_write_col(this->base.fitsOut, TSHORT, FRAMEMETA_CAMERAID, 1, 1, 1, &cameraID, &status);
+
+    int16_t cameraConfigID = 1; // TODO
+    fits_write_col(this->base.fitsOut, TSHORT, FRAMEMETA_CAMERACONFIGID, 1, 1, 1, &cameraConfigID, &status);
+
+    int16_t telescopeID = 1; // TODO
+    fits_write_col(this->base.fitsOut, TSHORT, FRAMEMETA_TELESCOPEID, 1, 1, 1, &telescopeID, &status);
+
+    // stuff to keep from psf.hdr header
+    int sourceId = -1, imageId = -1;
+    float fwhmMaj, fwhmMin, momentMaj, momentMin, psfFwhm, momentFwhm;
+    long pspsImageId = -1;
+
+    // DVO variables
+    SkyList *skylist = NULL;
+    dvoDetection *dvoDetections = NULL;
+    int maxDvoDetId = -1, numDvoDetections = -1;
+    Image *image = NULL;
+
+    // stuff for detections table
+    uint32_t s,d, invalidDvoRows, smfJumps, unmatched, totalDetections = 0;
+
+    long longnull = -999;
+    float floatnull = -999.0;
+    int anynull = 0;
+
+    char ccdNumber[3], extensionName[15];
+    // for storing FITS column data
+    long* ippIDet = (long*)calloc(this->MAXDETECT, sizeof(long));
+    float* instMag = (float*)calloc(this->MAXDETECT, sizeof(float));
+    float* instMagErr = (float*)calloc(this->MAXDETECT, sizeof(float));
+    float* peakMag = (float*)calloc(this->MAXDETECT, sizeof(float));
+    uint64_t* flags = (uint64_t*)calloc(this->MAXDETECT, sizeof(uint64_t));
+    long* objID = (long*)calloc(this->MAXDETECT, sizeof(long));
+    long* detectID = (long*)calloc(this->MAXDETECT, sizeof(long));
+    long* ippObjID = (long*)calloc(this->MAXDETECT, sizeof(long));
+    long* ippDetectID = (long*)calloc(this->MAXDETECT, sizeof(long));
+    long* imageID = (long*)calloc(this->MAXDETECT, sizeof(long));
+    double* obsTimes = (double*)calloc(this->MAXDETECT, sizeof(double));
+    float* instFlux = (float*)calloc(this->MAXDETECT, sizeof(float));
+    float* instFluxErr = (float*)calloc(this->MAXDETECT, sizeof(float));
+    float* peakFlux = (float*)calloc(this->MAXDETECT, sizeof(float));
+    int8_t* filterIDs = (int8_t*)calloc(this->MAXDETECT, sizeof(int8_t));
+    int8_t* surveyIDs = (int8_t*)calloc(this->MAXDETECT, sizeof(int8_t));
+
+    char** assocDate = (char**)calloc(this->MAXDETECT, sizeof(char*));
+    for (uint32_t i=0; i<this->MAXDETECT;i++) assocDate[i] = (char*)malloc(20*sizeof(char));
+
+    // some stuff is the same for all detections so we can populate here
+    for (long s = 0; s<this->MAXDETECT; s++) {
+
+        filterIDs[s] = filterID;
+        surveyIDs[s] = this->base.surveyID;
+        strcpy(assocDate[s], this->base.todaysDate);
+    }
+
+    long maxObjID = LONG_MIN, minObjID = LONG_MAX;
+    uint64_t imageFlags;
+    short nOta = 0;
+    long i;
+    bool isDuplicate;
+    uint32_t numOfDuplicates, numInvalidFlux;
+    long numDetectionsOut, totalDetectionsOut = 0, numPhotoRef, totalNumPhotoRef = 0;
+    long* removeList = (long*)calloc(this->MAXDETECT, sizeof(long));
+    long thisObjId;
+    bool firstTimeIn = true, peakFluxOk, instFluxOk;
+    int ippIDetNum, instMagNum, instMagErrNum, peakMagNum;
+    bool error = false;
+
+    // loop round all 60 chips
+    for (int x=0; x<8; x++) {
+        for (int y=0; y<8; y++) {
+
+            // dodge the corners
+            if (x==0 && y==0) continue;
+            if (x==0 && y==7) continue;
+            if (x==7 && y==0) continue;
+            if (x==7 && y==7) continue;
+
+            sprintf(ccdNumber, "%d%d", x, y);
+
+            // check we can move to detections table in smf
+            sprintf(extensionName, "XY%s.psf", ccdNumber);
+            status=0;
+            if (fits_movnam_hdu(fitsIn, BINARY_TBL, extensionName, 0, &status)) {
+                psError(PS_ERR_IO, false, "Can't move to extension: %s skipping this chip\n", extensionName);
+                continue;
+            }
+
+            // move to header extension
+            sprintf(extensionName, "XY%s.hdr", ccdNumber);
+            status=0;
+            if (fits_movnam_hdu(fitsIn, IMAGE_HDU, extensionName, 0, &status)) {
+                psError(PS_ERR_IO, false, "Can't move to extension: %s skipping this chip\n", extensionName);
+                continue;
+            }
+
+            // stuff to save from psf.hdr
+            status=0; fits_read_key(fitsIn, TFLOAT, "FWHM_MAJ", &fwhmMaj, NULL, &status);
+            status=0; fits_read_key(fitsIn, TFLOAT, "FWHM_MIN", &fwhmMin, NULL, &status);
+            status=0; fits_read_key(fitsIn, TFLOAT, "IQ_FW1", &momentMaj, NULL, &status);
+            status=0; fits_read_key(fitsIn, TFLOAT, "IQ_FW2", &momentMin, NULL, &status);
+            status=0; fits_read_key(fitsIn, TLONG, "IMAGEID", &imageId, NULL, &status);
+            status=0; fits_read_key(fitsIn, TLONG, "SOURCEID", &sourceId, NULL, &status);
+            status=0; fits_read_key(fitsIn, TLONG, "NASTRO", &numPhotoRef, NULL, &status);
+            totalNumPhotoRef += numPhotoRef; // total up for storing in FrameMeta
+            // access DVO database
+            skylist = dvoSkyListByExternID(this->base.dvoConfig, sourceId, imageId, &image);
+            if (skylist == NULL) {
+                psError(PS_ERR_IO, false,
+                        "DVO: can't find SkyList for sourceId='%d' imageId='%d' (CCD = XY%s): skipping this chip\n",
+                        sourceId, imageId, ccdNumber);
+                continue;
+            }
+
+            // create unique int from 'frameID' (aka exposure ID) and ccd number
+            pspsImageId = (this->expId*100) + image->ccdnum;
+
+            // now get DVO detections
+            dvoDetections = NULL;
+            numDvoDetections = dvoGetDetections(skylist, image->imageID, &dvoDetections, &maxDvoDetId);
+
+
+            if (numDvoDetections > this->MAXDETECT ) {
+
+                psError(PS_ERR_IO, false,
+                        " Number of detections (%d) exceeds max limit (%ld)\n",
+                        numDvoDetections, this->MAXDETECT);
+                error = true;
+                break;
+            }
+
+            // create ImageMeta
+            ippToPspsConfig_writeTable(this->base.config, fitsIn, this->base.fitsOut, 1, "ImageMeta", true);
+            psfFwhm = (fwhmMaj+fwhmMin)/2;
+            momentFwhm = (momentMaj+momentMin)/2;
+            imageFlags = (uint64_t)image->flags;
+            fits_write_col(this->base.fitsOut, TLONGLONG, IMAGEMETA_IMAGEID, 1, 1, 1, &pspsImageId, &status);
+            fits_write_col(this->base.fitsOut, TLONG, IMAGEMETA_FRAMEID, 1, 1, 1, &this->expId, &status);
+            fits_write_col(this->base.fitsOut, TSHORT, IMAGEMETA_CCDID, 1, 1, 1, &image->ccdnum, &status);
+            fits_write_col(this->base.fitsOut, TLONG, IMAGEMETA_PHOTOCALID, 1, 1, 1, &image->photcode, &status);
+            fits_write_col(this->base.fitsOut, TBYTE, IMAGEMETA_FILTERID, 1, 1, 1, &filterID, &status);
+            fits_write_col(this->base.fitsOut, TFLOAT, IMAGEMETA_PHOTOSCAT, 1, 1, 1, &zptObs, &status);
+            fits_write_col(this->base.fitsOut, TFLOAT, IMAGEMETA_PSFFWHM, 1, 1, 1, &psfFwhm, &status);
+            fits_write_col(this->base.fitsOut, TFLOAT, IMAGEMETA_MOMENTFWHM, 1, 1, 1, &momentFwhm, &status);
+            fits_write_col(this->base.fitsOut, TFLOAT, IMAGEMETA_PHOTOZERO, 1, 1, 1, &zptObs, &status);
+            fits_write_col(this->base.fitsOut, TLONGLONG, IMAGEMETA_QAFLAGS, 1, 1, 1, &imageFlags, &status);
+
+            // now move BACK to detections table in smf
+            sprintf(extensionName, "XY%s.psf", ccdNumber);
+            status=0;
+            if (fits_movnam_hdu(fitsIn, BINARY_TBL, extensionName, 0, &status)) {
+                psError(PS_ERR_IO, false, "Can't move to extension: %s skipping\n", extensionName);
+                continue;
+            }
+
+            // keep a running count of 'images' we find in order to write total to FrameMeta at the end
+            nOta++;
+
+            long nDet = 0;
+            if (fits_get_num_rows(fitsIn, &nDet, &status)) {
+                fits_report_error(stderr, status);
+            }
+
+            // loop round detections to populate some extra stuff
+            s = d = totalDetections = invalidDvoRows = smfJumps = unmatched = 0;
+
+            // determine column numbers for certain IPP detection columns
+            if (firstTimeIn) {
+
+                status=0;fits_get_colnum(fitsIn, CASESEN, "IPP_IDET", &ippIDetNum, &status);
+                if (status) psError(PS_ERR_IO, false, "Unable to read col num for IPP_IDET");
+                status=0;fits_get_colnum(fitsIn, CASESEN, "PSF_INST_MAG", &instMagNum, &status);
+                if (status) psError(PS_ERR_IO, false, "Unable to read col num for PSF_INST_MAG");
+                status=0;fits_get_colnum(fitsIn, CASESEN, "PSF_INST_MAG_SIG", &instMagErrNum, &status);
+                if (status) psError(PS_ERR_IO, false, "Unable to read col num for PSF_INST_MAG_SIG");
+                status=0;fits_get_colnum(fitsIn, CASESEN, "PEAK_FLUX_AS_MAG", &peakMagNum, &status);
+                if (status) psError(PS_ERR_IO, false, "Unable to read col num for PEAK_FLUX_AS_MAG");
+
+                firstTimeIn=false;
+            }
+
+            anynull = 0;
+            fits_read_col(fitsIn, TLONG, ippIDetNum, 1, 1, nDet, &longnull, ippIDet, &anynull, &status);
+            fits_read_col(fitsIn, TFLOAT, instMagNum, 1, 1, nDet, &floatnull, instMag, &anynull, &status);
+            fits_read_col(fitsIn, TFLOAT, instMagErrNum, 1, 1, nDet, &floatnull, instMagErr, &anynull, &status);
+            fits_read_col(fitsIn, TFLOAT, peakMagNum, 1, 1, nDet, &floatnull, peakMag, &anynull, &status);
+
+            // DVO detections are ordered by IPP_IDET, which increments from 0 in SMF table
+            // both DVO detections and smf detections should increment. however, there may be gaps in smf and 'invalid' rows in dvo
+            numOfDuplicates = 0;
+            numInvalidFlux = 0;
+            for (long s = 0; s<nDet; s++) {
+
+                isDuplicate = false;
+
+                // count jumps in smf file
+                if (s>0 && (ippIDet[s] != (ippIDet[s-1] + 1))) smfJumps++;
+
+                while (ippIDet[s] > dvoDetections[d].meas.detID && dvoDetections[d].meas.detID <= maxDvoDetId) {
+
+                    d++;
+                    if (!dvoDetections[d].valid) invalidDvoRows++;
+                }
+
+                if (ippIDet[s] == dvoDetections[d].meas.detID ) {
+
+                    // TODO HACK duplicates bug - don't include any duplicates
+                    thisObjId = dvoDetections[d].ave.extID;
+                    for (i=0; i<totalDetections; i++) {
+                        if (thisObjId == objID[i]) {
+                            removeList[numOfDuplicates+numInvalidFlux] = s+1;
+                            numOfDuplicates++;
+                            isDuplicate=true;
+                            break;
+                        }
+                    }
+                    // populate some arrays to be shoved in table in bulk later
+                    objID[s] = thisObjId;
+                    detectID[s] = dvoDetections[d].meas.extID;
+                    ippObjID[s] = (uint64_t)dvoDetections[d].ave.catID*1000000000 + (uint64_t)dvoDetections[d].ave.objID;
+                    ippDetectID[s] = dvoDetections[d].meas.detID;
+
+                    // the 'photFlags' are the same as those in the 'FLAGS' column of the smf
+                    flags[s] = ((uint64_t)dvoDetections[d].meas.dbFlags << 32) | (uint64_t)dvoDetections[d].meas.photFlags;
+                    imageID[s] = pspsImageId;
+                    obsTimes[s] = obsTime;
+
+                    // calculate flux and flux errors from magnitudes
+                    peakFluxOk = getFlux(exposureTime, peakMag[s], &peakFlux[s], 0.0, NULL);
+                    instFluxOk = getFlux(exposureTime, instMag[s], &instFlux[s], instMagErr[s], &instFluxErr[s]);
+
+                    // check for invalid flux values (if not already labelled as a duplicate)
+                    if ( (!peakFluxOk || !instFluxOk) && !isDuplicate) {
+                        removeList[numOfDuplicates+numInvalidFlux] = s+1;
+                        numInvalidFlux++;
+                    }
+                    else {
+
+                        // store max/min objID
+                        if (objID[s] > maxObjID) maxObjID = objID[s];
+                        if (objID[s] < minObjID) minObjID = objID[s];
+                    }
+                    totalDetections++;
+                }
+                // if we get here then we cannot find this smf detection in DVO 
+                else {
+
+                    unmatched++;
+                    continue;
+                }
+
+                if (dvoDetections[d].meas.detID == maxDvoDetId) break;
+            }
+
+            // write number of rows (detections) to ImageMeta
+            numDetectionsOut = totalDetections - numOfDuplicates - numInvalidFlux;
+            fits_write_col(this->base.fitsOut, TLONG, IMAGEMETA_NDETECT, 1, 1, 1, &numDetectionsOut, &status);
+
+            // avoid writing out an empty table of detections
+            if (numDetectionsOut > 0) {
+
+                // detections
+                ippToPspsConfig_writeTable(this->base.config, fitsIn, this->base.fitsOut, nDet, "Detection", false);
+                fits_write_col(this->base.fitsOut, TLONGLONG, DETECTION_OBJID, 1, 1, nDet, objID, &status);
+                fits_write_col(this->base.fitsOut, TLONGLONG, DETECTION_DETECTID, 1, 1, nDet, detectID, &status);
+                fits_write_col(this->base.fitsOut, TLONGLONG, DETECTION_IPPOBJID, 1, 1, nDet, ippObjID, &status);
+                fits_write_col(this->base.fitsOut, TLONGLONG, DETECTION_IPPDETECTID, 1, 1, nDet, ippDetectID, &status);
+                fits_write_col(this->base.fitsOut, TBYTE, DETECTION_FILTERID, 1, 1, nDet, filterIDs, &status);
+                fits_write_col(this->base.fitsOut, TBYTE, DETECTION_SURVEYID, 1, 1, nDet, surveyIDs, &status);
+                fits_write_col(this->base.fitsOut, TLONGLONG, DETECTION_IMAGEID, 1, 1, nDet, imageID, &status);
+                fits_write_col(this->base.fitsOut, TDOUBLE, DETECTION_OBSTIME, 1, 1, nDet, obsTimes, &status);
+                fits_write_col(this->base.fitsOut, TFLOAT, DETECTION_INSTFLUX, 1, 1, nDet, instFlux, &status);
+                fits_write_col(this->base.fitsOut, TFLOAT, DETECTION_INSTFLUXERR, 1, 1, nDet, instFluxErr, &status);
+                fits_write_col(this->base.fitsOut, TFLOAT, DETECTION_PEAKADU, 1, 1, nDet, peakFlux, &status);
+                fits_write_col(this->base.fitsOut, TSTRING, DETECTION_ASSOCDATE, 1, 1, nDet, assocDate, &status);
+                fits_write_col(this->base.fitsOut, TLONGLONG, DETECTION_INFOFLAG, 1, 1, nDet, flags, &status);
+                if (numOfDuplicates||numInvalidFlux) fits_delete_rowlist(this->base.fitsOut, removeList, numOfDuplicates+numInvalidFlux, &status);
+
+                // skinny object
+                ippToPspsConfig_writeTable(this->base.config, fitsIn, this->base.fitsOut, nDet, "SkinnyObject", false);
+                fits_write_col(this->base.fitsOut, TLONGLONG, SKINNYOBJECT_OBJID, 1, 1, nDet, objID, &status);
+                fits_write_col(this->base.fitsOut, TLONGLONG, SKINNYOBJECT_IPPOBJID, 1, 1, nDet, ippObjID, &status);
+                fits_write_col(this->base.fitsOut, TBYTE, SKINNYOBJECT_SURVEYID, 1, 1, nDet, surveyIDs, &status);
+                if (numOfDuplicates||numInvalidFlux) fits_delete_rowlist(this->base.fitsOut, removeList, numOfDuplicates+numInvalidFlux, &status);
+
+                // object calibration color
+                ippToPspsConfig_writeTable(this->base.config, fitsIn, this->base.fitsOut, nDet, "ObjectCalColor", false);
+                fits_write_col(this->base.fitsOut, TLONGLONG, OBJECTCALCOLOR_OBJID, 1, 1, nDet, objID, &status);
+                fits_write_col(this->base.fitsOut, TLONGLONG, OBJECTCALCOLOR_IPPOBJID, 1, 1, nDet, ippObjID, &status);
+                fits_write_col(this->base.fitsOut, TBYTE, OBJECTCALCOLOR_FILTERID, 1, 1, nDet, filterIDs, &status);
+                if (numOfDuplicates||numInvalidFlux) fits_delete_rowlist(this->base.fitsOut, removeList, numOfDuplicates+numInvalidFlux, &status);
+            }
+
+            psLogMsg("ippToPsps", PS_LOG_INFO,
+                    "+-----------+---------+----------+------------------+---------------+--------------+\n"
+                    "| Extension | Rows in | Rows out | Missing from DVO | Duplicate IDs | Invalid Flux |\n"
+                    "|  %s |  %5ld  |   %5ld  |      %5d       |    %5d      |    %5d     |\n",
+                    extensionName, nDet, numDetectionsOut, unmatched, numOfDuplicates, numInvalidFlux);
+
+            totalDetectionsOut += numDetectionsOut;
+
+            if (dvoDetections!= NULL) dvoFree(dvoDetections);
+            SkyListFree(skylist);
+        }
+
+        if (error) break;
+    }
+
+    psLogMsg("ippToPsps", PS_LOG_INFO, "Total detections for this exposure = %ld\n", totalDetectionsOut);
+
+    // free-up memory
+    free(ippIDet);
+    free(instMag);
+    free(instMagErr);
+    free(peakMag);
+    free(flags);
+    free(objID);
+    free(detectID);
+    free(ippObjID);
+    free(ippDetectID);
+    free(imageID);
+    free(obsTimes);
+    free(instFlux);
+    free(instFluxErr);
+    free(peakFlux);
+    free(filterIDs);
+    free(surveyIDs);
+    free(removeList);
+    for (uint32_t i=0; i<this->MAXDETECT;i++) free(assocDate[i]);
+    free(assocDate);
+
+    // write number of images we have found into FrameMeta table
+    status=0;
+    if (fits_movnam_hdu(this->base.fitsOut, BINARY_TBL, "FrameMeta", 0, &status))
+        psError(PS_ERR_IO, false, "Can't move back to FrameMeta extension to write number of OTAs\n");
+    else {
+        fits_write_col(this->base.fitsOut, TSHORT, FRAMEMETA_NOTA, 1, 1, 1, &nOta, &status);
+        fits_write_col(this->base.fitsOut, TSHORT, FRAMEMETA_NUMPHOTOREF, 1, 1, 1, &totalNumPhotoRef, &status);
+    }
+    status=0;
+    if (fits_close_file(fitsIn, &status)) fits_report_error(stderr, status);
+    // write results
+    if (this->base.resultsXmlDoc) {
+
+        xmlNodePtr rootNode = xmlDocGetRootElement(this->base.resultsXmlDoc);
+        char tmp[100];
+        sprintf(tmp, "%ld", minObjID);
+        xmlNewChild(rootNode, NULL, BAD_CAST "minObjID", BAD_CAST tmp);
+        sprintf(tmp, "%ld", maxObjID);
+        xmlNewChild(rootNode, NULL, BAD_CAST "maxObjID", BAD_CAST tmp);
+        sprintf(tmp, "%ld", totalDetectionsOut);
+        xmlNewChild(rootNode, NULL, BAD_CAST "totalDetections", BAD_CAST tmp);
+    }
+
+    psLogMsg("ippToPsps", PS_LOG_INFO, "Data written for a total of %d chips/OTAs", nOta);
+
+    if (error || nOta < 1) this->base.exitCode = PS_EXIT_DATA_ERROR;
+    else this->base.exitCode = PS_EXIT_SUCCESS;
+
+    return this->base.exitCode;
+}
+
+
+/**
+  Print-out this class. Calls base-calls print method first.
+  */
+static void print(DetectionBatch* this) {
+
+    this->base.print(&this->base);
+
+    printf("* exp ID          : %d\n", this->expId);
+    printf("* exp name        : '%s'\n",  this->expName ? this->expName : "undef");
+    printf("\n");
+}
+
+/**
+  Reads command-line arguments.  Calls base-calls print method first.
+  */
+static bool parseArguments(DetectionBatch* this, int argc, char **argv) {
+
+    bool haveExpId = false;
+    bool haveExpName = false;
+
+    int32_t optind = 1;
+    while( ( optind < argc ) ) {
+
+        char * sw = argv[optind];
+
+        if( argv[optind][0] == '-' ) { 
+
+            if(strcmp(sw, "-expid") == 0 ) {
+                optind++; if( optind > ( argc-1 ) ) break;
+                this->expId = atoi(argv[optind]);
+                haveExpId = true;
+            }
+            else if(strcmp(sw, "-expname") == 0 ) {
+                optind++; if( optind > ( argc-1 ) ) break;
+                strcpy(this->expName, argv[optind]);
+                haveExpName = true;
+            }
+        }
+        optind++;
+    }
+
+    this->base.parseArguments(&this->base, argc, argv);
+
+    if (
+            !this->base.gotResultsPath() ||
+            !this->base.gotFitsInPath() ||
+            !this->base.gotFitsOutPath() ||
+            !this->base.gotConfig() ||
+            !this->base.gotSurveyType() ||
+            !haveExpId || 
+            !haveExpName) {
+
+        printf("\n* ERROR with supplied arguments:");
+        this->print(this);
+        this->base.exitCode = PS_EXIT_CONFIG_ERROR;
+        return false;
+    }
+
+    return true;
+}
+
+/**
+  Constructor
+  */
+DetectionBatch* new_DetectionBatch(int *argc, char **argv) {
+
+    DetectionBatch *this = (DetectionBatch*)calloc(1, sizeof(DetectionBatch));
+
+    // call base-class constructor
+    if (!new_Batch(&this->base)) {
+
+        psError(PS_ERR_IO, false, "Unable to create Batch base-class object");
+        return this;
+    }
+
+    this->MAXDETECT = 150000;
+
+    this->print = print;
+    this->destroy = destroy;
+    this->base.run = run;
+
+    this->expName = (char*)calloc(100, sizeof(char));
+
+    if (!parseArguments(this, *argc, argv)) { return this; }
+
+    strcat(this->base.configsDir, "/detection");
+    sprintf(this->base.fitsOutFile, "%08d.FITS", this->expId);
+
+    this->base.init(&this->base);
+
+    return this;
+}
+
+/**
+  Main
+  */
+int main(int argc, char **argv) {
+
+    psTimerStart("detectionbatch");
+
+    ippToPsps_VersionPrint();
+
+    int exitCode;
+
+    DetectionBatch* detectionBatch = new_DetectionBatch(&argc, argv);
+    detectionBatch->base.run(detectionBatch);
+    exitCode = detectionBatch->base.exitCode;
+
+    detectionBatch->destroy(detectionBatch);
+
+    double secs = psTimerMark("ippToPsps");
+
+    psLogMsg("detectionbatch", 3, "detectionbatch completed %ssuccessfully, with exit code %d, in %.1f %s\n",
+            (exitCode == PS_EXIT_SUCCESS) ? "" : "un",
+            exitCode,
+            (secs<60.0) ? secs : (secs/60.0),
+            (secs<60.0) ? "sec(s)" : "min(s)");
+
+    // tidy up
+    psTimerStop();
+    psLibFinalize();
+
+    return exitCode;
+}
+
+
Index: trunk/ippToPsps/src/DetectionBatch.h
===================================================================
--- trunk/ippToPsps/src/DetectionBatch.h	(revision 30147)
+++ trunk/ippToPsps/src/DetectionBatch.h	(revision 30147)
@@ -0,0 +1,35 @@
+/** @file DetectionBatch.h
+ *
+ *  @brief DetectionBatch
+ *
+ *  @ingroup ippToPsps
+ *
+ *  @author IfA
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+#ifndef IPPTOPSPS_DETECTIONBATCH_H
+#define IPPTOPSPS_DETECTIONBATCH_H
+
+#include "Batch.h"
+
+/**
+  Sub-class of Batch for detections
+  */
+typedef struct DetectionBatch {
+
+    // fields
+    Batch base;             // base class
+    size_t MAXDETECT;    // max number of detections
+    uint32_t expId;         // exposure ID
+    char* expName;      // the exposure name
+
+    // methods
+    void (*print)();
+    void (*destroy)();
+
+} DetectionBatch;
+
+DetectionBatch *new_DetectionBatch(int *argc, char **argv);
+
+# endif // IPPTOPSPS_DETECTIONBATCH_H 
Index: trunk/ippToPsps/src/DetectionBatchEnums.h
===================================================================
--- trunk/ippToPsps/src/DetectionBatchEnums.h	(revision 30147)
+++ trunk/ippToPsps/src/DetectionBatchEnums.h	(revision 30147)
@@ -0,0 +1,181 @@
+#ifndef DETECTIONBATCHENUMS_H
+#define DETECTIONBATCHENUMS_H
+
+
+typedef enum {
+  FRAMEMETA_FRAMEID = 1,
+  FRAMEMETA_FRAMENAME = 2,
+  FRAMEMETA_SURVEYID = 3,
+  FRAMEMETA_FILTERID = 4,
+  FRAMEMETA_CAMERAID = 5,
+  FRAMEMETA_CAMERACONFIGID = 6,
+  FRAMEMETA_TELESCOPEID = 7,
+  FRAMEMETA_ANALYSISVER = 8,
+  FRAMEMETA_P1RECIP = 9,
+  FRAMEMETA_P2RECIP = 10,
+  FRAMEMETA_P3RECIP = 11,
+  FRAMEMETA_NOTA = 12,
+  FRAMEMETA_PHOTOSCAT = 13,
+  FRAMEMETA_NUMPHOTOREF = 14,
+  FRAMEMETA_EXPSTART = 15,
+  FRAMEMETA_EXPTIME = 16,
+  FRAMEMETA_AIRMASS = 17,
+  FRAMEMETA_RABORE = 18,
+  FRAMEMETA_DECBORE = 19,
+  FRAMEMETA_CTYPE1 = 20,
+  FRAMEMETA_CTYPE2 = 21,
+  FRAMEMETA_CRVAL1 = 22,
+  FRAMEMETA_CRVAL2 = 23,
+  FRAMEMETA_CRPIX1 = 24,
+  FRAMEMETA_CRPIX2 = 25,
+  FRAMEMETA_CDELT1 = 26,
+  FRAMEMETA_CDELT2 = 27,
+  FRAMEMETA_PC001001 = 28,
+  FRAMEMETA_PC001002 = 29,
+  FRAMEMETA_PC002001 = 30,
+  FRAMEMETA_PC002002 = 31,
+  FRAMEMETA_POLYORDER = 32,
+  FRAMEMETA_PCA1X3Y0 = 33,
+  FRAMEMETA_PCA1X2Y1 = 34,
+  FRAMEMETA_PCA1X1Y2 = 35,
+  FRAMEMETA_PCA1X0Y3 = 36,
+  FRAMEMETA_PCA1X2Y0 = 37,
+  FRAMEMETA_PCA1X1Y1 = 38,
+  FRAMEMETA_PCA1X0Y2 = 39,
+  FRAMEMETA_PCA2X3Y0 = 40,
+  FRAMEMETA_PCA2X2Y1 = 41,
+  FRAMEMETA_PCA2X1Y2 = 42,
+  FRAMEMETA_PCA2X0Y3 = 43,
+  FRAMEMETA_PCA2X2Y0 = 44,
+  FRAMEMETA_PCA2X1Y1 = 45,
+  FRAMEMETA_PCA2X0Y2 = 46,
+  FRAMEMETA_CALIBMODNUM = 47,
+  FRAMEMETA_DATARELEASE = 48,
+} FrameMeta;
+
+typedef enum {
+  IMAGEMETA_IMAGEID = 1,
+  IMAGEMETA_FRAMEID = 2,
+  IMAGEMETA_CCDID = 3,
+  IMAGEMETA_PHOTOCALID = 4,
+  IMAGEMETA_FILTERID = 5,
+  IMAGEMETA_BIAS = 6,
+  IMAGEMETA_BIASSCAT = 7,
+  IMAGEMETA_SKY = 8,
+  IMAGEMETA_SKYSCAT = 9,
+  IMAGEMETA_NDETECT = 10,
+  IMAGEMETA_MAGSAT = 11,
+  IMAGEMETA_COMPLETMAG = 12,
+  IMAGEMETA_ASTROSCAT = 13,
+  IMAGEMETA_PHOTOSCAT = 14,
+  IMAGEMETA_NUMASTROREF = 15,
+  IMAGEMETA_NUMPHOTOREF = 16,
+  IMAGEMETA_NX = 17,
+  IMAGEMETA_NY = 18,
+  IMAGEMETA_PSFMODELID = 19,
+  IMAGEMETA_PSFFWHM = 20,
+  IMAGEMETA_PSFWIDMAJOR = 21,
+  IMAGEMETA_PSFWIDMINOR = 22,
+  IMAGEMETA_PSFTHETA = 23,
+  IMAGEMETA_MOMENTFWHM = 24,
+  IMAGEMETA_MOMENTWIDMAJOR = 25,
+  IMAGEMETA_MOMENTWIDMINOR = 26,
+  IMAGEMETA_APRESID = 27,
+  IMAGEMETA_DAPRESID = 28,
+  IMAGEMETA_DETECTORID = 29,
+  IMAGEMETA_QAFLAGS = 30,
+  IMAGEMETA_DETREND1 = 31,
+  IMAGEMETA_DETREND2 = 32,
+  IMAGEMETA_DETREND3 = 33,
+  IMAGEMETA_DETREND4 = 34,
+  IMAGEMETA_DETREND5 = 35,
+  IMAGEMETA_DETREND6 = 36,
+  IMAGEMETA_DETREND7 = 37,
+  IMAGEMETA_DETREND8 = 38,
+  IMAGEMETA_PHOTOZERO = 39,
+  IMAGEMETA_CTYPE1 = 40,
+  IMAGEMETA_CTYPE2 = 41,
+  IMAGEMETA_CRVAL1 = 42,
+  IMAGEMETA_CRVAL2 = 43,
+  IMAGEMETA_CRPIX1 = 44,
+  IMAGEMETA_CRPIX2 = 45,
+  IMAGEMETA_CDELT1 = 46,
+  IMAGEMETA_CDELT2 = 47,
+  IMAGEMETA_PC001001 = 48,
+  IMAGEMETA_PC001002 = 49,
+  IMAGEMETA_PC002001 = 50,
+  IMAGEMETA_PC002002 = 51,
+  IMAGEMETA_POLYORDER = 52,
+  IMAGEMETA_PCA1X3Y0 = 53,
+  IMAGEMETA_PCA1X2Y1 = 54,
+  IMAGEMETA_PCA1X1Y2 = 55,
+  IMAGEMETA_PCA1X0Y3 = 56,
+  IMAGEMETA_PCA1X2Y0 = 57,
+  IMAGEMETA_PCA1X1Y1 = 58,
+  IMAGEMETA_PCA1X0Y2 = 59,
+  IMAGEMETA_PCA2X3Y0 = 60,
+  IMAGEMETA_PCA2X2Y1 = 61,
+  IMAGEMETA_PCA2X1Y2 = 62,
+  IMAGEMETA_PCA2X0Y3 = 63,
+  IMAGEMETA_PCA2X2Y0 = 64,
+  IMAGEMETA_PCA2X1Y1 = 65,
+  IMAGEMETA_PCA2X0Y2 = 66,
+  IMAGEMETA_CALIBMODNUM = 67,
+  IMAGEMETA_DATARELEASE = 68,
+} ImageMeta;
+
+typedef enum {
+  DETECTION_OBJID = 1,
+  DETECTION_DETECTID = 2,
+  DETECTION_IPPOBJID = 3,
+  DETECTION_IPPDETECTID = 4,
+  DETECTION_FILTERID = 5,
+  DETECTION_SURVEYID = 6,
+  DETECTION_IMAGEID = 7,
+  DETECTION_OBSTIME = 8,
+  DETECTION_XPOS = 9,
+  DETECTION_YPOS = 10,
+  DETECTION_XPOSERR = 11,
+  DETECTION_YPOSERR = 12,
+  DETECTION_INSTFLUX = 13,
+  DETECTION_INSTFLUXERR = 14,
+  DETECTION_PEAKADU = 15,
+  DETECTION_PSFWIDMAJOR = 16,
+  DETECTION_PSFWIDMINOR = 17,
+  DETECTION_PSFTHETA = 18,
+  DETECTION_PSFLIKELIHOOD = 19,
+  DETECTION_PSFCF = 20,
+  DETECTION_MOMENTXX = 21,
+  DETECTION_MOMENTXY = 22,
+  DETECTION_MOMENTYY = 23,
+  DETECTION_CRLIKELIHOOD = 24,
+  DETECTION_EXTENDEDLIKELIHOOD = 25,
+  DETECTION_INFOFLAG = 26,
+  DETECTION_SKY = 27,
+  DETECTION_SKYERR = 28,
+  DETECTION_SGSEP = 29,
+  DETECTION_ACTIVEFLAG = 30,
+  DETECTION_ASSOCDATE = 31,
+  DETECTION_HISTORYMODNUM = 32,
+  DETECTION_DATARELEASE = 33,
+} Detection;
+
+typedef enum {
+  SKINNYOBJECT_OBJID = 1,
+  SKINNYOBJECT_IPPOBJID = 2,
+  SKINNYOBJECT_PROJECTIONCELLID = 3,
+  SKINNYOBJECT_DATARELEASE = 4,
+  SKINNYOBJECT_SURVEYID = 5,
+} SkinnyObject;
+
+typedef enum {
+  OBJECTCALCOLOR_OBJID = 1,
+  OBJECTCALCOLOR_IPPOBJID = 2,
+  OBJECTCALCOLOR_FILTERID = 3,
+  OBJECTCALCOLOR_CALCOLOR = 4,
+  OBJECTCALCOLOR_CALCOLORERR = 5,
+  OBJECTCALCOLOR_CALIBMODNUM = 6,
+  OBJECTCALCOLOR_DATARELEASE = 7,
+} ObjectCalColor;
+
+#endif
Index: trunk/ippToPsps/src/DiffBatchEnums.h
===================================================================
--- trunk/ippToPsps/src/DiffBatchEnums.h	(revision 30147)
+++ trunk/ippToPsps/src/DiffBatchEnums.h	(revision 30147)
@@ -0,0 +1,99 @@
+#ifndef DIFFBATCHENUMS_H
+#define DIFFBATCHENUMS_H
+
+
+typedef enum {
+  STACKMETA_STACKMETAID = 1,
+  STACKMETA_SKYCELLID = 2,
+  STACKMETA_SURVEYID = 3,
+  STACKMETA_PHOTOCALID = 4,
+  STACKMETA_FILTERID = 5,
+  STACKMETA_STACKTYPEID = 6,
+  STACKMETA_STACKGROUPID = 7,
+  STACKMETA_MAGSAT = 8,
+  STACKMETA_ANALVER = 9,
+  STACKMETA_NP2IMAGES = 10,
+  STACKMETA_COMPLETMAG = 11,
+  STACKMETA_ASTROSCAT = 12,
+  STACKMETA_PHOTOSCAT = 13,
+  STACKMETA_NASTROREF = 14,
+  STACKMETA_NPHOREF = 15,
+  STACKMETA_MEAN = 16,
+  STACKMETA_MAX = 17,
+  STACKMETA_PHOTOZERO = 18,
+  STACKMETA_PHOTOCOLOR = 19,
+  STACKMETA_CTYPE1 = 20,
+  STACKMETA_CTYPE2 = 21,
+  STACKMETA_CRVAL1 = 22,
+  STACKMETA_CRVAL2 = 23,
+  STACKMETA_CRPIX1 = 24,
+  STACKMETA_CRPIX2 = 25,
+  STACKMETA_CDELT1 = 26,
+  STACKMETA_CDELT2 = 27,
+  STACKMETA_PC001001 = 28,
+  STACKMETA_PC001002 = 29,
+  STACKMETA_PC002001 = 30,
+  STACKMETA_PC002002 = 31,
+  STACKMETA_CALIBMODNUM = 32,
+  STACKMETA_DATARELEASE = 33,
+} StackMeta;
+
+typedef enum {
+  STACKTOIMAGE_STACKMETAID = 1,
+  STACKTOIMAGE_IMAGEID = 2,
+} StackToImage;
+
+typedef enum {
+  STACKLOWSIGDELTA_STACKMETAID = 1,
+  STACKLOWSIGDELTA_DATATABLE = 2,
+  STACKLOWSIGDELTA_DATARELEASE = 3,
+} StackLowSigDelta;
+
+typedef enum {
+  STACKHIGHSIGDELTA_PARTITIONKEY = 1,
+  STACKHIGHSIGDELTA_STACKDIFFID = 2,
+  STACKHIGHSIGDELTA_IPPDETECTID = 3,
+  STACKHIGHSIGDELTA_FILTERID = 4,
+  STACKHIGHSIGDELTA_OBSTIME = 5,
+  STACKHIGHSIGDELTA_XPOS = 6,
+  STACKHIGHSIGDELTA_YPOS = 7,
+  STACKHIGHSIGDELTA_XPOSERR = 8,
+  STACKHIGHSIGDELTA_YPOSERR = 9,
+  STACKHIGHSIGDELTA_INSTMAG = 10,
+  STACKHIGHSIGDELTA_INSTMAGERR = 11,
+  STACKHIGHSIGDELTA_PEAKFLUXMAG = 12,
+  STACKHIGHSIGDELTA_PSFWIDMAJOR = 13,
+  STACKHIGHSIGDELTA_PSFWIDMINOR = 14,
+  STACKHIGHSIGDELTA_PSFTHETA = 15,
+  STACKHIGHSIGDELTA_PSFLIKELIHOOD = 16,
+  STACKHIGHSIGDELTA_PSFCF = 17,
+  STACKHIGHSIGDELTA_INFOFLAG = 18,
+  STACKHIGHSIGDELTA_NFRAMES = 19,
+  STACKHIGHSIGDELTA_HTMID = 20,
+  STACKHIGHSIGDELTA_ZONEID = 21,
+  STACKHIGHSIGDELTA_RA = 22,
+  STACKHIGHSIGDELTA_DEC = 23,
+  STACKHIGHSIGDELTA_RAERR = 24,
+  STACKHIGHSIGDELTA_DECERR = 25,
+  STACKHIGHSIGDELTA_CX = 26,
+  STACKHIGHSIGDELTA_CY = 27,
+  STACKHIGHSIGDELTA_CZ = 28,
+  STACKHIGHSIGDELTA_CALMAG = 29,
+  STACKHIGHSIGDELTA_CALMAGERR = 30,
+  STACKHIGHSIGDELTA_SKY = 31,
+  STACKHIGHSIGDELTA_SKYERR = 32,
+  STACKHIGHSIGDELTA_SGSEP = 33,
+  STACKHIGHSIGDELTA_DATARELEASE = 34,
+} StackHighSigDelta;
+
+typedef enum {
+  OBJECTCALCOLOR_OBJID = 1,
+  OBJECTCALCOLOR_IPPOBJID = 2,
+  OBJECTCALCOLOR_FILTERID = 3,
+  OBJECTCALCOLOR_CALCOLOR = 4,
+  OBJECTCALCOLOR_CALCOLORERR = 5,
+  OBJECTCALCOLOR_CALIBMODNUM = 6,
+  OBJECTCALCOLOR_DATARELEASE = 7,
+} ObjectCalColor;
+
+#endif
Index: trunk/ippToPsps/src/DifferenceBatch.c
===================================================================
--- trunk/ippToPsps/src/DifferenceBatch.c	(revision 30147)
+++ trunk/ippToPsps/src/DifferenceBatch.c	(revision 30147)
@@ -0,0 +1,119 @@
+/** @file ippToPspsBatchDifference.c
+ *
+ *  @ingroup ippToPsps
+ *
+ *  @author IfA
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+#include "ippToPsps.h"
+#include "ippToPspsConfig.h"
+#include "ippToPspsDiffEnums.h"
+
+/**
+  \brief Loops round all the diff cmf files (one per skycell) and generates one FITS  
+  */
+int ippToPsps_batchDifference(IppToPsps *this) {
+
+    if (this->numOfInputFiles < 1) return PS_EXIT_DATA_ERROR;
+
+    uint32_t skycell = 0; // TODO
+    long tableSize;
+    float SIG_CONST = 5.0; // TODO
+    double obsTime;
+    float obsTimes[MAXDETECT];
+
+    char skycellStr[10];
+    char extensionName[20];
+    sprintf(extensionName, "SkyChip.psf");
+
+    int status;
+    fitsfile *fitsIn;         
+    int nKeys;
+    status=0;
+
+    float psfSigma[MAXDETECT];
+    long numLowSig = 0;
+    long numHighSig = 0;
+    long highSig[MAXDETECT];
+    long lowSig[MAXDETECT];
+    int anynull = 0;
+    float floatnull = -999.0;
+
+    for (uint16_t i = 0; i<this->numOfInputFiles; i++) {
+
+        if (fits_open_file(&fitsIn, this->inputFiles[i], READONLY, &status)) {
+
+            psError(PS_ERR_IO, false, "Unable to open file: '%s'", this->inputFiles[i]);
+            break; 
+        }
+
+        //psLogMsg("ippToPsps", PS_LOG_INFO,"Opened %s", this->inputFiles[i]);
+
+        skycell = i; // TODO
+        sprintf(skycellStr, "SC%03d", skycell);
+
+        // build StackMeta from primary header
+        fits_get_hdrspace(fitsIn, &nKeys, NULL, &status);
+        ippToPspsConfig_writeTable(this->config, fitsIn,  this->fitsOut, 1, "StackMeta", true);
+        fits_write_col(this->fitsOut, TLONG, STACKMETA_SKYCELLID, 1, 1, 1, &skycell, &status);
+
+        // build StackToImage
+        ippToPspsConfig_writeTable(this->config, fitsIn,  this->fitsOut, 1, "StackToImage", true);
+        //  psMetadataAdd(headerOut, PS_LIST_TAIL, "SKYCELL_ID", PS_DATA_S32, "Skycell ID", skycell);
+
+        // save some stuff for later
+        status=0; fits_read_key(fitsIn, TDOUBLE, "MJD-OBS", &obsTime, NULL, &status);
+
+        if (fits_movnam_hdu(fitsIn, BINARY_TBL, extensionName, 0, &status)) {
+            psError(PS_ERR_IO, false, "Can't move to extension: %s skipping\n", extensionName);
+            continue;
+        }
+        if (fits_get_num_rows(fitsIn, &tableSize, &status)) {
+            psError(PS_ERR_IO, false, "Can't count rows in extension: %s skipping\n", extensionName);
+            continue;
+        }
+
+        numLowSig = numHighSig = 0;
+
+        //  get magnitude error (PSF_INST_MAG_SIG)
+        fits_read_col(fitsIn, TFLOAT, 9, 1, 1, tableSize, &floatnull, psfSigma, &anynull, &status);
+
+        for (long j = 0; j<tableSize; j++) {
+
+            obsTimes[j] = obsTime;
+
+            // split between low and high 'significance difference detections'
+            if (psfSigma[j] > (1.0/SIG_CONST)) {
+
+                //     psMetadataAdd(rowOut, 0, "stackMetaID", PS_DATA_S64, "reference to stack", 0); // TODO
+                lowSig[numLowSig] = j+1;
+                numLowSig++;
+            }
+            else {
+
+                highSig[numHighSig] = j+1;
+                numHighSig++;
+            }
+        }
+
+        psLogMsg("ippToPsps", PS_LOG_INFO, 
+                "Reading skycell '%d'. High significant detections = %ld low significant detections = %ld", 
+                skycell, numHighSig, numLowSig);
+
+        //  psMetadataAdd(headerOut, PS_LIST_TAIL, "SKYCELL_ID", PS_DATA_S32, "Skycell ID", skycell);
+
+        // write out low and high significant tables
+        ippToPspsConfig_writeTable(this->config, fitsIn, this->fitsOut, 1, "StackLowSigDelta", false);
+        ippToPspsConfig_writeTable(this->config, fitsIn, this->fitsOut, tableSize, "StackHighSigDelta", false);
+        fits_write_col(this->fitsOut, TFLOAT, STACKHIGHSIGDELTA_OBSTIME, 1, 1, tableSize, obsTimes, &status);
+        if (numLowSig) fits_delete_rowlist(this->fitsOut, lowSig, numLowSig, &status);
+
+
+        //   psMetadataAdd(headerOut, PS_LIST_TAIL, "SKYCELL_ID", PS_DATA_S32, "Skycell ID", skycell);
+
+        if (fits_close_file(fitsIn, &status)) fits_report_error(stderr, status);
+    }
+
+    return PS_EXIT_SUCCESS;
+}
Index: trunk/ippToPsps/src/InitBatch.c
===================================================================
--- trunk/ippToPsps/src/InitBatch.c	(revision 30147)
+++ trunk/ippToPsps/src/InitBatch.c	(revision 30147)
@@ -0,0 +1,116 @@
+#include "InitBatch.h"
+
+/**
+  Destructor
+  */
+static void destroy(InitBatch* this) {
+
+    // call superclass destructor
+    this->base.destroy(&this->base);
+    free (this);
+}
+
+/**
+  Does the work.
+  */
+static int run(InitBatch* this) {
+
+    if (this->base.exitCode != PS_EXIT_SUCCESS) return this->base.exitCode;
+
+    if (!ippToPspsConfig_populateFromFile(this->base.config, this->base.fitsOut)) 
+        this->base.exitCode = PS_EXIT_CONFIG_ERROR;
+    else this->base.exitCode = PS_EXIT_SUCCESS;
+
+    return this->base.exitCode;
+}
+
+/**
+  Print-out this class. Calls base-calls print method first.
+  */
+static void print(InitBatch* this) {
+
+    this->base.print(&this->base);
+}
+
+/**
+  Reads command-line arguments.  Calls base-calls print method first.
+  */
+static bool parseArguments(InitBatch* this, int argc, char **argv) {
+
+    this->base.parseArguments(&this->base, argc, argv);
+
+    if (
+            !this->base.gotFitsOutPath() ||
+            !this->base.gotConfig() ) {
+
+        printf("\n* ERROR with supplied arguments:");
+        this->print(this);
+        this->base.exitCode = PS_EXIT_CONFIG_ERROR;
+        return false;
+    }
+
+
+    return true;
+}
+
+/**
+  Constructor
+  */
+InitBatch* new_InitBatch(int *argc, char **argv) {
+
+    InitBatch *this = (InitBatch*)calloc(1, sizeof(InitBatch));
+
+    // call base-class constructor
+    if (!new_Batch(&this->base)) {
+
+        psError(PS_ERR_IO, false, "Unable to create Batch base-class object");
+        return this;
+    }
+
+    this->print = print;
+    this->destroy = destroy;
+    this->base.run = run;
+
+    if (!parseArguments(this, *argc, argv)) { return this; }
+
+    strcat(this->base.configsDir, "/init");
+    sprintf(this->base.fitsOutFile, "00000000.FITS");
+
+    this->base.init(&this->base);
+
+    return this;
+}
+
+/**
+  Main
+  */
+int main(int argc, char **argv) {
+
+    psTimerStart("initbatch");
+
+    ippToPsps_VersionPrint();
+
+    int exitCode;
+
+    InitBatch* initBatch = new_InitBatch(&argc, argv);
+    initBatch->base.run(initBatch);
+    exitCode = initBatch->base.exitCode;
+
+    initBatch->destroy(initBatch);
+
+    double secs = psTimerMark("initbatch");
+
+    psLogMsg("initbatch", 3, "initbatch completed %ssuccessfully, with exit code %d, in %.1f %s\n",
+            (exitCode == PS_EXIT_SUCCESS) ? "" : "un",
+            exitCode,
+            (secs<60.0) ? secs : (secs/60.0),
+            (secs<60.0) ? "sec(s)" : "min(s)");
+
+    // tidy up
+    psTimerStop();
+    psLibFinalize();
+
+    return exitCode;
+}
+
+
Index: trunk/ippToPsps/src/InitBatch.h
===================================================================
--- trunk/ippToPsps/src/InitBatch.h	(revision 30147)
+++ trunk/ippToPsps/src/InitBatch.h	(revision 30147)
@@ -0,0 +1,33 @@
+/** @file InitBatch.h
+ *
+ *  @brief InitBatch
+ *
+ *  @ingroup ippToPsps
+ *
+ *  @author IfA
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+#ifndef IPPTOPSPS_INITBATCH_H
+#define IPPTOPSPS_INITBATCH_H
+
+#include "Batch.h"
+
+/**
+  Sub-class of Batch for detections
+  */
+typedef struct InitBatch {
+
+    // fields
+    Batch base;             // base class
+
+    // methods
+    void (*print)();
+    void (*destroy)();
+
+} InitBatch;
+
+InitBatch *new_InitBatch(int *argc, char **argv);
+
+# endif // IPPTOPSPS_INITBATCH_H 
+
Index: trunk/ippToPsps/src/Makefile.am
===================================================================
--- trunk/ippToPsps/src/Makefile.am	(revision 30146)
+++ trunk/ippToPsps/src/Makefile.am	(revision 30147)
@@ -14,32 +14,40 @@
 
 # Force recompilation of ippToPspsVersion.c, since it gets the version information
-ippToPspsVersion.c: ippToPspsVersionDefinitions.h
-ippToPspsVersionDefinitions.h: ippToPspsVersionDefinitions.h.in FORCE
-	-$(RM) ippToPspsVersionDefinitions.h
-	$(SED) -e "s|@IPPTOPSPS_VERSION@|\"$(IPPTOPSPS_VERSION)\"|" -e "s|@IPPTOPSPS_BRANCH@|\"$(IPPTOPSPS_BRANCH)\"|" -e "s|@IPPTOPSPS_SOURCE@|\"$(IPPTOPSPS_SOURCE)\"|" ippToPspsVersionDefinitions.h.in > ippToPspsVersionDefinitions.h
+Version.c: VersionDefinitions.h
+VersionDefinitions.h: VersionDefinitions.h.in FORCE
+	-$(RM) VersionDefinitions.h
+	$(SED) -e "s|@IPPTOPSPS_VERSION@|\"$(IPPTOPSPS_VERSION)\"|" -e "s|@IPPTOPSPS_BRANCH@|\"$(IPPTOPSPS_BRANCH)\"|" -e "s|@IPPTOPSPS_SOURCE@|\"$(IPPTOPSPS_SOURCE)\"|" VersionDefinitions.h.in > VersionDefinitions.h
 FORCE: ;
 
-bin_PROGRAMS = ippToPsps
+# all the programs we create
+bin_PROGRAMS = initbatch detectionbatch stackbatch
 
-ippToPsps_CFLAGS = $(IPPTOPSPS_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS) -I/usr/include/libxml2
-ippToPsps_LDFLAGS = $(IPPTOPSPS_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS) -lxml2
 
-ippToPsps_SOURCES = \
-	main.c \
-        ippToPsps.c \
-	ippToPspsVersion.c \
-	ippToPspsConfig.c \
-	ippToPspsBatchTest.c \
-	ippToPspsBatchInit.c \
-	ippToPspsBatchDetection.c \
-	ippToPspsBatchStack.c \
-	ippToPspsBatchDifference.c   
+# initbatch
+initbatch_CFLAGS = $(IPPTOPSPS_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS) -I/usr/include/libxml2
+initbatch_LDFLAGS = $(IPPTOPSPS_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS) -lxml2
+initbatch_SOURCES = \
+	InitBatch.c \
+        Batch.c \
+	Version.c \
+	Config.c
 
-include_HEADERS = \
-	ippToPsps.h \
-	ippToPspsConfig.h \
-	ippToPspsDetEnums.h \
-	ippToPspsDiffEnums.h \
-	ippToPspsStackEnums.h 
+# detectionbatch
+detectionbatch_CFLAGS = $(IPPTOPSPS_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS) -I/usr/include/libxml2
+detectionbatch_LDFLAGS = $(IPPTOPSPS_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS) -lxml2
+detectionbatch_SOURCES = \
+	DetectionBatch.c \
+        Batch.c \
+	Version.c \
+	Config.c
+
+# stackbatch
+stackbatch_CFLAGS = $(IPPTOPSPS_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS) -I/usr/include/libxml2
+stackbatch_LDFLAGS = $(IPPTOPSPS_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS) -lxml2
+stackbatch_SOURCES = \
+	StackBatch.c \
+        Batch.c \
+	Version.c \
+	Config.c
 
 clean-local:
Index: trunk/ippToPsps/src/StackBatch.c
===================================================================
--- trunk/ippToPsps/src/StackBatch.c	(revision 30147)
+++ trunk/ippToPsps/src/StackBatch.c	(revision 30147)
@@ -0,0 +1,324 @@
+#include "StackBatch.h"
+#include "StackBatchEnums.h"
+
+/**
+  Destructor
+  */
+static void destroy(StackBatch* this) {
+
+    // call superclass destructor
+    this->base.destroy(&this->base);
+    free (this);
+}
+
+/**
+  Does the work.
+  */
+static int run(StackBatch* this) {
+
+    if (this->base.exitCode != PS_EXIT_SUCCESS) return this->base.exitCode; 
+
+    int status = 0;
+    fitsfile *fitsIn;
+
+    if (fits_open_file(&fitsIn, this->base.inputFiles[0], READONLY, &status)) {
+
+        fits_report_error(stderr, status);
+        return PS_EXIT_SYS_ERROR;
+    }
+
+
+    // get primary header and pull stuff out for later
+    int nKeys = 0;
+    fits_get_hdrspace(fitsIn, &nKeys, NULL, &status);
+    float exposureTime; status=0; fits_read_key(fitsIn, TFLOAT, "EXPTIME", &exposureTime, NULL, &status);
+    char filterType[20]; status=0; fits_read_key(fitsIn, TSTRING, "FILTER", filterType, NULL, &status);
+
+
+    char** assocDate = (char**)calloc(this->MAXDETECT, sizeof(char**));
+    for (uint32_t i=0; i<this->MAXDETECT;i++) assocDate[i] = (char*)calloc(20,sizeof(char));
+
+
+
+    // write StackMeta
+    ippToPspsConfig_writeTable(this->base.config, fitsIn, this->base.fitsOut, 1, "StackMeta", true);
+    fits_write_col(this->base.fitsOut, TLONG, STACKMETA_SKYCELLID, 1, 1, 1, &this->skycellId, &status);
+
+    int8_t filterID = -1;
+    if (!ippToPspsConfig_getFilterId(this->base.config, filterType, &filterID)) {
+
+//        this->base.exitCode = PS_EXIT_DATA_ERROR;
+    //    return this->base.exitCode; TODO
+    }
+
+    long* removeList = (long*)calloc(this->MAXDETECT, sizeof(long));
+    float* instMag = (float*)calloc(this->MAXDETECT, sizeof(float));
+    int8_t* filterIDs = (int8_t*)calloc(this->MAXDETECT, sizeof(int8_t));
+    int8_t* surveyIDs = (int8_t*)calloc(this->MAXDETECT, sizeof(int8_t));
+    float floatnull = -999.0;
+    int anynull = 0;
+
+    fits_write_col(this->base.fitsOut, TBYTE, STACKMETA_FILTERID, 1, 1, 1, &filterID, &status);
+
+    fits_write_col(this->base.fitsOut, TBYTE, STACKMETA_SURVEYID, 1, 1, 1, &this->base.surveyID, &status);
+
+
+    // psf detections
+    char extensionName[15];
+    sprintf(extensionName, "Chip.psf");
+    if (fits_movnam_hdu(fitsIn, BINARY_TBL, extensionName, 0, &status)) {
+        psError(PS_ERR_IO, false, "Can't move to extension: %s\n", extensionName);
+
+    }
+    else {
+
+        // some stuff is the same for all detections so we can populate here
+        for (long s = 0; s<this->MAXDETECT; s++) {
+
+            filterIDs[s] = filterID;
+            surveyIDs[s] = this->base.surveyID;
+            strcpy(assocDate[s], this->base.todaysDate);
+        }
+
+
+        long nDet = 0;
+        if (fits_get_num_rows(fitsIn, &nDet, &status)) {
+            fits_report_error(stderr, status);
+        }
+
+        int instMagNum;
+        status=0;fits_get_colnum(fitsIn, CASESEN, "PSF_INST_MAG", &instMagNum, &status);
+        if (status) psError(PS_ERR_IO, false, "Unable to read col num for PSF_INST_MAG");
+        fits_read_col(fitsIn, TFLOAT, instMagNum, 1, 1, nDet, &floatnull, instMag, &anynull, &status);
+
+
+        printf("Looping through %ld psf detections\n", nDet);
+        float mag;
+        long unmatched = 0, totalDetections = 0, numOfDuplicates = 0, numInvalidFlux = 0, numDetectionsOut = 0;
+
+        for (long s = 0; s<nDet; s++) {
+
+            // TODO implement this match in DVO
+            if (1) {
+
+                mag = instMag[s];
+                if (!isfinite(mag) || mag < -998.0) {
+
+                    removeList[numOfDuplicates+numInvalidFlux] = s+1;
+                    numInvalidFlux++;
+                }
+
+                totalDetections++;
+            }
+            else {
+
+                unmatched++;
+                continue;
+            }
+        }
+
+        numDetectionsOut = totalDetections - numInvalidFlux;
+
+        if (numDetectionsOut > 0) {
+
+            ippToPspsConfig_writeTable(this->base.config, fitsIn, this->base.fitsOut, nDet, "StackDetection", false);
+            fits_write_col(this->base.fitsOut, TLONG, STACKDETECTION_SKYCELLID, 1, 1, 1, &this->skycellId, &status);
+            fits_write_col(this->base.fitsOut, TBYTE, STACKDETECTION_FILTERID, 1, 1, nDet, filterIDs, &status);
+            fits_write_col(this->base.fitsOut, TBYTE, STACKDETECTION_SURVEYID, 1, 1, nDet, surveyIDs, &status);
+            fits_write_col(this->base.fitsOut, TSTRING, STACKDETECTION_ASSOCDATE, 1, 1, nDet, assocDate, &status);
+
+            if (numInvalidFlux) fits_delete_rowlist(this->base.fitsOut, removeList, numInvalidFlux, &status);
+
+        }
+        psLogMsg("ippToPsps", PS_LOG_INFO,
+                "+---------------+---------+----------+------------------+---------------+--------------+\n"
+                "|   Extension   | Rows in | Rows out | Missing from DVO | Duplicate IDs | Invalid Flux |\n"
+                "|  %12s |  %5ld  |   %5ld  |      %5ld       |    %5ld      |    %5ld     |\n",
+                extensionName, nDet, numDetectionsOut, unmatched, numOfDuplicates, numInvalidFlux);
+
+    }
+
+
+
+    // extended source
+    sprintf(extensionName, "Chip.xsrc");
+    if (fits_movnam_hdu(fitsIn, BINARY_TBL, extensionName, 0, &status)) {
+        psError(PS_ERR_IO, false, "Can't move to extension: %s\n", extensionName);
+
+    }
+    else {
+
+        int colNum;
+        int type;
+        long repeat;
+
+        ippToPspsConfig_getFitsColumnMeta(
+                "PROF_FLUX",
+                &colNum,
+                &type,
+                &repeat,
+                fitsIn);
+        printf("PROF_FILL = %d %d %ld\n", colNum, type, repeat);
+        float* vector = calloc(repeat, sizeof(float));
+
+        ippToPspsConfig_getColumnVector(
+                colNum,
+                1,
+                type,
+                repeat,
+                vector,
+                fitsIn);
+
+
+
+        free(vector);
+
+        long nDet = 0;
+        if (fits_get_num_rows(fitsIn, &nDet, &status)) {
+            fits_report_error(stderr, status);
+        }
+
+        printf("Looping through %ld extended source detections\n", nDet);
+        for (long s = 0; s<nDet; s++) {
+
+
+
+        }
+
+        ippToPspsConfig_writeTable(this->base.config, fitsIn, this->base.fitsOut, nDet, "StackApFlx", false);
+        fits_write_col(this->base.fitsOut, TBYTE, STACKAPFLX_FILTERID, 1, 1, nDet, filterIDs, &status);
+        fits_write_col(this->base.fitsOut, TBYTE, STACKAPFLX_SURVEYID, 1, 1, nDet, surveyIDs, &status);
+    }
+
+
+    // free stuff up
+    free(removeList);
+    free(instMag);
+    free(filterIDs);
+    free(surveyIDs);
+
+    status=0;
+    if (fits_close_file(fitsIn, &status)) fits_report_error(stderr, status);
+
+
+    return this->base.exitCode;
+}
+
+
+/**
+  Print-out this class. Calls base-calls print method first.
+  */
+static void print(StackBatch* this) {
+
+    this->base.print(&this->base);
+
+    printf("* skycell ID      : %d\n", this->skycellId);
+    printf("\n");
+}
+
+/**
+  Reads command-line arguments.  Calls base-calls print method first.
+  */
+static bool parseArguments(StackBatch* this, int argc, char **argv) {
+
+    bool haveSkycellId = false;
+
+    int32_t optind = 1;
+    while( ( optind < argc ) ) {
+
+        char * sw = argv[optind];
+
+        if( argv[optind][0] == '-' ) { 
+
+            if(strcmp(sw, "-skycellid") == 0 ) {
+                optind++; if( optind > ( argc-1 ) ) break;
+                this->skycellId = atoi(argv[optind]);
+                haveSkycellId = true;
+            }
+        }
+        optind++;
+    }
+
+    this->base.parseArguments(&this->base, argc, argv);
+
+    if (
+            !this->base.gotResultsPath() ||
+            !this->base.gotFitsInPath() ||
+            !this->base.gotFitsOutPath() ||
+            !this->base.gotConfig() ||
+            !this->base.gotSurveyType() ||
+            !haveSkycellId) {
+
+        printf("\n* ERROR with supplied arguments:");
+        this->print(this);
+        this->base.exitCode = PS_EXIT_CONFIG_ERROR;
+        return false;
+    }
+
+    return true;
+}
+
+/**
+  Constructor
+  */
+StackBatch* new_StackBatch(int *argc, char **argv) {
+
+    StackBatch *this = (StackBatch*)calloc(1, sizeof(StackBatch));
+
+    // call base-class constructor
+    if (!new_Batch(&this->base)) {
+
+        psError(PS_ERR_IO, false, "Unable to create Batch base-class object");
+        return this;
+    }
+
+    this->MAXDETECT = 150000;
+
+    this->print = print;
+    this->destroy = destroy;
+    this->base.run = run;
+
+    if (!parseArguments(this, *argc, argv)) { return this; }
+
+    strcat(this->base.configsDir, "/stack");
+    sprintf(this->base.fitsOutFile, "%08d.FITS", this->skycellId);
+
+    this->base.init(&this->base);
+
+    return this;
+}
+
+/**
+  Main
+  */
+int main(int argc, char **argv) {
+
+    psTimerStart("stackbatch");
+
+    ippToPsps_VersionPrint();
+
+    int exitCode;
+
+    StackBatch* stackBatch = new_StackBatch(&argc, argv);
+    stackBatch->base.run(stackBatch);
+    exitCode = stackBatch->base.exitCode;
+
+    stackBatch->destroy(stackBatch);
+
+    double secs = psTimerMark("stackbatch");
+
+    psLogMsg("stackbatch", 3, "stackbatch completed %ssuccessfully, with exit code %d, in %.1f %s\n",
+            (exitCode == PS_EXIT_SUCCESS) ? "" : "un",
+            exitCode,
+            (secs<60.0) ? secs : (secs/60.0),
+            (secs<60.0) ? "sec(s)" : "min(s)");
+
+    // tidy up
+    psTimerStop();
+    psLibFinalize();
+
+    return exitCode;
+}
+
+
+
Index: trunk/ippToPsps/src/StackBatch.h
===================================================================
--- trunk/ippToPsps/src/StackBatch.h	(revision 30147)
+++ trunk/ippToPsps/src/StackBatch.h	(revision 30147)
@@ -0,0 +1,34 @@
+/** @file StackBatch.h
+ *
+ *  @brief StackBatch
+ *
+ *  @ingroup ippToPsps
+ *
+ *  @author IfA
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+#ifndef IPPTOPSPS_STACKBATCH_H
+#define IPPTOPSPS_STACKBATCH_H
+
+#include "Batch.h"
+
+/**
+  Sub-class of Batch for detections
+  */
+typedef struct StackBatch {
+
+    // fields
+    Batch base;             // base class
+    size_t MAXDETECT;       // max number of detections
+    uint32_t skycellId;     // skycell ID
+
+    // methods
+    void (*print)();
+    void (*destroy)();
+
+} StackBatch;
+
+StackBatch *new_StackBatch(int *argc, char **argv);
+
+# endif // IPPTOPSPS_STACKBATCH_H 
Index: trunk/ippToPsps/src/StackBatchEnums.h
===================================================================
--- trunk/ippToPsps/src/StackBatchEnums.h	(revision 30147)
+++ trunk/ippToPsps/src/StackBatchEnums.h	(revision 30147)
@@ -0,0 +1,392 @@
+#ifndef STACKBATCHENUMS_H
+#define STACKBATCHENUMS_H
+
+
+typedef enum {
+  STACKMETA_STACKMETAID = 1,
+  STACKMETA_SKYCELLID = 2,
+  STACKMETA_SURVEYID = 3,
+  STACKMETA_PHOTOCALID = 4,
+  STACKMETA_FILTERID = 5,
+  STACKMETA_STACKTYPEID = 6,
+  STACKMETA_STACKGROUPID = 7,
+  STACKMETA_MAGSAT = 8,
+  STACKMETA_ANALVER = 9,
+  STACKMETA_NP2IMAGES = 10,
+  STACKMETA_COMPLETMAG = 11,
+  STACKMETA_ASTROSCAT = 12,
+  STACKMETA_PHOTOSCAT = 13,
+  STACKMETA_NASTROREF = 14,
+  STACKMETA_NPHOREF = 15,
+  STACKMETA_MEAN = 16,
+  STACKMETA_MAX = 17,
+  STACKMETA_PHOTOZERO = 18,
+  STACKMETA_PHOTOCOLOR = 19,
+  STACKMETA_CTYPE1 = 20,
+  STACKMETA_CTYPE2 = 21,
+  STACKMETA_CRVAL1 = 22,
+  STACKMETA_CRVAL2 = 23,
+  STACKMETA_CRPIX1 = 24,
+  STACKMETA_CRPIX2 = 25,
+  STACKMETA_CDELT1 = 26,
+  STACKMETA_CDELT2 = 27,
+  STACKMETA_PC001001 = 28,
+  STACKMETA_PC001002 = 29,
+  STACKMETA_PC002001 = 30,
+  STACKMETA_PC002002 = 31,
+  STACKMETA_CALIBMODNUM = 32,
+  STACKMETA_DATARELEASE = 33,
+} StackMeta;
+
+typedef enum {
+  STACKDETECTION_OBJID = 1,
+  STACKDETECTION_STACKDETECTID = 2,
+  STACKDETECTION_IPPOBJID = 3,
+  STACKDETECTION_IPPDETECTID = 4,
+  STACKDETECTION_FILTERID = 5,
+  STACKDETECTION_STACKTYPEID = 6,
+  STACKDETECTION_STACKGROUPID = 7,
+  STACKDETECTION_SURVEYID = 8,
+  STACKDETECTION_PRIMARYF = 9,
+  STACKDETECTION_STACKMETAID = 10,
+  STACKDETECTION_SKYCELLID = 11,
+  STACKDETECTION_PROJECTIONCELLID = 12,
+  STACKDETECTION_STACKVER = 13,
+  STACKDETECTION_OBSTIME = 14,
+  STACKDETECTION_XPOS = 15,
+  STACKDETECTION_YPOS = 16,
+  STACKDETECTION_XPOSERR = 17,
+  STACKDETECTION_YPOSERR = 18,
+  STACKDETECTION_INSTFLUX = 19,
+  STACKDETECTION_INSTFLUXERR = 20,
+  STACKDETECTION_PEAKFLUX = 21,
+  STACKDETECTION_SKY = 22,
+  STACKDETECTION_SKYERR = 23,
+  STACKDETECTION_SGSEP = 24,
+  STACKDETECTION_PSFWIDMAJOR = 25,
+  STACKDETECTION_PSFWIDMINOR = 26,
+  STACKDETECTION_PSFTHETA = 27,
+  STACKDETECTION_PSFLIKELIHOOD = 28,
+  STACKDETECTION_PSFCF = 29,
+  STACKDETECTION_INFOFLAG = 30,
+  STACKDETECTION_NFRAMES = 31,
+  STACKDETECTION_ACTIVEFLAG = 32,
+  STACKDETECTION_ASSOCDATE = 33,
+  STACKDETECTION_HISTORYMODNUM = 34,
+  STACKDETECTION_DATARELEASE = 35,
+} StackDetection;
+
+typedef enum {
+  STACKAPFLX_OBJID = 1,
+  STACKAPFLX_STACKDETECTID = 2,
+  STACKAPFLX_IPPOBJID = 3,
+  STACKAPFLX_IPPDETECTID = 4,
+  STACKAPFLX_FILTERID = 5,
+  STACKAPFLX_STACKTYPEID = 6,
+  STACKAPFLX_STACKGROUPID = 7,
+  STACKAPFLX_SURVEYID = 8,
+  STACKAPFLX_PRIMARYF = 9,
+  STACKAPFLX_STACKMETAID = 10,
+  STACKAPFLX_ISOPHOTMAG = 11,
+  STACKAPFLX_ISOPHOTMAGERR = 12,
+  STACKAPFLX_ISOPHOTMAJAXIS = 13,
+  STACKAPFLX_ISOPHOTMAJAXISERR = 14,
+  STACKAPFLX_ISOPHOTMINAXIS = 15,
+  STACKAPFLX_ISOPHOTMINAXISERR = 16,
+  STACKAPFLX_ISOPHOTMAJAXISGRAD = 17,
+  STACKAPFLX_ISOPHOTMINAXISGRAD = 18,
+  STACKAPFLX_ISOPHOTPA = 19,
+  STACKAPFLX_ISOPHOTPAERR = 20,
+  STACKAPFLX_ISOPHOTPAGRAD = 21,
+  STACKAPFLX_PETRADIUS = 22,
+  STACKAPFLX_PETRADIUSERR = 23,
+  STACKAPFLX_PETMAG = 24,
+  STACKAPFLX_PETMAGERR = 25,
+  STACKAPFLX_PETR50 = 26,
+  STACKAPFLX_PETR50ERR = 27,
+  STACKAPFLX_PETR90 = 28,
+  STACKAPFLX_PETR90ERR = 29,
+  STACKAPFLX_PETCF = 30,
+  STACKAPFLX_FLXR1 = 31,
+  STACKAPFLX_FLXR1ERR = 32,
+  STACKAPFLX_FLXR1STD = 33,
+  STACKAPFLX_FLXR1FILL = 34,
+  STACKAPFLX_FLXR2 = 35,
+  STACKAPFLX_FLXR2ERR = 36,
+  STACKAPFLX_FLXR2STD = 37,
+  STACKAPFLX_FLXR2FILL = 38,
+  STACKAPFLX_FLXR3 = 39,
+  STACKAPFLX_FLXR3ERR = 40,
+  STACKAPFLX_FLXR3STD = 41,
+  STACKAPFLX_FLXR3FILL = 42,
+  STACKAPFLX_FLXR4 = 43,
+  STACKAPFLX_FLXR4ERR = 44,
+  STACKAPFLX_FLXR4STD = 45,
+  STACKAPFLX_FLXR4FILL = 46,
+  STACKAPFLX_FLXR5 = 47,
+  STACKAPFLX_FLXR5ERR = 48,
+  STACKAPFLX_FLXR5STD = 49,
+  STACKAPFLX_FLXR5FILL = 50,
+  STACKAPFLX_FLXR6 = 51,
+  STACKAPFLX_FLXR6ERR = 52,
+  STACKAPFLX_FLXR6STD = 53,
+  STACKAPFLX_FLXR6FILL = 54,
+  STACKAPFLX_FLXR7 = 55,
+  STACKAPFLX_FLXR7ERR = 56,
+  STACKAPFLX_FLXR7STD = 57,
+  STACKAPFLX_FLXR7FILL = 58,
+  STACKAPFLX_FLXR8 = 59,
+  STACKAPFLX_FLXR8ERR = 60,
+  STACKAPFLX_FLXR8STD = 61,
+  STACKAPFLX_FLXR8FILL = 62,
+  STACKAPFLX_FLXR9 = 63,
+  STACKAPFLX_FLXR9ERR = 64,
+  STACKAPFLX_FLXR9STD = 65,
+  STACKAPFLX_FLXR9FILL = 66,
+  STACKAPFLX_FLXR10 = 67,
+  STACKAPFLX_FLXR10ERR = 68,
+  STACKAPFLX_FLXR10STD = 69,
+  STACKAPFLX_FLXR10FILL = 70,
+  STACKAPFLX_C1FLXR1 = 71,
+  STACKAPFLX_C1FLXR1ERR = 72,
+  STACKAPFLX_C1FLXR1STD = 73,
+  STACKAPFLX_C1FLXR1FILL = 74,
+  STACKAPFLX_C1FLXR2 = 75,
+  STACKAPFLX_C1FLXR2ERR = 76,
+  STACKAPFLX_C1FLXR2STD = 77,
+  STACKAPFLX_C1FLXR2FILL = 78,
+  STACKAPFLX_C1FLXR3 = 79,
+  STACKAPFLX_C1FLXR3ERR = 80,
+  STACKAPFLX_C1FLXR3STD = 81,
+  STACKAPFLX_C1FLXR3FILL = 82,
+  STACKAPFLX_C1FLXR4 = 83,
+  STACKAPFLX_C1FLXR4ERR = 84,
+  STACKAPFLX_C1FLXR4STD = 85,
+  STACKAPFLX_C1FLXR4FILL = 86,
+  STACKAPFLX_C1FLXR5 = 87,
+  STACKAPFLX_C1FLXR5ERR = 88,
+  STACKAPFLX_C1FLXR5STD = 89,
+  STACKAPFLX_C1FLXR5FILL = 90,
+  STACKAPFLX_C1FLXR6 = 91,
+  STACKAPFLX_C1FLXR6ERR = 92,
+  STACKAPFLX_C1FLXR6STD = 93,
+  STACKAPFLX_C1FLXR6FILL = 94,
+  STACKAPFLX_C1FLXR7 = 95,
+  STACKAPFLX_C1FLXR7ERR = 96,
+  STACKAPFLX_C1FLXR7STD = 97,
+  STACKAPFLX_C1FLXR7FILL = 98,
+  STACKAPFLX_C1FLXR8 = 99,
+  STACKAPFLX_C1FLXR8ERR = 100,
+  STACKAPFLX_C1FLXR8STD = 101,
+  STACKAPFLX_C1FLXR8FILL = 102,
+  STACKAPFLX_C1FLXR9 = 103,
+  STACKAPFLX_C1FLXR9ERR = 104,
+  STACKAPFLX_C1FLXR9STD = 105,
+  STACKAPFLX_C1FLXR9FILL = 106,
+  STACKAPFLX_C1FLXR10 = 107,
+  STACKAPFLX_C1FLXR10ERR = 108,
+  STACKAPFLX_C1FLXR10STD = 109,
+  STACKAPFLX_C1FLXR10FILL = 110,
+  STACKAPFLX_C2FLXR1 = 111,
+  STACKAPFLX_C2FLXR1ERR = 112,
+  STACKAPFLX_C2FLXR1STD = 113,
+  STACKAPFLX_C2FLXR1FILL = 114,
+  STACKAPFLX_C2FLXR2 = 115,
+  STACKAPFLX_C2FLXR2ERR = 116,
+  STACKAPFLX_C2FLXR2STD = 117,
+  STACKAPFLX_C2FLXR2FILL = 118,
+  STACKAPFLX_C2FLXR3 = 119,
+  STACKAPFLX_C2FLXR3ERR = 120,
+  STACKAPFLX_C2FLXR3STD = 121,
+  STACKAPFLX_C2FLXR3FILL = 122,
+  STACKAPFLX_C2FLXR4 = 123,
+  STACKAPFLX_C2FLXR4ERR = 124,
+  STACKAPFLX_C2FLXR4STD = 125,
+  STACKAPFLX_C2FLXR4FILL = 126,
+  STACKAPFLX_C2FLXR5 = 127,
+  STACKAPFLX_C2FLXR5ERR = 128,
+  STACKAPFLX_C2FLXR5STD = 129,
+  STACKAPFLX_C2FLXR5FILL = 130,
+  STACKAPFLX_C2FLXR6 = 131,
+  STACKAPFLX_C2FLXR6ERR = 132,
+  STACKAPFLX_C2FLXR6STD = 133,
+  STACKAPFLX_C2FLXR6FILL = 134,
+  STACKAPFLX_C2FLXR7 = 135,
+  STACKAPFLX_C2FLXR7ERR = 136,
+  STACKAPFLX_C2FLXR7STD = 137,
+  STACKAPFLX_C2FLXR7FILL = 138,
+  STACKAPFLX_C2FLXR8 = 139,
+  STACKAPFLX_C2FLXR8ERR = 140,
+  STACKAPFLX_C2FLXR8STD = 141,
+  STACKAPFLX_C2FLXR8FILL = 142,
+  STACKAPFLX_C2FLXR9 = 143,
+  STACKAPFLX_C2FLXR9ERR = 144,
+  STACKAPFLX_C2FLXR9STD = 145,
+  STACKAPFLX_C2FLXR9FILL = 146,
+  STACKAPFLX_C2FLXR10 = 147,
+  STACKAPFLX_C2FLXR10ERR = 148,
+  STACKAPFLX_C2FLXR10STD = 149,
+  STACKAPFLX_C2FLXR10FILL = 150,
+  STACKAPFLX_LOGC = 151,
+  STACKAPFLX_LOGA = 152,
+  STACKAPFLX_ACTIVEFLAG = 153,
+  STACKAPFLX_DATARELEASE = 154,
+} StackApFlx;
+
+typedef enum {
+  STACKMODELFIT_OBJID = 1,
+  STACKMODELFIT_STACKDETECTID = 2,
+  STACKMODELFIT_IPPOBJID = 3,
+  STACKMODELFIT_IPPDETECTID = 4,
+  STACKMODELFIT_FILTERID = 5,
+  STACKMODELFIT_STACKTYPEID = 6,
+  STACKMODELFIT_STACKGROUPID = 7,
+  STACKMODELFIT_SURVEYID = 8,
+  STACKMODELFIT_PRIMARYF = 9,
+  STACKMODELFIT_STACKMETAID = 10,
+  STACKMODELFIT_DEVRADIUS = 11,
+  STACKMODELFIT_DEVRADIUSERR = 12,
+  STACKMODELFIT_DEVMAG = 13,
+  STACKMODELFIT_DEVMAGERR = 14,
+  STACKMODELFIT_DEVAB = 15,
+  STACKMODELFIT_DEVABERR = 16,
+  STACKMODELFIT_DEVPHI = 17,
+  STACKMODELFIT_DEVPHIERR = 18,
+  STACKMODELFIT_RADEVOFF = 19,
+  STACKMODELFIT_DECDEVOFF = 20,
+  STACKMODELFIT_RADEVOFFERR = 21,
+  STACKMODELFIT_DECDEVOFFERR = 22,
+  STACKMODELFIT_DEVCF = 23,
+  STACKMODELFIT_DEVLIKELIHOOD = 24,
+  STACKMODELFIT_DEVCOVAR11 = 25,
+  STACKMODELFIT_DEVCOVAR12 = 26,
+  STACKMODELFIT_DEVCOVAR13 = 27,
+  STACKMODELFIT_DEVCOVAR14 = 28,
+  STACKMODELFIT_DEVCOVAR15 = 29,
+  STACKMODELFIT_DEVCOVAR16 = 30,
+  STACKMODELFIT_DEVCOVAR17 = 31,
+  STACKMODELFIT_DEVCOVAR22 = 32,
+  STACKMODELFIT_DEVCOVAR23 = 33,
+  STACKMODELFIT_DEVCOVAR24 = 34,
+  STACKMODELFIT_DEVCOVAR25 = 35,
+  STACKMODELFIT_DEVCOVAR26 = 36,
+  STACKMODELFIT_DEVCOVAR27 = 37,
+  STACKMODELFIT_DEVCOVAR33 = 38,
+  STACKMODELFIT_DEVCOVAR34 = 39,
+  STACKMODELFIT_DEVCOVAR35 = 40,
+  STACKMODELFIT_DEVCOVAR36 = 41,
+  STACKMODELFIT_DEVCOVAR37 = 42,
+  STACKMODELFIT_DEVCOVAR44 = 43,
+  STACKMODELFIT_DEVCOVAR45 = 44,
+  STACKMODELFIT_DEVCOVAR46 = 45,
+  STACKMODELFIT_DEVCOVAR47 = 46,
+  STACKMODELFIT_DEVCOVAR55 = 47,
+  STACKMODELFIT_DEVCOVAR56 = 48,
+  STACKMODELFIT_DEVCOVAR57 = 49,
+  STACKMODELFIT_DEVCOVAR66 = 50,
+  STACKMODELFIT_DEVCOVAR67 = 51,
+  STACKMODELFIT_DEVCOVAR77 = 52,
+  STACKMODELFIT_EXPRADIUS = 53,
+  STACKMODELFIT_EXPRADIUSERR = 54,
+  STACKMODELFIT_EXPMAG = 55,
+  STACKMODELFIT_EXPMAGERR = 56,
+  STACKMODELFIT_EXPAB = 57,
+  STACKMODELFIT_EXPABERR = 58,
+  STACKMODELFIT_EXPPHI = 59,
+  STACKMODELFIT_EXPPHIERR = 60,
+  STACKMODELFIT_RAEXPOFF = 61,
+  STACKMODELFIT_DECEXPOFF = 62,
+  STACKMODELFIT_RAEXPOFFERR = 63,
+  STACKMODELFIT_DECEXPOFFERR = 64,
+  STACKMODELFIT_EXPCF = 65,
+  STACKMODELFIT_EXPLIKELIHOOD = 66,
+  STACKMODELFIT_EXPCOVAR11 = 67,
+  STACKMODELFIT_EXPCOVAR12 = 68,
+  STACKMODELFIT_EXPCOVAR13 = 69,
+  STACKMODELFIT_EXPCOVAR14 = 70,
+  STACKMODELFIT_EXPCOVAR15 = 71,
+  STACKMODELFIT_EXPCOVAR16 = 72,
+  STACKMODELFIT_EXPCOVAR17 = 73,
+  STACKMODELFIT_EXPCOVAR22 = 74,
+  STACKMODELFIT_EXPCOVAR23 = 75,
+  STACKMODELFIT_EXPCOVAR24 = 76,
+  STACKMODELFIT_EXPCOVAR25 = 77,
+  STACKMODELFIT_EXPCOVAR26 = 78,
+  STACKMODELFIT_EXPCOVAR27 = 79,
+  STACKMODELFIT_EXPCOVAR33 = 80,
+  STACKMODELFIT_EXPCOVAR34 = 81,
+  STACKMODELFIT_EXPCOVAR35 = 82,
+  STACKMODELFIT_EXPCOVAR36 = 83,
+  STACKMODELFIT_EXPCOVAR37 = 84,
+  STACKMODELFIT_EXPCOVAR44 = 85,
+  STACKMODELFIT_EXPCOVAR45 = 86,
+  STACKMODELFIT_EXPCOVAR46 = 87,
+  STACKMODELFIT_EXPCOVAR47 = 88,
+  STACKMODELFIT_EXPCOVAR55 = 89,
+  STACKMODELFIT_EXPCOVAR56 = 90,
+  STACKMODELFIT_EXPCOVAR57 = 91,
+  STACKMODELFIT_EXPCOVAR66 = 92,
+  STACKMODELFIT_EXPCOVAR67 = 93,
+  STACKMODELFIT_EXPCOVAR77 = 94,
+  STACKMODELFIT_SERRADIUS = 95,
+  STACKMODELFIT_SERRADIUSERR = 96,
+  STACKMODELFIT_SERMAG = 97,
+  STACKMODELFIT_SERMAGERR = 98,
+  STACKMODELFIT_SERAB = 99,
+  STACKMODELFIT_SERABERR = 100,
+  STACKMODELFIT_SERNU = 101,
+  STACKMODELFIT_SERNUERR = 102,
+  STACKMODELFIT_SERPHI = 103,
+  STACKMODELFIT_SERPHIERR = 104,
+  STACKMODELFIT_RASEROFF = 105,
+  STACKMODELFIT_DECSEROFF = 106,
+  STACKMODELFIT_RASEROFFERR = 107,
+  STACKMODELFIT_DECSEROFFERR = 108,
+  STACKMODELFIT_SERCF = 109,
+  STACKMODELFIT_SERLIKELIHOOD = 110,
+  STACKMODELFIT_SERSICCOVAR11 = 111,
+  STACKMODELFIT_SERSICCOVAR12 = 112,
+  STACKMODELFIT_SERSICCOVAR13 = 113,
+  STACKMODELFIT_SERSICCOVAR14 = 114,
+  STACKMODELFIT_SERSICCOVAR15 = 115,
+  STACKMODELFIT_SERSICCOVAR16 = 116,
+  STACKMODELFIT_SERSICCOVAR17 = 117,
+  STACKMODELFIT_SERSICCOVAR18 = 118,
+  STACKMODELFIT_SERSICCOVAR22 = 119,
+  STACKMODELFIT_SERSICCOVAR23 = 120,
+  STACKMODELFIT_SERSICCOVAR24 = 121,
+  STACKMODELFIT_SERSICCOVAR25 = 122,
+  STACKMODELFIT_SERSICCOVAR26 = 123,
+  STACKMODELFIT_SERSICCOVAR27 = 124,
+  STACKMODELFIT_SERSICCOVAR28 = 125,
+  STACKMODELFIT_SERSICCOVAR33 = 126,
+  STACKMODELFIT_SERSICCOVAR34 = 127,
+  STACKMODELFIT_SERSICCOVAR35 = 128,
+  STACKMODELFIT_SERSICCOVAR36 = 129,
+  STACKMODELFIT_SERSICCOVAR37 = 130,
+  STACKMODELFIT_SERSICCOVAR38 = 131,
+  STACKMODELFIT_SERSICCOVAR44 = 132,
+  STACKMODELFIT_SERSICCOVAR45 = 133,
+  STACKMODELFIT_SERSICCOVAR46 = 134,
+  STACKMODELFIT_SERSICCOVAR47 = 135,
+  STACKMODELFIT_SERSICCOVAR48 = 136,
+  STACKMODELFIT_SERSICCOVAR55 = 137,
+  STACKMODELFIT_SERSICCOVAR56 = 138,
+  STACKMODELFIT_SERSICCOVAR57 = 139,
+  STACKMODELFIT_SERSICCOVAR58 = 140,
+  STACKMODELFIT_SERSICCOVAR66 = 141,
+  STACKMODELFIT_SERSICCOVAR67 = 142,
+  STACKMODELFIT_SERSICCOVAR68 = 143,
+  STACKMODELFIT_SERSICCOVAR77 = 144,
+  STACKMODELFIT_SERSICCOVAR78 = 145,
+  STACKMODELFIT_SERSICCOVAR88 = 146,
+  STACKMODELFIT_ACTIVEFLAG = 147,
+  STACKMODELFIT_DATARELEASE = 148,
+} StackModelFit;
+
+typedef enum {
+  STACKTOIMAGE_STACKMETAID = 1,
+  STACKTOIMAGE_IMAGEID = 2,
+} StackToImage;
+
+#endif
Index: trunk/ippToPsps/src/Version.c
===================================================================
--- trunk/ippToPsps/src/Version.c	(revision 30147)
+++ trunk/ippToPsps/src/Version.c	(revision 30147)
@@ -0,0 +1,116 @@
+/** @file ippToPspsVersion.c
+ *
+ *  @brief
+ *
+ *  @ingroup ippToPsps
+ *
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+#include <pslib.h>
+#include <psmodules.h>
+#include "VersionDefinitions.h"
+
+#ifndef IPPTOPSPS_VERSION
+#error "IPPTOPSPS_VERSION is not set"
+#endif
+#ifndef IPPTOPSPS_BRANCH
+#error "IPPTOPSPS_BRANCH is not set"
+#endif
+#ifndef IPPTOPSPS_SOURCE
+#error "IPPTOPSPS_SOURCE is not set"
+#endif
+
+psString ippToPsps_Version(void)
+{
+    char *value = NULL;
+    psStringAppend(&value, "%s@%s", IPPTOPSPS_BRANCH, IPPTOPSPS_VERSION);
+    return value;
+}
+
+psString ippToPsps_Source(void)
+{
+  return psStringCopy(IPPTOPSPS_SOURCE);
+}
+
+psString ippToPsps_VersionLong(void)
+{
+    psString version = ippToPsps_Version();  // Version, to return
+    psString source = ippToPsps_Source();    // Source
+
+    psStringPrepend(&version, "ippToPsps ");
+    psStringAppend(&version, " from %s, built %s, %s", source, __DATE__, __TIME__);
+    psFree(source);
+
+#ifdef __OPTIMIZE__
+    psStringAppend(&version, " optimised");
+#else
+    psStringAppend(&version, " unoptimised");
+#endif
+
+    return version;
+};
+
+bool ippToPsps_VersionHeader(psMetadata *header)
+{
+    PS_ASSERT_METADATA_NON_NULL(header, false);
+
+    psString version = ippToPsps_Version(); // Software version
+    psString source = ippToPsps_Source();   // Software source
+
+    psMetadataAddStr(header, PS_LIST_TAIL, "IPP2PS_V", PS_META_REPLACE, NULL, IPPTOPSPS_VERSION);
+    
+    psStringPrepend(&version, "ippToPsps version: ");
+    psStringPrepend(&source, "ippToPsps source: ");
+
+    psMetadataAddStr(header, PS_LIST_TAIL, "HISTORY", PS_META_DUPLICATE_OK, NULL, version);
+    psMetadataAddStr(header, PS_LIST_TAIL, "HISTORY", PS_META_DUPLICATE_OK, NULL, source);
+
+    psFree(version);
+    psFree(source);
+
+    return true;
+}
+
+bool ippToPsps_VersionHeaderFull(psMetadata *header)
+{
+    PS_ASSERT_METADATA_NON_NULL(header, false);
+
+    psTime *time = psTimeGetNow(PS_TIME_TAI); // The time now
+    psString timeString = psTimeToISO(time); // The time in an ISO string
+    psFree(time);
+    psString history = NULL;               // History string
+    psStringAppend(&history, "ippToPsps at %s", timeString);
+    psFree(timeString);
+    psMetadataAddStr(header, PS_LIST_TAIL, "HISTORY", PS_META_DUPLICATE_OK, NULL, history);
+    psFree(history);
+
+    psLibVersionHeader(header);
+    psModulesVersionHeader(header);
+    ippToPsps_VersionHeader(header);
+
+    return true;
+}
+
+void ippToPsps_VersionPrint(void)
+{
+    psTime *time = psTimeGetNow(PS_TIME_TAI); // The time now
+    psString timeString = psTimeToISO(time); // The time in an ISO string
+    psFree(time);
+    psLogMsg("ippToPsps", PS_LOG_INFO, "ippToPsps at %s", timeString);
+    psFree(timeString);
+
+    psString pslib = psLibVersionLong();// psLib version
+    psString psmodules = psModulesVersionLong(); // psModules version
+    psString ippToPsps = ippToPsps_VersionLong(); // ippToPsps version
+
+    psLogMsg("ippToPsps", PS_LOG_INFO, "%s", pslib);
+    psLogMsg("ippToPsps", PS_LOG_INFO, "%s", psmodules);
+    psLogMsg("ippToPsps", PS_LOG_INFO, "%s", ippToPsps);
+
+    psFree(pslib);
+    psFree(psmodules);
+    psFree(ippToPsps);
+
+    return;
+}
Index: trunk/ippToPsps/src/VersionDefinitions.h
===================================================================
--- trunk/ippToPsps/src/VersionDefinitions.h	(revision 30147)
+++ trunk/ippToPsps/src/VersionDefinitions.h	(revision 30147)
@@ -0,0 +1,8 @@
+#ifndef IPPTOPSPS_VERSION_DEFINITIONS_H
+#define IPPTOPSPS_VERSION_DEFINITIONS_H
+
+#define IPPTOPSPS_VERSION "29648:30000M" // SVN version
+#define IPPTOPSPS_BRANCH  "trunk/ippToPsps"  // SVN branch
+#define IPPTOPSPS_SOURCE  "60eb6cdc-a59c-4636-a4e0-dba66a9721fd"  // SVN source
+
+#endif
Index: trunk/ippToPsps/src/VersionDefinitions.h.in
===================================================================
--- trunk/ippToPsps/src/VersionDefinitions.h.in	(revision 30147)
+++ trunk/ippToPsps/src/VersionDefinitions.h.in	(revision 30147)
@@ -0,0 +1,8 @@
+#ifndef IPPTOPSPS_VERSION_DEFINITIONS_H
+#define IPPTOPSPS_VERSION_DEFINITIONS_H
+
+#define IPPTOPSPS_VERSION @IPPTOPSPS_VERSION@ // SVN version
+#define IPPTOPSPS_BRANCH  @IPPTOPSPS_BRANCH@  // SVN branch
+#define IPPTOPSPS_SOURCE  @IPPTOPSPS_SOURCE@  // SVN source
+
+#endif
Index: trunk/ippToPsps/src/ippToPsps.c
===================================================================
--- trunk/ippToPsps/src/ippToPsps.c	(revision 30146)
+++ 	(revision )
@@ -1,381 +1,0 @@
-/** @file ippToPsps.c
- *
- *  @ingroup ippToPsps
- *
- *  @author IfA
- *  Copyright 2009 Institute for Astronomy, University of Hawaii
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <sys/stat.h>
-
-#include <pslib.h>
-#include <psmodules.h>
-#include "ippToPsps.h"
-
-extern int ippToPsps_batchTest(IppToPsps *data);
-extern int ippToPsps_batchInit(IppToPsps *data);
-extern int ippToPsps_batchDetection(IppToPsps *data);
-extern int ippToPsps_batchStack(IppToPsps *data);
-extern int ippToPsps_batchDifference(IppToPsps *data);
-
-// Gets uncalibrated instrumental flux from magnitude
-__inline bool ippToPsps_getFlux(const float exposureTime, const float magnitude, float* flux, const float magnitudeErr, float* fluxErr) {
-
-    *flux = powf(10.0, -0.4*magnitude) / exposureTime;
-    if (!isfinite(*flux) || *flux < 0.000001) return false;
-    if (fluxErr) *fluxErr = fabsf((magnitudeErr * *flux)/1.085736);
-//      if (fluxErr)    printf("Mag = %03.03f, Flux = %03.03f, Mag err = %03.03f, Flux Err = %03.03f\n", magnitude, *flux, magnitudeErr, *fluxErr);
-
-    return true;
-}
-
-// Destructor
-static void ippToPsps_Destructor(IppToPsps* this) {
-
-    // if we created an output file...
-    if (this->fitsOut) {
-
-        // if unsuccessful, then delete FITS file
-        if (this->exitCode != PS_EXIT_SUCCESS) {
-
-            psError(PS_ERR_UNKNOWN, false, "Failed, so deleting %s", this->fitsOutPath);
-
-            // if process failed, we need to delete that FITS file
-            if (remove(this->fitsOutPath) == -1) {
-
-                psError(PS_ERR_UNKNOWN, false, "Unable to delete %s", this->fitsOutPath);
-            }
-        }
-        // ...otherwise, close file
-        else {
-
-            int status = 0;
-            if (fits_close_file(this->fitsOut, &status)) {
-
-                psError(PS_ERR_IO, false, "Unable to close FITS file %s", this->fitsOutPath);
-                fits_report_error(stderr, status);
-            }
-        }
-    }
-
-    // save XML document for results
-    if (this->resultsXmlDoc) {
-
-        xmlSaveFormatFileEnc(this->resultsPath, this->resultsXmlDoc, "UTF-8", 1);
-
-        xmlFreeDoc(this->resultsXmlDoc);
-        xmlCleanupParser();
-        xmlMemoryDump();
-    }
-
-    psFree(this->fitsInPath);
-    psFree(this->resultsPath);
-    psFree(this->fitsOutPath);
-    psFree(this->configsDir);
-    psFree(this->pmconfig);
-
-
-    for(uint32_t i=0; i<this->numOfInputFiles; i++)
-        free(this->inputFiles[i]);
-    free(this->inputFiles);
-
-    if (this->dvoConfig != NULL) dvoConfigFree(this->dvoConfig);
-
-    ippToPspsConfig_Destructor(this->config);
-
-    pmConfigDone();
-
-    return;
-}
-
-// read file-input file and populate array of paths
-static bool ippToPsps_readInputFilePaths(IppToPsps* this) {
-
-    FILE* file = fopen (this->fitsInPath, "r");
-
-    if (file == NULL) {
-
-        psError(PS_ERR_UNKNOWN, false, "Unable to open file at %s", this->fitsInPath);
-        return false;
-    }
-
-    this->numOfInputFiles = 0;
-    char line[1000];
-    while (fgets(line, 1000, file) != NULL) this->numOfInputFiles++;
-
-    printf ("Number of input files %d\n", this->numOfInputFiles);
-
-    if (this->numOfInputFiles < 1) return false;
-
-    this->inputFiles = (char**)calloc(this->numOfInputFiles, sizeof(char*));
-    for(uint32_t i=0; i<this->numOfInputFiles; i++)
-        this->inputFiles[i] = (char*)calloc(1000, 1);
-
-    rewind(file);
-    uint16_t i = 0;
-    while (fgets(line, 1000, file) != NULL) {
-
-        sprintf(this->inputFiles[i], "%s", line);
-
-        // remove newline
-        for(uint16_t j=0;j<strlen(this->inputFiles[i]);j++)
-            if (this->inputFiles[i][j] == '\n') this->inputFiles[i][j] = '\0';
-        i++;
-    }
-
-    fclose(file);
-
-    return true;
-}
-
-// Prints usage to stdout.
-static void usage(IppToPsps *this, const char *program, psMetadata *arguments) {
-
-    fprintf(stderr, "\nUsage: %s\n", program);
-    fprintf(stderr, "\n");
-    psArgumentHelp(arguments);
-    fprintf(stderr, "\n");
-}
-
-// the available IPP batch types for PSPS
-typedef enum {
-
-    BATCH_TEST,
-    BATCH_INIT,
-    BATCH_DETECTION,
-    BATCH_STACK,
-    BATCH_DIFFERENCE,
-    BATCH_UNDEFINED
-
-} ippProducts;
-
-// Deals with command-line args.
-static bool ippToPsps_Arguments(IppToPsps *this, int argc, char **argv) {
-
-    assert(this);
-    assert(this->pmconfig);
-
-    psMetadata *arguments = psMetadataAlloc();
-    psMetadataAddStr(arguments, PS_LIST_TAIL, "-id", 0, "ID", NULL);
-    psMetadataAddStr(arguments, PS_LIST_TAIL, "-expname", 0, "Exposure name", NULL);
-    psMetadataAddStr(arguments, PS_LIST_TAIL, "-survey", 0, "Survey type", NULL);
-    psMetadataAddStr(arguments, PS_LIST_TAIL, "-input", 0, "Path to FITS inout", NULL);
-    psMetadataAddStr(arguments, PS_LIST_TAIL, "-output", 0, "Path to FITS output", NULL);
-    psMetadataAddStr(arguments, PS_LIST_TAIL, "-results", 0, "Path to results output", NULL);
-    psMetadataAddStr(arguments, PS_LIST_TAIL, "-config", 0, "Path to config dir", NULL);
-    psMetadataAddStr(arguments, PS_LIST_TAIL, "-batch", 0, "Product type: [IN|P2|ST|TODO]", NULL);
-
-    bool ret = true;
-    if (argc < 2 || !psArgumentParse(arguments, &argc, argv)) {
-
-        usage(this, argv[0], arguments);
-        ret = false;
-    }
-    else {
-
-        char *tmp = psMemIncrRefCounter(psMetadataLookupStr(NULL, arguments, "-id"));
-        if (tmp) this->id = atoi(tmp);
-        //free(tmp); tmp = NULL;
-        this->expName = psMemIncrRefCounter(psMetadataLookupStr(NULL, arguments, "-expname"));
-        this->surveyType = psMemIncrRefCounter(psMetadataLookupStr(NULL, arguments, "-survey"));
-        this->fitsInPath = psMemIncrRefCounter(psMetadataLookupStr(NULL, arguments, "-input"));
-        this->resultsPath = psMemIncrRefCounter(psMetadataLookupStr(NULL, arguments, "-results"));
-        this->fitsOutPath = psMemIncrRefCounter(psMetadataLookupStr(NULL, arguments, "-output"));
-        this->configsDir = psMemIncrRefCounter(psMetadataLookupStr(NULL, arguments, "-config"));
-        tmp = psMemIncrRefCounter(psMetadataLookupStr(NULL, arguments, "-batch"));
-
-        if (!tmp) this->batchType = BATCH_UNDEFINED;
-        else if (strcmp(tmp, "test") == 0) this->batchType = BATCH_TEST;
-        else if (strcmp(tmp, "IN") == 0) this->batchType = BATCH_INIT;
-        else if (strcmp(tmp, "P2") == 0) this->batchType = BATCH_DETECTION;
-        else if (strcmp(tmp, "ST") == 0) this->batchType = BATCH_STACK;
-        else if (strcmp(tmp, "TODO") == 0) this->batchType = BATCH_DIFFERENCE;
-        else this->batchType = BATCH_UNDEFINED;
-
-        if (
-                (this->batchType != BATCH_INIT && !this->expName) || 
-                (this->batchType != BATCH_INIT && !this->surveyType) || 
-                (this->batchType != BATCH_INIT && !this->fitsInPath) || 
-                (this->batchType != BATCH_INIT && !this->resultsPath) || 
-                (this->batchType != BATCH_INIT && this->id == -1) ||
-                !this->fitsOutPath || 
-                !this->configsDir || 
-                this->batchType == BATCH_UNDEFINED ) {
-
-            usage(this,argv[0], arguments);
-            ret = false;
-        }
-    }
-
-    psTrace("ippToPsps", 1, "Done reading command-line arguments\n");
-    psFree(arguments);
-
-    return ret;
-}
-
-// Runs the requested process
-static int ippToPsps_run(IppToPsps *this) {
-
-    // any files?
-    if (this->batchType == BATCH_DETECTION ||
-            this->batchType == BATCH_STACK ||
-            this->batchType == BATCH_DIFFERENCE ) {
-
-        if (this->numOfInputFiles < 1) {
-
-            this->exitCode = PS_EXIT_DATA_ERROR;
-            psError(PS_ERR_UNKNOWN, false, "No input files for this batch");
-        }
-
-    }
-
-    if(this->exitCode == PS_EXIT_SUCCESS) {
-
-        // which batchType?
-        switch(this->batchType) {
-
-            case BATCH_TEST:
-                this->exitCode = ippToPsps_batchTest(this);
-                break;
-            case BATCH_INIT:
-                this->exitCode = ippToPsps_batchInit(this);
-                break;
-            case BATCH_DETECTION:
-                this->exitCode = ippToPsps_batchDetection(this);
-                break;
-            case BATCH_STACK:
-                this->exitCode = ippToPsps_batchStack(this);
-                break;
-            case BATCH_DIFFERENCE:
-                this->exitCode = ippToPsps_batchDifference(this);
-                break;
-            default:
-                psError(PS_ERR_UNKNOWN, false, "Unable to run for this batch type (%d)", this->batchType);
-                this->exitCode = false;
-                break;
-        }
-    }
-
-    return this->exitCode;
-}
-
-// Constructor
-IppToPsps *ippToPsps_Constructor(int *argc, char **argv) {
-
-    PS_ASSERT_PTR_NON_NULL(argc, NULL);
-    PS_ASSERT_PTR_NON_NULL(argv, NULL);
-
-    IppToPsps *this = psAlloc(sizeof(IppToPsps));
-    psMemSetDeallocator(this, (psFreeFunc)ippToPsps_Destructor);
-
-    // deal with DVO database
-    bool haveDvo = false;
-    for (int i=0;i<*argc; i++) {
-
-        if (strcmp(argv[i], "CATDIR") == 0) {haveDvo = true; break;}
-    }
-    if (haveDvo) this->dvoConfig = dvoConfigRead(argc, argv);
-    else this->dvoConfig = NULL;
-
-    // remaining args
-    this->id = -1;
-    this->expName = NULL;
-    this->surveyType = NULL;
-    this->surveyID = -1;
-    this->fitsInPath = NULL;
-    this->resultsPath = NULL;
-    this->resultsXmlDoc = NULL;
-    this->numOfInputFiles = 0;
-    this->inputFiles = NULL;
-    this->fitsOutPath = NULL;
-    this->fitsOut = NULL;
-    this->configsDir = NULL;
-    this->config = NULL;
-    this->pmconfig = pmConfigRead(argc, argv, NULL);
-    this->exitCode = PS_EXIT_SUCCESS;
-    this->run = ippToPsps_run;
-
-    // sort out current time
-    time_t now = time(NULL);;
-    struct tm *ts = gmtime(&now); // TODO should be UTC
-    strftime(this->todaysDate, sizeof(this->todaysDate), "%Y-%m-%d", ts);
-
-    if (!this->pmconfig) {
-
-        psError(PS_ERR_UNKNOWN, false, "Unable to read configuration.");
-        this->exitCode = PS_EXIT_CONFIG_ERROR;
-        return this;
-    }
-
-    if (!ippToPsps_Arguments(this, *argc, argv)) {
-
-        psFree(this);
-        this->exitCode = PS_EXIT_CONFIG_ERROR;
-        return this;
-    }
-
-    if (this->batchType != BATCH_INIT && !ippToPsps_readInputFilePaths(this)) {
-
-        this->exitCode = PS_EXIT_DATA_ERROR;
-        return this;
-    }
-
-    if (this->batchType == BATCH_TEST)
-        psStringAppend(&this->configsDir, "/test");
-    if (this->batchType == BATCH_INIT)
-        psStringAppend(&this->configsDir, "/init");
-    if (this->batchType == BATCH_DETECTION)
-        psStringAppend(&this->configsDir, "/detection");
-    if (this->batchType == BATCH_DIFFERENCE)
-        psStringAppend(&this->configsDir, "/diff");
-    if (this->batchType == BATCH_STACK)
-        psStringAppend(&this->configsDir, "/stack");
-
-    // create filename
-    char outputName[100];
-    sprintf(outputName, "%08d.FITS", this->id);
-    psStringAppend(&this->fitsOutPath, "/%s", outputName);
-
-    // create an output FITS file
-    int status=0;
-    if (fits_create_file(&this->fitsOut, this->fitsOutPath, &status)) {
-        fits_report_error(stderr, status);
-        psError(PS_ERR_IO, false, "Unable to create file at: '%s'", this->fitsOutPath);
-        this->exitCode = PS_EXIT_SYS_ERROR;
-        return this;
-    }
-
-    // create a config object
-    this->config = ippToPspsConfig_Constructor(this->configsDir);
-    if (this->config == NULL) {
-
-        this->exitCode = PS_EXIT_CONFIG_ERROR;
-        return this;
-    }
-
-    // get survey ID using config object
-    if (this->batchType != BATCH_INIT && 
-            !ippToPspsConfig_getSurveyId(this->config, this->surveyType, &this->surveyID)) {
-        
-        this->exitCode = PS_EXIT_CONFIG_ERROR;
-        return this;
-    }
-
-    // create XML document for results 
-    if (this->resultsPath) {
-
-        this->resultsXmlDoc = xmlNewDoc(BAD_CAST "1.0");
-        xmlNodePtr rootNode = xmlNewNode(NULL, BAD_CAST "ippToPsps_Results");
-        xmlDocSetRootElement(this->resultsXmlDoc, rootNode);
-        xmlNewChild(rootNode, NULL, BAD_CAST "filename", BAD_CAST outputName);
-    }
-
-    return this;
-}
-
-
Index: trunk/ippToPsps/src/ippToPsps.h
===================================================================
--- trunk/ippToPsps/src/ippToPsps.h	(revision 30146)
+++ 	(revision )
@@ -1,56 +1,0 @@
-/** @file ippToPsps.h
- *
- *  @brief ippToPsps
- *
- *  @ingroup ippToPsps
- *
- *  @author IfA
- *  Copyright 2009 Institute for Astronomy, University of Hawaii
- */
-
-#ifndef IPPTOPSPS_H
-#define IPPTOPSPS_H
-
-#include <psmodules.h>
-#include <dvo_util.h>
-#include "ippToPspsConfig.h"
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-
-#define MAXDETECT 60000 //TODO limit ok?
-
-typedef struct {
-
-    uint32_t id;                 // ID: might be expId for detections, skycell ID etc
-    psString expName;           // the exposure name
-    psString surveyType;        // the survey type, eg 3PI, MD01, STS, SSS
-    int8_t surveyID;            // survey ID
-    uint8_t batchType;          // PSPS batch type
-    psString fitsInPath;        // path to FITS input
-    psString resultsPath;       // path to results file
-    xmlDocPtr resultsXmlDoc;    // pointer to XML document for results
-    uint16_t numOfInputFiles;   // number of input files
-    char** inputFiles;          // array of input file names
-    psString fitsOutPath;       // path to FITS output
-    fitsfile *fitsOut;          // output FITS file
-    psString configsDir;        // path to IPP/PSPS mapping file
-    pmConfig* pmconfig;         // pmConfig
-    dvoConfig* dvoConfig;       // dvo database
-    IppToPspsConfig* config;    // config structure
-    char todaysDate[12];        // today's date
-    int exitCode;               // ps exit code
-
-    int (*run)();
-
-} IppToPsps;
-
-IppToPsps *ippToPsps_Constructor(int *argc, char **argv);
-void ippToPsps_VersionPrint(void);
-bool ippToPsps_getFlux(
-        const float exposureTime, 
-        const float magnitude, 
-        float* flux, 
-        const float magnitudeErr, 
-        float* fluxErr);
-
-# endif // IPPTOPSPS_H 
Index: trunk/ippToPsps/src/ippToPspsBatchDetection.c
===================================================================
--- trunk/ippToPsps/src/ippToPspsBatchDetection.c	(revision 30146)
+++ 	(revision )
@@ -1,389 +1,0 @@
-/** @file ippToPspsBatchDetection.c
- *
- *  @ingroup ippToPsps
- *
- *  @author IfA
- *  Copyright 2009 Institute for Astronomy, University of Hawaii
- */
-
-#include <limits.h>
-#include "ippToPsps.h"
-#include "ippToPspsConfig.h"
-#include "ippToPspsDetEnums.h"
-
-/**
-  \brief Generates all three FITS binary tables TODO update this comment:
-
-  - ImageMeta x 1
-  - FrameMeta x 60 chips
-  - Detection x 60 chips
-
-  Loop loads the data from the input smf file(s), consults the DVO database, then prepares an output FITS format suitable for PSPS.
-  */
-int ippToPsps_batchDetection(IppToPsps *this) {
-
-    int status = 0;
-    fitsfile *fitsIn;         
-
-    if (fits_open_file(&fitsIn, this->inputFiles[0], READONLY, &status)) {
-
-        fits_report_error(stderr, status);
-        return PS_EXIT_SYS_ERROR;
-    }
-
-    // get primary header and pull stuff out for later
-    int nKeys;
-    fits_get_hdrspace(fitsIn, &nKeys, NULL, &status);
-
-    float zptObs, exposureTime;
-    char filterType[20];
-    double obsTime;
-    double expStart;
-    double expTime;
-    status=0; fits_read_key(fitsIn, TFLOAT, "ZPT_OBS", &zptObs, NULL, &status);
-    status=0; fits_read_key(fitsIn, TFLOAT, "EXPREQ", &exposureTime, NULL, &status);
-    status=0; fits_read_key(fitsIn, TSTRING, "FILTERID", filterType, NULL, &status);
-    status=0; fits_read_key(fitsIn, TDOUBLE, "MJD-OBS", &expStart, NULL, &status);
-    status=0; fits_read_key(fitsIn, TDOUBLE, "EXPTIME", &expTime, NULL, &status);
-    obsTime = expStart + (expTime/172800.0); // exp start plus half exp time (converted from secs to days)
-   
-    ippToPspsConfig_writeTable(this->config, fitsIn, this->fitsOut, 1, "FrameMeta", true);
-
-    // FrameMeta values
-    fits_write_col(this->fitsOut, TLONG, FRAMEMETA_FRAMEID, 1, 1, 1, &this->id, &status);
-    fits_write_col(this->fitsOut, TSTRING, FRAMEMETA_FRAMENAME, 1, 1, 1, &this->expName, &status);
-
-    fits_write_col(this->fitsOut, TBYTE, FRAMEMETA_SURVEYID, 1, 1, 1, &this->surveyID, &status);
-
-    int8_t filterID = -1;
-    if (!ippToPspsConfig_getFilterId(this->config, filterType, &filterID)) {return PS_EXIT_DATA_ERROR;}
-    fits_write_col(this->fitsOut, TBYTE, FRAMEMETA_FILTERID, 1, 1, 1, &filterID, &status);
-
-    int16_t cameraID = 1; // TODO
-    fits_write_col(this->fitsOut, TSHORT, FRAMEMETA_CAMERAID, 1, 1, 1, &cameraID, &status);
-
-    int16_t cameraConfigID = 1; // TODO
-    fits_write_col(this->fitsOut, TSHORT, FRAMEMETA_CAMERACONFIGID, 1, 1, 1, &cameraConfigID, &status);
-
-    int16_t telescopeID = 1; // TODO
-    fits_write_col(this->fitsOut, TSHORT, FRAMEMETA_TELESCOPEID, 1, 1, 1, &telescopeID, &status);
-
-    // stuff to keep from psf.hdr header
-    int sourceId = -1, imageId = -1;
-    float fwhmMaj, fwhmMin, momentMaj, momentMin, psfFwhm, momentFwhm;
-    long pspsImageId = -1;
-
-    // DVO variables
-    SkyList *skylist = NULL;
-    dvoDetection *dvoDetections = NULL;
-    int maxDvoDetId = -1, numDvoDetections = -1;
-    Image *image = NULL;
-
-    // stuff for detections table
-    uint32_t s,d, invalidDvoRows, smfJumps, unmatched, totalDetections = 0;
-
-    long longnull = -999;
-    float floatnull = -999.0;
-    int anynull = 0;
-
-    char ccdNumber[3], extensionName[15];
-
-    // for storing FITS column data
-    long ippIDet[MAXDETECT];
-    float instMag[MAXDETECT], instMagErr[MAXDETECT], peakMag[MAXDETECT];
-    uint64_t flags[MAXDETECT];
-    long objID[MAXDETECT], detectID[MAXDETECT], ippObjID[MAXDETECT], ippDetectID[MAXDETECT], imageID[MAXDETECT];
-    double obsTimes[MAXDETECT];
-    float instFlux[MAXDETECT], instFluxErr[MAXDETECT], peakFlux[MAXDETECT];
-    int8_t filterIDs[MAXDETECT], surveyIDs[MAXDETECT];
-
-    char** assocDate = (char**)calloc(MAXDETECT, sizeof(char**));
-    for (uint32_t i=0; i<MAXDETECT;i++) assocDate[i] = (char*)calloc(20,sizeof(char));
-
-    // some stuff is the same for all detections so we can populate here
-    for (long s = 0; s<MAXDETECT; s++) {
-
-        filterIDs[s] = filterID;
-        surveyIDs[s] = this->surveyID;
-        strcpy(assocDate[s], this->todaysDate);
-    }
-
-    long maxObjID = LONG_MIN, minObjID = LONG_MAX;
-    uint64_t imageFlags;
-    short nOta = 0;
-    long i;
-    bool isDuplicate;
-    uint32_t numOfDuplicates, numInvalidFlux;
-    long numDetectionsOut, totalDetectionsOut = 0, numPhotoRef, totalNumPhotoRef = 0;
-    long removeList[MAXDETECT];
-    long thisObjId;
-    bool firstTimeIn = true, peakFluxOk, instFluxOk;
-    int ippIDetNum, instMagNum, instMagErrNum, peakMagNum;
-
-    // loop round all 60 chips
-    for (int x=0; x<8; x++) {
-        for (int y=0; y<8; y++) {
-
-            // dodge the corners
-            if (x==0 && y==0) continue;
-            if (x==0 && y==7) continue;
-            if (x==7 && y==0) continue;
-            if (x==7 && y==7) continue;
-
-            sprintf(ccdNumber, "%d%d", x, y);
-
-            // check we can move to detections table in smf
-            sprintf(extensionName, "XY%s.psf", ccdNumber);
-            status=0;
-            if (fits_movnam_hdu(fitsIn, BINARY_TBL, extensionName, 0, &status)) {
-                psError(PS_ERR_IO, false, "Can't move to extension: %s skipping this chip\n", extensionName);
-                continue;
-            }
-
-            // move to header extension
-            sprintf(extensionName, "XY%s.hdr", ccdNumber);
-            status=0;
-            if (fits_movnam_hdu(fitsIn, IMAGE_HDU, extensionName, 0, &status)) {
-                psError(PS_ERR_IO, false, "Can't move to extension: %s skipping this chip\n", extensionName);
-                continue;
-            }
-
-            // stuff to save from psf.hdr
-            status=0; fits_read_key(fitsIn, TFLOAT, "FWHM_MAJ", &fwhmMaj, NULL, &status);
-            status=0; fits_read_key(fitsIn, TFLOAT, "FWHM_MIN", &fwhmMin, NULL, &status);
-            status=0; fits_read_key(fitsIn, TFLOAT, "IQ_FW1", &momentMaj, NULL, &status);
-            status=0; fits_read_key(fitsIn, TFLOAT, "IQ_FW2", &momentMin, NULL, &status);
-            status=0; fits_read_key(fitsIn, TLONG, "IMAGEID", &imageId, NULL, &status);
-            status=0; fits_read_key(fitsIn, TLONG, "SOURCEID", &sourceId, NULL, &status);
-            status=0; fits_read_key(fitsIn, TLONG, "NASTRO", &numPhotoRef, NULL, &status);
-            totalNumPhotoRef += numPhotoRef; // total up for storing in FrameMeta
-
-            // access DVO database
-            skylist = dvoSkyListByExternID(this->dvoConfig, sourceId, imageId, &image);
-            if (skylist == NULL) {
-                psError(PS_ERR_IO, false, 
-                        "DVO: can't find SkyList for sourceId='%d' imageId='%d' (CCD = XY%s): skipping this chip\n",
-                        sourceId, imageId, ccdNumber);
-                continue;
-            }
-
-            // create unique int from 'frameID' (aka exposure ID) and ccd number
-            pspsImageId = (this->id*100) + image->ccdnum;
-
-            // now get DVO detections
-            dvoDetections = NULL;
-            numDvoDetections = dvoGetDetections(skylist, image->imageID, &dvoDetections, &maxDvoDetId);
-
-            // TODO check nDet < MAXDETECT
-
-            // create ImageMeta
-            ippToPspsConfig_writeTable(this->config, fitsIn, this->fitsOut, 1, "ImageMeta", true);
-            psfFwhm = (fwhmMaj+fwhmMin)/2;
-            momentFwhm = (momentMaj+momentMin)/2;
-            imageFlags = (uint64_t)image->flags;
-            fits_write_col(this->fitsOut, TLONGLONG, IMAGEMETA_IMAGEID, 1, 1, 1, &pspsImageId, &status);
-            fits_write_col(this->fitsOut, TLONG, IMAGEMETA_FRAMEID, 1, 1, 1, &this->id, &status);
-            fits_write_col(this->fitsOut, TSHORT, IMAGEMETA_CCDID, 1, 1, 1, &image->ccdnum, &status);
-            fits_write_col(this->fitsOut, TLONG, IMAGEMETA_PHOTOCALID, 1, 1, 1, &image->photcode, &status);
-            fits_write_col(this->fitsOut, TBYTE, IMAGEMETA_FILTERID, 1, 1, 1, &filterID, &status);
-            fits_write_col(this->fitsOut, TFLOAT, IMAGEMETA_PHOTOSCAT, 1, 1, 1, &zptObs, &status);
-            fits_write_col(this->fitsOut, TFLOAT, IMAGEMETA_PSFFWHM, 1, 1, 1, &psfFwhm, &status);
-            fits_write_col(this->fitsOut, TFLOAT, IMAGEMETA_MOMENTFWHM, 1, 1, 1, &momentFwhm, &status);
-            fits_write_col(this->fitsOut, TFLOAT, IMAGEMETA_PHOTOZERO, 1, 1, 1, &zptObs, &status);
-            fits_write_col(this->fitsOut, TLONGLONG, IMAGEMETA_QAFLAGS, 1, 1, 1, &imageFlags, &status);
-
-            // now move BACK to detections table in smf
-            sprintf(extensionName, "XY%s.psf", ccdNumber);
-            status=0;
-            if (fits_movnam_hdu(fitsIn, BINARY_TBL, extensionName, 0, &status)) {
-                psError(PS_ERR_IO, false, "Can't move to extension: %s skipping\n", extensionName);
-                continue;
-            }
-
-            // keep a running count of 'images' we find in order to write total to FrameMeta at the end
-            nOta++;
-
-            long nDet = 0;
-            if (fits_get_num_rows(fitsIn, &nDet, &status)) {
-                fits_report_error(stderr, status);
-            }
-
-            // loop round detections to populate some extra stuff
-            s = d = totalDetections = invalidDvoRows = smfJumps = unmatched = 0;
-
-            // determine column numbers for certain IPP detection columns
-            if (firstTimeIn) {
-
-                status=0;fits_get_colnum(fitsIn, CASESEN, "IPP_IDET", &ippIDetNum, &status);
-                if (status) psError(PS_ERR_IO, false, "Unable to read col num for IPP_IDET");
-                status=0;fits_get_colnum(fitsIn, CASESEN, "PSF_INST_MAG", &instMagNum, &status);
-                if (status) psError(PS_ERR_IO, false, "Unable to read col num for PSF_INST_MAG");
-                status=0;fits_get_colnum(fitsIn, CASESEN, "PSF_INST_MAG_SIG", &instMagErrNum, &status);
-                if (status) psError(PS_ERR_IO, false, "Unable to read col num for PSF_INST_MAG_SIG");
-                status=0;fits_get_colnum(fitsIn, CASESEN, "PEAK_FLUX_AS_MAG", &peakMagNum, &status);
-                if (status) psError(PS_ERR_IO, false, "Unable to read col num for PEAK_FLUX_AS_MAG");
-
-                firstTimeIn=false;
-            }
-
-            anynull = 0;
-            fits_read_col(fitsIn, TLONG, ippIDetNum, 1, 1, nDet, &longnull, ippIDet, &anynull, &status);
-            fits_read_col(fitsIn, TFLOAT, instMagNum, 1, 1, nDet, &floatnull, instMag, &anynull, &status);
-            fits_read_col(fitsIn, TFLOAT, instMagErrNum, 1, 1, nDet, &floatnull, instMagErr, &anynull, &status);
-            fits_read_col(fitsIn, TFLOAT, peakMagNum, 1, 1, nDet, &floatnull, peakMag, &anynull, &status);
-
-            // DVO detections are ordered by IPP_IDET, which increments from 0 in SMF table
-            // both DVO detections and smf detections should increment. however, there may be gaps in smf and 'invalid' rows in dvo
-            numOfDuplicates = 0;
-            numInvalidFlux = 0;
-            for (long s = 0; s<nDet; s++) {
-
-                isDuplicate = false;
-
-                // count jumps in smf file
-                if (s>0 && (ippIDet[s] != (ippIDet[s-1] + 1))) smfJumps++;
-
-                while (ippIDet[s] > dvoDetections[d].meas.detID && dvoDetections[d].meas.detID <= maxDvoDetId) {
-
-                    d++;
-                    if (!dvoDetections[d].valid) invalidDvoRows++;
-                }
-
-                if (ippIDet[s] == dvoDetections[d].meas.detID ) {
-
-                    // TODO HACK duplicates bug - don't include any duplicates
-                    thisObjId = dvoDetections[d].ave.extID;
-                    for (i=0; i<totalDetections; i++) {
-                        if (thisObjId == objID[i]) {
-                            removeList[numOfDuplicates+numInvalidFlux] = s+1;
-                            numOfDuplicates++;
-                            isDuplicate=true;
-                            break;
-                        }
-                    }
-                    // populate some arrays to be shoved in table in bulk later
-                    objID[s] = thisObjId;
-                    detectID[s] = dvoDetections[d].meas.extID;
-                    ippObjID[s] = (uint64_t)dvoDetections[d].ave.catID*1000000000 + (uint64_t)dvoDetections[d].ave.objID;
-                    ippDetectID[s] = dvoDetections[d].meas.detID;
-                    
-                    // the 'photFlags' are the same as those in the 'FLAGS' column of the smf
-                    flags[s] = ((uint64_t)dvoDetections[d].meas.dbFlags << 32) | (uint64_t)dvoDetections[d].meas.photFlags; 
-                    imageID[s] = pspsImageId;
-                    obsTimes[s] = obsTime;
-
-                    // calculate flux and flux errors from magnitudes
-                    peakFluxOk = ippToPsps_getFlux(exposureTime, peakMag[s], &peakFlux[s], 0.0, NULL);
-                    instFluxOk = ippToPsps_getFlux(exposureTime, instMag[s], &instFlux[s], instMagErr[s], &instFluxErr[s]);
-
-                    // check for invalid flux values (if not already labelled as a duplicate)
-                    if ( (!peakFluxOk || !instFluxOk) && !isDuplicate) {
-                        removeList[numOfDuplicates+numInvalidFlux] = s+1;
-                        numInvalidFlux++;
-                    }
-                    else {
-
-                        // store max/min objID
-                        if (objID[s] > maxObjID) maxObjID = objID[s];
-                        if (objID[s] < minObjID) minObjID = objID[s];
-                    }
-                    totalDetections++;
-                }
-                // if we get here then we cannot find this smf detection in DVO 
-                else {
-
-                    unmatched++;
-                    continue;
-                }
-
-                if (dvoDetections[d].meas.detID == maxDvoDetId) break;
-            }
-
-            // write number of rows (detections) to ImageMeta
-            numDetectionsOut = totalDetections - numOfDuplicates - numInvalidFlux;
-            fits_write_col(this->fitsOut, TLONG, IMAGEMETA_NDETECT, 1, 1, 1, &numDetectionsOut, &status);
-
-            // avoid writing out an empty table of detections
-            if (numDetectionsOut > 0) {
-
-                // detections
-                ippToPspsConfig_writeTable(this->config, fitsIn, this->fitsOut, nDet, "Detection", false);
-                fits_write_col(this->fitsOut, TLONGLONG, DETECTION_OBJID, 1, 1, nDet, objID, &status);
-                fits_write_col(this->fitsOut, TLONGLONG, DETECTION_DETECTID, 1, 1, nDet, detectID, &status);
-                fits_write_col(this->fitsOut, TLONGLONG, DETECTION_IPPOBJID, 1, 1, nDet, ippObjID, &status);
-                fits_write_col(this->fitsOut, TLONGLONG, DETECTION_IPPDETECTID, 1, 1, nDet, ippDetectID, &status);
-                fits_write_col(this->fitsOut, TBYTE, DETECTION_FILTERID, 1, 1, nDet, filterIDs, &status);
-                fits_write_col(this->fitsOut, TBYTE, DETECTION_SURVEYID, 1, 1, nDet, surveyIDs, &status);
-                fits_write_col(this->fitsOut, TLONGLONG, DETECTION_IMAGEID, 1, 1, nDet, imageID, &status);
-                fits_write_col(this->fitsOut, TDOUBLE, DETECTION_OBSTIME, 1, 1, nDet, obsTimes, &status);
-                fits_write_col(this->fitsOut, TFLOAT, DETECTION_INSTFLUX, 1, 1, nDet, instFlux, &status);
-                fits_write_col(this->fitsOut, TFLOAT, DETECTION_INSTFLUXERR, 1, 1, nDet, instFluxErr, &status);
-                fits_write_col(this->fitsOut, TFLOAT, DETECTION_PEAKADU, 1, 1, nDet, peakFlux, &status);
-                fits_write_col(this->fitsOut, TSTRING, DETECTION_ASSOCDATE, 1, 1, nDet, assocDate, &status); 
-                fits_write_col(this->fitsOut, TLONGLONG, DETECTION_INFOFLAG, 1, 1, nDet, flags, &status); 
-                if (numOfDuplicates||numInvalidFlux) fits_delete_rowlist(this->fitsOut, removeList, numOfDuplicates+numInvalidFlux, &status);
-
-                // skinny object
-                ippToPspsConfig_writeTable(this->config, fitsIn, this->fitsOut, nDet, "SkinnyObject", false);
-                fits_write_col(this->fitsOut, TLONGLONG, SKINNYOBJECT_OBJID, 1, 1, nDet, objID, &status);
-                fits_write_col(this->fitsOut, TLONGLONG, SKINNYOBJECT_IPPOBJID, 1, 1, nDet, ippObjID, &status);
-                fits_write_col(this->fitsOut, TBYTE, SKINNYOBJECT_SURVEYID, 1, 1, nDet, surveyIDs, &status);
-                if (numOfDuplicates||numInvalidFlux) fits_delete_rowlist(this->fitsOut, removeList, numOfDuplicates+numInvalidFlux, &status);
-
-                // object calibration color
-                ippToPspsConfig_writeTable(this->config, fitsIn, this->fitsOut, nDet, "ObjectCalColor", false);
-                fits_write_col(this->fitsOut, TLONGLONG, OBJECTCALCOLOR_OBJID, 1, 1, nDet, objID, &status);
-                fits_write_col(this->fitsOut, TLONGLONG, OBJECTCALCOLOR_IPPOBJID, 1, 1, nDet, ippObjID, &status);
-                fits_write_col(this->fitsOut, TBYTE, OBJECTCALCOLOR_FILTERID, 1, 1, nDet, filterIDs, &status);
-                if (numOfDuplicates||numInvalidFlux) fits_delete_rowlist(this->fitsOut, removeList, numOfDuplicates+numInvalidFlux, &status);
-            }
-
-            psLogMsg("ippToPsps", PS_LOG_INFO,
-                    "+-----------+---------+----------+------------------+---------------+--------------+\n"
-                    "| Extension | Rows in | Rows out | Missing from DVO | Duplicate IDs | Invalid Flux |\n"
-                    "|  %s |  %5ld  |   %5ld  |      %5d       |    %5d      |    %5d     |\n",
-                    extensionName, nDet, numDetectionsOut, unmatched, numOfDuplicates, numInvalidFlux);
-
-            totalDetectionsOut += numDetectionsOut;
-
-            if (dvoDetections!= NULL) dvoFree(dvoDetections);
-            SkyListFree(skylist);
-        }
-    }
-
-    psLogMsg("ippToPsps", PS_LOG_INFO, "Total detections for this exposure = %ld\n", totalDetectionsOut);
-
-    for (uint32_t i=0; i<MAXDETECT;i++) free(assocDate[i]);
-    free(assocDate);
-
-    // write number of images we have found into FrameMeta table
-    status=0; 
-    if (fits_movnam_hdu(this->fitsOut, BINARY_TBL, "FrameMeta", 0, &status))
-        psError(PS_ERR_IO, false, "Can't move back to FrameMeta extension to write number of OTAs\n");
-    else { 
-        fits_write_col(this->fitsOut, TSHORT, FRAMEMETA_NOTA, 1, 1, 1, &nOta, &status);
-        fits_write_col(this->fitsOut, TSHORT, FRAMEMETA_NUMPHOTOREF, 1, 1, 1, &totalNumPhotoRef, &status);
-    }
-    status=0;
-    if (fits_close_file(fitsIn, &status)) fits_report_error(stderr, status);
-
-    // write results
-    if (this->resultsXmlDoc) {
-
-        xmlNodePtr rootNode = xmlDocGetRootElement(this->resultsXmlDoc);
-        char tmp[100];
-        sprintf(tmp, "%ld", minObjID);
-        xmlNewChild(rootNode, NULL, BAD_CAST "minObjID", BAD_CAST tmp);
-        sprintf(tmp, "%ld", maxObjID);
-        xmlNewChild(rootNode, NULL, BAD_CAST "maxObjID", BAD_CAST tmp);
-        sprintf(tmp, "%ld", totalDetectionsOut);
-        xmlNewChild(rootNode, NULL, BAD_CAST "totalDetections", BAD_CAST tmp);
-    }
-
-    psLogMsg("ippToPsps", PS_LOG_INFO, "Data written for a total of %d chips/OTAs", nOta);
-
-    if (nOta < 1) return PS_EXIT_DATA_ERROR;
-
-    return PS_EXIT_SUCCESS;
-}
-
Index: trunk/ippToPsps/src/ippToPspsBatchDifference.c
===================================================================
--- trunk/ippToPsps/src/ippToPspsBatchDifference.c	(revision 30146)
+++ 	(revision )
@@ -1,119 +1,0 @@
-/** @file ippToPspsBatchDifference.c
- *
- *  @ingroup ippToPsps
- *
- *  @author IfA
- *  Copyright 2009 Institute for Astronomy, University of Hawaii
- */
-
-#include "ippToPsps.h"
-#include "ippToPspsConfig.h"
-#include "ippToPspsDiffEnums.h"
-
-/**
-  \brief Loops round all the diff cmf files (one per skycell) and generates one FITS  
-  */
-int ippToPsps_batchDifference(IppToPsps *this) {
-
-    if (this->numOfInputFiles < 1) return PS_EXIT_DATA_ERROR;
-
-    uint32_t skycell = 0; // TODO
-    long tableSize;
-    float SIG_CONST = 5.0; // TODO
-    double obsTime;
-    float obsTimes[MAXDETECT];
-
-    char skycellStr[10];
-    char extensionName[20];
-    sprintf(extensionName, "SkyChip.psf");
-
-    int status;
-    fitsfile *fitsIn;         
-    int nKeys;
-    status=0;
-
-    float psfSigma[MAXDETECT];
-    long numLowSig = 0;
-    long numHighSig = 0;
-    long highSig[MAXDETECT];
-    long lowSig[MAXDETECT];
-    int anynull = 0;
-    float floatnull = -999.0;
-
-    for (uint16_t i = 0; i<this->numOfInputFiles; i++) {
-
-        if (fits_open_file(&fitsIn, this->inputFiles[i], READONLY, &status)) {
-
-            psError(PS_ERR_IO, false, "Unable to open file: '%s'", this->inputFiles[i]);
-            break; 
-        }
-
-        //psLogMsg("ippToPsps", PS_LOG_INFO,"Opened %s", this->inputFiles[i]);
-
-        skycell = i; // TODO
-        sprintf(skycellStr, "SC%03d", skycell);
-
-        // build StackMeta from primary header
-        fits_get_hdrspace(fitsIn, &nKeys, NULL, &status);
-        ippToPspsConfig_writeTable(this->config, fitsIn,  this->fitsOut, 1, "StackMeta", true);
-        fits_write_col(this->fitsOut, TLONG, STACKMETA_SKYCELLID, 1, 1, 1, &skycell, &status);
-
-        // build StackToImage
-        ippToPspsConfig_writeTable(this->config, fitsIn,  this->fitsOut, 1, "StackToImage", true);
-        //  psMetadataAdd(headerOut, PS_LIST_TAIL, "SKYCELL_ID", PS_DATA_S32, "Skycell ID", skycell);
-
-        // save some stuff for later
-        status=0; fits_read_key(fitsIn, TDOUBLE, "MJD-OBS", &obsTime, NULL, &status);
-
-        if (fits_movnam_hdu(fitsIn, BINARY_TBL, extensionName, 0, &status)) {
-            psError(PS_ERR_IO, false, "Can't move to extension: %s skipping\n", extensionName);
-            continue;
-        }
-        if (fits_get_num_rows(fitsIn, &tableSize, &status)) {
-            psError(PS_ERR_IO, false, "Can't count rows in extension: %s skipping\n", extensionName);
-            continue;
-        }
-
-        numLowSig = numHighSig = 0;
-
-        //  get magnitude error (PSF_INST_MAG_SIG)
-        fits_read_col(fitsIn, TFLOAT, 9, 1, 1, tableSize, &floatnull, psfSigma, &anynull, &status);
-
-        for (long j = 0; j<tableSize; j++) {
-
-            obsTimes[j] = obsTime;
-
-            // split between low and high 'significance difference detections'
-            if (psfSigma[j] > (1.0/SIG_CONST)) {
-
-                //     psMetadataAdd(rowOut, 0, "stackMetaID", PS_DATA_S64, "reference to stack", 0); // TODO
-                lowSig[numLowSig] = j+1;
-                numLowSig++;
-            }
-            else {
-
-                highSig[numHighSig] = j+1;
-                numHighSig++;
-            }
-        }
-
-        psLogMsg("ippToPsps", PS_LOG_INFO, 
-                "Reading skycell '%d'. High significant detections = %ld low significant detections = %ld", 
-                skycell, numHighSig, numLowSig);
-
-        //  psMetadataAdd(headerOut, PS_LIST_TAIL, "SKYCELL_ID", PS_DATA_S32, "Skycell ID", skycell);
-
-        // write out low and high significant tables
-        ippToPspsConfig_writeTable(this->config, fitsIn, this->fitsOut, 1, "StackLowSigDelta", false);
-        ippToPspsConfig_writeTable(this->config, fitsIn, this->fitsOut, tableSize, "StackHighSigDelta", false);
-        fits_write_col(this->fitsOut, TFLOAT, STACKHIGHSIGDELTA_OBSTIME, 1, 1, tableSize, obsTimes, &status);
-        if (numLowSig) fits_delete_rowlist(this->fitsOut, lowSig, numLowSig, &status);
-
-
-        //   psMetadataAdd(headerOut, PS_LIST_TAIL, "SKYCELL_ID", PS_DATA_S32, "Skycell ID", skycell);
-
-        if (fits_close_file(fitsIn, &status)) fits_report_error(stderr, status);
-    }
-
-    return PS_EXIT_SUCCESS;
-}
Index: trunk/ippToPsps/src/ippToPspsBatchInit.c
===================================================================
--- trunk/ippToPsps/src/ippToPspsBatchInit.c	(revision 30146)
+++ 	(revision )
@@ -1,23 +1,0 @@
-/** @file ippToPspsBatchInit.c
- *
- *  @ingroup ippToPsps
- *
- *  @author IfA
- *  Copyright 2009 Institute for Astronomy, University of Hawaii
- */
-
-#include "ippToPsps.h"
-#include "ippToPspsConfig.h"
-
-/**
-  \brief 
-
-*/
-int ippToPsps_batchInit(IppToPsps *this) {
-
-    if (!ippToPspsConfig_populateFromFile(this->config, this->fitsOut)) return PS_EXIT_CONFIG_ERROR;
-
-    return PS_EXIT_SUCCESS;
-}
-
-
Index: trunk/ippToPsps/src/ippToPspsBatchStack.c
===================================================================
--- trunk/ippToPsps/src/ippToPspsBatchStack.c	(revision 30146)
+++ 	(revision )
@@ -1,165 +1,0 @@
-/** @file ippToPspsBatchStack.c
- *
- *  @ingroup ippToPsps
- *
- *  @author IfA
- *  Copyright 2009 Institute for Astronomy, University of Hawaii
- */
-
-#include "ippToPsps.h"
-#include "ippToPspsConfig.h"
-#include "ippToPspsStackEnums.h"
-
-
-/**
- * \brief  
- */
-int ippToPsps_batchStack(IppToPsps *this) {
-
-    int status = 0;
-    fitsfile *fitsIn;
-
-    if (fits_open_file(&fitsIn, this->inputFiles[0], READONLY, &status)) {
-
-        fits_report_error(stderr, status);
-        return PS_EXIT_SYS_ERROR;
-    }
-
-    long removeList[MAXDETECT];
-    float instMag[MAXDETECT];
-    float floatnull = -999.0;
-    int anynull = 0;
-
-    // get primary header and pull stuff out for later
-    int nKeys = 0;
-    fits_get_hdrspace(fitsIn, &nKeys, NULL, &status);
-    float exposureTime; status=0; fits_read_key(fitsIn, TFLOAT, "EXPTIME", &exposureTime, NULL, &status);
-    char filterType[20]; status=0; fits_read_key(fitsIn, TSTRING, "FPA.FILTERID", filterType, NULL, &status);
-
-
-    char** assocDate = (char**)calloc(MAXDETECT, sizeof(char**));
-    for (uint32_t i=0; i<MAXDETECT;i++) assocDate[i] = (char*)calloc(20,sizeof(char));
-    int8_t filterIDs[MAXDETECT], surveyIDs[MAXDETECT];
-
-
-    // write StackMeta
-    ippToPspsConfig_writeTable(this->config, fitsIn, this->fitsOut, 1, "StackMeta", true);
-    fits_write_col(this->fitsOut, TLONG, STACKMETA_SKYCELLID, 1, 1, 1, &this->id, &status);
-
-    int8_t filterID = -1;
-    if (!ippToPspsConfig_getFilterId(this->config, filterType, &filterID)) {return PS_EXIT_DATA_ERROR;}
-    fits_write_col(this->fitsOut, TBYTE, STACKMETA_FILTERID, 1, 1, 1, &filterID, &status);
-
-    fits_write_col(this->fitsOut, TBYTE, STACKMETA_SURVEYID, 1, 1, 1, &this->surveyID, &status);
-
-
-    // psf detections
-    char extensionName[15];
-    sprintf(extensionName, "SkyChip.psf");
-    if (fits_movnam_hdu(fitsIn, BINARY_TBL, extensionName, 0, &status)) {
-        psError(PS_ERR_IO, false, "Can't move to extension: %s\n", extensionName);
-        
-    }
-    else {
-   
-        // some stuff is the same for all detections so we can populate here
-        for (long s = 0; s<MAXDETECT; s++) {
-
-            filterIDs[s] = filterID;
-            surveyIDs[s] = this->surveyID;
-            strcpy(assocDate[s], this->todaysDate);
-        }
-
-
-        long nDet = 0;
-        if (fits_get_num_rows(fitsIn, &nDet, &status)) {
-            fits_report_error(stderr, status);
-        }
-
-        int instMagNum;
-        status=0;fits_get_colnum(fitsIn, CASESEN, "PSF_INST_MAG", &instMagNum, &status);
-        if (status) psError(PS_ERR_IO, false, "Unable to read col num for PSF_INST_MAG");
-        fits_read_col(fitsIn, TFLOAT, instMagNum, 1, 1, nDet, &floatnull, instMag, &anynull, &status);
-
-
-        printf("Looping through %ld psf detections\n", nDet);
-        float mag;
-        long unmatched = 0, totalDetections = 0, numOfDuplicates = 0, numInvalidFlux = 0, numDetectionsOut = 0;
-
-        for (long s = 0; s<nDet; s++) {
-
-            // TODO implement this match in DVO
-            if (1) {
-
-                mag = instMag[s];
-                if (!isfinite(mag) || mag < -998.0) {
-
-                    removeList[numOfDuplicates+numInvalidFlux] = s+1;
-                    numInvalidFlux++;
-                }
-
-                totalDetections++;
-            }
-            else {
-
-                unmatched++;
-                continue;
-            }
-        }
-
-        numDetectionsOut = totalDetections - numInvalidFlux;
-
-        if (numDetectionsOut > 0) {
-
-            ippToPspsConfig_writeTable(this->config, fitsIn, this->fitsOut, nDet, "StackDetection", false);
-            fits_write_col(this->fitsOut, TLONG, STACKDETECTION_SKYCELLID, 1, 1, 1, &this->id, &status);
-            fits_write_col(this->fitsOut, TBYTE, STACKDETECTION_FILTERID, 1, 1, nDet, filterIDs, &status);
-            fits_write_col(this->fitsOut, TBYTE, STACKDETECTION_SURVEYID, 1, 1, nDet, surveyIDs, &status);
-            fits_write_col(this->fitsOut, TSTRING, STACKDETECTION_ASSOCDATE, 1, 1, nDet, assocDate, &status);
-
-            if (numInvalidFlux) fits_delete_rowlist(this->fitsOut, removeList, numInvalidFlux, &status);
-
-        }
-        psLogMsg("ippToPsps", PS_LOG_INFO,
-                "+---------------+---------+----------+------------------+---------------+--------------+\n"
-                "|   Extension   | Rows in | Rows out | Missing from DVO | Duplicate IDs | Invalid Flux |\n"
-                "|  %12s |  %5ld  |   %5ld  |      %5ld       |    %5ld      |    %5ld     |\n",
-                extensionName, nDet, numDetectionsOut, unmatched, numOfDuplicates, numInvalidFlux);
-
-    }
-
-
-
-    // extended source
-    sprintf(extensionName, "SkyChip.xsrc");
-    if (fits_movnam_hdu(fitsIn, BINARY_TBL, extensionName, 0, &status)) {
-        psError(PS_ERR_IO, false, "Can't move to extension: %s\n", extensionName);
-
-    }
-    else {
-
-        long nDet = 0;
-        if (fits_get_num_rows(fitsIn, &nDet, &status)) {
-            fits_report_error(stderr, status);
-        }
-
-        printf("Looping through %ld extended source detections\n", nDet);
-        for (long s = 0; s<nDet; s++) {
-
-
-
-        }
-
-        ippToPspsConfig_writeTable(this->config, fitsIn, this->fitsOut, nDet, "StackApFlx", false);
-        fits_write_col(this->fitsOut, TBYTE, STACKAPFLX_FILTERID, 1, 1, nDet, filterIDs, &status);
-        fits_write_col(this->fitsOut, TBYTE, STACKAPFLX_SURVEYID, 1, 1, nDet, surveyIDs, &status);
-    }
-
-    status=0;
-    if (fits_close_file(fitsIn, &status)) fits_report_error(stderr, status);
-
-
-    return PS_EXIT_SUCCESS;
-}
-
-
Index: trunk/ippToPsps/src/ippToPspsBatchTest.c
===================================================================
--- trunk/ippToPsps/src/ippToPspsBatchTest.c	(revision 30146)
+++ 	(revision )
@@ -1,350 +1,0 @@
-/** @file ippToPspsBatchDetection.c
- *
- *  @ingroup ippToPsps
- *
- *  @author IfA
- *  Copyright 2009 Institute for Astronomy, University of Hawaii
- */
-
-#include <limits.h>
-#include "ippToPsps.h"
-#include "ippToPspsConfig.h"
-#include "ippToPspsTestEnums.h"
-#include "fitsio.h"
-
-
-/**
-  \brief test data for checking PSPS values correspond with IPP 
-
-*/
-int ippToPsps_batchTest(IppToPsps *this) {
-
-    if (this->numOfInputFiles < 1) return PS_EXIT_DATA_ERROR;
-
-    int status = 0;
-    fitsfile *fitsIn;         
-    int nKeys;
-
-    if (fits_open_file(&fitsIn, this->inputFiles[0], READONLY, &status)) {
-
-        fits_report_error(stderr, status);
-        return PS_EXIT_SYS_ERROR;
-    }
-
-    // get primary header and pull stuff out for later
-    fits_get_hdrspace(fitsIn, &nKeys, NULL, &status);
-
-    float zptObs, zeroPoint, exposureTime;
-    char filterType[20];
-    status=0; fits_read_key(fitsIn, TFLOAT, "ZPT_OBS", &zptObs, NULL, &status);
-    status=0; fits_read_key(fitsIn, TFLOAT, "ZPT_REF", &zeroPoint, NULL, &status);
-    status=0; fits_read_key(fitsIn, TFLOAT, "EXPREQ", &exposureTime, NULL, &status);
-    status=0; fits_read_key(fitsIn, TSTRING, "FILTERID", filterType, NULL, &status);
-
-//    ippToPspsConfig_writeTable(this->config, fitsIn, this->fitsOut, 1, "FrameMeta", true);
-
-    // FrameMeta values
-//    fits_write_col(this->fitsOut, TLONG, FRAMEMETA_FRAMEID, 1, 1, 1, &this->id, &status);
-
-    int8_t filterID = -1;
-    ippToPspsConfig_getFilterId(this->config, filterType, &filterID);
-//    fits_write_col(this->fitsOut, TBYTE, FRAMEMETA_FILTERID, 1, 1, 1, &filterID, &status);
-
-    // stuff to keep from psf.hdr header
-    double obsTime = 0.0;
-    int sourceId = -1;
-    int imageId = -1;
-    float fwhmMaj;
-    float fwhmMin;
-    float momentMaj;
-    float momentMin;
-    float psfFwhm;
-    float momentFwhm;
-    long pspsImageId = -1;
-
-    // DVO variables
-    SkyList *skylist = NULL;
-    dvoDetection *dvoDetections = NULL;
-    int maxDvoDetId = -1;
-    int numDvoDetections = -1;
-    Image *pImage = NULL;
-
-    // stuff for detections table
-    time_t now;
-    struct tm *ts;
-    char timeStr[12];
-    now = time(NULL);
-    ts = gmtime(&now); // TODO should be UTC
-    strftime(timeStr, sizeof(timeStr), "%Y-%m-%d", ts);
-
-    uint32_t totalDetections = 0;
-    uint32_t s,d;
-    uint32_t invalidDvoRows;
-    uint32_t smfJumps;
-    uint32_t unmatched;
-
-    long longnull = -999;
-    float floatnull = -999.0;
-    int anynull = 0;
-
-    char ccdNumber[3];
-    char extensionName[15];
-
-    long ippIDet[MAXDETECT];
-    float instMag[MAXDETECT];
-    float instMagErr[MAXDETECT];
-    float peakMag[MAXDETECT];
-    uint64_t flags[MAXDETECT];
-    long objID[MAXDETECT];
-    long detectID[MAXDETECT];
-    long ippObjID[MAXDETECT];
-    long ippDetectID[MAXDETECT];
-    long imageID[MAXDETECT];
-    float obsTimes[MAXDETECT];
-    float instFlux[MAXDETECT];
-    float instFluxErr[MAXDETECT];
-    float peakFlux[MAXDETECT];
-    int8_t filterIDs[MAXDETECT];
-
-    char** assocDate = (char**)calloc(MAXDETECT, sizeof(char**));
-    for (uint32_t i=0; i<MAXDETECT;i++) assocDate[i] = (char*)calloc(20,sizeof(char));
-
-    // some stuff is the same for all detections so we can populate here
-    for (long s = 0; s<MAXDETECT; s++) {
-
-        filterIDs[s] = filterID;
-        strcpy(assocDate[s], timeStr);
-    }
-
-    long maxObjID = LONG_MIN; 
-    long minObjID = LONG_MAX;
-    uint64_t imageFlags;
-    short nOta = 0;
-    long i;
-    bool isDuplicate;
-    uint32_t numOfDuplicates;
-    uint32_t numInvalidFlux;
-    long numDetectionsOut;
-    long removeList[MAXDETECT];
-    long thisObjId;
-    bool firstTimeIn = true, peakFluxOk, instFluxOk;
-    int ippIDetNum, instMagNum, instMagErrNum, peakMagNum;
-
-    // loop round all 60 chips
-    for (int x=0; x<8; x++) {
-        for (int y=0; y<8; y++) {
-
-            // dodge the corners
-            if (x==0 && y==0) continue;
-            if (x==0 && y==7) continue;
-            if (x==7 && y==0) continue;
-            if (x==7 && y==7) continue;
-
-            sprintf(ccdNumber, "%d%d", x, y);
-
-            // check we can move to detections table in smf
-            sprintf(extensionName, "XY%s.psf", ccdNumber);
-            status=0;
-            if (fits_movnam_hdu(fitsIn, BINARY_TBL, extensionName, 0, &status)) {
-                psError(PS_ERR_IO, false, "Can't move to extension: %s skipping this chip\n", extensionName);
-                continue;
-            }
-
-            // move to header extension
-            sprintf(extensionName, "XY%s.hdr", ccdNumber);
-            status=0;
-            if (fits_movnam_hdu(fitsIn, IMAGE_HDU, extensionName, 0, &status)) {
-                psError(PS_ERR_IO, false, "Can't move to extension: %s skipping this chip\n", extensionName);
-                continue;
-            }
-
-            // stuff to save from psf.hdr
-            status=0; fits_read_key(fitsIn, TFLOAT, "FWHM_MAJ", &fwhmMaj, NULL, &status);
-            status=0; fits_read_key(fitsIn, TFLOAT, "FWHM_MIN", &fwhmMin, NULL, &status);
-            status=0; fits_read_key(fitsIn, TFLOAT, "IQ_FW1", &momentMaj, NULL, &status);
-            status=0; fits_read_key(fitsIn, TFLOAT, "IQ_FW2", &momentMin, NULL, &status);
-            status=0; fits_read_key(fitsIn, TDOUBLE, "MJD-OBS", &obsTime, NULL, &status);
-
-            status=0; fits_read_key(fitsIn, TLONG, "IMAGEID", &imageId, NULL, &status);
-            status=0; fits_read_key(fitsIn, TLONG, "SOURCEID", &sourceId, NULL, &status);
-
-            // access DVO database
-            skylist = dvoSkyListByExternID(this->dvoConfig, sourceId, imageId, &pImage);
-            if (skylist == NULL) {
-                psError(PS_ERR_IO, false, "DVO: can't find SkyList for sourceId='%d' imageId='%d' (CCD = XY%s): skipping\n", sourceId, imageId, ccdNumber);
-                continue;
-            }
-
-            // create unique int from 'frameID' (aka exposure ID) and ccd number
-            pspsImageId = (this->id*100) + pImage->ccdnum;
-
-            // now get DVO detections
-            dvoDetections = NULL;
-            numDvoDetections = dvoGetDetections(skylist, pImage->imageID, &dvoDetections, &maxDvoDetId);
-
-            // TODO check nDet < MAXDETECT
-
-            // create ImageMeta
-    //        ippToPspsConfig_writeTable(this->config, fitsIn, this->fitsOut, 1, "ImageMeta", true);
-            psfFwhm = (fwhmMaj+fwhmMin)/2;
-            momentFwhm = (momentMaj+momentMin)/2;
-            imageFlags = (uint64_t)pImage->flags;
-      //      fits_write_col(this->fitsOut, TLONG, IMAGEMETA_PHOTOCALID, 1, 1, 1, &pImage->photcode, &status); 
-        //    fits_write_col(this->fitsOut, TBYTE, IMAGEMETA_FILTERID, 1, 1, 1, &filterID, &status);
-        //    fits_write_col(this->fitsOut, TFLOAT, IMAGEMETA_PHOTOSCAT, 1, 1, 1, &zptObs, &status);
-        //    fits_write_col(this->fitsOut, TFLOAT, IMAGEMETA_PSFFWHM, 1, 1, 1, &psfFwhm, &status);
-        //    fits_write_col(this->fitsOut, TFLOAT, IMAGEMETA_PHOTOZERO, 1, 1, 1, &zptObs, &status);
-        //    fits_write_col(this->fitsOut, TLONGLONG, IMAGEMETA_QAFLAGS, 1, 1, 1, &imageFlags, &status);
-
-            // now move BACK to detections table in smf
-            sprintf(extensionName, "XY%s.psf", ccdNumber);
-            status=0;
-            if (fits_movnam_hdu(fitsIn, BINARY_TBL, extensionName, 0, &status)) {
-                psError(PS_ERR_IO, false, "Can't move to extension: %s skipping\n", extensionName);
-                continue;
-            }
-
-            // keep a running count of 'images' we find in order to write total to FrameMeta at the end
-            nOta++;
-
-            long nDet = 0;
-            if (fits_get_num_rows(fitsIn, &nDet, &status)) {
-                fits_report_error(stderr, status);
-            }
-
-            // loop round detections to populate some extra stuff
-            s = d = totalDetections = invalidDvoRows = smfJumps = unmatched = 0;
-
-            // determine column numbers for certain IPP detection columns
-            if (firstTimeIn) {
-
-                status=0;fits_get_colnum(fitsIn, CASESEN, "IPP_IDET", &ippIDetNum, &status);
-                if (status) psError(PS_ERR_IO, false, "Unable to read col num for IPP_IDET");
-                status=0;fits_get_colnum(fitsIn, CASESEN, "PSF_INST_MAG", &instMagNum, &status);
-                if (status) psError(PS_ERR_IO, false, "Unable to read col num for PSF_INST_MAG");
-                status=0;fits_get_colnum(fitsIn, CASESEN, "PSF_INST_MAG_SIG", &instMagErrNum, &status);
-                if (status) psError(PS_ERR_IO, false, "Unable to read col num for PSF_INST_MAG_SIG");
-                status=0;fits_get_colnum(fitsIn, CASESEN, "PEAK_FLUX_AS_MAG", &peakMagNum, &status);
-                if (status) psError(PS_ERR_IO, false, "Unable to read col num for PEAK_FLUX_AS_MAG");
-
-                firstTimeIn=false;
-            }
-
-            anynull = 0;
-            fits_read_col(fitsIn, TLONG, ippIDetNum, 1, 1, nDet, &longnull, ippIDet, &anynull, &status);
-            fits_read_col(fitsIn, TFLOAT, instMagNum, 1, 1, nDet, &floatnull, instMag, &anynull, &status);
-            fits_read_col(fitsIn, TFLOAT, instMagErrNum, 1, 1, nDet, &floatnull, instMagErr, &anynull, &status);
-            fits_read_col(fitsIn, TFLOAT, peakMagNum, 1, 1, nDet, &floatnull, peakMag, &anynull, &status);
-
-            // DVO detections are ordered by IPP_IDET, which increments from 0 in SMF table
-            // both DVO detections and smf detections should increment. however, there may be gaps in smf and 'invalid' rows in dvo
-            numOfDuplicates = 0;
-            numInvalidFlux = 0;
-            for (long s = 0; s<nDet; s++) {
-
-                isDuplicate = false;
-
-                // count jumps in smf file
-                if (s>0 && (ippIDet[s] != (ippIDet[s-1] + 1))) smfJumps++;
-
-                while (ippIDet[s] > dvoDetections[d].meas.detID && dvoDetections[d].meas.detID <= maxDvoDetId) {
-
-                    d++;
-                    if (!dvoDetections[d].valid) invalidDvoRows++;
-                }
-
-                if (ippIDet[s] == dvoDetections[d].meas.detID ) {
-
-                    // TODO HACK duplicates bug - don't include any duplicates
-                    thisObjId = dvoDetections[d].ave.extID;
-                    for (i=0; i<totalDetections; i++) {
-                        if (thisObjId == objID[i]) {
-                            removeList[numOfDuplicates+numInvalidFlux] = s+1;
-                            numOfDuplicates++;
-                            isDuplicate=true;
-                            break;
-                        }
-                    }
-                    // populate some arrays to be shoved in table in bulk later
-                    objID[s] = thisObjId;
-                    detectID[s] = dvoDetections[d].meas.extID;
-                    ippObjID[s] = (uint64_t)dvoDetections[d].ave.catID*1000000000 + (uint64_t)dvoDetections[d].ave.objID;
-                    ippDetectID[s] = dvoDetections[d].meas.detID;
-                    flags[s] = ((uint64_t)dvoDetections[d].meas.dbFlags << 32) | (uint64_t)dvoDetections[d].meas.photFlags;
-                    imageID[s] = pspsImageId;
-                    obsTimes[s] = obsTime;
-
-                    peakFluxOk = ippToPsps_getFlux(exposureTime, peakMag[s], &peakFlux[s], 0.0, NULL);
-                    instFluxOk = ippToPsps_getFlux(exposureTime, instMag[s], &instFlux[s], instMagErr[s], &instFluxErr[s]);
-
-                    // check for invalid flux values (if not already labelled as a duplicate)
-                    if ( (!peakFluxOk || !instFluxOk) && !isDuplicate) {
-                        removeList[numOfDuplicates+numInvalidFlux] = s+1;
-                        numInvalidFlux++;
-                    }
-
-                    // store max/min objID
-                    if (objID[s] > maxObjID) maxObjID = objID[s];
-                    if (objID[s] < minObjID) minObjID = objID[s];
-
-                    totalDetections++;
-                }
-                // if we get here then we cannot find this smf detection in DVO 
-                else {
-
-                    unmatched++;
-                    continue;
-                }
-
-                if (dvoDetections[d].meas.detID == maxDvoDetId) break;
-            }
-
-            // write number of rows (detections) to ImageMeta
-            numDetectionsOut = totalDetections - numOfDuplicates - numInvalidFlux;
-          //  fits_write_col(this->fitsOut, TLONG, IMAGEMETA_NDETECT, 1, 1, 1, &numDetectionsOut, &status);
-
-            // detections
-            ippToPspsConfig_writeTable(this->config, fitsIn, this->fitsOut, nDet, "Detection", false);
-            fits_write_col(this->fitsOut, TLONGLONG, DETECTION_OBJID, 1, 1, nDet, objID, &status);
-            fits_write_col(this->fitsOut, TLONGLONG, DETECTION_DETECTID, 1, 1, nDet, detectID, &status);
-            fits_write_col(this->fitsOut, TLONGLONG, DETECTION_IPPOBJID, 1, 1, nDet, ippObjID, &status);
-            fits_write_col(this->fitsOut, TLONGLONG, DETECTION_IPPDETECTID, 1, 1, nDet, ippDetectID, &status);
-            fits_write_col(this->fitsOut, TBYTE, DETECTION_FILTERID, 1, 1, nDet, filterIDs, &status);
-            fits_write_col(this->fitsOut, TLONGLONG, DETECTION_IMAGEID, 1, 1, nDet, imageID, &status);
-            fits_write_col(this->fitsOut, TFLOAT, DETECTION_INSTFLUX, 1, 1, nDet, instFlux, &status);
-            //fits_write_col(this->fitsOut, TFLOAT, DETECTION_INSTFLUXERR, 1, 1, nDet, instFluxErr, &status);
-            //fits_write_col(this->fitsOut, TFLOAT, DETECTION_PEAKADU, 1, 1, nDet, peakFlux, &status);
-            fits_write_col(this->fitsOut, TLONGLONG, DETECTION_INFOFLAG, 1, 1, nDet, flags, &status);
-            if (numOfDuplicates||numInvalidFlux) fits_delete_rowlist(this->fitsOut, removeList, numOfDuplicates+numInvalidFlux, &status);
-
-
-            psLogMsg("ippToPsps", PS_LOG_INFO,
-                    "+-----------+---------+----------+------------------+---------------+--------------+\n"
-                    "| Extension | Rows in | Rows out | Missing from DVO | Duplicate IDs | Invalid Flux |\n"
-                    "|  %s |  %5ld  |   %5ld  |      %5d       |    %5d      |    %5d     |\n",
-                    extensionName, nDet, numDetectionsOut, unmatched, numOfDuplicates, numInvalidFlux);
-
-            if (dvoDetections!= NULL) dvoFree(dvoDetections);
-            SkyListFree(skylist);
-        }
-    }
-
-    for (uint32_t i=0; i<MAXDETECT;i++) free(assocDate[i]);
-    free(assocDate);
-
-    // write number of images we have found into FrameMeta table
-    status=0; 
-    //if (fits_movnam_hdu(this->fitsOut, BINARY_TBL, "FrameMeta", 0, &status))
-      //  psError(PS_ERR_IO, false, "Can't move back to FrameMeta extension to write number of OTAs\n");
-    //else 
-    //    fits_write_col(this->fitsOut, TSHORT, FRAMEMETA_NOTA, 1, 1, 1, &nOta, &status);
-
-    status=0;
-    if (fits_close_file(fitsIn, &status)) fits_report_error(stderr, status);
-
-    psLogMsg("ippToPsps", PS_LOG_INFO, "Data written for a total of %d chips/OTAs", nOta);
-
-    return PS_EXIT_SUCCESS;
-}
-
-
Index: trunk/ippToPsps/src/ippToPspsConfig.c
===================================================================
--- trunk/ippToPsps/src/ippToPspsConfig.c	(revision 30146)
+++ 	(revision )
@@ -1,921 +1,0 @@
-/** @file ippToPspsConfig.c
- *
- *  @ingroup ippToPsps
- *
- *  @author IfA
- *  Copyright 2009 Institute for Astronomy, University of Hawaii
- */
-
-#include "ippToPspsConfig.h"
-#include <ctype.h>
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-
-// Gets PS type from string
-static int ippToPsps_GetDataType(char *typename) {
-
-    if (!strncmp(typename, "TBYTE", 5))  return TBYTE;
-    if (!strncmp(typename, "TSHORT", 6)) return TSHORT;
-    if (!strncmp(typename, "TLONGLONG", 9)) return TLONGLONG;
-    if (!strncmp(typename, "TLONG", 5)) return TLONG;
-    if (!strncmp(typename, "TFLOAT", 6)) return TFLOAT;
-    if (!strncmp(typename, "TDOUBLE", 7)) return TDOUBLE;
-    if (!strncmp(typename, "TSTRING", 7)) return TSTRING;
-
-    psError(PS_ERR_IO, false, "Don't understand type '%s'", typename);
-
-    return 0;
-}
-
-// finds a column within this table
-static IppToPspsConfig_Column* ippToPspsConfig_findColumn(IppToPspsConfig_Table* table, const char* name) {
-
-    IppToPspsConfig_Column* column = NULL;
-
-    for (uint32_t i=0; i<table->numOfColumns; i++) {
-
-        if (strcmp(table->columns[i].pspsName, name) == 0) {
-            column = table->columns+i;
-            break;
-        }
-    }
-
-    if (!column) psError(PS_ERR_IO, false, "Could not find column '%s' in table '%s'", name, table->name);
-
-    return column;
-}
-
-// finds a table from the array of tables
-static IppToPspsConfig_Table* ippToPspsConfig_findTable(IppToPspsConfig* this, const char* name) {
-
-    IppToPspsConfig_Table* table = NULL;
-
-    for (uint32_t i=0; i<this->numOfTables; i++) {
-
-        if (strcmp(this->tables[i].name, name) == 0) {
-            table = this->tables+i;
-            break;
-        }
-    }
-
-    if (!table) psError(PS_ERR_IO, false, "Could not find table '%s'", name);
-
-    return table;
-}
-
-// gets an attribute value from XML node
-static bool ippToPspsConfig_getAttribute(xmlNode* node, const char* attName, char* _value) {
-
-    xmlChar* value = xmlGetProp(node, (const xmlChar*)attName);
-    if (!value) return false;
-    sprintf(_value, "%s", value);
-    xmlFree(value);
-
-    return true;
-}
-
-// creates a FITS binary table and populates it with defaults based on definition in schema XML
-static bool ippToPspsConfig_createTable(IppToPspsConfig_Table* table, fitsfile* fitsOut, const long nRows) {
-
-    if (!table) return false;
-    if (nRows < 1) return false;
-
-    long nCols = table->numOfColumns;
-
-    char** colNames = (char**)calloc(nCols, sizeof(char*));
-    char** colTypes = (char**)calloc(nCols, sizeof(char*));
-
-    uint32_t i = 0;
-    for (i=0;i<nCols;i++) colTypes[i] = (char*)calloc(5,sizeof(char));
-
-    i = 0;
-    for (uint32_t m=0; m<table->numOfColumns; m++) {
-
-        colNames[i] = table->columns[i].pspsName;
-
-        //        sprintf(colNames[i], table->columns[i].pspsName);
-
-        switch (table->columns[i].pspsType) {
-
-            case TBYTE:
-                sprintf(colTypes[i],"1B");
-                break;
-            case TSHORT:
-                sprintf(colTypes[i],"1I");
-                break;
-            case TLONG:
-                sprintf(colTypes[i],"1J"); // TODO
-                break;
-            case TLONGLONG:
-                sprintf(colTypes[i],"1K");
-                break;
-            case TFLOAT:
-                sprintf(colTypes[i],"1E");
-                break;
-            case TDOUBLE:
-                sprintf(colTypes[i],"1D");
-                break;
-            case TSTRING:
-                sprintf(colTypes[i],"32A"); // TODO width?
-                break;
-
-            default:
-                break;
-        }
-
-        i++;
-    }
-
-    int status = 0;
-    if (fits_create_tbl(fitsOut, BINARY_TBL, nRows, nCols, colNames, colTypes, NULL, table->name, &status)) {
-
-        fits_report_error(stderr, status);
-        psError(PS_ERR_IO,"Unable to create table: %s", table->name);
-    }
-
-    for (i=0;i<nCols;i++) free(colTypes[i]);
-    free(colTypes);
-    free(colNames);
-
-    // now insert defaults
-    int8_t* int8col = (int8_t*)calloc(nRows, sizeof(int8_t));
-    int16_t* int16col = (int16_t*)calloc(nRows, sizeof(int16_t));
-    long* longcol = (long*)calloc(nRows, sizeof(long));
-    float* floatcol = (float*)calloc(nRows, sizeof(float));
-    double* doublecol = (double*)calloc(nRows, sizeof(double));
-    char** strcol = (char**)calloc(nRows, sizeof(char**));
-    for (uint32_t i=0; i<nRows;i++)
-        strcol[i] = (char*)calloc(20,sizeof(char)); // TODO 20? size issue
-
-    uint32_t j;
-    int64_t tempLong;
-    double tempDouble;
-    char tempStr[20];
-
-    int col;
-    for (uint32_t i=0; i<table->numOfColumns; i++) {
-
-        col = i+1;
-
-        strcpy(tempStr,table->columns[i].defaultValue);
-        tempLong = atol(tempStr);
-        tempDouble = atof(tempStr);
-
-        switch (table->columns[i].pspsType) {
-
-            case TBYTE:
-                for(j=0;j<nRows;j++) int8col[j] = (int8_t)tempLong;
-                fits_write_col(fitsOut, TBYTE, col, 1, 1, nRows, int8col, &status);
-                break;
-            case TSHORT:
-                for(j=0;j<nRows;j++) int16col[j] = (int16_t)tempLong;
-                fits_write_col(fitsOut, TSHORT, col, 1, 1, nRows, int16col, &status);
-                break;
-            case TLONG:
-                for(j=0;j<nRows;j++) longcol[j] = (long)tempLong;
-                fits_write_col(fitsOut, TLONG, col, 1, 1, nRows, longcol, &status);
-                break;
-
-            case TLONGLONG:
-                for(j=0;j<nRows;j++) longcol[j] = tempLong;
-                fits_write_col(fitsOut, TLONGLONG, col, 1, 1, nRows, longcol, &status);
-                break;
-
-            case TFLOAT:
-                for(j=0;j<nRows;j++) floatcol[j] = (float)tempDouble;
-                fits_write_col(fitsOut, TFLOAT, col, 1, 1, nRows, floatcol, &status);
-                break;
-
-            case TDOUBLE:
-                for(j=0;j<nRows;j++) doublecol[j] = tempDouble;
-                fits_write_col(fitsOut, TDOUBLE, col, 1, 1, nRows, doublecol, &status);
-                break;
-
-            case TSTRING:
-                for(j=0;j<nRows;j++) strcpy(strcol[j], tempStr);
-                fits_write_col(fitsOut, TSTRING, col, 1, 1, nRows, strcol, &status);
-                break;
-
-            default:
-                break;
-
-        }
-    }
-
-    free(int8col);
-    free(int16col);
-    free(longcol);
-    free(floatcol);
-    free(doublecol);
-    for (uint32_t i=0; i<nRows;i++) free(strcol[i]);
-    free(strcol);
-
-    return true;
-}
-
-// count number of children with the provided name
-static int ippToPspsConfig_countChildren(xmlNode* rootNode, const char* name) {
-
-    int count = 0;
-    xmlNode* node = NULL;
-
-    for (node = rootNode->children; node; node = node->next) {
-
-        if (strcmp((const char*)node->name, name)==0) count++;
-    } 
-
-    return count;
-}
-
-// searches through this table and finds attribute value for a provided key
-static bool ippToPspsConfig_getRowAttribute(IppToPspsConfig* this, xmlNode* tableNode, 
-        const char* keyName, const char* keyValue, 
-        const char* attName, char* attValue) {
-
-    xmlNode* node = NULL;
-
-    char buffer[100];
-
-    // loop round all available rows for this table
-    for (node = tableNode->children; node; node = node->next) {
-        if (node->type == XML_ELEMENT_NODE) {
-            //psLogMsg("ippToPsps", PS_LOG_INFO, "Node name '%s'",  (const char*)node->name );
-
-            if (strcmp((const char*)node->name, "row")==0) {
-            //psLogMsg("ippToPsps", PS_LOG_INFO, " Looking for key '%s'",  keyName );
-
-                if (!ippToPspsConfig_getAttribute(node, keyName, buffer)) continue;
-            //psLogMsg("ippToPsps", PS_LOG_INFO, "Found key '%s' value '%s'",  keyName, buffer );
-
-                if (strcmp(buffer, keyValue) != 0) continue;
-                ippToPspsConfig_getAttribute(node, attName, attValue);
-                //printf("FOUND %s %s %s %s \n", keyName, buffer, attName, attValue );
-                return true;
-
-            }
-        }
-    }
-
-    psLogMsg("ippToPsps", PS_LOG_INFO, "Could not find value for '%s' for '%s' with value '%s'", attName, keyName, keyValue );
-    return false;
-}
-
-// opens an XML file and returns the document
-static xmlDoc* ippToPspsConfig_openXmlFile(const char* path) {
-
-    xmlDoc* doc = xmlReadFile(path, NULL, 0);
-    if (doc == NULL) psError(PS_ERR_IO, false, "Unable to open XML file at %s", path);
-    return doc;
-}
-
-// closes an XML file 
-static bool ippToPspsConfig_closeXmlFile(xmlDoc* doc) {
-
-    xmlFreeDoc(doc);
-    xmlCleanupParser();
-
-    return true;
-}
-
-// gets filter ID for this filter name from 'init' data 
-static bool ippToPspsConfig_getInitValue(
-        IppToPspsConfig* this, 
-        const char* tableName,
-        const char* keyName, const char* keyValue,
-        const char* attName, char* attValue) {
-
-    bool ret = true;
-
-    psString path = NULL;
-    psStringAppend(&path, "%s/../init/data.xml", this->configsPath); // TODO nasty
-
-    xmlDoc* doc = ippToPspsConfig_openXmlFile(path);
-
-    if (doc == NULL) {
-        psFree(path);
-        return false;
-    }
-    psFree(path);
-
-    xmlNode* rootElement = xmlDocGetRootElement(doc);
-
-    if (strcmp((const char*)rootElement->name, "tabledata")!=0) {
-        psError(PS_ERR_IO, false, "Root node of XML is not 'tabledata', as it should be");
-        return false;
-    }
-
-    xmlNode* node = NULL;
-    char tempStr[100];
-
-    // loop round all available tables
-    for (node = rootElement->children; node; node = node->next) {
-        if (node->type == XML_ELEMENT_NODE) {
-
-            if (strcmp((const char*)node->name, "table")!=0) continue;
-            if (!ippToPspsConfig_getAttribute(node, "name", tempStr)) continue;
-            if (strcmp(tempStr, tableName)!=0) continue;
-
-            ret = ippToPspsConfig_getRowAttribute(this, node, keyName, keyValue, attName, attValue);
-            break;
-        }
-
-    }
-
-    ippToPspsConfig_closeXmlFile(doc);
-
-    return ret;
-}
-
-// gets survey ID from survey name
-bool ippToPspsConfig_getSurveyId(IppToPspsConfig* this, const char* surveyType, int8_t* surveyId) {
-
-    char buffer[10];
-    if (!ippToPspsConfig_getInitValue(this, "Survey", "name", surveyType, "surveyID", buffer)) {
-
-        *surveyId = -1;
-        return false;
-    }
-
-    *surveyId = atoi(buffer);
-    return true;
-}
-
-// gets filter ID from filter type
-bool ippToPspsConfig_getFilterId(IppToPspsConfig* this, const char* filterType, int8_t* filterId) {
-
-    char tmp[2];
-    strncpy(tmp,filterType,1);
-    tmp[1] = '\0';
-    char buffer[10];
-    if (!ippToPspsConfig_getInitValue(this, "Filter", "filterType", tmp, "filterID", buffer)) {
-
-        *filterId = -1;
-        return false;
-    }
-
-    *filterId = atoi(buffer);
-    return true;
-}
-
-// populate the provided table with data from XML
-static bool ippToPspsConfig_populateTable(IppToPspsConfig_Table* table, xmlNode* rootElement, fitsfile *fitsOut) {
-
-    char tempStr[100];
-    xmlNode* node = NULL;
-    xmlNode* tableNode = NULL;
-
-    // first check we have data for this table in XML file
-    for (node = rootElement->children; node; node = node->next) {
-        if (node->type == XML_ELEMENT_NODE) {
-
-            if (strcmp((const char*)node->name, "table")!=0) continue;
-            if (!ippToPspsConfig_getAttribute(node, "name", tempStr)) continue;
-            if (strcmp(tempStr, table->name)==0) {tableNode = node; break;}
-        }
-    }
-
-    if(!tableNode) {
-
-        psError(PS_ERR_IO,"Could not find table: %s", table->name);
-        return false;
-    }
-
-    // now count the number of rows
-    int nRows = ippToPspsConfig_countChildren(tableNode, "row");
-    if (nRows < 1) return false;
-    if (!ippToPspsConfig_createTable(table, fitsOut, nRows)) return false;
-
-    int rows=0;
-    int status;
-    char** strcol = (char**)calloc(1, sizeof(char**));
-    strcol[0] = (char*)calloc(32,sizeof(char)); // TODO 20? size issue
-
-    int8_t* bytecol = calloc(1, sizeof(uint8_t));
-    int16_t* shortcol = calloc(1, sizeof(uint16_t));
-    long* longcol = calloc(1, sizeof(long));
-    double* doublecol = calloc(1, sizeof(double));
-    float* floatcol = calloc(1, sizeof(float));
-
-    int col;
-
-    // now get rows
-    for (node = tableNode->children; node; node = node->next) {
-
-        if (strcmp((const char*)node->name, "row")!=0) continue;
-
-        rows++;
-
-        // get column data for this row
-        for (int i=0;i<table->numOfColumns;i++) {
-
-            col = i+1;
-
-            if (!ippToPspsConfig_getAttribute(node, table->columns[i].pspsName, tempStr)) continue;
-
-            strncpy(strcol[0], tempStr, 32);
-            status=0;
-            //psLogMsg("ippToPsps", PS_LOG_INFO, "Values %s - %ld - %f - %d", strcol[0], longcol[0], doublecol[0], bytecol[0]);
-            switch (table->columns[i].pspsType) {
-
-                case TBYTE:
-                    bytecol[0] = atoi(tempStr);
-                    fits_write_col(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, bytecol, &status); 
-                    break;
-                case TSHORT:
-                    shortcol[0] = atoi(tempStr);
-                    fits_write_col(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, shortcol, &status); 
-                    break;
-                case TLONG:
-                case TLONGLONG:
-                    longcol[0] = atol(tempStr);
-                    fits_write_col(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, longcol, &status); 
-                    break;
-                case TFLOAT:
-                    floatcol[0] = atof(tempStr);
-                    fits_write_col(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, floatcol, &status);
-                    break;
-                case TDOUBLE:
-                    doublecol[0] = atof(tempStr);
-                    fits_write_col(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, doublecol, &status);
-                    break;
-                case TSTRING:
-                    fits_write_col(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, strcol, &status); 
-                    break;
-
-            }
-            if (status) psError(PS_ERR_IO, false, "Unable to write value of %s to column %s in table %s", 
-                    tempStr, table->columns[i].pspsName, table->name);
-        }
-    }
-
-    free(bytecol);
-    free(shortcol);
-    free(longcol);
-    free(floatcol);
-    free(doublecol);
-    free(strcol[0]);
-    free(strcol);
-
-    return true;
-}
-
-// loads a table description from XML
-static bool ippToPspsConfig_loadTableDescription(IppToPspsConfig_Table* table, xmlNode* tableNode) {
-
-    bool ret = true;
-    char tableName[100];
-    ippToPspsConfig_getAttribute(tableNode, "name", tableName);
-    strcpy(table->name, tableName);
-
-    // count how many columns we have coming in and allocate memory for them
-    table->numOfColumns = ippToPspsConfig_countChildren(tableNode, "column");
-    table->columns = calloc(table->numOfColumns, sizeof(IppToPspsConfig_Column));
-    //    psLogMsg("ippToPsps", PS_LOG_INFO, " Found '%d' columns", table->numOfColumns);
-
-    char buffer[200];
-    xmlNode* node;
-    int columnNum = 0;
-
-    for (node = tableNode->children; node; node = node->next) {
-
-        if (strcmp((const char*)node->name, "column") != 0) continue;
-
-        table->columns[columnNum].usingDefault = true;
-
-        // column name
-        ippToPspsConfig_getAttribute(node, "name", buffer);
-        sprintf(table->columns[columnNum].pspsName, buffer);
-
-        // column type
-        ippToPspsConfig_getAttribute(node, "type", buffer);
-        table->columns[columnNum].pspsType = ippToPsps_GetDataType(buffer);
-
-        // default value
-        ippToPspsConfig_getAttribute(node, "default", buffer);
-        sprintf(table->columns[columnNum].defaultValue, buffer);
-
-        // comment
-        ippToPspsConfig_getAttribute(node, "comment", buffer);
-        sprintf(table->columns[columnNum].comment, buffer);
-
-        # if 0
-        psLogMsg("ippToPsps", PS_LOG_INFO, "'%s'  name='%s' type='%d'  default='%s' comment='%s'", 
-                table->name,
-                table->columns[columnNum].pspsName, 
-                table->columns[columnNum].pspsType, 
-                table->columns[columnNum].defaultValue, 
-                table->columns[columnNum].comment);
-# endif
-        columnNum++;
-    }   
-
-
-    if (columnNum < 1) {
-
-        psError(PS_ERR_IO, false, "Found no columns for table '%s'", tableName);
-        ret = false;
-    }
-
-    if (columnNum != table->numOfColumns)
-        psError(PS_ERR_IO, false, "Mismatch between number of columns expected (%d) and those found (%d)", table->numOfColumns, columnNum);
-
-    return ret;
-}
-
-// read table shapes from XML file
-bool ippToPspsConfig_loadTableDescriptions(IppToPspsConfig* this) {
-
-    bool ret = true;
-
-    psString path = NULL;
-    psStringAppend(&path, "%s/tables.xml", this->configsPath);
-
-    xmlDoc* doc = ippToPspsConfig_openXmlFile(path);
-
-    if (doc == NULL) {
-
-        psFree(path);
-        return false;
-    }
-    psFree(path);
-
-    xmlNode* rootElement = xmlDocGetRootElement(doc);
-
-    if (strcmp((const char*)rootElement->name, "tableDescriptions")!=0) {
-
-        psError(PS_ERR_IO, false, "Root node of XML is not 'tableDescriptions', as it should be");
-        return false;
-    }
-
-    // count how many tables we have coming in and allocate memory for them
-    this->numOfTables = ippToPspsConfig_countChildren(rootElement, "table");
-    this->tables = calloc(this->numOfTables, sizeof(IppToPspsConfig_Table));
-    //    psLogMsg("ippToPsps", PS_LOG_INFO, " Found '%d' tables", this->numOfTables);
-
-    xmlNode* node = NULL;
-    IppToPspsConfig_Table* table = NULL;
-
-    int tableNum = 0;
-    // loop round all available table descriptions
-    for (node = rootElement->children; node; node = node->next) {
-        if (node->type == XML_ELEMENT_NODE) {
-
-            if (strcmp((const char*)node->name, "table")==0) {
-
-                table = this->tables+tableNum;
-
-                if (!ippToPspsConfig_loadTableDescription(table, node)) ret = false;
-                else tableNum++;
-            }
-        }
-    }
-
-    if (tableNum != this->numOfTables)
-        psError(PS_ERR_IO, false, "Mismatch between number of tables expected (%d) and those found (%d)", this->numOfTables, tableNum);
-
-    ippToPspsConfig_closeXmlFile(doc);
-
-    return ret;
-}
-
-// loads mappings from XML for a particular table
-static bool ippToPspsConfig_loadTableMappings(IppToPspsConfig* this, xmlNode* tableNode) {
-
-    bool ret = false;
-
-    xmlNode* node = NULL;
-
-    char tableName[100];
-    ippToPspsConfig_getAttribute(tableNode, "name", tableName);
-
-    IppToPspsConfig_Table* table = ippToPspsConfig_findTable(this, tableName);
-    IppToPspsConfig_Column* column = NULL;
-    if (!table) return false;
-
-    char buffer[100];
-    //psLogMsg("ippToPsps", PS_LOG_INFO, "Table '%s'", tableName);
-
-    // loop round all available mappings for this table
-    for (node = tableNode->children; node; node = node->next) {
-        if (node->type == XML_ELEMENT_NODE) {
-
-            if (strcmp((const char*)node->name, "map")==0) {
-
-                // column type
-                ippToPspsConfig_getAttribute(node, "pspsName", buffer);
-                column = ippToPspsConfig_findColumn(table, buffer);
-
-                if (!column) continue;
-
-                // IPP name
-                ippToPspsConfig_getAttribute(node, "ippName", buffer);
-                strcpy(column->ippName, buffer);
-
-                // IPP type
-                ippToPspsConfig_getAttribute(node, "ippType", buffer);
-                column->ippType = ippToPsps_GetDataType(buffer); 
-
-                column->usingDefault = false;
-
-                //psLogMsg("ippToPsps", PS_LOG_INFO, "...mapping PSPS:'%s' to '%s' '%d'", column->pspsName, column->ippName, column->ippColNum );
-            }
-        }
-    }
-
-    return ret;
-}
-
-// reads table mappings from XML file
-static bool ippToPspsConfig_loadMappings(IppToPspsConfig* this) {
-
-    bool ret = true;
-
-    psString path = NULL;
-    psStringAppend(&path, "%s/map.xml", this->configsPath);
-
-    xmlDoc* doc = ippToPspsConfig_openXmlFile(path);
-
-    if (doc == NULL) {
-        psFree(path);
-        return false;
-    }
-    psFree(path);
-
-    xmlNode* rootElement = xmlDocGetRootElement(doc);
-
-    if (strcmp((const char*)rootElement->name, "tabledata")!=0) {
-        psError(PS_ERR_IO, false, "Root node of XML is not 'tabledata', as it should be");
-        return false;
-    }
-
-    xmlNode* node = NULL;
-
-    // loop round all available tables
-    for (node = rootElement->children; node; node = node->next) {
-        if (node->type == XML_ELEMENT_NODE) {
-
-            if (strcmp((const char*)node->name, "table")==0) {
-
-                if (!ippToPspsConfig_loadTableMappings(this, node)) ret = false;
-            }
-        }
-    }
-
-    ippToPspsConfig_closeXmlFile(doc);
-
-    return ret;
-}
-
-// populate the provided table with data from XML
-bool ippToPspsConfig_populateFromFile(IppToPspsConfig* this, fitsfile *fitsOut) {
-
-    bool ret = true;
-
-    psString path = NULL;
-    psStringAppend(&path, "%s/data.xml", this->configsPath);
-
-    xmlDoc* doc = ippToPspsConfig_openXmlFile(path);
-
-    if (doc == NULL) {
-        psFree(path);
-        return false;
-    }
-    psFree(path);
-
-    xmlNode* rootElement = xmlDocGetRootElement(doc);
-
-    if (strcmp((const char*)rootElement->name, "tabledata")!=0) {
-        psError(PS_ERR_IO, false, "Root node of XML is not 'tabledata', as it should be");
-        return false;
-    }
-
-    for (uint32_t i=0; i<this->numOfTables; i++) {
-        if (!ippToPspsConfig_populateTable(this->tables+i, rootElement, fitsOut)) {
-            ret = false;
-        }
-    }
-
-    ippToPspsConfig_closeXmlFile(doc);
-
-    return ret;
-}
-
-// gets metadata about a column 
-bool ippToPspsConfig_getFitsColumnMeta(
-        char* name,
-        int* colNum,
-        int* type,
-        long* repeat,
-        fitsfile *fitsIn ) {
-
-    int status = 0;
-    fits_get_colnum(fitsIn, CASESEN, name, colNum, &status);
-    if (status) {
-        psError(PS_ERR_IO, false, "Unable to read col '%s'", name);
-        return false;
-    }
-
-    status = 0;
-    fits_get_eqcoltype(fitsIn, *colNum, type, repeat, NULL, &status);
-    if (status) {
-        psError(PS_ERR_IO, false, "Unable to read type info for '%s'", name);
-        return false;
-    }
-
-    return true;
-}
-
-// populate with data from another FITS table into this one
-static bool ippToPspsConfig_populateTableFromFits(
-        IppToPspsConfig_Table* table,
-        fitsfile *fitsIn, 
-        fitsfile *fitsOut,
-        const long nRows, 
-        const bool fromHeader) {
-
-    if (!table) return false;
-    if (!fitsIn) return false;
-
-    int8_t* int8col = (int8_t*)calloc(nRows, sizeof(int8_t));
-    int16_t* int16col = (int16_t*)calloc(nRows, sizeof(int16_t));
-    long* longcol = (long*)calloc(nRows, sizeof(long));
-    float* floatcol = (float*)calloc(nRows, sizeof(float));
-    double* doublecol = (double*)calloc(nRows, sizeof(double));
-    char** strcol = (char**)calloc(nRows, sizeof(char**));
-    for (uint32_t i=0; i<nRows;i++)
-        strcol[i] = (char*)calloc(50,sizeof(char)); // TODO 20? size issue
-
-    int8_t int8null = -99;
-    int16_t int16null = -999;
-    long longnull = -999;
-    float floatnull = -999.0;
-    double doublenull = -999.0;
-
-    int anynull = 0;
-    int readStatus = 0;
-    int writeStatus = 0;
-
-    // first loop round all columns and get IPP col numbers for provided column names TODO only do once, first time in
-    if(!fromHeader) {
-
-        for (uint32_t i=0; i<table->numOfColumns; i++) {
-
-            if (strlen(table->columns[i].ippName) < 1) continue;
-
-            if (!ippToPspsConfig_getFitsColumnMeta(
-                    table->columns[i].ippName,
-                    &table->columns[i].ippColNum,
-                    &table->columns[i].ippType,
-                    &table->columns[i].ippRepeat,
-                    fitsIn)) {return false;}
-        }
-    }
-
-    int col;
-    for (uint32_t i=0; i<table->numOfColumns; i++) {
-
-        readStatus = 0;
-        writeStatus = 0;
-
-        if (!table->columns[i].usingDefault) {
-
-            col = i+1;
-
-            switch (table->columns[i].ippType) {
-
-                case TBYTE:
-                    if (fromHeader) {
-                        fits_read_key(fitsIn, TBYTE, table->columns[i].ippName, &int8col[0], NULL, &readStatus);
-                        if (!isfinite(int8col[0])) int8col[0] = int8null;
-                    }
-                    else fits_read_col(fitsIn, TBYTE, table->columns[i].ippColNum, 1, 1, nRows, &int8null, int8col, &anynull, &readStatus);
-                    fits_write_col(fitsOut, TBYTE, col, 1, 1, nRows, int8col, &writeStatus);
-                    break;
-                case TSHORT:
-                    if (fromHeader) {
-                        fits_read_key(fitsIn, TSHORT, table->columns[i].ippName, &int16col[0], NULL, &readStatus);
-                        if (!isfinite(int16col[0])) int16col[0] = int16null;
-                    }
-                    else fits_read_col(fitsIn, TSHORT, table->columns[i].ippColNum, 1, 1, nRows, &int16null, int16col, &anynull, &readStatus);
-                    fits_write_col(fitsOut, TSHORT, col, 1, 1, nRows, int16col, &writeStatus);
-                    break;
-                case TLONG:
-                    if (fromHeader) {
-                        fits_read_key(fitsIn, TLONG, table->columns[i].ippName, &longcol[0], NULL, &readStatus);
-                        if (!isfinite(longcol[0])) longcol[0] = longnull;
-                    }
-                    else fits_read_col(fitsIn, TLONG, table->columns[i].ippColNum, 1, 1, nRows, &longnull, longcol, &anynull, &readStatus);
-                    fits_write_col(fitsOut, TLONG, col, 1, 1, nRows, longcol, &writeStatus);
-                    break;
-                case TLONGLONG:
-                    if (fromHeader) {
-                        fits_read_key(fitsIn, TLONGLONG, table->columns[i].ippName, &longcol[0], NULL, &readStatus);
-                        if (!isfinite(longcol[0])) longcol[0] = longnull;
-                    }
-                    else fits_read_col(fitsIn, TLONGLONG, table->columns[i].ippColNum, 1, 1, nRows, &longnull, longcol, &anynull, &readStatus);
-                    fits_write_col(fitsOut, TLONGLONG, col, 1, 1, nRows, longcol, &writeStatus);
-                    break;
-                case TFLOAT:
-                    if (fromHeader) {
-                        fits_read_key(fitsIn, TFLOAT, table->columns[i].ippName,&floatcol[0], NULL, &readStatus); 
-                        if (!isfinite(floatcol[0])) floatcol[0] = floatnull;
-                    }
-                    else fits_read_col(fitsIn, TFLOAT, table->columns[i].ippColNum, 1, 1, nRows, &floatnull, floatcol, &anynull, &readStatus);
-                    fits_write_col(fitsOut, TFLOAT, col, 1, 1, nRows, floatcol, &writeStatus);
-                    break;
-                case TDOUBLE:
-                    if (fromHeader) {
-                        fits_read_key(fitsIn, TDOUBLE, table->columns[i].ippName, &doublecol[0], NULL, &readStatus);
-                        if (!isfinite(doublecol[0])) doublecol[0] = doublenull;
-                    }
-                    else fits_read_col(fitsIn, TDOUBLE, table->columns[i].ippColNum, 1, 1, nRows, &doublenull, doublecol, &anynull, &readStatus);
-                    fits_write_col(fitsOut, TDOUBLE, col, 1, 1, nRows, doublecol, &writeStatus);
-                    break;
-                case TSTRING:
-                    if (fromHeader) fits_read_key(fitsIn, TSTRING, table->columns[i].ippName, strcol[0], NULL, &readStatus);
-                    else fits_read_col(fitsIn, TSTRING, table->columns[i].ippColNum, 1, 1, nRows, " ", strcol, &anynull, &readStatus);
-                    fits_write_col(fitsOut, TSTRING, col, 1, 1, nRows, strcol, &writeStatus);
-                    break;
-
-                default:
-                    psError(PS_ERR_IO, false, "Don't know IPP type (%d) for mapping from  '%d'  '%s' to '%s'", table->columns[i].ippType,
-                            table->columns[i].ippColNum, table->columns[i].ippName, table->columns[i].pspsName);
-                    break;
-            }
-
-            // TODO need these errors, but strange error handling runs out of memory
-            //if (readStatus) {
-            //    psError(PS_ERR_IO, false, "Unable to read col num '%d' col name '%s', type %d", 
-            //        table->columns[i].ippColNum, table->columns[i].ippName, table->columns[i].ippType);
-            //    fits_report_error(stderr, readStatus);
-            //}
-            //if (writeStatus) {
-            //    psError(PS_ERR_IO, false, "Unable to write col '%s'", table->columns[i].pspsName );
-            //    fits_report_error(stderr, writeStatus);
-            //}
-        }
-    }
-
-    free(int8col);
-    free(int16col);
-    free(longcol);
-    free(floatcol);
-    free(doublecol);
-    for (uint32_t i=0; i<nRows;i++) free(strcol[i]);
-    free(strcol);
-
-    return true;
-}
-
-// creates and populates a table
-bool ippToPspsConfig_writeTable(
-        IppToPspsConfig* this, 
-        fitsfile* fitsIn,
-        fitsfile* fitsOut,
-        const long nRows,
-        const char* tableName,
-        const bool fromHeader) {
-
-
-    IppToPspsConfig_Table* table = ippToPspsConfig_findTable(this, tableName);
-    if (!table) return false;
-
-    if(!ippToPspsConfig_createTable(table, fitsOut, nRows)) return false;
-    return ippToPspsConfig_populateTableFromFits(table, fitsIn, fitsOut, nRows, fromHeader);
-}
-
-// Destructor.
-void ippToPspsConfig_Destructor(IppToPspsConfig* this) {
-
-    if (this != NULL ) {
-
-        // TODO check logic here
-        for (int i=0;i<this->numOfTables;i++)
-            free(this->tables[i].columns);
-
-        free(this->tables);
-        psFree(this->configsPath);
-        free(this);
-    }
-}
-
-// Constructor. Loads IPP -> PSPS mappings from a csv
-IppToPspsConfig* ippToPspsConfig_Constructor(const char* path) {
-
-    IppToPspsConfig* this = NULL;
-
-    this = malloc(sizeof(IppToPspsConfig));
-
-    this->configsPath = NULL;
-    psStringAppend(&this->configsPath, path);
-
-    // load tables descriptions from XML
-    if (ippToPspsConfig_loadTableDescriptions(this)) {
-
-        // load any mappings we may have from XML        
-        ippToPspsConfig_loadMappings(this);
-    }
-
-    return this;
-}
-
Index: trunk/ippToPsps/src/ippToPspsConfig.h
===================================================================
--- trunk/ippToPsps/src/ippToPspsConfig.h	(revision 30146)
+++ 	(revision )
@@ -1,65 +1,0 @@
-/** @file ippToPspsConfig.h
- *
- *  @brief ippToPsps
- *
- *  @ingroup ippToPsps
- *
- *  @author IfA
- *  Copyright 2009 Institute for Astronomy, University of Hawaii
- */
-
-#ifndef IPPTOPSPSCONFIG_H
-#define IPPTOPSPSCONFIG_H
-
-#include <psmodules.h>
-
-// column class
-typedef struct {
-
-    int ippColNum;
-    char ippName[100];
-    int ippType;
-    long ippRepeat;
-    char pspsName[100]; // TODO change to 'name'
-    int pspsType;
-    bool usingDefault;
-    char defaultValue[100];
-    char comment[300];
-
-} IppToPspsConfig_Column;
-
-// table class
-typedef struct {
-
-    char name[32];
-    IppToPspsConfig_Column* columns;
-    int numOfColumns;
-
-} IppToPspsConfig_Table;
-
-//  
-typedef struct {
-
-    psString configsPath;
-    IppToPspsConfig_Table* tables;
-    int numOfTables;
-
-} IppToPspsConfig; 
-
-IppToPspsConfig* ippToPspsConfig_Constructor(const char* filePath);
-bool ippToPspsConfig_populateFromFile(IppToPspsConfig* this, fitsfile *fitsOut); // TODO remove
-void ippToPspsConfig_Destructor();
-bool ippToPspsConfig_writeTable(
-        IppToPspsConfig* this,
-        fitsfile* fitsIn,
-        fitsfile* fitsOut,
-        const long nRows,
-        const char* tableName, 
-        const bool fromHeader);
-
-// getters
-bool ippToPspsConfig_getFilterId(IppToPspsConfig* this, const char* filterType, int8_t* filterId);
-bool ippToPspsConfig_getSurveyId(IppToPspsConfig* this, const char* surveyType, int8_t* surveyId);
-
-#endif // IPPTOPSPSCONFIG_H
-
Index: trunk/ippToPsps/src/ippToPspsDetEnums.h
===================================================================
--- trunk/ippToPsps/src/ippToPspsDetEnums.h	(revision 30146)
+++ 	(revision )
@@ -1,181 +1,0 @@
-#ifndef IPPTOPSPSDETENUMS_H
-#define IPPTOPSPSDETENUMS_H
-
-
-typedef enum {
-  FRAMEMETA_FRAMEID = 1,
-  FRAMEMETA_FRAMENAME = 2,
-  FRAMEMETA_SURVEYID = 3,
-  FRAMEMETA_FILTERID = 4,
-  FRAMEMETA_CAMERAID = 5,
-  FRAMEMETA_CAMERACONFIGID = 6,
-  FRAMEMETA_TELESCOPEID = 7,
-  FRAMEMETA_ANALYSISVER = 8,
-  FRAMEMETA_P1RECIP = 9,
-  FRAMEMETA_P2RECIP = 10,
-  FRAMEMETA_P3RECIP = 11,
-  FRAMEMETA_NOTA = 12,
-  FRAMEMETA_PHOTOSCAT = 13,
-  FRAMEMETA_NUMPHOTOREF = 14,
-  FRAMEMETA_EXPSTART = 15,
-  FRAMEMETA_EXPTIME = 16,
-  FRAMEMETA_AIRMASS = 17,
-  FRAMEMETA_RABORE = 18,
-  FRAMEMETA_DECBORE = 19,
-  FRAMEMETA_CTYPE1 = 20,
-  FRAMEMETA_CTYPE2 = 21,
-  FRAMEMETA_CRVAL1 = 22,
-  FRAMEMETA_CRVAL2 = 23,
-  FRAMEMETA_CRPIX1 = 24,
-  FRAMEMETA_CRPIX2 = 25,
-  FRAMEMETA_CDELT1 = 26,
-  FRAMEMETA_CDELT2 = 27,
-  FRAMEMETA_PC001001 = 28,
-  FRAMEMETA_PC001002 = 29,
-  FRAMEMETA_PC002001 = 30,
-  FRAMEMETA_PC002002 = 31,
-  FRAMEMETA_POLYORDER = 32,
-  FRAMEMETA_PCA1X3Y0 = 33,
-  FRAMEMETA_PCA1X2Y1 = 34,
-  FRAMEMETA_PCA1X1Y2 = 35,
-  FRAMEMETA_PCA1X0Y3 = 36,
-  FRAMEMETA_PCA1X2Y0 = 37,
-  FRAMEMETA_PCA1X1Y1 = 38,
-  FRAMEMETA_PCA1X0Y2 = 39,
-  FRAMEMETA_PCA2X3Y0 = 40,
-  FRAMEMETA_PCA2X2Y1 = 41,
-  FRAMEMETA_PCA2X1Y2 = 42,
-  FRAMEMETA_PCA2X0Y3 = 43,
-  FRAMEMETA_PCA2X2Y0 = 44,
-  FRAMEMETA_PCA2X1Y1 = 45,
-  FRAMEMETA_PCA2X0Y2 = 46,
-  FRAMEMETA_CALIBMODNUM = 47,
-  FRAMEMETA_DATARELEASE = 48,
-} FrameMeta;
-
-typedef enum {
-  IMAGEMETA_IMAGEID = 1,
-  IMAGEMETA_FRAMEID = 2,
-  IMAGEMETA_CCDID = 3,
-  IMAGEMETA_PHOTOCALID = 4,
-  IMAGEMETA_FILTERID = 5,
-  IMAGEMETA_BIAS = 6,
-  IMAGEMETA_BIASSCAT = 7,
-  IMAGEMETA_SKY = 8,
-  IMAGEMETA_SKYSCAT = 9,
-  IMAGEMETA_NDETECT = 10,
-  IMAGEMETA_MAGSAT = 11,
-  IMAGEMETA_COMPLETMAG = 12,
-  IMAGEMETA_ASTROSCAT = 13,
-  IMAGEMETA_PHOTOSCAT = 14,
-  IMAGEMETA_NUMASTROREF = 15,
-  IMAGEMETA_NUMPHOTOREF = 16,
-  IMAGEMETA_NX = 17,
-  IMAGEMETA_NY = 18,
-  IMAGEMETA_PSFMODELID = 19,
-  IMAGEMETA_PSFFWHM = 20,
-  IMAGEMETA_PSFWIDMAJOR = 21,
-  IMAGEMETA_PSFWIDMINOR = 22,
-  IMAGEMETA_PSFTHETA = 23,
-  IMAGEMETA_MOMENTFWHM = 24,
-  IMAGEMETA_MOMENTWIDMAJOR = 25,
-  IMAGEMETA_MOMENTWIDMINOR = 26,
-  IMAGEMETA_APRESID = 27,
-  IMAGEMETA_DAPRESID = 28,
-  IMAGEMETA_DETECTORID = 29,
-  IMAGEMETA_QAFLAGS = 30,
-  IMAGEMETA_DETREND1 = 31,
-  IMAGEMETA_DETREND2 = 32,
-  IMAGEMETA_DETREND3 = 33,
-  IMAGEMETA_DETREND4 = 34,
-  IMAGEMETA_DETREND5 = 35,
-  IMAGEMETA_DETREND6 = 36,
-  IMAGEMETA_DETREND7 = 37,
-  IMAGEMETA_DETREND8 = 38,
-  IMAGEMETA_PHOTOZERO = 39,
-  IMAGEMETA_CTYPE1 = 40,
-  IMAGEMETA_CTYPE2 = 41,
-  IMAGEMETA_CRVAL1 = 42,
-  IMAGEMETA_CRVAL2 = 43,
-  IMAGEMETA_CRPIX1 = 44,
-  IMAGEMETA_CRPIX2 = 45,
-  IMAGEMETA_CDELT1 = 46,
-  IMAGEMETA_CDELT2 = 47,
-  IMAGEMETA_PC001001 = 48,
-  IMAGEMETA_PC001002 = 49,
-  IMAGEMETA_PC002001 = 50,
-  IMAGEMETA_PC002002 = 51,
-  IMAGEMETA_POLYORDER = 52,
-  IMAGEMETA_PCA1X3Y0 = 53,
-  IMAGEMETA_PCA1X2Y1 = 54,
-  IMAGEMETA_PCA1X1Y2 = 55,
-  IMAGEMETA_PCA1X0Y3 = 56,
-  IMAGEMETA_PCA1X2Y0 = 57,
-  IMAGEMETA_PCA1X1Y1 = 58,
-  IMAGEMETA_PCA1X0Y2 = 59,
-  IMAGEMETA_PCA2X3Y0 = 60,
-  IMAGEMETA_PCA2X2Y1 = 61,
-  IMAGEMETA_PCA2X1Y2 = 62,
-  IMAGEMETA_PCA2X0Y3 = 63,
-  IMAGEMETA_PCA2X2Y0 = 64,
-  IMAGEMETA_PCA2X1Y1 = 65,
-  IMAGEMETA_PCA2X0Y2 = 66,
-  IMAGEMETA_CALIBMODNUM = 67,
-  IMAGEMETA_DATARELEASE = 68,
-} ImageMeta;
-
-typedef enum {
-  DETECTION_OBJID = 1,
-  DETECTION_DETECTID = 2,
-  DETECTION_IPPOBJID = 3,
-  DETECTION_IPPDETECTID = 4,
-  DETECTION_FILTERID = 5,
-  DETECTION_SURVEYID = 6,
-  DETECTION_IMAGEID = 7,
-  DETECTION_OBSTIME = 8,
-  DETECTION_XPOS = 9,
-  DETECTION_YPOS = 10,
-  DETECTION_XPOSERR = 11,
-  DETECTION_YPOSERR = 12,
-  DETECTION_INSTFLUX = 13,
-  DETECTION_INSTFLUXERR = 14,
-  DETECTION_PEAKADU = 15,
-  DETECTION_PSFWIDMAJOR = 16,
-  DETECTION_PSFWIDMINOR = 17,
-  DETECTION_PSFTHETA = 18,
-  DETECTION_PSFLIKELIHOOD = 19,
-  DETECTION_PSFCF = 20,
-  DETECTION_MOMENTXX = 21,
-  DETECTION_MOMENTXY = 22,
-  DETECTION_MOMENTYY = 23,
-  DETECTION_CRLIKELIHOOD = 24,
-  DETECTION_EXTENDEDLIKELIHOOD = 25,
-  DETECTION_INFOFLAG = 26,
-  DETECTION_SKY = 27,
-  DETECTION_SKYERR = 28,
-  DETECTION_SGSEP = 29,
-  DETECTION_ACTIVEFLAG = 30,
-  DETECTION_ASSOCDATE = 31,
-  DETECTION_HISTORYMODNUM = 32,
-  DETECTION_DATARELEASE = 33,
-} Detection;
-
-typedef enum {
-  SKINNYOBJECT_OBJID = 1,
-  SKINNYOBJECT_IPPOBJID = 2,
-  SKINNYOBJECT_PROJECTIONCELLID = 3,
-  SKINNYOBJECT_DATARELEASE = 4,
-  SKINNYOBJECT_SURVEYID = 5,
-} SkinnyObject;
-
-typedef enum {
-  OBJECTCALCOLOR_OBJID = 1,
-  OBJECTCALCOLOR_IPPOBJID = 2,
-  OBJECTCALCOLOR_FILTERID = 3,
-  OBJECTCALCOLOR_CALCOLOR = 4,
-  OBJECTCALCOLOR_CALCOLORERR = 5,
-  OBJECTCALCOLOR_CALIBMODNUM = 6,
-  OBJECTCALCOLOR_DATARELEASE = 7,
-} ObjectCalColor;
-
-#endif
Index: trunk/ippToPsps/src/ippToPspsDiffEnums.h
===================================================================
--- trunk/ippToPsps/src/ippToPspsDiffEnums.h	(revision 30146)
+++ 	(revision )
@@ -1,118 +1,0 @@
-#ifndef IPPTOPSPSDIFFENUMS_H
-#define IPPTOPSPSDIFFENUMS_H
-
-
-typedef enum {
-  STACKMETA_STACKMETAID = 1,
-  STACKMETA_SKYCELLID = 2,
-  STACKMETA_SURVEYID = 3,
-  STACKMETA_PHOTOCALID = 4,
-  STACKMETA_FILTERID = 5,
-  STACKMETA_STACKTYPEID = 6,
-  STACKMETA_REFIMAGEID = 7,
-  STACKMETA_SUBTRIMAGEID = 8,
-  STACKMETA_MAGSAT = 9,
-  STACKMETA_ANALVER = 10,
-  STACKMETA_NP2IMAGES = 11,
-  STACKMETA_COMPLETMAG = 12,
-  STACKMETA_ASTROSCAT = 13,
-  STACKMETA_PHOTOSCAT = 14,
-  STACKMETA_NASTROREF = 15,
-  STACKMETA_NPHOREF = 16,
-  STACKMETA_PSFFWHM = 17,
-  STACKMETA_PSFMODELID = 18,
-  STACKMETA_PSFWIDMAJOR = 19,
-  STACKMETA_PSFWIDMINOR = 20,
-  STACKMETA_PSFTHETA = 21,
-  STACKMETA_PSFEXTRA1 = 22,
-  STACKMETA_PSFEXTRA2 = 23,
-  STACKMETA_PHOTOZERO = 24,
-  STACKMETA_PHOTOCOLOR = 25,
-  STACKMETA_CTYPE1 = 26,
-  STACKMETA_CTYPE2 = 27,
-  STACKMETA_CRVAL1 = 28,
-  STACKMETA_CRVAL2 = 29,
-  STACKMETA_CRPIX1 = 30,
-  STACKMETA_CRPIX2 = 31,
-  STACKMETA_PC001001 = 32,
-  STACKMETA_PC001002 = 33,
-  STACKMETA_PC002001 = 34,
-  STACKMETA_PC002002 = 35,
-  STACKMETA_POLYORDER = 36,
-  STACKMETA_PCA1X3Y0 = 37,
-  STACKMETA_PCA1X2Y1 = 38,
-  STACKMETA_PCA1X1Y2 = 39,
-  STACKMETA_PCA1X0Y3 = 40,
-  STACKMETA_PCA1X2Y0 = 41,
-  STACKMETA_PCA1X1Y1 = 42,
-  STACKMETA_PCA1X0Y2 = 43,
-  STACKMETA_PCA2X3Y0 = 44,
-  STACKMETA_PCA2X2Y1 = 45,
-  STACKMETA_PCA2X1Y2 = 46,
-  STACKMETA_PCA2X0Y3 = 47,
-  STACKMETA_PCA2X2Y0 = 48,
-  STACKMETA_PCA2X1Y1 = 49,
-  STACKMETA_PCA2X0Y2 = 50,
-  STACKMETA_CALIBMODNUM = 51,
-  STACKMETA_DATARELEASE = 52,
-} StackMeta;
-
-typedef enum {
-  STACKTOIMAGE_STACKMETAID = 1,
-  STACKTOIMAGE_IMAGEID = 2,
-} StackToImage;
-
-typedef enum {
-  STACKLOWSIGDELTA_STACKMETAID = 1,
-  STACKLOWSIGDELTA_DATATABLE = 2,
-  STACKLOWSIGDELTA_DATARELEASE = 3,
-} StackLowSigDelta;
-
-typedef enum {
-  STACKHIGHSIGDELTA_PARTITIONKEY = 1,
-  STACKHIGHSIGDELTA_STACKDIFFID = 2,
-  STACKHIGHSIGDELTA_IPPDETECTID = 3,
-  STACKHIGHSIGDELTA_FILTERID = 4,
-  STACKHIGHSIGDELTA_OBSTIME = 5,
-  STACKHIGHSIGDELTA_XPOS = 6,
-  STACKHIGHSIGDELTA_YPOS = 7,
-  STACKHIGHSIGDELTA_XPOSERR = 8,
-  STACKHIGHSIGDELTA_YPOSERR = 9,
-  STACKHIGHSIGDELTA_INSTMAG = 10,
-  STACKHIGHSIGDELTA_INSTMAGERR = 11,
-  STACKHIGHSIGDELTA_PEAKFLUXMAG = 12,
-  STACKHIGHSIGDELTA_PSFWIDMAJOR = 13,
-  STACKHIGHSIGDELTA_PSFWIDMINOR = 14,
-  STACKHIGHSIGDELTA_PSFTHETA = 15,
-  STACKHIGHSIGDELTA_PSFLIKELIHOOD = 16,
-  STACKHIGHSIGDELTA_PSFCF = 17,
-  STACKHIGHSIGDELTA_INFOFLAG = 18,
-  STACKHIGHSIGDELTA_NFRAMES = 19,
-  STACKHIGHSIGDELTA_HTMID = 20,
-  STACKHIGHSIGDELTA_ZONEID = 21,
-  STACKHIGHSIGDELTA_RA = 22,
-  STACKHIGHSIGDELTA_DEC = 23,
-  STACKHIGHSIGDELTA_RAERR = 24,
-  STACKHIGHSIGDELTA_DECERR = 25,
-  STACKHIGHSIGDELTA_CX = 26,
-  STACKHIGHSIGDELTA_CY = 27,
-  STACKHIGHSIGDELTA_CZ = 28,
-  STACKHIGHSIGDELTA_CALMAG = 29,
-  STACKHIGHSIGDELTA_CALMAGERR = 30,
-  STACKHIGHSIGDELTA_SKY = 31,
-  STACKHIGHSIGDELTA_SKYERR = 32,
-  STACKHIGHSIGDELTA_SGSEP = 33,
-  STACKHIGHSIGDELTA_DATARELEASE = 34,
-} StackHighSigDelta;
-
-typedef enum {
-  OBJECTCALCOLOR_OBJID = 1,
-  OBJECTCALCOLOR_IPPOBJID = 2,
-  OBJECTCALCOLOR_FILTERID = 3,
-  OBJECTCALCOLOR_CALCOLOR = 4,
-  OBJECTCALCOLOR_CALCOLORERR = 5,
-  OBJECTCALCOLOR_CALIBMODNUM = 6,
-  OBJECTCALCOLOR_DATARELEASE = 7,
-} ObjectCalColor;
-
-#endif
Index: trunk/ippToPsps/src/ippToPspsTestEnums.h
===================================================================
--- trunk/ippToPsps/src/ippToPspsTestEnums.h	(revision 30146)
+++ 	(revision )
@@ -1,19 +1,0 @@
-#ifndef IPPTOPSPSDETENUMS_H
-#define IPPTOPSPSDETENUMS_H
-
-
-
-typedef enum {
-  DETECTION_OBJID = 1,
-  DETECTION_DETECTID,
-  DETECTION_IPPOBJID,
-  DETECTION_IPPDETECTID,
-  DETECTION_FILTERID,
-  DETECTION_IMAGEID,
-  DETECTION_RA ,
-  DETECTION_DEC ,
-  DETECTION_INFOFLAG,
-  DETECTION_INSTFLUX,
-} Detection;
-
-#endif
Index: trunk/ippToPsps/src/ippToPspsVersion.c
===================================================================
--- trunk/ippToPsps/src/ippToPspsVersion.c	(revision 30146)
+++ 	(revision )
@@ -1,115 +1,0 @@
-/** @file ippToPspsVersion.c
- *
- *  @brief
- *
- *  @ingroup ippToPsps
- *
- *  Copyright 2009 Institute for Astronomy, University of Hawaii
- */
-
-#include "ippToPsps.h"
-#include "ippToPspsVersionDefinitions.h"
-
-#ifndef IPPTOPSPS_VERSION
-#error "IPPTOPSPS_VERSION is not set"
-#endif
-#ifndef IPPTOPSPS_BRANCH
-#error "IPPTOPSPS_BRANCH is not set"
-#endif
-#ifndef IPPTOPSPS_SOURCE
-#error "IPPTOPSPS_SOURCE is not set"
-#endif
-
-psString ippToPsps_Version(void)
-{
-    char *value = NULL;
-    psStringAppend(&value, "%s@%s", IPPTOPSPS_BRANCH, IPPTOPSPS_VERSION);
-    return value;
-}
-
-psString ippToPsps_Source(void)
-{
-  return psStringCopy(IPPTOPSPS_SOURCE);
-}
-
-psString ippToPsps_VersionLong(void)
-{
-    psString version = ippToPsps_Version();  // Version, to return
-    psString source = ippToPsps_Source();    // Source
-
-    psStringPrepend(&version, "ippToPsps ");
-    psStringAppend(&version, " from %s, built %s, %s", source, __DATE__, __TIME__);
-    psFree(source);
-
-#ifdef __OPTIMIZE__
-    psStringAppend(&version, " optimised");
-#else
-    psStringAppend(&version, " unoptimised");
-#endif
-
-    return version;
-};
-
-bool ippToPsps_VersionHeader(psMetadata *header)
-{
-    PS_ASSERT_METADATA_NON_NULL(header, false);
-
-    psString version = ippToPsps_Version(); // Software version
-    psString source = ippToPsps_Source();   // Software source
-
-    psMetadataAddStr(header, PS_LIST_TAIL, "IPP2PS_V", PS_META_REPLACE, NULL, IPPTOPSPS_VERSION);
-    
-    psStringPrepend(&version, "ippToPsps version: ");
-    psStringPrepend(&source, "ippToPsps source: ");
-
-    psMetadataAddStr(header, PS_LIST_TAIL, "HISTORY", PS_META_DUPLICATE_OK, NULL, version);
-    psMetadataAddStr(header, PS_LIST_TAIL, "HISTORY", PS_META_DUPLICATE_OK, NULL, source);
-
-    psFree(version);
-    psFree(source);
-
-    return true;
-}
-
-bool ippToPsps_VersionHeaderFull(psMetadata *header)
-{
-    PS_ASSERT_METADATA_NON_NULL(header, false);
-
-    psTime *time = psTimeGetNow(PS_TIME_TAI); // The time now
-    psString timeString = psTimeToISO(time); // The time in an ISO string
-    psFree(time);
-    psString history = NULL;               // History string
-    psStringAppend(&history, "ippToPsps at %s", timeString);
-    psFree(timeString);
-    psMetadataAddStr(header, PS_LIST_TAIL, "HISTORY", PS_META_DUPLICATE_OK, NULL, history);
-    psFree(history);
-
-    psLibVersionHeader(header);
-    psModulesVersionHeader(header);
-    ippToPsps_VersionHeader(header);
-
-    return true;
-}
-
-void ippToPsps_VersionPrint(void)
-{
-    psTime *time = psTimeGetNow(PS_TIME_TAI); // The time now
-    psString timeString = psTimeToISO(time); // The time in an ISO string
-    psFree(time);
-    psLogMsg("ippToPsps", PS_LOG_INFO, "ippToPsps at %s", timeString);
-    psFree(timeString);
-
-    psString pslib = psLibVersionLong();// psLib version
-    psString psmodules = psModulesVersionLong(); // psModules version
-    psString ippToPsps = ippToPsps_VersionLong(); // ippToPsps version
-
-    psLogMsg("ippToPsps", PS_LOG_INFO, "%s", pslib);
-    psLogMsg("ippToPsps", PS_LOG_INFO, "%s", psmodules);
-    psLogMsg("ippToPsps", PS_LOG_INFO, "%s", ippToPsps);
-
-    psFree(pslib);
-    psFree(psmodules);
-    psFree(ippToPsps);
-
-    return;
-}
Index: trunk/ippToPsps/src/ippToPspsVersionDefinitions.h.in
===================================================================
--- trunk/ippToPsps/src/ippToPspsVersionDefinitions.h.in	(revision 30146)
+++ 	(revision )
@@ -1,8 +1,0 @@
-#ifndef IPPTOPSPS_VERSION_DEFINITIONS_H
-#define IPPTOPSPS_VERSION_DEFINITIONS_H
-
-#define IPPTOPSPS_VERSION @IPPTOPSPS_VERSION@ // SVN version
-#define IPPTOPSPS_BRANCH  @IPPTOPSPS_BRANCH@  // SVN branch
-#define IPPTOPSPS_SOURCE  @IPPTOPSPS_SOURCE@  // SVN source
-
-#endif
Index: trunk/ippToPsps/src/main.c
===================================================================
--- trunk/ippToPsps/src/main.c	(revision 30146)
+++ 	(revision )
@@ -1,41 +1,0 @@
-/** @file ippToPsps.c
- *
- *  @brief
- *
- *  @ingroup ippToPsps
- *
- *  @author IfA
- *  Copyright 2009 Institute for Astronomy, University of Hawaii
- */
-
-#include "ippToPsps.h"
-
-// Main 
-int main(int argc, char **argv) {
-
-    psTimerStart("ippToPsps");
-
-    ippToPsps_VersionPrint();
-
-    int exitCode;
-
-    // create ippToPsps
-    IppToPsps *ippToPsps = ippToPsps_Constructor(&argc, argv);
-    ippToPsps->run(ippToPsps);
-    exitCode = ippToPsps->exitCode;
-    psFree(ippToPsps);
-
-    double secs = psTimerMark("ippToPsps");
-
-    psLogMsg("ippToPsps", 3, "ippToPsps completed %ssuccessfully, with exit code %d, in %.1f %s\n", 
-            (exitCode == PS_EXIT_SUCCESS) ? "" : "un",
-            exitCode,
-            (secs<60.0) ? secs : (secs/60.0),
-            (secs<60.0) ? "sec(s)" : "min(s)");
-
-    // tidy up
-    psTimerStop();
-    psLibFinalize();
-
-    return exitCode;
-}
