Changeset 6448 for branches/rel10_ifa/psModules/src/objects/pmObjects.c
- Timestamp:
- Feb 17, 2006, 7:13:42 AM (20 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/rel10_ifa/psModules/src/objects/pmObjects.c
r6329 r6448 6 6 * @author EAM, IfA: significant modifications. 7 7 * 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 $ 10 10 * 11 11 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 25 25 psS32 y, 26 26 psF32 counts, 27 pmPeakType class)27 pmPeakType type) 28 28 { 29 29 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); … … 32 32 tmp->y = y; 33 33 tmp->counts = counts; 34 tmp-> class = class;34 tmp->type = type; 35 35 36 36 psTrace(__func__, 3, "---- %s() end ----\n", __func__); … … 77 77 psFree(tmp->moments); 78 78 psFree(tmp->modelPSF); 79 psFree(tmp->modelFLT); 79 psFree(tmp->modelEXT); 80 psFree(tmp->blends); 80 81 psTrace(__func__, 4, "---- %s() end ----\n", __func__); 81 82 } … … 85 86 psVector containing the specified row of data from the psImage. 86 87 87 XXX: Is there a better way to do this? 88 XXX: Is there a better way to do this? 88 89 XXX EAM: does this really need to alloc a new vector??? 89 90 *****************************************************************************/ … … 211 212 // XXX EAM : i changed this to match pmModelEval above, but see 212 213 // XXX EAM the note below in pmSourceContour 213 psF32 oldValue = pmModelEval(source->model FLT, source->pixels, subCol, subRow);214 psF32 oldValue = pmModelEval(source->modelEXT, source->pixels, subCol, subRow); 214 215 if (oldValue == level) { 215 216 psTrace(__func__, 4, "---- %s() end ----\n", __func__); … … 233 234 234 235 while (subCol != lastColumn) { 235 psF32 newValue = pmModelEval(source->model FLT, source->pixels, subCol, subRow);236 psF32 newValue = pmModelEval(source->modelEXT, source->pixels, subCol, subRow); 236 237 if (oldValue == level) { 237 238 psTrace(__func__, 4, "---- %s() end ----\n", __func__); … … 310 311 tmp->mask = NULL; 311 312 tmp->moments = NULL; 313 tmp->blends = NULL; 312 314 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; 315 318 psMemSetDeallocator(tmp, (psFreeFunc) sourceFree); 316 319 … … 436 439 XXX: In the output psArray elements, should we use the image row/column offsets? 437 440 Currently, we do not. 441 XXX EAM : this function needs to return peaks in *parent* coords 438 442 439 443 XXX: Merge with CVS 1.20. This had the proper code for images with a single 440 444 row or column. 445 441 446 *****************************************************************************/ 442 447 psArray *pmFindImagePeaks(const psImage *image, … … 456 461 psArray *list = NULL; 457 462 463 psU32 col0 = image->col0; 464 psU32 row0 = image->row0; 465 458 466 // 459 467 // Find peaks in row 0 only. … … 462 470 tmpRow = getRowVectorFromImage((psImage *) image, row); 463 471 psVector *row1 = pmFindVectorPeaks(tmpRow, threshold); 472 // pmFindVectorPeaks returns coords in the vector, not corrected for col0 464 473 465 474 for (psU32 i = 0 ; i < row1->n ; i++ ) { … … 474 483 475 484 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); 477 486 } 478 487 } … … 484 493 (image->data.F32[row][col] >= image->data.F32[row+1][col+1])) { 485 494 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); 487 496 } 488 497 } … … 493 502 (image->data.F32[row][col] >= image->data.F32[row+1][col-1])) { 494 503 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); 496 505 } 497 506 } … … 532 541 (image->data.F32[row][col] >= image->data.F32[row+1][col+1])) { 533 542 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); 535 544 } 536 545 } else if (col < (image->numCols - 1)) { … … 567 576 } 568 577 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); 570 579 } 571 580 } … … 579 588 (image->data.F32[row][col] >= image->data.F32[row+1][col])) { 580 589 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); 582 591 } 583 592 } else { … … 603 612 (image->data.F32[row][col] > image->data.F32[row][col+1])) { 604 613 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); 606 615 } 607 616 } … … 613 622 (image->data.F32[row][col] >= image->data.F32[row][col+1])) { 614 623 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); 616 625 } 617 626 } … … 622 631 (image->data.F32[row][col] > image->data.F32[row][col-1])) { 623 632 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); 625 634 } 626 635 } … … 728 737 XXX: Sync with IfA on whether the peak x/y coords are data structure coords, 729 738 or they use the image row/column offsets. 739 XXX EAM : peak->x,y uses parent coordinates 730 740 731 741 XXX: Should we simply set pmSource->peak = peak? If so, should we increase … … 776 786 return(false); 777 787 } 778 source->moments = pmMomentsAlloc(); 788 if (source->moments == NULL) { 789 source->moments = pmMomentsAlloc(); 790 } 779 791 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 797 bool 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; 780 835 psTrace(__func__, 3, "---- %s(true) end ----\n", __func__); 781 836 return (true); … … 830 885 psS32 numPixels = 0; 831 886 psF32 Sum = 0.0; 887 psF32 Var = 0.0; 832 888 psF32 X1 = 0.0; 833 889 psF32 Y1 = 0.0; … … 841 897 psF32 xPeak = source->peak->x; 842 898 psF32 yPeak = source->peak->y; 899 psF32 xOff = source->pixels->col0 - source->peak->x; 900 psF32 yOff = source->pixels->row0 - source->peak->y; 843 901 844 902 // XXX why do I get different results for these two methods of finding Sx? … … 851 909 // XXX EAM : mask == 0 is valid 852 910 911 psF32 **vPix = source->pixels->data.F32; 912 psF32 **vWgt = source->weight->data.F32; 913 psU8 **vMsk = source->mask->data.U8; 914 853 915 for (psS32 row = 0; row < source->pixels->numRows ; row++) { 854 916 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])) { 856 918 continue; 857 919 } 858 920 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; 861 926 862 927 // XXX EAM : calculate xDiff, yDiff up front; … … 866 931 } 867 932 868 psF32 pDiff = source->pixels->data.F32[row][col] - sky; 933 psF32 pDiff = vPix[row][col] - sky; 934 psF32 wDiff = vWgt[row][col]; 869 935 870 936 // XXX EAM : check for valid S/N in pixel 871 937 // 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) { 873 939 continue; 874 940 } 875 941 942 Var += wDiff; 876 943 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); 885 956 numPixels++; 886 957 } 887 958 } 959 960 // if we have less than (1/4) of the possible pixels, force a retry 888 961 // 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"); 891 964 psTrace(__func__, 3, "---- %s(false) end ----\n", __func__); 892 965 return (false); … … 905 978 y = Y1/Sum; 906 979 if ((fabs(x) > radius) || (fabs(y) > radius)) { 907 psTrace (".psModules.pmSourceMoments", 5,980 psTrace (".psModules.pmSourceMoments", 3, 908 981 "large centroid swing; invalid peak %d, %d\n", 909 982 source->peak->x, source->peak->y); … … 918 991 source->moments->Sxy = XY/Sum - x*y; 919 992 source->moments->Sum = Sum; 993 source->moments->SN = Sum / sqrt(Var); 920 994 source->moments->Peak = peakPixel; 921 995 source->moments->nPixels = numPixels; … … 976 1050 977 1051 /****************************************************************************** 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. 980 1054 *****************************************************************************/ 981 1055 … … 1138 1212 1139 1213 /****************************************************************************** 1140 pmSourceRoughClass(source, metadata): make a guess at the source1141 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 1148 1222 *****************************************************************************/ 1149 1223 … … 1155 1229 1156 1230 int Nsat = 0; 1157 int N gal= 0;1231 int Next = 0; 1158 1232 int Nstar = 0; 1159 1233 int Npsf = 0; 1160 1234 int Ncr = 0; 1161 1235 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 1164 1240 psVector *starsn = psVectorAlloc (sources->n, PS_TYPE_F32); 1165 1241 starsn->n = 0; … … 1167 1243 // check return status value (do these exist?) 1168 1244 bool status; 1169 psF32 RDNOISE = psMetadataLookupF32 (&status, metadata, "RDNOISE");1170 psF32 GAIN = psMetadataLookupF32 (&status, metadata, "GAIN");1171 1245 psF32 PSF_SN_LIM = psMetadataLookupF32 (&status, metadata, "PSF_SN_LIM"); 1172 // psF32 SATURATE = psMetadataLookupF32 (&status, metadata, "SATURATE");1173 1246 1174 1247 // XXX allow clump size to be scaled relative to sigmas? … … 1178 1251 pmSource *tmpSrc = (pmSource *) sources->data[i]; 1179 1252 1180 tmpSrc->peak-> class= 0;1253 tmpSrc->peak->type = 0; 1181 1254 1182 1255 psF32 sigX = tmpSrc->moments->Sx; 1183 1256 psF32 sigY = tmpSrc->moments->Sy; 1184 1257 1185 // calculate and save signal-to-noise estimates1186 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 1193 1258 // 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); 1195 1262 1196 1263 // saturated star (size consistent with PSF or larger) 1197 1264 // Nsigma should be user-configured parameter 1198 1265 bool big = (sigX > (clump.X - clump.dX)) && (sigY > (clump.Y - clump.dY)); 1266 big = true; 1199 1267 if ((Nsatpix > 1) && big) { 1200 tmpSrc->type = PM_SOURCE_SATSTAR; 1268 tmpSrc->type = PM_SOURCE_STAR; 1269 tmpSrc->mode = PM_SOURCE_SATSTAR; 1201 1270 Nsatstar ++; 1202 1271 continue; … … 1206 1275 if (Nsatpix > 1) { 1207 1276 tmpSrc->type = PM_SOURCE_SATURATED; 1277 tmpSrc->mode = PM_SOURCE_DEFAULT; 1208 1278 Nsat ++; 1209 1279 continue; … … 1215 1285 if ((sigX < 0.05) || (sigY < 0.05)) { 1216 1286 tmpSrc->type = PM_SOURCE_DEFECT; 1287 tmpSrc->mode = PM_SOURCE_DEFAULT; 1217 1288 Ncr ++; 1218 1289 continue; 1219 1290 } 1220 1291 1221 // likely unsaturated galaxy(too large to be stellar)1292 // likely unsaturated extended source (too large to be stellar) 1222 1293 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 ++; 1225 1297 continue; 1226 1298 } 1227 1299 1228 1300 // the rest are probable stellar objects 1229 starsn->data.F32[starsn->n] = SN;1301 starsn->data.F32[starsn->n] = tmpSrc->moments->SN; 1230 1302 starsn->n ++; 1231 1303 Nstar ++; 1232 1304 1233 // PSF star (within 1.5 sigma of clump center 1305 // PSF star (within 1.5 sigma of clump center, S/N > limit) 1234 1306 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; 1237 1310 Npsf ++; 1238 1311 continue; … … 1240 1313 1241 1314 // random type of star 1242 tmpSrc->type = PM_SOURCE_OTHER; 1315 tmpSrc->type = PM_SOURCE_STAR; 1316 tmpSrc->mode = PM_SOURCE_DEFAULT; 1243 1317 } 1244 1318 … … 1254 1328 psTrace (".pmObjects.pmSourceRoughClass", 2, "Nstar: %3d\n", Nstar); 1255 1329 psTrace (".pmObjects.pmSourceRoughClass", 2, "Npsf: %3d\n", Npsf); 1256 psTrace (".pmObjects.pmSourceRoughClass", 2, "N gal: %3d\n", Ngal);1330 psTrace (".pmObjects.pmSourceRoughClass", 2, "Next: %3d\n", Next); 1257 1331 psTrace (".pmObjects.pmSourceRoughClass", 2, "Nsatstar: %3d\n", Nsatstar); 1258 1332 psTrace (".pmObjects.pmSourceRoughClass", 2, "Nsat: %3d\n", Nsat); … … 1264 1338 1265 1339 /** pmSourceDefinePixels() 1266 * 1340 * 1267 1341 * Define psImage subarrays for the source located at coordinates x,y on the 1268 1342 * image set defined by readout. The pixels defined by this operation consist of … … 1276 1350 * example). This function should be used to define a region of interest around a 1277 1351 * source, including both source and sky pixels. 1278 * 1352 * 1279 1353 * XXX: must code this. 1280 * 1354 * 1281 1355 */ 1282 1356 bool pmSourceDefinePixels( … … 1294 1368 1295 1369 /****************************************************************************** 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. 1299 1373 *****************************************************************************/ 1300 1374 bool pmSourceSetPixelsCircle(pmSource *source, … … 1369 1443 1370 1444 /****************************************************************************** 1371 pmSourceModelGuess(source, model): This function allocates a new1372 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 in1377 image, not subImage coords. Therefore, the calls to the model evaluation1378 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. 1379 1453 *****************************************************************************/ 1380 1454 pmModel *pmSourceModelGuess(pmSource *source, … … 1394 1468 1395 1469 /****************************************************************************** 1396 evalModel(source, level, row): a private function which evaluates the1397 source->modelPSF function at the specified coords. The coords are subImage, not1398 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 whether1405 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 during1414 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. 1415 1489 *****************************************************************************/ 1416 1490 … … 1441 1515 1442 1516 /****************************************************************************** 1443 pmSourceContour(src, img, level, mode): For an input subImage, and model, this1444 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 should1453 be using only the image counts1517 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 1454 1528 *****************************************************************************/ 1455 1529 psArray *pmSourceContour(pmSource *source, … … 1464 1538 PS_ASSERT_PTR_NON_NULL(source->peak, false); 1465 1539 PS_ASSERT_PTR_NON_NULL(source->pixels, false); 1466 PS_ASSERT_PTR_NON_NULL(source->model FLT, false);1467 // XXX EAM : what is the purpose of modelPSF/model FLT?1540 PS_ASSERT_PTR_NON_NULL(source->modelEXT, false); 1541 // XXX EAM : what is the purpose of modelPSF/modelEXT? 1468 1542 1469 1543 // … … 1558 1632 } 1559 1633 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 1635 static psF32 PM_SOURCE_FIT_MODEL_NUM_ITERATIONS = 15; 1636 static psF32 PM_SOURCE_FIT_MODEL_TOLERANCE = 0.1; 1637 1638 bool 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 1646 bool pmSourceFitModel (pmSource *source, 1647 pmModel *model, 1648 const bool PSF) 1573 1649 { 1574 1650 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); … … 1579 1655 PS_ASSERT_PTR_NON_NULL(source->mask, false); 1580 1656 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 1581 1661 psBool fitStatus = true; 1582 1662 psBool onPic = true; 1583 1663 psBool rc = true; 1584 1664 1585 // XXX EAM : is it necessary for the mask & weight to exist? the1586 // tests below could be conditions (!NULL)1587 1588 1665 psVector *params = model->params; 1589 1666 psVector *dparams = model->dparams; … … 1592 1669 pmModelFunc modelFunc = pmModelFunc_GetFunction (model->type); 1593 1670 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; 1600 1682 for (psS32 i = 0; i < source->pixels->numRows; i++) { 1601 1683 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) { 1608 1706 psTrace (".pmObjects.pmSourceFitModel", 4, "insufficient valid pixels\n"); 1609 1707 psTrace(__func__, 3, "---- %s(false) end ----\n", __func__); 1610 1708 model->status = PM_MODEL_BADARGS; 1709 psFree (x); 1710 psFree (y); 1711 psFree (yErr); 1611 1712 return(false); 1612 1713 } 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 1637 1719 psMinimization *myMin = psMinimizationAlloc(PM_SOURCE_FIT_MODEL_NUM_ITERATIONS, 1638 1720 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 1641 1724 if (PSF) { 1642 1725 paramMask = psVectorAlloc (params->n, PS_TYPE_U8); … … 1648 1731 } 1649 1732 } 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 1652 1739 psImage *covar = psImageAlloc (params->n, params->n, PS_TYPE_F64); 1653 1740 1654 1741 psTrace (".pmObjects.pmSourceFitModel", 5, "fitting function\n"); 1655 1742 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); 1661 1744 for (int i = 0; i < dparams->n; i++) { 1662 1745 if ((paramMask != NULL) && paramMask->data.U8[i]) … … 1673 1756 if (paramMask != NULL) { 1674 1757 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); 1676 1759 for (int i = 0; i < dparams->n; i++) { 1677 1760 if (!paramMask->data.U8[i]) … … 1698 1781 } 1699 1782 1783 source->mode |= PM_SOURCE_FITTED; 1784 1700 1785 psFree(x); 1701 1786 psFree(y); … … 1703 1788 psFree(myMin); 1704 1789 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, ¶ms_min, ¶ms_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); 1830 1794 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 false1838 // XXX EAM: psMinimizeLMChi2 does not check convergence1839 1840 // XXX EAM: save the resulting chisq, nDOF, nIter1841 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 parameters1846 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 status1857 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 these1864 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);1878 1795 1879 1796 rc = (onPic && fitStatus);
Note:
See TracChangeset
for help on using the changeset viewer.
