Index: /trunk/psModules/src/detrend/pmFringeStats.c
===================================================================
--- /trunk/psModules/src/detrend/pmFringeStats.c	(revision 7561)
+++ /trunk/psModules/src/detrend/pmFringeStats.c	(revision 7562)
@@ -3,6 +3,6 @@
  *  @author Eugene Magnier, IfA
  *
- *  @version $Revision: 1.6 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2006-06-02 00:55:23 $
+ *  @version $Revision: 1.7 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-06-14 22:04:40 $
  *
  *  Copyright 2004 IfA
@@ -192,4 +192,192 @@
 }
 
+
+bool pmFringeStatsWriteFits(psFits *fits, const pmFringeStats *fringe, const char *extname)
+{
+    // Make sure the input is well-behaved
+    PS_ASSERT_PTR_NON_NULL(fits, false);
+    PS_ASSERT_PTR_NON_NULL(fringe, false);
+    pmFringeRegions *regions = fringe->regions; // The fringe regions
+    PS_ASSERT_PTR_NON_NULL(regions, false);
+    psVector *x = regions->x;           // The x positions
+    psVector *y = regions->y;           // The y positions
+    psVector *mask = regions->mask;     // The region mask
+    int numRows = x->n;                 // Number of rows in the table
+    PS_ASSERT_INT_POSITIVE(regions->nRequested, false);
+    PS_ASSERT_VECTOR_NON_NULL(x, false);
+    PS_ASSERT_VECTOR_NON_NULL(y, false);
+    PS_ASSERT_VECTOR_TYPE(x, PS_TYPE_F32, false);
+    PS_ASSERT_VECTOR_TYPE(y, PS_TYPE_F32, false);
+    PS_ASSERT_VECTOR_SIZE(y, numRows, false);
+    if (mask) {
+        PS_ASSERT_VECTOR_NON_NULL(mask, false);
+        PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_U8, false);
+        PS_ASSERT_VECTOR_SIZE(mask, numRows, false);
+    }
+    psVector *f = fringe->f;            // The fringe measurements
+    psVector *df = fringe->df;      // The fringe standard deviatiations
+    PS_ASSERT_VECTOR_NON_NULL(f, false);
+    PS_ASSERT_VECTOR_NON_NULL(df, false);
+    PS_ASSERT_VECTOR_TYPE(f, PS_TYPE_F32, false);
+    PS_ASSERT_VECTOR_TYPE(df, PS_TYPE_F32, false);
+    PS_ASSERT_VECTOR_SIZE(f, numRows, false);
+    PS_ASSERT_VECTOR_SIZE(df, numRows, false);
+
+    if (extname && strlen(extname) > 0) {
+        if (!psFitsMoveExtName(fits, extname)) {
+            psError(PS_ERR_IO, false, "Unable to move to extension %s\n", extname);
+            return false;
+        }
+    } else if (!psFitsMoveExtNum(fits, 0, false)) {
+        psError(PS_ERR_IO, false, "Unable to move to PHU\n");
+        return false;
+    }
+
+    // We need to write:
+    // Scalars: dX, dY, nX, nY
+    // Vectors: x, y, mask, f, df
+
+    psMetadata *scalars = psMetadataAlloc(); // Metadata to hold the scalars; will be the header
+    psMetadataAddF32(scalars, PS_LIST_TAIL, "PSFRNGDX", PS_META_REPLACE, "Median box half-width",
+                     regions->dX);
+    psMetadataAddF32(scalars, PS_LIST_TAIL, "PSFRNGDY", PS_META_REPLACE, "Median box half-height",
+                     regions->dY);
+    psMetadataAddF32(scalars, PS_LIST_TAIL, "PSFRNGNX", PS_META_REPLACE, "Large-scale smoothing in x",
+                     regions->nX);
+    psMetadataAddF32(scalars, PS_LIST_TAIL, "PSFRNGNY", PS_META_REPLACE, "Large-scale smoothing in y",
+                     regions->nY);
+
+    psArray *table = psArrayAlloc(numRows); // The table
+    // Translate the vectors into the required format for psFitsWriteTable()
+    for (long i = 0; i < numRows; i++) {
+        psMetadata *row = psMetadataAlloc();
+        psArraySet(table, i, row);
+        psMetadataAddF32(row, PS_LIST_TAIL, "x", PS_META_REPLACE, "Fringe position in x", x->data.F32[i]);
+        psMetadataAddF32(row, PS_LIST_TAIL, "y", PS_META_REPLACE, "Fringe position in y", y->data.F32[i]);
+        if (mask) {
+            psMetadataAddU8(row, PS_LIST_TAIL, "mask", PS_META_REPLACE, "Mask", mask->data.F32[i]);
+        } else {
+            psMetadataAddU8(row, PS_LIST_TAIL, "mask", PS_META_REPLACE, "Mask", 0);
+        }
+        psMetadataAddF32(row, PS_LIST_TAIL, "f", PS_META_REPLACE, "Fringe measurement", f->data.F32[i]);
+        psMetadataAddF32(row, PS_LIST_TAIL, "df", PS_META_REPLACE, "Fringe stdev", df->data.F32[i]);
+        psFree(row);                    // Drop reference
+    }
+
+    bool success;                       // Success of operation
+    if (!(success = psFitsWriteTable(fits, scalars, table, extname))) {
+        psError(PS_ERR_IO, false, "Unable to write fringe data to extension %s\n", extname);
+    }
+    psFree(scalars);
+    psFree(table);
+
+    return success;
+}
+
+pmFringeStats *pmFringeStatsReadFits(const psFits *fits, const char *extname)
+{
+    PS_ASSERT_PTR_NON_NULL(fits, NULL);
+
+    if (extname && strlen(extname) > 0) {
+        if (!psFitsMoveExtName(fits, extname)) {
+            psError(PS_ERR_IO, false, "Unable to move to extension %s\n", extname);
+            return NULL;
+        }
+    } else if (!psFitsMoveExtNum(fits, 0, false)) {
+        psError(PS_ERR_IO, false, "Unable to move to PHU\n");
+        return NULL;
+    }
+
+    psMetadata *header = psFitsReadHeader(NULL, fits); // The FITS header
+
+    // Need to retrieve the scalars: dX, dY, nX, nY
+    bool mdok = true;                   // Status of MD lookup
+    int dX = psMetadataLookupS32(&mdok, header, "PSFRNGDX");
+    if (!mdok || dX <= 0) {
+        psError(PS_ERR_IO, true, "Unable to find PSFRNGDX in header of extension %s.\n");
+        return NULL;
+    }
+    int dY = psMetadataLookupS32(&mdok, header, "PSFRNGDY");
+    if (!mdok || dY <= 0) {
+        psError(PS_ERR_IO, true, "Unable to find PSFRNGDY in header of extension %s.\n");
+        return NULL;
+    }
+    int nX = psMetadataLookupS32(&mdok, header, "PSFRNGNX");
+    if (!mdok || nX <= 0) {
+        psError(PS_ERR_IO, true, "Unable to find PSFRNGNX in header of extension %s.\n");
+        return NULL;
+    }
+    int nY = psMetadataLookupS32(&mdok, header, "PSFRNGNY");
+    if (!mdok || nY <= 0) {
+        psError(PS_ERR_IO, true, "Unable to find PSFRNGNY in header of extension %s.\n");
+        return NULL;
+    }
+
+    // Now the vectors: x, y, mask, f, df
+    psArray *table = psFitsReadTable(fits); // The table
+    long numRows = table->n;            // Number of rows
+
+    pmFringeRegions *regions = pmFringeRegionsAlloc(numRows, dX, dY, nX, nY); // The fringe regions
+    if (regions->x) {
+        psFree(regions->x);
+    }
+    if (regions->y) {
+        psFree(regions->y);
+    }
+    if (regions->mask) {
+        psFree(regions->mask);
+    }
+
+    psVector *x = psVectorAlloc(numRows, PS_TYPE_F32); // x position
+    psVector *y = psVectorAlloc(numRows, PS_TYPE_F32); // y position
+    psVector *mask = psVectorAlloc(numRows, PS_TYPE_U8); // mask
+    x->n = y->n = mask->n = numRows;
+    regions->x = x;
+    regions->y = y;
+    regions->mask = mask;
+    pmFringeStats *fringes = pmFringeStatsAlloc(regions); // The fringe measurements
+    psFree(regions);                    // Drop reference
+    psVector *f = fringes->f;           // fringe measurement
+    psVector *df = fringes->df;     // fringe stdev
+
+    // Translate the table into vectors
+    for (long i = 0; i < numRows; i++) {
+        psMetadata *row = table->data[i]; // Table row
+        x->data.F32[i] = psMetadataLookupF32(&mdok, row, "x");
+        if (!mdok) {
+            psError(PS_ERR_IO, true, "Unable to find x position.\n");
+            psFree(fringes);
+            return NULL;
+        }
+        y->data.F32[i] = psMetadataLookupF32(&mdok, row, "y");
+        if (!mdok) {
+            psError(PS_ERR_IO, true, "Unable to find y position.\n");
+            psFree(fringes);
+            return NULL;
+        }
+        mask->data.U8[i] = psMetadataLookupF32(&mdok, row, "mask");
+        if (!mdok) {
+            psError(PS_ERR_IO, true, "Unable to find mask value.\n");
+            psFree(fringes);
+            return NULL;
+        }
+        f->data.F32[i] = psMetadataLookupF32(&mdok, row, "f");
+        if (!mdok) {
+            psError(PS_ERR_IO, true, "Unable to find fringe measurement.\n");
+            psFree(fringes);
+            return NULL;
+        }
+        df->data.F32[i] = psMetadataLookupF32(&mdok, row, "df");
+        if (!mdok) {
+            psError(PS_ERR_IO, true, "Unable to find fringe stdev.\n");
+            psFree(fringes);
+            return NULL;
+        }
+    }
+
+    return fringes;
+}
+
+
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
 // pmFringeScale
Index: /trunk/psModules/src/detrend/pmFringeStats.h
===================================================================
--- /trunk/psModules/src/detrend/pmFringeStats.h	(revision 7561)
+++ /trunk/psModules/src/detrend/pmFringeStats.h	(revision 7562)
@@ -5,6 +5,6 @@
  *  @author Eugene Magnier, IfA
  *
- *  @version $Revision: 1.4 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2006-04-22 03:21:00 $
+ *  @version $Revision: 1.5 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-06-14 22:04:40 $
  *
  *  Copyright 2004 IfA, University of Hawaii
@@ -82,4 +82,14 @@
 );
 
+// Write the fringe stats for an image to a FITS table
+bool pmFringeStatsWriteFits(psFits *fits, // FITS file to which to write
+                            const pmFringeStats *fringe, // Fringe statistics to be written
+                            const char *extname // Extension name for table
+                           );
+
+// Read the fringe stats for an image from a FITS table
+pmFringeStats *pmFringeStatsReadFits(const psFits *fits, // FITS file from which to read
+                                     const char *extname // Extension name to read
+                                    );
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
