Index: /trunk/psModules/src/camera/pmFPAfile.c
===================================================================
--- /trunk/psModules/src/camera/pmFPAfile.c	(revision 19188)
+++ /trunk/psModules/src/camera/pmFPAfile.c	(revision 19189)
@@ -440,55 +440,58 @@
     PS_ASSERT_STRING_NON_EMPTY(type, PM_FPA_FILE_NONE);
 
-    if (!strcasecmp (type, "SX"))     {
+    if (!strcasecmp(type, "SX"))     {
         return PM_FPA_FILE_SX;
     }
-    if (!strcasecmp (type, "OBJ"))     {
+    if (!strcasecmp(type, "OBJ"))     {
         return PM_FPA_FILE_OBJ;
     }
-    if (!strcasecmp (type, "CMP"))     {
+    if (!strcasecmp(type, "CMP"))     {
         return PM_FPA_FILE_CMP;
     }
-    if (!strcasecmp (type, "CMF"))     {
+    if (!strcasecmp(type, "CMF"))     {
         return PM_FPA_FILE_CMF;
     }
-    if (!strcasecmp (type, "RAW"))     {
+    if (!strcasecmp(type, "RAW"))     {
         return PM_FPA_FILE_RAW;
     }
-    if (!strcasecmp (type, "IMAGE"))     {
+    if (!strcasecmp(type, "IMAGE"))     {
         return PM_FPA_FILE_IMAGE;
     }
-    if (!strcasecmp (type, "PSF"))     {
+    if (!strcasecmp(type, "PSF"))     {
         return PM_FPA_FILE_PSF;
     }
-    if (!strcasecmp (type, "JPEG"))     {
+    if (!strcasecmp(type, "JPEG"))     {
         return PM_FPA_FILE_JPEG;
     }
-    if (!strcasecmp (type, "KAPA"))     {
+    if (!strcasecmp(type, "KAPA"))     {
         return PM_FPA_FILE_KAPA;
     }
-    if (!strcasecmp (type, "MASK"))     {
+    if (!strcasecmp(type, "MASK"))     {
         return PM_FPA_FILE_MASK;
     }
-    if (!strcasecmp (type, "WEIGHT"))     {
+    if (!strcasecmp(type, "WEIGHT"))     {
         return PM_FPA_FILE_WEIGHT;
     }
-    if (!strcasecmp (type, "FRINGE")) {
+    if (!strcasecmp(type, "FRINGE")) {
         return PM_FPA_FILE_FRINGE;
     }
-    if (!strcasecmp (type, "DARK"))     {
+    if (!strcasecmp(type, "DARK"))     {
         return PM_FPA_FILE_DARK;
     }
-    if (!strcasecmp (type, "HEADER"))     {
+    if (!strcasecmp(type, "HEADER"))     {
         return PM_FPA_FILE_HEADER;
     }
     // deprecate this?
-    if (!strcasecmp (type, "ASTROM"))     {
+    if (!strcasecmp(type, "ASTROM"))     {
         return PM_FPA_FILE_ASTROM_MODEL;
     }
-    if (!strcasecmp (type, "ASTROM.MODEL"))     {
+    if (!strcasecmp(type, "ASTROM.MODEL"))     {
         return PM_FPA_FILE_ASTROM_MODEL;
     }
-    if (!strcasecmp (type, "ASTROM.REFSTARS"))     {
+    if (!strcasecmp(type, "ASTROM.REFSTARS"))     {
         return PM_FPA_FILE_ASTROM_REFSTARS;
+    }
+    if (!strcasecmp(type, "SUBKERNEL"))     {
+        return PM_FPA_FILE_SUBKERNEL;
     }
 
@@ -531,4 +534,6 @@
       case PM_FPA_FILE_ASTROM_REFSTARS:
         return ("ASTROM.REFSTARS");
+      case PM_FPA_FILE_SUBKERNEL:
+        return ("SUBKERNEL");
       default:
         return ("NONE");
Index: /trunk/psModules/src/camera/pmFPAfile.h
===================================================================
--- /trunk/psModules/src/camera/pmFPAfile.h	(revision 19188)
+++ /trunk/psModules/src/camera/pmFPAfile.h	(revision 19189)
@@ -4,6 +4,6 @@
  * @author EAM, IfA
  *
- * @version $Revision: 1.31 $ $Name: not supported by cvs2svn $
- * @date $Date: 2008-08-01 03:15:46 $
+ * @version $Revision: 1.32 $ $Name: not supported by cvs2svn $
+ * @date $Date: 2008-08-25 22:14:04 $
  * Copyright 2004-2005 Institute for Astronomy, University of Hawaii
  */
@@ -45,4 +45,5 @@
     PM_FPA_FILE_ASTROM_MODEL,
     PM_FPA_FILE_ASTROM_REFSTARS,
+    PM_FPA_FILE_SUBKERNEL,
 } pmFPAfileType;
 
Index: /trunk/psModules/src/camera/pmFPAfileIO.c
===================================================================
--- /trunk/psModules/src/camera/pmFPAfileIO.c	(revision 19188)
+++ /trunk/psModules/src/camera/pmFPAfileIO.c	(revision 19189)
@@ -40,4 +40,5 @@
 #include "pmSourcePlots.h"
 #include "pmFPAConstruct.h"
+#include "pmSubtractionIO.h"
 #include "pmConcepts.h"
 
@@ -188,4 +189,7 @@
         }
         break;
+      case PM_FPA_FILE_SUBKERNEL:
+        status = pmSubtractionReadKernels(view, file, config);
+        break;
       case PM_FPA_FILE_SX:
       case PM_FPA_FILE_RAW:
@@ -258,38 +262,39 @@
       case PM_FPA_FILE_FRINGE:
       case PM_FPA_FILE_DARK: {
-            // create FPA structure component based on view
-            psMetadata *format = file->format; // Camera format configuration
-            if (!format) {
-                format = config->format;
-            }
-
-            pmFPA *nameSource = file->src; // Source of FPA.OBS
-            if (!nameSource) {
-                nameSource = file->fpa;
-            }
-            bool mdok;                  // Status of MD lookup
-            const char *fpaObs = psMetadataLookupStr(&mdok, nameSource->concepts, "FPA.OBS"); // Obs. id
-
-            pmFPAAddSourceFromView(file->fpa, fpaObs, view, format);
-            psTrace ("psModules.camera", 5, "created fpa data elements for %s (%s) (%d:%d:%d)\n",
-                     file->name, file->name, view->chip, view->cell, view->readout);
-            break;
-    }
-    case PM_FPA_FILE_HEADER:
-      psAbort ("Create not defined for HEADER");
-      break;
-    case PM_FPA_FILE_SX:
-    case PM_FPA_FILE_RAW:
-    case PM_FPA_FILE_OBJ:
-    case PM_FPA_FILE_CMP:
-    case PM_FPA_FILE_CMF:
-    case PM_FPA_FILE_PSF:
-    case PM_FPA_FILE_ASTROM_MODEL:
-    case PM_FPA_FILE_ASTROM_REFSTARS:
-    case PM_FPA_FILE_JPEG:
-    case PM_FPA_FILE_KAPA:
-        break;
-
-    default:
+          // create FPA structure component based on view
+          psMetadata *format = file->format; // Camera format configuration
+          if (!format) {
+              format = config->format;
+          }
+
+          pmFPA *nameSource = file->src; // Source of FPA.OBS
+          if (!nameSource) {
+              nameSource = file->fpa;
+          }
+          bool mdok;                  // Status of MD lookup
+          const char *fpaObs = psMetadataLookupStr(&mdok, nameSource->concepts, "FPA.OBS"); // Obs. id
+
+          pmFPAAddSourceFromView(file->fpa, fpaObs, view, format);
+          psTrace ("psModules.camera", 5, "created fpa data elements for %s (%s) (%d:%d:%d)\n",
+                   file->name, file->name, view->chip, view->cell, view->readout);
+          break;
+      }
+      case PM_FPA_FILE_HEADER:
+        psAbort ("Create not defined for HEADER");
+        break;
+      case PM_FPA_FILE_SUBKERNEL:
+      case PM_FPA_FILE_SX:
+      case PM_FPA_FILE_RAW:
+      case PM_FPA_FILE_OBJ:
+      case PM_FPA_FILE_CMP:
+      case PM_FPA_FILE_CMF:
+      case PM_FPA_FILE_PSF:
+      case PM_FPA_FILE_ASTROM_MODEL:
+      case PM_FPA_FILE_ASTROM_REFSTARS:
+      case PM_FPA_FILE_JPEG:
+      case PM_FPA_FILE_KAPA:
+        break;
+
+      default:
         psError(PS_ERR_IO, true, "Unsupported type for %s: %d", file->name, file->type);
         return false;
@@ -435,4 +440,7 @@
             }
         }
+        break;
+      case PM_FPA_FILE_SUBKERNEL:
+        status = pmSubtractionWriteKernels(view, file, config);
         break;
       case PM_FPA_FILE_SX:
@@ -512,4 +520,5 @@
       case PM_FPA_FILE_FRINGE:
       case PM_FPA_FILE_DARK:
+      case PM_FPA_FILE_SUBKERNEL:
       case PM_FPA_FILE_CMF:
       case PM_FPA_FILE_PSF:
@@ -577,4 +586,5 @@
         status = pmFPAviewFreeData(view, file);
         break;
+      case PM_FPA_FILE_SUBKERNEL:
       case PM_FPA_FILE_SX:
       case PM_FPA_FILE_RAW:
@@ -720,4 +730,5 @@
       case PM_FPA_FILE_FRINGE:
       case PM_FPA_FILE_DARK:
+      case PM_FPA_FILE_SUBKERNEL:
       case PM_FPA_FILE_CMF:
       case PM_FPA_FILE_PSF:
@@ -899,9 +910,11 @@
         status = pmFPAviewFitsWritePHU (view, file, config);
         break;
+      case PM_FPA_FILE_SUBKERNEL:
+        status = pmSubtractionWritePHU(view, file, config);
       case PM_FPA_FILE_CMF:
         status = pmSource_CMF_WritePHU (view, file, config);
         break;
       case PM_FPA_FILE_PSF:
-        status = pmPSFmodelWritePHU (view, file, config);
+        status = pmPSFmodelWritePHU(view, file, config);
         break;
       case PM_FPA_FILE_ASTROM_REFSTARS:
Index: /trunk/psModules/src/imcombine/pmSubtractionIO.c
===================================================================
--- /trunk/psModules/src/imcombine/pmSubtractionIO.c	(revision 19188)
+++ /trunk/psModules/src/imcombine/pmSubtractionIO.c	(revision 19189)
@@ -1,7 +1,12 @@
 #include <stdio.h>
 #include <pslib.h>
+#include <strings.h>
 
 #include "pmHDU.h"
 #include "pmFPA.h"
+#include "pmFPAview.h"
+#include "pmFPAfile.h"
+#include "pmFPAfileFitsIO.h"
+#include "pmConcepts.h"
 
 #include "pmSubtraction.h"
@@ -62,9 +67,10 @@
 }
 
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
 bool pmReadoutWriteSubtractionKernels(pmReadout *ro, psFits *fits)
 {
     PM_ASSERT_READOUT_NON_NULL(ro, false);
     PS_ASSERT_FITS_NON_NULL(fits, false);
-
 
     // Extract the regions and solutions used in the image matching
@@ -159,6 +165,6 @@
     // CVS tags, used to identify the version of this file (in case incompatibilities are introduced)
     psString cvsFile = psStringCopy("$RCSfile: pmSubtractionIO.c,v $");
-    psString cvsRev  = psStringCopy("$Revision: 1.1 $");
-    psString cvsDate = psStringCopy("$Date: 2008-06-16 21:59:43 $");
+    psString cvsRev  = psStringCopy("$Revision: 1.2 $");
+    psString cvsDate = psStringCopy("$Date: 2008-08-25 22:14:04 $");
     psStringSubstitute(&cvsFile, NULL, "RCSfile: ");
     psStringSubstitute(&cvsRev,  NULL, "Revision: ");
@@ -190,4 +196,75 @@
     return true;
 }
+
+static bool pmCellWriteSubtractionKernels(pmCell *cell, const pmFPAview *view,
+                                          pmFPAfile *file, pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(cell, false);
+    PS_ASSERT_PTR_NON_NULL(cell->readouts, false);
+    PS_ASSERT_PTR_NON_NULL(view, false);
+
+    pmFPAview *thisView = pmFPAviewAlloc(view->nRows); // Copy of input view
+    *thisView = *view;
+
+    for (int i = 0; i < cell->readouts->n; i++) {
+        pmReadout *readout = cell->readouts->data[i];
+        thisView->readout = i;
+        if (!pmReadoutWriteSubtractionKernels(readout, file->fits)) {
+            psError(PS_ERR_IO, false, "Failed to write %dth readout", i);
+            psFree(thisView);
+            return false;
+        }
+    }
+    psFree(thisView);
+    return true;
+}
+
+static bool pmChipWriteSubtractionKernels(pmChip *chip, const pmFPAview *view,
+                                          pmFPAfile *file, pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(chip, false);
+    PS_ASSERT_PTR_NON_NULL(chip->cells, false);
+    PS_ASSERT_PTR_NON_NULL(view, false);
+
+    pmFPAview *thisView = pmFPAviewAlloc(view->nRows); // Copy of input view
+    *thisView = *view;
+
+    for (int i = 0; i < chip->cells->n; i++) {
+        pmCell *cell = chip->cells->data[i];
+        thisView->cell = i;
+        if (!pmCellWriteSubtractionKernels(cell, thisView, file, config)) {
+            psError(PS_ERR_IO, false, "Failed to write %dth cell", i);
+            psFree(thisView);
+            return false;
+        }
+    }
+    psFree(thisView);
+    return true;
+}
+
+static bool pmFPAWriteSubtractionKernels(pmFPA *fpa, const pmFPAview *view,
+                                         pmFPAfile *file, pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(view, false);
+    PS_ASSERT_PTR_NON_NULL(fpa, false);
+    PS_ASSERT_PTR_NON_NULL(fpa->chips, false);
+
+    pmFPAview *thisView = pmFPAviewAlloc(view->nRows); // Copy of input view
+    *thisView = *view;
+
+    for (int i = 0; i < fpa->chips->n; i++) {
+        pmChip *chip = fpa->chips->data[i];
+        thisView->chip = i;
+        if (!pmChipWriteSubtractionKernels(chip, thisView, file, config)) {
+            psError(PS_ERR_IO, false, "Failed to write %dth chip", i);
+            psFree(thisView);
+            return false;
+        }
+    }
+    psFree(thisView);
+    return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 
@@ -283,2 +360,248 @@
     return true;
 }
+
+static bool pmCellReadSubtractionKernels(pmCell *cell, const pmFPAview *view,
+                                         pmFPAfile *file, pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(view, false);
+    PS_ASSERT_PTR_NON_NULL(cell, false);
+    PS_ASSERT_PTR_NON_NULL(cell->readouts, false);
+
+    pmFPAview *thisView = pmFPAviewAlloc(view->nRows); // Copy of input view
+    *thisView = *view;
+
+    // Create a readout if none exists
+    if (!cell->readouts || cell->readouts->n == 0) {
+        pmReadout *readout = pmReadoutAlloc(cell); // New readout
+        psFree(readout);                // Drop reference
+    }
+
+    cell->data_exists = false;
+    for (int i = 0; i < cell->readouts->n; i++) {
+        pmReadout *readout = cell->readouts->data[i];
+        thisView->readout = i;
+        pmReadoutReadSubtractionKernels(readout, file->fits);
+        if (!readout->data_exists) {
+            continue;
+        }
+
+        // load in the concept information for this cell
+        if (!pmConceptsReadCell(cell, PM_CONCEPT_SOURCE_HEADER, true, NULL)) {
+            psErrorClear();
+            psWarning("Difficulty reading concepts for cell; attempting to proceed.");
+        }
+        cell->data_exists = true;
+    }
+    psFree(thisView);
+
+    return true;
+}
+
+static bool pmChipReadSubtractionKernels(pmChip *chip, const pmFPAview *view,
+                                         pmFPAfile *file, pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(view, false);
+    PS_ASSERT_PTR_NON_NULL(chip, false);
+    PS_ASSERT_PTR_NON_NULL(chip->cells, false);
+
+    pmFPAview *thisView = pmFPAviewAlloc(view->nRows); // Copy of input view
+    *thisView = *view;
+
+    chip->data_exists = false;
+    for (int i = 0; i < chip->cells->n; i++) {
+        pmCell *cell = chip->cells->data[i];
+        thisView->cell = i;
+        pmCellReadSubtractionKernels(cell, thisView, file, config);
+        if (!cell->data_exists) {
+            continue;
+        }
+        chip->data_exists = true;
+    }
+    psFree(thisView);
+
+    if (!pmConceptsReadChip(chip, PM_CONCEPT_SOURCE_HEADER, true, true, NULL)) {
+        psError(PS_ERR_IO, false, "Failed to read concepts for chip.\n");
+        return false;
+    }
+
+    return true;
+}
+
+static bool pmFPAReadSubtractionKernels(pmFPA *fpa, const pmFPAview *view,
+                                        pmFPAfile *file, pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(view, false);
+    PS_ASSERT_PTR_NON_NULL(file, false);
+    PS_ASSERT_PTR_NON_NULL(file->fpa, false);
+    PS_ASSERT_PTR_NON_NULL(file->fpa->chips, false);
+
+    pmFPAview *thisView = pmFPAviewAlloc(view->nRows); // Copy of input view
+    *thisView = *view;
+
+    for (int i = 0; i < fpa->chips->n; i++) {
+        pmChip *chip = fpa->chips->data[i];
+        thisView->chip = i;
+        pmChipReadSubtractionKernels(chip, thisView, file, config);
+    }
+    psFree(thisView);
+
+    if (!pmConceptsReadFPA(fpa, PM_CONCEPT_SOURCE_HEADER, true, NULL)) {
+        psError(PS_ERR_IO, false, "Failed to read concepts for fpa.\n");
+        return false;
+    }
+
+    return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool pmSubtractionWriteKernels(const pmFPAview *view, pmFPAfile *file, pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(view, false);
+    PS_ASSERT_PTR_NON_NULL(file, false);
+    PS_ASSERT_PTR_NON_NULL(file->fpa, false);
+
+    pmFPA *fpa = pmFPAfileSuitableFPA(file, view, config, false); // Suitable FPA for writing
+
+    if (view->chip == -1) {
+        if (!pmFPAWriteSubtractionKernels(fpa, view, file, config)) {
+            psError(PS_ERR_IO, false, "Failed to write subtraction kernels from fpa");
+            psFree(fpa);
+            return false;
+        }
+        psFree(fpa);
+        return true;
+    }
+
+    if (view->chip >= fpa->chips->n) {
+        psError(PS_ERR_UNKNOWN, false, "Writing chip == %d (>= chips->n == %ld)", view->chip, fpa->chips->n);
+        psFree(fpa);
+        return false;
+    }
+    pmChip *chip = fpa->chips->data[view->chip];
+
+    if (view->cell == -1) {
+        if (!pmChipWriteSubtractionKernels(chip, view, file, config)) {
+            psError(PS_ERR_IO, false, "Failed to write objects from chip");
+            psFree(fpa);
+            return false;
+        }
+        psFree(fpa);
+        return true;
+    }
+
+    if (view->cell >= chip->cells->n) {
+        psError(PS_ERR_UNKNOWN, false, "Writing cell == %d (>= cells->n == %ld)",
+                view->cell, chip->cells->n);
+        psFree(fpa);
+        return false;
+    }
+    pmCell *cell = chip->cells->data[view->cell];
+
+    if (view->readout == -1) {
+        if (!pmCellWriteSubtractionKernels(cell, view, file, config)) {
+            psError(PS_ERR_IO, false, "Failed to write objects from cell");
+            psFree(fpa);
+            return false;
+        }
+        psFree(fpa);
+        return true;
+    }
+
+    if (view->readout >= cell->readouts->n) {
+        psError(PS_ERR_UNKNOWN, false, "Writing readout == %d (>= readouts->n == %ld)",
+                view->readout, cell->readouts->n);
+        psFree(fpa);
+        return false;
+    }
+    pmReadout *readout = cell->readouts->data[view->readout];
+
+    if (!pmReadoutWriteSubtractionKernels(readout, file->fits)) {
+        psError(PS_ERR_IO, false, "Failed to write objects from readout %d", view->readout);
+        psFree(fpa);
+        return false;
+    }
+
+    psFree(fpa);
+    return true;
+}
+
+bool pmSubtractionWritePHU(const pmFPAview *view, pmFPAfile *file, pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(view, false);
+    PS_ASSERT_PTR_NON_NULL(file, false);
+
+    if (file->wrote_phu) {
+        return true;
+    }
+    if (file->fileLevel != PM_FPA_LEVEL_FPA) {
+        return true;
+    }
+    if (file->fpa->chips->n == 1) {
+        return true;
+    }
+
+    // find the FPA phu
+    pmFPA *fpa = pmFPAfileSuitableFPA(file, view, config, false); // Suitable FPA for writing
+    pmHDU *phu = psMemIncrRefCounter(pmFPAviewThisPHU(view, fpa));
+    psFree(fpa);
+
+    // if there is no PHU, this is a single header+image (extension-less) file. This could be the case for an
+    // input SPLIT set of files being written out as a MEF.  if there is a PHU, write it out as a 'blank'
+    psMetadata *outhead = psMetadataAlloc();
+    if (phu) {
+        psMetadataCopy (outhead, phu->header);
+    }
+    psFree(phu);
+
+    pmConfigConformHeader(outhead, file->format);
+
+    psFitsWriteBlank(file->fits, outhead, "");
+    file->wrote_phu = true;
+
+    psTrace("pmFPAfile", 5, "wrote phu %s (type: %d)\n", file->filename, file->type);
+    psFree(outhead);
+
+    return true;
+}
+
+bool pmSubtractionReadKernels(const pmFPAview *view, pmFPAfile *file, pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(view, false);
+    PS_ASSERT_PTR_NON_NULL(file, false);
+    PS_ASSERT_PTR_NON_NULL(file->fpa, false);
+
+    pmFPA *fpa = file->fpa;
+
+    if (view->chip == -1) {
+        pmFPAReadSubtractionKernels(fpa, view, file, config);
+        return true;
+    }
+
+    if (view->chip >= fpa->chips->n) {
+        return false;
+    }
+    pmChip *chip = fpa->chips->data[view->chip];
+
+    if (view->cell == -1) {
+        pmChipReadSubtractionKernels(chip, view, file, config);
+        return true;
+    }
+
+    if (view->cell >= chip->cells->n) {
+        return false;
+    }
+    pmCell *cell = chip->cells->data[view->cell];
+
+    if (view->readout == -1) {
+        pmCellReadSubtractionKernels(cell, view, file, config);
+        return true;
+    }
+
+    if (view->readout >= cell->readouts->n) {
+        return false;
+    }
+    pmReadout *readout = cell->readouts->data[view->readout];
+
+    return pmReadoutReadSubtractionKernels(readout, file->fits);
+}
Index: /trunk/psModules/src/imcombine/pmSubtractionIO.h
===================================================================
--- /trunk/psModules/src/imcombine/pmSubtractionIO.h	(revision 19188)
+++ /trunk/psModules/src/imcombine/pmSubtractionIO.h	(revision 19189)
@@ -20,3 +20,18 @@
 
 
+bool pmSubtractionReadKernels(const pmFPAview *view, ///< View into which to read
+                              pmFPAfile *file, ///< File from which to read
+                              pmConfig *config ///< Configuration
+                              );
+
+bool pmSubtractionWriteKernels(const pmFPAview *view, ///< View from which to write
+                               pmFPAfile *file, ///< File to which to write
+                               pmConfig *config ///< Configuration
+                               );
+
+bool pmSubtractionWritePHU(const pmFPAview *view, // View to PHU
+                           pmFPAfile *file, ///< File to which to write
+                           pmConfig *config ///< Configuration
+                           );
+
 #endif
