Index: /trunk/archive/scripts/src/phase2/Makefile.am
===================================================================
--- /trunk/archive/scripts/src/phase2/Makefile.am	(revision 5650)
+++ /trunk/archive/scripts/src/phase2/Makefile.am	(revision 5651)
@@ -12,4 +12,5 @@
 	pmFPAConceptsSet.c \
 	pmFPAConstruct.c \
+	pmFPAMorph.c \
 	pmFPARead.c \
 	pmFPAWrite.c \
Index: /trunk/archive/scripts/src/phase2/ipprc.config
===================================================================
--- /trunk/archive/scripts/src/phase2/ipprc.config	(revision 5650)
+++ /trunk/archive/scripts/src/phase2/ipprc.config	(revision 5651)
@@ -8,8 +8,7 @@
 ### Setups for each camera system
 CAMERAS		METADATA
-#	MEGACAM_SINGLE	STR	megacam_single.config
 	MEGACAM_RAW	STR	megacam_raw.config
+	GPC1_RAW	STR	gpc1_raw.config
 	MEGACAM_SPLICE	STR	megacam_splice.config
-	GPC1_RAW	STR	gpc1_raw.config
 #	LRIS_BLUE	STR	lris_blue.config
 #	LRIS_RED	STR	lris_red.config
@@ -23,4 +22,5 @@
 TRACE		METADATA			# Trace levels
 	pap			S32	10
+	pmFPAPrint		S32	10
 #	pmConfigRead		S32	10
 #	pmFPAWriteMask		S32	10
Index: /trunk/archive/scripts/src/phase2/papPhase2.c
===================================================================
--- /trunk/archive/scripts/src/phase2/papPhase2.c	(revision 5650)
+++ /trunk/archive/scripts/src/phase2/papPhase2.c	(revision 5651)
@@ -17,4 +17,5 @@
 #include "pmSubtractBias.h"
 #include "pmChipMosaic.h"
+#include "pmFPAMorph.h"
 
 // Phase 2 needs to:
@@ -287,4 +288,7 @@
     }
 
+    pmFPAPrint(input);
+    exit(1);
+
 #ifdef PRODUCTION
     psFitsClose(inputFile);
@@ -296,5 +300,5 @@
     pmFPAReadMask(input, inputFile);
     pmFPAReadWeight(input, inputFile);
-#else
+//#else
     {
 	// Generate mask and weight frame
@@ -827,8 +831,22 @@
     psLogMsg("phase2", PS_LOG_INFO, "Processing completed after %f sec.\n", psTimerMark("phase2"));
 
+
+#if 1
+    // Testing pmFPAMorph
+    psMetadata *newCamera = psMetadataConfigParse(NULL, NULL, "megacam_splice.config", true);
+    pmFPA *newFPA = pmFPAConstruct(newCamera);
+    pmFPAMorph(newFPA, input, true, 0, 0);
+    psFits *newFile = psFitsAlloc("morph.fits");
+    pmFPAWrite(newFile, newFPA, database);
+    psFree(newFile);
+    psFree(newFPA);
+#endif
+
+#if 0
     // Write the output
     pmFPAWrite(outputFile, input, database);
     pmFPAWriteMask(input, outputFile);
     pmFPAWriteWeight(input, outputFile);
+#endif
 
     psLogMsg("phase2", PS_LOG_INFO, "Output completed after %f sec.\n", psTimerMark("phase2"));
Index: /trunk/archive/scripts/src/phase2/phase2.config
===================================================================
--- /trunk/archive/scripts/src/phase2/phase2.config	(revision 5650)
+++ /trunk/archive/scripts/src/phase2/phase2.config	(revision 5651)
@@ -6,5 +6,5 @@
 BIAS		BOOL	FALSE		# Bias subtraction
 DARK		BOOL	FALSE		# Dark subtraction
-OVERSCAN	BOOL	TRUE		# Overscan subtraction
+OVERSCAN	BOOL	FALSE		# Overscan subtraction
 FLAT		BOOL	FALSE		# Flat-field normalisation
 FRINGE		BOOL	FALSE		# Fringe subtraction
Index: /trunk/archive/scripts/src/phase2/pmConfig.c
===================================================================
--- /trunk/archive/scripts/src/phase2/pmConfig.c	(revision 5650)
+++ /trunk/archive/scripts/src/phase2/pmConfig.c	(revision 5651)
@@ -283,5 +283,5 @@
     } // Done looking at all cameras
     if (! winner) {
-	psError(PS_ERR_IO, true, "Unable to find an camera that matches input FITS header!\n");
+	psError(PS_ERR_IO, true, "Unable to find a camera that matches input FITS header!\n");
     }
 
Index: /trunk/archive/scripts/src/phase2/pmFPA.h
===================================================================
--- /trunk/archive/scripts/src/phase2/pmFPA.h	(revision 5650)
+++ /trunk/archive/scripts/src/phase2/pmFPA.h	(revision 5651)
@@ -75,5 +75,7 @@
     psImage *mask;                     // Mask for image
     psImage *weight;                   // Weight for image
