IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Dec 17, 2004, 4:27:42 PM (22 years ago)
Author:
gusciora
Message:

This code appears to work correctly.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/psModules/src/pmSubtractSky.c

    r2720 r2755  
    66 *  @author GLG, MHPCC
    77 *
    8  *  @version $Revision: 1.7 $ $Name: not supported by cvs2svn $
    9  *  @date $Date: 2004-12-16 00:47:01 $
     8 *  @version $Revision: 1.8 $ $Name: not supported by cvs2svn $
     9 *  @date $Date: 2004-12-18 02:27:42 $
    1010 *
    1111 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
     
    1717#include "pslib.h"
    1818#include "psConstants.h"
    19 
    20 // XXX: this is pmFit in pmSubtractBias.c, named psFit here.
    21 typedef enum {
    22     PM_FIT_NONE,                              ///< No fit
    23     PM_FIT_POLYNOMIAL,                        ///< Fit polynomial
    24     PM_FIT_SPLINE                             ///< Fit cubic splines
    25 } psFit;
    26 
     19#include "pmSubtractSky.h"
     20
     21/******************************************************************************
     22 *****************************************************************************/
    2723int p_psDetermineNumBits(unsigned int data)
    2824{
     
    4036}
    4137
     38/******************************************************************************
     39 *****************************************************************************/
    4240psU64 getHighestPriorityStatOption(psU64 statOptions)
    4341{
     
    6058}
    6159
    62 
    6360/******************************************************************************
    6461psImage *binImage(origImage, binFactor, statOptions): This routine takes an
     
    6764 
    6865XXX: use static vectors for myStats, binVector and binMask.
     66XXX: I coded this before I was aware of a psLib reBin function.  I don't
     67use this function in this module.  I'm keeping it here in the event that
     68requirements change and we might need a custom reBin function.
    6969 *****************************************************************************/
    7070psImage *binImage(psImage *origImage,
     
    7272                  psStatsOptions statOptions)
    7373{
     74    if (binFactor <= 0) {
     75        psLogMsg(__func__, PS_LOG_WARN,
     76                 "WARNING: binImage(): binFactor is %d\n", binFactor);
     77        return(origImage);
     78    }
     79    if (binFactor == 1) {
     80        return(origImage);
     81    }
     82
    7483    psVector *binVector = psVectorAlloc(binFactor * binFactor, PS_TYPE_F32);
    7584    psVector *binMask = psVectorAlloc(binFactor * binFactor, PS_TYPE_U8);
    7685    psStats *myStats = psStatsAlloc(statOptions);
    77 
    78     if (binFactor <= 0) {
    79         psLogMsg(__func__, PS_LOG_WARN,
    80                  "WARNING: binImage(): binFactor is %d\n", binFactor);
    81         return(origImage);
    82     }
    83     if (binFactor == 1) {
    84         return(origImage);
    85     }
    8686
    8787    for (int row = 0; row < origImage->numRows ; row+=binFactor) {
     
    115115        }
    116116    }
    117     psFree(myStats);
    118117    psFree(binVector);
    119118    psFree(binMask);
     119    psFree(myStats);
    120120
    121121    return(origImage);
     
    123123
    124124/******************************************************************************
    125 buildPolyTerms(): this routine computes a 2-D array polyTerms[] that holds
     125 *****************************************************************************/
     126psS32 CalculatePolyTerms(psS32 xOrder, psS32 yOrder)
     127{
     128    psS32 maxOrder = PS_MAX(xOrder, yOrder);
     129    psS32 localPolyTerms = 0;
     130    psS32 order = 0;
     131    psS32 num=0;
     132
     133    for (order=0;order<=maxOrder;order++) {
     134        for (num=0;num<=order;num++) {
     135            if (((order-num) <= xOrder) && (num <= yOrder)) {
     136                localPolyTerms++;
     137            }
     138        }
     139    }
     140    return(localPolyTerms);
     141}
     142
     143/******************************************************************************
     144buildPolyTerms(): this routine computes a 2-D array polyTerms[][] that holds
    126145terms for the polynomial that is used to model the sky background.  We use
    127 this array primarily for convenience in many computations involving that sky
    128 model polynomials.  It is defined as:
     146this array primarily for convenience in computations involving sky model
     147polynomials.  It is defined as:
    129148    polyTerms[i][0] = the power to which X is raised in the i-th term of in an
    130149    poly-order sky background polynomial.
     
    133152    poly-order sky background polynomial.
    134153 *****************************************************************************/
    135 psS32 **buildPolyTerms(psS32 polyOrder)
     154psS32 **buildPolyTerms(psS32 xOrder, psS32 yOrder)
    136155{
    137156    psS32 i=0;
    138157    psS32 order = 0;
    139158    psS32 num=0;
    140     psS32 localPolyTerms= (((polyOrder+1) * (polyOrder + 2)) / 2);
    141 
    142     // We create the data structure which we hold the xy order of each coeff.
     159    psS32 localPolyTerms = CalculatePolyTerms(xOrder, yOrder);
     160    psS32 maxOrder = PS_MAX(xOrder, yOrder);
     161
     162    // Create the data structure which we hold the xy order of each coeff.
    143163    psS32 **polyTerms = (psS32 **) psAlloc(localPolyTerms * sizeof(psS32 *));
    144164    for (i=0; i < localPolyTerms ; i++) {
     
    150170    // calculates the power to which x/y are raised in that i-th term.
    151171    // We first do the 0-order terms, then the 1-order terms, etc.
    152     for (order=0;order<=polyOrder;order++) {
     172    for (order=0;order<=maxOrder;order++) {
    153173        for (num=0;num<=order;num++) {
    154             polyTerms[i][0] = order-num;
    155             polyTerms[i][1] = num;
    156             i++;
    157         }
     174            if (((order-num) <= xOrder) && (num <= yOrder)) {
     175                polyTerms[i][0] = order-num;
     176                polyTerms[i][1] = num;
     177                i++;
     178            }
     179        }
     180    }
     181
     182    // XXX: Get rid of this.
     183    for (i=0; i < localPolyTerms ; i++) {
     184        psTrace(".psModule.pmSubtractSky.buildPolyTerms", 6,
     185                "x^%d * y^%d\n", polyTerms[i][0], polyTerms[i][1]);
    158186    }
    159187
     
    161189}
    162190
    163 #define PS_TWENTY 20
    164 
     191/******************************************************************************
     192This procedure calculates various combinations of powers of x and y and stores
     193them in the data structure sums[][].  After it completes:
     194 
     195    sums[i][j] == x^i * y^j
     196 *****************************************************************************/
    165197// XXX: Use variable size arrays for polynomial sums.
    166 /** @brief This procedure calculates various combinations of powers of x and y
    167  *   and stores them in the data structure sums[][].  After it completes:
    168  *          sums[i][j] == x^i * y^j
    169  */
     198#define PS_MAX_POLYNOMIAL_ORDER 20
    170199void buildSums(psF64 x,
    171200               psF64 y,
    172                psF64 sums[PS_TWENTY][PS_TWENTY],
    173                psS32 polyOrder)
     201               psF64 sums[PS_MAX_POLYNOMIAL_ORDER][PS_MAX_POLYNOMIAL_ORDER],
     202               psS32 xOrder,
     203               psS32 yOrder)
    174204{
    175205    psS32 i = 0;
     
    180210    xSum = 1.0;
    181211    ySum = 1.0;
    182     for(i=0;i<=polyOrder;i++) {
     212    for(i=0;i<=xOrder;i++) {
    183213        ySum = xSum;
    184         for(j=0;j<=polyOrder;j++) {
     214        for(j=0;j<=yOrder;j++) {
    185215            sums[i][j] = ySum;
    186216            ySum*= y;
     
    191221
    192222/******************************************************************************
    193  
    194223 *****************************************************************************/
    195224psPolynomial2D *ImageFitPolynomial(psPolynomial2D *myPoly,
     
    197226                                   psImage *maskImage)
    198227{
     228    psTrace(".psModule.pmSubtractSky.ImageFitPolynomial", 4,
     229            "---- ImageFitPolynomial() begin ----\n");
    199230    PS_POLY_CHECK_NULL(myPoly, NULL);
    200231    PS_POLY_CHECK_TYPE(myPoly, PS_POLYNOMIAL_ORD, NULL);
    201     PS_INT_CHECK_NON_EQUALS(myPoly->nX, myPoly->nY, NULL);
    202232    PS_IMAGE_CHECK_NULL(binnedImage, NULL);
    203233    PS_IMAGE_CHECK_EMPTY(binnedImage, NULL);
     
    207237    PS_IMAGE_CHECK_TYPE(maskImage, PS_TYPE_U8, NULL);
    208238    PS_IMAGE_CHECK_SIZE_EQUAL(binnedImage, maskImage, NULL);
     239    psS32 oldPolyX = -1;
     240    psS32 oldPolyY = -1;
     241
     242    // The matrix equations become singular if there are more powers of X
     243    // in myPoly then there are rows of the image.  I think.  Similarly for
     244    // powers of Y and columns.  So.  Here we reduce the complexity of the
     245    // polynomial if there are not enough rows/columns in the input image.
     246
     247    if (myPoly->nX > binnedImage->numRows) {
     248        psLogMsg(__func__, PS_LOG_WARN,
     249                 "WARNING: ImageFitPolynomial(): Reducing polynomial complexity in x-dimension.\n");
     250        oldPolyX = myPoly->nX;
     251        myPoly->nX = binnedImage->numRows;
     252    }
     253    if (myPoly->nY > binnedImage->numCols) {
     254        psLogMsg(__func__, PS_LOG_WARN,
     255                 "WARNING: ImageFitPolynomial(): Reducing polynomial complexity in y-dimension.\n");
     256        oldPolyY = myPoly->nY;
     257        myPoly->nY = binnedImage->numCols;
     258    }
    209259    psS32 i;
    210260    psS32 j;
     
    213263    psS32 aRow;
    214264    psS32 aCol;
    215     psS32 polyOrder = myPoly->nX;
    216     psS32 localPolyTerms= (((polyOrder+1) * (polyOrder + 2)) / 2);
    217     psS32 **polyTerms = buildPolyTerms(polyOrder);
    218     psF64 sums[PS_TWENTY][PS_TWENTY];
    219     psImage *A = psImageAlloc(localPolyTerms+1, localPolyTerms+1, PS_TYPE_F64);
    220     psVector *B = psVectorAlloc(localPolyTerms+1, PS_TYPE_F64);
    221     psVector *outPerm = NULL;
     265    // XXX: Document this.  The myPoly->nX and ->nY terms are actual 1 larger
     266    // than the order of the polynomial.
     267    psS32 **polyTerms = buildPolyTerms(myPoly->nX-1, myPoly->nY-1);
     268    psS32 localPolyTerms = CalculatePolyTerms(myPoly->nX-1, myPoly->nY-1);
     269    psF64 sums[PS_MAX_POLYNOMIAL_ORDER][PS_MAX_POLYNOMIAL_ORDER];
     270    psImage *A = psImageAlloc(localPolyTerms, localPolyTerms, PS_TYPE_F64);
     271    psImage *Aout = psImageAlloc(localPolyTerms, localPolyTerms, PS_TYPE_F64);
     272    psVector *B = psVectorAlloc(localPolyTerms, PS_TYPE_F64);
     273    psVector *outPerm = psVectorAlloc(localPolyTerms, PS_TYPE_F64);
    222274
    223275    for(i=0;i<A->numRows;i++) {
     
    232284    for (x=0;x<binnedImage->numRows;x++) {
    233285        for (y=0;y<binnedImage->numCols;y++) {
    234             if (maskImage->data.U8[x][y] != 0) {
    235                 buildSums((psF64) x, (psF64) y, sums, polyOrder);
     286            if (maskImage->data.U8[x][y] == 0) {
     287                buildSums((psF64) x, (psF64) y, sums, myPoly->nX-1, myPoly->nY-1);
    236288
    237289                /************************************************************
    238                 Equation (7) from the ADD describes 16 linear equations.
     290                Equation (7) from the pilot ADD describes 16 linear equations.
    239291                The i-th equation is simply the partial derivative of the
    240292                sky background polynomial (1) w.r.t. to the i-th term in
     
    251303                    }
    252304                }
    253 
    254305                // Build the B[] vector, which is the right-hand side of (7).
    255                 for (i=0;i<=localPolyTerms;i++) {
     306                for (i=0;i<localPolyTerms;i++) {
    256307                    B->data.F64[i]+= binnedImage->data.F32[x][y] *
    257308                                     sums[ polyTerms[i][0] ][ polyTerms[i][1] ];
     
    260311        }
    261312    }
    262     psImage *ALUD = psMatrixLUD(NULL, outPerm, A);
    263     psVector *C = psMatrixLUSolve(C, ALUD, B, outPerm);
    264 
     313
     314    // XXX: Put this loop inside a psTrace conditional, somehow.
     315    for (aRow=0;aRow<localPolyTerms;aRow++) {
     316        for (aCol=0;aCol<localPolyTerms;aCol++) {
     317            psTrace(".psModule.pmSubtractSky.ImageFitPolynomial", 6,
     318                    "A[%d][%d] is %f\n", aRow, aCol, A->data.F64[aRow][aCol]);
     319        }
     320    }
     321    // XXX: Put this loop inside a psTrace conditional, somehow.
     322    for (i=0;i<=localPolyTerms;i++) {
     323        psTrace(".psModule.pmSubtractSky.ImageFitPolynomial", 6,
     324                "B[%d] is %f\n", i, B->data.F64[i]);
     325    }
     326
     327
     328    // Solve the matrix equations for the polynomial coefficients C.
     329    Aout = psMatrixLUD(Aout, outPerm, A);
     330    psVector *C = psVectorAlloc(localPolyTerms, PS_TYPE_F64);
     331    psMatrixLUSolve(C, Aout, B, outPerm);
     332
     333    // Set the appropriate coefficients in the myPoly structure.
    265334    for (i=0;i<localPolyTerms;i++) {
    266335        myPoly->coeff[ polyTerms[i][0] ][ polyTerms[i][1] ] = C->data.F64[i];
    267     }
    268 
     336        psTrace(".psModule.pmSubtractSky.ImageFitPolynomial", 6,
     337                "myPoly->coeff[%d][%d] is %f\n", polyTerms[i][0], polyTerms[i][1], myPoly->coeff[ polyTerms[i][0] ][ polyTerms[i][1] ]);
     338    }
     339
     340    // Free data structures that were allocated in this module.
    269341    for (i=0;i<localPolyTerms;i++) {
    270342        psFree(polyTerms[i]);
     
    272344    psFree(polyTerms);
    273345    psFree(A);
    274     psFree(ALUD);
     346    psFree(Aout);
    275347    psFree(B);
    276348    psFree(C);
    277349    psFree(outPerm);
    278350
     351    // We restore the original size of the polynomial and set remaining
     352    // coefficients to 0.0.
     353    if (oldPolyX != -1) {
     354        myPoly->nX = oldPolyX;
     355        for (i=oldPolyX ; i < myPoly->nX ; i++) {
     356            for (j=0;j<myPoly->nY ; j++) {
     357                myPoly->coeff[i][j] = 0.0;
     358            }
     359        }
     360    }
     361    if (oldPolyY != -1) {
     362        myPoly->nY = oldPolyY;
     363        for (i=0 ; i < myPoly->nX ; i++) {
     364            for (j=oldPolyY;j<myPoly->nY ; j++) {
     365                myPoly->coeff[i][j] = 0.0;
     366            }
     367        }
     368    }
     369
     370    psTrace(".psModule.pmSubtractSky.ImageFitPolynomial", 4,
     371            "---- ImageFitPolynomial() end successfully ----\n");
    279372    return(myPoly);
    280373}
     
    293386                         float clipSD)
    294387{
     388    psTrace(".psModule.pmSubtractSky", 4,
     389            "---- pmSubtractSky() begin ----\n");
     390
    295391    // Return the original input readout if the fit specs are poorly defined.
    296392    if ((fitSpec == NULL) ||
     
    299395    }
    300396    psImage *origImage = in->image;
    301     psImage *maskImage = in->mask;
    302397    psImage *binnedImage = NULL;
    303398    psPolynomial2D *myPoly;
     399    psImage *binnedMaskImage = NULL;
    304400
    305401    psStatsOptions statOptions = stats->options;
    306     if (1 < p_psDetermineNumBits(statOptions)) {
     402    if (1 > p_psDetermineNumBits(statOptions)) {
    307403        //XXX  psWarning(PS_ERR_UNKNOWN,true, "Multiple statistical options have been requested.\n");
    308404        statOptions = getHighestPriorityStatOption(statOptions);
     405        // XXX: Don't modify input parameter.
     406        stats->options = statOptions;
    309407        if (statOptions <= 0) {
    310408            psLogMsg(__func__, PS_LOG_WARN,
     
    314412    }
    315413
     414    //
     415    // Generate required warning messages.
     416    //
     417    if (0 == p_psDetermineNumBits(statOptions)) {
     418        psLogMsg(__func__, PS_LOG_WARN,
     419                 "WARNING: pmSubtractSky(): no stats->options was requested\n");
     420    }
     421    if (binFactor <= 0) {
     422        psLogMsg(__func__, PS_LOG_WARN,
     423                 "WARNING: pmSubtractSky(): binFactor is %d\n", binFactor);
     424    }
     425    if (stats == NULL) {
     426        psLogMsg(__func__, PS_LOG_WARN,
     427                 "WARNING: pmSubtractSky(): input parameter stats is NULL\n");
     428    }
     429
     430    //
    316431    // Bin the input image according to input parameters.
    317     if ((binFactor <= 0) || (stats == NULL)) {
    318         // Simply use the original image: no binning.
    319         if (binFactor <= 0) {
    320             psLogMsg(__func__, PS_LOG_WARN,
    321                      "WARNING: pmSubtractSky(): binFactor is %d\n", binFactor);
    322         }
    323         if (stats == NULL) {
    324             psLogMsg(__func__, PS_LOG_WARN,
    325                      "WARNING: pmSubtractSky(): input parameter stats is NULL\n");
    326         }
    327         binnedImage = origImage;
     432    //
     433    if ((binFactor <= 1) ||
     434            (stats == NULL) ||
     435            (0 == p_psDetermineNumBits(statOptions))) {
     436        binnedImage = psImageCopy(binnedImage, origImage, PS_TYPE_F32);
    328437    } else {
    329         // Call a private function to do the binning.
    330         binnedImage = binImage(origImage, binFactor, statOptions);
    331     }
    332 
     438        // Add the original image mask in here.
     439        binnedImage = psImageCopy(binnedImage, origImage, PS_TYPE_F32);
     440        binnedImage = psImageRebin(NULL, binnedImage, NULL, 0, binFactor, stats);
     441    }
     442    psTrace(".psModule.pmSubtractSky", 4,
     443            "binnedImage size is (%d, %d)\n", binnedImage->numRows, binnedImage->numCols);
     444
     445    //
    333446    // Clip pixels that are outside the acceptable range.
     447    //
    334448    if (clipSD <= 0.0) {
    335449        psLogMsg(__func__, PS_LOG_WARN,
     
    342456        myStats =  psImageStats(myStats, binnedImage, NULL, 0);
    343457        p_psGetStatValue(myStats, &binnedMean);
     458        psTrace(".psModule.pmSubtractSky", 8,
     459                "binned Mean is %f\n", binnedMean);
    344460
    345461        myStats->options = PS_STAT_SAMPLE_STDEV;
     
    347463        p_psGetStatValue(myStats, &binnedStdev);
    348464        psFree(myStats);
     465        psTrace(".psModule.pmSubtractSky", 8,
     466                "binned StDev is %f\n", binnedStdev);
    349467
    350468        // Clip all pixels which are more than clipSD sigmas from the mean.
     
    352470        // XXX: we must unset this later since we modify the image mask.
    353471        // XXX: Determine which pixels, mask or image, should be clipped.
     472
     473        binnedMaskImage = psImageAlloc(binnedImage->numCols,
     474                                       binnedImage->numRows,
     475                                       PS_TYPE_U8);
     476
     477        psTrace(".psModule.pmSubtractSky", 8,
     478                "clipSD is %f\n", clipSD);
     479
    354480        for (int row = 0; row < binnedImage->numRows ; row++) {
    355481            for (int col = 0; col < binnedImage->numCols ; col++) {
    356482                if (fabs(binnedImage->data.F32[row][col] - binnedMean) >
    357483                        (clipSD * binnedStdev)) {
    358                     maskImage->data.U8[row][col] = 1;
     484                    binnedMaskImage->data.U8[row][col] = 1;
    359485                }
    360486            }
     
    362488    }
    363489
    364     // XXX: fit the polynomial to the binned image
     490    //
     491    // Fit the polynomial to the binned image
     492    //
    365493    if (fit == PM_FIT_POLYNOMIAL) {
    366494        myPoly = (psPolynomial2D *) fitSpec;
    367 
    368         // XXX Ensure that the polynomial is of type Chebyshev.
    369         myPoly = ImageFitPolynomial(myPoly, binnedImage, maskImage);
    370 
    371         // XXX Do we need to do something with ordinate scaling if Chebyshev?
    372         binnedImage = psImageEvalPolynomial(binnedImage, myPoly);
    373     }
    374 
     495        PS_POLY_CHECK_NULL(myPoly, NULL);
     496        PS_POLY_CHECK_TYPE(myPoly, PS_POLYNOMIAL_ORD, NULL);
     497
     498        myPoly = ImageFitPolynomial(myPoly, binnedImage, binnedMaskImage);
     499
     500        if (myPoly != NULL) {
     501            // XXX:Add ordinary polynomials to psImageEvalPolynomial()
     502            for (int row = 0; row < binnedImage->numRows ; row++) {
     503                for (int col = 0; col < binnedImage->numCols ; col++) {
     504                    binnedImage->data.F32[row][col] =
     505                        psPolynomial2DEval(myPoly, (psF32) row, (psF32) col);
     506                    psTrace(".psModule.pmSubtractSky", 8,
     507                            "binned Image[%d][%d] is %f\n",
     508                            row, col, binnedImage->data.F32[row][col]);
     509                }
     510            }
     511        } else {
     512            psLogMsg(__func__, PS_LOG_WARN,
     513                     "WARNING: pmSubtractSky(): could not model sky with a polynomial.\n");
     514            psFree(binnedMaskImage);
     515            if (!((binFactor <= 1) || (stats == NULL))) {
     516                psFree(binnedImage);
     517            }
     518            return(in);
     519        }
     520    } else {
     521        //XXX: error
     522    }
     523
     524    //
    375525    //Subtract the polynomially fitted image from the original image
    376     if (binFactor <= 0) {
     526    //
     527    if (binFactor <= 1) {
    377528        // The binned image is the same size as the original image.
    378529        for (int row = 0; row < origImage->numRows ; row++) {
     
    384535        for (int row = 0; row < origImage->numRows ; row++) {
    385536            for (int col = 0; col < origImage->numCols ; col++) {
    386                 int binRow = row / binFactor;
    387                 int binCol = col / binFactor;
    388                 origImage->data.F32[row][col]-= binnedImage->data.F32[binRow][binCol];
    389             }
    390         }
    391 
    392     }
    393 
    394     if (!((binFactor <= 0) || (stats == NULL))) {
     537                // We calculate the F32 value of the pixel coordinates in the
     538                // binned image and then use a pixel interpolation routine to
     539                // determine the value of the pixel at that location.
     540                psF32 binRowF64 = ((psF32) row) / ((psF32) binFactor);
     541                psF32 binColF64 = ((psF32) col) / ((psF32) binFactor);
     542
     543                // We add 0.5 to the pixel locations since the pixel
     544                // interpolation routine defines the location of pixel
     545                // (i, j) as (i+0.5, j+0.5).
     546                binRowF64+= 0.5;
     547                binColF64+= 0.5;
     548
     549                psF32 binPixel = (psF32) psImagePixelInterpolate(
     550                                     binnedImage, binRowF64, binColF64,
     551                                     NULL, 0, 0.0, PS_INTERPOLATE_BILINEAR);
     552                origImage->data.F32[row][col]-= binPixel;
     553
     554                psTrace(".psModule.pmSubtractSky", 8,
     555                        "image[%d][%d] <--> binnedImage[%.2f][%.2f]: %f (%f)\n",
     556                        row, col, binRowF64-0.5, binColF64-0.5, binPixel,
     557                        binnedImage->data.F32[(psS32)binRowF64][(psS32)binColF64]);
     558            }
     559        }
     560
     561    }
     562
     563    psFree(binnedMaskImage);
     564    if (!((binFactor <= 1) || (stats == NULL))) {
    395565        psFree(binnedImage);
    396566    }
    397567
     568    psTrace(".psModule.pmSubtractSky", 4,
     569            "---- pmSubtractSky() exit successfully ----\n");
    398570    return(in);
    399571}
Note: See TracChangeset for help on using the changeset viewer.