Index: trunk/psModules/src/detrend/pmPatternIO.c
===================================================================
--- trunk/psModules/src/detrend/pmPatternIO.c	(revision 26923)
+++ trunk/psModules/src/detrend/pmPatternIO.c	(revision 41892)
@@ -8,4 +8,5 @@
 #include "pmFPAview.h"
 #include "pmFPAfile.h"
+#include "pmFPAUtils.h"
 #include "pmFPAfileFitsIO.h"
 #include "pmFPAHeader.h"
@@ -452,2 +453,109 @@
     return pmReadoutReadPattern(readout, file->fits);
 }
+
+/**************** PatternRowAmp(litude) I/O *************************/
+
+bool pmPatternRowAmpRead (const pmFPAview *view, pmFPAfile *file, const pmConfig *config)
+    {
+        // read the full model in one pass: require the level to be FPA
+        if (view->chip != -1) {
+            psError(PS_ERR_IO, false, "Pattern Row Amplitude must be read at the FPA level");
+            return false;
+        }
+
+        if (!pmPatternRowAmpReadFPA (file)) {
+            psError(PS_ERR_IO, false, "Failed to read Pattern Row Amplitude for fpa");
+            return false;
+        }
+        return true;
+    }
+
+// read in all chip-level Pattern Row Amplitude data for this FPA
+bool pmPatternRowAmpReadFPA (pmFPAfile *file) {
+
+    if (!pmPatternRowAmpReadChips (file)) {
+        psError(PS_ERR_IO, false, "Failed to read Pattern Row Amplitude for chips");
+        return false;
+    }
+
+    return true;
+}
+
+// read the set of tables, one for each chip
+bool pmPatternRowAmpReadChips (pmFPAfile *file) {
+
+    bool haveData, status;
+
+    // loop over the extensions
+    // for each extension, use the extname (eg, XY01.ptn) to assign to a chip
+
+    // move to the start of the file
+    haveData = psFitsMoveExtNum (file->fits, 1, false);
+    if (!haveData) {
+        psError(PS_ERR_IO, false, "Failed to read even the first extension?");
+        return false;
+    }
+
+    int nGood = 0;
+    int nTotal = 0;
+    while (haveData) {
+
+	// load the header
+	psMetadata *header = psFitsReadHeader(NULL, file->fits); // The FITS header
+	if (!header) psAbort("cannot read model header");
+
+	// load the full model in one shot
+	psArray *model = psFitsReadTable (file->fits);
+	if (!model) psAbort("cannot read model");
+	
+	// determine the chip:
+	char *extname = psMetadataLookupStr (&status, header, "EXTNAME");
+	psLogMsg ("psModules.detrend", 8, "read %ld rows from Pattern Row Amplitude file, extname %s\n", model->n, extname);
+	nTotal += model->n;
+
+	// I expect to find a name of the form: chipName.ptn (eg, XY01.ptn)
+	// where chipName like 'XY01'
+	psAssert (strlen(extname) == 8, "invalid extension %s", extname);
+	psAssert (extname[5] == 'p', "invalid extension %s", extname);
+	psAssert (extname[6] == 't', "invalid extension %s", extname);
+	psAssert (extname[7] == 'n', "invalid extension %s", extname);
+
+	char chipName[5];
+	strncpy (chipName, extname, 4);
+	chipName[4] = 0;
+
+	pmChip *chip = pmConceptsChipFromName (file->fpa, chipName);
+	if (!chip) psAbort ("invalid chip?");
+
+	// parse the model entries
+	for (int i = 0; i < model->n; i++) {
+	    psMetadata *row = model->data[i];
+	    psAssert (row, "missing model row");
+
+	    char *cellName = psMetadataLookupStr(&status, row, "CELL_NAME");
+	    if (!cellName) continue;
+
+	    float amplitude = psMetadataLookupF32(&status, row, "VALUE_MEDIAN");
+
+	    int cellNumber = pmChipFindCell (chip, cellName);
+	    psAssert ((cellNumber >=0) && (cellNumber < chip->cells->n), "invalid cell number");
+
+	    pmCell *cell = chip->cells->data[cellNumber];
+	    if (!cell) continue;
+
+	    psAssert (cell->analysis, "oops");
+
+	    psMetadataAddF32 (cell->analysis, PS_LIST_TAIL, "PTN.ROW.AMP", PS_META_REPLACE, "", amplitude);
+	    nGood ++;
+	}
+
+	psFree (model);
+	psFree (header);
+
+	// move to the next extension
+	haveData = psFitsMoveExtNum (file->fits, 1, true);
+    }
+    psLogMsg ("psModules.detrend", 4, "read %d of %d rows from Pattern Row Amplitude file\n", nGood, nTotal);
+
+    return true;
+}