+#if 0
     psList *bias;                      // List of bias section (sub-)images
+#endif
     psMetadata *analysis;              // Readout-level analysis metadata
     pmCell *parent;                    // Parent cell
Index: /trunk/archive/scripts/src/phase2/pmFPAConstruct.c
===================================================================
--- /trunk/archive/scripts/src/phase2/pmFPAConstruct.c	(revision 5650)
+++ /trunk/archive/scripts/src/phase2/pmFPAConstruct.c	(revision 5651)
@@ -272,41 +272,45 @@
     )
 {
-    psTrace(__func__, 0, "FPA:\n");
+    psTrace(__func__, 1, "FPA:\n");
     if (fpa->hdu) {
-	psTrace(__func__, 1, "---> FPA is extension %s.\n", fpa->hdu->extname);
+	psTrace(__func__, 2, "---> FPA is extension %s.\n", fpa->hdu->extname);
 	if (! fpa->hdu->images) {
-	    psTrace(__func__, 1, "---> NO PIXELS for extension %s\n", fpa->hdu->extname);
-	}
-    }
+	    psTrace(__func__, 2, "---> NO PIXELS for extension %s\n", fpa->hdu->extname);
+	}
+    }
+    psMetadataPrint(fpa->concepts, 2);
 
     psArray *chips = fpa->chips;	// Array of chips
     // Iterate over the FPA
     for (int i = 0; i < chips->n; i++) {
-	psTrace(__func__, 1, "Chip: %d\n", i);
+	psTrace(__func__, 3, "Chip: %d\n", i);
 	pmChip *chip = chips->data[i]; // The chip
 	if (chip->hdu) {
-	    psTrace(__func__, 2, "---> Chip is extension %s.\n", chip->hdu->extname);
+	    psTrace(__func__, 4, "---> Chip is extension %s.\n", chip->hdu->extname);
 	    if (! chip->hdu->images) {
-		psTrace(__func__, 2, "---> NO PIXELS for extension %s\n", chip->hdu->extname);
-	    }
-	}
+		psTrace(__func__, 4, "---> NO PIXELS for extension %s\n", chip->hdu->extname);
+	    }
+	}
+	psMetadataPrint(chip->concepts, 4);
+
 	// Iterate over the chip
 	psArray *cells = chip->cells;	// Array of cells
 	for (int j = 0; j < cells->n; j++) {
-	    psTrace(__func__, 2, "Cell: %d\n", j);
+	    psTrace(__func__, 5, "Cell: %d\n", j);
 	    pmCell *cell = cells->data[j]; // The cell
 	    if (cell->hdu) {
-		psTrace(__func__, 3, "---> Cell is extension %s.\n", cell->hdu->extname);
+		psTrace(__func__, 6, "---> Cell is extension %s.\n", cell->hdu->extname);
 		if (! cell->hdu->images) {
-		    psTrace(__func__, 3, "---> NO PIXELS for extension %s\n", cell->hdu->extname);
-		}
-	    }
-	    psMetadataPrint(cell->concepts, 3);
-	    psTrace(__func__, 3, "Readouts:\n");
+		    psTrace(__func__, 6, "---> NO PIXELS for extension %s\n", cell->hdu->extname);
+		}
+	    }
+	    psMetadataPrint(cell->concepts, 6);
+
+	    psTrace(__func__, 7, "Readouts:\n");
 	    psArray *readouts = cell->readouts;	// Array of readouts
 	    for (int k = 0; k < readouts->n; k++) {
 		pmReadout *readout = readouts->data[k]; // The readout
 		psImage *image = readout->image; // The image
-		psTrace(__func__, 4, "Image: [%d:%d,%d:%d] (%dx%d)\n", image->col0, image->col0 + 
+		psTrace(__func__, 8, "Image: [%d:%d,%d:%d] (%dx%d)\n", image->col0, image->col0 + 
 			image->numCols, image->row0, image->row0 + image->numRows, image->numCols,
 			image->numRows);
Index: /trunk/archive/scripts/src/phase2/pmFPAMorph.c
===================================================================
--- /trunk/archive/scripts/src/phase2/pmFPAMorph.c	(revision 5650)
+++ /trunk/archive/scripts/src/phase2/pmFPAMorph.c	(revision 5651)
@@ -3,5 +3,8 @@
 #include <assert.h>
 #include "pslib.h"
-#include "papmodule.h"
+
+#include "papStuff.h"
+#include "pmFPA.h"
+#include "pmFPAMorph.h"
 
 #define MAX(x,y) ((x) > (y) ? (x) : (y))
@@ -23,4 +26,11 @@
 	}
 	break;
+      case PS_TYPE_F32:
+	for (int y = 0; y < image->numRows; y++) {
+	    for (int x = 0; x < image->numCols; x++) {
+		flipped->data.F32[y][size - x - 1] = image->data.F32[y][x];
+	    }
+	}
+	break;
       default:
 	psError(PS_ERR_IO, true, "Image type %x not yet supported for flip.\n", image->type.type);
@@ -51,4 +61,6 @@
 }
 
