IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 6183


Ignore:
Timestamp:
Jan 22, 2006, 11:12:20 AM (21 years ago)
Author:
magnier
Message:

fixed minor bugs in pmSourceFitModelInit

Location:
branches/eam_rel9_p0/psModules/src/objects
Files:
2 edited

Legend:

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

    r6182 r6183  
    66 *  @author EAM, IfA: significant modifications.
    77 *
    8  *  @version $Revision: 1.5.4.3 $ $Name: not supported by cvs2svn $
    9  *  @date $Date: 2006-01-22 20:20:47 $
     8 *  @version $Revision: 1.5.4.4 $ $Name: not supported by cvs2svn $
     9 *  @date $Date: 2006-01-22 21:12:19 $
    1010 *
    1111 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
    … …  
    884884            // XXX EAM : should this limit be user-defined?
    885885            if (PS_SQR(pDiff) < wDiff) {
    886 
    887                 Var += wDiff;
    888                 Sum += pDiff;
    889 
    890                 psF32 xWght = xDiff * pDiff;
    891                 psF32 yWght = yDiff * pDiff;
    892 
    893                 X1  += xWght;
    894                 Y1  += yWght;
    895                 XY  += xDiff * yWght;
    896 
    897                 X2  += xDiff * xWght;
    898                 Y2  += yDiff * yWght;
    899 
    900                 peakPixel = PS_MAX (vPix[row][col], peakPixel);
    901                 numPixels++;
    902             }
    903         }
    904 
    905         // if we have less than (1/4) of the possible pixels, force a retry
    906         // XXX EAM - the limit is a bit arbitrary.  make it user defined?
    907         if ((numPixels < 0.75*R2) || (Sum <= 0)) {
    908             psTrace (".psModules.pmSourceMoments", 3, "no valid pixels for source\n");
    909             psTrace(__func__, 3, "---- %s(false) end ----\n", __func__);
    910             return (false);
    911         }
    912 
    913         psTrace (".psModules.pmSourceMoments", 5,
    914                  "sky: %f  Sum: %f  X1: %f  Y1: %f  X2: %f  Y2: %f  XY: %f  Npix: %d\n",
    915                  sky, Sum, X1, Y1, X2, Y2, XY, numPixels);
    916 
    917         //
    918         // first moment X  = X1/Sum + xc
    919         // second moment X = sqrt (X2/Sum - (X1/Sum)^2)
    920         // Sxy             = XY / Sum
    921         //
    922         x = X1/Sum;
    923         y = Y1/Sum;
    924         if ((fabs(x) > radius) || (fabs(y) > radius)) {
    925             psTrace (".psModules.pmSourceMoments", 3,
    926                      "large centroid swing; invalid peak %d, %d\n",
    927                      source->peak->x, source->peak->y);
    928             psTrace(__func__, 3, "---- %s(false) end ----\n", __func__);
    929             return (false);
    930         }
    931 
    932         source->moments->x = x + xPeak;
    933         source->moments->y = y + yPeak;
    934 
    935         // XXX EAM : Sxy needs to have x*y subtracted
    936         source->moments->Sxy = XY/Sum - x*y;
    937         source->moments->Sum = Sum;
    938         source->moments->SN  = Sum / sqrt(Var);
    939         source->moments->Peak = peakPixel;
    940         source->moments->nPixels = numPixels;
    941 
    942         // XXX EAM : these values can be negative, so we need to limit the range
    943         source->moments->Sx = sqrt(PS_MAX(X2/Sum - PS_SQR(x), 0));
    944         source->moments->Sy = sqrt(PS_MAX(Y2/Sum - PS_SQR(y), 0));
    945 
    946         psTrace (".psModules.pmSourceMoments", 4,
    947                  "sky: %f  Sum: %f  x: %f  y: %f  Sx: %f  Sy: %f  Sxy: %f\n",
    948                  sky, Sum, source->moments->x, source->moments->y,
    949                  source->moments->Sx, source->moments->Sy, source->moments->Sxy);
    950 
    951         psTrace(__func__, 3, "---- %s(true) end ----\n", __func__);
    952         return(true);
    953     }
    954 
    955     // XXX EAM : I used
    956     int pmComparePeakAscend (const void **a, const void **b) {
    957         psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    958         pmPeak *A = *(pmPeak **)a;
    959         pmPeak *B = *(pmPeak **)b;
    960 
    961         psF32 diff;
    962 
    963         diff = A->counts - B->counts;
    964         if (diff < FLT_EPSILON) {
    965             psTrace(__func__, 3, "---- %s(-1) end ----\n", __func__);
    966             return (-1);
    967         } else if (diff > FLT_EPSILON) {
    968             psTrace(__func__, 3, "---- %s(+1) end ----\n", __func__);
    969             return (+1);
    970         }
    971         psTrace(__func__, 3, "---- %s(0) end ----\n", __func__);
    972         return (0);
    973     }
    974 
    975     int pmComparePeakDescend (const void **a, const void **b) {
    976         psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    977         pmPeak *A = *(pmPeak **)a;
    978         pmPeak *B = *(pmPeak **)b;
    979 
    980         psF32 diff;
    981 
    982         diff = A->counts - B->counts;
    983         if (diff < FLT_EPSILON) {
    984             psTrace(__func__, 3, "---- %s(+1) end ----\n", __func__);
    985             return (+1);
    986         } else if (diff > FLT_EPSILON) {
    987             psTrace(__func__, 3, "---- %s(-1) end ----\n", __func__);
    988             return (-1);
    989         }
    990         psTrace(__func__, 3, "---- %s(0) end ----\n", __func__);
    991         return (0);
    992     }
    993 
    994     /******************************************************************************
     886                continue;
     887            }
     888
     889            Var += wDiff;
     890            Sum += pDiff;
     891
     892            psF32 xWght = xDiff * pDiff;
     893            psF32 yWght = yDiff * pDiff;
     894
     895            X1  += xWght;
     896            Y1  += yWght;
     897            XY  += xDiff * yWght;
     898
     899            X2  += xDiff * xWght;
     900            Y2  += yDiff * yWght;
     901
     902            peakPixel = PS_MAX (vPix[row][col], peakPixel);
     903            numPixels++;
     904        }
     905    }
     906
     907    // if we have less than (1/4) of the possible pixels, force a retry
     908    // XXX EAM - the limit is a bit arbitrary.  make it user defined?
     909    if ((numPixels < 0.75*R2) || (Sum <= 0)) {
     910        psTrace (".psModules.pmSourceMoments", 3, "no valid pixels for source\n");
     911        psTrace(__func__, 3, "---- %s(false) end ----\n", __func__);
     912        return (false);
     913    }
     914
     915    psTrace (".psModules.pmSourceMoments", 5,
     916             "sky: %f  Sum: %f  X1: %f  Y1: %f  X2: %f  Y2: %f  XY: %f  Npix: %d\n",
     917             sky, Sum, X1, Y1, X2, Y2, XY, numPixels);
     918
     919    //
     920    // first moment X  = X1/Sum + xc
     921    // second moment X = sqrt (X2/Sum - (X1/Sum)^2)
     922    // Sxy             = XY / Sum
     923    //
     924    x = X1/Sum;
     925    y = Y1/Sum;
     926    if ((fabs(x) > radius) || (fabs(y) > radius)) {
     927        psTrace (".psModules.pmSourceMoments", 3,
     928                 "large centroid swing; invalid peak %d, %d\n",
     929                 source->peak->x, source->peak->y);
     930        psTrace(__func__, 3, "---- %s(false) end ----\n", __func__);
     931        return (false);
     932    }
     933
     934    source->moments->x = x + xPeak;
     935    source->moments->y = y + yPeak;
     936
     937    // XXX EAM : Sxy needs to have x*y subtracted
     938    source->moments->Sxy = XY/Sum - x*y;
     939    source->moments->Sum = Sum;
     940    source->moments->SN  = Sum / sqrt(Var);
     941    source->moments->Peak = peakPixel;
     942    source->moments->nPixels = numPixels;
     943
     944    // XXX EAM : these values can be negative, so we need to limit the range
     945    source->moments->Sx = sqrt(PS_MAX(X2/Sum - PS_SQR(x), 0));
     946    source->moments->Sy = sqrt(PS_MAX(Y2/Sum - PS_SQR(y), 0));
     947
     948    psTrace (".psModules.pmSourceMoments", 4,
     949             "sky: %f  Sum: %f  x: %f  y: %f  Sx: %f  Sy: %f  Sxy: %f\n",
     950             sky, Sum, source->moments->x, source->moments->y,
     951             source->moments->Sx, source->moments->Sy, source->moments->Sxy);
     952
     953    psTrace(__func__, 3, "---- %s(true) end ----\n", __func__);
     954    return(true);
     955}
     956
     957// XXX EAM : I used
     958int pmComparePeakAscend (const void **a, const void **b)
     959{
     960    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     961    pmPeak *A = *(pmPeak **)a;
     962    pmPeak *B = *(pmPeak **)b;
     963
     964    psF32 diff;
     965
     966    diff = A->counts - B->counts;
     967    if (diff < FLT_EPSILON) {
     968        psTrace(__func__, 3, "---- %s(-1) end ----\n", __func__);
     969        return (-1);
     970    } else if (diff > FLT_EPSILON) {
     971        psTrace(__func__, 3, "---- %s(+1) end ----\n", __func__);
     972        return (+1);
     973    }
     974    psTrace(__func__, 3, "---- %s(0) end ----\n", __func__);
     975    return (0);
     976}
     977
     978int pmComparePeakDescend (const void **a, const void **b)
     979{
     980    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     981    pmPeak *A = *(pmPeak **)a;
     982    pmPeak *B = *(pmPeak **)b;
     983
     984    psF32 diff;
     985
     986    diff = A->counts - B->counts;
     987    if (diff < FLT_EPSILON) {
     988        psTrace(__func__, 3, "---- %s(+1) end ----\n", __func__);
     989        return (+1);
     990    } else if (diff > FLT_EPSILON) {
     991        psTrace(__func__, 3, "---- %s(-1) end ----\n", __func__);
     992        return (-1);
     993    }
     994    psTrace(__func__, 3, "---- %s(0) end ----\n", __func__);
     995    return (0);
     996}
     997
     998/******************************************************************************
    995999    pmSourcePSFClump(source, metadata): Find the likely PSF clump in the
    9961000    sigma-x, sigma-y plane. return 0,0 clump in case of error.
    997     *****************************************************************************/
    998 
    999     // XXX EAM include a S/N cutoff in selecting the sources?
    1000     pmPSFClump pmSourcePSFClump(psArray *sources, psMetadata *metadata) {
    1001         psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    1002 
    1003         # define NPIX 10
    1004         # define SCALE 0.1
    1005 
    1006         psArray *peaks  = NULL;
    1007         pmPSFClump emptyClump = {0.0, 0.0, 0.0, 0.0};
    1008         pmPSFClump psfClump = emptyClump;
    1009 
    1010         PS_ASSERT_PTR_NON_NULL(sources, emptyClump);
    1011         PS_ASSERT_PTR_NON_NULL(metadata, emptyClump);
    1012 
    1013         // find the sigmaX, sigmaY clump
     1001*****************************************************************************/
     1002
     1003// XXX EAM include a S/N cutoff in selecting the sources?
     1004pmPSFClump pmSourcePSFClump(psArray *sources, psMetadata *metadata)
     1005{
     1006    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     1007
     1008    # define NPIX 10
     1009    # define SCALE 0.1
     1010
     1011    psArray *peaks  = NULL;
     1012    pmPSFClump emptyClump = {0.0, 0.0, 0.0, 0.0};
     1013    pmPSFClump psfClump = emptyClump;
     1014
     1015    PS_ASSERT_PTR_NON_NULL(sources, emptyClump);
     1016    PS_ASSERT_PTR_NON_NULL(metadata, emptyClump);
     1017
     1018    // find the sigmaX, sigmaY clump
     1019    {
     1020        psStats *stats  = NULL;
     1021        psImage *splane = NULL;
     1022        int binX, binY;
     1023        bool status;
     1024
     1025        psF32 SX_MAX = psMetadataLookupF32 (&status, metadata, "MOMENTS_SX_MAX");
     1026        if (!status)
     1027            SX_MAX = 10.0;
     1028        psF32 SY_MAX = psMetadataLookupF32 (&status, metadata, "MOMENTS_SY_MAX");
     1029        if (!status)
     1030            SY_MAX = 10.0;
     1031
     1032        // construct a sigma-plane image
     1033        // psImageAlloc does zero the data
     1034        splane = psImageAlloc (SX_MAX/SCALE, SY_MAX/SCALE, PS_TYPE_F32);
     1035        for (int i = 0; i < splane->numRows; i++)
    10141036        {
    1015             psStats *stats  = NULL;
    1016             psImage *splane = NULL;
    1017             int binX, binY;
    1018             bool status;
    1019 
    1020             psF32 SX_MAX = psMetadataLookupF32 (&status, metadata, "MOMENTS_SX_MAX");
    1021             if (!status)
    1022                 SX_MAX = 10.0;
    1023             psF32 SY_MAX = psMetadataLookupF32 (&status, metadata, "MOMENTS_SY_MAX");
    1024             if (!status)
    1025                 SY_MAX = 10.0;
    1026 
    1027             // construct a sigma-plane image
    1028             // psImageAlloc does zero the data
    1029             splane = psImageAlloc (SX_MAX/SCALE, SY_MAX/SCALE, PS_TYPE_F32);
    1030             for (int i = 0; i < splane->numRows; i++)
    1031             {
    1032                 memset (splane->data.F32[i], 0, splane->numCols*sizeof(PS_TYPE_F32));
    1033             }
    1034 
    1035             // place the sources in the sigma-plane image (ignore 0,0 values?)
    1036             for (psS32 i = 0 ; i < sources->n ; i++)
    1037             {
    1038                 pmSource *tmpSrc = (pmSource *) sources->data[i];
    1039                 if (tmpSrc == NULL) {
    1040                     continue;
    1041                 }
    1042                 if (tmpSrc->moments == NULL) {
    1043                     continue;
    1044                 }
    1045 
    1046                 // Sx,Sy are limited at 0.  a peak at 0,0 is artificial
    1047                 if ((fabs(tmpSrc->moments->Sx) < FLT_EPSILON) && (fabs(tmpSrc->moments->Sy) < FLT_EPSILON)) {
    1048                     continue;
    1049                 }
    1050 
    1051                 // for the moment, force splane dimensions to be 10x10 image pix
    1052                 binX = tmpSrc->moments->Sx/SCALE;
    1053                 if (binX < 0)
    1054                     continue;
    1055                 if (binX >= splane->numCols)
    1056                     continue;
    1057 
    1058                 binY = tmpSrc->moments->Sy/SCALE;
    1059                 if (binY < 0)
    1060                     continue;
    1061                 if (binY >= splane->numRows)
    1062                     continue;
    1063 
    1064                 splane->data.F32[binY][binX] += 1.0;
    1065             }
    1066 
    1067             // find the peak in this image
    1068             stats = psStatsAlloc (PS_STAT_MAX);
    1069             stats = psImageStats (stats, splane, NULL, 0);
    1070             peaks = pmFindImagePeaks (splane, stats[0].max / 2);
    1071             psTrace (".pmObjects.pmSourceRoughClass", 2, "clump threshold is %f\n", stats[0].max/2);
    1072 
    1073             psFree (splane);
    1074             psFree (stats);
    1075 
    1076         }
    1077         // XXX EAM : possible errors:
    1078         //           1) no peak in splane
    1079         //           2) no significant peak in splane
    1080 
    1081         // measure statistics on Sx, Sy if Sx, Sy within range of clump
     1037            memset (splane->data.F32[i], 0, splane->numCols*sizeof(PS_TYPE_F32));
     1038        }
     1039
     1040        // place the sources in the sigma-plane image (ignore 0,0 values?)
     1041        for (psS32 i = 0 ; i < sources->n ; i++)
    10821042        {
    1083             pmPeak *clump;
    1084             psF32 minSx, maxSx;
    1085             psF32 minSy, maxSy;
    1086             psVector *tmpSx = NULL;
    1087             psVector *tmpSy = NULL;
    1088             psStats *stats  = NULL;
    1089 
    1090             // XXX EAM : this lets us takes the single highest peak
    1091             psArraySort (peaks, pmComparePeakDescend);
    1092             clump = peaks->data[0];
    1093             psTrace (".pmObjects.pmSourceRoughClass", 2, "clump is at %d, %d (%f)\n", clump->x, clump->y, clump->counts);
    1094 
    1095             // define section window for clump
    1096             minSx = clump->x * SCALE - 0.2;
    1097             maxSx = clump->x * SCALE + 0.2;
    1098             minSy = clump->y * SCALE - 0.2;
    1099             maxSy = clump->y * SCALE + 0.2;
    1100 
    1101             tmpSx = psVectorAlloc (sources->n, PS_TYPE_F32);
    1102             tmpSy = psVectorAlloc (sources->n, PS_TYPE_F32);
    1103             tmpSx->n = 0;
    1104             tmpSy->n = 0;
    1105 
    1106             // XXX clip sources based on flux?
    1107             // create vectors with Sx, Sy values in window
    1108             for (psS32 i = 0 ; i < sources->n ; i++)
    1109             {
    1110                 pmSource *tmpSrc = (pmSource *) sources->data[i];
    1111 
    1112                 if (tmpSrc->moments->Sx < minSx)
    1113                     continue;
    1114                 if (tmpSrc->moments->Sx > maxSx)
    1115                     continue;
    1116                 if (tmpSrc->moments->Sy < minSy)
    1117                     continue;
    1118                 if (tmpSrc->moments->Sy > maxSy)
    1119                     continue;
    1120                 tmpSx->data.F32[tmpSx->n] = tmpSrc->moments->Sx;
    1121                 tmpSy->data.F32[tmpSy->n] = tmpSrc->moments->Sy;
    1122                 tmpSx->n++;
    1123                 tmpSy->n++;
    1124                 if (tmpSx->n == tmpSx->nalloc) {
    1125                     psVectorRealloc (tmpSx, tmpSx->nalloc + 100);
    1126                     psVectorRealloc (tmpSy, tmpSy->nalloc + 100);
    1127                 }
    1128             }
    1129 
    1130             // measures stats of Sx, Sy
    1131             stats = psStatsAlloc (PS_STAT_CLIPPED_MEAN | PS_STAT_CLIPPED_STDEV);
    1132 
    1133             stats = psVectorStats (stats, tmpSx, NULL, NULL, 0);
    1134             psfClump.X  = stats->clippedMean;
    1135             psfClump.dX = stats->clippedStdev;
    1136 
    1137             stats = psVectorStats (stats, tmpSy, NULL, NULL, 0);
    1138             psfClump.Y  = stats->clippedMean;
    1139             psfClump.dY = stats->clippedStdev;
    1140 
    1141             psTrace (".pmObjects.pmSourceRoughClass", 2, "clump  X,  Y: %f, %f\n", psfClump.X, psfClump.Y);
    1142             psTrace (".pmObjects.pmSourceRoughClass", 2, "clump DX, DY: %f, %f\n", psfClump.dX, psfClump.dY);
    1143             // these values should be pushed on the metadata somewhere
    1144 
    1145             psFree (stats);
    1146             psFree (peaks);
    1147             psFree (tmpSx);
    1148             psFree (tmpSy);
    1149         }
    1150 
    1151         psTrace(__func__, 3, "---- %s() end ----\n", __func__);
    1152         return (psfClump);
    1153     }
    1154 
    1155     /******************************************************************************
     1043            pmSource *tmpSrc = (pmSource *) sources->data[i];
     1044            if (tmpSrc == NULL) {
     1045                continue;
     1046            }
     1047            if (tmpSrc->moments == NULL) {
     1048                continue;
     1049            }
     1050
     1051            // Sx,Sy are limited at 0.  a peak at 0,0 is artificial
     1052            if ((fabs(tmpSrc->moments->Sx) < FLT_EPSILON) && (fabs(tmpSrc->moments->Sy) < FLT_EPSILON)) {
     1053                continue;
     1054            }
     1055
     1056            // for the moment, force splane dimensions to be 10x10 image pix
     1057            binX = tmpSrc->moments->Sx/SCALE;
     1058            if (binX < 0)
     1059                continue;
     1060            if (binX >= splane->numCols)
     1061                continue;
     1062
     1063            binY = tmpSrc->moments->Sy/SCALE;
     1064            if (binY < 0)
     1065                continue;
     1066            if (binY >= splane->numRows)
     1067                continue;
     1068
     1069            splane->data.F32[binY][binX] += 1.0;
     1070        }
     1071
     1072        // find the peak in this image
     1073        stats = psStatsAlloc (PS_STAT_MAX);
     1074        stats = psImageStats (stats, splane, NULL, 0);
     1075        peaks = pmFindImagePeaks (splane, stats[0].max / 2);
     1076        psTrace (".pmObjects.pmSourceRoughClass", 2, "clump threshold is %f\n", stats[0].max/2);
     1077
     1078        psFree (splane);
     1079        psFree (stats);
     1080
     1081    }
     1082    // XXX EAM : possible errors:
     1083    //           1) no peak in splane
     1084    //           2) no significant peak in splane
     1085
     1086    // measure statistics on Sx, Sy if Sx, Sy within range of clump
     1087    {
     1088        pmPeak *clump;
     1089        psF32 minSx, maxSx;
     1090        psF32 minSy, maxSy;
     1091        psVector *tmpSx = NULL;
     1092        psVector *tmpSy = NULL;
     1093        psStats *stats  = NULL;
     1094
     1095        // XXX EAM : this lets us takes the single highest peak
     1096        psArraySort (peaks, pmComparePeakDescend);
     1097        clump = peaks->data[0];
     1098        psTrace (".pmObjects.pmSourceRoughClass", 2, "clump is at %d, %d (%f)\n", clump->x, clump->y, clump->counts);
     1099
     1100        // define section window for clump
     1101        minSx = clump->x * SCALE - 0.2;
     1102        maxSx = clump->x * SCALE + 0.2;
     1103        minSy = clump->y * SCALE - 0.2;
     1104        maxSy = clump->y * SCALE + 0.2;
     1105
     1106        tmpSx = psVectorAlloc (sources->n, PS_TYPE_F32);
     1107        tmpSy = psVectorAlloc (sources->n, PS_TYPE_F32);
     1108        tmpSx->n = 0;
     1109        tmpSy->n = 0;
     1110
     1111        // XXX clip sources based on flux?
     1112        // create vectors with Sx, Sy values in window
     1113        for (psS32 i = 0 ; i < sources->n ; i++)
     1114        {
     1115            pmSource *tmpSrc = (pmSource *) sources->data[i];
     1116
     1117            if (tmpSrc->moments->Sx < minSx)
     1118                continue;
     1119            if (tmpSrc->moments->Sx > maxSx)
     1120                continue;
     1121            if (tmpSrc->moments->Sy < minSy)
     1122                continue;
     1123            if (tmpSrc->moments->Sy > maxSy)
     1124                continue;
     1125            tmpSx->data.F32[tmpSx->n] = tmpSrc->moments->Sx;
     1126            tmpSy->data.F32[tmpSy->n] = tmpSrc->moments->Sy;
     1127            tmpSx->n++;
     1128            tmpSy->n++;
     1129            if (tmpSx->n == tmpSx->nalloc) {
     1130                psVectorRealloc (tmpSx, tmpSx->nalloc + 100);
     1131                psVectorRealloc (tmpSy, tmpSy->nalloc + 100);
     1132            }
     1133        }
     1134
     1135        // measures stats of Sx, Sy
     1136        stats = psStatsAlloc (PS_STAT_CLIPPED_MEAN | PS_STAT_CLIPPED_STDEV);
     1137
     1138        stats = psVectorStats (stats, tmpSx, NULL, NULL, 0);
     1139        psfClump.X  = stats->clippedMean;
     1140        psfClump.dX = stats->clippedStdev;
     1141
     1142        stats = psVectorStats (stats, tmpSy, NULL, NULL, 0);
     1143        psfClump.Y  = stats->clippedMean;
     1144        psfClump.dY = stats->clippedStdev;
     1145
     1146        psTrace (".pmObjects.pmSourceRoughClass", 2, "clump  X,  Y: %f, %f\n", psfClump.X, psfClump.Y);
     1147        psTrace (".pmObjects.pmSourceRoughClass", 2, "clump DX, DY: %f, %f\n", psfClump.dX, psfClump.dY);
     1148        // these values should be pushed on the metadata somewhere
     1149
     1150        psFree (stats);
     1151        psFree (peaks);
     1152        psFree (tmpSx);
     1153        psFree (tmpSy);
     1154    }
     1155
     1156    psTrace(__func__, 3, "---- %s() end ----\n", __func__);
     1157    return (psfClump);
     1158}
     1159
     1160/******************************************************************************
    11561161    pmSourceRoughClass(source, metadata): make a guess at the source
    11571162    classification.
    … …  
    11621167     
    11631168    EAM: I moved S/N calculation to pmSourceMoments, using weight image
    1164     *****************************************************************************/
    1165 
    1166     bool pmSourceRoughClass(psArray *sources, psMetadata *metadata, pmPSFClump clump) {
    1167         psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    1168 
    1169         psBool rc = true;
    1170 
    1171         int Nsat     = 0;
    1172         int Next     = 0;
    1173         int Nstar    = 0;
    1174         int Npsf     = 0;
    1175         int Ncr      = 0;
    1176         int Nsatstar = 0;
    1177         // psRegion allArray = psRegionSet (0, 0, 0, 0);
    1178         psRegion inner;
    1179 
    1180         // report stats on S/N values for star-like objects
    1181         psVector *starsn = psVectorAlloc (sources->n, PS_TYPE_F32);
    1182         starsn->n = 0;
    1183 
    1184         // check return status value (do these exist?)
    1185         bool status;
    1186         psF32 PSF_SN_LIM = psMetadataLookupF32 (&status, metadata, "PSF_SN_LIM");
    1187 
    1188         // XXX allow clump size to be scaled relative to sigmas?
    1189         // make rough IDs based on clumpX,Y,DX,DY
    1190         for (psS32 i = 0 ; i < sources->n ; i++) {
    1191 
    1192             pmSource *tmpSrc = (pmSource *) sources->data[i];
    1193 
    1194             tmpSrc->peak->class = 0;
    1195 
    1196             psF32 sigX = tmpSrc->moments->Sx;
    1197             psF32 sigY = tmpSrc->moments->Sy;
    1198 
    1199             // XXX EAM : can we use the value of SATURATE if mask is NULL?
    1200             inner = psRegionForSquare (tmpSrc->peak->x - tmpSrc->mask->col0, tmpSrc->peak->y - tmpSrc->mask->row0, 2);
    1201             int Nsatpix = psImageCountPixelMask (tmpSrc->mask, inner, PSPHOT_MASK_SATURATED);
    1202 
    1203             // saturated star (size consistent with PSF or larger)
    1204             // Nsigma should be user-configured parameter
    1205             bool big = (sigX > (clump.X - clump.dX)) && (sigY > (clump.Y - clump.dY));
    1206             big = true;
    1207             if ((Nsatpix > 1) && big) {
    1208                 tmpSrc->type = PM_SOURCE_STAR;
    1209                 tmpSrc->mode = PM_SOURCE_SATSTAR;
    1210                 Nsatstar ++;
    1211                 continue;
    1212             }
    1213 
    1214             // saturated object (not a star, eg bleed trails, hot pixels)
    1215             if (Nsatpix > 1) {
    1216                 tmpSrc->type = PM_SOURCE_SATURATED;
    1217                 tmpSrc->mode = PM_SOURCE_DEFAULT;
    1218                 Nsat ++;
    1219                 continue;
    1220             }
    1221 
    1222             // likely defect (too small to be stellar) (push out to 3 sigma)
    1223             // low S/N objects which are small are probably stellar
    1224             // only set candidate defects if
    1225             if ((sigX < 0.05) || (sigY < 0.05)) {
    1226                 tmpSrc->type = PM_SOURCE_DEFECT;
    1227                 tmpSrc->mode = PM_SOURCE_DEFAULT;
    1228                 Ncr ++;
    1229                 continue;
    1230             }
    1231 
    1232             // likely unsaturated extended source (too large to be stellar)
    1233             if ((sigX > (clump.X + 3*clump.dX)) || (sigY > (clump.Y + 3*clump.dY))) {
    1234                 tmpSrc->type = PM_SOURCE_EXTENDED;
    1235                 tmpSrc->mode = PM_SOURCE_DEFAULT;
    1236                 Next ++;
    1237                 continue;
    1238             }
    1239 
    1240             // the rest are probable stellar objects
    1241             starsn->data.F32[starsn->n] = tmpSrc->moments->SN;
    1242             starsn->n ++;
    1243             Nstar ++;
    1244 
    1245             // PSF star (within 1.5 sigma of clump center, S/N > limit)
    1246             psF32 radius = hypot ((sigX-clump.X)/clump.dX, (sigY-clump.Y)/clump.dY);
    1247             if ((tmpSrc->moments->SN > PSF_SN_LIM) && (radius < 1.5)) {
    1248                 tmpSrc->type = PM_SOURCE_STAR;
    1249                 tmpSrc->mode = PM_SOURCE_PSFSTAR;
    1250                 Npsf ++;
    1251                 continue;
    1252             }
    1253 
    1254             // random type of star
     1169*****************************************************************************/
     1170
     1171bool pmSourceRoughClass(psArray *sources, psMetadata *metadata, pmPSFClump clump)
     1172{
     1173    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     1174
     1175    psBool rc = true;
     1176
     1177    int Nsat     = 0;
     1178    int Next     = 0;
     1179    int Nstar    = 0;
     1180    int Npsf     = 0;
     1181    int Ncr      = 0;
     1182    int Nsatstar = 0;
     1183    // psRegion allArray = psRegionSet (0, 0, 0, 0);
     1184    psRegion inner;
     1185
     1186    // report stats on S/N values for star-like objects
     1187    psVector *starsn = psVectorAlloc (sources->n, PS_TYPE_F32);
     1188    starsn->n = 0;
     1189
     1190    // check return status value (do these exist?)
     1191    bool status;
     1192    psF32 PSF_SN_LIM = psMetadataLookupF32 (&status, metadata, "PSF_SN_LIM");
     1193
     1194    // XXX allow clump size to be scaled relative to sigmas?
     1195    // make rough IDs based on clumpX,Y,DX,DY
     1196    for (psS32 i = 0 ; i < sources->n ; i++) {
     1197
     1198        pmSource *tmpSrc = (pmSource *) sources->data[i];
     1199
     1200        tmpSrc->peak->class = 0;
     1201
     1202        psF32 sigX = tmpSrc->moments->Sx;
     1203        psF32 sigY = tmpSrc->moments->Sy;
     1204
     1205        // XXX EAM : can we use the value of SATURATE if mask is NULL?
     1206        inner = psRegionForSquare (tmpSrc->peak->x - tmpSrc->mask->col0, tmpSrc->peak->y - tmpSrc->mask->row0, 2);
     1207        int Nsatpix = psImageCountPixelMask (tmpSrc->mask, inner, PSPHOT_MASK_SATURATED);
     1208
     1209        // saturated star (size consistent with PSF or larger)
     1210        // Nsigma should be user-configured parameter
     1211        bool big = (sigX > (clump.X - clump.dX)) && (sigY > (clump.Y - clump.dY));
     1212        big = true;
     1213        if ((Nsatpix > 1) && big) {
    12551214            tmpSrc->type = PM_SOURCE_STAR;
     1215            tmpSrc->mode = PM_SOURCE_SATSTAR;
     1216            Nsatstar ++;
     1217            continue;
     1218        }
     1219
     1220        // saturated object (not a star, eg bleed trails, hot pixels)
     1221        if (Nsatpix > 1) {
     1222            tmpSrc->type = PM_SOURCE_SATURATED;
    12561223            tmpSrc->mode = PM_SOURCE_DEFAULT;
    1257         }
    1258 
    1259         {
    1260             psStats *stats  = NULL;
    1261             stats = psStatsAlloc (PS_STAT_MIN | PS_STAT_MAX);
    1262             stats = psVectorStats (stats, starsn, NULL, NULL, 0);
    1263             psLogMsg ("pmObjects", 3, "SN range: %f - %f\n", stats[0].min, stats[0].max);
    1264             psFree (stats);
    1265             psFree (starsn);
    1266         }
    1267 
    1268         psTrace (".pmObjects.pmSourceRoughClass", 2, "Nstar:    %3d\n", Nstar);
    1269         psTrace (".pmObjects.pmSourceRoughClass", 2, "Npsf:     %3d\n", Npsf);
    1270         psTrace (".pmObjects.pmSourceRoughClass", 2, "Next:     %3d\n", Next);
    1271         psTrace (".pmObjects.pmSourceRoughClass", 2, "Nsatstar: %3d\n", Nsatstar);
    1272         psTrace (".pmObjects.pmSourceRoughClass", 2, "Nsat:     %3d\n", Nsat);
    1273         psTrace (".pmObjects.pmSourceRoughClass", 2, "Ncr:      %3d\n", Ncr);
    1274 
    1275         psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc);
    1276         return(rc);
    1277     }
    1278 
    1279     /** pmSourceDefinePixels()
    1280      *
    1281      * Define psImage subarrays for the source located at coordinates x,y on the
    1282      * image set defined by readout. The pixels defined by this operation consist of
    1283      * a square window (of full width 2Radius+1) centered on the pixel which contains
    1284      * the given coordinate, in the frame of the readout. The window is defined to
    1285      * have limits which are valid within the boundary of the readout image, thus if
    1286      * the radius would fall outside the image pixels, the subimage is truncated to
    1287      * only consist of valid pixels. If readout->mask or readout->weight are not
    1288      * NULL, matching subimages are defined for those images as well. This function
    1289      * fails if no valid pixels can be defined (x or y less than Radius, for
    1290      * example). This function should be used to define a region of interest around a
    1291      * source, including both source and sky pixels.
    1292      *
    1293      * XXX: must code this.
    1294      *
    1295      */
    1296     bool pmSourceDefinePixels(
    1297         pmSource *mySource,                 ///< Add comment.
    1298         pmReadout *readout,                 ///< Add comment.
    1299         psF32 x,                            ///< Add comment.
    1300         psF32 y,                            ///< Add comment.
    1301         psF32 Radius)                       ///< Add comment.
     1224            Nsat ++;
     1225            continue;
     1226        }
     1227
     1228        // likely defect (too small to be stellar) (push out to 3 sigma)
     1229        // low S/N objects which are small are probably stellar
     1230        // only set candidate defects if
     1231        if ((sigX < 0.05) || (sigY < 0.05)) {
     1232            tmpSrc->type = PM_SOURCE_DEFECT;
     1233            tmpSrc->mode = PM_SOURCE_DEFAULT;
     1234            Ncr ++;
     1235            continue;
     1236        }
     1237
     1238        // likely unsaturated extended source (too large to be stellar)
     1239        if ((sigX > (clump.X + 3*clump.dX)) || (sigY > (clump.Y + 3*clump.dY))) {
     1240            tmpSrc->type = PM_SOURCE_EXTENDED;
     1241            tmpSrc->mode = PM_SOURCE_DEFAULT;
     1242            Next ++;
     1243            continue;
     1244        }
     1245
     1246        // the rest are probable stellar objects
     1247        starsn->data.F32[starsn->n] = tmpSrc->moments->SN;
     1248        starsn->n ++;
     1249        Nstar ++;
     1250
     1251        // PSF star (within 1.5 sigma of clump center, S/N > limit)
     1252        psF32 radius = hypot ((sigX-clump.X)/clump.dX, (sigY-clump.Y)/clump.dY);
     1253        if ((tmpSrc->moments->SN > PSF_SN_LIM) && (radius < 1.5)) {
     1254            tmpSrc->type = PM_SOURCE_STAR;
     1255            tmpSrc->mode = PM_SOURCE_PSFSTAR;
     1256            Npsf ++;
     1257            continue;
     1258        }
     1259
     1260        // random type of star
     1261        tmpSrc->type = PM_SOURCE_STAR;
     1262        tmpSrc->mode = PM_SOURCE_DEFAULT;
     1263    }
     1264
    13021265    {
    1303         psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    1304         psLogMsg(__func__, PS_LOG_WARN, "WARNING: pmSourceDefinePixels() has not been implemented.  Returning FALSE.\n");
    1305         psTrace(__func__, 3, "---- %s() end ----\n", __func__);
    1306         return(false);
    1307     }
    1308 
    1309     /******************************************************************************
     1266        psStats *stats  = NULL;
     1267        stats = psStatsAlloc (PS_STAT_MIN | PS_STAT_MAX);
     1268        stats = psVectorStats (stats, starsn, NULL, NULL, 0);
     1269        psLogMsg ("pmObjects", 3, "SN range: %f - %f\n", stats[0].min, stats[0].max);
     1270        psFree (stats);
     1271        psFree (starsn);
     1272    }
     1273
     1274    psTrace (".pmObjects.pmSourceRoughClass", 2, "Nstar:    %3d\n", Nstar);
     1275    psTrace (".pmObjects.pmSourceRoughClass", 2, "Npsf:     %3d\n", Npsf);
     1276    psTrace (".pmObjects.pmSourceRoughClass", 2, "Next:     %3d\n", Next);
     1277    psTrace (".pmObjects.pmSourceRoughClass", 2, "Nsatstar: %3d\n", Nsatstar);
     1278    psTrace (".pmObjects.pmSourceRoughClass", 2, "Nsat:     %3d\n", Nsat);
     1279    psTrace (".pmObjects.pmSourceRoughClass", 2, "Ncr:      %3d\n", Ncr);
     1280
     1281    psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc);
     1282    return(rc);
     1283}
     1284
     1285/** pmSourceDefinePixels()
     1286 *
     1287 * Define psImage subarrays for the source located at coordinates x,y on the
     1288 * image set defined by readout. The pixels defined by this operation consist of
     1289 * a square window (of full width 2Radius+1) centered on the pixel which contains
     1290 * the given coordinate, in the frame of the readout. The window is defined to
     1291 * have limits which are valid within the boundary of the readout image, thus if
     1292 * the radius would fall outside the image pixels, the subimage is truncated to
     1293 * only consist of valid pixels. If readout->mask or readout->weight are not
     1294 * NULL, matching subimages are defined for those images as well. This function
     1295 * fails if no valid pixels can be defined (x or y less than Radius, for
     1296 * example). This function should be used to define a region of interest around a
     1297 * source, including both source and sky pixels.
     1298 *
     1299 * XXX: must code this.
     1300 *
     1301 */
     1302bool pmSourceDefinePixels(
     1303    pmSource *mySource,                 ///< Add comment.
     1304    pmReadout *readout,                 ///< Add comment.
     1305    psF32 x,                            ///< Add comment.
     1306    psF32 y,                            ///< Add comment.
     1307    psF32 Radius)                       ///< Add comment.
     1308{
     1309    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     1310    psLogMsg(__func__, PS_LOG_WARN, "WARNING: pmSourceDefinePixels() has not been implemented.  Returning FALSE.\n");
     1311    psTrace(__func__, 3, "---- %s() end ----\n", __func__);
     1312    return(false);
     1313}
     1314
     1315/******************************************************************************
    13101316    pmSourceSetPixelsCircle(source, image, radius)
    13111317     
    13121318    XXX: This was replaced by DefinePixels in SDRS.  Remove it.
    1313     *****************************************************************************/
    1314     bool pmSourceSetPixelsCircle(pmSource *source,
    1315                                  const psImage *image,
    1316                                  psF32 radius) {
    1317         psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    1318         PS_ASSERT_IMAGE_NON_NULL(image, false);
    1319         PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false);
    1320         PS_ASSERT_PTR_NON_NULL(source, false);
    1321         PS_ASSERT_PTR_NON_NULL(source->moments, false);
    1322         PS_ASSERT_PTR_NON_NULL(source->peak, false);
    1323         PS_FLOAT_COMPARE(0.0, radius, false);
    1324 
    1325         //
    1326         // We define variables for code readability.
    1327         //
    1328         // XXX: Since the peak->xy coords are in image, not subImage coords,
    1329         // these variables should be renamed for clarity (imageCenterRow, etc).
    1330         //
    1331         psS32 radiusS32 = (psS32) radius;
    1332         psS32 SubImageCenterRow = source->peak->y;
    1333         psS32 SubImageCenterCol = source->peak->x;
    1334         // XXX EAM : for the circle to stay on the image
    1335         // XXX EAM : EndRow is *exclusive* of pixel region (ie, last pixel + 1)
    1336         psS32 SubImageStartRow  = PS_MAX (0, SubImageCenterRow - radiusS32);
    1337         psS32 SubImageEndRow    = PS_MIN (image->numRows, SubImageCenterRow + radiusS32 + 1);
    1338         psS32 SubImageStartCol  = PS_MAX (0, SubImageCenterCol - radiusS32);
    1339         psS32 SubImageEndCol    = PS_MIN (image->numCols, SubImageCenterCol + radiusS32 + 1);
    1340 
    1341         // XXX: Must recycle image.
    1342         // XXX EAM: this message reflects a programming error we know about.
    1343         //          i am setting it to a trace message which we can take out
    1344         if (source->pixels != NULL) {
    1345             psTrace (".psModule.pmObjects.pmSourceSetPixelsCircle", 4,
    1346                      "WARNING: pmSourceSetPixelsCircle(): image->pixels not NULL.  Freeing and reallocating.\n");
    1347             psFree(source->pixels);
    1348         }
    1349         source->pixels = psImageSubset((psImage *) image, psRegionSet(SubImageStartCol,
    1350                                        SubImageStartRow,
    1351                                        SubImageEndCol,
    1352                                        SubImageEndRow));
    1353 
    1354         // XXX: Must recycle image.
    1355         if (source->mask != NULL) {
    1356             psFree(source->mask);
    1357         }
    1358         source->mask = psImageAlloc(source->pixels->numCols,
    1359                                     source->pixels->numRows,
    1360                                     PS_TYPE_U8); // XXX EAM : type was F32
    1361 
    1362         //
    1363         // Loop through the subimage mask, initialize mask to 0 or 1.
    1364         // XXX EAM: valid pixels should have 0, not 1
    1365         for (psS32 row = 0 ; row < source->mask->numRows; row++) {
    1366             for (psS32 col = 0 ; col < source->mask->numCols; col++) {
    1367 
    1368                 if (checkRadius2((psF32) radiusS32,
    1369                                  (psF32) radiusS32,
    1370                                  radius,
    1371                                  (psF32) col,
    1372                                  (psF32) row)) {
    1373                     source->mask->data.U8[row][col] = 0;
    1374                 } else {
    1375                     source->mask->data.U8[row][col] = 1;
    1376                 }
    1377             }
    1378         }
    1379         psTrace(__func__, 3, "---- %s(true) end ----\n", __func__);
    1380         return(true);
    1381     }
    1382 
    1383     /******************************************************************************
     1319*****************************************************************************/
     1320bool pmSourceSetPixelsCircle(pmSource *source,
     1321                             const psImage *image,
     1322                             psF32 radius)
     1323{
     1324    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     1325    PS_ASSERT_IMAGE_NON_NULL(image, false);
     1326    PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false);
     1327    PS_ASSERT_PTR_NON_NULL(source, false);
     1328    PS_ASSERT_PTR_NON_NULL(source->moments, false);
     1329    PS_ASSERT_PTR_NON_NULL(source->peak, false);
     1330    PS_FLOAT_COMPARE(0.0, radius, false);
     1331
     1332    //
     1333    // We define variables for code readability.
     1334    //
     1335    // XXX: Since the peak->xy coords are in image, not subImage coords,
     1336    // these variables should be renamed for clarity (imageCenterRow, etc).
     1337    //
     1338    psS32 radiusS32 = (psS32) radius;
     1339    psS32 SubImageCenterRow = source->peak->y;
     1340    psS32 SubImageCenterCol = source->peak->x;
     1341    // XXX EAM : for the circle to stay on the image
     1342    // XXX EAM : EndRow is *exclusive* of pixel region (ie, last pixel + 1)
     1343    psS32 SubImageStartRow  = PS_MAX (0, SubImageCenterRow - radiusS32);
     1344    psS32 SubImageEndRow    = PS_MIN (image->numRows, SubImageCenterRow + radiusS32 + 1);
     1345    psS32 SubImageStartCol  = PS_MAX (0, SubImageCenterCol - radiusS32);
     1346    psS32 SubImageEndCol    = PS_MIN (image->numCols, SubImageCenterCol + radiusS32 + 1);
     1347
     1348    // XXX: Must recycle image.
     1349    // XXX EAM: this message reflects a programming error we know about.
     1350    //          i am setting it to a trace message which we can take out
     1351    if (source->pixels != NULL) {
     1352        psTrace (".psModule.pmObjects.pmSourceSetPixelsCircle", 4,
     1353                 "WARNING: pmSourceSetPixelsCircle(): image->pixels not NULL.  Freeing and reallocating.\n");
     1354        psFree(source->pixels);
     1355    }
     1356    source->pixels = psImageSubset((psImage *) image, psRegionSet(SubImageStartCol,
     1357                                   SubImageStartRow,
     1358                                   SubImageEndCol,
     1359                                   SubImageEndRow));
     1360
     1361    // XXX: Must recycle image.
     1362    if (source->mask != NULL) {
     1363        psFree(source->mask);
     1364    }
     1365    source->mask = psImageAlloc(source->pixels->numCols,
     1366                                source->pixels->numRows,
     1367                                PS_TYPE_U8); // XXX EAM : type was F32
     1368
     1369    //
     1370    // Loop through the subimage mask, initialize mask to 0 or 1.
     1371    // XXX EAM: valid pixels should have 0, not 1
     1372    for (psS32 row = 0 ; row < source->mask->numRows; row++) {
     1373        for (psS32 col = 0 ; col < source->mask->numCols; col++) {
     1374
     1375            if (checkRadius2((psF32) radiusS32,
     1376                             (psF32) radiusS32,
     1377                             radius,
     1378                             (psF32) col,
     1379                             (psF32) row)) {
     1380                source->mask->data.U8[row][col] = 0;
     1381            } else {
     1382                source->mask->data.U8[row][col] = 1;
     1383            }
     1384        }
     1385    }
     1386    psTrace(__func__, 3, "---- %s(true) end ----\n", __func__);
     1387    return(true);
     1388}
     1389
     1390/******************************************************************************
    13841391    pmSourceModelGuess(source, model): This function allocates a new
    13851392    pmModel structure based on the given modelType specified in the argument list. 
    … …  
    13901397    image, not subImage coords.  Therefore, the calls to the model evaluation
    13911398    functions will be in image, not subImage coords.  Remember this.
    1392     *****************************************************************************/
    1393     pmModel *pmSourceModelGuess(pmSource *source,
    1394                                 pmModelType modelType) {
    1395         psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    1396         PS_ASSERT_PTR_NON_NULL(source->moments, false);
    1397         PS_ASSERT_PTR_NON_NULL(source->peak, false);
    1398 
    1399         pmModel *model = pmModelAlloc(modelType);
    1400 
    1401         pmModelGuessFunc modelGuessFunc = pmModelGuessFunc_GetFunction(modelType);
    1402         modelGuessFunc(model, source);
    1403         psTrace(__func__, 3, "---- %s() end ----\n", __func__);
    1404         return(model);
    1405     }
    1406 
    1407     /******************************************************************************
     1399*****************************************************************************/
     1400pmModel *pmSourceModelGuess(pmSource *source,
     1401                            pmModelType modelType)
     1402{
     1403    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     1404    PS_ASSERT_PTR_NON_NULL(source->moments, false);
     1405    PS_ASSERT_PTR_NON_NULL(source->peak, false);
     1406
     1407    pmModel *model = pmModelAlloc(modelType);
     1408
     1409    pmModelGuessFunc modelGuessFunc = pmModelGuessFunc_GetFunction(modelType);
     1410    modelGuessFunc(model, source);
     1411    psTrace(__func__, 3, "---- %s() end ----\n", __func__);
     1412    return(model);
     1413}
     1414
     1415/******************************************************************************
    14081416    evalModel(source, level, row): a private function which evaluates the
    14091417    source->modelPSF function at the specified coords.  The coords are subImage, not
    … …  
    14251433    XXX: For a while, the first psVectorAlloc() was generating a seg fault during
    14261434    testing.  Try to reproduce that and debug.
    1427     *****************************************************************************/
    1428 
    1429     // XXX EAM : I have made this a public function
    1430     // XXX EAM : this now uses a pmModel as the input
    1431     // XXX EAM : it was using src->type to find the model, not model->type
    1432     psF32 pmModelEval(pmModel *model, psImage *image, psS32 col, psS32 row) {
    1433         psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    1434         PS_ASSERT_PTR_NON_NULL(image, false);
    1435         PS_ASSERT_PTR_NON_NULL(model, false);
    1436         PS_ASSERT_PTR_NON_NULL(model->params, false);
    1437 
    1438         // Allocate the x coordinate structure and convert row/col to image space.
    1439         //
    1440         psVector *x = psVectorAlloc(2, PS_TYPE_F32);
    1441         x->data.F32[0] = (psF32) (col + image->col0);
    1442         x->data.F32[1] = (psF32) (row + image->row0);
    1443         psF32 tmpF;
    1444         pmModelFunc modelFunc;
    1445 
    1446         modelFunc = pmModelFunc_GetFunction (model->type);
    1447         tmpF = modelFunc (NULL, model->params, x);
    1448         psFree(x);
    1449         psTrace(__func__, 3, "---- %s() end ----\n", __func__);
    1450         return(tmpF);
    1451     }
    1452 
    1453     /******************************************************************************
     1435*****************************************************************************/
     1436
     1437// XXX EAM : I have made this a public function
     1438// XXX EAM : this now uses a pmModel as the input
     1439// XXX EAM : it was using src->type to find the model, not model->type
     1440psF32 pmModelEval(pmModel *model, psImage *image, psS32 col, psS32 row)
     1441{
     1442    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     1443    PS_ASSERT_PTR_NON_NULL(image, false);
     1444    PS_ASSERT_PTR_NON_NULL(model, false);
     1445    PS_ASSERT_PTR_NON_NULL(model->params, false);
     1446
     1447    // Allocate the x coordinate structure and convert row/col to image space.
     1448    //
     1449    psVector *x = psVectorAlloc(2, PS_TYPE_F32);
     1450    x->data.F32[0] = (psF32) (col + image->col0);
     1451    x->data.F32[1] = (psF32) (row + image->row0);
     1452    psF32 tmpF;
     1453    pmModelFunc modelFunc;
     1454
     1455    modelFunc = pmModelFunc_GetFunction (model->type);
     1456    tmpF = modelFunc (NULL, model->params, x);
     1457    psFree(x);
     1458    psTrace(__func__, 3, "---- %s() end ----\n", __func__);
     1459    return(tmpF);
     1460}
     1461
     1462/******************************************************************************
    14541463    pmSourceContour(src, img, level, mode): For an input subImage, and model, this
    14551464    routine returns a psArray of coordinates that evaluate to the specified level.
    … …  
    14631472    XXX EAM : this function is using the model for the contour, but it should
    14641473              be using only the image counts
    1465     *****************************************************************************/
    1466     psArray *pmSourceContour(pmSource *source,
    1467                              const psImage *image,
    1468                              psF32 level,
    1469                              pmContourType mode) {
    1470         psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    1471         PS_ASSERT_PTR_NON_NULL(source, false);
    1472         PS_ASSERT_PTR_NON_NULL(image, false);
    1473         PS_ASSERT_PTR_NON_NULL(source->moments, false);
    1474         PS_ASSERT_PTR_NON_NULL(source->peak, false);
    1475         PS_ASSERT_PTR_NON_NULL(source->pixels, false);
    1476         PS_ASSERT_PTR_NON_NULL(source->modelEXT, false);
    1477         // XXX EAM : what is the purpose of modelPSF/modelEXT?
    1478 
    1479         //
    1480         // Allocate data for x/y pairs.
    1481         //
    1482         psVector *xVec = psVectorAlloc(2 * source->pixels->numRows, PS_TYPE_F32);
    1483         psVector *yVec = psVectorAlloc(2 * source->pixels->numRows, PS_TYPE_F32);
    1484 
    1485         //
    1486         // Start at the row with peak pixel, then decrement.
    1487         //
    1488         psS32 col = source->peak->x;
    1489         for (psS32 row = source->peak->y; row>= 0 ; row--) {
    1490             // XXX: yVec contain no real information.  Do we really need it?
    1491             yVec->data.F32[row] = (psF32) (source->pixels->row0 + row);
    1492             yVec->data.F32[row+yVec->n] = (psF32) (source->pixels->row0 + row);
    1493 
    1494             // Starting at peak pixel, search leftwards for the column intercept.
    1495             psF32 leftIntercept = findValue(source, level, row, col, 0);
    1496             if (isnan(leftIntercept)) {
    1497                 psError(PS_ERR_UNKNOWN, true, "Could not find contour edge (NAN)");
    1498                 psFree(xVec);
    1499                 psFree(yVec);
    1500                 psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__);
    1501                 return(NULL);
    1502                 //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n");
    1503             }
    1504             xVec->data.F32[row] = ((psF32) source->pixels->col0) + leftIntercept;
    1505 
    1506             // Starting at peak pixel, search rightwards for the column intercept.
    1507 
    1508             psF32 rightIntercept = findValue(source, level, row, col, 1);
    1509             if (isnan(rightIntercept)) {
    1510                 psError(PS_ERR_UNKNOWN, true, "Could not find contour edge (NAN)");
    1511                 psFree(xVec);
    1512                 psFree(yVec);
    1513                 psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__);
    1514                 return(NULL);
    1515                 //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n");
    1516             }
    1517             psTrace(__func__, 4, "The intercepts are (%.2f, %.2f)\n", leftIntercept, rightIntercept);
    1518             xVec->data.F32[row+xVec->n] = ((psF32) source->pixels->col0) + rightIntercept;
    1519 
    1520             // Set starting column for next row
    1521             col = (psS32) ((leftIntercept + rightIntercept) / 2.0);
    1522         }
    1523         //
    1524         // Start at the row (+1) with peak pixel, then increment.
    1525         //
    1526         col = source->peak->x;
    1527         for (psS32 row = 1 + source->peak->y; row < source->pixels->numRows ; row++) {
    1528             // XXX: yVec contain no real information.  Do we really need it?
    1529             yVec->data.F32[row] = (psF32) (source->pixels->row0 + row);
    1530             yVec->data.F32[row+yVec->n] = (psF32) (source->pixels->row0 + row);
    1531 
    1532             // Starting at peak pixel, search leftwards for the column intercept.
    1533             psF32 leftIntercept = findValue(source, level, row, col, 0);
    1534             if (isnan(leftIntercept)) {
    1535                 psError(PS_ERR_UNKNOWN, true, "Could not find contour edge (NAN)");
    1536                 psFree(xVec);
    1537                 psFree(yVec);
    1538                 psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__);
    1539                 return(NULL);
    1540                 //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n");
    1541             }
    1542             xVec->data.F32[row] = ((psF32) source->pixels->col0) + leftIntercept;
    1543 
    1544             // Starting at peak pixel, search rightwards for the column intercept.
    1545             psF32 rightIntercept = findValue(source, level, row, col, 1);
    1546             if (isnan(rightIntercept)) {
    1547                 psError(PS_ERR_UNKNOWN, true, "Could not find contour edge (NAN)");
    1548                 psFree(xVec);
    1549                 psFree(yVec);
    1550                 psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__);
    1551                 return(NULL);
    1552                 //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n");
    1553             }
    1554             xVec->data.F32[row+xVec->n] = ((psF32) source->pixels->col0) + rightIntercept;
    1555 
    1556             // Set starting column for next row
    1557             col = (psS32) ((leftIntercept + rightIntercept) / 2.0);
    1558         }
    1559 
    1560         //
    1561         // Allocate an array for result, store coord vectors there.
    1562         //
    1563         psArray *tmpArray = psArrayAlloc(2);
    1564         tmpArray->data[0] = (psPtr *) yVec;
    1565         tmpArray->data[1] = (psPtr *) xVec;
    1566         psTrace(__func__, 3, "---- %s() end ----\n", __func__);
    1567         return(tmpArray);
    1568     }
    1569 
    1570     // save a static values so they may be set externally
    1571     static psF32 PM_SOURCE_FIT_MODEL_NUM_ITERATIONS = 15;
    1572     static psF32 PM_SOURCE_FIT_MODEL_TOLERANCE = 0.1;
    1573 
    1574     bool pmSourceFitModelInit (float nIter, float tol) {
    1575 
    1576         PM_SOURCE_FIT_MODEL_NUM_ITERATIONS = nIter;
    1577         PM_SOURCE_FIT_MODEL_TOLERANCE = tol;
    1578     }
    1579 
    1580     bool pmSourceFitModel (pmSource *source,
    1581                            pmModel *model,
    1582                            const bool PSF) {
    1583         psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    1584         PS_ASSERT_PTR_NON_NULL(source, false);
    1585         PS_ASSERT_PTR_NON_NULL(source->moments, false);
    1586         PS_ASSERT_PTR_NON_NULL(source->peak, false);
    1587         PS_ASSERT_PTR_NON_NULL(source->pixels, false);
    1588         PS_ASSERT_PTR_NON_NULL(source->mask, false);
    1589         PS_ASSERT_PTR_NON_NULL(source->weight, false);
    1590 
    1591         // XXX EAM : is it necessary for the mask & weight to exist?  the
    1592         //           tests below could be conditions (!NULL)
    1593 
    1594         psBool fitStatus = true;
    1595         psBool onPic     = true;
    1596         psBool rc        = true;
    1597 
    1598         psVector *params = model->params;
    1599         psVector *dparams = model->dparams;
    1600         psVector *paramMask = NULL;
    1601 
    1602         pmModelFunc modelFunc = pmModelFunc_GetFunction (model->type);
    1603 
    1604         int nParams = PSF ? 4 : params->n;
    1605 
    1606         // maximum number of valid pixels
    1607         psS32 nPix = source->pixels->numRows * source->pixels->numCols;
    1608 
    1609         // construct the coordinate and value entries
    1610         psArray *x = psArrayAlloc(nPix);
    1611         psVector *y = psVectorAlloc(nPix, PS_TYPE_F32);
    1612         psVector *yErr = psVectorAlloc(nPix, PS_TYPE_F32);
    1613 
    1614         nPix = 0;
    1615         for (psS32 i = 0; i < source->pixels->numRows; i++) {
    1616             for (psS32 j = 0; j < source->pixels->numCols; j++) {
    1617                 if (source->mask->data.U8[i][j]) {
    1618                     continue;
    1619                 }
    1620                 psVector *coord = psVectorAlloc(2, PS_TYPE_F32);
    1621 
    1622                 // Convert i/j to image space:
    1623                 coord->data.F32[0] = (psF32) (j + source->pixels->col0);
    1624                 coord->data.F32[1] = (psF32) (i + source->pixels->row0);
    1625                 x->data[nPix] = (psPtr *) coord;
    1626                 y->data.F32[nPix] = source->pixels->data.F32[i][j];
    1627 
    1628                 // psMinimizeLMChi2 takes wt = 1/dY^2
    1629                 if (source->weight->data.F32[i][j] == 0) {
    1630                     continue;
    1631                 }
    1632                 yErr->data.F32[nPix] = 1.0 / source->weight->data.F32[i][j];
    1633                 nPix++;
    1634             }
    1635         }
    1636         if (nPix <  nParams + 1) {
    1637             psTrace (".pmObjects.pmSourceFitModel", 4, "insufficient valid pixels\n");
    1638             psTrace(__func__, 3, "---- %s(false) end ----\n", __func__);
    1639             model->status = PM_MODEL_BADARGS;
    1640             psFree (x);
    1641             psFree (y);
    1642             psFree (yErr);
    1643             return(false);
    1644         }
    1645         x->n = nPix;
    1646         y->n = nPix;
    1647         yErr->n = nPix;
    1648 
    1649         psMinimization *myMin = psMinimizationAlloc(PM_SOURCE_FIT_MODEL_NUM_ITERATIONS,
    1650                                 PM_SOURCE_FIT_MODEL_TOLERANCE);
    1651 
    1652         // PSF model only fits first 4 parameters, EXT model fits all
    1653         if (PSF) {
    1654             paramMask = psVectorAlloc (params->n, PS_TYPE_U8);
    1655             for (int i = 0; i < 4; i++) {
    1656                 paramMask->data.U8[i] = 0;
    1657             }
    1658             for (int i = 4; i < paramMask->n; i++) {
    1659                 paramMask->data.U8[i] = 1;
    1660             }
    1661         }
    1662 
    1663         // Set the parameter range checks
    1664         pmModelLimits modelLimits = pmModelLimits_GetFunction (model->type);
    1665         psVector *beta_lim = NULL;
    1666         psVector *params_min = NULL;
    1667         psVector *params_max = NULL;
    1668 
    1669         // XXX EAM : in this implementation, I pass in the limits with the covar matrix.
    1670         //           in the SDRS, I define a new psMinimization which will take these in
    1671         psImage *covar = psImageAlloc (params->n, 3, PS_TYPE_F64);
    1672         modelLimits (&beta_lim, &params_min, &params_max);
    1673         for (int i = 0; i < params->n; i++) {
    1674             covar->data.F64[0][i] = beta_lim->data.F32[i];
    1675             covar->data.F64[1][i] = params_min->data.F32[i];
    1676             covar->data.F64[2][i] = params_max->data.F32[i];
    1677         }
    1678 
    1679         psTrace (".pmObjects.pmSourceFitModel", 5, "fitting function\n");
    1680         fitStatus = psMinimizeLMChi2(myMin, covar, params, paramMask, x, y, yErr, modelFunc);
     1474*****************************************************************************/
     1475psArray *pmSourceContour(pmSource *source,
     1476                         const psImage *image,
     1477                         psF32 level,
     1478                         pmContourType mode)
     1479{
     1480    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     1481    PS_ASSERT_PTR_NON_NULL(source, false);
     1482    PS_ASSERT_PTR_NON_NULL(image, false);
     1483    PS_ASSERT_PTR_NON_NULL(source->moments, false);
     1484    PS_ASSERT_PTR_NON_NULL(source->peak, false);
     1485    PS_ASSERT_PTR_NON_NULL(source->pixels, false);
     1486    PS_ASSERT_PTR_NON_NULL(source->modelEXT, false);
     1487    // XXX EAM : what is the purpose of modelPSF/modelEXT?
     1488
     1489    //
     1490    // Allocate data for x/y pairs.
     1491    //
     1492    psVector *xVec = psVectorAlloc(2 * source->pixels->numRows, PS_TYPE_F32);
     1493    psVector *yVec = psVectorAlloc(2 * source->pixels->numRows, PS_TYPE_F32);
     1494
     1495    //
     1496    // Start at the row with peak pixel, then decrement.
     1497    //
     1498    psS32 col = source->peak->x;
     1499    for (psS32 row = source->peak->y; row>= 0 ; row--) {
     1500        // XXX: yVec contain no real information.  Do we really need it?
     1501        yVec->data.F32[row] = (psF32) (source->pixels->row0 + row);
     1502        yVec->data.F32[row+yVec->n] = (psF32) (source->pixels->row0 + row);
     1503
     1504        // Starting at peak pixel, search leftwards for the column intercept.
     1505        psF32 leftIntercept = findValue(source, level, row, col, 0);
     1506        if (isnan(leftIntercept)) {
     1507            psError(PS_ERR_UNKNOWN, true, "Could not find contour edge (NAN)");
     1508            psFree(xVec);
     1509            psFree(yVec);
     1510            psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__);
     1511            return(NULL);
     1512            //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n");
     1513        }
     1514        xVec->data.F32[row] = ((psF32) source->pixels->col0) + leftIntercept;
     1515
     1516        // Starting at peak pixel, search rightwards for the column intercept.
     1517
     1518        psF32 rightIntercept = findValue(source, level, row, col, 1);
     1519        if (isnan(rightIntercept)) {
     1520            psError(PS_ERR_UNKNOWN, true, "Could not find contour edge (NAN)");
     1521            psFree(xVec);
     1522            psFree(yVec);
     1523            psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__);
     1524            return(NULL);
     1525            //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n");
     1526        }
     1527        psTrace(__func__, 4, "The intercepts are (%.2f, %.2f)\n", leftIntercept, rightIntercept);
     1528        xVec->data.F32[row+xVec->n] = ((psF32) source->pixels->col0) + rightIntercept;
     1529
     1530        // Set starting column for next row
     1531        col = (psS32) ((leftIntercept + rightIntercept) / 2.0);
     1532    }
     1533    //
     1534    // Start at the row (+1) with peak pixel, then increment.
     1535    //
     1536    col = source->peak->x;
     1537    for (psS32 row = 1 + source->peak->y; row < source->pixels->numRows ; row++) {
     1538        // XXX: yVec contain no real information.  Do we really need it?
     1539        yVec->data.F32[row] = (psF32) (source->pixels->row0 + row);
     1540        yVec->data.F32[row+yVec->n] = (psF32) (source->pixels->row0 + row);
     1541
     1542        // Starting at peak pixel, search leftwards for the column intercept.
     1543        psF32 leftIntercept = findValue(source, level, row, col, 0);
     1544        if (isnan(leftIntercept)) {
     1545            psError(PS_ERR_UNKNOWN, true, "Could not find contour edge (NAN)");
     1546            psFree(xVec);
     1547            psFree(yVec);
     1548            psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__);
     1549            return(NULL);
     1550            //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n");
     1551        }
     1552        xVec->data.F32[row] = ((psF32) source->pixels->col0) + leftIntercept;
     1553
     1554        // Starting at peak pixel, search rightwards for the column intercept.
     1555        psF32 rightIntercept = findValue(source, level, row, col, 1);
     1556        if (isnan(rightIntercept)) {
     1557            psError(PS_ERR_UNKNOWN, true, "Could not find contour edge (NAN)");
     1558            psFree(xVec);
     1559            psFree(yVec);
     1560            psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__);
     1561            return(NULL);
     1562            //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n");
     1563        }
     1564        xVec->data.F32[row+xVec->n] = ((psF32) source->pixels->col0) + rightIntercept;
     1565
     1566        // Set starting column for next row
     1567        col = (psS32) ((leftIntercept + rightIntercept) / 2.0);
     1568    }
     1569
     1570    //
     1571    // Allocate an array for result, store coord vectors there.
     1572    //
     1573    psArray *tmpArray = psArrayAlloc(2);
     1574    tmpArray->data[0] = (psPtr *) yVec;
     1575    tmpArray->data[1] = (psPtr *) xVec;
     1576    psTrace(__func__, 3, "---- %s() end ----\n", __func__);
     1577    return(tmpArray);
     1578}
     1579
     1580// save a static values so they may be set externally
     1581static psF32 PM_SOURCE_FIT_MODEL_NUM_ITERATIONS = 15;
     1582static psF32 PM_SOURCE_FIT_MODEL_TOLERANCE = 0.1;
     1583
     1584bool pmSourceFitModelInit (float nIter, float tol)
     1585{
     1586
     1587    PM_SOURCE_FIT_MODEL_NUM_ITERATIONS = nIter;
     1588    PM_SOURCE_FIT_MODEL_TOLERANCE = tol;
     1589    return true;
     1590}
     1591
     1592bool pmSourceFitModel (pmSource *source,
     1593                       pmModel *model,
     1594                       const bool PSF)
     1595{
     1596    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     1597    PS_ASSERT_PTR_NON_NULL(source, false);
     1598    PS_ASSERT_PTR_NON_NULL(source->moments, false);
     1599    PS_ASSERT_PTR_NON_NULL(source->peak, false);
     1600    PS_ASSERT_PTR_NON_NULL(source->pixels, false);
     1601    PS_ASSERT_PTR_NON_NULL(source->mask, false);
     1602    PS_ASSERT_PTR_NON_NULL(source->weight, false);
     1603
     1604    // XXX EAM : is it necessary for the mask & weight to exist?  the
     1605    //           tests below could be conditions (!NULL)
     1606
     1607    psBool fitStatus = true;
     1608    psBool onPic     = true;
     1609    psBool rc        = true;
     1610
     1611    psVector *params = model->params;
     1612    psVector *dparams = model->dparams;
     1613    psVector *paramMask = NULL;
     1614
     1615    pmModelFunc modelFunc = pmModelFunc_GetFunction (model->type);
     1616
     1617    int nParams = PSF ? 4 : params->n;
     1618
     1619    // maximum number of valid pixels
     1620    psS32 nPix = source->pixels->numRows * source->pixels->numCols;
     1621
     1622    // construct the coordinate and value entries
     1623    psArray *x = psArrayAlloc(nPix);
     1624    psVector *y = psVectorAlloc(nPix, PS_TYPE_F32);
     1625    psVector *yErr = psVectorAlloc(nPix, PS_TYPE_F32);
     1626
     1627    nPix = 0;
     1628    for (psS32 i = 0; i < source->pixels->numRows; i++) {
     1629        for (psS32 j = 0; j < source->pixels->numCols; j++) {
     1630            if (source->mask->data.U8[i][j]) {
     1631                continue;
     1632            }
     1633            psVector *coord = psVectorAlloc(2, PS_TYPE_F32);
     1634
     1635            // Convert i/j to image space:
     1636            coord->data.F32[0] = (psF32) (j + source->pixels->col0);
     1637            coord->data.F32[1] = (psF32) (i + source->pixels->row0);
     1638            x->data[nPix] = (psPtr *) coord;
     1639            y->data.F32[nPix] = source->pixels->data.F32[i][j];
     1640
     1641            // psMinimizeLMChi2 takes wt = 1/dY^2
     1642            if (source->weight->data.F32[i][j] == 0) {
     1643                continue;
     1644            }
     1645            yErr->data.F32[nPix] = 1.0 / source->weight->data.F32[i][j];
     1646            nPix++;
     1647        }
     1648    }
     1649    if (nPix <  nParams + 1) {
     1650        psTrace (".pmObjects.pmSourceFitModel", 4, "insufficient valid pixels\n");
     1651        psTrace(__func__, 3, "---- %s(false) end ----\n", __func__);
     1652        model->status = PM_MODEL_BADARGS;
     1653        psFree (x);
     1654        psFree (y);
     1655        psFree (yErr);
     1656        return(false);
     1657    }
     1658    x->n = nPix;
     1659    y->n = nPix;
     1660    yErr->n = nPix;
     1661
     1662    psMinimization *myMin = psMinimizationAlloc(PM_SOURCE_FIT_MODEL_NUM_ITERATIONS,
     1663                            PM_SOURCE_FIT_MODEL_TOLERANCE);
     1664
     1665    // PSF model only fits first 4 parameters, EXT model fits all
     1666    if (PSF) {
     1667        paramMask = psVectorAlloc (params->n, PS_TYPE_U8);
     1668        for (int i = 0; i < 4; i++) {
     1669            paramMask->data.U8[i] = 0;
     1670        }
     1671        for (int i = 4; i < paramMask->n; i++) {
     1672            paramMask->data.U8[i] = 1;
     1673        }
     1674    }
     1675
     1676    // Set the parameter range checks
     1677    pmModelLimits modelLimits = pmModelLimits_GetFunction (model->type);
     1678    psVector *beta_lim = NULL;
     1679    psVector *params_min = NULL;
     1680    psVector *params_max = NULL;
     1681
     1682    // XXX EAM : in this implementation, I pass in the limits with the covar matrix.
     1683    //           in the SDRS, I define a new psMinimization which will take these in
     1684    psImage *covar = psImageAlloc (params->n, 3, PS_TYPE_F64);
     1685    modelLimits (&beta_lim, &params_min, &params_max);
     1686    for (int i = 0; i < params->n; i++) {
     1687        covar->data.F64[0][i] = beta_lim->data.F32[i];
     1688        covar->data.F64[1][i] = params_min->data.F32[i];
     1689        covar->data.F64[2][i] = params_max->data.F32[i];
     1690    }
     1691
     1692    psTrace (".pmObjects.pmSourceFitModel", 5, "fitting function\n");
     1693    fitStatus = psMinimizeLMChi2(myMin, covar, params, paramMask, x, y, yErr, modelFunc);
     1694    for (int i = 0; i < dparams->n; i++) {
     1695        if ((paramMask != NULL) && paramMask->data.U8[i])
     1696            continue;
     1697        dparams->data.F32[i] = sqrt(covar->data.F64[i][i]);
     1698    }
     1699
     1700    // save the resulting chisq, nDOF, nIter
     1701    model->chisq = myMin->value;
     1702    model->nIter = myMin->iter;
     1703    model->nDOF  = y->n - nParams;
     1704
     1705    // get the Gauss-Newton distance for fixed model parameters
     1706    if (paramMask != NULL) {
     1707        psVector *delta = psVectorAlloc (params->n, PS_TYPE_F64);
     1708        psMinimizeGaussNewtonDelta(delta, params, NULL, x, y, yErr, modelFunc);
    16811709        for (int i = 0; i < dparams->n; i++) {
    1682             if ((paramMask != NULL) && paramMask->data.U8[i])
     1710            if (!paramMask->data.U8[i])
    16831711                continue;
    1684             dparams->data.F32[i] = sqrt(covar->data.F64[i][i]);
    1685         }
    1686 
    1687         // save the resulting chisq, nDOF, nIter
    1688         model->chisq = myMin->value;
    1689         model->nIter = myMin->iter;
    1690         model->nDOF  = y->n - nParams;
    1691 
    1692         // get the Gauss-Newton distance for fixed model parameters
    1693         if (paramMask != NULL) {
    1694             psVector *delta = psVectorAlloc (params->n, PS_TYPE_F64);
    1695             psMinimizeGaussNewtonDelta(delta, params, NULL, x, y, yErr, modelFunc);
    1696             for (int i = 0; i < dparams->n; i++) {
    1697                 if (!paramMask->data.U8[i])
    1698                     continue;
    1699                 dparams->data.F32[i] = delta->data.F64[i];
    1700             }
    1701         }
    1702 
    1703         // set the model success or failure status
    1704         if (!fitStatus) {
    1705             model->status = PM_MODEL_NONCONVERGE;
    1706         } else {
    1707             model->status = PM_MODEL_SUCCESS;
    1708         }
    1709 
    1710         // models can go insane: reject these
    1711         onPic &= (params->data.F32[2] >= source->pixels->col0);
    1712         onPic &= (params->data.F32[2] <  source->pixels->col0 + source->pixels->numCols);
    1713         onPic &= (params->data.F32[3] >= source->pixels->row0);
    1714         onPic &= (params->data.F32[3] <  source->pixels->row0 + source->pixels->numRows);
    1715         if (!onPic) {
    1716             model->status = PM_MODEL_OFFIMAGE;
    1717         }
    1718 
    1719         source->mode |= PM_SOURCE_FITTED;
    1720 
    1721         psFree(x);
    1722         psFree(y);
    1723         psFree(yErr);
    1724         psFree(myMin);
    1725         psFree(covar);
    1726         psFree(paramMask);
    1727 
    1728         rc = (onPic && fitStatus);
    1729         psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc);
    1730         return(rc);
    1731     }
    1732 
    1733     bool p_pmSourceAddOrSubModel(psImage *image,
    1734                                  psImage *mask,
    1735                                  pmModel *model,
    1736                                  bool center,
    1737                                  bool sky,
    1738                                  bool add
    1739                                     ) {
    1740         psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    1741 
    1742         PS_ASSERT_PTR_NON_NULL(model, false);
    1743         PS_ASSERT_IMAGE_NON_NULL(image, false);
    1744         PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false);
    1745 
    1746         psVector *x = psVectorAlloc(2, PS_TYPE_F32);
    1747         psVector *params = model->params;
    1748         pmModelFunc modelFunc = pmModelFunc_GetFunction (model->type);
    1749         psS32 imageCol;
    1750         psS32 imageRow;
    1751         psF32 skyValue = params->data.F32[0];
    1752         psF32 pixelValue;
    1753 
    1754         for (psS32 i = 0; i < image->numRows; i++) {
    1755             for (psS32 j = 0; j < image->numCols; j++) {
    1756                 if ((mask != NULL) && mask->data.U8[i][j])
    1757                     continue;
    1758 
    1759                 // XXX: Should you be adding the pixels for the entire subImage,
    1760                 // or a radius of pixels around it?
    1761 
    1762                 // Convert i/j to imace coord space:
    1763                 // XXX: Make sure you have col/row order correct.
    1764                 // XXX EAM : 'center' option changes this
    1765                 // XXX EAM : i == numCols/2 -> x = model->params->data.F32[2]
    1766                 if (center) {
    1767                     imageCol = j - 0.5*image->numCols + model->params->data.F32[2];
    1768                     imageRow = i - 0.5*image->numRows + model->params->data.F32[3];
    1769                 } else {
    1770                     imageCol = j + image->col0;
    1771                     imageRow = i + image->row0;
    1772                 }
    1773 
    1774                 x->data.F32[0] = (float) imageCol;
    1775                 x->data.F32[1] = (float) imageRow;
    1776 
    1777                 // set the appropriate pixel value for this coordinate
    1778                 if (sky) {
    1779                     pixelValue = modelFunc (NULL, params, x);
    1780                 } else {
    1781                     pixelValue = modelFunc (NULL, params, x) - skyValue;
    1782                 }
    1783 
    1784 
    1785                 // add or subtract the value
    1786                 if (add
    1787                    ) {
    1788                     image->data.F32[i][j] += pixelValue;
    1789                 }
    1790                 else {
    1791                     image->data.F32[i][j] -= pixelValue;
    1792                 }
    1793             }
    1794         }
    1795         psFree(x);
    1796         psTrace(__func__, 3, "---- %s(true) end ----\n", __func__);
    1797         return(true);
    1798     }
    1799 
    1800 
    1801 
    1802     /******************************************************************************
    1803      *****************************************************************************/
    1804     bool pmSourceAddModel(psImage *image,
    1805                           psImage *mask,
    1806                           pmModel *model,
    1807                           bool center,
    1808                           bool sky) {
    1809         psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    1810         psBool rc = p_pmSourceAddOrSubModel(image, mask, model, center, sky, true);
    1811         psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc);
    1812         return(rc);
    1813     }
    1814 
    1815     /******************************************************************************
    1816      *****************************************************************************/
    1817     bool pmSourceSubModel(psImage *image,
    1818                           psImage *mask,
    1819                           pmModel *model,
    1820                           bool center,
    1821                           bool sky) {
    1822         psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    1823         psBool rc = p_pmSourceAddOrSubModel(image, mask, model, center, sky, false);
    1824         psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc);
    1825         return(rc);
    1826     }
    1827 
    1828     bool pmSourcePhotometry (float *fitMag, float *obsMag, pmModel *model, psImage *image, psImage *mask) {
    1829 
    1830         float obsSum = 0;
    1831         float fitSum = 0;
    1832         float sky = model->params->data.F32[0];
    1833 
    1834         pmModelFlux modelFluxFunc = pmModelFlux_GetFunction (model->type);
    1835         fitSum = modelFluxFunc (model->params);
    1836 
    1837         for (int ix = 0; ix < image->numCols; ix++) {
    1838             for (int iy = 0; iy < image->numRows; iy++) {
    1839                 if (mask->data.U8[iy][ix])
    1840                     continue;
    1841                 obsSum += image->data.F32[iy][ix] - sky;
    1842             }
    1843         }
    1844         if (obsSum <= 0)
    1845             return false;
    1846         if (fitSum <= 0)
    1847             return false;
    1848 
    1849         *fitMag = -2.5*log10(fitSum);
    1850         *obsMag = -2.5*log10(obsSum);
    1851         return (true);
    1852     }
    1853 
     1712            dparams->data.F32[i] = delta->data.F64[i];
     1713        }
     1714    }
     1715
     1716    // set the model success or failure status
     1717    if (!fitStatus) {
     1718        model->status = PM_MODEL_NONCONVERGE;
     1719    } else {
     1720        model->status = PM_MODEL_SUCCESS;
     1721    }
     1722
     1723    // models can go insane: reject these
     1724    onPic &= (params->data.F32[2] >= source->pixels->col0);
     1725    onPic &= (params->data.F32[2] <  source->pixels->col0 + source->pixels->numCols);
     1726    onPic &= (params->data.F32[3] >= source->pixels->row0);
     1727    onPic &= (params->data.F32[3] <  source->pixels->row0 + source->pixels->numRows);
     1728    if (!onPic) {
     1729        model->status = PM_MODEL_OFFIMAGE;
     1730    }
     1731
     1732    source->mode |= PM_SOURCE_FITTED;
     1733
     1734    psFree(x);
     1735    psFree(y);
     1736    psFree(yErr);
     1737    psFree(myMin);
     1738    psFree(covar);
     1739    psFree(paramMask);
     1740
     1741    rc = (onPic && fitStatus);
     1742    psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc);
     1743    return(rc);
     1744}
     1745
     1746bool p_pmSourceAddOrSubModel(psImage *image,
     1747                             psImage *mask,
     1748                             pmModel *model,
     1749                             bool center,
     1750                             bool sky,
     1751                             bool add
     1752                                )
     1753{
     1754    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     1755
     1756    PS_ASSERT_PTR_NON_NULL(model, false);
     1757    PS_ASSERT_IMAGE_NON_NULL(image, false);
     1758    PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false);
     1759
     1760    psVector *x = psVectorAlloc(2, PS_TYPE_F32);
     1761    psVector *params = model->params;
     1762    pmModelFunc modelFunc = pmModelFunc_GetFunction (model->type);
     1763    psS32 imageCol;
     1764    psS32 imageRow;
     1765    psF32 skyValue = params->data.F32[0];
     1766    psF32 pixelValue;
     1767
     1768    for (psS32 i = 0; i < image->numRows; i++) {
     1769        for (psS32 j = 0; j < image->numCols; j++) {
     1770            if ((mask != NULL) && mask->data.U8[i][j])
     1771                continue;
     1772
     1773            // XXX: Should you be adding the pixels for the entire subImage,
     1774            // or a radius of pixels around it?
     1775
     1776            // Convert i/j to imace coord space:
     1777            // XXX: Make sure you have col/row order correct.
     1778            // XXX EAM : 'center' option changes this
     1779            // XXX EAM : i == numCols/2 -> x = model->params->data.F32[2]
     1780            if (center) {
     1781                imageCol = j - 0.5*image->numCols + model->params->data.F32[2];
     1782                imageRow = i - 0.5*image->numRows + model->params->data.F32[3];
     1783            } else {
     1784                imageCol = j + image->col0;
     1785                imageRow = i + image->row0;
     1786            }
     1787
     1788            x->data.F32[0] = (float) imageCol;
     1789            x->data.F32[1] = (float) imageRow;
     1790
     1791            // set the appropriate pixel value for this coordinate
     1792            if (sky) {
     1793                pixelValue = modelFunc (NULL, params, x);
     1794            } else {
     1795                pixelValue = modelFunc (NULL, params, x) - skyValue;
     1796            }
     1797
     1798
     1799            // add or subtract the value
     1800            if (add
     1801               ) {
     1802                image->data.F32[i][j] += pixelValue;
     1803            }
     1804            else {
     1805                image->data.F32[i][j] -= pixelValue;
     1806            }
     1807        }
     1808    }
     1809    psFree(x);
     1810    psTrace(__func__, 3, "---- %s(true) end ----\n", __func__);
     1811    return(true);
     1812}
     1813
     1814
     1815
     1816/******************************************************************************
     1817 *****************************************************************************/
     1818bool pmSourceAddModel(psImage *image,
     1819                      psImage *mask,
     1820                      pmModel *model,
     1821                      bool center,
     1822                      bool sky)
     1823{
     1824    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     1825    psBool rc = p_pmSourceAddOrSubModel(image, mask, model, center, sky, true);
     1826    psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc);
     1827    return(rc);
     1828}
     1829
     1830/******************************************************************************
     1831 *****************************************************************************/
     1832bool pmSourceSubModel(psImage *image,
     1833                      psImage *mask,
     1834                      pmModel *model,
     1835                      bool center,
     1836                      bool sky)
     1837{
     1838    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     1839    psBool rc = p_pmSourceAddOrSubModel(image, mask, model, center, sky, false);
     1840    psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc);
     1841    return(rc);
     1842}
     1843
     1844bool pmSourcePhotometry (float *fitMag, float *obsMag, pmModel *model, psImage *image, psImage *mask)
     1845{
     1846
     1847    float obsSum = 0;
     1848    float fitSum = 0;
     1849    float sky = model->params->data.F32[0];
     1850
     1851    pmModelFlux modelFluxFunc = pmModelFlux_GetFunction (model->type);
     1852    fitSum = modelFluxFunc (model->params);
     1853
     1854    for (int ix = 0; ix < image->numCols; ix++) {
     1855        for (int iy = 0; iy < image->numRows; iy++) {
     1856            if (mask->data.U8[iy][ix])
     1857                continue;
     1858            obsSum += image->data.F32[iy][ix] - sky;
     1859        }
     1860    }
     1861    if (obsSum <= 0)
     1862        return false;
     1863    if (fitSum <= 0)
     1864        return false;
     1865
     1866    *fitMag = -2.5*log10(fitSum);
     1867    *obsMag = -2.5*log10(obsSum);
     1868    return (true);
     1869}
     1870
  • branches/eam_rel9_p0/psModules/src/objects/pmObjects.h

    r6182 r6183  
    1010 *  @author GLG, MHPCC
    1111 *
    12  *  @version $Revision: 1.4.4.5 $ $Name: not supported by cvs2svn $
    13  *  @date $Date: 2006-01-22 20:20:47 $
     12 *  @version $Revision: 1.4.4.6 $ $Name: not supported by cvs2svn $
     13 *  @date $Date: 2006-01-22 21:12:20 $
    1414 *
    1515 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
    … …  
    476476
    477477bool pmSourceFitModelInit(
    478     float nIter;   ///< max number of allowed iterations
    479     float tol    ///< convergence criterion
     478    float nIter,   ///< max number of allowed iterations
     479    float tol      ///< convergence criterion
    480480);
    481481
Note: See TracChangeset for help on using the changeset viewer.