Index: trunk/psModules/test/detrend/tap_pmFlatField.c
===================================================================
--- trunk/psModules/test/detrend/tap_pmFlatField.c	(revision 13879)
+++ trunk/psModules/test/detrend/tap_pmFlatField.c	(revision 15160)
@@ -1,30 +1,9 @@
-/** @file tst_pmFlatField.c
- *
- *  @brief Contains the tests for pmFlatField.c:
- *
- *    Test A - Divide input image by flat image
- *    Test B - Mask flat image data
- *    Test C - Mask flat image data starting with non-null mask
- *    Test E - Attempt to use null input image
- *    Test F - Attempt tp use null flat image
- *    Test G - Attempt to use input image bigger than flat image
- *    Test H - Attempt to use input image mask bigger than flat image
- *    Test I - Attempt to use offset greater than input image
- *    Test J - Attempt to use complex input image
- *    Test K - Attempt to use complex flat image
- *    Test L - Attempt to use non-equal input and flat image types
- *    Test M - Attempt to use non-mask type mask image
+/** @file tap_pmFlatField.c
  *
  * XXX: Added a mask argument to pmFlatField().  Must add tests.  For now, all
  * masks are NULL.
  *
- *  @author Ross Harman, MHPCC
- *
  *  XXX: I added the CELL.TRIMSEC region code but there are not tests for it.
  *
- *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2007-06-19 18:28:38 $
- *
- *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
  */
 #include <stdio.h>
@@ -34,167 +13,93 @@
 #include "tap.h"
 #include "pstap.h"