+
+#if 0
 // Return a list of the region strings and the method for interpreting them
 static psList *getRegions(psString *method, // Method for evaluating the regions
@@ -67,4 +79,88 @@
     return regionStrings;
 }
+#endif
+
+
+// Splice an image into another image
+static psRegion *spliceImage(psImage *target, // Target image onto which to splice
+			     int *x0, int *y0, // Starting coordinates to splice to
+			     psImage *source, // Source image from which to splice
+			     const psRegion *from, // Region to splice from
+			     int readdir, // Read direction
+			     bool xFlip, bool yFlip // Flip x and y axes?
+			)
+{
+    psImage *toSplice = psImageSubset(source, *from); // Subimage, to splice into target
+    if (xFlip) {
+	int size = 0;		// Size of flipped image
+	if (readdir == 1) {
+	    size = toSplice->numCols;
+	} else if (readdir == 2) {
+	    size = target->numCols;
+	}
+	psImage *temp = xFlipImage(toSplice, size);
+	psFree(toSplice);
+	toSplice = temp;
+    }
+    if (yFlip) {
+	int size = 0;		// Size of flipped image
+	if (readdir == 1) {
+	    size = target->numRows;
+	} else if (readdir == 2) {
+	    size = toSplice->numRows;
+	}
+	psImage *temp = yFlipImage(toSplice, size);
+	psFree(toSplice);
+	toSplice = temp;
+    }
+
+    (void)psImageOverlaySection(target, toSplice, *x0, *y0, "=");
+
+    if (readdir == 1) {
+	*x0 += toSplice->numCols;
+    } else if (readdir == 2) {
+	*y0 += toSplice->numRows;
+    }
+
+    // Return the region where we pasted the image
+    psRegion *outRegion = psAlloc(sizeof(psRegion));
+    // Addding 1 to get FITS standard
+    outRegion->x0 = *x0 + 1;
+    outRegion->x1 = *x0 + toSplice->numCols;
+    outRegion->y0 = *y0 + 1;
+    outRegion->y1 = *y0 + toSplice->numRows;
+
+    psFree(toSplice);
+    return outRegion;
+}
+
+// Splice bias regions (overscans)
+static bool spliceBias(psImage *splice,	// Image to which to splice
+		       int *x0, int *y0, // Starting position for splice
+		       const pmCell *in, // Input cell
+		       pmCell *out,	// Output cell
+		       int xFlip, int yFlip, // Flip the image?
+		       int readNum,	// Number of readout
+		       int readdir	// Read direction
+		       )
+{
+    psArray *readouts = in->readouts; // The readouts;
+    pmReadout *readout = readouts->data[readNum]; // The readout of interest
+    psList *inBiassecs = psMetadataLookupPtr(NULL, in->concepts, "CELL.BIASSEC"); // List of input biassecs
+    psListIterator *inBiassecsIter = psListIteratorAlloc(inBiassecs, PS_LIST_HEAD, false);
+    psRegion *inBiassec = NULL; // BIASSEC from list
+    psList *outBiassecs = psListAlloc(NULL); // List of biassecs for output
+    while (inBiassec = psListGetAndIncrement(inBiassecsIter)) {
+	psRegion *outBiassec = spliceImage(splice, x0, y0, readout->image, inBiassec, readdir, xFlip,
+					   yFlip);
+	psListAdd(outBiassecs, PS_LIST_TAIL, outBiassec);
+    }
+    psFree(inBiassecsIter);
+    psMetadataAdd(out->concepts, PS_LIST_TAIL, "CELL.BIASSEC", PS_DATA_LIST | PS_META_REPLACE,
+		  "BIASSEC from pmFPAMorph", outBiassecs);
+    
+    return true;
+}
+
 
 // Splice a list of cells together
@@ -79,11 +175,11 @@
     psTrace(__func__, 5, "Splicing together all cells in the bucket.\n");
 
-    if (inCells->size != outCells->size) {
+    if (inCells->n != outCells->n) {
 	psError(PS_ERR_IO, true, "Sizes of input (%d) and output (%d) lists of cells don't match.\n",
-		inCells->size, outCells->size);
+		inCells->n, outCells->n);
 	return NULL;
     }
 
-    int numCells = inCells->size;	// Number of cells
+    int numCells = inCells->n;		// Number of cells
     int readdir = 0;			// Read direction for CCD; currently unknown
     int numReadouts = 0;		// Number of readouts in a cell
@@ -97,6 +193,8 @@
     psVector *yFlip = psVectorAlloc(numCells, PS_TYPE_U8); // Do we need to flip in y?
 
+
+    // We go through the cells to make sure everything's kosher, and to get the sizes.
     psListIterator *inCellsIter = psListIteratorAlloc(inCells, PS_LIST_HEAD, false); // Iterator for cells
