Index: trunk/ippToPsps/src/StackBatch.c
===================================================================
--- trunk/ippToPsps/src/StackBatch.c	(revision 30147)
+++ trunk/ippToPsps/src/StackBatch.c	(revision 31011)
@@ -1,4 +1,6 @@
 #include "StackBatch.h"
 #include "StackBatchEnums.h"
+
+#include "Fits.h"
 
 /**
@@ -13,181 +15,96 @@
 
 /**
-  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);
-
-
+  Creates the StackDetection table
+  */
+static bool createStackDetectionTable(
+        StackBatch* this,
+        Fits* fitsIn,
+        int8_t* filterIDs,
+        int8_t* surveyIDs,
+        long* skycellIDs,
+        float exposureTime
+        ) {
+
+    char extensionName[25];
+    sprintf(extensionName, "SkyChip.psf");
+    long nDet = 0;
+    if (!fitsIn->moveToBinaryTableAndCountRows(fitsIn, extensionName, &nDet)) return false;
+
+
+    // allocate stuff
     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);
+    float* peakMag = (float*)calloc(this->MAXDETECT, sizeof(float));
+    float* peakFlux = (float*)calloc(this->MAXDETECT, sizeof(float));
+    int* flags1 = (int*)calloc(this->MAXDETECT, sizeof(int));
+    int* flags2 = (int*)calloc(this->MAXDETECT, sizeof(int));
+    uint64_t* infoFlags = (uint64_t*)calloc(this->MAXDETECT, sizeof(uint64_t));
+
+    bool peakFluxOk;
+
+    // some stuff is the same for all detections so we can populate here
+    for (long s = 0; s<this->MAXDETECT; s++) {
+
+        // if running in test mode, don't use today's date
+        if (this->base.testMode) strcpy(assocDate[s], "2010-01-01");
+        else strcpy(assocDate[s], this->base.todaysDate);
+    }
+
+    fitsIn->readColumnUsingName(fitsIn, TFLOAT, "PSF_INST_MAG", 1, 1, nDet, instMag);
+    fitsIn->readColumnUsingName(fitsIn, TFLOAT, "PEAK_FLUX_AS_MAG", 1, 1, nDet, peakMag);
+    fitsIn->readColumnUsingName(fitsIn, TLONG, "FLAGS", 1, 1, nDet, flags1);
+    fitsIn->readColumnUsingName(fitsIn, TLONG, "FLAGS2", 1, 1, nDet, flags2);
+
+    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) {
+
+            //infoFlags[s] = ((uint64_t)flags1[s] << 32) | (uint64_t)flags2[s]; TODO implement after schema change to make infoFlag 64-bit
+            infoFlags[s] = (uint64_t)flags1[s];
+
+            peakFluxOk = getFlux(exposureTime, peakMag[s], &peakFlux[s], 0.0, NULL);
+
+            mag = instMag[s];
+            if (!peakFluxOk || !isfinite(mag) || mag < -998.0) {
+
+                removeList[numOfDuplicates+numInvalidFlux] = s+1;
+                numInvalidFlux++;
+            }
+
+            totalDetections++;
         }
-
-
-        long nDet = 0;
-        if (fits_get_num_rows(fitsIn, &nDet, &status)) {
-            fits_report_error(stderr, status);
+        else {
+
+            unmatched++;
+            continue;
         }
-
-        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);
-    }
+    }
+
+    numDetectionsOut = totalDetections - numInvalidFlux;
+    if (numDetectionsOut > 0) {
+
+        this->base.config->createAndPopulateTable(this->base.config, fitsIn, this->base.fitsOut, nDet, "StackDetection", false);
+        this->base.fitsOut->writeColumn(this->base.fitsOut, TLONG, STACKDETECTION_SKYCELLID, 1, 1, nDet, skycellIDs);
+        this->base.fitsOut->writeColumn(this->base.fitsOut, TBYTE, STACKDETECTION_FILTERID, 1, 1, nDet, filterIDs);
+        this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKDETECTION_PEAKFLUX, 1, 1, nDet, peakFlux);
+        this->base.fitsOut->writeColumn(this->base.fitsOut, TBYTE, STACKDETECTION_SURVEYID, 1, 1, nDet, surveyIDs);
+        this->base.fitsOut->writeColumn(this->base.fitsOut, TSTRING, STACKDETECTION_ASSOCDATE, 1, 1, nDet, assocDate);
+        this->base.fitsOut->writeColumn(this->base.fitsOut, TLONGLONG, STACKDETECTION_INFOFLAG, 1, 1, nDet, flags1);
+
+        if (numInvalidFlux) this->base.fitsOut->deleteRows(this->base.fitsOut, removeList, numInvalidFlux);
+
+    }
+    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);
 
 
@@ -195,14 +112,258 @@
     free(removeList);
     free(instMag);
