Index: /trunk/ppArith/.cvsignore
===================================================================
--- /trunk/ppArith/.cvsignore	(revision 8479)
+++ /trunk/ppArith/.cvsignore	(revision 8479)
@@ -0,0 +1,11 @@
+Makefile
+Makefile.in
+aclocal.m4
+autom4te.cache
+compile
+config.log
+config.status
+configure
+depcomp
+install-sh
+missing
Index: /trunk/ppArith/Makefile.am
===================================================================
--- /trunk/ppArith/Makefile.am	(revision 8479)
+++ /trunk/ppArith/Makefile.am	(revision 8479)
@@ -0,0 +1,3 @@
+SUBDIRS = src
+
+CLEANFILES = *~ core core.*
Index: /trunk/ppArith/autogen.sh
===================================================================
--- /trunk/ppArith/autogen.sh	(revision 8479)
+++ /trunk/ppArith/autogen.sh	(revision 8479)
@@ -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=ppArith
+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/ppArith/configure.ac
===================================================================
--- /trunk/ppArith/configure.ac	(revision 8479)
+++ /trunk/ppArith/configure.ac	(revision 8479)
@@ -0,0 +1,62 @@
+AC_PREREQ(2.59)
+
+AC_INIT([ppArith], [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"]
+)
+
+ppArith_CFLAGS="-Wall -Werror -std=c99"
+ppArith_LDFLAGS=""
+
+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"]
+)
+ 
+dnl handle path coverage checking
+AC_ARG_ENABLE(coverage,
+  [AS_HELP_STRING(--enable-coverage,enable path coverage checking)],
+  [AC_MSG_RESULT(path coverage enabled)
+   CFLAGS="${CFLAGS=} -fprofile-arcs -ftest-coverage -pg"]
+)
+ 
+PKG_CHECK_MODULES([PSLIB], [pslib >= 0.9.0])
+PKG_CHECK_MODULES([PSMODULE], [psmodule >= 0.0.0])
+
+dnl handle profiler building
+AC_ARG_ENABLE(profile,
+  [AS_HELP_STRING(--enable-profile,enable compiler profiler information inclusion)],
+  [AC_MSG_RESULT(compile optimization enabled)
+  ppArith_CFLAGS="${ppArith_CFLAGS} -g -pg"
+  ppArith_LDFLAGS="${ppArith_LDFLAGS} -pg -Wl,--start-group -Wl,-Bstatic"]
+  )
+   
+AC_SUBST([ppArith_CFLAGS])
+AC_SUBST([ppArith_LDFLAGS])
+
+AC_CONFIG_FILES([
+  Makefile
+  src/Makefile
+])
+AC_OUTPUT
Index: /trunk/ppArith/src/.cvsignore
===================================================================
--- /trunk/ppArith/src/.cvsignore	(revision 8479)
+++ /trunk/ppArith/src/.cvsignore	(revision 8479)
@@ -0,0 +1,4 @@
+Makefile
+Makefile.in
+ppArith
+.deps
Index: /trunk/ppArith/src/Makefile.am
===================================================================
--- /trunk/ppArith/src/Makefile.am	(revision 8479)
+++ /trunk/ppArith/src/Makefile.am	(revision 8479)
@@ -0,0 +1,23 @@
+bin_PROGRAMS = ppArith
+
+ppArith_CFLAGS += $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
+ppArith_LDFLAGS += $(PSMODULE_LIBS) $(PSLIB_LIBS) -Wl,-Bdynamic
+
+ppArith_SOURCES =		\
+	ppArith.c		\
+	ppArithData.c		\
+	ppArithLoop.c		\
+	ppArithSetup.c
+
+noinst_HEADERS =		\
+	ppArith.h		\
+	ppArithData.h
+
+
+CLEANFILES = *~
+
+clean-local:
+	-rm -f TAGS
+# Tags for emacs
+tags:
+	etags `find . -name \*.[ch] -print`
Index: /trunk/ppArith/src/ppArith.c
===================================================================
--- /trunk/ppArith/src/ppArith.c	(revision 8479)
+++ /trunk/ppArith/src/ppArith.c	(revision 8479)
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+
+#include "ppArith.h"
+
+int main(int argc, char *argv[])
+{
+    psLibInit(NULL);
+    psTimerStart(TIMERNAME);
+    psMemSetThreadSafety(false);
+
+    // Parse the configuration and arguments
+    pmConfig *config = pmConfigRead(&argc, argv);
+
+    // Get the options, open the files
+    ppArithData *data = ppArithSetup(config);
+
+    // Go through the FPA and do the hard work
+    ppArithLoop(data, config);
+
+    psFree(data);
+    psFree(config);
+    pmConceptsDone();
+    pmConfigDone();
+    psLibFinalize();
+
+    return EXIT_SUCCESS;
+}
Index: /trunk/ppArith/src/ppArith.h
===================================================================
--- /trunk/ppArith/src/ppArith.h	(revision 8479)
+++ /trunk/ppArith/src/ppArith.h	(revision 8479)
@@ -0,0 +1,21 @@
+#ifndef PP_ARITH_H
+#define PP_ARITH_H
+
+#define RECIPENAME "PPARITH"
+#define TIMERNAME "PPARITH"
+#define INPUTNAME "PPARITH.INPUT"
+#define OUTPUTNAME "PPARITH.OUTPUT"
+
+#include <psmodules.h>
+#include "ppArithData.h"
+
+// Set up the options and input/output files
+ppArithData *ppArithSetup(pmConfig *config // Configuration
+    );
+
+// Loop over the input image and do all the hard work
+void ppArithLoop(ppArithData *data,       // The data
+                 pmConfig *config        // Configuration
+    );
+
+#endif
Index: /trunk/ppArith/src/ppArithData.c
===================================================================
--- /trunk/ppArith/src/ppArithData.c	(revision 8479)
+++ /trunk/ppArith/src/ppArithData.c	(revision 8479)
@@ -0,0 +1,27 @@
+#include <stdio.h>
+#include <pslib.h>
+
+#include "ppArithData.h"
+
+static void arithDataFree(ppArithData *data // Data to free
+    )
+{
+    // Nothing to free; this function is just for identification purposes
+    return;
+}
+
+
+ppArithData *ppArithDataAlloc(void)
+{
+    ppArithData *data = psAlloc(sizeof(ppArithData)); // Newly allocated data
+    psMemSetDeallocator(data, (psFreeFunc)arithDataFree);
+
+    data->input1 = NULL;
+    data->input2 = NULL;
+    data->constant = NAN;
+    data->operation = NULL;
+    data->output = NULL;
+
+    return data;
+}
+
Index: /trunk/ppArith/src/ppArithData.h
===================================================================
--- /trunk/ppArith/src/ppArithData.h	(revision 8479)
+++ /trunk/ppArith/src/ppArithData.h	(revision 8479)
@@ -0,0 +1,18 @@
+#ifndef PP_NORM_DATA_H
+#define PP_NORM_DATA_H
+
+#include <psmodules.h>
+
+// Options for processing
+typedef struct {
+    pmFPAfile *input1;                  // First input
+    pmFPAfile *input2;                  // Second input
+    float constant;                     // A constant value
+    const char *operation;              // Operation to perform
+    pmFPAfile *output;                  // FPA file for output
+} ppArithData;
+
+// Allocator
+ppArithData *ppArithDataAlloc(void);
+
+#endif
Index: /trunk/ppArith/src/ppArithLoop.c
===================================================================
--- /trunk/ppArith/src/ppArithLoop.c	(revision 8479)
+++ /trunk/ppArith/src/ppArithLoop.c	(revision 8479)
@@ -0,0 +1,100 @@
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <pslib.h>
+#include <psmodules.h>
+
+#include "ppArith.h"
+
+
+void ppArithLoop(ppArithData *data,       // The data
+                 pmConfig *config        // Configuration
+    )
+{
+    bool mdok;                          // Status of MD lookup
+    pmFPAfile *input1 = psMetadataLookupPtr(&mdok, config->files, INPUTNAME); // Input FPA file
+    if (!input1 || !mdok) {
+        psAbort(__func__, "Should never get here: I'm sure I saved it.\n");
+    }
+
+    // Iterate through the FPA
+    pmFPAview *view = pmFPAviewAlloc(0);// View of FPA
+    if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
+        psError(PS_ERR_IO, false, "Unable to check file I/O.\n");
+        goto done;
+    }
+    pmChip *chip;                       // Chip, from iteration
+    while ((chip = pmFPAviewNextChip(view, input1->fpa, 1))) {
+        if (!chip->file_exists) {
+            continue;
+        }
+        const char *chipName = psMetadataLookupStr(NULL, chip->concepts, "CHIP.NAME"); // Name of chip
+        if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) {
+            psError(PS_ERR_IO, false, "Unable to check file I/O at chip %s.\n", chipName);
+            goto done;
+        }
+        pmCell *cell;                   // Cell, from iteration
+        while ((cell = pmFPAviewNextCell(view, input1->fpa, 1))) {
+            if (!cell->file_exists) {
+                continue;
+            }
+            const char *cellName = psMetadataLookupStr(NULL, cell->concepts, "CELL.NAME"); // Name of cell
+            if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
+                psError(PS_ERR_IO, false, "Unable to check file I/O at chip %s, cell %s.\n",
+                        chipName, cellName);
+                goto done;
+            }
+
+            pmReadout *readout;         // Readout, from iteration
+            for (int roNum = 0; (readout = pmFPAviewNextReadout(view, input1->fpa, 1)); roNum++) {
+                if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
+                    psError(PS_ERR_IO, false, "Unable to check file I/O at chip %s, cell %s, readout %d.\n",
+                            chipName, cellName, roNum);
+                    goto done;
+                }
+
+                // Perform the operations
+                psBinaryOp(readout->image, readout->image, data->operation,
+                           psScalarAlloc(data->constant, PS_TYPE_F32));
+
+                if (psListLength(readout->bias) > 0) {
+                    psListIterator *iter = psListIteratorAlloc(readout->bias, PS_LIST_HEAD, false);
+                    psImage *bias;      // Bias image, from iteration
+                    while ((bias = psListGetAndIncrement(iter))) {
+                        psBinaryOp(bias, bias, data->operation, psScalarAlloc(data->constant, PS_TYPE_F32));
+                    }
+                    psFree(iter);
+                }
+
+                if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) {
+                    psError(PS_ERR_IO, false, "Unable to check file I/O at chip %s, cell %s, readout %d.\n",
+                            chipName, cellName, roNum);
+                    goto done;
+                }
+
+                pmReadoutFreeData(readout);
+            }
+
+            if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) {
+                psError(PS_ERR_IO, false, "Unable to check file I/O at chip %s, cell %s.\n",
+                        chipName, cellName);
+                goto done;
+            }
+            pmCellFreeData(cell);
+        }
+        if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) {
+            psError(PS_ERR_IO, false, "Unable to check file I/O at chip %s.\n", chipName);
+            goto done;
+        }
+        pmChipFreeData(chip);
+    }
+    if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) {
+        psError(PS_ERR_IO, false, "Unable to check file I/O.\n");
+        goto done;
+    }
+    pmFPAFreeData(input1->fpa);
+
+done:
+    psFree(view);
+    return;
+}
Index: /trunk/ppArith/src/ppArithSetup.c
===================================================================
--- /trunk/ppArith/src/ppArithSetup.c	(revision 8479)
+++ /trunk/ppArith/src/ppArithSetup.c	(revision 8479)
@@ -0,0 +1,124 @@
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+#include <string.h>
+
+#include "ppArith.h"
+#include "ppArithData.h"
+
+// Print usage information and die
+static void usageAndDie(pmConfig *config      // Configuration (contains the arguments list)
+    )
+{
+    printf("Normalize the input FPA.\n\n"
+           "Usage:\n"
+           "\t%s -file1 INPUT1.fits -op OP -file2 INPUT2.fits -out OUTPUT\n"
+           "OR\n"
+           "\t%s -file1 INPUT1.fits -op OP -constant CONSTANT -out OUTPUT\n"
+           "\n", config->argv[0], config->argv[0]);
+    psArgumentHelp(config->arguments);
+    psFree(config);
+    psLibFinalize();
+    pmConceptsDone();
+    pmConfigDone();
+    exit(EXIT_FAILURE);
+}
+
+ppArithData *ppArithSetup(pmConfig *config // Configuration
+    )
+{
+    // Setup and parse command-line arguments
+    psMetadata *arguments = config->arguments; // Arguments
+    psMetadataAddStr(arguments, PS_LIST_TAIL, "-op", 0, "Operation to apply", NULL);
+    psMetadataAddF32(arguments, PS_LIST_TAIL, "-constant", 0, "Constant", NAN);
+    psMetadataAddStr(arguments, PS_LIST_TAIL, "-out", 0, "Output", NULL);
+
+    // No command-line arguments: print the help
+    if (*config->argc == 1) {
+        usageAndDie(config);
+    }
+
+    // Get input files
+    if (!pmConfigFileSetsMD(arguments, config, "INPUT1", "-file1", "-list1")) {
+        psError(PS_ERR_IO, false, "Unable to open input files #1.\n");
+        usageAndDie(config);
+    }
+
+    // If no constant, look for a second file
+    if (!psMetadataLookup(arguments, "-constant")) {
+        if (!pmConfigFileSetsMD(arguments, config, "INPUT2", "-file2", "-list2")) {
+            psError(PS_ERR_IO, false, "Unable to open input files #2.\n");
+            usageAndDie(config);
+        }
+    }
+
+    if (!psArgumentParse(arguments, config->argc, config->argv)) {
+        printf("Unable to parse command-line arguments.\n\n");
+        usageAndDie(config);
+    }
+
+    // Check for mandatory arguments
+    if (!psMetadataLookup(arguments, "-op")) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "No operation specified.\n");
+        usageAndDie(config);
+    }
+    const char *outName = psMetadataLookupStr(NULL, arguments, "-out");
+    if (!outName || strlen(outName) == 0) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "No output specified.\n");
+        usageAndDie(config);
+    }
+    psMetadataAddStr(config->arguments, PS_LIST_TAIL, "OUTPUT", 0, "Name of the output image", outName);
+
+
+    // Now process what we've got
+    ppArithData *data = ppArithDataAlloc(); // The data
+
+    // Read the camera
+    bool status = false;                // Status of function calls
+    data->input1 = pmFPAfileDefineFromArgs(&status, config, INPUTNAME, "INPUT1");
+    if (!status) {
+        psError(PS_ERR_IO, false, "Failed to build FPA from %s.\n", INPUTNAME);
+        goto die;
+    }
+
+    if (psMetadataLookup(arguments, "INPUT2")) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Binary operation with two files is not yet supported.\n");
+        goto die;
+
+        data->input2 = pmFPAfileDefineFromArgs(&status, config, INPUTNAME, "INPUT2");
+        if (!status) {
+            psError(PS_ERR_IO, false, "Failed to build FPA from %s.\n", INPUTNAME);
+            goto die;
+        }
+    }
+
+    pmFPAfile *output = pmFPAfileDefineOutput(config, data->input1->fpa, OUTPUTNAME);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "Failed to build output from %s.\n", OUTPUTNAME);
+        goto die;
+    }
+
+    data->operation = psMetadataLookupStr(NULL, arguments, "-op"); // Operation to perform
+    if (strcmp(data->operation, "+") &&
+        strcmp(data->operation, "-") &&
+        strcmp(data->operation, "*") &&
+        strcmp(data->operation, "/")) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unknown operation: %s\n", data->operation);
+        goto die;
+    }
+
+    if (!data->input2) {
+        data->constant = psMetadataLookupF32(NULL, arguments, "-constant");
+    }
+
+    return data;
+
+    // Common path for error conditions: clean up and exit.
+die:
+    psFree(config);
+    psFree(data);
+    pmConceptsDone();
+    pmConfigDone();
+    psLibFinalize();
+    exit(EXIT_FAILURE);
+}
