IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Dec 13, 2005, 5:47:35 PM (21 years ago)
Author:
Paul Price
Message:

Upgrading for psLib-0.9.0

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/archive/scripts/src/phase2/pmFPAMorph.c

    r5651 r5786  
    1414// Flip the chip in x
    1515static psImage *xFlipImage(psImage *image, // Image to be flipped
    16                            int size     // Size of image in flip dimension
     16                           int size     // Size of image in flip dimension
    1717    )
    1818{
     
    2020    switch (image->type.type) {
    2121      case PS_TYPE_U16:
    22         for (int y = 0; y < image->numRows; y++) {
    23             for (int x = 0; x < image->numCols; x++) {
    24                 flipped->data.U16[y][size - x - 1] = image->data.U16[y][x];
    25             }
    26         }
    27         break;
     22        for (int y = 0; y < image->numRows; y++) {
     23            for (int x = 0; x < image->numCols; x++) {
     24                flipped->data.U16[y][size - x - 1] = image->data.U16[y][x];
     25            }
     26        }
     27        break;
    2828      case PS_TYPE_F32:
    29         for (int y = 0; y < image->numRows; y++) {
    30             for (int x = 0; x < image->numCols; x++) {
    31                 flipped->data.F32[y][size - x - 1] = image->data.F32[y][x];
    32             }
    33         }
    34         break;
     29        for (int y = 0; y < image->numRows; y++) {
     30            for (int x = 0; x < image->numCols; x++) {
     31                flipped->data.F32[y][size - x - 1] = image->data.F32[y][x];
     32            }
     33        }
     34        break;
    3535      default:
    36         psError(PS_ERR_IO, true, "Image type %x not yet supported for flip.\n", image->type.type);
     36        psError(PS_ERR_IO, true, "Image type %x not yet supported for flip.\n", image->type.type);
    3737    }
    3838
     
    4242// Flip the chip in y
    4343static psImage *yFlipImage(psImage *image, // Image to be flipped
    44                            int size     // Size of image in flip dimension
     44                           int size     // Size of image in flip dimension
    4545    )
    4646{
     
    4848    switch (image->type.type) {
    4949      case PS_TYPE_U16:
    50         for (int y = 0; y < image->numRows; y++) {
    51             for (int x = 0; x < image->numCols; x++) {
    52                 flipped->data.U16[size - y - 1][x] = image->data.U16[y][x];
    53             }
    54         }
    55         break;
     50        for (int y = 0; y < image->numRows; y++) {
     51            for (int x = 0; x < image->numCols; x++) {
     52                flipped->data.U16[size - y - 1][x] = image->data.U16[y][x];
     53            }
     54        }
     55        break;
    5656      default:
    57         psError(PS_ERR_IO, true, "Image type %x not yet supported for flip.\n", image->type.type);
     57        psError(PS_ERR_IO, true, "Image type %x not yet supported for flip.\n", image->type.type);
    5858    }
    5959
     
    6565// Return a list of the region strings and the method for interpreting them
    6666static psList *getRegions(psString *method, // Method for evaluating the regions
    67                           psString methodValues // The METHOD:VALUES string
     67                          psString methodValues // The METHOD:VALUES string
    6868    )
    6969{
    7070    char *values = strchr(methodValues, ':'); // The VALUES
    7171    *method = psStringNCopy(methodValues, strlen(methodValues) - strlen(values)); // The METHOD
    72     psList *regionStrings = NULL;       // List of the region strings
     72    psList *regionStrings = NULL;       // List of the region strings
    7373    if (strncmp(*method, "HEADER", 6) == 0 || strncmp(*method, "HD", 2) == 0) {
    74         regionStrings = papSplit(values, ", ");
     74        regionStrings = papSplit(values, ", ");
    7575    } else if (strncmp(*method, "VALUE", 5) == 0 || strncmp(*method, "VAL", 3) == 0) {
    76         regionStrings = papSplit(values, "; ");
     76        regionStrings = papSplit(values, "; ");
    7777    }
    7878
     
    8484// Splice an image into another image
    8585static psRegion *spliceImage(psImage *target, // Target image onto which to splice
    86                              int *x0, int *y0, // Starting coordinates to splice to
    87                              psImage *source, // Source image from which to splice
    88                              const psRegion *from, // Region to splice from
    89                              int readdir, // Read direction
    90                              bool xFlip, bool yFlip // Flip x and y axes?
    91                         )
     86                             int *x0, int *y0, // Starting coordinates to splice to
     87                             psImage *source, // Source image from which to splice
     88                             const psRegion *from, // Region to splice from
     89                             int readdir, // Read direction
     90                             bool xFlip, bool yFlip // Flip x and y axes?
     91                        )
    9292{
    9393    psImage *toSplice = psImageSubset(source, *from); // Subimage, to splice into target
    9494    if (xFlip) {
    95         int size = 0;           // Size of flipped image
    96         if (readdir == 1) {
    97             size = toSplice->numCols;
    98         } else if (readdir == 2) {
    99             size = target->numCols;
    100         }
    101         psImage *temp = xFlipImage(toSplice, size);
    102         psFree(toSplice);
    103         toSplice = temp;
     95        int size = 0;           // Size of flipped image
     96        if (readdir == 1) {
     97            size = toSplice->numCols;
     98        } else if (readdir == 2) {
     99            size = target->numCols;
     100        }
     101        psImage *temp = xFlipImage(toSplice, size);
     102        psFree(toSplice);
     103        toSplice = temp;
    104104    }
    105105    if (yFlip) {
    106         int size = 0;           // Size of flipped image
    107         if (readdir == 1) {
    108             size = target->numRows;
    109         } else if (readdir == 2) {
    110             size = toSplice->numRows;
    111         }
    112         psImage *temp = yFlipImage(toSplice, size);
    113         psFree(toSplice);
    114         toSplice = temp;
    115     }
    116 
     106        int size = 0;           // Size of flipped image
     107        if (readdir == 1) {
     108            size = target->numRows;
     109        } else if (readdir == 2) {
     110            size = toSplice->numRows;
     111        }
     112        psImage *temp = yFlipImage(toSplice, size);
     113        psFree(toSplice);
     114        toSplice = temp;
     115    }
     116
     117    psTrace(__func__, 5, "Splicing %dx%d image in at %d,%d\n", toSplice->numCols, toSplice->numRows,
     118            *x0, *y0);
    117119    (void)psImageOverlaySection(target, toSplice, *x0, *y0, "=");
    118120
    119121    if (readdir == 1) {
    120         *x0 += toSplice->numCols;
     122        *x0 += toSplice->numCols;
    121123    } else if (readdir == 2) {
    122         *y0 += toSplice->numRows;
     124        *y0 += toSplice->numRows;
    123125    }
    124126
     
    136138
    137139// Splice bias regions (overscans)
    138 static bool spliceBias(psImage *splice, // Image to which to splice
    139                        int *x0, int *y0, // Starting position for splice
    140                        const pmCell *in, // Input cell
    141                        pmCell *out,     // Output cell
    142                        int xFlip, int yFlip, // Flip the image?
    143                        int readNum,     // Number of readout
    144                        int readdir      // Read direction
    145                        )
     140static bool spliceBias(psImage *splice, // Image to which to splice
     141                       int *x0, int *y0, // Starting position for splice
     142                       const pmCell *in, // Input cell
     143                       pmCell *out,     // Output cell
     144                       int xFlip, int yFlip, // Flip the image?
     145                       int readNum,     // Number of readout
     146                       int readdir      // Read direction
     147                       )
    146148{
    147149    psArray *readouts = in->readouts; // The readouts;
     
    152154    psList *outBiassecs = psListAlloc(NULL); // List of biassecs for output
    153155    while (inBiassec = psListGetAndIncrement(inBiassecsIter)) {
    154         psRegion *outBiassec = spliceImage(splice, x0, y0, readout->image, inBiassec, readdir, xFlip,
    155                                            yFlip);
    156         psListAdd(outBiassecs, PS_LIST_TAIL, outBiassec);
     156        psRegion *outBiassec = spliceImage(splice, x0, y0, readout->image, inBiassec, readdir, xFlip,
     157                                           yFlip);
     158        psListAdd(outBiassecs, PS_LIST_TAIL, outBiassec);
    157159    }
    158160    psFree(inBiassecsIter);
    159161    psMetadataAdd(out->concepts, PS_LIST_TAIL, "CELL.BIASSEC", PS_DATA_LIST | PS_META_REPLACE,
    160                   "BIASSEC from pmFPAMorph", outBiassecs);
    161    
     162                  "BIASSEC from pmFPAMorph", outBiassecs);
     163
    162164    return true;
    163165}
    164166
     167psImage *p_pmImageMosaic(const psArray *source, // Images to splice in
     168                         const psVector *xFlip, const psVector *yFlip, // Need to flip x and y?
     169                         const psVector *xBinSource, const psVector *yBinSource, // Binning in x and y of
     170                                                                                 // source images
     171                         int xBinTarget, int yBinTarget, // Binning in x and y of target images
     172                         const psVector *x0, const psVector *y0 // Offsets for source images on target
     173                         );
    165174
    166175// Splice a list of cells together
     176// We need to do the following:
     177// 1. Copy the contents of the cells (i.e., the readouts) over from the in to the out
     178// 2. Splice together everything in the bucket for the image that we will write out
    167179static psArray *spliceCells(psList *outCells, // List of target cells (required for parity info)
    168                             psList *inCells, // List of cells to splice together
    169                             bool posDep // Position dependent placement of overscans?
     180                            psList *inCells, // List of cells to splice together
     181                            bool posDep // Position dependent placement of overscans?
    170182    )
    171183{
     
    176188
    177189    if (inCells->n != outCells->n) {
    178         psError(PS_ERR_IO, true, "Sizes of input (%d) and output (%d) lists of cells don't match.\n",
    179                 inCells->n, outCells->n);
    180         return NULL;
    181     }
    182 
    183     int numCells = inCells->n;          // Number of cells
    184     int readdir = 0;                    // Read direction for CCD; currently unknown
    185     int numReadouts = 0;                // Number of readouts in a cell
    186     psArray *spliced = NULL;            // Array of spliced readouts
    187     psElemType type = 0;                // Image type (U16, S32, F32, etc)
    188 
    189     psVector *xSize = NULL;             // Size of spliced image in x
    190     psVector *ySize = NULL;             // Size of spliced image in y
     190        psError(PS_ERR_IO, true, "Sizes of input (%d) and output (%d) lists of cells don't match.\n",
     191                inCells->n, outCells->n);
     192        return NULL;
     193    }
     194
     195    int numCells = inCells->n;          // Number of cells
     196    int readdir = 0;                    // Read direction for CCD; currently unknown
     197    int numReadouts = 0;                // Number of readouts in a cell
     198    psArray *spliced = NULL;            // Array of spliced readouts
     199    psElemType type = 0;                // Image type (U16, S32, F32, etc)
    191200
    192201    psVector *xFlip = psVectorAlloc(numCells, PS_TYPE_U8); // Do we need to flip in x?
    193202    psVector *yFlip = psVectorAlloc(numCells, PS_TYPE_U8); // Do we need to flip in y?
    194 
     203    psVector *xBin = psVectorAlloc(numCells, PS_TYPE_S32); // Binning in x
     204    psVector *yBin = psVectorAlloc(numCells, PS_TYPE_S32); // Binning in y
     205    psVector *x0 = psVectorAlloc(numCells, PS_TYPE_S32); // Offset in x
     206    psVector *y0 = psVectorAlloc(numCells, PS_TYPE_S32); // Offset in y
     207    int xBinOut = 0;                    // Binning in x for output
     208    int yBinOut = 0;                    // Binning in y for output
    195209
    196210    // We go through the cells to make sure everything's kosher, and to get the sizes.
    197211    psListIterator *inCellsIter = psListIteratorAlloc(inCells, PS_LIST_HEAD, false); // Iterator for cells
    198     pmCell *inCell = NULL;              // Cell from list of input cells
    199212    psListIterator *outCellsIter = psListIteratorAlloc(outCells, PS_LIST_HEAD, false); // Iterator for cells
    200     int cellNum = 0;                    // Cell number;
     213    pmCell *inCell = NULL;              // Cell from list of input cells
     214    pmCell *outCell = NULL;             // Cell from list of output cells
     215    int cellNum = -1;                   // Cell number
     216    while (inCell = psListGetAndIncrement(inCellsIter) && outCell = psListGetAndIncrement(outCellsIter)) {
     217        cellNum++;
     218        psArray *inReadouts = inCell->readouts;   // The readouts comprising the cell
     219
     220        // Get and check the read direction
     221        int cellReaddir = psMetadataLookupS32(NULL, inCell->concepts, "CELL.READDIR");
     222        psTrace(__func__, 10, "Checking read direction for cell %d: %d\n", cellNum, cellReaddir);
     223        if (cellNum == 0) {
     224            // First run through; set it.
     225            readdir = cellReaddir;
     226        } else if (readdir != cellReaddir) {
     227            psError(PS_ERR_IO, true, "Trying to splice cells with different read directions (%d vs %d). I "
     228                    "don't know how to do that!\n", readdir, cellReaddir);
     229            // XXX Clean up before returning
     230            return NULL;
     231        }
     232
     233        // Get and check the number of readouts
     234        if (! spliced) {
     235            numReadouts = inReadouts->n;
     236            spliced = psArrayAlloc(numReadouts);
     237            xSize = psVectorAlloc(numReadouts, PS_TYPE_S32);
     238            ySize = psVectorAlloc(numReadouts, PS_TYPE_S32);
     239            for (int i = 0; i < numReadouts; i++) {
     240                xSize->data.S32[i] = 0;
     241                ySize->data.S32[i] = 0;
     242            }
     243        } else if (inReadouts->n != numReadouts) {
     244            psError(PS_ERR_IO, true, "Trying to splice cells with different number of reads (%d vs %d)\n",
     245                    numReadouts, readouts->n);
     246            // XXX Clean up before returning
     247            return NULL;
     248        }
     249
     250        // Get and check the binning --- we can't splice to cells that have different binnings, because
     251        // the spliced image can't be defined.  Hence all the "to" cells must have the same binning.
     252        xBinIn = psMetadataLookupS32(NULL, inCell->concepts, "CELL.XBIN");
     253        yBinIn = psMetadataLookupS32(NULL, inCell->concepts, "CELL.YBIN");
     254        int xBinCheck = psMetadataLookupS32(NULL, outCell->concepts, "CELL.XBIN");
     255        int yBinCheck = psMetadataLookupS32(NULL, outCell->concepts, "CELL.YBIN");
     256        if (xBinOut == 0) {
     257            xBinOut = xBinCheck;
     258        } else if (xBinCheck != xBinOut) {
     259            psError(PS_ERR_IO, true, "Trying to splice to cells with different x binnings (%d vs %d)\n",
     260                    xBinOut, xBinCheck);
     261            // XXX Clean up before returning
     262            return NULL;
     263        }
     264        if (yBinOut == 0) {
     265            yBinOut = yBinCheck;
     266        } else if (yBinCheck != yBinOut) {
     267            psError(PS_ERR_IO, true, "Trying to splice to cells with different y binnings (%d vs %d)\n",
     268                    yBinOut, yBinCheck);
     269            // XXX Clean up before returning
     270            return NULL;
     271        }
     272
     273        // Copy the readouts over
     274        psArray *outReadouts = psArrayAlloc(inReadouts->n); // Array of readouts for the output cell
     275        for (int i = 0; i < inReadouts->n; i++) {
     276            outReadouts->data[i] = psMemIncrRefCounter(inReadouts->data[i]);
     277        }
     278
     279        // Get the offsets
     280        x0->data.S32[i] = psMetadataLookupS32(NULL, inCell->concepts, "CELL.X0");
     281        y0->data.S32[i] = psMetadataLookupS32(NULL, inCell->concepts, "CELL.Y0");
     282
     283        // Get and check the parity
     284        int xParityIn = psMetadataLookupS32(NULL, inCell->concepts, "CELL.XPARITY");
     285        int yParityIn = psMetadataLookupS32(NULL, inCell->concepts, "CELL.YPARITY");
     286        int xParityOut = psMetadataLookupS32(NULL, outCell->concepts, "CELL.XPARITY");
     287        int yParityOut = psMetadataLookupS32(NULL, outCell->concepts, "CELL.YPARITY");
     288        if (xParityIn == 0 || xParityOut == 0 || yParityIn == 0 || yParityOut == 0) {
     289            psError(PS_ERR_IO, false, "Unable to determine parity of cell!\n");
     290            // XXX Clean up before returning
     291            return NULL;
     292        }
     293        if (xParityIn != xParityOut) {
     294            for (int i = 0; i < outReadouts->n; i++) {
     295                psImage *image = outReadouts->data[i];
     296                outReadouts->data[i] = xFlipImage(image);
     297                psFree(image);
     298            }
     299            // Correct CELL.X0 for the parity shift
     300            psMetadataItem *x0item = psMetadataLookup(inCell->concepts, "CELL.X0");
     301            x0item->data.S32 -= xSize->data.S32[cellNum];
     302        }
     303        if (yParityIn != yParityOut) {
     304            for (int i = 0; i < outReadouts->n; i++) {
     305                psImage *image = outReadouts->data[i];
     306                outReadouts->data[i] = xFlipImage(image);
     307                psFree(image);
     308            }
     309            // Correct CELL.Y 0 for the parity shift
     310            psMetadataItem *y0item = psMetadataLookup(inCell->concepts, "CELL.Y0");
     311            y0item->data.S32 -= ySize->data.S32[cellNum];
     312        }
     313
     314        //////////////////////////////////////////////////////////////////////////////////////////////////////
     315        // DO I WANT TO DO THIS????
     316        // Wouldn't it be better to splice all the images together first, and then divvy up the components?
     317        //////////////////////////////////////////////////////////////////////////////////////////////////////
     318
     319
     320        // Manipulate the images, if required
     321        for (int i = 0; i < outReadouts->n; i++) {
     322            psImage *image = manipulate(outReadouts
     323
     324                         psImage *image = psMemIncrRefCounter(outReadouts->data[i]);
     325                         if (xParityIn != xParityOut) {
     326                             psImage *image = xFlipImage(image);
     327                         }
     328
     329
     330        // THIS ISN'T SO SIMPLE: we need to SET the output x0,y0 based on where the image actually gets pasted
     331        // Get the offsets
     332        x0->data.S32[i] = psMetadataLookupS32(NULL, outCell->concepts, "CELL.X0");
     333        y0->data.S32[i] = psMetadataLookupS32(NULL, outCell->concepts, "CELL.Y0");
     334
     335
     336
     337
     338// Splice a list of cells together
     339static psArray *spliceCells(psList *outCells, // List of target cells (required for parity info)
     340                            psList *inCells, // List of cells to splice together
     341                            bool posDep // Position dependent placement of overscans?
     342    )
     343{
     344    assert(outCells);
     345    assert(inCells);
     346
     347    psTrace(__func__, 5, "Splicing together all cells in the bucket.\n");
     348
     349    if (inCells->n != outCells->n) {
     350        psError(PS_ERR_IO, true, "Sizes of input (%d) and output (%d) lists of cells don't match.\n",
     351                inCells->n, outCells->n);
     352        return NULL;
     353    }
     354
     355    int numCells = inCells->n;          // Number of cells
     356    int readdir = 0;                    // Read direction for CCD; currently unknown
     357    int numReadouts = 0;                // Number of readouts in a cell
     358    psArray *spliced = NULL;            // Array of spliced readouts
     359    psElemType type = 0;                // Image type (U16, S32, F32, etc)
     360
     361    psVector *xSize = NULL;             // Size of spliced image in x
     362    psVector *ySize = NULL;             // Size of spliced image in y
     363
     364    psVector *xFlip = psVectorAlloc(numCells, PS_TYPE_U8); // Do we need to flip in x?
     365    psVector *yFlip = psVectorAlloc(numCells, PS_TYPE_U8); // Do we need to flip in y?
     366
     367
     368    // We go through the cells to make sure everything's kosher, and to get the sizes.
     369    psListIterator *inCellsIter = psListIteratorAlloc(inCells, PS_LIST_HEAD, false); // Iterator for cells
     370    psListIterator *outCellsIter = psListIteratorAlloc(outCells, PS_LIST_HEAD, false); // Iterator for cells
     371    pmCell *inCell = NULL;              // Cell from list of input cells
     372    int cellNum = 0;                    // Cell number;
    201373    while (inCell = psListGetAndIncrement(inCellsIter)) {
    202         psArray *readouts = inCell->readouts;   // The readouts comprising the cell
    203 
    204         // Get and check the read direction
    205         int cellReaddir = psMetadataLookupS32(NULL, inCell->concepts, "CELL.READDIR");
    206         if (readdir == 0) {
    207             // Zero means unknown; set it.
    208             readdir = cellReaddir;
    209         } else if (readdir != cellReaddir) {
    210             psError(PS_ERR_IO, true, "Trying to splice cells with different read directions (%d vs %d). I "
    211                     "don't know how to do that!\n", readdir, cellReaddir);
    212             // XXX Clean up before returning
    213             return NULL;
    214         }
    215 
    216         // Get and check the number of readouts
    217         if (! spliced) {
    218             numReadouts = readouts->n;
    219             spliced = psArrayAlloc(numReadouts);
    220             xSize = psVectorAlloc(numReadouts, PS_TYPE_S32);
    221             ySize = psVectorAlloc(numReadouts, PS_TYPE_S32);
    222             for (int i = 0; i < numReadouts; i++) {
    223                 xSize->data.S32[i] = 0;
    224                 ySize->data.S32[i] = 0;
    225             }
    226         } else if (readouts->n != numReadouts) {
    227             psError(PS_ERR_IO, true, "Trying to splice cells with different number of reads (%d vs %d)\n",
    228                     numReadouts, readouts->n);
    229             // XXX Clean up before returning
    230             return NULL;
    231         }
    232 
    233         // Get and check the cell parities
    234         pmCell *outCell = psListGetAndIncrement(outCellsIter);  // Corresponding output cell
    235         int xParityIn = psMetadataLookupS32(NULL, inCell->concepts, "CELL.XPARITY");
    236         int yParityIn = psMetadataLookupS32(NULL, inCell->concepts, "CELL.YPARITY");
    237         int xParityOut = psMetadataLookupS32(NULL, outCell->concepts, "CELL.XPARITY");
    238         int yParityOut = psMetadataLookupS32(NULL, outCell->concepts, "CELL.YPARITY");
    239         if (xParityIn == 0 || xParityOut == 0 || yParityIn == 0 || yParityOut == 0) {
    240             psError(PS_ERR_IO, false, "Unable to determine parity of cell!\n");
    241             // XXX Clean up before returning
    242             return NULL;
    243         }
    244 
    245         if (yParityIn == yParityOut) {
    246             yFlip->data.U8[cellNum] = 0;
    247         } else {
    248             psTrace(__func__, 7, "Need to flip y.\n");
    249             yFlip->data.U8[cellNum] = 1;
    250         }
    251         if (xParityIn == xParityOut) {
    252             xFlip->data.U8[cellNum] = 0;
    253         } else {
    254             psTrace(__func__, 7, "Need to flip x.\n");
    255             xFlip->data.U8[cellNum] = 1;
    256         }
    257         cellNum++;
    258 
    259         // Calculate the sizes of the spliced images
    260         for (int i = 0; i < numReadouts; i++) {
    261             pmReadout *readout = readouts->data[i]; // The readout of interest
    262             psImage *image = readout->image; // The image pixels
    263 
    264             // Check image type
    265             if (type == 0) {
    266                 type = image->type.type;
    267             } else if (image->type.type != type) {
    268                 psError(PS_ERR_IO, true, "Trying to splice readouts with different image types (%d vs %d)\n",
    269                         type, image->type.type);
    270                 // XXX Clean up before returning
    271                 return NULL;
    272             }
    273 
    274             psRegion *trimsec = psMetadataLookupPtr(NULL, inCell->concepts, "CELL.TRIMSEC"); // Trim section
    275             psList *biassecs = psMetadataLookupPtr(NULL, inCell->concepts, "CELL.BIASSEC"); // Bias section
    276             psListIterator *biassecsIter = psListIteratorAlloc(biassecs, PS_LIST_HEAD, false); // Iterator
    277             psRegion *biassec = NULL;   // Bias section from list iteration
    278 
    279             // Get the size of the spliced image
    280             if (readdir == 1) {
    281                 xSize->data.S32[i] += trimsec->x1 - trimsec->x0;
    282                 ySize->data.S32[i] = MAX(ySize->data.S32[i], trimsec->y1 - trimsec->y0);
    283                 while (biassec = psListGetAndIncrement(biassecsIter)) {
    284                     xSize->data.S32[i] += biassec->x1 - biassec->x0;
    285                     ySize->data.S32[i] = MAX(ySize->data.S32[i], biassec->y1 - biassec->y0);
    286                 }
    287             } else if (readdir == 2) {
    288                 ySize->data.S32[i] += trimsec->y1 - trimsec->y0;
    289                 xSize->data.S32[i] = MAX(xSize->data.S32[i], trimsec->x1 - trimsec->x0);
    290                 while (biassec = psListGetAndIncrement(biassecsIter)) {
    291                     ySize->data.S32[i] += biassec->y1 - biassec->y0;
    292                     xSize->data.S32[i] = MAX(ySize->data.S32[i], biassec->x1 - biassec->x0);
    293                 }
    294             } else {
    295                 psError(PS_ERR_IO, true, "Invalid read direction: %d\n", readdir);
    296                 // XXX Clean up before returning
    297                 return NULL;
    298             }
    299             psFree(biassecsIter);
    300         }
    301 
    302         // Copy the concepts over
    303         psMetadataCopy(outCell->concepts, inCell->concepts);
     374        psArray *readouts = inCell->readouts;   // The readouts comprising the cell
     375
     376        // Get and check the read direction
     377        int cellReaddir = psMetadataLookupS32(NULL, inCell->concepts, "CELL.READDIR");
     378        psTrace(__func__, 10, "Checking read direction for cell %d: %d\n", cellNum, cellReaddir);
     379        if (cellNum == 0) {
     380            // First run through; set it.
     381            readdir = cellReaddir;
     382        } else if (readdir != cellReaddir) {
     383            psError(PS_ERR_IO, true, "Trying to splice cells with different read directions (%d vs %d). I "
     384                    "don't know how to do that!\n", readdir, cellReaddir);
     385            // XXX Clean up before returning
     386            return NULL;
     387        }
     388
     389        // Get and check the number of readouts
     390        if (! spliced) {
     391            numReadouts = readouts->n;
     392            spliced = psArrayAlloc(numReadouts);
     393            xSize = psVectorAlloc(numReadouts, PS_TYPE_S32);
     394            ySize = psVectorAlloc(numReadouts, PS_TYPE_S32);
     395            for (int i = 0; i < numReadouts; i++) {
     396                xSize->data.S32[i] = 0;
     397                ySize->data.S32[i] = 0;
     398            }
     399        } else if (readouts->n != numReadouts) {
     400            psError(PS_ERR_IO, true, "Trying to splice cells with different number of reads (%d vs %d)\n",
     401                    numReadouts, readouts->n);
     402            // XXX Clean up before returning
     403            return NULL;
     404        }
     405
     406        // Get and check the cell parities
     407        pmCell *outCell = psListGetAndIncrement(outCellsIter);  // Corresponding output cell
     408        int xParityIn = psMetadataLookupS32(NULL, inCell->concepts, "CELL.XPARITY");
     409        int yParityIn = psMetadataLookupS32(NULL, inCell->concepts, "CELL.YPARITY");
     410        int xParityOut = psMetadataLookupS32(NULL, outCell->concepts, "CELL.XPARITY");
     411        int yParityOut = psMetadataLookupS32(NULL, outCell->concepts, "CELL.YPARITY");
     412        if (xParityIn == 0 || xParityOut == 0 || yParityIn == 0 || yParityOut == 0) {
     413            psError(PS_ERR_IO, false, "Unable to determine parity of cell!\n");
     414            // XXX Clean up before returning
     415            return NULL;
     416        }
     417
     418        if (yParityIn == yParityOut) {
     419            yFlip->data.U8[cellNum] = 0;
     420        } else {
     421            psTrace(__func__, 7, "Need to flip y.\n");
     422            yFlip->data.U8[cellNum] = 1;
     423        }
     424        if (xParityIn == xParityOut) {
     425            xFlip->data.U8[cellNum] = 0;
     426        } else {
     427            psTrace(__func__, 7, "Need to flip x.\n");
     428            xFlip->data.U8[cellNum] = 1;
     429        }
     430        cellNum++;
     431
     432        // Calculate the sizes of the spliced images
     433        for (int i = 0; i < numReadouts; i++) {
     434            pmReadout *readout = readouts->data[i]; // The readout of interest
     435            psImage *image = readout->image; // The image pixels
     436
     437            // Check image type
     438            if (type == 0) {
     439                type = image->type.type;
     440            } else if (image->type.type != type) {
     441                psError(PS_ERR_IO, true, "Trying to splice readouts with different image types (%d vs %d)\n",
     442                        type, image->type.type);
     443                // XXX Clean up before returning
     444                return NULL;
     445            }
     446
     447            psRegion *trimsec = psMetadataLookupPtr(NULL, inCell->concepts, "CELL.TRIMSEC"); // Trim section
     448            psList *biassecs = psMetadataLookupPtr(NULL, inCell->concepts, "CELL.BIASSEC"); // Bias section
     449            psListIterator *biassecsIter = psListIteratorAlloc(biassecs, PS_LIST_HEAD, false); // Iterator
     450            psRegion *biassec = NULL;   // Bias section from list iteration
     451
     452            // Get the size of the spliced image
     453            if (readdir == 1) {
     454                psTrace(__func__, 7, "TRIMSEC is %.0fx%.0f\n", trimsec->x1 - trimsec->x0,
     455                        trimsec->y1 - trimsec->y0);
     456                xSize->data.S32[i] += trimsec->x1 - trimsec->x0;
     457                ySize->data.S32[i] = MAX(ySize->data.S32[i], trimsec->y1 - trimsec->y0);
     458                while (biassec = psListGetAndIncrement(biassecsIter)) {
     459                    psTrace(__func__, 9, "BIASSEC is %.0fx%.0f\n", biassec->x1 - biassec->x0,
     460                        biassec->y1 - biassec->y0);
     461                    xSize->data.S32[i] += biassec->x1 - biassec->x0;
     462                    ySize->data.S32[i] = MAX(ySize->data.S32[i], biassec->y1 - biassec->y0);
     463                }
     464            } else if (readdir == 2) {
     465                ySize->data.S32[i] += trimsec->y1 - trimsec->y0;
     466                xSize->data.S32[i] = MAX(xSize->data.S32[i], trimsec->x1 - trimsec->x0);
     467                while (biassec = psListGetAndIncrement(biassecsIter)) {
     468                    ySize->data.S32[i] += biassec->y1 - biassec->y0;
     469                    xSize->data.S32[i] = MAX(ySize->data.S32[i], biassec->x1 - biassec->x0);
     470                }
     471            } else {
     472                psError(PS_ERR_IO, true, "Invalid read direction: %d\n", readdir);
     473                // XXX Clean up before returning
     474                return NULL;
     475            }
     476            psFree(biassecsIter);
     477        }
    304478    }
    305479    psFree(inCellsIter);
     
    308482
    309483    // Make sure all the readouts have the same size
    310     int numRows = ySize->data.S32[0];   // Number of rows for spliced image
    311     int numCols = xSize->data.S32[0];   // Number of columns for spliced image
     484    int numRows = ySize->data.S32[0];   // Number of rows for spliced image
     485    int numCols = xSize->data.S32[0];   // Number of columns for spliced image
    312486    for (int i = 1; i < numReadouts; i++) {
    313         if (xSize->data.S32[i] != numCols || ySize->data.S32[i] != numRows) {
    314             psError(PS_ERR_IO, true, "Spliced readouts would have different sizes: %dx%d vs %dx%d\n",
    315                     numCols, numRows, xSize->data.S32[i], ySize->data.S32[i]);
    316         }
     487        if (xSize->data.S32[i] != numCols || ySize->data.S32[i] != numRows) {
     488            psError(PS_ERR_IO, true, "Spliced readouts would have different sizes: %dx%d vs %dx%d\n",
     489                    numCols, numRows, xSize->data.S32[i], ySize->data.S32[i]);
     490        }
    317491    }
    318492
     
    321495    // Now we have done the requisite checks, and know the sizes; we just go through and splice together
    322496    for (int i = 0; i < numReadouts; i++) {
    323         psImage *splice = psImageAlloc(numCols, numRows, type); // The spliced image
    324         int x0 = 0, y0 = 0;             // Position at which the splice begins
    325 
    326         // Position-dependent overscans first
    327         if (posDep) {
    328             for (int cellNum = 0; cellNum < inCells->n / 2; cellNum++) {
    329                 pmCell *inCell = psListGet(inCells, cellNum); // Input cell of interest
    330                 pmCell *outCell = psListGet(outCells, cellNum); // Output cell of interest
    331                 spliceBias(splice, &x0, &y0, inCell, outCell, xFlip->data.U8[i], yFlip->data.U8[i], i,
    332                            readdir);
    333             }
    334         }
    335 
    336         // Then the images
    337         psListIterator *inCellsIter = psListIteratorAlloc(inCells, PS_LIST_HEAD, false);// Iterator for cells
    338         pmCell *inCell = NULL;          // Cell from the list of cells
    339         psListIterator *outCellsIter = psListIteratorAlloc(outCells, PS_LIST_HEAD, false); // Iterator
    340         int cellNum = 0;                // Cell number
    341         while (inCell = psListGetAndIncrement(inCellsIter)) {
    342             psArray *readouts = inCell->readouts; // The readouts comprising the cell
    343             pmReadout *readout = readouts->data[i]; // The specific readout of interest
    344             pmCell *outCell = psListGetAndIncrement(outCellsIter); // Output cell
    345             psRegion *inTrimsec = psMetadataLookupPtr(NULL, inCell->concepts, "CELL.TRIMSEC"); // TRIMSEC
    346             psRegion *outTrimsec = spliceImage(splice, &x0, &y0, readout->image, inTrimsec, readdir,
    347                                                xFlip->data.U8[cellNum], yFlip->data.U8[cellNum]);
    348 
    349             // Update the output TRIMSEC
    350             psMetadataAdd(outCell->concepts, PS_LIST_TAIL, "CELL.TRIMSEC", PS_DATA_UNKNOWN | PS_META_REPLACE,
    351                              "TRIMSEC from pmFPAMorph", outTrimsec);
    352         }
    353         psFree(inCellsIter);
    354         psFree(outCellsIter);
    355 
    356         // Then the biases
    357         if (! posDep) {
    358             // Need to only do half the biases
    359             for (int cellNum = inCells->n / 2; cellNum < inCells->n; cellNum++) {
    360                 pmCell *inCell = psListGet(inCells, cellNum); // Input cell of interest
    361                 pmCell *outCell = psListGet(outCells, cellNum); // Output cell of interest
    362                 spliceBias(splice, &x0, &y0, inCell, outCell, xFlip->data.U8[i], yFlip->data.U8[i], i,
    363                            readdir);
    364             }
    365         } else {
    366             // Need to do all the biases
    367             for (int cellNum = 0; cellNum < inCells->n; cellNum++) {
    368                 pmCell *inCell = psListGet(inCells, cellNum); // Input cell of interest
    369                 pmCell *outCell = psListGet(outCells, cellNum); // Output cell of interest
    370                 spliceBias(splice, &x0, &y0, inCell, outCell, xFlip->data.U8[i], yFlip->data.U8[i], i,
    371                            readdir);
    372             }
    373         }
    374 
    375         spliced->data[i] = splice;
     497        psImage *splice = psImageAlloc(numCols, numRows, type); // The spliced image
     498        int x0 = 0, y0 = 0;             // Position at which the splice begins
     499
     500        // Position-dependent overscans first
     501        if (posDep) {
     502            psTrace(__func__, 8, "Doing first position-dependent biases...\n");
     503            for (int cellNum = 0; cellNum < inCells->n / 2; cellNum++) {
     504                psTrace(__func__, 9, "Cell %d...\n", cellNum);
     505                pmCell *inCell = psListGet(inCells, cellNum); // Input cell of interest
     506                pmCell *outCell = psListGet(outCells, cellNum); // Output cell of interest
     507                spliceBias(splice, &x0, &y0, inCell, outCell, xFlip->data.U8[i], yFlip->data.U8[i], i,
     508                           readdir);
     509            }
     510        }
     511
     512        // Then the images
     513        psListIterator *inCellsIter = psListIteratorAlloc(inCells, PS_LIST_HEAD, false);// Iterator for cells
     514        pmCell *inCell = NULL;          // Cell from the list of cells
     515        psListIterator *outCellsIter = psListIteratorAlloc(outCells, PS_LIST_HEAD, false); // Iterator
     516        int cellNum = 0;                // Cell number
     517        while (inCell = psListGetAndIncrement(inCellsIter)) {
     518            psArray *readouts = inCell->readouts; // The readouts comprising the cell
     519            pmReadout *readout = readouts->data[i]; // The specific readout of interest
     520            pmCell *outCell = psListGetAndIncrement(outCellsIter); // Output cell
     521            psRegion *inTrimsec = psMetadataLookupPtr(NULL, inCell->concepts, "CELL.TRIMSEC"); // TRIMSEC
     522            psRegion *outTrimsec = spliceImage(splice, &x0, &y0, readout->image, inTrimsec, readdir,
     523                                               xFlip->data.U8[cellNum], yFlip->data.U8[cellNum]);
     524
     525            // Update the output TRIMSEC
     526            psMetadataAdd(outCell->concepts, PS_LIST_TAIL, "CELL.TRIMSEC", PS_DATA_UNKNOWN | PS_META_REPLACE,
     527                             "TRIMSEC from pmFPAMorph", outTrimsec);
     528        }
     529        psFree(inCellsIter);
     530        psFree(outCellsIter);
     531
     532        // Then the biases
     533        if (posDep) {
     534            // Need to only do half the biases
     535            psTrace(__func__, 8, "Doing second position-dependent biases...\n");
     536            for (int cellNum = inCells->n / 2; cellNum < inCells->n; cellNum++) {
     537                psTrace(__func__, 9, "Cell %d...\n", cellNum);
     538                pmCell *inCell = psListGet(inCells, cellNum); // Input cell of interest
     539                pmCell *outCell = psListGet(outCells, cellNum); // Output cell of interest
     540                spliceBias(splice, &x0, &y0, inCell, outCell, xFlip->data.U8[i], yFlip->data.U8[i], i,
     541                           readdir);
     542            }
     543        } else {
     544            // Need to do all the biases
     545            for (int cellNum = 0; cellNum < inCells->n; cellNum++) {
     546                pmCell *inCell = psListGet(inCells, cellNum); // Input cell of interest
     547                pmCell *outCell = psListGet(outCells, cellNum); // Output cell of interest
     548                spliceBias(splice, &x0, &y0, inCell, outCell, xFlip->data.U8[i], yFlip->data.U8[i], i,
     549                           readdir);
     550            }
     551        }
     552
     553        spliced->data[i] = splice;
    376554
    377555    } // Iterating over readouts
     
    384562
    385563
    386 bool pmFPAMorph(pmFPA *toFPA,           // FPA structure to which to morph
    387                 pmFPA *fromFPA,         // FPA structure from which to morph
    388                 bool positionDependent, // Is the position of the overscan dependent on the position?
    389                 int chipNum,            // Chip number, in case the scopes are different
    390                 int cellNum             // Cell number, in case the scopes are different
     564bool pmFPAMorph(pmFPA *toFPA,           // FPA structure to which to morph
     565                pmFPA *fromFPA,         // FPA structure from which to morph
     566                bool positionDependent, // Is the position of the overscan dependent on the position?
     567                int chipNum,            // Chip number, in case the scopes are different
     568                int cellNum             // Cell number, in case the scopes are different
    391569    )
    392570{
     
    394572    psList *sourceCells = psListAlloc(NULL); // List of source cells
    395573
    396     psArray *toChips = toFPA->chips;    // Array of chips
    397     psArray *fromChips = fromFPA->chips;// Array of chips   
     574    psArray *toChips = toFPA->chips;    // Array of chips
     575    psArray *fromChips = fromFPA->chips;// Array of chips
     576
     577    psTrace(__func__, 1, "Copying FPA concepts over...\n");
     578    pap_psMetadataCopy(toFPA->concepts, fromFPA->concepts);
     579    pap_psMetadataCopy(toFPA->phu, fromFPA->phu);
    398580
    399581    for (int i = 0; i < toChips->n; i++) {
    400         pmChip *toChip = toChips->data[i];
    401         pmChip *fromChip = NULL;
    402         // Select the correct chip
    403         if (toChips->n == 1 && fromChips->n > chipNum) {
    404             fromChip = fromChips->data[chipNum];
    405         } else if (fromChips->n == 1 && toChips->n > chipNum) {
    406             fromChip = fromChips->data[0];
    407         } else if (toChips->n == fromChips->n) {
    408             fromChip = fromChips->data[i];
    409         } else {
    410             psError(PS_ERR_IO, true, "Unable to discern intended chip.\n");
    411             return false;
    412         }
    413        
    414         psArray *toCells = toChip->cells; // Array of cells
    415         psArray *fromCells = fromChip->cells; // Array of cells
    416 
    417         for (int j = 0; j < toCells->n; j++) {
    418             pmCell *toCell = toCells->data[j];
    419             pmCell *fromCell = NULL;
    420             // Select the correct cell
    421             if (toCells->n == 1 && fromCells->n > cellNum) {
    422                 fromCell = fromCells->data[cellNum];
    423             } else if (fromCells->n == 1 && toCells->n > cellNum) {
    424                 fromCell = fromCells->data[0];
    425             } else if (toCells->n == fromCells->n) {
    426                 fromCell = fromCells->data[j];
    427             } else {
    428                 psError(PS_ERR_IO, true, "Unable to discern intended cell.\n");
    429                 return false;
    430             }
    431 
    432             psTrace(__func__, 5, "Putting chip %d, cell %d in the bucket.\n", i, j);
    433             psListAdd(targetCells, PS_LIST_TAIL, toCell);
    434             psListAdd(sourceCells, PS_LIST_TAIL, fromCell);
    435 
    436 #if 1
    437             int xParityIn = psMetadataLookupS32(NULL, fromCell->concepts, "CELL.XPARITY");
    438             int yParityIn = psMetadataLookupS32(NULL, fromCell->concepts, "CELL.YPARITY");
    439             int xParityOut = psMetadataLookupS32(NULL, toCell->concepts, "CELL.XPARITY");
    440             int yParityOut = psMetadataLookupS32(NULL, toCell->concepts, "CELL.YPARITY");
    441             psTrace(__func__, 3, "Chip %d, cell %d: in (%d,%d) out (%d,%d)\n", i, j, xParityIn, yParityIn,
    442                     xParityOut, yParityOut);
     582        pmChip *toChip = toChips->data[i];
     583        pmChip *fromChip = NULL;
     584        // Select the correct chip
     585        if (toChips->n == 1 && fromChips->n > chipNum) {
     586            fromChip = fromChips->data[chipNum];
     587        } else if (fromChips->n == 1 && toChips->n > chipNum) {
     588            fromChip = fromChips->data[0];
     589        } else if (toChips->n == fromChips->n) {
     590            fromChip = fromChips->data[i];
     591        } else {
     592            psError(PS_ERR_IO, true, "Unable to discern intended chip.\n");
     593            return false;
     594        }
     595
     596        if (! fromChip->valid) {
     597            toChip->valid = false;
     598            continue;
     599        }
     600
     601        psTrace(__func__, 2, "Copying chip %d concepts over...\n", i);
     602        pap_psMetadataCopy(toChip->concepts, fromChip->concepts);
     603
     604        psArray *toCells = toChip->cells; // Array of cells
     605        psArray *fromCells = fromChip->cells; // Array of cells
     606
     607        for (int j = 0; j < toCells->n; j++) {
     608            pmCell *toCell = toCells->data[j];
     609            pmCell *fromCell = NULL;
     610            // Select the correct cell
     611            if (toCells->n == 1 && fromCells->n > cellNum) {
     612                fromCell = fromCells->data[cellNum];
     613            } else if (fromCells->n == 1 && toCells->n > cellNum) {
     614                fromCell = fromCells->data[0];
     615            } else if (toCells->n == fromCells->n) {
     616                fromCell = fromCells->data[j];
     617            } else {
     618                psError(PS_ERR_IO, true, "Unable to discern intended cell.\n");
     619                return false;
     620            }
     621
     622            if (! fromCell->valid) {
     623                toCell->valid = false;
     624                continue;
     625            }
     626
     627#ifdef TESTING
     628            int xParityIn = psMetadataLookupS32(NULL, fromCell->concepts, "CELL.XPARITY");
     629            int yParityIn = psMetadataLookupS32(NULL, fromCell->concepts, "CELL.YPARITY");
     630            int xParityOut = psMetadataLookupS32(NULL, toCell->concepts, "CELL.XPARITY");
     631            int yParityOut = psMetadataLookupS32(NULL, toCell->concepts, "CELL.YPARITY");
     632            psTrace(__func__, 3, "Chip %d, cell %d: in (%d,%d) out (%d,%d)\n", i, j, xParityIn, yParityIn,
     633                    xParityOut, yParityOut);
    443634#endif
    444635
    445             // Copy the cell contents over
    446             toCell->readouts = psMemIncrRefCounter(fromCell->readouts);
    447            
    448             if (toCell->hdu && strlen(toCell->hdu->extname) > 0) {
    449                 // Splice the component cells
    450                 p_pmHDU *hdu = toCell->hdu;
    451                 if (! hdu->header) {
    452                     hdu->header = psMetadataAlloc();
    453                 }
    454                 hdu->images = spliceCells(targetCells, sourceCells, positionDependent);
    455                 // Purge the lists
    456                 while (psListRemove(targetCells, PS_LIST_TAIL));
    457                 while (psListRemove(sourceCells, PS_LIST_TAIL));
    458             }
    459 
    460         }
    461 
    462         if (toChip->hdu && strlen(toChip->hdu->extname) > 0) {
    463             // Splice the component cells
    464             p_pmHDU *hdu = toChip->hdu;
    465             if (! hdu->header) {
    466                 hdu->header = psMetadataAlloc();
    467             }
    468             hdu->images = spliceCells(targetCells, sourceCells, positionDependent);
    469             // Purge the lists
    470             while (psListRemove(targetCells, PS_LIST_TAIL));
    471             while (psListRemove(sourceCells, PS_LIST_TAIL));
    472         }
     636#ifdef TESTING
     637            psMetadataPrint(toCell->concepts, 7);
     638#endif
     639
     640            // Copy the concepts over
     641
     642            // Need to be a little tricky here --- some concepts are already set from the camera configuration
     643            // file (e.g., CELL.NAME), and we want to preserve these, not replace it with the old value.
     644            psTrace(__func__, 3, "Copying cell %d concepts over...\n", j);
     645            psMetadata *newConcepts = pap_psMetadataCopy(NULL, fromCell->concepts);
     646            pap_psMetadataCopy(newConcepts, toCell->concepts); // This preserves any already existing concepts
     647            psFree(toCell->concepts);
     648            toCell->concepts = newConcepts;
     649
     650            // Now, we need to check if the following concepts for the target cell are defined statically:
     651            // CELL.XPARITY, CELL.YPARITY, CELL.XBIN, CELL.YBIN, CELL.X0, CELL.Y0
     652            // 1. If they are specified by the header, we can do what we want (because we can set the header).
     653            // 2. If they are not specified by the header, we use those values.
     654            const char *checkConcepts[4] = { "CELL.XPARITY",
     655                                             "CELL.YPARITY",
     656                                             "CELL.XBIN",
     657                                             "CELL.YBIN",
     658                                             "CELL.X0",
     659                                             "CELL.Y0" }; // Concepts that we need to check
     660            bool mdok = false;          // Result of MD lookup
     661            psMetadata *translation = psMetadataLookupMD(&mdok, toFPA->camera, "TRANSLATION"); // Header
     662                                        // translation table
     663            if (!mdok || ! translation) {
     664                psError(PS_ERR_IO, true, "Unable to find TRANSLATION in camera configuration!\n");
     665                return false;
     666            }
     667            for (int c = 0; c < 4; c++) {
     668                psString headerName = psMetadataLookupString(&mdok, translation, checkConcepts[c]); // Name of
     669                                        // header holding the concept, or NULL
     670                if (!mdok || strlen(headerName) <= 0) {
     671                    p_pmCellIngestConcept(toFPA, toChip, toCell, db, checkConcepts[c]);
     672                }
     673            }
     674
     675#ifdef TESTING
     676            psMetadataPrint(toCell->concepts, 7);
     677#endif
     678
     679            psTrace(__func__, 5, "Putting chip %d, cell %d in the bucket.\n", i, j);
     680            psListAdd(targetCells, PS_LIST_TAIL, toCell);
     681            psListAdd(sourceCells, PS_LIST_TAIL, fromCell);
     682
     683            // Copy the cell contents over
     684            toCell->readouts = psMemIncrRefCounter(fromCell->readouts);
     685
     686            if (toCell->hdu && strlen(toCell->hdu->extname) > 0) {
     687                // Splice the component cells
     688                p_pmHDU *hdu = toCell->hdu;
     689                if (! hdu->header) {
     690                    hdu->header = psMetadataAlloc();
     691                }
     692                hdu->images = spliceCells(targetCells, sourceCells, positionDependent);
     693                // Purge the lists
     694                while (psListRemove(targetCells, PS_LIST_TAIL));
     695                while (psListRemove(sourceCells, PS_LIST_TAIL));
     696            }
     697
     698        }
     699
     700        if (toChip->hdu && strlen(toChip->hdu->extname) > 0) {
     701            // Splice the component cells
     702            p_pmHDU *hdu = toChip->hdu;
     703            if (! hdu->header) {
     704                hdu->header = psMetadataAlloc();
     705            }
     706            hdu->images = spliceCells(targetCells, sourceCells, positionDependent);
     707            // Purge the lists
     708            while (psListRemove(targetCells, PS_LIST_TAIL));
     709            while (psListRemove(sourceCells, PS_LIST_TAIL));
     710        }
    473711
    474712    }
    475713
    476714    if (toFPA->hdu && strlen(toFPA->hdu->extname) > 0) {
    477         // Splice the component cells
    478         p_pmHDU *hdu = toFPA->hdu;
    479         if (! hdu->header) {
    480             hdu->header = psMetadataAlloc();
    481         }
    482         hdu->images = spliceCells(targetCells, sourceCells, positionDependent);
    483         // Purge the lists
    484         while (psListRemove(targetCells, PS_LIST_TAIL));
    485         while (psListRemove(sourceCells, PS_LIST_TAIL));
     715        // Splice the component cells
     716        p_pmHDU *hdu = toFPA->hdu;
     717        if (! hdu->header) {
     718            hdu->header = psMetadataAlloc();
     719        }
     720        hdu->images = spliceCells(targetCells, sourceCells, positionDependent);
     721        // Purge the lists
     722        while (psListRemove(targetCells, PS_LIST_TAIL));
     723        while (psListRemove(sourceCells, PS_LIST_TAIL));
    486724    }
    487725
Note: See TracChangeset for help on using the changeset viewer.