Changeset 34404 for trunk/psphot/src/psphotDeblendSatstars.c
- Timestamp:
- Sep 5, 2012, 4:19:30 PM (14 years ago)
- Location:
- trunk/psphot
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/psphot
- Property svn:mergeinfo changed
/branches/eam_branches/ipp-20120805/psphot (added) merged: 34360,34368-34369,34377-34378,34380,34392,34399
- Property svn:mergeinfo changed
-
trunk/psphot/src
- Property svn:mergeinfo changed
/branches/eam_branches/ipp-20120805/psphot/src (added) merged: 34360,34368-34369,34377-34378,34380,34392,34399
- Property svn:mergeinfo changed
-
trunk/psphot/src/psphotDeblendSatstars.c
r31154 r34404 1 1 # include "psphotInternal.h" 2 3 typedef struct { 4 float min; 5 float max; 6 float lower20; 7 float upper20; 8 int Npts; 9 } QuickStats; 10 11 bool psImageQuickStats (QuickStats *stats, psImage *image, psRegion region); 12 float InterpolateValues (float X0, float Y0, float X1, float Y1, float X); 13 bool psphotVisualScaleImage (int kapaFD, psImage *inImage, psImage *inMask, const char *name, float factor, int channel); 2 14 3 15 // for now, let's store the detections on the readout->analysis for each readout … … 16 28 } 17 29 30 /** this function does 3 things: 31 32 1) choose likely saturated stars 33 - mode | SATSTAR 34 - if moments->Peak > 0.5*SATURATION, examine region of peak pixels (ensure we go down to 0.1*SAT) for SAT mask 35 36 2) adjust the window for saturated objects 37 38 3) measure the radial profile 39 40 4) subtract the radial profile 41 42 TBD: 43 44 * function to replace the radial profile for a source 45 * recenter the profile (based on cross-correlation / convolution with 1D profile) 46 47 * raise a bit somewhere for these super saturated stars (if they were so modeled) 48 * consider the subtraction bit : when to raise it? 49 50 **/ 51 18 52 bool psphotDeblendSatstarsReadout (pmConfig *config, const pmFPAview *view, const char *filerule, int fileIndex) { 53 54 int N; 55 pmSource *source; 56 bool status; 57 58 // XXX disable this function for now 59 return true; 60 61 psTimerStart ("psphot.deblend.sat"); 62 63 // find the currently selected readout 64 pmFPAfile *file = pmFPAfileSelectSingle(config->files, filerule, fileIndex); // File of interest 65 psAssert (file, "missing file?"); 66 67 pmReadout *readout = pmFPAviewThisReadout(view, file->fpa); 68 psAssert (readout, "missing readout?"); 69 70 pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS"); 71 psAssert (detections, "missing detections?"); 72 73 psArray *sources = detections->newSources; 74 psAssert (sources, "missing sources?"); 75 76 if (!sources->n) { 77 psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping satstar blend"); 78 return true; 79 } 80 81 // select the appropriate recipe information 82 psMetadata *recipe = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE); 83 psAssert (recipe, "missing recipe?"); 84 85 // user-defined masks to test for good/bad pixels (build from recipe list if not yet set) 86 psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels 87 assert (maskVal); 88 89 // user-defined masks to test for good/bad pixels (build from recipe list if not yet set) 90 psImageMaskType maskSat = psMetadataLookupImageMask(&status, recipe, "MASK.SAT"); // Mask value for bad pixels 91 assert (maskSat); 92 93 float SATURATION = NAN; 94 { 95 // XXX do we need to set this differently from the value used to mark saturated pixels? 96 pmCell *cell = readout->parent; 97 98 // do not completely trust the values in the header... 99 float CELL_SATURATION = psMetadataLookupF32 (&status, cell->concepts, "CELL.SATURATION"); 100 float MIN_SATURATION = psMetadataLookupF32 (&status, recipe, "DEBLEND_MIN_SATURATION"); 101 if (!status || !isfinite(MIN_SATURATION)) { 102 MIN_SATURATION = 40000.0; 103 } 104 if (!isfinite(CELL_SATURATION)) { 105 SATURATION = MIN_SATURATION; 106 } else { 107 SATURATION = PS_MAX(MIN_SATURATION, CELL_SATURATION); 108 } 109 } 110 111 // source analysis is done in peak order (brightest first) 112 // we use an index for this so the spatial sorting is kept 113 psVector *SN = psVectorAlloc (sources->n, PS_DATA_F32); 114 for (int i = 0; i < SN->n; i++) { 115 source = sources->data[i]; 116 SN->data.F32[i] = source->moments->SN; 117 } 118 psVector *index = psVectorSortIndex (NULL, SN); 119 // this results in an index of increasing SN 120 121 // psphotVisualPlotRadialProfiles (recipe, sources, PM_SOURCE_MODE_SATSTAR); 122 123 int BIG_RADIUS = 250; 124 int BIG_SIGMA = BIG_RADIUS / 4.0; 125 126 int display = psphotKapaChannel (1); 127 psphotVisualScaleImage (display, (psImage *) source->pixels->parent, NULL, "image", 1.0, 0); 128 129 // examine sources in decreasing SN order 130 for (int i = sources->n - 1; i >= 0; i--) { 131 N = index->data.U32[i]; 132 source = sources->data[N]; 133 134 bool isSat = source->mode & PM_SOURCE_MODE_SATSTAR; 135 136 // for fairly bright stars, check the pixels near the peak again 137 if (source->moments->Peak > 0.5*SATURATION) { 138 // pmSourceRoughClass does this analysis, but uses a small (5x5) window. 139 // here we use a larger window since stacks can have some funny features 140 psRegion inner; 141 QuickStats stats; 142 // grow out the search radius until we have lower20 < 0.1*SATURATION 143 for (int radius = 2; radius < 30; radius ++) { 144 inner = psRegionForSquare (source->peak->x, source->peak->y, radius); 145 inner = psRegionForImage (source->maskView, inner); 146 psImageQuickStats (&stats, readout->image, inner); 147 if ((stats.Npts > 1) && (stats.lower20 < 0.1*SATURATION)) break; 148 } 149 int Nsatpix = psImageCountPixelMask (source->maskView, inner, maskSat); 150 // fprintf (stderr, "test object: %d,%d : %d vs %d : %f - %f - %f - %f\n", 151 // source->peak->x, source->peak->y, Nsatpix, stats.Npts, 152 // stats.min, stats.lower20, stats.upper20, stats.max); 153 if (Nsatpix > 1) isSat = true; 154 } 155 if (!isSat) continue; 156 157 // For saturated stars, choose a much larger box NOTE this is slightly sleazy, but 158 // only slightly: pmSourceRedefinePixels uses the readout to pass the pointers to 159 // the parent image data. I guess the API could be simplified: we could recover 160 // this from the source in the function 161 162 pmReadout tmpReadout; 163 tmpReadout.image = (psImage *)source->pixels->parent; 164 tmpReadout.mask = (psImage *)source->maskView->parent; 165 tmpReadout.variance = (psImage *)source->variance->parent; 166 167 // re-allocate image, weight, mask arrays for each peak with box big enough to fit BIG_RADIUS 168 pmSourceRedefinePixels (source, &tmpReadout, source->peak->x, source->peak->y, BIG_RADIUS + 2); 169 170 psTrace ("psphot", 4, "retrying moments for %d, %d\n", source->peak->x, source->peak->y); 171 status = pmSourceMoments (source, BIG_RADIUS, BIG_SIGMA, 0.0, 5.0, maskVal); 172 source->mode |= PM_SOURCE_MODE_BIG_RADIUS; 173 174 if (!psphotSatstarProfileModel (source, maskVal)) continue; 175 176 source->mode |= PM_SOURCE_MODE_SATSTAR; // yes, this source IS saturated 177 source->mode2 |= PM_SOURCE_MODE2_SATSTAR_PROFILE; // and we have in fact subtracted the profile 178 179 // XXX visualize, model, and subtract 180 // if (!psphotVisualRadialProfileSatstar (source, maskVal)) { 181 // break; 182 // } 183 184 // generate radial profile, store on the source structure 185 } 186 // show the image after object have been subtracted 187 psphotVisualScaleImage (display, (psImage *) source->pixels->parent, NULL, "image", 1.0, 1); 188 189 psFree (SN); 190 psFree (index); 191 192 psLogMsg ("psphot", PS_LOG_INFO, "deblend satstar: %f sec\n", psTimerMark ("psphot.deblend.sat")); 193 return true; 194 } 195 196 bool psphotDeblendSatstarsReadoutOld (pmConfig *config, const pmFPAview *view, const char *filerule, int fileIndex) { 19 197 20 198 int N; … … 219 397 return true; 220 398 } 399 400 // create a model for the radial profile of a saturated star (is this actually more generic?) 401 bool psphotSatstarProfileModel (pmSource *source, psImageMaskType maskVal) { 402 403 // XXX user define somewhere? 404 float Rmax = 320.0; 405 406 // XXX is this ever the case?? 407 bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED); 408 if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal); 409 410 int nPts = source->pixels->numRows * source->pixels->numCols; 411 psVector *logR = psVectorAllocEmpty (nPts, PS_TYPE_F32); 412 psVector *flux = psVectorAllocEmpty (nPts, PS_TYPE_F32); 413 414 int ng = 0; 415 416 // choose the best center for this profile 417 float Xo = NAN; 418 float Yo = NAN; 419 420 if (source->modelPSF) { 421 // XXX do we ever have a PSF model for a SATSTAR? 422 Xo = source->modelPSF->params->data.F32[PM_PAR_XPOS]; 423 Yo = source->modelPSF->params->data.F32[PM_PAR_YPOS]; 424 } else { 425 Xo = source->moments->Mx; 426 Yo = source->moments->My; 427 } 428 429 float Xc = Xo - source->pixels->col0 - 0.5; 430 float Yc = Yo - source->pixels->row0 - 0.5; 431 432 for (int iy = 0; iy < source->pixels->numRows; iy++) { 433 for (int ix = 0; ix < source->pixels->numCols; ix++) { 434 if ((source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & maskVal)) continue; 435 // XXX do this faster by generating R^2 and returning 0.5*log10(R^2)? 436 logR->data.F32[ng] = log10(hypot (ix - Xc, iy - Yc)); 437 flux->data.F32[ng] = source->pixels->data.F32[iy][ix]; 438 ng++; 439 } 440 } 441 logR->n = ng; 442 flux->n = ng; 443 444 // XXX do something sensible here if there are no pixels 445 446 // measure the radial profile 447 psVector *logFmodel = NULL; 448 psVector *logRmodel = NULL; 449 psphotSatstarProfileCreate (source, &logRmodel, &logFmodel, logR, flux, Rmax); 450 451 // XXX do something sensible here if the profile is crap 452 453 source->satstar = pmSourceSatstarAlloc(); 454 source->satstar->Xo = Xo; 455 source->satstar->Yo = Yo; 456 source->satstar->Rmax = Rmax; 457 source->satstar->logFmodel = logFmodel; 458 source->satstar->logRmodel = logRmodel; 459 460 // subtract the profile (false => subtract) 461 psphotSatstarProfileOp (source, maskVal, 1.0, 0, false); 462 463 psFree (logR); 464 psFree (flux); 465 466 return true; 467 } 468 469 // Take logR + flux and generate radial bins logRmodelOut, logFmodelOut 470 bool psphotSatstarProfileCreate (pmSource *source, psVector **logRmodelOut, psVector **logFmodelOut, psVector *logR, psVector *flux, float Rmax) { 471 472 // we have log(radius) & log(flux). find the median flux in log radial bins 473 474 float logRmax = log10(Rmax); 475 float logRdel = 0.1; // XXX user-define? 476 477 psVector *logRmodel = psVectorAlloc (1 + (int) (logRmax / logRdel), PS_TYPE_F32); 478 psVector *logFmodel = psVectorAlloc (1 + (int) (logRmax / logRdel), PS_TYPE_F32); 479 480 pmSourceRadialProfileSortPair (logR, flux); 481 482 psStats *fluxStats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN); 483 psVector *fluxVals = psVectorAllocEmpty (100, PS_TYPE_F32); 484 485 int bin = 0; 486 for (int i = 0; i < logRmodel->n; i++) { 487 488 // bin (i) has log radius range (i*logRdel : (i+1)*logRdel) 489 float lRmin = logRdel*(i + 0); 490 float lRmax = logRdel*(i + 1); 491 492 // reset the flux vector 493 fluxVals->n = 0; 494 psStatsInit (fluxStats); 495 496 while (logR->data.F32[bin] < lRmax) { 497 if (isfinite(flux->data.F32[bin])) { 498 psVectorAppend (fluxVals, flux->data.F32[bin]); 499 } 500 bin ++; 501 } 502 503 // we have the set of fluxes for this bin; find the median values 504 505 float Rmin = pow(10.0, lRmin); 506 float Rmax = pow(10.0, lRmax); 507 508 float Rmean = (2.0/3.0) * (pow(Rmax, 3.0) - pow(Rmin, 3.0)) / (PS_SQR(Rmax) - PS_SQR(Rmin)); 509 logRmodel->data.F32[i] = log10(Rmean); 510 511 float Area = M_PI * (PS_SQR(Rmax) - PS_SQR(Rmin)); 512 if (fluxVals->n < 0.25*Area) { 513 logFmodel->data.F32[i] = NAN; 514 continue; 515 } 516 517 psVectorStats (fluxStats, fluxVals, NULL, NULL, 0); 518 if (fluxStats->robustMedian > 0.0) { 519 logFmodel->data.F32[i] = log10(fluxStats->robustMedian); 520 } else { 521 logFmodel->data.F32[i] = -3.0; 522 } 523 // fprintf (stderr, "R: %f, F: %f +/- %f\n", Rmean, fluxStats->robustMedian, fluxStats->robustStdev); 524 } 525 526 // now how do i use this to subtract a model?? 527 *logRmodelOut = logRmodel; 528 *logFmodelOut = logFmodel; 529 530 // need to free stuff 531 psFree (fluxStats); 532 psFree (fluxVals); 533 534 return true; 535 } 536 537 bool psphotSatstarProfileOp (pmSource *source, psImageMaskType maskVal, float FACTOR, pmModelOpMode mode, bool add) { 538 539 int alt; 540 float logRdel = 0.1; 541 542 float Xc = source->satstar->Xo - source->pixels->col0 - 0.5; 543 float Yc = source->satstar->Yo - source->pixels->row0 - 0.5; 544 psVector *logRmodel = source->satstar->logRmodel; 545 psVector *logFmodel = source->satstar->logFmodel; 546 547 for (int iy = 0; iy < source->pixels->numRows; iy++) { 548 for (int ix = 0; ix < source->pixels->numCols; ix++) { 549 if ((source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & maskVal)) continue; 550 551 float radius = hypot (ix - Xc, iy - Yc) ; 552 float logR = log10(radius); 553 554 int bin = (int)(logR / logRdel); 555 556 // we are going to interpolate if possible, or extrapolate if necessary 557 if (bin >= logRmodel->n - 1) bin = logRmodel->n - 1; 558 if (bin < 0) bin = 0; 559 560 // interpolate to the current radial position 561 // XXX BIG HACK : skip nan bins for now 562 563 float logF0 = logFmodel->data.F32[bin]; 564 float logR0 = logRmodel->data.F32[bin]; 565 if (!isfinite(logF0)) continue; 566 567 // interpolate between closest two bins if possible, extrapolate on ends 568 if (logR < logR0) { 569 alt = (bin > 0) ? bin - 1 : bin + 1; 570 } else { 571 alt = (bin < logRmodel->n - 1) ? bin + 1 : bin - 1; 572 } 573 574 float logF1 = logFmodel->data.F32[alt]; 575 float logR1 = logRmodel->data.F32[alt]; 576 if (!isfinite(logF1)) continue; 577 578 // XXX use linear flux, not logFlux 579 float logF = InterpolateValues (logR0, logF0, logR1, logF1, logR); 580 float flux = pow (10.0, logF); 581 582 if (mode & PM_MODEL_OP_NOISE) { 583 if (add) { 584 source->variance->data.F32[iy][ix] += FACTOR * flux; 585 } else { 586 source->variance->data.F32[iy][ix] -= FACTOR * flux; 587 } 588 } else { 589 if (add) { 590 source->pixels->data.F32[iy][ix] += flux; 591 } else { 592 source->pixels->data.F32[iy][ix] -= flux; 593 } 594 } 595 } 596 } 597 return true; 598 } 599 600 // Take logR + flux and generate radial bins logRmodelOut, logFmodelOut 601 bool psphotSatstarPhotometry (pmSource *source) { 602 603 if (!source->satstar) return false; 604 605 psVector *logRmodel = source->satstar->logRmodel; 606 psVector *logFmodel = source->satstar->logFmodel; 607 608 float fluxTotal = 0.0; 609 float logRdel = 0.1; // XXX user-define (or carry in satstar) 610 611 // integrate flux in radial bins 612 for (int i = 0; i < logRmodel->n; i++) { 613 // just add up the mean flux in each bin and multiply by the area of the bin 614 615 float logF = logFmodel->data.F32[i]; 616 if (!isfinite(logF)) continue; 617 float flux = pow(10.0, logF); // this is the mean flux per pixel (ie, surface brightness) 618 619 // bin (i) has log radius range (i*logRdel : (i+1)*logRdel) 620 float lRmin = logRdel*(i + 0); 621 float lRmax = logRdel*(i + 1); 622 623 float Rmin = pow(10.0, lRmin); 624 float Rmax = pow(10.0, lRmax); 625 626 float Area = M_PI * (PS_SQR(Rmax) - PS_SQR(Rmin)); 627 628 fluxTotal += flux * Area; 629 } 630 631 source->psfMag = -2.5*log10(fluxTotal); 632 source->psfMagErr = 0.05; 633 634 // XXX I have no idea of a realistic error on the photometry here. the bottom line is that 635 // the error is totally dominated by the loss of charge due to saturation. I am not 636 // modeling the profile in any real detail other than to follow the radial bins. 637 638 source->extMag = NAN; 639 source->apMag = NAN; 640 source->apMagRaw = NAN; 641 source->apFlux = fluxTotal; 642 source->apFluxErr = 0.05*fluxTotal; 643 644 return true; 645 } 646 647 # if (0) 648 static bool skipDisplay = false; 649 bool psphotVisualRadialProfileSatstar (pmSource *source, psImageMaskType maskVal) { 650 651 int kapaImage = -1; 652 int kapaGraph = -1; 653 Graphdata graphdata; 654 655 if (!pmVisualTestLevel("psphot.satstar", 3)) { 656 skipDisplay = true; 657 } 658 659 float Rmax = 320.0; 660 661 bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED); 662 if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal); 663 664 int nPts = source->pixels->numRows * source->pixels->numCols; 665 psVector *rg = psVectorAllocEmpty (nPts, PS_TYPE_F32); 666 psVector *Rg = psVectorAllocEmpty (nPts, PS_TYPE_F32); 667 psVector *fg = psVectorAllocEmpty (nPts, PS_TYPE_F32); 668 psVector *Fg = psVectorAllocEmpty (nPts, PS_TYPE_F32); 669 psVector *rb = psVectorAllocEmpty (nPts, PS_TYPE_F32); 670 psVector *Rb = psVectorAllocEmpty (nPts, PS_TYPE_F32); 671 psVector *fb = psVectorAllocEmpty (nPts, PS_TYPE_F32); 672 673 int ng = 0; 674 int nb = 0; 675 676 float Xo = NAN; 677 float Yo = NAN; 678 679 if (source->modelPSF) { 680 Xo = source->modelPSF->params->data.F32[PM_PAR_XPOS] - source->pixels->col0; 681 Yo = source->modelPSF->params->data.F32[PM_PAR_YPOS] - source->pixels->row0; 682 } else { 683 Xo = source->moments->Mx - source->pixels->col0; 684 Yo = source->moments->My - source->pixels->row0; 685 } 686 687 for (int iy = 0; iy < source->pixels->numRows; iy++) { 688 for (int ix = 0; ix < source->pixels->numCols; ix++) { 689 if ((source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & maskVal)) { 690 rb->data.F32[nb] = hypot (ix + 0.5 - Xo, iy + 0.5 - Yo) ; 691 // rb->data.F32[nb] = hypot (ix - Xo, iy - Yo) ; 692 Rb->data.F32[nb] = log10(rb->data.F32[nb]); 693 fb->data.F32[nb] = log10(source->pixels->data.F32[iy][ix]); 694 nb++; 695 } else { 696 rg->data.F32[ng] = hypot (ix + 0.5 - Xo, iy + 0.5 - Yo) ; 697 // rg->data.F32[ng] = hypot (ix - Xo, iy - Yo) ; 698 Rg->data.F32[ng] = log10(rg->data.F32[ng]); 699 Fg->data.F32[ng] = source->pixels->data.F32[iy][ix]; 700 fg->data.F32[ng] = log10(Fg->data.F32[ng]); 701 ng++; 702 } 703 } 704 } 705 rg->n = ng; 706 Rg->n = ng; 707 fg->n = ng; 708 Fg->n = ng; 709 rb->n = nb; 710 Rb->n = nb; 711 fb->n = nb; 712 713 if (!skipDisplay) { 714 kapaImage = psphotKapaChannel (1); 715 if (kapaImage == -1) return false; 716 717 kapaGraph = psphotKapaChannel (2); 718 if (kapaGraph == -1) return false; 719 720 KapaSection section; // put the positive profile in one and the residuals in another? 721 722 // first section : mag vs CR nSigma 723 section.dx = 1.0; 724 section.dy = 0.5; 725 section.x = 0.0; 726 section.y = 0.0; 727 section.bg = -1; 728 section.name = NULL; 729 psStringAppend (§ion.name, "linlog"); 730 KapaSetSection (kapaGraph, §ion); 731 psFree (section.name); 732 733 // first section : mag vs CR nSigma 734 section.dx = 1.0; 735 section.dy = 0.5; 736 section.x = 0.0; 737 section.y = 0.5; 738 section.bg = -1; 739 section.name = NULL; 740 psStringAppend (§ion.name, "loglog"); 741 KapaSetSection (kapaGraph, §ion); 742 psFree (section.name); 743 744 KapaInitGraph (&graphdata); 745 746 // ** linlog ** 747 KapaSelectSection (kapaGraph, "linlog"); 748 749 // examine sources to set data range 750 graphdata.xmin = -0.05; 751 graphdata.xmax = Rmax + 0.05; 752 graphdata.ymin = -0.05; 753 graphdata.ymax = +8.05; 754 KapaSetLimits (kapaGraph, &graphdata); 755 756 KapaSetFont (kapaGraph, "helvetica", 14); 757 KapaBox (kapaGraph, &graphdata); 758 KapaSendLabel (kapaGraph, "radius (pixels)", KAPA_LABEL_XM); 759 KapaSendLabel (kapaGraph, "log flux (counts)", KAPA_LABEL_YM); 760 761 graphdata.color = KapaColorByName ("black"); 762 graphdata.ptype = 2; 763 graphdata.size = 0.5; 764 graphdata.style = 2; 765 KapaPrepPlot (kapaGraph, ng, &graphdata); 766 KapaPlotVector (kapaGraph, ng, rg->data.F32, "x"); 767 KapaPlotVector (kapaGraph, ng, fg->data.F32, "y"); 768 769 graphdata.color = KapaColorByName ("red"); 770 graphdata.ptype = 0; 771 graphdata.size = 0.3; 772 graphdata.style = 2; 773 KapaPrepPlot (kapaGraph, nb, &graphdata); 774 KapaPlotVector (kapaGraph, nb, rb->data.F32, "x"); 775 KapaPlotVector (kapaGraph, nb, fb->data.F32, "y"); 776 777 // ** loglog ** 778 KapaSelectSection (kapaGraph, "loglog"); 779 780 // examine sources to set data range 781 graphdata.xmin = -1.51; 782 graphdata.xmax = log10(Rmax) + 0.02; 783 graphdata.ymin = -5.05; 784 graphdata.ymax = +8.05; 785 graphdata.color = KapaColorByName ("black"); 786 KapaSetLimits (kapaGraph, &graphdata); 787 788 KapaSetFont (kapaGraph, "helvetica", 14); 789 KapaBox (kapaGraph, &graphdata); 790 KapaSendLabel (kapaGraph, "log radius (pixels)", KAPA_LABEL_XM); 791 KapaSendLabel (kapaGraph, "log flux (counts)", KAPA_LABEL_YM); 792 793 graphdata.color = KapaColorByName ("black"); 794 graphdata.ptype = 2; 795 graphdata.size = 0.5; 796 graphdata.style = 2; 797 KapaPrepPlot (kapaGraph, ng, &graphdata); 798 KapaPlotVector (kapaGraph, ng, Rg->data.F32, "x"); 799 KapaPlotVector (kapaGraph, ng, fg->data.F32, "y"); 800 801 graphdata.color = KapaColorByName ("red"); 802 graphdata.ptype = 0; 803 graphdata.size = 0.3; 804 graphdata.style = 2; 805 KapaPrepPlot (kapaGraph, nb, &graphdata); 806 KapaPlotVector (kapaGraph, nb, Rb->data.F32, "x"); 807 KapaPlotVector (kapaGraph, nb, fb->data.F32, "y"); 808 } 809 810 // measure the radial profile 811 psVector *logFmodel = NULL; 812 psVector *logRmodel = NULL; 813 psphotTestRadialModel (source, &logRmodel, &logFmodel, Rg, Fg, Rmax); 814 815 if (!skipDisplay) { 816 graphdata.color = KapaColorByName ("red"); 817 graphdata.ptype = 2; 818 graphdata.size = 1.0; 819 graphdata.style = 2; 820 KapaPrepPlot (kapaGraph, logRmodel->n, &graphdata); 821 KapaPlotVector (kapaGraph, logRmodel->n, logRmodel->data.F32, "x"); 822 KapaPlotVector (kapaGraph, logRmodel->n, logFmodel->data.F32, "y"); 823 } 824 825 // subtract the model from the images 826 psphotTestRadialModelSub (source, logRmodel, logFmodel, Xo, Yo, Rmax, maskVal); 827 828 psFree (logRmodel); 829 psFree (logFmodel); 830 831 if (!skipDisplay && source->modelPSF) { 832 // generate model profiles (major and minor axis): 833 // create a model with theta = 0.0 so major and minor axes are equiv to x and y: 834 psEllipseShape rawShape, rotShape; 835 836 rawShape.sx = source->modelPSF->params->data.F32[PM_PAR_SXX] / M_SQRT2; 837 rawShape.sy = source->modelPSF->params->data.F32[PM_PAR_SYY] / M_SQRT2; 838 rawShape.sxy = source->modelPSF->params->data.F32[PM_PAR_SXY]; 839 840 psEllipseAxes axes = psEllipseShapeToAxes (rawShape, 20.0); 841 842 axes.theta = 0.0; 843 844 rotShape = psEllipseAxesToShape (axes); 845 846 psVector *params = psVectorAlloc(source->modelPSF->params->n, PS_TYPE_F32); 847 for (int i = 0; i < source->modelPSF->params->n; i++) { 848 params->data.F32[i] = source->modelPSF->params->data.F32[i]; 849 } 850 params->data.F32[PM_PAR_SXX] = rotShape.sx * M_SQRT2; 851 params->data.F32[PM_PAR_SYY] = rotShape.sy * M_SQRT2; 852 params->data.F32[PM_PAR_SXY] = rotShape.sxy; 853 params->data.F32[PM_PAR_XPOS] = 0.0; 854 params->data.F32[PM_PAR_YPOS] = 0.0; 855 856 psVector *rmod = psVectorAlloc(Rmax*10, PS_TYPE_F32); 857 psVector *fmaj = psVectorAlloc(Rmax*10, PS_TYPE_F32); 858 psVector *fmin = psVectorAlloc(Rmax*10, PS_TYPE_F32); 859 860 psVector *coord = psVectorAlloc(2, PS_TYPE_F32); 861 862 float r = 0.0; 863 for (int i = 0; i < rmod->n; i++) { 864 r = i*0.1; 865 rmod->data.F32[i] = r; 866 867 coord->data.F32[1] = r; 868 coord->data.F32[0] = 0.0; 869 fmaj->data.F32[i] = log10(source->modelPSF->modelFunc (NULL, params, coord)); 870 871 coord->data.F32[0] = r; 872 coord->data.F32[1] = 0.0; 873 fmin->data.F32[i] = log10(source->modelPSF->modelFunc (NULL, params, coord)); 874 } 875 psFree (coord); 876 psFree (params); 877 878 float FWHM_MAJOR = 2.0*source->modelPSF->modelRadius (source->modelPSF->params, 0.5*source->modelPSF->params->data.F32[PM_PAR_I0]); 879 float FWHM_MINOR = FWHM_MAJOR * (axes.minor / axes.major); 880 if (FWHM_MAJOR < FWHM_MINOR) PS_SWAP (FWHM_MAJOR, FWHM_MINOR); 881 882 psEllipseMoments emoments; 883 emoments.x2 = source->moments->Mxx; 884 emoments.xy = source->moments->Mxy; 885 emoments.y2 = source->moments->Myy; 886 axes = psEllipseMomentsToAxes (emoments, 20.0); 887 float MOMENTS_MAJOR = 2.355*axes.major; 888 float MOMENTS_MINOR = 2.355*axes.minor; 889 890 float logHM = log10(0.5*source->modelPSF->params->data.F32[PM_PAR_I0]); 891 892 // reset source Add/Sub state to recorded 893 if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal); 894 895 // ** linlog ** 896 KapaSelectSection (kapaGraph, "linlog"); 897 KapaGetGraphData (kapaGraph, &graphdata); 898 graphdata.color = KapaColorByName ("blue"); 899 graphdata.ptype = 0; 900 graphdata.size = 0.0; 901 graphdata.style = 0; 902 KapaPrepPlot (kapaGraph, rmod->n, &graphdata); 903 KapaPlotVector (kapaGraph, rmod->n, rmod->data.F32, "x"); 904 KapaPlotVector (kapaGraph, rmod->n, fmin->data.F32, "y"); 905 plotline (kapaGraph, &graphdata, graphdata.xmin, logHM, graphdata.xmax, logHM); 906 plotline (kapaGraph, &graphdata, 0.5*FWHM_MINOR, graphdata.ymin, 0.5*FWHM_MINOR, graphdata.ymax); 907 graphdata.ltype = 1; 908 plotline (kapaGraph, &graphdata, 0.5*MOMENTS_MINOR, graphdata.ymin, 0.5*MOMENTS_MINOR, graphdata.ymax); 909 graphdata.ltype = 0; 910 911 graphdata.color = KapaColorByName ("green"); 912 graphdata.ptype = 0; 913 graphdata.size = 0.0; 914 graphdata.style = 0; 915 KapaPrepPlot (kapaGraph, rmod->n, &graphdata); 916 KapaPlotVector (kapaGraph, rmod->n, rmod->data.F32, "x"); 917 KapaPlotVector (kapaGraph, rmod->n, fmaj->data.F32, "y"); 918 plotline (kapaGraph, &graphdata, 0.5*FWHM_MAJOR, graphdata.ymin, 0.5*FWHM_MAJOR, graphdata.ymax); 919 graphdata.ltype = 1; 920 plotline (kapaGraph, &graphdata, 0.5*MOMENTS_MAJOR, graphdata.ymin, 0.5*MOMENTS_MAJOR, graphdata.ymax); 921 graphdata.ltype = 0; 922 923 for (int i = 0; i < rmod->n; i++) { 924 rmod->data.F32[i] = log10(rmod->data.F32[i]); 925 } 926 927 // ** loglog ** 928 KapaSelectSection (kapaGraph, "loglog"); 929 KapaGetGraphData (kapaGraph, &graphdata); 930 graphdata.color = KapaColorByName ("blue"); 931 graphdata.ptype = 0; 932 graphdata.size = 0.0; 933 graphdata.style = 0; 934 KapaPrepPlot (kapaGraph, rmod->n, &graphdata); 935 KapaPlotVector (kapaGraph, rmod->n, rmod->data.F32, "x"); 936 KapaPlotVector (kapaGraph, rmod->n, fmin->data.F32, "y"); 937 938 graphdata.color = KapaColorByName ("green"); 939 graphdata.ptype = 0; 940 graphdata.size = 0.0; 941 graphdata.style = 0; 942 KapaPrepPlot (kapaGraph, rmod->n, &graphdata); 943 KapaPlotVector (kapaGraph, rmod->n, rmod->data.F32, "x"); 944 KapaPlotVector (kapaGraph, rmod->n, fmaj->data.F32, "y"); 945 946 psFree (rmod); 947 psFree (fmin); 948 psFree (fmaj); 949 } 950 951 if (!skipDisplay) { 952 KiiCenter (kapaImage, source->peak->xf, source->peak->yf, 1); 953 psphotVisualScaleImage (kapaImage, (psImage *) source->pixels->parent, NULL, "image", 1.0, 1); 954 KiiOverlay overlay; 955 overlay.x = source->peak->xf; 956 overlay.y = source->peak->yf; 957 overlay.dx = 5; 958 overlay.dy = 5; 959 overlay.angle = 0.0; 960 overlay.type = KiiOverlayTypeByName ("circle"); 961 KiiLoadOverlay (kapaImage, &overlay, 1, "red"); 962 overlay.x = source->moments->Mx; 963 overlay.y = source->moments->My; 964 overlay.dx = 8; 965 overlay.dy = 8; 966 overlay.angle = 0.0; 967 overlay.type = KiiOverlayTypeByName ("circle"); 968 KiiLoadOverlay (kapaImage, &overlay, 1, "blue"); 969 } 970 971 psFree (rg); 972 psFree (Rg); 973 psFree (fg); 974 psFree (Fg); 975 psFree (rb); 976 psFree (Rb); 977 psFree (fb); 978 979 if (skipDisplay) return true; 980 981 // pause and wait for user input: 982 // continue, save (provide name), ?? 983 char key[10]; 984 fprintf (stdout, "[q]uit satstar? [e]rase and continue? [o]verplot and continue? [s]kip rest of stars? : "); 985 if (!fgets(key, 8, stdin)) { 986 psWarning("Unable to read option"); 987 } 988 if (key[0] == 'e') { 989 KapaClearPlots (kapaGraph); 990 } 991 if (key[0] == 'q') { 992 return false; 993 } 994 if (key[0] == 's') { 995 skipDisplay = true; 996 } 997 return true; 998 } 999 # endif 1000 1001 // only valid for F32 1002 bool psImageQuickStats (QuickStats *stats, psImage *image, psRegion region) { 1003 1004 psAssert (image->type.type == PS_TYPE_F32, "unsupported image type"); 1005 1006 int Npix = (region.y1 - region.y0) * (region.x1 - region.x0); 1007 psVector *tmp = psVectorAllocEmpty (Npix, PS_TYPE_F32); 1008 1009 int bin = 0; 1010 for (int iy = region.y0; iy < region.y1; iy++) { 1011 for (int ix = region.x0; ix < region.x1; ix++) { 1012 if (!isfinite(image->data.F32[iy][ix])) continue; 1013 tmp->data.F32[bin] = image->data.F32[iy][ix]; 1014 bin ++; 1015 } 1016 } 1017 tmp->n = bin; 1018 1019 if (bin < 1) { 1020 stats->min = NAN; 1021 stats->lower20 = NAN; 1022 stats->upper20 = NAN; 1023 stats->max = NAN; 1024 stats->Npts = 0; 1025 psFree (tmp); 1026 return true; 1027 } 1028 1029 1030 psVectorSortInPlace (tmp); 1031 1032 int N20 = 0.2*tmp->n; 1033 int N80 = 0.8*tmp->n; 1034 int Nmax = tmp->n - 1; 1035 1036 stats->min = tmp->data.F32[0]; 1037 stats->lower20 = tmp->data.F32[N20]; 1038 stats->upper20 = tmp->data.F32[N80]; 1039 stats->max = tmp->data.F32[Nmax]; 1040 stats->Npts = bin; 1041 psFree (tmp); 1042 1043 return true; 1044 } 1045 1046 bool psphotAddOrSubSatstarsReadout (pmConfig *config, const pmFPAview *view, const char *filerule, int fileIndex, psMetadata *recipe, bool add) { 1047 1048 bool status; 1049 1050 psTimerStart ("psphot.deblend.sat"); 1051 1052 // find the currently selected readout 1053 pmFPAfile *file = pmFPAfileSelectSingle(config->files, filerule, fileIndex); // File of interest 1054 psAssert (file, "missing file?"); 1055 1056 pmReadout *readout = pmFPAviewThisReadout(view, file->fpa); 1057 psAssert (readout, "missing readout?"); 1058 1059 pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS"); 1060 psAssert (detections, "missing detections?"); 1061 1062 psArray *sources = detections->allSources; 1063 psAssert (sources, "missing sources?"); 1064 1065 if (!sources->n) { 1066 psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping satstar blend"); 1067 return true; 1068 } 1069 1070 // user-defined masks to test for good/bad pixels (build from recipe list if not yet set) 1071 psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels 1072 assert (maskVal); 1073 1074 // examine sources in decreasing SN order 1075 for (int i = 0; i < sources->n; i++) { 1076 pmSource *source = sources->data[i]; 1077 1078 if (!(source->mode2 & PM_SOURCE_MODE2_SATSTAR_PROFILE)) continue; 1079 1080 if (!psphotSatstarProfileOp (source, maskVal, 1.0, 0, add)) continue; 1081 } 1082 1083 psLogMsg ("psphot", PS_LOG_DETAIL, "satstar op: %f sec\n", psTimerMark ("psphot.deblend.sat")); 1084 return true; 1085 } 1086
Note:
See TracChangeset
for help on using the changeset viewer.
