Index: /trunk/ppFringe/.cvsignore
===================================================================
--- /trunk/ppFringe/.cvsignore	(revision 7826)
+++ /trunk/ppFringe/.cvsignore	(revision 7826)
@@ -0,0 +1,11 @@
+Makefile.in
+aclocal.m4
+autom4te.cache
+compile
+configure
+depcomp
+install-sh
+missing
+Makefile
+config.log
+config.status
Index: /trunk/ppFringe/Makefile.am
===================================================================
--- /trunk/ppFringe/Makefile.am	(revision 7826)
+++ /trunk/ppFringe/Makefile.am	(revision 7826)
@@ -0,0 +1,3 @@
+SUBDIRS = src
+
+CLEANFILES = *~ core core.*
Index: /trunk/ppFringe/autogen.sh
===================================================================
--- /trunk/ppFringe/autogen.sh	(revision 7826)
+++ /trunk/ppFringe/autogen.sh	(revision 7826)
@@ -0,0 +1,103 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+ORIGDIR=`pwd`
+cd $srcdir
+
+PROJECT=ppFringe
+TEST_TYPE=-f
+# change this to be a unique filename in the top level dir
+FILE=autogen.sh
+
+DIE=0
+
+LIBTOOLIZE=libtoolize
+ACLOCAL=aclocal
+AUTOHEADER=autoheader
+AUTOMAKE=automake
+AUTOCONF=autoconf
+
+#($LIBTOOLIZE --version) < /dev/null > /dev/null 2>&1 || {
+#        echo
+#        echo "You must have $LIBTOOlIZE installed to compile $PROJECT."
+#        echo "Download the appropriate package for your distribution,"
+#        echo "or get the source tarball at http://ftp.gnu.org/gnu/libtool/"
+#        DIE=1
+#}
+
+($ACLOCAL --version) < /dev/null > /dev/null 2>&1 || {
+        echo
+        echo "You must have $ACLOCAL installed to compile $PROJECT."
+        echo "Download the appropriate package for your distribution,"
+        echo "or get the source tarball at http://ftp.gnu.org/gnu/automake/"
+        DIE=1
+}
+
+#($AUTOHEADER --version) < /dev/null > /dev/null 2>&1 || {
+#        echo
+#        echo "You must have $AUTOHEADER installed to compile $PROJECT."
+#        echo "Download the appropriate package for your distribution,"
+#        echo "or get the source tarball at http://ftp.gnu.org/gnu/autoconf/"
+#        DIE=1
+#}
+
+($AUTOMAKE --version) < /dev/null > /dev/null 2>&1 || {
+        echo
+        echo "You must have $AUTOMAKE installed to compile $PROJECT."
+        echo "Download the appropriate package for your distribution,"
+        echo "or get the source tarball at http://ftp.gnu.org/gnu/automake/"
+        DIE=1
+}
+
+($AUTOCONF --version) < /dev/null > /dev/null 2>&1 || {
+        echo
+        echo "You must have $AUTOCONF installed to compile $PROJECT."
+        echo "Download the appropriate package for your distribution,"
+        echo "or get the source tarball at http://ftp.gnu.org/gnu/autoconf/"
+        DIE=1
+}
+
+if test "$DIE" -eq 1; then
+        exit 1
+fi
+
+test $TEST_TYPE $FILE || {
+        echo "You must run this script in the top-level $PROJECT directory"
+        exit 1
+}
+
+if test -z "$*"; then
+        echo "I am going to run ./configure with no arguments - if you wish "
+        echo "to pass any to it, please specify them on the $0 command line."
+fi
+
+#$LIBTOOLIZE --copy --force || echo "$LIBTOOlIZE failed"
+$ACLOCAL || echo "$ACLOCAL failed"
+#$AUTOHEADER || echo "$AUTOHEADER failed"
+$AUTOMAKE --add-missing --force-missing --copy || echo "$AUTOMAKE failed"
+$AUTOCONF || echo "$AUTOCONF failed"
+
+cd $ORIGDIR
+
+run_configure=true
+for arg in $*; do
+    case $arg in
+        --no-configure)
+            run_configure=false
+            ;;
+        *)
+            ;;
+    esac
+done
+
+if $run_configure; then
+    $srcdir/configure --enable-maintainer-mode "$@"
+    echo
+    echo "Now type 'make' to compile $PROJECT."
+else
+    echo
+    echo "Now run 'configure' and 'make' to compile $PROJECT."
+fi
Index: /trunk/ppFringe/configure.ac
===================================================================
--- /trunk/ppFringe/configure.ac	(revision 7826)
+++ /trunk/ppFringe/configure.ac	(revision 7826)
@@ -0,0 +1,35 @@
+AC_PREREQ(2.59)
+
+AC_INIT([ppFringe], [0.0.1], [price@ifa.hawaii.edu])
+AC_CONFIG_SRCDIR([src])
+
+AM_INIT_AUTOMAKE([1.6 foreign dist-bzip2])
+dnl AM_CONFIG_HEADER([config.h])
+AM_MAINTAINER_MODE
+
+AC_LANG(C)
+AC_GNU_SOURCE
+AC_PROG_CC
+AC_PROG_INSTALL
+dnl AC_PROG_LIBTOOL
+
+dnl handle debug building
+AC_ARG_ENABLE(optimize,
+  [AS_HELP_STRING(--enable-optimize,enable compiler optimization)],
+  [AC_MSG_RESULT(compile optimization enabled)
+   CFLAGS="${CFLAGS=} -O2"],
+  [AC_MSG_RESULT([compile optimization disabled])
+   CFLAGS="${CFLAGS=} -O0 -g"]
+)
+
+PKG_CHECK_MODULES([PSLIB], [pslib >= 0.9.0]) 
+PKG_CHECK_MODULES([PSMODULE], [psmodule >= 0.0.0]) 
+
+ppFringe_CFLAGS="-Wall -Werror -std=c99"
+AC_SUBST([ppFringe_CFLAGS])
+
+AC_CONFIG_FILES([
+  Makefile
+  src/Makefile
+])
+AC_OUTPUT
Index: /trunk/ppFringe/src/.cvsignore
===================================================================
--- /trunk/ppFringe/src/.cvsignore	(revision 7826)
+++ /trunk/ppFringe/src/.cvsignore	(revision 7826)
@@ -0,0 +1,4 @@
+Makefile.in
+ppFringe
+Makefile
+.deps
Index: /trunk/ppFringe/src/Makefile.am
===================================================================
--- /trunk/ppFringe/src/Makefile.am	(revision 7826)
+++ /trunk/ppFringe/src/Makefile.am	(revision 7826)
@@ -0,0 +1,26 @@
+bin_PROGRAMS = ppFringe
+
+ppFringe_CFLAGS += $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
+ppFringe_LDFLAGS = $(PSMODULE_LIBS) $(PSLIB_LIBS)
+### For profiling:
+#ppMerge_CFLAGS += -g -pg -fprofile-arcs $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
+#ppMerge_LDFLAGS = -pg -Wl,--start-group -Wl,-Bstatic $(PSMODULE_LIBS) $(PSLIB_LIBS) -Wl,-Bdynamic
+
+ppFringe_SOURCES =		\
+	ppFringe.c		\
+	ppFringeData.c		\
+	ppFringeLoop.c		\
+	ppFringeSetup.c
+
+noinst_HEADERS =		\
+	ppFringeData.h		\
+	ppFringe.h		\
+	ppFringeSetup.h
+
+CLEANFILES = *~
+
+clean-local:
+	-rm -f TAGS
+# Tags for emacs
+tags:
+	etags `find . -name \*.[ch] -print`
Index: /trunk/ppFringe/src/ppFringe.c
===================================================================
--- /trunk/ppFringe/src/ppFringe.c	(revision 7826)
+++ /trunk/ppFringe/src/ppFringe.c	(revision 7826)
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+
+#include "ppFringe.h"
+
+int main(int argc, char *argv[])
+{
+
+    psLibInit(NULL);
+    psTimerStart(TIMERNAME);
+
+    // Parse the configuration and arguments
+    pmConfig *config = pmConfigRead(&argc, argv);
+
+    // Get the options, open the files
+    ppFringeData *data = ppFringeSetup(config);
+
+    // Go through the FPA and measure the fringes
+    ppFringeLoop(data, config);
+
+    psFree(data);
+    psFree(config);
+    pmConceptsDone();
+    pmConfigDone();
+    psLibFinalize();
+
+    return EXIT_SUCCESS;
+}
Index: /trunk/ppFringe/src/ppFringe.h
===================================================================
--- /trunk/ppFringe/src/ppFringe.h	(revision 7826)
+++ /trunk/ppFringe/src/ppFringe.h	(revision 7826)
@@ -0,0 +1,19 @@
+#ifndef PP_FRINGE_H
+#define PP_FRINGE_H
+
+#define RECIPE "PPFRINGE"
+#define TIMERNAME "PPFRINGE"
+
+#include <psmodules.h>
+#include "ppFringeData.h"
+
+// Set up the options and input/output files
+ppFringeData *ppFringeSetup(pmConfig *config // Configuration
+    );
+
+// Loop over the input image and do all the hard work
+void ppFringeLoop(ppFringeData *data,   // The data
+                  const pmConfig *config// Configuration
+    );
+
+#endif
Index: /trunk/ppFringe/src/ppFringeData.c
===================================================================
--- /trunk/ppFringe/src/ppFringeData.c	(revision 7826)
+++ /trunk/ppFringe/src/ppFringeData.c	(revision 7826)
@@ -0,0 +1,54 @@
+#include <stdio.h>
+#include <pslib.h>
+
+#include "ppFringeData.h"
+
+static void fringeDataFree(ppFringeData *data // Data to free
+    )
+{
+    psFree(data->inName);
+    psFree(data->outName);
+    psFree(data->templateName);
+    psFree(data->numPoints);
+    psFree(data->inFPA);
+
+    if (data->inFile) {
+        psFitsClose(data->inFile);
+        data->inFile = NULL;
+    }
+    if (data->outFile) {
+        psFitsClose(data->outFile);
+        data->outFile = NULL;
+    }
+    if (data->templateFile) {
+        psFitsClose(data->templateFile);
+        data->templateFile = NULL;
+    }
+    return;
+}
+
+
+ppFringeData *ppFringeDataAlloc(void)
+{
+    ppFringeData *data = psAlloc(sizeof(ppFringeData)); // Newly allocated data
+    psMemSetDeallocator(data, (psFreeFunc)fringeDataFree);
+
+    data->inName = NULL;
+    data->outName = NULL;
+    data->templateName = NULL;
+    data->numPoints = 0;
+    data->xWidth = 0;
+    data->yWidth = 0;
+    data->xSmooth = 0;
+    data->ySmooth = 0;
+    data->maskVal = 0;
+
+    data->inFile = NULL;
+    data->outFile = NULL;
+    data->templateFile = NULL;
+    data->inFPA = NULL;
+
+    return data;
+}
+
+
Index: /trunk/ppFringe/src/ppFringeData.h
===================================================================
--- /trunk/ppFringe/src/ppFringeData.h	(revision 7826)
+++ /trunk/ppFringe/src/ppFringeData.h	(revision 7826)
@@ -0,0 +1,26 @@
+#ifndef PP_FRINGE_DATA_H
+#define PP_FRINGE_DATA_H
+
+#include <pslib.h>
+#include <psmodules.h>
+
+typedef struct {
+    // Options
+    const char *inName;                 // Input FITS image file
+    const char *outName;                // Output FITS table file
+    const char *templateName;           // Name of template output file
+    int numPoints;                      // Number of fringe points
+    int xWidth, yWidth;                 // Width of fringe points in x and y
+    int xSmooth, ySmooth;               // Large-scale smoothing in x and y
+    psMaskType maskVal;                 // Mask value
+    // Data
+    psFits *inFile;                     // Input file handle
+    psFits *outFile;                    // Output file handle
+    psFits *templateFile;               // Template file handle
+    pmFPA *inFPA;                       // Input FPA
+} ppFringeData;
+
+// Allocator
+ppFringeData *ppFringeDataAlloc(void);
+
+#endif
Index: /trunk/ppFringe/src/ppFringeLoop.c
===================================================================
--- /trunk/ppFringe/src/ppFringeLoop.c	(revision 7826)
+++ /trunk/ppFringe/src/ppFringeLoop.c	(revision 7826)
@@ -0,0 +1,81 @@
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+
+#include "ppFringe.h"
+
+void ppFringeLoop(ppFringeData *data,   // The data
+                  const pmConfig *config// Configuration
+    )
+{
+    psFitsWriteBlank(data->outFile, NULL);
+
+    pmFPA *fpa = data->inFPA;           // The FPA of interest
+    psArray *chips = fpa->chips;        // Array of component chips
+    for (long i = 0; i < chips->n; i++) {
+        pmChip *chip = chips->data[i];  // The chip of interest
+        if (!chip) {
+            continue;
+        }
+        const char *chipName = psMetadataLookupStr(NULL, chip->concepts, "CHIP.NAME"); // Name of chip
+        psArray *cells = chip->cells;   // Array of component cells
+        for (long j = 0; j < cells->n; j++) {
+            pmCell *cell = cells->data[j]; // The cell of interest
+            if (!cell) {
+                continue;
+            }
+            const char *cellName = psMetadataLookupStr(NULL, cell->concepts, "CELL.NAME"); // Name of cell
+
+            if (!pmCellRead(cell, data->inFile, config->database)) {
+                psLogMsg(__func__, PS_LOG_WARN, "Unable to read chip %s cell %s\n", chipName, cellName);
+                continue;
+            }
+
+            psArray *readouts = cell->readouts; // Array of component readouts
+            if (readouts->n == 0) {
+                continue;
+            }
+            if (readouts->n > 1) {
+                psLogMsg(__func__, PS_LOG_WARN, "Multiple readouts (%ld) present in chip %s cell %s --- "
+                         "using only the first.\n", readouts->n, chipName, cellName);
+            }
+            pmReadout *readout = readouts->data[0]; // The readout of interest
+            if (!readout->image) {
+                psLogMsg(__func__, PS_LOG_WARN, "No image associated with readout in chip %s cell %s --- "
+                         "ignored.\n", chipName, cellName);
+                continue;
+            }
+
+            // Create points to measure fringes
+            pmFringeRegions *regions = pmFringeRegionsAlloc(data->numPoints, data->xWidth, data->yWidth,
+                                                            data->xSmooth, data->ySmooth);
+            if (!pmFringeRegionsCreatePoints(regions, readout->image)) {
+                psLogMsg(__func__, PS_LOG_WARN, "Unable to create fringe regions for chip %s cell %s --- "
+                         "ignored.\n", chipName, cellName);
+                psFree(regions);
+                continue;
+            }
+
+            // Measure fringes
+            pmFringeStats *fringeStats = pmFringeStatsMeasure(regions, readout, data->maskVal);
+            if (!fringeStats) {
+                psLogMsg(__func__, PS_LOG_WARN, "Unable to measure fringes for chip %s cell %s --- "
+                         "ignored.\n", chipName, cellName);
+                psFree(regions);
+                continue;
+            }
+
+            // Write fringe measurements
+            psString extname = NULL;
+            psStringAppend(&extname, "%s_%s", chipName, cellName);
+            if (!pmFringeStatsWriteFits(data->outFile, fringeStats, extname)) {
+                psLogMsg(__func__, PS_LOG_WARN, "Unable to write fringe measurements for chip %s cell %s --- "
+                         "ignored.\n", chipName, cellName);
+                psFree(regions);
+                psFree(fringeStats);
+                continue;
+            }
+        }
+    }
+
+}
Index: /trunk/ppFringe/src/ppFringeSetup.c
===================================================================
--- /trunk/ppFringe/src/ppFringeSetup.c	(revision 7826)
+++ /trunk/ppFringe/src/ppFringeSetup.c	(revision 7826)
@@ -0,0 +1,122 @@
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+#include <string.h>
+
+#include "ppFringe.h"
+
+// Print usage information and die
+static void usageAndDie(pmConfig *config      // Configuration (contains the arguments list)
+    )
+{
+    printf("Generate fringe points for a FITS image file.\n\n"
+           "Usage:\n"
+           "\t%s INPUT.fits OUTPUT.fits\n"
+           "\n", config->argv[0]);
+    psArgumentHelp(config->arguments);
+    psFree(config);
+    psLibFinalize();
+    exit(EXIT_FAILURE);
+}
+
+ppFringeData *ppFringeSetup(pmConfig *config // Configuration
+    )
+{
+    if (*config->argc == 1) {
+        // No command-line arguments: print the help
+        usageAndDie(config);
+    }
+
+    // Setup and parse command-line arguments
+    psMetadata *arguments = psMetadataAlloc();
+    psMetadataAddStr(arguments, PS_LIST_TAIL, "-template", 0, "Template output", NULL);
+    psMetadataAddStr(arguments, PS_LIST_TAIL, "-detid", 0, "Detrend identifier", NULL);
+    psMetadataAddStr(arguments, PS_LIST_TAIL, "-classid", 0, "Class identifier", NULL);
+    if (!psArgumentParse(config->arguments, config->argc, config->argv) || *config->argc < 2) {
+        printf("Unable to parse command-line arguments.\n\n");
+        usageAndDie(config);
+    }
+
+    ppFringeData *data = ppFringeDataAlloc(); // The data
+    data->inName = config->argv[1];
+    data->outName = config->argv[2];
+    data->templateName = psMetadataLookupStr(NULL, arguments, "-template");
+
+    // Open the input file, determine the camera
+    data->inFile = psFitsOpen(data->inName, "r");
+    if (!data->inFile) {
+        psError(PS_ERR_IO, false, "Unable to open input file %s\n", data->inName);
+        goto die;
+    }
+    psMetadata *header = psFitsReadHeader(NULL, data->inFile); // The FITS (primary) header
+    psMetadata *format = pmConfigCameraFormatFromHeader(config, header);
+    if (!format) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to determine camera format for %s\n", data->inName);
+        psFree(header);
+        goto die;
+    }
+    data->inFPA = pmFPAConstruct(config->camera);
+    if (!data->inFPA) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to construct FPA for %s\n", data->inName);
+        psFree(header);
+        psFree(format);
+        goto die;
+    }
+    pmFPAview *view = pmFPAAddSourceFromHeader(data->inFPA, header, format);
+    psFree(header);
+    psFree(format);
+    if (!view) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to add input file %s to FPA.\n", data->inName);
+        goto die;
+    }
+
+    // Now we have a camera format, we can read the recipe
+    bool mdok;                          // Status of MD lookup
+    psMetadata *recipe = psMetadataLookupMD(&mdok, config->recipes, RECIPE); // The recipe
+    if (!recipe) {
+        psError(PS_ERR_IO, true, "Unable to find recipe %s.\n", RECIPE);
+        goto die;
+    }
+
+    #define READ_RECIPE_ITEM(NAME, RECIPE, TARGET, TYPE) \
+    { \
+        bool mdok; \
+        TARGET = psMetadataLookup##TYPE(&mdok, RECIPE, NAME); \
+        if (!mdok || TARGET <= 0) { \
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "%s in the recipe is not valid: %d.\n", NAME, \
+                    TARGET); \
+            goto die; \
+        } \
+    }
+
+    READ_RECIPE_ITEM("NUMPOINTS", recipe, data->numPoints, S32);
+    READ_RECIPE_ITEM("XWIDTH", recipe, data->xWidth, S32);
+    READ_RECIPE_ITEM("YWIDTH", recipe, data->yWidth, S32);
+    READ_RECIPE_ITEM("XSMOOTH", recipe, data->xSmooth, S32);
+    READ_RECIPE_ITEM("YSMOOTH", recipe, data->ySmooth, S32);
+    READ_RECIPE_ITEM("MASKVAL", recipe, data->maskVal, U8);
+
+    // Open the output and template file
+    data->outFile = psFitsOpen(data->outName, "w");
+    if (!data->outFile) {
+        psError(PS_ERR_IO, false, "Unable to open output file %s\n", data->outName);
+        goto die;
+    }
+
+    if (data->templateName && strlen(data->templateName) > 0) {
+        data->templateFile = psFitsOpen(data->templateName, "r");
+        if (!data->templateFile) {
+            psError(PS_ERR_IO, false, "Unable to open template file %s\n", data->templateName);
+            goto die;
+        }
+    }
+
+    return data;
+
+    // Common path for error conditions: clean up and exit.
+die:
+    psFree(config);
+    psFree(data);
+    psLibFinalize();
+    exit(EXIT_FAILURE);
+}
Index: /trunk/ppFringe/src/ppFringeSetup.h
===================================================================
--- /trunk/ppFringe/src/ppFringeSetup.h	(revision 7826)
+++ /trunk/ppFringe/src/ppFringeSetup.h	(revision 7826)
@@ -0,0 +1,5 @@
+#ifndef PP_FRINGE_SETUP_H
+#define PP_FRINGE_SETUP_H
+
+
+#endif