-    papCell *inCell = NULL;		// Cell from list of input cells
+    pmCell *inCell = NULL;		// Cell from list of input cells
     psListIterator *outCellsIter = psListIteratorAlloc(outCells, PS_LIST_HEAD, false); // Iterator for cells
     int cellNum = 0;			// Cell number; 
@@ -104,15 +202,17 @@
 	psArray *readouts = inCell->readouts;	// The readouts comprising the cell
 
-	// Check the read direction
+	// Get and check the read direction
 	int cellReaddir = psMetadataLookupS32(NULL, inCell->concepts, "CELL.READDIR");
 	if (readdir == 0) {
+	    // Zero means unknown; set it.
 	    readdir = cellReaddir;
 	} else if (readdir != cellReaddir) {
-	    psError(PS_ERR_IO, true, "Trying to splice cells with different read directions (%d vs %d)\n",
-		    readdir, cellReaddir);
+	    psError(PS_ERR_IO, true, "Trying to splice cells with different read directions (%d vs %d). I "
+		    "don't know how to do that!\n", readdir, cellReaddir);
 	    // XXX Clean up before returning
 	    return NULL;
 	}
-	// Check the number of readouts
+
+	// Get and check the number of readouts
 	if (! spliced) {
 	    numReadouts = readouts->n;
@@ -131,10 +231,10 @@
 	}
 
-	// Get the cell parities
-	papCell *outCell = psListGetAndIncrement(outCellsIter);	// Corresponding output cell
-	int xParityIn = psMetadataLookupS32(NULL, inCell, "CELL.XPARITY");
-	int yParityIn = psMetadataLookupS32(NULL, inCell, "CELL.YPARITY");
-	int xParityOut = psMetadataLookupS32(NULL, outCell, "CELL.XPARITY");
-	int yParityOut = psMetadataLookupS32(NULL, outCell, "CELL.YPARITY");
+	// Get and check the cell parities
+	pmCell *outCell = psListGetAndIncrement(outCellsIter);	// Corresponding output cell
+	int xParityIn = psMetadataLookupS32(NULL, inCell->concepts, "CELL.XPARITY");
+	int yParityIn = psMetadataLookupS32(NULL, inCell->concepts, "CELL.YPARITY");
+	int xParityOut = psMetadataLookupS32(NULL, outCell->concepts, "CELL.XPARITY");
+	int yParityOut = psMetadataLookupS32(NULL, outCell->concepts, "CELL.YPARITY");
 	if (xParityIn == 0 || xParityOut == 0 || yParityIn == 0 || yParityOut == 0) {
 	    psError(PS_ERR_IO, false, "Unable to determine parity of cell!\n");
@@ -159,7 +259,6 @@
 	// Calculate the sizes of the spliced images
 	for (int i = 0; i < numReadouts; i++) {
-	    papReadout *readout = readouts->data[i]; // The readout of interest
+	    pmReadout *readout = readouts->data[i]; // The readout of interest
 	    psImage *image = readout->image; // The image pixels
-	    psList *overscans = readout->overscans; // The overscan regions
 
 	    // Check image type
@@ -173,13 +272,24 @@
 	    }
 
+	    psRegion *trimsec = psMetadataLookupPtr(NULL, inCell->concepts, "CELL.TRIMSEC"); // Trim section
+	    psList *biassecs = psMetadataLookupPtr(NULL, inCell->concepts, "CELL.BIASSEC"); // Bias section
+	    psListIterator *biassecsIter = psListIteratorAlloc(biassecs, PS_LIST_HEAD, false); // Iterator
+	    psRegion *biassec = NULL;	// Bias section from list iteration
+
 	    // Get the size of the spliced image
 	    if (readdir == 1) {
-		psTrace(__func__, 9, "Image size: %dx%d\n", image->numCols, image->numRows);
-		xSize->data.S32[i] += image->numCols;
-		ySize->data.S32[i] = MAX(ySize->data.S32[i], image->numRows);
+		xSize->data.S32[i] += trimsec->x1 - trimsec->x0;
+		ySize->data.S32[i] = MAX(ySize->data.S32[i], trimsec->y1 - trimsec->y0);
+		while (biassec = psListGetAndIncrement(biassecsIter)) {
+		    xSize->data.S32[i] += biassec->x1 - biassec->x0;
+		    ySize->data.S32[i] = MAX(ySize->data.S32[i], biassec->y1 - biassec->y0);
+		}
 	    } else if (readdir == 2) {
-		psTrace(__func__, 9, "Image size: %dx%d\n", image->numCols, image->numRows);
-		ySize->data.S32[i] += image->numRows;
-		xSize->data.S32[i] = MAX(xSize->data.S32[i], image->numCols);
+		ySize->data.S32[i] += trimsec->y1 - trimsec->y0;
+		xSize->data.S32[i] = MAX(xSize->data.S32[i], trimsec->x1 - trimsec->x0);
+		while (biassec = psListGetAndIncrement(biassecsIter)) {
+		    ySize->data.S32[i] += biassec->y1 - biassec->y0;
+		    xSize->data.S32[i] = MAX(ySize->data.S32[i], biassec->x1 - biassec->x0);
+		}
 	    } else {
 		psError(PS_ERR_IO, true, "Invalid read direction: %d\n", readdir);
@@ -187,35 +297,13 @@
 		return NULL;
 	    }
-
-	    psListIterator *overscansIter = psListIteratorAlloc(overscans, PS_LIST_HEAD, false);
-	    psImage *overscan = NULL;	// Overscan image
-	    while (overscan = psListGetAndIncrement(overscansIter)) {
-
-		// Check image type
-		if (type == 0) {
-		    type = image->type.type;
-		} else if (image->type.type != type) {
-		    psError(PS_ERR_IO, true, "Trying to splice readouts with different image types "
-			    "(%d vs %d)\n", type, image->type.type);
-		    // XXX Clean up before returning
-		    return NULL;
-		}
-
-		// Get the size of the spliced image
-		if (readdir == 1) {
-		    psTrace(__func__, 9, "Overscan size: %dx%d\n", image->numCols, image->numRows);
-		    xSize->data.S32[i] += overscan->numCols;
-		    ySize->data.S32[i] = MAX(ySize->data.S32[i], overscan->numRows);
-		} else if (readdir == 2) {
-		    psTrace(__func__, 9, "Overscan size: %dx%d\n", image->numCols, image->numRows);
-		    ySize->data.S32[i] += overscan->numRows;
-		    xSize->data.S32[i] = MAX(xSize->data.S32[i], overscan->numCols);
-		}
-	    }
-
-	}
+	    psFree(biassecsIter);
+	}
+
+	// Copy the concepts over
+	psMetadataCopy(outCell->concepts, inCell->concepts);
     }
     psFree(inCellsIter);
     psFree(outCellsIter);