-#define BADFLAT 0
-
-#define CREATE_AND_SET_IMAGE(NAME,TYPE,VALUE,NROWS,NCOLS)                                                    \
-psImage *NAME = (psImage*)psImageAlloc(NCOLS,NROWS,PS_TYPE_##TYPE);                                          \
-for(int i=0; i<NAME->numRows; i++) {                                                                         \
-    for(int j=0; j<NAME->numCols; j++) {                                                                     \
-        NAME->data.TYPE[i][j] = VALUE;                                                                       \
-    }                                                                                                        \
+#define BADFLAT			0
+#define VERBOSE                 1
+#define ERR_TRACE_LEVEL         10
+#define TEST_NUM_ROWS		8
+#define TEST_NUM_COLS		8
+#define NUM_BIAS_DATA		2
+#define NUM_HDUS		8
+#define MISC_NUM                32
+#define MISC_NAME              "META00"
+#define CELL_ALLOC_NAME        "CellName"
+#define NUM_READOUTS            3
+#define BASE_IMAGE              10
+#define BASE_MASK               40
+#define BASE_WEIGHT             70
+
+/******************************************************************************
+generateSimpleReadout(): This function generates a pmReadout data structure and then
+populates its members with real data.
+ *****************************************************************************/
+pmReadout *generateSimpleReadout(pmCell *cell)
+{
+    pmReadout *readout = pmReadoutAlloc(cell);
+    readout->image = psImageAlloc(TEST_NUM_COLS, TEST_NUM_ROWS, PS_TYPE_F32);
+    for (int i=0;i<TEST_NUM_ROWS;i++) {
+        for (int j=0;j<TEST_NUM_COLS;j++) {
+            readout->image->data.F32[i][j] = (float) (i + j);
+        }
+    }
+    readout->mask = psImageAlloc(TEST_NUM_COLS, TEST_NUM_ROWS, PS_TYPE_U8);
+    readout->weight = psImageAlloc(TEST_NUM_COLS, TEST_NUM_ROWS, PS_TYPE_F32);
+    for (psS32 i = 0 ; i < NUM_BIAS_DATA ; i++) {
+        psImage *tmpImage = psImageAlloc(TEST_NUM_COLS, TEST_NUM_ROWS, PS_TYPE_F32);
+        psImageInit(tmpImage, (double) i);
+        psListAdd(readout->bias, PS_LIST_HEAD, tmpImage);
+        psFree(tmpImage);
+    }
+    psMetadataAddS32(readout->analysis, PS_LIST_HEAD, MISC_NAME, 0, NULL, MISC_NUM);
+    return(readout);
 }
 
-
-void testFlatField()
+/******************************************************************************
+generateSimpleCell(): This function generates a pmCell data structure and then
+populates its members with real data.
+ *****************************************************************************/
+pmCell *generateSimpleCell(pmChip *chip)
 {
-    // Test A - Divide input image by flat image
-    CREATE_AND_SET_IMAGE(inImage,F64,6.0,3,3)
-    pmReadout *inReadout = pmReadoutAlloc(NULL);
-    inReadout->image = inImage;
-    inReadout->row0 = 0;
-    inReadout->col0 = 0;
-    CREATE_AND_SET_IMAGE(inMask, U8, 0, 3,3);
-    inReadout->mask = inMask;
-    CREATE_AND_SET_IMAGE(flatImage1,F64,2.0,3,3)
-    pmReadout *flatReadout = pmReadoutAlloc(NULL);
-    flatReadout->row0 = 0;
-    flatReadout->col0 = 0;
-    flatReadout->image = flatImage1;
-    if ( !pmFlatField(inReadout, flatReadout, BADFLAT) ) {
-        psError(PS_ERR_UNKNOWN,true,"Test A - Returned false should be true");
-        return;
-    }
-
-
-    // Test B - Mask flat image data
-    CREATE_AND_SET_IMAGE(flatImage2,F64,0.0,3,3)
-    flatReadout->image = flatImage2;
-    if ( !pmFlatField(inReadout, flatReadout, BADFLAT) ) {
-        psError(PS_ERR_UNKNOWN,true,"Test B - Returned false should be true");
-        return;
-    }
-
-
-    // Test C - Mask flat image data starting with non-null mask
-    flatImage2->data.F64[0][0] = 3.0;
-    flatImage2->data.F64[0][1] = -3.0;
-    CREATE_AND_SET_IMAGE(mask1,U8,0,3,3);
-    psFree(inReadout->mask);
-    inReadout->mask = mask1;
-    if ( !pmFlatField(inReadout, flatReadout, BADFLAT) ) {
-        psError(PS_ERR_UNKNOWN,true,"Test C - Returned false should be true");
-        return;
-    }
-
-
-    // Test D - Attempt to use null flat readout
-    if( pmFlatField(inReadout, NULL, BADFLAT) ) {
-        psError(PS_ERR_UNKNOWN,true,"Test D - Returned true should be false");
-        return;
-    }
-
-
-
-    // Test E - Attempt to use null input image
-    psImage *temp = inReadout->image;
-    inReadout->image = NULL;
-    if ( pmFlatField(inReadout, flatReadout, BADFLAT) ) {
-        psError(PS_ERR_UNKNOWN,true,"Test E - Returned true should be false" );
-        return;
-    }
-    inReadout->image = temp    ;
-
-
-
-    // Test F - Attempt tp use null flat image
-    temp = flatReadout->image;
-    flatReadout->image = NULL;
-    if ( pmFlatField(inReadout, flatReadout, BADFLAT) ) {
-        psError(PS_ERR_UNKNOWN,true,"Test F - Returned true should be false" );
-        return;
-    }
-    flatReadout->image = temp;
-
-
-
-    // Test G - Attempt to use input image bigger than flat image
-    CREATE_AND_SET_IMAGE(smallFlat,F64,0.0,2,2);
-    temp = flatReadout->image;
-    flatReadout->image = smallFlat;
-    if ( pmFlatField(inReadout, flatReadout, BADFLAT) ) {
-        psError(PS_ERR_UNKNOWN,true,"Test G - Returned true should be false");
-        return;
-    }
-    flatReadout->image = temp;
-
-
-
-    // Test H - Attempt to use input image mask bigger than flat image
-    CREATE_AND_SET_IMAGE(largeMask,F64,0.0,5,5);
-    inReadout->mask = largeMask;
-    if ( pmFlatField(inReadout, flatReadout, BADFLAT) ) {
-        psError(PS_ERR_UNKNOWN,true,"Test H - Returned true should be false");
-        return;
-    }
-    inReadout->mask = mask1;
-
-
-
-    // Test I - Attempt to use offset greater than input image
-    *(int*)&inReadout->col0 = 50;
-    *(int*)&inReadout->row0 = 50;
-    if ( pmFlatField(inReadout, flatReadout, BADFLAT) ) {
-        psError(PS_ERR_UNKNOWN,true,"Test I - Returned true should be false");
-        return;
-    }
-    *(int*)&inReadout->col0 = 0;
-    *(int*)&inReadout->row0 = 0;
-
-
-
-//    // Test J - Attempt to use complex input image
-//    *(psElemType* ) & inReadout->image->type.type = PS_TYPE_C64;
-//    if ( pmFlatField(inReadout, flatReadout, BADFLAT) ) {
-//        psError(PS_ERR_UNKNOWN,true,"Test J - Returned true should be false");
-//        return;
-//    }
-//    *(psElemType* ) & inReadout->image->type.type = PS_TYPE_F64;
-
-
-
-//    // Test K - Attempt to use complex flat image
-//    *(psElemType* ) & flatReadout->image->type.type = PS_TYPE_C64;
-//    if ( pmFlatField(inReadout, flatReadout, BADFLAT) ) {
-//        psError(PS_ERR_UNKNOWN,true,"Test K - Returned ture should be false");
-//        return;
-//    }
-//    *(psElemType* ) & flatReadout->image->type.type = PS_TYPE_F64;
-
-
-    // Test L - Attempt to use non-equal input and flat image types
-    *(psElemType* ) & flatReadout->image->type.type = PS_TYPE_F32;
-    if ( pmFlatField(inReadout, flatReadout, BADFLAT) ) {
-        psError(PS_ERR_UNKNOWN,true,"Test L - Returned true should be false");
-        return;
-    }
-    *(psElemType* ) & flatReadout->image->type.type = PS_TYPE_F64;
-
-
-    // Test M - Attempt to use non-mask type mask image
-    *(psElemType* ) & inReadout->mask->type.type = PS_TYPE_F32;
-    if ( pmFlatField(inReadout, flatReadout, BADFLAT) ) {
-        psError(PS_ERR_UNKNOWN,true,"Test M - Returned true should be false");
-        return;
-    }
-    *(psElemType* ) & inReadout->mask->type.type = PS_TYPE_MASK;
-
-
-    // Free memory
-    psFree(inReadout);
-    psFree(flatReadout);
-    //psFree(inImage);
-    psFree(flatImage1);
-    //psFree(flatImage1);
-    psFree(smallFlat);
-    psFree(largeMask);
+    pmCell *cell = pmCellAlloc(chip, CELL_ALLOC_NAME);
+
+    psMetadataAddS32(cell->analysis, PS_LIST_HEAD, MISC_NAME, 0, NULL, MISC_NUM);
+    psMetadataAddS32(cell->concepts, PS_LIST_HEAD, MISC_NAME, 0, NULL, MISC_NUM);
+    psArrayRealloc(cell->readouts, NUM_READOUTS);
+    cell->hdu = pmHDUAlloc("cellExtName");
+    for (int i = 0 ; i < NUM_READOUTS ; i++) {
+        cell->readouts->data[i] = generateSimpleReadout(cell);
+    }
+
+    bool rc = pmConfigFileRead(&cell->hdu->format, "../camera/data/camera0/format0.config", "Camera format 0");
+    if (!rc) {
+        diag("pmConfigFileRead() was unsuccessful (from generateSimpleCell())");
+    }
+
+    cell->hdu->images = psArrayAlloc(NUM_HDUS);
+    cell->hdu->masks = psArrayAlloc(NUM_HDUS);
+    cell->hdu->weights = psArrayAlloc(NUM_HDUS);
+    for (int k = 0 ; k < NUM_HDUS ; k++) {
+        cell->hdu->images->data[k]  = psImageAlloc(TEST_NUM_COLS, TEST_NUM_ROWS, PS_TYPE_F32);
+        cell->hdu->masks->data[k]   = psImageAlloc(TEST_NUM_COLS, TEST_NUM_ROWS, PS_TYPE_MASK);
+        cell->hdu->weights->data[k] = psImageAlloc(TEST_NUM_COLS, TEST_NUM_ROWS, PS_TYPE_F32);
+        psImageInit(cell->hdu->images->data[k], (float) (BASE_IMAGE+k));
+        psImageInit(cell->hdu->masks->data[k], (psU8) (BASE_MASK+k));
+        psImageInit(cell->hdu->weights->data[k], (float) (BASE_WEIGHT+k));
+    }
+
+    //XXX: Should the region be set some other way?  Like through the various config files?
+//    psRegion *region = psRegionAlloc(0.0, TEST_NUM_COLS-1, 0.0, TEST_NUM_ROWS-1);
+    psRegion *region = psRegionAlloc(0.0, 0.0, 0.0, 0.0);
+    // You shouldn't have to remove the key from the metadata.  Find out how to simply change the key value.
+    psMetadataRemoveKey(cell->concepts, "CELL.TRIMSEC");
+    psMetadataAddPtr(cell->concepts, PS_LIST_TAIL|PS_META_REPLACE, "CELL.TRIMSEC", PS_DATA_REGION, "I am a region", region);
+    psFree(region);
+    return(cell);
+}
+
+void myFreeCell(pmCell *cell)
+{
+    for (int k = 0 ; k < cell->readouts->n ; k++) {
+        psFree(cell->readouts->data[k]);
+    }
+    psFree(cell);
 }
 
@@ -203,8 +108,241 @@
     psLogSetFormat("HLNM");
     psLogSetLevel(PS_LOG_INFO);
-    plan_tests(20);
-
-    testFlatField();
+    plan_tests(28);
+
+
+    // bool pmFlatField(pmReadout *in, pmReadout *flat, psMaskType badFlat)
+    // Test pmFlatField() with NULL input psReadout
+    {
+        psMemId id = psMemGetId();
+        pmReadout *in = generateSimpleReadout(NULL);
+        pmReadout *flat = generateSimpleReadout(NULL);
+        ok(!pmFlatField(NULL, flat, 0), "pmFlatField(NULL, flat, 0) returned FALSE");
+        psFree(in);
+        psFree(flat);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+
+    // bool pmFlatField(pmReadout *in, pmReadout *flat, psMaskType badFlat)
+    // Test pmFlatField() with NULL input psReadout->image
+    {
+        psMemId id = psMemGetId();
+        pmReadout *in = generateSimpleReadout(NULL);
+        psFree(in->image);
+        in->image = NULL;
+        pmReadout *flat = generateSimpleReadout(NULL);
+        ok(!pmFlatField(in, flat, 0), "pmFlatField(in, flat, 0) returned FALSE with NULL input psReadout->image");
+        psFree(in);
+        psFree(flat);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+    // bool pmFlatField(pmReadout *in, pmReadout *flat, psMaskType badFlat)
+    // Test pmFlatField() with NULL input psReadout->image
+    {
+        psMemId id = psMemGetId();
+        pmReadout *in = generateSimpleReadout(NULL);
+        psFree(in->image);
+        in->image = psImageAlloc(0, 0, PS_TYPE_F32);
+        pmReadout *flat = generateSimpleReadout(NULL);
+        ok(!pmFlatField(in, flat, 0), "pmFlatField(in, flat, 0) returned FALSE with empty input psReadout->image");
+        psFree(in);
+        psFree(flat);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+
+    // bool pmFlatField(pmReadout *in, pmReadout *flat, psMaskType badFlat)
+    // Test pmFlatField() with NULL input flat
+    {
+        psMemId id = psMemGetId();
+        pmReadout *in = generateSimpleReadout(NULL);
+        pmReadout *flat = generateSimpleReadout(NULL);
+        ok(!pmFlatField(in, NULL, 0), "pmFlatField(in, NULL, 0) returned FALSE");
+        psFree(in);
+        psFree(flat);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+
+    // bool pmFlatField(pmReadout *in, pmReadout *flat, psMaskType badFlat)
+    // Test pmFlatField() with NULL input flat->image
+    {
+        psMemId id = psMemGetId();
+        pmReadout *in = generateSimpleReadout(NULL);
+        pmReadout *flat = generateSimpleReadout(NULL);
+        psFree(flat->image);
+        flat->image = NULL;
+        ok(!pmFlatField(in, NULL, 0), "pmFlatField(in, flat, 0) returned FALSE with NULL input flat->image");
+        psFree(in);
+        psFree(flat);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+
+    // bool pmFlatField(pmReadout *in, pmReadout *flat, psMaskType badFlat)
+    // Test pmFlatField() with NULL input flat->image
+    {
+        psMemId id = psMemGetId();
+        pmReadout *in = generateSimpleReadout(NULL);
+        pmReadout *flat = generateSimpleReadout(NULL);
+        psFree(flat->image);
+        flat->image = psImageAlloc(0, 0, PS_TYPE_F32);
+        ok(!pmFlatField(in, NULL, 0), "pmFlatField(in, flat, 0) returned FALSE with empty input flat->image");
+        psFree(in);
+        psFree(flat);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+
+    // bool pmFlatField(pmReadout *in, pmReadout *flat, psMaskType badFlat)
+    // Test pmFlatField() with differing types of flat/in image
+    {
+        psMemId id = psMemGetId();
+        pmReadout *in = generateSimpleReadout(NULL);
+        pmReadout *flat = generateSimpleReadout(NULL);
+        psFree(flat->image);
+        flat->image = psImageAlloc(0, 0, PS_TYPE_F64);
+        ok(!pmFlatField(in, NULL, 0), "pmFlatField(in, flat, 0) returned FALSE with differing types of flat/in image");
+        psFree(in);
+        psFree(flat);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+
+    // Test pmFlatField() with input image larger than flat image
+    {
+        psMemId id = psMemGetId();
+        pmReadout *in = generateSimpleReadout(NULL);
+        pmReadout *flat = generateSimpleReadout(NULL);
+        psFree(flat->image);
+        flat->image = psImageAlloc(TEST_NUM_ROWS/2, TEST_NUM_COLS/2, PS_TYPE_F32);
+        ok(!pmFlatField(in, flat, 1), "pmFlatField(in, flat, 0) returned FALSE with input image larger than flat image");
+        psFree(in);
+        psFree(flat);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+
+    // Test pmFlatField() with input image and flat image of differing types
+    {
+        psMemId id = psMemGetId();
+        pmReadout *in = generateSimpleReadout(NULL);
+        pmReadout *flat = generateSimpleReadout(NULL);
+        psFree(flat->image);
+        flat->image = psImageAlloc(TEST_NUM_ROWS, TEST_NUM_COLS, PS_TYPE_F64);
+        ok(!pmFlatField(in, flat, 1), "pmFlatField(in, flat, 0) returned FALSE with input image and flat image of differing types");
+        psFree(in);
+        psFree(flat);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+
+    // Test pmFlatField() with input image mask smaller than input image
+    {
+        psMemId id = psMemGetId();
+        pmReadout *in = generateSimpleReadout(NULL);
+        pmReadout *flat = generateSimpleReadout(NULL);
+        psFree(in->mask);
+        in->mask = psImageAlloc(TEST_NUM_ROWS/2, TEST_NUM_COLS/2, PS_TYPE_MASK);
+        ok(!pmFlatField(in, flat, 1), "pmFlatField(in, flat, 0) returned FALSE with input image mask smaller than input image");
+        psFree(in);
+        psFree(flat);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+
+    // Test pmFlatField() with input image mask of incorrect type
+    {
+        psMemId id = psMemGetId();
+        pmReadout *in = generateSimpleReadout(NULL);
+        pmReadout *flat = generateSimpleReadout(NULL);
+        psFree(in->mask);
+        in->mask = psImageAlloc(TEST_NUM_ROWS, TEST_NUM_COLS, PS_TYPE_F32);
+        ok(!pmFlatField(in, flat, 1), "pmFlatField(in, flat, 0) returned FALSE with input image mask of incorrect type");
+        psFree(in);
+        psFree(flat);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+
+    // Test pmFlatField() with offset greater than input image
+    // XXX: Must rewrite with offsets coming from metadata
+    if (0) {
+        psMemId id = psMemGetId();
+        pmReadout *in = generateSimpleReadout(NULL);
+        pmReadout *flat = generateSimpleReadout(NULL);
+        *(int*)&in->col0 = 50;
+        *(int*)&in->row0 = 50;
+        ok(!pmFlatField(in, flat, 1), "pmFlatField(in, flat, 0) returned FALSE with offset greater than input image");
+        psFree(in);
+        psFree(flat);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+
+    // Test pmFlatField() with acceptable input data
+    // Set the flat field to 1
+    {
+        psMemId id = psMemGetId();
+        pmCell *cell = generateSimpleCell(NULL);
+        pmReadout *in = generateSimpleReadout(cell);
+        pmReadout *flat = generateSimpleReadout(cell);
+        psImageInit(in->image, 6.0);
+        psImageInit(in->mask, 0);
+        psImageInit(flat->image, 2.0);
+        ok(pmFlatField(in, flat, 1), "pmFlatField(in, flat, 0) returned TRUE with acceptable input data");
+        bool errorFlag = false;
+        for (int i = 0 ; i < in->image->numRows ; i++) {
+            for (int j = 0 ; j < in->image->numCols ; j++) {
+                if (in->image->data.F32[i][j] != 3.0) {
+                    if (VERBOSE) diag("ERROR: image[%d][%d] is %.2f, should be 3.0", i, j,
+                        in->image->data.F32[i][j]);
+		}
+                if (in->mask->data.PS_TYPE_MASK_DATA[i][j] != 0) {
+                    if (VERBOSE) diag("ERROR: mask[%d][%d] is %d, should be 0", i, j,
+                        in->image->data.PS_TYPE_MASK_DATA[i][j]);
+		}
+	    }
+	}
+        ok(!errorFlag, "pmFlatField() set the image data correctly");
+
+        psFree(in);
+        psFree(flat);
+        myFreeCell(cell);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+
+    // Test pmFlatField() with acceptable input data
+    // Set the flat field to -1
+    {
+        psMemId id = psMemGetId();
+        pmCell *cell = generateSimpleCell(NULL);
+        pmReadout *in = generateSimpleReadout(cell);
+        pmReadout *flat = generateSimpleReadout(cell);
+        psImageInit(in->image, 6.0);
+        psImageInit(in->mask, 0);
+        psImageInit(flat->image, -1.0);
+        ok(pmFlatField(in, flat, 1), "pmFlatField(in, flat, 0) returned TRUE with acceptable input data");
+        bool errorFlag = false;
+        for (int i = 0 ; i < in->image->numRows ; i++) {
+            for (int j = 0 ; j < in->image->numCols ; j++) {
+                if (!isnan(in->image->data.F32[i][j])) {
+                    if (VERBOSE) diag("ERROR: image[%d][%d] is %.2f, should be NAN", i, j,
+                        in->image->data.F32[i][j]);
+		}
+                if (in->mask->data.PS_TYPE_MASK_DATA[i][j] != 1) {
+                    if (VERBOSE) diag("ERROR: mask[%d][%d] is %d, should be 0", i, j,
+                        in->image->data.PS_TYPE_MASK_DATA[i][j]);
+		}
+	    }
+	}
+        ok(!errorFlag, "pmFlatField() set the image data correctly");
+
+        psFree(in);
+        psFree(flat);
+        myFreeCell(cell);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
 }
-
-
