Index: trunk/ppViz/Makefile.am
===================================================================
--- trunk/ppViz/Makefile.am	(revision 26352)
+++ trunk/ppViz/Makefile.am	(revision 26352)
@@ -0,0 +1,3 @@
+SUBDIRS = src
+
+CLEANFILES = *.pyc *~ core core.*
Index: trunk/ppViz/autogen.sh
===================================================================
--- trunk/ppViz/autogen.sh	(revision 26352)
+++ trunk/ppViz/autogen.sh	(revision 26352)
@@ -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=ppViz
+TEST_TYPE=-f
+# change this to be a unique filename in the top level dir
+FILE=autogen.sh
+
+DIE=0
+
+LIBTOOLIZE=libtoolize
+ACLOCAL="aclocal $ACLOCAL_FLAGS"
+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/ppViz/configure.ac
===================================================================
--- trunk/ppViz/configure.ac	(revision 26352)
+++ trunk/ppViz/configure.ac	(revision 26352)
@@ -0,0 +1,38 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_PREREQ(2.61)
+
+AC_INIT([ppViz], [0.1.1], [ipp-support@ifa.hawaii.edu])
+AC_CONFIG_SRCDIR([src])
+
+AM_INIT_AUTOMAKE([1.6 foreign dist-bzip2])
+AM_CONFIG_HEADER([src/config.h])
+AM_MAINTAINER_MODE
+
+IPP_STDCFLAGS
+
+AC_LANG(C)
+AC_GNU_SOURCE
+AC_PROG_CC_C99
+AC_PROG_INSTALL
+AC_PROG_LIBTOOL
+AC_SYS_LARGEFILE
+
+PKG_CHECK_MODULES([PSLIB], [pslib >= 1.0.0])
+PKG_CHECK_MODULES([PSMODULE], [psmodules >= 1.0.0])
+
+dnl Set CFLAGS for build
+IPP_STDOPTS
+CFLAGS="${CFLAGS} -Wall -Werror"
+
+IPP_VERSION
+
+AC_SUBST([PPVIZ_CFLAGS])
+AC_SUBST([PPVIZ_LIBS])
+
+AC_CONFIG_FILES([
+  Makefile
+  src/Makefile
+  src/ppVizPSF/Makefile
+])
+
+AC_OUTPUT
Index: trunk/ppViz/src/Makefile.am
===================================================================
--- trunk/ppViz/src/Makefile.am	(revision 26352)
+++ trunk/ppViz/src/Makefile.am	(revision 26352)
@@ -0,0 +1,3 @@
+SUBDIRS = ppVizPSF
+
+CLEANFILES = *.pyc *~ core core.*
Index: trunk/ppViz/src/ppVizPSF/Makefile.am
===================================================================
--- trunk/ppViz/src/ppVizPSF/Makefile.am	(revision 26352)
+++ trunk/ppViz/src/ppVizPSF/Makefile.am	(revision 26352)
@@ -0,0 +1,47 @@
+bin_PROGRAMS = ppVizPSF
+
+if HAVE_SVNVERSION
+PPVIZPSF_VERSION=`$(SVNVERSION) ..`
+else
+PPVIZPSF_VERSION="UNKNOWN"
+endif
+
+if HAVE_SVN
+PPVIZPSF_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 }'`
+PPVIZPSF_SOURCE=`$(SVN) info | $(SED) -n -e 's/Repository UUID: // p'`
+else
+PPVIZPSF_BRANCH="UNKNOWN"
+PPVIZPSF_SOURCE="UNKNOWN"
+endif
+
+# Force recompilation of ppVizPSFVersion.c, since it gets the version information
+ppVizPSFVersion.c: ppVizPSFVersionDefinitions.h
+ppVizPSFVersionDefinitions.h: ppVizPSFVersionDefinitions.h.in FORCE
+	-$(RM) ppVizPSFVersionDefinitions.h
+	$(SED) -e "s|@PPVIZPSF_VERSION@|\"$(PPVIZPSF_VERSION)\"|" -e "s|@PPVIZPSF_BRANCH@|\"$(PPVIZPSF_BRANCH)\"|" -e "s|@PPVIZPSF_SOURCE@|\"$(PPVIZPSF_SOURCE)\"|" ppVizPSFVersionDefinitions.h.in > ppVizPSFVersionDefinitions.h
+FORCE: ;
+
+BUILT_SOURCES = ppVizPSFVersionDefinitions.h
+
+
+ppVizPSF_CPPFLAGS = $(PSLIB_CFLAGS) $(PSMODULE_CFLAGS) $(PPVIZPSF_CFLAGS)
+ppVizPSF_LDFLAGS  = $(PSLIB_LIBS)   $(PSMODULE_LIBS)   $(PPVIZPSF_LIBS)
+
+ppVizPSF_SOURCES =		\
+	ppVizPSF.c		\
+	ppVizPSFArguments.c	\
+	ppVizPSFCamera.c	\
+	ppVizPSFData.c		\
+	ppVizPSFLoop.c		\
+	ppVizPSFVersion.c            
+
+noinst_HEADERS = \
+	ppVizPSF.h
+
+clean-local:
+	-rm -f TAGS
+
+# Tags for emacs
+tags:
+	etags `find . -name \*.[ch] -print`
+
Index: trunk/ppViz/src/ppVizPSF/ppVizPSF.c
===================================================================
--- trunk/ppViz/src/ppVizPSF/ppVizPSF.c	(revision 26352)
+++ trunk/ppViz/src/ppVizPSF/ppVizPSF.c	(revision 26352)
@@ -0,0 +1,41 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+
+#include "ppVizPSF.h"
+
+int main(int argc, char *argv[])
+{
+    ppVizPSFData *data = ppVizPSFDataInit(&argc, argv);
+    if (!data) {
+        psErrorStackPrint(stderr, "Unable to initialise.");
+        return PS_EXIT_CONFIG_ERROR;
+    }
+
+    if (!ppVizPSFArguments(data, argc, argv)) {
+        psErrorStackPrint(stderr, "Unable to parse arguments.");
+        psFree(data);
+        return PS_EXIT_CONFIG_ERROR;
+    }
+
+    if (!ppVizPSFCamera(data)) {
+        psErrorStackPrint(stderr, "Unable to parse camera configuration.");
+        psFree(data);
+        return PS_EXIT_CONFIG_ERROR;
+    }
+
+    if (!ppVizPSFLoop(data)) {
+        psErrorStackPrint(stderr, "Unable to process data.");
+        psFree(data);
+        return PS_EXIT_DATA_ERROR;
+    }
+
+    psFree(data);
+
+    return PS_EXIT_SUCCESS;
+}
+
Index: trunk/ppViz/src/ppVizPSF/ppVizPSF.h
===================================================================
--- trunk/ppViz/src/ppVizPSF/ppVizPSF.h	(revision 26352)
+++ trunk/ppViz/src/ppVizPSF/ppVizPSF.h	(revision 26352)
@@ -0,0 +1,41 @@
+#ifndef PP_VIZPSF_H
+#define PP_VIZPSF_H
+
+#include <pslib.h>
+#include <psmodules.h>
+
+#define PPVIZPSF_RECIPE "PPVIZPSF"      // Recipe name
+
+// Data for processing
+typedef struct {
+    psString psfName;                   // Filename with PSF
+    psString sourcesName;               // Filename with sources
+    psString outRoot;                   // Output root name
+    float minFlux;                      // Minimum flux for sources
+    pmConfig *config;                   // Configuration
+} ppVizPSFData;
+
+/// Initialise data for processing
+ppVizPSFData *ppVizPSFDataInit(int *argc, char *argv[] // Command-line arguments
+    );
+
+/// Parse command-line arguments
+bool ppVizPSFArguments(ppVizPSFData *data, // Data for processing
+                        int argc, char *argv[] // Command-line arguments
+    );
+
+/// Parse camera configurations
+bool ppVizPSFCamera(ppVizPSFData *data // Data for processing
+    );
+
+/// Loop over input data, processing
+bool ppVizPSFLoop(ppVizPSFData *data // Data for processing
+    );
+
+/// Add version information to header
+bool ppVizPSFVersionHeader(
+    psMetadata *header                  // Header to supplement
+    );
+
+
+#endif
Index: trunk/ppViz/src/ppVizPSF/ppVizPSFArguments.c
===================================================================
--- trunk/ppViz/src/ppVizPSF/ppVizPSFArguments.c	(revision 26352)
+++ trunk/ppViz/src/ppVizPSF/ppVizPSFArguments.c	(revision 26352)
@@ -0,0 +1,70 @@
+/** @file ppVizPSFArguments.c
+ *
+ *  @brief
+ *
+ *  @ingroup ppVizPSF
+ *
+ *  @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 "ppVizPSF.h"
+
+/// Print usage information and die
+static void usage(const char *program,  // Name of the program
+                  psMetadata *arguments, // Command-line arguments
+                  ppVizPSFData *data   // Run-time data
+    )
+{
+    fprintf(stderr, "\nPan-STARRS PSF visualisation\n\n");
+    fprintf(stderr,
+            "Usage: %s -psf PSF.psf -sources SOURCES.cmf OUTPUT_ROOT\n\n",
+            program);
+    fprintf(stderr, "\n");
+    psArgumentHelp(arguments);
+    psFree(arguments);
+    psFree(data);
+
+    pmConfigDone();
+    psLibFinalize();
+
+    exit(PS_EXIT_CONFIG_ERROR);
+}
+
+
+bool ppVizPSFArguments(ppVizPSFData *data, int argc, char *argv[])
+{
+    assert(data);
+    assert(data->config);
+
+    psMetadata *arguments = psMetadataAlloc(); // Command-line arguments
+    psMetadataAddStr(arguments, PS_LIST_TAIL, "-psf", 0, "Filename of PSF", NULL);
+    psMetadataAddStr(arguments, PS_LIST_TAIL, "-sources", 0, "Filename of sources", NULL);
+    if (argc == 1 || !psArgumentParse(arguments, &argc, argv) || argc != 2) {
+        usage(argv[0], arguments, data);
+    }
+
+    data->psfName = psMemIncrRefCounter(psMetadataLookupStr(NULL, arguments, "-psf"));
+    data->sourcesName = psMemIncrRefCounter(psMetadataLookupStr(NULL, arguments, "-sources"));
+    data->outRoot = psStringCopy(argv[1]);
+
+    psTrace("ppVizPSF", 1, "Done reading command-line arguments\n");
+    psFree(arguments);
+
+    PS_ASSERT_STRING_NON_EMPTY(data->psfName, false);
+    PS_ASSERT_STRING_NON_EMPTY(data->sourcesName, false);
+    PS_ASSERT_STRING_NON_EMPTY(data->outRoot, false);
+
+    return true;
+}
+
+
Index: trunk/ppViz/src/ppVizPSF/ppVizPSFCamera.c
===================================================================
--- trunk/ppViz/src/ppVizPSF/ppVizPSFCamera.c	(revision 26352)
+++ trunk/ppViz/src/ppVizPSF/ppVizPSFCamera.c	(revision 26352)
@@ -0,0 +1,67 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+
+#include "ppVizPSF.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 ppVizPSFCamera(ppVizPSFData *data // Run-time data
+    )
+{
+    bool status;                        // Status of file definition
+
+    fileArguments("PSF", data->psfName, "Input PSF", data->config);
+    pmFPAfile *psf = pmFPAfileDefineFromArgs(&status, data->config, "PSPHOT.LOAD.PSF", "PSF"); // File
+    if (!status || !psf) {
+        psError(PS_ERR_IO, false, "Failed to build file from PSPHOT.LOAD.PSF");
+        return false;
+    }
+
+    fileArguments("SOURCES", data->psfName, "Input sources", data->config);
+    pmFPAfile *srcs = pmFPAfileDefineFromArgs(&status, data->config, "PSPHOT.LOAD.SOURCES", "SOURCES"); // File
+    if (!status || !srcs) {
+        psError(PS_ERR_IO, false, "Failed to build file from PSPHOT.LOAD.SOURCES");
+        return false;
+    }
+
+    if (!pmFPAfileDefineOutput(data->config, NULL, "PPVIZPSF.OUTPUT")) {
+        psError(psErrorCodeLast(), false, "Unable to define output.");
+        return false;
+    }
+
+    // Now the camera has been determined, we can read the recipe
+    psMetadata *recipe = psMetadataLookupMetadata(NULL, data->config->recipes, PPVIZPSF_RECIPE); // Recipe
+    if (!recipe) {
+        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find recipe %s", PPVIZPSF_RECIPE);
+        return false;
+    }
+
+    data->minFlux = psMetadataLookupF32(NULL, recipe, "MINFLUX"); // Minimum flux
+    if (!isfinite(data->minFlux) || data->minFlux <= 0) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unable to find legitimate value for MINFLUX");
+        return false;
+    }
+
+    return true;
+}
Index: trunk/ppViz/src/ppVizPSF/ppVizPSFData.c
===================================================================
--- trunk/ppViz/src/ppVizPSF/ppVizPSFData.c	(revision 26352)
+++ trunk/ppViz/src/ppVizPSF/ppVizPSFData.c	(revision 26352)
@@ -0,0 +1,46 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+
+#include "ppVizPSF.h"
+
+// Destructor
+static void vizPSFDataFree(ppVizPSFData *data // Data to free
+    )
+{
+    psFree(data->psfName);
+    psFree(data->sourcesName);
+    psFree(data->outRoot);
+    psFree(data->config);
+    return;
+}
+
+
+ppVizPSFData *ppVizPSFDataAlloc(void)
+{
+    ppVizPSFData *data = psAlloc(sizeof(ppVizPSFData)); // Processing data, to return
+    psMemSetDeallocator(data, (psFreeFunc)vizPSFDataFree);
+
+    data->psfName = NULL;
+    data->sourcesName = NULL;
+    data->outRoot = NULL;
+    data->config = NULL;
+    data->minFlux = NAN;
+
+    return data;
+}
+
+
+ppVizPSFData *ppVizPSFDataInit(int *argc, char **argv)
+{
+    PS_ASSERT_PTR_NON_NULL(argc, NULL);
+    PS_ASSERT_PTR_NON_NULL(argv, NULL);
+
+    ppVizPSFData *data = ppVizPSFDataAlloc(); // Processing data, to return
+    data->config = pmConfigRead(argc, argv, PPVIZPSF_RECIPE);
+    return data;
+}
Index: trunk/ppViz/src/ppVizPSF/ppVizPSFLoop.c
===================================================================
--- trunk/ppViz/src/ppVizPSF/ppVizPSFLoop.c	(revision 26352)
+++ trunk/ppViz/src/ppVizPSF/ppVizPSFLoop.c	(revision 26352)
@@ -0,0 +1,112 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+
+#include "ppVizPSF.h"
+
+
+bool ppVizPSFLoop(ppVizPSFData *data // Run-time data
+    )
+{
+    pmConfig *config = data->config;                                        // Configuration data
+    pmFPAfile *psfFile = pmFPAfileSelectSingle(config->files, "PSPHOT.LOAD.PSF", 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, psfFile->fpa, 1)) != NULL) {
+        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;
+        }
+
+        if (chip->cells->n != 1) {
+            psWarning("More than one cell present for chip %d", view->chip);
+        }
+
+        pmCell *cell;                   // Cell from chip
+        while ((cell = pmFPAviewNextCell(view, psfFile->fpa, 1)) != NULL) {
+            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;
+            }
+
+            if (cell->readouts->n != 1) {
+                psWarning("More than one readout present for chip %d, cell %d", view->chip, view->cell);
+            }
+
+            pmReadout *readout;         // Readout from cell
+            while ((readout = pmFPAviewNextReadout (view, psfFile->fpa, 1)) != NULL) {
+                if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
+                    psError(PS_ERR_UNKNOWN, false, "Error loading data from files.");
+                    return false;
+                }
+                if (!readout->data_exists) {
+                    continue;
+                }
+
+                psArray *sources = psMetadataLookupPtr(NULL, readout->analysis, "PSPHOT.SOURCES"); // Sources
+                pmPSF *psf = psMetadataLookupPtr(NULL, chip->analysis, "PSPHOT.PSF");              // PSF
+
+                int numCols = psf->fieldNx, numRows = psf->fieldNy; // Size of image
+                if (numCols <= 0 || numRows <= 0) {
+                    psError(PS_ERR_UNKNOWN, true, "Image size isn't set: %dx%d.", numCols, numRows);
+                    return false;
+                }
+
+                if (!pmReadoutFakeFromSources(readout, numCols, numRows, sources, 0, NULL, NULL, psf,
+                                              data->minFlux, 0, false, true)) {
+                    psError(PS_ERR_UNKNOWN, false, "Unable to generate fake readout.");
+                    return false;
+                }
+
+                pmHDU *hdu = pmHDUGetLowest(psfFile->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();
+                }
+                ppVizPSFVersionHeader(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/ppVizPSF/ppVizPSFVersion.c
===================================================================
--- trunk/ppViz/src/ppVizPSF/ppVizPSFVersion.c	(revision 26352)
+++ trunk/ppViz/src/ppVizPSF/ppVizPSFVersion.c	(revision 26352)
@@ -0,0 +1,116 @@
+/** @file ppVizPSFVersion.c
+ *
+ *  @brief
+ *
+ *  @ingroup ppVizPSF
+ *
+ *  @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 "ppVizPSF.h"
+#include "ppVizPSFVersionDefinitions.h"
+
+#ifndef PPVIZPSF_VERSION
+#error "PPVIZPSF_VERSION is not set"
+#endif
+#ifndef PPVIZPSF_BRANCH
+#error "PPVIZPSF_BRANCH is not set"
+#endif
+#ifndef PPVIZPSF_SOURCE
+#error "PPVIZPSF_SOURCE is not set"
+#endif
+
+psString ppVizPSFVersion(void)
+{
+    char *value = NULL;
+    psStringAppend(&value, "%s@%s", PPVIZPSF_BRANCH, PPVIZPSF_VERSION);
+    return value;
+}
+
+psString ppVizPSFSource(void)
+{
+    return psStringCopy(PPVIZPSF_SOURCE);
+}
+
+psString ppVizPSFVersionLong(void)
+{
+    psString version = ppVizPSFVersion();  // Version, to return
+    psString source = ppVizPSFSource();    // Source
+
+    psStringPrepend(&version, "ppVizPSF ");
+    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 ppVizPSFVersionHeader(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, "ppVizPSF 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 = ppVizPSFVersion(); // Software version
+    psString source  = ppVizPSFSource();  // Software source
+
+    psStringPrepend(&version, "ppVizPSF version: ");
+    psStringPrepend(&version, "ppVizPSF 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 ppVizPSFVersionPrint(void)
+{
+    psTime *time = psTimeGetNow(PS_TIME_TAI); // The time now
+    psString timeString = psTimeToISO(time); // The time in an ISO string
+    psFree(time);
+    psLogMsg("ppVizPSF", PS_LOG_INFO, "ppVizPSF at %s", timeString);
+    psFree(timeString);
+
+    psString pslib = psLibVersionLong();// psLib version
+    psString psmodules = psModulesVersionLong(); // psModules version
+    psString ppVizPSF = ppVizPSFVersionLong(); // ppVizPSF version
+
+    psLogMsg("ppVizPSF", PS_LOG_INFO, "%s", pslib);
+    psLogMsg("ppVizPSF", PS_LOG_INFO, "%s", psmodules);
+    psLogMsg("ppVizPSF", PS_LOG_INFO, "%s", ppVizPSF);
+
+    psFree(pslib);
+    psFree(psmodules);
+    psFree(ppVizPSF);
+
+    return;
+}
Index: trunk/ppViz/src/ppVizPSF/ppVizPSFVersionDefinitions.h.in
===================================================================
--- trunk/ppViz/src/ppVizPSF/ppVizPSFVersionDefinitions.h.in	(revision 26352)
+++ trunk/ppViz/src/ppVizPSF/ppVizPSFVersionDefinitions.h.in	(revision 26352)
@@ -0,0 +1,8 @@
+#ifndef PPVIZPSF_VERSION_DEFINITIONS_H
+#define PPVIZPSF_VERSION_DEFINITIONS_H
+
+#define PPVIZPSF_VERSION @PPVIZPSF_VERSION@ // SVN version
+#define PPVIZPSF_BRANCH  @PPVIZPSF_BRANCH@  // SVN branch
+#define PPVIZPSF_SOURCE  @PPVIZPSF_SOURCE@  // SVN source
+
+#endif