+
 
     // Make sure all the readouts have the same size
@@ -234,137 +322,57 @@
     for (int i = 0; i < numReadouts; i++) {
 	psImage *splice = psImageAlloc(numCols, numRows, type); // The spliced image
-
+	int x0 = 0, y0 = 0;		// Position at which the splice begins
+
+	// Position-dependent overscans first
+	if (posDep) {
+	    for (int cellNum = 0; cellNum < inCells->n / 2; cellNum++) {
+		pmCell *inCell = psListGet(inCells, cellNum); // Input cell of interest
+		pmCell *outCell = psListGet(outCells, cellNum);	// Output cell of interest
+		spliceBias(splice, &x0, &y0, inCell, outCell, xFlip->data.U8[i], yFlip->data.U8[i], i,
+			   readdir);
+	    }
+	}
+
+	// Then the images
 	psListIterator *inCellsIter = psListIteratorAlloc(inCells, PS_LIST_HEAD, false);// Iterator for cells
-	papCell *inCell = NULL;		// Cell from the list of cells
+	pmCell *inCell = NULL;		// Cell from the list of cells
 	psListIterator *outCellsIter = psListIteratorAlloc(outCells, PS_LIST_HEAD, false); // Iterator
 	int cellNum = 0;		// Cell number
-	int x0 = 0, y0 = 0;		// Position at which the splice begins
 	while (inCell = psListGetAndIncrement(inCellsIter)) {
 	    psArray *readouts = inCell->readouts; // The readouts comprising the cell
-	    papReadout *readout = readouts->data[i]; // The specific readout of interest
-	    psImage *image = readout->image; // The image pixels
-	    psList *overscans = readout->overscans; // The overscan regions
-	    papCell *outCell = psListGetAndIncrement(outCellsIter); // Output cell
-	    
-	    psImage *toSplice = psMemIncrRefCounter(image); // Image to splice in
-	    if (xFlip->data.U8[cellNum]) {
-		int size = 0;		// Size of flipped image
-		if (readdir == 1) {
-		    size = toSplice->numCols;
-		} else if (readdir == 2) {
-		    size = numCols;
-		}
-		psImage *temp = xFlipImage(toSplice, size);
-		psFree(toSplice);
-		toSplice = temp;
-	    }
-	    if (yFlip->data.U8[cellNum]) {
-		int size = 0;		// Size of flipped image
-		if (readdir == 1) {
-		    size = numRows;
-		} else if (readdir == 2) {
-		    size = toSplice->numRows;
-		}
-		psImage *temp = yFlipImage(toSplice, size);
-		psFree(toSplice);
-		toSplice = temp;
-	    }
-
-	    (void)psImageOverlaySection(splice, toSplice, x0, y0, "=");
-
-	    if (readdir == 1) {
-		x0 += toSplice->numCols;
-	    } else if (readdir == 2) {
-		y0 += toSplice->numRows;
-	    }
-
-	    // Update the TRIMSEC for the output cell
-	    psString trimsecString = psMetadataLookupString(NULL, outCell, "CELL.TRIMSEC");
-	    psString trimsecMethod = NULL; // Method of determining trimsec
-	    psList *trimsecs = getRegions(&trimsecMethod, trimsecString); // List of trimsecs
-	    if (strncmp(trimsecMethod, "HEADER", 6) != 0 && strncmp(trimsecMethod, "HD", 2) != 0) {
-		psError(PS_ERR_IO, true, "Can only splice cells if the CELL.TRIMSEC (= %s) is determined "
-			"from the header.\n", trimsecString);
-		// XXX Clean up before returning
-		return NULL;
-	    }
-	    if (trimsecs->size != 1) {
-		psError(PS_ERR_IO, true, "Multiple headers specified for CELL.TRIMSEC: %s\n", trimsecString);
-		// XXX Clean up before returning
-		return NULL;
-	    }
-	    psString trimsecName = trimsecs->head->data; // Grab header for TRIMSEC off the list
-	    psFree(trimsecs);
-
-	    // TRIMSEC region; add 1 to get FITS standard
-	    psRegion trimsecRegion = {x0 + 1, x0 + toSplice->numCols, y0 + 1, y0 + toSplice->numRows};
-	    psString trimsecValue = psRegionToString(trimsecRegion);
-	    psMetadataAddStr(header, PS_LIST_TAIL, trimsecName, 0, "TRIMSEC from pmFPAMorph", trimsecValue);
-	    // XXX Does psMetadataAddStr overwrite a previous value?
-
-	    // Repeat the above for each overscan (flip, overlay, update BIASSEC)
-	    // Prepare the BIASSEC
-	    psString biassecString = psMetadataLookupString(NULL, outCell, "CELL.BIASSEC");
-	    psString biassecMethod = NULL; // Method of determining biassec
-	    psList *biassecs = getRegions(&biassecMethod, biassecString); // List of biassecs
-	    if (strncmp(biassecMethod, "HEADER", 6) != 0 && strncmp(biassecMethod, "HD", 2) != 0) {
-		psError(PS_ERR_IO, true, "Can only splice cells if the CELL.BIASSEC (= %s) is determined "
-			"from the header.\n", biassecString);
-		// XXX Clean up before returning
-		return NULL;
-	    }
-	    if (biassecs->size != overscans->size);
-
-	    psListIterator *overscansIter = psListIteratorAlloc(overscans, PS_LIST_HEAD, false);
-	    psImage *overscan = NULL;	// Overscan from list
-	    psListIterator *biassecsIter = psListIteratorAlloc(biassecs, PS_LIST_HEAD, false);
-	    psString biassecName = NULL;// FITS header keyword for biassec
-	    while ((overscan = psListGetAndIncrement(overscansIter)) &&
-		   (biassecName = psListGetAndIncrement(biassecsIter))) {
-		// Splice the overscan on
-		psImage *toSplice = psMemIncrRefCounter(overscan); // Image to splice in
-		if (xFlip->data.U8[cellNum]) {
-		    int size = 0;	// Size of flipped image
-		    if (readdir == 1) {
-			size = toSplice->numCols;
-		    } else if (readdir == 2) {
-			size = numCols;
-		    }
-		    psImage *temp = xFlipImage(toSplice, size);
-		    psFree(toSplice);
-		    toSplice = temp;
-		}
-		if (yFlip->data.U8[cellNum]) {
-		    int size = 0;	// Size of flipped image
-		    if (readdir == 1) {
-			size = numRows;
-		    } else if (readdir == 2) {
-			size = toSplice->numRows;
-		    }
-		    psImage *temp = yFlipImage(toSplice, size);
-		    psFree(toSplice);
-		    toSplice = temp;
-		}
-		
-		(void)psImageOverlaySection(splice, toSplice, x0, y0, "=");
-
-		if (readdir == 1) {
-		    x0 += toSplice->numCols;
-		} else if (readdir == 2) {
-		    y0 += toSplice->numRows;
-		}
-
-		// Update the header
-		psRegion biassecRegion = {x0 + 1, x0 + toSplice->numCols, y0 + 1, y0 + toSplice->numRows};
-		psString biassecValue = psRegionToString(biassecRegion);
-		psMetadataAddStr(header, PS_LIST_TAIL, biassecName, 0, "BIASSEC from pmFPAMorph",
-				 biassecValue);
-	    }
-	    psFree(overscansIter);
-	    psFree(biassecsIter);
-	    psFree(biassecs);
-	} // Iterating over input cells
+	    pmReadout *readout = readouts->data[i]; // The specific readout of interest
+	    pmCell *outCell = psListGetAndIncrement(outCellsIter); // Output cell
+	    psRegion *inTrimsec = psMetadataLookupPtr(NULL, inCell->concepts, "CELL.TRIMSEC"); // TRIMSEC
+	    psRegion *outTrimsec = spliceImage(splice, &x0, &y0, readout->image, inTrimsec, readdir,
+					       xFlip->data.U8[cellNum], yFlip->data.U8[cellNum]);
+
+	    // Update the output TRIMSEC
+	    psMetadataAdd(outCell->concepts, PS_LIST_TAIL, "CELL.TRIMSEC", PS_DATA_UNKNOWN | PS_META_REPLACE,
+			     "TRIMSEC from pmFPAMorph", outTrimsec);
+	}
+	psFree(inCellsIter);
+	psFree(outCellsIter);
+
+	// Then the biases
+	if (! posDep) {
+	    // Need to only do half the biases
+	    for (int cellNum = inCells->n / 2; cellNum < inCells->n; cellNum++) {
+		pmCell *inCell = psListGet(inCells, cellNum); // Input cell of interest
+		pmCell *outCell = psListGet(outCells, cellNum);	// Output cell of interest
+		spliceBias(splice, &x0, &y0, inCell, outCell, xFlip->data.U8[i], yFlip->data.U8[i], i,
+			   readdir);
+	    }
+	} else {
+	    // Need to do all the biases
+	    for (int cellNum = 0; cellNum < inCells->n; cellNum++) {
+		pmCell *inCell = psListGet(inCells, cellNum); // Input cell of interest
+		pmCell *outCell = psListGet(outCells, cellNum);	// Output cell of interest
+		spliceBias(splice, &x0, &y0, inCell, outCell, xFlip->data.U8[i], yFlip->data.U8[i], i,
+			   readdir);
+	    }
+	}
 
 	spliced->data[i] = splice;
