IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 34404


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:
22 edited

Legend:

Unmodified
Added
Removed
  • trunk/psphot

  • trunk/psphot/src

  • trunk/psphot/src/psphot.h

    r34354 r34404  
    281281bool            psphotVisualShowSatStars (psMetadata *recipe, pmPSF *psf, psArray *sources);
    282282bool            psphotVisualShowPSFModel (pmReadout *readout, pmPSF *psf);
    283 bool            psphotVisualPlotRadialProfile (int myKapa, pmSource *source, psImageMaskType maskVal);
    284 bool            psphotVisualPlotRadialProfiles (psMetadata *recipe, psArray *sources);
     283bool            psphotVisualPlotRadialProfile (int myKapa, pmSource *source, psImageMaskType maskVal, pmSourceMode showmode);
     284bool            psphotVisualPlotRadialProfiles (psMetadata *recipe, psArray *sources, pmSourceMode showmode);
    285285bool            psphotVisualShowFlags (psArray *sources);
    286286bool            psphotVisualShowSourceSize (pmReadout *readout, psArray *sources);
     
    295295bool            psphotVisualClose(void);
    296296
     297int             psphotKapaChannel (int channel);
     298void            plotline (int myKapa, Graphdata *graphdata, float x0, float y0, float x1, float y1);
     299
     300
    297301bool psphotPetrosian (pmSource *source, psMetadata *recipe, float skynoise, psImageMaskType maskVal);
    298302bool psphotPetrosianRadialBins (pmSource *source, float radiusMax, float skynoise);
     
    511515    );
    512516
     517bool psphotSatstarProfileModel (pmSource *source, psImageMaskType maskVal);
     518bool psphotSatstarProfileCreate (pmSource *source, psVector **logRmodelOut, psVector **logFmodelOut, psVector *logR, psVector *flux, float Rmax);
     519bool psphotSatstarProfileOp (pmSource *source, psImageMaskType maskVal, float FACTOR, pmModelOpMode mode, bool add);
     520bool psphotVisualRadialProfileSatstar (pmSource *source, psImageMaskType maskVal);
     521bool psphotAddOrSubSatstarsReadout (pmConfig *config, const pmFPAview *view, const char *filerule, int fileIndex, psMetadata *recipe, bool add);
     522bool psphotSatstarPhotometry (pmSource *source);
     523
    513524bool psphotSourceMemory(pmConfig *config, const pmFPAview *view, const char *filerule);
    514525bool psphotSourceMemoryReadout(pmConfig *config, const pmFPAview *view, const char *filerule, int index);
  • trunk/psphot/src/psphotAddNoise.c

    r33980 r34404  
    7676    }
    7777
     78    psphotVisualShowImage (readout);
     79
    7880    // loop over all source
    7981    for (int i = 0; i < sources->n; i++) {
    8082        pmSource *source = sources->data[i];
     83
     84        // add or subtract noise for a saturated star.  satstars modeled as a radial profile
     85        // need special handling
     86        if (source->mode2 & PM_SOURCE_MODE2_SATSTAR_PROFILE) {
     87            psphotSatstarProfileOp (source, maskVal, FACTOR, PM_MODEL_OP_NOISE, add);
     88            continue;
     89        }
    8190
    8291        // skip sources which were not subtracted
     
    92101    }
    93102
     103    psphotVisualShowImage (readout);
     104
    94105    return true;
    95106}
  • trunk/psphot/src/psphotApResid.c

    r34363 r34404  
    200200        if (source->mode &  PM_SOURCE_MODE_FAIL) SKIPSTAR ("FAIL STAR");
    201201        if (source->mode &  PM_SOURCE_MODE_POOR) SKIPSTAR ("POOR STAR");
     202
     203        // skip saturated stars modeled with a radial profile
     204        if (source->mode2 & PM_SOURCE_MODE2_SATSTAR_PROFILE) SKIPSTAR ("SATSTAR");
    202205
    203206        if (source->mode &  PM_SOURCE_MODE_EXT_LIMIT) SKIPSTAR ("EXTENDED");
  • trunk/psphot/src/psphotBlendFit.c

    r34258 r34404  
    11# include "psphotInternal.h"
     2bool psphotBlendFitSetSource(pmSource *source, psImage *IDimage, float sigSigma);
    23
    34// for now, let's store the detections on the readout->analysis for each readout
     
    9293    float skySig = psMetadataLookupF32(&status, recipe, "SKY_SIG");
    9394    assert (status && isfinite(skySig) && skySig > 0);
     95
     96# if (0)
     97    // **** test block : generate an ID image where pixels are set based the source models (flux > 0.1 peak && flux > 2.0 skySig)
     98    psImage *IDimage = psImageAlloc (readout->image->numCols, readout->image->numRows, PS_TYPE_S32);
     99    psImageInit (IDimage, 0);
     100
     101    // start with the currently known moments (Mxx, Myy, Mxy) and generate a window image
     102    for (int i = 0; i < sources->n; i++) {
     103        pmSource *source = sources->data[i];
     104        psphotBlendFitSetSource (source, IDimage, skySig);
     105    }
     106    psphotSaveImage (NULL, IDimage, "idimage.fits");
     107# endif
    94108
    95109    // Define source fitting parameters for extended source fits
     
    241255        pmSource *source = sources->data[i];
    242256
    243 # if (0)
    244 # define TEST_X 34
    245 # define TEST_Y 28
    246    
     257        int TEST_ON = false;
     258# if (1)
     259# define TEST_X 653
     260# define TEST_Y 466
    247261        if ((fabs(source->peak->xf - TEST_X) < 5) && (fabs(source->peak->yf - TEST_Y) < 5)) {
    248262            fprintf (stderr, "test object\n");
    249         }
    250 
     263            //  psTraceSetLevel("psLib.math.psMinimizeLMChi2", 5);
     264            TEST_ON = true;
     265        }
    251266# undef TEST_X
    252267# undef TEST_Y
     
    258273        if (source->type == PM_SOURCE_TYPE_DEFECT) continue;
    259274        if (source->type == PM_SOURCE_TYPE_SATURATED) continue;
     275
     276        // skip saturated stars modeled with a radial profile
     277        if (source->mode2 & PM_SOURCE_MODE2_SATSTAR_PROFILE) continue;
    260278
    261279        // skip DBL second sources (ie, added by psphotFitBlob
     
    306324        if (source->mode & PM_SOURCE_MODE_EXT_LIMIT) {
    307325            if (psphotFitBlob (readout, source, newSources, psf, fitOptions, maskVal, markVal)) {
     326                if (TEST_ON) {
     327                    psTraceSetLevel("psLib.math.psMinimizeLMChi2", 0);
     328                }
    308329                psTrace ("psphot", 5, "source at %7.1f, %7.1f is ext", source->peak->xf, source->peak->yf);
    309330                Next ++;
     
    312333        } else {
    313334            if (psphotFitBlend (readout, source, psf, fitOptions, maskVal, markVal)) {
     335                if (TEST_ON) {
     336                    psTraceSetLevel("psLib.math.psMinimizeLMChi2", 0);
     337                }
    314338                source->type = PM_SOURCE_TYPE_STAR;
    315339                psTrace ("psphot", 5, "source at %7.1f, %7.1f is psf", source->peak->xf, source->peak->yf);
     
    349373}
    350374
     375bool psphotBlendFitSetSource(pmSource *source, psImage *IDimage, float skySigma) {
     376
     377    if (!source) return false;
     378    if (!source->peak) return false; // XXX how can we have a peak-less source?
     379    if (!source->moments) return false;
     380    if (source->type == PM_SOURCE_TYPE_DEFECT) return false;
     381    if (source->type == PM_SOURCE_TYPE_SATURATED) return false;
     382    if (source->mode2 == PM_SOURCE_MODE2_MATCHED) return false;
     383    psAssert(IDimage, "need a window");
     384
     385    if (source->mode2 & PM_SOURCE_MODE2_SATSTAR_PROFILE) {
     386        // find the radius at which we hit something like 0.1*SATURATION
     387        return false;
     388    }
     389
     390    if (!isfinite(source->moments->Mrf) || source->moments->Mrf < 0 ) return false;
     391
     392    // we have a source with moments Mx, My, Mxx, Mxy, Myy.  we just need to define a Gaussian that has
     393    // these values (and peak of 1.0)
     394
     395    int Nx = IDimage->numCols;
     396    int Ny = IDimage->numRows;
     397
     398    float Xo = source->moments->Mx;
     399    float Yo = source->moments->My;
     400
     401    psEllipseMoments moments;
     402    moments.x2 = source->moments->Mxx;
     403    moments.y2 = source->moments->Myy;
     404    moments.xy = source->moments->Mxy;
     405
     406    psEllipseAxes axes = psEllipseMomentsToAxes(moments, 20.0);
     407    if (! (isfinite(axes.major) && isfinite(axes.minor) && isfinite(axes.theta)) ) {
     408        fprintf (stderr, "invalid axes found id: %4d major: %f minor: %f theta: %f\n", source->id, axes.major, axes.minor, axes.theta);
     409        return false;
     410    }
     411
     412    // Use 1st radial moment as size, not sigma.  Why this factor of 0.5 ?
     413    float scale = 0.5 * source->moments->Mrf / axes.major;
     414    axes.major *= scale;
     415    axes.minor *= scale;
     416
     417    psEllipseShape shape = psEllipseAxesToShape(axes);
     418    if (! (isfinite(shape.sx) && isfinite(shape.sy) && isfinite(shape.sxy)) ) {
     419        fprintf (stderr, "invalid shape found id: %d sx: %f sy %f sxy: %f\n", source->id, shape.sx, shape.sy, shape.sxy);
     420        return false;
     421    }
     422
     423    float Smajor = axes.major;
     424
     425    // we want to go to 2.15 sigma (0.1 Io)
     426    int minX = PS_MIN(PS_MAX(Xo - 2.15*Smajor, 0), Nx - 1);
     427    int maxX = PS_MIN(PS_MAX(Xo + 2.15*Smajor, 0), Nx - 1);
     428    int minY = PS_MIN(PS_MAX(Yo - 2.15*Smajor, 0), Ny - 1);
     429    int maxY = PS_MIN(PS_MAX(Yo + 2.15*Smajor, 0), Ny - 1);
     430
     431    float rMxx = 0.5 / PS_SQR(shape.sx);
     432    float rMyy = 0.5 / PS_SQR(shape.sy);
     433    float Sxy = -1. * shape.sxy;    // factor of -1 is included to match the previous window function
     434                                    // implementation. XXX: Is this correct?
     435
     436    int ID = source->id;
     437    float Io = source->peak->rawFlux;
     438    for (int iy = minY; iy < maxY; iy++) {
     439        for (int ix = minX; ix < maxX; ix++) {
     440
     441            float dX = (ix + 0.5 - Xo);
     442            float dY = (iy + 0.5 - Yo);
     443
     444            float z = rMxx * PS_SQR(dX) + rMyy * PS_SQR(dY) + Sxy*dX*dY;
     445
     446            float f = Io*exp(-z);
     447           
     448            if (f < 2.0*skySigma) continue;
     449            IDimage->data.S32[iy][ix] = ID;
     450        }
     451    }
     452
     453    return true;
     454}
  • 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
  • trunk/psphot/src/psphotExtendedSourceAnalysis.c

    r33089 r34404  
    218218        if (source->mode & PM_SOURCE_MODE_SATSTAR) continue;
    219219
     220        // skip saturated stars modeled with a radial profile
     221        if (source->mode2 & PM_SOURCE_MODE2_SATSTAR_PROFILE) continue;
     222
    220223        // optionally allow non-extended objects to get petrosians as well
    221224        if (!doPetroStars) {
  • trunk/psphot/src/psphotExtendedSourceFits.c

    r34258 r34404  
    317317        if (source->type == PM_SOURCE_TYPE_DEFECT) continue;
    318318        if (source->type == PM_SOURCE_TYPE_SATURATED) continue;
     319
     320        // skip saturated stars modeled with a radial profile
     321        if (source->mode2 & PM_SOURCE_MODE2_SATSTAR_PROFILE) continue;
    319322
    320323        // XXX this should use peak?
  • trunk/psphot/src/psphotFindDetections.c

    r33914 r34404  
    120120    if (useFootprints) {
    121121        if (replaceSourcesForFootprints) {
     122            // subtract the noise for all sources including satstars
    122123            psphotAddOrSubNoiseReadout(config, view, filerule, index, recipe, false);
    123124            psphotReplaceAllSourcesReadout (config, view, filerule, index, recipe, false);
     125
     126            // add in the satstars
     127            psphotAddOrSubSatstarsReadout (config, view, filerule, index, recipe, true);
     128
    124129            psFree (significance);
    125130            significance = psphotSignificanceImage (readout, recipe, maskVal);
     131
     132            // display the significance image
     133            psphotVisualShowSignificance (significance->variance, 0.98*threshold, 1.02*threshold);
    126134        }
    127135
     
    130138        if (replaceSourcesForFootprints) {
    131139            psphotRemoveAllSourcesReadout (config, view, filerule, index, recipe, false);
     140
     141            // subtract the satstars
     142            psphotAddOrSubSatstarsReadout (config, view, filerule, index, recipe, false);
    132143        }
    133144    }
  • trunk/psphot/src/psphotFitSourcesLinear.c

    r34274 r34404  
    222222        if (source->type == PM_SOURCE_TYPE_DEFECT) continue;
    223223        if (source->type == PM_SOURCE_TYPE_SATURATED) continue;
     224
     225        // skip saturated stars modeled with a radial profile
     226        if (source->mode2 & PM_SOURCE_MODE2_SATSTAR_PROFILE) continue;
    224227
    225228        // do not include CRs in the full ensemble fit
  • trunk/psphot/src/psphotGuessModels.c

    r33089 r34404  
    169169        source->tmpFlags |= PM_SOURCE_TMPF_MODEL_GUESS;
    170170
    171         // skip non-astronomical objects (very likely defects)
    172         if (source->mode & PM_SOURCE_MODE_MOMENTS_FAILURE) continue;
     171        // skip non-astronomical objects (very likely defects) and satstars with profiles subtracted
     172        if (source->mode  & PM_SOURCE_MODE_MOMENTS_FAILURE) continue;
     173        if (source->mode2 & PM_SOURCE_MODE2_SATSTAR_PROFILE) continue;
    173174        if (source->type == PM_SOURCE_TYPE_DEFECT) continue;
    174175        if (source->type == PM_SOURCE_TYPE_SATURATED) continue;
  • trunk/psphot/src/psphotKronIterate.c

    r34317 r34404  
    331331            }
    332332
     333            // skip saturated stars modeled with a radial profile
     334            if (source->mode2 & PM_SOURCE_MODE2_SATSTAR_PROFILE) continue;
     335
    333336            // replace object in image
    334337            bool reSubtract = false;
  • trunk/psphot/src/psphotMagnitudes.c

    r33089 r34404  
    182182        if (saveTest) {
    183183            psphotSaveImage(NULL, testImage, "test.image.1.fits");
     184        }
     185
     186        // satstars modeled as a radial profile need special handling
     187        if (source->mode2 & PM_SOURCE_MODE2_SATSTAR_PROFILE) {
     188            psphotSatstarPhotometry (source);
     189            continue;
    184190        }
    185191
  • trunk/psphot/src/psphotRadialApertures.c

    r34136 r34404  
    240240        if (source->mode & PM_SOURCE_MODE_DEFECT) continue;
    241241
     242        // skip saturated stars modeled with a radial profile
     243        if (source->mode2 & PM_SOURCE_MODE2_SATSTAR_PROFILE) continue;
     244
    242245        // XXX measure radial apertures even for saturated stars
    243246        // if (source->mode & PM_SOURCE_MODE_SATSTAR) continue;
  • trunk/psphot/src/psphotRadialProfileWings.c

    r33839 r34404  
    190190        if (!source->moments) continue;
    191191
     192        // skip saturated stars modeled with a radial profile
     193        if (source->mode2 & PM_SOURCE_MODE2_SATSTAR_PROFILE) continue;
     194
     195        // skip non-detected sources matched from other images
     196        if (source->mode2 & PM_SOURCE_MODE2_MATCHED) return true; // skip matched sources (no signal)
     197
     198        // XXX unclear if I should run this analysis on both 1st and 2nd pass for 1st pass objects,
     199        // or just use the 1st pass value.  I think I should just use the 1st pass value, so skip
     200        // any that have already been assigned
     201        if (isfinite(source->skyRadius)) return true;
     202
    192203        // replace object in image
    193204        bool reSubtract = false;
     
    226237
    227238    // psImageMaskType **vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA;
    228 
    229     // XXX unclear if I should run this analysis on both 1st and 2nd pass for 1st pass objects,
    230     // or just use the 1st pass value.  I think I should just use the 1st pass value, so skip
    231     // any that have already been assigned
    232     if (isfinite(source->skyRadius)) return true;
    233 
    234     if (source->mode2 & PM_SOURCE_MODE2_MATCHED) return true; // skip matched sources (no signal)
    235239
    236240    // radii will be MIN_RADIUS to MAX_RADIUS in NN log steps:
  • trunk/psphot/src/psphotReadout.c

    r34317 r34404  
    128128    }
    129129
    130     // find blended neighbors of very saturated stars (detections->newSources)
    131     // if (!psphotDeblendSatstars (config, view, filerule)) {
    132     // psError (PSPHOT_ERR_UNKNOWN, false, "failed on satstar deblend analysis");
    133     // return psphotReadoutCleanup (config, view, filerule);
    134     // }
    135 
    136130    // mark blended peaks PS_SOURCE_BLEND (detections->newSources)
    137131    // XXX I've deactivated this because it was preventing galaxies close to stars from being
     
    149143    }
    150144
     145    // find and subtract radial profile models for saturated stars (XXX change name eventually)
     146    if (!psphotDeblendSatstars (config, view, filerule)) {
     147        psError (PSPHOT_ERR_UNKNOWN, false, "failed on satstar deblend analysis");
     148        return psphotReadoutCleanup (config, view, filerule);
     149    }
     150
    151151    // if we were not supplied a PSF model, determine the IQ stats here (detections->newSources)
    152152    if (!psphotImageQuality (config, view, filerule)) { // pass 1
     
    221221    // NOTE: this block performs the 2nd pass low-significance PSF detection stage
    222222    {
    223         // add noise for subtracted objects
     223        // add noise for subtracted objects & subtracted saturated stars
    224224        psphotAddNoise (config, view, filerule); // pass 1 (detections->allSources)
    225225
     
    253253        // merge the newly selected sources into the existing list
    254254        // NOTE: merge OLD and NEW
    255         // XXX check on free of sources...
    256255        psphotMergeSources (config, view, filerule); // (detections->newSources + detections->allSources -> detections->allSources)
    257256
     
    294293        // merge the newly selected sources into the existing list
    295294        // NOTE: merge OLD and NEW
    296         // XXX check on free of sources...
    297295        psphotMergeSources (config, view, filerule); // (detections->newSources + detections->allSources -> detections->allSources)
    298296
  • trunk/psphot/src/psphotSourceSize.c

    r34258 r34404  
    498498            continue;
    499499        }
     500
     501        // skip saturated stars modeled with a radial profile
     502        if (source->mode2 & PM_SOURCE_MODE2_SATSTAR_PROFILE) continue;
    500503
    501504        // we are classifying by moments and PSF_MAG - KRON_MAG
  • trunk/psphot/src/psphotSourceStats.c

    r34321 r34404  
    447447        }
    448448
     449        // skip saturated stars modeled with a radial profile (this probably never happens, since it is set after)
     450        if (source->mode2 & PM_SOURCE_MODE2_SATSTAR_PROFILE) continue;
     451
    449452        if (!(source->peak->type == PM_PEAK_SUSPECT_SATURATION)) {
    450453            // measure basic source moments (no S/N clipping on input pixels)
     
    521524    float PSF_SN_LIM = 2.0*psMetadataLookupF32(&status, recipe, "PSF_SN_LIM"); psAssert (status, "missing PSF_SN_LIM");
    522525
    523 
     526    // XXX this will cause an error in the vector length is > 8
    524527    # define NSIGMA 8
    525528    // moved to config file
     
    538541            sigma[i] = sigmavec->data.F32[i];
    539542        }
     543        assert (sigmavec->n <= 8);
    540544        nsigma = sigmavec->n;
    541545    } else {
  • trunk/psphot/src/psphotStackImageLoop.c

  • trunk/psphot/src/psphotStackMatchPSFs.c

    r34352 r34404  
    4646    }
    4747
    48     // loop over the available readouts (ignore chisq image)psLogMsg ("psphot", PS_LOG_INFO, "--- psphot Source Stats ---");
     48    // loop over the available readouts (ignore chisq image)
    4949    for (int i = 0; i < num; i++) {
    5050        if (!psphotStackMatchPSFsReadout (config, view, options, i)) {
  • trunk/psphot/src/psphotVisual.c

    r31452 r34404  
    262262}
    263263
     264static psImage *posImage = NULL;
     265static psImage *delImage = NULL;
     266
    264267bool psphotVisualShowImage (pmReadout *readout) {
    265268
     
    277280    psphotVisualScaleImage (kapa, readout->variance, readout->mask, "variance", 1.0, 1);
    278281    psphotVisualScaleImage (kapa, readout->image, readout->mask, "image", sqrt(factor), 0);
     282
     283    if (posImage == NULL) {
     284        posImage = psImageCopy (NULL, readout->image, PS_TYPE_F32);
     285    }
    279286
    280287    pmVisualAskUser(NULL);
     
    11391146    // after displaying (as an image) the psf stars, we cycle throught them and display their
    11401147    // radial profiles:
    1141     psphotVisualPlotRadialProfiles (recipe, sources);
     1148    psphotVisualPlotRadialProfiles (recipe, sources, PM_SOURCE_MODE_PSFSTAR);
    11421149
    11431150    return true;
     
    12731280}
    12741281
    1275 static void plotline (int myKapa, Graphdata *graphdata, float x0, float y0, float x1, float y1)
     1282void plotline (int myKapa, Graphdata *graphdata, float x0, float y0, float x1, float y1)
    12761283{
    12771284    float x[2], y[2];
     
    12851292}
    12861293
    1287 bool psphotVisualPlotRadialProfile (int myKapa, pmSource *source, psImageMaskType maskVal) {
     1294bool psphotVisualPlotRadialProfile (int myKapa, pmSource *source, psImageMaskType maskVal, pmSourceMode showmode) {
    12881295
    12891296    Graphdata graphdata;
     1297
     1298    float Rmax = (showmode & PM_SOURCE_MODE_SATSTAR) ? 100.0 : 30.0;
    12901299
    12911300    bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     
    13021311    int ng = 0;
    13031312    int nb = 0;
    1304     float Xo = source->modelPSF->params->data.F32[PM_PAR_XPOS] - source->pixels->col0;
    1305     float Yo = source->modelPSF->params->data.F32[PM_PAR_YPOS] - source->pixels->row0;
     1313
     1314    float Xo = NAN;
     1315    float Yo = NAN;
     1316
     1317    if (source->modelPSF) {
     1318        Xo = source->modelPSF->params->data.F32[PM_PAR_XPOS] - source->pixels->col0;
     1319        Yo = source->modelPSF->params->data.F32[PM_PAR_YPOS] - source->pixels->row0;
     1320    } else {
     1321        Xo = source->moments->Mx - source->pixels->col0;
     1322        Yo = source->moments->My - source->pixels->row0;
     1323    }
     1324
    13061325    for (int iy = 0; iy < source->pixels->numRows; iy++) {
    13071326        for (int ix = 0; ix < source->pixels->numCols; ix++) {
    1308             if (source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix]) {
     1327            if ((source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & maskVal)) {
    13091328                rb->data.F32[nb] = hypot (ix + 0.5 - Xo, iy + 0.5 - Yo) ;
    13101329                // rb->data.F32[nb] = hypot (ix - Xo, iy - Yo) ;
     
    13221341    }
    13231342
    1324     // generate model profiles (major and minor axis):
    1325     // create a model with theta = 0.0 so major and minor axes are equiv to x and y:
    1326     psEllipseShape rawShape, rotShape;
    1327 
    1328     rawShape.sx  = source->modelPSF->params->data.F32[PM_PAR_SXX] / M_SQRT2;
    1329     rawShape.sy  = source->modelPSF->params->data.F32[PM_PAR_SYY] / M_SQRT2;
    1330     rawShape.sxy = source->modelPSF->params->data.F32[PM_PAR_SXY];
    1331 
    1332     psEllipseAxes axes = psEllipseShapeToAxes (rawShape, 20.0);
    1333 
    1334     axes.theta = 0.0;
    1335 
    1336     rotShape = psEllipseAxesToShape (axes);
    1337 
    1338     psVector *params = psVectorAlloc(source->modelPSF->params->n, PS_TYPE_F32);
    1339     for (int i = 0; i < source->modelPSF->params->n; i++) {
    1340         params->data.F32[i] = source->modelPSF->params->data.F32[i];
    1341     }
    1342     params->data.F32[PM_PAR_SXX] = rotShape.sx * M_SQRT2;
    1343     params->data.F32[PM_PAR_SYY] = rotShape.sy * M_SQRT2;
    1344     params->data.F32[PM_PAR_SXY] = rotShape.sxy;
    1345     params->data.F32[PM_PAR_XPOS] = 0.0;
    1346     params->data.F32[PM_PAR_YPOS] = 0.0;
    1347 
    1348     psVector *rmod = psVectorAlloc(300, PS_TYPE_F32);
    1349     psVector *fmaj = psVectorAlloc(300, PS_TYPE_F32);
    1350     psVector *fmin = psVectorAlloc(300, PS_TYPE_F32);
    1351 
    1352     psVector *coord = psVectorAlloc(2, PS_TYPE_F32);
    1353 
    1354     float r = 0.0;
    1355     for (int i = 0; i < rmod->n; i++) {
    1356         r = i*0.1;
    1357         rmod->data.F32[i] = r;
    1358 
    1359         coord->data.F32[1] = r;
    1360         coord->data.F32[0] = 0.0;
    1361         fmaj->data.F32[i] = log10(source->modelPSF->modelFunc (NULL, params, coord));
    1362 
    1363         coord->data.F32[0] = r;
    1364         coord->data.F32[1] = 0.0;
    1365         fmin->data.F32[i] = log10(source->modelPSF->modelFunc (NULL, params, coord));
    1366     }
    1367     psFree (coord);
    1368     psFree (params);
    1369 
    1370     float FWHM_MAJOR = 2.0*source->modelPSF->modelRadius (source->modelPSF->params, 0.5*source->modelPSF->params->data.F32[PM_PAR_I0]);
    1371     float FWHM_MINOR = FWHM_MAJOR * (axes.minor / axes.major);
    1372     if (FWHM_MAJOR < FWHM_MINOR) PS_SWAP (FWHM_MAJOR, FWHM_MINOR);
    1373 
    1374     psEllipseMoments emoments;
    1375     emoments.x2 = source->moments->Mxx;
    1376     emoments.xy = source->moments->Mxy;
    1377     emoments.y2 = source->moments->Myy;
    1378     axes = psEllipseMomentsToAxes (emoments, 20.0);
    1379     float MOMENTS_MAJOR = 2.355*axes.major;
    1380     float MOMENTS_MINOR = 2.355*axes.minor;
    1381 
    1382     float logHM = log10(0.5*source->modelPSF->params->data.F32[PM_PAR_I0]);
    1383 
    1384     // reset source Add/Sub state to recorded
    1385     if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    1386 
    13871343    KapaInitGraph (&graphdata);
    13881344
     
    13921348    // examine sources to set data range
    13931349    graphdata.xmin =  -0.05;
    1394     graphdata.xmax = +30.05;
     1350    graphdata.xmax = Rmax + 0.05;
    13951351    graphdata.ymin = -0.05;
    13961352    graphdata.ymax = +8.05;
     
    14181374    KapaPlotVector (myKapa, nb, fb->data.F32, "y");
    14191375
    1420     graphdata.color = KapaColorByName ("blue");
    1421     graphdata.ptype = 0;
    1422     graphdata.size = 0.0;
    1423     graphdata.style = 0;
    1424     KapaPrepPlot   (myKapa, rmod->n, &graphdata);
    1425     KapaPlotVector (myKapa, rmod->n, rmod->data.F32, "x");
    1426     KapaPlotVector (myKapa, rmod->n, fmin->data.F32, "y");
    1427     plotline (myKapa, &graphdata, 0.0, logHM, 30.0, logHM);
    1428     plotline (myKapa, &graphdata, 0.5*FWHM_MINOR, 0.0, 0.5*FWHM_MINOR, 5.0);
    1429     graphdata.ltype = 1;
    1430     plotline (myKapa, &graphdata, 0.5*MOMENTS_MINOR, 0.0, 0.5*MOMENTS_MINOR, 5.0);
    1431     graphdata.ltype = 0;
    1432        
    1433     graphdata.color = KapaColorByName ("green");
    1434     graphdata.ptype = 0;
    1435     graphdata.size = 0.0;
    1436     graphdata.style = 0;
    1437     KapaPrepPlot   (myKapa, rmod->n, &graphdata);
    1438     KapaPlotVector (myKapa, rmod->n, rmod->data.F32, "x");
    1439     KapaPlotVector (myKapa, rmod->n, fmaj->data.F32, "y");
    1440     plotline (myKapa, &graphdata, 0.5*FWHM_MAJOR, 0.0, 0.5*FWHM_MAJOR, 5.0);
    1441     graphdata.ltype = 1;
    1442     plotline (myKapa, &graphdata, 0.5*MOMENTS_MAJOR, 0.0, 0.5*MOMENTS_MAJOR, 5.0);
    1443     graphdata.ltype = 0;
    1444        
    1445     for (int i = 0; i < rmod->n; i++) {
    1446         rmod->data.F32[i] = log10(rmod->data.F32[i]);
    1447     }
    1448 
    14491376    // ** loglog **
    14501377    KapaSelectSection (myKapa, "loglog");
     
    14521379    // examine sources to set data range
    14531380    graphdata.xmin = -1.51;
    1454     graphdata.xmax = +1.51;
     1381    graphdata.xmax = log10(Rmax) + 0.02;
    14551382    graphdata.ymin = -0.05;
    14561383    graphdata.ymax = +8.05;
     
    14791406    KapaPlotVector (myKapa, nb, fb->data.F32, "y");
    14801407
    1481     graphdata.color = KapaColorByName ("blue");
    1482     graphdata.ptype = 0;
    1483     graphdata.size = 0.0;
    1484     graphdata.style = 0;
    1485     KapaPrepPlot   (myKapa, rmod->n, &graphdata);
    1486     KapaPlotVector (myKapa, rmod->n, rmod->data.F32, "x");
    1487     KapaPlotVector (myKapa, rmod->n, fmin->data.F32, "y");
    1488 
    1489     graphdata.color = KapaColorByName ("green");
    1490     graphdata.ptype = 0;
    1491     graphdata.size = 0.0;
    1492     graphdata.style = 0;
    1493     KapaPrepPlot   (myKapa, rmod->n, &graphdata);
    1494     KapaPlotVector (myKapa, rmod->n, rmod->data.F32, "x");
    1495     KapaPlotVector (myKapa, rmod->n, fmaj->data.F32, "y");
    1496 
    1497     psFree (rmod);
    1498     psFree (fmin);
    1499     psFree (fmaj);
     1408    if (source->modelPSF) {
     1409        // generate model profiles (major and minor axis):
     1410        // create a model with theta = 0.0 so major and minor axes are equiv to x and y:
     1411        psEllipseShape rawShape, rotShape;
     1412
     1413        rawShape.sx  = source->modelPSF->params->data.F32[PM_PAR_SXX] / M_SQRT2;
     1414        rawShape.sy  = source->modelPSF->params->data.F32[PM_PAR_SYY] / M_SQRT2;
     1415        rawShape.sxy = source->modelPSF->params->data.F32[PM_PAR_SXY];
     1416
     1417        psEllipseAxes axes = psEllipseShapeToAxes (rawShape, 20.0);
     1418
     1419        axes.theta = 0.0;
     1420
     1421        rotShape = psEllipseAxesToShape (axes);
     1422
     1423        psVector *params = psVectorAlloc(source->modelPSF->params->n, PS_TYPE_F32);
     1424        for (int i = 0; i < source->modelPSF->params->n; i++) {
     1425            params->data.F32[i] = source->modelPSF->params->data.F32[i];
     1426        }
     1427        params->data.F32[PM_PAR_SXX] = rotShape.sx * M_SQRT2;
     1428        params->data.F32[PM_PAR_SYY] = rotShape.sy * M_SQRT2;
     1429        params->data.F32[PM_PAR_SXY] = rotShape.sxy;
     1430        params->data.F32[PM_PAR_XPOS] = 0.0;
     1431        params->data.F32[PM_PAR_YPOS] = 0.0;
     1432
     1433        psVector *rmod = psVectorAlloc(Rmax*10, PS_TYPE_F32);
     1434        psVector *fmaj = psVectorAlloc(Rmax*10, PS_TYPE_F32);
     1435        psVector *fmin = psVectorAlloc(Rmax*10, PS_TYPE_F32);
     1436
     1437        psVector *coord = psVectorAlloc(2, PS_TYPE_F32);
     1438
     1439        float r = 0.0;
     1440        for (int i = 0; i < rmod->n; i++) {
     1441            r = i*0.1;
     1442            rmod->data.F32[i] = r;
     1443
     1444            coord->data.F32[1] = r;
     1445            coord->data.F32[0] = 0.0;
     1446            fmaj->data.F32[i] = log10(source->modelPSF->modelFunc (NULL, params, coord));
     1447
     1448            coord->data.F32[0] = r;
     1449            coord->data.F32[1] = 0.0;
     1450            fmin->data.F32[i] = log10(source->modelPSF->modelFunc (NULL, params, coord));
     1451        }
     1452        psFree (coord);
     1453        psFree (params);
     1454
     1455        float FWHM_MAJOR = 2.0*source->modelPSF->modelRadius (source->modelPSF->params, 0.5*source->modelPSF->params->data.F32[PM_PAR_I0]);
     1456        float FWHM_MINOR = FWHM_MAJOR * (axes.minor / axes.major);
     1457        if (FWHM_MAJOR < FWHM_MINOR) PS_SWAP (FWHM_MAJOR, FWHM_MINOR);
     1458
     1459        psEllipseMoments emoments;
     1460        emoments.x2 = source->moments->Mxx;
     1461        emoments.xy = source->moments->Mxy;
     1462        emoments.y2 = source->moments->Myy;
     1463        axes = psEllipseMomentsToAxes (emoments, 20.0);
     1464        float MOMENTS_MAJOR = 2.355*axes.major;
     1465        float MOMENTS_MINOR = 2.355*axes.minor;
     1466
     1467        float logHM = log10(0.5*source->modelPSF->params->data.F32[PM_PAR_I0]);
     1468
     1469        // reset source Add/Sub state to recorded
     1470        if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
     1471
     1472        // ** linlog **
     1473        KapaSelectSection (myKapa, "linlog");
     1474        KapaGetGraphData (myKapa, &graphdata);
     1475        graphdata.color = KapaColorByName ("blue");
     1476        graphdata.ptype = 0;
     1477        graphdata.size = 0.0;
     1478        graphdata.style = 0;
     1479        KapaPrepPlot   (myKapa, rmod->n, &graphdata);
     1480        KapaPlotVector (myKapa, rmod->n, rmod->data.F32, "x");
     1481        KapaPlotVector (myKapa, rmod->n, fmin->data.F32, "y");
     1482        plotline (myKapa, &graphdata, graphdata.xmin, logHM, graphdata.xmax, logHM);
     1483        plotline (myKapa, &graphdata, 0.5*FWHM_MINOR, graphdata.ymin, 0.5*FWHM_MINOR, graphdata.ymax);
     1484        graphdata.ltype = 1;
     1485        plotline (myKapa, &graphdata, 0.5*MOMENTS_MINOR, graphdata.ymin, 0.5*MOMENTS_MINOR, graphdata.ymax);
     1486        graphdata.ltype = 0;
     1487       
     1488        graphdata.color = KapaColorByName ("green");
     1489        graphdata.ptype = 0;
     1490        graphdata.size = 0.0;
     1491        graphdata.style = 0;
     1492        KapaPrepPlot   (myKapa, rmod->n, &graphdata);
     1493        KapaPlotVector (myKapa, rmod->n, rmod->data.F32, "x");
     1494        KapaPlotVector (myKapa, rmod->n, fmaj->data.F32, "y");
     1495        plotline (myKapa, &graphdata, 0.5*FWHM_MAJOR, graphdata.ymin, 0.5*FWHM_MAJOR, graphdata.ymax);
     1496        graphdata.ltype = 1;
     1497        plotline (myKapa, &graphdata, 0.5*MOMENTS_MAJOR, graphdata.ymin, 0.5*MOMENTS_MAJOR, graphdata.ymax);
     1498        graphdata.ltype = 0;
     1499       
     1500        for (int i = 0; i < rmod->n; i++) {
     1501            rmod->data.F32[i] = log10(rmod->data.F32[i]);
     1502        }
     1503
     1504        // ** loglog **
     1505        KapaSelectSection (myKapa, "loglog");
     1506        KapaGetGraphData (myKapa, &graphdata);
     1507        graphdata.color = KapaColorByName ("blue");
     1508        graphdata.ptype = 0;
     1509        graphdata.size = 0.0;
     1510        graphdata.style = 0;
     1511        KapaPrepPlot   (myKapa, rmod->n, &graphdata);
     1512        KapaPlotVector (myKapa, rmod->n, rmod->data.F32, "x");
     1513        KapaPlotVector (myKapa, rmod->n, fmin->data.F32, "y");
     1514
     1515        graphdata.color = KapaColorByName ("green");
     1516        graphdata.ptype = 0;
     1517        graphdata.size = 0.0;
     1518        graphdata.style = 0;
     1519        KapaPrepPlot   (myKapa, rmod->n, &graphdata);
     1520        KapaPlotVector (myKapa, rmod->n, rmod->data.F32, "x");
     1521        KapaPlotVector (myKapa, rmod->n, fmaj->data.F32, "y");
     1522
     1523        psFree (rmod);
     1524        psFree (fmin);
     1525        psFree (fmaj);
     1526    }
    15001527
    15011528    psFree (rg);
     
    15081535}
    15091536
    1510 bool psphotVisualPlotRadialProfiles (psMetadata *recipe, psArray *sources) {
     1537bool psphotVisualPlotRadialProfiles (psMetadata *recipe, psArray *sources, pmSourceMode showmode) {
    15111538
    15121539    KapaSection section;  // put the positive profile in one and the residuals in another?
     
    15491576
    15501577        pmSource *source = sources->data[i];
    1551         if (!(source->mode & PM_SOURCE_MODE_PSFSTAR)) continue;
    1552 
    1553         psphotVisualPlotRadialProfile (myKapa, source, maskVal);
     1578        if (!(source->mode & showmode)) continue;
     1579
     1580        psphotVisualPlotRadialProfile (myKapa, source, maskVal, showmode);
     1581
     1582        if (pmVisualTestLevel("psphot.image", 1)) {
     1583          int display = psphotKapaChannel (1);
     1584          KiiCenter (display, source->peak->xf, source->peak->yf, 1);
     1585          KiiOverlay overlay;
     1586          overlay.x = source->peak->xf;
     1587          overlay.y = source->peak->yf;
     1588          overlay.dx = 5;
     1589          overlay.dy = 5;
     1590          overlay.angle = 0.0;
     1591          overlay.type = KiiOverlayTypeByName ("circle");
     1592          KiiLoadOverlay (display, &overlay, 1, "red");
     1593          overlay.x = source->moments->Mx;
     1594          overlay.y = source->moments->My;
     1595          overlay.dx = 8;
     1596          overlay.dy = 8;
     1597          overlay.angle = 0.0;
     1598          overlay.type = KiiOverlayTypeByName ("circle");
     1599          KiiLoadOverlay (display, &overlay, 1, "blue");
     1600        }
    15541601
    15551602        // pause and wait for user input:
     
    25402587    }
    25412588
    2542     if (reshow) {
     2589    if (false && reshow) {
    25432590        psphotVisualShowMask (myKapa, readout->mask, "mask", 2);
    25442591        psphotVisualScaleImage (myKapa, readout->variance, readout->mask, "variance", 1.0, 1);
    25452592    }
    2546     psphotVisualScaleImage (myKapa, readout->image, readout->mask, "resid", sqrt(factor), 0);
     2593
     2594    if (posImage) {
     2595        delImage = (psImage *) psBinaryOp(delImage, posImage, "-", readout->image);
     2596        psphotVisualScaleImage (myKapa, posImage, readout->mask, "posimage", sqrt(factor), 0);
     2597        psphotVisualScaleImage (myKapa, delImage, readout->mask, "delimage", sqrt(factor), 2);
     2598    }
     2599
     2600    psphotVisualScaleImage (myKapa, readout->image, readout->mask, "resid", sqrt(factor), 1);
    25472601
    25482602    pmVisualAskUser(NULL);
Note: See TracChangeset for help on using the changeset viewer.