Index: /trunk/ppNorm/configure.ac
===================================================================
--- /trunk/ppNorm/configure.ac	(revision 8395)
+++ /trunk/ppNorm/configure.ac	(revision 8396)
@@ -23,6 +23,6 @@
 )
 
-ppNorm_CFLAGS="-Wall -Werror -std=c99"
-ppNorm_LDFLAGS=""
+ppNormCalc_CFLAGS="-Wall -Werror -std=c99"
+ppNormCalc_LDFLAGS=""
                                                                                 
 dnl handle debug building
@@ -49,10 +49,10 @@
   [AS_HELP_STRING(--enable-profile,enable compiler profiler information inclusion)],
   [AC_MSG_RESULT(compile optimization enabled)
-  ppNorm_CFLAGS="${ppNorm_CFLAGS} -g -pg"
-  ppNorm_LDFLAGS="${ppNorm_LDFLAGS} -pg -Wl,--start-group -Wl,-Bstatic"]
+  ppNormCalc_CFLAGS="${ppNormCalc_CFLAGS} -g -pg"
+  ppNormCalc_LDFLAGS="${ppNormCalc_LDFLAGS} -pg -Wl,--start-group -Wl,-Bstatic"]
   )
    
-AC_SUBST([ppNorm_CFLAGS])
-AC_SUBST([ppNorm_LDFLAGS])
+AC_SUBST([ppNormCalc_CFLAGS])
+AC_SUBST([ppNormCalc_LDFLAGS])
 
 AC_CONFIG_FILES([
Index: /trunk/ppNorm/src/Makefile.am
===================================================================
--- /trunk/ppNorm/src/Makefile.am	(revision 8395)
+++ /trunk/ppNorm/src/Makefile.am	(revision 8396)
@@ -1,16 +1,11 @@
-bin_PROGRAMS = ppNorm
+bin_PROGRAMS = ppNormCalc
 
-ppNorm_CFLAGS += $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
-ppNorm_LDFLAGS += $(PSMODULE_LIBS) $(PSLIB_LIBS) -Wl,-Bdynamic
+ppNormCalc_CFLAGS += $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
+ppNormCalc_LDFLAGS += $(PSMODULE_LIBS) $(PSLIB_LIBS) -Wl,-Bdynamic
 
-ppNorm_SOURCES =		\
-	ppNorm.c		\
-	ppNormData.c		\
-	ppNormLoop.c		\
-	ppNormSetup.c
+ppNormCalc_SOURCES =		\
+	ppNormCalc.c
 
-noinst_HEADERS =		\
-	ppNormData.h		\
-	ppNorm.h
+noinst_HEADERS =
 
 CLEANFILES = *~
Index: /trunk/ppNorm/src/ppNormCalc.c
===================================================================
--- /trunk/ppNorm/src/ppNormCalc.c	(revision 8396)
+++ /trunk/ppNorm/src/ppNormCalc.c	(revision 8396)
@@ -0,0 +1,108 @@
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+
+
+int main(int argc, char *argv[])
+{
+    psLibInit(NULL);
+    pmConfig *config = pmConfigRead(&argc, argv);
+    psFree(config);
+
+    if (argc != 2) {
+        printf("Calculate normalisation for flat fields.\n\n"
+               "Usage: %s IN.mdc\n\n"
+               "where IN.mdc is a metadata config file containing the background\n"
+               "value for each component of each exposure.\n\n", argv[0]);
+        exit(EXIT_FAILURE);
+    }
+
+    int badLines = 0;                   // Number of bad lines
+    psMetadata *exposures = psMetadataConfigParse(NULL, &badLines, argv[1], false); // Exposure statistics
+    if (badLines > 0) {
+        psLogMsg("ppNormCalc", PS_LOG_WARN, "%d bad lines found when reading %s\n", argv[1]);
+    }
+
+    // Get a list of all the components
+    psMetadata *components = psMetadataAlloc(); // Components of the exposures
+    psMetadataIterator *expIter = psMetadataIteratorAlloc(exposures, PS_LIST_HEAD, NULL); // Iterator
+    psMetadataItem *expItem;            // Item from iteration
+    while ((expItem = psMetadataGetAndIncrement(expIter))) {
+        if (expItem->type != PS_DATA_METADATA) {
+            psLogMsg("ppNormCalc", PS_LOG_WARN,
+                     "Metadata item %s is not of type METADATA --- ignored.\n",
+                     expItem->name);
+            continue;
+        }
+
+        // Inspect each component for this exposure; add it if we don't know about it
+        psMetadata *comps = expItem->data.V; // The components
+        psMetadataIterator *compsIter = psMetadataIteratorAlloc(comps, PS_LIST_HEAD, NULL); // Iterator
+        psMetadataItem *compsItem;      // Item from iteration
+        while ((compsItem = psMetadataGetAndIncrement(compsIter))) {
+            if (compsItem->type != PS_TYPE_F32) {
+                psLogMsg("ppNormCalc", PS_LOG_WARN,
+                         "Component %s within exposure %s is not of type F32 --- ignored.\n",
+                         compsItem->name, expItem->name);
+                continue;
+            }
+            if (!psMetadataLookup(components, compsItem->name)) {
+                psMetadataAddBool(components, PS_LIST_TAIL, compsItem->name, 0, NULL, true);
+            }
+        }
+        psFree(compsIter);
+    }
+
+    // Convert to a matrix
+    int numComps = psListLength(components->list); // Number of components
+    int numExps = psListLength(exposures->list); // Number of exposures
+    psImage *matrix = psImageAlloc(numComps, numExps, PS_TYPE_F32); // Matrix of backgrounds
+    psMetadataIteratorSet(expIter, PS_LIST_HEAD);
+    for (int expNum = 0; (expItem = psMetadataGetAndIncrement(expIter)); expNum++) {
+        if (expItem->type != PS_DATA_METADATA) {
+            continue;
+        }
+        psMetadata *comps = expItem->data.V; // The components
+        psMetadataIterator *compsIter = psMetadataIteratorAlloc(components, PS_LIST_HEAD, NULL); // Iterator
+        psMetadataItem *compsItem;      // Item from iteration
+        for (int compNum = 0; (compsItem = psMetadataGetAndIncrement(compsIter)); compNum++) {
+            matrix->data.F32[expNum][compNum] = psMetadataLookupF32(NULL, comps, compsItem->name);
+        }
+        psFree(compsIter);
+    }
+    psFree(expIter);
+
+    // Do the normalisation
+    psVector *gains = psVectorAlloc(numComps, PS_TYPE_F32); // Vector of gains for each component
+    gains->n = numComps;
+    psVectorInit(gains, 100.0);
+    if (!pmFlatNormalize(NULL, &gains, matrix)) {
+        psLogMsg("ppNormCalc", PS_LOG_ERROR, "Normalisation didn't converge.\n");
+        exit(EXIT_FAILURE);
+    }
+    psFree(matrix);
+
+
+    // Output a MDC format to stdout
+    psMetadata *outputMD = psMetadataAlloc(); // Output metadata
+    psMetadataIterator *compsIter = psMetadataIteratorAlloc(components, PS_LIST_HEAD, NULL); // Iterator
+    psMetadataItem *compsItem;          // Item from iteration
+    for (int compNum = 0; (compsItem = psMetadataGetAndIncrement(compsIter)); compNum++) {
+        psMetadataAddF32(outputMD, PS_LIST_TAIL, compsItem->name, 0, NULL, gains->data.F32[compNum]);
+    }
+    psFree(compsIter);
+    psString outputString = psMetadataConfigFormat(outputMD);
+    printf("%s", outputString);
+    psFree(outputString);
+    psFree(outputMD);
+
+    // Clean up
+    psFree(gains);
+    psFree(components);
+    psFree(exposures);
+
+    pmConfigDone();
+    psLibFinalize();
+
+    return EXIT_SUCCESS;
+}