+
     } // Iterating over readouts
 
@@ -426,21 +434,23 @@
 	    psListAdd(sourceCells, PS_LIST_TAIL, fromCell);
 
-	    int xParityIn = psMetadataLookupS32(NULL, fromCell, "CELL.XPARITY");
-	    int yParityIn = psMetadataLookupS32(NULL, fromCell, "CELL.YPARITY");
-	    int xParityOut = psMetadataLookupS32(NULL, toCell, "CELL.XPARITY");
-	    int yParityOut = psMetadataLookupS32(NULL, toCell, "CELL.YPARITY");
+#if 1
+	    int xParityIn = psMetadataLookupS32(NULL, fromCell->concepts, "CELL.XPARITY");
+	    int yParityIn = psMetadataLookupS32(NULL, fromCell->concepts, "CELL.YPARITY");
+	    int xParityOut = psMetadataLookupS32(NULL, toCell->concepts, "CELL.XPARITY");
+	    int yParityOut = psMetadataLookupS32(NULL, toCell->concepts, "CELL.YPARITY");
 	    psTrace(__func__, 3, "Chip %d, cell %d: in (%d,%d) out (%d,%d)\n", i, j, xParityIn, yParityIn,
 		    xParityOut, yParityOut);
+#endif
 
 	    // Copy the cell contents over
 	    toCell->readouts = psMemIncrRefCounter(fromCell->readouts);
 	    
