Index: trunk/ppViz/configure.ac
===================================================================
--- trunk/ppViz/configure.ac	(revision 27403)
+++ trunk/ppViz/configure.ac	(revision 27404)
@@ -35,4 +35,5 @@
   src/ppVizPSF/Makefile
   src/ppCoord/Makefile
+  src/ppVizPattern/Makefile
 ])
 
Index: trunk/ppViz/src/Makefile.am
===================================================================
--- trunk/ppViz/src/Makefile.am	(revision 27403)
+++ trunk/ppViz/src/Makefile.am	(revision 27404)
@@ -1,3 +1,3 @@
-SUBDIRS = ppVizPSF ppCoord
+SUBDIRS = ppVizPSF ppCoord ppVizPattern
 
 CLEANFILES = *.pyc *~ core core.*
Index: trunk/ppViz/src/ppVizPattern/Makefile.am
===================================================================
--- trunk/ppViz/src/ppVizPattern/Makefile.am	(revision 27404)
+++ trunk/ppViz/src/ppVizPattern/Makefile.am	(revision 27404)
@@ -0,0 +1,47 @@
+bin_PROGRAMS = ppVizPattern
+
+if HAVE_SVNVERSION
+PPVIZPATTERN_VERSION=`$(SVNVERSION) ..`
+else
+PPVIZPATTERN_VERSION="UNKNOWN"
+endif
+
+if HAVE_SVN
+PPVIZPATTERN_BRANCH=`$(SVN) info .. | $(SED) -n -e '/URL:/ h' -e '/Repository Root:/ { x; H; x; s|Repository Root: \(.*\)\nURL: \1\(.*\)|\2| ; s|^/|| ; s|/[a-zA-Z]*/src.*|| ; p }'`
+PPVIZPATTERN_SOURCE=`$(SVN) info | $(SED) -n -e 's/Repository UUID: // p'`
+else
+PPVIZPATTERN_BRANCH="UNKNOWN"
+PPVIZPATTERN_SOURCE="UNKNOWN"
+endif
+
+# Force recompilation of ppVizPatternVersion.c, since it gets the version information
+ppVizPatternVersion.c: ppVizPatternVersionDefinitions.h
+ppVizPatternVersionDefinitions.h: ppVizPatternVersionDefinitions.h.in FORCE
+	-$(RM) ppVizPatternVersionDefinitions.h
+	$(SED) -e "s|@PPVIZPATTERN_VERSION@|\"$(PPVIZPATTERN_VERSION)\"|" -e "s|@PPVIZPATTERN_BRANCH@|\"$(PPVIZPATTERN_BRANCH)\"|" -e "s|@PPVIZPATTERN_SOURCE@|\"$(PPVIZPATTERN_SOURCE)\"|" ppVizPatternVersionDefinitions.h.in > ppVizPatternVersionDefinitions.h
+FORCE: ;
+
+BUILT_SOURCES = ppVizPatternVersionDefinitions.h
+
+
+ppVizPattern_CPPFLAGS = $(PSLIB_CFLAGS) $(PSMODULE_CFLAGS) $(PPVIZPATTERN_CFLAGS)
+ppVizPattern_LDFLAGS  = $(PSLIB_LIBS)   $(PSMODULE_LIBS)   $(PPVIZPATTERN_LIBS)
+
+ppVizPattern_SOURCES =		\
+	ppVizPattern.c		\
+	ppVizPatternArguments.c	\
+	ppVizPatternCamera.c	\
+	ppVizPatternData.c		\
+	ppVizPatternLoop.c		\
+	ppVizPatternVersion.c            
+
+noinst_HEADERS = \
+	ppVizPattern.h
+
+clean-local:
+	-rm -f TAGS
+
+# Tags for emacs
+tags:
+	etags `find . -name \*.[ch] -print`
+
Index: trunk/ppViz/src/ppVizPattern/ppVizPattern.c
===================================================================
--- trunk/ppViz/src/ppVizPattern/ppVizPattern.c	(revision 27404)
+++ trunk/ppViz/src/ppVizPattern/ppVizPattern.c	(revision 27404)
@@ -0,0 +1,43 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+
+#include "ppVizPattern.h"
+
+int main(int argc, char *argv[])
+{
+    ppVizPatternVersionPrint();
+
+    ppVizPatternData *data = ppVizPatternDataInit(&argc, argv);
+    if (!data) {
+        psErrorStackPrint(stderr, "Unable to initialise.");
+        return PS_EXIT_CONFIG_ERROR;
+    }
+
+    if (!ppVizPatternArguments(data, argc, argv)) {
+        psErrorStackPrint(stderr, "Unable to parse arguments.");
+        psFree(data);
+        return PS_EXIT_CONFIG_ERROR;
+    }
+
+    if (!ppVizPatternCamera(data)) {
+        psErrorStackPrint(stderr, "Unable to parse camera configuration.");
+        psFree(data);
+        return PS_EXIT_CONFIG_ERROR;
+    }
+
+    if (!ppVizPatternLoop(data)) {
+        psErrorStackPrint(stderr, "Unable to process data.");
+        psFree(data);
+        return PS_EXIT_DATA_ERROR;
+    }
+
+    psFree(data);
+
+    return PS_EXIT_SUCCESS;
+}
+
Index: trunk/ppViz/src/ppVizPattern/ppVizPattern.h
===================================================================
--- trunk/ppViz/src/ppVizPattern/ppVizPattern.h	(revision 27404)
+++ trunk/ppViz/src/ppVizPattern/ppVizPattern.h	(revision 27404)
@@ -0,0 +1,41 @@
+#ifndef PP_VIZPSF_H
+#define PP_VIZPSF_H
+
+#include <pslib.h>
+#include <psmodules.h>
+
+#define PPVIZPATTERN_RECIPE "PPVIZPATTERN"      // Recipe name
+
+// Data for processing
+typedef struct {
+    psString patternName;               // Filename with pattern
+    psString outRoot;                   // Output root name
+    pmConfig *config;                   // Configuration
+} ppVizPatternData;
+
+/// Initialise data for processing
+ppVizPatternData *ppVizPatternDataInit(int *argc, char *argv[] // Command-line arguments
+    );
+
+/// Parse command-line arguments
+bool ppVizPatternArguments(ppVizPatternData *data, // Data for processing
+                        int argc, char *argv[] // Command-line arguments
+    );
+
+/// Parse camera configurations
+bool ppVizPatternCamera(ppVizPatternData *data // Data for processing
+    );
+
+/// Loop over input data, processing
+bool ppVizPatternLoop(ppVizPatternData *data // Data for processing
+    );
+
+/// Add version information to header
+bool ppVizPatternVersionHeader(
+    psMetadata *header                  // Header to supplement
+    );
+
+/// Print version information to stdout
+void ppVizPatternVersionPrint(void);
+
+#endif
Index: trunk/ppViz/src/ppVizPattern/ppVizPatternArguments.c
===================================================================
--- trunk/ppViz/src/ppVizPattern/ppVizPatternArguments.c	(revision 27404)
+++ trunk/ppViz/src/ppVizPattern/ppVizPatternArguments.c	(revision 27404)
@@ -0,0 +1,68 @@
+/** @file ppVizPatternArguments.c
+ *
+ *  @brief
+ *
+ *  @ingroup ppVizPattern
+ *
+ *  @author Paul Price
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <pslib.h>
+#include <psmodules.h>
+
+#include "ppVizPattern.h"
+
+/// Print usage information and die
+static void usage(const char *program,  // Name of the program
+                  psMetadata *arguments, // Command-line arguments
+                  ppVizPatternData *data   // Run-time data
+    )
+{
+    fprintf(stderr, "\nPan-STARRS pattern visualisation\n\n");
+    fprintf(stderr,
+            "Usage: %s -pattern PATTERN.ptn OUTPUT_ROOT\n\n",
+            program);
+    fprintf(stderr, "\n");
+    psArgumentHelp(arguments);
+    psFree(arguments);
+    psFree(data);
+
+    pmConfigDone();
+    psLibFinalize();
+
+    exit(PS_EXIT_CONFIG_ERROR);
+}
+
+
+bool ppVizPatternArguments(ppVizPatternData *data, int argc, char *argv[])
+{
+    assert(data);
+    assert(data->config);
+
+    psMetadata *arguments = psMetadataAlloc(); // Command-line arguments
+    psMetadataAddStr(arguments, PS_LIST_TAIL, "-pattern", 0, "Filename of pattern correction", NULL);
+    if (argc == 1 || !psArgumentParse(arguments, &argc, argv) || argc != 2) {
+        usage(argv[0], arguments, data);
+    }
+
+    data->patternName = psMemIncrRefCounter(psMetadataLookupStr(NULL, arguments, "-pattern"));
+    data->outRoot = psStringCopy(argv[1]);
+    psMetadataAddStr(data->config->arguments, PS_LIST_TAIL, "OUTPUT", 0, "Output root name", data->outRoot);
+
+    psTrace("ppVizPattern", 1, "Done reading command-line arguments\n");
+    psFree(arguments);
+
+    PS_ASSERT_STRING_NON_EMPTY(data->patternName, false);
+    PS_ASSERT_STRING_NON_EMPTY(data->outRoot, false);
+
+    return true;
+}
+
+
Index: trunk/ppViz/src/ppVizPattern/ppVizPatternCamera.c
===================================================================
--- trunk/ppViz/src/ppVizPattern/ppVizPatternCamera.c	(revision 27404)
+++ trunk/ppViz/src/ppVizPattern/ppVizPatternCamera.c	(revision 27404)
@@ -0,0 +1,59 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+
+#include "ppVizPattern.h"
+
+/// Add a single filename to the arguments as an array, so that it can be used with pmFPAfileBindFromArgs, etc
+static void fileArguments(const char *file, // The symbolic name for the file
+                          const char *name, // The name of the file
+                          const char *comment, // Description of the file
+                          pmConfig *config // Configuration
+    )
+{
+    psArray *files = psArrayAlloc(1); // Array with file names
+    files->data[0] = psStringCopy(name);
+    if (psMetadataLookup(config->arguments, file)) {
+        psMetadataRemoveKey(config->arguments, file);
+    }
+    psMetadataAddArray(config->arguments, PS_LIST_TAIL, file, 0, comment, files);
+    psFree(files);
+    return;
+}
+
+
+bool ppVizPatternCamera(ppVizPatternData *data // Run-time data
+    )
+{
+    bool status;                        // Status of file definition
+
+    fileArguments("PATTERN", data->patternName, "Input pattern", data->config);
+    pmFPAfile *input = pmFPAfileDefineFromArgs(&status, data->config, "PPVIZPATTERN.INPUT",
+                                               "PATTERN"); // File
+    if (!status || !input) {
+        psError(PS_ERR_IO, false, "Failed to build file from PPVIZPATTERN.INPUT");
+        return false;
+    }
+
+    pmFPAfile *output = pmFPAfileDefineOutput(data->config, input->fpa, "PPVIZPATTERN.OUTPUT");
+    if (!output) {
+        psError(psErrorCodeLast(), false, "Unable to define output.");
+        return false;
+    }
+    output->save = true;
+
+#if 0
+    // Now the camera has been determined, we can read the recipe
+    psMetadata *recipe = psMetadataLookupMetadata(NULL, data->config->recipes, PPVIZPATTERN_RECIPE); // Recipe
+    if (!recipe) {
+        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find recipe %s", PPVIZPATTERN_RECIPE);
+        return false;
+    }
+#endif
+
+    return true;
+}
Index: trunk/ppViz/src/ppVizPattern/ppVizPatternData.c
===================================================================
--- trunk/ppViz/src/ppVizPattern/ppVizPatternData.c	(revision 27404)
+++ trunk/ppViz/src/ppVizPattern/ppVizPatternData.c	(revision 27404)
@@ -0,0 +1,47 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+
+#include "ppVizPattern.h"
+
+// Destructor
+static void vizPatternDataFree(ppVizPatternData *data // Data to free
+    )
+{
+    psFree(data->patternName);
+    psFree(data->outRoot);
+    psFree(data->config);
+    return;
+}
+
+
+ppVizPatternData *ppVizPatternDataAlloc(void)
+{
+    ppVizPatternData *data = psAlloc(sizeof(ppVizPatternData)); // Processing data, to return
+    psMemSetDeallocator(data, (psFreeFunc)vizPatternDataFree);
+
+    data->patternName = NULL;
+    data->outRoot = NULL;
+    data->config = NULL;
+
+    return data;
+}
+
+
+ppVizPatternData *ppVizPatternDataInit(int *argc, char **argv)
+{
+    PS_ASSERT_PTR_NON_NULL(argc, NULL);
+    PS_ASSERT_PTR_NON_NULL(argv, NULL);
+
+    ppVizPatternData *data = ppVizPatternDataAlloc(); // Processing data, to return
+    data->config = pmConfigRead(argc, argv, PPVIZPATTERN_RECIPE);
+    if (!data->config) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to read configuration.");
+        return NULL;
+    }
+    return data;
+}
Index: trunk/ppViz/src/ppVizPattern/ppVizPatternLoop.c
===================================================================
--- trunk/ppViz/src/ppVizPattern/ppVizPatternLoop.c	(revision 27404)
+++ trunk/ppViz/src/ppVizPattern/ppVizPatternLoop.c	(revision 27404)
@@ -0,0 +1,122 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+
+#include "ppVizPattern.h"
+
+#define MASK_BAD 0xFFFF                 // Mask for bad pixels
+
+bool ppVizPatternLoop(ppVizPatternData *data // Run-time data
+    )
+{
+    pmConfig *config = data->config;                                        // Configuration data
+    pmFPAfile *input = pmFPAfileSelectSingle(config->files, "PPVIZPATTERN.INPUT", 0); // File with PSF
+
+    pmFPAview *view = pmFPAviewAlloc(0); // Pointer into FPA hierarchy
+    if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
+        return NULL;
+    }
+
+    pmChip *chip;                       // Chip from FPA
+    while ((chip = pmFPAviewNextChip(view, input->fpa, 1))) {
+        if (!chip->process || !chip->file_exists) {
+            continue;
+        }
+        if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
+            psError(PS_ERR_UNKNOWN, false, "Error loading data from files.");
+            return false;
+        }
+
+        pmCell *cell;                   // Cell from chip
+        while ((cell = pmFPAviewNextCell(view, input->fpa, 1))) {
+            if (!cell->process || !cell->file_exists) {
+                continue;
+            }
+            if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
+                psError(PS_ERR_UNKNOWN, false, "Error loading data from files.");
+                return false;
+            }
+
+            pmReadout *readout;         // Readout from cell
+            while ((readout = pmFPAviewNextReadout(view, input->fpa, 1))) {
+                if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
+                    psError(PS_ERR_UNKNOWN, false, "Error loading data from files.");
+                    return false;
+                }
+                if (!readout->data_exists) {
+                    continue;
+                }
+
+                int numCols = 0, numRows = 0; // Size of image
+
+                // Get size of image from concepts
+                if (numCols == 0 || numRows == 0) {
+                    numCols = psMetadataLookupS32(NULL, cell->concepts, "CELL.XSIZE");
+                    numRows = psMetadataLookupS32(NULL, cell->concepts, "CELL.YSIZE");
+                }
+
+                // Get size of image from TRIMSEC
+                if (numCols == 0 || numRows == 0) {
+                    psRegion *trimsec = psMetadataLookupPtr(NULL, cell->concepts, "CELL.TRIMSEC");
+                    numCols = trimsec->x1 - trimsec->x0;
+                    numRows = trimsec->y1 - trimsec->y0;
+                }
+
+                if (numCols <= 0 || numRows <= 0) {
+                    psError(PS_ERR_UNKNOWN, true, "Image size isn't set: %dx%d.", numCols, numRows);
+                    return false;
+                }
+
+                readout->image = psImageAlloc(numCols, numRows, PS_TYPE_F32);
+                psImageInit(readout->image, 0.0);
+
+                if (!pmPatternRowApply(readout, MASK_BAD) || !pmPatternCellApply(readout, MASK_BAD)) {
+                    psError(PS_ERR_UNKNOWN, false, "Unable to apply pattern correction.");
+                    return false;
+                }
+
+                readout->data_exists = true;
+                readout->parent->data_exists = true;
+                readout->parent->parent->data_exists = true;
+
+                pmHDU *hdu = pmHDUGetLowest(input->fpa, chip, cell); // HDU for readout
+                if (!hdu) {
+                    psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find HDU for data.");
+                    return false;
+                }
+                if (!hdu->header) {
+                    hdu->header = psMetadataAlloc();
+                }
+                ppVizPatternVersionHeader(hdu->header);
+
+
+                // Readout
+                if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
+                    psError(PS_ERR_UNKNOWN, false, "Error saving data to files.");
+                    return false;
+                }
+            }
+            // Cell
+            if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
+                psError(PS_ERR_UNKNOWN, false, "Error saving data to files.");
+                return false;
+            }
+        }
+        // Chip
+        if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
+            psError(PS_ERR_UNKNOWN, false, "Error saving data to files.");
+            return false;
+        }
+    }
+    // FPA
+    if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
+        psError(PS_ERR_UNKNOWN, false, "Error saving data to files.");
+        return false;
+    }
+
+    return true;
+}
Index: trunk/ppViz/src/ppVizPattern/ppVizPatternVersion.c
===================================================================
--- trunk/ppViz/src/ppVizPattern/ppVizPatternVersion.c	(revision 27404)
+++ trunk/ppViz/src/ppVizPattern/ppVizPatternVersion.c	(revision 27404)
@@ -0,0 +1,116 @@
+/** @file ppVizPatternVersion.c
+ *
+ *  @brief
+ *
+ *  @ingroup ppVizPattern
+ *
+ *  @author IfA
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-06 19:45:30 $
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+
+#include "ppVizPattern.h"
+#include "ppVizPatternVersionDefinitions.h"
+
+#ifndef PPVIZPATTERN_VERSION
+#error "PPVIZPATTERN_VERSION is not set"
+#endif
+#ifndef PPVIZPATTERN_BRANCH
+#error "PPVIZPATTERN_BRANCH is not set"
+#endif
+#ifndef PPVIZPATTERN_SOURCE
+#error "PPVIZPATTERN_SOURCE is not set"
+#endif
+
+psString ppVizPatternVersion(void)
+{
+    char *value = NULL;
+    psStringAppend(&value, "%s@%s", PPVIZPATTERN_BRANCH, PPVIZPATTERN_VERSION);
+    return value;
+}
+
+psString ppVizPatternSource(void)
+{
+    return psStringCopy(PPVIZPATTERN_SOURCE);
+}
+
+psString ppVizPatternVersionLong(void)
+{
+    psString version = ppVizPatternVersion();  // Version, to return
+    psString source = ppVizPatternSource();    // Source
+
+    psStringPrepend(&version, "ppVizPattern ");
+    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 ppVizPatternVersionHeader(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, "ppVizPattern at %s", timeString);
+    psFree(timeString);
+    psMetadataAddStr(header, PS_LIST_TAIL, "HISTORY", PS_META_DUPLICATE_OK, NULL, history);
+    psFree(history);
+
+    psLibVersionHeader(header);
+    psModulesVersionHeader(header);
+
+    psString version = ppVizPatternVersion(); // Software version
+    psString source  = ppVizPatternSource();  // Software source
+
+    psStringPrepend(&version, "ppVizPattern version: ");
+    psStringPrepend(&version, "ppVizPattern 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;
+}
+
+void ppVizPatternVersionPrint(void)
+{
+    psTime *time = psTimeGetNow(PS_TIME_TAI); // The time now
+    psString timeString = psTimeToISO(time); // The time in an ISO string
+    psFree(time);
+    psLogMsg("ppVizPattern", PS_LOG_INFO, "ppVizPattern at %s", timeString);
+    psFree(timeString);
+
+    psString pslib = psLibVersionLong();// psLib version
+    psString psmodules = psModulesVersionLong(); // psModules version
+    psString ppVizPattern = ppVizPatternVersionLong(); // ppVizPattern version
+
+    psLogMsg("ppVizPattern", PS_LOG_INFO, "%s", pslib);
+    psLogMsg("ppVizPattern", PS_LOG_INFO, "%s", psmodules);
+    psLogMsg("ppVizPattern", PS_LOG_INFO, "%s", ppVizPattern);
+
+    psFree(pslib);
+    psFree(psmodules);
+    psFree(ppVizPattern);
+
+    return;
+}
Index: trunk/ppViz/src/ppVizPattern/ppVizPatternVersionDefinitions.h.in
===================================================================
--- trunk/ppViz/src/ppVizPattern/ppVizPatternVersionDefinitions.h.in	(revision 27404)
+++ trunk/ppViz/src/ppVizPattern/ppVizPatternVersionDefinitions.h.in	(revision 27404)
@@ -0,0 +1,8 @@
+#ifndef PPVIZPATTERN_VERSION_DEFINITIONS_H
+#define PPVIZPATTERN_VERSION_DEFINITIONS_H
+
+#define PPVIZPATTERN_VERSION @PPVIZPATTERN_VERSION@ // SVN version
+#define PPVIZPATTERN_BRANCH  @PPVIZPATTERN_BRANCH@  // SVN branch
+#define PPVIZPATTERN_SOURCE  @PPVIZPATTERN_SOURCE@  // SVN source
+
+#endif
