IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Sep 5, 2012, 4:19:30 PM (14 years ago)
Author:
eugene
Message:

adding SATSTAR profile code (but keeping it disabled for now)

Location:
trunk/psphot
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/psphot

  • trunk/psphot/src

  • trunk/psphot/src/psphotDeblendSatstars.c

    r31154 r34404  
    11# include "psphotInternal.h"
     2
     3typedef struct {
     4    float min;
     5    float max;
     6    float lower20;
     7    float upper20;
     8    int Npts;
     9} QuickStats;
     10
     11bool psImageQuickStats (QuickStats *stats, psImage *image, psRegion region);
     12float InterpolateValues (float X0, float Y0, float X1, float Y1, float X);
     13bool psphotVisualScaleImage (int kapaFD, psImage *inImage, psImage *inMask, const char *name, float factor, int channel);
    214
    315// for now, let's store the detections on the readout->analysis for each readout
     
    1628}
    1729
     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
    1852bool 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
     196bool psphotDeblendSatstarsReadoutOld (pmConfig *config, const pmFPAview *view, const char *filerule, int fileIndex) {
    19197
    20198    int N;
     
    219397    return true;
    220398}
     399
     400// create a model for the radial profile of a saturated star (is this actually more generic?)
     401bool 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
     470bool 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
     537bool 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
     601bool 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)
     648static bool skipDisplay = false;
     649bool 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 (&section.name, "linlog");
     730        KapaSetSection (kapaGraph, &section);
     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 (&section.name, "loglog");
     741        KapaSetSection (kapaGraph, &section);
     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
     1002bool 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
     1046bool 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.