-	    if (toCell->private && strlen(toCell->private->extname) > 0) {
+	    if (toCell->hdu && strlen(toCell->hdu->extname) > 0) {
 		// Splice the component cells
-		p_pmHDU *hdu = toCell->private;
+		p_pmHDU *hdu = toCell->hdu;
 		if (! hdu->header) {
 		    hdu->header = psMetadataAlloc();
 		}
-		hdu->pixels = spliceCells(hdu->header, targetCells, sourceCells, positionDependent);
+		hdu->images = spliceCells(targetCells, sourceCells, positionDependent);
 		// Purge the lists
 		while (psListRemove(targetCells, PS_LIST_TAIL));
@@ -450,11 +460,11 @@
 	}
 
-	if (toChip->private && strlen(toChip->private->extname) > 0) {
+	if (toChip->hdu && strlen(toChip->hdu->extname) > 0) {
 	    // Splice the component cells
-	    p_pmHDU *hdu = toChip->private;
+	    p_pmHDU *hdu = toChip->hdu;
 	    if (! hdu->header) {
 		hdu->header = psMetadataAlloc();
 	    }
-	    hdu->pixels = spliceCells(hdu->header, targetCells, sourceCells);
+	    hdu->images = spliceCells(targetCells, sourceCells, positionDependent);
 	    // Purge the lists
 	    while (psListRemove(targetCells, PS_LIST_TAIL));
@@ -464,5 +474,16 @@
     }
 
+    if (toFPA->hdu && strlen(toFPA->hdu->extname) > 0) {
+	// Splice the component cells
+	p_pmHDU *hdu = toFPA->hdu;
+	if (! hdu->header) {
+	    hdu->header = psMetadataAlloc();
+	}
+	hdu->images = spliceCells(targetCells, sourceCells, positionDependent);
+	// Purge the lists
+	while (psListRemove(targetCells, PS_LIST_TAIL));
+	while (psListRemove(sourceCells, PS_LIST_TAIL));
+    }
+
     return true;
 }
-
Index: /trunk/archive/scripts/src/phase2/pmFPAMorph.h
===================================================================
--- /trunk/archive/scripts/src/phase2/pmFPAMorph.h	(revision 5650)
+++ /trunk/archive/scripts/src/phase2/pmFPAMorph.h	(revision 5651)
@@ -3,6 +3,7 @@
 
 // Morph one focal plane representation into another
-bool pmFPAMorph(papFPA *toFPA,		// FPA structure to which to morph
-		papFPA *fromFPA,	// FPA structure from which to morph
+bool pmFPAMorph(pmFPA *toFPA,		// FPA structure to which to morph
+		pmFPA *fromFPA,		// FPA structure from which to morph
+		bool positionDependent, // Is the position of the overscan dependent on the position?
 		int chipNum,		// Chip number, in case the scopes are different
 		int cellNum		// Cell number, in case the scopes are different
Index: /trunk/archive/scripts/src/phase2/psAdditionals.c
===================================================================
--- /trunk/archive/scripts/src/phase2/psAdditionals.c	(revision 5650)
+++ /trunk/archive/scripts/src/phase2/psAdditionals.c	(revision 5651)
@@ -3,4 +3,75 @@
 #include "pslib.h"
 #include "psAdditionals.h"
+
+
+psMetadata *psMetadataCopy(psMetadata *out,
+                           const psMetadata *in)
+{
+    PS_ASSERT_PTR_NON_NULL(in,NULL);
+    if (out ==  NULL) {
+        out = psMetadataAlloc();
+    }
+    psMetadataItem *inItem = NULL;
+    psMetadataIterator *iter = psMetadataIteratorAlloc(*(psMetadata**)&in, PS_LIST_HEAD, NULL);
+    unsigned long numPointers = 0;	// Number of pointers we were forced to copy
+    while (inItem = psMetadataGetAndIncrement(iter)) {
+	psMetadataItem *outItem = NULL;
+
+	// Need to look for MULTI, which won't be picked up using the iterator.
+	psMetadataItem *multiCheckItem = psMetadataLookup(in, inItem->name);
+	int multiFlag = 0;		// Flag to indicate MULTI or not
+	if (multiCheckItem->type == PS_DATA_METADATA_MULTI) {
+	    multiFlag = PS_DATA_METADATA_MULTI;
+	}
+
+#define PS_METADATA_COPY_CASE(NAME,TYPE) \
+          case PS_TYPE_##NAME: \
+            psMetadataAdd(out, PS_LIST_TAIL, inItem->name, PS_TYPE_##NAME | multiFlag, inItem->comment, \
+			  inItem->data.TYPE); \
+            break;
+
+	switch (inItem->type) {
+	    // Numerical types
+	    PS_METADATA_COPY_CASE(BOOL,B);
+	    PS_METADATA_COPY_CASE(S8, S8);
+	    PS_METADATA_COPY_CASE(S16, S16);
+	    PS_METADATA_COPY_CASE(S32, S32);
+	    PS_METADATA_COPY_CASE(U8, U8);
+	    PS_METADATA_COPY_CASE(U16, U16);
+	    PS_METADATA_COPY_CASE(U32, U32);
+	    PS_METADATA_COPY_CASE(F32, F32);
+	    PS_METADATA_COPY_CASE(F64, F64);
+
+	    // String: relying on the fact that this will copy the string, not point at it.
+	  case PS_DATA_STRING:
+            psMetadataAdd(out, PS_LIST_TAIL, inItem->name, PS_DATA_STRING | multiFlag, inItem->comment,
+			  inItem->data.V);
+            break;
+
+	    // Metadata: copy the next level and stuff that in too
+	  case PS_DATA_METADATA:
+	    {
+		psMetadata *metadata = psMetadataCopy(NULL, inItem->data.md);
+		psMetadataAdd(out, PS_LIST_TAIL, inItem->name, PS_DATA_METADATA | multiFlag, inItem->comment,
+			      metadata);
+		break;
+	    }
+	    // Other kinds of pointers
+	  default:
+	    numPointers++;
+	    psMetadataItemAlloc(inItem->name, inItem->type, inItem->comment, inItem->data.V);
+	    break;
+	}
+    }
+    psFree(iter);
+
+    if (numPointers > 0) {
+	psLogMsg(__func__, PS_LOG_WARN, "Forced to copy %d pointers when copying metadata.  Updating the "
+		 "copied psMetadata will affect the original!\n");
+    }
+
+    return out;
+}
+
 
 psMetadata *psMetadataLookupMD(bool *status, const psMetadata *md, const char *key)
Index: /trunk/archive/scripts/src/phase2/psAdditionals.h
===================================================================
--- /trunk/archive/scripts/src/phase2/psAdditionals.h	(revision 5650)
+++ /trunk/archive/scripts/src/phase2/psAdditionals.h	(revision 5651)
@@ -3,4 +3,7 @@
 
 #include "pslib.h"
+
+// Deep copy of metadata
+psMetadata *psMetadataCopy(psMetadata *out, const psMetadata *in);
 
 // Get a value from the metadata that we believe should be metadata.
