IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Feb 17, 2006, 7:13:42 AM (20 years ago)
Author:
magnier
Message:

bulk merge of eam_rel9_p0 onto this branch

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/rel10_ifa/psModules/src/objects/pmObjects.c

    r6329 r6448  
    66 *  @author EAM, IfA: significant modifications.
    77 *
    8  *  @version $Revision: 1.9 $ $Name: not supported by cvs2svn $
    9  *  @date $Date: 2006-02-06 22:17:54 $
     8 *  @version $Revision: 1.9.4.1 $ $Name: not supported by cvs2svn $
     9 *  @date $Date: 2006-02-17 17:13:42 $
    1010 *
    1111 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
     
    2525                    psS32 y,
    2626                    psF32 counts,
    27                     pmPeakType class)
     27                    pmPeakType type)
    2828{
    2929    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     
    3232    tmp->y = y;
    3333    tmp->counts = counts;
    34     tmp->class = class;
     34    tmp->type = type;
    3535
    3636    psTrace(__func__, 3, "---- %s() end ----\n", __func__);
     
    7777    psFree(tmp->moments);
    7878    psFree(tmp->modelPSF);
    79     psFree(tmp->modelFLT);
     79    psFree(tmp->modelEXT);
     80    psFree(tmp->blends);
    8081    psTrace(__func__, 4, "---- %s() end ----\n", __func__);
    8182}
     
    8586psVector containing the specified row of data from the psImage.
    8687 
    87 XXX: Is there a better way to do this?
     88XXX: Is there a better way to do this? 
    8889XXX EAM: does this really need to alloc a new vector???
    8990*****************************************************************************/
     
    211212    // XXX EAM : i changed this to match pmModelEval above, but see
    212213    // XXX EAM   the note below in pmSourceContour
    213     psF32 oldValue = pmModelEval(source->modelFLT, source->pixels, subCol, subRow);
     214    psF32 oldValue = pmModelEval(source->modelEXT, source->pixels, subCol, subRow);
    214215    if (oldValue == level) {
    215216        psTrace(__func__, 4, "---- %s() end ----\n", __func__);
     
    233234
    234235    while (subCol != lastColumn) {
    235         psF32 newValue = pmModelEval(source->modelFLT, source->pixels, subCol, subRow);
     236        psF32 newValue = pmModelEval(source->modelEXT, source->pixels, subCol, subRow);
    236237        if (oldValue == level) {
    237238            psTrace(__func__, 4, "---- %s() end ----\n", __func__);
     
    310311    tmp->mask = NULL;
    311312    tmp->moments = NULL;
     313    tmp->blends = NULL;
    312314    tmp->modelPSF = NULL;
    313     tmp->modelFLT = NULL;
    314     tmp->type = 0;
     315    tmp->modelEXT = NULL;
     316    tmp->type = PM_SOURCE_UNKNOWN;
     317    tmp->mode = PM_SOURCE_DEFAULT;
    315318    psMemSetDeallocator(tmp, (psFreeFunc) sourceFree);
    316319
     
    436439XXX: In the output psArray elements, should we use the image row/column offsets?
    437440     Currently, we do not.
     441XXX EAM : this function needs to return peaks in *parent* coords
    438442 
    439443XXX: Merge with CVS 1.20.  This had the proper code for images with a single
    440444row or column.
     445 
    441446*****************************************************************************/
    442447psArray *pmFindImagePeaks(const psImage *image,
     
    456461    psArray *list = NULL;
    457462
     463    psU32 col0 = image->col0;
     464    psU32 row0 = image->row0;
     465
    458466    //
    459467    // Find peaks in row 0 only.
     
    462470    tmpRow = getRowVectorFromImage((psImage *) image, row);
    463471    psVector *row1 = pmFindVectorPeaks(tmpRow, threshold);
     472    // pmFindVectorPeaks returns coords in the vector, not corrected for col0
    464473
    465474    for (psU32 i = 0 ; i < row1->n ; i++ ) {
     
    474483
    475484                if (image->data.F32[row][col] > threshold) {
    476                     list = myListAddPeak(list, row, col, image->data.F32[row][col], PM_PEAK_EDGE);
     485                    list = myListAddPeak(list, row + row0, col + col0, image->data.F32[row][col], PM_PEAK_EDGE);
    477486                }
    478487            }
     
    484493                    (image->data.F32[row][col] >= image->data.F32[row+1][col+1])) {
    485494                if (image->data.F32[row][col] > threshold) {
    486                     list = myListAddPeak(list, row, col, image->data.F32[row][col], PM_PEAK_EDGE);
     495                    list = myListAddPeak(list, row + row0, col + col0, image->data.F32[row][col], PM_PEAK_EDGE);
    487496                }
    488497            }
     
    493502                    (image->data.F32[row][col] >= image->data.F32[row+1][col-1])) {
    494503                if (image->data.F32[row][col] > threshold) {
    495                     list = myListAddPeak(list, row, col, image->data.F32[row][col], PM_PEAK_EDGE);
     504                    list = myListAddPeak(list, row + row0, col + col0, image->data.F32[row][col], PM_PEAK_EDGE);
    496505                }
    497506            }
     
    532541                        (image->data.F32[row][col] >= image->data.F32[row+1][col+1])) {
    533542                    myType = PM_PEAK_EDGE;
    534                     list = myListAddPeak(list, row, col, image->data.F32[row][col], myType);
     543                    list = myListAddPeak(list, row + row0, col + col0, image->data.F32[row][col], myType);
    535544                }
    536545            } else if (col < (image->numCols - 1)) {
     
    567576                        }
    568577
    569                         list = myListAddPeak(list, row, col, image->data.F32[row][col], myType);
     578                        list = myListAddPeak(list, row + row0, col + col0, image->data.F32[row][col], myType);
    570579                    }
    571580                }
     
    579588                        (image->data.F32[row][col] >= image->data.F32[row+1][col])) {
    580589                    myType = PM_PEAK_EDGE;
    581                     list = myListAddPeak(list, row, col, image->data.F32[row][col], myType);
     590                    list = myListAddPeak(list, row + row0, col + col0, image->data.F32[row][col], myType);
    582591                }
    583592            } else {
     
    603612                    (image->data.F32[row][col] >  image->data.F32[row][col+1])) {
    604613                if (image->data.F32[row][col] > threshold) {
    605                     list = myListAddPeak(list, row, col, image->data.F32[row][col], PM_PEAK_EDGE);
     614                    list = myListAddPeak(list, row + row0, col + col0, image->data.F32[row][col], PM_PEAK_EDGE);
    606615                }
    607616            }
     
    613622                    (image->data.F32[row][col] >= image->data.F32[row][col+1])) {
    614623                if (image->data.F32[row][col] > threshold) {
    615                     list = myListAddPeak(list, row, col, image->data.F32[row][col], PM_PEAK_EDGE);
     624                    list = myListAddPeak(list, row + row0, col + col0, image->data.F32[row][col], PM_PEAK_EDGE);
    616625                }
    617626            }
     
    622631                    (image->data.F32[row][col] >  image->data.F32[row][col-1])) {
    623632                if (image->data.F32[row][col] > threshold) {
    624                     list = myListAddPeak(list, row, col, image->data.F32[row][col], PM_PEAK_EDGE);
     633                    list = myListAddPeak(list, row + row0, col + col0, image->data.F32[row][col], PM_PEAK_EDGE);
    625634                }
    626635            }
     
    728737XXX: Sync with IfA on whether the peak x/y coords are data structure coords,
    729738     or they use the image row/column offsets.
     739XXX  EAM : peak->x,y uses parent coordinates
    730740 
    731741XXX: Should we simply set pmSource->peak = peak?  If so, should we increase
     
    776786        return(false);
    777787    }
    778     source->moments = pmMomentsAlloc();
     788    if (source->moments == NULL) {
     789        source->moments = pmMomentsAlloc();
     790    }
    779791    source->moments->Sky = (psF32) tmpF64;
     792    psTrace(__func__, 3, "---- %s(true) end ----\n", __func__);
     793    return (true);
     794}
     795
     796// A complementary function to pmSourceLocalSky: calculate the local median variance
     797bool pmSourceLocalSkyVariance(
     798    pmSource *source,
     799    psStatsOptions statsOptions,
     800    psF32 Radius)
     801{
     802    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     803    PS_ASSERT_PTR_NON_NULL(source, false);
     804    PS_ASSERT_IMAGE_NON_NULL(source->weight, false);
     805    PS_ASSERT_IMAGE_NON_NULL(source->mask, false);
     806    PS_ASSERT_PTR_NON_NULL(source->peak, false);
     807    PS_ASSERT_INT_POSITIVE(Radius, false);
     808    PS_ASSERT_INT_NONNEGATIVE(Radius, false);
     809
     810    psImage *image = source->weight;
     811    psImage *mask  = source->mask;
     812    pmPeak *peak  = source->peak;
     813    psRegion srcRegion;
     814
     815    srcRegion = psRegionForSquare(peak->x, peak->y, Radius);
     816    srcRegion = psRegionForImage(mask, srcRegion);
     817
     818    psImageMaskRegion(mask, srcRegion, "OR", PSPHOT_MASK_MARKED);
     819    psStats *myStats = psStatsAlloc(statsOptions);
     820    myStats = psImageStats(myStats, image, mask, 0xff);
     821    psImageMaskRegion(mask, srcRegion, "AND", ~PSPHOT_MASK_MARKED);
     822
     823    psF64 tmpF64;
     824    p_psGetStatValue(myStats, &tmpF64);
     825    psFree(myStats);
     826
     827    if (isnan(tmpF64)) {
     828        psTrace(__func__, 3, "---- %s(false) end ----\n", __func__);
     829        return(false);
     830    }
     831    if (source->moments == NULL) {
     832        source->moments = pmMomentsAlloc();
     833    }
     834    source->moments->dSky = (psF32) tmpF64;
    780835    psTrace(__func__, 3, "---- %s(true) end ----\n", __func__);
    781836    return (true);
     
    830885    psS32 numPixels = 0;
    831886    psF32 Sum = 0.0;
     887    psF32 Var = 0.0;
    832888    psF32 X1 = 0.0;
    833889    psF32 Y1 = 0.0;
     
    841897    psF32 xPeak = source->peak->x;
    842898    psF32 yPeak = source->peak->y;
     899    psF32 xOff = source->pixels->col0 - source->peak->x;
     900    psF32 yOff = source->pixels->row0 - source->peak->y;
    843901
    844902    // XXX why do I get different results for these two methods of finding Sx?
     
    851909    // XXX EAM : mask == 0 is valid
    852910
     911    psF32 **vPix = source->pixels->data.F32;
     912    psF32 **vWgt = source->weight->data.F32;
     913    psU8  **vMsk = source->mask->data.U8;
     914
    853915    for (psS32 row = 0; row < source->pixels->numRows ; row++) {
    854916        for (psS32 col = 0; col < source->pixels->numCols ; col++) {
    855             if ((source->mask != NULL) && (source->mask->data.U8[row][col])) {
     917            if ((source->mask != NULL) && (vMsk[row][col])) {
    856918                continue;
    857919            }
    858920
    859             psF32 xDiff = col + source->pixels->col0 - xPeak;
    860             psF32 yDiff = row + source->pixels->row0 - yPeak;
     921            // psF32 xDiff = col + source->pixels->col0 - xPeak;
     922            // psF32 yDiff = row + source->pixels->row0 - yPeak;
     923
     924            psF32 xDiff = col + xOff;
     925            psF32 yDiff = row + yOff;
    861926
    862927            // XXX EAM : calculate xDiff, yDiff up front;
     
    866931            }
    867932
    868             psF32 pDiff = source->pixels->data.F32[row][col] - sky;
     933            psF32 pDiff = vPix[row][col] - sky;
     934            psF32 wDiff = vWgt[row][col];
    869935
    870936            // XXX EAM : check for valid S/N in pixel
    871937            // XXX EAM : should this limit be user-defined?
    872             if (pDiff / sqrt(source->weight->data.F32[row][col]) < 1) {
     938            if (PS_SQR(pDiff) < wDiff) {
    873939                continue;
    874940            }
    875941
     942            Var += wDiff;
    876943            Sum += pDiff;
    877             X1  += xDiff * pDiff;
    878             Y1  += yDiff * pDiff;
    879             XY  += xDiff * yDiff * pDiff;
    880 
    881             X2  += PS_SQR(xDiff) * pDiff;
    882             Y2  += PS_SQR(yDiff) * pDiff;
    883 
    884             peakPixel = PS_MAX (source->pixels->data.F32[row][col], peakPixel);
     944
     945            psF32 xWght = xDiff * pDiff;
     946            psF32 yWght = yDiff * pDiff;
     947
     948            X1  += xWght;
     949            Y1  += yWght;
     950            XY  += xDiff * yWght;
     951
     952            X2  += xDiff * xWght;
     953            Y2  += yDiff * yWght;
     954
     955            peakPixel = PS_MAX (vPix[row][col], peakPixel);
    885956            numPixels++;
    886957        }
    887958    }
     959
     960    // if we have less than (1/4) of the possible pixels, force a retry
    888961    // XXX EAM - the limit is a bit arbitrary.  make it user defined?
    889     if ((numPixels < 3) || (Sum <= 0)) {
    890         psTrace (".psModules.pmSourceMoments", 5, "no valid pixels for source\n");
     962    if ((numPixels < 0.75*R2) || (Sum <= 0)) {
     963        psTrace (".psModules.pmSourceMoments", 3, "no valid pixels for source\n");
    891964        psTrace(__func__, 3, "---- %s(false) end ----\n", __func__);
    892965        return (false);
     
    905978    y = Y1/Sum;
    906979    if ((fabs(x) > radius) || (fabs(y) > radius)) {
    907         psTrace (".psModules.pmSourceMoments", 5,
     980        psTrace (".psModules.pmSourceMoments", 3,
    908981                 "large centroid swing; invalid peak %d, %d\n",
    909982                 source->peak->x, source->peak->y);
     
    918991    source->moments->Sxy = XY/Sum - x*y;
    919992    source->moments->Sum = Sum;
     993    source->moments->SN  = Sum / sqrt(Var);
    920994    source->moments->Peak = peakPixel;
    921995    source->moments->nPixels = numPixels;
     
    9761050
    9771051/******************************************************************************
    978 pmSourcePSFClump(source, metadata): Find the likely PSF clump in the
    979 sigma-x, sigma-y plane. return 0,0 clump in case of error.
     1052    pmSourcePSFClump(source, metadata): Find the likely PSF clump in the
     1053    sigma-x, sigma-y plane. return 0,0 clump in case of error.
    9801054*****************************************************************************/
    9811055
     
    11381212
    11391213/******************************************************************************
    1140 pmSourceRoughClass(source, metadata): make a guess at the source
    1141 classification.
    1142  
    1143 XXX: push the clump info into the metadata?
    1144  
    1145 XXX: How can this function ever return FALSE?
    1146  
    1147 XXX EAM : add the saturated mask value to metadata
     1214    pmSourceRoughClass(source, metadata): make a guess at the source
     1215    classification.
     1216    
     1217    XXX: push the clump info into the metadata?
     1218    
     1219    XXX: How can this function ever return FALSE?
     1220    
     1221    EAM: I moved S/N calculation to pmSourceMoments, using weight image
    11481222*****************************************************************************/
    11491223
     
    11551229
    11561230    int Nsat     = 0;
    1157     int Ngal     = 0;
     1231    int Next     = 0;
    11581232    int Nstar    = 0;
    11591233    int Npsf     = 0;
    11601234    int Ncr      = 0;
    11611235    int Nsatstar = 0;
    1162     psRegion allArray = psRegionSet (0, 0, 0, 0);
    1163 
     1236    // psRegion allArray = psRegionSet (0, 0, 0, 0);
     1237    psRegion inner;
     1238
     1239    // report stats on S/N values for star-like objects
    11641240    psVector *starsn = psVectorAlloc (sources->n, PS_TYPE_F32);
    11651241    starsn->n = 0;
     
    11671243    // check return status value (do these exist?)
    11681244    bool status;
    1169     psF32 RDNOISE    = psMetadataLookupF32 (&status, metadata, "RDNOISE");
    1170     psF32 GAIN       = psMetadataLookupF32 (&status, metadata, "GAIN");
    11711245    psF32 PSF_SN_LIM = psMetadataLookupF32 (&status, metadata, "PSF_SN_LIM");
    1172     // psF32 SATURATE = psMetadataLookupF32 (&status, metadata, "SATURATE");
    11731246
    11741247    // XXX allow clump size to be scaled relative to sigmas?
     
    11781251        pmSource *tmpSrc = (pmSource *) sources->data[i];
    11791252
    1180         tmpSrc->peak->class = 0;
     1253        tmpSrc->peak->type = 0;
    11811254
    11821255        psF32 sigX = tmpSrc->moments->Sx;
    11831256        psF32 sigY = tmpSrc->moments->Sy;
    11841257
    1185         // calculate and save signal-to-noise estimates
    1186         psF32 S  = tmpSrc->moments->Sum;
    1187         psF32 A  = 4 * M_PI * sigX * sigY;
    1188         psF32 B  = tmpSrc->moments->Sky;
    1189         psF32 RT = sqrt(S + (A * B) + (A * PS_SQR(RDNOISE) / sqrt(GAIN)));
    1190         psF32 SN = (S * sqrt(GAIN) / RT);
    1191         tmpSrc->moments->SN = SN;
    1192 
    11931258        // XXX EAM : can we use the value of SATURATE if mask is NULL?
    1194         int Nsatpix = psImageCountPixelMask (tmpSrc->mask, allArray, PSPHOT_MASK_SATURATED);
     1259        // inner = psRegionForSquare (tmpSrc->peak->x - tmpSrc->mask->col0, tmpSrc->peak->y - tmpSrc->mask->row0, 2);
     1260        inner = psRegionForSquare (tmpSrc->peak->x, tmpSrc->peak->y, 2);
     1261        int Nsatpix = psImageCountPixelMask (tmpSrc->mask, inner, PSPHOT_MASK_SATURATED);
    11951262
    11961263        // saturated star (size consistent with PSF or larger)
    11971264        // Nsigma should be user-configured parameter
    11981265        bool big = (sigX > (clump.X - clump.dX)) && (sigY > (clump.Y - clump.dY));
     1266        big = true;
    11991267        if ((Nsatpix > 1) && big) {
    1200             tmpSrc->type = PM_SOURCE_SATSTAR;
     1268            tmpSrc->type = PM_SOURCE_STAR;
     1269            tmpSrc->mode = PM_SOURCE_SATSTAR;
    12011270            Nsatstar ++;
    12021271            continue;
     
    12061275        if (Nsatpix > 1) {
    12071276            tmpSrc->type = PM_SOURCE_SATURATED;
     1277            tmpSrc->mode = PM_SOURCE_DEFAULT;
    12081278            Nsat ++;
    12091279            continue;
     
    12151285        if ((sigX < 0.05) || (sigY < 0.05)) {
    12161286            tmpSrc->type = PM_SOURCE_DEFECT;
     1287            tmpSrc->mode = PM_SOURCE_DEFAULT;
    12171288            Ncr ++;
    12181289            continue;
    12191290        }
    12201291
    1221         // likely unsaturated galaxy (too large to be stellar)
     1292        // likely unsaturated extended source (too large to be stellar)
    12221293        if ((sigX > (clump.X + 3*clump.dX)) || (sigY > (clump.Y + 3*clump.dY))) {
    1223             tmpSrc->type = PM_SOURCE_GALAXY;
    1224             Ngal ++;
     1294            tmpSrc->type = PM_SOURCE_EXTENDED;
     1295            tmpSrc->mode = PM_SOURCE_DEFAULT;
     1296            Next ++;
    12251297            continue;
    12261298        }
    12271299
    12281300        // the rest are probable stellar objects
    1229         starsn->data.F32[starsn->n] = SN;
     1301        starsn->data.F32[starsn->n] = tmpSrc->moments->SN;
    12301302        starsn->n ++;
    12311303        Nstar ++;
    12321304
    1233         // PSF star (within 1.5 sigma of clump center
     1305        // PSF star (within 1.5 sigma of clump center, S/N > limit)
    12341306        psF32 radius = hypot ((sigX-clump.X)/clump.dX, (sigY-clump.Y)/clump.dY);
    1235         if ((SN > PSF_SN_LIM) && (radius < 1.5)) {
    1236             tmpSrc->type = PM_SOURCE_PSFSTAR;
     1307        if ((tmpSrc->moments->SN > PSF_SN_LIM) && (radius < 1.5)) {
     1308            tmpSrc->type = PM_SOURCE_STAR;
     1309            tmpSrc->mode = PM_SOURCE_PSFSTAR;
    12371310            Npsf ++;
    12381311            continue;
     
    12401313
    12411314        // random type of star
    1242         tmpSrc->type = PM_SOURCE_OTHER;
     1315        tmpSrc->type = PM_SOURCE_STAR;
     1316        tmpSrc->mode = PM_SOURCE_DEFAULT;
    12431317    }
    12441318
     
    12541328    psTrace (".pmObjects.pmSourceRoughClass", 2, "Nstar:    %3d\n", Nstar);
    12551329    psTrace (".pmObjects.pmSourceRoughClass", 2, "Npsf:     %3d\n", Npsf);
    1256     psTrace (".pmObjects.pmSourceRoughClass", 2, "Ngal:     %3d\n", Ngal);
     1330    psTrace (".pmObjects.pmSourceRoughClass", 2, "Next:     %3d\n", Next);
    12571331    psTrace (".pmObjects.pmSourceRoughClass", 2, "Nsatstar: %3d\n", Nsatstar);
    12581332    psTrace (".pmObjects.pmSourceRoughClass", 2, "Nsat:     %3d\n", Nsat);
     
    12641338
    12651339/** pmSourceDefinePixels()
    1266  *
     1340 * 
    12671341 * Define psImage subarrays for the source located at coordinates x,y on the
    12681342 * image set defined by readout. The pixels defined by this operation consist of
     
    12761350 * example). This function should be used to define a region of interest around a
    12771351 * source, including both source and sky pixels.
    1278  *
     1352 * 
    12791353 * XXX: must code this.
    1280  *
     1354 * 
    12811355 */
    12821356bool pmSourceDefinePixels(
     
    12941368
    12951369/******************************************************************************
    1296 pmSourceSetPixelsCircle(source, image, radius)
    1297  
    1298 XXX: This was replaced by DefinePixels in SDRS.  Remove it.
     1370    pmSourceSetPixelsCircle(source, image, radius)
     1371    
     1372    XXX: This was replaced by DefinePixels in SDRS.  Remove it.
    12991373*****************************************************************************/
    13001374bool pmSourceSetPixelsCircle(pmSource *source,
     
    13691443
    13701444/******************************************************************************
    1371 pmSourceModelGuess(source, model): This function allocates a new
    1372 pmModel structure based on the given modelType specified in the argument list.
    1373 The corresponding pmModelGuess function is returned, and used to
    1374 supply the values of the params array in the pmModel structure.
    1375  
    1376 XXX: Many parameters are based on the src->moments structure, which is in
    1377 image, not subImage coords.  Therefore, the calls to the model evaluation
    1378 functions will be in image, not subImage coords.  Remember this.
     1445    pmSourceModelGuess(source, model): This function allocates a new
     1446    pmModel structure based on the given modelType specified in the argument list. 
     1447    The corresponding pmModelGuess function is returned, and used to
     1448    supply the values of the params array in the pmModel structure. 
     1449    
     1450    XXX: Many parameters are based on the src->moments structure, which is in
     1451    image, not subImage coords.  Therefore, the calls to the model evaluation
     1452    functions will be in image, not subImage coords.  Remember this.
    13791453*****************************************************************************/
    13801454pmModel *pmSourceModelGuess(pmSource *source,
     
    13941468
    13951469/******************************************************************************
    1396 evalModel(source, level, row): a private function which evaluates the
    1397 source->modelPSF function at the specified coords.  The coords are subImage, not
    1398 image coords.
    1399  
    1400 NOTE: The coords are in subImage source->pixel coords, not image coords.
    1401  
    1402 XXX: reverse order of row,col args?
    1403  
    1404 XXX: rename all coords in this file such that their name defines whether
    1405 the coords is in subImage or image space.
    1406  
    1407 XXX: This should probably be a public pmModules function.
    1408  
    1409 XXX: Use static vectors for x.
    1410  
    1411 XXX: Figure out if it's (row, col) or (col, row) for the model functions.
    1412  
    1413 XXX: For a while, the first psVectorAlloc() was generating a seg fault during
    1414 testing.  Try to reproduce that and debug.
     1470    evalModel(source, level, row): a private function which evaluates the
     1471    source->modelPSF function at the specified coords.  The coords are subImage, not
     1472    image coords.
     1473    
     1474    NOTE: The coords are in subImage source->pixel coords, not image coords.
     1475    
     1476    XXX: reverse order of row,col args?
     1477    
     1478    XXX: rename all coords in this file such that their name defines whether
     1479    the coords is in subImage or image space.
     1480    
     1481    XXX: This should probably be a public pmModules function.
     1482    
     1483    XXX: Use static vectors for x.
     1484    
     1485    XXX: Figure out if it's (row, col) or (col, row) for the model functions.
     1486    
     1487    XXX: For a while, the first psVectorAlloc() was generating a seg fault during
     1488    testing.  Try to reproduce that and debug.
    14151489*****************************************************************************/
    14161490
     
    14411515
    14421516/******************************************************************************
    1443 pmSourceContour(src, img, level, mode): For an input subImage, and model, this
    1444 routine returns a psArray of coordinates that evaluate to the specified level.
    1445  
    1446 XXX: Probably should remove the "image" argument.
    1447 XXX: What type should the output coordinate vectors consist of?  col,row?
    1448 XXX: Why a pmArray output?
    1449 XXX: doex x,y correspond with col,row or row/col?
    1450 XXX: What is mode?
    1451 XXX: The top, bottom of the contour is not correctly determined.
    1452 XXX EAM : this function is using the model for the contour, but it should
    1453           be using only the image counts
     1517    pmSourceContour(src, img, level, mode): For an input subImage, and model, this
     1518    routine returns a psArray of coordinates that evaluate to the specified level.
     1519    
     1520    XXX: Probably should remove the "image" argument.
     1521    XXX: What type should the output coordinate vectors consist of?  col,row?
     1522    XXX: Why a pmArray output?
     1523    XXX: doex x,y correspond with col,row or row/col?
     1524    XXX: What is mode?
     1525    XXX: The top, bottom of the contour is not correctly determined.
     1526    XXX EAM : this function is using the model for the contour, but it should
     1527              be using only the image counts
    14541528*****************************************************************************/
    14551529psArray *pmSourceContour(pmSource *source,
     
    14641538    PS_ASSERT_PTR_NON_NULL(source->peak, false);
    14651539    PS_ASSERT_PTR_NON_NULL(source->pixels, false);
    1466     PS_ASSERT_PTR_NON_NULL(source->modelFLT, false);
    1467     // XXX EAM : what is the purpose of modelPSF/modelFLT?
     1540    PS_ASSERT_PTR_NON_NULL(source->modelEXT, false);
     1541    // XXX EAM : what is the purpose of modelPSF/modelEXT?
    14681542
    14691543    //
     
    15581632}
    15591633
    1560 // XXX EAM : these are better starting values, but should be available from metadata?
    1561 #define PM_SOURCE_FIT_MODEL_NUM_ITERATIONS 15
    1562 #define PM_SOURCE_FIT_MODEL_TOLERANCE 0.1
    1563 /******************************************************************************
    1564 pmSourceFitModel(source, model): must create the appropiate arguments to the
    1565 LM minimization routines for the various p_pmMinLM_XXXXXX_Vec() functions.
    1566  
    1567 XXX: should there be a mask value?
    1568 XXX EAM : fit the specified model (not necessarily the one in source)
    1569 *****************************************************************************/
    1570 bool pmSourceFitModel_v5(pmSource *source,
    1571                          pmModel *model,
    1572                          const bool PSF)
     1634// save a static values so they may be set externally
     1635static psF32 PM_SOURCE_FIT_MODEL_NUM_ITERATIONS = 15;
     1636static psF32 PM_SOURCE_FIT_MODEL_TOLERANCE = 0.1;
     1637
     1638bool pmSourceFitModelInit (float nIter, float tol)
     1639{
     1640
     1641    PM_SOURCE_FIT_MODEL_NUM_ITERATIONS = nIter;
     1642    PM_SOURCE_FIT_MODEL_TOLERANCE = tol;
     1643    return true;
     1644}
     1645
     1646bool pmSourceFitModel (pmSource *source,
     1647                       pmModel *model,
     1648                       const bool PSF)
    15731649{
    15741650    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     
    15791655    PS_ASSERT_PTR_NON_NULL(source->mask, false);
    15801656    PS_ASSERT_PTR_NON_NULL(source->weight, false);
     1657
     1658    // XXX EAM : is it necessary for the mask & weight to exist?  the
     1659    //           tests below could be conditions (!NULL)
     1660
    15811661    psBool fitStatus = true;
    15821662    psBool onPic     = true;
    15831663    psBool rc        = true;
    15841664
    1585     // XXX EAM : is it necessary for the mask & weight to exist?  the
    1586     //           tests below could be conditions (!NULL)
    1587 
    15881665    psVector *params = model->params;
    15891666    psVector *dparams = model->dparams;
     
    15921669    pmModelFunc modelFunc = pmModelFunc_GetFunction (model->type);
    15931670
    1594     int nParams = PSF ? params->n - 4 : params->n;
    1595 
    1596     // find the number of valid pixels
    1597     // XXX EAM : this loop and the loop below could just be one pass
    1598     //           using the psArrayAdd and psVectorExtend functions
    1599     psS32 count = 0;
     1671    int nParams = PSF ? 4 : params->n;
     1672
     1673    // maximum number of valid pixels
     1674    psS32 nPix = source->pixels->numRows * source->pixels->numCols;
     1675
     1676    // construct the coordinate and value entries
     1677    psArray *x = psArrayAlloc(nPix);
     1678    psVector *y = psVectorAlloc(nPix, PS_TYPE_F32);
     1679    psVector *yErr = psVectorAlloc(nPix, PS_TYPE_F32);
     1680
     1681    nPix = 0;
    16001682    for (psS32 i = 0; i < source->pixels->numRows; i++) {
    16011683        for (psS32 j = 0; j < source->pixels->numCols; j++) {
    1602             if (source->mask->data.U8[i][j] == 0) {
    1603                 count++;
    1604             }
    1605         }
    1606     }
    1607     if (count <  nParams + 1) {
     1684            // skip masked points
     1685            if (source->mask->data.U8[i][j]) {
     1686                continue;
     1687            }
     1688            // skip zero-weight points
     1689            if (source->weight->data.F32[i][j] == 0) {
     1690                continue;
     1691            }
     1692
     1693            psVector *coord = psVectorAlloc(2, PS_TYPE_F32);
     1694
     1695            // Convert i/j to image space:
     1696            coord->data.F32[0] = (psF32) (j + source->pixels->col0);
     1697            coord->data.F32[1] = (psF32) (i + source->pixels->row0);
     1698            x->data[nPix] = (psPtr *) coord;
     1699            y->data.F32[nPix] = source->pixels->data.F32[i][j];
     1700            // psMinimizeLMChi2 takes wt = 1/dY^2
     1701            yErr->data.F32[nPix] = 1.0 / source->weight->data.F32[i][j];
     1702            nPix++;
     1703        }
     1704    }
     1705    if (nPix <  nParams + 1) {
    16081706        psTrace (".pmObjects.pmSourceFitModel", 4, "insufficient valid pixels\n");
    16091707        psTrace(__func__, 3, "---- %s(false) end ----\n", __func__);
    16101708        model->status = PM_MODEL_BADARGS;
     1709        psFree (x);
     1710        psFree (y);
     1711        psFree (yErr);
    16111712        return(false);
    16121713    }
    1613 
    1614     // construct the coordinate and value entries
    1615     psArray *x = psArrayAlloc(count);
    1616     psVector *y = psVectorAlloc(count, PS_TYPE_F32);
    1617     psVector *yErr = psVectorAlloc(count, PS_TYPE_F32);
    1618     psS32 tmpCnt = 0;
    1619     for (psS32 i = 0; i < source->pixels->numRows; i++) {
    1620         for (psS32 j = 0; j < source->pixels->numCols; j++) {
    1621             if (source->mask->data.U8[i][j] == 0) {
    1622                 psVector *coord = psVectorAlloc(2, PS_TYPE_F32);
    1623                 // XXX: Convert i/j to image space:
    1624                 // XXX EAM: coord order is (x,y) == (col,row)
    1625                 coord->data.F32[0] = (psF32) (j + source->pixels->col0);
    1626                 coord->data.F32[1] = (psF32) (i + source->pixels->row0);
    1627                 x->data[tmpCnt] = (psPtr *) coord;
    1628                 y->data.F32[tmpCnt] = source->pixels->data.F32[i][j];
    1629                 yErr->data.F32[tmpCnt] = sqrt (source->weight->data.F32[i][j]);
    1630                 // XXX EAM : note the wasted effort: we carry dY^2, take sqrt(), then
    1631                 //           the minimization function calculates sq()
    1632                 tmpCnt++;
    1633             }
    1634         }
    1635     }
    1636 
     1714    x->n = nPix;
     1715    y->n = nPix;
     1716    yErr->n = nPix;
     1717
     1718    // XXX EAM : the new minimization API supplies the constraints as a struct
    16371719    psMinimization *myMin = psMinimizationAlloc(PM_SOURCE_FIT_MODEL_NUM_ITERATIONS,
    16381720                            PM_SOURCE_FIT_MODEL_TOLERANCE);
    1639 
    1640     // PSF model only fits first 4 parameters, FLT model fits all
     1721    psMinConstrain *constrain = psMinConstrainAlloc();
     1722
     1723    // PSF model only fits first 4 parameters, EXT model fits all
    16411724    if (PSF) {
    16421725        paramMask = psVectorAlloc (params->n, PS_TYPE_U8);
     
    16481731        }
    16491732    }
    1650 
    1651     // XXX EAM : covar must be F64?
     1733    constrain->paramMask = paramMask;
     1734
     1735    // Set the parameter range checks
     1736    pmModelLimits modelLimits = pmModelLimits_GetFunction (model->type);
     1737    modelLimits (&constrain->paramDelta, &constrain->paramMin, &constrain->paramMax);
     1738
    16521739    psImage *covar = psImageAlloc (params->n, params->n, PS_TYPE_F64);
    16531740
    16541741    psTrace (".pmObjects.pmSourceFitModel", 5, "fitting function\n");
    16551742
    1656     psMinConstrain *constrain = psMinConstrainAlloc();
    1657     constrain->paramMask = paramMask;
    1658     fitStatus = psMinimizeLMChi2(myMin, covar, params, constrain,
    1659                                  x, y, yErr, modelFunc);
    1660     psFree(constrain);
     1743    fitStatus = psMinimizeLMChi2(myMin, covar, params, constrain, x, y, yErr, modelFunc);
    16611744    for (int i = 0; i < dparams->n; i++) {
    16621745        if ((paramMask != NULL) && paramMask->data.U8[i])
     
    16731756    if (paramMask != NULL) {
    16741757        psVector *delta = psVectorAlloc (params->n, PS_TYPE_F64);
    1675         psMinimizeGaussNewtonDelta (delta, params, NULL, x, y, yErr, modelFunc);
     1758        psMinimizeGaussNewtonDelta(delta, params, NULL, x, y, yErr, modelFunc);
    16761759        for (int i = 0; i < dparams->n; i++) {
    16771760            if (!paramMask->data.U8[i])
     
    16981781    }
    16991782
     1783    source->mode |= PM_SOURCE_FITTED;
     1784
    17001785    psFree(x);
    17011786    psFree(y);
     
    17031788    psFree(myMin);
    17041789    psFree(covar);
    1705     psFree(paramMask);
    1706 
    1707     rc = (onPic && fitStatus);
    1708     psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc);
    1709     return(rc);
    1710 }
    1711 
    1712 // XXX EAM : new version with parameter range limits and weight enhancement
    1713 bool pmSourceFitModel (pmSource *source,
    1714                        pmModel *model,
    1715                        const bool PSF)
    1716 {
    1717     psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    1718     PS_ASSERT_PTR_NON_NULL(source, false);
    1719     PS_ASSERT_PTR_NON_NULL(source->moments, false);
    1720     PS_ASSERT_PTR_NON_NULL(source->peak, false);
    1721     PS_ASSERT_PTR_NON_NULL(source->pixels, false);
    1722     PS_ASSERT_PTR_NON_NULL(source->mask, false);
    1723     PS_ASSERT_PTR_NON_NULL(source->weight, false);
    1724 
    1725     // XXX EAM : is it necessary for the mask & weight to exist?  the
    1726     //           tests below could be conditions (!NULL)
    1727 
    1728     psBool fitStatus = true;
    1729     psBool onPic     = true;
    1730     psBool rc        = true;
    1731     psF32  Ro, ymodel;
    1732 
    1733     psVector *params = model->params;
    1734     psVector *dparams = model->dparams;
    1735     psVector *paramMask = NULL;
    1736 
    1737     pmModelFunc modelFunc = pmModelFunc_GetFunction (model->type);
    1738 
    1739     // XXX EAM : I need to use the sky value to constrain the weight model
    1740     int nParams = PSF ? params->n - 4 : params->n;
    1741     psF32 So = params->data.F32[0];
    1742 
    1743     // find the number of valid pixels
    1744     // XXX EAM : this loop and the loop below could just be one pass
    1745     //           using the psArrayAdd and psVectorExtend functions
    1746     psS32 count = 0;
    1747     for (psS32 i = 0; i < source->pixels->numRows; i++) {
    1748         for (psS32 j = 0; j < source->pixels->numCols; j++) {
    1749             if (source->mask->data.U8[i][j] == 0) {
    1750                 count++;
    1751             }
    1752         }
    1753     }
    1754     if (count <  nParams + 1) {
    1755         psTrace (".pmObjects.pmSourceFitModel", 4, "insufficient valid pixels\n");
    1756         psTrace(__func__, 3, "---- %s(false) end ----\n", __func__);
    1757         model->status = PM_MODEL_BADARGS;
    1758         return(false);
    1759     }
    1760 
    1761     // construct the coordinate and value entries
    1762     psArray *x = psArrayAlloc(count);
    1763     psVector *y = psVectorAlloc(count, PS_TYPE_F32);
    1764     psVector *yErr = psVectorAlloc(count, PS_TYPE_F32);
    1765     psS32 tmpCnt = 0;
    1766     for (psS32 i = 0; i < source->pixels->numRows; i++) {
    1767         for (psS32 j = 0; j < source->pixels->numCols; j++) {
    1768             if (source->mask->data.U8[i][j] == 0) {
    1769                 psVector *coord = psVectorAlloc(2, PS_TYPE_F32);
    1770                 // XXX: Convert i/j to image space:
    1771                 // XXX EAM: coord order is (x,y) == (col,row)
    1772                 coord->data.F32[0] = (psF32) (j + source->pixels->col0);
    1773                 coord->data.F32[1] = (psF32) (i + source->pixels->row0);
    1774                 x->data[tmpCnt] = (psPtr *) coord;
    1775                 y->data.F32[tmpCnt] = source->pixels->data.F32[i][j];
    1776 
    1777                 // compare observed flux to model flux to adjust weight
    1778                 ymodel = modelFunc (NULL, model->params, coord);
    1779 
    1780                 // this test enhances the weight based on deviation from the model flux
    1781                 Ro = 1.0 + fabs (y->data.F32[tmpCnt] - ymodel) / sqrt(PS_SQR(ymodel - So) + PS_SQR(So));
    1782 
    1783                 // psMinimizeLMChi2_EAM takes wt = 1/dY^2
    1784                 if (source->weight->data.F32[i][j] == 0) {
    1785                     yErr->data.F32[tmpCnt] = 0.0;
    1786                 } else {
    1787                     yErr->data.F32[tmpCnt] = 1.0 / (source->weight->data.F32[i][j] * Ro);
    1788                 }
    1789                 tmpCnt++;
    1790             }
    1791         }
    1792     }
    1793 
    1794     psMinimization *myMin = psMinimizationAlloc(PM_SOURCE_FIT_MODEL_NUM_ITERATIONS,
    1795                             PM_SOURCE_FIT_MODEL_TOLERANCE);
    1796 
    1797     // PSF model only fits first 4 parameters, FLT model fits all
    1798     if (PSF) {
    1799         paramMask = psVectorAlloc (params->n, PS_TYPE_U8);
    1800         for (int i = 0; i < 4; i++) {
    1801             paramMask->data.U8[i] = 0;
    1802         }
    1803         for (int i = 4; i < paramMask->n; i++) {
    1804             paramMask->data.U8[i] = 1;
    1805         }
    1806     }
    1807 
    1808     // XXX EAM : I've added three types of parameter range checks
    1809     // XXX EAM : this requires my new psMinimization functions
    1810     pmModelLimits modelLimits = pmModelLimits_GetFunction (model->type);
    1811     psVector *beta_lim = NULL;
    1812     psVector *params_min = NULL;
    1813     psVector *params_max = NULL;
    1814 
    1815     // XXX EAM : in this implementation, I pass in the limits with the covar matrix.
    1816     //           in the SDRS, I define a new psMinimization which will take these in
    1817     psImage *covar = psImageAlloc (params->n, 3, PS_TYPE_F64);
    1818     modelLimits (&beta_lim, &params_min, &params_max);
    1819     for (int i = 0; i < params->n; i++) {
    1820         covar->data.F64[0][i] = beta_lim->data.F32[i];
    1821         covar->data.F64[1][i] = params_min->data.F32[i];
    1822         covar->data.F64[2][i] = params_max->data.F32[i];
    1823     }
    1824 
    1825     psTrace (".pmObjects.pmSourceFitModel", 5, "fitting function\n");
    1826     psMinConstrain *constrain = psMinConstrainAlloc();
    1827     constrain->paramMask = paramMask;
    1828     fitStatus = psMinimizeLMChi2(myMin, covar, params, constrain,
    1829                                  x, y, yErr, modelFunc);
     1790    psFree(constrain->paramMask);
     1791    psFree(constrain->paramMin);
     1792    psFree(constrain->paramMax);
     1793    psFree(constrain->paramDelta);
    18301794    psFree(constrain);
    1831     for (int i = 0; i < dparams->n; i++) {
    1832         if ((paramMask != NULL) && paramMask->data.U8[i])
    1833             continue;
    1834         dparams->data.F32[i] = sqrt(covar->data.F64[i][i]);
    1835     }
    1836 
    1837     // XXX EAM: we need to do something (give an error?) if rc is false
    1838     // XXX EAM: psMinimizeLMChi2 does not check convergence
    1839 
    1840     // XXX EAM: save the resulting chisq, nDOF, nIter
    1841     model->chisq = myMin->value;
    1842     model->nIter = myMin->iter;
    1843     model->nDOF  = y->n - nParams;
    1844 
    1845     // XXX EAM get the Gauss-Newton distance for fixed model parameters
    1846     if (paramMask != NULL) {
    1847         psVector *delta = psVectorAlloc (params->n, PS_TYPE_F64);
    1848         psMinimizeGaussNewtonDelta(delta, params, NULL, x, y, yErr, modelFunc);
    1849         for (int i = 0; i < dparams->n; i++) {
    1850             if (!paramMask->data.U8[i])
    1851                 continue;
    1852             dparams->data.F32[i] = delta->data.F64[i];
    1853         }
    1854     }
    1855 
    1856     // set the model success or failure status
    1857     if (!fitStatus) {
    1858         model->status = PM_MODEL_NONCONVERGE;
    1859     } else {
    1860         model->status = PM_MODEL_SUCCESS;
    1861     }
    1862 
    1863     // XXX models can go insane: reject these
    1864     onPic &= (params->data.F32[2] >= source->pixels->col0);
    1865     onPic &= (params->data.F32[2] <  source->pixels->col0 + source->pixels->numCols);
    1866     onPic &= (params->data.F32[3] >= source->pixels->row0);
    1867     onPic &= (params->data.F32[3] <  source->pixels->row0 + source->pixels->numRows);
    1868     if (!onPic) {
    1869         model->status = PM_MODEL_OFFIMAGE;
    1870     }
    1871 
    1872     psFree(x);
    1873     psFree(y);
    1874     psFree(yErr);
    1875     psFree(myMin);
    1876     psFree(covar);
    1877     psFree(paramMask);
    18781795
    18791796    rc = (onPic && fitStatus);
Note: See TracChangeset for help on using the changeset viewer.