+    free(flags1);
+    free(flags2);
+    free(infoFlags);
+    for (uint32_t i=0; i<this->MAXDETECT;i++) free(assocDate[i]);
+    free(assocDate);
+
+    return true;
+}
+/**
+  Structure to encapsulate block of flux values for StackApFlx table
+  */
+typedef struct {
+
+    float* flx;
+    float* flxErr;
+    float* flxStd;
+    float* flxFill;
+
+} StackApFlxFluxes;
+
+/**
+  Creates the StackApFlx table for extended source attributes
+  */
+static bool createStackApFlxTable(
+        StackBatch* this,
+        Fits* fitsIn,
+        int8_t* filterIDs,
+        int8_t* surveyIDs
+        ) {
+
+    long nDet = 0;
+    if (!fitsIn->moveToBinaryTableAndCountRows(fitsIn, "SkyChip.xrad", &nDet)) return false;
+
+
+    int aperFluxColNum, aperFluxErrColNum, aperFluxStDevColNum, aperFluxFillColNum;
+    int type; // all the same type
+    long repeat;
+
+    fitsIn->getColumnMeta(fitsIn, "APER_FLUX", &aperFluxColNum, &type, &repeat);
+    fitsIn->getColumnMeta(fitsIn, "APER_FLUX_ERR", &aperFluxErrColNum, &type, &repeat);
+    fitsIn->getColumnMeta(fitsIn, "APER_FLUX_STDEV", &aperFluxStDevColNum, &type, &repeat);
+    fitsIn->getColumnMeta(fitsIn, "APER_FILL", &aperFluxFillColNum, &type, &repeat);
+    float* vector = calloc(repeat, sizeof(float));
+
+    // we store 10 different flux values
+    StackApFlxFluxes* stackApFlxFluxes = (StackApFlxFluxes*)calloc(11, sizeof(StackApFlxFluxes));
+    for (long i=0; i<11; i++) {
+
+        stackApFlxFluxes[i].flx = (float*)calloc(nDet, sizeof(float));
+        stackApFlxFluxes[i].flxErr = (float*)calloc(nDet, sizeof(float));
+        stackApFlxFluxes[i].flxStd = (float*)calloc(nDet, sizeof(float));
+        stackApFlxFluxes[i].flxFill = (float*)calloc(nDet, sizeof(float));
+    }
+
+    printf("Looping through %ld extended source detections\n", nDet);
+    for (long s=0; s<nDet; s++) {
+
+        fitsIn->getColumnVector(fitsIn, aperFluxColNum,s, type, repeat, vector);
+        for (int i=0; i<repeat; i++) stackApFlxFluxes[i].flx[s] = vector[i];
+
+        fitsIn->getColumnVector(fitsIn, aperFluxErrColNum,s, type, repeat, vector);
+        for (int i=0; i<repeat; i++) stackApFlxFluxes[i].flxErr[s] = vector[i];
+
+        fitsIn->getColumnVector(fitsIn, aperFluxStDevColNum,s, type, repeat, vector);
+        for (int i=0; i<repeat; i++) stackApFlxFluxes[i].flxStd[s] = vector[i];
+
+        fitsIn->getColumnVector(fitsIn, aperFluxFillColNum,s, type, repeat, vector);
+        for (int i=0; i<repeat; i++) stackApFlxFluxes[i].flxFill[s] = vector[i];
+
+    }
+
+    free(vector);
+
+    //int status = 0;
+    this->base.config->createAndPopulateTable(this->base.config, fitsIn, this->base.fitsOut, nDet, "StackApFlx", false);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TBYTE, STACKAPFLX_FILTERID, 1, 1, nDet, filterIDs);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TBYTE, STACKAPFLX_SURVEYID, 1, 1, nDet, surveyIDs);
+
+    // R1->r10 flux values
+    // 1
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR1, 1, 1, nDet, stackApFlxFluxes[0].flx);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR1ERR, 1, 1, nDet, stackApFlxFluxes[0].flxErr);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR1STD, 1, 1, nDet, stackApFlxFluxes[0].flxStd);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR1FILL, 1, 1, nDet, stackApFlxFluxes[0].flxFill);
+    // 2
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR2, 1, 1, nDet, stackApFlxFluxes[1].flx);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR2ERR, 1, 1, nDet, stackApFlxFluxes[1].flxErr);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR2STD, 1, 1, nDet, stackApFlxFluxes[1].flxStd);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR2FILL, 1, 1, nDet, stackApFlxFluxes[1].flxFill);
+    // 3
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR3, 1, 1, nDet, stackApFlxFluxes[2].flx);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR3ERR, 1, 1, nDet, stackApFlxFluxes[2].flxErr);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR3STD, 1, 1, nDet, stackApFlxFluxes[2].flxStd);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR3FILL, 1, 1, nDet, stackApFlxFluxes[2].flxFill);
+    // 4
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR4, 1, 1, nDet, stackApFlxFluxes[3].flx);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR4ERR, 1, 1, nDet, stackApFlxFluxes[3].flxErr);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR4STD, 1, 1, nDet, stackApFlxFluxes[3].flxStd);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR4FILL, 1, 1, nDet, stackApFlxFluxes[3].flxFill);
+    // 5
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR5, 1, 1, nDet, stackApFlxFluxes[4].flx);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR5ERR, 1, 1, nDet, stackApFlxFluxes[4].flxErr);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR5STD, 1, 1, nDet, stackApFlxFluxes[4].flxStd);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR5FILL, 1, 1, nDet, stackApFlxFluxes[4].flxFill);
+    // 6
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR6, 1, 1, nDet, stackApFlxFluxes[5].flx);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR6ERR, 1, 1, nDet, stackApFlxFluxes[5].flxErr);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR6STD, 1, 1, nDet, stackApFlxFluxes[5].flxStd);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR6FILL, 1, 1, nDet, stackApFlxFluxes[5].flxFill);
+    // 7
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR7, 1, 1, nDet, stackApFlxFluxes[6].flx);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR7ERR, 1, 1, nDet, stackApFlxFluxes[6].flxErr);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR7STD, 1, 1, nDet, stackApFlxFluxes[6].flxStd);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR7FILL, 1, 1, nDet, stackApFlxFluxes[6].flxFill);
+    // 8
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR8, 1, 1, nDet, stackApFlxFluxes[7].flx);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR8ERR, 1, 1, nDet, stackApFlxFluxes[7].flxErr);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR8STD, 1, 1, nDet, stackApFlxFluxes[7].flxStd);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR8FILL, 1, 1, nDet, stackApFlxFluxes[7].flxFill);
+    // 9
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR9, 1, 1, nDet, stackApFlxFluxes[8].flx);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR9ERR, 1, 1, nDet, stackApFlxFluxes[8].flxErr);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR9STD, 1, 1, nDet, stackApFlxFluxes[8].flxStd);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR9FILL, 1, 1, nDet, stackApFlxFluxes[8].flxFill);
+    // 10
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR10, 1, 1, nDet, stackApFlxFluxes[9].flx);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR10ERR, 1, 1, nDet, stackApFlxFluxes[9].flxErr);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR10STD, 1, 1, nDet, stackApFlxFluxes[9].flxStd);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TFLOAT, STACKAPFLX_FLXR10FILL, 1, 1, nDet, stackApFlxFluxes[9].flxFill);
+
+    for (long i=0; i<11; i++) {
+
+        free(stackApFlxFluxes[i].flx);
+        free(stackApFlxFluxes[i].flxErr);
+        free(stackApFlxFluxes[i].flxStd);
+        free(stackApFlxFluxes[i].flxFill);
+    }
+
+    free(stackApFlxFluxes);
+
+    return true;
+}
+
+/**
+  Creates the StackModelFit table
+  */
+static bool createStackModelFitTable(
+        StackBatch* this,
+        Fits *fitsIn,
+        int8_t* filterIDs,
+        int8_t* surveyIDs) {
+
+    long nDet = 0;
+    if (!fitsIn->moveToBinaryTableAndCountRows(fitsIn, "SkyChip.xfit", &nDet)) return false;
+
+    long* ippIdets = (long*)calloc(this->MAXDETECT, sizeof(long));
+    char** modelTypes = (char**)calloc(this->MAXDETECT, sizeof(char**));
+    for (uint32_t i=0; i<this->MAXDETECT;i++) modelTypes[i] = (char*)calloc(20,sizeof(char));
+
+    // read whole columns
+    fitsIn->readColumnUsingName(fitsIn, TLONG, "IPP_IDET", 1, 1, nDet, ippIdets);
+    fitsIn->readColumnUsingName(fitsIn, TSTRING, "MODEL_TYPE", 1, 1, nDet, modelTypes);
+
+    printf("Looping through %ld model fit rows\n", nDet);
+    for (long i = 0; i<nDet; i++) {
+
+        printf("IPP_IDET %ld model %s\n", ippIdets[i], modelTypes[i]);
+
+    }
+
+    this->base.config->createAndPopulateTable(this->base.config, fitsIn, this->base.fitsOut, nDet, "StackModelFit", false);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TBYTE, STACKMODELFIT_FILTERID, 1, 1, nDet, filterIDs);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TBYTE, STACKMODELFIT_SURVEYID, 1, 1, nDet, surveyIDs);
+
+    // free up
+    free(ippIdets);
+    for (uint32_t i=0; i<this->MAXDETECT;i++) free(modelTypes[i]);
+    free(modelTypes);
+
+    return true;
+}
+
+/**
+  Creates the StackToImage table
+  */
+static bool createStackToImageTable(
+        StackBatch* this,
+        Fits* fitsIn
+        ) {
+
+    this->base.config->createAndPopulateTable(this->base.config, fitsIn, this->base.fitsOut, 3/*TODO*/, "StackToImage", false);
+
+    return true;
+}
+
+/**
+  Does the work. Writes all extensions to new FITS file.
+  */
+static int run(StackBatch* this) {
+
+    if (this->base.exitCode != PS_EXIT_SUCCESS) return this->base.exitCode; 
+
+    // open input FITS file
+    Fits* fitsIn = existing_Fits(this->base.inputFiles[0]);
+    if (fitsIn->getFilePtr(fitsIn) == NULL)  return PS_EXIT_SYS_ERROR;
+
+    // get primary header and pull stuff out for later
+    float exposureTime; fitsIn->getHeaderKeyValue(fitsIn, TFLOAT, "EXPTIME", &exposureTime);
+    char filterType[20]; fitsIn->getHeaderKeyValue(fitsIn, TSTRING, "FILTER", filterType);
+
+    int8_t filterID = -1;
+    if (!this->base.config->getFilterId(this->base.config, filterType, &filterID)) {
+
+        //        this->base.exitCode = PS_EXIT_DATA_ERROR;
+        //    return this->base.exitCode; TODO
+    }
+
+    exposureTime = 60.0;// TODO
+    filterID = 3; // TODO
+
+    // write StackMeta
+    this->base.config->createAndPopulateTable(this->base.config, fitsIn, this->base.fitsOut, 1, "StackMeta", true);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TLONG, STACKMETA_SKYCELLID, 1, 1, 1, &this->skycellId);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TBYTE, STACKMETA_FILTERID, 1, 1, 1, &filterID);
+    this->base.fitsOut->writeColumn(this->base.fitsOut, TBYTE, STACKMETA_SURVEYID, 1, 1, 1, &this->base.surveyID);
+
+    // allocate stuff for other extensions
+    int8_t* filterIDs = (int8_t*)calloc(this->MAXDETECT, sizeof(int8_t));
+    int8_t* surveyIDs = (int8_t*)calloc(this->MAXDETECT, sizeof(int8_t));
+    long* skycellIDs = (long*)calloc(this->MAXDETECT, sizeof(long));
+
+    // some stuff is the same for all detections so we can populate here
+    for (long s = 0; s<this->MAXDETECT; s++) {
+
+        skycellIDs[s] = this->skycellId;
+        filterIDs[s] = filterID;
+        surveyIDs[s] = this->base.surveyID;
+    }
+
+    // create all extensions
+    createStackDetectionTable(this, fitsIn, filterIDs, surveyIDs, skycellIDs, exposureTime);
+    createStackApFlxTable(this, fitsIn, filterIDs, surveyIDs);
+    printf("dsdsdddds\n\n");
+    createStackModelFitTable(this, fitsIn, filterIDs, surveyIDs);
+    createStackToImageTable(this, fitsIn);
+
+    // free stuff up
     free(filterIDs);
     free(surveyIDs);
-
-    status=0;
-    if (fits_close_file(fitsIn, &status)) fits_report_error(stderr, status);
-
+    free(skycellIDs);
+    fitsIn->destroy(fitsIn);
 
     return this->base.exitCode;
 }
-
 
 /**
@@ -240,5 +401,7 @@
     }
 
-    this->base.parseArguments(&this->base, argc, argv);
+    char fitsOutFile[40];
+    sprintf(fitsOutFile, "%08d.FITS", this->skycellId);
+    this->base.parseArguments(&this->base, argc, argv, "/stack", fitsOutFile);
 
     if (
@@ -275,14 +438,10 @@
     this->MAXDETECT = 150000;
 
+    // method pointers
     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);
+    parseArguments(this, *argc, argv);
 
     return this;
@@ -321,4 +480,2 @@
 }
 
-
-
