Changeset 26893
- Timestamp:
- Feb 10, 2010, 7:34:39 PM (16 years ago)
- Location:
- trunk/psModules/src
- Files:
-
- 2 deleted
- 53 edited
- 8 copied
-
astrom/pmAstrometryObjects.c (modified) (16 diffs)
-
camera/pmFPA.c (modified) (1 diff)
-
camera/pmFPAMaskWeight.c (modified) (4 diffs)
-
camera/pmFPAMosaic.c (modified) (6 diffs)
-
camera/pmFPAfile.c (modified) (2 diffs)
-
camera/pmFPAfile.h (modified) (1 diff)
-
camera/pmFPAfileIO.c (modified) (11 diffs)
-
config/pmConfigRecipeValue.c (modified) (1 diff)
-
detrend/Makefile.am (modified) (2 diffs)
-
detrend/pmPattern.c (modified) (9 diffs)
-
detrend/pmPattern.h (modified) (2 diffs)
-
detrend/pmPatternIO.c (copied) (copied from branches/eam_branches/20091201/psModules/src/detrend/pmPatternIO.c )
-
detrend/pmPatternIO.h (copied) (copied from branches/eam_branches/20091201/psModules/src/detrend/pmPatternIO.h )
-
imcombine/Makefile.am (modified) (2 diffs)
-
imcombine/pmImageCombine.c (modified) (5 diffs)
-
imcombine/pmPSFEnvelope.c (modified) (3 diffs)
-
imcombine/pmPSFEnvelope.h (modified) (1 diff)
-
imcombine/pmStackReject.c (modified) (3 diffs)
-
imcombine/pmSubtraction.c (modified) (31 diffs)
-
imcombine/pmSubtraction.h (modified) (3 diffs)
-
imcombine/pmSubtractionAnalysis.c (modified) (3 diffs)
-
imcombine/pmSubtractionAnalysis.h (modified) (1 diff)
-
imcombine/pmSubtractionDeconvolve.c (copied) (copied from branches/eam_branches/20091201/psModules/src/imcombine/pmSubtractionDeconvolve.c )
-
imcombine/pmSubtractionDeconvolve.h (copied) (copied from branches/eam_branches/20091201/psModules/src/imcombine/pmSubtractionDeconvolve.h )
-
imcombine/pmSubtractionEquation.c (modified) (51 diffs)
-
imcombine/pmSubtractionEquation.h (modified) (2 diffs)
-
imcombine/pmSubtractionHermitian.c (copied) (copied from branches/eam_branches/20091201/psModules/src/imcombine/pmSubtractionHermitian.c )
-
imcombine/pmSubtractionHermitian.h (copied) (copied from branches/eam_branches/20091201/psModules/src/imcombine/pmSubtractionHermitian.h )
-
imcombine/pmSubtractionIO.c (modified) (4 diffs)
-
imcombine/pmSubtractionKernels.c (modified) (30 diffs)
-
imcombine/pmSubtractionKernels.h (modified) (15 diffs)
-
imcombine/pmSubtractionMask.c (modified) (3 diffs)
-
imcombine/pmSubtractionMask.h (modified) (1 diff)
-
imcombine/pmSubtractionMatch.c (modified) (25 diffs)
-
imcombine/pmSubtractionMatch.h (modified) (3 diffs)
-
imcombine/pmSubtractionParams.c (modified) (4 diffs)
-
imcombine/pmSubtractionParams.h (modified) (1 diff)
-
imcombine/pmSubtractionStamps.c (modified) (31 diffs)
-
imcombine/pmSubtractionStamps.h (modified) (7 diffs)
-
imcombine/pmSubtractionThreads.c (modified) (1 diff)
-
imcombine/pmSubtractionVisual.c (modified) (14 diffs)
-
imcombine/pmSubtractionVisual.h (modified) (1 diff)
-
objects/pmDetections.c (modified) (2 diffs)
-
objects/pmDetections.h (modified) (1 diff)
-
objects/pmFootprintCullPeaks.c (modified) (7 diffs)
-
objects/pmFootprintFindAtPoint.c (modified) (13 diffs)
-
objects/pmObjects.c (deleted)
-
objects/pmObjects.h (deleted)
-
objects/pmPSF.c (modified) (2 diffs)
-
objects/pmPSF.h (modified) (1 diff)
-
objects/pmPeaks.c (modified) (3 diffs)
-
objects/pmPhotObj.c (copied) (copied from branches/eam_branches/20091201/psModules/src/objects/pmPhotObj.c )
-
objects/pmPhotObj.h (copied) (copied from branches/eam_branches/20091201/psModules/src/objects/pmPhotObj.h )
-
objects/pmSource.c (modified) (8 diffs)
-
objects/pmSource.h (modified) (3 diffs)
-
objects/pmSourceIO.c (modified) (4 diffs)
-
objects/pmSourceIO_CMF_PS1_V2.c (modified) (1 diff)
-
objects/pmSourceIO_MatchedRefs.c (modified) (1 diff)
-
objects/pmSourceMoments.c (modified) (6 diffs)
-
objects/pmSourcePlotApResid.c (modified) (3 diffs)
-
objects/pmSourcePlotMoments.c (modified) (3 diffs)
-
objects/pmSourcePlotPSFModel.c (modified) (3 diffs)
-
psmodules.h (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psModules/src/astrom/pmAstrometryObjects.c
r26359 r26893 108 108 } 109 109 110 if (found1->data.S8[i]) {111 i++;112 continue;113 }114 if (found2->data.S8[j]) {115 j++;116 continue;117 }110 if (found1->data.S8[i]) { 111 i++; 112 continue; 113 } 114 if (found2->data.S8[j]) { 115 j++; 116 continue; 117 } 118 118 119 119 jStart = j; … … 128 128 continue; 129 129 } 130 if (found2->data.S8[j]) {131 j++;132 continue;133 }130 if (found2->data.S8[j]) { 131 j++; 132 continue; 133 } 134 134 135 135 // got a match; add to output list … … 138 138 psFree (match); 139 139 140 found1->data.S8[i] = 1;141 found2->data.S8[j] = 1;140 found1->data.S8[i] = 1; 141 found2->data.S8[j] = 1; 142 142 143 143 j++; … … 196 196 psArray *matches = match_lists(x1, y1, x2, y2, sorted1, sorted2, RADIUS); \ 197 197 \ 198 psFree( (void *)sorted1); \199 psFree( (void *)sorted2); \198 psFree(sorted1); \ 199 psFree(sorted2); \ 200 200 psFree(x1); \ 201 201 psFree(y1); \ … … 314 314 if (!xRes) abort(); 315 315 psFree (xFit); 316 316 317 317 psVector *yFit = psPolynomial2DEvalVector (map->y, X, Y); 318 318 if (!yFit) abort(); … … 322 322 323 323 // extract a high-quality subset (unmasked, S/N > XXX) and position errors 324 // XXX for now, generate a position error based on the magnitude error 324 // XXX for now, generate a position error based on the magnitude error 325 325 psVector *xErr = psVectorAllocEmpty (match->n, PS_TYPE_F32); 326 326 psVector *yErr = psVectorAllocEmpty (match->n, PS_TYPE_F32); … … 329 329 330 330 for (int i = 0; i < match->n; i++) { 331 if (mask->data.PS_TYPE_VECTOR_MASK_DATA[i]) continue;331 if (mask->data.PS_TYPE_VECTOR_MASK_DATA[i]) continue; 332 332 pmAstromMatch *pair = match->data[i]; 333 333 pmAstromObj *rawStar = raw->data[pair->raw]; … … 335 335 if (rawStar->dMag > 0.02) continue; 336 336 337 // two likely failure values: NAN or 0.0 --> use dMag in this case338 float xErrValue, yErrValue;339 if (isfinite(rawStar->chip->xErr) && (rawStar->chip->xErr > 0.0)) {340 xErrValue = rawStar->chip->xErr;341 } else {342 xErrValue = PS_MAX(0.005, rawStar->dMag);343 }344 if (isfinite(rawStar->chip->yErr) && (rawStar->chip->yErr > 0.0)) {345 yErrValue = rawStar->chip->yErr;346 } else {347 yErrValue = PS_MAX(0.005, rawStar->dMag);348 }349 350 psVectorAppend (xErr, xErrValue);351 psVectorAppend (yErr, yErrValue);352 psVectorAppend (xResGood, xRes->data.F32[i]);353 psVectorAppend (yResGood, yRes->data.F32[i]);337 // two likely failure values: NAN or 0.0 --> use dMag in this case 338 float xErrValue, yErrValue; 339 if (isfinite(rawStar->chip->xErr) && (rawStar->chip->xErr > 0.0)) { 340 xErrValue = rawStar->chip->xErr; 341 } else { 342 xErrValue = PS_MAX(0.005, rawStar->dMag); 343 } 344 if (isfinite(rawStar->chip->yErr) && (rawStar->chip->yErr > 0.0)) { 345 yErrValue = rawStar->chip->yErr; 346 } else { 347 yErrValue = PS_MAX(0.005, rawStar->dMag); 348 } 349 350 psVectorAppend (xErr, xErrValue); 351 psVectorAppend (yErr, yErrValue); 352 psVectorAppend (xResGood, xRes->data.F32[i]); 353 psVectorAppend (yResGood, yRes->data.F32[i]); 354 354 } 355 355 … … 434 434 // Get the minimum and maximum values 435 435 if (!psVectorStats(stats, myVector, NULL, NULL, 0)) { 436 psFree(stats);437 return NAN;436 psFree(stats); 437 return NAN; 438 438 } 439 439 min = stats->min; 440 440 max = stats->max; 441 441 if (isnan(min) || isnan(max)) { 442 psFree(stats);443 return NAN;442 psFree(stats); 443 return NAN; 444 444 } 445 445 … … 448 448 // If all data points have the same value, then we set the appropriate members of stats and return. 449 449 if (fabs(max - min) <= FLT_EPSILON) { 450 psFree (stats);451 return 0.0;452 } 453 454 // Define the histogram bin size. 450 psFree (stats); 451 return 0.0; 452 } 453 454 // Define the histogram bin size. 455 455 float binSize = 0.001; 456 456 long numBins = PS_MIN(100000, (max - min) / binSize); // Number of bins … … 463 463 464 464 if (!psVectorHistogram(histogram, myVector, NULL, NULL, 0)) { 465 // if psVectorHistogram returns false, we have a programming error466 psAbort ("Unable to generate histogram");465 // if psVectorHistogram returns false, we have a programming error 466 psAbort ("Unable to generate histogram"); 467 467 } 468 468 if (psTraceGetLevel("psModules.astrom") >= 8) { 469 PS_VECTOR_PRINT_F32(histogram->bounds);470 PS_VECTOR_PRINT_F32(histogram->nums);469 PS_VECTOR_PRINT_F32(histogram->bounds); 470 PS_VECTOR_PRINT_F32(histogram->nums); 471 471 } 472 472 … … 475 475 cumulative->nums->data.F32[0] = histogram->nums->data.F32[0]; 476 476 for (long i = 1; i < histogram->nums->n; i++) { 477 cumulative->nums->data.F32[i] = cumulative->nums->data.F32[i-1] + histogram->nums->data.F32[i];478 cumulative->bounds->data.F32[i-1] = histogram->bounds->data.F32[i];477 cumulative->nums->data.F32[i] = cumulative->nums->data.F32[i-1] + histogram->nums->data.F32[i]; 478 cumulative->bounds->data.F32[i-1] = histogram->bounds->data.F32[i]; 479 479 } 480 480 if (psTraceGetLevel("psModules.astrom") >= 8) { 481 PS_VECTOR_PRINT_F32(cumulative->bounds);482 PS_VECTOR_PRINT_F32(cumulative->nums);481 PS_VECTOR_PRINT_F32(cumulative->bounds); 482 PS_VECTOR_PRINT_F32(cumulative->nums); 483 483 } 484 484 … … 837 837 } 838 838 839 if (psTraceGetLevel("psModules.astrom") >= 5) {840 char line[16];841 psFits *fits = psFitsOpen ("grid.image.fits", "w");842 psFitsWriteImage (fits, NULL, gridNP, 0, NULL);843 psFitsClose (fits);844 fprintf (stderr, "wrote grid image, press return to continue\n");845 if (!fgets(line, 15, stdin)) {846 fprintf(stderr, "Something went wrong; continuing.");839 if (psTraceGetLevel("psModules.astrom") >= 5) { 840 char line[16]; 841 psFits *fits = psFitsOpen ("grid.image.fits", "w"); 842 psFitsWriteImage (fits, NULL, gridNP, 0, NULL); 843 psFitsClose (fits); 844 fprintf (stderr, "wrote grid image, press return to continue\n"); 845 if (!fgets (line, 15, stdin)) { 846 fprintf(stderr, "Error waiting for RETURN."); 847 847 } 848 }848 } 849 849 850 850 // only check bins with at least 1/2 of max bin … … 1191 1191 psArray *pmAstromRadiusMatchUniq (psArray *rawstars, psArray *refstars, psArray *matches) { 1192 1192 1193 // I have the matches between the refstars and the rawstars. 1193 // I have the matches between the refstars and the rawstars. 1194 1194 // For each refstar, find the single match which has the smallest radius and reject 1195 // all others. 1195 // all others. 1196 1196 1197 1197 // create an array of refstars->n arrays, each containing all of the matches for the 1198 // given refstar. 1198 // given refstar. 1199 1199 1200 1200 psArray *refstarMatches = psArrayAlloc (refstars->n); … … 1202 1202 for (int i = 0; i < matches->n; i++) { 1203 1203 1204 pmAstromMatch *match = matches->data[i];1205 1206 // accumulate this refstar match on the array for this refstar (create if needed)1207 psArray *refSet = refstarMatches->data[match->ref];1208 if (!refSet) {1209 refstarMatches->data[match->ref] = psArrayAllocEmpty (8);1210 refSet = refstarMatches->data[match->ref];1211 }1212 1213 pmAstromMatchInfo *matchInfo = pmAstromMatchInfoAlloc();1214 1215 pmAstromObj *refStar = refstars->data[match->ref];1216 pmAstromObj *rawStar = rawstars->data[match->raw];1217 1218 matchInfo->match = match; // reference to the match of interest1219 matchInfo->radius = hypot (refStar->FP->x - rawStar->FP->x, refStar->FP->y - rawStar->FP->y);1220 1221 psArrayAdd (refSet, 8, matchInfo); // matchInfo->match is just a reference1222 psFree (matchInfo);1204 pmAstromMatch *match = matches->data[i]; 1205 1206 // accumulate this refstar match on the array for this refstar (create if needed) 1207 psArray *refSet = refstarMatches->data[match->ref]; 1208 if (!refSet) { 1209 refstarMatches->data[match->ref] = psArrayAllocEmpty (8); 1210 refSet = refstarMatches->data[match->ref]; 1211 } 1212 1213 pmAstromMatchInfo *matchInfo = pmAstromMatchInfoAlloc(); 1214 1215 pmAstromObj *refStar = refstars->data[match->ref]; 1216 pmAstromObj *rawStar = rawstars->data[match->raw]; 1217 1218 matchInfo->match = match; // reference to the match of interest 1219 matchInfo->radius = hypot (refStar->FP->x - rawStar->FP->x, refStar->FP->y - rawStar->FP->y); 1220 1221 psArrayAdd (refSet, 8, matchInfo); // matchInfo->match is just a reference 1222 psFree (matchInfo); 1223 1223 } 1224 1224 … … 1229 1229 for (int i = 0; i < refstars->n; i++) { 1230 1230 1231 psArray *refSet = refstarMatches->data[i];1232 if (!refSet) continue;1233 if (refSet->n == 0) continue; // not certain how this can happen...1234 1235 if (refSet->n == 1) {1236 pmAstromMatchInfo *matchInfo = refSet->data[0];1237 psArrayAdd (unique, 32, matchInfo->match);1238 continue;1239 }1240 1241 pmAstromMatchInfo *matchInfo = refSet->data[0];1242 float minRadius = matchInfo->radius;1243 pmAstromMatch *minMatch = matchInfo->match;1244 for (int j = 1; j < refSet->n; j++) {1245 pmAstromMatchInfo *matchInfo = refSet->data[j];1246 if (minRadius < matchInfo->radius) continue;1247 minMatch = matchInfo->match;1248 minRadius = matchInfo->radius;1249 }1250 1251 psArrayAdd (unique, 32, minMatch); // minMatch is just a reference to a match on matches,1231 psArray *refSet = refstarMatches->data[i]; 1232 if (!refSet) continue; 1233 if (refSet->n == 0) continue; // not certain how this can happen... 1234 1235 if (refSet->n == 1) { 1236 pmAstromMatchInfo *matchInfo = refSet->data[0]; 1237 psArrayAdd (unique, 32, matchInfo->match); 1238 continue; 1239 } 1240 1241 pmAstromMatchInfo *matchInfo = refSet->data[0]; 1242 float minRadius = matchInfo->radius; 1243 pmAstromMatch *minMatch = matchInfo->match; 1244 for (int j = 1; j < refSet->n; j++) { 1245 pmAstromMatchInfo *matchInfo = refSet->data[j]; 1246 if (minRadius < matchInfo->radius) continue; 1247 minMatch = matchInfo->match; 1248 minRadius = matchInfo->radius; 1249 } 1250 1251 psArrayAdd (unique, 32, minMatch); // minMatch is just a reference to a match on matches, 1252 1252 } 1253 1253 -
trunk/psModules/src/camera/pmFPA.c
r26466 r26893 105 105 psFree(fpa->concepts); 106 106 psFree(fpa->analysis); 107 psFree( (void *)fpa->camera);107 psFree(fpa->camera); 108 108 psFree(fpa->hdu); 109 109 -
trunk/psModules/src/camera/pmFPAMaskWeight.c
r26076 r26893 370 370 371 371 psImage *image = readout->image, *mask = readout->mask, *variance = readout->variance; // Readout parts 372 373 372 int numCols = image->numCols, numRows = image->numRows; // Size of image 374 int numPix = numCols * numRows; // Number of pixels 375 int num = PS_MAX(sample, numPix); // Number we care about 373 374 int xMin, xMax, yMin, yMax; // Bounds of image 375 if (mask) { 376 xMin = numCols; 377 xMax = 0; 378 yMin = numRows; 379 yMax = 0; 380 for (int y = 0; y < numRows; y++) { 381 for (int x = 0; x < numCols; x++) { 382 if (mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) { 383 continue; 384 } 385 xMin = PS_MIN(xMin, x); 386 xMax = PS_MAX(xMax, x); 387 yMin = PS_MIN(yMin, y); 388 yMax = PS_MAX(yMax, y); 389 } 390 } 391 } else { 392 xMin = 0; 393 xMax = numCols; 394 yMin = 0; 395 yMax = numRows; 396 } 397 398 int xNum = xMax - xMin, yNum = yMax - yMin; // Number of pixels 399 400 int numPix = xNum * yNum; // Number of pixels 401 int num = PS_MIN(sample, numPix); // Number we care about 376 402 psVector *signoise = psVectorAllocEmpty(num, PS_TYPE_F32); // Signal-to-noise values 377 403 … … 379 405 // We have an image smaller than Nsubset, so just loop over the image pixels 380 406 int index = 0; // Index for vector 381 for (int y = 0; y < numRows; y++) {382 for (int x = 0; x < numCols; x++) {407 for (int y = yMin; y < yMax; y++) { 408 for (int x = xMin; x < xMax; x++) { 383 409 if ((mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) || 384 410 !isfinite(image->data.F32[y][x]) || !isfinite(variance->data.F32[y][x])) { … … 397 423 // Pixel coordinates 398 424 int pixel = numPix * psRandomUniform(rng); 399 int x = pixel % numCols;400 int y = pixel / numCols;425 int x = xMin + pixel % xNum; 426 int y = yMin + pixel / xNum; 401 427 402 428 if ((mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) || … … 428 454 // Check valid range of correction factor 429 455 if ((isfinite(minValid) && correction < minValid) || (isfinite(maxValid) && correction > maxValid)) { 430 psWarning("Variance renormalisation is outside valid range: %f vs %f:%f --- no correction made", 431 correction, minValid, maxValid); 432 return true; 433 } 434 435 psBinaryOp(variance, variance, "*", psScalarAlloc(PS_SQR(correction), PS_TYPE_F32)); 456 psError(PS_ERR_UNKNOWN, true, "Variance renormalisation is outside valid range: %f vs %f:%f --- no correction made", correction, minValid, maxValid); 457 psMetadataAddF32(readout->analysis, PS_LIST_TAIL, PM_READOUT_ANALYSIS_RENORM, 0, "Renormalisation of variance", PS_SQR(correction)); 458 return false; 459 } 460 461 psImage *subImage = psImageSubset(variance, psRegionSet(xMin, xMax, yMin, yMax)); // Smaller image 462 psBinaryOp(subImage, subImage, "*", psScalarAlloc(PS_SQR(correction), PS_TYPE_F32)); 463 psFree(subImage); 436 464 437 465 pmHDU *hdu = pmHDUFromReadout(readout); // HDU for readout -
trunk/psModules/src/camera/pmFPAMosaic.c
r25383 r26893 626 626 bool good = true; // Is everything good? 627 627 628 const char *cellName = psMetadataLookupStr(NULL, cell->concepts, "CELL.NAME"); // Name of cell 629 const char *chipName = psMetadataLookupStr(NULL, cell->parent->concepts, "CHIP.NAME"); // Name of chip 630 628 631 // Offset of the cell on the chip 629 632 int x0Cell = psMetadataLookupS32(&mdok, cell->concepts, "CELL.X0"); 630 633 if (!mdok) { 631 psError(PS_ERR_UNKNOWN, true, "CELL.X0 for cell is not set.\n");634 psError(PS_ERR_UNKNOWN, true, "CELL.X0 for cell %s,%s is not set.\n", chipName, cellName); 632 635 good = false; 633 636 } 634 637 int y0Cell = psMetadataLookupS32(&mdok, cell->concepts, "CELL.Y0"); 635 638 if (!mdok) { 636 psError(PS_ERR_UNKNOWN, true, "CELL.Y0 for cell is not set.\n");639 psError(PS_ERR_UNKNOWN, true, "CELL.Y0 for cell %s,%s is not set.\n", chipName, cellName); 637 640 good = false; 638 641 } 639 psTrace("psModules.camera", 5, "Cell %ld: x0=%d y0=%d\n", index, x0Cell, y0Cell); 642 psTrace("psModules.camera", 5, "Cell %s,%s (%ld): x0=%d y0=%d\n", 643 chipName, cellName, index, x0Cell, y0Cell); 640 644 641 645 // Offset of the chip on the FPA … … 649 653 x0Chip = psMetadataLookupS32(&mdok, chip->concepts, "CHIP.X0"); 650 654 if (!mdok) { 651 psError(PS_ERR_UNKNOWN, true, "CHIP.X0 for chip is not set.\n");655 psError(PS_ERR_UNKNOWN, true, "CHIP.X0 for chip %s is not set.\n", chipName); 652 656 good = false; 653 657 } 654 658 y0Chip = psMetadataLookupS32(&mdok, chip->concepts, "CHIP.Y0"); 655 659 if (!mdok) { 656 psError(PS_ERR_UNKNOWN, true, "CHIP.Y0 for chip is not set.\n");660 psError(PS_ERR_UNKNOWN, true, "CHIP.Y0 for chip %s is not set.\n", chipName); 657 661 good = false; 658 662 } … … 662 666 xBin->data.S32[index] = psMetadataLookupS32(&mdok, cell->concepts, "CELL.XBIN"); 663 667 if (!mdok || xBin->data.S32[index] == 0) { 664 psError(PS_ERR_UNKNOWN, true, "CELL.XBIN for cell is not set.\n");668 psError(PS_ERR_UNKNOWN, true, "CELL.XBIN for cell %s,%s is not set.\n", chipName, cellName); 665 669 return false; 666 670 } else if (xBin->data.S32[index] < *xBinMin) { … … 669 673 yBin->data.S32[index] = psMetadataLookupS32(&mdok, cell->concepts, "CELL.YBIN"); 670 674 if (!mdok || yBin->data.S32[index] == 0) { 671 psError(PS_ERR_UNKNOWN, true, "CELL.YBIN for cell is not set.\n");675 psError(PS_ERR_UNKNOWN, true, "CELL.YBIN for cell %s,%s is not set.\n", chipName, cellName); 672 676 return false; 673 677 } else if (yBin->data.S32[index] < *yBinMin) { … … 678 682 int xParityCell = psMetadataLookupS32(&mdok, cell->concepts, "CELL.XPARITY"); 679 683 if (!mdok || (xParityCell != 1 && xParityCell != -1)) { 680 psError(PS_ERR_UNKNOWN, true, "CELL.XPARITY for cell is not set.\n");684 psError(PS_ERR_UNKNOWN, true, "CELL.XPARITY for cell %s,%s is not set.\n", chipName, cellName); 681 685 return false; 682 686 } 683 687 int yParityCell = psMetadataLookupS32(&mdok, cell->concepts, "CELL.YPARITY"); 684 688 if (!mdok || (yParityCell != 1 && yParityCell != -1)) { 685 psError(PS_ERR_UNKNOWN, true, "CELL.YPARITY for cell is not set.\n");689 psError(PS_ERR_UNKNOWN, true, "CELL.YPARITY for cell %s,%s is not set.\n", chipName, cellName); 686 690 return false; 687 691 } … … 693 697 xParityChip = psMetadataLookupS32(&mdok, chip->concepts, "CHIP.XPARITY"); 694 698 if (!mdok || (xParityChip != 1 && xParityChip != -1)) { 695 psError(PS_ERR_UNKNOWN, true, "CHIP.XPARITY for chip is not set.\n");699 psError(PS_ERR_UNKNOWN, true, "CHIP.XPARITY for chip %s is not set.\n", chipName); 696 700 return false; 697 701 } 698 702 yParityChip = psMetadataLookupS32(&mdok, chip->concepts, "CHIP.YPARITY"); 699 703 if (!mdok || (yParityChip != 1 && yParityChip != -1)) { 700 psError(PS_ERR_UNKNOWN, true, "CHIP.YPARITY for chip is not set.\n");704 psError(PS_ERR_UNKNOWN, true, "CHIP.YPARITY for chip %s is not set.\n", chipName); 701 705 return false; 702 706 } -
trunk/psModules/src/camera/pmFPAfile.c
r23746 r26893 519 519 if (!strcasecmp(type, "SUBKERNEL")) { 520 520 return PM_FPA_FILE_SUBKERNEL; 521 } 522 if (!strcasecmp(type, "PATTERN")) { 523 return PM_FPA_FILE_PATTERN; 521 524 } 522 525 … … 563 566 case PM_FPA_FILE_SUBKERNEL: 564 567 return ("SUBKERNEL"); 568 case PM_FPA_FILE_PATTERN: 569 return "PATTERN"; 565 570 default: 566 571 return ("NONE"); -
trunk/psModules/src/camera/pmFPAfile.h
r25979 r26893 49 49 PM_FPA_FILE_SUBKERNEL, 50 50 PM_FPA_FILE_SRCTEXT, 51 PM_FPA_FILE_PATTERN, 51 52 } pmFPAfileType; 52 53 -
trunk/psModules/src/camera/pmFPAfileIO.c
r25979 r26893 43 43 #include "pmFPAConstruct.h" 44 44 #include "pmSubtractionIO.h" 45 #include "pmPatternIO.h" 45 46 #include "pmConcepts.h" 46 47 #include "pmConfigRun.h" … … 66 67 67 68 switch (place) { 68 case PM_FPA_BEFORE:69 case PM_FPA_BEFORE: 69 70 if (!pmFPAfileRead (file, view, config)) { 70 71 psError(PS_ERR_IO, false, "failed READ in FPA_BEFORE block for %s", file->name); … … 76 77 } 77 78 break; 78 case PM_FPA_AFTER:79 if (!pmFPAfileWrite (file, view, config)) {79 case PM_FPA_AFTER: 80 if (!pmFPAfileWrite (file, view, config)) { 80 81 psError(PS_ERR_IO, false, "failed WRITE in FPA_AFTER block for %s", file->name); 81 82 goto failure; … … 86 87 } 87 88 break; 88 default:89 default: 89 90 psAbort("You can't get here"); 90 91 } … … 202 203 status = pmSubtractionReadKernels(view, file, config); 203 204 break; 205 case PM_FPA_FILE_PATTERN: 206 status = pmPatternRead(view, file, config); 207 break; 204 208 case PM_FPA_FILE_SX: 205 209 case PM_FPA_FILE_RAW: … … 273 277 case PM_FPA_FILE_VARIANCE: 274 278 case PM_FPA_FILE_FRINGE: 275 case PM_FPA_FILE_DARK: { 276 // create FPA structure component based on view 277 psMetadata *format = file->format; // Camera format configuration 278 if (!format) { 279 format = config->format; 280 } 281 282 pmFPA *nameSource = file->src; // Source of FPA.OBS 283 if (!nameSource) { 284 nameSource = file->fpa; 285 } 286 bool mdok; // Status of MD lookup 287 const char *fpaObs = psMetadataLookupStr(&mdok, nameSource->concepts, "FPA.OBS"); // Obs. id 288 289 pmFPAAddSourceFromView(file->fpa, fpaObs, view, format); 290 psTrace ("psModules.camera", 5, "created fpa data elements for %s (%s) (%d:%d:%d)\n", 291 file->name, file->name, view->chip, view->cell, view->readout); 292 break; 293 } 279 case PM_FPA_FILE_DARK: 280 case PM_FPA_FILE_PATTERN: 281 { 282 // create FPA structure component based on view 283 psMetadata *format = file->format; // Camera format configuration 284 if (!format) { 285 format = config->format; 286 } 287 288 pmFPA *nameSource = file->src; // Source of FPA.OBS 289 if (!nameSource) { 290 nameSource = file->fpa; 291 } 292 bool mdok; // Status of MD lookup 293 const char *fpaObs = psMetadataLookupStr(&mdok, nameSource->concepts, "FPA.OBS"); // Obs. id 294 295 pmFPAAddSourceFromView(file->fpa, fpaObs, view, format); 296 psTrace ("psModules.camera", 5, "created fpa data elements for %s (%s) (%d:%d:%d)\n", 297 file->name, file->name, view->chip, view->cell, view->readout); 298 break; 299 } 294 300 case PM_FPA_FILE_HEADER: 295 301 psAbort ("Create not defined for HEADER"); … … 462 468 status = pmSubtractionWriteKernels(view, file, config); 463 469 break; 470 case PM_FPA_FILE_PATTERN: 471 status = pmPatternWrite(view, file, config); 472 break; 464 473 case PM_FPA_FILE_SX: 465 474 case PM_FPA_FILE_RAW: … … 543 552 case PM_FPA_FILE_DARK: 544 553 case PM_FPA_FILE_SUBKERNEL: 554 case PM_FPA_FILE_PATTERN: 545 555 case PM_FPA_FILE_CMF: 546 556 case PM_FPA_FILE_WCS: … … 610 620 break; 611 621 case PM_FPA_FILE_SUBKERNEL: 622 case PM_FPA_FILE_PATTERN: 612 623 case PM_FPA_FILE_SX: 613 624 case PM_FPA_FILE_RAW: … … 771 782 case PM_FPA_FILE_DARK: 772 783 case PM_FPA_FILE_SUBKERNEL: 784 case PM_FPA_FILE_PATTERN: 773 785 case PM_FPA_FILE_CMF: 774 786 case PM_FPA_FILE_WCS: … … 962 974 case PM_FPA_FILE_SUBKERNEL: 963 975 status = pmSubtractionWritePHU(view, file, config); 976 break; 977 case PM_FPA_FILE_PATTERN: 978 status = pmPatternWritePHU(view, file, config); 979 break; 964 980 case PM_FPA_FILE_CMF: 965 981 status = pmSource_CMF_WritePHU (view, file, config); -
trunk/psModules/src/config/pmConfigRecipeValue.c
r26682 r26893 68 68 } 69 69 70 menu = chipItem->data.md; // Menu with values by chip 71 70 72 pmCell *cell = pmFPAviewThisCell(view, fpa); // Cell of interest 71 73 const char *cellName = psMetadataLookupStr(NULL, cell->concepts, "CELL.NAME"); // Name of cell -
trunk/psModules/src/detrend/Makefile.am
r24891 r26893 17 17 pmDark.c \ 18 18 pmRemnance.c \ 19 pmPattern.c 19 pmPattern.c \ 20 pmPatternIO.c 20 21 21 22 # pmSkySubtract.c … … 35 36 pmDark.h \ 36 37 pmRemnance.h \ 37 pmPattern.h 38 pmPattern.h \ 39 pmPatternIO.h 38 40 39 41 # pmSkySubtract.h -
trunk/psModules/src/detrend/pmPattern.c
r24905 r26893 1 1 #include <stdio.h> 2 #include <string.h> 2 3 #include <pslib.h> 3 4 … … 9 10 // Mask a row as bad 10 11 static void patternMaskRow(pmReadout *ro, // Readout to mask 11 int y, // Row to mask12 int y, // Row to mask 12 13 psImageMaskType bad // Mask value to give 13 14 ) … … 17 18 psAssert(y < image->numRows, "Row not in image"); 18 19 19 int numCols = image->numCols; // Size of image20 int numCols = image->numCols; // Number of columns 20 21 for (int x = 0; x < numCols; x++) { 21 22 image->data.F32[y][x] = NAN; … … 29 30 return; 30 31 } 32 33 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 34 // Measurement and application 35 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 31 36 32 37 bool pmPatternRow(pmReadout *ro, int order, int iter, float rej, float thresh, … … 63 68 float lower = stats->robustMedian - thresh * stats->robustStdev; // Lower bound for data 64 69 float upper = stats->robustMedian + thresh * stats->robustStdev; // Upper bound for data 70 float background = stats->robustMedian; 65 71 psFree(stats); 66 72 psFree(rng); … … 79 85 psPolynomial1D *poly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, order); // Polynomial to fit 80 86 psVector *data = psVectorAlloc(numCols, PS_TYPE_F32); // Data to fit 87 88 psImage *corr = psImageAlloc(order + 1, numRows, PS_TYPE_F64); // Corrections applied 89 psImageInit(corr, NAN); 81 90 82 91 for (int y = 0; y < numRows; y++) { … … 104 113 continue; 105 114 } 115 116 poly->coeff[0] -= background; 117 memcpy(corr->data.F64[y], poly->coeff, (order + 1) * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 106 118 psVector *solution = psPolynomial1DEvalVector(poly, indices); // Solution vector 107 119 if (!solution) { … … 117 129 psFree(solution); 118 130 } 131 132 psMetadataAddImage(ro->analysis, PS_LIST_TAIL, PM_PATTERN_ROW_CORRECTION, PS_META_REPLACE, 133 "Pattern row correction", corr); 134 psFree(corr); 119 135 120 136 psFree(indices); … … 126 142 return true; 127 143 } 144 145 bool pmPatternRowApply(pmReadout *ro, psImageMaskType maskBad) 146 { 147 PM_ASSERT_READOUT_NON_NULL(ro, false); 148 PM_ASSERT_READOUT_IMAGE(ro, false); 149 150 bool mdok; // Status of MD lookup 151 psImage *corr = psMetadataLookupPtr(&mdok, ro->analysis, PM_PATTERN_ROW_CORRECTION); // Correction 152 if (!mdok) { 153 // No correction to apply 154 return true; 155 } 156 157 psImage *image = ro->image; // Image of interest 158 int numCols = image->numCols, numRows = image->numRows; // Size of image 159 160 if (corr->numRows != numRows) { 161 psError(PS_ERR_BAD_PARAMETER_SIZE, true, 162 "Number of rows of image (%d) does not match number of rows of pattern correction (%d)\n", 163 numRows, corr->numRows); 164 return false; 165 } 166 167 int order = corr->numCols - 1; // Polynomial order 168 psPolynomial1D *poly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, order); // Polynomial to apply 169 psVector *indices = psVectorAlloc(numCols, PS_TYPE_F32); // Indices for polynomial 170 float norm = 2.0 / (float)numCols; // Normalisation for indices 171 for (int x = 0; x < numCols; x++) { 172 indices->data.F32[x] = x * norm - 1.0; 173 } 174 175 for (int y = 0; y < numRows; y++) { 176 memcpy(poly->coeff, corr->data.F64[y], (order + 1) * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 177 psVector *solution = psPolynomial1DEvalVector(poly, indices); // Solution vector 178 if (!solution) { 179 psWarning("Unable to evaluate polynomial for row %d", y); 180 psErrorClear(); 181 patternMaskRow(ro, y, maskBad); 182 continue; 183 } 184 185 for (int x = 0; x < numCols; x++) { 186 image->data.F32[y][x] -= solution->data.F32[x]; 187 } 188 psFree(solution); 189 } 190 191 psFree(poly); 192 psFree(indices); 193 194 return true; 195 } 196 197 198 bool pmPatternCell(pmChip *chip, const psVector *tweak, psStatsOptions bgStat, psStatsOptions cellStat, 199 psImageMaskType maskVal, psImageMaskType maskBad) 200 { 201 PS_ASSERT_PTR_NON_NULL(chip, false); 202 PS_ASSERT_VECTOR_NON_NULL(tweak, false); 203 PS_ASSERT_VECTOR_SIZE(tweak, chip->cells->n, false); 204 PS_ASSERT_VECTOR_TYPE(tweak, PS_TYPE_U8, false); 205 206 int numCells = tweak->n; // Number of cells 207 208 psVector *mean = psVectorAlloc(numCells, PS_TYPE_F32); // Mean for each cell 209 psVector *meanMask = psVectorAlloc(numCells, PS_TYPE_VECTOR_MASK); // Mask for means 210 psVectorInit(mean, NAN); 211 psVectorInit(meanMask, 0); 212 213 // Mask bits 214 enum { 215 PM_PATTERN_IGNORE = 0x01, // Ignore this cell 216 PM_PATTERN_TWEAK = 0x02, // Tweak this cell 217 PM_PATTERN_ERROR = 0x04, // Error in calculating background 218 PM_PATTERN_ALL = 0xFF, // All causes 219 }; 220 221 // Count number of cells to tweak 222 int numTweak = 0; // Number of cells to tweak 223 int numIgnore = 0; // Number of cells to ignore 224 for (int i = 0; i < numCells; i++) { 225 pmCell *cell = chip->cells->data[i]; // Cell of interest 226 if (!cell || !cell->data_exists || !cell->process || 227 cell->readouts->n == 0 || cell->readouts->n > 1 || !cell->readouts->data[0]) { 228 numIgnore++; 229 meanMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PM_PATTERN_IGNORE; 230 continue; 231 } 232 if (tweak->data.U8[i]) { 233 meanMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PM_PATTERN_TWEAK; 234 numTweak++; 235 } 236 } 237 if (numTweak == 0) { 238 // Nothing to do 239 psFree(mean); 240 psFree(meanMask); 241 return true; 242 } 243 if (numTweak >= numCells - numIgnore) { 244 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Cannot pattern-correct all cells within a chip."); 245 psFree(mean); 246 psFree(meanMask); 247 return false; 248 } 249 250 // Measure mean of each cell 251 // This is not really the perfect thing to do, which would be to take a common mean for the set of cells 252 // which aren't being tweaked (because some cells will be heavily masked, so shouldn't be weighted the 253 // same as pure cells), but it's simple and fast. 254 psStats *bgStats = psStatsAlloc(bgStat); // Statistics on background 255 psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator 256 for (int i = 0; i < numCells; i++) { 257 if (meanMask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PM_PATTERN_IGNORE) { 258 continue; 259 } 260 pmCell *cell = chip->cells->data[i]; // Cell of interest 261 pmReadout *ro = cell->readouts->data[0]; // Readout of interest 262 263 psStatsInit(bgStats); 264 #if 1 265 if (!psImageBackground(bgStats, NULL, ro->image, ro->mask, maskVal, rng)) { 266 psWarning("Unable to measure background for cell %d\n", i); 267 psErrorClear(); 268 meanMask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= PM_PATTERN_ERROR; 269 continue; 270 } 271 #else 272 if (!psImageStats(bgStats, ro->image, ro->mask, maskVal)) { 273 psWarning("Unable to measure background for cell %d\n", i); 274 psErrorClear(); 275 meanMask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= PM_PATTERN_ERROR; 276 continue; 277 } 278 #endif 279 mean->data.F32[i] = psStatsGetValue(bgStats, bgStat); 280 if (!isfinite(mean->data.F32[i])) { 281 psWarning("Non-finite background for cell %d\n", i); 282 psErrorClear(); 283 meanMask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= PM_PATTERN_ERROR; 284 continue; 285 } 286 } 287 psFree(bgStats); 288 psFree(rng); 289 290 psStats *cellStats = psStatsAlloc(cellStat); // Statistics on cells 291 if (!psVectorStats(cellStats, mean, NULL, meanMask, PM_PATTERN_ALL)) { 292 psError(PS_ERR_UNKNOWN, false, "Unable to calculate mean cell background."); 293 psFree(mean); 294 psFree(meanMask); 295 psFree(cellStats); 296 return false; 297 } 298 299 float background = psStatsGetValue(cellStats, cellStat); // Background value for chip 300 psFree(cellStats); 301 if (!isfinite(background)) { 302 psError(PS_ERR_UNKNOWN, false, "Non-finite mean cell background."); 303 psFree(mean); 304 psFree(meanMask); 305 return false; 306 } 307 308 psLogMsg("psModules.detrend", PS_LOG_DETAIL, "Mean chip background is %f", background); 309 310 for (int i = 0; i < numCells; i++) { 311 if (meanMask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PM_PATTERN_IGNORE) { 312 continue; 313 } 314 if (!(meanMask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PM_PATTERN_TWEAK)) { 315 continue; 316 } 317 pmCell *cell = chip->cells->data[i]; // Cell of interest 318 pmReadout *ro = cell->readouts->data[0]; // Readout of interest 319 if (meanMask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PM_PATTERN_ERROR) { 320 psImageInit(ro->image, NAN); 321 psBinaryOp(ro->mask, ro->mask, "|", psScalarAlloc(maskBad, PS_TYPE_IMAGE_MASK)); 322 psMetadataAddF32(ro->analysis, PS_LIST_TAIL, PM_PATTERN_CELL_CORRECTION, PS_META_REPLACE, 323 "Pattern cell correction solution", NAN); 324 continue; 325 } 326 float correction = background - mean->data.F32[i]; // Correction to apply 327 const char *cellName = psMetadataLookupStr(NULL, cell->concepts, "CELL.NAME"); // Name of cell 328 psLogMsg("psModules.detrend", PS_LOG_DETAIL, "Correcting background of cell %s by %f", 329 cellName, correction); 330 psBinaryOp(ro->image, ro->image, "+", psScalarAlloc(correction, PS_TYPE_F32)); 331 psMetadataAddF32(ro->analysis, PS_LIST_TAIL, PM_PATTERN_CELL_CORRECTION, PS_META_REPLACE, 332 "Pattern cell correction solution", correction); 333 } 334 335 psFree(mean); 336 psFree(meanMask); 337 338 return true; 339 } 340 341 bool pmPatternCellApply(pmReadout *ro, psImageMaskType maskBad) 342 { 343 PM_ASSERT_READOUT_NON_NULL(ro, false); 344 PM_ASSERT_READOUT_IMAGE(ro, false); 345 346 bool mdok; // Status of MD lookup 347 float corr = psMetadataLookupF32(&mdok, ro->analysis, PM_PATTERN_CELL_CORRECTION); // Correction to apply 348 if (!mdok) { 349 // No correction to apply 350 return true; 351 } 352 353 psImage *image = ro->image, *mask = ro->mask; // Image and mask of interest 354 int numCols = image->numCols, numRows = image->numRows; // Size of image 355 356 if (!isfinite(corr)) { 357 for (int y = 0; y < numRows; y++) { 358 for (int x = 0; x < numCols; x++) { 359 image->data.F32[y][x] = NAN; 360 } 361 } 362 if (mask) { 363 for (int y = 0; y < numRows; y++) { 364 for (int x = 0; x < numCols; x++) { 365 mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] |= maskBad; 366 } 367 } 368 } 369 } else { 370 for (int y = 0; y < numRows; y++) { 371 for (int x = 0; x < numCols; x++) { 372 image->data.F32[y][x] += corr; 373 } 374 } 375 } 376 377 return true; 378 } 379 380 -
trunk/psModules/src/detrend/pmPattern.h
r24903 r26893 18 18 /// @{ 19 19 20 #define PM_PATTERN_ROW_CORRECTION "PATTERN.ROW.CORRECTION" // Pattern row correction on analysis metadata 21 #define PM_PATTERN_CELL_CORRECTION "PATTERN.CELL.CORRECTION" // Pattern cell correction on analysis metadata 22 20 23 /// Fit and remove pattern noise over rows 21 24 bool pmPatternRow( … … 31 34 ); 32 35 36 /// Apply previously measured row pattern correction 37 bool pmPatternRowApply(pmReadout *ro, ///< Readout to correct 38 psImageMaskType maskBad ///< Mask value to give bad pixels 39 ); 40 41 /// Fix the background on cells known to be troublesome 42 bool pmPatternCell( 43 pmChip *chip, ///< Chip to correct 44 const psVector *tweak, ///< U8 vector indicating whether to tweak the corresponding cell 45 psStatsOptions bgStat, ///< Statistic to use for background measurement 46 psStatsOptions cellStat, ///< Statistic to use for combination of cell background measurements 47 psImageMaskType maskVal, ///< Mask value to use 48 psImageMaskType maskBad ///< Mask value to give bad pixels 49 ); 50 51 /// Apply previously measured cell pattern correction 52 bool pmPatternCellApply(pmReadout *ro, ///< Readout to correct 53 psImageMaskType maskBad ///< Mask value to give bad pixels 54 ); 55 56 33 57 /// @} 34 58 #endif -
trunk/psModules/src/imcombine/Makefile.am
r23242 r26893 13 13 pmSubtractionIO.c \ 14 14 pmSubtractionKernels.c \ 15 pmSubtractionHermitian.c \ 16 pmSubtractionDeconvolve.c \ 15 17 pmSubtractionMask.c \ 16 18 pmSubtractionMatch.c \ … … 32 34 pmSubtractionIO.h \ 33 35 pmSubtractionKernels.h \ 36 pmSubtractionHermitian.h \ 37 pmSubtractionDeconvolve.h \ 34 38 pmSubtractionMask.h \ 35 39 pmSubtractionMatch.h \ -
trunk/psModules/src/imcombine/pmImageCombine.c
r23989 r26893 118 118 psImage *mask = masks->data[i]; // Mask of interest 119 119 pixelMasks->data.PS_TYPE_VECTOR_MASK_DATA[i] = (mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal); 120 } 121 // Set the pixel error data, if necessary120 } 121 // Set the pixel error data, if necessary 122 122 if (errors) { 123 123 psImage *error = errors->data[i]; // Error image of interest … … 132 132 // Combine all the pixels, using the specified stat. 133 133 if (!psVectorStats(stats, pixelData, pixelErrors, pixelMasks, 0xff)) { 134 psError(PS_ERR_UNKNOWN, false, "failure to measure stats");135 return false;136 }137 if (isnan(stats->sampleMean)) {134 psError(PS_ERR_UNKNOWN, false, "failure to measure stats"); 135 return false; 136 } 137 if (isnan(stats->sampleMean)) { 138 138 combine->data.F32[y][x] = NAN; 139 139 psFree(buffer); … … 141 141 } 142 142 float combinedPixel = stats->sampleMean; // Value of the combination 143 143 144 144 if (iter == 0) { 145 145 // Save the value produced with no rejection, since it may be useful later … … 369 369 psStats *stats = psStatsAlloc(PS_STAT_SAMPLE_MEDIAN); 370 370 if (!psVectorStats(stats, pixels, NULL, mask, 1)) { 371 psError(PS_ERR_UNKNOWN, false, "failure to measure stats");371 psError(PS_ERR_UNKNOWN, false, "failure to measure stats"); 372 372 } 373 373 float median = stats->sampleMedian; … … 640 640 (psPlaneTransform * )outToIn->data[otherImg], 641 641 outCoords); 642 psS32 xPix = (int)(inCoords->x +0.5);643 psS32 yPix = (int)(inCoords->y +0.5);642 psS32 xPix = (int)(inCoords->x - 0.5); 643 psS32 yPix = (int)(inCoords->y - 0.5); 644 644 if ((xPix >= 0) && (xPix <= ((psImage*)(images->data[otherImg]))->numCols - 1) && 645 645 (yPix >= 0) && (yPix <= ((psImage*)(images->data[otherImg]))->numRows - 1)) { -
trunk/psModules/src/imcombine/pmPSFEnvelope.c
r25754 r26893 65 65 int radius, // Radius of each PSF 66 66 const char *modelName,// Name of PSF model to use 67 int xOrder, int yOrder // Order for PSF variation fit 67 int xOrder, int yOrder, // Order for PSF variation fit 68 psImageMaskType maskVal 68 69 ) 69 70 { … … 154 155 pmModelClassSetLimits(PM_MODEL_LIMITS_IGNORE); 155 156 pmModel *model = pmModelFromPSFforXY(psf, numCols / 2.0, numRows / 2.0, PEAK_FLUX); // Test model 156 model->modelSetLimits(PM_MODEL_LIMITS_STRICT); 157 for (int j = 0; j < model->params->n && goodPSF; j++) { 158 if (!model->modelLimits(PS_MINIMIZE_PARAM_MIN, j, model->params->data.F32, NULL) || 159 !model->modelLimits(PS_MINIMIZE_PARAM_MAX, j, model->params->data.F32, NULL)) { 160 goodPSF = false; 157 if (!model) { 158 goodPSF = false; 159 } else { 160 model->modelSetLimits(PM_MODEL_LIMITS_STRICT); 161 for (int j = 0; j < model->params->n && goodPSF; j++) { 162 if (!model->modelLimits(PS_MINIMIZE_PARAM_MIN, j, model->params->data.F32, NULL) || 163 !model->modelLimits(PS_MINIMIZE_PARAM_MAX, j, model->params->data.F32, NULL)) { 164 goodPSF = false; 165 } 161 166 } 162 }163 psFree(model);167 psFree(model); 168 } 164 169 if (!goodPSF) { 165 170 psWarning("PSF %d is bad --- not including in envelope calculation.", i); … … 360 365 361 366 // measure the source moments: tophat windowing, no pixel S/N cutoff 362 if (!pmSourceMoments(source, maxRadius, 0.0, 1.0)) { 367 // XXX probably should be passing the maskVal to this function so we can pass it along here... 368 if (!pmSourceMoments(source, maxRadius, 0.0, 1.0, maskVal)) { 363 369 // Can't do anything about it; limp along as best we can 364 370 psErrorClear(); -
trunk/psModules/src/imcombine/pmPSFEnvelope.h
r15837 r26893 17 17 int radius, // Radius of each PSF 18 18 const char *modelName, // Name of PSF model to use 19 int xOrder, int yOrder // Order for PSF variation 19 int xOrder, int yOrder, // Order for PSF variation 20 psImageMaskType maskVal 20 21 ); 21 22 -
trunk/psModules/src/imcombine/pmStackReject.c
r25468 r26893 35 35 { 36 36 int size = kernels->size; // Half-size of convolution kernel 37 psImage *polyValues = p_pmSubtractionPolynomialFromCoords(NULL, kernels, numCols, numRows, 38 xMin + size + 1, yMin + size + 1); // Polynomial 37 int x = PS_MIN(xMin + size + 1, kernels->xMax); // x coordinate of interest 38 int y = PS_MIN(yMin + size + 1, kernels->yMax); // y coordinate of interest 39 40 psImage *polyValues = p_pmSubtractionPolynomialFromCoords(NULL, kernels, x, y); // Polynomial 39 41 int box = p_pmSubtractionBadRadius(NULL, kernels, polyValues, false, poorFrac); // Radius of bad box 40 42 psTrace("psModules.imcombine", 10, "Growing by %d", box); … … 150 152 pmReadout *inRO = pmReadoutAlloc(NULL); // Readout with input image 151 153 inRO->image = image; 154 convRO->image = psImageAlloc(image->numCols, image->numRows, PS_TYPE_F32); 152 155 for (int i = 0; i < numRegions; i++) { 153 156 psRegion *region = subRegions->data[i]; // Region of interest 154 157 pmSubtractionKernels *kernels = subKernels->data[i]; // Kernel of interest 155 if (!pmSubtractionConvolve(NULL, convRO, NULL, inRO, NULL, stride, 0, 0, 1.0, 0.0, 158 if (!pmSubtractionConvolve(NULL, convRO, NULL, inRO, NULL, stride, 0, 0, 1.0, 0.0, 0.0, 156 159 region, kernels, false, true)) { 157 160 psError(PS_ERR_UNKNOWN, false, "Unable to convolve mask image in region %d.", i); … … 165 168 166 169 // Image of the kernel at the centre of the region 167 float xNorm = (region->x0 + 0.5 * (region->x1 - region->x0) - kernels->numCols/2.0) / 168 (float)kernels->numCols; 169 float yNorm = (region->y0 + 0.5 * (region->y1 - region->y0) - kernels->numRows/2.0) / 170 (float)kernels->numRows; 171 psImage *kernel = pmSubtractionKernelImage(kernels, xNorm, yNorm, false); 170 psImage *kernel = pmSubtractionKernelImage(kernels, 0.5, 0.5, false); 172 171 if (!kernel) { 173 172 psError(PS_ERR_UNKNOWN, false, "Unable to generate kernel image."); -
trunk/psModules/src/imcombine/pmSubtraction.c
r26584 r26893 21 21 #include "pmSubtractionStamps.h" 22 22 #include "pmSubtractionEquation.h" 23 #include "pmSubtractionVisual.h" 23 24 #include "pmSubtractionThreads.h" 24 25 … … 63 64 } 64 65 65 // Contribute to an image of the solved kernel component for ISIS66 static void solvedKernel ISIS(psKernel *kernel, // Kernel, updated67 const pmSubtractionKernels *kernels, // Kernel basis functions68 float value, // Normalisation value for basis function69 int index // Index of basis function of interest66 // Contribute to an image of the solved kernel component using the preCalculated image 67 static void solvedKernelPreCalc(psKernel *kernel, // Kernel, updated 68 const pmSubtractionKernels *kernels, // Kernel basis functions 69 float value, // Normalisation value for basis function 70 int index // Index of basis function of interest 70 71 ) 71 72 { 72 73 int size = kernels->size; // Kernel half-size 73 p sArray*preCalc = kernels->preCalc->data[index]; // Precalculated values74 pmSubtractionKernelPreCalc *preCalc = kernels->preCalc->data[index]; // Precalculated values 74 75 #if 0 75 psVector *xKernel = preCalc->data[0]; // Kernel in x76 psVector *yKernel = preCalc->data[1]; // Kernel in y77 76 // Iterating over the kernel 78 77 for (int y = 0, v = -size; v <= size; y++, v++) { 79 float yValue = value * yKernel->data.F32[y];78 float yValue = value * preCalc->yKernel->data.F32[y]; 80 79 for (int x = 0, u = -size; u <= size; x++, u++) { 81 kernel->kernel[v][u] += yValue * xKernel->data.F32[x];80 kernel->kernel[v][u] += yValue * preCalc->xKernel->data.F32[x]; 82 81 } 83 82 } … … 87 86 } 88 87 #else 89 psKernel *k = preCalc->data[2]; // Kernel image90 88 for (int v = -size; v <= size; v++) { 91 89 for (int u = -size; u <= size; u++) { 92 kernel->kernel[v][u] += value * k->kernel[v][u];90 kernel->kernel[v][u] += value * preCalc->kernel->kernel[v][u]; 93 91 } 94 92 } … … 119 117 for (int i = 0; i < numKernels; i++) { 120 118 double value = p_pmSubtractionSolutionCoeff(kernels, polyValues, i, wantDual); // Polynomial value 119 if (wantDual) { 120 // The model is built with the dual convolution terms added, so to produce zero residual the 121 // equation results in negative coefficients which we must undo. 122 value *= -1.0; 123 } 121 124 122 125 switch (kernels->type) { … … 149 152 case PM_SUBTRACTION_KERNEL_GUNK: { 150 153 if (i < kernels->inner) { 151 solvedKernel ISIS(kernel, kernels, value, i);154 solvedKernelPreCalc(kernel, kernels, value, i); 152 155 } else { 153 156 // Using delta function … … 159 162 break; 160 163 } 161 case PM_SUBTRACTION_KERNEL_ISIS: { 162 solvedKernelISIS(kernel, kernels, value, i); 164 case PM_SUBTRACTION_KERNEL_ISIS: 165 case PM_SUBTRACTION_KERNEL_ISIS_RADIAL: 166 case PM_SUBTRACTION_KERNEL_HERM: 167 case PM_SUBTRACTION_KERNEL_DECONV_HERM: { 168 solvedKernelPreCalc(kernel, kernels, value, i); 163 169 break; 164 170 } 165 171 case PM_SUBTRACTION_KERNEL_RINGS: { 166 psArray *preCalc = kernels->preCalc->data[i]; // Precalculated data 167 psVector *uCoords = preCalc->data[0]; // u coordinates 168 psVector *vCoords = preCalc->data[1]; // v coordinates 169 psVector *poly = preCalc->data[2]; // Polynomial values 170 int num = uCoords->n; // Number of pixels 172 pmSubtractionKernelPreCalc *preCalc = kernels->preCalc->data[i]; // Precalculated kernels 173 int num = preCalc->uCoords->n; // Number of pixels 171 174 172 175 for (int j = 0; j < num; j++) { 173 int u = uCoords->data.S32[j], v = vCoords->data.S32[j]; // Kernel coordinates 174 kernel->kernel[v][u] += poly->data.F32[j] * value; 176 int u = preCalc->uCoords->data.S32[j]; 177 int v = preCalc->vCoords->data.S32[j]; // Kernel coordinates 178 kernel->kernel[v][u] += preCalc->poly->data.F32[j] * value; 175 179 } 176 180 // Photometric scaling is built into the kernel --- no subtraction! … … 419 423 *target |= maskBad; 420 424 } else if (*source & subConvPoor) { 425 *target &= ~maskBad; 421 426 *target |= maskPoor; 427 } else { 428 *target &= ~maskBad & ~maskPoor; 422 429 } 423 430 } … … 454 461 #endif 455 462 456 // Convolve a stamp using a n ISISkernel basis function457 static psKernel *convolveStamp ISIS(const psKernel *image, // Image to convolve458 const pmSubtractionKernels *kernels, // Kernel basis functions459 int index, // Index of basis function of interest460 int footprint // Half-size of stamp463 // Convolve a stamp using a pre-calculated kernel basis function 464 static psKernel *convolveStampPreCalc(const psKernel *image, // Image to convolve 465 const pmSubtractionKernels *kernels, // Kernel basis functions 466 int index, // Index of basis function of interest 467 int footprint // Half-size of stamp 461 468 ) 462 469 { 463 p sArray*preCalc = kernels->preCalc->data[index]; // Precalculated data470 pmSubtractionKernelPreCalc *preCalc = kernels->preCalc->data[index]; // Precalculated data 464 471 #if 0 465 472 // Convolving using separable convolution 466 psVector *xKernel = preCalc->data[0]; // Kernel in x467 psVector *yKernel = preCalc->data[1]; // Kernel in y468 473 int size = kernels->size; // Size of kernel 469 474 … … 477 482 float value = 0.0; // Value of convolved pixel 478 483 int uMin = x - size, uMax = x + size; // Range for u 479 psF32 *xKernelData = & xKernel->data.F32[xKernel->n - 1]; // Kernel values484 psF32 *xKernelData = &preCalc->xKernel->data.F32[xKernel->n - 1]; // Kernel values 480 485 psF32 *imageData = &image->kernel[y][uMin]; // Image values 481 486 for (int u = uMin; u <= uMax; u++, xKernelData--, imageData++) { … … 492 497 float value = 0.0; // Value of convolved pixel 493 498 int vMin = y - size, vMax = y + size; // Range for v 494 psF32 *yKernelData = & yKernel->data.F32[yKernel->n - 1]; // Kernel values499 psF32 *yKernelData = &preCalc->yKernel->data.F32[yKernel->n - 1]; // Kernel values 495 500 psF32 *imageData = &temp->kernel[x][vMin]; // Image values; NOTE: wrong way! 496 501 for (int v = vMin; v <= vMax; v++, yKernelData--, imageData++) { … … 509 514 #else 510 515 // Convolving using precalculated kernel 511 return p_pmSubtractionConvolveStampPrecalc(image, preCalc-> data[2]);516 return p_pmSubtractionConvolveStampPrecalc(image, preCalc->kernel); 512 517 #endif 513 518 } … … 525 530 int x0 = - image->xMin, y0 = - image->yMin; // Position of centre of convolved image 526 531 psKernel *convolved = psKernelAllocFromImage(conv, x0, y0); // Kernel version 532 533 // pmSubtractionVisualShowSubtraction(image->image, kernel->image, conv); 534 527 535 psFree(conv); 528 536 return convolved; … … 569 577 } 570 578 579 void p_pmSubtractionPolynomialNormCoords(float *xOut, float *yOut, float xIn, float yIn, 580 int xMin, int xMax, int yMin, int yMax) 581 { 582 float xNormSize = xMax - xMin, yNormSize = yMax - yMin; // Size to use for normalisation 583 *xOut = 2.0 * (float)(xIn - xMin - xNormSize/2.0) / xNormSize; 584 *yOut = 2.0 * (float)(yIn - yMin - yNormSize/2.0) / yNormSize; 585 return; 586 } 587 571 588 psImage *p_pmSubtractionPolynomialFromCoords(psImage *output, const pmSubtractionKernels *kernels, 572 int numCols, int numRows, intx, int y)589 int x, int y) 573 590 { 574 591 assert(kernels); 575 assert(numCols > 0 && numRows > 0); 576 577 // Size to use when calculating normalised coordinates (different from actual size when convolving 578 // subimage) 579 int xNormSize = (kernels->numCols > 0 ? kernels->numCols : numCols); 580 int yNormSize = (kernels->numRows > 0 ? kernels->numRows : numRows); 581 582 // Normalised coordinates 583 float yNorm = 2.0 * (float)(y - yNormSize/2.0) / (float)yNormSize; 584 float xNorm = 2.0 * (float)(x - xNormSize/2.0) / (float)xNormSize; 585 592 593 float xNorm, yNorm; // Normalised coordinates 594 p_pmSubtractionPolynomialNormCoords(&xNorm, &yNorm, x, y, 595 kernels->xMin, kernels->xMax, kernels->yMin, kernels->yMax); 586 596 return p_pmSubtractionPolynomial(output, kernels->spatialOrder, xNorm, yNorm); 587 597 } … … 664 674 if (index < kernels->inner) { 665 675 // Photometric scaling is already built in to the precalculated kernel 666 return convolveStamp ISIS(image, kernels, index, footprint);676 return convolveStampPreCalc(image, kernels, index, footprint); 667 677 } 668 678 // Using delta function … … 673 683 return convolved; 674 684 } 675 case PM_SUBTRACTION_KERNEL_ISIS: { 676 return convolveStampISIS(image, kernels, index, footprint); 677 } 685 case PM_SUBTRACTION_KERNEL_ISIS: 686 case PM_SUBTRACTION_KERNEL_ISIS_RADIAL: 687 case PM_SUBTRACTION_KERNEL_HERM: 688 case PM_SUBTRACTION_KERNEL_DECONV_HERM: { 689 return convolveStampPreCalc(image, kernels, index, footprint); 690 } 678 691 case PM_SUBTRACTION_KERNEL_RINGS: { 679 psKernel *convolved = psKernelAlloc(-footprint, footprint, 680 -footprint, footprint); // Convolved image 681 psArray *preCalc = kernels->preCalc->data[index]; // Precalculated data 682 psVector *uCoords = preCalc->data[0]; // u coordinates 683 psVector *vCoords = preCalc->data[1]; // v coordinates 684 psVector *poly = preCalc->data[2]; // Polynomial values 685 int num = uCoords->n; // Number of pixels 686 psS32 *uData = uCoords->data.S32, *vData = vCoords->data.S32; // Dereference u,v coordinates 687 psF32 *polyData = poly->data.F32; // Dereference polynomial values 692 psKernel *convolved = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Convolved image 693 pmSubtractionKernelPreCalc *preCalc = kernels->preCalc->data[index]; // Precalculated data 694 695 int num = preCalc->uCoords->n; // Number of pixels 696 psS32 *uData = preCalc->uCoords->data.S32; // Dereference v coordinate 697 psS32 *vData = preCalc->vCoords->data.S32; // Dereference u coordinate 698 psF32 *polyData = preCalc->poly->data.F32; // Dereference polynomial values 688 699 psF32 **imageData = image->kernel; // Dereference image 689 700 psF32 **convData = convolved->kernel; // Dereference convolved image … … 765 776 766 777 767 768 769 778 int pmSubtractionRejectStamps(pmSubtractionKernels *kernels, pmSubtractionStampList *stamps, 770 779 const psVector *deviations, psImage *subMask, float sigmaRej) … … 860 869 int numGood = 0; // Number of good stamps 861 870 double newMean = 0.0; // New mean 871 psString log = NULL; // Log message 872 psStringAppend(&log, "Rejecting stamps, mean = %f, threshold = %f\n", mean, limit); 862 873 for (int i = 0; i < stamps->num; i++) { 863 874 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest … … 872 883 // Mask out the stamp in the image so you it's not found again 873 884 psTrace("psModules.imcombine", 3, "Rejecting stamp %d (%d,%d)\n", i, 874 (int)(stamp->x + 0.5), (int)(stamp->y + 0.5)); 885 (int)(stamp->x - 0.5), (int)(stamp->y - 0.5)); 886 psStringAppend(&log, "Stamp %d (%d,%d): %f\n", i, 887 (int)(stamp->x - 0.5), (int)(stamp->y - 0.5), 888 fabsf(deviations->data.F32[i] - mean)); 875 889 numRejected++; 876 890 for (int y = stamp->y - footprint; y <= stamp->y + footprint; y++) { … … 895 909 psFree(stamp->weight); 896 910 stamp->image1 = stamp->image2 = stamp->weight = NULL; 897 psFree(stamp->matrix1); 898 psFree(stamp->matrix2); 899 psFree(stamp->matrixX); 900 stamp->matrix1 = stamp->matrix2 = stamp->matrixX = NULL; 901 psFree(stamp->vector1); 902 psFree(stamp->vector2); 903 stamp->vector1 = stamp->vector2 = NULL; 911 psFree(stamp->matrix); 912 stamp->matrix = NULL; 913 psFree(stamp->vector); 914 stamp->vector = NULL; 904 915 } else { 905 916 numGood++; … … 910 921 } 911 922 newMean /= numGood; 923 924 if (numRejected == 0) { 925 psStringAppend(&log, "<none>\n"); 926 } 927 psLogMsg("psModules.imcombine", PS_LOG_DETAIL, "%s", log); 928 psFree(log); 912 929 913 930 if (ds9) { … … 995 1012 psVector *backup = psVectorCopy(NULL, solution, PS_TYPE_F64); // Backup version 996 1013 997 int num = wantDual ? solution->n - 1 : solution->n;// Number of kernel basis functions1014 int num = kernels->num; // Number of kernel basis functions 998 1015 999 1016 psImage *polyValues = p_pmSubtractionPolynomial(NULL, kernels->spatialOrder, x, y); // Solved polynomial … … 1060 1077 // Only generate polynomial values every kernel footprint, since we have already assumed 1061 1078 // (with the stamps) that it does not vary rapidly on this scale. 1062 psImage *polyValues = p_pmSubtractionPolynomialFromCoords(NULL, kernels, numCols, numRows, 1063 xMin + x0 + size + 1, 1064 yMin + y0 + size + 1); 1079 psImage *polyValues = p_pmSubtractionPolynomialFromCoords(NULL, kernels, xMin + x0 + size + 1, 1080 yMin + y0 + size + 1); // Polynomial 1065 1081 float background = doBG ? p_pmSubtractionSolutionBackground(kernels, polyValues) : 0.0; // Background term 1066 1082 … … 1137 1153 bool pmSubtractionConvolve(pmReadout *out1, pmReadout *out2, const pmReadout *ro1, const pmReadout *ro2, 1138 1154 psImage *subMask, int stride, psImageMaskType maskBad, psImageMaskType maskPoor, 1139 float poorFrac, float kernelError, const psRegion *region,1155 float poorFrac, float kernelError, float covarFrac, const psRegion *region, 1140 1156 const pmSubtractionKernels *kernels, bool doBG, bool useFFT) 1141 1157 { … … 1146 1162 PM_ASSERT_READOUT_NON_NULL(ro1, false); 1147 1163 PM_ASSERT_READOUT_IMAGE(ro1, false); 1164 PM_ASSERT_READOUT_IMAGE(out1, false); 1148 1165 numCols = ro1->image->numCols; 1149 1166 numRows = ro1->image->numRows; … … 1155 1172 PM_ASSERT_READOUT_NON_NULL(ro2, false); 1156 1173 PM_ASSERT_READOUT_IMAGE(ro2, false); 1174 PM_ASSERT_READOUT_IMAGE(out2, false); 1157 1175 if (numCols == 0 && numRows == 0) { 1158 1176 numCols = ro2->image->numCols; … … 1177 1195 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(kernelError, 0.0, false); 1178 1196 PS_ASSERT_FLOAT_LESS_THAN_OR_EQUAL(kernelError, 1.0, false); 1197 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(covarFrac, 0.0, false); 1198 PS_ASSERT_FLOAT_LESS_THAN(covarFrac, 1.0, false); 1179 1199 if (region && psRegionIsNaN(*region)) { 1180 1200 psString string = psRegionToString(*region); … … 1188 1208 bool threaded = pmSubtractionThreaded(); // Running threaded? 1189 1209 1190 // Outputs1191 if (kernels->mode == PM_SUBTRACTION_MODE_1 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) {1192 if (!out1->image) {1193 out1->image = psImageAlloc(numCols, numRows, PS_TYPE_F32);1194 }1195 if (ro1->variance) {1196 if (!out1->variance) {1197 out1->variance = psImageAlloc(numCols, numRows, PS_TYPE_F32);1198 }1199 psImageInit(out1->variance, 0.0);1200 }1201 }1202 if (kernels->mode == PM_SUBTRACTION_MODE_2 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) {1203 if (!out2->image) {1204 out2->image = psImageAlloc(numCols, numRows, PS_TYPE_F32);1205 }1206 if (ro2->variance) {1207 if (!out2->variance) {1208 out2->variance = psImageAlloc(numCols, numRows, PS_TYPE_F32);1209 }1210 psImageInit(out2->variance, 0.0);1211 }1212 }1213 1210 psImage *convMask = NULL; // Convolved mask image (common to inputs 1 and 2) 1214 1211 if (subMask) { 1215 1212 if (kernels->mode == PM_SUBTRACTION_MODE_1 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 1216 if (!out1->mask) {1217 out1->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK);1218 }1219 psImageInit(out1->mask, 0);1220 1213 convMask = out1->mask; 1221 1214 } 1222 1215 if (kernels->mode == PM_SUBTRACTION_MODE_2 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 1223 if (!out2->mask) {1224 out2->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK);1225 }1226 psImageInit(out2->mask, 0);1227 1216 if (!convMask) { 1228 1217 convMask = out2->mask; … … 1244 1233 1245 1234 // Get region for convolution: [xMin:xMax,yMin:yMax] 1246 int xMin = size, xMax = numCols- size;1247 int yMin = size, yMax = numRows- size;1235 int xMin = kernels->xMin + size, xMax = kernels->xMax - size; 1236 int yMin = kernels->yMin + size, yMax = kernels->yMax - size; 1248 1237 if (region) { 1249 1238 xMin = PS_MAX(region->x0, xMin); … … 1336 1325 1337 1326 // Calculate covariances 1338 // This can take a while, so we only do it for a single instance 1339 // XXX psImageCovarianceCalculate could be multithreaded 1327 // This can be fairly involved, so we only do it for a single instance 1328 // Enable threads for covariance calculation, since we're not threading on top of it. 1329 oldThreads = psImageCovarianceSetThreads(true); 1340 1330 if (kernels->mode == PM_SUBTRACTION_MODE_1 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 1341 1331 psKernel *kernel = pmSubtractionKernel(kernels, 0.0, 0.0, false); // Convolution kernel 1332 psKernelTruncate(kernel, covarFrac); 1342 1333 out1->covariance = psImageCovarianceCalculate(kernel, ro1->covariance); 1343 1334 psFree(kernel); … … 1346 1337 psKernel *kernel = pmSubtractionKernel(kernels, 0.0, 0.0, 1347 1338 kernels->mode == PM_SUBTRACTION_MODE_DUAL); // Conv. kernel 1339 psKernelTruncate(kernel, covarFrac); 1348 1340 out2->covariance = psImageCovarianceCalculate(kernel, ro2->covariance); 1349 1341 psFree(kernel); 1350 1342 } 1343 psImageCovarianceSetThreads(oldThreads); 1351 1344 1352 1345 // Copy anything that wasn't convolved … … 1388 1381 } 1389 1382 1390 1391 1383 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Convolve image: %f sec", 1392 1384 psTimerClear("pmSubtractionConvolve")); -
trunk/psModules/src/imcombine/pmSubtraction.h
r25279 r26893 113 113 psImageMaskType maskPoor, ///< Mask value to give poor pixels 114 114 float poorFrac, ///< Fraction for "poor" 115 float sysError, ///< Relative systematic error 115 float kernelError, ///< Relative systematic error in kernel 116 float covarFrac, ///< Truncation fraction for kernel before covariance calculation 116 117 const psRegion *region, ///< Region to convolve (or NULL) 117 118 const pmSubtractionKernels *kernels, ///< Kernel parameters … … 127 128 ); 128 129 130 /// Return normalised coordinates 131 void p_pmSubtractionPolynomialNormCoords( 132 float *xOut, float *yOut, ///< Normalised coordinates, returned 133 float xIn, float yIn, ///< Input coordinates 134 int xMin, int xMax, int yMin, int yMax ///< Bounds of validity 135 ); 136 129 137 /// Given (normalised) coordinates (x,y), generate a matrix where the elements (i,j) are x^i * y^j 130 138 psImage *p_pmSubtractionPolynomial(psImage *output, ///< Output matrix, or NULL … … 138 146 psImage *p_pmSubtractionPolynomialFromCoords(psImage *output, ///< Output matrix, or NULL 139 147 const pmSubtractionKernels *kernels, ///< Kernel parameters 140 int numCols, int numRows, ///< Size of image of interest141 148 int x, int y ///< Position of interest 142 149 ); -
trunk/psModules/src/imcombine/pmSubtractionAnalysis.c
r25999 r26893 117 117 } 118 118 119 // sample difference images 120 { 121 psMetadataAddArray(analysis, PS_LIST_TAIL, "SUBTRACTION.SAMPLE.STAMP.SET", PS_META_DUPLICATE_OK, "Sample Difference Stamps", kernels->sampleStamps); 122 } 119 123 120 124 #ifdef TESTING … … 269 273 // Difference in background 270 274 { 271 psImage *polyValues = p_pmSubtractionPolynomialFromCoords(NULL, kernels, numCols, numRows, 272 numCols / 2.0, numRows / 2.0); // Polynomial 275 psImage *polyValues = p_pmSubtractionPolynomial(NULL, kernels->spatialOrder, 0.0, 0.0); // Polynomial 273 276 float bg = p_pmSubtractionSolutionBackground(kernels, polyValues); // Background difference 274 277 … … 295 298 psMetadataAddF32(header, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_DEV_RMS, 0, "RMS stamp deviation", 296 299 kernels->rms); 300 301 psMetadataAddF32(analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FSIGMA_RES_MEAN, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResMean); 302 psMetadataAddF32(analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FSIGMA_RES_STDEV, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResStdev); 303 psMetadataAddF32(analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMIN_RES_MEAN, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResMean); 304 psMetadataAddF32(analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMIN_RES_STDEV, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResStdev); 305 psMetadataAddF32(analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMAX_RES_MEAN, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResMean); 306 psMetadataAddF32(analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMAX_RES_STDEV, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResStdev); 307 308 psMetadataAddF32(header, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FSIGMA_RES_MEAN, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResMean); 309 psMetadataAddF32(header, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FSIGMA_RES_STDEV, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResStdev); 310 psMetadataAddF32(header, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMIN_RES_MEAN, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResMean); 311 psMetadataAddF32(header, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMIN_RES_STDEV, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResStdev); 312 psMetadataAddF32(header, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMAX_RES_MEAN, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResMean); 313 psMetadataAddF32(header, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMAX_RES_STDEV, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResStdev); 297 314 } 298 315 -
trunk/psModules/src/imcombine/pmSubtractionAnalysis.h
r25060 r26893 24 24 #define PM_SUBTRACTION_ANALYSIS_DECONV_MAX "SUBTRACTION.DECONV.MAX" // Maximum deconvolution fraction 25 25 26 #define PM_SUBTRACTION_ANALYSIS_FSIGMA_RES_MEAN "SUBTRACTION.RES.FSIGMA.MEAN" // RMS stamp deviation 27 #define PM_SUBTRACTION_ANALYSIS_FSIGMA_RES_STDEV "SUBTRACTION.RES.FSIGMA.STDEV" // RMS stamp deviation 28 #define PM_SUBTRACTION_ANALYSIS_FMIN_RES_MEAN "SUBTRACTION.RES.FMIN.MEAN" // RMS stamp deviation 29 #define PM_SUBTRACTION_ANALYSIS_FMIN_RES_STDEV "SUBTRACTION.RES.FMIN.STDEV" // RMS stamp deviation 30 #define PM_SUBTRACTION_ANALYSIS_FMAX_RES_MEAN "SUBTRACTION.RES.FMAX.MEAN" // RMS stamp deviation 31 #define PM_SUBTRACTION_ANALYSIS_FMAX_RES_STDEV "SUBTRACTION.RES.FMAX.STDEV" // RMS stamp deviation 32 26 33 // Derive QA information about the subtraction 27 34 bool pmSubtractionAnalysis( -
trunk/psModules/src/imcombine/pmSubtractionEquation.c
r26035 r26893 17 17 //#define TESTING // TESTING output for debugging; may not work with threads! 18 18 19 #define USE_WEIGHT // Include weight (1/variance) in equation? 19 //#define USE_WEIGHT // Include weight (1/variance) in equation? 20 //#define USE_WINDOW // Include weight (1/variance) in equation? 20 21 21 22 … … 27 28 static bool calculateMatrixVector(psImage *matrix, // Least-squares matrix, updated 28 29 psVector *vector, // Least-squares vector, updated 30 double *norm, // Normalisation, updated 29 31 const psKernel *input, // Input image (target) 30 32 const psKernel *reference, // Reference image (convolution source) 31 33 const psKernel *weight, // Weight image 34 const psKernel *window, // Window image 32 35 const psArray *convolutions, // Convolutions for each kernel 33 36 const pmSubtractionKernels *kernels, // Kernels 34 37 const psImage *polyValues, // Spatial polynomial values 35 int footprint // (Half-)Size of stamp 38 int footprint, // (Half-)Size of stamp 39 int normWindow, // Window (half-)size for normalisation measurement 40 const pmSubtractionEquationCalculationMode mode 36 41 ) 37 42 { … … 51 56 52 57 // Evaluate polynomial-polynomial terms 58 // XXX we can skip this if we are not calculating kernel coeffs 53 59 for (int iyOrder = 0, iIndex = 0; iyOrder <= spatialOrder; iyOrder++) { 54 60 for (int ixOrder = 0; ixOrder <= spatialOrder - iyOrder; ixOrder++, iIndex++) { … … 64 70 } 65 71 72 // initialize the matrix and vector for NOP on all coeffs. we only fill in the coeffs we 73 // choose to calculate 74 psImageInit(matrix, 0.0); 75 psVectorInit(vector, 1.0); 76 for (int i = 0; i < matrix->numCols; i++) { 77 matrix->data.F64[i][i] = 1.0; 78 } 79 80 // the order of the elements in the matrix and vector is: 81 // [kernel 0, x^0 y^0][kernel 1 x^0 y^0]...[kernel N, x^0 y^0] 82 // [kernel 0, x^1 y^0][kernel 1 x^1 y^0]...[kernel N, x^1 y^0] 83 // [kernel 0, x^n y^m][kernel 1 x^n y^m]...[kernel N, x^n y^m] 84 // normalization 85 // bg 0, bg 1, bg 2 (only 0 is currently used?) 66 86 67 87 for (int i = 0; i < numKernels; i++) { … … 74 94 for (int x = - footprint; x <= footprint; x++) { 75 95 double cc = iConv->kernel[y][x] * jConv->kernel[y][x]; 76 #ifdef USE_WEIGHT 77 cc *= weight->kernel[y][x]; 78 #endif 96 if (weight) { 97 cc *= weight->kernel[y][x]; 98 } 99 if (window) { 100 cc *= window->kernel[y][x]; 101 } 79 102 sumCC += cc; 80 103 } 81 104 } 82 105 83 // Spatial variation 84 for (int iTerm = 0, iIndex = i; iTerm < numPoly; iTerm++, iIndex += numKernels) { 85 for (int jTerm = 0, jIndex = j; jTerm < numPoly; jTerm++, jIndex += numKernels) { 86 double value = sumCC * poly2[iTerm][jTerm]; 87 matrix->data.F64[iIndex][jIndex] = value; 88 matrix->data.F64[jIndex][iIndex] = value; 106 // Spatial variation of kernel coeffs 107 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 108 for (int iTerm = 0, iIndex = i; iTerm < numPoly; iTerm++, iIndex += numKernels) { 109 for (int jTerm = 0, jIndex = j; jTerm < numPoly; jTerm++, jIndex += numKernels) { 110 double value = sumCC * poly2[iTerm][jTerm]; 111 matrix->data.F64[iIndex][jIndex] = value; 112 matrix->data.F64[jIndex][iIndex] = value; 113 } 89 114 } 90 115 } … … 102 127 double rc = ref * conv; 103 128 double c = conv; 104 #ifdef USE_WEIGHT 105 float wtVal = weight->kernel[y][x]; 106 ic *= wtVal; 107 rc *= wtVal; 108 c *= wtVal; 109 #endif 129 if (weight) { 130 float wtVal = weight->kernel[y][x]; 131 ic *= wtVal; 132 rc *= wtVal; 133 c *= wtVal; 134 } 135 if (window) { 136 float winVal = window->kernel[y][x]; 137 ic *= winVal; 138 rc *= winVal; 139 c *= winVal; 140 } 110 141 sumIC += ic; 111 142 sumRC += rc; … … 117 148 double normTerm = sumRC * poly[iTerm]; 118 149 double bgTerm = sumC * poly[iTerm]; 119 matrix->data.F64[iIndex][normIndex] = normTerm; 120 matrix->data.F64[normIndex][iIndex] = normTerm; 121 matrix->data.F64[iIndex][bgIndex] = bgTerm; 122 matrix->data.F64[bgIndex][iIndex] = bgTerm; 123 vector->data.F64[iIndex] = sumIC * poly[iTerm]; 150 if ((mode & PM_SUBTRACTION_EQUATION_NORM) && (mode & PM_SUBTRACTION_EQUATION_KERNELS)) { 151 matrix->data.F64[iIndex][normIndex] = normTerm; 152 matrix->data.F64[normIndex][iIndex] = normTerm; 153 } 154 if ((mode & PM_SUBTRACTION_EQUATION_BG) && (mode & PM_SUBTRACTION_EQUATION_KERNELS)) { 155 matrix->data.F64[iIndex][bgIndex] = bgTerm; 156 matrix->data.F64[bgIndex][iIndex] = bgTerm; 157 } 158 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 159 vector->data.F64[iIndex] = sumIC * poly[iTerm]; 160 if (!(mode & PM_SUBTRACTION_EQUATION_NORM)) { 161 // subtract norm * sumRC * poly[iTerm] 162 psAssert (kernels->solution1, "programming error: define solution first!"); 163 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 164 double norm = fabs(kernels->solution1->data.F64[normIndex]); // Normalisation 165 vector->data.F64[iIndex] -= norm * normTerm; 166 } 167 } 124 168 } 125 169 } … … 130 174 double sumR = 0.0; // Sum of the reference 131 175 double sumI = 0.0; // Sum of the input 176 double normI1 = 0.0, normI2 = 0.0; // Sum of I_1 and I_2 within the normalisation window 132 177 for (int y = - footprint; y <= footprint; y++) { 133 178 for (int x = - footprint; x <= footprint; x++) { … … 137 182 double rr = PS_SQR(ref); 138 183 double one = 1.0; 139 #ifdef USE_WEIGHT 140 float wtVal = weight->kernel[y][x]; 141 rr *= wtVal; 142 ir *= wtVal; 143 in *= wtVal; 144 ref *= wtVal; 145 one *= wtVal; 146 #endif 184 185 if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(normWindow)) { 186 normI1 += ref; 187 normI2 += in; 188 } 189 190 if (weight) { 191 float wtVal = weight->kernel[y][x]; 192 rr *= wtVal; 193 ir *= wtVal; 194 in *= wtVal; 195 ref *= wtVal; 196 one *= wtVal; 197 } 198 if (window) { 199 float winVal = window->kernel[y][x]; 200 rr *= winVal; 201 ir *= winVal; 202 in *= winVal; 203 ref *= winVal; 204 one *= winVal; 205 } 147 206 sumRR += rr; 148 207 sumIR += ir; … … 152 211 } 153 212 } 154 matrix->data.F64[normIndex][normIndex] = sumRR; 155 matrix->data.F64[bgIndex][bgIndex] = sum1; 156 matrix->data.F64[normIndex][bgIndex] = matrix->data.F64[bgIndex][normIndex] = sumR; 157 vector->data.F64[normIndex] = sumIR; 158 vector->data.F64[bgIndex] = sumI; 213 214 *norm = normI2 / normI1; 215 216 if (mode & PM_SUBTRACTION_EQUATION_NORM) { 217 matrix->data.F64[normIndex][normIndex] = sumRR; 218 vector->data.F64[normIndex] = sumIR; 219 // subtract sum over kernels * kernel solution 220 } 221 if (mode & PM_SUBTRACTION_EQUATION_BG) { 222 matrix->data.F64[bgIndex][bgIndex] = sum1; 223 vector->data.F64[bgIndex] = sumI; 224 } 225 if ((mode & PM_SUBTRACTION_EQUATION_NORM) && (mode & PM_SUBTRACTION_EQUATION_BG)) { 226 matrix->data.F64[normIndex][bgIndex] = sumR; 227 matrix->data.F64[bgIndex][normIndex] = sumR; 228 } 229 230 // check for any NAN values in the result, skip if found: 231 for (int iy = 0; iy < matrix->numRows; iy++) { 232 for (int ix = 0; ix < matrix->numCols; ix++) { 233 if (!isfinite(matrix->data.F64[iy][ix])) { 234 fprintf (stderr, "WARNING: NAN in matrix\n"); 235 return false; 236 } 237 } 238 } 239 for (int ix = 0; ix < vector->n; ix++) { 240 if (!isfinite(vector->data.F64[ix])) { 241 fprintf (stderr, "WARNING: NAN in vector\n"); 242 return false; 243 } 244 } 159 245 160 246 return true; 161 247 } 162 248 249 163 250 // Calculate the least-squares matrix and vector for dual convolution 164 static bool calculateDualMatrixVector(psImage *matrix1, // Least-squares matrix, updated 165 psVector *vector1, // Least-squares vector, updated 166 psImage *matrix2, // Least-squares matrix, updated 167 psVector *vector2, // Least-squares vector, updated 168 psImage *matrixX, // Cross-matrix 251 static bool calculateDualMatrixVector(psImage *matrix, // Least-squares matrix, updated 252 psVector *vector, // Least-squares vector, updated 253 double *norm, // Normalisation, updated 169 254 const psKernel *image1, // Image 1 170 255 const psKernel *image2, // Image 2 171 256 const psKernel *weight, // Weight image 257 const psKernel *window, // Window image 172 258 const psArray *convolutions1, // Convolutions of image 1 for each kernel 173 259 const psArray *convolutions2, // Convolutions of image 2 for each kernel 174 260 const pmSubtractionKernels *kernels, // Kernels 175 261 const psImage *polyValues, // Spatial polynomial values 176 int footprint // (Half-)Size of stamp 262 int footprint, // (Half-)Size of stamp 263 int normWindow, // Window (half-)size for normalisation measurement 264 const pmSubtractionEquationCalculationMode mode 177 265 ) 178 266 { 179 // A_ij = A_i A_j180 // B_ij = B_i B_j181 // C_ij = A_i B_j182 // d_i = A_i I_2183 // e_i = B_i I_2184 185 // A_i = I_1 * k_i186 // B_i = I_2 * k_i187 188 // Background: A_i = 1.0189 // Normalisation: A_i = I_1190 191 267 int numKernels = kernels->num; // Number of kernels 192 268 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation … … 196 272 double poly[numPoly]; // Polynomial terms 197 273 double poly2[numPoly][numPoly]; // Polynomial-polynomial values 274 275 int numBackground = PM_SUBTRACTION_POLYTERMS(kernels->bgOrder); // Number of background terms 276 int numParams = numKernels * numPoly + 1 + numBackground; // Number of regular parameters 277 int numParams2 = numKernels * numPoly; // Number of additional parameters for dual 278 int numDual = numParams + numParams2; // Total number of parameters for dual 279 280 psAssert(matrix && 281 matrix->type.type == PS_TYPE_F64 && 282 matrix->numCols == numDual && 283 matrix->numRows == numDual, 284 "Least-squares matrix is bad."); 285 psAssert(vector && 286 vector->type.type == PS_TYPE_F64 && 287 vector->n == numDual, 288 "Least-squares vector is bad."); 198 289 199 290 // Evaluate polynomial-polynomial terms … … 212 303 213 304 305 // initialize the matrix and vector for NOP on all coeffs. we only fill in the coeffs we 306 // choose to calculate 307 psImageInit(matrix, 0.0); 308 psVectorInit(vector, 1.0); 309 for (int i = 0; i < matrix->numCols; i++) { 310 matrix->data.F64[i][i] = 1.0; 311 } 312 214 313 for (int i = 0; i < numKernels; i++) { 215 314 psKernel *iConv1 = convolutions1->data[i]; // Convolution 1 for index i … … 219 318 psKernel *jConv2 = convolutions2->data[j]; // Convolution 2 for index j 220 319 221 double sumAA = 0.0; // Sum of convolution products for matrix A222 double sumBB = 0.0; // Sum of convolution products for matrix B223 double sumAB = 0.0; // Sum of convolution products for matrix C320 double sumAA = 0.0; // Sum of convolution products between image 1 321 double sumBB = 0.0; // Sum of convolution products between image 2 322 double sumAB = 0.0; // Sum of convolution products across images 1 and 2 224 323 for (int y = - footprint; y <= footprint; y++) { 225 324 for (int x = - footprint; x <= footprint; x++) { … … 227 326 double bb = iConv2->kernel[y][x] * jConv2->kernel[y][x]; 228 327 double ab = iConv1->kernel[y][x] * jConv2->kernel[y][x]; 229 #ifdef USE_WEIGHT 230 float wtVal = weight->kernel[y][x]; 231 aa *= wtVal; 232 bb *= wtVal; 233 ab *= wtVal; 234 #endif 328 if (weight) { 329 float wtVal = weight->kernel[y][x]; 330 aa *= wtVal; 331 bb *= wtVal; 332 ab *= wtVal; 333 } 334 if (window) { 335 float wtVal = window->kernel[y][x]; 336 aa *= wtVal; 337 bb *= wtVal; 338 ab *= wtVal; 339 } 235 340 sumAA += aa; 236 341 sumBB += bb; … … 239 344 } 240 345 241 // Spatial variation 242 for (int iTerm = 0, iIndex = i; iTerm < numPoly; iTerm++, iIndex += numKernels) { 243 for (int jTerm = 0, jIndex = j; jTerm < numPoly; jTerm++, jIndex += numKernels) { 244 double aa = sumAA * poly2[iTerm][jTerm]; 245 double bb = sumBB * poly2[iTerm][jTerm]; 246 double ab = sumAB * poly2[iTerm][jTerm]; 247 matrix1->data.F64[iIndex][jIndex] = aa; 248 matrix1->data.F64[jIndex][iIndex] = aa; 249 matrix2->data.F64[iIndex][jIndex] = bb; 250 matrix2->data.F64[jIndex][iIndex] = bb; 251 matrixX->data.F64[iIndex][jIndex] = ab; 346 // Spatial variation of kernel coeffs 347 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 348 for (int iTerm = 0, iIndex = i; iTerm < numPoly; iTerm++, iIndex += numKernels) { 349 for (int jTerm = 0, jIndex = j; jTerm < numPoly; jTerm++, jIndex += numKernels) { 350 double aa = sumAA * poly2[iTerm][jTerm]; 351 double bb = sumBB * poly2[iTerm][jTerm]; 352 double ab = sumAB * poly2[iTerm][jTerm]; 353 354 matrix->data.F64[iIndex][jIndex] = aa; 355 matrix->data.F64[jIndex][iIndex] = aa; 356 357 matrix->data.F64[iIndex + numParams][jIndex + numParams] = bb; 358 matrix->data.F64[jIndex + numParams][iIndex + numParams] = bb; 359 360 matrix->data.F64[iIndex][jIndex + numParams] = ab; 361 matrix->data.F64[jIndex + numParams][iIndex] = ab; 362 } 252 363 } 253 364 } … … 259 370 for (int x = - footprint; x <= footprint; x++) { 260 371 double ab = iConv1->kernel[y][x] * jConv2->kernel[y][x]; 261 #ifdef USE_WEIGHT 262 ab *= weight->kernel[y][x]; 263 #endif 372 if (weight) { 373 ab *= weight->kernel[y][x]; 374 } 375 if (window) { 376 ab *= window->kernel[y][x]; 377 } 264 378 sumAB += ab; 265 379 } 266 380 } 267 381 268 // Spatial variation 269 for (int iTerm = 0, iIndex = i; iTerm < numPoly; iTerm++, iIndex += numKernels) { 270 for (int jTerm = 0, jIndex = j; jTerm < numPoly; jTerm++, jIndex += numKernels) { 271 double ab = sumAB * poly2[iTerm][jTerm]; 272 matrixX->data.F64[iIndex][jIndex] = ab; 273 } 274 } 275 } 276 277 double sumAI2 = 0.0; // Sum of A.I_2 products (for vector 1) 278 double sumBI2 = 0.0; // Sum of B.I_2 products (for vector 2) 279 double sumAI1 = 0.0; // Sum of A.I_1 products (for matrix 1, normalisation) 280 double sumA = 0.0; // Sum of A (for matrix 1, background) 281 double sumBI1 = 0.0; // Sum of B.I_1 products (for matrix X, normalisation) 282 double sumB = 0.0; // Sum of B products (for matrix X, background) 283 double sumI2 = 0.0; // Sum of I_2 (for vector 1, background) 284 double sumI1I2 = 0.0; // Sum of I_1.I_2 (for vector 1, normalisation) 382 // Spatial variation of kernel coeffs 383 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 384 for (int iTerm = 0, iIndex = i; iTerm < numPoly; iTerm++, iIndex += numKernels) { 385 for (int jTerm = 0, jIndex = j; jTerm < numPoly; jTerm++, jIndex += numKernels) { 386 double ab = sumAB * poly2[iTerm][jTerm]; 387 matrix->data.F64[iIndex][jIndex + numParams] = ab; 388 matrix->data.F64[jIndex + numParams][iIndex] = ab; 389 } 390 } 391 } 392 } 393 394 double sumAI2 = 0.0; // Sum of A.I_2 products (for vector) 395 double sumBI2 = 0.0; // Sum of B.I_2 products (for vector) 396 double sumAI1 = 0.0; // Sum of A.I_1 products (for matrix, normalisation) 397 double sumA = 0.0; // Sum of A (for matrix, background) 398 double sumBI1 = 0.0; // Sum of B.I_1 products (for matrix, normalisation) 399 double sumB = 0.0; // Sum of B products (for matrix, background) 400 double sumI2 = 0.0; // Sum of I_2 (for vector, background) 285 401 for (int y = - footprint; y <= footprint; y++) { 286 402 for (int x = - footprint; x <= footprint; x++) { 287 floata = iConv1->kernel[y][x];288 floatb = iConv2->kernel[y][x];403 double a = iConv1->kernel[y][x]; 404 double b = iConv2->kernel[y][x]; 289 405 float i1 = image1->kernel[y][x]; 290 406 float i2 = image2->kernel[y][x]; … … 294 410 double ai1 = a * i1; 295 411 double bi1 = b * i1; 296 double i1i2 = i1 * i2; 297 298 #ifdef USE_WEIGHT 299 float wtVal = weight->kernel[y][x]; 300 ai2 *= wtVal; 301 bi2 *= wtVal; 302 ai1 *= wtVal; 303 bi1 *= wtVal; 304 i1i2 *= wtVal; 305 a *= wtVal; 306 b *= wtVal; 307 i2 *= wtVal; 308 #endif 309 412 413 if (weight) { 414 float wtVal = weight->kernel[y][x]; 415 ai2 *= wtVal; 416 bi2 *= wtVal; 417 ai1 *= wtVal; 418 bi1 *= wtVal; 419 a *= wtVal; 420 b *= wtVal; 421 i2 *= wtVal; 422 } 423 if (window) { 424 float wtVal = window->kernel[y][x]; 425 ai2 *= wtVal; 426 bi2 *= wtVal; 427 ai1 *= wtVal; 428 bi1 *= wtVal; 429 a *= wtVal; 430 b *= wtVal; 431 i2 *= wtVal; 432 } 310 433 sumAI2 += ai2; 311 434 sumBI2 += bi2; … … 315 438 sumB += b; 316 439 sumI2 += i2; 317 sumI1I2 += i1i2;318 440 } 319 441 } … … 323 445 double bi2 = sumBI2 * poly[iTerm]; 324 446 double ai1 = sumAI1 * poly[iTerm]; 325 double a = sumA * poly[iTerm];447 double a = sumA * poly[iTerm]; 326 448 double bi1 = sumBI1 * poly[iTerm]; 327 double b = sumB * poly[iTerm]; 328 329 matrix1->data.F64[iIndex][normIndex] = ai1; 330 matrix1->data.F64[normIndex][iIndex] = ai1; 331 matrix1->data.F64[iIndex][bgIndex] = a; 332 matrix1->data.F64[bgIndex][iIndex] = a; 333 vector1->data.F64[iIndex] = ai2; 334 vector2->data.F64[iIndex] = bi2; 335 matrixX->data.F64[iIndex][normIndex] = bi1; 336 matrixX->data.F64[iIndex][bgIndex] = b; 337 } 338 } 339 340 double sumI1 = 0.0; // Sum of I_1 (for matrix 1, background-normalisation) 341 double sumI1I1 = 0.0; // Sum of I_1^2 (for matrix 1, normalisation-normalisation) 342 double sum1 = 0.0; // Sum of 1 (for matrix 1, background-background) 343 double sumI2 = 0.0; // Sum of I_2 (for vector 1, background) 344 double sumI1I2 = 0.0; // Sum of I_1.I_2 (for vector 1, normalisation) 449 double b = sumB * poly[iTerm]; 450 451 if ((mode & PM_SUBTRACTION_EQUATION_NORM) && (mode & PM_SUBTRACTION_EQUATION_KERNELS)) { 452 matrix->data.F64[iIndex][normIndex] = ai1; 453 matrix->data.F64[normIndex][iIndex] = ai1; 454 matrix->data.F64[iIndex + numParams][normIndex] = bi1; 455 matrix->data.F64[normIndex][iIndex + numParams] = bi1; 456 } 457 if ((mode & PM_SUBTRACTION_EQUATION_BG) && (mode & PM_SUBTRACTION_EQUATION_KERNELS)) { 458 matrix->data.F64[iIndex][bgIndex] = a; 459 matrix->data.F64[bgIndex][iIndex] = a; 460 matrix->data.F64[iIndex + numParams][bgIndex] = b; 461 matrix->data.F64[bgIndex][iIndex + numParams] = b; 462 } 463 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 464 vector->data.F64[iIndex] = ai2; 465 vector->data.F64[iIndex + numParams] = bi2; 466 if (!(mode & PM_SUBTRACTION_EQUATION_NORM)) { 467 // subtract norm * sumRC * poly[iTerm] 468 psAssert (kernels->solution1, "programming error: define solution first!"); 469 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 470 double norm = fabs(kernels->solution1->data.F64[normIndex]); // Normalisation 471 vector->data.F64[iIndex] -= norm * ai1; 472 vector->data.F64[iIndex + numParams] -= norm * bi1; 473 } 474 } 475 } 476 } 477 478 double sumI1 = 0.0; // Sum of I_1 (for matrix, background-normalisation) 479 double sumI1I1 = 0.0; // Sum of I_1^2 (for matrix, normalisation-normalisation) 480 double sum1 = 0.0; // Sum of 1 (for matrix, background-background) 481 double sumI2 = 0.0; // Sum of I_2 (for vector, background) 482 double sumI1I2 = 0.0; // Sum of I_1.I_2 (for vector, normalisation) 483 double normI1 = 0.0, normI2 = 0.0; // Sum of I_1 and I_2 within the normalisation window 345 484 for (int y = - footprint; y <= footprint; y++) { 346 485 for (int x = - footprint; x <= footprint; x++) { 347 floati1 = image1->kernel[y][x];348 floati2 = image2->kernel[y][x];486 double i1 = image1->kernel[y][x]; 487 double i2 = image2->kernel[y][x]; 349 488 350 489 double i1i1 = i1 * i1; … … 352 491 double i1i2 = i1 * i2; 353 492 354 #ifdef USE_WEIGHT 355 float wtVal = weight->kernel[y][x]; 356 i1 *= wtVal; 357 i1i1 *= wtVal; 358 one *= wtVal; 359 i2 *= wtVal; 360 i1i2 *= wtVal; 361 #endif 362 493 if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(normWindow)) { 494 normI1 += i1; 495 normI2 += i2; 496 } 497 498 if (weight) { 499 float wtVal = weight->kernel[y][x]; 500 i1 *= wtVal; 501 i1i1 *= wtVal; 502 one *= wtVal; 503 i2 *= wtVal; 504 i1i2 *= wtVal; 505 } 506 if (window) { 507 float wtVal = window->kernel[y][x]; 508 i1 *= wtVal; 509 i1i1 *= wtVal; 510 one *= wtVal; 511 i2 *= wtVal; 512 i1i2 *= wtVal; 513 } 363 514 sumI1 += i1; 364 515 sumI1I1 += i1i1; … … 368 519 } 369 520 } 370 matrix1->data.F64[bgIndex][normIndex] = sumI1; 371 matrix1->data.F64[normIndex][bgIndex] = sumI1; 372 matrix1->data.F64[normIndex][normIndex] = sumI1I1; 373 matrix1->data.F64[bgIndex][bgIndex] = sum1; 374 vector1->data.F64[bgIndex] = sumI2; 375 vector1->data.F64[normIndex] = sumI1I2; 521 522 *norm = normI2 / normI1; 523 524 if (mode & PM_SUBTRACTION_EQUATION_NORM) { 525 matrix->data.F64[normIndex][normIndex] = sumI1I1; 526 vector->data.F64[normIndex] = sumI1I2; 527 } 528 if (mode & PM_SUBTRACTION_EQUATION_BG) { 529 matrix->data.F64[bgIndex][bgIndex] = sum1; 530 vector->data.F64[bgIndex] = sumI2; 531 } 532 if ((mode & PM_SUBTRACTION_EQUATION_NORM) && (mode & PM_SUBTRACTION_EQUATION_BG)) { 533 matrix->data.F64[bgIndex][normIndex] = sumI1; 534 matrix->data.F64[normIndex][bgIndex] = sumI1; 535 } 536 537 // check for any NAN values in the result, skip if found: 538 for (int iy = 0; iy < matrix->numRows; iy++) { 539 for (int ix = 0; ix < matrix->numCols; ix++) { 540 if (!isfinite(matrix->data.F64[iy][ix])) { 541 fprintf (stderr, "WARNING: NAN in matrix\n"); 542 return false; 543 } 544 } 545 } 546 for (int ix = 0; ix < vector->n; ix++) { 547 if (!isfinite(vector->data.F64[ix])) { 548 fprintf (stderr, "WARNING: NAN in vector\n"); 549 return false; 550 } 551 } 552 376 553 377 554 return true; 378 555 } 379 556 380 // Merge dual matrices and vectors into single matrix equation 381 // Have: Aa = Ct.b + d 382 // Have: Ca = Bb + e 383 // Set: F = ( A -Ct ; C -B ) 384 // Set: g = ( a ; b ) 385 // Set: h = ( d ; e ) 386 // So that we combine the above two equations: Fg = h 387 static bool calculateEquationDual(psImage **outMatrix, 388 psVector **outVector, 389 const psImage *sumMatrix1, 390 const psImage *sumMatrix2, 391 const psImage *sumMatrixX, 392 const psVector *sumVector1, 393 const psVector *sumVector2 394 ) 395 { 396 psAssert(sumMatrix1 && sumMatrix2 && sumMatrixX, "Require input matrices"); 397 psAssert(sumVector1 && sumVector2, "Require input vectors"); 398 int num1 = sumVector1->n; // Number of parameters in first set 399 int num2 = sumVector2->n; // Number of parameters in second set 400 int num = num1 + num2; // Number of parameters in new set 401 402 psAssert(sumMatrix1->type.type == PS_TYPE_F64 && 403 sumMatrix2->type.type == PS_TYPE_F64 && 404 sumMatrixX->type.type == PS_TYPE_F64 && 405 sumVector1->type.type == PS_TYPE_F64 && 406 sumVector2->type.type == PS_TYPE_F64, 407 "Require input type is F64"); 408 409 psAssert(outMatrix, "Require output matrix"); 410 psAssert(outVector, "Require output vector"); 411 if (!*outMatrix) { 412 *outMatrix = psImageAlloc(num, num, PS_TYPE_F64); 413 } 414 if (!*outVector) { 415 *outVector = psVectorAlloc(num, PS_TYPE_F64); 416 } 417 psImage *matrix = *outMatrix; 418 psVector *vector = *outVector; 419 420 psAssert(sumMatrix1->numCols == num1 && sumMatrix1->numRows == num1, "Require size NxN"); 421 psAssert(sumMatrix2->numCols == num2 && sumMatrix2->numRows == num2, "Require size MxM"); 422 psAssert(sumMatrixX->numCols == num1 && sumMatrixX->numRows == num2, "Require size MxN"); 423 424 memcpy(vector->data.F64, sumVector1->data.F64, num1 * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 425 memcpy(&vector->data.F64[num1], sumVector2->data.F64, num2 * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 426 427 for (int i = 0; i < num1; i++) { 428 memcpy(matrix->data.F64[i], sumMatrix1->data.F64[i], num1 * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 429 for (int j = 0, k = num1; j < num2; j++, k++) { 430 matrix->data.F64[i][k] = - sumMatrixX->data.F64[j][i]; 431 } 432 } 433 for (int i1 = 0, i2 = num1; i1 < num2; i1++, i2++) { 434 memcpy(matrix->data.F64[i2], sumMatrixX->data.F64[i1], num1 * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 435 for (int j = 0, k = num1; j < num2; j++, k++) { 436 matrix->data.F64[i2][k] = - sumMatrix2->data.F64[i1][j]; 437 } 438 } 439 440 return true; 441 } 442 443 557 #if 1 444 558 // Add in penalty term to least-squares vector 445 staticbool calculatePenalty(psImage *matrix, // Matrix to which to add in penalty term559 bool calculatePenalty(psImage *matrix, // Matrix to which to add in penalty term 446 560 psVector *vector, // Vector to which to add in penalty term 447 561 const pmSubtractionKernels *kernels, // Kernel parameters … … 456 570 int spatialOrder = kernels->spatialOrder; // Order of spatial variations 457 571 int numKernels = kernels->num; // Number of kernel components 572 int numSpatial = PM_SUBTRACTION_POLYTERMS(spatialOrder); // Number of spatial variations 573 int numParams = numKernels * numSpatial; // Number of kernel parameters 574 575 // order is : 576 // [p_0,x_0,y_0 p_1,x_0,y_0, p_2,x_0,y_0] 577 // [p_0,x_1,y_0 p_1,x_1,y_0, p_2,x_1,y_0] 578 // [p_0,x_0,y_1 p_1,x_0,y_1, p_2,x_0,y_1] 579 // [norm] 580 // [bg] 581 // [q_0,x_0,y_0 q_1,x_0,y_0, q_2,x_0,y_0] 582 // [q_0,x_1,y_0 q_1,x_1,y_0, q_2,x_1,y_0] 583 // [q_0,x_0,y_1 q_1,x_0,y_1, q_2,x_0,y_1] 584 458 585 for (int i = 0; i < numKernels; i++) { 459 586 for (int yOrder = 0, index = i; yOrder <= spatialOrder; yOrder++) { 460 587 for (int xOrder = 0; xOrder <= spatialOrder - yOrder; xOrder++, index += numKernels) { 461 588 // Contribution to chi^2: a_i^2 P_i 462 matrix->data.F64[index][index] -= norm * penalties->data.F32[i]; 589 psAssert(isfinite(penalties->data.F32[i]), "Invalid penalty"); 590 matrix->data.F64[index][index] += norm * penalties->data.F32[i]; 591 if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 592 matrix->data.F64[index + numParams + 2][index + numParams + 2] += norm * penalties->data.F32[i]; 593 // matrix[i][i] is ~ (k_i * I_1)(k_i * I_1) 594 // penalties scale with second moments 595 // 596 } 463 597 } 464 598 } … … 467 601 return true; 468 602 } 603 # endif 469 604 470 605 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// … … 476 611 // Calculate the value of a polynomial, specified by coefficients and polynomial values 477 612 double p_pmSubtractionCalculatePolynomial(const psVector *coeff, // Coefficients 478 const psImage *polyValues, // Polynomial values479 int order, // Order of polynomials480 int index, // Index at which to begin481 int step // Step between subsequent indices482 )613 const psImage *polyValues, // Polynomial values 614 int order, // Order of polynomials 615 int index, // Index at which to begin 616 int step // Step between subsequent indices 617 ) 483 618 { 484 619 double sum = 0.0; // Value of the polynomial sum … … 495 630 496 631 double p_pmSubtractionSolutionCoeff(const pmSubtractionKernels *kernels, const psImage *polyValues, 497 int index, bool wantDual)632 int index, bool wantDual) 498 633 { 499 634 #if 0 … … 548 683 const pmSubtractionKernels *kernels = job->args->data[1]; // Kernels 549 684 int index = PS_SCALAR_VALUE(job->args->data[2], S32); // Stamp index 550 551 return pmSubtractionCalculateEquationStamp(stamps, kernels, index); 685 pmSubtractionEquationCalculationMode mode = PS_SCALAR_VALUE(job->args->data[3], S32); // calculation model 686 687 return pmSubtractionCalculateEquationStamp(stamps, kernels, index, mode); 552 688 } 553 689 554 690 bool pmSubtractionCalculateEquationStamp(pmSubtractionStampList *stamps, const pmSubtractionKernels *kernels, 555 int index )691 int index, const pmSubtractionEquationCalculationMode mode) 556 692 { 557 693 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false); … … 566 702 int numBackground = PM_SUBTRACTION_POLYTERMS(kernels->bgOrder); // Number of background terms 567 703 704 // numKernels is the number of unique kernel images (one for each Gaussian modified by a specific polynomial). 705 // = \sum_i^N_Gaussians [(order + 1) * (order + 2) / 2], eg for 1 Gauss and 1st order, numKernels = 3 706 568 707 // Total number of parameters to solve for: coefficient of each kernel basis function, multipled by the 569 708 // number of coefficients for the spatial polynomial, normalisation and a constant background offset. 570 709 int numParams = numKernels * numSpatial + 1 + numBackground; 710 if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 711 // An additional image is convolved 712 numParams += numKernels * numSpatial; 713 } 571 714 572 715 pmSubtractionStamp *stamp = stamps->stamps->data[index]; // Stamp of interest 573 716 psAssert(stamp->status == PM_SUBTRACTION_STAMP_CALCULATE, "We only operate on stamps with this state."); 574 717 575 // Generate convolutions 718 // Generate convolutions: these are generated once and saved 576 719 if (!pmSubtractionConvolveStamp(stamp, kernels, footprint)) { 577 720 psError(PS_ERR_UNKNOWN, false, "Unable to convolve stamp %d.", index); … … 603 746 #endif 604 747 748 // XXX visualize the set of convolved stamps 749 605 750 psImage *polyValues = p_pmSubtractionPolynomial(NULL, spatialOrder, 606 751 stamp->xNorm, stamp->yNorm); // Polynomial terms 607 752 608 bool new = stamp->vector 1? false : true; // Is this a new run?753 bool new = stamp->vector ? false : true; // Is this a new run? 609 754 if (new) { 610 stamp->matrix 1= psImageAlloc(numParams, numParams, PS_TYPE_F64);611 stamp->vector 1= psVectorAlloc(numParams, PS_TYPE_F64);755 stamp->matrix = psImageAlloc(numParams, numParams, PS_TYPE_F64); 756 stamp->vector = psVectorAlloc(numParams, PS_TYPE_F64); 612 757 } 613 758 #ifdef TESTING 614 psImageInit(stamp->matrix 1, NAN);615 psVectorInit(stamp->vector 1, NAN);759 psImageInit(stamp->matrix, NAN); 760 psVectorInit(stamp->vector, NAN); 616 761 #endif 617 762 618 763 bool status; // Status of least-squares matrix/vector calculation 764 765 psKernel *weight = NULL; 766 psKernel *window = NULL; 767 768 #ifdef USE_WEIGHT 769 weight = stamp->weight; 770 #endif 771 #ifdef USE_WINDOW 772 window = stamps->window; 773 #endif 774 619 775 switch (kernels->mode) { 620 776 case PM_SUBTRACTION_MODE_1: 621 status = calculateMatrixVector(stamp->matrix 1, stamp->vector1, stamp->image2, stamp->image1,622 stamp->weight, stamp->convolutions1, kernels, polyValues,623 footprint);777 status = calculateMatrixVector(stamp->matrix, stamp->vector, &stamp->norm, stamp->image2, stamp->image1, 778 weight, window, stamp->convolutions1, kernels, 779 polyValues, footprint, stamps->normWindow, mode); 624 780 break; 625 781 case PM_SUBTRACTION_MODE_2: 626 status = calculateMatrixVector(stamp->matrix 1, stamp->vector1, stamp->image1, stamp->image2,627 stamp->weight, stamp->convolutions2, kernels, polyValues,628 footprint);782 status = calculateMatrixVector(stamp->matrix, stamp->vector, &stamp->norm, stamp->image1, stamp->image2, 783 weight, window, stamp->convolutions2, kernels, 784 polyValues, footprint, stamps->normWindow, mode); 629 785 break; 630 786 case PM_SUBTRACTION_MODE_DUAL: 631 if (new) { 632 stamp->matrix2 = psImageAlloc(numKernels * numSpatial, numKernels * numSpatial, PS_TYPE_F64); 633 stamp->matrixX = psImageAlloc(numParams, numKernels * numSpatial, PS_TYPE_F64); 634 stamp->vector2 = psVectorAlloc(numKernels * numSpatial, PS_TYPE_F64); 635 } 636 #ifdef TESTING 637 psImageInit(stamp->matrix2, NAN); 638 psImageInit(stamp->matrixX, NAN); 639 psVectorInit(stamp->vector2, NAN); 640 #endif 641 status = calculateDualMatrixVector(stamp->matrix1, stamp->vector1, stamp->matrix2, stamp->vector2, 642 stamp->matrixX, stamp->image1, stamp->image2, stamp->weight, 643 stamp->convolutions1, stamp->convolutions2, kernels, polyValues, 644 footprint); 787 status = calculateDualMatrixVector(stamp->matrix, stamp->vector, &stamp->norm, 788 stamp->image1, stamp->image2, 789 weight, window, stamp->convolutions1, stamp->convolutions2, 790 kernels, polyValues, footprint, stamps->normWindow, mode); 645 791 break; 646 792 default: … … 651 797 stamp->status = PM_SUBTRACTION_STAMP_REJECTED; 652 798 psWarning("Rejecting stamp %d (%d,%d) because of bad equation", 653 index, (int)(stamp->x + 0.5), (int)(stamp->y +0.5));799 index, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5)); 654 800 } else { 655 801 stamp->status = PM_SUBTRACTION_STAMP_USED; … … 659 805 { 660 806 psString matrixName = NULL; 661 psStringAppend(&matrixName, "matrix 1_%d.fits", index);807 psStringAppend(&matrixName, "matrix_%d.fits", index); 662 808 psFits *matrixFile = psFitsOpen(matrixName, "w"); 663 809 psFree(matrixName); 664 psFitsWriteImage(matrixFile, NULL, stamp->matrix 1, 0, NULL);810 psFitsWriteImage(matrixFile, NULL, stamp->matrix, 0, NULL); 665 811 psFitsClose(matrixFile); 666 812 667 813 matrixName = NULL; 668 psStringAppend(&matrixName, "vector 1_%d.fits", index);669 psImage *dummy = psImageAlloc(stamp->vector 1->n, 1, PS_TYPE_F64);670 memcpy(dummy->data.F64[0], stamp->vector 1->data.F64,671 PSELEMTYPE_SIZEOF(PS_TYPE_F64) * stamp->vector 1->n);814 psStringAppend(&matrixName, "vector_%d.fits", index); 815 psImage *dummy = psImageAlloc(stamp->vector->n, 1, PS_TYPE_F64); 816 memcpy(dummy->data.F64[0], stamp->vector->data.F64, 817 PSELEMTYPE_SIZEOF(PS_TYPE_F64) * stamp->vector->n); 672 818 matrixFile = psFitsOpen(matrixName, "w"); 673 819 psFree(matrixName); … … 675 821 psFree(dummy); 676 822 psFitsClose(matrixFile); 677 678 if (stamp->vector2) {679 matrixName = NULL;680 psStringAppend(&matrixName, "vector2_%d.fits", index);681 dummy = psImageAlloc(stamp->vector2->n, 1, PS_TYPE_F64);682 memcpy(dummy->data.F64[0], stamp->vector2->data.F64,683 PSELEMTYPE_SIZEOF(PS_TYPE_F64) * stamp->vector2->n);684 matrixFile = psFitsOpen(matrixName, "w");685 psFree(matrixName);686 psFitsWriteImage(matrixFile, NULL, dummy, 0, NULL);687 psFree(dummy);688 psFitsClose(matrixFile);689 }690 691 if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) {692 matrixName = NULL;693 psStringAppend(&matrixName, "matrix2_%d.fits", index);694 matrixFile = psFitsOpen(matrixName, "w");695 psFree(matrixName);696 psFitsWriteImage(matrixFile, NULL, stamp->matrix2, 0, NULL);697 psFitsClose(matrixFile);698 699 matrixName = NULL;700 psStringAppend(&matrixName, "matrixX_%d.fits", index);701 matrixFile = psFitsOpen(matrixName, "w");702 psFree(matrixName);703 psFitsWriteImage(matrixFile, NULL, stamp->matrixX, 0, NULL);704 psFitsClose(matrixFile);705 }706 823 } 707 824 #endif … … 712 829 } 713 830 714 bool pmSubtractionCalculateEquation(pmSubtractionStampList *stamps, const pmSubtractionKernels *kernels) 831 bool pmSubtractionCalculateEquation(pmSubtractionStampList *stamps, const pmSubtractionKernels *kernels, 832 const pmSubtractionEquationCalculationMode mode) 715 833 { 716 834 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false); … … 727 845 } 728 846 847 if ((stamp->x <= 0.0) && (stamp->y <= 0.0)) { 848 psAbort ("bad stamp"); 849 } 850 if (!isfinite(stamp->x) && !isfinite(stamp->y)) { 851 psAbort ("bad stamp"); 852 } 853 729 854 if (pmSubtractionThreaded()) { 730 855 psThreadJob *job = psThreadJobAlloc("PSMODULES_SUBTRACTION_CALCULATE_EQUATION"); … … 732 857 psArrayAdd(job->args, 1, (pmSubtractionKernels*)kernels); // Casting away const to put on array 733 858 PS_ARRAY_ADD_SCALAR(job->args, i, PS_TYPE_S32); 859 PS_ARRAY_ADD_SCALAR(job->args, mode, PS_TYPE_S32); 734 860 if (!psThreadJobAddPending(job)) { 735 861 psFree(job); … … 738 864 psFree(job); 739 865 } else { 740 pmSubtractionCalculateEquationStamp(stamps, kernels, i );866 pmSubtractionCalculateEquationStamp(stamps, kernels, i, mode); 741 867 } 742 868 } … … 748 874 749 875 pmSubtractionVisualPlotLeastSquares(stamps); 876 pmSubtractionVisualShowKernels((pmSubtractionKernels *)kernels); 877 pmSubtractionVisualShowBasis(stamps); 750 878 751 879 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Calculate equation: %f sec", … … 756 884 } 757 885 758 bool pmSubtractionSolveEquation(pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps) 886 // private functions used on pmSubtractionSolveEquation 887 bool psVectorWriteFile (char *filename, const psVector *vector); 888 bool psFitsWriteImageSimple (char *filename, psImage *image, psMetadata *header); 889 890 psImage *p_pmSubSolve_wUt (psVector *w, psImage *U); 891 psImage *p_pmSubSolve_VwUt (psImage *V, psImage *wUt); 892 893 bool p_pmSubSolve_SetWeights (psVector *wApply, psVector *w, psVector *wMask); 894 895 bool p_pmSubSolve_UtB (psVector **UtB, psImage *U, psVector *B); 896 bool p_pmSubSolve_wUtB (psVector **wUtB, psVector *w, psVector *UtB); 897 bool p_pmSubSolve_VwUtB (psVector **VwUtB, psImage *V, psVector *wUtB); 898 899 bool p_pmSubSolve_Ax (psVector **B, psImage *A, psVector *x); 900 bool p_pmSubSolve_VdV (double *value, psVector *x, psVector *y); 901 bool p_pmSubSolve_y2 (double *y2, pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps); 902 903 psImage *p_pmSubSolve_Xvar (psImage *V, psVector *w); 904 905 double p_pmSubSolve_ChiSquare (pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps); 906 907 bool pmSubtractionSolveEquation(pmSubtractionKernels *kernels, 908 const pmSubtractionStampList *stamps, 909 const pmSubtractionEquationCalculationMode mode) 759 910 { 760 911 PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(kernels, false); … … 762 913 763 914 // Check inputs 764 int numParams = -1; // Number of parameters 765 int numParams2 = 0; // Number of parameters for part solution (DUAL mode) 915 int numKernels = kernels->num; // Number of kernel basis functions 916 int numSpatial = PM_SUBTRACTION_POLYTERMS(kernels->spatialOrder); // Number of spatial variations 917 int numBackground = PM_SUBTRACTION_POLYTERMS(kernels->bgOrder); // Number of background terms 918 int numParams = numKernels * numSpatial + 1 + numBackground; // Number of parameters being solved for 919 int numSolution1 = numParams, numSolution2 = 0; // Number of parameters for each solution 920 if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 921 // An additional image is convolved 922 numSolution2 = numKernels * numSpatial; 923 numParams += numSolution2; 924 } 925 766 926 for (int i = 0; i < stamps->num; i++) { 767 927 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest … … 771 931 } 772 932 773 PS_ASSERT_VECTOR_NON_NULL(stamp->vector1, false); 774 if (numParams == -1) { 775 numParams = stamp->vector1->n; 776 } 777 PS_ASSERT_VECTOR_SIZE(stamp->vector1, (long)numParams, false); 778 PS_ASSERT_VECTOR_TYPE(stamp->vector1, PS_TYPE_F64, false); 779 PS_ASSERT_IMAGE_NON_NULL(stamp->matrix1, false); 780 PS_ASSERT_IMAGE_SIZE(stamp->matrix1, numParams, numParams, false); 781 PS_ASSERT_IMAGE_TYPE(stamp->matrix1, PS_TYPE_F64, false); 782 783 if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 784 PS_ASSERT_IMAGE_NON_NULL(stamp->matrix2, false); 785 PS_ASSERT_IMAGE_NON_NULL(stamp->matrixX, false); 786 if (numParams2 == 0) { 787 numParams2 = stamp->matrix2->numCols; 788 } 789 PS_ASSERT_IMAGE_SIZE(stamp->matrix2, numParams2, numParams2, false); 790 PS_ASSERT_IMAGE_SIZE(stamp->matrixX, numParams, numParams2, false); 791 PS_ASSERT_IMAGE_TYPE(stamp->matrix2, PS_TYPE_F64, false); 792 PS_ASSERT_IMAGE_TYPE(stamp->matrixX, PS_TYPE_F64, false); 793 PS_ASSERT_VECTOR_NON_NULL(stamp->vector2, false); 794 PS_ASSERT_VECTOR_SIZE(stamp->vector2, (long)numParams2, false); 795 PS_ASSERT_VECTOR_TYPE(stamp->vector2, PS_TYPE_F64, false); 796 } 797 } 798 if (numParams == -1) { 799 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "No suitable stamps found."); 800 return NULL; 933 PS_ASSERT_VECTOR_NON_NULL(stamp->vector, false); 934 PS_ASSERT_VECTOR_SIZE(stamp->vector, (long)numParams, false); 935 PS_ASSERT_VECTOR_TYPE(stamp->vector, PS_TYPE_F64, false); 936 PS_ASSERT_IMAGE_NON_NULL(stamp->matrix, false); 937 PS_ASSERT_IMAGE_SIZE(stamp->matrix, numParams, numParams, false); 938 PS_ASSERT_IMAGE_TYPE(stamp->matrix, PS_TYPE_F64, false); 801 939 } 802 940 … … 814 952 psVectorInit(sumVector, 0.0); 815 953 psImageInit(sumMatrix, 0.0); 954 955 psVector *norms = psVectorAllocEmpty(stamps->num, PS_TYPE_F64); // Normalisations 956 816 957 int numStamps = 0; // Number of good stamps 817 958 for (int i = 0; i < stamps->num; i++) { 818 959 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 819 820 960 if (stamp->status == PM_SUBTRACTION_STAMP_USED) { 821 822 #ifdef TESTING 823 // XXX double-check for NAN in data: 824 for (int iy = 0; iy < stamp->matrix1->numRows; iy++) { 825 for (int ix = 0; ix < stamp->matrix1->numCols; ix++) { 826 if (!isfinite(stamp->matrix1->data.F64[iy][ix])) { 827 fprintf (stderr, "WARNING: NAN in matrix1\n"); 828 } 829 } 830 } 831 for (int ix = 0; ix < stamp->vector1->n; ix++) { 832 if (!isfinite(stamp->vector1->data.F64[ix])) { 833 fprintf (stderr, "WARNING: NAN in vector1\n"); 834 } 835 } 836 #endif 837 838 (void)psBinaryOp(sumMatrix, sumMatrix, "+", stamp->matrix1); 839 (void)psBinaryOp(sumVector, sumVector, "+", stamp->vector1); 961 (void)psBinaryOp(sumMatrix, sumMatrix, "+", stamp->matrix); 962 (void)psBinaryOp(sumVector, sumVector, "+", stamp->vector); 963 psVectorAppend(norms, stamp->norm); 840 964 pmSubtractionStampPrint(ds9, stamp->x, stamp->y, stamps->footprint, "green"); 841 965 numStamps++; … … 845 969 } 846 970 847 #ifdef TESTING848 for (int ix = 0; ix < sumVector->n; ix++) {849 if (!isfinite(sumVector->data.F64[ix])) {850 fprintf (stderr, "WARNING: NAN in vector1\n");851 }852 }853 #endif854 855 971 #if 0 856 972 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index for background … … 858 974 #endif 859 975 860 #ifdef TESTING 861 for (int ix = 0; ix < sumVector->n; ix++) { 862 if (!isfinite(sumVector->data.F64[ix])) { 863 fprintf (stderr, "WARNING: NAN in vector1\n"); 864 } 865 } 976 psVector *solution = NULL; // Solution to equation! 977 solution = psVectorAlloc(numParams, PS_TYPE_F64); 978 psVectorInit(solution, 0); 979 980 #if 0 981 // Regular, straight-forward solution 982 solution = psMatrixSolveSVD(solution, sumMatrix, sumVector, NAN); 983 #else 866 984 { 867 psImage *inverse = psMatrixInvert(NULL, sumMatrix, NULL); 868 psFits *fits = psFitsOpen("matrixInv.fits", "w"); 869 psFitsWriteImage(fits, NULL, inverse, 0, NULL); 870 psFitsClose(fits); 871 psFree(inverse); 872 } 873 { 874 psImage *X = psMatrixInvert(NULL, sumMatrix, NULL); 875 psImage *Xt = psMatrixTranspose(NULL, X); 876 psImage *XtX = psMatrixMultiply(NULL, Xt, X); 877 psFits *fits = psFitsOpen("matrixErr.fits", "w"); 878 psFitsWriteImage(fits, NULL, XtX, 0, NULL); 879 psFitsClose(fits); 880 psFree(X); 881 psFree(Xt); 882 psFree(XtX); 883 } 884 #endif 885 886 psVector *permutation = NULL; // Permutation vector, required for LU decomposition 887 psImage *luMatrix = psMatrixLUDecomposition(NULL, &permutation, sumMatrix); 985 // Solve normalisation and background separately 986 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 987 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index for background 988 989 psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN); // Statistics for norm 990 if (!psVectorStats(stats, norms, NULL, NULL, 0)) { 991 psError(PS_ERR_UNKNOWN, false, "Unable to determine median normalisation"); 992 psFree(stats); 993 psFree(sumMatrix); 994 psFree(sumVector); 995 psFree(norms); 996 return false; 997 } 998 999 double normValue = stats->robustMedian; 1000 // double bgValue = 0.0; 1001 1002 psFree(stats); 1003 1004 fprintf(stderr, "Norm: %lf\n", normValue); 1005 1006 // Solve kernel components 1007 for (int i = 0; i < numSolution1; i++) { 1008 sumVector->data.F64[i] -= normValue * sumMatrix->data.F64[normIndex][i]; 1009 1010 sumMatrix->data.F64[i][normIndex] = 0.0; 1011 sumMatrix->data.F64[normIndex][i] = 0.0; 1012 } 1013 sumVector->data.F64[bgIndex] -= normValue * sumMatrix->data.F64[normIndex][bgIndex]; 1014 sumMatrix->data.F64[bgIndex][normIndex] = 0.0; 1015 sumMatrix->data.F64[normIndex][bgIndex] = 0.0; 1016 1017 sumMatrix->data.F64[normIndex][normIndex] = 1.0; 1018 sumVector->data.F64[normIndex] = 0.0; 1019 1020 solution = psMatrixSolveSVD(solution, sumMatrix, sumVector, NAN); 1021 1022 solution->data.F64[normIndex] = normValue; 1023 } 1024 # endif 1025 1026 if (!kernels->solution1) { 1027 kernels->solution1 = psVectorAlloc(sumVector->n, PS_TYPE_F64); 1028 psVectorInit(kernels->solution1, 0.0); 1029 } 1030 1031 // only update the solutions that we chose to calculate: 1032 if (mode & PM_SUBTRACTION_EQUATION_NORM) { 1033 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 1034 kernels->solution1->data.F64[normIndex] = solution->data.F64[normIndex]; 1035 } 1036 if (mode & PM_SUBTRACTION_EQUATION_BG) { 1037 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index in matrix for background 1038 kernels->solution1->data.F64[bgIndex] = solution->data.F64[bgIndex]; 1039 } 1040 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 1041 int numKernels = kernels->num; 1042 int spatialOrder = kernels->spatialOrder; // Order of spatial variation 1043 int numPoly = PM_SUBTRACTION_POLYTERMS(spatialOrder); // Number of polynomial terms 1044 for (int i = 0; i < numKernels * numPoly; i++) { 1045 kernels->solution1->data.F64[i] = solution->data.F64[i]; 1046 } 1047 } 1048 1049 psFree(solution); 1050 psFree(sumVector); 888 1051 psFree(sumMatrix); 889 if (!luMatrix) {890 psError(PS_ERR_UNKNOWN, true, "LU Decomposition of least-squares matrix failed.\n");891 psFree(sumVector);892 psFree(luMatrix);893 psFree(permutation);894 return NULL;895 }896 kernels->solution1 = psMatrixLUSolution(kernels->solution1, luMatrix, sumVector, permutation);897 1052 898 1053 #ifdef TESTING … … 900 1055 for (int ix = 0; ix < kernels->solution1->n; ix++) { 901 1056 if (!isfinite(kernels->solution1->data.F64[ix])) { 902 fprintf (stderr, "WARNING: NAN in vector1\n"); 903 } 904 } 905 #endif 906 907 psFree(sumVector); 908 psFree(luMatrix); 909 psFree(permutation); 910 if (!kernels->solution1) { 911 psError(PS_ERR_UNKNOWN, true, "Failed to solve the least-squares system.\n"); 912 return NULL; 913 } 1057 fprintf (stderr, "WARNING: NAN in vector\n"); 1058 } 1059 } 1060 #endif 1061 914 1062 } else { 915 1063 // Dual convolution solution 916 1064 917 1065 // Accumulation of stamp matrices/vectors 918 psImage *sumMatrix1 = psImageAlloc(numParams, numParams, PS_TYPE_F64); 919 psImage *sumMatrix2 = psImageAlloc(numParams2, numParams2, PS_TYPE_F64); 920 psImage *sumMatrixX = psImageAlloc(numParams, numParams2, PS_TYPE_F64); 921 psVector *sumVector1 = psVectorAlloc(numParams, PS_TYPE_F64); 922 psVector *sumVector2 = psVectorAlloc(numParams, PS_TYPE_F64); 923 psImageInit(sumMatrix1, 0.0); 924 psImageInit(sumMatrix2, 0.0); 925 psImageInit(sumMatrixX, 0.0); 926 psVectorInit(sumVector1, 0.0); 927 psVectorInit(sumVector2, 0.0); 1066 psImage *sumMatrix = psImageAlloc(numParams, numParams, PS_TYPE_F64); 1067 psVector *sumVector = psVectorAlloc(numParams, PS_TYPE_F64); 1068 psImageInit(sumMatrix, 0.0); 1069 psVectorInit(sumVector, 0.0); 1070 1071 psVector *norms = psVectorAllocEmpty(stamps->num, PS_TYPE_F64); // Normalisations 928 1072 929 1073 int numStamps = 0; // Number of good stamps … … 931 1075 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 932 1076 if (stamp->status == PM_SUBTRACTION_STAMP_USED) { 933 (void)psBinaryOp(sumMatrix 1, sumMatrix1, "+", stamp->matrix1);934 (void)psBinaryOp(sum Matrix2, sumMatrix2, "+", stamp->matrix2);935 (void)psBinaryOp(sumMatrixX, sumMatrixX, "+", stamp->matrixX); 936 (void)psBinaryOp(sumVector1, sumVector1, "+", stamp->vector1);937 (void)psBinaryOp(sumVector2, sumVector2, "+", stamp->vector2); 1077 (void)psBinaryOp(sumMatrix, sumMatrix, "+", stamp->matrix); 1078 (void)psBinaryOp(sumVector, sumVector, "+", stamp->vector); 1079 1080 psVectorAppend(norms, stamp->norm); 1081 938 1082 pmSubtractionStampPrint(ds9, stamp->x, stamp->y, stamps->footprint, "green"); 939 1083 numStamps++; … … 941 1085 } 942 1086 943 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index for background944 calculatePenalty(sumMatrix1, sumVector1, kernels, sumMatrix1->data.F64[bgIndex][bgIndex]);945 calculatePenalty(sumMatrix2, sumVector2, kernels, -sumMatrix1->data.F64[bgIndex][bgIndex]);946 947 psImage *sumMatrix = NULL; // Combined matrix948 psVector *sumVector = NULL; // Combined vector949 calculateEquationDual(&sumMatrix, &sumVector, sumMatrix1, sumMatrix2,950 sumMatrixX, sumVector1, sumVector2);951 952 1087 #ifdef TESTING 1088 psFitsWriteImageSimple ("sumMatrix.fits", sumMatrix, NULL); 1089 psVectorWriteFile("sumVector.dat", sumVector); 1090 #endif 1091 1092 #if 1 1093 // int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index for background 1094 // calculatePenalty(sumMatrix, sumVector, kernels, sumMatrix->data.F64[bgIndex][bgIndex]); 1095 1096 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 1097 calculatePenalty(sumMatrix, sumVector, kernels, sumMatrix->data.F64[normIndex][normIndex] / 1000.0); 1098 #endif 1099 1100 psVector *solution = NULL; // Solution to equation! 1101 solution = psVectorAlloc(numParams, PS_TYPE_F64); 1102 psVectorInit(solution, 0); 1103 1104 #if 0 1105 // Regular, straight-forward solution 1106 solution = psMatrixSolveSVD(solution, sumMatrix, sumVector, NAN); 1107 #else 953 1108 { 954 psFits *fits = psFitsOpen("sumMatrix.fits", "w"); 955 psFitsWriteImage(fits, NULL, sumMatrix, 0, NULL); 956 psFitsClose(fits); 957 } 958 { 959 psImage *image = psImageAlloc(1, numParams + numParams2, PS_TYPE_F64); 960 psFits *fits = psFitsOpen("sumVector.fits", "w"); 961 for (int i = 0; i < numParams + numParams2; i++) { 962 image->data.F64[0][i] = sumVector->data.F64[i]; 963 } 964 psFitsWriteImage(fits, NULL, image, 0, NULL); 965 psFree(image); 966 psFitsClose(fits); 967 } 968 #endif 969 970 psVector *solution = NULL; // Solution to equation! 971 { 972 solution = psMatrixSolveSVD(solution, sumMatrix, sumVector); 973 if (!solution) { 974 psError(PS_ERR_UNKNOWN, false, "SVD solution of least-squares equation failed.\n"); 1109 // Solve normalisation and background separately 1110 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 1111 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index for background 1112 1113 #if 0 1114 psImage *normMatrix = psImageAlloc(2, 2, PS_TYPE_F64); 1115 psVector *normVector = psVectorAlloc(2, PS_TYPE_F64); 1116 1117 normMatrix->data.F64[0][0] = sumMatrix->data.F64[normIndex][normIndex]; 1118 normMatrix->data.F64[1][1] = sumMatrix->data.F64[bgIndex][bgIndex]; 1119 normMatrix->data.F64[0][1] = normMatrix->data.F64[1][0] = sumMatrix->data.F64[normIndex][bgIndex]; 1120 1121 normVector->data.F64[0] = sumVector->data.F64[normIndex]; 1122 normVector->data.F64[1] = sumVector->data.F64[bgIndex]; 1123 1124 psVector *normSolution = psMatrixSolveSVD(NULL, normMatrix, normVector, NAN); 1125 1126 double normValue = normSolution->data.F64[0]; 1127 double bgValue = normSolution->data.F64[1]; 1128 1129 psFree(normMatrix); 1130 psFree(normVector); 1131 psFree(normSolution); 1132 #endif 1133 1134 psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN); // Statistics for norm 1135 if (!psVectorStats(stats, norms, NULL, NULL, 0)) { 1136 psError(PS_ERR_UNKNOWN, false, "Unable to determine median normalisation"); 1137 psFree(stats); 975 1138 psFree(sumMatrix); 976 1139 psFree(sumVector); 977 return NULL; 978 } 979 980 int numSpatial = PM_SUBTRACTION_POLYTERMS(kernels->spatialOrder); // Number of spatial variations 981 int numKernels = kernels->num; // Number of kernel basis functions 982 983 // Remove a kernel basis for image 1 from the equation 984 #define MASK_BASIS_1(INDEX) \ 985 { \ 986 for (int j = 0, index = INDEX; j < numSpatial; j++, index += numKernels) { \ 987 for (int k = 0; k < numParams2; k++) { \ 988 sumMatrix1->data.F64[k][index] = 0.0; \ 989 sumMatrix1->data.F64[index][k] = 0.0; \ 990 sumMatrixX->data.F64[k][index] = 0.0; \ 991 } \ 992 sumMatrix1->data.F64[bgIndex][index] = 0.0; \ 993 sumMatrix1->data.F64[index][bgIndex] = 0.0; \ 994 sumMatrix1->data.F64[normIndex][index] = 0.0; \ 995 sumMatrix1->data.F64[index][normIndex] = 0.0; \ 996 sumMatrix1->data.F64[index][index] = 1.0; \ 997 sumVector1->data.F64[index] = 0.0; \ 998 } \ 999 } 1000 1001 // Remove a kernel basis for image 2 from the equation 1002 #define MASK_BASIS_2(INDEX) \ 1003 { \ 1004 for (int j = 0, index = INDEX; j < numSpatial; j++, index += numKernels) { \ 1005 for (int k = 0; k < numParams2; k++) { \ 1006 sumMatrix2->data.F64[k][index] = 0.0; \ 1007 sumMatrix2->data.F64[index][k] = 0.0; \ 1008 sumMatrixX->data.F64[index][k] = 0.0; \ 1009 } \ 1010 sumMatrix2->data.F64[index][index] = 1.0; \ 1011 sumMatrixX->data.F64[index][normIndex] = 0.0; \ 1012 sumMatrixX->data.F64[index][bgIndex] = 0.0; \ 1013 sumVector2->data.F64[index] = 0.0; \ 1014 } \ 1015 } 1016 1017 #define TOL 1.0e-5 1018 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 1019 double norm = fabs(solution->data.F64[normIndex]); // Normalisation 1020 double thresh = norm * TOL; // Threshold for low parameters 1021 for (int i = 0; i < numKernels; i++) { 1022 // Getting 0th order parameter value. In the presence of spatial variation, the actual value 1023 // of the parameter will vary over the image. We are in effect getting the value in the 1024 // centre of the image. If we use different polynomial functions (e.g., Chebyshev), we may 1025 // have to change this to properly determine the value of the parameter at the centre. 1026 double param1 = solution->data.F64[i], 1027 param2 = solution->data.F64[numParams + i]; // Parameters of interest 1028 bool mask1 = false, mask2 = false; // Masked the parameter? 1029 if (fabs(param1) < thresh) { 1030 psTrace("psModules.imcombine", 7, "Parameter %d: 1 below threshold\n", i); 1031 MASK_BASIS_1(i); 1032 mask1 = true; 1033 } 1034 if (fabs(param2) < thresh) { 1035 psTrace("psModules.imcombine", 7, "Parameter %d: 2 below threshold\n", i); 1036 MASK_BASIS_2(i); 1037 mask2 = true; 1038 } 1039 1040 if (!mask1 && !mask2) { 1041 if (fabs(param1) < fabs(param2)) { 1042 psTrace("psModules.imcombine", 7, "Parameter %d: 1 < 2\n", i); 1043 MASK_BASIS_1(i); 1044 } else { 1045 psTrace("psModules.imcombine", 7, "Parameter %d: 2 < 1\n", i); 1046 MASK_BASIS_2(i); 1047 } 1048 } 1049 } 1050 } 1051 1052 calculateEquationDual(&sumMatrix, &sumVector, sumMatrix1, sumMatrix2, 1053 sumMatrixX, sumVector1, sumVector2); 1140 psFree(norms); 1141 return false; 1142 } 1143 1144 double normValue = stats->robustMedian; 1145 1146 psFree(stats); 1147 1148 fprintf(stderr, "Norm: %lf\n", normValue); 1149 1150 // Solve kernel components 1151 for (int i = 0; i < numSolution2; i++) { 1152 sumVector->data.F64[i] -= normValue * sumMatrix->data.F64[normIndex][i]; 1153 sumVector->data.F64[i + numSolution1] -= normValue * sumMatrix->data.F64[normIndex][i + numSolution1]; 1154 1155 sumMatrix->data.F64[i][normIndex] = 0.0; 1156 sumMatrix->data.F64[normIndex][i] = 0.0; 1157 1158 sumMatrix->data.F64[i + numSolution1][normIndex] = 0.0; 1159 sumMatrix->data.F64[normIndex][i + numSolution1] = 0.0; 1160 } 1161 sumVector->data.F64[bgIndex] -= normValue * sumMatrix->data.F64[normIndex][bgIndex]; 1162 sumMatrix->data.F64[bgIndex][normIndex] = 0.0; 1163 sumMatrix->data.F64[normIndex][bgIndex] = 0.0; 1164 1165 sumMatrix->data.F64[normIndex][normIndex] = 1.0; 1166 1167 sumVector->data.F64[normIndex] = 0.0; 1168 1169 solution = psMatrixSolveSVD(solution, sumMatrix, sumVector, NAN); 1170 1171 solution->data.F64[normIndex] = normValue; 1172 } 1173 #endif 1174 1054 1175 1055 1176 #ifdef TESTING 1056 { 1057 psFits *fits = psFitsOpen("sumMatrixFix.fits", "w"); 1058 psFitsWriteImage(fits, NULL, sumMatrix, 0, NULL); 1059 psFitsClose(fits); 1060 } 1061 { 1062 psImage *image = psImageAlloc(1, numParams + numParams2, PS_TYPE_F64); 1063 psFits *fits = psFitsOpen("sumVectorFix.fits", "w"); 1064 for (int i = 0; i < numParams + numParams2; i++) { 1065 image->data.F64[0][i] = sumVector->data.F64[i]; 1066 } 1067 psFitsWriteImage(fits, NULL, image, 0, NULL); 1068 psFree(image); 1069 psFitsClose(fits); 1070 } 1071 #endif 1072 1073 solution = psMatrixSolveSVD(solution, sumMatrix, sumVector); 1074 if (!solution) { 1075 psError(PS_ERR_UNKNOWN, false, "SVD solution of least-squares equation failed.\n"); 1076 psFree(sumMatrix); 1077 psFree(sumVector); 1078 return NULL; 1079 } 1080 1081 psFree(sumMatrix1); 1082 psFree(sumMatrix2); 1083 psFree(sumMatrixX); 1084 psFree(sumVector1); 1085 psFree(sumVector2); 1177 for (int i = 0; i < solution->n; i++) { 1178 fprintf(stderr, "Dual solution %d: %lf\n", i, solution->data.F64[i]); 1179 } 1180 #endif 1086 1181 1087 1182 psFree(sumMatrix); 1088 1183 psFree(sumVector); 1089 1184 1090 #ifdef TESTING 1091 { 1092 psImage *image = psImageAlloc(1, numParams + numParams2, PS_TYPE_F64); 1093 psFits *fits = psFitsOpen("solnVector.fits", "w"); 1094 for (int i = 0; i < numParams + numParams2; i++) { 1095 image->data.F64[0][i] = solution->data.F64[i]; 1096 } 1097 psFitsWriteImage(fits, NULL, image, 0, NULL); 1098 psFree(image); 1099 psFitsClose(fits); 1100 } 1101 #endif 1185 psFree(norms); 1102 1186 1103 1187 if (!kernels->solution1) { 1104 kernels->solution1 = psVectorAlloc(numParams, PS_TYPE_F64); 1188 kernels->solution1 = psVectorAlloc(numSolution1, PS_TYPE_F64); 1189 psVectorInit (kernels->solution1, 0.0); 1105 1190 } 1106 1191 if (!kernels->solution2) { 1107 kernels->solution2 = psVectorAlloc(numParams2, PS_TYPE_F64); 1108 } 1109 1110 memcpy(kernels->solution1->data.F64, solution->data.F64, numParams * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 1111 memcpy(kernels->solution2->data.F64, &solution->data.F64[numParams], 1112 numParams2 * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 1192 kernels->solution2 = psVectorAlloc(numSolution2, PS_TYPE_F64); 1193 psVectorInit (kernels->solution2, 0.0); 1194 } 1195 1196 // only update the solutions that we chose to calculate: 1197 if (mode & PM_SUBTRACTION_EQUATION_NORM) { 1198 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 1199 kernels->solution1->data.F64[normIndex] = solution->data.F64[normIndex]; 1200 } 1201 if (mode & PM_SUBTRACTION_EQUATION_BG) { 1202 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index in matrix for background 1203 kernels->solution1->data.F64[bgIndex] = solution->data.F64[bgIndex]; 1204 } 1205 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 1206 int numKernels = kernels->num; 1207 for (int i = 0; i < numKernels * numSpatial; i++) { 1208 // XXX fprintf (stderr, "keep\n"); 1209 kernels->solution1->data.F64[i] = solution->data.F64[i]; 1210 kernels->solution2->data.F64[i] = solution->data.F64[i + numSolution1]; 1211 } 1212 } 1213 1214 1215 memcpy(kernels->solution1->data.F64, solution->data.F64, 1216 numSolution1 * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 1217 memcpy(kernels->solution2->data.F64, &solution->data.F64[numSolution1], 1218 numSolution2 * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 1113 1219 1114 1220 psFree(solution); … … 1131 1237 } 1132 1238 1133 pmSubtractionVisualPlotLeastSquares((pmSubtractionStampList *) stamps); //casting away const1239 // pmSubtractionVisualPlotLeastSquares((pmSubtractionStampList *) stamps); //casting away const 1134 1240 return true; 1135 1241 } 1136 1242 1243 bool pmSubtractionResidualStats(psVector *fSigRes, psVector *fMaxRes, psVector *fMinRes, psKernel *target, psKernel *source, psKernel *residual, double norm, int footprint) { 1244 1245 // XXX measure some useful stats on the residuals 1246 float sum = 0.0; 1247 float peak = 0.0; 1248 for (int y = - footprint; y <= footprint; y++) { 1249 for (int x = - footprint; x <= footprint; x++) { 1250 sum += 0.5*(target->kernel[y][x] + source->kernel[y][x] * norm); 1251 peak = PS_MAX(peak, 0.5*(target->kernel[y][x] + source->kernel[y][x] * norm)); 1252 } 1253 } 1254 1255 // only count pixels with more than X% of the source flux 1256 // calculate stdev(dflux) 1257 float dflux1 = 0.0; 1258 float dflux2 = 0.0; 1259 int npix = 0; 1260 1261 float dmax = 0.0; 1262 float dmin = 0.0; 1263 1264 for (int y = - footprint; y <= footprint; y++) { 1265 for (int x = - footprint; x <= footprint; x++) { 1266 float dflux = 0.5*(target->kernel[y][x] + source->kernel[y][x] * norm); 1267 if (dflux < 0.02*sum) continue; 1268 dflux1 += residual->kernel[y][x]; 1269 dflux2 += PS_SQR(residual->kernel[y][x]); 1270 dmax = PS_MAX(residual->kernel[y][x], dmax); 1271 dmin = PS_MIN(residual->kernel[y][x], dmin); 1272 npix ++; 1273 } 1274 } 1275 float sigma = sqrt(dflux2 / npix - PS_SQR(dflux1/npix)); 1276 if (!isfinite(sum)) return false; 1277 if (!isfinite(dmax)) return false; 1278 if (!isfinite(dmin)) return false; 1279 if (!isfinite(peak)) return false; 1280 1281 // fprintf (stderr, "sum: %f, peak: %f, sigma: %f, fsigma: %f, fmax: %f, fmin: %f\n", sum, peak, sigma, sigma/sum, dmax/peak, dmin/peak); 1282 psVectorAppend(fSigRes, sigma/sum); 1283 psVectorAppend(fMaxRes, dmax/peak); 1284 psVectorAppend(fMinRes, dmin/peak); 1285 return true; 1286 } 1287 1137 1288 psVector *pmSubtractionCalculateDeviations(pmSubtractionStampList *stamps, 1138 constpmSubtractionKernels *kernels)1289 pmSubtractionKernels *kernels) 1139 1290 { 1140 1291 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, NULL); … … 1151 1302 psKernel *residual = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Residual image 1152 1303 1304 // set up holding images for the visualization 1305 pmSubtractionVisualShowFitInit (stamps); 1306 1307 psVector *fSigRes = psVectorAllocEmpty(stamps->num, PS_TYPE_F32); 1308 psVector *fMinRes = psVectorAllocEmpty(stamps->num, PS_TYPE_F32); 1309 psVector *fMaxRes = psVectorAllocEmpty(stamps->num, PS_TYPE_F32); 1310 1311 // we want to save the residual images for the 9 brightest stamps. 1312 // identify the 9 brightest stamps 1313 psVector *keepStamps = psVectorAlloc(stamps->num, PS_TYPE_S32); 1314 psVectorInit (keepStamps, 0); 1315 { 1316 psVector *flux = psVectorAlloc(stamps->num, PS_TYPE_F32); 1317 psVectorInit (flux, 0.0); 1318 1319 for (int i = 0; i < stamps->num; i++) { 1320 pmSubtractionStamp *stamp = stamps->stamps->data[i]; 1321 if (!isfinite(stamp->flux)) continue; 1322 flux->data.F32[i] = stamp->flux; 1323 } 1324 1325 psVector *index = psVectorSortIndex(NULL, flux); 1326 for (int i = 0; (i < stamps->num) && (i < 9); i++) { 1327 int n = stamps->num - i - 1; 1328 keepStamps->data.S32[index->data.S32[n]] = 1; 1329 fprintf (stderr, "keeping %d (%d of %d)\n", index->data.S32[n], n, 9); 1330 } 1331 psFree (flux); 1332 psFree (index); 1333 1334 // this function is called multiple times in the iteration, but 1335 // we only know after the interation is done if we will try again. 1336 // therefore we must save the sample each time, and blow away the old one 1337 // if it exists. 1338 psFree (kernels->sampleStamps); 1339 kernels->sampleStamps = psArrayAllocEmpty(9); 1340 } 1341 1342 psString log = psStringCopy("Deviations:\n"); // Log message with deviations 1153 1343 for (int i = 0; i < stamps->num; i++) { 1154 1344 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // The stamp of interest … … 1210 1400 for (int y = - footprint; y <= footprint; y++) { 1211 1401 for (int x = - footprint; x <= footprint; x++) { 1212 residual->kernel[y][x] -= convolution->kernel[y][x] * coefficient;1402 residual->kernel[y][x] += convolution->kernel[y][x] * coefficient; 1213 1403 } 1214 1404 } 1215 1405 } 1406 1407 // XXX visualize the target, source, convolution and residual 1408 pmSubtractionVisualShowFitAddStamp (target, source, residual, background, norm, i); 1409 1216 1410 for (int y = - footprint; y <= footprint; y++) { 1217 1411 for (int x = - footprint; x <= footprint; x++) { 1218 residual->kernel[y][x] += target->kernel[y][x] - background - source->kernel[y][x] * norm; 1219 } 1220 } 1412 residual->kernel[y][x] += background + source->kernel[y][x] * norm - target->kernel[y][x]; 1413 } 1414 } 1415 1416 if (keepStamps->data.S32[i]) { 1417 psImage *sample = psImageCopy(NULL, residual->image, PS_TYPE_F32); 1418 psArrayAdd (kernels->sampleStamps, 9, sample); 1419 psFree (sample); 1420 } 1421 1422 pmSubtractionResidualStats(fSigRes, fMaxRes, fMinRes, target, source, residual, norm, footprint); 1423 1221 1424 } else { 1222 1425 // Dual convolution … … 1234 1437 for (int y = - footprint; y <= footprint; y++) { 1235 1438 for (int x = - footprint; x <= footprint; x++) { 1236 residual->kernel[y][x] += conv2->kernel[y][x] * coeff2 -conv1->kernel[y][x] * coeff1;1439 residual->kernel[y][x] += conv2->kernel[y][x] * coeff2 + conv1->kernel[y][x] * coeff1; 1237 1440 } 1238 1441 } 1239 1442 } 1443 1444 // XXX visualize the target, source, convolution and residual 1445 pmSubtractionVisualShowFitAddStamp (image2, image1, residual, background, norm, i); 1446 1240 1447 for (int y = - footprint; y <= footprint; y++) { 1241 1448 for (int x = - footprint; x <= footprint; x++) { 1242 residual->kernel[y][x] += image2->kernel[y][x] - background - image1->kernel[y][x] * norm; 1243 } 1244 } 1449 residual->kernel[y][x] += background + image1->kernel[y][x] * norm - image2->kernel[y][x]; 1450 } 1451 } 1452 if (keepStamps->data.S32[i]) { 1453 psImage *sample = psImageCopy(NULL, residual->image, PS_TYPE_F32); 1454 psArrayAdd (kernels->sampleStamps, 9, sample); 1455 psFree (sample); 1456 } 1457 1458 pmSubtractionResidualStats(fSigRes, fMaxRes, fMinRes, image1, image2, residual, norm, footprint); 1245 1459 } 1246 1460 … … 1257 1471 deviations->data.F32[i] = devNorm * deviation; 1258 1472 psTrace("psModules.imcombine", 5, "Deviation for stamp %d (%d,%d): %f\n", 1259 i, (int)(stamp->x + 0.5), (int)(stamp->y + 0.5), deviations->data.F32[i]); 1473 i, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5), deviations->data.F32[i]); 1474 psStringAppend(&log, "Stamp %d (%d,%d): %f\n", 1475 i, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5), deviations->data.F32[i]); 1260 1476 if (!isfinite(deviations->data.F32[i])) { 1261 1477 stamp->status = PM_SUBTRACTION_STAMP_REJECTED; 1262 1478 psTrace("psModules.imcombine", 5, 1263 1479 "Rejecting stamp %d (%d,%d) because of non-finite deviation\n", 1264 i, (int)(stamp->x + 0.5), (int)(stamp->y +0.5));1480 i, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5)); 1265 1481 continue; 1266 1482 } … … 1302 1518 1303 1519 } 1520 1521 psLogMsg("psModules.imcombine", PS_LOG_DETAIL, "%s", log); 1522 psFree(log); 1523 1524 // calculate and report the normalization and background for the image center 1525 { 1526 polyValues = p_pmSubtractionPolynomial(polyValues, kernels->spatialOrder, 0.0, 0.0); 1527 double norm = p_pmSubtractionSolutionNorm(kernels); // Normalisation 1528 double background = p_pmSubtractionSolutionBackground(kernels, polyValues);// Difference in background 1529 psLogMsg("psModules.imcombine", PS_LOG_INFO, "normalization: %f, background: %f", norm, background); 1530 1531 pmSubtractionVisualShowFit(norm); 1532 pmSubtractionVisualPlotFit(kernels); 1533 1534 psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); 1535 psVectorStats (stats, fSigRes, NULL, NULL, 0); 1536 kernels->fSigResMean = stats->robustMedian; 1537 kernels->fSigResStdev = stats->robustStdev; 1538 1539 psStatsInit (stats); 1540 psVectorStats (stats, fMaxRes, NULL, NULL, 0); 1541 kernels->fMaxResMean = stats->robustMedian; 1542 kernels->fMaxResStdev = stats->robustStdev; 1543 1544 psStatsInit (stats); 1545 psVectorStats (stats, fMinRes, NULL, NULL, 0); 1546 kernels->fMinResMean = stats->robustMedian; 1547 kernels->fMinResStdev = stats->robustStdev; 1548 1549 // XXX save these values somewhere 1550 psLogMsg("psModules.imcombine", PS_LOG_INFO, "fSigma: %f +/- %f, fMaxRes: %f +/- %f, fMinRes: %f +/- %f", 1551 kernels->fSigResMean, kernels->fSigResStdev, 1552 kernels->fMaxResMean, kernels->fMaxResStdev, 1553 kernels->fMinResMean, kernels->fMinResStdev); 1554 1555 psFree (fSigRes); 1556 psFree (fMaxRes); 1557 psFree (fMinRes); 1558 psFree (stats); 1559 } 1560 1304 1561 psFree(residual); 1305 1562 psFree(polyValues); 1306 1563 1564 1307 1565 return deviations; 1308 1566 } 1567 1568 // we are supplied U, not Ut; w represents a diagonal matrix (also, we apply 1/w instead of w) 1569 psImage *p_pmSubSolve_wUt (psVector *w, psImage *U) { 1570 1571 psAssert (w->n == U->numCols, "w and U dimensions do not match"); 1572 1573 // wUt has dimensions transposed relative to Ut. 1574 psImage *wUt = psImageAlloc (U->numRows, U->numCols, PS_TYPE_F64); 1575 psImageInit (wUt, 0.0); 1576 1577 for (int i = 0; i < wUt->numCols; i++) { 1578 for (int j = 0; j < wUt->numRows; j++) { 1579 if (!isfinite(w->data.F64[j])) continue; 1580 if (w->data.F64[j] == 0.0) continue; 1581 wUt->data.F64[j][i] = U->data.F64[i][j] / w->data.F64[j]; 1582 } 1583 } 1584 return wUt; 1585 } 1586 1587 // XXX this is just standard matrix multiplication: use psMatrixMultiply? 1588 psImage *p_pmSubSolve_VwUt (psImage *V, psImage *wUt) { 1589 1590 psAssert (V->numCols == wUt->numRows, "matrix dimensions do not match"); 1591 1592 psImage *Ainv = psImageAlloc (wUt->numCols, V->numRows, PS_TYPE_F64); 1593 1594 for (int i = 0; i < Ainv->numCols; i++) { 1595 for (int j = 0; j < Ainv->numRows; j++) { 1596 double sum = 0.0; 1597 for (int k = 0; k < V->numCols; k++) { 1598 sum += V->data.F64[j][k] * wUt->data.F64[k][i]; 1599 } 1600 Ainv->data.F64[j][i] = sum; 1601 } 1602 } 1603 return Ainv; 1604 } 1605 1606 // we are supplied U, not Ut 1607 bool p_pmSubSolve_UtB (psVector **UtB, psImage *U, psVector *B) { 1608 1609 psAssert (U->numRows == B->n, "U and B dimensions do not match"); 1610 1611 UtB[0] = psVectorRecycle (UtB[0], U->numCols, PS_TYPE_F64); 1612 1613 for (int i = 0; i < U->numCols; i++) { 1614 double sum = 0.0; 1615 for (int j = 0; j < U->numRows; j++) { 1616 sum += B->data.F64[j] * U->data.F64[j][i]; 1617 } 1618 UtB[0]->data.F64[i] = sum; 1619 } 1620 return true; 1621 } 1622 1623 // w is diagonal 1624 bool p_pmSubSolve_wUtB (psVector **wUtB, psVector *w, psVector *UtB) { 1625 1626 psAssert (w->n == UtB->n, "w and UtB dimensions do not match"); 1627 1628 // wUt has dimensions transposed relative to Ut. 1629 wUtB[0] = psVectorRecycle (wUtB[0], w->n, PS_TYPE_F64); 1630 psVectorInit (wUtB[0], 0.0); 1631 1632 for (int i = 0; i < w->n; i++) { 1633 if (!isfinite(w->data.F64[i])) continue; 1634 if (w->data.F64[i] == 0.0) continue; 1635 wUtB[0]->data.F64[i] = UtB->data.F64[i] / w->data.F64[i]; 1636 } 1637 return true; 1638 } 1639 1640 // this is basically matrix * vector 1641 bool p_pmSubSolve_VwUtB (psVector **VwUtB, psImage *V, psVector *wUtB) { 1642 1643 psAssert (V->numCols == wUtB->n, "V and wUtB dimensions do not match"); 1644 1645 VwUtB[0] = psVectorRecycle (*VwUtB, V->numRows, PS_TYPE_F64); 1646 1647 for (int j = 0; j < V->numRows; j++) { 1648 double sum = 0.0; 1649 for (int i = 0; i < V->numCols; i++) { 1650 sum += V->data.F64[j][i] * wUtB->data.F64[i]; 1651 } 1652 VwUtB[0]->data.F64[j] = sum; 1653 } 1654 return true; 1655 } 1656 1657 // this is basically matrix * vector 1658 bool p_pmSubSolve_Ax (psVector **B, psImage *A, psVector *x) { 1659 1660 psAssert (A->numCols == x->n, "A and x dimensions do not match"); 1661 1662 B[0] = psVectorRecycle (*B, A->numRows, PS_TYPE_F64); 1663 1664 for (int j = 0; j < A->numRows; j++) { 1665 double sum = 0.0; 1666 for (int i = 0; i < A->numCols; i++) { 1667 sum += A->data.F64[j][i] * x->data.F64[i]; 1668 } 1669 B[0]->data.F64[j] = sum; 1670 } 1671 return true; 1672 } 1673 1674 // this is basically Vector * vector 1675 bool p_pmSubSolve_VdV (double *value, psVector *x, psVector *y) { 1676 1677 psAssert (x->n == y->n, "x and y dimensions do not match"); 1678 1679 double sum = 0.0; 1680 for (int i = 0; i < x->n; i++) { 1681 sum += x->data.F64[i] * y->data.F64[i]; 1682 } 1683 *value = sum; 1684 return true; 1685 } 1686 1687 bool p_pmSubSolve_y2 (double *y2, pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps) { 1688 1689 int footprint = stamps->footprint; // Half-size of stamps 1690 1691 double sum = 0.0; 1692 for (int i = 0; i < stamps->num; i++) { 1693 1694 pmSubtractionStamp *stamp = stamps->stamps->data[i]; 1695 if (stamp->status != PM_SUBTRACTION_STAMP_USED) continue; 1696 1697 psKernel *weight = NULL; 1698 psKernel *window = NULL; 1699 psKernel *input = NULL; 1700 1701 #ifdef USE_WEIGHT 1702 weight = stamp->weight; 1703 #endif 1704 #ifdef USE_WINDOW 1705 window = stamps->window; 1706 #endif 1707 1708 switch (kernels->mode) { 1709 // MODE_1 : convolve image 1 to match image 2 (and vice versa) 1710 case PM_SUBTRACTION_MODE_1: 1711 input = stamp->image2; 1712 break; 1713 case PM_SUBTRACTION_MODE_2: 1714 input = stamp->image1; 1715 break; 1716 default: 1717 psAbort ("programming error"); 1718 } 1719 1720 for (int y = - footprint; y <= footprint; y++) { 1721 for (int x = - footprint; x <= footprint; x++) { 1722 double in = input->kernel[y][x]; 1723 double value = in*in; 1724 if (weight) { 1725 float wtVal = weight->kernel[y][x]; 1726 value *= wtVal; 1727 } 1728 if (window) { 1729 float winVal = window->kernel[y][x]; 1730 value *= winVal; 1731 } 1732 sum += value; 1733 } 1734 } 1735 } 1736 *y2 = sum; 1737 return true; 1738 } 1739 1740 double p_pmSubSolve_ChiSquare (pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps) { 1741 1742 int footprint = stamps->footprint; // Half-size of stamps 1743 int numKernels = kernels->num; // Number of kernels 1744 1745 double sum = 0.0; 1746 1747 psKernel *residual = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Residual image 1748 psImageInit(residual->image, 0.0); 1749 1750 psImage *polyValues = NULL; // Polynomial values 1751 1752 for (int i = 0; i < stamps->num; i++) { 1753 1754 pmSubtractionStamp *stamp = stamps->stamps->data[i]; 1755 if (stamp->status != PM_SUBTRACTION_STAMP_USED) continue; 1756 1757 psKernel *weight = NULL; 1758 psKernel *window = NULL; 1759 psKernel *target = NULL; 1760 psKernel *source = NULL; 1761 1762 psArray *convolutions = NULL; 1763 1764 #ifdef USE_WEIGHT 1765 weight = stamp->weight; 1766 #endif 1767 #ifdef USE_WINDOW 1768 window = stamps->window; 1769 #endif 1770 1771 switch (kernels->mode) { 1772 // MODE_1 : convolve image 1 to match image 2 (and vice versa) 1773 case PM_SUBTRACTION_MODE_1: 1774 target = stamp->image2; 1775 source = stamp->image1; 1776 convolutions = stamp->convolutions1; 1777 break; 1778 case PM_SUBTRACTION_MODE_2: 1779 target = stamp->image1; 1780 source = stamp->image2; 1781 convolutions = stamp->convolutions2; 1782 break; 1783 default: 1784 psAbort ("programming error"); 1785 } 1786 1787 // Calculate coefficients of the kernel basis functions 1788 polyValues = p_pmSubtractionPolynomial(polyValues, kernels->spatialOrder, stamp->xNorm, stamp->yNorm); 1789 double norm = p_pmSubtractionSolutionNorm(kernels); // Normalisation 1790 double background = p_pmSubtractionSolutionBackground(kernels, polyValues);// Difference in background 1791 1792 psImageInit(residual->image, 0.0); 1793 for (int j = 0; j < numKernels; j++) { 1794 psKernel *convolution = convolutions->data[j]; // Convolution 1795 double coefficient = p_pmSubtractionSolutionCoeff(kernels, polyValues, j, false); // Coefficient 1796 for (int y = - footprint; y <= footprint; y++) { 1797 for (int x = - footprint; x <= footprint; x++) { 1798 residual->kernel[y][x] -= convolution->kernel[y][x] * coefficient; 1799 } 1800 } 1801 } 1802 1803 for (int y = - footprint; y <= footprint; y++) { 1804 for (int x = - footprint; x <= footprint; x++) { 1805 double resid = target->kernel[y][x] - background - source->kernel[y][x] * norm + residual->kernel[y][x]; 1806 double value = PS_SQR(resid); 1807 if (weight) { 1808 float wtVal = weight->kernel[y][x]; 1809 value *= wtVal; 1810 } 1811 if (window) { 1812 float winVal = window->kernel[y][x]; 1813 value *= winVal; 1814 } 1815 sum += value; 1816 } 1817 } 1818 } 1819 psFree (polyValues); 1820 psFree (residual); 1821 1822 return sum; 1823 } 1824 1825 bool p_pmSubSolve_SetWeights (psVector *wApply, psVector *w, psVector *wMask) { 1826 1827 for (int i = 0; i < w->n; i++) { 1828 wApply->data.F64[i] = wMask->data.U8[i] ? 0.0 : w->data.F64[i]; 1829 } 1830 return true; 1831 } 1832 1833 // we are supplied V and w; w represents a diagonal matrix (also, we apply 1/w instead of w) 1834 psImage *p_pmSubSolve_Xvar (psImage *V, psVector *w) { 1835 1836 psAssert (w->n == V->numCols, "w and U dimensions do not match"); 1837 1838 psImage *Vn = psImageAlloc (V->numCols, V->numRows, PS_TYPE_F64); 1839 psImageInit (Vn, 0.0); 1840 1841 // generate Vn = V * w^{-1} 1842 for (int j = 0; j < Vn->numRows; j++) { 1843 for (int i = 0; i < Vn->numCols; i++) { 1844 if (!isfinite(w->data.F64[i])) continue; 1845 if (w->data.F64[i] == 0.0) continue; 1846 Vn->data.F64[j][i] = V->data.F64[j][i] / w->data.F64[i]; 1847 } 1848 } 1849 1850 psImage *Xvar = psImageAlloc (V->numCols, V->numRows, PS_TYPE_F64); 1851 psImageInit (Xvar, 0.0); 1852 1853 // generate Xvar = Vn * Vn^T 1854 for (int j = 0; j < Vn->numRows; j++) { 1855 for (int i = 0; i < Vn->numCols; i++) { 1856 double sum = 0.0; 1857 for (int k = 0; k < Vn->numCols; k++) { 1858 sum += Vn->data.F64[k][i]*Vn->data.F64[k][j]; 1859 } 1860 Xvar->data.F64[j][i] = sum; 1861 } 1862 } 1863 return Xvar; 1864 } 1865 1866 // I get confused by the index values between the image vs matrix usage: In terms 1867 // of the elements of an image A(x,y) = A->data.F64[y][x] = A_x,y, a matrix 1868 // multiplication is: A_k,j * B_i,k = C_i,j 1869 1870 1871 bool psFitsWriteImageSimple (char *filename, psImage *image, psMetadata *header) { 1872 1873 psFits *fits = psFitsOpen(filename, "w"); 1874 psFitsWriteImage(fits, header, image, 0, NULL); 1875 psFitsClose(fits); 1876 1877 return true; 1878 } 1879 1880 bool psVectorWriteFile (char *filename, const psVector *vector) { 1881 1882 FILE *f = fopen (filename, "w"); 1883 int fd = fileno(f); 1884 p_psVectorPrint (fd, vector, "unnamed"); 1885 fclose (f); 1886 1887 return true; 1888 } 1889 1890 1891 # if 0 1892 1893 #ifdef TESTING 1894 psFitsWriteImageSimple("A.fits", sumMatrix, NULL); 1895 psVectorWriteFile ("B.dat", sumVector); 1896 #endif 1897 1898 # define SVD_ANALYSIS 0 1899 # define COEFF_SIG 0.0 1900 # define SVD_TOL 0.0 1901 1902 // Use SVD to determine the kernel coeffs (and validate) 1903 if (SVD_ANALYSIS) { 1904 1905 // We have sumVector and sumMatrix. we are trying to solve the following equation: 1906 // sumMatrix * x = sumVector. 1907 1908 // we can use any standard matrix inversion to solve this. However, the basis 1909 // functions in general have substantial correlation, so that the solution may be 1910 // somewhat poorly determined or unstable. If not numerically ill-conditioned, the 1911 // system of equations may be statistically ill-conditioned. Noise in the image 1912 // will drive insignificant, but correlated, terms in the solution. To avoid these 1913 // problems, we can use SVD to identify numerically unconstrained values and to 1914 // avoid statistically badly determined value. 1915 1916 // A = sumMatrix, B = sumVector 1917 // SVD: A = U w V^T -> A^{-1} = V (1/w) U^T 1918 // x = V (1/w) (U^T B) 1919 // \sigma_x = sqrt(diag(A^{-1})) 1920 // solve for x and A^{-1} to get x & dx 1921 // identify the elements of (1/w) that are nan (1/0.0) -> set to 0.0 1922 // identify the elements of x that are insignificant (x / dx < 1.0? < 0.5?) -> set to 0.0 1923 1924 // If I use the SVD trick to re-condition the matrix, I need to break out the 1925 // kernel and normalization terms from the background term. 1926 // XXX is this true? or was this due to an error in the analysis? 1927 1928 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index in matrix for background 1929 1930 // now pull out the kernel elements into their own square matrix 1931 psImage *kernelMatrix = psImageAlloc (sumMatrix->numCols - 1, sumMatrix->numRows - 1, PS_TYPE_F64); 1932 psVector *kernelVector = psVectorAlloc (sumMatrix->numCols - 1, PS_TYPE_F64); 1933 1934 for (int ix = 0, kx = 0; ix < sumMatrix->numCols; ix++) { 1935 if (ix == bgIndex) continue; 1936 for (int iy = 0, ky = 0; iy < sumMatrix->numRows; iy++) { 1937 if (iy == bgIndex) continue; 1938 kernelMatrix->data.F64[ky][kx] = sumMatrix->data.F64[iy][ix]; 1939 ky++; 1940 } 1941 kernelVector->data.F64[kx] = sumVector->data.F64[ix]; 1942 kx++; 1943 } 1944 1945 psImage *U = NULL; 1946 psImage *V = NULL; 1947 psVector *w = NULL; 1948 if (!psMatrixSVD (&U, &w, &V, kernelMatrix)) { 1949 psError(PS_ERR_UNKNOWN, false, "failed to perform SVD on sumMatrix\n"); 1950 return NULL; 1951 } 1952 1953 // calculate A_inverse: 1954 // Ainv = V * w * U^T 1955 psImage *wUt = p_pmSubSolve_wUt (w, U); 1956 psImage *Ainv = p_pmSubSolve_VwUt (V, wUt); 1957 psImage *Xvar = NULL; 1958 psFree (wUt); 1959 1960 # ifdef TESTING 1961 // kernel terms: 1962 for (int i = 0; i < w->n; i++) { 1963 fprintf (stderr, "w: %f\n", w->data.F64[i]); 1964 } 1965 # endif 1966 // loop over w adding in more and more of the values until chisquare is no longer 1967 // dropping significantly. 1968 // XXX this does not seem to work very well: we seem to need all terms even for 1969 // simple cases... 1970 1971 psVector *Xsvd = NULL; 1972 { 1973 psVector *Ax = NULL; 1974 psVector *UtB = NULL; 1975 psVector *wUtB = NULL; 1976 1977 psVector *wApply = psVectorAlloc(w->n, PS_TYPE_F64); 1978 psVector *wMask = psVectorAlloc(w->n, PS_TYPE_U8); 1979 psVectorInit (wMask, 1); // start by masking everything 1980 1981 double chiSquareLast = NAN; 1982 int maxWeight = 0; 1983 1984 double Axx, Bx, y2; 1985 1986 // XXX this is an attempt to exclude insignificant modes. 1987 // it was not successful with the ISIS kernel set: removing even 1988 // the least significant mode leaves additional ringing / noise 1989 // because the terms are so coupled. 1990 for (int k = 0; false && (k < w->n); k++) { 1991 1992 // unmask the k-th weight 1993 wMask->data.U8[k] = 0; 1994 p_pmSubSolve_SetWeights(wApply, w, wMask); 1995 1996 // solve for x: 1997 // x = V * w * (U^T * B) 1998 p_pmSubSolve_UtB (&UtB, U, kernelVector); 1999 p_pmSubSolve_wUtB (&wUtB, wApply, UtB); 2000 p_pmSubSolve_VwUtB (&Xsvd, V, wUtB); 2001 2002 // chi-square for this system of equations: 2003 // chi-square = sum over terms of: (Ax - B)*x - b*x - y^2 2004 // y^2 = \sum_stamps \sum_pixels input->kernel[y][x]^2 2005 p_pmSubSolve_Ax (&Ax, kernelMatrix, Xsvd); 2006 p_pmSubSolve_VdV (&Axx, Ax, Xsvd); 2007 p_pmSubSolve_VdV (&Bx, kernelVector, Xsvd); 2008 p_pmSubSolve_y2 (&y2, kernels, stamps); 2009 2010 // apparently, this works (compare with the brute force value below 2011 double chiSquare = Axx - 2.0*Bx + y2; 2012 double deltaChi = (k == 0) ? chiSquare : chiSquareLast - chiSquare; 2013 chiSquareLast = chiSquare; 2014 2015 // fprintf (stderr, "chi square = %f, delta: %f\n", chiSquare, deltaChi); 2016 if (k && !maxWeight && (deltaChi < 1.0)) { 2017 maxWeight = k; 2018 } 2019 } 2020 2021 // keep all terms or we get extra ringing 2022 maxWeight = w->n; 2023 psVectorInit (wMask, 1); 2024 for (int k = 0; k < maxWeight; k++) { 2025 wMask->data.U8[k] = 0; 2026 } 2027 p_pmSubSolve_SetWeights(wApply, w, wMask); 2028 2029 // solve for x: 2030 // x = V * w * (U^T * B) 2031 p_pmSubSolve_UtB (&UtB, U, kernelVector); 2032 p_pmSubSolve_wUtB (&wUtB, wApply, UtB); 2033 p_pmSubSolve_VwUtB (&Xsvd, V, wUtB); 2034 2035 // chi-square for this system of equations: 2036 // chi-square = sum over terms of: (Ax - B)*x - b*x - y^2 2037 // y^2 = \sum_stamps \sum_pixels input->kernel[y][x]^2 2038 p_pmSubSolve_Ax (&Ax, kernelMatrix, Xsvd); 2039 p_pmSubSolve_VdV (&Axx, Ax, Xsvd); 2040 p_pmSubSolve_VdV (&Bx, kernelVector, Xsvd); 2041 p_pmSubSolve_y2 (&y2, kernels, stamps); 2042 2043 // apparently, this works (compare with the brute force value below 2044 double chiSquare = Axx - 2.0*Bx + y2; 2045 psLogMsg ("psModules.imcombine", PS_LOG_INFO, "model kernel with %d terms; chi square = %f\n", maxWeight, chiSquare); 2046 2047 // re-calculate A^{-1} to get new variances: 2048 // Ainv = V * w * U^T 2049 // XXX since we keep all terms, this is identical to Ainv 2050 psImage *wUt = p_pmSubSolve_wUt (wApply, U); 2051 Xvar = p_pmSubSolve_VwUt (V, wUt); 2052 psFree (wUt); 2053 2054 psFree (Ax); 2055 psFree (UtB); 2056 psFree (wUtB); 2057 psFree (wApply); 2058 psFree (wMask); 2059 } 2060 2061 // copy the kernel solutions to the full solution vector: 2062 solution = psVectorAlloc(sumVector->n, PS_TYPE_F64); 2063 solutionErr = psVectorAlloc(sumVector->n, PS_TYPE_F64); 2064 2065 for (int ix = 0, kx = 0; ix < sumVector->n; ix++) { 2066 if (ix == bgIndex) { 2067 solution->data.F64[ix] = 0; 2068 solutionErr->data.F64[ix] = 0.001; 2069 continue; 2070 } 2071 solutionErr->data.F64[ix] = sqrt(Ainv->data.F64[kx][kx]); 2072 solution->data.F64[ix] = Xsvd->data.F64[kx]; 2073 kx++; 2074 } 2075 2076 psFree (kernelMatrix); 2077 psFree (kernelVector); 2078 2079 psFree (U); 2080 psFree (V); 2081 psFree (w); 2082 2083 psFree (Ainv); 2084 psFree (Xsvd); 2085 } else { 2086 psVector *permutation = NULL; // Permutation vector, required for LU decomposition 2087 psImage *luMatrix = psMatrixLUDecomposition(NULL, &permutation, sumMatrix); 2088 if (!luMatrix) { 2089 psError(PS_ERR_UNKNOWN, true, "LU Decomposition of least-squares matrix failed.\n"); 2090 psFree(solution); 2091 psFree(sumVector); 2092 psFree(sumMatrix); 2093 psFree(luMatrix); 2094 psFree(permutation); 2095 return NULL; 2096 } 2097 2098 solution = psMatrixLUSolution(NULL, luMatrix, sumVector, permutation); 2099 psFree(luMatrix); 2100 psFree(permutation); 2101 if (!solution) { 2102 psError(PS_ERR_UNKNOWN, true, "Failed to solve the least-squares system.\n"); 2103 psFree(solution); 2104 psFree(sumVector); 2105 psFree(sumMatrix); 2106 return NULL; 2107 } 2108 2109 // XXX LUD does not provide A^{-1}? fake the error for now 2110 solutionErr = psVectorAlloc(sumVector->n, PS_TYPE_F64); 2111 for (int ix = 0; ix < sumVector->n; ix++) { 2112 solutionErr->data.F64[ix] = 0.1*solution->data.F64[ix]; 2113 } 2114 } 2115 2116 if (!kernels->solution1) { 2117 kernels->solution1 = psVectorAlloc (sumVector->n, PS_TYPE_F64); 2118 psVectorInit (kernels->solution1, 0.0); 2119 } 2120 2121 // only update the solutions that we chose to calculate: 2122 if (mode & PM_SUBTRACTION_EQUATION_NORM) { 2123 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 2124 kernels->solution1->data.F64[normIndex] = solution->data.F64[normIndex]; 2125 } 2126 if (mode & PM_SUBTRACTION_EQUATION_BG) { 2127 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index in matrix for background 2128 kernels->solution1->data.F64[bgIndex] = solution->data.F64[bgIndex]; 2129 } 2130 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 2131 int numKernels = kernels->num; 2132 int spatialOrder = kernels->spatialOrder; // Order of spatial variation 2133 int numPoly = PM_SUBTRACTION_POLYTERMS(spatialOrder); // Number of polynomial terms 2134 for (int i = 0; i < numKernels * numPoly; i++) { 2135 // XXX fprintf (stderr, "%f +/- %f (%f) -> ", solution->data.F64[i], solutionErr->data.F64[i], fabs(solution->data.F64[i]/solutionErr->data.F64[i])); 2136 if (fabs(solution->data.F64[i] / solutionErr->data.F64[i]) < COEFF_SIG) { 2137 // XXX fprintf (stderr, "drop\n"); 2138 kernels->solution1->data.F64[i] = 0.0; 2139 } else { 2140 // XXX fprintf (stderr, "keep\n"); 2141 kernels->solution1->data.F64[i] = solution->data.F64[i]; 2142 } 2143 } 2144 } 2145 // double chiSquare = p_pmSubSolve_ChiSquare (kernels, stamps); 2146 // fprintf (stderr, "chi square Brute = %f\n", chiSquare); 2147 2148 psFree(solution); 2149 psFree(sumVector); 2150 psFree(sumMatrix); 2151 # endif 2152 2153 #ifdef TESTING 2154 // XXX double-check for NAN in data: 2155 for (int iy = 0; iy < stamp->matrix->numRows; iy++) { 2156 for (int ix = 0; ix < stamp->matrix->numCols; ix++) { 2157 if (!isfinite(stamp->matrix->data.F64[iy][ix])) { 2158 fprintf (stderr, "WARNING: NAN in matrix\n"); 2159 } 2160 } 2161 } 2162 for (int ix = 0; ix < stamp->vector->n; ix++) { 2163 if (!isfinite(stamp->vector->data.F64[ix])) { 2164 fprintf (stderr, "WARNING: NAN in vector\n"); 2165 } 2166 } 2167 #endif 2168 2169 #ifdef TESTING 2170 for (int ix = 0; ix < sumVector->n; ix++) { 2171 if (!isfinite(sumVector->data.F64[ix])) { 2172 fprintf (stderr, "WARNING: NAN in vector\n"); 2173 } 2174 } 2175 #endif 2176 2177 #ifdef TESTING 2178 for (int ix = 0; ix < sumVector->n; ix++) { 2179 if (!isfinite(sumVector->data.F64[ix])) { 2180 fprintf (stderr, "WARNING: NAN in vector\n"); 2181 } 2182 } 2183 { 2184 psImage *inverse = psMatrixInvert(NULL, sumMatrix, NULL); 2185 psFitsWriteImageSimple("matrixInv.fits", inverse, NULL); 2186 psFree(inverse); 2187 } 2188 { 2189 psImage *X = psMatrixInvert(NULL, sumMatrix, NULL); 2190 psImage *Xt = psMatrixTranspose(NULL, X); 2191 psImage *XtX = psMatrixMultiply(NULL, Xt, X); 2192 psFitsWriteImageSimple("matrixErr.fits", XtX, NULL); 2193 psFree(X); 2194 psFree(Xt); 2195 psFree(XtX); 2196 } 2197 #endif 2198 -
trunk/psModules/src/imcombine/pmSubtractionEquation.h
r19299 r26893 4 4 #include "pmSubtractionStamps.h" 5 5 #include "pmSubtractionKernels.h" 6 7 typedef enum { 8 PM_SUBTRACTION_EQUATION_NONE = 0x00, 9 PM_SUBTRACTION_EQUATION_NORM = 0x01, 10 PM_SUBTRACTION_EQUATION_BG = 0x02, 11 PM_SUBTRACTION_EQUATION_KERNELS = 0x04, 12 PM_SUBTRACTION_EQUATION_ALL = 0x07, // value should be NORM | BG | KERNELS 13 } pmSubtractionEquationCalculationMode; 6 14 7 15 /// Execute a thread job to calculate the least-squares equation for a stamp … … 12 20 bool pmSubtractionCalculateEquationStamp(pmSubtractionStampList *stamps, ///< Stamps 13 21 const pmSubtractionKernels *kernels, ///< Kernel parameters 14 int index ///< Index of stamp 15 ); 22 int index, ///< Index of stamp 23 const pmSubtractionEquationCalculationMode mode 24 ); 16 25 17 26 /// Calculate the least-squares equation to match the image quality 18 27 bool pmSubtractionCalculateEquation(pmSubtractionStampList *stamps, ///< Stamps 19 const pmSubtractionKernels *kernels ///< Kernel parameters 20 ); 28 const pmSubtractionKernels *kernels, ///< Kernel parameters 29 const pmSubtractionEquationCalculationMode mode 30 ); 21 31 22 32 /// Solve the least-squares equation to match the image quality 23 33 bool pmSubtractionSolveEquation(pmSubtractionKernels *kernels, ///< Kernel parameters 24 const pmSubtractionStampList *stamps ///< Stamps 34 const pmSubtractionStampList *stamps, ///< Stamps 35 const pmSubtractionEquationCalculationMode mode 25 36 ); 26 37 27 38 /// Calculate deviations 28 39 psVector *pmSubtractionCalculateDeviations(pmSubtractionStampList *stamps, ///< Stamps 29 constpmSubtractionKernels *kernels ///< Kernel parameters40 pmSubtractionKernels *kernels ///< Kernel parameters 30 41 ); 31 42 -
trunk/psModules/src/imcombine/pmSubtractionIO.c
r23378 r26893 80 80 while ((item = psMetadataGetAndIncrement(iter))) { 81 81 assert(item->type == PS_DATA_UNKNOWN); 82 // Set the normalisation dimensions, since these will be otherwise unavailable when reading the83 // images by scans.84 82 pmSubtractionKernels *kernel = item->data.V; // Kernel used in subtraction 85 kernel->numCols = ro->image->numCols;86 kernel->numRows = ro->image->numRows;87 88 83 kernels = psArrayAdd(kernels, ARRAY_BUFFER, kernel); 89 84 } … … 126 121 kernel->bgOrder); 127 122 psMetadataAddS32(row, PS_LIST_TAIL, NAME_MODE, 0, "Matching mode (enum)", kernel->mode); 128 psMetadataAddS32(row, PS_LIST_TAIL, NAME_COLS, 0, "Number of columns", kernel->numCols);129 psMetadataAddS32(row, PS_LIST_TAIL, NAME_ROWS, 0, "Number of rows", kernel->numRows);130 123 if (kernel->mode == PM_SUBTRACTION_MODE_1 || kernel->mode == PM_SUBTRACTION_MODE_2) { 131 124 psMetadataAddVector(row, PS_LIST_TAIL, NAME_SOL1, 0, "Solution vector 1", kernel->solution1); … … 318 311 319 312 TABLE_LOOKUP(int, S32, bg, NAME_BG); 320 TABLE_LOOKUP(int, S32, numCols, NAME_COLS);321 TABLE_LOOKUP(int, S32, numRows, NAME_ROWS);322 313 323 314 TABLE_LOOKUP(float, F32, mean, NAME_MEAN); … … 325 316 TABLE_LOOKUP(int, S32, numStamps, NAME_NUMSTAMPS); 326 317 327 pmSubtractionKernels *kernels = pmSubtractionKernelsFromDescription(description, bg, mode); 328 kernels->numCols = numCols; 329 kernels->numRows = numRows; 318 pmSubtractionKernels *kernels = pmSubtractionKernelsFromDescription(description, bg, *region, mode); 330 319 kernels->mean = mean; 331 320 kernels->rms = rms; -
trunk/psModules/src/imcombine/pmSubtractionKernels.c
r26156 r26893 10 10 #include "pmSubtraction.h" 11 11 #include "pmSubtractionKernels.h" 12 #include "pmSubtractionHermitian.h" 13 #include "pmSubtractionDeconvolve.h" 14 #include "pmSubtractionVisual.h" 12 15 13 16 #define RINGS_BUFFER 10 // Buffer size for RINGS data 14 15 17 16 18 // Free function for pmSubtractionKernels … … 27 29 psFree(kernels->solution1); 28 30 psFree(kernels->solution2); 31 psFree(kernels->sampleStamps); 32 } 33 34 // Free function for pmSubtractionPreCalcKernel 35 static void pmSubtractionKernelPreCalcFree(pmSubtractionKernelPreCalc *kernel) 36 { 37 psFree(kernel->xKernel); 38 psFree(kernel->yKernel); 39 psFree(kernel->kernel); 40 41 psFree(kernel->uCoords); 42 psFree(kernel->vCoords); 43 psFree(kernel->poly); 29 44 } 30 45 … … 45 60 46 61 // Generate 1D convolution kernel for ISIS 47 static psVector *subtractionKernelISIS(float sigma, // Gaussian width62 psVector *pmSubtractionKernelISIS(float sigma, // Gaussian width 48 63 int order, // Polynomial order 49 64 int size // Kernel half-size … … 57 72 for (int i = 0, x = -size; x <= size; i++, x++) { 58 73 kernel->data.F32[i] = norm * power(x, order) * expf(expNorm * PS_SQR(x)); 74 } 75 76 return kernel; 77 } 78 79 // Generate 1D convolution kernel for HERM (normalized for 2D) 80 psVector *pmSubtractionKernelHERM(float sigma, // Gaussian width 81 int order, // Polynomial order 82 int size // Kernel half-size 83 ) 84 { 85 int fullSize = 2 * size + 1; // Full size of kernel 86 psVector *kernel = psVectorAlloc(fullSize, PS_TYPE_F32); // Kernel to return 87 88 // for now, we are only allowing equal orders and sigmas in X and Y 89 float nf = exp(lgamma(order + 1)); 90 float norm = 1.0 / sqrt(nf*sigma*sqrt(M_2_PI)); 91 92 for (int i = 0, x = -size; x <= size; i++, x++) { 93 float xf = x / sigma; 94 float z = -0.25*xf*xf; 95 kernel->data.F32[i] = norm * p_pmSubtractionHermitianPolynomial(xf, order) * exp(z); 96 } 97 98 return kernel; 99 } 100 101 // Generate 1D convolution kernel for HERM (normalized for 2D) 102 psKernel *pmSubtractionKernelHERM_RADIAL(float sigma, // Gaussian width 103 int order, // Polynomial order 104 int size // Kernel half-size 105 ) 106 { 107 psKernel *kernel = psKernelAlloc(-size, size, -size, size); // 2D Kernel 108 109 // for now, we are only allowing equal orders and sigmas in X and Y 110 float nf = exp(lgamma(order + 1)); 111 float norm = 1.0 / sqrt(nf*sigma*sqrt(M_2_PI)); 112 113 // generate 2D radial hermitian 114 for (int v = -size; v <= size; v++) { 115 for (int u = -size; u <= size; u++) { 116 float r = hypot(u, v) / sigma; 117 float z = -0.25*r*r; 118 kernel->kernel[v][u] = norm * p_pmSubtractionHermitianPolynomial(r, order) * exp(z); 119 } 59 120 } 60 121 … … 96 157 kernels->preCalc->data[index] = NULL; 97 158 kernels->penalties->data.F32[index] = kernels->penalty * PS_SQR(PS_SQR(u) + PS_SQR(v)); 98 159 psAssert (isfinite(kernels->penalties->data.F32[index]), "invalid penalty"); 99 160 psTrace("psModules.imcombine", 7, "Kernel %d: %d %d\n", index, u, v); 100 161 } … … 110 171 } 111 172 173 bool pmSubtractionKernelPreCalcNormalize(pmSubtractionKernels *kernels, pmSubtractionKernelPreCalc *preCalc, 174 int index, int size, int uOrder, int vOrder, float fwhm, 175 bool AlardLuptonStyle, bool forceZeroNull) 176 { 177 // we have 4 cases here: 178 // 1) for odd functions, normalize the kernel by the maximum swing / Npix 179 // 2) for even functions, normalize the kernel to unity 180 // 3) for alard-lupton style normalization, subtract 1 from the 0,0 pixel for all even functions 181 // 4) for deconvolved hermitians, subtract 1 from the 0,0 pixel for the 0,0 function(s) 182 183 // Calculate moments 184 double penalty = 0.0; // Moment, for penalty 185 double sum = 0.0, sum2 = 0.0; // Sum of kernel component 186 float min = INFINITY, max = -INFINITY; // Minimum and maximum kernel value 187 for (int v = -size; v <= size; v++) { 188 for (int u = -size; u <= size; u++) { 189 double value = preCalc->kernel->kernel[v][u]; 190 double value2 = PS_SQR(value); 191 sum += value; 192 sum2 += value2; 193 penalty += value2 * PS_SQR((PS_SQR(u) + PS_SQR(v))); 194 min = PS_MIN(value, min); 195 max = PS_MAX(value, max); 196 } 197 } 198 199 #if 0 200 fprintf(stderr, "%d raw: %lf, null: %f, min: %lf, max: %lf, moment: %lf\n", index, sum, preCalc->kernel->kernel[0][0], min, max, penalty); 201 #endif 202 203 bool zeroNull = false; // Zero out using the null position? 204 float scale2D = NAN; // Scaling for 2-D kernels 205 206 if (AlardLuptonStyle) { 207 if (uOrder % 2 == 0 && vOrder % 2 == 0) { 208 // Even functions: normalise to unit sum and subtract null pixel so that sum is zero 209 scale2D = 1.0 / fabs(sum); 210 zeroNull = true; 211 } else { 212 // Odd functions: choose normalisation so that parameters have about the same strength as for even 213 // functions, no subtraction of null pixel because the sum is already (near) zero 214 scale2D = 1.0 / sqrt(sum2); 215 zeroNull = false; 216 } 217 } 218 219 if (!AlardLuptonStyle && (uOrder == 0 && vOrder == 0)) { 220 zeroNull = true; 221 } 222 if (forceZeroNull) { 223 // Force rescaling and subtraction of null pixel even though the order doesn't indicate it's even 224 scale2D = 1.0 / fabs(sum); 225 zeroNull = true; 226 } 227 if (!forceZeroNull && ((uOrder % 2) || (vOrder % 2))) { 228 // Odd function 229 scale2D = 1.0 / sqrt(sum2); 230 } 231 232 float scale1D = sqrtf(scale2D); // Scaling for 1-D kernels 233 if (preCalc->xKernel) { 234 psBinaryOp(preCalc->xKernel, preCalc->xKernel, "*", psScalarAlloc(scale1D, PS_TYPE_F32)); 235 } 236 if (preCalc->yKernel) { 237 psBinaryOp(preCalc->yKernel, preCalc->yKernel, "*", psScalarAlloc(scale1D, PS_TYPE_F32)); 238 } 239 240 psBinaryOp(preCalc->kernel->image, preCalc->kernel->image, "*", psScalarAlloc(scale2D, PS_TYPE_F32)); 241 penalty *= 1.0 / sum2; 242 243 if (zeroNull) { 244 preCalc->kernel->kernel[0][0] -= 1.0; 245 } 246 247 #if 0 248 { 249 double sum = 0.0; // Sum of kernel component 250 float min = INFINITY, max = -INFINITY; // Minimum and maximum kernel value 251 for (int v = -size; v <= size; v++) { 252 for (int u = -size; u <= size; u++) { 253 sum += preCalc->kernel->kernel[v][u]; 254 min = PS_MIN(preCalc->kernel->kernel[v][u], min); 255 max = PS_MAX(preCalc->kernel->kernel[v][u], max); 256 } 257 } 258 fprintf(stderr, "%d mod: %lf, null: %f, min: %lf, max: %lf, scale: %f\n", index, sum, preCalc->kernel->kernel[0][0], min, max, scale2D); 259 } 260 #endif 261 262 kernels->widths->data.F32[index] = fwhm; 263 kernels->u->data.S32[index] = uOrder; 264 kernels->v->data.S32[index] = vOrder; 265 if (kernels->preCalc->data[index]) { 266 psFree(kernels->preCalc->data[index]); 267 } 268 kernels->preCalc->data[index] = preCalc; 269 kernels->penalties->data.F32[index] = kernels->penalty * penalty; 270 psAssert (isfinite(kernels->penalties->data.F32[index]), "invalid penalty"); 271 psTrace("psModules.imcombine", 7, "Kernel %d: %f %d %d %f\n", index, fwhm, uOrder, vOrder, penalty); 272 273 return true; 274 } 275 112 276 pmSubtractionKernels *p_pmSubtractionKernelsRawISIS(int size, int spatialOrder, 113 const psVector *fwhms , const psVector *orders,114 float penalty, p mSubtractionMode mode)115 { 116 PS_ASSERT_VECTOR_NON_NULL(fwhms , NULL);117 PS_ASSERT_VECTOR_TYPE(fwhms , PS_TYPE_F32, NULL);118 PS_ASSERT_VECTOR_NON_NULL(orders , NULL);119 PS_ASSERT_VECTOR_TYPE(orders , PS_TYPE_S32, NULL);120 PS_ASSERT_VECTORS_SIZE_EQUAL(fwhms , orders, NULL);277 const psVector *fwhmsIN, const psVector *ordersIN, 278 float penalty, psRegion bounds, pmSubtractionMode mode) 279 { 280 PS_ASSERT_VECTOR_NON_NULL(fwhmsIN, NULL); 281 PS_ASSERT_VECTOR_TYPE(fwhmsIN, PS_TYPE_F32, NULL); 282 PS_ASSERT_VECTOR_NON_NULL(ordersIN, NULL); 283 PS_ASSERT_VECTOR_TYPE(ordersIN, PS_TYPE_S32, NULL); 284 PS_ASSERT_VECTORS_SIZE_EQUAL(fwhmsIN, ordersIN, NULL); 121 285 PS_ASSERT_INT_POSITIVE(size, NULL); 122 286 PS_ASSERT_INT_NONNEGATIVE(spatialOrder, NULL); 287 288 // check the requested fwhm values: any values <= 0.0 should be dropped 289 psVector *fwhms = psVectorAllocEmpty (fwhmsIN->n, PS_TYPE_F32); 290 psVector *orders = psVectorAllocEmpty (ordersIN->n, PS_TYPE_S32); 291 for (int i = 0; i < fwhmsIN->n; i++) { 292 if (fwhmsIN->data.F32[i] <= FLT_EPSILON) continue; 293 psVectorAppend(fwhms, fwhmsIN->data.F32[i]); 294 psVectorAppend(orders, ordersIN->data.S32[i]); 295 } 123 296 124 297 int numGaussians = fwhms->n; // Number of Gaussians … … 133 306 134 307 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_ISIS, size, 135 spatialOrder, penalty, mode); // The kernels308 spatialOrder, penalty, bounds, mode); // Kernels 136 309 psStringAppend(&kernels->description, "ISIS(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty); 137 310 … … 141 314 142 315 // Set the kernel parameters 143 int fullSize = 2 * size + 1; // Full size of kernels144 316 for (int i = 0, index = 0; i < numGaussians; i++) { 145 317 float sigma = fwhms->data.F32[i] / (2.0 * sqrtf(2.0 * logf(2.0))); // Gaussian sigma … … 147 319 for (int uOrder = 0; uOrder <= orders->data.S32[i]; uOrder++) { 148 320 for (int vOrder = 0; vOrder <= orders->data.S32[i] - uOrder; vOrder++, index++) { 149 psArray *preCalc = psArrayAlloc(3); // Array to hold precalculated values 150 psVector *xKernel = preCalc->data[0] = subtractionKernelISIS(sigma, uOrder, size); // x Kernel 151 psVector *yKernel = preCalc->data[1] = subtractionKernelISIS(sigma, vOrder, size); // y Kernel 152 psKernel *kernel = preCalc->data[2] = psKernelAlloc(-size, size, -size, size); // Kernel 153 154 // Calculate moments 155 double moment = 0.0; // Moment, for penalty 156 for (int v = -size, y = 0; v <= size; v++, y++) { 157 for (int u = -size, x = 0; u <= size; u++, x++) { 158 double value = xKernel->data.F32[x] * yKernel->data.F32[y]; // Value of kernel 159 kernel->kernel[v][u] = value; 160 moment += value * PS_SQR((PS_SQR(u) + PS_SQR(v))); 161 } 321 322 pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_ISIS, uOrder, vOrder, size, sigma); // structure to hold precalculated values 323 pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], true, false); 324 // pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], false, false); 325 } 326 } 327 } 328 329 return kernels; 330 } 331 332 pmSubtractionKernels *pmSubtractionKernelsISIS_RADIAL(int size, int spatialOrder, 333 const psVector *fwhmsIN, const psVector *ordersIN, 334 float penalty, psRegion bounds, pmSubtractionMode mode) 335 { 336 PS_ASSERT_VECTOR_NON_NULL(fwhmsIN, NULL); 337 PS_ASSERT_VECTOR_TYPE(fwhmsIN, PS_TYPE_F32, NULL); 338 PS_ASSERT_VECTOR_NON_NULL(ordersIN, NULL); 339 PS_ASSERT_VECTOR_TYPE(ordersIN, PS_TYPE_S32, NULL); 340 PS_ASSERT_VECTORS_SIZE_EQUAL(fwhmsIN, ordersIN, NULL); 341 PS_ASSERT_INT_POSITIVE(size, NULL); 342 PS_ASSERT_INT_NONNEGATIVE(spatialOrder, NULL); 343 344 // check the requested fwhm values: any values <= 0.0 should be dropped 345 psVector *fwhms = psVectorAllocEmpty (fwhmsIN->n, PS_TYPE_F32); 346 psVector *orders = psVectorAllocEmpty (ordersIN->n, PS_TYPE_S32); 347 for (int i = 0; i < fwhmsIN->n; i++) { 348 if (fwhmsIN->data.F32[i] <= FLT_EPSILON) continue; 349 psVectorAppend(fwhms, fwhmsIN->data.F32[i]); 350 psVectorAppend(orders, ordersIN->data.S32[i]); 351 } 352 353 int numGaussians = fwhms->n; // Number of Gaussians 354 355 int num = 0; // Number of basis functions 356 psString params = NULL; // List of parameters 357 for (int i = 0; i < numGaussians; i++) { 358 int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian 359 psStringAppend(¶ms, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]); 360 num += (gaussOrder + 1) * (gaussOrder + 2) / 2; 361 num += (11 - gaussOrder - 1); // include all higher order radial terms 362 } 363 364 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_ISIS_RADIAL, size, 365 spatialOrder, penalty, bounds, mode); // Kernels 366 psStringAppend(&kernels->description, "ISIS_RADIAL(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty); 367 368 psLogMsg("psModules.imcombine", PS_LOG_INFO, "ISIS_RADIAL kernel: %s,%d --> %d elements", params, spatialOrder, num); 369 psFree(params); 370 371 // Set the kernel parameters 372 for (int i = 0, index = 0; i < numGaussians; i++) { 373 float sigma = fwhms->data.F32[i] / (2.0 * sqrtf(2.0 * logf(2.0))); // Gaussian sigma 374 // Iterate over (u,v) order 375 for (int uOrder = 0; uOrder <= orders->data.S32[i]; uOrder++) { 376 for (int vOrder = 0; vOrder <= orders->data.S32[i] - uOrder; vOrder++, index++) { 377 pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_ISIS, uOrder, vOrder, size, sigma); // structure to hold precalculated values 378 pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], true, false); 379 } 380 } 381 for (int order = orders->data.S32[i] + 1; order < 11; order ++, index ++) { 382 // XXX modify size for hermitians to account for sqrt(2) in Hermitian definition (relative to ISIS Gaussian) 383 pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_ISIS_RADIAL, order, order, size, sigma / sqrt(2.0)); // structure to hold precalculated values 384 pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, order, order, fwhms->data.F32[i], true, true); 385 } 386 } 387 return kernels; 388 } 389 390 pmSubtractionKernels *pmSubtractionKernelsHERM(int size, int spatialOrder, 391 const psVector *fwhmsIN, const psVector *ordersIN, 392 float penalty, psRegion bounds, pmSubtractionMode mode) 393 { 394 PS_ASSERT_VECTOR_NON_NULL(fwhmsIN, NULL); 395 PS_ASSERT_VECTOR_TYPE(fwhmsIN, PS_TYPE_F32, NULL); 396 PS_ASSERT_VECTOR_NON_NULL(ordersIN, NULL); 397 PS_ASSERT_VECTOR_TYPE(ordersIN, PS_TYPE_S32, NULL); 398 PS_ASSERT_VECTORS_SIZE_EQUAL(fwhmsIN, ordersIN, NULL); 399 PS_ASSERT_INT_POSITIVE(size, NULL); 400 PS_ASSERT_INT_NONNEGATIVE(spatialOrder, NULL); 401 402 // check the requested fwhm values: any values <= 0.0 should be dropped 403 psVector *fwhms = psVectorAllocEmpty (fwhmsIN->n, PS_TYPE_F32); 404 psVector *orders = psVectorAllocEmpty (ordersIN->n, PS_TYPE_S32); 405 for (int i = 0; i < fwhmsIN->n; i++) { 406 if (fwhmsIN->data.F32[i] <= FLT_EPSILON) continue; 407 psVectorAppend(fwhms, fwhmsIN->data.F32[i]); 408 psVectorAppend(orders, ordersIN->data.S32[i]); 409 } 410 411 int numGaussians = fwhms->n; // Number of Gaussians 412 413 int num = 0; // Number of basis functions 414 psString params = NULL; // List of parameters 415 for (int i = 0; i < numGaussians; i++) { 416 int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian 417 psStringAppend(¶ms, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]); 418 num += (gaussOrder + 1) * (gaussOrder + 2) / 2; 419 } 420 421 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_HERM, size, 422 spatialOrder, penalty, bounds, mode); // Kernels 423 psStringAppend(&kernels->description, "HERM(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty); 424 425 psLogMsg("psModules.imcombine", PS_LOG_INFO, "HERM kernel: %s,%d --> %d elements", 426 params, spatialOrder, num); 427 psFree(params); 428 429 // Set the kernel parameters 430 for (int i = 0, index = 0; i < numGaussians; i++) { 431 float sigma = fwhms->data.F32[i] / (2.0 * sqrtf(2.0 * logf(2.0))); // Gaussian sigma 432 // Iterate over (u,v) order 433 for (int uOrder = 0; uOrder <= orders->data.S32[i]; uOrder++) { 434 for (int vOrder = 0; vOrder <= orders->data.S32[i] - uOrder; vOrder++, index++) { 435 pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_HERM, uOrder, vOrder, size, sigma); // structure to hold precalculated values 436 pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], true, false); 437 } 438 } 439 } 440 441 return kernels; 442 } 443 444 pmSubtractionKernels *pmSubtractionKernelsDECONV_HERM(int size, int spatialOrder, 445 const psVector *fwhmsIN, const psVector *ordersIN, 446 float penalty, psRegion bounds, pmSubtractionMode mode) 447 { 448 PS_ASSERT_VECTOR_NON_NULL(fwhmsIN, NULL); 449 PS_ASSERT_VECTOR_TYPE(fwhmsIN, PS_TYPE_F32, NULL); 450 PS_ASSERT_VECTOR_NON_NULL(ordersIN, NULL); 451 PS_ASSERT_VECTOR_TYPE(ordersIN, PS_TYPE_S32, NULL); 452 PS_ASSERT_VECTORS_SIZE_EQUAL(fwhmsIN, ordersIN, NULL); 453 PS_ASSERT_INT_POSITIVE(size, NULL); 454 PS_ASSERT_INT_NONNEGATIVE(spatialOrder, NULL); 455 456 // check the requested fwhm values: any values <= 0.0 should be dropped 457 psVector *fwhms = psVectorAllocEmpty (fwhmsIN->n, PS_TYPE_F32); 458 psVector *orders = psVectorAllocEmpty (ordersIN->n, PS_TYPE_S32); 459 for (int i = 0; i < fwhmsIN->n; i++) { 460 if (fwhmsIN->data.F32[i] <= FLT_EPSILON) continue; 461 psVectorAppend(fwhms, fwhmsIN->data.F32[i]); 462 psVectorAppend(orders, ordersIN->data.S32[i]); 463 } 464 465 int numGaussians = fwhms->n; // Number of Gaussians 466 467 int num = 0; // Number of basis functions 468 psString params = NULL; // List of parameters 469 for (int i = 0; i < numGaussians; i++) { 470 int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian 471 psStringAppend(¶ms, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]); 472 num += PS_SQR(gaussOrder + 1); 473 } 474 475 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_DECONV_HERM, size, 476 spatialOrder, penalty, bounds, mode); // Kernels 477 psStringAppend(&kernels->description, "DECONV_HERM(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty); 478 479 psLogMsg("psModules.imcombine", PS_LOG_INFO, "DECONVOLVED HERM kernel: %s,%d --> %d elements", params, spatialOrder, num); 480 psFree(params); 481 482 // XXXXX hard-wired reference sigma for now of 1.7 pix (== 4.0 pix fwhm == 1.0 arcsec in simtest) 483 // generate the Gaussian deconvolution kernel 484 # define DECONV_SIGMA 1.6 485 psKernel *kernelGauss = pmSubtractionDeconvolveGauss (size, DECONV_SIGMA); 486 487 # if 1 488 psArray *deconKernels = psArrayAllocEmpty(100); 489 # endif 490 491 // Set the kernel parameters 492 for (int i = 0, index = 0; i < numGaussians; i++) { 493 float sigma = fwhms->data.F32[i] / (2.0 * sqrtf(2.0 * logf(2.0))); // Gaussian sigma 494 // Iterate over (u,v) order 495 for (int uOrder = 0; uOrder <= orders->data.S32[i]; uOrder++) { 496 for (int vOrder = 0; vOrder <= orders->data.S32[i]; vOrder++, index++) { 497 498 pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_HERM, uOrder, vOrder, size, sigma); // structure to hold precalculated values 499 500 // save the generated 2D kernel as the target, deconvolve it by Gaussian, replacing the generated 2D kernel 501 psKernel *kernelTarget = preCalc->kernel; 502 preCalc->kernel = pmSubtractionDeconvolveKernel(kernelTarget, kernelGauss); // Kernel 503 504 // XXX do we use Alard-Lupton normalization (last param true) or not? 505 pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], true, false); 506 507 // XXXX test demo that deconvolved kernel is valid 508 # if 1 509 psImage *kernelConv = psImageConvolveFFT(NULL, preCalc->kernel->image, NULL, 0, kernelGauss); 510 psArrayAdd (deconKernels, 100, kernelConv); 511 psFree (kernelConv); 512 513 if (!uOrder && !vOrder){ 514 pmSubtractionVisualShowSubtraction (kernelTarget->image, preCalc->kernel->image, kernelConv); 162 515 } 163 164 // Normalise sum of kernel component to unity for even functions 165 if (uOrder % 2 == 0 && vOrder % 2 == 0) { 166 double sum = 0.0; // Sum of kernel component 167 for (int v = 0; v < fullSize; v++) { 168 for (int u = 0; u < fullSize; u++) { 169 sum += xKernel->data.F32[u] * yKernel->data.F32[v]; 170 } 171 } 172 sum = 1.0 / sqrt(sum); 173 psBinaryOp(xKernel, xKernel, "*", psScalarAlloc(sum, PS_TYPE_F32)); 174 psBinaryOp(yKernel, yKernel, "*", psScalarAlloc(sum, PS_TYPE_F32)); 175 psBinaryOp(kernel->image, kernel->image, "*", psScalarAlloc(PS_SQR(sum), PS_TYPE_F32)); 176 kernel->kernel[0][0] -= 1.0; 177 moment *= PS_SQR(sum); 516 # endif 517 } 518 } 519 } 520 521 # if 1 522 psImage *dot = psImageAlloc(deconKernels->n, deconKernels->n, PS_TYPE_F32); 523 for (int i = 0; i < deconKernels->n; i++) { 524 for (int j = 0; j <= i; j++) { 525 psImage *t1 = deconKernels->data[i]; 526 psImage *t2 = deconKernels->data[j]; 527 528 double sum = 0.0; 529 for (int iy = 0; iy < t1->numRows; iy++) { 530 for (int ix = 0; ix < t1->numCols; ix++) { 531 sum += t1->data.F32[iy][ix] * t2->data.F32[iy][ix]; 178 532 } 179 180 181 #if 0182 double sum = 0.0; // Sum of kernel component183 for (int v = -size; v <= size; v++) {184 for (int u = -size; u <= size; u++) {185 sum += kernel->kernel[v][u];186 }187 }188 fprintf(stderr, "%d sum: %lf\n", index, sum);189 #endif190 191 kernels->widths->data.F32[index] = fwhms->data.F32[i];192 kernels->u->data.S32[index] = uOrder;193 kernels->v->data.S32[index] = vOrder;194 if (kernels->preCalc->data[index]) {195 psFree(kernels->preCalc->data[index]);196 }197 kernels->preCalc->data[index] = preCalc;198 kernels->penalties->data.F32[index] = kernels->penalty * fabsf(moment);199 200 psTrace("psModules.imcombine", 7, "Kernel %d: %f %d %d %f\n", index,201 fwhms->data.F32[i], uOrder, vOrder, fabsf(moment));202 533 } 203 } 204 } 534 dot->data.F32[j][i] = sum; 535 dot->data.F32[i][j] = sum; 536 } 537 } 538 pmSubtractionVisualShowSubtraction (dot, NULL, NULL); 539 psFree (dot); 540 psFree (deconKernels); 541 # endif 205 542 206 543 return kernels; … … 212 549 213 550 pmSubtractionKernels *pmSubtractionKernelsAlloc(int numBasisFunctions, pmSubtractionKernelsType type, 214 int size, int spatialOrder, float penalty, 551 int size, int spatialOrder, float penalty, psRegion bounds, 215 552 pmSubtractionMode mode) 216 553 { … … 224 561 kernels->v = psVectorAlloc(numBasisFunctions, PS_TYPE_S32); 225 562 kernels->widths = psVectorAlloc(numBasisFunctions, PS_TYPE_F32); 563 kernels->uStop = NULL; 564 kernels->vStop = NULL; 565 kernels->xMin = bounds.x0; 566 kernels->xMax = bounds.x1; 567 kernels->yMin = bounds.y0; 568 kernels->yMax = bounds.y1; 226 569 kernels->preCalc = psArrayAlloc(numBasisFunctions); 227 570 kernels->penalty = penalty; 228 571 kernels->penalties = psVectorAlloc(numBasisFunctions, PS_TYPE_F32); 229 kernels->uStop = NULL;230 kernels->vStop = NULL;231 572 kernels->size = size; 232 573 kernels->inner = 0; … … 234 575 kernels->bgOrder = 0; 235 576 kernels->mode = mode; 236 kernels->numCols = 0;237 kernels->numRows = 0;238 577 kernels->solution1 = NULL; 239 578 kernels->solution2 = NULL; 579 kernels->mean = NAN; 580 kernels->rms = NAN; 581 kernels->numStamps = 0; 582 kernels->sampleStamps = NULL; 583 584 kernels->fSigResMean = NAN; 585 kernels->fSigResStdev = NAN; 586 kernels->fMaxResMean = NAN; 587 kernels->fMaxResStdev = NAN; 588 kernels->fMinResMean = NAN; 589 kernels->fMinResStdev = NAN; 240 590 241 591 return kernels; 242 592 } 243 593 244 pmSubtractionKernels *pmSubtractionKernelsPOIS(int size, int spatialOrder, float penalty, 594 pmSubtractionKernelPreCalc *pmSubtractionKernelPreCalcAlloc(pmSubtractionKernelsType type, int uOrder, int vOrder, int size, float sigma) { 595 596 pmSubtractionKernelPreCalc *preCalc = psAlloc(sizeof(pmSubtractionKernelPreCalc)); // Kernels, to return 597 psMemSetDeallocator(preCalc, (psFreeFunc)pmSubtractionKernelPreCalcFree); 598 599 // 1D kernel realizations: 600 switch (type) { 601 case PM_SUBTRACTION_KERNEL_ISIS: 602 preCalc->xKernel = pmSubtractionKernelISIS(sigma, uOrder, size); 603 preCalc->yKernel = pmSubtractionKernelISIS(sigma, vOrder, size); 604 preCalc->uCoords = NULL; 605 preCalc->vCoords = NULL; 606 preCalc->poly = NULL; 607 break; 608 case PM_SUBTRACTION_KERNEL_HERM: 609 preCalc->xKernel = pmSubtractionKernelHERM(sigma, uOrder, size); 610 preCalc->yKernel = pmSubtractionKernelHERM(sigma, vOrder, size); 611 preCalc->uCoords = NULL; 612 preCalc->vCoords = NULL; 613 preCalc->poly = NULL; 614 break; 615 case PM_SUBTRACTION_KERNEL_RINGS: 616 // the RINGS kernel uses the uCoords, vCoords, and poly elements of the structure 617 // we allocate these vectors here, but leave the kernel generation to the main function 618 preCalc->xKernel = NULL; 619 preCalc->yKernel = NULL; 620 preCalc->kernel = NULL; 621 preCalc->uCoords = psVectorAllocEmpty(size, PS_TYPE_S32); // u coords 622 preCalc->vCoords = psVectorAllocEmpty(size, PS_TYPE_S32); // v coords 623 preCalc->poly = psVectorAllocEmpty(size, PS_TYPE_F32); // Polynomial 624 return preCalc; 625 case PM_SUBTRACTION_KERNEL_ISIS_RADIAL: 626 preCalc->kernel = pmSubtractionKernelHERM_RADIAL(sigma, uOrder, size); 627 preCalc->xKernel = NULL; 628 preCalc->yKernel = NULL; 629 preCalc->uCoords = NULL; 630 preCalc->vCoords = NULL; 631 preCalc->poly = NULL; 632 return preCalc; 633 default: 634 psAbort("programming error: invalid type for PreCalc kernel"); 635 } 636 637 preCalc->kernel = psKernelAlloc(-size, size, -size, size); // 2D Kernel 638 639 // generate 2D kernel from 1D realizations 640 for (int v = -size, y = 0; v <= size; v++, y++) { 641 for (int u = -size, x = 0; u <= size; u++, x++) { 642 preCalc->kernel->kernel[v][u] = preCalc->xKernel->data.F32[x] * preCalc->yKernel->data.F32[y]; // Value of kernel 643 } 644 } 645 646 return preCalc; 647 } 648 649 pmSubtractionKernels *pmSubtractionKernelsPOIS(int size, int spatialOrder, float penalty, psRegion bounds, 245 650 pmSubtractionMode mode) 246 651 { … … 251 656 252 657 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(0, PM_SUBTRACTION_KERNEL_POIS, size, 253 spatialOrder, penalty, mode); // The kernels658 spatialOrder, penalty, bounds, mode); // Kernels 254 659 psStringAppend(&kernels->description, "POIS(%d,%d,%.2e)", size, spatialOrder, penalty); 255 660 psLogMsg("psModules.imcombine", PS_LOG_INFO, "POIS kernel: %d,%d --> %d elements", … … 266 671 pmSubtractionKernels *pmSubtractionKernelsISIS(int size, int spatialOrder, 267 672 const psVector *fwhms, const psVector *orders, 268 float penalty, p mSubtractionMode mode)673 float penalty, psRegion bounds, pmSubtractionMode mode) 269 674 { 270 675 pmSubtractionKernels *kernels = p_pmSubtractionKernelsRawISIS(size, spatialOrder, fwhms, orders, 271 penalty, mode); // Kernels676 penalty, bounds, mode); // Kernels 272 677 if (!kernels) { 273 678 return NULL; … … 278 683 279 684 pmSubtractionKernels *pmSubtractionKernelsSPAM(int size, int spatialOrder, int inner, int binning, 280 float penalty, p mSubtractionMode mode)685 float penalty, psRegion bounds, pmSubtractionMode mode) 281 686 { 282 687 PS_ASSERT_INT_POSITIVE(size, NULL); … … 299 704 300 705 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_SPAM, size, 301 spatialOrder, penalty, mode); // The kernels706 spatialOrder, penalty, bounds, mode); // Kernels 302 707 kernels->inner = inner; 303 708 psStringAppend(&kernels->description, "SPAM(%d,%d,%d,%d,%.2e)", size, inner, binning, spatialOrder, … … 370 775 371 776 pmSubtractionKernels *pmSubtractionKernelsFRIES(int size, int spatialOrder, int inner, float penalty, 372 p mSubtractionMode mode)777 psRegion bounds, pmSubtractionMode mode) 373 778 { 374 779 PS_ASSERT_INT_POSITIVE(size, NULL); … … 397 802 398 803 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_FRIES, size, 399 spatialOrder, penalty, mode); // The kernels804 spatialOrder, penalty, bounds, mode); // Kernels 400 805 kernels->inner = inner; 401 806 psStringAppend(&kernels->description, "FRIES(%d,%d,%d,%.2e)", size, inner, spatialOrder, penalty); … … 463 868 } 464 869 465 // Grid United with Normal Kernel 870 // Grid United with Normal Kernel [description: GUNK=ISIS(...)+POIS(...)] 466 871 pmSubtractionKernels *pmSubtractionKernelsGUNK(int size, int spatialOrder, const psVector *fwhms, 467 872 const psVector *orders, int inner, float penalty, 468 p mSubtractionMode mode)873 psRegion bounds, pmSubtractionMode mode) 469 874 { 470 875 PS_ASSERT_INT_POSITIVE(size, NULL); … … 479 884 480 885 pmSubtractionKernels *kernels = p_pmSubtractionKernelsRawISIS(size, spatialOrder, fwhms, orders, 481 penalty, mode); // Kernels886 penalty, bounds, mode); // Kernels 482 887 kernels->type = PM_SUBTRACTION_KERNEL_GUNK; 483 888 psStringPrepend(&kernels->description, "GUNK="); … … 495 900 // RINGS --- just what it says 496 901 pmSubtractionKernels *pmSubtractionKernelsRINGS(int size, int spatialOrder, int inner, int ringsOrder, 497 float penalty, p mSubtractionMode mode)902 float penalty, psRegion bounds, pmSubtractionMode mode) 498 903 { 499 904 PS_ASSERT_INT_POSITIVE(size, NULL); … … 526 931 527 932 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_RINGS, size, 528 spatialOrder, penalty, mode); // The kernels933 spatialOrder, penalty, bounds, mode); // Kernels 529 934 kernels->inner = inner; 530 935 psStringAppend(&kernels->description, "RINGS(%d,%d,%d,%d,%.2e)", size, inner, ringsOrder, spatialOrder, … … 566 971 for (int vOrder = 0; vOrder <= (i == 0 ? 0 : ringsOrder - uOrder); vOrder++, index++) { 567 972 568 psArray *data = psArrayAlloc(3); // Container for data 569 psVector *uCoords = data->data[0] = psVectorAllocEmpty(RINGS_BUFFER, PS_TYPE_S32); // u coords 570 psVector *vCoords = data->data[1] = psVectorAllocEmpty(RINGS_BUFFER, PS_TYPE_S32); // v coords 571 psVector *poly = data->data[2] = psVectorAllocEmpty(RINGS_BUFFER, PS_TYPE_F32); // Polynomial 973 pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc (PM_SUBTRACTION_KERNEL_RINGS, 0, 0, RINGS_BUFFER, 0.0); 572 974 double moment = 0.0; // Moment, for penalty 573 975 574 976 if (i == 0) { 575 977 // Central pixel is easy 576 uCoords->data.S32[0] = vCoords->data.S32[0] = 0; 577 poly->data.F32[0] = 1.0; 578 uCoords->n = vCoords->n = poly->n = 1; 978 preCalc->uCoords->data.S32[0] = 0; 979 preCalc->vCoords->data.S32[0] = 0; 980 preCalc->poly->data.F32[0] = 1.0; 981 preCalc->uCoords->n = 1; 982 preCalc->vCoords->n = 1; 983 preCalc->poly->n = 1; 579 984 radiusLast = 0; 580 985 moment = 0.0; … … 594 999 float polyVal = uPoly * vPoly; // Value of polynomial 595 1000 if (polyVal != 0) { // No point adding it otherwise 596 uCoords->data.S32[j] = u;597 vCoords->data.S32[j] = v;598 p oly->data.F32[j] = polyVal;1001 preCalc->uCoords->data.S32[j] = u; 1002 preCalc->vCoords->data.S32[j] = v; 1003 preCalc->poly->data.F32[j] = polyVal; 599 1004 norm += polyVal; 600 moment += polyVal* PS_SQR(PS_SQR(u) + PS_SQR(v));601 602 psVectorExtend( uCoords, RINGS_BUFFER, 1);603 psVectorExtend( vCoords, RINGS_BUFFER, 1);604 psVectorExtend(p oly, RINGS_BUFFER, 1);1005 moment += PS_SQR(polyVal) * PS_SQR(PS_SQR(u) + PS_SQR(v)); 1006 1007 psVectorExtend(preCalc->uCoords, RINGS_BUFFER, 1); 1008 psVectorExtend(preCalc->vCoords, RINGS_BUFFER, 1); 1009 psVectorExtend(preCalc->poly, RINGS_BUFFER, 1); 605 1010 psTrace("psModules.imcombine", 9, "u = %d, v = %d, poly = %f\n", 606 u, v, p oly->data.F32[j]);1011 u, v, preCalc->poly->data.F32[j]); 607 1012 j++; 608 1013 } … … 612 1017 // Normalise kernel component to unit sum 613 1018 if (uOrder % 2 == 0 && vOrder % 2 == 0) { 614 psBinaryOp(p oly,poly, "*", psScalarAlloc(1.0 / norm, PS_TYPE_F32));1019 psBinaryOp(preCalc->poly, preCalc->poly, "*", psScalarAlloc(1.0 / norm, PS_TYPE_F32)); 615 1020 // Add subtraction of 0,0 component to preserve photometric scaling 616 uCoords->data.S32[j] = 0;617 vCoords->data.S32[j] = 0;618 p oly->data.F32[j] = -1.0;619 psVectorExtend( uCoords, RINGS_BUFFER, 1);620 psVectorExtend( vCoords, RINGS_BUFFER, 1);621 psVectorExtend(p oly, RINGS_BUFFER, 1);1021 preCalc->uCoords->data.S32[j] = 0; 1022 preCalc->vCoords->data.S32[j] = 0; 1023 preCalc->poly->data.F32[j] = -1.0; 1024 psVectorExtend(preCalc->uCoords, RINGS_BUFFER, 1); 1025 psVectorExtend(preCalc->vCoords, RINGS_BUFFER, 1); 1026 psVectorExtend(preCalc->poly, RINGS_BUFFER, 1); 622 1027 } else { 623 1028 norm = powf(size, uOrder) * powf(size, vOrder); 624 psBinaryOp(p oly,poly, "*", psScalarAlloc(1.0 / norm, PS_TYPE_F32));1029 psBinaryOp(preCalc->poly, preCalc->poly, "*", psScalarAlloc(1.0 / norm, PS_TYPE_F32)); 625 1030 } 626 moment /= norm;1031 moment /= PS_SQR(norm); 627 1032 } 628 1033 629 psTrace("psModules.imcombine", 8, "%ld pixels in kernel\n", uCoords->n);630 631 kernels->preCalc->data[index] = data;1034 psTrace("psModules.imcombine", 8, "%ld pixels in kernel\n", preCalc->uCoords->n); 1035 1036 kernels->preCalc->data[index] = preCalc; 632 1037 kernels->u->data.S32[index] = uOrder; 633 1038 kernels->v->data.S32[index] = vOrder; 634 1039 kernels->penalties->data.F32[index] = kernels->penalty * fabsf(moment); 1040 if (!isfinite(kernels->penalties->data.F32[index])) { 1041 psAbort ("invalid penalty"); 1042 } 635 1043 636 1044 psTrace("psModules.imcombine", 7, "Kernel %d: %d %d %d\n", index, … … 645 1053 pmSubtractionKernels *pmSubtractionKernelsGenerate(pmSubtractionKernelsType type, int size, int spatialOrder, 646 1054 const psVector *fwhms, const psVector *orders, int inner, 647 int binning, int ringsOrder, float penalty, 1055 int binning, int ringsOrder, float penalty, psRegion bounds, 648 1056 pmSubtractionMode mode) 649 1057 { 650 1058 switch (type) { 651 1059 case PM_SUBTRACTION_KERNEL_POIS: 652 return pmSubtractionKernelsPOIS(size, spatialOrder, penalty, mode);1060 return pmSubtractionKernelsPOIS(size, spatialOrder, penalty, bounds, mode); 653 1061 case PM_SUBTRACTION_KERNEL_ISIS: 654 return pmSubtractionKernelsISIS(size, spatialOrder, fwhms, orders, penalty, mode); 1062 return pmSubtractionKernelsISIS(size, spatialOrder, fwhms, orders, penalty, bounds, mode); 1063 case PM_SUBTRACTION_KERNEL_ISIS_RADIAL: 1064 return pmSubtractionKernelsISIS_RADIAL(size, spatialOrder, fwhms, orders, penalty, bounds, mode); 1065 case PM_SUBTRACTION_KERNEL_HERM: 1066 return pmSubtractionKernelsHERM(size, spatialOrder, fwhms, orders, penalty, bounds, mode); 1067 case PM_SUBTRACTION_KERNEL_DECONV_HERM: 1068 return pmSubtractionKernelsDECONV_HERM(size, spatialOrder, fwhms, orders, penalty, bounds, mode); 655 1069 case PM_SUBTRACTION_KERNEL_SPAM: 656 return pmSubtractionKernelsSPAM(size, spatialOrder, inner, binning, penalty, mode);1070 return pmSubtractionKernelsSPAM(size, spatialOrder, inner, binning, penalty, bounds, mode); 657 1071 case PM_SUBTRACTION_KERNEL_FRIES: 658 return pmSubtractionKernelsFRIES(size, spatialOrder, inner, penalty, mode);1072 return pmSubtractionKernelsFRIES(size, spatialOrder, inner, penalty, bounds, mode); 659 1073 case PM_SUBTRACTION_KERNEL_GUNK: 660 return pmSubtractionKernelsGUNK(size, spatialOrder, fwhms, orders, inner, penalty, mode);1074 return pmSubtractionKernelsGUNK(size, spatialOrder, fwhms, orders, inner, penalty, bounds, mode); 661 1075 case PM_SUBTRACTION_KERNEL_RINGS: 662 return pmSubtractionKernelsRINGS(size, spatialOrder, inner, ringsOrder, penalty, mode);1076 return pmSubtractionKernelsRINGS(size, spatialOrder, inner, ringsOrder, penalty, bounds, mode); 663 1077 default: 664 1078 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unknown kernel type: %x", type); … … 696 1110 697 1111 pmSubtractionKernels *pmSubtractionKernelsFromDescription(const char *description, int bgOrder, 698 p mSubtractionMode mode)1112 psRegion bounds, pmSubtractionMode mode) 699 1113 { 700 1114 PS_ASSERT_STRING_NON_EMPTY(description, NULL); … … 715 1129 float penalty = 0.0; // Penalty for wideness 716 1130 717 if (strncmp(description, "ISIS", 4) == 0) { 718 // XXX Support for GUNK 719 if (strstr(description, "+POIS")) { 720 type = PM_SUBTRACTION_KERNEL_GUNK; 721 psAbort("Deciphering GUNK kernels (%s) is not currently supported.", description); 722 } else { 723 type = PM_SUBTRACTION_KERNEL_ISIS; 724 char *ptr = (char*)description + 5; // Eat "ISIS(" 725 PARSE_STRING_NUMBER(size, ptr, ',', parseStringInt); 726 727 // Count the number of Gaussians 728 int numGauss = 0; 729 for (char *string = ptr; string; string = strchr(string + 1, '(')) { 730 numGauss++; 731 } 732 733 fwhms = psVectorAlloc(numGauss, PS_TYPE_F32); 734 orders = psVectorAlloc(numGauss, PS_TYPE_S32); 735 736 for (int i = 0; i < numGauss; i++) { 737 ptr++; // Eat the '(' 738 PARSE_STRING_NUMBER(fwhms->data.F32[i], ptr, ',', parseStringFloat); // Eat "1.234," 739 PARSE_STRING_NUMBER(orders->data.S32[i], ptr, ')', parseStringInt); // Eat "3)" 740 } 741 742 ptr++; // Eat ',' 743 PARSE_STRING_NUMBER(spatialOrder, ptr, ',', parseStringInt); 744 penalty = parseStringFloat(ptr); 745 } 746 } else if (strncmp(description, "RINGS", 5) == 0) { 747 type = PM_SUBTRACTION_KERNEL_RINGS; 748 char *ptr = (char*)description + 6; 1131 // currently known descriptions: 1132 // ISIS(...), ISIS_RADIAL(...), HERM(...), DECONV_HERM(...), POIS(...), SPAM(...), 1133 // FRIES(...), GUNK=ISIS(...)+POIS(...), RINGS(...), 1134 // the descriptive name is the set of characters before the ( 1135 1136 type = pmSubtractionKernelsTypeFromString (description); 1137 char *ptr = strchr(description, '(') + 1; 1138 psAssert (ptr, "description is missing kernel parameters"); 1139 1140 switch (type) { 1141 case PM_SUBTRACTION_KERNEL_ISIS: 1142 case PM_SUBTRACTION_KERNEL_ISIS_RADIAL: 1143 case PM_SUBTRACTION_KERNEL_HERM: 1144 case PM_SUBTRACTION_KERNEL_DECONV_HERM: 1145 PARSE_STRING_NUMBER(size, ptr, ',', parseStringInt); 1146 1147 // Count the number of Gaussians 1148 int numGauss = 0; 1149 for (char *string = ptr; string; string = strchr(string + 1, '(')) { 1150 numGauss++; 1151 } 1152 1153 fwhms = psVectorAlloc(numGauss, PS_TYPE_F32); 1154 orders = psVectorAlloc(numGauss, PS_TYPE_S32); 1155 1156 for (int i = 0; i < numGauss; i++) { 1157 ptr++; // Eat the '(' 1158 PARSE_STRING_NUMBER(fwhms->data.F32[i], ptr, ',', parseStringFloat); // Eat "1.234," 1159 PARSE_STRING_NUMBER(orders->data.S32[i], ptr, ')', parseStringInt); // Eat "3)" 1160 } 1161 1162 ptr++; // Eat ',' 1163 PARSE_STRING_NUMBER(spatialOrder, ptr, ',', parseStringInt); 1164 penalty = parseStringFloat(ptr); 1165 break; 1166 case PM_SUBTRACTION_KERNEL_RINGS: 749 1167 PARSE_STRING_NUMBER(size, ptr, ',', parseStringInt); 750 1168 PARSE_STRING_NUMBER(inner, ptr, ',', parseStringInt); … … 752 1170 PARSE_STRING_NUMBER(spatialOrder, ptr, ',', parseStringInt); 753 1171 PARSE_STRING_NUMBER(penalty, ptr, ')', parseStringInt); 754 } else { 755 psAbort("Deciphering kernels other than ISIS and RINGS is not currently supported."); 756 } 757 758 759 return pmSubtractionKernelsGenerate(type, size, spatialOrder, fwhms, orders, 760 inner, binning, ringsOrder, penalty, mode); 761 } 762 763 1172 break; 1173 default: 1174 psAbort("Deciphering kernels other than ISIS, HERM, DECONV_HERM or RINGS is not currently supported."); 1175 } 1176 1177 return pmSubtractionKernelsGenerate(type, size, spatialOrder, fwhms, orders, inner, binning, 1178 ringsOrder, penalty, bounds, mode); 1179 } 1180 1181 1182 // the input string can either be just the name or the description string. Currently known 1183 // descriptions: ISIS(...), ISIS_RADIAL(...), HERM(...), DECONV_HERM(...), POIS(...), 1184 // SPAM(...), FRIES(...), GUNK=ISIS(...)+POIS(...), RINGS(...), 764 1185 pmSubtractionKernelsType pmSubtractionKernelsTypeFromString(const char *type) 765 1186 { 766 if (strcasecmp(type, "POIS") == 0) { 1187 // for a bare name (ISIS, HERM), use the full string length. 1188 // otherwise, use the length up to the first '(' 1189 int nameLength = strlen(type); 1190 char *ptr = strchr(type, '('); 1191 if (ptr) { 1192 nameLength = ptr - type; 1193 } 1194 1195 if (strncasecmp(type, "POIS", nameLength) == 0) { 767 1196 return PM_SUBTRACTION_KERNEL_POIS; 768 1197 } 769 if (str casecmp(type, "ISIS") == 0) {1198 if (strncasecmp(type, "ISIS", nameLength) == 0) { 770 1199 return PM_SUBTRACTION_KERNEL_ISIS; 771 1200 } 772 if (strcasecmp(type, "SPAM") == 0) { 1201 if (strncasecmp(type, "ISIS_RADIAL", nameLength) == 0) { 1202 return PM_SUBTRACTION_KERNEL_ISIS_RADIAL; 1203 } 1204 if (strncasecmp(type, "HERM", nameLength) == 0) { 1205 return PM_SUBTRACTION_KERNEL_HERM; 1206 } 1207 if (strncasecmp(type, "DECONV_HERM", nameLength) == 0) { 1208 return PM_SUBTRACTION_KERNEL_DECONV_HERM; 1209 } 1210 if (strncasecmp(type, "SPAM", nameLength) == 0) { 773 1211 return PM_SUBTRACTION_KERNEL_SPAM; 774 1212 } 775 if (str casecmp(type, "FRIES") == 0) {1213 if (strncasecmp(type, "FRIES", nameLength) == 0) { 776 1214 return PM_SUBTRACTION_KERNEL_FRIES; 777 1215 } 778 if (str casecmp(type, "GUNK") == 0) {1216 if (strncasecmp(type, "GUNK", nameLength) == 0) { 779 1217 return PM_SUBTRACTION_KERNEL_GUNK; 780 1218 } 781 if (strcasecmp(type, "RINGS") == 0) { 1219 // note that GUNK has a somewhat different description 1220 if (strncasecmp(type, "GUNK=ISIS", nameLength) == 0) { 1221 return PM_SUBTRACTION_KERNEL_GUNK; 1222 } 1223 if (strncasecmp(type, "RINGS", nameLength) == 0) { 782 1224 return PM_SUBTRACTION_KERNEL_RINGS; 783 1225 } … … 810 1252 out->bgOrder = in->bgOrder; 811 1253 out->mode = in->mode; 812 out->numCols = in->numCols; 813 out->numRows = in->numRows; 1254 out->xMin = in->xMin; 1255 out->xMax = in->xMax; 1256 out->yMin = in->yMin; 1257 out->yMax = in->yMax; 814 1258 out->solution1 = in->solution1 ? psVectorCopy(NULL, in->solution1, PS_TYPE_F64) : NULL; 815 1259 out->solution2 = in->solution2 ? psVectorCopy(NULL, in->solution2, PS_TYPE_F64) : NULL; 1260 out->sampleStamps = psMemIncrRefCounter(in->sampleStamps); 816 1261 817 1262 return out; -
trunk/psModules/src/imcombine/pmSubtractionKernels.h
r26157 r26893 10 10 PM_SUBTRACTION_KERNEL_POIS, ///< Pan-STARRS Optimal Image Subtraction --- delta functions 11 11 PM_SUBTRACTION_KERNEL_ISIS, ///< Traditional kernel --- gaussians modified by polynomials 12 PM_SUBTRACTION_KERNEL_ISIS_RADIAL, ///< ISIS + higher-order radial Hermitians 13 PM_SUBTRACTION_KERNEL_HERM, ///< Hermitian polynomial kernels 14 PM_SUBTRACTION_KERNEL_DECONV_HERM, ///< Deconvolved Hermitian polynomial kernels 12 15 PM_SUBTRACTION_KERNEL_SPAM, ///< Summed Pixels for Advanced Matching --- summed delta functions 13 16 PM_SUBTRACTION_KERNEL_FRIES, ///< Fibonacci Radius Increases Excellence of Subtraction … … 29 32 pmSubtractionKernelsType type; ///< Type of kernels --- allowing the use of multiple kernels 30 33 psString description; ///< Description of the kernel parameters 34 int xMin, xMax, yMin, yMax; ///< Bounds of image (for normalisation) 31 35 long num; ///< Number of kernel components (not including the spatial ones) 32 psVector *u, *v; ///< Offset (for POIS) or polynomial order (for ISIS )33 psVector *widths; ///< Gaussian FWHMs (ISIS )36 psVector *u, *v; ///< Offset (for POIS) or polynomial order (for ISIS, HERM or DECONV_HERM) 37 psVector *widths; ///< Gaussian FWHMs (ISIS, HERM or DECONV_HERM) 34 38 psVector *uStop, *vStop; ///< Width of kernel element (SPAM,FRIES only) 35 psArray *preCalc; ///< Array of images containing pre-calculated kernel (for ISIS )39 psArray *preCalc; ///< Array of images containing pre-calculated kernel (for ISIS, HERM or DECONV_HERM) 36 40 float penalty; ///< Penalty for wideness 37 41 psVector *penalties; ///< Penalty for each kernel component … … 41 45 int bgOrder; ///< The order for the background fitting 42 46 pmSubtractionMode mode; ///< Mode for subtraction 43 int numCols, numRows; ///< Size of image (for normalisation), or zero to use image provided44 47 psVector *solution1, *solution2; ///< Solution for the PSF matching 45 48 // Quality information 46 49 float mean, rms; ///< Mean and RMS of chi^2 from stamps 47 50 int numStamps; ///< Number of good stamps 51 float fSigResMean; ///< mean fractional stdev of residuals 52 float fSigResStdev; ///< stdev of fractional stdev of residuals 53 float fMaxResMean; ///< mean fractional positive swing in residuals 54 float fMaxResStdev; ///< stdev of fractional positive swing in residuals 55 float fMinResMean; ///< mean fractional negative swing in residuals 56 float fMinResStdev; ///< stdev of fractional negative swing in residuals 57 psArray *sampleStamps; ///< array of brightest set of stamps for output visualizations 48 58 } pmSubtractionKernels; 59 60 // pmSubtractionKernels->preCalc is an array of pmSubtractionKernelPreCalc structures 61 typedef struct { 62 psVector *uCoords; // used by RINGS 63 psVector *vCoords; // used by RINGS 64 psVector *poly; // used by RINGS 65 66 psVector *xKernel; // used by ISIS, HERM, DECONV_HERM 67 psVector *yKernel; // used by ISIS, HERM, DECONV_HERM 68 psKernel *kernel; // used by ISIS, HERM, DECONV_HERM 69 } pmSubtractionKernelPreCalc; 49 70 50 71 // Assertion to check pmSubtractionKernels … … 64 85 PS_ASSERT_VECTOR_SIZE((KERNELS)->widths, (KERNELS)->num, RETURNVALUE); \ 65 86 } \ 87 if ((KERNELS)->type == PM_SUBTRACTION_KERNEL_ISIS_RADIAL) { \ 88 PS_ASSERT_VECTOR_NON_NULL((KERNELS)->widths, RETURNVALUE); \ 89 PS_ASSERT_VECTOR_TYPE((KERNELS)->widths, PS_TYPE_F32, RETURNVALUE); \ 90 PS_ASSERT_VECTOR_SIZE((KERNELS)->widths, (KERNELS)->num, RETURNVALUE); \ 91 } \ 92 if ((KERNELS)->type == PM_SUBTRACTION_KERNEL_HERM) { \ 93 PS_ASSERT_VECTOR_NON_NULL((KERNELS)->widths, RETURNVALUE); \ 94 PS_ASSERT_VECTOR_TYPE((KERNELS)->widths, PS_TYPE_F32, RETURNVALUE); \ 95 PS_ASSERT_VECTOR_SIZE((KERNELS)->widths, (KERNELS)->num, RETURNVALUE); \ 96 } \ 97 if ((KERNELS)->type == PM_SUBTRACTION_KERNEL_DECONV_HERM) { \ 98 PS_ASSERT_VECTOR_NON_NULL((KERNELS)->widths, RETURNVALUE); \ 99 PS_ASSERT_VECTOR_TYPE((KERNELS)->widths, PS_TYPE_F32, RETURNVALUE); \ 100 PS_ASSERT_VECTOR_SIZE((KERNELS)->widths, (KERNELS)->num, RETURNVALUE); \ 101 } \ 66 102 if ((KERNELS)->uStop || (KERNELS)->vStop) { \ 67 103 PS_ASSERT_VECTOR_NON_NULL((KERNELS)->uStop, RETURNVALUE); \ … … 99 135 } 100 136 137 // Generate 1D convolution kernel for ISIS 138 psVector *pmSubtractionKernelISIS(float sigma, // Gaussian width 139 int order, // Polynomial order 140 int size // Kernel half-size 141 ); 142 143 // Generate 1D convolution kernel for HERM (normalized for 2D) 144 psVector *pmSubtractionKernelHERM(float sigma, // Gaussian width 145 int order, // Polynomial order 146 int size // Kernel half-size 147 ); 148 101 149 /// Generate a delta-function grid for subtraction kernels (like the POIS kernel) 102 150 bool p_pmSubtractionKernelsAddGrid(pmSubtractionKernels *kernels, ///< The subtraction kernels to append to … … 114 162 int spatialOrder, ///< Order of spatial variations 115 163 float penalty, ///< Penalty for wideness 164 psRegion bounds, ///< Bounds for validity 116 165 pmSubtractionMode mode ///< Mode for subtraction 117 166 ); 167 168 /// Allocator for pre-calculated kernel data structure 169 pmSubtractionKernelPreCalc *pmSubtractionKernelPreCalcAlloc( 170 pmSubtractionKernelsType type, ///< type of kernel to allocate (not all can be pre-calculated) 171 int uOrder, ///< order in x-direction 172 int vOrder, ///< order in x-direction 173 int size, ///< Half-size of the kernel 174 float sigma ///< sigma of gaussian kernel 175 ); 176 118 177 119 178 /// Generate POIS kernels … … 121 180 int spatialOrder, ///< Order of spatial variations 122 181 float penalty, ///< Penalty for wideness 182 psRegion bounds, ///< Bounds for validity 123 183 pmSubtractionMode mode ///< Mode for subtraction 124 184 ); … … 130 190 const psVector *orders, ///< Polynomial order of gaussians 131 191 float penalty, ///< Penalty for wideness 192 psRegion bounds, ///< Bounds for validity 132 193 pmSubtractionMode mode ///< Mode for subtraction 133 194 ); … … 139 200 const psVector *orders, ///< Polynomial order of gaussians 140 201 float penalty, ///< Penalty for wideness 202 psRegion bounds, ///< Bounds for validity 141 203 pmSubtractionMode mode ///< Mode for subtraction 142 204 ); 205 206 /// Generate ISIS + RADIAL_HERM kernels 207 pmSubtractionKernels *pmSubtractionKernelsISIS_RADIAL(int size, ///< Half-size of the kernel 208 int spatialOrder, ///< Order of spatial variations 209 const psVector *fwhms, ///< Gaussian FWHMs 210 const psVector *orders, ///< Polynomial order of gaussians 211 float penalty, ///< Penalty for wideness 212 psRegion bounds, ///< Bounds for validity 213 pmSubtractionMode mode ///< Mode for subtraction 214 ); 215 216 /// Generate HERM kernels 217 pmSubtractionKernels *pmSubtractionKernelsHERM(int size, ///< Half-size of the kernel 218 int spatialOrder, ///< Order of spatial variations 219 const psVector *fwhms, ///< Gaussian FWHMs 220 const psVector *orders, ///< order of hermitian polynomials 221 float penalty, ///< Penalty for wideness 222 psRegion bounds, ///< Bounds for validity 223 pmSubtractionMode mode ///< Mode for subtraction 224 ); 225 226 /// Generate DECONV_HERM kernels 227 pmSubtractionKernels *pmSubtractionKernelsDECONV_HERM(int size, ///< Half-size of the kernel 228 int spatialOrder, ///< Order of spatial variations 229 const psVector *fwhms, ///< Gaussian FWHMs 230 const psVector *orders, ///< order of hermitian polynomials 231 float penalty, ///< Penalty for wideness 232 psRegion bounds, ///< Bounds for validity 233 pmSubtractionMode mode ///< Mode for subtraction 234 ); 143 235 144 236 /// Generate SPAM kernels … … 148 240 int binning, ///< Kernel binning factor 149 241 float penalty, ///< Penalty for wideness 242 psRegion bounds, ///< Bounds for validity 150 243 pmSubtractionMode mode ///< Mode for subtraction 151 244 ); … … 156 249 int inner, ///< Inner radius to preserve unbinned 157 250 float penalty, ///< Penalty for wideness 251 psRegion bounds, ///< Bounds for validity 158 252 pmSubtractionMode mode ///< Mode for subtraction 159 253 ); … … 166 260 int inner, ///< Inner radius containing grid of delta functions 167 261 float penalty, ///< Penalty for wideness 262 psRegion bounds, ///< Bounds for validity 168 263 pmSubtractionMode mode ///< Mode for subtraction 169 264 ); … … 175 270 int ringsOrder, ///< Polynomial order 176 271 float penalty, ///< Penalty for wideness 272 psRegion bounds, ///< Bounds for validity 177 273 pmSubtractionMode mode ///< Mode for subtraction 178 274 ); … … 189 285 int ringsOrder, ///< Polynomial order for RINGS 190 286 float penalty, ///< Penalty for wideness 287 psRegion bounds, ///< Bounds for validity 191 288 pmSubtractionMode mode ///< Mode for subtraction 192 289 ); … … 196 293 const char *description, ///< Description of kernel 197 294 int bgOrder, ///< Polynomial order for background fitting 295 psRegion bounds, ///< Bounds for validity 198 296 pmSubtractionMode mode ///< Mode for subtraction 199 297 ); -
trunk/psModules/src/imcombine/pmSubtractionMask.c
r24257 r26893 38 38 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 39 39 40 psImage *pmSubtractionMask(const psImage *mask1, const psImage *mask2, psImageMaskType maskVal, 41 int size, int footprint, float badFrac, pmSubtractionMode mode) 42 { 43 PS_ASSERT_IMAGE_NON_NULL(mask1, NULL); 44 PS_ASSERT_IMAGE_TYPE(mask1, PS_TYPE_IMAGE_MASK, NULL); 45 if (mask2) { 46 PS_ASSERT_IMAGE_NON_NULL(mask2, NULL); 47 PS_ASSERT_IMAGE_TYPE(mask2, PS_TYPE_IMAGE_MASK, NULL); 48 PS_ASSERT_IMAGES_SIZE_EQUAL(mask2, mask1, NULL); 49 } 40 psImage *pmSubtractionMask(psRegion *bounds, const pmReadout *ro1, const pmReadout *ro2, 41 psImageMaskType maskVal, int size, int footprint, float badFrac, 42 pmSubtractionMode mode) 43 { 44 PM_ASSERT_READOUT_NON_NULL(ro1, NULL); 45 PM_ASSERT_READOUT_IMAGE(ro1, NULL); 46 PM_ASSERT_READOUT_MASK(ro1, NULL); 47 PM_ASSERT_READOUT_NON_NULL(ro2, NULL); 48 PM_ASSERT_READOUT_IMAGE(ro2, NULL); 49 PM_ASSERT_READOUT_MASK(ro2, NULL); 50 PS_ASSERT_IMAGES_SIZE_EQUAL(ro1->image, ro2->image, NULL); 50 51 PS_ASSERT_INT_NONNEGATIVE(size, NULL); 51 52 PS_ASSERT_INT_NONNEGATIVE(footprint, NULL); … … 55 56 } 56 57 57 int numCols = mask1->numCols, numRows = mask1->numRows; // Size of the images58 int numCols = ro1->image->numCols, numRows = ro1->image->numRows; // Size of the images 58 59 59 60 // Dereference inputs for convenience 60 psImageMaskType **data1 = mask1->data.PS_TYPE_IMAGE_MASK_DATA; 61 psImageMaskType **data2 = NULL; 62 if (mask2) { 63 data2 = mask2->data.PS_TYPE_IMAGE_MASK_DATA; 64 } 61 psF32 **imageData1 = ro1->image->data.F32, **imageData2 = ro2->image->data.F32; 62 psImageMaskType **maskData1 = ro1->mask->data.PS_TYPE_IMAGE_MASK_DATA, 63 **maskData2 = ro2->mask->data.PS_TYPE_IMAGE_MASK_DATA; 65 64 66 65 // First, a pass through to determine the fraction of bad pixels 67 if (isfinite(badFrac) && badFrac != 1.0) { 66 if (bounds || (isfinite(badFrac) && badFrac != 1.0)) { 67 int xMin = numCols, xMax = 0, yMin = numRows, yMax = 0; // Bounds of good pixels 68 68 int numBad = 0; // Number of bad pixels 69 69 for (int y = 0; y < numRows; y++) { 70 70 for (int x = 0; x < numCols; x++) { 71 if ( data1[y][x] & maskVal) {71 if ((maskData1[y][x] & maskVal) || !isfinite(imageData1[y][x])) { 72 72 numBad++; 73 73 continue; 74 74 } 75 if ( data2 && data2[y][x] & maskVal) {75 if ((maskData2[y][x] & maskVal) || !isfinite(imageData2[y][x])) { 76 76 numBad++; 77 continue; 77 78 } 78 } 79 } 80 if (numBad > badFrac * numCols * numRows) { 79 xMin = PS_MIN(xMin, x); 80 xMax = PS_MAX(xMax, x); 81 yMin = PS_MIN(yMin, y); 82 yMax = PS_MAX(yMax, y); 83 } 84 } 85 if (bounds) { 86 bounds->x0 = xMin; 87 bounds->x1 = xMax; 88 bounds->y0 = yMin; 89 bounds->y1 = yMax; 90 } 91 if (isfinite(badFrac) && badFrac != 1.0 && numBad > badFrac * numCols * numRows) { 81 92 psError(PM_ERR_SMALL_AREA, true, 82 93 "Fraction of bad pixels (%d/%d=%f) exceeds limit (%f)\n", … … 117 128 for (int y = 0; y < numRows; y++) { 118 129 for (int x = 0; x < numCols; x++) { 119 if ( data1[y][x] & maskVal) {130 if (maskData1[y][x] & maskVal) { 120 131 maskData[y][x] |= PM_SUBTRACTION_MASK_BAD_1; 121 132 } 122 if ( data2 && data2[y][x] & maskVal) {133 if (maskData2[y][x] & maskVal) { 123 134 maskData[y][x] |= PM_SUBTRACTION_MASK_BAD_2; 124 135 } -
trunk/psModules/src/imcombine/pmSubtractionMask.h
r23851 r26893 5 5 6 6 /// Generate a mask for use in the subtraction process 7 psImage *pmSubtractionMask(const psImage *refMask, ///< Mask for the reference image (will be convolved) 8 const psImage *inMask, ///< Mask for the input image, or NULL 9 psImageMaskType maskVal, ///< Value to mask out 10 int size, ///< Half-size of the kernel (pmSubtractionKernels.size) 11 int footprint, ///< Half-size of the kernel footprint 12 float badFrac, ///< Maximum fraction of bad input pixels to accept 13 pmSubtractionMode mode ///< Subtraction mode 7 psImage *pmSubtractionMask( 8 psRegion *bounds, ///< Bounds of valid pixels (or NULL), returned 9 const pmReadout *ro1, ///< Readout 1 10 const pmReadout *ro2, ///< Readout 2 11 psImageMaskType maskVal, ///< Value to mask out 12 int size, ///< Half-size of the kernel (pmSubtractionKernels.size) 13 int footprint, ///< Half-size of the kernel footprint 14 float badFrac, ///< Maximum fraction of bad input pixels to accept 15 pmSubtractionMode mode ///< Subtraction mode 14 16 ); 15 17 -
trunk/psModules/src/imcombine/pmSubtractionMatch.c
r26035 r26893 28 28 static bool useFFT = true; // Do convolutions using FFT 29 29 30 # define SEPARATE 0 31 # if (SEPARATE) 32 # define SUBMODE PM_SUBTRACTION_EQUATION_NORM 33 # else 34 # define SUBMODE PM_SUBTRACTION_EQUATION_ALL 35 # endif 30 36 31 37 //#define TESTING … … 64 70 const psImage *subMask, // Mask for subtraction, or NULL 65 71 psImage *variance, // Variance map 66 const psRegion *region, // Region of interest , or NULL72 const psRegion *region, // Region of interest 67 73 float thresh1, // Threshold for stamp finding on readout 1 68 74 float thresh2, // Threshold for stamp finding on readout 2 69 75 float stampSpacing, // Spacing between stamps 76 float normFrac, // Fraction of flux in window for normalisation window 70 77 float sysError, // Relative systematic error in images 78 float skyError, // Relative systematic error in images 71 79 int size, // Kernel half-size 72 80 int footprint, // Convolution footprint for stamps … … 74 82 ) 75 83 { 84 PS_ASSERT_PTR_NON_NULL(stamps, false); 85 PM_ASSERT_READOUT_NON_NULL(ro1, false); 86 PM_ASSERT_READOUT_NON_NULL(ro2, false); 87 PS_ASSERT_IMAGE_NON_NULL(subMask, false); 88 PS_ASSERT_IMAGE_NON_NULL(variance, false); 89 PS_ASSERT_PTR_NON_NULL(region, false); 90 76 91 psTrace("psModules.imcombine", 3, "Finding stamps...\n"); 77 92 … … 79 94 80 95 *stamps = pmSubtractionStampsFind(*stamps, image1, image2, subMask, region, thresh1, thresh2, 81 size, footprint, stampSpacing, sysError, mode);96 size, footprint, stampSpacing, normFrac, sysError, skyError, mode); 82 97 if (!*stamps) { 83 98 psError(psErrorCodeLast(), false, "Unable to find stamps."); … … 88 103 89 104 psTrace("psModules.imcombine", 3, "Extracting stamps...\n"); 90 if (!pmSubtractionStampsExtract(*stamps, ro1->image, ro2 ? ro2->image : NULL, variance, size)) {105 if (!pmSubtractionStampsExtract(*stamps, ro1->image, ro2->image, variance, size, *region)) { 91 106 psError(PS_ERR_UNKNOWN, false, "Unable to extract stamps."); 92 107 return false; … … 102 117 const pmReadout *ro1, const pmReadout *ro2, // Input images 103 118 int stride, // Size for convolution patches 119 float normFrac, // Fraction of window for normalisation window 104 120 float sysError, // Systematic error in images 121 float skyError, // Systematic error in images 105 122 float kernelError, // Systematic error in kernel 123 float covarFrac, // Fraction for kernel truncation before covariance 106 124 psImageMaskType maskVal, // Value to mask for input 107 125 psImageMaskType maskBad, // Mask for output bad pixels … … 149 167 PS_ASSERT_IMAGES_SIZE_EQUAL(ro1->image, ro2->image, false); 150 168 PS_ASSERT_INT_NONNEGATIVE(stride, false); 169 if (isfinite(normFrac)) { 170 PS_ASSERT_FLOAT_LARGER_THAN(normFrac, 0.0, false); 171 PS_ASSERT_FLOAT_LESS_THAN(normFrac, 1.0, false); 172 } 151 173 if (isfinite(sysError)) { 152 174 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(sysError, 0.0, false); 153 175 PS_ASSERT_FLOAT_LESS_THAN(sysError, 1.0, false); 154 176 } 177 if (isfinite(sysError)) { 178 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(skyError, 0.0, false); 179 } 155 180 if (isfinite(kernelError)) { 156 181 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(kernelError, 0.0, false); 157 182 PS_ASSERT_FLOAT_LESS_THAN(kernelError, 1.0, false); 158 183 } 184 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(covarFrac, 0.0, false); 185 PS_ASSERT_FLOAT_LESS_THAN(covarFrac, 1.0, false); 159 186 // Don't care about maskVal 160 187 // Don't care about maskBad … … 198 225 } 199 226 227 bool pmSubtractionMaskInvalid (const pmReadout *readout, psImageMaskType maskVal) { 228 229 if (!readout) return true; 230 231 psImage *image = readout->image; 232 psImage *mask = readout->mask; 233 psImage *variance = readout->variance; 234 for (int y = 0; y < image->numRows; y++) { 235 for (int x = 0; x < image->numCols; x++) { 236 if (mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) continue; 237 bool valid = false; 238 valid = isfinite(image->data.F32[y][x]); 239 if (variance) { 240 valid &= isfinite(variance->data.F32[y][x]); 241 } 242 if (valid) continue; 243 mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = maskVal; 244 } 245 } 246 247 return true; 248 } 200 249 201 250 bool pmSubtractionMatchPrecalc(pmReadout *conv1, pmReadout *conv2, const pmReadout *ro1, const pmReadout *ro2, 202 psMetadata *analysis, int stride, float kernelError, 251 psMetadata *analysis, int stride, float kernelError, float covarFrac, 203 252 psImageMaskType maskVal, psImageMaskType maskBad, psImageMaskType maskPoor, 204 253 float poorFrac, float badFrac) … … 270 319 } 271 320 272 if (!subtractionMatchCheck(conv1, conv2, ro1, ro2, stride, NAN, kernelError,321 if (!subtractionMatchCheck(conv1, conv2, ro1, ro2, stride, NAN, NAN, NAN, kernelError, covarFrac, 273 322 maskVal, maskBad, maskPoor, poorFrac, badFrac, mode)) { 274 323 psFree(kernels); … … 277 326 } 278 327 279 psImage *subMask = pmSubtractionMask(ro1->mask, ro2 ? ro2->mask : NULL, maskVal, size, 0, 328 pmSubtractionMaskInvalid(ro1, maskVal); 329 pmSubtractionMaskInvalid(ro2, maskVal); 330 331 psRegion bounds = psRegionSet(NAN, NAN, NAN, NAN); // Bounds of valid pixels 332 333 psImage *subMask = pmSubtractionMask(&bounds, ro1, ro2, maskVal, size, 0, 280 334 badFrac, mode); // Subtraction mask 281 335 if (!subMask) { … … 306 360 307 361 if (!pmSubtractionConvolve(conv1, conv2, ro1, ro2, subMask, stride, maskBad, maskPoor, poorFrac, 308 kernelError, region, kernel, true, useFFT)) {362 kernelError, covarFrac, region, kernel, true, useFFT)) { 309 363 psError(PS_ERR_UNKNOWN, false, "Unable to convolve image."); 310 364 psFree(outAnalysis); … … 336 390 int inner, int ringsOrder, int binning, float penalty, 337 391 bool optimum, const psVector *optFWHMs, int optOrder, float optThreshold, 338 int iter, float rej, float sysError, float kernelError, psImageMaskType maskVal,339 psImageMaskType maskBad, psImageMaskType maskPoor, float poorFrac,340 float badFrac, pmSubtractionMode subMode)392 int iter, float rej, float normFrac, float sysError, float skyError, 393 float kernelError, float covarFrac, psImageMaskType maskVal, psImageMaskType maskBad, 394 psImageMaskType maskPoor, float poorFrac, float badFrac, pmSubtractionMode subMode) 341 395 { 342 if (!subtractionMatchCheck(conv1, conv2, ro1, ro2, stride, sysError, kernelError,343 maskVal, maskBad, maskPoor, poorFrac, badFrac, subMode)) {396 if (!subtractionMatchCheck(conv1, conv2, ro1, ro2, stride, normFrac, sysError, skyError, kernelError, 397 covarFrac, maskVal, maskBad, maskPoor, poorFrac, badFrac, subMode)) { 344 398 return false; 345 399 } … … 399 453 // Putting important variable declarations here, since they are freed after a "goto" if there is an error. 400 454 psImage *subMask = NULL; // Mask for subtraction 401 psRegion *region = NULL;// Iso-kernel region455 psRegion *region = psRegionAlloc(NAN, NAN, NAN, NAN); // Iso-kernel region 402 456 psString regionString = NULL; // String for region 403 457 pmSubtractionStampList *stamps = NULL; // Stamps for matching PSF … … 412 466 memCheck("start"); 413 467 414 subMask = pmSubtractionMask(ro1->mask, ro2 ? ro2->mask : NULL, maskVal, size, footprint, 415 badFrac, subMode); 468 pmSubtractionMaskInvalid(ro1, maskVal); 469 pmSubtractionMaskInvalid(ro2, maskVal); 470 471 psRegion bounds = psRegionSet(NAN, NAN, NAN, NAN); // Bounds of valid pixels 472 473 subMask = pmSubtractionMask(&bounds, ro1, ro2, maskVal, size, footprint, badFrac, subMode); 416 474 if (!subMask) { 417 475 psError(psErrorCodeLast(), false, "Unable to generate subtraction mask."); … … 423 481 // Get region of interest 424 482 int xRegions = 1, yRegions = 1; // Number of iso-kernel regions 425 float xRegionSize = 0, yRegionSize = 0; // Size of iso-kernel regions483 float xRegionSize = NAN, yRegionSize = NAN; // Size of iso-kernel regions 426 484 if (isfinite(regionSize) && regionSize != 0.0) { 427 xRegions = numCols / regionSize + 1; 428 yRegions = numRows / regionSize + 1; 429 xRegionSize = (float)numCols / (float)xRegions; 430 yRegionSize = (float)numRows / (float)yRegions; 431 region = psRegionAlloc(NAN, NAN, NAN, NAN); 432 } 433 485 xRegions = (bounds.x1 - bounds.x0) / regionSize + 1; 486 yRegions = (bounds.y1 - bounds.y0) / regionSize + 1; 487 xRegionSize = (float)(bounds.x1 - bounds.x0) / (float)xRegions; 488 yRegionSize = (float)(bounds.y1 - bounds.y0) / (float)yRegions; 489 } else { 490 xRegionSize = bounds.x1 - bounds.x0; 491 yRegionSize = bounds.y1 - bounds.y0; 492 } 493 494 // General background subtraction and measurement of stamp threshold 434 495 float stampThresh1 = NAN, stampThresh2 = NAN; // Stamp thresholds for images 435 496 { 436 psStats *bg = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); // Statistics for backgroun 497 psStats *bg = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); // Statistics for background 437 498 if (ro1) { 499 psStatsInit(bg); 438 500 if (!psImageBackground(bg, NULL, ro1->image, ro1->mask, maskVal, rng)) { 439 501 psError(PS_ERR_UNKNOWN, false, "Unable to measure background statistics."); … … 441 503 goto MATCH_ERROR; 442 504 } 443 stampThresh1 = bg->robustMedian + threshold * bg->robustStdev; 505 stampThresh1 = threshold * bg->robustStdev; 506 psBinaryOp(ro1->image, ro1->image, "-", psScalarAlloc((float)bg->robustMedian, PS_TYPE_F32)); 444 507 } 445 508 if (ro2) { 509 psStatsInit(bg); 446 510 if (!psImageBackground(bg, NULL, ro2->image, ro2->mask, maskVal, rng)) { 447 511 psError(PS_ERR_UNKNOWN, false, "Unable to measure background statistics."); … … 449 513 goto MATCH_ERROR; 450 514 } 451 stampThresh2 = bg->robustMedian + threshold * bg->robustStdev; 452 } 515 stampThresh2 = threshold * bg->robustStdev; 516 psBinaryOp(ro2->image, ro2->image, "-", psScalarAlloc((float)bg->robustMedian, PS_TYPE_F32)); 517 } 453 518 psFree(bg); 454 519 } 520 521 // Just in case the iso-kernel region doesn't cover the entire image... 522 if (subMode == PM_SUBTRACTION_MODE_1 || subMode == PM_SUBTRACTION_MODE_UNSURE || 523 subMode == PM_SUBTRACTION_MODE_DUAL) { 524 if (!conv1->image) { 525 conv1->image = psImageAlloc(numCols, numRows, PS_TYPE_F32); 526 } 527 psImageInit(conv1->image, NAN); 528 if (ro1->variance) { 529 if (!conv1->variance) { 530 conv1->variance = psImageAlloc(numCols, numRows, PS_TYPE_F32); 531 } 532 psImageInit(conv1->variance, NAN); 533 } 534 if (subMask) { 535 if (!conv1->mask) { 536 conv1->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK); 537 } 538 psImageInit(conv1->mask, maskBad); 539 } 540 } 541 if (subMode == PM_SUBTRACTION_MODE_2 || subMode == PM_SUBTRACTION_MODE_UNSURE || 542 subMode == PM_SUBTRACTION_MODE_DUAL) { 543 if (!conv2->image) { 544 conv2->image = psImageAlloc(numCols, numRows, PS_TYPE_F32); 545 } 546 psImageInit(conv2->image, NAN); 547 if (ro2->variance) { 548 if (!conv2->variance) { 549 conv2->variance = psImageAlloc(numCols, numRows, PS_TYPE_F32); 550 } 551 psImageInit(conv2->variance, NAN); 552 } 553 if (subMask) { 554 if (!conv2->mask) { 555 conv2->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK); 556 } 557 psImageInit(conv2->mask, maskBad); 558 } 559 } 560 455 561 456 562 // Iterate over iso-kernel regions … … 459 565 psTrace("psModules.imcombine", 1, "Subtracting region %d of %d...\n", 460 566 j * xRegions + i + 1, xRegions * yRegions); 461 if (region) {462 *region = psRegionSet((int)(i * xRegionSize),(int)((i + 1) * xRegionSize),463 (int)(j * yRegionSize), (int)((j + 1) * yRegionSize));464 psFree(regionString);465 regionString = psRegionToString(*region);466 psTrace("psModules.imcombine", 3, "Iso-kernel region: %s out of %d,%d\n",467 regionString, numCols, numRows);468 }567 *region = psRegionSet(bounds.x0 + (int)(i * xRegionSize), 568 bounds.x0 + (int)((i + 1) * xRegionSize), 569 bounds.y0 + (int)(j * yRegionSize), 570 bounds.y0 + (int)((j + 1) * yRegionSize)); 571 psFree(regionString); 572 regionString = psRegionToString(*region); 573 psLogMsg("psModules.imcombine", PS_LOG_DETAIL, "Iso-kernel region: %s out of %d,%d\n", 574 regionString, numCols, numRows); 469 575 470 576 if (stampsName && strlen(stampsName) > 0) { 471 577 stamps = pmSubtractionStampsSetFromFile(stampsName, ro1->image, subMask, region, size, 472 footprint, stampSpacing, sysError, subMode); 578 footprint, stampSpacing, normFrac, 579 sysError, skyError, subMode); 473 580 } else if (sources) { 474 581 stamps = pmSubtractionStampsSetFromSources(sources, ro1->image, subMask, region, size, 475 footprint, stampSpacing, sysError, subMode); 582 footprint, stampSpacing, normFrac, 583 sysError, skyError, subMode); 476 584 } 477 585 478 586 // We get the stamps here; we will also attempt to get stamps at the first iteration, but it 479 587 // doesn't matter. 480 if (!subtractionGetStamps(&stamps, ro1, ro2, subMask, variance, NULL, stampThresh1, stampThresh2,481 stampSpacing, sysError, size, footprint, subMode)) {588 if (!subtractionGetStamps(&stamps, ro1, ro2, subMask, variance, region, stampThresh1, stampThresh2, 589 stampSpacing, normFrac, sysError, skyError, size, footprint, subMode)) { 482 590 goto MATCH_ERROR; 483 591 } 484 592 593 594 // generate the window function from the set of stamps 595 if (!pmSubtractionStampsGetWindow(stamps, size)) { 596 psError(PS_ERR_UNKNOWN, false, "Unable to get stamp window."); 597 goto MATCH_ERROR; 598 } 485 599 486 600 // Define kernel basis functions 487 601 if (optimum && (type == PM_SUBTRACTION_KERNEL_ISIS || type == PM_SUBTRACTION_KERNEL_GUNK)) { 488 kernels = pmSubtractionKernelsOptimumISIS(type, size, inner, spatialOrder, optFWHMs, optOrder, 489 stamps, footprint, optThreshold, penalty, subMode); 602 kernels = pmSubtractionKernelsOptimumISIS(type, size, inner, spatialOrder, 603 optFWHMs, optOrder, stamps, footprint, 604 optThreshold, penalty, bounds, subMode); 490 605 if (!kernels) { 491 606 psErrorClear(); … … 496 611 // Not an ISIS/GUNK kernel, or the optimum kernel search failed 497 612 kernels = pmSubtractionKernelsGenerate(type, size, spatialOrder, isisWidths, isisOrders, 498 inner, binning, ringsOrder, penalty, subMode); 613 inner, binning, ringsOrder, penalty, bounds, subMode); 614 // pmSubtractionVisualShowKernels(kernels); 499 615 } 500 616 … … 545 661 546 662 if (!subtractionGetStamps(&stamps, ro1, ro2, subMask, variance, region, 547 stampThresh1, stampThresh2, stampSpacing, sysError, 548 size, footprint, subMode)) { 549 goto MATCH_ERROR; 550 } 551 552 psTrace("psModules.imcombine", 3, "Calculating equation...\n"); 553 if (!pmSubtractionCalculateEquation(stamps, kernels)) { 663 stampThresh1, stampThresh2, stampSpacing, normFrac, 664 sysError, skyError, size, footprint, subMode)) { 665 goto MATCH_ERROR; 666 } 667 668 // generate the window function from the set of stamps 669 if (!pmSubtractionStampsGetWindow(stamps, size)) { 670 psError(PS_ERR_UNKNOWN, false, "Unable to get stamps window."); 671 goto MATCH_ERROR; 672 } 673 674 // XXX step 1: calculate normalization 675 psTrace("psModules.imcombine", 3, "Calculating equation for normalization...\n"); 676 if (!pmSubtractionCalculateEquation(stamps, kernels, SUBMODE)) { 554 677 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 555 678 goto MATCH_ERROR; 556 679 } 557 680 681 psTrace("psModules.imcombine", 3, "Solving equation for normalization...\n"); 682 if (!pmSubtractionSolveEquation(kernels, stamps, SUBMODE)) { 683 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 684 goto MATCH_ERROR; 685 } 686 memCheck(" solve equation"); 687 688 # if (SEPARATE) 689 // set USED -> CALCULATE 690 pmSubtractionStampsResetStatus (stamps); 691 692 // XXX step 2: calculate kernel parameters 693 psTrace("psModules.imcombine", 3, "Calculating equation for kernels...\n"); 694 if (!pmSubtractionCalculateEquation(stamps, kernels, PM_SUBTRACTION_EQUATION_KERNELS)) { 695 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 696 goto MATCH_ERROR; 697 } 558 698 memCheck(" calculate equation"); 559 699 560 psTrace("psModules.imcombine", 3, "Solving equation...\n"); 561 562 if (!pmSubtractionSolveEquation(kernels, stamps)) { 700 psTrace("psModules.imcombine", 3, "Solving equation for kernels...\n"); 701 if (!pmSubtractionSolveEquation(kernels, stamps, PM_SUBTRACTION_EQUATION_KERNELS)) { 563 702 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 564 703 goto MATCH_ERROR; 565 704 } 566 567 705 memCheck(" solve equation"); 568 706 # endif 569 707 psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations 570 708 if (!deviations) { … … 587 725 } 588 726 727 // if we hit the max number of iterations and we have rejected stamps, re-solve 589 728 if (numRejected > 0) { 590 psTrace("psModules.imcombine", 3, "Solving equation...\n"); 591 if (!pmSubtractionSolveEquation(kernels, stamps)) { 729 // XXX step 1: calculate normalization 730 psTrace("psModules.imcombine", 3, "Calculating equation for normalization...\n"); 731 if (!pmSubtractionCalculateEquation(stamps, kernels, SUBMODE)) { 592 732 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 593 733 goto MATCH_ERROR; 594 734 } 735 736 // solve normalization 737 psTrace("psModules.imcombine", 3, "Solving equation for kernels...\n"); 738 if (!pmSubtractionSolveEquation(kernels, stamps, SUBMODE)) { 739 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 740 goto MATCH_ERROR; 741 } 742 743 # if (SEPARATE) 744 // set USED -> CALCULATE 745 pmSubtractionStampsResetStatus (stamps); 746 747 // XXX step 2: calculate kernel parameters 748 psTrace("psModules.imcombine", 3, "Calculating equation for normalization...\n"); 749 if (!pmSubtractionCalculateEquation(stamps, kernels, PM_SUBTRACTION_EQUATION_KERNELS)) { 750 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 751 goto MATCH_ERROR; 752 } 753 754 // solve kernel parameters 755 psTrace("psModules.imcombine", 3, "Solving equation for kernels...\n"); 756 if (!pmSubtractionSolveEquation(kernels, stamps, PM_SUBTRACTION_EQUATION_KERNELS)) { 757 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 758 goto MATCH_ERROR; 759 } 760 memCheck(" solve equation"); 761 # endif 595 762 psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations 596 763 if (!deviations) { … … 615 782 psTrace("psModules.imcombine", 2, "Convolving...\n"); 616 783 if (!pmSubtractionConvolve(conv1, conv2, ro1, ro2, subMask, stride, maskBad, maskPoor, poorFrac, 617 kernelError, region, kernels, true, useFFT)) {784 kernelError, covarFrac, region, kernels, true, useFFT)) { 618 785 psError(PS_ERR_UNKNOWN, false, "Unable to convolve image."); 619 786 goto MATCH_ERROR; … … 897 1064 assert(kernels); 898 1065 899 psTrace("psModules.imcombine", 3, "Calculating %s equation...\n", description);900 if (!pmSubtractionCalculateEquation(stamps, kernels )) {1066 psTrace("psModules.imcombine", 3, "Calculating %s normalization equation...\n", description); 1067 if (!pmSubtractionCalculateEquation(stamps, kernels, SUBMODE)) { 901 1068 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 902 1069 return false; 903 1070 } 904 1071 905 psTrace("psModules.imcombine", 3, "Solving %s equation...\n", description);906 if (!pmSubtractionSolveEquation(kernels, stamps )) {1072 psTrace("psModules.imcombine", 3, "Solving %s normalization equation...\n", description); 1073 if (!pmSubtractionSolveEquation(kernels, stamps, SUBMODE)) { 907 1074 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 908 1075 return false; 909 1076 } 1077 1078 # if (SEPARATE) 1079 // set USED -> CALCULATE 1080 pmSubtractionStampsResetStatus (stamps); 1081 1082 psTrace("psModules.imcombine", 3, "Calculating %s kernel coeffs equation...\n", description); 1083 if (!pmSubtractionCalculateEquation(stamps, kernels, PM_SUBTRACTION_EQUATION_KERNELS)) { 1084 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 1085 return false; 1086 } 1087 1088 psTrace("psModules.imcombine", 3, "Solving %s kernel coeffs equation...\n", description); 1089 if (!pmSubtractionSolveEquation(kernels, stamps, PM_SUBTRACTION_EQUATION_KERNELS)) { 1090 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 1091 return false; 1092 } 1093 # endif 910 1094 911 1095 psTrace("psModules.imcombine", 3, "Calculate %s deviations...\n", description); … … 927 1111 if (numRejected > 0) { 928 1112 // Allow re-fit with reduced stamps set 929 psTrace("psModules.imcombine", 3, " Resolving %sequation...\n", description);930 if (!pmSubtraction SolveEquation(kernels, stamps)) {1113 psTrace("psModules.imcombine", 3, "Calculating %s normalization equation...\n", description); 1114 if (!pmSubtractionCalculateEquation(stamps, kernels, PM_SUBTRACTION_EQUATION_ALL)) { 931 1115 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 932 1116 return false; 933 1117 } 1118 1119 psTrace("psModules.imcombine", 3, "Resolving %s equation...\n", description); 1120 if (!pmSubtractionSolveEquation(kernels, stamps, PM_SUBTRACTION_EQUATION_ALL)) { 1121 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 1122 return false; 1123 } 934 1124 psTrace("psModules.imcombine", 3, "Recalculate %s deviations...\n", description); 1125 1126 # if (SEPARATE) 1127 // set USED -> CALCULATE 1128 pmSubtractionStampsResetStatus (stamps); 1129 1130 psTrace("psModules.imcombine", 3, "Calculating %s normalization equation...\n", description); 1131 if (!pmSubtractionCalculateEquation(stamps, kernels, PM_SUBTRACTION_EQUATION_KERNELS)) { 1132 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 1133 return false; 1134 } 1135 1136 psTrace("psModules.imcombine", 3, "Resolving %s equation...\n", description); 1137 if (!pmSubtractionSolveEquation(kernels, stamps, PM_SUBTRACTION_EQUATION_KERNELS)) { 1138 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 1139 return false; 1140 } 1141 psTrace("psModules.imcombine", 3, "Recalculate %s deviations...\n", description); 1142 # endif 1143 935 1144 psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations 936 1145 if (!deviations) { … … 1019 1228 } 1020 1229 1230 1231 bool pmSubtractionParamsScale(int *kernelSize, int *stampSize, psVector *widths, 1232 float fwhm1, float fwhm2, float scaleRef, float scaleMin, float scaleMax) 1233 { 1234 PS_ASSERT_PTR_NON_NULL(kernelSize, false); 1235 PS_ASSERT_PTR_NON_NULL(stampSize, false); 1236 PS_ASSERT_VECTOR_NON_NULL(widths, false); 1237 PS_ASSERT_VECTOR_TYPE(widths, PS_TYPE_F32, false); 1238 PS_ASSERT_FLOAT_LARGER_THAN(fwhm1, 0.0, false); 1239 PS_ASSERT_FLOAT_LARGER_THAN(fwhm2, 0.0, false); 1240 PS_ASSERT_FLOAT_LARGER_THAN(scaleRef, 0.0, false); 1241 PS_ASSERT_FLOAT_LARGER_THAN(scaleMin, 0.0, false); 1242 PS_ASSERT_FLOAT_LARGER_THAN(scaleMax, 0.0, false); 1243 PS_ASSERT_FLOAT_LARGER_THAN(scaleMax, scaleMin, false); 1244 1245 // float diff = sqrtf(PS_SQR(PS_MAX(fwhm1, fwhm2)) - PS_SQR(PS_MIN(fwhm1, fwhm2))); // Difference 1246 float scale = PS_MAX(fwhm1, fwhm2) / scaleRef; // Scaling factor 1247 1248 if (isfinite(scaleMin) && scale < scaleMin) { 1249 scale = scaleMin; 1250 } 1251 if (isfinite(scaleMax) && scale > scaleMax) { 1252 scale = scaleMax; 1253 } 1254 1255 for (int i = 0; i < widths->n; i++) { 1256 widths->data.F32[i] *= scale; 1257 } 1258 *kernelSize = *kernelSize * scale + 0.5; 1259 *stampSize = *stampSize * scale + 0.5; 1260 1261 psLogMsg("psModules.imcombine", PS_LOG_INFO, 1262 "Scaling kernel parameters by %f: %d %d", scale, *kernelSize, *stampSize); 1263 1264 return true; 1265 } -
trunk/psModules/src/imcombine/pmSubtractionMatch.h
r26035 r26893 39 39 int iter, ///< Rejection iterations 40 40 float rej, ///< Rejection threshold 41 float normFrac, ///< Fraction of flux in window for normalisation window 41 42 float sysError, ///< Relative systematic error in images 43 float skyError, ///< Relative systematic error in images 42 44 float kernelError, ///< Relative systematic error in kernel 45 float covarFrac, ///< Fraction for kernel truncation before covariance calculation 43 46 psImageMaskType maskVal, ///< Value to mask for input 44 47 psImageMaskType maskBad, ///< Mask for output bad pixels … … 57 60 int stride, ///< Size for convolution patches 58 61 float kernelError, ///< Relative systematic error in kernel 62 float covarFrac, ///< Fraction for kernel truncation before covariance calc. 59 63 psImageMaskType maskVal, ///< Value to mask for input 60 64 psImageMaskType maskBad, ///< Mask for output bad pixels … … 94 98 ); 95 99 100 101 /// Scale subtraction parameters according to the FWHMs of the inputs 102 bool pmSubtractionParamsScale( 103 int *kernelSize, ///< Half-size of the kernel 104 int *stampSize, ///< Half-size of the stamp (footprint) 105 psVector *widths, ///< ISIS widths 106 float fwhm1, float fwhm2, ///< FWHMs for inputs 107 float scaleRef, ///< Reference width for scaling 108 float scaleMin, ///< Minimum scaling ratio, or NAN 109 float scaleMax ///< Maximum scaling ratio, or NAN 110 ); 111 112 96 113 #endif -
trunk/psModules/src/imcombine/pmSubtractionParams.c
r26035 r26893 204 204 int spatialOrder, const psVector *fwhms, int maxOrder, 205 205 const pmSubtractionStampList *stamps, int footprint, 206 float tolerance, float penalty, pmSubtractionMode mode) 206 float tolerance, float penalty, psRegion bounds, 207 pmSubtractionMode mode) 207 208 { 208 209 if (type != PM_SUBTRACTION_KERNEL_ISIS && type != PM_SUBTRACTION_KERNEL_GUNK) { … … 232 233 psVectorInit(orders, maxOrder); 233 234 pmSubtractionKernels *kernels = p_pmSubtractionKernelsRawISIS(size, spatialOrder, fwhms, orders, 234 penalty, mode); // Kernels235 penalty, bounds, mode); // Kernels 235 236 psFree(orders); 236 237 psFree(kernels->description); … … 482 483 // Maintain photometric scaling 483 484 if (type == PM_SUBTRACTION_KERNEL_ISIS) { 484 psKernel *subtract = kernels->preCalc->data[0]; // Kernel to subtract from the rest 485 486 // XXX in r26035, this code was just wrong. we had: 487 488 // psKernel *subtract = kernels->preCalc->data[0] 489 490 // but, kernels->preCalc was an array of psArray, not an array of kernels. It is now 491 // an array of pmSubtractionKernelPreCalc. 492 493 pmSubtractionKernelPreCalc *subtract = kernels->preCalc->data[0]; // Kernel to subtract from the rest 494 485 495 for (int i = 1; i < newSize; i++) { 486 496 if (kernels->u->data.S32[i] % 2 == 0 && kernels->v->data.S32[i] % 2 == 0) { 487 p sKernel *kernel= kernels->preCalc->data[i]; // Kernel of interest488 psBinaryOp( kernel->image, kernel->image, "-", subtract->image);497 pmSubtractionKernelPreCalc *preCalc = kernels->preCalc->data[i]; // Kernel of interest 498 psBinaryOp(preCalc->kernel->image, preCalc->kernel->image, "-", subtract->kernel->image); 489 499 } 490 500 } … … 495 505 for (int i = 0; i < newSize; i++) { 496 506 if (kernels->u->data.S32[i] % 2 == 0 && kernels->v->data.S32[i] % 2 == 0) { 497 p sKernel *kernel= kernels->preCalc->data[i]; // Kernel of interest498 kernel->kernel[0][0] -= 1.0;507 pmSubtractionKernelPreCalc *preCalc = kernels->preCalc->data[i]; // Kernel of interest 508 preCalc->kernel->kernel[0][0] -= 1.0; 499 509 } 500 510 } -
trunk/psModules/src/imcombine/pmSubtractionParams.h
r18287 r26893 17 17 float tolerance, ///< Maximum difference in chi^2 18 18 float penalty, ///< Penalty for wideness 19 pmSubtractionMode mode // Mode for subtraction 19 psRegion bounds, ///< Bounds of validity 20 pmSubtractionMode mode ///< Mode for subtraction 20 21 ); 21 22 -
trunk/psModules/src/imcombine/pmSubtractionStamps.c
r26046 r26893 46 46 psFree(list->y); 47 47 psFree(list->flux); 48 psFree(list->window); 48 49 } 49 50 … … 57 58 psFree(stamp->convolutions1); 58 59 psFree(stamp->convolutions2); 59 60 psFree(stamp->matrix1); 61 psFree(stamp->matrix2); 62 psFree(stamp->matrixX); 63 psFree(stamp->vector1); 64 psFree(stamp->vector2); 65 60 psFree(stamp->matrix); 61 psFree(stamp->vector); 66 62 } 67 63 … … 80 76 81 77 // Search a region for a suitable stamp 82 bool stampSearch( int *xStamp, int *yStamp, // Coordinates of stamp, to return78 bool stampSearch(float *xStamp, float *yStamp, // Coordinates of stamp, to return 83 79 float *fluxStamp, // Flux of stamp, to return 84 80 const psImage *image1, const psImage *image2, // Images to search … … 93 89 *fluxStamp = -INFINITY; // Flux of best stamp 94 90 91 // fprintf (stderr, "xMin, xMax: %d, %d -> ", xMin, xMax); 92 95 93 // Ensure we're not going to go outside the bounds of the image 96 94 xMin = PS_MAX(border, xMin); … … 99 97 yMax = PS_MIN(numRows - border - 1, yMax); 100 98 99 if (xMax < xMin) return false; 100 if (yMax < yMin) return false; 101 102 psAssert (xMin <= xMax, "x mismatch?"); 103 psAssert (yMin <= yMax, "y mismatch?"); 104 101 105 for (int y = yMin; y <= yMax; y++) { 102 106 for (int x = xMin; x <= xMax; x++) { … … 115 119 ((image1) ? image1->data.F32[y][x] : image2->data.F32[y][x]); // Flux at pixel 116 120 if (flux > *fluxStamp) { 117 *xStamp = x ;118 *yStamp = y ;121 *xStamp = x + 0.5; 122 *yStamp = y + 0.5; 119 123 *fluxStamp = flux; 120 124 found = true; … … 180 184 181 185 pmSubtractionStampList *pmSubtractionStampListAlloc(int numCols, int numRows, const psRegion *region, 182 int footprint, float spacing, float sysErr) 186 int footprint, float spacing, float normFrac, 187 float sysErr, float skyErr) 183 188 { 184 189 pmSubtractionStampList *list = psAlloc(sizeof(pmSubtractionStampList)); // Stamp list to return … … 220 225 list->y = NULL; 221 226 list->flux = NULL; 227 list->window = NULL; 228 list->normFrac = normFrac; 229 list->normWindow = 0; 222 230 list->footprint = footprint; 223 231 list->sysErr = sysErr; 232 list->skyErr = skyErr; 224 233 225 234 return list; … … 239 248 out->y = NULL; 240 249 out->flux = NULL; 250 out->window = psMemIncrRefCounter(in->window); 241 251 out->footprint = in->footprint; 252 out->normWindow = in->normWindow; 242 253 243 254 for (int i = 0; i < num; i++) { … … 280 291 } 281 292 282 outStamp->matrix1 = inStamp->matrix1 ? psImageCopy(NULL, inStamp->matrix1, PS_TYPE_F64) : NULL; 283 outStamp->matrix2 = inStamp->matrix2 ? psImageCopy(NULL, inStamp->matrix2, PS_TYPE_F64) : NULL; 284 outStamp->matrixX = inStamp->matrixX ? psImageCopy(NULL, inStamp->matrixX, PS_TYPE_F64) : NULL; 285 outStamp->vector1 = inStamp->vector1 ? psVectorCopy(NULL, inStamp->vector1, PS_TYPE_F64) : NULL; 286 outStamp->vector2 = inStamp->vector2 ? psVectorCopy(NULL, inStamp->vector2, PS_TYPE_F64) : NULL; 293 outStamp->matrix = inStamp->matrix ? psImageCopy(NULL, inStamp->matrix, PS_TYPE_F64) : NULL; 294 outStamp->vector = inStamp->vector ? psVectorCopy(NULL, inStamp->vector, PS_TYPE_F64) : NULL; 287 295 288 296 out->stamps->data[i] = outStamp; … … 310 318 stamp->convolutions2 = NULL; 311 319 312 stamp->matrix1 = NULL; 313 stamp->matrix2 = NULL; 314 stamp->matrixX = NULL; 315 stamp->vector1 = NULL; 316 stamp->vector2 = NULL; 320 stamp->matrix = NULL; 321 stamp->vector = NULL; 322 stamp->norm = NAN; 317 323 318 324 return stamp; … … 323 329 const psImage *image2, const psImage *subMask, 324 330 const psRegion *region, float thresh1, float thresh2, 325 int size, int footprint, float spacing, float sysErr,326 pmSubtractionMode mode)331 int size, int footprint, float spacing, float normFrac, 332 float sysErr, float skyErr, pmSubtractionMode mode) 327 333 { 328 334 if (!image1 && !image2) { … … 380 386 381 387 if (!stamps) { 382 stamps = pmSubtractionStampListAlloc(numCols, numRows, region, footprint, spacing, sysErr); 388 stamps = pmSubtractionStampListAlloc(numCols, numRows, region, footprint, spacing, 389 normFrac, sysErr, skyErr); 383 390 } 384 391 … … 402 409 numSearch++; 403 410 404 int xStamp = 0, yStamp =0; // Coordinates of stamp411 float xStamp = 0.0, yStamp = 0.0; // Coordinates of stamp 405 412 float fluxStamp = -INFINITY; // Flux of stamp 406 413 bool goodStamp = false; // Found a good stamp? … … 414 421 // Take stamps off the top of the (sorted) list 415 422 for (int j = xList->n - 1; j >= 0 && !goodStamp; j--) { 416 int xCentre = xList->data.F32[j] + 0.5, yCentre = yList->data.F32[j] + 0.5;// Stamp centre417 418 423 // Chop off the top of the list 419 424 xList->n = j; … … 421 426 fluxList->n = j; 422 427 428 #if 0 423 429 // Fish around a bit to see if we can find a pixel that isn't masked 430 // This is not a good idea if we're using the window feature 424 431 psTrace("psModules.imcombine", 7, "Searching for stamp %d around %d,%d\n", 425 432 i, xCentre, yCentre); 426 433 427 434 // Search bounds 435 int xCentre = xList->data.F32[j] - 0.5, yCentre = yList->data.F32[j] - 0.5;// Stamp centre 428 436 int search = footprint - size; // Search radius 429 437 int xMin = PS_MAX(border, xCentre - search); … … 434 442 goodStamp = stampSearch(&xStamp, &yStamp, &fluxStamp, image1, image2, thresh1, thresh2, 435 443 subMask, xMin, xMax, yMin, yMax, numCols, numRows, border); 444 // fprintf (stderr, "find: %d %d ==> %5.1f %5.1f (\n", xCentre, yCentre, xStamp, yStamp); 445 #else 446 // Only search the exact centre pixel 447 goodStamp = stampSearch(&xStamp, &yStamp, &fluxStamp, image1, image2, thresh1, thresh2, 448 subMask, xList->data.F32[j], xList->data.F32[j], 449 yList->data.F32[j], yList->data.F32[j], numCols, numRows, border); 450 #endif 451 if (0 && goodStamp) { 452 fprintf (stderr, "find: %6.1f < %6.1f < %6.1f, %6.1f < %6.1f %6.1f\n", 453 region->x0 + size, xStamp, region->x1 - size, 454 region->y0 + size, yStamp, region->y1 - size); 455 } 436 456 } 437 457 } else { … … 488 508 const psImage *image, const psImage *subMask, 489 509 const psRegion *region, int size, int footprint, 490 float spacing, float sysErr, pmSubtractionMode mode) 510 float spacing, float normFrac, float sysErr, float skyErr, 511 pmSubtractionMode mode) 491 512 492 513 { … … 509 530 pmSubtractionStampList *stamps = pmSubtractionStampListAlloc(subMask->numCols, subMask->numRows, 510 531 region, footprint, spacing, 511 sysErr); // Stamp list532 normFrac, sysErr, skyErr); // Stamp list 512 533 int numStamps = stamps->num; // Number of stamps 513 534 … … 531 552 for (int i = 0; i < numStars; i++) { 532 553 float xStamp = x->data.F32[i], yStamp = y->data.F32[i]; // Coordinates of stamp 533 int xPix = xStamp + 0.5, yPix = yStamp +0.5; // Pixel coordinate of stamp554 int xPix = xStamp - 0.5, yPix = yStamp - 0.5; // Pixel coordinate of stamp 534 555 if (!checkStampRegion(xPix, yPix, region)) { 535 556 // It's not in the big region … … 539 560 continue; 540 561 } 562 563 // fprintf (stderr, "stamp: %5.1f %5.1f == %d %d\n", xStamp, yStamp, xPix, yPix); 541 564 542 565 bool found = false; … … 607 630 608 631 632 bool pmSubtractionStampsGetWindow(pmSubtractionStampList *stamps, int kernelSize) 633 { 634 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false); 635 PS_ASSERT_INT_NONNEGATIVE(kernelSize, false); 636 637 int size = stamps->footprint; // Size of postage stamps 638 639 psFree (stamps->window); 640 stamps->window = psKernelAlloc(-size, size, -size, size); 641 psImageInit(stamps->window->image, 0.0); 642 643 // generate normalizations for each stamp 644 psVector *norm1 = psVectorAlloc(stamps->num, PS_TYPE_F32); 645 psVector *norm2 = psVectorAlloc(stamps->num, PS_TYPE_F32); 646 for (int i = 0; i < stamps->num; i++) { 647 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 648 if (!stamp) continue; 649 if (!stamp->image1) continue; 650 if (!stamp->image2) continue; 651 652 float sum1 = 0.0; 653 float sum2 = 0.0; 654 for (int y = -size; y <= size; y++) { 655 for (int x = -size; x <= size; x++) { 656 sum1 += stamp->image1->kernel[y][x]; 657 sum2 += stamp->image2->kernel[y][x]; 658 } 659 } 660 norm1->data.F32[i] = sum1; 661 norm2->data.F32[i] = sum2; 662 } 663 664 // storage vector for flux data 665 psStats *stats = psStatsAlloc (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); 666 psVector *flux1 = psVectorAllocEmpty(2*stamps->num, PS_TYPE_F32); 667 psVector *flux2 = psVectorAllocEmpty(2*stamps->num, PS_TYPE_F32); 668 669 // generate the window pixels 670 double sum = 0.0; // Sum inside the window 671 float maxValue = 0.0; // Maximum value, for normalisation 672 for (int y = -size; y <= size; y++) { 673 for (int x = -size; x <= size; x++) { 674 675 flux1->n = 0; 676 flux2->n = 0; 677 for (int i = 0; i < stamps->num; i++) { 678 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 679 if (!stamp) continue; 680 if (!stamp->image1) continue; 681 if (!stamp->image2) continue; 682 683 psVectorAppend(flux1, stamp->image1->kernel[y][x] / norm1->data.F32[i]); 684 psVectorAppend(flux2, stamp->image2->kernel[y][x] / norm2->data.F32[i]); 685 } 686 687 psStatsInit (stats); 688 if (!psVectorStats (stats, flux1, NULL, NULL, 0)) { 689 psAbort ("failed to generate stats"); 690 } 691 float f1 = stats->robustMedian; 692 psStatsInit (stats); 693 if (!psVectorStats (stats, flux2, NULL, NULL, 0)) { 694 psAbort ("failed to generate stats"); 695 } 696 float f2 = stats->robustMedian; 697 698 stamps->window->kernel[y][x] = f1 + f2; 699 if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(size)) { 700 sum += stamps->window->kernel[y][x]; 701 } 702 maxValue = PS_MAX(maxValue, stamps->window->kernel[y][x]); 703 } 704 } 705 706 psTrace("psModules.imcombine", 3, "Window total: %f, threshold: %f\n", 707 sum, (1.0 - stamps->normFrac) * sum); 708 bool done = false; 709 for (int radius = 1; radius <= size && !done; radius++) { 710 double within = 0.0; 711 for (int y = -radius; y <= radius; y++) { 712 for (int x = -radius; x <= radius; x++) { 713 if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(radius)) { 714 within += stamps->window->kernel[y][x]; 715 } 716 } 717 } 718 psTrace("psModules.imcombine", 5, "Radius %d: %f\n", radius, within); 719 if (within > (1.0 - stamps->normFrac) * sum) { 720 stamps->normWindow = radius; 721 done = true; 722 } 723 } 724 725 psTrace("psModules.imcombine", 3, "Normalisation window radius set to %d\n", stamps->normWindow); 726 if (stamps->normWindow == 0 || stamps->normWindow >= size) { 727 psError(PS_ERR_UNKNOWN, true, "Unable to determine normalisation window size."); 728 return false; 729 } 730 731 // re-normalize so chisquare values are sensible 732 for (int y = -size; y <= size; y++) { 733 for (int x = -size; x <= size; x++) { 734 stamps->window->kernel[y][x] /= maxValue; 735 } 736 } 737 738 #if 0 739 { 740 psFits *fits = psFitsOpen ("window.fits", "w"); 741 psFitsWriteImage (fits, NULL, stamps->window->image, 0, NULL); 742 psFitsClose (fits); 743 } 744 #endif 745 746 psFree (stats); 747 psFree (flux1); 748 psFree(flux2); 749 psFree (norm1); 750 psFree (norm2); 751 return true; 752 } 753 609 754 bool pmSubtractionStampsExtract(pmSubtractionStampList *stamps, psImage *image1, psImage *image2, 610 psImage *variance, int kernelSize )755 psImage *variance, int kernelSize, psRegion bounds) 611 756 { 612 757 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false); … … 625 770 } 626 771 627 int numCols = image1->numCols, numRows = image1->numRows; // Size of images628 772 int size = kernelSize + stamps->footprint; // Size of postage stamps 629 773 … … 634 778 } 635 779 636 if (isnan(stamp->xNorm)) { 637 stamp->xNorm = 2.0 * (stamp->x - (float)numCols/2.0) / (float)numCols; 638 } 639 if (isnan(stamp->yNorm)) { 640 stamp->yNorm = 2.0 * (stamp->y - (float)numRows/2.0) / (float)numRows; 641 } 642 643 int x = stamp->x + 0.5, y = stamp->y + 0.5; // Stamp coordinates 644 if (x < size || x > numCols - size || y < size || y > numRows - size) { 645 psError(PS_ERR_UNKNOWN, false, "Stamp %d (%d,%d) is within the image border.\n", i, x, y); 780 p_pmSubtractionPolynomialNormCoords(&stamp->xNorm, &stamp->yNorm, stamp->x, stamp->y, 781 bounds.x0, bounds.x1, bounds.y0, bounds.y1); 782 783 int x = stamp->x - 0.5, y = stamp->y - 0.5; // Stamp coordinates 784 // fprintf (stderr, "stamp: %5.1f %5.1f == %d %d (size: %d)\n", stamp->x, stamp->y, x, y, size); 785 786 if (x < bounds.x0 + size || x > bounds.x1 - size || y < bounds.y0 + size || y > bounds.y1 - size) { 787 psError(PS_ERR_UNKNOWN, false, "Stamp %d (%d,%d) is within the region border.\n", i, x, y); 646 788 return false; 647 789 } … … 668 810 psImage *varSub = psImageSubset(variance, region); // Subimage with stamp 669 811 psKernel *var = psKernelAllocFromImage(varSub, size, size); // Variance postage stamp 670 if (isfinite(stamps->sysErr) && stamps->sysErr > 0) { 812 813 if ((isfinite(stamps->skyErr) && (stamps->skyErr > 0)) || 814 (isfinite(stamps->sysErr) && (stamps->sysErr > 0))) { 671 815 float sysErr = 0.25 * PS_SQR(stamps->sysErr); // Systematic error 816 float skyErr = stamps->skyErr; 672 817 psKernel *image1 = stamp->image1, *image2 = stamp->image2; // Input images 673 818 for (int y = -size; y <= size; y++) { 674 819 for (int x = -size; x <= size; x++) { 675 820 float additional = image1->kernel[y][x] + image2->kernel[y][x]; 676 weight->kernel[y][x] = 1.0 / ( var->kernel[y][x] + sysErr * PS_SQR(additional));821 weight->kernel[y][x] = 1.0 / (skyErr + var->kernel[y][x] + sysErr * PS_SQR(additional)); 677 822 } 678 823 } … … 698 843 pmSubtractionStampList *pmSubtractionStampsSetFromSources(const psArray *sources, const psImage *image, 699 844 const psImage *subMask, const psRegion *region, 700 int size, int footprint, float spacing, float sysErr, 845 int size, int footprint, float spacing, 846 float normFrac, float sysErr, float skyErr, 701 847 pmSubtractionMode mode) 702 848 { … … 722 868 y->data.F32[numOut] = source->peak->yf; 723 869 } 870 // fprintf (stderr, "stamp: %5.1f %5.1f\n", x->data.F32[numOut], y->data.F32[numOut]); 724 871 numOut++; 725 872 } … … 728 875 729 876 pmSubtractionStampList *stamps = pmSubtractionStampsSet(x, y, image, subMask, region, size, 730 footprint, spacing, sysErr, mode); // Stamps 877 footprint, spacing, normFrac, 878 sysErr, skyErr, mode); // Stamps 731 879 psFree(x); 732 880 psFree(y); … … 742 890 pmSubtractionStampList *pmSubtractionStampsSetFromFile(const char *filename, const psImage *image, 743 891 const psImage *subMask, const psRegion *region, 744 int size, int footprint, float spacing, float sysErr,745 pmSubtractionMode mode)892 int size, int footprint, float spacing, float normFrac, 893 float sysErr, float skyErr, pmSubtractionMode mode) 746 894 { 747 895 PS_ASSERT_STRING_NON_EMPTY(filename, NULL); … … 760 908 761 909 pmSubtractionStampList *stamps = pmSubtractionStampsSet(x, y, image, subMask, region, size, footprint, 762 spacing, sysErr, mode);910 spacing, normFrac, sysErr, skyErr, mode); 763 911 psFree(data); 764 912 … … 766 914 767 915 } 916 917 918 bool pmSubtractionStampsResetStatus (pmSubtractionStampList *stamps) { 919 920 for (int i = 0; i < stamps->num; i++) { 921 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 922 if (!stamp) continue; 923 if (stamp->status != PM_SUBTRACTION_STAMP_USED) continue; 924 stamp->status = PM_SUBTRACTION_STAMP_CALCULATE; 925 } 926 return true; 927 } 928 -
trunk/psModules/src/imcombine/pmSubtractionStamps.h
r26035 r26893 24 24 psArray *flux; ///< Fluxes for possible stamps (or NULL) 25 25 int footprint; ///< Half-size of stamps 26 psKernel *window; ///< window function generated from ensemble of stamps 27 float normFrac; ///< Fraction of flux in window for normalisation window 28 int normWindow; ///< Size of window for measuring normalisation 26 29 float sysErr; ///< Systematic error 30 float skyErr; ///< increase effective readnoise 27 31 } pmSubtractionStampList; 28 32 29 33 /// Allocate a list of stamps 30 pmSubtractionStampList *pmSubtractionStampListAlloc(int numCols, // Number of columns in image 31 int numRows, // Number of rows in image 32 const psRegion *region, // Region for stamps, or NULL 33 int footprint, // Half-size of stamps 34 float spacing, // Rough average spacing between stamps 35 float sysErr // Relative systematic error or NAN 34 pmSubtractionStampList *pmSubtractionStampListAlloc( 35 int numCols, // Number of columns in image 36 int numRows, // Number of rows in image 37 const psRegion *region, // Region for stamps, or NULL 38 int footprint, // Half-size of stamps 39 float spacing, // Rough average spacing between stamps 40 float normFrac, // Fraction of flux in window for normalisation window 41 float sysErr, // Relative systematic error or NAN 42 float skyErr // Relative systematic error or NAN 36 43 ); 37 44 … … 73 80 psArray *convolutions1; ///< Convolutions of image 1 for each kernel component, or NULL 74 81 psArray *convolutions2; ///< Convolutions of image 2 for each kernel component, or NULL 75 psImage *matrix 1, *matrix2; ///< Least-squares matrices for each image, or NULL76 ps Image *matrixX; ///< Cross-matrix (for mode DUAL), or NULL77 psVector *vector1, *vector2; ///< Least-squares vectors for each image, or NULL82 psImage *matrix; ///< Least-squares matrix, or NULL 83 psVector *vector; ///< Least-squares vector, or NULL 84 double norm; ///< Normalisation difference 78 85 pmSubtractionStampStatus status; ///< Status of stamp 79 86 } pmSubtractionStamp; … … 83 90 84 91 /// Find stamps on an image 85 pmSubtractionStampList *pmSubtractionStampsFind(pmSubtractionStampList *stamps, ///< Output stamps, or NULL 86 const psImage *image1, ///< Image for which to find stamps 87 const psImage *image2, ///< Image for which to find stamps 88 const psImage *mask, ///< Mask, or NULL 89 const psRegion *region, ///< Region to search, or NULL 90 float thresh1, ///< Threshold for stamps in image 1 91 float thresh2, ///< Threshold for stamps in image 2 92 int size, ///< Kernel half-size 93 int footprint, ///< Half-size for stamps 94 float spacing, ///< Rough spacing for stamps 95 float sysErr, ///< Relative systematic error in images 96 pmSubtractionMode mode ///< Mode for subtraction 92 pmSubtractionStampList *pmSubtractionStampsFind( 93 pmSubtractionStampList *stamps, ///< Output stamps, or NULL 94 const psImage *image1, ///< Image for which to find stamps 95 const psImage *image2, ///< Image for which to find stamps 96 const psImage *mask, ///< Mask, or NULL 97 const psRegion *region, ///< Region to search, or NULL 98 float thresh1, ///< Threshold for stamps in image 1 99 float thresh2, ///< Threshold for stamps in image 2 100 int size, ///< Kernel half-size 101 int footprint, ///< Half-size for stamps 102 float spacing, ///< Rough spacing for stamps 103 float normFrac, // Fraction of flux in window for normalisation window 104 float sysErr, ///< Relative systematic error in images 105 float skyErr, ///< Relative systematic error in images 106 pmSubtractionMode mode ///< Mode for subtraction 97 107 ); 98 108 99 109 /// Set stamps based on a list of x,y 100 pmSubtractionStampList *pmSubtractionStampsSet(const psVector *x, ///< x coordinates for each stamp 101 const psVector *y, ///< y coordinates for each stamp 102 const psImage *image, ///< Image for flux of stamp 103 const psImage *mask, ///< Mask, or NULL 104 const psRegion *region, ///< Region to search, or NULL 105 int size, ///< Kernel half-size 106 int footprint, ///< Half-size for stamps 107 float spacing, ///< Rough spacing for stamps 108 float sysErr, ///< Systematic error in images 109 pmSubtractionMode mode ///< Mode for subtraction 110 pmSubtractionStampList *pmSubtractionStampsSet( 111 const psVector *x, ///< x coordinates for each stamp 112 const psVector *y, ///< y coordinates for each stamp 113 const psImage *image, ///< Image for flux of stamp 114 const psImage *mask, ///< Mask, or NULL 115 const psRegion *region, ///< Region to search, or NULL 116 int size, ///< Kernel half-size 117 int footprint, ///< Half-size for stamps 118 float spacing, ///< Rough spacing for stamps 119 float normFrac, // Fraction of flux in window for normalisation window 120 float sysErr, ///< Systematic error in images 121 float skyErr, ///< Systematic error in images 122 pmSubtractionMode mode ///< Mode for subtraction 110 123 ); 111 124 … … 119 132 int footprint, ///< Half-size for stamps 120 133 float spacing, ///< Rough spacing for stamps 134 float normFrac, // Fraction of flux in window for normalisation window 121 135 float sysErr, ///< Systematic error in images 136 float skyErr, ///< Systematic error in images 122 137 pmSubtractionMode mode ///< Mode for subtraction 123 138 ); … … 132 147 int footprint, ///< Half-size for stamps 133 148 float spacing, ///< Rough spacing for stamps 149 float normFrac, // Fraction of flux in window for normalisation window 134 150 float sysErr, ///< Systematic error in images 151 float skyErr, ///< Systematic error in images 135 152 pmSubtractionMode mode ///< Mode for subtraction 153 ); 154 155 /// Calculate the window and normalisation window from the stamps 156 bool pmSubtractionStampsGetWindow( 157 pmSubtractionStampList *stamps, ///< List of stamps 158 int kernelSize ///< Half-size of kernel 136 159 ); 137 160 … … 141 164 psImage *image2, ///< Input image (or NULL) 142 165 psImage *variance, ///< Variance map 143 int kernelSize ///< Kernel half-size 166 int kernelSize, ///< Kernel half-size 167 psRegion bounds ///< Bounds of validity 144 168 ); 145 169 … … 168 192 ); 169 193 194 195 bool pmSubtractionStampsResetStatus (pmSubtractionStampList *stamps); 196 170 197 #endif -
trunk/psModules/src/imcombine/pmSubtractionThreads.c
r21363 r26893 69 69 70 70 { 71 psThreadTask *task = psThreadTaskAlloc("PSMODULES_SUBTRACTION_CALCULATE_EQUATION", 3);71 psThreadTask *task = psThreadTaskAlloc("PSMODULES_SUBTRACTION_CALCULATE_EQUATION", 4); 72 72 task->function = &pmSubtractionCalculateEquationThread; 73 73 psThreadTaskAdd(task); -
trunk/psModules/src/imcombine/pmSubtractionVisual.c
r23487 r26893 16 16 17 17 #include "pmKapaPlots.h" 18 #include "pmSubtraction.h" 18 19 #include "pmSubtractionStamps.h" 20 #include "pmSubtractionEquation.h" 19 21 20 22 #include "pmVisual.h" … … 32 34 static bool plotLeastSquares = true; 33 35 static bool plotImage = true; 36 34 37 // variables to store plotting window indices 35 static int kapa = -1;38 static int kapa1 = -1; 36 39 static int kapa2 = -1; 40 static int kapa3 = -1; 37 41 38 42 /** function prototypes*/ … … 46 50 bool pmSubtractionVisualClose(void) 47 51 { 48 if(kapa != -1) 49 KiiClose(kapa); 50 if(kapa2 != -1) 51 KiiClose(kapa2); 52 if(kapa1 != -1) KiiClose(kapa1); 53 if(kapa2 != -1) KiiClose(kapa2); 52 54 return true; 53 55 } … … 60 62 bool pmSubtractionVisualPlotConvKernels(psImage *convKernels) { 61 63 if (!pmVisualIsVisual() || !plotConvKernels) return true; 62 if (!pmVisualInitWindow(&kapa , "ppSub:Images")) {63 return false; 64 } 65 pmVisualScaleImage(kapa , convKernels, "Convolution_Kernels", 0, true);64 if (!pmVisualInitWindow(&kapa1, "ppSub:Images")) { 65 return false; 66 } 67 pmVisualScaleImage(kapa1, convKernels, "Convolution_Kernels", 0, true); 66 68 pmVisualAskUser(&plotConvKernels); 67 69 return true; … … 74 76 bool pmSubtractionVisualPlotStamps(pmSubtractionStampList *stamps, pmReadout *ro) { 75 77 if (!pmVisualIsVisual() || !plotStamps) return true; 76 if (!pmVisualInitWindow (&kapa , "ppSub:Images")) {78 if (!pmVisualInitWindow (&kapa1, "ppSub:Images")) { 77 79 return false; 78 80 } … … 134 136 stampNum++; 135 137 } 136 pmVisualScaleImage(kapa , canvas, "Subtraction_Stamps", 0, true);138 pmVisualScaleImage(kapa1, canvas, "Subtraction_Stamps", 0, true); 137 139 138 140 pmVisualAskUser(&plotStamps); … … 144 146 145 147 if (!pmVisualIsVisual() || !plotLeastSquares) return true; 146 if (!pmVisualInitWindow (&kapa , "PPSub:Images")) {148 if (!pmVisualInitWindow (&kapa1, "PPSub:Images")) { 147 149 return false; 148 150 } … … 157 159 if (stamp == NULL) continue; 158 160 159 psImage *im = stamp->matrix1; 160 if (im == NULL) im = stamp->matrix2; 161 if (im == NULL) im = stamp->matrixX; 161 psImage *im = stamp->matrix; 162 162 if (im == NULL) continue; 163 163 … … 187 187 if (stamp == NULL) continue; 188 188 189 psImage *im = stamp->matrix1; 190 if (im == NULL) im = stamp->matrix2; 191 if (im == NULL) im = stamp->matrixX; 189 psImage *im = stamp->matrix; 192 190 if (im == NULL) continue; 193 191 … … 197 195 198 196 psImage *canvas32 = pmVisualImageToFloat(canvas); 199 pmVisualScaleImage(kapa , canvas32, "Least_Squares", 0, true);197 pmVisualScaleImage(kapa1, canvas32, "Least_Squares", 0, true); 200 198 201 199 pmVisualAskUser(&plotLeastSquares); … … 207 205 bool pmSubtractionVisualShowSubtraction(psImage *image, psImage *ref, psImage *sub) { 208 206 if (!pmVisualIsVisual() || !plotImage) return true; 209 if (!pmVisualInitWindow (&kapa, "PPSub:Images")) { 210 return false; 211 } 212 213 pmVisualScaleImage(kapa, image, "Image", 0, true); 214 pmVisualScaleImage(kapa, ref, "Reference", 1, true); 215 pmVisualScaleImage(kapa, sub, "Subtraction", 2, true); 207 if (!pmVisualInitWindow (&kapa1, "PPSub:Images")) { 208 return false; 209 } 210 211 pmVisualScaleImage(kapa1, image, "Image", 0, true); 212 pmVisualScaleImage(kapa1, ref, "Reference", 1, true); 213 pmVisualScaleImage(kapa1, sub, "Subtraction", 2, true); 214 pmVisualAskUser(&plotImage); 215 return true; 216 } 217 218 bool pmSubtractionVisualShowKernels(pmSubtractionKernels *kernels) { 219 220 if (!pmVisualIsVisual()) return true; 221 if (!pmVisualInitWindow (&kapa1, "PPSub:Images")) { 222 return false; 223 } 224 225 // get the kernel sizes 226 int footprint = kernels->size; 227 228 // output image is a grid of NXsub by NYsub sub-images 229 int NXsub = sqrt(kernels->num); 230 int NYsub = kernels->num / NXsub; 231 if (kernels->num % NXsub) NYsub++; 232 233 int NXpix = NXsub * (2*footprint + 1 + 3); 234 int NYpix = NYsub * (2*footprint + 1 + 3); 235 236 psImage *output = psImageAlloc(NXpix, NYpix, PS_TYPE_F32); 237 psImageInit (output, 0.0); 238 239 for (int i = 0; i < kernels->num; i++) { 240 pmSubtractionKernelPreCalc *preCalc = kernels->preCalc->data[i]; 241 psKernel *kernel = preCalc->kernel; 242 243 int xSub = i % NXsub; 244 int ySub = i / NXsub; 245 246 int xPix = xSub * (2*footprint + 1 + 3) + footprint; 247 int yPix = ySub * (2*footprint + 1 + 3) + footprint; 248 249 double sum = 0.0; 250 for (int y = -footprint; y <= footprint; y++) { 251 for (int x = -footprint; x <= footprint; x++) { 252 output->data.F32[y + yPix][x + xPix] = kernel->kernel[y][x]; 253 sum += kernel->kernel[y][x]; 254 } 255 } 256 fprintf (stderr, "kernel %d, sum %f\n", i, sum); 257 } 258 259 pmVisualScaleImage(kapa1, output, "Image", 0, true); 260 pmVisualAskUser(&plotImage); 261 return true; 262 } 263 264 bool pmSubtractionVisualShowBasis(pmSubtractionStampList *stamps) { 265 266 if (!pmVisualIsVisual()) return true; 267 if (!pmVisualInitWindow (&kapa2, "ppSub:StampMasterImage")) { 268 return false; 269 } 270 271 // get the kernel sizes 272 int footprint = stamps->footprint; 273 274 // choose the brightest stamp 275 pmSubtractionStamp *maxStamp = NULL; 276 float maxFlux = NAN; 277 for (int i = 0; i < stamps->num; i++) { 278 pmSubtractionStamp *stamp = stamps->stamps->data[i]; 279 if (!isfinite(stamp->flux)) continue; 280 if (!stamp->convolutions1 && !stamp->convolutions2) continue; 281 if (!maxStamp) { 282 maxFlux = stamp->flux; 283 maxStamp = stamp; 284 continue; 285 } 286 if (stamp->flux > maxFlux) { 287 maxFlux = stamp->flux; 288 maxStamp = stamp; 289 } 290 } 291 292 if (!isfinite(maxStamp->flux)) { 293 fprintf (stderr, "no valid stamps?\n"); 294 } 295 296 int nKernels = 0; 297 298 if (maxStamp->convolutions1) { 299 // output image is a grid of NXsub by NYsub sub-images 300 nKernels = maxStamp->convolutions1->n; 301 int NXsub = sqrt(nKernels); 302 int NYsub = nKernels / NXsub; 303 if (nKernels % NXsub) NYsub++; 304 305 int NXpix = NXsub * (2*footprint + 1 + 3); 306 int NYpix = NYsub * (2*footprint + 1 + 3); 307 308 psImage *output = psImageAlloc(NXpix, NYpix, PS_TYPE_F32); 309 psImageInit (output, 0.0); 310 311 for (int i = 0; i < nKernels; i++) { 312 psKernel *kernel = maxStamp->convolutions1->data[i]; 313 314 int xSub = i % NXsub; 315 int ySub = i / NXsub; 316 317 int xPix = xSub * (2*footprint + 1 + 3) + footprint; 318 int yPix = ySub * (2*footprint + 1 + 3) + footprint; 319 320 double sum = 0.0; 321 for (int y = -footprint; y <= footprint; y++) { 322 for (int x = -footprint; x <= footprint; x++) { 323 output->data.F32[y + yPix][x + xPix] = kernel->kernel[y][x]; 324 sum += kernel->kernel[y][x]; 325 } 326 } 327 fprintf (stderr, "kernel %d, sum %f\n", i, sum); 328 } 329 pmVisualScaleImage(kapa2, output, "Image", 0, true); 330 } 331 332 if (maxStamp->convolutions2) { 333 // output image is a grid of NXsub by NYsub sub-images 334 nKernels = maxStamp->convolutions2->n; 335 int NXsub = sqrt(nKernels); 336 int NYsub = nKernels / NXsub; 337 if (nKernels % NXsub) NYsub++; 338 339 int NXpix = NXsub * (2*footprint + 1 + 3); 340 int NYpix = NYsub * (2*footprint + 1 + 3); 341 342 psImage *output = psImageAlloc(NXpix, NYpix, PS_TYPE_F32); 343 psImageInit (output, 0.0); 344 345 for (int i = 0; i < nKernels; i++) { 346 psKernel *kernel = maxStamp->convolutions2->data[i]; 347 348 int xSub = i % NXsub; 349 int ySub = i / NXsub; 350 351 int xPix = xSub * (2*footprint + 1 + 3) + footprint; 352 int yPix = ySub * (2*footprint + 1 + 3) + footprint; 353 354 double sum = 0.0; 355 for (int y = -footprint; y <= footprint; y++) { 356 for (int x = -footprint; x <= footprint; x++) { 357 output->data.F32[y + yPix][x + xPix] = kernel->kernel[y][x]; 358 sum += kernel->kernel[y][x]; 359 } 360 } 361 fprintf (stderr, "kernel %d, sum %f\n", i, sum); 362 } 363 pmVisualScaleImage(kapa2, output, "Image", 1, true); 364 } 365 216 366 pmVisualAskUser(&plotImage); 217 367 return true; … … 240 390 241 391 overlay[Noverlay].type = KII_OVERLAY_BOX; 392 if ((stamp->x < 1.0) && (stamp->y < 1.0)) { 393 // fprintf (stderr, "stamp zero: %f %f\n", stamp->x, stamp->y); 394 continue; 395 } 396 if (!isfinite(stamp->x) && !isfinite(stamp->y)) { 397 // fprintf (stderr, "stamp nan: %f %f\n", stamp->x, stamp->y); 398 continue; 399 } 242 400 overlay[Noverlay].x = stamp->x; 243 401 overlay[Noverlay].y = stamp->y; … … 255 413 } 256 414 415 static int footprint = 0; 416 static int NX = 0; 417 static int NY = 0; 418 static psImage *sourceImage = NULL; 419 static psImage *targetImage = NULL; 420 static psImage *residualImage = NULL; 421 static psImage *fresidualImage = NULL; 422 static psImage *differenceImage = NULL; 423 static psImage *convolutionImage = NULL; 424 425 bool pmSubtractionVisualShowFitInit(pmSubtractionStampList *stamps) { 426 427 if (!pmVisualIsVisual()) return true; 428 429 // generate 4 storage images large enough to hold the N stamps: 430 431 footprint = stamps->footprint; 432 433 float NXf = sqrt(stamps->num); 434 NX = (int) NXf == NXf ? NXf : NXf + 1.0; 435 436 float NYf = stamps->num / NX; 437 NY = (int) NYf == NY ? NYf : NYf + 1.0; 438 439 int NXpix = (2*footprint + 1) * NX; 440 NXpix += (NX > 1) ? 3 * NX : 0; 441 442 int NYpix = (2*footprint + 1) * NY; 443 NYpix += (NY > 1) ? 3 * NY : 0; 444 445 sourceImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 446 targetImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 447 residualImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 448 fresidualImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 449 differenceImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 450 convolutionImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 451 452 psImageInit (sourceImage, 0.0); 453 psImageInit (targetImage, 0.0); 454 psImageInit (residualImage, 0.0); 455 psImageInit (fresidualImage, 0.0); 456 psImageInit (differenceImage, 0.0); 457 psImageInit (convolutionImage, 0.0); 458 459 return true; 460 } 461 462 bool pmSubtractionVisualShowFitAddStamp(psKernel *target, psKernel *source, psKernel *convolution, double background, double norm, int index) { 463 464 if (!pmVisualIsVisual()) return true; 465 466 double sum; 467 468 int NXoff = index % NX; 469 int NYoff = index / NX; 470 471 int NXpix = NXoff * (2*footprint + 1 + 3) + footprint; 472 int NYpix = NYoff * (2*footprint + 1 + 3) + footprint; 473 474 // insert the (target) kernel into the (target) image: 475 sum = 0.0; 476 for (int y = -footprint; y <= footprint; y++) { 477 for (int x = -footprint; x <= footprint; x++) { 478 targetImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x]; 479 sum += targetImage->data.F32[y + NYpix][x + NXpix]; 480 } 481 } 482 targetImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 483 484 // insert the (source) kernel into the (source) image: 485 sum = 0.0; 486 for (int y = -footprint; y <= footprint; y++) { 487 for (int x = -footprint; x <= footprint; x++) { 488 sourceImage->data.F32[y + NYpix][x + NXpix] = source->kernel[y][x]; 489 sum += sourceImage->data.F32[y + NYpix][x + NXpix]; 490 } 491 } 492 sourceImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 493 494 // insert the (convolution) kernel into the (convolution) image: 495 sum = 0.0; 496 for (int y = -footprint; y <= footprint; y++) { 497 for (int x = -footprint; x <= footprint; x++) { 498 convolutionImage->data.F32[y + NYpix][x + NXpix] = -convolution->kernel[y][x]; 499 sum += convolutionImage->data.F32[y + NYpix][x + NXpix]; 500 } 501 } 502 convolutionImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 503 504 // insert the (difference) kernel into the (difference) image: 505 sum = 0.0; 506 for (int y = -footprint; y <= footprint; y++) { 507 for (int x = -footprint; x <= footprint; x++) { 508 differenceImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x] - background - source->kernel[y][x] * norm; 509 sum += differenceImage->data.F32[y + NYpix][x + NXpix]; 510 } 511 } 512 differenceImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 513 514 // insert the (residual) kernel into the (residual) image: 515 sum = 0.0; 516 for (int y = -footprint; y <= footprint; y++) { 517 for (int x = -footprint; x <= footprint; x++) { 518 residualImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x] - background - source->kernel[y][x] * norm - convolution->kernel[y][x]; 519 sum += residualImage->data.F32[y + NYpix][x + NXpix]; 520 } 521 } 522 residualImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 523 524 // insert the (fresidual) kernel into the (fresidual) image: 525 for (int y = -footprint; y <= footprint; y++) { 526 for (int x = -footprint; x <= footprint; x++) { 527 fresidualImage->data.F32[y + NYpix][x + NXpix] = residualImage->data.F32[y + NYpix][x + NXpix] / sqrt(PS_MAX(target->kernel[y][x], 100.0)); 528 } 529 } 530 return true; 531 } 532 533 bool pmSubtractionVisualShowFit(double norm) { 534 535 // for testing, dump the residual image and exit 536 if (0) { 537 psMetadata *header = psMetadataAlloc(); 538 psMetadataAddF32 (header, PS_LIST_TAIL, "NORM", 0, "Normalization", norm); 539 psFits *fits = psFitsOpen("resid.fits", "w"); 540 psFitsWriteImage(fits, header, residualImage, 0, NULL); 541 psFitsClose(fits); 542 // exit (0); 543 } 544 545 if (!pmVisualIsVisual()) return true; 546 if (!pmVisualInitWindow(&kapa1, "ppSub:Images")) return false; 547 if (!pmVisualInitWindow(&kapa2, "ppSub:Misc")) return false; 548 549 KiiEraseOverlay (kapa1, "red"); 550 KiiEraseOverlay (kapa2, "red"); 551 552 pmVisualScaleImage(kapa1, targetImage, "Target Stamps", 0, true); 553 pmVisualScaleImage(kapa1, sourceImage, "Source Stamps", 1, true); 554 pmVisualScaleImage(kapa1, convolutionImage, "Convolution Stamps", 2, true); 555 KiiCenter (kapa1, 0.5*targetImage->numCols, 0.5*targetImage->numRows, 1); 556 557 pmVisualScaleImage(kapa2, fresidualImage, "Frac Residual Stamps", 2, true); 558 pmVisualScaleImage(kapa2, differenceImage, "Difference Stamps", 0, true); 559 560 if (1) { 561 KiiImage image; 562 KapaImageData data; 563 Coords coords; 564 strcpy (coords.ctype, "RA---TAN"); 565 566 image.data2d = residualImage->data.F32; 567 image.Nx = residualImage->numCols; 568 image.Ny = residualImage->numRows; 569 strcpy (data.name, "Residual Stamps"); 570 strcpy (data.file, "Residual Stamps"); 571 572 data.zero = -300.0; 573 data.range = +600.0; 574 data.logflux = 0; 575 576 KiiSetChannel (kapa2, 1); 577 KiiNewPicture2D (kapa2, &image, &data, &coords); 578 } else { 579 pmVisualScaleImage(kapa2, residualImage, "Residual Stamps", 1, true); 580 } 581 582 KiiCenter (kapa2, 0.5*residualImage->numCols, 0.5*residualImage->numRows, 1); 583 584 pmVisualAskUser(NULL); 585 586 psFree(targetImage); 587 psFree(sourceImage); 588 psFree(convolutionImage); 589 psFree(differenceImage); 590 psFree(residualImage); 591 psFree(fresidualImage); 592 593 targetImage = NULL; 594 sourceImage = NULL; 595 convolutionImage = NULL; 596 differenceImage = NULL; 597 residualImage = NULL; 598 fresidualImage = NULL; 599 600 return true; 601 } 602 603 bool pmSubtractionVisualPlotFit(const pmSubtractionKernels *kernels) { 604 605 Graphdata graphdata; 606 607 if (!pmVisualIsVisual()) return true; 608 if (!pmVisualInitWindow(&kapa3, "ppSub:plots")) return false; 609 610 KapaClearSections (kapa3); 611 KapaInitGraph (&graphdata); 612 613 psVector *x = psVectorAllocEmpty (kernels->num, PS_TYPE_F32); 614 psVector *y = psVectorAllocEmpty (kernels->num, PS_TYPE_F32); 615 616 graphdata.xmin = -1.0; 617 graphdata.xmax = kernels->num + 1.0; 618 graphdata.ymin = +32.0; 619 graphdata.ymax = -32.0; 620 621 psImage *polyValues = p_pmSubtractionPolynomial(NULL, kernels->spatialOrder, 0.0, 0.0); 622 623 // construct the plot vectors 624 for (int i = 0; i < kernels->num; i++) { 625 x->data.F32[i] = i; 626 y->data.F32[i] = p_pmSubtractionSolutionCoeff(kernels, polyValues, i, false); 627 graphdata.ymin = PS_MIN(graphdata.ymin, y->data.F32[i]); 628 graphdata.ymax = PS_MAX(graphdata.ymax, y->data.F32[i]); 629 } 630 x->n = y->n = kernels->num; 631 632 float range; 633 range = graphdata.xmax - graphdata.xmin; 634 graphdata.xmax += 0.05*range; 635 graphdata.xmin -= 0.05*range; 636 range = graphdata.ymax - graphdata.ymin; 637 graphdata.ymax += 0.05*range; 638 graphdata.ymin -= 0.05*range; 639 640 KapaSetLimits (kapa3, &graphdata); 641 642 KapaSetFont (kapa3, "helvetica", 14); 643 KapaBox (kapa3, &graphdata); 644 KapaSendLabel (kapa3, "kernel number", KAPA_LABEL_XM); 645 KapaSendLabel (kapa3, "coeff", KAPA_LABEL_YM); 646 647 graphdata.color = KapaColorByName ("black"); 648 graphdata.ptype = 2; 649 graphdata.size = 0.5; 650 graphdata.style = 2; 651 652 KapaPrepPlot (kapa3, x->n, &graphdata); 653 KapaPlotVector (kapa3, x->n, x->data.F32, "x"); 654 KapaPlotVector (kapa3, x->n, y->data.F32, "y"); 655 656 psFree (x); 657 psFree (y); 658 659 pmVisualAskUser(NULL); 660 return true; 661 } 662 257 663 #else 258 664 bool pmSubtractionVisualClose(void) {return true;} … … 261 667 bool pmSubtractionVisualPlotLeastSquares(pmSubtractionStampList *stamps) {return true;} 262 668 bool pmSubtractionVisualShowSubtraction(psImage *image, psImage *ref, psImage *sub) {return true;} 669 bool pmSubtractionVisualShowFitInit(pmSubtractionStampList *stamps) {return true;} 670 bool pmSubtractionVisualShowFitAddStamp(psKernel *target, psKernel *source, psKernel *convolution, double background, double norm, int index) {return true;} 671 bool pmSubtractionVisualShowFit() {return true;} 672 bool pmSubtractionVisualPlotFit(const pmSubtractionKernels *kernels); 263 673 #endif -
trunk/psModules/src/imcombine/pmSubtractionVisual.h
r23487 r26893 7 7 bool pmSubtractionVisualPlotLeastSquares(pmSubtractionStampList *stamps); 8 8 bool pmSubtractionVisualShowSubtraction(psImage *image, psImage *ref, psImage *sub); 9 bool pmSubtractionVisualShowFitInit(pmSubtractionStampList *stamps); 10 bool pmSubtractionVisualShowFitAddStamp(psKernel *target, psKernel *source, psKernel *convolution, double background, double norm, int index); 11 bool pmSubtractionVisualShowFit(double norm); 12 bool pmSubtractionVisualPlotFit(const pmSubtractionKernels *kernels); 13 bool pmSubtractionVisualShowKernels(pmSubtractionKernels *kernels); 14 bool pmSubtractionVisualShowBasis(pmSubtractionStampList *stamps); 9 15 10 16 #endif -
trunk/psModules/src/objects/pmDetections.c
r23487 r26893 26 26 psFree (detections->peaks); 27 27 psFree (detections->oldPeaks); 28 psFree (detections->oldFootprints); 29 30 psFree (detections->newSources); 31 psFree (detections->allSources); 28 32 return; 29 33 } … … 35 39 psMemSetDeallocator(detections, (psFreeFunc) pmDetectionsFree); 36 40 37 detections->footprints = NULL; 38 detections->peaks = NULL; 39 detections->oldPeaks = NULL; 40 detections->last = 0; 41 detections->footprints = NULL; 42 detections->peaks = NULL; 43 detections->oldPeaks = NULL; 44 detections->oldFootprints = NULL; 45 detections->newSources = NULL; 46 detections->allSources = NULL; 47 detections->last = 0; 41 48 42 49 return (detections); -
trunk/psModules/src/objects/pmDetections.h
r23487 r26893 21 21 typedef struct { 22 22 psArray *footprints; // collection of footprints in the image 23 psArray *oldFootprints; // collection of footprints previously found 23 24 psArray *peaks; // collection of all peaks contained by the footprints 24 25 psArray *oldPeaks; // collection of all peaks previously found 26 psArray *newSources; // collection of sources 27 psArray *allSources; // collection of sources 25 28 int last; 26 29 } pmDetections; -
trunk/psModules/src/objects/pmFootprintCullPeaks.c
r24888 r26893 29 29 */ 30 30 31 # define IN_PEAK 1 31 # define IN_PEAK 1 32 32 psErrorCode pmFootprintCullPeaks(const psImage *img, // the image wherein lives the footprint 33 const psImage *weight,// corresponding variance image34 pmFootprint *fp, // Footprint containing mortal peaks35 const float nsigma_delta, // how many sigma above local background a peak needs to be to survive36 const float fPadding, // fractional padding added to stdev since bright peaks have unreasonably high significance37 const float min_threshold) { // minimum permitted coll height33 const psImage *weight, // corresponding variance image 34 pmFootprint *fp, // Footprint containing mortal peaks 35 const float nsigma_delta, // how many sigma above local background a peak needs to be to survive 36 const float fPadding, // fractional padding added to stdev since bright peaks have unreasonably high significance 37 const float min_threshold) { // minimum permitted coll height 38 38 assert (img != NULL); assert (img->type.type == PS_TYPE_F32); 39 39 assert (weight != NULL); assert (weight->type.type == PS_TYPE_F32); … … 42 42 43 43 if (fp->peaks == NULL || fp->peaks->n == 0) { // nothing to do 44 return PS_ERR_NONE;45 } 46 47 psRegion subRegion; // desired subregion; 1 larger than bounding box (grr)44 return PS_ERR_NONE; 45 } 46 47 psRegion subRegion; // desired subregion; 1 larger than bounding box (grr) 48 48 subRegion.x0 = fp->bbox.x0; subRegion.x1 = fp->bbox.x1 + 1; 49 49 subRegion.y0 = fp->bbox.y0; subRegion.y1 = fp->bbox.y1 + 1; … … 55 55 psImage *idImg = psImageAlloc(subImg->numCols, subImg->numRows, PS_TYPE_S32); 56 56 57 // We need a psArray of peaks brighter than the current peak. 57 // We need a psArray of peaks brighter than the current peak. 58 58 // We reject peaks which either: 59 59 // 1) are below the local threshold … … 67 67 // The brightest peak is always safe; go through other peaks trying to cull them 68 68 for (int i = 1; i < fp->peaks->n; i++) { // n.b. fp->peaks->n can change within the loop 69 const pmPeak *peak = fp->peaks->data[i]; 70 int x = peak->x - subImg->col0; 71 int y = peak->y - subImg->row0; 72 // 73 // Find the level nsigma below the peak that must separate the peak 74 // from any of its friends 75 // 76 assert (x >= 0 && x < subImg->numCols && y >= 0 && y < subImg->numRows); 77 78 // const float stdev = sqrt(subWt->data.F32[y][x]); 79 // float threshold = subImg->data.F32[y][x] - nsigma_delta*stdev; 80 81 const float stdev = sqrt(subWt->data.F32[y][x]); 82 const float flux = subImg->data.F32[y][x]; 83 const float fStdev = fabs(stdev/flux); 84 const float stdev_pad = fabs(flux * hypot(fStdev, fPadding)); 85 // if flux is negative, careful with fStdev 86 87 float threshold = flux - nsigma_delta*stdev_pad; 88 89 if (isnan(threshold) || threshold < min_threshold) { 90 // min_threshold is assumed to be below the detection threshold, 91 // so all the peaks are pmFootprint, and this isn't the brightest 69 const pmPeak *peak = fp->peaks->data[i]; 70 int x = peak->x - subImg->col0; 71 int y = peak->y - subImg->row0; 72 // 73 // Find the level nsigma below the peak that must separate the peak 74 // from any of its friends 75 // 76 assert (x >= 0 && x < subImg->numCols && y >= 0 && y < subImg->numRows); 77 78 // const float stdev = sqrt(subWt->data.F32[y][x]); 79 // float threshold = subImg->data.F32[y][x] - nsigma_delta*stdev; 80 81 const float stdev = sqrt(subWt->data.F32[y][x]); 82 const float flux = subImg->data.F32[y][x]; 83 const float fStdev = fabs(stdev/flux); 84 const float stdev_pad = fabs(flux * hypot(fStdev, fPadding)); 85 // if flux is negative, careful with fStdev 86 87 float threshold = flux - nsigma_delta*stdev_pad; 88 89 if (isnan(threshold) || threshold < min_threshold) { 90 // min_threshold is assumed to be below the detection threshold, 91 // so all the peaks are pmFootprint, and this isn't the brightest 92 continue; 93 } 94 95 // XXX EAM : if stdev >= 0, i'm not sure how this can ever be true? 96 if (threshold > subImg->data.F32[y][x]) { 97 threshold = subImg->data.F32[y][x] - 10*FLT_EPSILON; 98 } 99 100 // XXX this is a bit expensive: psImageAlloc for every peak contained in this footprint 101 // perhaps this should alloc a single ID image above and pass it in to be set. 102 103 // XXX optionally use the faster pmFootprintsFind if the subimage size is large (eg, M31) 104 105 // XXX this is not quite there yet: 106 // pmFootprint *peakFootprint = NULL; 107 // int area = subImg->numCols * subImg->numRows; 108 // if (area > 30000) { 109 110 pmFootprint *peakFootprint = pmFootprintsFindAtPoint(subImg, threshold, brightPeaks, peak->y, peak->x); 111 112 // at this point brightPeaks only has the peaks brighter than the current 113 114 // XXX need to supply the image here 115 // we set the IDs to either 1 (in peak) or 0 (not in peak) 116 pmSetFootprintID (idImg, peakFootprint, IN_PEAK); 117 psFree(peakFootprint); 118 119 // If this peak has not already been assigned to a source, then we can look for any 120 // brighter peaks within its footprint. Check if any of the previous (brighter) peaks 121 // are within the footprint of this peak If so, the current peak is bogus; drop it. 122 bool keep = true; 123 for (int j = 0; keep && !peak->assigned && (j < brightPeaks->n); j++) { 124 const pmPeak *peak2 = fp->peaks->data[j]; 125 int x2 = peak2->x - subImg->col0; 126 int y2 = peak2->y - subImg->row0; 127 if (idImg->data.S32[y2][x2] == IN_PEAK) { 128 // There's a brighter peak within the footprint above threshold; so cull our initial peak 129 keep = false; 130 } 131 } 132 if (!keep) { 133 psAssert (!peak->assigned, "logic error: trying to drop a previously-assigned peak"); // we should not drop any already assigned peaks. 92 134 continue; 93 135 } 94 136 95 // XXX EAM : if stdev >= 0, i'm not sure how this can ever be true? 96 if (threshold > subImg->data.F32[y][x]) { 97 threshold = subImg->data.F32[y][x] - 10*FLT_EPSILON; 98 } 99 100 // XXX this is a bit expensive: psImageAlloc for every peak contained in this footprint 101 // perhaps this should alloc a single ID image above and pass it in to be set. 102 103 // XXX optionally use the faster pmFootprintsFind if the subimage size is large (eg, M31) 104 105 // XXX this is not quite there yet: 106 // pmFootprint *peakFootprint = NULL; 107 // int area = subImg->numCols * subImg->numRows; 108 // if (area > 30000) { 109 110 pmFootprint *peakFootprint = pmFootprintsFindAtPoint(subImg, threshold, brightPeaks, peak->y, peak->x); 111 112 // at this point brightPeaks only has the peaks brighter than the current 113 114 // XXX need to supply the image here 115 // we set the IDs to either 1 (in peak) or 0 (not in peak) 116 pmSetFootprintID (idImg, peakFootprint, IN_PEAK); 117 psFree(peakFootprint); 118 119 // Check if any of the previous (brighter) peaks are within the footprint of this peak 120 // If so, the current peak is bogus; drop it. 121 bool keep = true; 122 for (int j = 0; keep && (j < brightPeaks->n); j++) { 123 const pmPeak *peak2 = fp->peaks->data[j]; 124 int x2 = peak2->x - subImg->col0; 125 int y2 = peak2->y - subImg->row0; 126 if (idImg->data.S32[y2][x2] == IN_PEAK) 127 // There's a brighter peak within the footprint above threshold; so cull our initial peak 128 keep = false; 129 } 130 if (!keep) continue; 131 132 psArrayAdd (brightPeaks, 128, fp->peaks->data[i]); 137 psArrayAdd (brightPeaks, 128, fp->peaks->data[i]); 133 138 } 134 139 … … 151 156 */ 152 157 psErrorCode pmFootprintCullPeaks_OLD(const psImage *img, // the image wherein lives the footprint 153 const psImage *weight,// corresponding variance image154 pmFootprint *fp, // Footprint containing mortal peaks155 const float nsigma_delta, // how many sigma above local background a peak needs to be to survive156 const float fPadding, // fractional padding added to stdev since bright peaks have unreasonably high significance157 const float min_threshold) { // minimum permitted coll height158 const psImage *weight, // corresponding variance image 159 pmFootprint *fp, // Footprint containing mortal peaks 160 const float nsigma_delta, // how many sigma above local background a peak needs to be to survive 161 const float fPadding, // fractional padding added to stdev since bright peaks have unreasonably high significance 162 const float min_threshold) { // minimum permitted coll height 158 163 assert (img != NULL); assert (img->type.type == PS_TYPE_F32); 159 164 assert (weight != NULL); assert (weight->type.type == PS_TYPE_F32); … … 162 167 163 168 if (fp->peaks == NULL || fp->peaks->n == 0) { // nothing to do 164 return PS_ERR_NONE;165 } 166 167 psRegion subRegion; // desired subregion; 1 larger than bounding box (grr)169 return PS_ERR_NONE; 170 } 171 172 psRegion subRegion; // desired subregion; 1 larger than bounding box (grr) 168 173 subRegion.x0 = fp->bbox.x0; subRegion.x1 = fp->bbox.x1 + 1; 169 174 subRegion.y0 = fp->bbox.y0; subRegion.y1 = fp->bbox.y1 + 1; … … 185 190 // 186 191 for (int i = 1; i < fp->peaks->n; i++) { // n.b. fp->peaks->n can change within the loop 187 const pmPeak *peak = fp->peaks->data[i];188 int x = peak->x - subImg->col0;189 int y = peak->y - subImg->row0;190 //191 // Find the level nsigma below the peak that must separate the peak192 // from any of its friends193 //194 assert (x >= 0 && x < subImg->numCols && y >= 0 && y < subImg->numRows);195 196 // stdev ~ sqrt(flux) : for bright regions (f ~ 1e6, sqrt(f) = 1e3 -- unrealistically small deviations)197 // add additional padding in quadrature:198 199 const float stdev = sqrt(subWt->data.F32[y][x]);200 const float flux = subImg->data.F32[y][x];201 const float fStdev = stdev/flux;202 const float stdev_pad = flux * hypot(fStdev, fPadding);203 float threshold = flux - nsigma_delta*stdev_pad;204 205 if (isnan(threshold) || threshold < min_threshold) {206 #if 1 // min_threshold is assumed to be below the detection threshold,207 // so all the peaks are pmFootprint, and this isn't the brightest208 // XXX mark peak to be dropped209 (void)psArrayRemoveIndex(fp->peaks, i);210 i--;// we moved everything down one211 continue;192 const pmPeak *peak = fp->peaks->data[i]; 193 int x = peak->x - subImg->col0; 194 int y = peak->y - subImg->row0; 195 // 196 // Find the level nsigma below the peak that must separate the peak 197 // from any of its friends 198 // 199 assert (x >= 0 && x < subImg->numCols && y >= 0 && y < subImg->numRows); 200 201 // stdev ~ sqrt(flux) : for bright regions (f ~ 1e6, sqrt(f) = 1e3 -- unrealistically small deviations) 202 // add additional padding in quadrature: 203 204 const float stdev = sqrt(subWt->data.F32[y][x]); 205 const float flux = subImg->data.F32[y][x]; 206 const float fStdev = stdev/flux; 207 const float stdev_pad = flux * hypot(fStdev, fPadding); 208 float threshold = flux - nsigma_delta*stdev_pad; 209 210 if (isnan(threshold) || threshold < min_threshold) { 211 #if 1 // min_threshold is assumed to be below the detection threshold, 212 // so all the peaks are pmFootprint, and this isn't the brightest 213 // XXX mark peak to be dropped 214 (void)psArrayRemoveIndex(fp->peaks, i); 215 i--; // we moved everything down one 216 continue; 212 217 #else 213 218 #error n.b. We will be running LOTS of checks at this threshold, so only find the footprint once 214 threshold = min_threshold;219 threshold = min_threshold; 215 220 #endif 216 }217 218 // XXX EAM : if stdev >= 0, i'm not sure how this can ever be true?219 if (threshold > subImg->data.F32[y][x]) {220 threshold = subImg->data.F32[y][x] - 10*FLT_EPSILON;221 }222 223 // XXX this is a bit expensive: psImageAlloc for every peak contained in this footprint224 // perhaps this should alloc a single ID image above and pass it in to be set.225 226 const int peak_id = 1;// the ID for the peak of interest227 brightPeaks->n = i;// only stop at a peak brighter than we are228 229 // XXX optionally use the faster pmFootprintsFind if the subimage size is large (eg, M31)230 231 pmFootprint *peakFootprint = pmFootprintsFindAtPoint(subImg, threshold, brightPeaks, peak->y, peak->x);232 brightPeaks->n = 0;// don't double free233 psImage *idImg = pmSetFootprintID(NULL, peakFootprint, peak_id);234 psFree(peakFootprint);235 236 // Check if any of the previous (brighter) peaks are within the footprint of this peak237 // If so, the current peak is bogus; drop it.238 int j;239 for (j = 0; j < i; j++) {240 const pmPeak *peak2 = fp->peaks->data[j];241 int x2 = peak2->x - subImg->col0;242 int y2 = peak2->y - subImg->row0;243 const int peak2_id = idImg->data.S32[y2][x2]; // the ID for some other peak244 245 if (peak2_id == peak_id) {// There's a brighter peak within the footprint above246 ;// threshold; so cull our initial peak247 (void)psArrayRemoveIndex(fp->peaks, i);248 i--;// we moved everything down one249 break;250 }251 }252 if (j == i) {253 j++;254 }255 256 psFree(idImg);221 } 222 223 // XXX EAM : if stdev >= 0, i'm not sure how this can ever be true? 224 if (threshold > subImg->data.F32[y][x]) { 225 threshold = subImg->data.F32[y][x] - 10*FLT_EPSILON; 226 } 227 228 // XXX this is a bit expensive: psImageAlloc for every peak contained in this footprint 229 // perhaps this should alloc a single ID image above and pass it in to be set. 230 231 const int peak_id = 1; // the ID for the peak of interest 232 brightPeaks->n = i; // only stop at a peak brighter than we are 233 234 // XXX optionally use the faster pmFootprintsFind if the subimage size is large (eg, M31) 235 236 pmFootprint *peakFootprint = pmFootprintsFindAtPoint(subImg, threshold, brightPeaks, peak->y, peak->x); 237 brightPeaks->n = 0; // don't double free 238 psImage *idImg = pmSetFootprintID(NULL, peakFootprint, peak_id); 239 psFree(peakFootprint); 240 241 // Check if any of the previous (brighter) peaks are within the footprint of this peak 242 // If so, the current peak is bogus; drop it. 243 int j; 244 for (j = 0; j < i; j++) { 245 const pmPeak *peak2 = fp->peaks->data[j]; 246 int x2 = peak2->x - subImg->col0; 247 int y2 = peak2->y - subImg->row0; 248 const int peak2_id = idImg->data.S32[y2][x2]; // the ID for some other peak 249 250 if (peak2_id == peak_id) { // There's a brighter peak within the footprint above 251 ; // threshold; so cull our initial peak 252 (void)psArrayRemoveIndex(fp->peaks, i); 253 i--; // we moved everything down one 254 break; 255 } 256 } 257 if (j == i) { 258 j++; 259 } 260 261 psFree(idImg); 257 262 } 258 263 259 264 brightPeaks->n = 0; psFree(brightPeaks); 260 psFree( (psImage *)subImg);261 psFree( (psImage *)subWt);265 psFree(subImg); 266 psFree(subWt); 262 267 263 268 return PS_ERR_NONE; -
trunk/psModules/src/objects/pmFootprintFindAtPoint.c
r21183 r26893 29 29 * so we set appropriate mask bits 30 30 * 31 * EAM : these function were confusingly using "startspan" and "spartspan" 31 * EAM : these function were confusingly using "startspan" and "spartspan" 32 32 * I've rationalized them all to 'startspan' 33 33 */ … … 36 36 // An enum for what we should do with a Startspan 37 37 // 38 typedef enum {PM_SSPAN_DOWN = 0, // scan down from this span39 PM_SSPAN_UP,// scan up from this span40 PM_SSPAN_RESTART,// restart scanning from this span41 PM_SSPAN_DONE// this span is processed42 } PM_SSPAN_DIR; // How to continue searching38 typedef enum {PM_SSPAN_DOWN = 0, // scan down from this span 39 PM_SSPAN_UP, // scan up from this span 40 PM_SSPAN_RESTART, // restart scanning from this span 41 PM_SSPAN_DONE // this span is processed 42 } PM_SSPAN_DIR; // How to continue searching 43 43 // 44 44 // An enum for mask's pixel values. We're looking for pixels that are above threshold, and 45 45 // we keep extra book-keeping information in the PM_SSPAN_STOP plane. It's simpler to be 46 // able to check for 46 // able to check for 47 47 // 48 48 enum { 49 PM_SSPAN_INITIAL = 0x0, // initial state of pixels.50 PM_SSPAN_DETECTED = 0x1, // we've seen this pixel51 PM_SSPAN_STOP = 0x2 // you may stop searching when you see this pixel49 PM_SSPAN_INITIAL = 0x0, // initial state of pixels. 50 PM_SSPAN_DETECTED = 0x1, // we've seen this pixel 51 PM_SSPAN_STOP = 0x2 // you may stop searching when you see this pixel 52 52 }; 53 53 // … … 55 55 // 56 56 typedef struct { 57 const pmSpan *span; // save the pixel range58 PM_SSPAN_DIR direction; // How to continue searching59 bool stop; // should we stop searching?57 const pmSpan *span; // save the pixel range 58 PM_SSPAN_DIR direction; // How to continue searching 59 bool stop; // should we stop searching? 60 60 } Startspan; 61 61 62 62 static void startspanFree(Startspan *sspan) { 63 psFree( (void *)sspan->span);63 psFree(sspan->span); 64 64 } 65 65 66 66 static Startspan * 67 StartspanAlloc(const pmSpan *span, // The span in question68 psImage *mask,// Pixels that we've already detected69 const PM_SSPAN_DIR dir// Should we continue searching towards the top of the image?67 StartspanAlloc(const pmSpan *span, // The span in question 68 psImage *mask, // Pixels that we've already detected 69 const PM_SSPAN_DIR dir // Should we continue searching towards the top of the image? 70 70 ) { 71 71 Startspan *sspan = psAlloc(sizeof(Startspan)); … … 75 75 sspan->direction = dir; 76 76 sspan->stop = false; 77 78 if (mask != NULL) { // remember that we've detected these pixels79 psImageMaskType *mpix = &mask->data.PS_TYPE_IMAGE_MASK_DATA[span->y - mask->row0][span->x0 - mask->col0];80 81 for (int i = 0; i <= span->x1 - span->x0; i++) {82 mpix[i] |= PM_SSPAN_DETECTED;83 if (mpix[i] & PM_SSPAN_STOP) {84 sspan->stop = true;85 }86 }87 } 88 77 78 if (mask != NULL) { // remember that we've detected these pixels 79 psImageMaskType *mpix = &mask->data.PS_TYPE_IMAGE_MASK_DATA[span->y - mask->row0][span->x0 - mask->col0]; 80 81 for (int i = 0; i <= span->x1 - span->x0; i++) { 82 mpix[i] |= PM_SSPAN_DETECTED; 83 if (mpix[i] & PM_SSPAN_STOP) { 84 sspan->stop = true; 85 } 86 } 87 } 88 89 89 return sspan; 90 90 } … … 94 94 // 95 95 static bool add_startspan(psArray *startspans, // the saved Startspans 96 const pmSpan *sp, // the span in question97 psImage *mask, // mask of detected/stop pixels98 const PM_SSPAN_DIR dir) { // the desired direction to search96 const pmSpan *sp, // the span in question 97 psImage *mask, // mask of detected/stop pixels 98 const PM_SSPAN_DIR dir) { // the desired direction to search 99 99 if (dir == PM_SSPAN_RESTART) { 100 if (add_startspan(startspans, sp, mask, PM_SSPAN_UP) ||101 add_startspan(startspans, sp, NULL, PM_SSPAN_DOWN)) {102 return true;103 }100 if (add_startspan(startspans, sp, mask, PM_SSPAN_UP) || 101 add_startspan(startspans, sp, NULL, PM_SSPAN_DOWN)) { 102 return true; 103 } 104 104 } else { 105 Startspan *sspan = StartspanAlloc(sp, mask, dir);106 if (sspan->stop) {// we detected a stop bit107 psFree(sspan);// don't allocate new span108 109 return true;110 } else {111 psArrayAdd(startspans, 1, sspan);112 psFree(sspan);// as it's now owned by startspans113 }105 Startspan *sspan = StartspanAlloc(sp, mask, dir); 106 if (sspan->stop) { // we detected a stop bit 107 psFree(sspan); // don't allocate new span 108 109 return true; 110 } else { 111 psArrayAdd(startspans, 1, sspan); 112 psFree(sspan); // as it's now owned by startspans 113 } 114 114 } 115 115 … … 127 127 */ 128 128 static bool do_startspan(pmFootprint *fp, // the footprint that we're building 129 const psImage *img, // the psImage we're working on130 psImage *mask, // the associated masks131 const float threshold,// Threshold132 psArray *startspans) {// specify which span to process next133 bool F32 = false; // is this an F32 image?129 const psImage *img, // the psImage we're working on 130 psImage *mask, // the associated masks 131 const float threshold, // Threshold 132 psArray *startspans) { // specify which span to process next 133 bool F32 = false; // is this an F32 image? 134 134 if (img->type.type == PS_TYPE_F32) { 135 F32 = true;135 F32 = true; 136 136 } else if (img->type.type == PS_TYPE_S32) { 137 F32 = false;138 } else { // N.b. You can't trivially add more cases here; F32 is just a bool139 psError(PS_ERR_UNKNOWN, true, "Unsupported psImage type: %d", img->type.type);140 return NULL;141 } 142 143 psF32 *imgRowF32 = NULL; // row pointer if F32144 psS32 *imgRowS32 = NULL; // " " " " !F32145 psImageMaskType *maskRow = NULL; // masks's row pointer146 137 F32 = false; 138 } else { // N.b. You can't trivially add more cases here; F32 is just a bool 139 psError(PS_ERR_UNKNOWN, true, "Unsupported psImage type: %d", img->type.type); 140 return NULL; 141 } 142 143 psF32 *imgRowF32 = NULL; // row pointer if F32 144 psS32 *imgRowS32 = NULL; // " " " " !F32 145 psImageMaskType *maskRow = NULL; // masks's row pointer 146 147 147 const int row0 = img->row0; 148 148 const int col0 = img->col0; 149 149 const int numRows = img->numRows; 150 150 const int numCols = img->numCols; 151 151 152 152 /********************************************************************************************************/ 153 153 154 154 Startspan *sspan = NULL; 155 155 for (int i = 0; i < startspans->n; i++) { 156 sspan = startspans->data[i];157 if (sspan->direction != PM_SSPAN_DONE) {158 break;159 }160 if (sspan->stop) {161 break;162 }156 sspan = startspans->data[i]; 157 if (sspan->direction != PM_SSPAN_DONE) { 158 break; 159 } 160 if (sspan->stop) { 161 break; 162 } 163 163 } 164 164 if (sspan == NULL || sspan->direction == PM_SSPAN_DONE) { // no more Startspans to process 165 return false;166 } 167 if (sspan->stop) { // they don't want any more spans processed168 return false;165 return false; 166 } 167 if (sspan->stop) { // they don't want any more spans processed 168 return false; 169 169 } 170 170 /* … … 179 179 * Go through image identifying objects 180 180 */ 181 int nx0, nx1 = -1; // new values of x0, x1181 int nx0, nx1 = -1; // new values of x0, x1 182 182 const int di = (dir == PM_SSPAN_UP) ? 1 : -1; // how much i changes to get to the next row 183 bool stop = false; // should I stop searching for spans?183 bool stop = false; // should I stop searching for spans? 184 184 185 185 for (int i = sspan->span->y -row0 + di; i < numRows && i >= 0; i += di) { 186 imgRowF32 = img->data.F32[i];// only one of187 imgRowS32 = img->data.S32[i];// these is valid!188 maskRow = mask->data.PS_TYPE_IMAGE_MASK_DATA[i];189 //190 // Search left from the pixel diagonally to the left of (i - di, x0). If there's191 // a connected span there it may need to grow up and/or down, so push it onto192 // the stack for later consideration193 //194 nx0 = -1;195 for (int j = x0 - 1; j >= -1; j--) {196 double pixVal = (j < 0) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]);197 if ((maskRow[j] & PM_SSPAN_DETECTED) || pixVal < threshold) {198 if (j < x0 - 1) {// we found some pixels above threshold199 nx0 = j + 1;200 }201 break;202 }203 }204 205 if (nx0 < 0) {// no span to the left206 nx1 = x0 - 1;// we're going to resume searching at nx1 + 1207 } else {208 //209 // Search right in leftmost span210 //211 //nx1 = 0;// make gcc happy212 for (int j = nx0 + 1; j <= numCols; j++) {213 double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]);214 if ((maskRow[j] & PM_SSPAN_DETECTED) || pixVal < threshold) {215 nx1 = j - 1;216 break;217 }218 }219 220 const pmSpan *sp = pmFootprintAddSpan(fp, i + row0, nx0 + col0, nx1 + col0);221 222 if (add_startspan(startspans, sp, mask, PM_SSPAN_RESTART)) {223 stop = true;224 break;225 }226 }227 //228 // Now look for spans connected to the old span. The first of these we'll229 // simply process, but others will have to be deferred for later consideration.230 //231 // In fact, if the span overhangs to the right we'll have to defer the overhang232 // until later too, as it too can grow in both directions233 //234 // Note that column numCols exists virtually, and always ends the last span; this235 // is why we claim below that sx1 is always set236 //237 bool first = false;// is this the first new span detected?238 for (int j = nx1 + 1; j <= x1 + 1; j++) {239 double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]);240 if (!(maskRow[j] & PM_SSPAN_DETECTED) && pixVal >= threshold) {241 int sx0 = j++;// span that we're working on is sx0:sx1242 int sx1 = -1;// We know that if we got here, we'll also set sx1243 for (; j <= numCols; j++) {244 double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]);245 if ((maskRow[j] & PM_SSPAN_DETECTED) || pixVal < threshold) { // end of span246 sx1 = j;247 break;248 }249 }250 assert (sx1 >= 0);251 252 const pmSpan *sp;253 if (first) {254 if (sx1 <= x1) {255 sp = pmFootprintAddSpan(fp, i + row0, sx0 + col0, sx1 + col0 - 1);256 if (add_startspan(startspans, sp, mask, PM_SSPAN_DONE)) {257 stop = true;258 break;259 }260 } else {// overhangs to right261 sp = pmFootprintAddSpan(fp, i + row0, sx0 + col0, x1 + col0);262 if (add_startspan(startspans, sp, mask, PM_SSPAN_DONE)) {263 stop = true;264 break;265 }266 sp = pmFootprintAddSpan(fp, i + row0, x1 + 1 + col0, sx1 + col0 - 1);267 if (add_startspan(startspans, sp, mask, PM_SSPAN_RESTART)) {268 stop = true;269 break;270 }271 }272 first = false;273 } else {274 sp = pmFootprintAddSpan(fp, i + row0, sx0 + col0, sx1 + col0 - 1);275 if (add_startspan(startspans, sp, mask, PM_SSPAN_RESTART)) {276 stop = true;277 break;278 }279 }280 }281 }282 283 if (stop || first == false) {// we're done284 break;285 }286 287 x0 = nx0; x1 = nx1;186 imgRowF32 = img->data.F32[i]; // only one of 187 imgRowS32 = img->data.S32[i]; // these is valid! 188 maskRow = mask->data.PS_TYPE_IMAGE_MASK_DATA[i]; 189 // 190 // Search left from the pixel diagonally to the left of (i - di, x0). If there's 191 // a connected span there it may need to grow up and/or down, so push it onto 192 // the stack for later consideration 193 // 194 nx0 = -1; 195 for (int j = x0 - 1; j >= -1; j--) { 196 double pixVal = (j < 0) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]); 197 if ((maskRow[j] & PM_SSPAN_DETECTED) || pixVal < threshold) { 198 if (j < x0 - 1) { // we found some pixels above threshold 199 nx0 = j + 1; 200 } 201 break; 202 } 203 } 204 205 if (nx0 < 0) { // no span to the left 206 nx1 = x0 - 1; // we're going to resume searching at nx1 + 1 207 } else { 208 // 209 // Search right in leftmost span 210 // 211 //nx1 = 0; // make gcc happy 212 for (int j = nx0 + 1; j <= numCols; j++) { 213 double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]); 214 if ((maskRow[j] & PM_SSPAN_DETECTED) || pixVal < threshold) { 215 nx1 = j - 1; 216 break; 217 } 218 } 219 220 const pmSpan *sp = pmFootprintAddSpan(fp, i + row0, nx0 + col0, nx1 + col0); 221 222 if (add_startspan(startspans, sp, mask, PM_SSPAN_RESTART)) { 223 stop = true; 224 break; 225 } 226 } 227 // 228 // Now look for spans connected to the old span. The first of these we'll 229 // simply process, but others will have to be deferred for later consideration. 230 // 231 // In fact, if the span overhangs to the right we'll have to defer the overhang 232 // until later too, as it too can grow in both directions 233 // 234 // Note that column numCols exists virtually, and always ends the last span; this 235 // is why we claim below that sx1 is always set 236 // 237 bool first = false; // is this the first new span detected? 238 for (int j = nx1 + 1; j <= x1 + 1; j++) { 239 double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]); 240 if (!(maskRow[j] & PM_SSPAN_DETECTED) && pixVal >= threshold) { 241 int sx0 = j++; // span that we're working on is sx0:sx1 242 int sx1 = -1; // We know that if we got here, we'll also set sx1 243 for (; j <= numCols; j++) { 244 double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]); 245 if ((maskRow[j] & PM_SSPAN_DETECTED) || pixVal < threshold) { // end of span 246 sx1 = j; 247 break; 248 } 249 } 250 assert (sx1 >= 0); 251 252 const pmSpan *sp; 253 if (first) { 254 if (sx1 <= x1) { 255 sp = pmFootprintAddSpan(fp, i + row0, sx0 + col0, sx1 + col0 - 1); 256 if (add_startspan(startspans, sp, mask, PM_SSPAN_DONE)) { 257 stop = true; 258 break; 259 } 260 } else { // overhangs to right 261 sp = pmFootprintAddSpan(fp, i + row0, sx0 + col0, x1 + col0); 262 if (add_startspan(startspans, sp, mask, PM_SSPAN_DONE)) { 263 stop = true; 264 break; 265 } 266 sp = pmFootprintAddSpan(fp, i + row0, x1 + 1 + col0, sx1 + col0 - 1); 267 if (add_startspan(startspans, sp, mask, PM_SSPAN_RESTART)) { 268 stop = true; 269 break; 270 } 271 } 272 first = false; 273 } else { 274 sp = pmFootprintAddSpan(fp, i + row0, sx0 + col0, sx1 + col0 - 1); 275 if (add_startspan(startspans, sp, mask, PM_SSPAN_RESTART)) { 276 stop = true; 277 break; 278 } 279 } 280 } 281 } 282 283 if (stop || first == false) { // we're done 284 break; 285 } 286 287 x0 = nx0; x1 = nx1; 288 288 } 289 289 /* … … 309 309 */ 310 310 pmFootprint * 311 pmFootprintsFindAtPoint(const psImage *img, // image to search312 const float threshold,// Threshold313 const psArray *peaks, // array of peaks; finding one terminates search for footprint314 int row, int col) { // starting position (in img's parent's coordinate system)311 pmFootprintsFindAtPoint(const psImage *img, // image to search 312 const float threshold, // Threshold 313 const psArray *peaks, // array of peaks; finding one terminates search for footprint 314 int row, int col) { // starting position (in img's parent's coordinate system) 315 315 assert(img != NULL); 316 316 317 bool F32 = false; // is this an F32 image?317 bool F32 = false; // is this an F32 image? 318 318 if (img->type.type == PS_TYPE_F32) { 319 319 F32 = true; 320 320 } else if (img->type.type == PS_TYPE_S32) { 321 321 F32 = false; 322 } else { // N.b. You can't trivially add more cases here; F32 is just a bool322 } else { // N.b. You can't trivially add more cases here; F32 is just a bool 323 323 psError(PS_ERR_UNKNOWN, true, "Unsupported psImage type: %d", img->type.type); 324 324 return NULL; 325 325 } 326 psF32 *imgRowF32 = NULL; // row pointer if F32327 psS32 *imgRowS32 = NULL; // " " " " !F32328 326 psF32 *imgRowF32 = NULL; // row pointer if F32 327 psS32 *imgRowS32 = NULL; // " " " " !F32 328 329 329 const int row0 = img->row0; 330 330 const int col0 = img->col0; … … 339 339 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 340 340 "row/col == (%d, %d) are out of bounds [%d--%d, %d--%d]", 341 row + row0, col + col0, row0, row0 + numRows - 1, col0, col0 + numCols - 1);341 row + row0, col + col0, row0, row0 + numRows - 1, col0, col0 + numCols - 1); 342 342 return NULL; 343 343 } … … 347 347 return pmFootprintAlloc(0, img); 348 348 } 349 349 350 350 pmFootprint *fp = pmFootprintAlloc(1 + img->numRows/10, img); 351 351 /* … … 364 364 if (peaks != NULL) { 365 365 for (int i = 0; i < peaks->n; i++) { 366 pmPeak *peak = peaks->data[i];367 mask->data.PS_TYPE_IMAGE_MASK_DATA[peak->y - mask->row0][peak->x - mask->col0] |= PM_SSPAN_STOP;366 pmPeak *peak = peaks->data[i]; 367 mask->data.PS_TYPE_IMAGE_MASK_DATA[peak->y - mask->row0][peak->x - mask->col0] |= PM_SSPAN_STOP; 368 368 } 369 369 } … … 372 372 */ 373 373 psArray *startspans = psArrayAllocEmpty(1); // spans where we have to restart the search 374 375 imgRowF32 = img->data.F32[row]; // only one of376 imgRowS32 = img->data.S32[row]; // these is valid!374 375 imgRowF32 = img->data.F32[row]; // only one of 376 imgRowS32 = img->data.S32[row]; // these is valid! 377 377 psImageMaskType *maskRow = mask->data.PS_TYPE_IMAGE_MASK_DATA[row]; 378 378 { 379 379 int i; 380 380 for (i = col; i >= 0; i--) { 381 pixVal = F32 ? imgRowF32[i] : imgRowS32[i];382 if ((maskRow[i] & PM_SSPAN_DETECTED) || pixVal < threshold) {383 break;384 }381 pixVal = F32 ? imgRowF32[i] : imgRowS32[i]; 382 if ((maskRow[i] & PM_SSPAN_DETECTED) || pixVal < threshold) { 383 break; 384 } 385 385 } 386 386 int i0 = i; 387 387 for (i = col; i < numCols; i++) { 388 pixVal = F32 ? imgRowF32[i] : imgRowS32[i];389 if ((maskRow[i] & PM_SSPAN_DETECTED) || pixVal < threshold) {390 break;391 }388 pixVal = F32 ? imgRowF32[i] : imgRowS32[i]; 389 if ((maskRow[i] & PM_SSPAN_DETECTED) || pixVal < threshold) { 390 break; 391 } 392 392 } 393 393 int i1 = i; … … 404 404 */ 405 405 psFree(mask); 406 psFree(startspans); // restores the image pixel407 408 return fp; // pmFootprint really406 psFree(startspans); // restores the image pixel 407 408 return fp; // pmFootprint really 409 409 } -
trunk/psModules/src/objects/pmPSF.c
r24206 r26893 42 42 #include "pmErrorCodes.h" 43 43 44 45 #define MAX_AXIS_RATIO 20.0 // Maximum axis ratio for PSF model 46 44 47 /*****************************************************************************/ 45 48 /* FUNCTION IMPLEMENTATION - PUBLIC */ … … 405 408 return psf; 406 409 } 410 411 412 float pmPSFtoFWHM(const pmPSF *psf, float x, float y) 413 { 414 PS_ASSERT_PTR_NON_NULL(psf, NAN); 415 416 pmModel *model = pmModelFromPSFforXY(psf, x, y, 1.0); // Model of source 417 if (!model) { 418 psError(PS_ERR_UNKNOWN, false, "Unable to determine PSF model at %f,%f\n", x, y); 419 return NAN; 420 } 421 psF32 *params = model->params->data.F32; // Model parameters 422 psEllipseAxes axes = pmPSF_ModelToAxes(params, MAX_AXIS_RATIO); // Ellipse axes 423 424 // Curiously, the minor axis can be larger than the major axis, so need to check. 425 float fwhm = 2.355 * PS_MAX(axes.minor, axes.major); // FWHM, converted from sigma 426 427 psFree(model); 428 429 return fwhm; 430 } -
trunk/psModules/src/objects/pmPSF.h
r25754 r26893 111 111 psEllipseAxes pmPSF_ModelToAxes (psF32 *modelPar, double maxAR); 112 112 113 /// Calculate FWHM value from a PSF 114 float pmPSFtoFWHM( 115 const pmPSF *psf, // PSF of interest 116 float x, float y // Position of interest 117 ); 118 119 113 120 /// @} 114 121 # endif -
trunk/psModules/src/objects/pmPeaks.c
r26391 r26893 416 416 417 417 } else { 418 ps Error(PS_ERR_UNKNOWN, true, "peak specifiedvalid column range.");418 psLogMsg ("psModules.objects", 5, "peak specified outside valid column range."); 419 419 } 420 420 } … … 501 501 } 502 502 } else { 503 psError(PS_ERR_UNKNOWN, true, "peak specified outside valid column range.");503 psLogMsg ("psModules.objects", 5, "peak specified outside valid column range."); 504 504 } 505 505 … … 545 545 } 546 546 } else { 547 ps Error(PS_ERR_UNKNOWN, true, "peak specified outside valid column range.");547 psLogMsg ("psModules.objects", 5, "peak specified outside valid column range."); 548 548 } 549 549 } -
trunk/psModules/src/objects/pmSource.c
r26395 r26893 3 3 * Functions to define and manipulate sources on images 4 4 * 5 * @author GLG, MHPCC6 * @author EAM, IfA: significant modifications.5 * @author EAM, IfA 6 * @author GLG, MHPCC (initial code base) 7 7 * 8 8 * @version $Revision: 1.70 $ $Name: not supported by cvs2svn $ 9 9 * @date $Date: 2009-02-16 22:29:59 $ 10 * 11 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii 12 * 10 * Copyright 2009 Institute for Astronomy, University of Hawaii 13 11 */ 14 12 … … 277 275 // psphot-specific function which applies the recipe values 278 276 // only apply selection to sources within specified region 279 pmPSFClump pmSourcePSFClump(ps Region *region, psArray *sources, psMetadata *recipe)277 pmPSFClump pmSourcePSFClump(psImage **savedImage, psRegion *region, psArray *sources, float PSF_SN_LIM, float PSF_CLUMP_GRID_SCALE, psF32 SX_MAX, psF32 SY_MAX, psF32 AR_MAX) 280 278 { 281 279 psTrace("psModules.objects", 10, "---- begin ----\n"); … … 287 285 288 286 PS_ASSERT_PTR_NON_NULL(sources, errorClump); 289 PS_ASSERT_PTR_NON_NULL(recipe, errorClump);290 291 bool status = true; // Status of MD lookup292 float PSF_SN_LIM = psMetadataLookupF32(&status, recipe, "PSF_SN_LIM");293 if (!status) {294 PSF_SN_LIM = 0;295 }296 float PSF_CLUMP_GRID_SCALE = psMetadataLookupF32(&status, recipe, "PSF_CLUMP_GRID_SCALE");297 if (!status) {298 PSF_CLUMP_GRID_SCALE = 0.1;299 }300 287 301 288 // find the sigmaX, sigmaY clump 302 289 { 303 psF32 SX_MAX = psMetadataLookupF32(&status, recipe, "MOMENTS_SX_MAX");304 if (!status) {305 psWarning("MOMENTS_SX_MAX not set in recipe");306 SX_MAX = 10.0;307 }308 psF32 SY_MAX = psMetadataLookupF32(&status, recipe, "MOMENTS_SY_MAX");309 if (!status) {310 psWarning("MOMENTS_SY_MAX not set in recipe");311 SY_MAX = 10.0;312 }313 psF32 AR_MAX = psMetadataLookupF32(&status, recipe, "MOMENTS_AR_MAX");314 if (!status) {315 psWarning("MOMENTS_AR_MAX not set in recipe");316 AR_MAX = 3.0;317 }318 290 psF32 AR_MIN = 1.0 / AR_MAX; 319 291 … … 401 373 psfClump.nSigma = stats->sampleStdev; 402 374 403 const bool keep_psf_clump = psMetadataLookupBool(NULL, recipe, "KEEP_PSF_CLUMP"); 404 if (keep_psf_clump) 405 { 406 psMetadataAdd(recipe, PS_LIST_TAIL, 407 "PSF_CLUMP", PS_DATA_IMAGE, "Image of PSF coefficients", splane); 375 if (savedImage) { 376 *savedImage = psMemIncrRefCounter(splane); 408 377 } 409 378 psFree (splane); … … 411 380 412 381 // if we failed to find a valid peak, return the empty clump (failure signal) 413 if (!peaks || !peaks->n) { 382 if (peaks == NULL) { 383 psError(PS_ERR_UNKNOWN, false, "failure in peak analysis for PSF clump.\n"); 384 psFree (peaks); 385 return emptyClump; 386 } 387 388 if (peaks->n == 0) 389 { 414 390 psLogMsg ("psphot", 3, "failed to find a peak in the PSF clump image\n"); 415 391 if (nValid == 0) { … … 418 394 psLogMsg ("psphot", 3, "no significant peak\n"); 419 395 } 396 psFree (peaks); 420 397 return (emptyClump); 421 398 } … … 524 501 *****************************************************************************/ 525 502 526 bool pmSourceRoughClass(psRegion *region, psArray *sources, psMetadata *recipe, pmPSFClump clump, psImageMaskType maskSat)503 bool pmSourceRoughClass(psRegion *region, psArray *sources, float PSF_SN_LIM, float PSF_CLUMP_NSIGMA, pmPSFClump clump, psImageMaskType maskSat) 527 504 { 528 505 psTrace("psModules.objects", 10, "---- begin ----"); 529 506 530 507 PS_ASSERT_PTR_NON_NULL(sources, false); 531 PS_ASSERT_PTR_NON_NULL(recipe, false);532 508 533 509 int Nsat = 0; … … 542 518 psVector *starsn_peaks = psVectorAllocEmpty (sources->n, PS_TYPE_F32); 543 519 psVector *starsn_moments = psVectorAllocEmpty (sources->n, PS_TYPE_F32); 544 545 // get basic parameters, or set defaults546 bool status;547 float PSF_SN_LIM = psMetadataLookupF32 (&status, recipe, "PSF_SN_LIM");548 if (!status) PSF_SN_LIM = 20.0;549 float PSF_CLUMP_NSIGMA = psMetadataLookupF32 (&status, recipe, "PSF_CLUMP_NSIGMA");550 if (!status) PSF_CLUMP_NSIGMA = 1.5;551 552 // float INNER_RADIUS = psMetadataLookupF32 (&status, recipe, "SKY_INNER_RADIUS");553 520 554 521 pmSourceMode noMoments = PM_SOURCE_MODE_MOMENTS_FAILURE | PM_SOURCE_MODE_SKYVAR_FAILURE | PM_SOURCE_MODE_SKY_FAILURE | PM_SOURCE_MODE_BELOW_MOMENTS_SN; -
trunk/psModules/src/objects/pmSource.h
r25754 r26893 176 176 * 177 177 * The return value indicates the success (TRUE) of the operation. 178 * 179 * XXX: Limit the S/N of the candidate sources (part of Metadata)? (TBD). 180 * XXX: Save the clump parameters on the Metadata (TBD) 181 * 182 */ 178 */ 179 183 180 pmPSFClump pmSourcePSFClump( 181 psImage **savedImage, 184 182 psRegion *region, ///< restrict measurement to specified region 185 183 psArray *source, ///< The input pmSource 186 psMetadata *metadata ///< Contains classification parameters 184 float PSF_SN_LIM, 185 float PSF_CLUMP_GRID_SCALE, 186 psF32 SX_MAX, 187 psF32 SY_MAX, 188 psF32 AR_MAX 187 189 ); 188 190 … … 200 202 psRegion *region, ///< restrict measurement to specified region 201 203 psArray *sources, ///< The input pmSources 202 psMetadata *metadata, ///< Contains classification parameters 204 float PSF_SN_LIM, ///< min S/N for source to be used for PSF model 205 float PSF_CLUMP_NSIGMA, ///< size of region around peak of clump for PSF stars 203 206 pmPSFClump clump, ///< Statistics about the PSF clump 204 207 psImageMaskType maskSat ///< Mask value for saturated pixels … … 220 223 float radius, ///< Use a circle of pixels around the peak 221 224 float sigma, ///< size of Gaussian window function (<= 0.0 -> skip window) 222 float minSN ///< minimum pixel significance 225 float minSN, ///< minimum pixel significance 226 psImageMaskType maskVal 223 227 ); 224 228 -
trunk/psModules/src/objects/pmSourceIO.c
r26393 r26893 40 40 #include "pmPSF.h" 41 41 #include "pmModel.h" 42 #include "pmDetections.h" 42 43 #include "pmSource.h" 43 44 #include "pmModelClass.h" … … 344 345 345 346 // if sources is NULL, write out an empty table 346 // input / output sources are stored on the readout->analysis as "PSPHOT.SOURCES" -- a better name might be something like PM_SOURCE_DATA 347 psArray *sources = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.SOURCES"); 347 // input / output sources are stored on the readout->analysis as "PSPHOT.DETECTIONS" 348 349 psArray *sources = NULL; 350 pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS"); 351 if (detections) { 352 sources = detections->allSources; 353 } 348 354 if (!sources) { 355 detections = pmDetectionsAlloc(); 349 356 sources = psArrayAlloc(0); 350 psMetadataAddArray(readout->analysis, PS_LIST_TAIL, "PSPHOT.SOURCES", PS_META_REPLACE, "Blank array of sources", sources); 351 psFree(sources); // Held onto by the metadata, so we can continue to use 357 detections->allSources = sources; 358 psMetadataAddPtr(readout->analysis, PS_LIST_TAIL, "PSPHOT.DETECTIONS", PS_DATA_UNKNOWN | PS_META_REPLACE, "Blank array of sources", detections); 359 psFree(detections); // Held onto by the metadata, so we can continue to use 352 360 } 353 361 … … 1031 1039 } 1032 1040 readout->data_exists = true; 1033 status = psMetadataAdd (readout->analysis, PS_LIST_TAIL, "PSPHOT.SOURCES", PS_DATA_ARRAY, "input sources", sources); 1034 psFree (sources); 1041 1042 pmDetections *detections = pmDetectionsAlloc(); 1043 detections->allSources = sources; 1044 status = psMetadataAdd (readout->analysis, PS_LIST_TAIL, "PSPHOT.DETECTIONS", PS_DATA_ARRAY, "input sources", detections); 1045 psFree (detections); 1035 1046 return true; 1036 1047 } … … 1124 1135 bool status; 1125 1136 1126 // select the psf of interest 1127 pmPSF *psf = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.SOURCES"); 1128 if (!psf) return false; 1129 return true; 1130 } 1131 1132 1137 // select the detections of interest 1138 pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS"); 1139 if (!detections) return false; 1140 if (!detections->allSources) return false; 1141 return true; 1142 } 1143 1144 -
trunk/psModules/src/objects/pmSourceIO_CMF_PS1_V2.c
r25754 r26893 304 304 source->peak->dx = dPAR[PM_PAR_XPOS]; 305 305 source->peak->dy = dPAR[PM_PAR_YPOS]; 306 source->peak->SN = sqrt(source->peak->flux); // XXX a proxy: various functions sort by peak S/N 306 307 307 308 source->pixWeight = psMetadataLookupF32 (&status, row, "PSF_QF"); -
trunk/psModules/src/objects/pmSourceIO_MatchedRefs.c
r26392 r26893 163 163 164 164 // try find the MATCHED_REFS extension. if non-existent, note that we tried, and move on. 165 // It is not an error to lack this entry -- psFitsMoveExtNameClean does not raise an error 165 166 if (!psFitsMoveExtNameClean (fits, "MATCHED_REFS")) { 166 167 psMetadataAddBool (fpa->analysis, PS_LIST_TAIL, "READ.REFMATCH", PS_META_REPLACE, "attempted to read MATCHED_REFS", true); -
trunk/psModules/src/objects/pmSourceMoments.c
r25979 r26893 54 54 # define VALID_RADIUS(X,Y,RAD2) (((RAD2) >= (PS_SQR(X) + PS_SQR(Y))) ? 1 : 0) 55 55 56 bool pmSourceMoments(pmSource *source, psF32 radius, psF32 sigma, psF32 minSN )56 bool pmSourceMoments(pmSource *source, psF32 radius, psF32 sigma, psF32 minSN, psImageMaskType maskVal) 57 57 { 58 58 PS_ASSERT_PTR_NON_NULL(source, false); … … 114 114 for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) { 115 115 if (vMsk) { 116 if (*vMsk ) {116 if (*vMsk & maskVal) { 117 117 vMsk++; 118 118 continue; … … 135 135 // stars. 136 136 if (PS_SQR(pDiff) < minSN2*wDiff) continue; 137 if (pDiff < 0) continue; // XXX : MWV says I should include < 0.0 valued points...137 // if (pDiff < 0) continue; // XXX : MWV says I should include < 0.0 valued points... 138 138 139 139 // Apply a Gaussian window function. Be careful with the window function. S/N … … 226 226 for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) { 227 227 if (vMsk) { 228 if (*vMsk ) {228 if (*vMsk & maskVal) { 229 229 vMsk++; 230 230 continue; … … 249 249 // stars. 250 250 if (PS_SQR(pDiff) < minSN2*wDiff) continue; 251 if (pDiff < 0) continue;251 // if (pDiff < 0) continue; 252 252 253 253 // Apply a Gaussian window function. Be careful with the window function. S/N … … 315 315 source->moments->Myyyy = YYYY/Sum; 316 316 317 if (source->moments->Mxx < 0) {318 fprintf (stderr, "error: neg second moment??\n");319 }320 if (source->moments->Myy < 0) {321 fprintf (stderr, "error: neg second moment??\n");322 }317 // if (source->moments->Mxx < 0) { 318 // fprintf (stderr, "error: neg second moment??\n"); 319 // } 320 // if (source->moments->Myy < 0) { 321 // fprintf (stderr, "error: neg second moment??\n"); 322 // } 323 323 324 324 psTrace ("psModules.objects", 4, "Mxx: %f Mxy: %f Myy: %f Mxxx: %f Mxxy: %f Mxyy: %f Myyy: %f Mxxxx: %f Mxxxy: %f Mxxyy: %f Mxyyy: %f Mxyyy: %f\n", -
trunk/psModules/src/objects/pmSourcePlotApResid.c
r20937 r26893 34 34 #include "pmPSF.h" 35 35 #include "pmModel.h" 36 #include "pmDetections.h" 36 37 #include "pmSource.h" 37 38 #include "pmSourcePlots.h" … … 53 54 PS_ASSERT_PTR_NON_NULL(layout, false); 54 55 56 bool status; 55 57 Graphdata graphdata; 56 58 KapaSection section; … … 61 63 pmReadout *readout = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT"); 62 64 63 psArray *sources = psMetadataLookupPtr (NULL, readout->analysis, "PSPHOT.SOURCES"); 64 if (sources == NULL) 65 return false; 65 pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS"); 66 if (detections == NULL) return false; 67 68 psArray *sources = detections->allSources; 69 if (sources == NULL) return false; 66 70 67 71 int kapa = pmKapaOpen (false); -
trunk/psModules/src/objects/pmSourcePlotMoments.c
r20937 r26893 37 37 #include "pmPSF.h" 38 38 #include "pmModel.h" 39 #include "pmDetections.h" 39 40 #include "pmSource.h" 40 41 #include "pmSourcePlots.h" … … 54 55 PS_ASSERT_PTR_NON_NULL(layout, false); 55 56 57 bool status; 56 58 Graphdata graphdata; 57 59 KapaSection section; … … 62 64 pmReadout *readout = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT"); 63 65 64 psArray *sources = psMetadataLookupPtr (NULL, readout->analysis, "PSPHOT.SOURCES"); 65 if (sources == NULL) 66 return false; 66 pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS"); 67 if (detections == NULL) return false; 68 69 psArray *sources = detections->allSources; 70 if (sources == NULL) return false; 67 71 68 72 int kapa = pmKapaOpen (false); -
trunk/psModules/src/objects/pmSourcePlotPSFModel.c
r20937 r26893 37 37 #include "pmPSF.h" 38 38 #include "pmModel.h" 39 #include "pmDetections.h" 39 40 #include "pmSource.h" 40 41 #include "pmSourcePlots.h" … … 56 57 PS_ASSERT_PTR_NON_NULL(layout, false); 57 58 59 bool status; 58 60 Graphdata graphdata; 59 61 KapaSection section; … … 64 66 pmReadout *readout = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT"); 65 67 66 psArray *sources = psMetadataLookupPtr (NULL, readout->analysis, "PSPHOT.SOURCES"); 67 if (sources == NULL) 68 return false; 68 pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS"); 69 if (detections == NULL) return false; 70 71 psArray *sources = detections->allSources; 72 if (sources == NULL) return false; 69 73 70 74 int kapa = pmKapaOpen (false); -
trunk/psModules/src/psmodules.h
r26682 r26893 79 79 #include <pmRemnance.h> 80 80 #include <pmPattern.h> 81 #include <pmPatternIO.h> 81 82 82 83 // the following headers are from psModule:astrom … … 97 98 #include <pmSubtractionStamps.h> 98 99 #include <pmSubtractionKernels.h> 100 #include <pmSubtractionDeconvolve.h> 99 101 #include <pmSubtractionAnalysis.h> 100 102 #include <pmSubtractionMatch.h>
Note:
See TracChangeset
for help on using the changeset viewer.
