IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 25755


Ignore:
Timestamp:
Oct 2, 2009, 3:12:47 PM (17 years ago)
Author:
eugene
Message:

check in changes from gene@development branch : extensive changes to moments calculation, psf model generation, aperture residuals; improvements to extended source analysis

Location:
trunk/psphot
Files:
43 edited
10 copied

Legend:

Unmodified
Added
Removed
  • trunk/psphot/doc/notes.20090523.txt

    r24993 r25755  
     1
     220090809 : more on extended sources:
     3
     4 my algorithm for getting the petrosian radii and fluxes is:
     5
     6  * measure radial profile by interpolation to specific locations along the radial line
     7    (at low radii, this gives much more accurate results; at high radii, we may need to
     8    average a group of pixels -- say, for 15 deg separations, choose a box that is
     9    < 5 degree in width -- this is > 1 pixel at a distance of 12 pixels.
     10
     11    psphotRadialProfilesByAngle
     12
     13  * find intersection of profile with isophot
     14
     15    psphotRadiusFromProfile -> r50(theta)
     16
     17  * generate r50x, r50y and fit to ellipse
     18
     19    psphotEllipticalContour
     20
     21  * generate elliptical profile
     22
     23    psphotEllipticalProfile
     24
     25  * convert to \alpha r_i < r < \beta r_i bins
     26
     27    psphotPetrosianRadialBins
    128
    22920090725 : extended source radial profiles
     
    5481    *** get rest of math from my notebook...
    5582
    56 
    57 
    588320090525 : some clarity of issues:
    5984
  • trunk/psphot/doc/notes.txt

    r21164 r25755  
     1
     22009.09.26
     3
     4  Remaining PSPHOT Issues:
     5
     6  o soften errors a bit for bright stars?  (essentially allow a
     7    systematic error on the flat of some percentage).  this may help
     8    the very saturated stars (peaks > 10k) which seem to be
     9    excessively driven by the cores.
     10    ** did not seem to be a big success --> makes things worse for f =
     11    0.01, about the same for f = 0.005
     12
     13  o clean up and remove test bits of code.
     14
     15  o clean up psphot.config files : drop unused, fix some conflicting
     16    names, reduce camera-specific options, make S/N limits
     17    consistent...
     18
     19  * PSF Eval & ChiSq test??
     20
     21  * EXT fail fit?  lack of iterations?
     22
     23  * extended source output
     24
     25  * still some concerns with the source size analysis: the parameters
     26    space seems fine (Mxx, Myy, nSigma), but we need to define more
     27    sophisticated boundaries (perhaps include dMag or Mag). 
     28
     29  * some optimization issues:         
     30    * too many re-calculations of all magnitude / aperture data
     31    * is FluxScale really faster?  do we need a finer mapping? (5x5
     32      clearly yields too much scatter)
     33    * is psphotFitSourcesLinear.c (build matrix) super-slow when optimized?
     34
     35  * very saturated stars are somewhat segmented.
     36
     37  * footprint coverage in dense simtest image 005.001?
     38
     39  * footprint S/N limit vs peaks S/N limit?
     40
     41  * warning about burntool table?
     42
     43  * is the residual map failing to be masked at the radius?
     44
     45  * PSF 2D convergence : how to choose between marginally different
     46    options?  (note that the GPC1 images may go to 2x2 instead of 3x3)
     47
     48  * -visual needs more fine-grained control
     49
     50  * visualization graphs should reset the sections in general.
     51
     52  * some excess verbosity (my log level is 9, lower?)
     53
     54  -----
     55
     56  Apparently I'm getting bad psf vs ap mags because of the difference
     57  between linear and non-linear fits.  I think this is due to the
     58  weighting schemes:
     59
     60  psphotChoosePSF & psphotBlendFit depend on POISSON.ERRORS.PHOT.LMM,
     61  which is set to TRUE => use Poisson errors
     62
     63  psphotFitSourcesLinear depends on CONSTANT_PHOTOMETRIC_WEIGHTS,
     64  which is set to TRUE => do not use Poisson errors.
     65
     66  nothing seems to use the value POISSON.ERRORS.PHOT.LIN
     67
     68  ** Poisson errors seeem to be working much better than Constant
     69     errors (as judged by consistency between PSF and APERTURE
     70     magnitdues).  Not sure I understand this.  It could be that the
     71     implementation of Constant errors in the linear fitting analysis
     72     is busted. 
     73
     74  ** Also, I was getting some additional scatter from the FluxScale
     75     (lookup-table for Io -> mags). 
     76
     77     * surprisingly, it is not clear that the FluxScale method is
     78       faster than the more accurate integration technique...
     79
     802009.09.25
     81
     82  Notes on pmSourceMagnitudes:
     83
     84  * in psphotChoosePSF, in pmPSFtry: raw PSF & raw AP
     85  * in psphotChoosePSF, psphotMakeGrowthCurve: uses direct all to pmSourcePhotometryAper
     86  * in psphotSourceSize, in psphotSourceSizePSF, raw PSF & raw AP (but uses moments->Sum) for PSF stars
     87    NOTE: on the initial call, the PSF stars may have had multiple models tried and the psfMag
     88    may not be the value for the chosen model. 
     89  * in psphotSourceSize, in psphotSourceClassRegion, raw PSF & raw AP for all sources for which size is not yet measured.
     90  * in psphotApResid: raw PSF & raw AP for STARS only
     91  * in psphotMagnitudes; corrected PSF & AP mags
    192
    2932009.01.24
  • trunk/psphot/doc/outline.txt

    r10053 r25755  
    22Here is a summary outline of the steps taken by psphotReadout:
    33
    4 * setup (choose recipe, choose readout, define break-point)
    5 * create mask and weight images if needed, set mask for analysis region
    6 * psphotImageMedian : construct a background model image and subtract it
    7 * psphotFindPeaks   : smooth and find the peak pixels from the smoothed image
    8   - no pmSource defined yet, only pmPeak
    9 * psphotSourceStats : create sources for each peak and measure their moments
    10   - pmSource defined here, with pixels covering SKY_OUTER_RADIUS
    11   - no pmModel is defined yet.
    12 * psphotBasicDeblend : identify blended sources by proximity and valley depth
    13 * psphotRoughClass : source classification guess based on moments
    14   - set the source.type,mode.
    15   - re-calculate moments for saturated stars
    16 * psphotChoosePSF : define the psf model
    17   - this generates model fits to the identified psf stars
    18     (one for each tested model)
    19   - these models are not kept (seems like a waste, but later fits must be consistent)
    20 * psphotGuessModels : set the initial PSF model for each object (even EXTENDED)
    21   - creates modelPSF entries
     4* setup (choose recipe, readout, etc)
     5
     6* create mask and weight images if needed
     7
     8* construct a background model image and subtract it
     9
     10* generate the significance image (smoothed by small Gaussian)
     11
     12* find peaks and associated footprints
     13
     14* create sources for each peak and measure moments
     15  - scan over several window sigma values and choose an optimal window size
     16  - at this stage, the moments are aimed at identifying psf-like objects
     17
     18* identify blended sources by proximity and valley depth
     19
     20* crude source classification guess based on moments & saturated pixels
     21  - major goal is to identify the psf-stars
     22  - allows for 2D variations in the psf
     23
     24* use the selected PSF candidate stars to generate a PSF model 
     25  - fits PSF model parameters as a function of position
     26  - uses psfMag - apMag to choose order of 2D  (minimize systematic error in this value)
     27  - generates a PSF residual image & optional 2D variations
     28
     29* fit all detected sources to the psf model (linear fit for normalization only)
     30
     31* high-quality source classification
     32  - uses Mxx, Myy, psfMag - moment->Sum (equiv to apMags)
     33  * should the extended / psf cut be a function of galactic latitude?
     34  * should the cosmic ray / psf cut be a function of galactic latitude?
     35
     36* non-linear fit for all brighter sources to single psf, double psf, or extended source model
     37  - sources identified as extended above are fitted with extended source model
     38  * are group / clumps of sources being fitted in the best way?
     39  * is the psf-model ap mag being measured in an appropriate-size aperture?
     40  * is the criterion for choosing between 2 psfs and extended source OK?
     41  * is the test for double psf OK? (uses moments to guess starting positions)
     42 
     43* subtract, re-detect, measure faint sources (PSF-only)
     44
     45* optional extended source aperture-like measurements (petrosian, etc)
     46
     47* optional extended source non-linear fits (Sersic, etc)
     48
     49* measure psfMag-apMag correcion (2D)
     50  * convert analysis to use systematic error measurement
     51
     52* generate magnitudes
     53
     54* measure detection efficiency
     55
     56* output
  • trunk/psphot/src

    • Property svn:ignore
      •  

        old new  
        1818psphotVersionDefinitions.h
        1919psphotMomentsStudy
         20psphotPetrosianStudy
  • trunk/psphot/src/Makefile.am

    r25383 r25755  
    2525libpsphot_la_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
    2626
    27 bin_PROGRAMS = psphot psphotTest psphotMomentsStudy
     27bin_PROGRAMS = psphot psphotTest psphotMomentsStudy
     28# bin_PROGRAMS = psphotPetrosianStudy
     29# bin_PROGRAMS = psphot
    2830
    2931psphot_CFLAGS = $(PSPHOT_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
     
    3840psphotMomentsStudy_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
    3941psphotMomentsStudy_LDADD = libpsphot.la
     42
     43# psphotPetrosianStudy_CFLAGS = $(PSPHOT_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
     44# psphotPetrosianStudy_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
     45# psphotPetrosianStudy_LDADD = libpsphot.la
    4046
    4147psphot_SOURCES = \
     
    6167psphotMomentsStudy_SOURCES = \
    6268        psphotMomentsStudy.c
     69
     70# psphotPetrosianStudy_SOURCES = \
     71#         psphotPetrosianStudy.c
    6372
    6473libpsphot_la_SOURCES = \
     
    104113        psphotExtendedSourceAnalysis.c \
    105114        psphotExtendedSourceFits.c     \
    106         psphotRadialProfile.c          \
    107         psphotPetrosian.c              \
    108         psphotIsophotal.c              \
    109         psphotAnnuli.c                 \
    110         psphotKron.c                   \
    111115        psphotKernelFromPSF.c          \
    112116        psphotPSFConvModel.c           \
     
    129133        psphotThreadTools.c            \
    130134        psphotAddNoise.c               \
     135        psphotRadialProfile.c          \
     136        psphotRadialProfileByAngles.c  \
     137        psphotRadiiFromProfiles.c      \
     138        psphotEllipticalContour.c      \
     139        psphotEllipticalProfile.c      \
     140        psphotPetrosian.c              \
     141        psphotPetrosianRadialBins.c    \
     142        psphotPetrosianStats.c         \
    131143        psphotEfficiency.c
    132144
    133 # dropped? psphotGrowthCurve.c
     145# re-instate these
     146#       psphotIsophotal.c              \
     147#       psphotAnnuli.c                 \
     148#       psphotKron.c                   \
     149#       psphotPetrosianVisual.c        \
     150#
     151
     152# test versions
     153#       psphotPetrosianProfile.c       \
     154#       psphotPetrosianAnalysis.c      \
     155#
    134156
    135157include_HEADERS = \
  • trunk/psphot/src/psphot.h

    r25383 r25755  
    5858bool            psphotBlendFit_Threaded (psThreadJob *job);
    5959
    60 psArray        *psphotSourceStats (pmConfig *config, pmReadout *readout, pmDetections *detections);
     60psArray        *psphotSourceStats (pmConfig *config, pmReadout *readout, pmDetections *detections, bool setWindow);
    6161bool            psphotSourceStats_Threaded (psThreadJob *job);
    6262
     
    7171
    7272bool            psphotApResid (pmConfig *config, pmReadout *readout, psArray *sources, pmPSF *psf);
    73 bool            psphotApResidMags_Threaded (psThreadJob *job);
    7473
    7574bool            psphotSkyReplace (pmConfig *config, const pmFPAview *view);
     
    8786psImage        *psphotSignificanceImage (pmReadout *readout, psMetadata *recipe, const int pass, psImageMaskType maskVal);
    8887psArray        *psphotFindPeaks (psImage *significance, pmReadout *readout, psMetadata *recipe, const float threshold, const int nMax);
    89 bool            psphotFindFootprints (pmDetections *detections, psImage *significance, pmReadout *readout, psMetadata *recipe, const int pass, psImageMaskType maskVal);
     88bool            psphotFindFootprints (pmDetections *detections, psImage *significance, pmReadout *readout, psMetadata *recipe, const float threshold, const int pass, psImageMaskType maskVal);
    9089psErrorCode     psphotCullPeaks(const psImage *img, const psImage *weight, const psMetadata *recipe, psArray *footprints);
    9190
     
    9493
    9594// used by ApResid
    96 bool            psphotMagErrorScale (float *errorScale, float *errorFloor, psVector *dMag, psVector *dap, psVector *mask, int nGroup);
    97 bool            psphotApResidTrend (pmReadout *readout, pmPSF *psf, int Npsf, int scale, float *errorScale, float *errorFloor, psVector *mask, psVector *xPos, psVector *yPos, psVector *apResid, psVector *dMag);
     95pmTrend2D      *psphotApResidTrend (float *apResidSysErr, pmReadout *readout, int Nx, int Ny, psVector *xPos, psVector *yPos, psVector *apResid, psVector *dMag);
     96bool            psphotApResidMags_Threaded (psThreadJob *job);
    9897
    9998// basic support functions
     
    109108bool            psphotInitRadiusEXT (psMetadata *recipe, pmModelType type);
    110109bool            psphotCheckRadiusEXT (pmReadout *readout, pmSource *source, pmModel *model, psImageMaskType markVal);
     110float           psphotSetRadiusEXT (pmReadout *readout, pmSource *source, psImageMaskType markVal);
    111111
    112112// output functions
     
    159159bool            psphotSetState (pmSource *source, bool curState, psImageMaskType maskVal);
    160160bool            psphotDeblendSatstars (pmReadout *readout, psArray *sources, psMetadata *recipe);
    161 bool            psphotSourceSize (pmConfig *config, pmReadout *readout, psArray *sources, psMetadata *recipe, long first);
     161bool            psphotSourceSize (pmConfig *config, pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, long first);
    162162
    163163bool            psphotMakeResiduals (psArray *sources, psMetadata *recipe, pmPSF *psf, psImageMaskType maskVal);
     
    167167psKernel       *psphotKernelFromPSF (pmSource *source, int nPix);
    168168
    169 bool            psphotRadialProfile (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
    170 bool            psphotPetrosian (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
    171 bool            psphotIsophotal (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
    172 bool            psphotAnnuli (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
    173 bool            psphotKron (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
     169// functions related to extended source analysis
     170bool  psphotRadialProfile (pmSource *source, psMetadata *recipe, float skynoise, psImageMaskType maskVal);
     171bool  psphotRadialProfilesByAngles (pmSource *source, int Nsec, float Rmax);
     172float psphotRadiusFromProfile (pmSource *source, psVector *radius, psVector *flux, float fluxMin, float fluxMax);
     173bool  psphotRadiiFromProfiles (pmSource *source, float fluxMin, float fluxMax);
     174bool  psphotEllipticalProfile (pmSource *source);
     175bool  psphotEllipticalContour (pmSource *source);
    174176
    175177// psphotVisual functions
     
    190192bool psphotVisualShowSourceSize (pmReadout *readout, psArray *sources);
    191193bool psphotVisualShowResidualImage (pmReadout *readout);
    192 bool psphotVisualPlotApResid (psArray *sources);
    193 bool psphotVisualPlotSourceSize (psArray *sources);
     194bool psphotVisualPlotApResid (psArray *sources, float mean, float error);
     195bool psphotVisualPlotSourceSize (psMetadata *recipe, psArray *sources);
     196bool psphotVisualShowPetrosians (psArray *sources);
     197
     198// bool psphotPetrosianAnalysis (pmReadout *readout, psArray *sources, psMetadata *recipe);
     199// bool psphotPetrosianProfile (pmReadout *readout, pmSource *source, float skynoise);
     200
     201bool psphotPetrosian (pmSource *source, psMetadata *recipe, float skynoise, psImageMaskType maskVal);
     202bool psphotPetrosianRadialBins (pmSource *source, float radiusMax, float skynoise);
     203bool psphotPetrosianStats (pmSource *source);
     204
     205// XXX old versions, currently disabled
     206// bool            psphotIsophotal (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
     207// bool            psphotAnnuli (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
     208// bool            psphotKron (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
     209
     210// XXX visualization functions related to radial profiles (disabled)
     211// bool psphotPetrosianVisualProfileByAngle (psVector *radius, psVector *flux);
     212// bool psphotPetrosianVisualProfileRadii (psVector *radius, psVector *flux, psVector *radiusBin, psVector *fluxBin, float peakFlux, float RadiusRef);
     213// bool psphotPetrosianVisualEllipticalContour (pmPetrosian *petrosian);
     214// bool psphotPetrosianVisualStats (psVector *radBin, psVector *fluxBin,
     215//                               psVector *refRadius, psVector *meanSB,
     216//                               psVector *petRatio, psVector *petRatioErr, psVector *fluxSum,
     217//                               float petRadius, float ratioForRadius,
     218//                               float petFlux, float radiusForFlux);
    194219
    195220bool psphotImageQuality (psMetadata *recipe, psArray *sources);
  • trunk/psphot/src/psphotAddNoise.c

    r25383 r25755  
    5050
    5151        // skip sources which were not subtracted
     52        // NOTE: this bit is not modified when pmSourceOp applies to noise
    5253        if (!(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED)) continue;
    5354
     
    7980        axes.minor *= SIZE;
    8081        newshape = psEllipseAxesToShape (axes);
    81         PAR[PM_PAR_I0]  = FACTOR*PS_SQR(oldI0);
     82        PAR[PM_PAR_I0]  = FACTOR*oldI0;
    8283        PAR[PM_PAR_SXX] = newshape.sx;
    8384        PAR[PM_PAR_SYY] = newshape.sy;
  • trunk/psphot/src/psphotApResid.c

    r24878 r25755  
    3333    if (!measureAptrend) {
    3434        // save nan values since these were not calculated
    35         psMetadataAdd (recipe, PS_LIST_TAIL, "SKYBIAS",  PS_DATA_F32 | PS_META_REPLACE, "aperture sky bias",   NAN);
    36         psMetadataAdd (recipe, PS_LIST_TAIL, "SKYSAT",   PS_DATA_F32 | PS_META_REPLACE, "aperture-determined saturation",   NAN);
    3735        psMetadataAdd (recipe, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   NAN);
    3836        psMetadataAdd (recipe, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", NAN);
     37        psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", 0);
    3938        psMetadataAdd (recipe, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", NAN);
    40         psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", 0);
    4139        return true;
    4240    }
     
    5351    maskVal |= markVal;
    5452
    55     // S/N limit to perform full non-linear fits
     53    // clipping for extreme outliers
     54    // XXX this is not currently defined in the recipe
    5655    float MAX_AP_OFFSET = psMetadataLookupF32 (&status, recipe, "MAX_AP_OFFSET");
    5756
    58     // this is the smallest radius allowed: need to at least extend growth curve down to this...
     57    // options for how the photometry is calculated
     58    // XXX are these sensible?
    5959    bool IGNORE_GROWTH = psMetadataLookupBool (&status, recipe, "IGNORE_GROWTH");
    6060    bool INTERPOLATE_AP = psMetadataLookupBool (&status, recipe, "INTERPOLATE_AP");
     
    100100            PS_ARRAY_ADD_SCALAR(job->args, photMode, PS_TYPE_S32);
    101101            PS_ARRAY_ADD_SCALAR(job->args, maskVal,  PS_TYPE_IMAGE_MASK);
     102            PS_ARRAY_ADD_SCALAR(job->args, markVal,  PS_TYPE_IMAGE_MASK);
    102103
    103104            PS_ARRAY_ADD_SCALAR(job->args, 0,        PS_TYPE_S32); // this is used as a return value for Nskip
     
    110111            }
    111112            psFree(job);
    112 
    113 # if (0)
    114                 int nskip = 0;
    115                 int nfail = 0;
    116 
    117                 if (!psphotApResidMags_Unthreaded (&nskip, &nfail, sources, psf, photMode, maskVal)) {
    118                     psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
    119                     return false;
    120                 }
    121                 Nskip += nskip;
    122                 Nfail += nfail;
    123 # endif
    124 
    125113        }
    126114
     
    138126            } else {
    139127                psScalar *scalar = NULL;
    140                 scalar = job->args->data[4];
     128                scalar = job->args->data[5];
    141129                Nskip += scalar->data.S32;
    142                 scalar = job->args->data[5];
     130                scalar = job->args->data[6];
    143131                Nfail += scalar->data.S32;
    144132            }
     
    150138
    151139    // gather the stats to assess the aperture residuals
    152     psVector *mask    = psVectorAllocEmpty (300, PS_TYPE_VECTOR_MASK);
    153140    psVector *mag     = psVectorAllocEmpty (300, PS_TYPE_F32);
    154141    psVector *xPos    = psVectorAllocEmpty (300, PS_TYPE_F32);
     
    158145    Npsf = 0;
    159146
     147# ifdef DEBUG   
     148    FILE *f = fopen ("apresid.dat", "w");
     149    psAssert (f, "failed open");
     150# endif
     151
    160152    for (int i = 0; i < sources->n; i++) {
    161153        source = sources->data[i];
     
    170162        if (source->mode &  PM_SOURCE_MODE_EXT_LIMIT) SKIPSTAR ("EXTENDED");
    171163        if (source->mode &  PM_SOURCE_MODE_CR_LIMIT) SKIPSTAR ("COSMIC RAY");
     164        if (source->mode &  PM_SOURCE_MODE_DEFECT) SKIPSTAR ("DEFECT");
    172165           
    173166        if (!isfinite(source->apMag) || !isfinite(source->psfMag)) {
    174167            continue;
    175168        }
     169
     170        // XXX make this user-configurable?
     171        if (source->errMag > 0.01) continue;
    176172
    177173        // aperture residual for this source
     
    185181        }
    186182
    187         mag->data.F32[Npsf]     = source->psfMag;
    188         apResid->data.F32[Npsf] = dap;
    189         xPos->data.F32[Npsf]    = model->params->data.F32[PM_PAR_XPOS];
    190         yPos->data.F32[Npsf]    = model->params->data.F32[PM_PAR_YPOS];
    191 
    192         mask->data.PS_TYPE_VECTOR_MASK_DATA[Npsf] = 0;
    193 
    194         dMag->data.F32[Npsf] = model->dparams->data.F32[PM_PAR_I0] / model->params->data.F32[PM_PAR_I0];
    195 
    196         psVectorExtend (mag,     100, 1);
    197         psVectorExtend (mask,    100, 1);
    198         psVectorExtend (xPos,    100, 1);
    199         psVectorExtend (yPos,    100, 1);
    200         psVectorExtend (dMag,    100, 1);
    201         psVectorExtend (apResid, 100, 1);
     183# ifdef DEBUG
     184        fprintf (f, "%6.1f %6.1f : %6.1f %6.1f : %8.3f %8.3f %8.3f : %f : %f %f %f : %f\n",
     185                 source->peak->xf, source->peak->yf,
     186                 source->modelPSF->params->data.F32[PM_PAR_XPOS], source->modelPSF->params->data.F32[PM_PAR_YPOS],
     187                 source->psfMag, source->apMag, source->errMag,
     188                 source->modelPSF->params->data.F32[PM_PAR_I0],
     189                 source->modelPSF->params->data.F32[PM_PAR_SXX], source->modelPSF->params->data.F32[PM_PAR_SXY], source->modelPSF->params->data.F32[PM_PAR_SYY],
     190                 source->modelPSF->params->data.F32[PM_PAR_7]);
     191# endif
     192        if (!isfinite(source->psfMag)) psAbort ("nan in psfMag");
     193        if (!isfinite(source->errMag)) psAbort ("nan in errMag");
     194        if (!isfinite(source->apMag)) psAbort ("nan in apMag");
     195        if (!isfinite(model->params->data.F32[PM_PAR_XPOS])) psAbort ("nan in xPos");
     196        if (!isfinite(model->params->data.F32[PM_PAR_YPOS])) psAbort ("nan in yPos");
     197
     198        psVectorAppend (mag, source->psfMag);
     199        psVectorAppend (dMag,source->errMag);
     200        psVectorAppend (apResid, dap);
     201        psVectorAppend (xPos, model->params->data.F32[PM_PAR_XPOS]);
     202        psVectorAppend (yPos, model->params->data.F32[PM_PAR_YPOS]);
    202203        Npsf ++;
    203204    }
     
    205206    psLogMsg ("psphot.apresid", PS_LOG_DETAIL, "measure aperture residuals for %d objects (%d skipped, %d failed, %ld invalid)\n",
    206207              Npsf, Nskip, Nfail, sources->n - Npsf - Nskip - Nfail);
     208
     209# ifdef DEBUG
     210    fclose (f);
     211# endif
    207212
    208213    // XXX choose a better value here?
     
    212217    }
    213218
    214     // XXX deprecating the old code which allowed the ApResid to be fitted as a function of flux and r^2/flux
    215     // XXX is this asymmetric clipping still needed?  this analysis should come after neighbors are subtracted...
    216     // 3hi/1lo sigma clipping on the rflux vs metric fit
    217     // systematic error information
    218     float errorScale = 0.0;
    219     float errorFloor = 0.0;
    220 
     219    // XXX set the min number of needed source more carefully
     220    if ((Npsf < 15) && (APTREND_ORDER_MAX >= 4)) APTREND_ORDER_MAX = 3;
     221    if ((Npsf < 11) && (APTREND_ORDER_MAX >= 3)) APTREND_ORDER_MAX = 2;
     222    if ((Npsf <  8) && (APTREND_ORDER_MAX >= 2)) APTREND_ORDER_MAX = 1;
     223
     224    psFree (psf->ApTrend);
     225    psf->ApTrend = NULL;
    221226    float errorFloorMin = FLT_MAX;
    222     int entryMin = -1;
    223 
    224     // Fit out the dap vs mag trend, iterate over spatial scale until error Floor increases.
    225     // Stop if Npsf / (Nx * Ny) < 3
     227
     228    // as we loop over orders, we need to refer to the initial selection, but we modify the
     229    // option values to match the current guess: save the max values here:
     230    int NX = readout->image->numCols;
     231    int NY = readout->image->numRows;
    226232    for (int i = 1; i <= APTREND_ORDER_MAX; i++) {
    227 
    228         if (!psphotApResidTrend (readout, psf, Npsf, i, &errorScale, &errorFloor, mask, xPos, yPos, apResid, dMag)) {
    229             break;
    230         }
    231 
    232         // store the resulting errorFloor values and the scales, redo the best
     233       
     234        int Nx, Ny;
     235        if (NX > NY) {
     236            Nx = i;
     237            Ny = PS_MAX (1, (int)(i * (NY / (float)(NX)) + 0.5));
     238        } else {
     239            Ny = i;
     240            Nx = PS_MAX (1, (int)(i * (NX / (float)(NY)) + 0.5));
     241        }
     242
     243        float errorFloor;
     244        pmTrend2D *apTrend = psphotApResidTrend (&errorFloor, readout, Nx, Ny, xPos, yPos, apResid, dMag);
     245        if (!apTrend) {
     246            continue;
     247        }
     248
     249        // apply ApTrend results
     250        // float xc = 0.5*readout->image->numCols + readout->image->col0 + 0.5;
     251        // float yc = 0.5*readout->image->numRows + readout->image->row0 + 0.5;
     252        // float ApResid = pmTrend2DEval (psf->ApTrend, xc, yc); // ap-fit at chip center
     253        // if (!isfinite(ApResid)) psAbort("nan apresid @ center");
     254
     255        // store the minimum errorFloor and best ApTrend to keep
    233256        if (errorFloor < errorFloorMin) {
    234257            errorFloorMin = errorFloor;
    235             entryMin = i;
     258            psFree (psf->ApTrend);
     259            psf->ApTrend = psMemIncrRefCounter(apTrend);
    236260        }
    237     }
    238     if (entryMin == -1) {
     261        psFree (apTrend);
     262    }
     263    if (psf->ApTrend == NULL) {
    239264        psWarning("Failed to find a valid aperture residual value");
    240265        goto escape;
    241266    }
    242267
    243     // XXX catch error condition
    244     psphotApResidTrend (readout, psf, Npsf, entryMin, &errorScale, &errorFloor, mask, xPos, yPos, apResid, dMag);
     268    // apply ApTrend results
     269    float xc = 0.5*readout->image->numCols + readout->image->col0 + 0.5;
     270    float yc = 0.5*readout->image->numRows + readout->image->row0 + 0.5;
     271
     272    psf->ApResid  = pmTrend2DEval (psf->ApTrend, xc, yc); // ap-fit at chip center
     273    psf->dApResid = errorFloorMin;
     274    psf->nApResid = Npsf;
     275
     276    // save results for later output
     277    psMetadataAdd (recipe, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   psf->ApResid);
     278    psMetadataAdd (recipe, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", psf->dApResid);
     279    psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", psf->nApResid);
     280    psMetadataAdd (recipe, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", psf->growth->apLoss);
     281
     282    psLogMsg ("psphot.apresid", PS_LOG_DETAIL, "aperture residual: %f +/- %f\n", psf->ApResid, psf->dApResid);
     283    psLogMsg ("psphot.apresid", PS_LOG_INFO, "measure full-frame aperture residuals for %d sources: %f sec\n", Npsf, psTimerMark ("psphot.apresid"));
     284
     285    psFree (xPos);
     286    psFree (yPos);
     287    psFree (apResid);
     288    psFree (mag);
     289    psFree (dMag);
     290
     291    psphotVisualPlotApResid (sources, psf->ApResid, psf->dApResid);
     292
     293    return true;
     294
     295escape:
     296    // save nan values since these were not calculated
     297    psMetadataAdd (recipe, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   NAN);
     298    psMetadataAdd (recipe, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", NAN);
     299    psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", 0);
     300    psMetadataAdd (recipe, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", NAN);
     301
     302    psFree (xPos);
     303    psFree (yPos);
     304    psFree (apResid);
     305    psFree (mag);
     306    psFree (dMag);
     307    return false;
     308}
     309
     310pmTrend2D *psphotApResidTrend (float *apResidSysErr, pmReadout *readout, int Nx, int Ny, psVector *xPos, psVector *yPos, psVector *apResid, psVector *dMag) {
     311
     312    // the mask marks the values not used to calculate the ApTrend
     313    psVector *mask = psVectorAlloc(xPos->n, PS_TYPE_VECTOR_MASK);
     314    psVectorInit (mask, 0);
     315
     316    // XXX allow user to set this optionally?
     317    psStats *stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN | PS_STAT_SAMPLE_STDEV);
     318
     319    // measure Trend2D for the current spatial scale
     320    pmTrend2D *apTrend = pmTrend2DAlloc (PM_TREND_MAP, readout->image, Nx, Ny, stats);
     321
     322    // XXX somewhat arbitrary: soften the errors so the few bright stars do not totally dominate:
     323    // XXX use this or not?  probably not, since this is the point of the systematic error analysis
     324    psVector *dMagSoft = psVectorAlloc (dMag->n, PS_TYPE_F32);
     325    for (int i = 0; i < dMag->n; i++) {
     326        dMagSoft->data.F32[i] = hypot(dMag->data.F32[i], 0.005);
     327    }
     328
     329    // XXX test for errors here
     330    if (!pmTrend2DFit (apTrend, mask, 0xff, xPos, yPos, apResid, dMagSoft)) {
     331        psWarning("Failed to fit trend for %d x %d map", Nx, Ny);
     332        psFree (apTrend);
     333        return NULL;
     334    }
     335    if (apTrend->mode == PM_TREND_MAP) {
     336        // p_psImagePrint (2, apTrend->map->map, "ApTrend Before"); // XXX TEST:
     337        psImageMapRepair (apTrend->map->map);
     338        // p_psImagePrint (2, apTrend->map->map, "ApTrend After"); // XXX TEST:
     339    }
    245340
    246341    // construct the fitted values and the residuals
    247     psVector *apResidFit = pmTrend2DEvalVector (psf->ApTrend, mask, 0xff, xPos, yPos);
     342    psVector *apResidFit = pmTrend2DEvalVector (apTrend, mask, 0xff, xPos, yPos);
    248343    psVector *apResidRes = (psVector *) psBinaryOp (NULL, (void *) apResid, "-", (void *) apResidFit);
    249     psVector *dMagSys = (psVector *) psBinaryOp (NULL, (void *) dMag, "*", (void *) psScalarAlloc(errorScale, PS_TYPE_F32));
    250 
    251     if (psTraceGetLevel("psphot") >= 2) {
    252         FILE *dumpFile = fopen ("apresid.dat", "w");
     344
     345    // measure systematic error
     346    *apResidSysErr = psVectorSystematicError (apResidRes, dMag, 0.10);
     347    if (!isfinite(*apResidSysErr)) {
     348        psWarning("Failed to find systematic error for %d x %d map", Nx, Ny);
     349        psFree (apTrend);
     350        return NULL;
     351    }
     352
     353    psLogMsg ("psphot.apresid", PS_LOG_INFO, "result of %d x %d grid\n", Nx, Ny);
     354    psLogMsg ("psphot.apresid", PS_LOG_INFO, "systematic scatter floor: %f\n", *apResidSysErr);
     355
     356    if (psTraceGetLevel("psphot") >= 4) {
     357        char filename[64];
     358        snprintf (filename, 64, "apresid.%dx%d.dat", Nx, Ny);
     359        FILE *dumpFile = fopen (filename, "w");
    253360        for (int i = 0; i < xPos->n; i++) {
    254             fprintf (dumpFile, "%f %f  %f %f %f %f %f  %x\n",
     361            fprintf (dumpFile, "%f %f  %f %f %f %f  %x\n",
    255362                     xPos->data.F32[i], yPos->data.F32[i],
    256                      mag->data.F32[i], dMag->data.F32[i], dMagSys->data.F32[i],
     363                     dMag->data.F32[i], hypot(dMag->data.F32[i], *apResidSysErr),
    257364                     apResid->data.F32[i], apResidRes->data.F32[i],
    258365                     mask->data.PS_TYPE_VECTOR_MASK_DATA[i]);
     
    261368    }
    262369
    263     // apply ApTrend results
    264     float xc = 0.5*readout->image->numCols + readout->image->col0 + 0.5;
    265     float yc = 0.5*readout->image->numRows + readout->image->row0 + 0.5;
    266 
    267     psf->ApResid  = pmTrend2DEval (psf->ApTrend, xc, yc); // ap-fit at chip center
    268     psf->dApResid = errorFloor;
    269     psf->nApResid = Npsf;
    270 
    271     // save results for later output
    272     psMetadataAdd (recipe, PS_LIST_TAIL, "SKYBIAS",  PS_DATA_F32 | PS_META_REPLACE, "aperture sky bias",   0.0);
    273     psMetadataAdd (recipe, PS_LIST_TAIL, "SKYSAT",   PS_DATA_F32 | PS_META_REPLACE, "aperture-determined saturation",   0.0);
    274     psMetadataAdd (recipe, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   psf->ApResid);
    275     psMetadataAdd (recipe, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", psf->dApResid);
    276     psMetadataAdd (recipe, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", psf->growth->apLoss);
    277     psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", psf->nApResid);
    278 
    279     psLogMsg ("psphot.apresid", PS_LOG_DETAIL, "aperture residual: %f +/- %f\n", psf->ApResid, psf->dApResid);
    280     psLogMsg ("psphot.apresid", PS_LOG_INFO, "measure full-frame aperture residuals for %d sources: %f sec\n", Npsf, psTimerMark ("psphot.apresid"));
    281 
    282     psFree (mag);
    283370    psFree (mask);
    284     psFree (xPos);
    285     psFree (yPos);
    286 
    287     psFree (apResid);
    288     psFree (apResidFit);
    289     psFree (apResidRes);
    290 
    291     psFree (dMagSys);
    292     psFree (dMag);
    293 
    294     psphotVisualPlotApResid (sources);
    295 
    296     return true;
    297 
    298 escape:
    299     // save nan values since these were not calculated
    300     psMetadataAdd (recipe, PS_LIST_TAIL, "SKYBIAS",  PS_DATA_F32 | PS_META_REPLACE, "aperture sky bias",   NAN);
    301     psMetadataAdd (recipe, PS_LIST_TAIL, "SKYSAT",   PS_DATA_F32 | PS_META_REPLACE, "aperture-determined saturation",   NAN);
    302     psMetadataAdd (recipe, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   NAN);
    303     psMetadataAdd (recipe, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", NAN);
    304     psMetadataAdd (recipe, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", NAN);
    305     psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", 0);
    306 
    307     psFree (mag);
    308     psFree (mask);
    309     psFree (xPos);
    310     psFree (yPos);
    311     psFree (apResid);
    312     psFree (dMag);
    313     return false;
    314 }
    315 
    316 /*
    317   (aprMag' - fitMag) = rflux*skyBias + ApTrend(x,y)
    318   (aprMag - rflux*skyBias) - fitMag = ApTrend(x,y)
    319   (aprMag - rflux*skyBias) = fitMag + ApTrend(x,y)
    320 */
    321 
    322 // XXX this still sucks...  need a better way to estimate the error floor...
    323 bool psphotMagErrorScale (float *errorScale, float *errorFloor, psVector *dMag, psVector *dap, psVector *mask, int nGroup) {
    324 
    325     psStats *statsS = psStatsAlloc (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV);
    326     psStats *statsM = psStatsAlloc (PS_STAT_SAMPLE_MEAN);
    327 
    328     // measure the trend in bins with 10 values each; if < 10 total, use them all
    329     int nBin = PS_MAX (dMag->n / nGroup, 1);
    330 
    331     // output vectors for ApResid trend
    332     psVector *dSo = psVectorAlloc (nBin, PS_TYPE_F32);
    333     psVector *dMo = psVectorAlloc (nBin, PS_TYPE_F32);
    334     psVector *dRo = psVectorAlloc (nBin, PS_TYPE_F32);
    335 
    336     // use dMag to group the dMag and dap vectors
    337     psVector *index = psVectorSortIndex (NULL, dMag);
    338 
    339     // subset vectors for dMag and dap values within the given range
    340     psVector *dMSubset = psVectorAllocEmpty (nGroup, PS_TYPE_F32);
    341     psVector *dASubset = psVectorAllocEmpty (nGroup, PS_TYPE_F32);
    342     psVector *mkSubset = psVectorAllocEmpty (nGroup, PS_TYPE_VECTOR_MASK);
    343 
    344     int n = 0;
    345     for (int i = 0; i < dMo->n; i++) {
    346         int j;
    347         for (j = 0; (j < nGroup) && (n < dMag->n); j++, n++) {
    348             int N = index->data.U32[n];
    349             dMSubset->data.F32[j] = dMag->data.F32[N];
    350             dASubset->data.F32[j] = dap->data.F32[N];
    351             mkSubset->data.PS_TYPE_VECTOR_MASK_DATA[j] = mask->data.PS_TYPE_VECTOR_MASK_DATA[N];
    352         }
    353         dMSubset->n = j;
    354         dASubset->n = j;
    355         mkSubset->n = j;
    356 
    357         psStatsInit (statsS);
    358         psStatsInit (statsM);
    359 
    360         if (j > 2) {
    361             if (!psVectorStats (statsS, dASubset, NULL, mkSubset, 0xff)) {
    362                 psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
    363                 return false;
    364             }
    365             if (!psVectorStats (statsM, dMSubset, NULL, mkSubset, 0xff)) {
    366                 psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
    367                 return false;
    368             }
    369             dSo->data.F32[i] = statsS->robustStdev;
    370             dMo->data.F32[i] = statsM->sampleMean;
    371             dRo->data.F32[i] = statsS->robustStdev / statsM->sampleMean;
    372         } else {
    373             dSo->data.F32[i] = NAN;
    374             dMo->data.F32[i] = NAN;
    375             dRo->data.F32[i] = NAN;
    376         }
    377     }
    378     psFree (dMSubset);
    379     psFree (dASubset);
    380     psFree (mkSubset);
    381 
    382     psStats *stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN);
    383     if (!psVectorStats (stats, dRo, NULL, NULL, 0)) {
    384         psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
    385         return false;
    386     }
    387 
    388     *errorScale = stats->sampleMedian;
    389     for (int i = 0; i < dSo->n; i++) {
    390         *errorFloor = dSo->data.F32[i];
    391         if (fabs(*errorFloor) <= FLT_EPSILON) continue;
    392         if (isfinite(*errorFloor)) break;
    393     }
    394 
    395     psFree (stats);
    396     psFree (index);
    397 
    398     psFree (dRo);
    399     psFree (dMo);
    400     psFree (dSo);
    401 
    402     psFree (statsS);
    403     psFree (statsM);
    404 
    405     return true;
    406 }
    407 
    408 bool psphotApResidTrend (pmReadout *readout, pmPSF *psf, int Npsf, int scale, float *errorScale, float *errorFloor, psVector *mask, psVector *xPos, psVector *yPos, psVector *apResid, psVector *dMag) {
    409 
    410     int Nx, Ny;
    411 
    412     if (readout->image->numCols > readout->image->numRows) {
    413         Nx = scale;
    414         float AR = readout->image->numRows / (float) readout->image->numCols;
    415         Ny = (int) (Nx * AR + 0.5);
    416         Ny = PS_MAX (1, Ny);
    417     } else {
    418         Ny = scale;
    419         float AR = readout->image->numRows / (float) readout->image->numCols;
    420         Nx = (int) (Ny * AR + 0.5);
    421         Nx = PS_MAX (1, Nx);
    422     }
    423 
    424     // require at least 10 stars per spatial bin
    425     if (Npsf < 10*Nx*Ny) {
    426         return false;
    427     }
    428 
    429     // the mask marks the values not used to calculate the ApTrend
    430     psVectorInit (mask, 0);
    431 
    432     // XXX stats structure for use by ApTrend : make parameters user setable
    433     psStats *stats = psStatsAlloc (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV);
    434     stats->min = 2.0;
    435     stats->max = 3.0;
    436 
    437     // measure Trend2D for the current spatial scale
    438     psFree (psf->ApTrend);
    439     psf->ApTrend = pmTrend2DAlloc (PM_TREND_MAP, readout->image, Nx, Ny, stats);
    440 
    441     // XXX somewhat arbitrary: soften the errors so the few bright stars do not totally dominate:
    442     psVector *dMagSoft = psVectorAlloc (dMag->n, PS_TYPE_F32);
    443     for (int i = 0; i < dMag->n; i++) {
    444         dMagSoft->data.F32[i] = hypot(dMag->data.F32[i], 0.01);
    445     }
    446 
    447     // XXX test for errors here
    448     pmTrend2DFit (psf->ApTrend, mask, 0xff, xPos, yPos, apResid, dMagSoft);
    449 
    450     // construct the fitted values and the residuals
    451     psVector *apResidFit = pmTrend2DEvalVector (psf->ApTrend, mask, 0xff, xPos, yPos);
    452     psVector *apResidRes = (psVector *) psBinaryOp (NULL, (void *) apResid, "-", (void *) apResidFit);
    453 
    454     // measure systematic errorFloor & systematic / photon scale factor
    455     // XXX this is a bit arbitrary, but it forces ~3 stars from the bright bin per spatial bin
    456     int nGroup = PS_MAX (3*Nx*Ny, 10);
    457     psphotMagErrorScale (errorScale, errorFloor, dMag, apResidRes, mask, nGroup);
    458 
    459     psLogMsg ("psphot.apresid", PS_LOG_INFO, "result of %d x %d grid (%d stars per bin)\n", Nx, Ny, nGroup);
    460     psLogMsg ("psphot.apresid", PS_LOG_INFO, "systematic error / photon error: %f\n", *errorScale);
    461     psLogMsg ("psphot.apresid", PS_LOG_INFO, "systematic scatter floor: %f\n", *errorFloor);
    462 
    463371    psFree (stats);
    464372    psFree (dMagSoft);
     
    466374    psFree (apResidRes);
    467375
    468     return true;
     376    return apTrend;
    469377}
    470378
     
    480388    pmSourcePhotometryMode photMode = PS_SCALAR_VALUE(job->args->data[2],S32);
    481389    psImageMaskType maskVal         = PS_SCALAR_VALUE(job->args->data[3],PS_TYPE_IMAGE_MASK_DATA);
     390    psImageMaskType markVal         = PS_SCALAR_VALUE(job->args->data[4],PS_TYPE_IMAGE_MASK_DATA);
    482391
    483392    for (int i = 0; i < sources->n; i++) {
     
    490399        if (source->mode &  PM_SOURCE_MODE_POOR) SKIPSTAR ("POOR STAR");
    491400
    492         if (!pmSourceMagnitudes (source, psf, photMode, maskVal)) {
    493             Nskip ++;
    494             psTrace ("psphot", 3, "skip : bad source mag");
    495             continue;
     401        // replace object in image
     402        if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
     403            pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    496404        }
    497405
    498         if (!isfinite(source->apMag) || !isfinite(source->psfMag)) {
    499             Nfail ++;
    500             psTrace ("psphot", 3, "fail : nan mags : %f %f", source->apMag, source->psfMag);
    501             continue;
    502         }
    503         source->mode |= PM_SOURCE_MODE_AP_MAGS;
     406        // clear the mask bit and set the circular mask pixels
     407        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
     408        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", markVal);
     409
     410        bool status = pmSourceMagnitudes (source, psf, photMode, maskVal);
     411
     412        // clear the mask bit
     413        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
     414
     415        // re-subtract the object, leave local sky
     416        pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
     417
     418        if (!status) {
     419            Nskip ++;
     420            psTrace ("psphot", 3, "skip : bad source mag");
     421            continue;
     422        }
     423   
     424        if (!isfinite(source->apMag) || !isfinite(source->psfMag)) {
     425            Nfail ++;
     426            psTrace ("psphot", 3, "fail : nan mags : %f %f", source->apMag, source->psfMag);
     427            continue;
     428        }
     429        source->mode |= PM_SOURCE_MODE_AP_MAGS;
    504430    }
    505431
    506432    // change the value of a scalar on the array (wrap this and put it in psArray.h)
    507     scalar = job->args->data[4];
     433    scalar = job->args->data[5];
    508434    scalar->data.S32 = Nskip;
    509435
    510     scalar = job->args->data[5];
     436    scalar = job->args->data[6];
    511437    scalar->data.S32 = Nfail;
    512438
    513439    return true;
    514440}
    515 
    516 # if (0)
    517 bool psphotApResidMags_Unthreaded (int *nskip, int *nfail, psArray *sources, pmPSF *psf, pmSourcePhotometryMode photMode, psImageMaskType maskVal) {
    518 
    519     int Nskip = 0;
    520     int Nfail = 0;
    521 
    522     for (int i = 0; i < sources->n; i++) {
    523         pmSource *source = (pmSource *) sources->data[i];
    524 
    525         if (source->type != PM_SOURCE_TYPE_STAR) SKIPSTAR ("NOT STAR");
    526         if (source->mode &  PM_SOURCE_MODE_SATSTAR) SKIPSTAR ("SATSTAR");
    527         if (source->mode &  PM_SOURCE_MODE_BLEND) SKIPSTAR ("BLEND");
    528         if (source->mode &  PM_SOURCE_MODE_FAIL) SKIPSTAR ("FAIL STAR");
    529         if (source->mode &  PM_SOURCE_MODE_POOR) SKIPSTAR ("POOR STAR");
    530 
    531         if (!pmSourceMagnitudes (source, psf, photMode, maskVal)) {
    532             Nskip ++;
    533             psTrace ("psphot", 3, "skip : bad source mag");
    534             continue;
    535         }
    536 
    537         if (!isfinite(source->apMag) || !isfinite(source->psfMag)) {
    538             Nfail ++;
    539             psTrace ("psphot", 3, "fail : nan mags : %f %f", source->apMag, source->psfMag);
    540             continue;
    541         }
    542     }
    543 
    544     // change the value of a scalar on the array (wrap this and put it in psArray.h)
    545     *nskip = Nskip;
    546     *nfail = Nfail;
    547 
    548     return true;
    549 }
    550 # endif
  • trunk/psphot/src/psphotBlendFit.c

    r24029 r25755  
    254254        pmSourceCacheModel (source, maskVal);
    255255        pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    256         source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
    257256    }
    258257
     
    365364        pmSourceCacheModel (source, maskVal);
    366365        pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    367         source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
    368366    }
    369367
     
    374372    *nfail = Nfail;
    375373
     374    // moments are modified by the fit; re-display
     375    psphotVisualPlotMoments (recipe, sources);
     376    psphotVisualShowResidualImage (readout);
     377
    376378    return true;
    377379}
  • trunk/psphot/src/psphotChoosePSF.c

    r23989 r25755  
    11# include "psphotInternal.h"
    2 
    3 void psphotCountPSFStars (psArray *sources) {
    4 
    5     int nPSF = 0;
    6 
    7     // select the candidate PSF stars (pointers to original sources)
    8     for (int i = 0; i < sources->n; i++) {
    9         pmSource *source = sources->data[i];
    10         if (source->mode & PM_SOURCE_MODE_PSFSTAR) {
    11             nPSF ++;
    12         }
    13     }
    14 
    15     fprintf (stderr, "N PSF: %d\n", nPSF);
    16 }
    172
    183// try PSF models and select best option
     
    7358    // get the fixed PSF fit radius
    7459    // XXX check that PSF_FIT_RADIUS < SKY_OUTER_RADIUS
    75     options->radius = psMetadataLookupF32 (&status, recipe, "PSF_FIT_RADIUS");
    76     assert (status);
     60    // options->radius = psMetadataLookupF32 (&status, recipe, "PSF_FIT_RADIUS");
     61    // assert (status);
     62
     63    // We have calculated a Gaussian window function, use that for both the PSF fit radius and
     64    // the aperture radius (scaling SIGMA)
     65    float gaussSigma = psMetadataLookupF32(&status, recipe, "MOMENTS_GAUSS_SIGMA");
     66    float fitScale = psMetadataLookupF32(&status, recipe, "PSF_FIT_RADIUS_SCALE");
     67    float apScale = psMetadataLookupF32(&status, recipe, "PSF_APERTURE_SCALE");
     68    options->fitRadius = (int)(fitScale*gaussSigma);
     69    options->apRadius = (int)(apScale*gaussSigma);
     70
     71    // XXX use the same radii for standard analysis as for the PSF creation
     72    psMetadataAddF32(recipe, PS_LIST_TAIL, "PSF_FIT_RADIUS", PS_META_REPLACE, "fit radius", options->fitRadius);
     73    psMetadataAddF32(recipe, PS_LIST_TAIL, "PSF_APERTURE", PS_META_REPLACE, "psf aperture", options->apRadius);
    7774
    7875    // XXX ROBUST seems to be too agressive given the small numbers.
     
    9996
    10097    psArray *stars = psArrayAllocEmpty (sources->n);
    101 
    102     // psphotCountPSFStars (sources);
    10398
    10499    // select the candidate PSF stars (pointers to original sources)
     
    115110    }
    116111
    117     // psphotCountPSFStars (sources);
    118 
    119112    // check that the identified psf stars sufficiently cover the region; if not, extend the
    120113    // limits somewhat
    121114    psphotCheckStarDistribution (stars, sources, options);
    122 
    123     // psphotCountPSFStars (sources);
    124115
    125116    psLogMsg ("psphot.pspsf", PS_LOG_DETAIL, "selected candidate %ld PSF objects\n", stars->n);
     
    289280    // XXX test dump of psf star data and psf-subtracted image
    290281    if (psTraceGetLevel("psphot.psfstars") > 5) {
    291         psphotDumpPSFStars (readout, try, options->radius, maskVal, markVal);
     282        psphotDumpPSFStars (readout, try, options->fitRadius, maskVal, markVal);
    292283    }
    293284
    294285    // save only the best model;
    295     // XXX we are not saving the fitted sources
    296     // XXX do we want to keep them so we may optionally write them out?
    297286    pmPSF *psf = psMemIncrRefCounter(try->psf);
    298287    psFree (models);
     
    305294    }
    306295
    307     // psphotCountPSFStars (sources);
    308 
    309296    char *modelName = pmModelClassGetName (psf->type);
    310297    psLogMsg ("psphot.pspsf", PS_LOG_INFO, "select psf model: %f sec\n", psTimerMark ("psphot.choose.psf"));
     
    341328            // create modelPSF from this model
    342329            pmModel *modelPSF = pmModelFromPSFforXY (psf, xc, yc, 1.0);
    343             if (!modelPSF) continue;
     330            if (!modelPSF) {
     331                fprintf (stderr, "?");
     332                continue;
     333            }
    344334
    345335            // get the model full-width at half-max
     
    354344
    355345            float FWHM_MINOR = FWHM_MAJOR * (axes.minor / axes.major);
    356             if (!isfinite(FWHM_MAJOR) || !isfinite(FWHM_MINOR)) continue;
     346            if (!isfinite(FWHM_MAJOR) || !isfinite(FWHM_MINOR)) {
     347                fprintf (stderr, "!");
     348                continue;
     349            }
    357350            psVectorAppend (fwhmMajor, FWHM_MAJOR);
    358351            psVectorAppend (fwhmMinor, FWHM_MINOR);
  • trunk/psphot/src/psphotEfficiency.c

  • trunk/psphot/src/psphotExtendedSourceAnalysis.c

    r21519 r25755  
    2121    }
    2222
    23     // option to limit analysis to a specific region
    24     char *region = psMetadataLookupStr (&status, recipe, "ANALYSIS_REGION");
    25     psRegion AnalysisRegion = psRegionForImage (readout->image, psRegionFromString (region));
    26     if (psRegionIsNaN (AnalysisRegion)) psAbort("analysis region mis-defined");
     23    // XXX require petrosian analysis for non-linear fits?
     24
     25    // XXX temporary user-supplied systematic sky noise measurement (derive from background model)
     26    float skynoise = psMetadataLookupF32 (&status, recipe, "SKY.NOISE");
     27
     28# if (0)
     29    // if backModel or backStdev are missing, the values of sky and/or skyErr will be set to NAN
     30    // XXX use this to set skynoise
     31    pmReadout *backModel = psphotSelectBackground (config, view);
     32    pmReadout *backStdev = psphotSelectBackgroundStdev (config, view);
     33# endif
    2734
    2835    // S/N limit to perform full non-linear fits
     
    3845    sources = psArraySort (sources, pmSourceSortBySN);
    3946
    40     // XXX some init functions for the extended source recipe options?
     47    // option to limit analysis to a specific region
     48    char *region = psMetadataLookupStr (&status, recipe, "ANALYSIS_REGION");
     49    psRegion AnalysisRegion = psRegionForImage (readout->image, psRegionFromString (region));
     50    if (psRegionIsNaN (AnalysisRegion)) psAbort("analysis region mis-defined");
    4151
    4252    // choose the sources of interest
     
    4959        if (source->type == PM_SOURCE_TYPE_DEFECT) continue;
    5060        if (source->type == PM_SOURCE_TYPE_SATURATED) continue;
     61        if (source->mode & PM_SOURCE_MODE_DEFECT) continue;
     62        if (source->mode & PM_SOURCE_MODE_SATSTAR) continue;
     63        if (!(source->mode & PM_SOURCE_MODE_EXT_LIMIT)) continue;
    5164
    5265        // limit selection to some SN limit
     
    6881        // if we request any of these measurements, we require the radial profile
    6982        if (doPetrosian || doIsophotal || doAnnuli || doKron) {
    70             if (!psphotRadialProfile (source, recipe, maskVal)) {
     83            if (!psphotRadialProfile (source, recipe, skynoise, maskVal)) {
    7184                // all measurements below require the radial profile; skip them all
    7285                // re-subtract the object, leave local sky
    7386                psTrace ("psphot", 5, "failed to extract radial profile for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
    7487                pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    75                 source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
    7688                continue;
    7789            }
     
    7991        }
    8092
     93        // Petrosian Mags
     94        if (doPetrosian) {
     95            if (!psphotPetrosian (source, recipe, skynoise, maskVal)) {
     96                psTrace ("psphot", 5, "measured petrosian flux & radius for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
     97            } else {
     98                psTrace ("psphot", 5, "measured petrosian flux & radius for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
     99                Npetro ++;
     100                source->mode |= PM_SOURCE_MODE_EXTENDED_STATS;
     101            }
     102        }
     103
     104# if (0)
    81105        // Isophotal Mags
    82106        if (doIsophotal) {
     
    89113            }
    90114        }
    91 
    92         // Petrosian Mags
    93         if (doPetrosian) {
    94             if (!psphotPetrosian (source, recipe, maskVal)) {
    95                 psTrace ("psphot", 5, "measured petrosian flux & radius for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
    96             } else {
    97                 psTrace ("psphot", 5, "measured petrosian flux & radius for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
    98                 Npetro ++;
    99                 source->mode |= PM_SOURCE_MODE_EXTENDED_STATS;
    100             }
    101         }
    102 
    103115        // Kron Mags
    104116        if (doKron) {
     
    111123            }
    112124        }
    113 
    114         // Radial Annuli
    115         if (doAnnuli) {
    116             if (!psphotAnnuli (source, recipe, maskVal)) {
    117                 psError(PSPHOT_ERR_UNKNOWN, false, "failure in Annuli analysis");
    118                 return false;
    119             }
    120             psTrace ("psphot", 5, "measured annuli for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
    121             Nannuli ++;
    122             source->mode |= PM_SOURCE_MODE_EXTENDED_STATS;
    123         }
     125# endif
    124126
    125127        // re-subtract the object, leave local sky
    126128        pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    127         source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
     129
     130        if (source->extpars) {
     131            pmSourceRadialProfileFreeVectors(source->extpars->profile);
     132        }
    128133    }
    129134
     
    133138    psLogMsg ("psphot", PS_LOG_INFO, "  %d annuli\n", Nannuli);
    134139    psLogMsg ("psphot", PS_LOG_INFO, "  %d kron\n", Nkron);
     140
     141    psphotVisualShowResidualImage (readout);
     142
     143    if (doPetrosian) {
     144        psphotVisualShowPetrosians (sources);
     145    }
     146
    135147    return true;
    136148}
  • trunk/psphot/src/psphotExtendedSourceFits.c

    r21519 r25755  
    226226
    227227          pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    228           source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
    229228
    230229          psFree (modelFluxes);
     
    253252        // subtract the best fit from the object, leave local sky
    254253        pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    255         source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
    256254
    257255        // the initial model flux is no longer needed
  • trunk/psphot/src/psphotFake.c

  • trunk/psphot/src/psphotFindDetections.c

    r21183 r25755  
    5252    // optionally merge peaks into footprints
    5353    if (useFootprints) {
    54         psphotFindFootprints (detections, significance, readout, recipe, pass, maskVal);
     54        psphotFindFootprints (detections, significance, readout, recipe, threshold, pass, maskVal);
    5555    }
    5656
  • trunk/psphot/src/psphotFindFootprints.c

    r24274 r25755  
    11# include "psphotInternal.h"
    22
    3 bool psphotFindFootprints (pmDetections *detections, psImage *significance, pmReadout *readout, psMetadata *recipe, const int pass, psImageMaskType maskVal) {
     3bool psphotFindFootprints (pmDetections *detections, psImage *significance, pmReadout *readout, psMetadata *recipe, const float threshold, const int pass, psImageMaskType maskVal) {
    44
    55    bool status;
     
    99    int npixMin = psMetadataLookupS32(&status, recipe, "FOOTPRINT_NPIXMIN");
    1010    PS_ASSERT (status, false);
    11 
    12     float FOOTPRINT_NSIGMA_LIMIT;
    13     if (pass == 1) {
    14         FOOTPRINT_NSIGMA_LIMIT = psMetadataLookupS32(&status, recipe, "FOOTPRINT_NSIGMA_LIMIT");
    15     } else {
    16         FOOTPRINT_NSIGMA_LIMIT = psMetadataLookupS32(&status, recipe, "FOOTPRINT_NSIGMA_LIMIT_2");
    17     }
    18     PS_ASSERT (status, false);
    19 
    20     // XXX do we need to use the same threshold here as for peaks?  does it make sense for
    21     // these to be different?
    22 
    23     float threshold = PS_SQR(FOOTPRINT_NSIGMA_LIMIT);
    2411
    2512    int growRadius = 0;
  • trunk/psphot/src/psphotFindPeaks.c

    r21519 r25755  
    3131        peak->SN = sqrt(peak->value);
    3232        peak->flux = readout->image->data.F32[peak->y-row0][peak->x-col0];
     33        // if (peak->flux / peak->value > 5.0/12.0) {
     34        //     psWarning ("odd peak levels (1)");
     35        // }
     36        // if (peak->value / peak->flux > 5*12.0) {
     37        //     psWarning ("odd peak levels (2)");
     38        // }
    3339        if (readout->variance && isfinite (peak->dx)) {
    3440            peak->dx *= sqrt(readout->variance->data.F32[peak->y-row0][peak->x-col0]);
  • trunk/psphot/src/psphotFitSourcesLinear.c

    r25383 r25755  
    7676            if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) continue;
    7777        } else {
    78             if (source->mode & PM_SOURCE_MODE_BLEND) continue;
     78            // if (source->mode & PM_SOURCE_MODE_BLEND) continue;
    7979        }
    8080
     
    186186    if (SKY_FIT_LINEAR) {
    187187        psSparseBorderSolve (&norm, &skyfit, constraint, border, 5);
    188         fprintf (stderr, "skyfit: %f\n", skyfit->data.F32[0]);
     188        psLogMsg ("psphot", PS_LOG_MINUTIA, "skyfit: %f\n", skyfit->data.F32[0]);
    189189    } else {
    190190        norm = psSparseSolve (NULL, constraint, sparse, 5);
     
    215215        // subtract object
    216216        pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    217         source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
    218217    }
    219218    psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "sub models: %f sec (%d elements)\n", psTimerMark ("psphot.linear"), sparse->Nelem);
     
    239238
    240239    psphotVisualShowResidualImage (readout);
    241     psphotVisualShowFlags (sources);
     240    // psphotVisualShowFlags (sources);
    242241
    243242    return true;
     
    264263        float x = model->params->data.F32[PM_PAR_XPOS];
    265264        float y = model->params->data.F32[PM_PAR_YPOS];
    266         psImageMaskCircle (source->maskView, x, y, model->radiusFit, "AND", PS_NOT_IMAGE_MASK(markVal));
     265        psImageMaskCircle (source->maskView, x, y, model->fitRadius, "AND", PS_NOT_IMAGE_MASK(markVal));
    267266    }
    268267
  • trunk/psphot/src/psphotFitSourcesLinearStack.c

    r24584 r25755  
    168168        // subtract object
    169169        pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    170         source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
    171170    }
    172171    psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "sub models: %f sec (%d elements)\n", psTimerMark ("psphot.linear"), sparse->Nelem);
  • trunk/psphot/src/psphotGuessModels.c

    r24876 r25755  
    177177
    178178        // set the source PSF model
     179        psAssert (source->modelPSF == NULL, "failed to free one of the models?");
    179180        source->modelPSF = modelPSF;
    180181        source->modelPSF->residuals = psf->residuals;
    181182
    182183        pmSourceCacheModel (source, maskVal);  // ALLOC x14 (!)
    183 
    184184    }
    185185
  • trunk/psphot/src/psphotImageLoop.c

    r23957 r25755  
    6767
    6868                // Update the header
    69                 {
    70                     pmHDU *hdu = pmHDUGetHighest(input->fpa, chip, cell);
    71                     if (hdu && hdu != lastHDU) {
    72                         psphotVersionHeaderFull(hdu->header);
    73                         lastHDU = hdu;
    74                     }
     69                pmHDU *hdu = pmHDUGetHighest(input->fpa, chip, cell);
     70                if (hdu && hdu != lastHDU) {
     71                    psphotVersionHeaderFull(hdu->header);
     72                    lastHDU = hdu;
    7573                }
    7674
    77                 psImageMaskType maskSat = pmConfigMaskGet("SAT", config); // Mask value for saturated pixels
    78                 if (!pmReadoutMaskNonfinite(readout, maskSat)) {
    79                     psError(psErrorCodeLast(), false, "Unable to mask non-finite pixels.");
    80                     psFree(view);
    81                     return false;
    82                 }
     75                // if an external mask is supplied, ensure that NAN pixels are also masked
     76                if (readout->mask) {
     77                    psImageMaskType maskSat = pmConfigMaskGet("SAT", config); // Mask value for saturated pixels
     78                    if (!pmReadoutMaskNonfinite(readout, maskSat)) {
     79                        psError(psErrorCodeLast(), false, "Unable to mask non-finite pixels.");
     80                        psFree(view);
     81                        return false;
     82                    }
     83                }
    8384
    8485                // run the actual photometry analysis on this chip/cell/readout
  • trunk/psphot/src/psphotImageQuality.c

    r23989 r25755  
    279279#endif
    280280
    281     psLogMsg ("psphot", PS_LOG_INFO, "Image Quality Stats from %ld psf stars : FWHM (major, minor) : %f, %f\n",
     281    psLogMsg ("psphot", PS_LOG_INFO, "Image Quality Stats from %ld psf stars : FWHM (major, minor) [pixels]: %f, %f\n",
    282282              M2->n, fwhm_major, fwhm_minor);
    283283
    284     psLogMsg ("psphot", PS_LOG_INFO, "M_2 : %f +/- %f, M_3 : %f +/- %f, M_4 : %f +/- %f\n",
     284    psLogMsg ("psphot", PS_LOG_INFO, "M_2 : %f +/- %f, M_3 : %f +/- %f, M_4 : %f +/- %f  [pixels^n]\n",
    285285              vM2, dM2, vM3, dM3, vM4, dM4);
    286286
  • trunk/psphot/src/psphotMagnitudes.c

    r25383 r25755  
    7171            PS_ARRAY_ADD_SCALAR(job->args, photMode, PS_TYPE_S32);
    7272            PS_ARRAY_ADD_SCALAR(job->args, maskVal,  PS_TYPE_IMAGE_MASK);
     73            PS_ARRAY_ADD_SCALAR(job->args, markVal,  PS_TYPE_IMAGE_MASK);
    7374            PS_ARRAY_ADD_SCALAR(job->args, 0,        PS_TYPE_S32); // this is used as a return value for nAp
    7475
     
    102103                fprintf (stderr, "error with job\n");
    103104            } else {
    104                 psScalar *scalar = job->args->data[7];
     105                psScalar *scalar = job->args->data[8];
    105106                Nap += scalar->data.S32;
    106107            }
     
    127128    pmSourcePhotometryMode photMode = PS_SCALAR_VALUE(job->args->data[5],S32);
    128129    psImageMaskType maskVal         = PS_SCALAR_VALUE(job->args->data[6],PS_TYPE_IMAGE_MASK_DATA);
     130    psImageMaskType markVal         = PS_SCALAR_VALUE(job->args->data[7],PS_TYPE_IMAGE_MASK_DATA);
    129131
    130132    for (int i = 0; i < sources->n; i++) {
    131133        pmSource *source = (pmSource *) sources->data[i];
    132         status = pmSourceMagnitudes (source, psf, photMode, maskVal);
     134
     135        // replace object in image
     136        if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
     137            pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
     138        }
     139
     140        // clear the mask bit and set the circular mask pixels
     141        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
     142        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", markVal);
     143
     144        status = pmSourceMagnitudes (source, psf, photMode, maskVal); // maskVal includes markVal
    133145        if (status && isfinite(source->apMag)) Nap ++;
     146
     147        // clear the mask bit
     148        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
     149
     150        // re-subtract the object, leave local sky
     151        pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    134152
    135153        if (backModel) {
     
    155173
    156174    // change the value of a scalar on the array (wrap this and put it in psArray.h)
    157     psScalar *scalar = job->args->data[7];
     175    psScalar *scalar = job->args->data[8];
    158176    scalar->data.S32 = Nap;
    159177
  • trunk/psphot/src/psphotMakeFluxScale.c

    r20453 r25755  
    6060        goto DONE;
    6161    }
     62    if (trend->mode == PM_TREND_MAP) {
     63        // p_psImagePrint (2, trend->map->map, "FluxScale Before"); // XXX TEST:
     64        psImageMapRepair (trend->map->map);
     65        // p_psImagePrint (2, trend->map->map, "FluxScale After"); // XXX TEST:
     66    }
    6267
    6368    // XXX do something useful to measure residual statistics
  • trunk/psphot/src/psphotMakeResiduals.c

    r23989 r25755  
    11# include "psphotInternal.h"
     2
     3# define RESIDUAL_SOFTENING 0.005
    24
    35bool psphotMakeResiduals (psArray *sources, psMetadata *recipe, pmPSF *psf, psImageMaskType maskVal) {
     
    3133
    3234    float pixelSN = psMetadataLookupF32(&status, recipe, "PSF.RESIDUALS.PIX.SN");
     35    PS_ASSERT (status, false);
     36
     37    float radiusMax = psMetadataLookupF32(&status, recipe, "PSF.RESIDUALS.RADIUS");
    3338    PS_ASSERT (status, false);
    3439
     
    171176                bool offImage = false;
    172177                if (psImageInterpolate (&flux, &dflux, &mflux, ix, iy, interp) == PS_INTERPOLATE_STATUS_OFF) {
    173                     // fprintf (stderr, "off image: %f %f : %f %f\n", ix, iy, flux, dflux);
    174178                    // This pixel is off the image
    175179                    offImage = true;
     
    179183                }
    180184                fluxes->data.F32[i] = flux;
    181                 dfluxes->data.F32[i] = dflux;
     185                dfluxes->data.F32[i] = hypot(dflux, RESIDUAL_SOFTENING);
    182186                if (isnan(flux)) {
     187                    fmasks->data.PS_TYPE_VECTOR_MASK_DATA[i] = badMask;
     188                }
     189                if (isnan(dflux)) {
    183190                    fmasks->data.PS_TYPE_VECTOR_MASK_DATA[i] = badMask;
    184191                }
     
    234241                }
    235242
     243                float radius = hypot((ox - 0.5*resid->Ro->numCols), (oy - 0.5*resid->Ro->numRows));
     244                if (radius > radiusMax) {
     245                  resid->mask->data.PM_TYPE_RESID_MASK_DATA[oy][ox] = 1;
     246                  continue;
     247                }
     248
    236249                resid->Ro->data.F32[oy][ox] = psStatsGetValue(fluxStats, statOption);
    237250                resid->Rx->data.F32[oy][ox] = resid->Ry->data.F32[oy][ox] = 0.0;
     
    248261                  resid->mask->data.PM_TYPE_RESID_MASK_DATA[oy][ox] = 1;
    249262                }
    250 
    251                 // fprintf (stderr, "res: %2d %2d : %6.4f  %6.4f  %6.4f   %3d  %1d\n", ox, oy, resid->Ro->data.F32[oy][ox], fluxStats->sampleStdev, fluxStats->sampleStdev/sqrt(nKeep), nKeep, resid->mask->data.PM_TYPE_RESID_MASK_DATA[oy][ox]);
    252 
    253263            } else {
    254264                assert (SPATIAL_ORDER == 1);
     265
     266                float radius = hypot((ox - 0.5*resid->Ro->numCols), (oy - 0.5*resid->Ro->numRows));
     267                if (radius > radiusMax) {
     268                  resid->mask->data.PM_TYPE_RESID_MASK_DATA[oy][ox] = 1;
     269                  continue;
     270                }
     271
    255272                psImageInit(A, 0.0);
    256273                psVectorInit(B, 0.0);
     
    275292
    276293                if (!psMatrixGJSolve(A, B)) {
    277                     psError(PSPHOT_ERR_PSF, false, "Singular matrix solving for (y,x) = (%d,%d)'s residuals",
    278                             oy, ox);
    279                     psFree(resid); resid = NULL;
    280                     break;
     294                    resid->mask->data.PM_TYPE_RESID_MASK_DATA[oy][ox] = 1;
     295                    psWarning("Singular matrix solving for (y,x) = (%d,%d)'s residuals, masking", oy, ox);
     296                    continue;
    281297                }
    282298
     
    286302
    287303                float dRo = sqrt(A->data.F32[0][0]);
    288                 // fprintf (stderr, "res: %2d %2d : %6.4f  %6.4f  %6.4f   %3d  %1d\n",
    289                 // ox, oy, resid->Ro->data.F32[oy][ox], dRo, dRo/sqrt(nKeep), nKeep, resid->mask->data.PM_TYPE_RESID_MASK_DATA[oy][ox]);
    290304
    291305                if (fabs(resid->Ro->data.F32[oy][ox]) < pixelSN*dRo/sqrt(nKeep)) {
    292306                  resid->mask->data.PM_TYPE_RESID_MASK_DATA[oy][ox] = 1;
    293307                }
    294                 //resid->variance->data.F32[oy][ox] = XXX;
    295308            }
    296309        }
  • trunk/psphot/src/psphotMaskReadout.c

    r24484 r25755  
    3333    }
    3434
     35    bool softenVariance = psMetadataLookupBool (&status, recipe, "SOFTEN.VARIANCE");
     36    float softenFraction = psMetadataLookupF32 (&status, recipe, "SOFTEN.VARIANCE.FRACTION");
     37
    3538    // make this an option via the recipe
    36     if (0) {
     39    if (softenVariance) {
    3740      psImage *im = readout->image;
    3841      psImage *wt = readout->variance;
    39       psImage *mk = readout->mask;
    4042      for (int j = 0; j < im->numRows; j++) {
    4143        for (int i = 0; i < im->numCols; i++) {
    42           if (isfinite(im->data.F32[j][i]) && isfinite(wt->data.F32[j][i])) continue;
    43           mk->data.PS_TYPE_IMAGE_MASK_DATA[j][i] |= maskBad;
     44            if (!isfinite(im->data.F32[j][i])) continue;
     45            if (!isfinite(wt->data.F32[j][i])) continue;
     46            float sysError = softenFraction * im->data.F32[j][i];
     47            wt->data.F32[j][i] += PS_SQR(sysError);
    4448        }
    4549      }
  • trunk/psphot/src/psphotOutput.c

    r21366 r25755  
    3131    }
    3232    return background;
     33}
     34
     35// dump source stats for psf stars
     36bool psphotDumpStats (psArray *sources, char *stage) {
     37
     38    char filename[64];
     39    snprintf (filename, 64, "psf.%s.dat", stage);
     40    FILE *f = fopen (filename, "w");
     41    for (int i = 0; i < sources->n; i++) {
     42        pmSource *source = sources->data[i];
     43        if (!(source->mode & PM_SOURCE_MODE_PSFSTAR)) continue;
     44
     45        pmModel *model = source->modelPSF;
     46        if (!model) continue;
     47
     48        // int xc = source->peak->x - source->pixels->col0;
     49        // int yc = source->peak->y - source->pixels->row0;
     50        // float mcore = source->modelFlux ? source->modelFlux->data.F32[yc][xc] : NAN;
     51        // float mpeak = model ? model->params->data.F32[PM_PAR_I0] : NAN;
     52        // bool subtracted = source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED;
     53        // fprintf (stderr, "%d %d : %d : %f %f : %f %f\n", source->peak->x, source->peak->y, subtracted, source->peak->flux, source->pixels->data.F32[yc][xc], mcore, mpeak);
     54
     55        fprintf (f, "%6.1f %6.1f : %6.1f %6.1f : %8.3f %8.3f %8.3f : %f : %f %f %f : %f\n",
     56                 source->peak->xf, source->peak->yf,
     57                 model->params->data.F32[PM_PAR_XPOS], model->params->data.F32[PM_PAR_YPOS],
     58                 source->psfMag, source->apMag, source->errMag,
     59                 model->params->data.F32[PM_PAR_I0],
     60                 model->params->data.F32[PM_PAR_SXX], model->params->data.F32[PM_PAR_SXY], model->params->data.F32[PM_PAR_SYY],
     61                 model->params->data.F32[PM_PAR_7]);
     62    }
     63    fclose (f);
     64    return true;
    3365}
    3466
     
    160192    psMetadataItemSupplement (header, recipe, "DAPMIFIT");
    161193    psMetadataItemSupplement (header, recipe, "NAPMIFIT");
    162     psMetadataItemSupplement (header, recipe, "SKYBIAS");
    163     psMetadataItemSupplement (header, recipe, "SKYSAT");
    164194
    165195    // PSF model parameters (shape values for image center)
     
    256286        psImageKeepCircle (source->maskObj, x, y, radius, "OR", markVal);
    257287        pmModelSub (source->pixels, source->maskObj, source->modelPSF, PM_MODEL_OP_FULL, maskVal);
    258         psImageKeepCircle (source->maskObj, x, y, radius, "AND", PS_NOT_IMAGE_MASK(markVal));
     288        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
    259289    }
    260290
  • trunk/psphot/src/psphotPSFConvModel.c

    r21183 r25755  
    3737    }
    3838
     39    // adjust the pixels based on the footprint
     40    float radius = psphotSetRadiusEXT (readout, source, markVal);
     41    if (!pmSourceMoments (source, radius, 0.0, 0.0)) return false;
     42
    3943    // XXX test : modify the Io, SXX, SYY terms based on the psf SXX, SYY terms:
    4044    psEllipseShape psfShape;
     
    6771    psVector *params  = modelConv->params;
    6872    psVector *dparams = modelConv->dparams;
    69 
    70     psphotCheckRadiusEXT (readout, source, modelConv, markVal);
    7173
    7274    // create the minimization constraints
  • trunk/psphot/src/psphotPetrosian.c

    r21183 r25755  
    11# include "psphotInternal.h"
    22
    3 bool psphotPetrosian (pmSource *source, psMetadata *recipe, psImageMaskType maskVal) {
     3bool psphotPetrosian (pmSource *source, psMetadata *recipe, float skynoise, psImageMaskType maskVal) {
    44
    5   bool status;
     5    // XXX these need to go into recipe values
     6    float Rmax = 200;
    67
    7   assert (source->extpars);
    8   assert (source->extpars->profile);
    9   assert (source->extpars->profile->radius);
    10   assert (source->extpars->profile->flux);
     8    psAssert (source->extpars, "need to run psphotRadialProfile first");
     9    psAssert (source->extpars->profile, "need to run psphotRadialProfile first");
    1110
    12   psVector *radius = source->extpars->profile->radius;
    13   psVector *flux = source->extpars->profile->flux;
     11    // integrate the radial profile for radial bins defined for the petrosian measurement:
     12    // SB_i (r_i) where \alpha r_i < r < \beta r_i
     13    if (!psphotPetrosianRadialBins (source, Rmax, skynoise)) {
     14        psError (PS_ERR_UNKNOWN, false, "failed to generate elliptical profile");
     15        return false;
     16    }
     17 
     18    // use the SB_i from above to calculate the petrosian radius and the flux within that radius
     19    if (!psphotPetrosianStats (source)) {
     20        psError (PS_ERR_UNKNOWN, false, "failed to generate elliptical profile");
     21        return false;
     22    }
     23 
     24    psTrace ("psphot", 3, "source at %f,%f: petrosian radius: %f, flux: %f, axis ratio: %f, angle: %f",
     25             source->peak->xf, source->peak->yf,
     26             source->extpars->petrosian_80->radius,
     27             source->extpars->petrosian_80->flux,
     28             source->extpars->profile->axes.minor/source->extpars->profile->axes.major,
     29             source->extpars->profile->axes.theta*PS_DEG_RAD);
    1430
    15   // flux at which to measure isophotal parameters
    16   float PETROSIAN_R0 = psMetadataLookupF32 (&status, recipe, "PETROSIAN_R0");
    17   float PETROSIAN_RF = psMetadataLookupF32 (&status, recipe, "PETROSIAN_FLUX_RATIO");
    18   assert (status);
    19 
    20   // first find flux at R0
    21   int firstAbove = -1;
    22   int lastBelow = -1;
    23   for (int i = 0; i < radius->n; i++) {
    24     if (radius->data.F32[i] < PETROSIAN_R0) lastBelow = i;
    25     if ((firstAbove < 0) && (radius->data.F32[i] > PETROSIAN_R0)) firstAbove = i;
    26   }
    27   // if we don't go out far enough, we have a problem...
    28   if (lastBelow == radius->n - 1) {
    29     psTrace ("psphot", 5, "did not go out far enough to reach petrosian reference radius...");
    30     // XXX skip object? raise a flag ?
    31     return false;
    32   }
    33   if (firstAbove < 0) {
    34     psTrace ("psphot", 5, "did not go out far enough to bound petrosian reference radius");
    35     // XXX raise a flag ?
    36     return false;
    37   }
    38 
    39   // average flux in this range
    40   float fluxR0 = 0.0;
    41   int fluxRn = 0;
    42   for (int i = PS_MIN(firstAbove, lastBelow); i <= PS_MAX(firstAbove, lastBelow); i++) {
    43     fluxR0 += flux->data.F32[i];
    44     fluxRn ++;
    45   }
    46   fluxR0 /= (float)(fluxRn);
    47 
    48   // target flux for petrosian radius
    49   float fluxRP = fluxR0 * PETROSIAN_RF;
    50 
    51   // find the first bin below the flux level and the last above the level
    52   // XXX can this be done faster with bisection?
    53   // XXX do I need to worry about crazy outliers?
    54   // XXX should i be smoothing or fitting the curve?
    55   int firstBelow = -1;
    56   int lastAbove = -1;
    57   for (int i = 0; i < flux->n; i++) {
    58     if (flux->data.F32[i] > fluxRP) lastAbove = i;
    59     if ((firstBelow < 0) && (flux->data.F32[i] < fluxRP)) firstBelow = i;
    60   }
    61   // if we don't go out far enough, we have a problem...
    62   if (lastAbove == radius->n - 1) {
    63     psTrace ("psphot", 5, "did not go out far enough to reach petrosian radius...");
    64     // XXX skip object? raise a flag ?
    65     return false;
    66   }
    67   if (firstBelow < 0) {
    68     psTrace ("psphot", 5, "did not go out far enough to bound petrosian radius");
    69     // XXX raise a flag ?
    70     return false;
    71   }
    72 
    73   // need to examine pixels in this vicinity
    74   float fluxFirst = 0;
    75   float fluxLast = 0;
    76   for (int i = 0; i <= PS_MAX(firstBelow, lastAbove); i++) {
    77     if (i <= firstBelow) {
    78       fluxFirst += flux->data.F32[i];
    79     }
    80     if (i <= lastAbove) {
    81       fluxLast += flux->data.F32[i];
    82     }
    83   }
    84   float fluxRPSum    = 0.5*(fluxLast + fluxFirst);
    85   float fluxRPSumErr = 0.5*fabs(fluxLast - fluxFirst);
    86   // XXX need to use the weight appropriately here...
    87 
    88   float rad     = 0.5*(radius->data.F32[firstBelow] + radius->data.F32[lastAbove]);
    89   float radErr  = 0.5*fabs(radius->data.F32[firstBelow] - radius->data.F32[lastAbove]);
    90 
    91   if (!source->extpars->petrosian) {
    92     source->extpars->petrosian = pmSourcePetrosianValuesAlloc ();
    93   }
    94 
    95   // these are uncalibrated: instrumental mags and pixel units
    96   source->extpars->petrosian->mag    = -2.5*log10(fluxRPSum);
    97   source->extpars->petrosian->magErr = fluxRPSumErr / fluxRPSum;
    98 
    99   source->extpars->petrosian->rad    = rad;
    100   source->extpars->petrosian->radErr = radErr;
    101 
    102   psTrace ("psphot", 5, "Petrosian flux:%f +/- %f @ %f +/- %f for %f, %f\n",
    103            source->extpars->petrosian->mag, source->extpars->petrosian->magErr,
    104            source->extpars->petrosian->rad, source->extpars->petrosian->radErr,
    105            source->peak->xf, source->peak->yf);
    106 
    107   return true;
    108 
     31    return true;
    10932}
  • trunk/psphot/src/psphotRadialProfile.c

    r21366 r25755  
    11# include "psphotInternal.h"
    22
    3 # define COMPARE_RADIUS(A,B) (radius->data.F32[A] < radius->data.F32[B])
    4 # define SWAP_RADIUS(TYPE,A,B) { \
    5   float tmp; \
    6   if (A != B) { \
    7     tmp = radius->data.F32[A]; \
    8     radius->data.F32[A] = radius->data.F32[B]; \
    9     radius->data.F32[B] = tmp; \
    10     tmp = flux->data.F32[A]; \
    11     flux->data.F32[A] = flux->data.F32[B]; \
    12     flux->data.F32[B] = tmp; \
    13     tmp = variance->data.F32[A]; \
    14     variance->data.F32[A] = variance->data.F32[B]; \
    15     variance->data.F32[B] = tmp; \
    16   } \
    17 }
    18 
    19 bool psphotRadialProfile (pmSource *source, psMetadata *recipe, psImageMaskType maskVal) {
     3bool psphotRadialProfile (pmSource *source, psMetadata *recipe, float skynoise, psImageMaskType maskVal) {
    204
    215    // allocate pmSourceExtendedParameters, if not already defined
     
    2812    }
    2913
    30     int nPts = source->pixels->numRows * source->pixels->numCols;
    31     source->extpars->profile->radius = psVectorAllocEmpty (nPts, PS_TYPE_F32);
    32     source->extpars->profile->flux   = psVectorAllocEmpty (nPts, PS_TYPE_F32);
    33     source->extpars->profile->variance = psVectorAllocEmpty (nPts, PS_TYPE_F32);
     14    // XXX these need to go into recipe values
     15    int Nsec = 24;
     16    float Rmax = 200;
     17    float fluxMin = 0.0;
     18    float fluxMax = source->peak->flux;
    3419
    35     psVector *radius = source->extpars->profile->radius;
    36     psVector *flux   = source->extpars->profile->flux;
    37     psVector *variance = source->extpars->profile->variance;
     20    // generate a series of radial profiles at Nsec evenly spaced angles.  the profile flux
     21    // is measured by interpolation for small radii; for large radii, the pixels in a box
     22    // are averaged to increase the S/N
     23    if (!psphotRadialProfilesByAngles (source, Nsec, Rmax)) {
     24        psError (PS_ERR_UNKNOWN, false, "failed to measure radial profile for petrosian");
     25        return false;
     26    }
    3827
    39     // XXX use the extended source model here for Xo, Yo?
    40     // XXX define a radius scaled to the elliptical contour?
     28    // use the radial profiles to determine the radius of a given isophote.  this isophote
     29    // is used to determine the elliptical shape of the object, so it has a relatively high
     30    // value (nominally 50% of the peak)
     31    if (!psphotRadiiFromProfiles (source, fluxMin, fluxMax)) {
     32        psError (PS_ERR_UNKNOWN, false, "failed to measure isophotal radii from profiles");
     33        return false;
     34    }
    4135
    42     int n = 0;
    43 
    44     float Xo = 0.0;
    45     float Yo = 0.0;
    46 
    47     if (source->modelEXT) {
    48       Xo = source->modelEXT->params->data.F32[PM_PAR_XPOS] - source->pixels->col0;
    49       Yo = source->modelEXT->params->data.F32[PM_PAR_YPOS] - source->pixels->row0;
    50     } else {
    51       Xo = source->peak->xf - source->pixels->col0;
    52       Yo = source->peak->yf - source->pixels->row0;
     36    // convert the isophotal radius vs angle measurements to an elliptical contour
     37    if (!psphotEllipticalContour (source)) {
     38        psLogMsg ("psphot", 3, "failed to measure elliptical contour");
     39        return false;
    5340    }
    54     for (int iy = 0; iy < source->pixels->numRows; iy++) {
    55         for (int ix = 0; ix < source->pixels->numCols; ix++) {
    56             if (source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix]) continue;
    57             radius->data.F32[n] = hypot (ix - Xo, iy - Yo) ;
    58             flux->data.F32[n]   = source->pixels->data.F32[iy][ix];
    59             variance->data.F32[n] = source->variance->data.F32[iy][ix];
    60             n++;
    61         }
     41 
     42    // generate a single, normalized radial profile following the elliptical contours.
     43    // the radius is normalized by the axis ratio so that on the major axis, 1 pixel = 1 pixel
     44    if (!psphotEllipticalProfile (source)) {
     45        psError (PS_ERR_UNKNOWN, false, "failed to generate elliptical profile");
     46        return false;
    6247    }
    63     radius->n = n;
    64     variance->n = n;
    65     flux->n = n;
    66 
    67     // sort the vector set by the radius
    68     PSSORT (radius->n, COMPARE_RADIUS, SWAP_RADIUS, NONE);
    69 
     48 
    7049    return true;
    7150}
  • trunk/psphot/src/psphotRadiusChecks.c

    r21183 r25755  
    77                                        // and a per-object radius is calculated)
    88
     9static float PSF_APERTURE = 0;  // radius to use in PSF aperture mags
     10
     11
    912bool psphotInitRadiusPSF(const psMetadata *recipe, const pmModelType type) {
    1013
     
    1316    PSF_FIT_NSIGMA  = psMetadataLookupF32(&status, recipe, "PSF_FIT_NSIGMA");
    1417    PSF_FIT_PADDING = psMetadataLookupF32(&status, recipe, "PSF_FIT_PADDING");
    15     PSF_FIT_RADIUS =  psMetadataLookupF32(&status, recipe, "PSF_FIT_RADIUS");
     18    PSF_FIT_RADIUS  =  psMetadataLookupF32(&status, recipe, "PSF_FIT_RADIUS");
     19    PSF_APERTURE    =  psMetadataLookupF32(&status, recipe, "PSF_APERTURE");
    1620
    1721    return true;
     
    3438            radiusFit = model->modelRadius(model->params, 1.0);
    3539        }
     40        model->fitRadius = (RADIUS_TYPE)(radiusFit + PSF_FIT_PADDING);
     41    } else {
     42        model->fitRadius = radiusFit;
    3643    }
    37     model->radiusFit = (RADIUS_TYPE)(radiusFit + PSF_FIT_PADDING);
    38 
    39     if (isnan(model->radiusFit)) psAbort("error in radius");
     44    if (isnan(model->fitRadius)) psAbort("error in radius");
    4045       
    4146    if (source->mode & PM_SOURCE_MODE_SATSTAR) {
    42         model->radiusFit *= 2;
     47        model->fitRadius *= 2;
    4348    }
    4449
    45     bool status = pmSourceRedefinePixels (source, readout, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit);
     50    // radius used to measure aperture photometry
     51    source->apRadius = PSF_APERTURE;
     52
     53    bool status = pmSourceRedefinePixels (source, readout, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius);
    4654
    4755    // set the mask to flag the excluded pixels
    48     psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit, "OR", markVal);
     56    psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius, "OR", markVal);
    4957    return status;
    5058}
     
    5866
    5967    // set the fit radius based on the object flux limit and the model
    60     model->radiusFit = (RADIUS_TYPE) (model->modelRadius (model->params, PSF_FIT_NSIGMA*moments->dSky) + dR + PSF_FIT_PADDING);
    61     if (isnan(model->radiusFit)) psAbort("error in radius");
    62        
     68    float radiusFit = PSF_FIT_RADIUS;
     69    if (radiusFit <= 0) {               // use fixed radius
     70        if (moments == NULL) {
     71            radiusFit = model->modelRadius(model->params, PSF_FIT_NSIGMA*moments->dSky);
     72        } else {
     73            radiusFit = model->modelRadius(model->params, 1.0);
     74        }
     75        model->fitRadius = (RADIUS_TYPE)(radiusFit + PSF_FIT_PADDING);
     76    } else {
     77        model->fitRadius = radiusFit;
     78    }
     79    if (isnan(model->fitRadius)) psAbort("error in radius");
     80
     81    // above sets a radius for a single star, bump by blend separation
     82    model->fitRadius += dR;
     83
    6384    if (source->mode &  PM_SOURCE_MODE_SATSTAR) {
    64         model->radiusFit *= 2;
     85        model->fitRadius *= 2;
    6586    }
    6687
    67     bool status = pmSourceRedefinePixels (source, readout, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit);
     88    // radius used to measure aperture photometry
     89    source->apRadius = PSF_APERTURE;
     90
     91    bool status = pmSourceRedefinePixels (source, readout, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius);
    6892
    6993    // set the mask to flag the excluded pixels
    70     psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit, "OR", markVal);
     94    psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius, "OR", markVal);
    7195    return status;
    7296}
     
    7498static float EXT_FIT_NSIGMA;
    7599static float EXT_FIT_PADDING;
     100static float EXT_FIT_MAX_RADIUS;
    76101
    77102bool psphotInitRadiusEXT (psMetadata *recipe, pmModelType type) {
     
    79104    bool status;
    80105
    81     EXT_FIT_NSIGMA   = psMetadataLookupF32 (&status, recipe, "EXT_FIT_NSIGMA");
    82     EXT_FIT_PADDING  = psMetadataLookupF32 (&status, recipe, "EXT_FIT_PADDING");
     106    EXT_FIT_NSIGMA     = psMetadataLookupF32 (&status, recipe, "EXT_FIT_NSIGMA");
     107    EXT_FIT_PADDING    = psMetadataLookupF32 (&status, recipe, "EXT_FIT_PADDING");
     108    EXT_FIT_MAX_RADIUS = psMetadataLookupF32 (&status, recipe, "EXT_FIT_MAX_RADIUS");
    83109
    84110    return true;
     
    86112
    87113// call this function whenever you (re)-define the EXT model
     114float psphotSetRadiusEXT (pmReadout *readout, pmSource *source, psImageMaskType markVal) {
     115
     116    psAssert (source, "source not defined??");
     117    psAssert (source->peak, "peak not defined??");
     118
     119    pmPeak *peak = source->peak;
     120
     121    // set the radius based on the footprint:
     122    if (!peak->footprint) goto escape;
     123    pmFootprint *footprint = peak->footprint;
     124    if (!footprint->spans) goto escape;
     125    if (footprint->spans->n < 1) goto escape;
     126
     127    // find the max radius
     128    float radius = 0.0;
     129    for (int j = 0; j < footprint->spans->n; j++) {
     130        pmSpan *span = footprint->spans->data[j];
     131
     132        float dY  = span->y  - peak->yf;
     133        float dX0 = span->x0 - peak->xf;
     134        float dX1 = span->x1 - peak->xf;
     135
     136        radius = PS_MAX (radius, hypot(dY, dX0));
     137        radius = PS_MAX (radius, hypot(dY, dX1));
     138    }
     139
     140    radius += EXT_FIT_PADDING;
     141    if (isnan(radius)) psAbort("error in radius");
     142
     143    radius = PS_MIN (radius, EXT_FIT_MAX_RADIUS);
     144
     145    // redefine the pixels if needed
     146    pmSourceRedefinePixels (source, readout, peak->xf, peak->yf, radius);
     147
     148    // set the mask to flag the excluded pixels
     149    psImageKeepCircle (source->maskObj, peak->xf, peak->yf, radius, "OR", markVal);
     150    return radius;
     151
     152escape:
     153    return NAN;
     154    // bool result = psphotCheckRadiusEXT (readout, source, model, markVal);
     155    // return result;
     156}
     157
     158// alternative EXT radius based on model guess (for use without footprints)
    88159bool psphotCheckRadiusEXT (pmReadout *readout, pmSource *source, pmModel *model, psImageMaskType markVal) {
     160
     161    psAbort ("do not use this function");
    89162
    90163    psF32 *PAR = model->params->data.F32;
     
    96169    float rawRadius = model->modelRadius (model->params, EXT_FIT_NSIGMA*moments->dSky);
    97170
    98     model->radiusFit = rawRadius + EXT_FIT_PADDING;
    99     if (isnan(model->radiusFit)) psAbort("error in radius");
     171    model->fitRadius = rawRadius + EXT_FIT_PADDING;
     172    if (isnan(model->fitRadius)) psAbort("error in radius");
    100173
    101174    // redefine the pixels if needed
    102     bool status = pmSourceRedefinePixels (source, readout, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit);
     175    bool status = pmSourceRedefinePixels (source, readout, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius);
    103176
    104177    // set the mask to flag the excluded pixels
    105     psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit, "OR", markVal);
     178    psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius, "OR", markVal);
    106179    return status;
    107180}
  • trunk/psphot/src/psphotReadout.c

    r25738 r25755  
    8181
    8282    // construct sources and measure basic stats
    83     psArray *sources = psphotSourceStats (config, readout, detections);
     83    psArray *sources = psphotSourceStats (config, readout, detections, true);
    8484    if (!sources) return false;
    8585    if (!strcasecmp (breakPt, "PEAKS")) {
     
    126126        return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
    127127    }
    128 
    129128    psphotVisualShowPSFModel (readout, psf);
    130129
     
    132131    psphotLoadExtSources (config, view, sources);
    133132
    134     // construct an initial model for each object
     133    // construct an initial model for each object, set the radius to fitRadius, set circular fit mask
    135134    psphotGuessModels (config, readout, sources, psf);
    136135
    137     // XXX test output of models
    138     // psphotTestSourceOutput (readout, sources, recipe, psf);
    139 
    140     // linear PSF fit to source peaks
     136    // linear PSF fit to source peaks, subtract the models from the image (in PSF mask)
    141137    psphotFitSourcesLinear (readout, sources, recipe, psf, FALSE);
    142138
     
    144140    // psphotGuessModels or fitted until psphotFitSourcesLinear.
    145141    psphotVisualShowPSFStars (recipe, psf, sources);
    146     psphotVisualShowSatStars (recipe, psf, sources);
    147142
    148143    // identify CRs and extended sources
    149     psphotSourceSize (config, readout, sources, recipe, 0);
     144    psphotSourceSize (config, readout, sources, recipe, psf, 0);
    150145    if (!strcasecmp (breakPt, "ENSEMBLE")) {
    151146        goto finish;
    152147    }
     148    psphotVisualShowSatStars (recipe, psf, sources);
    153149
    154150    // non-linear PSF and EXT fit to brighter sources
     151    // replace model flux, adjust mask as needed, fit, subtract the models (full stamp)
    155152    psphotBlendFit (config, readout, sources, psf);
    156153
     
    158155    psphotReplaceAllSources (sources, recipe);
    159156
    160     // linear fit to include all sources
     157    // linear fit to include all sources (subtract again)
    161158    psphotFitSourcesLinear (readout, sources, recipe, psf, TRUE);
    162159
     
    165162        goto pass1finish;
    166163    }
    167 
    168     // XXX for the moment, drop the re-calc of the background (prove this works)
    169     // replace background in residual image
    170     // psphotSkyReplace (config, view);
    171     // re-measure background model (median, smoothed image)
    172     // psphotImageMedian (config, view);
     164    // NOTE: possibly re-measure background model here with objects subtracted
    173165
    174166    // add noise for subtracted objects
     
    182174
    183175    // define new sources based on only the new peaks
    184     psArray *newSources = psphotSourceStats (config, readout, detections);
     176    psArray *newSources = psphotSourceStats (config, readout, detections, false);
    185177
    186178    // set source type
     
    190182    }
    191183
    192     // create full input models
     184    // create full input models, set the radius to fitRadius, set circular fit mask
    193185    psphotGuessModels (config, readout, newSources, psf);
    194186
     
    206198
    207199    // measure source size for the remaining sources
    208     psphotSourceSize (config, readout, sources, recipe, 0);
     200    psphotSourceSize (config, readout, sources, recipe, psf, 0);
    209201
    210202    psphotExtendedSourceAnalysis (readout, sources, recipe);
  • trunk/psphot/src/psphotReadoutFindPSF.c

    r23442 r25755  
    4141
    4242    // construct sources and measure basic stats (moments, local sky)
    43     psArray *sources = psphotSourceStats(config, readout, detections);
     43    psArray *sources = psphotSourceStats(config, readout, detections, true);
    4444    if (!sources) return false;
    4545
  • trunk/psphot/src/psphotReadoutKnownSources.c

    r23442 r25755  
    4141
    4242    // construct sources and measure basic stats
    43     psArray *sources = psphotSourceStats (config, readout, detections);
     43    psArray *sources = psphotSourceStats (config, readout, detections, true);
    4444    if (!sources) return false;
    4545
  • trunk/psphot/src/psphotReadoutMinimal.c

    r25738 r25755  
    5656
    5757    // construct sources and measure basic stats
    58     psArray *sources = psphotSourceStats (config, readout, detections);
     58    psArray *sources = psphotSourceStats (config, readout, detections, true);
    5959    if (!sources) return false;
    6060
  • trunk/psphot/src/psphotReplaceUnfit.c

    r25383 r25755  
    1717    replace:
    1818        pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    19         source->tmpFlags &= ~PM_SOURCE_TMPF_SUBTRACTED;
    2019    }
    2120    psLogMsg ("psphot.replace", 3, "replace unfitted models: %f sec (%ld objects)\n", psTimerMark ("psphot.replace"), sources->n);
     
    4140
    4241      pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    43       source->tmpFlags &= ~PM_SOURCE_TMPF_SUBTRACTED;
    4442    }
    4543    psLogMsg ("psphot.replace", PS_LOG_INFO, "replaced models for %ld objects: %f sec\n", sources->n, psTimerMark ("psphot.replace"));
     
    6462      if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) continue;
    6563
    66       pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    67       source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
     64      pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    6865    }
    6966    psLogMsg ("psphot.replace", PS_LOG_INFO, "replaced models for %ld objects: %f sec\n", sources->n, psTimerMark ("psphot.replace"));
     
    7168}
    7269
     70# if (0)
    7371// add source, if the source has been subtracted; do not modify state
    7472bool psphotAddWithTest (pmSource *source, bool useState, psImageMaskType maskVal) {
     
    108106    return true;
    109107}
     108# endif
  • trunk/psphot/src/psphotRoughClass.c

    r23989 r25755  
    2626        for (int iy = 0; iy < NY; iy ++) {
    2727
    28             psRegion region = psRegionSet (ix*dX, (ix + 1)*dX, iy*dY, (iy + 1)*dY);
    29             if (!psphotRoughClassRegion (nRegion, &region, sources, recipe, havePSF)) {
     28            psRegion *region = psRegionAlloc (ix*dX, (ix + 1)*dX, iy*dY, (iy + 1)*dY);
     29            if (!psphotRoughClassRegion (nRegion, region, sources, recipe, havePSF)) {
    3030                psLogMsg ("psphot", 4, "Failed to determine rough classification for region %f,%f - %f,%f\n",
    31                          region.x0, region.y0, region.x1, region.y1);
     31                         region->x0, region->y0, region->x1, region->y1);
     32                psFree (region);
    3233                continue;
    3334            }
    34            
     35            psFree (region);
    3536            nRegion ++;
    3637        }
     
    4546    psphotVisualPlotMoments (recipe, sources);
    4647    psphotVisualShowRoughClass (sources);
    47     psphotVisualShowFlags (sources);
     48    // XXX better visualization: psphotVisualShowFlags (sources);
    4849
    4950    return true;
     
    6364    psMetadata *regionMD = psMetadataLookupPtr (&status, recipe, regionName);
    6465    if (!regionMD) {
     66        // allocate the region metadata folder and add this region to it.
    6567        regionMD = psMetadataAlloc();
    6668        psMetadataAddMetadata (recipe, PS_LIST_TAIL, regionName, PS_META_REPLACE, "psf clump region", regionMD);
    6769        psFree (regionMD);
    6870    }
     71    psMetadataAddPtr (regionMD, PS_LIST_TAIL, "REGION", PS_DATA_REGION | PS_META_REPLACE, "psf clump region", region);
    6972
    7073    if (!havePSF) {
    7174        // determine the PSF parameters from the source moment values
     75        // XXX why not save the psfClump as a PTR?
    7276        psfClump = pmSourcePSFClump (region, sources, recipe);
    7377        psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.X",  PS_META_REPLACE, "psf clump center", psfClump.X);
  • trunk/psphot/src/psphotSetThreads.c

    r23218 r25755  
    1010    psFree(task);
    1111
    12     task = psThreadTaskAlloc("PSPHOT_MAGNITUDES", 8);
     12    task = psThreadTaskAlloc("PSPHOT_MAGNITUDES", 9);
    1313    task->function = &psphotMagnitudes_Threaded;
    1414    psThreadTaskAdd(task);
     
    2020    psFree(task);
    2121
    22     task = psThreadTaskAlloc("PSPHOT_APRESID_MAGS", 6);
     22    task = psThreadTaskAlloc("PSPHOT_APRESID_MAGS", 7);
    2323    task->function = &psphotApResidMags_Threaded;
    2424    psThreadTaskAdd(task);
  • trunk/psphot/src/psphotSourceFits.c

    r24592 r25755  
    9090    psphotCheckRadiusPSFBlend (readout, source, PSF, markVal, dR);
    9191
    92     // fit PSF model (set/unset the pixel mask)
     92    // fit PSF model
    9393    pmSourceFitSet (source, modelSet, PM_SOURCE_FIT_PSF, maskVal);
     94
     95    // clear the circular mask
     96    psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
     97
     98    if (!isfinite(PSF->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
    9499
    95100    // correct model chisq for flux trend
     
    101106        pmSource *blend = sourceSet->data[i];
    102107        pmModel *model  = modelSet->data[i];
     108
     109        if (!isfinite(model->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
    103110
    104111        // correct model chisq for flux trend
     
    120127        pmSourceCacheModel (blend, maskVal);
    121128        pmSourceSub (blend, PM_MODEL_OP_FULL, maskVal);
    122         blend->tmpFlags |=  PM_SOURCE_TMPF_SUBTRACTED;
    123129        blend->mode |=  PM_SOURCE_MODE_BLEND_FIT;
    124130    }
     
    144150    pmSourceCacheModel (source, maskVal);
    145151    pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    146     source->tmpFlags |=  PM_SOURCE_TMPF_SUBTRACTED;
    147152    source->mode |=  PM_SOURCE_MODE_BLEND_FIT;
    148153    return true;
     
    167172    // fit PSF model (set/unset the pixel mask)
    168173    pmSourceFitModel (source, PSF, PM_SOURCE_FIT_PSF, maskVal);
     174
     175    if (!isfinite(PSF->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
     176
     177    // clear the circular mask
     178    psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
    169179
    170180    // correct model chisq for flux trend
     
    186196    pmSourceCacheModel (source, maskVal);
    187197    pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    188     source->tmpFlags |=  PM_SOURCE_TMPF_SUBTRACTED;
    189     return true;
    190 }
    191 
    192 static float EXT_MIN_SN;
    193 static float EXT_MOMENTS_RAD;
     198    return true;
     199}
     200
    194201static pmModelType modelTypeEXT;
    195202
     
    197204
    198205    bool status;
    199 
    200     // extended source model parameters
    201     EXT_MIN_SN       = psMetadataLookupF32 (&status, recipe, "EXT_MIN_SN");
    202     EXT_MOMENTS_RAD  = psMetadataLookupF32 (&status, recipe, "EXT_MOMENTS_RADIUS");
    203206
    204207    // extended source model descriptions
     
    221224    if (source->type == PM_SOURCE_TYPE_DEFECT) return false;
    222225    if (source->type == PM_SOURCE_TYPE_SATURATED) return false;
    223     if (source->peak->SN < EXT_MIN_SN) return false;
    224 
     226
     227    // set the radius based on the footprint (also sets the mask pixels)
     228    float radius = psphotSetRadiusEXT (readout, source, markVal);
     229
     230    // XXX note that this changes the source moments that are published...
    225231    // recalculate the source moments using the larger extended-source moments radius
    226232    // at this stage, skip Gaussian windowing, and do not clip pixels by S/N
    227     if (!pmSourceMoments (source, EXT_MOMENTS_RAD, 0.0, 0.0)) return false;
     233    // this uses the footprint to judge both radius and aperture?
     234    if (!pmSourceMoments (source, radius, 0.0, 0.0)) return false;
    228235
    229236    psTrace ("psphot", 5, "trying blob...\n");
     
    237244    // XXX need to handle failures better here
    238245    pmModel *EXT = psphotFitEXT (readout, source, modelTypeEXT, maskVal, markVal);
     246    if (!isfinite(EXT->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
     247
    239248    okEXT = psphotEvalEXT (tmpSrc, EXT);
    240249    chiEXT = EXT ? EXT->chisq / EXT->nDOF : NAN;
     
    246255    // XXX should I keep / save the flags set in the eval functions?
    247256
     257    // clear the circular mask
     258    psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
     259
    248260    // correct first model chisqs for flux trend
    249261    chiDBL = NAN;
    250262    ONE = DBL->data[0];
    251263    if (ONE) {
     264        if (!isfinite(ONE->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
    252265      chiTrend = psPolynomial1DEval (psf->ChiTrend, ONE->params->data.F32[1]);
    253266      ONE->chisqNorm = ONE->chisq / chiTrend;
     
    258271    ONE = DBL->data[1];
    259272    if (ONE) {
     273        if (!isfinite(ONE->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
    260274      chiTrend = psPolynomial1DEval (psf->ChiTrend, ONE->params->data.F32[1]);
    261275      ONE->chisqNorm = ONE->chisq / chiTrend;
     
    277291
    278292    // both models failed; reject them both
     293    // XXX -- change type flags to psf in this case and keep original moments?
    279294    psFree (EXT);
    280295    psFree (DBL);
     
    287302    // save new model
    288303    source->modelEXT = EXT;
     304    source->modelEXT->fitRadius = radius;
    289305    source->type = PM_SOURCE_TYPE_EXTENDED;
    290306    source->mode |= PM_SOURCE_MODE_EXTMODEL;
     
    293309    pmSourceCacheModel (source, maskVal);
    294310    pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    295     source->tmpFlags |=  PM_SOURCE_TMPF_SUBTRACTED;
     311
     312# if (PS_TRACE_ON)   
    296313    psTrace ("psphot", 5, "blob as EXT: %f %f\n", EXT->params->data.F32[PM_PAR_XPOS], EXT->params->data.F32[PM_PAR_YPOS]);
     314    if (psTraceGetLevel("psphot") >= 6) {
     315        psLogMsg ("psphot", 1, "source 2:\n");
     316        for (int i = 0; i < source->modelEXT->params->n; i++) {
     317            psLogMsg ("psphot", 1, "PAR %d : %f +/- %f\n", i, source->modelEXT->params->data.F32[i], source->modelEXT->dparams->data.F32[i]);
     318        }
     319    }
     320# endif
     321
    297322    return true;
    298323
     
    304329    psFree (source->modelPSF);
    305330    source->modelPSF = psMemIncrRefCounter (DBL->data[0]);
    306     source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
    307331    source->mode     |= PM_SOURCE_MODE_PAIR;
     332    source->modelPSF->fitRadius = radius;
    308333
    309334    // copy most data from the primary source (modelEXT, blends stay NULL)
    310     // XXX use pmSourceCopy?
    311335    pmSource *newSrc = pmSourceCopy (source);
    312336    newSrc->modelPSF = psMemIncrRefCounter (DBL->data[1]);
     337    newSrc->modelPSF->fitRadius = radius;
    313338
    314339    // build cached models and subtract
     
    317342    pmSourceCacheModel (newSrc, maskVal);
    318343    pmSourceSub (newSrc, PM_MODEL_OP_FULL, maskVal);
     344
     345# if (PS_TRACE_ON)   
    319346    psTrace ("psphot", 5, "blob as DBL: %f %f\n", ONE->params->data.F32[PM_PAR_XPOS], ONE->params->data.F32[PM_PAR_YPOS]);
     347    if (psTraceGetLevel("psphot") >= 6) {
     348        psLogMsg ("psphot", 1, "source 1:\n");
     349        for (int i = 0; i < newSrc->modelPSF->params->n; i++) {
     350            psLogMsg ("psphot", 1, "PAR %d : %f +/- %f\n", i, newSrc->modelPSF->params->data.F32[i], newSrc->modelPSF->dparams->data.F32[i]);
     351        }
     352        psLogMsg ("psphot", 1, "source 2:\n");
     353        for (int i = 0; i < source->modelPSF->params->n; i++) {
     354            psLogMsg ("psphot", 1, "PAR %d : %f +/- %f\n", i, source->modelPSF->params->data.F32[i], source->modelPSF->dparams->data.F32[i]);
     355        }
     356        psphotVisualShowResidualImage (readout);
     357    }
     358# endif
    320359
    321360    psArrayAdd (newSources, 100, newSrc);
     
    356395    // save the PSF model from the Ensemble fit
    357396    PSF = source->modelPSF;
    358     psphotCheckRadiusPSFBlend (readout, source, PSF, markVal, 8.0);
    359397    if (isnan(PSF->params->data.F32[1])) psAbort("nan in dbl fit");
    360398
     
    389427    PS_ASSERT (EXT, NULL);
    390428
    391     // if (isnan(EXT->params->data.F32[1])) psAbort("nan in ext fit");
    392 
    393     psphotCheckRadiusEXT (readout, source, EXT, markVal);
    394 
    395429    if ((source->moments->Mxx < 1e-3) || (source->moments->Myy < 1e-3)) {
    396430        psTrace ("psphot", 5, "problem source: moments: %f %f\n", source->moments->Mxx, source->moments->Myy);
     
    401435    return (EXT);
    402436}
    403 
  • trunk/psphot/src/psphotSourcePlots.c

    r21183 r25755  
    111111            if (Xo == 0) {
    112112                // place source alone on this row
    113                 psphotAddWithTest (source, true, maskVal); // replace source if subtracted
     113                bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     114                if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    114115                psphotRadialPlot (&kapa, "radial.plots.ps", source);
    115116                psphotMosaicSubimage (outpos, source, Xo, Yo, DX, DY, true);
    116117
    117                 psphotSubWithTest (source, false, maskVal); // remove source (force)
     118                pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    118119                psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
    119120
    120                 psphotSetState (source, false, maskVal); // replace source (has been subtracted)
     121                if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
     122
    121123                Yo += DY;
    122124                Xo = 0;
     
    126128                Yo += dY;
    127129                Xo = 0;
    128                 psphotAddWithTest (source, true, maskVal); // replace source if subtracted
     130
     131                bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     132                if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    129133                psphotRadialPlot (&kapa, "radial.plots.ps", source);
    130134                psphotMosaicSubimage (outpos, source, Xo, Yo, DX, DY, true);
    131135
    132                 psphotSubWithTest (source, false, maskVal); // remove source (force)
     136                pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    133137                psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
    134                 psphotSetState (source, false, maskVal); // replace source (has been subtracted)
     138                if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    135139
    136140                Xo = DX;
     
    139143        } else {
    140144            // extend this row
    141             psphotAddWithTest (source, true, maskVal); // replace source if subtracted
     145            bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     146            if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    142147            psphotRadialPlot (&kapa, "radial.plots.ps", source);
    143148            psphotMosaicSubimage (outpos, source, Xo, Yo, DX, DY, true);
    144149
    145             psphotSubWithTest (source, false, maskVal); // remove source (force)
     150            pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    146151            psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
    147             psphotSetState (source, false, maskVal); // replace source (has been subtracted)
     152            if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    148153
    149154            Xo += DX;
  • trunk/psphot/src/psphotSourceSize.c

    r21519 r25755  
    22# include <gsl/gsl_sf_gamma.h>
    33
    4 static float psphotModelContour(const psImage *image, const psImage *variance, const psImage *mask,
    5                                 psImageMaskType maskVal, const pmModel *model, float Ro);
    6 
    7 bool psphotMaskCosmicRay_Old (pmSource *source, psImageMaskType maskVal, psImageMaskType crMask);
    8 bool psphotMaskCosmicRay_New (psImage *mask, pmSource *source, psImageMaskType maskVal, psImageMaskType crMask);
     4typedef struct {
     5    psImageMaskType maskVal;
     6    psImageMaskType markVal;
     7    psImageMaskType crMask;
     8    float ApResid;
     9    float ApSysErr;
     10    float nSigmaApResid;
     11    float nSigmaMoments;
     12    float nSigmaCR;
     13    float soft;
     14    int grow;
     15} psphotSourceSizeOptions;
     16
     17bool psphotSourceSizePSF (psphotSourceSizeOptions *options, psArray *sources, pmPSF *psf);
     18bool psphotSourceClass (pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options);
     19bool psphotSourceClassRegion (psRegion *region, pmPSFClump *psfClump, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options);
     20bool psphotSourceSizeCR (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options);
     21bool psphotMaskCosmicRay (psImage *mask, pmSource *source, psImageMaskType maskVal, psImageMaskType crMask);
     22bool psphotMaskCosmicRayIsophot (pmSource *source, psImageMaskType maskVal, psImageMaskType crMask);
    923
    1024// we need to call this function after sources have been fitted to the PSF model and
     
    1428// deviation from the psf model at the r = FWHM/2 position
    1529
    16 bool psphotSourceSize(pmConfig *config, pmReadout *readout, psArray *sources, psMetadata *recipe, long first)
     30// XXX use an internal flag to mark sources which have already been measured
     31bool psphotSourceSize(pmConfig *config, pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, long first)
    1732{
    1833    bool status;
     34    psphotSourceSizeOptions options;
    1935
    2036    psTimerStart ("psphot.size");
    2137
    2238    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
    23     psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
    24     assert (maskVal);
     39    options.maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
     40    assert (options.maskVal);
     41
     42    options.markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT"); // Mask value for bad pixels
     43    assert (options.markVal);
    2544
    2645    // bit to mask the cosmic-ray pixels
    27     psImageMaskType crMask  = pmConfigMaskGet("CR", config); // Mask value for cosmic rays
    28 
    29     float CR_NSIGMA_LIMIT = psMetadataLookupF32 (&status, recipe, "PSPHOT.CR.NSIGMA.LIMIT");
     46    options.crMask  = pmConfigMaskGet("CR", config); // Mask value for cosmic rays
     47
     48    options.nSigmaCR = psMetadataLookupF32 (&status, recipe, "PSPHOT.CR.NSIGMA.LIMIT");
    3049    assert (status);
    3150
    32     float EXT_NSIGMA_LIMIT = psMetadataLookupF32 (&status, recipe, "PSPHOT.EXT.NSIGMA.LIMIT");
     51    // XXX recipe name is not great
     52    options.nSigmaApResid = psMetadataLookupF32 (&status, recipe, "PSPHOT.EXT.NSIGMA.LIMIT");
    3353    assert (status);
    3454
    35     int grow = psMetadataLookupS32(&status, recipe, "PSPHOT.CR.GROW"); // Growth size for CRs
    36     if (!status || grow < 0) {
     55    // XXX recipe name is not great
     56    options.nSigmaMoments = psMetadataLookupF32 (&status, recipe, "PSPHOT.EXT.NSIGMA.MOMENTS");
     57    assert (status);
     58
     59    options.grow = psMetadataLookupS32(&status, recipe, "PSPHOT.CR.GROW"); // Growth size for CRs
     60    if (!status || options.grow < 0) {
    3761        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "PSPHOT.CR.GROW is not positive.");
    3862        return false;
    3963    }
    4064
    41     float soft = psMetadataLookupF32(&status, recipe, "PSPHOT.CR.NSIGMA.SOFTEN"); // Softening parameter
    42     if (!status || !isfinite(soft) || soft < 0.0) {
     65    options.soft = psMetadataLookupF32(&status, recipe, "PSPHOT.CR.NSIGMA.SOFTEN"); // Softening parameter
     66    if (!status || !isfinite(options.soft) || options.soft < 0.0) {
    4367        psWarning("PSPHOT.CR.NSIGMA.SOFTEN not set; defaulting to zero.");
    44         soft = 0.0;
    45     }
    46 
    47     // loop over all source
    48     for (int i = first; i < sources->n; i++) {
    49         pmSource *source = sources->data[i];
    50 
    51         // skip source if it was already measured
    52         if (isfinite(source->crNsigma)) {
    53             psTrace("psphot", 7, "Not calculating extNsigma,crNsigma since already measured\n");
    54             continue;
     68        options.soft = 0.0;
     69    }
     70
     71    // We are using the value psfMag - 2.5*log10(moment.Sum) as a measure of the extendedness
     72    // of and object.  We need to model this distribution for the PSF stars before we can test
     73    // the significance for a specific object
     74    // XXX move this to the code that generates the PSF?
     75    // XXX store the results on pmPSF?
     76    psphotSourceSizePSF (&options, sources, psf);
     77
     78    // classify the sources based on ApResid and Moments (extended sources)
     79    psphotSourceClass(readout, sources, recipe, psf, &options);
     80
     81    psphotSourceSizeCR (readout, sources, &options);
     82
     83    psLogMsg ("psphot.size", PS_LOG_INFO, "measure source sizes for %ld sources: %f sec\n", sources->n - first, psTimerMark ("psphot.size"));
     84
     85    psphotVisualPlotSourceSize (recipe, sources);
     86    psphotVisualShowSourceSize (readout, sources);
     87    psphotVisualPlotApResid (sources, options.ApResid, options.ApSysErr);
     88
     89    return true;
     90}
     91
     92bool psphotMaskCosmicRay (psImage *mask, pmSource *source, psImageMaskType maskVal, psImageMaskType crMask) {
     93
     94    // replace the source flux
     95    pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
     96
     97    // flag this as a CR
     98    source->mode |= PM_SOURCE_MODE_CR_LIMIT;
     99    pmPeak *peak = source->peak;
     100    psAssert (peak, "NULL peak");
     101
     102    // grab the matching footprint
     103    pmFootprint *footprint = peak->footprint;
     104    if (!footprint) {
     105        // if we have not footprint, use the old code to mask by isophot
     106        psphotMaskCosmicRayIsophot (source, maskVal, crMask);
     107        return true;
     108    }
     109
     110    if (!footprint->spans) {
     111        // if we have no footprint, use the old code to mask by isophot
     112        psphotMaskCosmicRayIsophot (source, maskVal, crMask);
     113        return true;
     114    }
     115
     116    // mask all of the pixels covered by the spans of the footprint
     117    for (int j = 1; j < footprint->spans->n; j++) {
     118        pmSpan *span1 = footprint->spans->data[j];
     119
     120        int iy = span1->y;
     121        int xs = span1->x0;
     122        int xe = span1->x1;
     123
     124        for (int ix = xs; ix < xe; ix++) {
     125            mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= crMask;
     126        }
     127    }
     128    return true;
     129}
     130
     131bool psphotMaskCosmicRayIsophot (pmSource *source, psImageMaskType maskVal, psImageMaskType crMask) {
     132
     133    source->mode |= PM_SOURCE_MODE_CR_LIMIT;
     134    pmPeak *peak = source->peak;
     135    psAssert (peak, "NULL peak");
     136
     137    psImage *mask   = source->maskView;
     138    psImage *pixels = source->pixels;
     139    psImage *variance = source->variance;
     140
     141    // XXX This should be a recipe variable
     142# define SN_LIMIT 5.0
     143
     144    int xo = peak->x - pixels->col0;
     145    int yo = peak->y - pixels->row0;
     146
     147    // mark the pixels in this row to the left, then the right
     148    for (int ix = xo; ix >= 0; ix--) {
     149        float SN = pixels->data.F32[yo][ix] / sqrt(variance->data.F32[yo][ix]);
     150        if (SN > SN_LIMIT) {
     151            mask->data.PS_TYPE_IMAGE_MASK_DATA[yo][ix] |= crMask;
     152        }
     153    }
     154    for (int ix = xo + 1; ix < pixels->numCols; ix++) {
     155        float SN = pixels->data.F32[yo][ix] / sqrt(variance->data.F32[yo][ix]);
     156        if (SN > SN_LIMIT) {
     157            mask->data.PS_TYPE_IMAGE_MASK_DATA[yo][ix] |= crMask;
     158        }
     159    }
     160
     161    // for each of the neighboring rows, mark the high pixels if they have a marked neighbor
     162    // first go up:
     163    for (int iy = PS_MIN(yo, mask->numRows-2); iy >= 0; iy--) {
     164        // mark the pixels in this row to the left, then the right
     165        for (int ix = 0; ix < pixels->numCols; ix++) {
     166            float SN = pixels->data.F32[iy][ix] / sqrt(variance->data.F32[iy][ix]);
     167            if (SN < SN_LIMIT) continue;
     168
     169            bool valid = false;
     170            valid |= (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy+1][ix] & crMask);
     171            valid |= (ix > 0) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy+1][ix-1] & crMask) : 0;
     172            valid |= (ix <= mask->numCols) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy+1][ix+1] & crMask) : 0;
     173
     174            if (!valid) continue;
     175            mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= crMask;
     176        }
     177    }
     178    // next go down:
     179    for (int iy = PS_MIN(yo+1, mask->numRows-1); iy < pixels->numRows; iy++) {
     180        // mark the pixels in this row to the left, then the right
     181        for (int ix = 0; ix < pixels->numCols; ix++) {
     182            float SN = pixels->data.F32[iy][ix] / sqrt(variance->data.F32[iy][ix]);
     183            if (SN < SN_LIMIT) continue;
     184
     185            bool valid = false;
     186            valid |= (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy-1][ix] & crMask);
     187            valid |= (ix > 0) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy-1][ix-1] & crMask) : 0;
     188            valid |= (ix <= mask->numCols) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy-1][ix+1] & crMask) : 0;
     189
     190            if (!valid) continue;
     191            mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= crMask;
     192        }
     193    }
     194    return true;
     195}
     196
     197// model the apmifit distribution for the psf stars:
     198bool psphotSourceSizePSF (psphotSourceSizeOptions *options, psArray *sources, pmPSF *psf) {
     199
     200    // select stats from the psf stars
     201    psVector *Ap = psVectorAllocEmpty (100, PS_TYPE_F32);
     202    psVector *ApErr = psVectorAllocEmpty (100, PS_TYPE_F32);
     203   
     204    psImageMaskType maskVal = options->maskVal | options->markVal;
     205
     206    // XXX  why PHOT_WEIGHT??
     207    pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_WEIGHT;
     208
     209    for (int i = 0; i < sources->n; i++) {
     210        pmSource *source = sources->data[i];
     211        if (!(source->mode & PM_SOURCE_MODE_PSFSTAR)) continue;
     212
     213        // replace object in image
     214        if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
     215            pmSourceAdd (source, PM_MODEL_OP_FULL, options->maskVal);
    55216        }
    56217
    57         // source must have been subtracted
    58         if (!(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED)) {
     218        // clear the mask bit and set the circular mask pixels
     219        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));
     220        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", options->markVal);
     221
     222        // XXX can we test if psfMag is set and calculate only if needed?
     223        pmSourceMagnitudes (source, psf, photMode, maskVal); // maskVal includes markVal
     224       
     225        // clear the mask bit
     226        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));
     227
     228        // re-subtract the object, leave local sky
     229        pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal);
     230
     231        float apMag = -2.5*log10(source->moments->Sum);
     232        float dMag = source->psfMag - apMag;
     233       
     234        psVectorAppend (Ap, 100, dMag);
     235        psVectorAppend (ApErr, 100, source->errMag);
     236    }
     237
     238    // model the distribution as a mean or median value and a systematic error from that value:
     239    psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN);
     240    psVectorStats (stats, Ap, NULL, NULL, 0);
     241
     242    psVector *dAp = psVectorAlloc (Ap->n, PS_TYPE_F32);
     243    for (int i = 0; i < Ap->n; i++) {
     244        dAp->data.F32[i] = Ap->data.F32[i] - stats->robustMedian;
     245    }
     246
     247    options->ApResid = stats->robustMedian;
     248    options->ApSysErr = psVectorSystematicError(dAp, ApErr, 0.05);
     249    psLogMsg ("psphot", PS_LOG_DETAIL, "psf - Sum: %f +/- %f\n", options->ApResid, options->ApSysErr);
     250
     251    psFree (Ap);
     252    psFree (ApErr);
     253    psFree (stats);
     254    psFree (dAp);
     255
     256    return true;
     257}
     258
     259// classify sources based on the combination of psf-mag, Mxx, Myy
     260bool psphotSourceClass (pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options) {
     261
     262    bool status;
     263    pmPSFClump psfClump;
     264    char regionName[64];
     265
     266    psLogMsg("psModules.objects", PS_LOG_INFO, "Source Size classifications: %4s %4s %4s %4s %4s %4s", "Npsf", "Next", "Nsat", "Ncr", "Nmiss", "Nskip");
     267
     268    int nRegions = psMetadataLookupS32 (&status, recipe, "PSF.CLUMP.NREGIONS");
     269    for (int i = 0; i < nRegions; i ++) {
     270        snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", i);
     271        psMetadata *regionMD = psMetadataLookupPtr (&status, recipe, regionName);
     272        psAssert (regionMD, "regions must be defined by earlier call to psphotRoughClassRegion");
     273
     274        psRegion *region = psMetadataLookupPtr (&status, regionMD, "REGION");
     275        psAssert (region, "regions must be defined by earlier call to psphotRoughClassRegion");
     276
     277        // pull FWHM_X,Y from the recipe, use to define psfClump.X,Y
     278        psfClump.X  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");   psAssert (status, "missing PSF.CLUMP.X");
     279        psfClump.Y  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y");   psAssert (status, "missing PSF.CLUMP.Y");
     280        psfClump.dX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX");  psAssert (status, "missing PSF.CLUMP.DX");
     281        psfClump.dY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY");  psAssert (status, "missing PSF.CLUMP.DY");
     282
     283        if ((psfClump.X < 0) || (psfClump.Y < 0) || !psfClump.X || !psfClump.Y || isnan(psfClump.X) || isnan(psfClump.Y)) {
     284            psLogMsg ("psphot", 4, "Failed to find a valid PSF clump for region %f,%f - %f,%f\n", region->x0, region->y0, region->x1, region->y1);
     285            continue;
     286        }
     287       
     288        if (!psphotSourceClassRegion (region, &psfClump, sources, recipe, psf, options)) {
     289            psLogMsg ("psphot", 4, "Failed to determine source classification for region %f,%f - %f,%f\n", region->x0, region->y0, region->x1, region->y1);
     290            continue;
     291        }
     292    }   
     293
     294    return true;
     295}
     296
     297bool psphotSourceClassRegion (psRegion *region, pmPSFClump *psfClump, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options) {
     298
     299    PS_ASSERT_PTR_NON_NULL(sources, false);
     300    PS_ASSERT_PTR_NON_NULL(recipe, false);
     301
     302    int Nsat  = 0;
     303    int Next  = 0;
     304    int Npsf  = 0;
     305    int Ncr   = 0;
     306    int Nmiss = 0;
     307    int Nskip = 0;
     308
     309    pmSourceMode noMoments = PM_SOURCE_MODE_MOMENTS_FAILURE | PM_SOURCE_MODE_SKYVAR_FAILURE | PM_SOURCE_MODE_SKY_FAILURE | PM_SOURCE_MODE_BELOW_MOMENTS_SN;
     310    pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_WEIGHT;
     311
     312    psImageMaskType maskVal = options->maskVal | options->markVal;
     313
     314    for (psS32 i = 0 ; i < sources->n ; i++) {
     315
     316        pmSource *source = (pmSource *) sources->data[i];
     317
     318        // psfClumps are found for image subregions:
     319        // skip sources not in this region
     320        if (source->peak->x <  region->x0) continue;
     321        if (source->peak->x >= region->x1) continue;
     322        if (source->peak->y <  region->y0) continue;
     323        if (source->peak->y >= region->y1) continue;
     324
     325        // skip source if it was already measured
     326        if (source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED) {
     327            psTrace("psphot", 7, "Not calculating source size since it has already been measured\n");
     328            continue;
     329        }
     330
     331        // source must have been subtracted
     332        if (!(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED)) {
    59333            source->mode |= PM_SOURCE_MODE_SIZE_SKIPPED;
    60             psTrace("psphot", 7, "Not calculating extNsigma,crNsigma since source is not subtracted\n");
    61             continue;
     334            psTrace("psphot", 7, "Not calculating source size since source is not subtracted\n");
     335            continue;
     336        }
     337
     338        // we are basically classifying by moments; use the default if not found
     339        psAssert (source->moments, "why is this source missing moments?");
     340        if (source->mode & noMoments) {
     341            Nskip ++;
     342            continue;
     343        }
     344
     345        psF32 Mxx = source->moments->Mxx;
     346        psF32 Myy = source->moments->Myy;
     347
     348        // replace object in image
     349        if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
     350            pmSourceAdd (source, PM_MODEL_OP_FULL, options->maskVal);
    62351        }
    63352
    64         psF32 **resid  = source->pixels->data.F32;
    65         psF32 **variance = source->variance->data.F32;
    66         psImageMaskType **mask = source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA;
    67 
    68         // check for extendedness: measure the delta flux significance at the 1 sigma contour
    69         source->extNsigma = psphotModelContour(source->pixels, source->variance, source->maskObj, maskVal,
    70                                                source->modelPSF, 1.0);
    71 
    72         // XXX prevent a source from being both CR and EXT?
    73         if (source->extNsigma > EXT_NSIGMA_LIMIT) {
    74             source->mode |= PM_SOURCE_MODE_EXT_LIMIT;
    75         }
    76 
    77         // Integer position of peak
    78         int xPeak = source->peak->xf - source->pixels->col0 + 0.5;
    79         int yPeak = source->peak->yf - source->pixels->row0 + 0.5;
    80 
    81         // XXX for now, skip sources which are too close to a boundary
    82         // XXX raise a flag?
    83         if (xPeak < 1 || xPeak > source->pixels->numCols - 2 ||
    84             yPeak < 1 || yPeak > source->pixels->numRows - 2) {
    85             source->mode |= PM_SOURCE_MODE_SIZE_SKIPPED;
    86             psTrace("psphot", 7, "Not calculating crNsigma due to edge\n");
    87             continue;
    88         }
    89 
    90         // XXX for now, just skip any sources with masked pixels
    91         // XXX raise a flag?
    92         bool keep = true;
    93         for (int iy = -1; (iy <= +1) && keep; iy++) {
    94             for (int ix = -1; (ix <= +1) && keep; ix++) {
    95                 if (mask[yPeak+iy][xPeak+ix] & maskVal) {
    96                     keep = false;
    97                 }
    98             }
    99         }
    100         if (!keep) {
    101             psTrace("psphot", 7, "Not calculating crNsigma due to masked pixels\n");
    102             source->mode |= PM_SOURCE_MODE_SIZE_SKIPPED;
    103             continue;
    104         }
    105 
    106         // Compare the central pixel with those on either side, for the four possible lines through it.
    107 
    108         // Soften variances (add systematic error)
    109         float softening = soft * PS_SQR(source->peak->flux); // Softening for variances
    110 
    111         // Across the middle: y = 0
    112         float cX = 2*resid[yPeak][xPeak]   - resid[yPeak+0][xPeak-1]  - resid[yPeak+0][xPeak+1];
    113         float dcX = 4*variance[yPeak][xPeak] + variance[yPeak+0][xPeak-1] + variance[yPeak+0][xPeak+1];
    114         float nX = cX / sqrtf(dcX + softening);
    115 
    116         // Up the centre: x = 0
    117         float cY = 2*resid[yPeak][xPeak]   - resid[yPeak-1][xPeak+0]  - resid[yPeak+1][xPeak+0];
    118         float dcY = 4*variance[yPeak][xPeak] + variance[yPeak-1][xPeak+0] + variance[yPeak+1][xPeak+0];
    119         float nY = cY / sqrtf(dcY + softening);
    120 
    121         // Diagonal: x = y
    122         float cL = 2*resid[yPeak][xPeak]   - resid[yPeak-1][xPeak-1]  - resid[yPeak+1][xPeak+1];
    123         float dcL = 4*variance[yPeak][xPeak] + variance[yPeak-1][xPeak-1] + variance[yPeak+1][xPeak+1];
    124         float nL = cL / sqrtf(dcL + softening);
    125 
    126         // Diagonal: x = - y
    127         float cR = 2*resid[yPeak][xPeak]   - resid[yPeak+1][xPeak-1]  - resid[yPeak-1][xPeak+1];
    128         float dcR = 4*variance[yPeak][xPeak] + variance[yPeak+1][xPeak-1] + variance[yPeak-1][xPeak+1];
    129         float nR = cR / sqrtf(dcR + softening);
    130 
    131         // P(chisq > chisq_obs; Ndof) = gamma_Q (Ndof/2, chisq/2)
    132         // Ndof = 4 ? (four measurements, no free parameters)
    133         // XXX this value is going to be biased low because of systematic errors.
    134         // we need to calibrate it somehow
    135         // source->psfProb = gsl_sf_gamma_inc_Q (2, 0.5*chisq);
    136 
    137         // not strictly accurate: overcounts the chisq contribution from the center pixel (by
    138         // factor of 4); also biases a bit low if any pixels are masked
    139         // XXX I am not sure I want to keep this value...
    140         source->psfChisq = PS_SQR(nX) + PS_SQR(nY) + PS_SQR(nL) + PS_SQR(nR);
    141 
    142         float fCR = 0.0;
    143         int nCR = 0;
    144         if (nX > 0.0) {
    145             fCR += nX;
    146             nCR ++;
    147         }
    148         if (nY > 0.0) {
    149             fCR += nY;
    150             nCR ++;
    151         }
    152         if (nL > 0.0) {
    153             fCR += nL;
    154             nCR ++;
    155         }
    156         if (nR > 0.0) {
    157             fCR += nR;
    158             nCR ++;
    159         }
    160         source->crNsigma  = (nCR > 0)  ? fCR / nCR : 0.0;
    161         if (!isfinite(source->crNsigma)) {
    162             continue;
    163         }
    164 
    165         // this source is thought to be a cosmic ray.  flag the detection and mask the pixels
    166         if (source->crNsigma > CR_NSIGMA_LIMIT) {
    167             // XXX still testing... : psphotMaskCosmicRay_New (readout->mask, source, maskVal, crMask);
    168             psphotMaskCosmicRay_Old (source, maskVal, crMask);
    169         }
    170     }
    171 
    172     // now that we have masked pixels associated with CRs, we can grow the mask
    173     if (grow > 0) {
    174         bool oldThreads = psImageConvolveSetThreads(true); // Old value of threading for psImageConvolveMask
    175         psImage *newMask = psImageConvolveMask(NULL, readout->mask, crMask, crMask, -grow, grow, -grow, grow);
    176         psImageConvolveSetThreads(oldThreads);
    177         if (!newMask) {
    178             psError(PS_ERR_UNKNOWN, false, "Unable to grow CR mask");
    179             return false;
    180         }
    181         psFree(readout->mask);
    182         readout->mask = newMask;
    183     }
    184 
    185     psLogMsg ("psphot.size", PS_LOG_INFO, "measure source sizes for %ld sources: %f sec\n",
    186               sources->n - first, psTimerMark ("psphot.size"));
    187 
    188     psphotVisualPlotSourceSize (sources);
    189     psphotVisualShowSourceSize (readout, sources);
     353        // clear the mask bit and set the circular mask pixels
     354        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));
     355        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", options->markVal);
     356
     357        // XXX can we test if psfMag is set and calculate only if needed?
     358        pmSourceMagnitudes (source, psf, photMode, maskVal); // maskVal includes markVal
     359
     360        // clear the mask bit
     361        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));
     362
     363        // re-subtract the object, leave local sky
     364        pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal);
     365
     366        float apMag = -2.5*log10(source->moments->Sum);
     367        float dMag = source->psfMag - apMag;
     368        float nSigma = (dMag - options->ApResid) / hypot(source->errMag, options->ApSysErr);
     369
     370        source->extNsigma = nSigma;
     371        source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;
     372
     373        // Anything within this region is a probably PSF-like object. Saturated stars may land
     374        // in this region, but are detected elsewhere on the basis of their peak value.
     375        bool isPSF = (fabs(nSigma) < options->nSigmaApResid) && (fabs(Mxx - psfClump->X) < options->nSigmaMoments*psfClump->dX) && (fabs(Myy - psfClump->Y) < options->nSigmaMoments*psfClump->dY);
     376        if (isPSF) {
     377            Npsf ++;
     378            continue;
     379        }
     380
     381        // Defects may not always match CRs from peak curvature analysis
     382        // Defects may also be marked as SATSTAR -- XXX deactivate this flag?
     383        // XXX this rule is not great
     384        if ((Mxx < psfClump->X) || (Myy < psfClump->Y)) {
     385            source->mode |= PM_SOURCE_MODE_DEFECT;
     386            Ncr ++;
     387            continue;
     388        }
     389
     390        // saturated star (determined in PSF fit).  These may also be saturated galaxies, or
     391        // just large saturated regions.
     392        if (source->mode & PM_SOURCE_MODE_SATSTAR) {
     393            Nsat ++;
     394            continue;
     395        }
     396
     397        // XXX allow the Mxx, Myy to be less than psfClump->X,Y (by some nSigma)?
     398        bool isEXT = (nSigma > options->nSigmaApResid) || ((Mxx > psfClump->X) && (Myy > psfClump->Y));
     399        if (isEXT) {
     400            source->mode |= PM_SOURCE_MODE_EXT_LIMIT;
     401            Next ++;
     402            continue;
     403        }
     404
     405        psWarning ("sourse size was missed for %f,%f : %f %f -- %f\n", source->peak->xf, source->peak->yf, Mxx, Myy, nSigma);
     406        Nmiss ++;
     407    }
     408
     409    psLogMsg("psModules.objects", PS_LOG_INFO, "Source Size classifications: %4d %4d %4d %4d %4d %4d", Npsf, Next, Nsat, Ncr, Nmiss, Nskip);
    190410
    191411    return true;
     
    194414// given the PSF ellipse parameters, navigate around the 1sigma contour, return the total
    195415// deviation in sigmas.  This is measured on the residual image - should we ignore negative
    196 // deviations?
    197 static float psphotModelContour(const psImage *image, const psImage *variance, const psImage *mask,
    198                                 psImageMaskType maskVal, const pmModel *model, float Ro)
     416// deviations?  NOTE: This function was an early attempt to classify extended objects, and is
     417// no longer used by psphot.
     418float psphotModelContour(const psImage *image, const psImage *variance, const psImage *mask,
     419                         psImageMaskType maskVal, const pmModel *model, float Ro)
    199420{
    200421    psF32 *PAR = model->params->data.F32; // Model parameters
     
    211432    float Q = Ro * PS_SQR(sxx) / (1.0 - PS_SQR(sxx * syy * sxy) / 4.0);
    212433    if (Q < 0.0) {
    213         // ellipse is imaginary
    214         return NAN;
     434        // ellipse is imaginary
     435        return NAN;
    215436    }
    216437
     
    220441
    221442    for (int x = -radius; x <= radius; x++) {
    222         // Polynomial coefficients
    223         // XXX Should we be using the centre of the pixel as x or x+0.5?
    224         float A = PS_SQR (1.0 / syy);
    225         float B = x * sxy;
    226         float C = PS_SQR (x / sxx) - Ro;
    227         float T = PS_SQR(B) - 4*A*C;
    228         if (T < 0.0) {
    229             continue;
    230         }
    231 
    232         // y position in source frame
    233         float yP = (-B + sqrt (T)) / (2.0 * A);
    234         float yM = (-B - sqrt (T)) / (2.0 * A);
    235 
    236         // Get the closest pixel positions (image frame)
    237         int xPix  = x  + PAR[PM_PAR_XPOS] - image->col0 + 0.5;
    238         int yPixM = yM + PAR[PM_PAR_YPOS] - image->row0 + 0.5;
    239         int yPixP = yP + PAR[PM_PAR_YPOS] - image->row0 + 0.5;
    240 
    241         if (xPix < 0 || xPix >= image->numCols) {
    242             continue;
    243         }
    244 
    245         if (yPixM >= 0 && yPixM < image->numRows &&
    246             !(mask && (mask->data.PS_TYPE_IMAGE_MASK_DATA[yPixM][xPix] & maskVal))) {
    247             float dSigma = image->data.F32[yPixM][xPix] / sqrtf(variance->data.F32[yPixM][xPix]);
    248             nSigma += dSigma;
    249             nPts++;
    250         }
    251 
    252         if (yPixM == yPixP) {
    253             continue;
    254         }
    255 
    256         if (yPixP >= 0 && yPixP < image->numRows &&
    257             !(mask && (mask->data.PS_TYPE_IMAGE_MASK_DATA[yPixP][xPix] & maskVal))) {
    258             float dSigma = image->data.F32[yPixP][xPix] / sqrtf(variance->data.F32[yPixP][xPix]);
    259             nSigma += dSigma;
    260             nPts++;
    261         }
     443        // Polynomial coefficients
     444        // XXX Should we be using the centre of the pixel as x or x+0.5?
     445        float A = PS_SQR (1.0 / syy);
     446        float B = x * sxy;
     447        float C = PS_SQR (x / sxx) - Ro;
     448        float T = PS_SQR(B) - 4*A*C;
     449        if (T < 0.0) {
     450            continue;
     451        }
     452
     453        // y position in source frame
     454        float yP = (-B + sqrt (T)) / (2.0 * A);
     455        float yM = (-B - sqrt (T)) / (2.0 * A);
     456
     457        // Get the closest pixel positions (image frame)
     458        int xPix  = x  + PAR[PM_PAR_XPOS] - image->col0 + 0.5;
     459        int yPixM = yM + PAR[PM_PAR_YPOS] - image->row0 + 0.5;
     460        int yPixP = yP + PAR[PM_PAR_YPOS] - image->row0 + 0.5;
     461
     462        if (xPix < 0 || xPix >= image->numCols) {
     463            continue;
     464        }
     465
     466        if (yPixM >= 0 && yPixM < image->numRows &&
     467            !(mask && (mask->data.PS_TYPE_IMAGE_MASK_DATA[yPixM][xPix] & maskVal))) {
     468            float dSigma = image->data.F32[yPixM][xPix] / sqrtf(variance->data.F32[yPixM][xPix]);
     469            nSigma += dSigma;
     470            nPts++;
     471        }
     472
     473        if (yPixM == yPixP) {
     474            continue;
     475        }
     476
     477        if (yPixP >= 0 && yPixP < image->numRows &&
     478            !(mask && (mask->data.PS_TYPE_IMAGE_MASK_DATA[yPixP][xPix] & maskVal))) {
     479            float dSigma = image->data.F32[yPixP][xPix] / sqrtf(variance->data.F32[yPixP][xPix]);
     480            nSigma += dSigma;
     481            nPts++;
     482        }
    262483    }
    263484    nSigma /= nPts;
     
    265486}
    266487
    267 bool psphotMaskCosmicRay_New (psImage *mask, pmSource *source, psImageMaskType maskVal, psImageMaskType crMask) {
    268 
    269     // replace the source flux
    270     pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    271     source->tmpFlags &= ~PM_SOURCE_TMPF_SUBTRACTED;
    272 
    273     // flag this as a CR
    274     source->mode |= PM_SOURCE_MODE_CR_LIMIT;
    275     pmPeak *peak = source->peak;
    276     psAssert (peak, "NULL peak");
    277 
    278     // grab the matching footprint
    279     pmFootprint *footprint = peak->footprint;
    280     if (!footprint) {
    281         // if we have not footprint, use the old code to mask by isophot
    282         psphotMaskCosmicRay_Old (source, maskVal, crMask);
    283         return true;
    284     }
    285 
    286     if (!footprint->spans) {
    287         // if we have not footprint, use the old code to mask by isophot
    288         psphotMaskCosmicRay_Old (source, maskVal, crMask);
    289         return true;
    290     }
    291 
    292     // mask all of the pixels covered by the spans of the footprint
    293     for (int j = 1; j < footprint->spans->n; j++) {
    294         pmSpan *span1 = footprint->spans->data[j];
    295 
    296         int iy = span1->y;
    297         int xs = span1->x0;
    298         int xe = span1->x1;
    299 
    300         for (int ix = xs; ix < xe; ix++) {
    301             mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= crMask;
    302         }
     488bool psphotSourceSizeCR (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options) {
     489
     490    // classify the sources based on the CR test (place this in a function?)
     491    // XXX use an internal flag to mark sources which have already been measured
     492    for (int i = 0; i < sources->n; i++) {
     493        pmSource *source = sources->data[i];
     494
     495        // skip source if it was already measured
     496        if (source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED) {
     497            psTrace("psphot", 7, "Not calculating source size since it has already been measured\n");
     498            continue;
     499        }
     500
     501        // source must have been subtracted
     502        if (!(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED)) {
     503            source->mode |= PM_SOURCE_MODE_SIZE_SKIPPED;
     504            psTrace("psphot", 7, "Not calculating source size since source is not subtracted\n");
     505            continue;
     506        }
     507
     508        psF32 **resid  = source->pixels->data.F32;
     509        psF32 **variance = source->variance->data.F32;
     510        psImageMaskType **mask = source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA;
     511
     512        // Integer position of peak
     513        int xPeak = source->peak->xf - source->pixels->col0 + 0.5;
     514        int yPeak = source->peak->yf - source->pixels->row0 + 0.5;
     515
     516        // Skip sources which are too close to a boundary.  These are mostly caught as DEFECT
     517        if (xPeak < 1 || xPeak > source->pixels->numCols - 2 ||
     518            yPeak < 1 || yPeak > source->pixels->numRows - 2) {
     519            psTrace("psphot", 7, "Not calculating crNsigma due to edge\n");
     520            continue;
     521        }
     522
     523        // Skip sources with masked pixels.  These are mostly caught as DEFECT
     524        bool keep = true;
     525        for (int iy = -1; (iy <= +1) && keep; iy++) {
     526            for (int ix = -1; (ix <= +1) && keep; ix++) {
     527                if (mask[yPeak+iy][xPeak+ix] & options->maskVal) {
     528                    keep = false;
     529                }
     530            }
     531        }
     532        if (!keep) {
     533            psTrace("psphot", 7, "Not calculating crNsigma due to masked pixels\n");
     534            continue;
     535        }
     536
     537        // Compare the central pixel with those on either side, for the four possible lines through it.
     538
     539        // Soften variances (add systematic error)
     540        float softening = options->soft * PS_SQR(source->peak->flux); // Softening for variances
     541
     542        // Across the middle: y = 0
     543        float cX = 2*resid[yPeak][xPeak]   - resid[yPeak+0][xPeak-1]  - resid[yPeak+0][xPeak+1];
     544        float dcX = 4*variance[yPeak][xPeak] + variance[yPeak+0][xPeak-1] + variance[yPeak+0][xPeak+1];
     545        float nX = cX / sqrtf(dcX + softening);
     546
     547        // Up the centre: x = 0
     548        float cY = 2*resid[yPeak][xPeak]   - resid[yPeak-1][xPeak+0]  - resid[yPeak+1][xPeak+0];
     549        float dcY = 4*variance[yPeak][xPeak] + variance[yPeak-1][xPeak+0] + variance[yPeak+1][xPeak+0];
     550        float nY = cY / sqrtf(dcY + softening);
     551
     552        // Diagonal: x = y
     553        float cL = 2*resid[yPeak][xPeak]   - resid[yPeak-1][xPeak-1]  - resid[yPeak+1][xPeak+1];
     554        float dcL = 4*variance[yPeak][xPeak] + variance[yPeak-1][xPeak-1] + variance[yPeak+1][xPeak+1];
     555        float nL = cL / sqrtf(dcL + softening);
     556
     557        // Diagonal: x = - y
     558        float cR = 2*resid[yPeak][xPeak]   - resid[yPeak+1][xPeak-1]  - resid[yPeak-1][xPeak+1];
     559        float dcR = 4*variance[yPeak][xPeak] + variance[yPeak+1][xPeak-1] + variance[yPeak-1][xPeak+1];
     560        float nR = cR / sqrtf(dcR + softening);
     561
     562        // P(chisq > chisq_obs; Ndof) = gamma_Q (Ndof/2, chisq/2)
     563        // Ndof = 4 ? (four measurements, no free parameters)
     564        // XXX this value is going to be biased low because of systematic errors.
     565        // we need to calibrate it somehow
     566        // source->psfProb = gsl_sf_gamma_inc_Q (2, 0.5*chisq);
     567
     568        // not strictly accurate: overcounts the chisq contribution from the center pixel (by
     569        // factor of 4); also biases a bit low if any pixels are masked
     570        // XXX I am not sure I want to keep this value...
     571        source->psfChisq = PS_SQR(nX) + PS_SQR(nY) + PS_SQR(nL) + PS_SQR(nR);
     572
     573        float fCR = 0.0;
     574        int nCR = 0;
     575        if (nX > 0.0) {
     576            fCR += nX;
     577            nCR ++;
     578        }
     579        if (nY > 0.0) {
     580            fCR += nY;
     581            nCR ++;
     582        }
     583        if (nL > 0.0) {
     584            fCR += nL;
     585            nCR ++;
     586        }
     587        if (nR > 0.0) {
     588            fCR += nR;
     589            nCR ++;
     590        }
     591        source->crNsigma  = (nCR > 0)  ? fCR / nCR : 0.0;
     592        source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;
     593
     594        if (!isfinite(source->crNsigma)) {
     595            continue;
     596        }
     597
     598        // this source is thought to be a cosmic ray.  flag the detection and mask the pixels
     599        if (source->crNsigma > options->nSigmaCR) {
     600            source->mode |= PM_SOURCE_MODE_CR_LIMIT;
     601            // XXX still testing... : psphotMaskCosmicRay (readout->mask, source, maskVal, crMask);
     602            // XXX acting strange... psphotMaskCosmicRay_Old (source, maskVal, crMask);
     603        }
     604    }
     605
     606    // now that we have masked pixels associated with CRs, we can grow the mask
     607    if (options->grow > 0) {
     608        bool oldThreads = psImageConvolveSetThreads(true); // Old value of threading for psImageConvolveMask
     609        psImage *newMask = psImageConvolveMask(NULL, readout->mask, options->crMask, options->crMask, -options->grow, options->grow, -options->grow, options->grow);
     610        psImageConvolveSetThreads(oldThreads);
     611        if (!newMask) {
     612            psError(PS_ERR_UNKNOWN, false, "Unable to grow CR mask");
     613            return false;
     614        }
     615        psFree(readout->mask);
     616        readout->mask = newMask;
    303617    }
    304618    return true;
    305619}
    306 
    307 bool psphotMaskCosmicRay_Old (pmSource *source, psImageMaskType maskVal, psImageMaskType crMask) {
    308 
    309     source->mode |= PM_SOURCE_MODE_CR_LIMIT;
    310     pmPeak *peak = source->peak;
    311     psAssert (peak, "NULL peak");
    312 
    313     psImage *mask   = source->maskView;
    314     psImage *pixels = source->pixels;
    315     psImage *variance = source->variance;
    316 
    317     // XXX This should be a recipe variable
    318 # define SN_LIMIT 5.0
    319 
    320     int xo = peak->x - pixels->col0;
    321     int yo = peak->y - pixels->row0;
    322 
    323     // mark the pixels in this row to the left, then the right
    324     for (int ix = xo; ix >= 0; ix--) {
    325         float SN = pixels->data.F32[yo][ix] / sqrt(variance->data.F32[yo][ix]);
    326         if (SN > SN_LIMIT) {
    327             mask->data.PS_TYPE_IMAGE_MASK_DATA[yo][ix] |= crMask;
    328         }
    329     }
    330     for (int ix = xo + 1; ix < pixels->numCols; ix++) {
    331         float SN = pixels->data.F32[yo][ix] / sqrt(variance->data.F32[yo][ix]);
    332         if (SN > SN_LIMIT) {
    333             mask->data.PS_TYPE_IMAGE_MASK_DATA[yo][ix] |= crMask;
    334         }
    335     }
    336 
    337     // for each of the neighboring rows, mark the high pixels if they have a marked neighbor
    338     // first go up:
    339     for (int iy = PS_MIN(yo, mask->numRows-2); iy >= 0; iy--) {
    340         // mark the pixels in this row to the left, then the right
    341         for (int ix = 0; ix < pixels->numCols; ix++) {
    342             float SN = pixels->data.F32[iy][ix] / sqrt(variance->data.F32[iy][ix]);
    343             if (SN < SN_LIMIT) continue;
    344 
    345             bool valid = false;
    346             valid |= (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy+1][ix] & crMask);
    347             valid |= (ix > 0) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy+1][ix-1] & crMask) : 0;
    348             valid |= (ix <= mask->numCols) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy+1][ix+1] & crMask) : 0;
    349 
    350             if (!valid) continue;
    351             mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= crMask;
    352         }
    353     }
    354     // next go down:
    355     for (int iy = PS_MIN(yo+1, mask->numRows-1); iy < pixels->numRows; iy++) {
    356         // mark the pixels in this row to the left, then the right
    357         for (int ix = 0; ix < pixels->numCols; ix++) {
    358             float SN = pixels->data.F32[iy][ix] / sqrt(variance->data.F32[iy][ix]);
    359             if (SN < SN_LIMIT) continue;
    360 
    361             bool valid = false;
    362             valid |= (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy-1][ix] & crMask);
    363             valid |= (ix > 0) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy-1][ix-1] & crMask) : 0;
    364             valid |= (ix <= mask->numCols) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy-1][ix+1] & crMask) : 0;
    365 
    366             if (!valid) continue;
    367             mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= crMask;
    368         }
    369     }
    370     return true;
    371 }
  • trunk/psphot/src/psphotSourceStats.c

    r24589 r25755  
    11# include "psphotInternal.h"
    22
    3 psArray *psphotSourceStats (pmConfig *config, pmReadout *readout, pmDetections *detections) {
     3bool psphotSetMomentsWindow (psMetadata *recipe, psArray *sources);
     4
     5psArray *psphotSourceStats (pmConfig *config, pmReadout *readout, pmDetections *detections, bool setWindow) {
    46
    57    bool status = false;
     
    2123    float OUTER    = psMetadataLookupF32 (&status, recipe, "SKY_OUTER_RADIUS");
    2224    if (!status) return NULL;
     25
     26    OUTER = PS_MAX(OUTER, 20.0); // XXX Guarantee that we can encompass the max moments radius
     27
    2328    char *breakPt  = psMetadataLookupStr (&status, recipe, "BREAK_POINT");
    2429    if (!status) return NULL;
     
    6065        psphotVisualShowMoments (sources);
    6166        return sources;
     67    }
     68
     69    if (setWindow) {
     70        if (!psphotSetMomentsWindow(recipe, sources)) {
     71            psError(PS_ERR_UNEXPECTED_NULL, false, "Failed to determine Moments Window!");
     72            return NULL;
     73        }
    6274    }
    6375
     
    144156    float RADIUS       = psMetadataLookupF32 (&status, recipe, "PSF_MOMENTS_RADIUS");
    145157    if (!status) return false;
    146     float MIN_PIXEL_SN = psMetadataLookupF32 (&status, recipe, "MOMENTS_MIN_PIXEL_SN");
    147     if (!status) return false;
    148158    float SIGMA        = psMetadataLookupF32 (&status, recipe, "MOMENTS_GAUSS_SIGMA");
    149159    if (!status) return false;
     
    194204        }
    195205
    196         // measure basic source moments
    197         status = pmSourceMoments (source, RADIUS, SIGMA, MIN_PIXEL_SN);
     206        // measure basic source moments (no S/N clipping on input pixels)
     207        status = pmSourceMoments (source, RADIUS, SIGMA, 0.0);
    198208        if (status) {
    199209            Nmoments ++;
     
    205215        BIG_RADIUS = PS_MIN (INNER, 3*RADIUS);
    206216        psTrace ("psphot", 4, "retrying moments for %d, %d\n", source->peak->x, source->peak->y);
    207         status = pmSourceMoments (source, BIG_RADIUS, 3.0*SIGMA, MIN_PIXEL_SN);
     217        status = pmSourceMoments (source, BIG_RADIUS, 3.0*SIGMA, 0.0);
    208218        if (status) {
    209219            source->mode |= PM_SOURCE_MODE_BIG_RADIUS;
     
    231241}
    232242
    233 # if (0)
    234 bool psphotSourceStats_Unthreaded (int *nfail, int *nmoments, psArray *sources, psMetadata *recipe) {
    235 
    236     bool status = false;
    237     float BIG_RADIUS;
    238 
    239     float INNER    = psMetadataLookupF32 (&status, recipe, "SKY_INNER_RADIUS");
    240     if (!status) return false;
    241     float MIN_SN   = psMetadataLookupF32 (&status, recipe, "MOMENTS_SN_MIN");
    242     if (!status) return false;
    243     float RADIUS   = psMetadataLookupF32 (&status, recipe, "PSF_MOMENTS_RADIUS");
    244     if (!status) return false;
    245 
    246     // bit-masks to test for good/bad pixels
    247     psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT");
    248     assert (maskVal);
    249 
    250     // bit-mask to mark pixels not used in analysis
    251     psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT");
    252     assert (markVal);
    253 
    254     // maskVal is used to test for rejected pixels, and must include markVal
    255     maskVal |= markVal;
    256 
    257     // threaded measurement of the sources moments
    258     int Nfail = 0;
    259     int Nmoments = 0;
    260     for (int i = 0; i < sources->n; i++) {
    261         pmSource *source = sources->data[i];
    262 
    263         // skip faint sources for moments measurement
    264         if (source->peak->SN < MIN_SN) {
    265             continue;
    266         }
    267 
    268         // measure a local sky value
    269         // the local sky is now ignored; kept here for reference only
    270         status = pmSourceLocalSky (source, PS_STAT_SAMPLE_MEDIAN, INNER, maskVal, markVal);
    271         if (!status) {
    272             psErrorClear(); // XXX re-consider the errors raised here
    273             Nfail ++;
    274             continue;
    275         }
    276 
    277         // measure the local sky variance (needed if noise is not sqrt(signal))
    278         // XXX EAM : this should use ROBUST not SAMPLE median, but it is broken
    279         status = pmSourceLocalSkyVariance (source, PS_STAT_SAMPLE_MEDIAN, INNER, maskVal, markVal);
    280         if (!status) {
    281             Nfail ++;
    282             psErrorClear();
    283             continue;
    284         }
    285 
    286         // measure basic source moments
    287         status = pmSourceMoments (source, RADIUS, SIGMA, MIN_PIXEL_SN);
    288         if (status) {
    289             Nmoments ++;
    290             continue;
    291         }
    292 
    293         // if no valid pixels, or massive swing, likely saturated source,
    294         // try a much larger box
    295         BIG_RADIUS = PS_MIN (INNER, 3*RADIUS);
    296         psTrace ("psphot", 4, "retrying moments for %d, %d\n", source->peak->x, source->peak->y);
    297         status = pmSourceMoments (source, BIG_RADIUS, 3.0*SIGMA, MIN_PIXEL_SN);
    298         if (status) {
    299             Nmoments ++;
    300             continue;
    301         }
    302 
    303         Nfail ++;
    304         psErrorClear();
    305         continue;
    306     }
    307 
    308     // change the value of a scalar on the array (wrap this and put it in psArray.h)
    309     *nmoments = Nmoments;
    310     *nfail = Nfail;
    311 
     243// this function attempts to iteratively determine the best value for sigma of the moments weighting Gaussian
     244bool psphotSetMomentsWindow (psMetadata *recipe, psArray *sources) {
     245
     246    bool status;
     247
     248    float MIN_SN = psMetadataLookupF32 (&status, recipe, "MOMENTS_SN_MIN");
     249    if (!status) return false;
     250
     251    // XXX move this to a config file?
     252    float sigma[4] = {1.0, 2.0, 3.0, 4.5};
     253    float Sout[4];
     254
     255    // this sorts by peak->SN
     256    sources = psArraySort (sources, pmSourceSortBySN);
     257
     258    // loop over radii:
     259    for (int i = 0; i < 4; i++) {
     260
     261        // XXX move max source number to config
     262        for (int j = 0; (j < sources->n) && (j < 400); j++) {
     263 
     264            pmSource *source = sources->data[j];
     265            psAssert (source->moments, "force moments to exist");
     266            source->moments->nPixels = 0;
     267
     268            // skip faint sources for moments measurement
     269            if (source->peak->SN < MIN_SN) {
     270                continue;
     271            }
     272
     273            // measure basic source moments (no S/N clipping on input pixels)
     274            status = pmSourceMoments (source, 4*sigma[i], sigma[i], 0.0);
     275        }
     276
     277        // choose a grid scale that is a fixed fraction of the psf sigma^2
     278        psMetadataAddF32(recipe, PS_LIST_TAIL, "PSF_CLUMP_GRID_SCALE", PS_META_REPLACE, "clump grid", 0.1*PS_SQR(sigma[i]));
     279        psMetadataAddF32(recipe, PS_LIST_TAIL, "MOMENTS_SX_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(sigma[i]));
     280        psMetadataAddF32(recipe, PS_LIST_TAIL, "MOMENTS_SY_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(sigma[i]));
     281
     282        // determine the PSF parameters from the source moment values
     283        pmPSFClump psfClump = pmSourcePSFClump (NULL, sources, recipe);
     284        psLogMsg ("psphot", 3, "radius %.1f, nStars: %d, nSigma: %5.2f, X,  Y: %f, %f (%f, %f)\n", sigma[i], psfClump.nStars, psfClump.nSigma, psfClump.X, psfClump.Y, sqrt(psfClump.X) / sigma[i], sqrt(psfClump.Y) / sigma[i]);
     285
     286        psMetadataAddS32 (recipe, PS_LIST_TAIL, "PSF.CLUMP.NREGIONS",  PS_META_REPLACE, "psf clump regions", 1);
     287        psMetadata *regionMD = psMetadataLookupPtr (&status, recipe, "PSF.CLUMP.REGION.000");
     288        if (!regionMD) {
     289            regionMD = psMetadataAlloc();
     290            psMetadataAddMetadata (recipe, PS_LIST_TAIL, "PSF.CLUMP.REGION.000", PS_META_REPLACE, "psf clump region", regionMD);
     291            psFree (regionMD);
     292        }
     293        psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.X",  PS_META_REPLACE, "psf clump center", psfClump.X);
     294        psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.Y",  PS_META_REPLACE, "psf clump center", psfClump.Y);
     295        psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DX", PS_META_REPLACE, "psf clump center", psfClump.dX);
     296        psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DY", PS_META_REPLACE, "psf clump center", psfClump.dY);
     297           
     298        // psphotVisualPlotMoments (recipe, sources);
     299
     300        Sout[i] = sqrt(0.5*(psfClump.X + psfClump.Y)) / sigma[i];
     301    }
     302
     303    // we are looking for sigma for which Sout = 0.65 (or some other value)
     304
     305    float Sigma = NAN;
     306    float minS = Sout[0];
     307    float maxS = Sout[0];
     308    for (int i = 0; i < 4; i++) {
     309        minS = PS_MIN(Sout[i], minS);
     310        maxS = PS_MAX(Sout[i], maxS);
     311    }
     312    if (minS > 0.65) Sigma = sigma[3];
     313    if (maxS < 0.65) Sigma = sigma[0];
     314
     315    for (int i = 0; i < 3; i++) {
     316        if ((Sout[i] > 0.65) && (Sout[i+1] > 0.65)) continue;
     317        if ((Sout[i] < 0.65) && (Sout[i+1] < 0.65)) continue;
     318        Sigma = sigma[i] + (0.65 - Sout[i])*(sigma[i+1] - sigma[i])/(Sout[i+1] - Sout[i]);
     319    }
     320    psAssert (isfinite(Sigma), "did we miss a case?");
     321       
     322    // choose a grid scale that is a fixed fraction of the psf sigma^2
     323    psMetadataAddF32(recipe, PS_LIST_TAIL, "PSF_CLUMP_GRID_SCALE", PS_META_REPLACE, "clump grid", 0.1*PS_SQR(Sigma));
     324    psMetadataAddF32(recipe, PS_LIST_TAIL, "MOMENTS_SX_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(Sigma));
     325    psMetadataAddF32(recipe, PS_LIST_TAIL, "MOMENTS_SY_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(Sigma));
     326    psMetadataAddF32(recipe, PS_LIST_TAIL, "MOMENTS_GAUSS_SIGMA", PS_META_REPLACE, "moments limit", Sigma);
     327    psMetadataAddF32(recipe, PS_LIST_TAIL, "PSF_MOMENTS_RADIUS", PS_META_REPLACE, "moments limit", 4.0*Sigma);
     328
     329    psLogMsg ("psphot", 3, "using window function with sigma = %f\n", Sigma);
    312330    return true;
    313331}
    314 # endif
  • trunk/psphot/src/psphotVisual.c

    r24636 r25755  
    1515# include <kapa.h>
    1616
     17bool pmVisualLimitsFromVectors (Graphdata *graphdata, psVector *xVec, psVector *yVec);
     18
    1719// functions used to visualize the analysis as it goes
    1820// these are invoked by the -visual options
    1921
    20 static int kapa = -1;
     22static int kapa1 = -1;
    2123static int kapa2 = -1;
    2224static int kapa3 = -1;
    2325
     26int psphotKapaChannel (int channel) {
     27
     28    switch (channel) {
     29      case 1:
     30        if (kapa1 == -1) {
     31            kapa1 = KapaOpenNamedSocket ("kapa", "psphot:images");
     32            if (kapa1 == -1) {
     33                fprintf (stderr, "failure to open kapa; visual mode disabled\n");
     34                pmVisualSetVisual(false);
     35            }
     36        }
     37        return kapa1;
     38      case 2:
     39        if (kapa2 == -1) {
     40            kapa2 = KapaOpenNamedSocket ("kapa", "psphot:plots");
     41            if (kapa2 == -1) {
     42                fprintf (stderr, "failure to open kapa; visual mode disabled\n");
     43                pmVisualSetVisual(false);
     44            }
     45        }
     46        return kapa2;
     47      case 3:
     48        if (kapa3 == -1) {
     49            kapa3 = KapaOpenNamedSocket ("kapa", "psphot:stamps");
     50            if (kapa3 == -1) {
     51                fprintf (stderr, "failure to open kapa; visual mode disabled\n");
     52                pmVisualSetVisual(false);
     53            }
     54        }
     55        return kapa3;
     56      default:
     57        psAbort ("unknown kapa channel");
     58    }
     59    psAbort ("unknown kapa channel");
     60}
    2461
    2562bool psphotVisualShowMask (int kapaFD, psImage *inImage, const char *name, int channel) {
     
    131168    if (!pmVisualIsVisual()) return true;
    132169
    133     if (kapa == -1) {
    134         kapa = KapaOpenNamedSocket ("kapa", "psphot:images");
    135         if (kapa == -1) {
    136             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    137             pmVisualSetVisual(false);
    138             return false;
    139         }
    140     }
     170    int kapa = psphotKapaChannel (1);
     171    if (kapa == -1) return false;
    141172
    142173    // psphotVisualShowMask (kapa, readout->mask, "mask", 2);
     
    144175    psphotVisualScaleImage (kapa, readout->image, "image", 0);
    145176
    146     // pause and wait for user input:
    147     // continue, save (provide name), ??
    148     char key[10];
    149     fprintf (stdout, "[c]ontinue? ");
    150     if (!fgets(key, 8, stdin)) {
    151         psWarning("Unable to read option");
    152     }
     177    pmVisualAskUser(NULL);
    153178    return true;
    154179}
     
    160185    if (!pmVisualIsVisual()) return true;
    161186
    162     if (kapa == -1) {
    163         kapa = KapaOpenNamedSocket ("kapa", "psphot:images");
    164         if (kapa == -1) {
    165             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    166             pmVisualSetVisual(false);
    167             return false;
    168         }
    169     }
     187    int kapa = psphotKapaChannel (1);
     188    if (kapa == -1) return false;
    170189
    171190    bool status = false;
     
    181200    psphotVisualScaleImage (kapa, readout->image, "backsub", 0);
    182201
    183     // pause and wait for user input:
    184     // continue, save (provide name), ??
    185     char key[10];
    186     fprintf (stdout, "[c]ontinue? ");
    187     if (!fgets(key, 8, stdin)) {
    188         psWarning("Unable to read option");
    189     }
     202    pmVisualAskUser(NULL);
    190203    return true;
    191204}
     
    195208    if (!pmVisualIsVisual()) return true;
    196209
    197     if (kapa == -1) {
    198         kapa = KapaOpenNamedSocket ("kapa", "psphot:images");
    199         if (kapa == -1) {
    200             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    201             pmVisualSetVisual(false);
    202             return false;
    203         }
    204     }
    205 
    206     // XXX test: image->data.F32[10][10] = 10000;
     210    int kapa = psphotKapaChannel (1);
     211    if (kapa == -1) return false;
     212
    207213    psphotVisualRangeImage (kapa, image, "signif", 2, -1.0, 25.0*25.0);
    208214
    209     // pause and wait for user input:
    210     // continue, save (provide name), ??
    211     char key[10];
    212     fprintf (stdout, "[c]ontinue? ");
    213     if (!fgets(key, 8, stdin)) {
    214         psWarning("Unable to read option");
    215     }
     215    pmVisualAskUser(NULL);
    216216    return true;
    217217}
     
    224224    if (!pmVisualIsVisual()) return true;
    225225
    226     if (kapa == -1) {
    227         fprintf (stderr, "kapa not opened, skipping\n");
    228         return false;
    229     }
     226    int kapa = psphotKapaChannel (1);
     227    if (kapa == -1) return false;
    230228
    231229    psArray *peaks = detections->peaks;
     
    233231    // note: this uses the Ohana allocation tools:
    234232    // ALLOCATE (overlay, KiiOverlay, 3*peaks->n + 1);
    235     ALLOCATE (overlay, KiiOverlay, peaks->n);
     233    ALLOCATE (overlay, KiiOverlay, peaks->n + 2);
    236234
    237235    Noverlay = 0;
     
    271269    }
    272270
    273 # if (0)
     271# if (1)
    274272    overlay[Noverlay].type = KII_OVERLAY_BOX;
    275273    overlay[Noverlay].x = 10.0;
    276274    overlay[Noverlay].y = 10.0;
    277     overlay[Noverlay].dx = 0.5;
    278     overlay[Noverlay].dy = 0.5;
     275    overlay[Noverlay].dx = 1.0;
     276    overlay[Noverlay].dy = 1.0;
    279277    overlay[Noverlay].angle = 0.0;
    280278    overlay[Noverlay].text = NULL;
     
    285283    FREE (overlay);
    286284
    287     // pause and wait for user input:
    288     // continue, save (provide name), ??
    289     char key[10];
    290     fprintf (stdout, "[c]ontinue? ");
    291     if (!fgets(key, 8, stdin)) {
    292         psWarning("Unable to read option");
    293     }
     285    pmVisualAskUser(NULL);
    294286    return true;
    295287}
     
    302294    if (!pmVisualIsVisual()) return true;
    303295
    304     if (kapa == -1) {
    305         fprintf (stderr, "kapa not opened, skipping\n");
    306         return false;
    307     }
     296    int kapa = psphotKapaChannel (1);
     297    if (kapa == -1) return false;
    308298
    309299    psArray *footprints = detections->footprints;
     
    325315
    326316        // draw the top
     317        // XXX need to allow top (and bottom) to have more than one span
    327318        span = footprint->spans->data[0];
    328319        overlay[Noverlay].type = KII_OVERLAY_LINE;
     
    399390    FREE (overlay);
    400391
    401     // pause and wait for user input:
    402     // continue, save (provide name), ??
    403     char key[10];
    404     fprintf (stdout, "[c]ontinue? ");
    405     if (!fgets(key, 8, stdin)) {
    406         psWarning("Unable to read option");
    407     }
     392    pmVisualAskUser(NULL);
    408393    return true;
    409394}
     
    419404    if (!pmVisualIsVisual()) return true;
    420405
    421     if (kapa == -1) {
    422         fprintf (stderr, "kapa not opened, skipping\n");
    423         return false;
    424     }
     406    int kapa = psphotKapaChannel (1);
     407    if (kapa == -1) return false;
     408
     409    // XXX mark the different source classes with different color/shape dots
     410    // XXX are moments S/N and peak S/N consistent?
    425411
    426412    // note: this uses the Ohana allocation tools:
     
    448434        overlay[Noverlay].dx = 2.0*axes.major;
    449435        overlay[Noverlay].dy = 2.0*axes.minor;
    450         overlay[Noverlay].angle = -axes.theta * PS_DEG_RAD;  // XXXXXXXX the axes angle is negative to display of object on kapa
     436
     437        overlay[Noverlay].angle = axes.theta * PS_DEG_RAD;
     438
    451439        overlay[Noverlay].text = NULL;
    452440        Noverlay ++;
     
    456444    FREE (overlay);
    457445
    458     // pause and wait for user input:
    459     // continue, save (provide name), ??
    460     char key[10];
    461     fprintf (stdout, "[c]ontinue? ");
    462     if (!fgets(key, 8, stdin)) {
    463         psWarning("Unable to read option");
    464     }
    465 
     446    pmVisualAskUser(NULL);
    466447    return true;
    467448}
     
    475456    if (!pmVisualIsVisual()) return true;
    476457
    477     if (kapa3 == -1) {
    478         kapa3 = KapaOpenNamedSocket ("kapa", "psphot:plots");
    479         if (kapa3 == -1) {
    480             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    481             pmVisualSetVisual(false);
    482             return false;
    483         }
    484     }
    485 
    486     KapaClearPlots (kapa3);
     458    int myKapa = psphotKapaChannel (2);
     459    if (myKapa == -1) return false;
     460
     461    KapaClearPlots (myKapa);
    487462    KapaInitGraph (&graphdata);
    488     KapaSetFont (kapa3, "courier", 14);
     463    KapaSetFont (myKapa, "courier", 14);
    489464
    490465    float SN_LIM = psMetadataLookupF32(&status, recipe, "PSF_SN_LIM");
    491466
    492467    // select the max psfX,Y values for the plot limits
    493     float Xmin = 0.0, Xmax = 0.0;
    494     float Ymin = 0.0, Ymax = 0.0;
     468    float Xmin = 1000.0, Xmax = 0.0;
     469    float Ymin = 1000.0, Ymax = 0.0;
    495470    {
    496471        int nRegions = psMetadataLookupS32 (&status, recipe, "PSF.CLUMP.NREGIONS");
     
    511486            float Y1 = psfY + 4.0*psfdY;
    512487
    513             if (isfinite(X0)) { Xmin = PS_MAX(Xmin, X0); }
     488            if (isfinite(X0)) { Xmin = PS_MIN(Xmin, X0); }
    514489            if (isfinite(X1)) { Xmax = PS_MAX(Xmax, X1); }
    515             if (isfinite(Y0)) { Ymin = PS_MAX(Ymin, Y0); }
     490            if (isfinite(Y0)) { Ymin = PS_MIN(Ymin, Y0); }
    516491            if (isfinite(Y1)) { Ymax = PS_MAX(Ymax, Y1); }
    517492        }
    518493    }
     494    Xmin = PS_MAX(Xmin, -0.1);
     495    Ymin = PS_MAX(Ymin, -0.1);
    519496
    520497    // storage vectors for data to be plotted
     
    564541    section.y  = 0.00;
    565542    section.name = psStringCopy ("MxxMyy");
    566     KapaSetSection (kapa3, &section);
     543    KapaSetSection (myKapa, &section);
    567544    psFree (section.name);
    568545
     
    572549    graphdata.xmax = Xmax;
    573550    graphdata.ymax = Ymax;
    574     KapaSetLimits (kapa3, &graphdata);
    575 
    576     KapaBox (kapa3, &graphdata);
    577     KapaSendLabel (kapa3, "M_xx| (pixels)", KAPA_LABEL_XM);
    578     KapaSendLabel (kapa3, "M_yy| (pixels)", KAPA_LABEL_YM);
     551    KapaSetLimits (myKapa, &graphdata);
     552
     553    KapaBox (myKapa, &graphdata);
     554    KapaSendLabel (myKapa, "M_xx| (pixels)", KAPA_LABEL_XM);
     555    KapaSendLabel (myKapa, "M_yy| (pixels)", KAPA_LABEL_YM);
    579556
    580557    graphdata.color = KapaColorByName ("black");
     
    582559    graphdata.size = 0.3;
    583560    graphdata.style = 2;
    584     KapaPrepPlot (kapa3, nF, &graphdata);
    585     KapaPlotVector (kapa3, nF, xFaint->data.F32, "x");
    586     KapaPlotVector (kapa3, nF, yFaint->data.F32, "y");
     561    KapaPrepPlot (myKapa, nF, &graphdata);
     562    KapaPlotVector (myKapa, nF, xFaint->data.F32, "x");
     563    KapaPlotVector (myKapa, nF, yFaint->data.F32, "y");
    587564
    588565    graphdata.color = KapaColorByName ("red");
     
    590567    graphdata.size = 0.5;
    591568    graphdata.style = 2;
    592     KapaPrepPlot (kapa3, nB, &graphdata);
    593     KapaPlotVector (kapa3, nB, xBright->data.F32, "x");
    594     KapaPlotVector (kapa3, nB, yBright->data.F32, "y");
     569    KapaPrepPlot (myKapa, nB, &graphdata);
     570    KapaPlotVector (myKapa, nB, xBright->data.F32, "x");
     571    KapaPlotVector (myKapa, nB, yBright->data.F32, "y");
    595572
    596573    // second section: MagMyy
     
    600577    section.y  = 0.80;
    601578    section.name = psStringCopy ("MagMyy");
    602     KapaSetSection (kapa3, &section);
     579    KapaSetSection (myKapa, &section);
    603580    psFree (section.name);
    604581
     
    608585    graphdata.ymin = Ymin;
    609586    graphdata.ymax = Ymax;
    610     KapaSetLimits (kapa3, &graphdata);
     587    KapaSetLimits (myKapa, &graphdata);
    611588
    612589    strcpy (graphdata.labels, "0210");
    613     KapaBox (kapa3, &graphdata);
    614     KapaSendLabel (kapa3, "inst mag", KAPA_LABEL_XP);
    615     KapaSendLabel (kapa3, "M_yy| (pixels)", KAPA_LABEL_YM);
     590    KapaBox (myKapa, &graphdata);
     591    KapaSendLabel (myKapa, "inst mag", KAPA_LABEL_XP);
     592    KapaSendLabel (myKapa, "M_yy| (pixels)", KAPA_LABEL_YM);
    616593
    617594    graphdata.color = KapaColorByName ("black");
     
    619596    graphdata.size = 0.3;
    620597    graphdata.style = 2;
    621     KapaPrepPlot (kapa3, nF, &graphdata);
    622     KapaPlotVector (kapa3, nF, mFaint->data.F32, "x");
    623     KapaPlotVector (kapa3, nF, yFaint->data.F32, "y");
     598    KapaPrepPlot (myKapa, nF, &graphdata);
     599    KapaPlotVector (myKapa, nF, mFaint->data.F32, "x");
     600    KapaPlotVector (myKapa, nF, yFaint->data.F32, "y");
    624601
    625602    graphdata.color = KapaColorByName ("red");
     
    627604    graphdata.size = 0.5;
    628605    graphdata.style = 2;
    629     KapaPrepPlot (kapa3, nB, &graphdata);
    630     KapaPlotVector (kapa3, nB, mBright->data.F32, "x");
    631     KapaPlotVector (kapa3, nB, yBright->data.F32, "y");
     606    KapaPrepPlot (myKapa, nB, &graphdata);
     607    KapaPlotVector (myKapa, nB, mBright->data.F32, "x");
     608    KapaPlotVector (myKapa, nB, yBright->data.F32, "y");
    632609
    633610    // third section: MagMxx
     
    637614    section.y  = 0.00;
    638615    section.name = psStringCopy ("MagMxx");
    639     KapaSetSection (kapa3, &section);
     616    KapaSetSection (myKapa, &section);
    640617    psFree (section.name);
    641618
     
    645622    graphdata.ymin =  -7.9;
    646623    graphdata.ymax = -17.1;
    647     KapaSetLimits (kapa3, &graphdata);
     624    KapaSetLimits (myKapa, &graphdata);
    648625
    649626    strcpy (graphdata.labels, "2001");
    650     KapaBox (kapa3, &graphdata);
    651     KapaSendLabel (kapa3, "M_xx| (pixels)", KAPA_LABEL_XM);
    652     KapaSendLabel (kapa3, "inst mag", KAPA_LABEL_YP);
     627    KapaBox (myKapa, &graphdata);
     628    KapaSendLabel (myKapa, "M_xx| (pixels)", KAPA_LABEL_XM);
     629    KapaSendLabel (myKapa, "inst mag", KAPA_LABEL_YP);
    653630
    654631    graphdata.color = KapaColorByName ("black");
     
    656633    graphdata.size = 0.3;
    657634    graphdata.style = 2;
    658     KapaPrepPlot (kapa3, nF, &graphdata);
    659     KapaPlotVector (kapa3, nF, xFaint->data.F32, "x");
    660     KapaPlotVector (kapa3, nF, mFaint->data.F32, "y");
     635    KapaPrepPlot (myKapa, nF, &graphdata);
     636    KapaPlotVector (myKapa, nF, xFaint->data.F32, "x");
     637    KapaPlotVector (myKapa, nF, mFaint->data.F32, "y");
    661638
    662639    graphdata.color = KapaColorByName ("red");
     
    664641    graphdata.size = 0.5;
    665642    graphdata.style = 2;
    666     KapaPrepPlot (kapa3, nB, &graphdata);
    667     KapaPlotVector (kapa3, nB, xBright->data.F32, "x");
    668     KapaPlotVector (kapa3, nB, mBright->data.F32, "y");
     643    KapaPrepPlot (myKapa, nB, &graphdata);
     644    KapaPlotVector (myKapa, nB, xBright->data.F32, "x");
     645    KapaPlotVector (myKapa, nB, mBright->data.F32, "y");
    669646
    670647    // draw N circles to outline the clumps
    671648    {
    672         KapaSelectSection (kapa3, "MxxMyy");
     649        KapaSelectSection (myKapa, "MxxMyy");
    673650
    674651        // draw a circle centered on psfX,Y with size of the psf limit
     
    686663        graphdata.xmax = Xmax;
    687664        graphdata.ymax = Ymax;
    688         KapaSetLimits (kapa3, &graphdata);
     665        KapaSetLimits (myKapa, &graphdata);
    689666
    690667        for (int n = 0; n < nRegions; n++) {
     
    705682                yLimit->data.F32[i] = Ry*sin(i*2.0*M_PI/120.0) + psfY;
    706683            }
    707             KapaPrepPlot (kapa3, xLimit->n, &graphdata);
    708             KapaPlotVector (kapa3, xLimit->n, xLimit->data.F32, "x");
    709             KapaPlotVector (kapa3, yLimit->n, yLimit->data.F32, "y");
     684            KapaPrepPlot (myKapa, xLimit->n, &graphdata);
     685            KapaPlotVector (myKapa, xLimit->n, xLimit->data.F32, "x");
     686            KapaPlotVector (myKapa, yLimit->n, yLimit->data.F32, "y");
    710687        }
    711688        psFree (xLimit);
    712689        psFree (yLimit);
    713690    }
    714 
    715 # if (0)
    716     // *** make a histogram of the source counts in the x and y directions
    717     psHistogram *nX = psHistogramAlloc (graphdata.xmin, graphdata.xmax, 50.0);
    718     psHistogram *nY = psHistogramAlloc (graphdata.ymin, graphdata.ymax, 50.0);
    719     psVectorHistogram (nX, xFaint, NULL, NULL, 0);
    720     psVectorHistogram (nY, yFaint, NULL, NULL, 0);
    721     psVector *dX = psVectorAlloc (nX->nums->n, PS_TYPE_F32);
    722     psVector *vX = psVectorAlloc (nX->nums->n, PS_TYPE_F32);
    723     psVector *dY = psVectorAlloc (nY->nums->n, PS_TYPE_F32);
    724     psVector *vY = psVectorAlloc (nY->nums->n, PS_TYPE_F32);
    725     for (int i = 0; i < nX->nums->n; i++) {
    726         dX->data.F32[i] = nX->nums->data.S32[i];
    727         vX->data.F32[i] = 0.5*(nX->bounds->data.F32[i] + nX->bounds->data.F32[i+1]);
    728     }
    729     for (int i = 0; i < nY->nums->n; i++) {
    730         dY->data.F32[i] = nY->nums->data.S32[i];
    731         vY->data.F32[i] = 0.5*(nY->bounds->data.F32[i] + nY->bounds->data.F32[i+1]);
    732     }
    733 
    734     graphdata.color = KapaColorByName ("black");
    735     graphdata.ptype = 0;
    736     graphdata.size = 0.0;
    737     graphdata.style = 0;
    738     KapaPrepPlot (kapa3, dX->n, &graphdata);
    739     KapaPlotVector (kapa3, dX->n, dX->data.F32, "x");
    740     KapaPlotVector (kapa3, vX->n, vX->data.F32, "y");
    741 
    742     psFree (nX);
    743     psFree (dX);
    744     psFree (vX);
    745 
    746     psFree (nY);
    747     psFree (dY);
    748     psFree (vY);
    749 # endif
    750691
    751692    psFree (xBright);
     
    756697    psFree (mFaint);
    757698
    758     // pause and wait for user input:
    759     // continue, save (provide name), ??
    760     char key[10];
    761     fprintf (stdout, "[c]ontinue? ");
    762     if (!fgets(key, 8, stdin)) {
    763         psWarning("Unable to read option");
    764     }
     699    pmVisualAskUser(NULL);
    765700    return true;
    766701}
    767702
    768703// assumes 'kapa' value is checked and set
    769 bool psphotVisualShowRoughClass_Single (psArray *sources, pmSourceType type, pmSourceMode mode, char *color) {
     704bool psphotVisualShowRoughClass_Single (int myKapa, psArray *sources, pmSourceType type, pmSourceMode mode, char *color) {
    770705
    771706    int Noverlay;
     
    802737        overlay[Noverlay].dx = 2.0*axes.major;
    803738        overlay[Noverlay].dy = 2.0*axes.minor;
    804         overlay[Noverlay].angle = -axes.theta * PS_DEG_RAD;
     739        overlay[Noverlay].angle = axes.theta * PS_DEG_RAD;
    805740        overlay[Noverlay].text = NULL;
    806741        Noverlay ++;
    807742    }
    808743
    809     KiiLoadOverlay (kapa, overlay, Noverlay, color);
     744    KiiLoadOverlay (myKapa, overlay, Noverlay, color);
    810745    FREE (overlay);
    811746
     
    817752    if (!pmVisualIsVisual()) return true;
    818753
    819     if (kapa == -1) {
    820         fprintf (stderr, "kapa not opened, skipping\n");
    821         return false;
    822     }
    823 
    824     KiiEraseOverlay (kapa, "yellow"); // moments
    825 
    826     psphotVisualShowRoughClass_Single (sources, PM_SOURCE_TYPE_STAR, 0, "red");
    827     psphotVisualShowRoughClass_Single (sources, PM_SOURCE_TYPE_EXTENDED, 0, "blue");
    828     psphotVisualShowRoughClass_Single (sources, PM_SOURCE_TYPE_DEFECT, 0, "blue");
    829     psphotVisualShowRoughClass_Single (sources, PM_SOURCE_TYPE_SATURATED, 0, "red");
    830     psphotVisualShowRoughClass_Single (sources, PM_SOURCE_TYPE_STAR, PM_SOURCE_MODE_PSFSTAR, "yellow");
    831     psphotVisualShowRoughClass_Single (sources, PM_SOURCE_TYPE_STAR, PM_SOURCE_MODE_SATSTAR, "green");
    832 
    833     // pause and wait for user input:
    834     // continue, save (provide name), ??
    835     char key[10];
     754    int myKapa = psphotKapaChannel (1);
     755    if (myKapa == -1) return false;
     756
     757    KiiEraseOverlay (myKapa, "yellow"); // moments
     758
     759    psphotVisualShowRoughClass_Single (myKapa, sources, PM_SOURCE_TYPE_STAR, 0, "red");
     760    psphotVisualShowRoughClass_Single (myKapa, sources, PM_SOURCE_TYPE_EXTENDED, 0, "blue");
     761    psphotVisualShowRoughClass_Single (myKapa, sources, PM_SOURCE_TYPE_DEFECT, 0, "blue");
     762    psphotVisualShowRoughClass_Single (myKapa, sources, PM_SOURCE_TYPE_SATURATED, 0, "red");
     763    psphotVisualShowRoughClass_Single (myKapa, sources, PM_SOURCE_TYPE_STAR, PM_SOURCE_MODE_PSFSTAR, "yellow");
     764    psphotVisualShowRoughClass_Single (myKapa, sources, PM_SOURCE_TYPE_STAR, PM_SOURCE_MODE_SATSTAR, "green");
     765
    836766    fprintf (stdout, "red: STAR or SAT AREA; blue: EXTENDED or DEFECT; green: SATSTAR; yellow: PSFSTAR\n");
    837     fprintf (stdout, "[c]ontinue? ");
    838     if (!fgets(key, 8, stdin)) {
    839         psWarning("Unable to read option");
    840     }
     767    pmVisualAskUser(NULL);
    841768    return true;
    842769}
     
    846773    if (!pmVisualIsVisual()) return true;
    847774
    848     if (kapa2 == -1) {
    849         kapa2 = KapaOpenNamedSocket ("kapa", "psphot:psfstars");
    850         if (kapa2 == -1) {
    851             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    852             pmVisualSetVisual(false);
    853             return false;
    854         }
    855     }
     775    int myKapa = psphotKapaChannel (3);
     776    if (myKapa == -1) return false;
    856777
    857778    int DX = 64;
     
    898819
    899820    psImage *psfLogFlux = (psImage *) psUnaryOp (NULL, psfMosaic, "log");
    900     psphotVisualRangeImage (kapa2, psfLogFlux, "psf_mosaic",    0, -2.0, 3.0);
    901     psphotVisualRangeImage (kapa2, funMosaic, "psf_analytical", 1, -10.0, 100.0);
    902     psphotVisualRangeImage (kapa2, resMosaic, "psf_residual",   2, -10.0, 100.0);
     821    psphotVisualRangeImage (myKapa, psfLogFlux, "psf_mosaic",    0, -2.0, 3.0);
     822    psphotVisualRangeImage (myKapa, funMosaic, "psf_analytical", 1, -10.0, 100.0);
     823    psphotVisualRangeImage (myKapa, resMosaic, "psf_residual",   2, -10.0, 100.0);
    903824
    904825    psFree (psfMosaic);
     
    908829    psFree (modelRef);
    909830
    910     // pause and wait for user input:
    911     // continue, save (provide name), ??
    912     char key[10];
    913     fprintf (stdout, "[c]ontinue? ");
    914     if (!fgets(key, 8, stdin)) {
    915         psWarning("Unable to read option");
    916     }
     831    pmVisualAskUser(NULL);
    917832    return true;
    918833}
     
    924839    if (!pmVisualIsVisual()) return true;
    925840
    926     if (kapa2 == -1) {
    927         kapa2 = KapaOpenNamedSocket ("kapa", "psphot:psfstars");
    928         if (kapa2 == -1) {
    929             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    930             pmVisualSetVisual(false);
    931             return false;
    932         }
    933     }
     841    int myKapa = psphotKapaChannel (3);
     842    if (myKapa == -1) return false;
    934843
    935844    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
     
    1017926            if (Xo == 0) {
    1018927                // place source alone on this row
    1019                 psphotAddWithTest (source, true, maskVal); // replace source if subtracted
     928                bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     929                if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    1020930                psphotMosaicSubimage (outpos, source, Xo, Yo, DX, DY, true);
    1021931
    1022                 psphotSubWithTest (source, false, maskVal); // remove source (force)
     932                pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    1023933                psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
    1024                 psphotSetState (source, false, maskVal); // reset source Add/Sub state to recorded
     934
     935                if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    1025936
    1026937                Yo += DY;
     
    1032943                Xo = 0;
    1033944
    1034                 psphotAddWithTest (source, true, maskVal); // replace source if subtracted
     945                bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     946                if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    1035947                psphotMosaicSubimage (outpos, source, Xo, Yo, DX, DY, true);
    1036948
    1037                 psphotSubWithTest (source, false, maskVal); // remove source (force)
     949                pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    1038950                psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
    1039                 psphotSetState (source, false, maskVal); // replace source (has been subtracted)
     951
     952                if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    1040953
    1041954                Xo = DX;
     
    1044957        } else {
    1045958            // extend this row
    1046             psphotAddWithTest (source, true, maskVal); // replace source if subtracted
     959            bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     960            if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    1047961            psphotMosaicSubimage (outpos, source, Xo, Yo, DX, DY, true);
    1048962
    1049             psphotSubWithTest (source, false, maskVal); // remove source (force)
     963            pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    1050964            psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
    1051             psphotSetState (source, false, maskVal); // replace source (has been subtracted)
     965            if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    1052966
    1053967            Xo += DX;
     
    1056970    }
    1057971
    1058     psphotVisualRangeImage (kapa2, outpos, "psfpos", 0, -0.05, 0.95);
    1059     psphotVisualRangeImage (kapa2, outsub, "psfsub", 1, -0.05, 0.95);
    1060 
    1061     // pause and wait for user input:
    1062     // continue, save (provide name), ??
    1063     char key[10];
    1064     fprintf (stdout, "[c]ontinue? ");
    1065     if (!fgets(key, 8, stdin)) {
    1066         psWarning("Unable to read option");
    1067     }
    1068 
     972    psphotVisualRangeImage (myKapa, outpos, "psfpos", 0, -0.05, 0.95);
     973    psphotVisualRangeImage (myKapa, outsub, "psfsub", 1, -0.05, 0.95);
     974
     975    pmVisualAskUser(NULL);
    1069976    psFree (outpos);
    1070977    psFree (outsub);
     
    1084991    if (!pmVisualIsVisual()) return true;
    1085992
    1086     if (kapa2 == -1) {
    1087         kapa2 = KapaOpenNamedSocket ("kapa", "psphot:images");
    1088         if (kapa2 == -1) {
    1089             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    1090             pmVisualSetVisual(false);
    1091             return false;
    1092         }
    1093     }
     993    int myKapa = psphotKapaChannel (3);
     994    if (myKapa == -1) return false;
    1094995
    1095996    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
     
    11191020        pmSource *source = sources->data[i];
    11201021
    1121         bool keep = false;
    1122         keep |= (source->mode & PM_SOURCE_MODE_SATSTAR);
    1123         if (!keep) continue;
     1022        // only show "real" saturated stars (not defects)
     1023        if (!(source->mode & PM_SOURCE_MODE_SATSTAR)) continue;;
     1024        if (source->mode & PM_SOURCE_MODE_DEFECT) continue;;
    11241025
    11251026        // how does this subimage get placed into the output image?
     
    11641065        pmSource *source = sources->data[i];
    11651066
    1166         bool keep = false;
    1167         if (source->mode & PM_SOURCE_MODE_SATSTAR) {
    1168             nSAT ++;
    1169             keep = true;
    1170         }
    1171         if (!keep) continue;
     1067        // only show "real" saturated stars (not defects)
     1068        if (!(source->mode & PM_SOURCE_MODE_SATSTAR)) continue;;
     1069        if (source->mode & PM_SOURCE_MODE_DEFECT) continue;;
     1070        nSAT ++;
    11721071
    11731072        if (Xo + DX > NX) {
     
    11751074            if (Xo == 0) {
    11761075                // place source alone on this row
    1177                 psphotAddWithTest (source, true, maskVal); // replace source if subtracted
     1076                bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     1077                if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    11781078                psphotMosaicSubimage (outsat, source, Xo, Yo, DX, DY, false);
    1179                 psphotSetState (source, true, maskVal); // reset source Add/Sub state to recorded
     1079                if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    11801080
    11811081                Yo += DY;
     
    11861086                Yo += dY;
    11871087                Xo = 0;
    1188                 psphotAddWithTest (source, true, maskVal); // replace source if subtracted
     1088
     1089                bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     1090                if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    11891091                psphotMosaicSubimage (outsat, source, Xo, Yo, DX, DY, false);
    1190                 psphotSetState (source, true, maskVal); // replace source (has been subtracted)
     1092                if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    11911093
    11921094                Xo = DX;
     
    11951097        } else {
    11961098            // extend this row
    1197             psphotAddWithTest (source, true, maskVal); // replace source if subtracted
     1099            bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     1100            if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    11981101            psphotMosaicSubimage (outsat, source, Xo, Yo, DX, DY, false);
    1199             psphotSetState (source, true, maskVal); // replace source (has been subtracted)
     1102            if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    12001103
    12011104            Xo += DX;
     
    12041107    }
    12051108
    1206     psphotVisualScaleImage (kapa2, outsat, "satstar", 2);
    1207 
    1208     // pause and wait for user input:
    1209     // continue, save (provide name), ??
    1210     char key[10];
    1211     fprintf (stdout, "[c]ontinue? ");
    1212     if (!fgets(key, 8, stdin)) {
    1213         psWarning("Unable to read option");
    1214     }
    1215 
     1109    psphotVisualScaleImage (myKapa, outsat, "satstar", 2);
     1110
     1111    pmVisualAskUser(NULL);
    12161112    psFree (outsat);
    12171113    return true;
     
    12221118    Graphdata graphdata;
    12231119
    1224     bool state = !(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
    1225     psphotAddWithTest (source, true, maskVal); // replace source if subtracted
     1120    bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     1121    if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    12261122
    12271123    int nPts = source->pixels->numRows * source->pixels->numCols;
     
    12401136        for (int ix = 0; ix < source->pixels->numCols; ix++) {
    12411137            if (source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix]) {
    1242                 // rb->data.F32[nb] = hypot (ix + 0.5 - Xo, iy + 0.5 - Yo) ;
    1243                 rb->data.F32[nb] = hypot (ix - Xo, iy - Yo) ;
     1138                rb->data.F32[nb] = hypot (ix + 0.5 - Xo, iy + 0.5 - Yo) ;
     1139                // rb->data.F32[nb] = hypot (ix - Xo, iy - Yo) ;
    12441140                Rb->data.F32[nb] = log10(rb->data.F32[nb]);
    12451141                fb->data.F32[nb] = log10(source->pixels->data.F32[iy][ix]);
    12461142                nb++;
    12471143            } else {
    1248                 // rg->data.F32[ng] = hypot (ix + 0.5 - Xo, iy + 0.5 - Yo) ;
    1249                 rg->data.F32[ng] = hypot (ix - Xo, iy - Yo) ;
     1144                rg->data.F32[ng] = hypot (ix + 0.5 - Xo, iy + 0.5 - Yo) ;
     1145                // rg->data.F32[ng] = hypot (ix - Xo, iy - Yo) ;
    12501146                Rg->data.F32[ng] = log10(rg->data.F32[ng]);
    12511147                fg->data.F32[ng] = log10(source->pixels->data.F32[iy][ix]);
     
    12561152
    12571153    // reset source Add/Sub state to recorded
    1258     psphotSetState (source, state, maskVal);
     1154    if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    12591155
    12601156    KapaInitGraph (&graphdata);
     
    13371233    if (!pmVisualIsVisual()) return true;
    13381234
    1339     if (kapa3 == -1) {
    1340         kapa3 = KapaOpenNamedSocket ("kapa", "psphot:plots");
    1341         if (kapa3 == -1) {
    1342             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    1343             pmVisualSetVisual(false);
    1344             return false;
    1345         }
    1346     }
     1235    int myKapa = psphotKapaChannel (2);
     1236    if (myKapa == -1) return false;
    13471237
    13481238    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
     
    13511241    assert (maskVal);
    13521242
    1353     KapaClearPlots (kapa3);
     1243    KapaClearPlots (myKapa);
    13541244    // first section : mag vs CR nSigma
    13551245    section.dx = 1.0;
     
    13591249    section.name = NULL;
    13601250    psStringAppend (&section.name, "linlog");
    1361     KapaSetSection (kapa3, &section);
     1251    KapaSetSection (myKapa, &section);
    13621252    psFree (section.name);
    13631253
     
    13691259    section.name = NULL;
    13701260    psStringAppend (&section.name, "loglog");
    1371     KapaSetSection (kapa3, &section);
     1261    KapaSetSection (myKapa, &section);
    13721262    psFree (section.name);
    13731263
     
    13781268        if (!(source->mode & PM_SOURCE_MODE_PSFSTAR)) continue;
    13791269
    1380         psphotVisualPlotRadialProfile (kapa3, source, maskVal);
     1270        psphotVisualPlotRadialProfile (myKapa, source, maskVal);
    13811271
    13821272        // pause and wait for user input:
     
    13881278        }
    13891279        if (key[0] == 'e') {
    1390             KapaClearPlots (kapa3);
     1280            KapaClearPlots (myKapa);
    13911281        }
    13921282        if (key[0] == 's') {
     
    14071297    psEllipseAxes axes;
    14081298
     1299    // XXX skip this for now: it is not very clear
     1300    return true;
     1301
    14091302    if (!pmVisualIsVisual()) return true;
    14101303
    1411     if (kapa == -1) {
    1412         fprintf (stderr, "kapa not opened, skipping\n");
    1413         return false;
    1414     }
     1304    int myKapa = psphotKapaChannel (1);
     1305    if (myKapa == -1) return false;
    14151306
    14161307    // note: this uses the Ohana allocation tools:
     
    14851376    }
    14861377
    1487     KiiLoadOverlay (kapa, overlayE, NoverlayE, "red");
    1488     KiiLoadOverlay (kapa, overlayO, NoverlayO, "yellow");
     1378    KiiLoadOverlay (myKapa, overlayE, NoverlayE, "red");
     1379    KiiLoadOverlay (myKapa, overlayO, NoverlayO, "yellow");
    14891380    FREE (overlayE);
    14901381    FREE (overlayO);
    14911382
    1492     // pause and wait for user input:
    1493     // continue, save (provide name), ??
    1494     char key[10];
    14951383    fprintf (stdout, "even bits (0x0001, 0x0004, ... : red\n");
    14961384    fprintf (stdout, "odd bits (0x0002, 0x0008, ... : yellow\n");
    1497     fprintf (stdout, "[c]ontinue? ");
    1498     if (!fgets(key, 8, stdin)) {
    1499         psWarning("Unable to read option");
    1500     }
    1501 
    1502     return true;
    1503 }
    1504 
    1505 bool psphotVisualShowSourceSize (pmReadout *readout, psArray *sources) {
    1506 
    1507     int Noverlay, NOVERLAY;
     1385    pmVisualAskUser(NULL);
     1386
     1387    return true;
     1388}
     1389
     1390bool psphotVisualShowSourceSize_Single (int myKapa, psArray *sources, pmSourceMode mode, bool keep, float scale, char *color) {
     1391
     1392    int Noverlay;
    15081393    KiiOverlay *overlay;
    15091394
    1510     if (!pmVisualIsVisual()) return true;
    1511 
    1512     if (kapa == -1) {
    1513         fprintf (stderr, "kapa not opened, skipping\n");
    1514         return false;
    1515     }
     1395    psEllipseMoments emoments;
     1396    psEllipseAxes axes;
    15161397
    15171398    // note: this uses the Ohana allocation tools:
     1399    ALLOCATE (overlay, KiiOverlay, sources->n);
     1400
    15181401    Noverlay = 0;
    1519     NOVERLAY = 100;
    1520     ALLOCATE (overlay, KiiOverlay, sources->n);
    1521 
    1522     // mark CRs with red boxes
    15231402    for (int i = 0; i < sources->n; i++) {
    15241403
     
    15261405        if (source == NULL) continue;
    15271406
    1528         if (!(source->mode & PM_SOURCE_MODE_CR_LIMIT)) continue;
    1529 
    1530         overlay[Noverlay].type = KII_OVERLAY_BOX;
    1531         overlay[Noverlay].x = source->peak->xf;
    1532         overlay[Noverlay].y = source->peak->yf;
    1533 
    1534         overlay[Noverlay].dx = 4;
    1535         overlay[Noverlay].dy = 4;
    1536         overlay[Noverlay].angle = 0;
     1407        // if (source->type != type) continue;
     1408        if (mode) {
     1409            if (keep) {
     1410                if (!(source->mode & mode)) continue;
     1411            } else {
     1412                if (source->mode & mode) continue;
     1413            }
     1414        }
     1415
     1416        pmMoments *moments = source->moments;
     1417        if (moments == NULL) continue;
     1418
     1419        overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
     1420        overlay[Noverlay].x = moments->Mx;
     1421        overlay[Noverlay].y = moments->My;
     1422
     1423        emoments.x2 = moments->Mxx;
     1424        emoments.y2 = moments->Myy;
     1425        emoments.xy = moments->Mxy;
     1426
     1427        axes = psEllipseMomentsToAxes (emoments, 20.0);
     1428
     1429        overlay[Noverlay].dx = scale*2.0*axes.major;
     1430        overlay[Noverlay].dy = scale*2.0*axes.minor;
     1431        overlay[Noverlay].angle = axes.theta * PS_DEG_RAD;
    15371432        overlay[Noverlay].text = NULL;
    15381433        Noverlay ++;
    1539         CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
    1540     }
    1541     KiiLoadOverlay (kapa, overlay, Noverlay, "red");
    1542 
    1543 
    1544     Noverlay = 0;
    1545     for (int i = 0; i < sources->n; i++) {
    1546 
    1547         pmSource *source = sources->data[i];
    1548         if (source == NULL) continue;
    1549 
    1550         // mark EXTs with yellow circles
    1551         if (!(source->mode & PM_SOURCE_MODE_EXT_LIMIT)) continue;
    1552 
    1553         overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
    1554         overlay[Noverlay].x = source->peak->xf;
    1555         overlay[Noverlay].y = source->peak->yf;
    1556 
    1557         overlay[Noverlay].dx = 10;
    1558         overlay[Noverlay].dy = 10;
    1559         overlay[Noverlay].angle = 0;
    1560         overlay[Noverlay].text = NULL;
    1561         Noverlay ++;
    1562         CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
    1563     }
    1564 
    1565     KiiLoadOverlay (kapa, overlay, Noverlay, "blue");
     1434    }
     1435
     1436    KiiLoadOverlay (myKapa, overlay, Noverlay, color);
    15661437    FREE (overlay);
    15671438
    1568     psphotVisualShowMask (kapa, readout->mask, "mask", 2);
    1569 
    1570     // pause and wait for user input:
    1571     // continue, save (provide name), ??
    1572     char key[10];
    1573     fprintf (stdout, "CR: 4pix red BOX; EXT: 10pix blue circle\n");
    1574     fprintf (stdout, "[c]ontinue? ");
    1575     if (!fgets(key, 8, stdin)) {
    1576         psWarning("Unable to read option");
    1577     }
    1578 
    1579     return true;
    1580 }
    1581 
    1582 bool psphotVisualPlotSourceSize (psArray *sources) {
    1583 
     1439    return true;
     1440}
     1441
     1442bool psphotVisualShowSourceSize (pmReadout *readout, psArray *sources) {
     1443
     1444    if (!pmVisualIsVisual()) return true;
     1445
     1446    int myKapa = psphotKapaChannel (1);
     1447    if (myKapa == -1) return false;
     1448
     1449    KiiEraseOverlay (myKapa, "red");
     1450    KiiEraseOverlay (myKapa, "blue");
     1451    KiiEraseOverlay (myKapa, "green");
     1452    KiiEraseOverlay (myKapa, "yellow");
     1453
     1454    psphotVisualShowSourceSize_Single (myKapa, sources, PM_SOURCE_MODE_EXT_LIMIT | PM_SOURCE_MODE_DEFECT | PM_SOURCE_MODE_CR_LIMIT | PM_SOURCE_MODE_SATSTAR, 0, 1.0, "green");
     1455    psphotVisualShowSourceSize_Single (myKapa, sources, PM_SOURCE_MODE_EXT_LIMIT, 1, 1.0, "blue");
     1456    psphotVisualShowSourceSize_Single (myKapa, sources, PM_SOURCE_MODE_CR_LIMIT, 1, 1.0, "red");
     1457    psphotVisualShowSourceSize_Single (myKapa, sources, PM_SOURCE_MODE_DEFECT, 1, 2.0, "red");
     1458    psphotVisualShowSourceSize_Single (myKapa, sources, PM_SOURCE_MODE_SATSTAR, 1, 1.0, "yellow");
     1459
     1460    fprintf (stdout, "red: CR; blue: EXTENDED; green: PSF-like; yellow: SATSTAR\n");
     1461    pmVisualAskUser(NULL);
     1462    return true;
     1463}
     1464
     1465bool psphotVisualPlotSourceSize (psMetadata *recipe, psArray *sources) {
     1466
     1467    bool status;
    15841468    Graphdata graphdata;
    15851469    KapaSection section;
     
    15871471    if (!pmVisualIsVisual()) return true;
    15881472
    1589     if (kapa3 == -1) {
    1590         kapa3 = KapaOpenNamedSocket ("kapa", "psphot:plots");
    1591         if (kapa3 == -1) {
    1592             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    1593             pmVisualSetVisual(false);
    1594             return false;
     1473    int myKapa = psphotKapaChannel (2);
     1474    if (myKapa == -1) return false;
     1475
     1476    KapaClearPlots (myKapa);
     1477    KapaInitGraph (&graphdata);
     1478    KapaSetFont (myKapa, "courier", 14);
     1479
     1480    // select the max psfX,Y values for the plot limits
     1481    float Xmin = 1000.0, Xmax = 0.0;
     1482    float Ymin = 1000.0, Ymax = 0.0;
     1483    {
     1484        int nRegions = psMetadataLookupS32 (&status, recipe, "PSF.CLUMP.NREGIONS");
     1485        for (int n = 0; n < nRegions; n++) {
     1486
     1487            char regionName[64];
     1488            snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", n);
     1489            psMetadata *regionMD = psMetadataLookupPtr (&status, recipe, regionName);
     1490
     1491            float psfX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");
     1492            float psfY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y");
     1493            float psfdX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX");
     1494            float psfdY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY");
     1495
     1496            float X0 = psfX - 10.0*psfdX;
     1497            float X1 = psfX + 10.0*psfdX;
     1498            float Y0 = psfY - 10.0*psfdY;
     1499            float Y1 = psfY + 10.0*psfdY;
     1500
     1501            if (isfinite(X0)) { Xmin = PS_MIN(Xmin, X0); }
     1502            if (isfinite(X1)) { Xmax = PS_MAX(Xmax, X1); }
     1503            if (isfinite(Y0)) { Ymin = PS_MIN(Ymin, Y0); }
     1504            if (isfinite(Y1)) { Ymax = PS_MAX(Ymax, Y1); }
    15951505        }
    15961506    }
    1597 
    1598     KapaClearPlots (kapa3);
     1507    Xmin = PS_MAX(Xmin, -0.1);
     1508    Ymin = PS_MAX(Ymin, -0.1);
     1509
     1510    // storage vectors for data to be plotted
     1511    psVector *xSAT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1512    psVector *ySAT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1513    psVector *mSAT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1514    psVector *sSAT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1515
     1516    psVector *xPSF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1517    psVector *yPSF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1518    psVector *mPSF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1519    psVector *sPSF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1520
     1521    psVector *xEXT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1522    psVector *yEXT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1523    psVector *mEXT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1524    psVector *sEXT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1525
     1526    psVector *xDEF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1527    psVector *yDEF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1528    psVector *mDEF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1529    psVector *sDEF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1530
     1531    psVector *xCR = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1532    psVector *yCR = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1533    psVector *mCR = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1534    psVector *sCR = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1535
     1536    // construct the vectors
     1537    int nSAT = 0;
     1538    int nEXT = 0;
     1539    int nPSF = 0;
     1540    int nDEF = 0;
     1541    int nCR  = 0;
     1542    for (int i = 0; i < sources->n; i++) {
     1543        pmSource *source = sources->data[i];
     1544        if (source->moments == NULL) continue;
     1545
     1546        if (source->mode & PM_SOURCE_MODE_CR_LIMIT) {
     1547            xCR->data.F32[nCR] = source->moments->Mxx;
     1548            yCR->data.F32[nCR] = source->moments->Myy;
     1549            mCR->data.F32[nCR] = -2.5*log10(source->moments->Sum);
     1550            sCR->data.F32[nCR] = source->extNsigma;
     1551            nCR++;
     1552        }
     1553        if (source->mode & PM_SOURCE_MODE_SATSTAR) {
     1554            xSAT->data.F32[nSAT] = source->moments->Mxx;
     1555            ySAT->data.F32[nSAT] = source->moments->Myy;
     1556            mSAT->data.F32[nSAT] = -2.5*log10(source->moments->Sum);
     1557            sSAT->data.F32[nSAT] = source->extNsigma;
     1558            nSAT++;
     1559        }
     1560        if (source->mode & PM_SOURCE_MODE_EXT_LIMIT) {
     1561            xEXT->data.F32[nEXT] = source->moments->Mxx;
     1562            yEXT->data.F32[nEXT] = source->moments->Myy;
     1563            mEXT->data.F32[nEXT] = -2.5*log10(source->moments->Sum);
     1564            sEXT->data.F32[nEXT] = source->extNsigma;
     1565            nEXT++;
     1566            continue;
     1567        }
     1568        if (source->mode & PM_SOURCE_MODE_DEFECT) {
     1569            xDEF->data.F32[nDEF] = source->moments->Mxx;
     1570            yDEF->data.F32[nDEF] = source->moments->Myy;
     1571            mDEF->data.F32[nDEF] = -2.5*log10(source->moments->Sum);
     1572            sDEF->data.F32[nDEF] = source->extNsigma;
     1573            nDEF++;
     1574            continue;
     1575        }
     1576        if ((source->mode & PM_SOURCE_MODE_CR_LIMIT) || (source->mode & PM_SOURCE_MODE_SATSTAR)) {
     1577            continue;
     1578        }
     1579        xPSF->data.F32[nPSF] = source->moments->Mxx;
     1580        yPSF->data.F32[nPSF] = source->moments->Myy;
     1581        mPSF->data.F32[nPSF] = -2.5*log10(source->moments->Sum);
     1582        sPSF->data.F32[nPSF] = source->extNsigma;
     1583        nPSF++;
     1584    }
     1585    xSAT->n = nSAT;
     1586    ySAT->n = nSAT;
     1587    mSAT->n = nSAT;
     1588    sSAT->n = nSAT;
     1589
     1590    xPSF->n = nPSF;
     1591    yPSF->n = nPSF;
     1592    mPSF->n = nPSF;
     1593    sPSF->n = nPSF;
     1594
     1595    xEXT->n = nEXT;
     1596    yEXT->n = nEXT;
     1597    mEXT->n = nEXT;
     1598    sEXT->n = nEXT;
     1599
     1600    xCR->n = nCR;
     1601    yCR->n = nCR;
     1602    mCR->n = nCR;
     1603    sCR->n = nCR;
     1604
     1605    xDEF->n = nDEF;
     1606    yDEF->n = nDEF;
     1607    mDEF->n = nDEF;
     1608    sDEF->n = nDEF;
     1609
     1610    // four sections: MxxMyy, MagMxx, MagMyy, MagSigma
     1611
     1612    // first section: MxxMyy
     1613    section.dx = 0.75;
     1614    section.dy = 0.60;
     1615    section.x  = 0.00;
     1616    section.y  = 0.00;
     1617    section.name = psStringCopy ("MxxMyy");
     1618    KapaSetSection (myKapa, &section);
     1619    psFree (section.name);
     1620
     1621    graphdata.color = KapaColorByName ("black");
     1622    graphdata.xmin = Xmin;
     1623    graphdata.ymin = Ymin;
     1624    graphdata.xmax = Xmax;
     1625    graphdata.ymax = Ymax;
     1626    KapaSetLimits (myKapa, &graphdata);
     1627
     1628    KapaBox (myKapa, &graphdata);
     1629    KapaSendLabel (myKapa, "M_xx| (pixels)", KAPA_LABEL_XM);
     1630    KapaSendLabel (myKapa, "M_yy| (pixels)", KAPA_LABEL_YM);
     1631
     1632    graphdata.color = KapaColorByName ("black");
     1633    graphdata.ptype = 0;
     1634    graphdata.size = 0.5;
     1635    graphdata.style = 2;
     1636    KapaPrepPlot   (myKapa, nPSF, &graphdata);
     1637    KapaPlotVector (myKapa, nPSF, xPSF->data.F32, "x");
     1638    KapaPlotVector (myKapa, nPSF, yPSF->data.F32, "y");
     1639
     1640    graphdata.color = KapaColorByName ("blue");
     1641    graphdata.ptype = 0;
     1642    graphdata.size = 0.5;
     1643    graphdata.style = 2;
     1644    KapaPrepPlot   (myKapa, nEXT, &graphdata);
     1645    KapaPlotVector (myKapa, nEXT, xEXT->data.F32, "x");
     1646    KapaPlotVector (myKapa, nEXT, yEXT->data.F32, "y");
     1647
     1648    graphdata.color = KapaColorByName ("red");
     1649    graphdata.ptype = 0;
     1650    graphdata.size = 0.5;
     1651    graphdata.style = 2;
     1652    KapaPrepPlot   (myKapa, nDEF, &graphdata);
     1653    KapaPlotVector (myKapa, nDEF, xDEF->data.F32, "x");
     1654    KapaPlotVector (myKapa, nDEF, yDEF->data.F32, "y");
     1655
     1656    graphdata.color = KapaColorByName ("red");
     1657    graphdata.ptype = 7;
     1658    graphdata.size = 1.0;
     1659    graphdata.style = 2;
     1660    KapaPrepPlot   (myKapa, nCR, &graphdata);
     1661    KapaPlotVector (myKapa, nCR, xCR->data.F32, "x");
     1662    KapaPlotVector (myKapa, nCR, yCR->data.F32, "y");
     1663
     1664    graphdata.color = KapaColorByName ("blue");
     1665    graphdata.ptype = 7;
     1666    graphdata.size = 1.0;
     1667    graphdata.style = 2;
     1668    KapaPrepPlot   (myKapa, nSAT, &graphdata);
     1669    KapaPlotVector (myKapa, nSAT, xSAT->data.F32, "x");
     1670    KapaPlotVector (myKapa, nSAT, ySAT->data.F32, "y");
     1671
     1672    // second section: MagMyy
     1673    section.dx = 0.75;
     1674    section.dy = 0.20;
     1675    section.x  = 0.00;
     1676    section.y  = 0.80;
     1677    section.name = psStringCopy ("MagMyy");
     1678    KapaSetSection (myKapa, &section);
     1679    psFree (section.name);
     1680
     1681    graphdata.color = KapaColorByName ("black");
     1682    graphdata.xmin = -17.1;
     1683    graphdata.xmax =  -7.9;
     1684    graphdata.ymin = Ymin;
     1685    graphdata.ymax = Ymax;
     1686    KapaSetLimits (myKapa, &graphdata);
     1687
     1688    strcpy (graphdata.labels, "0210");
     1689    KapaBox (myKapa, &graphdata);
     1690    KapaSendLabel (myKapa, "inst mag", KAPA_LABEL_XP);
     1691    KapaSendLabel (myKapa, "M_yy| (pixels)", KAPA_LABEL_YM);
     1692
     1693    graphdata.color = KapaColorByName ("black");
     1694    graphdata.ptype = 0;
     1695    graphdata.size = 0.5;
     1696    graphdata.style = 2;
     1697    KapaPrepPlot   (myKapa, nPSF, &graphdata);
     1698    KapaPlotVector (myKapa, nPSF, mPSF->data.F32, "x");
     1699    KapaPlotVector (myKapa, nPSF, yPSF->data.F32, "y");
     1700
     1701    graphdata.color = KapaColorByName ("blue");
     1702    graphdata.ptype = 0;
     1703    graphdata.size = 0.5;
     1704    graphdata.style = 2;
     1705    KapaPrepPlot   (myKapa, nEXT, &graphdata);
     1706    KapaPlotVector (myKapa, nEXT, mEXT->data.F32, "x");
     1707    KapaPlotVector (myKapa, nEXT, yEXT->data.F32, "y");
     1708
     1709    graphdata.color = KapaColorByName ("red");
     1710    graphdata.ptype = 0;
     1711    graphdata.size = 0.5;
     1712    graphdata.style = 2;
     1713    KapaPrepPlot   (myKapa, nDEF, &graphdata);
     1714    KapaPlotVector (myKapa, nDEF, mDEF->data.F32, "x");
     1715    KapaPlotVector (myKapa, nDEF, yDEF->data.F32, "y");
     1716
     1717    graphdata.color = KapaColorByName ("red");
     1718    graphdata.ptype = 7;
     1719    graphdata.size = 1.0;
     1720    graphdata.style = 2;
     1721    KapaPrepPlot   (myKapa, nCR, &graphdata);
     1722    KapaPlotVector (myKapa, nCR, mCR->data.F32, "x");
     1723    KapaPlotVector (myKapa, nCR, yCR->data.F32, "y");
     1724
     1725    graphdata.color = KapaColorByName ("blue");
     1726    graphdata.ptype = 7;
     1727    graphdata.size = 1.0;
     1728    graphdata.style = 2;
     1729    KapaPrepPlot   (myKapa, nSAT, &graphdata);
     1730    KapaPlotVector (myKapa, nSAT, mSAT->data.F32, "x");
     1731    KapaPlotVector (myKapa, nSAT, ySAT->data.F32, "y");
     1732
     1733    // third section: MagMxx
     1734    section.dx = 0.25;
     1735    section.dy = 0.60;
     1736    section.x  = 0.80;
     1737    section.y  = 0.00;
     1738    section.name = psStringCopy ("MagMxx");
     1739    KapaSetSection (myKapa, &section);
     1740    psFree (section.name);
     1741
     1742    graphdata.color = KapaColorByName ("black");
     1743    graphdata.xmin = Xmin;
     1744    graphdata.xmax = Xmax;
     1745    graphdata.ymin =  -7.9;
     1746    graphdata.ymax = -17.1;
     1747    KapaSetLimits (myKapa, &graphdata);
     1748
     1749    strcpy (graphdata.labels, "2001");
     1750    KapaBox (myKapa, &graphdata);
     1751    KapaSendLabel (myKapa, "M_xx| (pixels)", KAPA_LABEL_XM);
     1752    KapaSendLabel (myKapa, "inst mag", KAPA_LABEL_YP);
     1753
     1754    graphdata.color = KapaColorByName ("black");
     1755    graphdata.ptype = 0;
     1756    graphdata.size = 0.5;
     1757    graphdata.style = 2;
     1758    KapaPrepPlot   (myKapa, nPSF, &graphdata);
     1759    KapaPlotVector (myKapa, nPSF, xPSF->data.F32, "x");
     1760    KapaPlotVector (myKapa, nPSF, mPSF->data.F32, "y");
     1761
     1762    graphdata.color = KapaColorByName ("blue");
     1763    graphdata.ptype = 0;
     1764    graphdata.size = 0.5;
     1765    graphdata.style = 2;
     1766    KapaPrepPlot   (myKapa, nEXT, &graphdata);
     1767    KapaPlotVector (myKapa, nEXT, xEXT->data.F32, "x");
     1768    KapaPlotVector (myKapa, nEXT, mEXT->data.F32, "y");
     1769
     1770    graphdata.color = KapaColorByName ("red");
     1771    graphdata.ptype = 0;
     1772    graphdata.size = 0.5;
     1773    graphdata.style = 2;
     1774    KapaPrepPlot   (myKapa, nDEF, &graphdata);
     1775    KapaPlotVector (myKapa, nDEF, xDEF->data.F32, "x");
     1776    KapaPlotVector (myKapa, nDEF, mDEF->data.F32, "y");
     1777
     1778    graphdata.color = KapaColorByName ("red");
     1779    graphdata.ptype = 7;
     1780    graphdata.size = 1.0;
     1781    graphdata.style = 2;
     1782    KapaPrepPlot   (myKapa, nCR, &graphdata);
     1783    KapaPlotVector (myKapa, nCR, xCR->data.F32, "x");
     1784    KapaPlotVector (myKapa, nCR, mCR->data.F32, "y");
     1785
     1786    graphdata.color = KapaColorByName ("blue");
     1787    graphdata.ptype = 7;
     1788    graphdata.size = 1.0;
     1789    graphdata.style = 2;
     1790    KapaPrepPlot   (myKapa, nSAT, &graphdata);
     1791    KapaPlotVector (myKapa, nSAT, xSAT->data.F32, "x");
     1792    KapaPlotVector (myKapa, nSAT, mSAT->data.F32, "y");
     1793
     1794    // fourth section: MagSigma
     1795    section.dx = 0.75;
     1796    section.dy = 0.15;
     1797    section.x  = 0.00;
     1798    section.y  = 0.65;
     1799    section.name = psStringCopy ("MagSigma");
     1800    KapaSetSection (myKapa, &section);
     1801    psFree (section.name);
     1802
     1803    graphdata.color = KapaColorByName ("black");
     1804    graphdata.xmax =  -7.9;
     1805    graphdata.xmin = -17.1;
     1806    graphdata.ymin = -20.1;
     1807    graphdata.ymax = +20.1;
     1808    KapaSetLimits (myKapa, &graphdata);
     1809
     1810    strcpy (graphdata.labels, "0100");
     1811    KapaBox (myKapa, &graphdata);
     1812    // KapaSendLabel (myKapa, "inst mag", KAPA_LABEL_XM);
     1813    KapaSendLabel (myKapa, "EXT&ss&c", KAPA_LABEL_YM);
     1814
     1815    graphdata.color = KapaColorByName ("black");
     1816    graphdata.ptype = 0;
     1817    graphdata.size = 0.5;
     1818    graphdata.style = 2;
     1819    KapaPrepPlot   (myKapa, nPSF, &graphdata);
     1820    KapaPlotVector (myKapa, nPSF, mPSF->data.F32, "x");
     1821    KapaPlotVector (myKapa, nPSF, sPSF->data.F32, "y");
     1822
     1823    graphdata.color = KapaColorByName ("blue");
     1824    graphdata.ptype = 0;
     1825    graphdata.size = 0.5;
     1826    graphdata.style = 2;
     1827    KapaPrepPlot   (myKapa, nEXT, &graphdata);
     1828    KapaPlotVector (myKapa, nEXT, mEXT->data.F32, "x");
     1829    KapaPlotVector (myKapa, nEXT, sEXT->data.F32, "y");
     1830
     1831    graphdata.color = KapaColorByName ("red");
     1832    graphdata.ptype = 0;
     1833    graphdata.size = 0.5;
     1834    graphdata.style = 2;
     1835    KapaPrepPlot   (myKapa, nDEF, &graphdata);
     1836    KapaPlotVector (myKapa, nDEF, mDEF->data.F32, "x");
     1837    KapaPlotVector (myKapa, nDEF, sDEF->data.F32, "y");
     1838
     1839    graphdata.color = KapaColorByName ("red");
     1840    graphdata.ptype = 7;
     1841    graphdata.size = 1.0;
     1842    graphdata.style = 2;
     1843    KapaPrepPlot   (myKapa, nCR, &graphdata);
     1844    KapaPlotVector (myKapa, nCR, mCR->data.F32, "x");
     1845    KapaPlotVector (myKapa, nCR, sCR->data.F32, "y");
     1846
     1847    graphdata.color = KapaColorByName ("blue");
     1848    graphdata.ptype = 7;
     1849    graphdata.size = 1.0;
     1850    graphdata.style = 2;
     1851    KapaPrepPlot   (myKapa, nSAT, &graphdata);
     1852    KapaPlotVector (myKapa, nSAT, mSAT->data.F32, "x");
     1853    KapaPlotVector (myKapa, nSAT, sSAT->data.F32, "y");
     1854
     1855    // draw N circles to outline the clumps
     1856    {
     1857        KapaSelectSection (myKapa, "MxxMyy");
     1858
     1859        // draw a circle centered on psfX,Y with size of the psf limit
     1860        psVector *xLimit  = psVectorAlloc (120, PS_TYPE_F32);
     1861        psVector *yLimit  = psVectorAlloc (120, PS_TYPE_F32);
     1862
     1863        int nRegions = psMetadataLookupS32 (&status, recipe, "PSF.CLUMP.NREGIONS");
     1864        float PSF_CLUMP_NSIGMA = psMetadataLookupF32 (&status, recipe, "PSF_CLUMP_NSIGMA");
     1865
     1866        graphdata.color = KapaColorByName ("blue");
     1867        graphdata.style = 0;
     1868
     1869        graphdata.xmin = Xmin;
     1870        graphdata.ymin = Ymin;
     1871        graphdata.xmax = Xmax;
     1872        graphdata.ymax = Ymax;
     1873        KapaSetLimits (myKapa, &graphdata);
     1874
     1875        for (int n = 0; n < nRegions; n++) {
     1876
     1877            char regionName[64];
     1878            snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", n);
     1879            psMetadata *regionMD = psMetadataLookupPtr (&status, recipe, regionName);
     1880
     1881            float psfX  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");
     1882            float psfY  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y");
     1883            float psfdX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX");
     1884            float psfdY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY");
     1885            float Rx = psfdX * PSF_CLUMP_NSIGMA;
     1886            float Ry = psfdY * PSF_CLUMP_NSIGMA;
     1887
     1888            for (int i = 0; i < xLimit->n; i++) {
     1889                xLimit->data.F32[i] = Rx*cos(i*2.0*M_PI/120.0) + psfX;
     1890                yLimit->data.F32[i] = Ry*sin(i*2.0*M_PI/120.0) + psfY;
     1891            }
     1892            KapaPrepPlot (myKapa, xLimit->n, &graphdata);
     1893            KapaPlotVector (myKapa, xLimit->n, xLimit->data.F32, "x");
     1894            KapaPlotVector (myKapa, yLimit->n, yLimit->data.F32, "y");
     1895        }
     1896        psFree (xLimit);
     1897        psFree (yLimit);
     1898    }
     1899
     1900    psFree (xSAT);
     1901    psFree (ySAT);
     1902    psFree (mSAT);
     1903
     1904    psFree (xEXT);
     1905    psFree (yEXT);
     1906    psFree (mEXT);
     1907
     1908    psFree (xPSF);
     1909    psFree (yPSF);
     1910    psFree (mPSF);
     1911
     1912    psFree (xDEF);
     1913    psFree (yDEF);
     1914    psFree (mDEF);
     1915
     1916    psFree (xCR);
     1917    psFree (yCR);
     1918    psFree (mCR);
     1919
     1920    pmVisualAskUser(NULL);
     1921    return true;
     1922}
     1923
     1924bool psphotVisualShowResidualImage (pmReadout *readout) {
     1925
     1926    if (!pmVisualIsVisual()) return true;
     1927
     1928    int myKapa = psphotKapaChannel (1);
     1929    if (myKapa == -1) return false;
     1930
     1931    psphotVisualScaleImage (myKapa, readout->image, "resid", 1);
     1932
     1933    pmVisualAskUser(NULL);
     1934    return true;
     1935}
     1936
     1937bool psphotVisualPlotApResid (psArray *sources, float mean, float error) {
     1938
     1939    Graphdata graphdata;
     1940    float lineX[2], lineY[2];
     1941
     1942    if (!pmVisualIsVisual()) return true;
     1943
     1944    int myKapa = psphotKapaChannel (2);
     1945    if (myKapa == -1) return false;
     1946
     1947    KapaClearPlots (myKapa);
    15991948    KapaInitGraph (&graphdata);
    1600 
    1601     // first section : mag vs CR nSigma
    1602     section.dx = 1.0;
    1603     section.dy = 0.5;
    1604     section.x = 0.0;
    1605     section.y = 0.0;
    1606     section.name = NULL;
    1607     psStringAppend (&section.name, "a1");
    1608     KapaSetSection (kapa3, &section);
    1609     psFree (section.name);
    16101949
    16111950    psVector *x = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
    16121951    psVector *y = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
    1613 
    1614     graphdata.xmin = +32.0;
    1615     graphdata.xmax = -32.0;
    1616     graphdata.ymin = +32.0;
    1617     graphdata.ymax = -32.0;
    1618 
    1619     // construct the plot vectors
    1620     int n = 0;
    1621     for (int i = 0; i < sources->n; i++) {
    1622         pmSource *source = sources->data[i];
    1623         if (!source) continue;
    1624         if (source->type != PM_SOURCE_TYPE_STAR) continue;
    1625         if (!isfinite (source->crNsigma)) continue;
    1626 
    1627         x->data.F32[n] = -2.5*log10(source->peak->flux);
    1628         y->data.F32[n] = source->crNsigma;
    1629         graphdata.xmin = PS_MIN(graphdata.xmin, x->data.F32[n]);
    1630         graphdata.xmax = PS_MAX(graphdata.xmax, x->data.F32[n]);
    1631         graphdata.ymin = -0.5;
    1632         graphdata.ymax = 10.0;
    1633 
    1634         n++;
    1635     }
    1636     x->n = y->n = n;
    1637 
    1638     float range;
    1639     range = graphdata.xmax - graphdata.xmin;
    1640     graphdata.xmax += 0.05*range;
    1641     graphdata.xmin -= 0.05*range;
    1642 
    1643     // XXX set the plot range to match the image
    1644     KapaSetLimits (kapa3, &graphdata);
    1645 
    1646     KapaSetFont (kapa3, "helvetica", 14);
    1647     KapaBox (kapa3, &graphdata);
    1648     KapaSendLabel (kapa3, "Peak as Mag", KAPA_LABEL_XM);
    1649     KapaSendLabel (kapa3, "CR N Sigma", KAPA_LABEL_YM);
    1650 
    1651     graphdata.color = KapaColorByName ("black");
    1652     graphdata.ptype = 2;
    1653     graphdata.size = 0.5;
    1654     graphdata.style = 2;
    1655     KapaPrepPlot (kapa3, n, &graphdata);
    1656     KapaPlotVector (kapa3, n, x->data.F32, "x");
    1657     KapaPlotVector (kapa3, n, y->data.F32, "y");
    1658 
    1659     // second section : mag vs EXT nSigma
    1660     section.dx = 1.0;
    1661     section.dy = 0.5;
    1662     section.x = 0.0;
    1663     section.y = 0.5;
    1664     section.name = NULL;
    1665     psStringAppend (&section.name, "a2");
    1666     KapaSetSection (kapa3, &section);
    1667     psFree (section.name);
    1668 
    1669     graphdata.xmin = +32.0;
    1670     graphdata.xmax = -32.0;
    1671     graphdata.ymin = +32.0;
    1672     graphdata.ymax = -32.0;
    1673 
    1674     // construct the plot vectors
    1675     n = 0;
    1676     for (int i = 0; i < sources->n; i++) {
    1677         pmSource *source = sources->data[i];
    1678         if (!source) continue;
    1679         if (source->type != PM_SOURCE_TYPE_STAR) continue;
    1680         if (!isfinite (source->extNsigma)) continue;
    1681 
    1682         x->data.F32[n] = -2.5*log10(source->peak->flux);
    1683         y->data.F32[n] = source->extNsigma;
    1684         graphdata.xmin = PS_MIN(graphdata.xmin, x->data.F32[n]);
    1685         graphdata.xmax = PS_MAX(graphdata.xmax, x->data.F32[n]);
    1686         graphdata.ymin = -0.5;
    1687         graphdata.ymax = 10.0;
    1688 
    1689         n++;
    1690     }
    1691     x->n = y->n = n;
    1692 
    1693     range = graphdata.xmax - graphdata.xmin;
    1694     graphdata.xmax += 0.05*range;
    1695     graphdata.xmin -= 0.05*range;
    1696 
    1697     // XXX set the plot range to match the image
    1698     KapaSetLimits (kapa3, &graphdata);
    1699 
    1700     KapaSetFont (kapa3, "helvetica", 14);
    1701     KapaBox (kapa3, &graphdata);
    1702     KapaSendLabel (kapa3, "EXT N Sigma", KAPA_LABEL_YM);
    1703 
    1704     graphdata.color = KapaColorByName ("black");
    1705     graphdata.ptype = 2;
    1706     graphdata.size = 0.5;
    1707     graphdata.style = 2;
    1708     KapaPrepPlot (kapa3, n, &graphdata);
    1709     KapaPlotVector (kapa3, n, x->data.F32, "x");
    1710     KapaPlotVector (kapa3, n, y->data.F32, "y");
    1711 
    1712     psFree (x);
    1713     psFree (y);
    1714 
    1715     // pause and wait for user input:
    1716     // continue, save (provide name), ??
    1717     char key[10];
    1718     fprintf (stdout, "[c]ontinue? ");
    1719     if (!fgets(key, 8, stdin)) {
    1720         psWarning("Unable to read option");
    1721     }
    1722     return true;
    1723 }
    1724 
    1725 bool psphotVisualShowResidualImage (pmReadout *readout) {
    1726 
    1727     if (!pmVisualIsVisual()) return true;
    1728 
    1729     if (kapa == -1) {
    1730         kapa = KapaOpenNamedSocket ("kapa", "psphot:images");
    1731         if (kapa == -1) {
    1732             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    1733             pmVisualSetVisual(false);
    1734             return false;
    1735         }
    1736     }
    1737 
    1738     psphotVisualScaleImage (kapa, readout->image, "resid", 1);
    1739 
    1740     // pause and wait for user input:
    1741     // continue, save (provide name), ??
    1742     char key[10];
    1743     fprintf (stdout, "[c]ontinue? ");
    1744     if (!fgets(key, 8, stdin)) {
    1745         psWarning("Unable to read option");
    1746     }
    1747     return true;
    1748 }
    1749 
    1750 bool psphotVisualPlotApResid (psArray *sources) {
    1751 
    1752     Graphdata graphdata;
    1753 
    1754     if (!pmVisualIsVisual()) return true;
    1755 
    1756     if (kapa3 == -1) {
    1757         kapa3 = KapaOpenNamedSocket ("kapa", "psphot:plots");
    1758         if (kapa3 == -1) {
    1759             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    1760             pmVisualSetVisual(false);
    1761             return false;
    1762         }
    1763     }
    1764 
    1765     KapaClearPlots (kapa3);
    1766     KapaInitGraph (&graphdata);
    1767 
    1768     psVector *x = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
    1769     psVector *y = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1952    psVector *dy = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
    17701953
    17711954    graphdata.xmin = +32.0;
     
    17851968        x->data.F32[n] = source->psfMag;
    17861969        y->data.F32[n] = source->apMag - source->psfMag;
     1970        dy->data.F32[n] = source->errMag;
    17871971        graphdata.xmin = PS_MIN(graphdata.xmin, x->data.F32[n]);
    17881972        graphdata.xmax = PS_MAX(graphdata.xmax, x->data.F32[n]);
     
    17921976        n++;
    17931977    }
    1794     x->n = y->n = n;
     1978    x->n = y->n = dy->n = n;
    17951979
    17961980    float range;
     
    18021986    graphdata.ymin -= 0.05*range;
    18031987
    1804     // XXX set the plot range to match the image
    1805     KapaSetLimits (kapa3, &graphdata);
    1806 
    1807     KapaSetFont (kapa3, "helvetica", 14);
    1808     KapaBox (kapa3, &graphdata);
    1809     KapaSendLabel (kapa3, "PSF Mag", KAPA_LABEL_XM);
    1810     KapaSendLabel (kapa3, "Ap Mag - PSF Mag", KAPA_LABEL_YM);
     1988    // XXX test
     1989    graphdata.xmin = -17.0;
     1990    graphdata.xmax =  -9.0;
     1991    graphdata.ymin = -0.31;
     1992    graphdata.ymax = +0.31;
     1993
     1994    KapaSetLimits (myKapa, &graphdata);
     1995
     1996    KapaSetFont (myKapa, "helvetica", 14);
     1997    KapaBox (myKapa, &graphdata);
     1998    KapaSendLabel (myKapa, "PSF Mag", KAPA_LABEL_XM);
     1999    KapaSendLabel (myKapa, "Ap Mag - PSF Mag", KAPA_LABEL_YM);
    18112000
    18122001    graphdata.color = KapaColorByName ("black");
     
    18142003    graphdata.size = 0.5;
    18152004    graphdata.style = 2;
    1816     KapaPrepPlot (kapa3, n, &graphdata);
    1817     KapaPlotVector (kapa3, n, x->data.F32, "x");
    1818     KapaPlotVector (kapa3, n, y->data.F32, "y");
     2005    graphdata.etype |= 0x01;
     2006    KapaPrepPlot (myKapa, n, &graphdata);
     2007    KapaPlotVector (myKapa, n, x->data.F32, "x");
     2008    KapaPlotVector (myKapa, n, y->data.F32, "y");
     2009    KapaPlotVector (myKapa, n, dy->data.F32, "dym");
     2010    KapaPlotVector (myKapa, n, dy->data.F32, "dyp");
     2011
     2012    graphdata.color = KapaColorByName ("blue");
     2013    graphdata.ptype = 0;
     2014    graphdata.size = 0.5;
     2015    graphdata.style = 0;
     2016    graphdata.etype = 0;
     2017    lineX[0] = graphdata.xmin;
     2018    lineX[1] = graphdata.xmax;
     2019    lineY[0] = lineY[1] = mean;
     2020    KapaPrepPlot (myKapa, 2, &graphdata);
     2021    KapaPlotVector (myKapa, 2, lineX, "x");
     2022    KapaPlotVector (myKapa, 2, lineY, "y");
     2023
     2024    graphdata.color = KapaColorByName ("red");
     2025    graphdata.ptype = 0;
     2026    graphdata.size = 0.5;
     2027    graphdata.style = 0;
     2028    graphdata.etype = 0;
     2029    lineX[0] = graphdata.xmin;
     2030    lineX[1] = graphdata.xmax;
     2031    lineY[0] = lineY[1] = mean + error;
     2032    KapaPrepPlot (myKapa, 2, &graphdata);
     2033    KapaPlotVector (myKapa, 2, lineX, "x");
     2034    KapaPlotVector (myKapa, 2, lineY, "y");
     2035
     2036    graphdata.color = KapaColorByName ("red");
     2037    graphdata.ptype = 0;
     2038    graphdata.size = 0.5;
     2039    graphdata.style = 0;
     2040    graphdata.etype = 0;
     2041    lineX[0] = graphdata.xmin;
     2042    lineX[1] = graphdata.xmax;
     2043    lineY[0] = lineY[1] = mean - error;
     2044    KapaPrepPlot (myKapa, 2, &graphdata);
     2045    KapaPlotVector (myKapa, 2, lineX, "x");
     2046    KapaPlotVector (myKapa, 2, lineY, "y");
    18192047
    18202048    psFree (x);
    18212049    psFree (y);
    1822 
    1823     // pause and wait for user input:
    1824     // continue, save (provide name), ??
    1825     char key[10];
    1826     fprintf (stdout, "[c]ontinue? ");
    1827     if (!fgets(key, 8, stdin)) {
    1828         psWarning("Unable to read option");
    1829     }
     2050    psFree (dy);
     2051
     2052    pmVisualAskUser(NULL);
     2053    return true;
     2054}
     2055
     2056bool psphotVisualShowPetrosians (psArray *sources) {
     2057
     2058    int Noverlay, NOVERLAY;
     2059    KiiOverlay *overlay;
     2060
     2061    if (!pmVisualIsVisual()) return true;
     2062
     2063    int kapa = psphotKapaChannel (1);
     2064    if (kapa == -1) return false;
     2065
     2066    Noverlay = 0;
     2067    NOVERLAY = 100;
     2068    ALLOCATE (overlay, KiiOverlay, NOVERLAY);
     2069
     2070    for (int i = 0; i < sources->n; i++) {
     2071        pmSource *source = sources->data[i];
     2072
     2073        if (!source) continue;
     2074        if (!source->extpars) continue;
     2075        if (!source->extpars->profile) continue;
     2076        if (!source->extpars->petrosian_80) continue;
     2077
     2078        pmSourceRadialProfile *profile = source->extpars->profile;
     2079        pmSourceExtendedFlux *petrosian = source->extpars->petrosian_80;
     2080
     2081        overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
     2082        overlay[Noverlay].x = source->peak->xf;
     2083        overlay[Noverlay].y = source->peak->yf;
     2084        overlay[Noverlay].dx = 2.0*petrosian->radius;
     2085        overlay[Noverlay].dy = 2.0*petrosian->radius*profile->axes.minor/profile->axes.major;
     2086        overlay[Noverlay].angle = profile->axes.theta * PS_DEG_RAD;
     2087        overlay[Noverlay].text = NULL;
     2088        Noverlay ++;
     2089        CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
     2090
     2091        overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
     2092        overlay[Noverlay].x = source->peak->xf;
     2093        overlay[Noverlay].y = source->peak->yf;
     2094        overlay[Noverlay].dx = 4.0*petrosian->radius;
     2095        overlay[Noverlay].dy = 4.0*petrosian->radius*profile->axes.minor/profile->axes.major;
     2096        overlay[Noverlay].angle = profile->axes.theta * PS_DEG_RAD;
     2097        overlay[Noverlay].text = NULL;
     2098        Noverlay ++;
     2099        CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
     2100    }
     2101
     2102    KiiLoadOverlay (kapa, overlay, Noverlay, "red");
     2103    FREE (overlay);
     2104
     2105    pmVisualAskUser(NULL);
    18302106    return true;
    18312107}
     
    18502126
    18512127# endif
     2128
     2129# if (0)
     2130// *** make a histogram of the source counts in the x and y directions
     2131psHistogram *nX = psHistogramAlloc (graphdata.xmin, graphdata.xmax, 50.0);
     2132psHistogram *nY = psHistogramAlloc (graphdata.ymin, graphdata.ymax, 50.0);
     2133psVectorHistogram (nX, xFaint, NULL, NULL, 0);
     2134psVectorHistogram (nY, yFaint, NULL, NULL, 0);
     2135psVector *dX = psVectorAlloc (nX->nums->n, PS_TYPE_F32);
     2136psVector *vX = psVectorAlloc (nX->nums->n, PS_TYPE_F32);
     2137psVector *dY = psVectorAlloc (nY->nums->n, PS_TYPE_F32);
     2138psVector *vY = psVectorAlloc (nY->nums->n, PS_TYPE_F32);
     2139for (int i = 0; i < nX->nums->n; i++) {
     2140    dX->data.F32[i] = nX->nums->data.S32[i];
     2141    vX->data.F32[i] = 0.5*(nX->bounds->data.F32[i] + nX->bounds->data.F32[i+1]);
     2142}
     2143for (int i = 0; i < nY->nums->n; i++) {
     2144    dY->data.F32[i] = nY->nums->data.S32[i];
     2145    vY->data.F32[i] = 0.5*(nY->bounds->data.F32[i] + nY->bounds->data.F32[i+1]);
     2146}
     2147
     2148graphdata.color = KapaColorByName ("black");
     2149graphdata.ptype = 0;
     2150graphdata.size = 0.0;
     2151graphdata.style = 0;
     2152KapaPrepPlot (myKapa, dX->n, &graphdata);
     2153KapaPlotVector (myKapa, dX->n, dX->data.F32, "x");
     2154KapaPlotVector (myKapa, vX->n, vX->data.F32, "y");
     2155
     2156psFree (nX);
     2157psFree (dX);
     2158psFree (vX);
     2159
     2160psFree (nY);
     2161psFree (dY);
     2162psFree (vY);
     2163
     2164# endif
     2165
Note: See TracChangeset for help on using the changeset viewer.