IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 29004 for trunk/psphot/src


Ignore:
Timestamp:
Aug 20, 2010, 1:14:11 PM (16 years ago)
Author:
eugene
Message:

Many changes:

  • psphot-related issues

1) added a new feature to psLib/src/fft/psImageFFT to allow for a pre-FFTed kernel generated for a specific image dimension which can then be applied to an arbitrary number of images for convolution -- this avoids the kernel FFT for every image convolution.
2) updated the psMinimizeLMM to include 2 levels of tolerance: minTol and maxTol: if the minimization reaches minTol, it stops. if it only reaches maxTol within maxIter, it stops and is considered successful, if it fails to reach maxTol, then it fails. This allows us to accept fits that are actually acceptable (within error) even if they are not as close as ideally possible.
3) add new stat: psfWeightNotPoor (vs psfWeightNotBad) : the first gives the fraction of psf-weighted unmasked pixels considering any mask bits (except the internal 'mark' bit), while the former considers only 'bad' mask bits -- these are written to QF_PSF and QF_PSF_PERFECT in the CMF files.
4) define user-set parameters for max and min valid flux in the linear fit analysis: Note this was the cause of the non-negative fluxes in forced photometry -- the min limit was hard-wired to 0.0.
5) significance image is now constructed as (image + (image/1000)2) / sqrt(variance) so that bright sources have well-defined peaks (other wise, they become somewhat flat-topped as image = sqrt(variance), leading to ill-defined peaks).
6) modification of the visualization functions to accept facility and level values akin to psTrace
7) modification of the source fitting APIs to allow thread- and source- independent fit options (iterations, tolerances, etc)
8) use Kron magnitude as test for source size (CR vs EXT) instead of PSF-based aperture
9) set a min systematic error in the aperture mags when used for size classification significance
10) threaded the psf-convolved model (PCM) fitting process (extended source fits)
11) for extended sources, adjust the radius based on the footprint and re-calculate moments for guess; save the psf-based moments for output in psf table
12) for Sersic fitting, choose the best index with a grid search using only a few iterations; iterate fully on the selected value.
13) same for Sersic fitting using the PCM fitting process
14) fixed a bug in which the PSF candidate stars which failed in the psf fitting were not correctly unmarked as being PSF stars
15) define galaxy fit radius based on sky stdev (global, not local)
16) move the PCM code to psModules
17) save and report the raw aperture mag in addition to the curve-of-growth corrected one (PS1_V3)
18) save and report the Kron parameters and higher-order moments
19) some psModule header reorganization for code clarity
20) fixed a bug in which the diff stats were counting 'marked' pixels (outside area of interest) as 'masked'.
21) save the radial profile aperture sizes in the headers
22) better guess for Sersic parameters based on moments (requires setting the functional form so that the scale length is right)

  • ppSub-related:

1) ensure masked pixels are NANed in output diff image
2) add code to flag detections if they have bright positive neighbors (+ output of these in PS1_DV2)
3) define separate penalties for each image (based on their fwhm values) (this requires the penalties to be calculated later in the code).
4) define separate apertures for each image for flux normalization
5) choose aperture based on curve-of-growth (was based on fixed fraction of full aperture flux, and thus noisy)
6) some fine tuning of the penalty factor (this still seems arbitrary, and results are somewhat sensitive to the right value)

Location:
trunk/psphot
Files:
29 edited

Legend:

Unmodified
Added
Removed
  • trunk/psphot

    • Property svn:mergeinfo deleted
  • trunk/psphot/src/Makefile.am

    r28013 r29004  
    163163        psphotOutput.c                 \
    164164        psphotFakeSources.c            \
    165         psphotModelWithPSF.c           \
    166165        psphotExtendedSourceAnalysis.c \
    167166        psphotExtendedSourceAnalysisByObject.c \
    168167        psphotExtendedSourceFits.c     \
    169168        psphotKernelFromPSF.c          \
    170         psphotPSFConvModel.c           \
    171169        psphotFitSet.c                 \
    172170        psphotSourceFreePixels.c       \
  • trunk/psphot/src/psphot.h

    r28013 r29004  
    1212
    1313#define PSPHOT_RECIPE_PSF_FAKE_ALLOW "PSF.FAKE.ALLOW" // Name for recipe component permitting fake PSFs
    14 
    15 // pmPCMData : PSF Convolved Model data storage structure
    16 typedef struct {
    17     psImage *model;
    18     psArray *dmodels;
    19     psImage *modelConv;
    20     psArray *dmodelsConv;
    21 } pmPCMData;
    2214
    2315// top-level psphot functions
     
    114106bool            psphotExtendedSourceFits (pmConfig *config, const pmFPAview *view, const char *filerule);
    115107bool            psphotExtendedSourceFitsReadout (pmConfig *config, const pmFPAview *view, const char *filerule, int index, psMetadata *recipe);
     108bool            psphotExtendedSourceFits_Threaded (psThreadJob *job);
    116109
    117110bool            psphotApResid (pmConfig *config, const pmFPAview *view, const char *filerule);
     
    188181
    189182// functions to set the correct source pixels
    190 bool            psphotInitRadiusPSF(const psMetadata *recipe, const psMetadata *analysis, const pmModelType type);
     183bool            psphotInitRadiusPSF (psMetadata *recipe, pmReadout *readout);
     184bool            psphotInitRadiusEXT (psMetadata *recipe, pmReadout *readout);
    191185
    192186bool            psphotCheckRadiusPSF (pmReadout *readout, pmSource *source, pmModel *model, psImageMaskType markVal);
    193187bool            psphotCheckRadiusPSFBlend (pmReadout *readout, pmSource *source, pmModel *model, psImageMaskType markVal, float dR);
    194 bool            psphotInitRadiusEXT (psMetadata *recipe, pmModelType type);
    195 bool            psphotCheckRadiusEXT (pmReadout *readout, pmSource *source, pmModel *model, psImageMaskType markVal);
    196 float           psphotSetRadiusEXT (pmReadout *readout, pmSource *source, psImageMaskType markVal);
     188bool            psphotSetRadiusFootprint (float *radius, pmReadout *readout, pmSource *source, psImageMaskType markVal, float factor);
     189bool            psphotSetRadiusModel (pmModel *model, pmReadout *readout, pmSource *source, psImageMaskType markVal, bool deep);
    197190
    198191bool            psphotDumpMoments (psMetadata *recipe, psArray *sources);
     
    210203//  functions to support the source fitting process
    211204bool            psphotInitLimitsPSF (psMetadata *recipe, pmReadout *readout);
    212 bool            psphotInitLimitsEXT (psMetadata *recipe);
    213 bool            psphotFitBlend (pmReadout *readout, pmSource *source, pmPSF *psf, psImageMaskType maskVal, psImageMaskType markVal);
    214 bool            psphotFitBlob (pmReadout *readout, pmSource *source, psArray *sources, pmPSF *psf, psImageMaskType maskVal, psImageMaskType markVal);
    215 bool            psphotFitPSF (pmReadout *readout, pmSource *source, pmPSF *psf, psImageMaskType maskVal, psImageMaskType markVal);
    216 pmModel        *psphotFitEXT (pmReadout *readout, pmSource *source, pmModelType modelType, psImageMaskType maskVal, psImageMaskType markVal);
    217 psArray        *psphotFitDBL (pmReadout *readout, pmSource *source, psImageMaskType maskVal, psImageMaskType markVal);
     205bool            psphotInitLimitsEXT (psMetadata *recipe, pmReadout *readout);
     206bool            psphotFitBlend (pmReadout *readout, pmSource *source, pmPSF *psf, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal);
     207bool            psphotFitBlob (pmReadout *readout, pmSource *source, psArray *sources, pmPSF *psf, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal);
     208bool            psphotFitPSF (pmReadout *readout, pmSource *source, pmPSF *psf, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal);
     209pmModel        *psphotFitEXT (pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, pmModelType modelType, psImageMaskType maskVal, psImageMaskType markVal);
     210psArray        *psphotFitDBL (pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal);
    218211
    219212// functions to support simultaneous multi-source fitting
     
    252245bool            psphotVisualShowBackground (pmConfig *config, const pmFPAview *view, pmReadout *readout);
    253246bool            psphotVisualShowSignificance (psImage *image, float min, float max);
     247bool            psphotVisualShowLogSignificance (psImage *image, float min, float max);
    254248bool            psphotVisualShowPeaks (pmDetections *detections);
    255249bool            psphotVisualShowFootprints (pmDetections *detections);
     
    292286bool psphotRadialBins (psMetadata *recipe, pmSource *source, float radiusMax, float skynoise);
    293287
    294 // structures & functions to support psf-convolved model fitting
    295 
    296 // psf-convolved model fitting
    297 bool psphotModelWithPSF_LMM (
    298     psMinimization *min,
    299     psImage *covar,
    300     psVector *params,
    301     psMinConstraint *constraint,
    302     pmSource *source,
    303     const psKernel *psf,
    304     psMinimizeLMChi2Func func);
    305 
    306 psF32 psphotModelWithPSF_SetABX(
    307     psImage  *alpha,
    308     psVector *beta,
    309     const psVector *params,
    310     const psVector *paramMask,
    311     pmPCMData *pcm,
    312     const pmSource *source,
    313     const psKernel *psf,
    314     psMinimizeLMChi2Func func);
    315 
    316 pmPCMData *pmPCMDataAlloc (
    317     const psVector *params,
    318     const psVector *paramMask,
    319     pmSource *source);
    320 
    321 psImage *pmPCMDataSaveImage (pmPCMData *pcm);
    322 
    323288int psphotKapaOpen (void);
    324289bool psphotKapaClose (void);
     
    364329
    365330bool psphotFitSourcesLinearStack (pmConfig *config, psArray *objects, bool final);
    366 int pmPhotObjSortBySN (const void **a, const void **b);
    367 int pmPhotObjSortByX (const void **a, const void **b);
    368331
    369332typedef enum {
     
    462425bool psphotStackObjectsUnifyPosition (psArray *objects);
    463426
     427bool psphotFitSersicIndex (pmModel *model, pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal);
     428
     429bool psphotFitSersicIndexPCM (pmPCMdata *pcm, pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal, int psfSize);
     430pmModel *psphotFitPCM (pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, pmModelType modelType, psImageMaskType maskVal, psImageMaskType markVal, int psfSize);
     431
    464432#endif
  • trunk/psphot/src/psphotAddNoise.c

    r28013 r29004  
    3434
    3535    bool status = false;
    36     psEllipseShape oldshape;
    37     psEllipseShape newshape;
    38     psEllipseAxes axes;
    3936
    4037    // find the currently selected readout
     
    8683        if (!(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED)) continue;
    8784
    88         // select appropriate model
    89         pmModel *model = pmSourceGetModel (NULL, source);
    90         if (model == NULL) continue;  // model must be defined
    91 
    92         if (add) {
    93             psTrace ("psphot", 4, "adding noise for object at %f,%f\n", model->params->data.F32[PM_PAR_XPOS], model->params->data.F32[PM_PAR_YPOS]);
    94         } else {
    95             psTrace ("psphot", 4, "remove noise for object at %f,%f\n", model->params->data.F32[PM_PAR_XPOS], model->params->data.F32[PM_PAR_YPOS]);
    96         }
    97 
    98         psF32 *PAR = model->params->data.F32;
    99 
    100         // save original values
    101         float oldI0  = PAR[PM_PAR_I0];
    102         oldshape.sx  = PAR[PM_PAR_SXX];
    103         oldshape.sy  = PAR[PM_PAR_SYY];
    104         oldshape.sxy = PAR[PM_PAR_SXY];
    105 
    106         // XXX can this be done more intelligently?
    107         if (oldI0 == 0.0) continue;
    108         if (!isfinite(oldI0)) continue;
    109 
    110         // increase size and height of source
    111         axes = psEllipseShapeToAxes (oldshape, 20.0);
    112         axes.major *= SIZE;
    113         axes.minor *= SIZE;
    114         newshape = psEllipseAxesToShape (axes);
    115         PAR[PM_PAR_I0]  = FACTOR*oldI0;
    116         PAR[PM_PAR_SXX] = newshape.sx;
    117         PAR[PM_PAR_SYY] = newshape.sy;
    118         PAR[PM_PAR_SXY] = newshape.sxy;
    119 
    120         // XXX if we use pmSourceOp, the size (and possibly Io) will not be respected
    121         pmSourceOp (source, PM_MODEL_OP_FULL | PM_MODEL_OP_NOISE, add, maskVal, 0, 0);
    122 
    123         // restore original values
    124         PAR[PM_PAR_I0]  = oldI0;
    125         PAR[PM_PAR_SXX] = oldshape.sx;
    126         PAR[PM_PAR_SYY] = oldshape.sy;
    127         PAR[PM_PAR_SXY] = oldshape.sxy;
     85        pmSourceNoiseOp (source, PM_MODEL_OP_FULL | PM_MODEL_OP_NOISE, FACTOR, SIZE, add, maskVal, 0, 0);
    12886    }
    12987    if (add) {
     
    13290        psLogMsg ("psphot.noise", PS_LOG_INFO, "sub noise for %ld objects: %f sec\n", sources->n, psTimerMark ("psphot.noise"));
    13391    }
     92
    13493    return true;
    13594}
  • trunk/psphot/src/psphotApResid.c

    r28524 r29004  
    459459        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", markVal);
    460460
    461         bool status = pmSourceMagnitudes (source, psf, photMode, maskVal);
     461        bool status = pmSourceMagnitudes (source, psf, photMode, maskVal, markVal);
    462462
    463463        // clear the mask bit
  • trunk/psphot/src/psphotArguments.c

    r25985 r29004  
    176176    }
    177177
    178     // visual : interactive display mode
    179     if ((N = psArgumentGet (argc, argv, "-visual"))) {
    180         psArgumentRemove (N, &argc, argv);
    181         pmVisualSetVisual(true);
    182     }
    183 
    184178    // break : used from recipe throughout psphotReadout
    185179    if ((N = psArgumentGet (argc, argv, "-break"))) {
  • trunk/psphot/src/psphotBlendFit.c

    r28405 r29004  
    6565    assert (status && fitIter > 0);
    6666
    67     float fitTol = psMetadataLookupF32 (&status, recipe, "EXT_FIT_TOL"); // Fit tolerance
    68     assert (status && isfinite(fitTol) && fitTol > 0);
     67    float fitMinTol = psMetadataLookupF32 (&status, recipe, "EXT_FIT_MIN_TOL"); // Fit tolerance
     68    assert (status && isfinite(fitMinTol) && fitMinTol > 0);
     69
     70    float fitMaxTol = psMetadataLookupF32 (&status, recipe, "EXT_FIT_MAX_TOL"); // Fit tolerance
     71    assert (status && isfinite(fitMaxTol) && fitMaxTol > 0);
    6972
    7073    bool poisson = psMetadataLookupBool(&status, recipe, "POISSON.ERRORS.PHOT.LMM"); // Poisson errors?
    7174    assert (status);
    7275
     76    float maxChisqDOF = psMetadataLookupF32 (&status, recipe, "EXT_FIT_MAX_CHISQ"); // Fit tolerance
     77
    7378    float skySig = psMetadataLookupF32(&status, recipe, "SKY_SIG");
    7479    assert (status && isfinite(skySig) && skySig > 0);
    7580
    7681    // Define source fitting parameters for extended source fits
    77     pmSourceFitModelInit(fitIter, fitTol, PS_SQR(skySig), poisson);
     82    pmSourceFitOptions *fitOptions = pmSourceFitOptionsAlloc();
     83    fitOptions->nIter         = fitIter;
     84    fitOptions->minTol        = fitMinTol;
     85    fitOptions->maxTol        = fitMaxTol;
     86    fitOptions->maxChisqDOF   = maxChisqDOF;
     87    fitOptions->poissonErrors = poisson;
     88    fitOptions->weight        = PS_SQR(skySig);
     89    fitOptions->mode          = PM_SOURCE_FIT_PSF;
    7890
    7991    psphotInitLimitsPSF (recipe, readout);
    80     psphotInitLimitsEXT (recipe);
    81     psphotInitRadiusPSF (recipe, readout->analysis, psf->type);
     92    psphotInitLimitsEXT (recipe, readout);
     93    psphotInitRadiusPSF (recipe, readout);
    8294
    8395    // starts the timer, sets up the array of fitSets
     
    88100    if (!sources->n) {
    89101        psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping blend");
     102        psFree (fitOptions);
    90103        return true;
    91104    }
     
    112125            psArrayAdd(job->args, 1, psf);
    113126            psArrayAdd(job->args, 1, newSources); // return for new sources
     127            psArrayAdd(job->args, 1, fitOptions); // default fit options
    114128            psFree (newSources);
    115129
     
    121135            if (!psThreadJobAddPending(job)) {
    122136                psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
     137                psFree (fitOptions);
    123138                return NULL;
    124139            }
    125 
    126 # if (0)
    127             {
    128                 int nfit = 0;
    129                 int npsf = 0;
    130                 int next = 0;
    131                 int nfail = 0;
    132                 psArray *newSources = psArrayAllocEmpty(16);
    133 
    134                 if (!psphotBlendFit_Unthreaded (&nfit, &npsf, &next, &nfail, readout, recipe, cells->data[j], psf, newSources)) {
    135                     psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
    136                     return NULL;
    137                 }
    138                 Nfit += nfit;
    139                 Npsf += npsf;
    140                 Next += next;
    141                 Nfail += nfail;
    142 
    143                 // add these back onto sources
    144                 for (int k = 0; k < newSources->n; k++) {
    145                     psArrayAdd (sources, 16, newSources->data[k]);
    146                 }
    147                 psFree (newSources);
    148             }
    149 # endif
    150140        }
    151141
     
    153143        if (!psThreadPoolWait (false)) {
    154144            psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
     145            psFree (fitOptions);
    155146            return NULL;
    156147        }
     
    163154            } else {
    164155                psScalar *scalar = NULL;
    165                 scalar = job->args->data[5];
     156                scalar = job->args->data[6];
    166157                Nfit += scalar->data.S32;
    167                 scalar = job->args->data[6];
     158                scalar = job->args->data[7];
    168159                Npsf += scalar->data.S32;
    169                 scalar = job->args->data[7];
     160                scalar = job->args->data[8];
    170161                Next += scalar->data.S32;
    171                 scalar = job->args->data[8];
     162                scalar = job->args->data[9];
    172163                Nfail += scalar->data.S32;
    173164
     
    186177      psphotSaveImage (NULL, readout->image,  "image.v2.fits");
    187178    }
     179    psFree (fitOptions);
    188180
    189181    psLogMsg ("psphot.psphotBlendFit", PS_LOG_INFO, "fit models: %f sec for %d objects (%d psf, %d ext, %d failed, %ld skipped)\n", psTimerMark ("psphot.fit.nonlinear"), Nfit, Npsf, Next, Nfail, sources->n - Nfit);
     
    204196    psScalar *scalar = NULL;
    205197
    206     pmReadout *readout  = job->args->data[0];
    207     psMetadata *recipe  = job->args->data[1];
    208     psArray *sources    = job->args->data[2];
    209     pmPSF *psf          = job->args->data[3];
    210     psArray *newSources = job->args->data[4];
     198    pmReadout *readout             = job->args->data[0];
     199    psMetadata *recipe             = job->args->data[1];
     200    psArray *sources               = job->args->data[2];
     201    pmPSF *psf                     = job->args->data[3];
     202    psArray *newSources            = job->args->data[4];
     203    pmSourceFitOptions *fitOptions = job->args->data[5];
    211204
    212205    // bit-masks to test for good/bad pixels
     
    269262        Nfit ++;
    270263
     264        if (0) {
     265            psF32 Mxx = source->moments->Mxx;
     266            psF32 Myy = source->moments->Myy;
     267            fprintf (stderr, "1: Mxx: %f, Myy: %f\n", Mxx, Myy);
     268        }
     269
    271270        // try fitting PSFs or extended sources depending on source->mode
    272271        // these functions subtract the resulting fitted source
    273272        if (source->mode & PM_SOURCE_MODE_EXT_LIMIT) {
    274             if (psphotFitBlob (readout, source, newSources, psf, maskVal, markVal)) {
     273            if (psphotFitBlob (readout, source, newSources, psf, fitOptions, maskVal, markVal)) {
    275274                source->type = PM_SOURCE_TYPE_EXTENDED;
    276275                psTrace ("psphot", 5, "source at %7.1f, %7.1f is ext", source->peak->xf, source->peak->yf);
     
    280279            }
    281280        } else {
    282             if (psphotFitBlend (readout, source, psf, maskVal, markVal)) {
     281            if (psphotFitBlend (readout, source, psf, fitOptions, maskVal, markVal)) {
    283282                source->type = PM_SOURCE_TYPE_STAR;
    284283                psTrace ("psphot", 5, "source at %7.1f, %7.1f is psf", source->peak->xf, source->peak->yf);
     
    289288        }
    290289
     290        if (0) {
     291            psF32 Mxx = source->moments->Mxx;
     292            psF32 Myy = source->moments->Myy;
     293            fprintf (stderr, "2: Mxx: %f, Myy: %f\n", Mxx, Myy);
     294        }
     295
    291296        psTrace ("psphot", 5, "source at %7.1f, %7.1f failed", source->peak->xf, source->peak->yf);
    292297        Nfail ++;
     
    298303
    299304    // change the value of a scalar on the array (wrap this and put it in psArray.h)
    300     scalar = job->args->data[5];
     305    scalar = job->args->data[6];
    301306    scalar->data.S32 = Nfit;
    302307
    303     scalar = job->args->data[6];
     308    scalar = job->args->data[7];
    304309    scalar->data.S32 = Npsf;
    305310
    306     scalar = job->args->data[7];
     311    scalar = job->args->data[8];
    307312    scalar->data.S32 = Next;
    308313
    309     scalar = job->args->data[8];
     314    scalar = job->args->data[9];
    310315    scalar->data.S32 = Nfail;
    311316
  • trunk/psphot/src/psphotChoosePSF.c

    r28013 r29004  
    7474
    7575    // structure to store user options defining the psf
    76     pmPSFOptions *options = pmPSFOptionsAlloc ();
     76    pmPSFOptions *options = pmPSFOptionsAlloc();
    7777
    7878    // load user options from the recipe. no need to check existence -- they are
     
    138138        return false;
    139139    }
    140     float fitTol = psMetadataLookupF32 (&status, recipe, "PSF_FIT_TOL"); // Fit tolerance
    141     if (!status || !isfinite(fitTol) || fitTol <= 0) {
    142         psError(PS_ERR_BAD_PARAMETER_VALUE, true, "PSF_FIT_TOL is not positive");
    143         return false;
    144     }
    145     pmSourceFitModelInit(fitIter, fitTol, PS_SQR(SKY_SIG), options->poissonErrorsPhotLMM);
    146 
     140    float fitMinTol = psMetadataLookupF32 (&status, recipe, "PSF_FIT_MIN_TOL"); // Fit tolerance
     141    if (!status || !isfinite(fitMinTol) || fitMinTol <= 0) {
     142        fitMinTol = psMetadataLookupF32 (&status, recipe, "PSF_FIT_TOL"); // Fit tolerance
     143        if (!status || !isfinite(fitMinTol) || fitMinTol <= 0) {
     144            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "PSF_FIT_MIN_TOL (and PSF_FIT_TOL) not defined or positive");
     145            return false;
     146        }
     147    }
     148    float fitMaxTol = psMetadataLookupF32 (&status, recipe, "PSF_FIT_MAX_TOL"); // Fit tolerance
     149    if (!status || !isfinite(fitMaxTol) || fitMaxTol <= 0) {
     150        fitMaxTol = 1.0;
     151    }
     152    float maxChisqDOF = psMetadataLookupF32 (&status, recipe, "PSF_FIT_MAX_CHISQ"); // Fit tolerance
     153
     154    // options which modify the behavior of the model fitting
     155    options->fitOptions                = pmSourceFitOptionsAlloc();
     156    options->fitOptions->nIter         = fitIter;
     157    options->fitOptions->minTol        = fitMinTol;
     158    options->fitOptions->maxTol        = fitMaxTol;
     159    options->fitOptions->maxChisqDOF   = maxChisqDOF;
     160    options->fitOptions->poissonErrors = options->poissonErrorsPhotLMM;
     161    options->fitOptions->weight        = PS_SQR(SKY_SIG);
     162    options->fitOptions->mode          = PM_SOURCE_FIT_PSF;
     163   
    147164    psArray *stars = psArrayAllocEmpty (sources->n);
    148165
     
    227244
    228245    // try each model option listed in config
     246    // pmPSFtryModel makes a local copy of the sources -- those points are not the same as those for 'sources'
    229247    for (int i = 0; i < modelNames->n; i++) {
    230248        char *modelName = modelNames->data[i];
     
    304322
    305323    // unset the PSFSTAR flag for stars not used for PSF model
     324    // XXX a more efficient way of achieving this would be to record a pair of arrays
     325    // of the source index and the source id for the psf stars.  but that would require we do
     326    // not re-sort the source list in the meanwhile
     327    int nDrop = 0;
    306328    for (int i = 0; i < try->sources->n; i++) {
    307329        pmSource *source = try->sources->data[i];
    308330        if (try->mask->data.PS_TYPE_VECTOR_MASK_DATA[i]) {
    309             source->mode &= ~PM_SOURCE_MODE_PSFSTAR;
    310         }
    311     }
     331            // need to find this source in the original list (these are copies, not pointers)
     332            for (int j = 0; j < sources->n; j++) {
     333                pmSource *realSource = sources->data[j];
     334                if (realSource->id != source->id) continue;
     335                realSource->mode &= ~PM_SOURCE_MODE_PSFSTAR;
     336                source->mode &= ~PM_SOURCE_MODE_PSFSTAR;
     337                nDrop ++;
     338                break;
     339            }
     340        }
     341    }
     342    // fprintf (stderr, "drop %d stars as PSF stars\n", nDrop);
     343
     344    // XXX is this working?
     345    // int N1 = 0;
     346    // for (int i = 0; i < try->sources->n; i++) {
     347    //     pmSource *source = try->sources->data[i];
     348    //  fprintf (stderr, "%llx : %d\n", (long long int) source, (source->mode & PM_SOURCE_MODE_PSFSTAR));
     349    //  if (source->mode & PM_SOURCE_MODE_PSFSTAR) {
     350    //      N1 ++;
     351    //     }
     352    // }
     353    // int N2 = 0;
     354    // for (int i = 0; i < sources->n; i++) {
     355    //     pmSource *source = sources->data[i];
     356    //  fprintf (stderr, "%llx : %d\n", (long long int) source, (source->mode & PM_SOURCE_MODE_PSFSTAR));
     357    //  if (source->mode & PM_SOURCE_MODE_PSFSTAR) {
     358    //      N2 ++;
     359    //     }
     360    // }
     361    // fprintf (stderr, "N1: %d, N2: %d\n", N1, N2);
    312362
    313363    // build a PSF residual image
  • trunk/psphot/src/psphotEllipticalContour.c

    r27819 r29004  
    8282    params->data.F32[PAR_RMIN]    = Rmin;
    8383
    84     psMinimization *myMin = psMinimizationAlloc (25, 0.001);
     84    psMinimization *myMin = psMinimizationAlloc (25, 0.01, 1.00);
    8585    psImage *covar = psImageAlloc (params->n, params->n, PS_TYPE_F32);
    8686   
  • trunk/psphot/src/psphotExtendedSourceAnalysis.c

    r28013 r29004  
    157157        }
    158158
    159 # if (0)
    160         // Isophotal Mags
    161         if (doIsophotal) {
    162             if (!psphotIsophotal (source, recipe, maskVal)) {
    163                 psTrace ("psphot", 5, "failed to measure isophotal mags for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
    164             } else {
    165                 psTrace ("psphot", 5, "measured isophotal mags for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
    166                 Nisophot ++;
    167                 source->mode |= PM_SOURCE_MODE_EXTENDED_STATS;
    168             }
    169         }
    170         // Kron Mags
    171         if (doKron) {
    172             if (!psphotKron (source, recipe, maskVal)) {
    173                 psTrace ("psphot", 5, "failed to measure kron mags for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
    174             } else {
    175                 psTrace ("psphot", 5, "measure kron mags for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
    176                 Nkron ++;
    177                 source->mode |= PM_SOURCE_MODE_EXTENDED_STATS;
    178             }
    179         }
    180 # endif
    181 
    182159        // re-subtract the object, leave local sky
    183160        pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
  • trunk/psphot/src/psphotExtendedSourceFits.c

    r28013 r29004  
    3131// non-linear model fitting for extended sources
    3232bool psphotExtendedSourceFitsReadout (pmConfig *config, const pmFPAview *view, const char *filerule, int index, psMetadata *recipe) {
     33
     34    bool status;
     35    int Next = 0;
     36    int Nconvolve = 0;
     37    int NconvolvePass = 0;
     38    int Nplain = 0;
     39    int NplainPass = 0;
     40
     41    psTimerStart ("psphot.extended");
     42
     43    // find the currently selected readout
     44    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filerule, index); // File of interest
     45    psAssert (file, "missing file?");
     46
     47    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     48    psAssert (readout, "missing readout?");
     49
     50    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     51    psAssert (detections, "missing detections?");
     52
     53    psArray *sources = detections->allSources;
     54    psAssert (sources, "missing sources?");
     55
     56    if (!sources->n) {
     57        psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping source size");
     58        return true;
     59    }
     60
     61    // determine the number of allowed threads
     62    int nThreads = psMetadataLookupS32(&status, config->arguments, "NTHREADS"); // Number of threads
     63    if (!status) {
     64        nThreads = 0;
     65    }
     66
     67    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
     68    psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
     69    assert (maskVal);
     70
     71    psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT"); // Mask value for bad pixels
     72    assert (markVal);
     73
     74    // maskVal is used to test for rejected pixels, and must include markVal
     75    maskVal |= markVal;
     76
     77    // select the collection of desired models
     78    psMetadata *models = psMetadataLookupMetadata (&status, recipe, "EXTENDED_SOURCE_MODELS");
     79    if (!status) {
     80        psWarning ("extended source model fits requested but model model is missing (EXTENDED_SOURCE_MODELS)\n");
     81        return true;
     82    }
     83    if (models->list->n == 0) {
     84        psWarning ("extended source model fits requested but no models are specified\n");
     85        return true;
     86    }
     87
     88    // validate the model entries
     89    psMetadataIterator *iter = psMetadataIteratorAlloc (models, PS_LIST_HEAD, NULL);
     90    psMetadataItem *item = NULL;
     91    while ((item = psMetadataGetAndIncrement (iter)) != NULL) {
     92
     93      if (item->type != PS_DATA_METADATA) {
     94        psAbort ("Invalid type for EXTENDED_SOURCE_MODEL entry %s, not a metadata folder", item->name);
     95        // XXX we could cull the bad entries or build a validated model folder
     96      }
     97
     98      psMetadata *model = (psMetadata *) item->data.md;
     99
     100      // check on the model type
     101      char *modelName = psMetadataLookupStr (&status, model, "MODEL");
     102      int modelType = pmModelClassGetType (modelName);
     103      if (modelType < 0) {
     104        psAbort ("Unknown model class for EXTENDED_SOURCE_MODEL entry %s: %s", item->name, modelName);
     105      }
     106      psMetadataAddS32 (model, PS_LIST_TAIL, "MODEL_TYPE", PS_META_REPLACE, "", modelType);
     107
     108      // check on the SNLIM, set a float value
     109      char *SNword = psMetadataLookupStr (&status, model, "SNLIM");
     110      if (!status) {
     111        psAbort("SNLIM not defined for extended source model %s\n", item->name);
     112      }
     113      float SNlim = atof (SNword);
     114      psMetadataAddF32 (model, PS_LIST_TAIL, "SNLIM_VALUE", PS_META_REPLACE, "", SNlim);
     115
     116      // check on the PSF-Convolution status
     117      char *convolvedWord = psMetadataLookupStr (&status, model, "PSF_CONVOLVED");
     118      if (!status || (strcasecmp (convolvedWord, "true") && strcasecmp (convolvedWord, "false"))) {
     119        psAbort ("PSF_CONVOLVED entry invalid or missing for EXTENDED_SOURCE_MODEL entry %s", item->name);
     120      }
     121      bool convolved = !strcasecmp (convolvedWord, "true");
     122      psMetadataAddBool (model, PS_LIST_TAIL, "PSF_CONVOLVED_VALUE", PS_META_REPLACE, "", convolved);
     123    }
     124    psFree (iter);
     125
     126    // option to limit analysis to a specific region
     127    char *region = psMetadataLookupStr (&status, recipe, "ANALYSIS_REGION");
     128    psRegion *AnalysisRegion = psRegionAlloc(0,0,0,0);
     129    *AnalysisRegion = psRegionForImage(readout->image, psRegionFromString (region));
     130    if (psRegionIsNaN (*AnalysisRegion)) psAbort("analysis region mis-defined");
     131
     132    // what fraction of the PSF is used? (radius in pixels : 2 -> 5x5 box)
     133    int psfSize = psMetadataLookupS32 (&status, recipe, "PCM_BOX_SIZE");
     134    assert (status);
     135
     136    // source analysis is done in S/N order (brightest first)
     137    sources = psArraySort (sources, pmSourceSortBySN);
     138
     139    // choose Cx, Cy (see psphotThreadTools.c for overview of the concepts)
     140    int Cx = 1, Cy = 1;
     141    psphotChooseCellSizes (&Cx, &Cy, readout, nThreads);
     142
     143    psArray *cellGroups = psphotAssignSources (Cx, Cy, sources);
     144
     145    for (int i = 0; i < cellGroups->n; i++) {
     146
     147        psArray *cells = cellGroups->data[i];
     148
     149        for (int j = 0; j < cells->n; j++) {
     150
     151            // allocate a job -- if threads are not defined, this just runs the job
     152            psThreadJob *job = psThreadJobAlloc ("PSPHOT_EXTENDED_FIT");
     153
     154            psArrayAdd(job->args, 1, readout);
     155            psArrayAdd(job->args, 1, cells->data[j]); // sources
     156            psArrayAdd(job->args, 1, models);
     157            psArrayAdd(job->args, 1, AnalysisRegion); // XXX make a pointer
     158
     159            PS_ARRAY_ADD_SCALAR(job->args, psfSize, PS_TYPE_S32);
     160            PS_ARRAY_ADD_SCALAR(job->args, maskVal, PS_TYPE_IMAGE_MASK);
     161            PS_ARRAY_ADD_SCALAR(job->args, markVal, PS_TYPE_IMAGE_MASK);
     162
     163            PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Next
     164            PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nconvolve
     165            PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for NconvolvePass
     166            PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nplain
     167            PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for NplainPass
     168
     169            if (!psThreadJobAddPending(job)) {
     170                psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
     171                psFree(AnalysisRegion);
     172                return false;
     173            }
     174        }
     175
     176        // wait for the threads to finish and manage results
     177        if (!psThreadPoolWait (false)) {
     178            psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
     179            psFree(AnalysisRegion);
     180            return false;
     181        }
     182
     183        // we have only supplied one type of job, so we can assume the types here
     184        psThreadJob *job = NULL;
     185        while ((job = psThreadJobGetDone()) != NULL) {
     186            if (job->args->n < 1) {
     187                fprintf (stderr, "error with job\n");
     188            } else {
     189                psScalar *scalar = NULL;
     190                scalar = job->args->data[7];
     191                Next += scalar->data.S32;
     192                scalar = job->args->data[8];
     193                Nconvolve += scalar->data.S32;
     194                scalar = job->args->data[9];
     195                NconvolvePass += scalar->data.S32;
     196                scalar = job->args->data[10];
     197                Nplain += scalar->data.S32;
     198                scalar = job->args->data[11];
     199                NplainPass += scalar->data.S32;
     200            }
     201            psFree(job);
     202            }
     203    }
     204    psFree (cellGroups);
     205    psFree(AnalysisRegion);
     206
     207    psLogMsg ("psphot", PS_LOG_INFO, "extended source analysis: %f sec for %d objects\n", psTimerMark ("psphot.extended"), Next);
     208    psLogMsg ("psphot", PS_LOG_INFO, "  %d convolved models (%d passed)\n", Nconvolve, NconvolvePass);
     209    psLogMsg ("psphot", PS_LOG_INFO, "  %d plain models (%d passed)\n", Nplain, NplainPass);
     210    return true;
     211}
     212
     213// non-linear model fitting for extended sources
     214bool psphotExtendedSourceFits_Threaded (psThreadJob *job) {
    33215
    34216    bool status;
     
    39221    int NplainPass = 0;
    40222    bool savePics = false;
    41 
    42     // find the currently selected readout
    43     pmFPAfile *file = pmFPAfileSelectSingle(config->files, filerule, index); // File of interest
    44     psAssert (file, "missing file?");
    45 
    46     pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
    47     psAssert (readout, "missing readout?");
    48 
    49     pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
    50     psAssert (detections, "missing detections?");
    51 
    52     psArray *sources = detections->allSources;
    53     psAssert (sources, "missing sources?");
    54 
    55     if (!sources->n) {
    56         psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping source size");
    57         return true;
    58     }
    59 
    60     // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
    61     psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
    62     assert (maskVal);
    63 
    64     psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT"); // Mask value for bad pixels
    65     assert (markVal);
    66 
    67     // maskVal is used to test for rejected pixels, and must include markVal
    68     maskVal |= markVal;
    69 
    70     // select the collection of desired models
    71     psMetadata *models = psMetadataLookupMetadata (&status, recipe, "EXTENDED_SOURCE_MODELS");
    72     if (!status) {
    73         psWarning ("extended source model fits requested but model model is missing (EXTENDED_SOURCE_MODELS)\n");
    74         return true;
    75     }
    76     if (models->list->n == 0) {
    77         psWarning ("extended source model fits requested but no models are specified\n");
    78         return true;
    79     }
    80 
    81     // validate the model entries
    82     psMetadataIterator *iter = psMetadataIteratorAlloc (models, PS_LIST_HEAD, NULL);
    83     psMetadataItem *item = NULL;
    84     while ((item = psMetadataGetAndIncrement (iter)) != NULL) {
    85 
    86       if (item->type != PS_DATA_METADATA) {
    87         psAbort ("Invalid type for EXTENDED_SOURCE_MODEL entry %s, not a metadata folder", item->name);
    88         // XXX we could cull the bad entries or build a validated model folder
    89       }
    90 
    91       psMetadata *model = (psMetadata *) item->data.md;
    92 
    93       // check on the model type
    94       char *modelName = psMetadataLookupStr (&status, model, "MODEL");
    95       int modelType = pmModelClassGetType (modelName);
    96       if (modelType < 0) {
    97         psAbort ("Unknown model class for EXTENDED_SOURCE_MODEL entry %s: %s", item->name, modelName);
    98       }
    99       psMetadataAddS32 (model, PS_LIST_TAIL, "MODEL_TYPE", PS_META_REPLACE, "", modelType);
    100 
    101       // check on the SNLIM, set a float value
    102       char *SNword = psMetadataLookupStr (&status, model, "SNLIM");
    103       if (!status) {
    104         psAbort("SNLIM not defined for extended source model %s\n", item->name);
    105       }
    106       float SNlim = atof (SNword);
    107       psMetadataAddF32 (model, PS_LIST_TAIL, "SNLIM_VALUE", PS_META_REPLACE, "", SNlim);
    108 
    109       // check on the PSF-Convolution status
    110       char *convolvedWord = psMetadataLookupStr (&status, model, "PSF_CONVOLVED");
    111       if (!status || (strcasecmp (convolvedWord, "true") && strcasecmp (convolvedWord, "false"))) {
    112         psAbort ("PSF_CONVOLVED entry invalid or missing for EXTENDED_SOURCE_MODEL entry %s", item->name);
    113       }
    114       bool convolved = !strcasecmp (convolvedWord, "true");
    115       psMetadataAddBool (model, PS_LIST_TAIL, "PSF_CONVOLVED_VALUE", PS_META_REPLACE, "", convolved);
    116     }
    117     psFree (iter);
    118 
    119     // option to limit analysis to a specific region
    120     char *region = psMetadataLookupStr (&status, recipe, "ANALYSIS_REGION");
    121     psRegion AnalysisRegion = psRegionForImage (readout->image, psRegionFromString (region));
    122     if (psRegionIsNaN (AnalysisRegion)) psAbort("analysis region mis-defined");
    123 
    124     // what fraction of the PSF is used? (radius in pixels : 2 -> 5x5 box)
    125     int psfSize = psMetadataLookupS32 (&status, recipe, "PCM_BOX_SIZE");
    126     assert (status);
    127 
    128     // source analysis is done in S/N order (brightest first)
    129     sources = psArraySort (sources, pmSourceSortBySN);
     223    float radius;
     224    psScalar *scalar = NULL;
     225
     226    // arguments: readout, sources, models, region, psfSize, maskVal, markVal
     227    pmReadout *readout      = job->args->data[0];
     228    psArray *sources        = job->args->data[1];
     229    psMetadata *models      = job->args->data[2];
     230    psRegion *region        = job->args->data[3];
     231    int psfSize             = PS_SCALAR_VALUE(job->args->data[4],PS_TYPE_IMAGE_MASK_DATA);
     232    psImageMaskType maskVal = PS_SCALAR_VALUE(job->args->data[5],PS_TYPE_IMAGE_MASK_DATA);
     233    psImageMaskType markVal = PS_SCALAR_VALUE(job->args->data[6],PS_TYPE_IMAGE_MASK_DATA);
     234
     235    // Define source fitting parameters for extended source fits
     236    pmSourceFitOptions *fitOptions = pmSourceFitOptionsAlloc();
     237    fitOptions->mode          = PM_SOURCE_FIT_EXT;
     238    // XXX for now, use the defaults for the rest:
     239    // fitOptions->nIter         = fitIter;
     240    // fitOptions->tol           = fitTol;
     241    // fitOptions->poissonErrors = poisson;
     242    // fitOptions->weight        = PS_SQR(skySig);
    130243
    131244    // choose the sources of interest
     
    140253
    141254        // XXX this should use peak?
    142         if (source->peak->x < AnalysisRegion.x0) continue;
    143         if (source->peak->y < AnalysisRegion.y0) continue;
    144         if (source->peak->x > AnalysisRegion.x1) continue;
    145         if (source->peak->y > AnalysisRegion.y1) continue;
     255        if (source->peak->x < region->x0) continue;
     256        if (source->peak->y < region->y0) continue;
     257        if (source->peak->x > region->x1) continue;
     258        if (source->peak->y > region->y1) continue;
    146259
    147260        // if model is NULL, we don't have a starting guess
     
    154267        }
    155268        Next ++;
     269
     270        // set the radius based on the footprint (also sets the mask pixels)
     271        if (!psphotSetRadiusFootprint(&radius, readout, source, markVal, 1.0)) {
     272            psFree (fitOptions)
     273            return false;
     274        }
     275
     276        // XXX note that this changes the source moments that are published...
     277        // recalculate the source moments using the larger extended-source moments radius
     278        // at this stage, skip Gaussian windowing, and do not clip pixels by S/N
     279        // this uses the footprint to judge both radius and aperture?
     280        // XXX save the psf-based moments for output
     281        if (!pmSourceMoments (source, radius, 0.0, 0.0, maskVal)) {
     282            // subtract the best fit from the object, leave local sky
     283            pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
     284            // XXX raise an error of some kind
     285            continue;
     286        }
    156287
    157288        // save the modelFlux here in case we need to subtract it (for failure)
     
    201332          pmModel *modelFit = NULL;
    202333          if (convolved) {
    203               modelFit = psphotPSFConvModel (readout, source, modelType, maskVal, markVal, psfSize);
     334              modelFit = psphotFitPCM (readout, source, fitOptions, modelType, maskVal, markVal, psfSize);
    204335              if (!modelFit) {
    205336                  psTrace ("psphot", 5, "failed to fit psf-conv model for object at %f, %f", source->moments->Mx, source->moments->My);
     
    215346              psFree (source->modelFlux);
    216347              source->modelFlux = NULL;
    217               modelFit = psphotFitEXT (readout, source, modelType, maskVal, markVal);
     348              modelFit = psphotFitEXT (readout, source, fitOptions, modelType, maskVal, markVal);
    218349              if (!modelFit) {
    219350                  psTrace ("psphot", 5, "failed to fit plain model for object at %f, %f", source->moments->Mx, source->moments->My);
     
    233364
    234365          // test for fit quality / result
     366          modelFit->fitRadius = radius;
    235367          psArrayAdd (source->modelFits, 4, modelFit);
    236368
     
    311443        }
    312444    }
    313 
    314     psLogMsg ("psphot", PS_LOG_INFO, "extended source analysis: %f sec for %d objects\n", psTimerMark ("psphot"), Next);
    315     psLogMsg ("psphot", PS_LOG_INFO, "  %d convolved models (%d passed)\n", Nconvolve, NconvolvePass);
    316     psLogMsg ("psphot", PS_LOG_INFO, "  %d plain models (%d passed)\n", Nplain, NplainPass);
     445    psFree (fitOptions);
     446
     447    // change the value of a scalar on the array (wrap this and put it in psArray.h)
     448    scalar = job->args->data[7];
     449    scalar->data.S32 = Next;
     450
     451    scalar = job->args->data[8];
     452    scalar->data.S32 = Nconvolve;
     453
     454    scalar = job->args->data[9];
     455    scalar->data.S32 = NconvolvePass;
     456
     457    scalar = job->args->data[10];
     458    scalar->data.S32 = Nplain;
     459
     460    scalar = job->args->data[11];
     461    scalar->data.S32 = NplainPass;
     462
    317463    return true;
    318464}
  • trunk/psphot/src/psphotFindDetections.c

    r28013 r29004  
    9090    psphotVisualShowSignificance (significance, -1.0, PS_SQR(3.0*NSIGMA_PEAK));
    9191
    92     // XXX getting some strange results from significance image
    93     if (0) {
    94         psImage *lsig = (psImage *) psUnaryOp (NULL, significance, "log");
    95         psphotVisualShowSignificance (lsig, 0.0, 4.0);
    96         psFree (lsig);
    97     }   
     92    // display the log significance image
     93    psphotVisualShowLogSignificance (significance, 0.0, 4.5);
    9894
    9995    // detect the peaks in the significance image
  • trunk/psphot/src/psphotFitSet.c

    r21183 r29004  
    2424    }
    2525
     26    // Define source fitting parameters for extended source fits
     27    pmSourceFitOptions *fitOptions = pmSourceFitOptionsAlloc();
     28    fitOptions->mode          = PM_SOURCE_FIT_EXT;
     29    // XXX for now, use the defaults for the rest:
     30    // fitOptions->nIter         = fitIter;
     31    // fitOptions->tol           = fitTol;
     32    // fitOptions->poissonErrors = poisson;
     33    // fitOptions->weight        = PS_SQR(skySig);
     34
    2635    // XXX pmSourceFitSet must cache the modelFlux?
    27     pmSourceFitSet (source, modelSet, mode, maskVal);
     36    pmSourceFitSet (source, modelSet, fitOptions, maskVal);
    2837
    2938    // write out positive object
  • trunk/psphot/src/psphotFitSourcesLinear.c

    r28426 r29004  
    100100    if (!status) {
    101101        SKY_FIT_LINEAR = false;
     102    }
     103   
     104    float MIN_VALID_FLUX = psMetadataLookupF32(&status, recipe, "PSF_FIT_MIN_VALID_FLUX");
     105    if (!status) {
     106        MIN_VALID_FLUX = 1e-8;
     107    }
     108    float MAX_VALID_FLUX = psMetadataLookupF32(&status, recipe, "PSF_FIT_MAX_VALID_FLUX");
     109    if (!status) {
     110        MAX_VALID_FLUX = 1e+8;
    102111    }
    103112
     
    228237
    229238    psSparseConstraint constraint;
    230     constraint.paramMin   = 0.0;
    231     constraint.paramMax   = 1e8;
    232     constraint.paramDelta = 1e8;
     239    constraint.paramMin   = MIN_VALID_FLUX;
     240    constraint.paramMax   = MAX_VALID_FLUX;
     241    constraint.paramDelta = 1e7;
    233242
    234243    // solve for normalization terms (need include local sky?)
  • trunk/psphot/src/psphotFitSourcesLinearStack.c

    r28426 r29004  
    170170    return true;
    171171}
    172 
    173 // sort by X (ascending)
    174 int pmPhotObjSortByX (const void **a, const void **b)
    175 {
    176     pmPhotObj *objA = *(pmPhotObj **)a;
    177     pmPhotObj *objB = *(pmPhotObj **)b;
    178 
    179     psF32 fA = objA->x;
    180     psF32 fB = objB->x;
    181 
    182     psF32 diff = fA - fB;
    183     if (diff > FLT_EPSILON) return (+1);
    184     if (diff < FLT_EPSILON) return (-1);
    185     return (0);
    186 }
  • trunk/psphot/src/psphotGuessModels.c

    r28405 r29004  
    8080
    8181    // setup the PSF fit radius details
    82     psphotInitRadiusPSF (recipe, readout->analysis, psf->type);
     82    psphotInitRadiusPSF (recipe, readout);
    8383
    8484    // choose Cx, Cy (see psphotThreadTools.c for overview of the concepts)
  • trunk/psphot/src/psphotLoadSRCTEXT.c

    r25983 r29004  
    8484            source->peak->yf   = PAR[PM_PAR_YPOS]; // but we know the pixel coordinate
    8585
    86             source->pixWeight = 1.0;
     86            source->pixWeightNotBad = 1.0;
     87            source->pixWeightNotPoor = 1.0;
    8788            source->crNsigma  = 0.0;
    8889            source->extNsigma = 0.0;
  • trunk/psphot/src/psphotMagnitudes.c

    r28405 r29004  
    124124                return false;
    125125            }
    126 
    127 # if (0)
    128                 int nap = 0;
    129                 if (!psphotMagnitudes_Unthreaded (&nap, cells->data[j], psf, binning, backModel, backStdev, photMode, maskVal)) {
    130                     psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
    131                     return false;
    132                 }
    133                 Nap += nap;
    134 # endif
    135126        }
    136127
     
    186177        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", markVal);
    187178
    188         status = pmSourceMagnitudes (source, psf, photMode, maskVal); // maskVal includes markVal
     179        status = pmSourceMagnitudes (source, psf, photMode, maskVal, markVal);
    189180        if (status && isfinite(source->apMag)) Nap ++;
    190181
     
    268259            psArrayAdd(job->args, 1, cells->data[j]); // sources
    269260            PS_ARRAY_ADD_SCALAR(job->args, maskVal,  PS_TYPE_IMAGE_MASK);
     261            PS_ARRAY_ADD_SCALAR(job->args, markVal,  PS_TYPE_IMAGE_MASK);
    270262
    271263            if (!psThreadJobAddPending(job)) {
     
    304296    psArray *sources                = job->args->data[0];
    305297    psImageMaskType maskVal         = PS_SCALAR_VALUE(job->args->data[1],PS_TYPE_IMAGE_MASK_DATA);
     298    psImageMaskType markVal         = PS_SCALAR_VALUE(job->args->data[2],PS_TYPE_IMAGE_MASK_DATA);
    306299
    307300    for (int i = 0; i < sources->n; i++) {
     
    312305        if (model == NULL) {
    313306          psTrace ("psphot", 3, "fail mag : no valid model");
    314           source->pixWeight = NAN;
     307          source->pixWeightNotBad = NAN;
     308          source->pixWeightNotPoor = NAN;
    315309          continue;
    316310        }
    317311
    318         status = pmSourcePixelWeight (&source->pixWeight, model, source->maskObj, maskVal);
     312        status = pmSourcePixelWeight (&source->pixWeightNotBad, &source->pixWeightNotPoor, model, source->maskObj, maskVal, markVal);
    319313        if (!status) {
    320314          psTrace ("psphot", 3, "fail to measure pixel weight");
    321           source->pixWeight = NAN;
     315          source->pixWeightNotBad = NAN;
     316          source->pixWeightNotPoor = NAN;
    322317          continue;
    323318        }
  • trunk/psphot/src/psphotModelWithPSF.c

    r21366 r29004  
    7373
    7474    // iterate until the tolerance is reached, or give up
    75     while ((min->iter < min->maxIter) && ((min->lastDelta > min->tol) || !isfinite(min->lastDelta))) {
     75    while ((min->iter < min->maxIter) && ((min->lastDelta > min->minTol) || !isfinite(min->lastDelta))) {
    7676        psTrace("psphot", 5, "Iteration number %d.  (max iterations is %d).\n", min->iter, min->maxIter);
    77         psTrace("psphot", 5, "Last delta is %f.  Min->tol is %f.\n", min->lastDelta, min->tol);
     77        psTrace("psphot", 5, "Last delta is %f.  Min->minTol is %f.\n", min->lastDelta, min->minTol);
    7878
    7979
     
    166166    psFree(pcm);
    167167
    168     if (min->iter == min->maxIter) {
    169         psTrace("psphot", 3, "---- end (false) ----\n");
    170         return(false);
    171     }
    172 
    173     psTrace("psphot", 3, "---- end (true) ----\n");
    174     return(true);
     168    // if the last improvement was at least as good as maxTol, accept the fit:
     169    if (min->lastDelta <= min->maxTol) {
     170        psTrace("psphot", 6, "---- end (true) ----\n");
     171        return(true);
     172    }
     173    psTrace("psphot", 6, "---- end (false) ----\n");
     174    return(false);
    175175}
    176176
  • trunk/psphot/src/psphotPSFConvModel.c

    r26894 r29004  
    44// save as static values so they may be set externally
    55static psF32 PM_SOURCE_FIT_MODEL_NUM_ITERATIONS = 15;
    6 static psF32 PM_SOURCE_FIT_MODEL_TOLERANCE = 0.1;
     6static psF32 PM_SOURCE_FIT_MODEL_MIN_TOL = 0.1;
     7static psF32 PM_SOURCE_FIT_MODEL_MAX_TOL = 2.0;
    78
    89// input source has both modelPSF and modelEXT.  on successful exit, we set the
    910// modelConv to contain the fitted parameters, and the modelFlux to contain the
    1011// convolved model image.
    11 pmModel *psphotPSFConvModel (pmReadout *readout, pmSource *source, pmModelType modelType, psImageMaskType maskVal, psImageMaskType markVal, int psfSize) {
     12
     13// XXX need to generalize this -- number of fitted parameters must be flexible based on the fitOptions
     14
     15pmModel *psphotPSFConvModel (pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, pmModelType modelType, psImageMaskType maskVal, psImageMaskType markVal, int psfSize) {
    1216   
    1317    // maskVal is used to test for rejected pixels, and must include markVal
     
    9094
    9195    // set up the minimization process
    92     psMinimization *myMin = psMinimizationAlloc (PM_SOURCE_FIT_MODEL_NUM_ITERATIONS, PM_SOURCE_FIT_MODEL_TOLERANCE);
     96    psMinimization *myMin = psMinimizationAlloc (PM_SOURCE_FIT_MODEL_NUM_ITERATIONS, PM_SOURCE_FIT_MODEL_MIN_TOL, PM_SOURCE_FIT_MODEL_MAX_TOL);
    9397
    9498    psImage *covar = psImageAlloc (params->n, params->n, PS_TYPE_F32);
  • trunk/psphot/src/psphotPetrosianVisual.c

    r27819 r29004  
    11# include "psphotInternal.h"
    2 # define FORCE_VISUAL 0
    32
    43// this function displays representative images as the psphot analysis progresses:
     
    5453    Graphdata graphdata;
    5554
    56     // return true;
    57     if (!FORCE_VISUAL && !pmVisualIsVisual()) return true;
     55    if (!pmVisualTestLevel("psphot.petro.byangle", 2)) return true;
    5856
    5957    if (kapa2 == -1) {
     
    10199    Graphdata graphdata;
    102100
    103     // return true;
    104     if (!FORCE_VISUAL && !pmVisualIsVisual()) return true;
     101    if (!pmVisualTestLevel("psphot.petro.radii", 2)) return true;
    105102
    106103    if (kapa == -1) {
     
    173170    KapaSection section;
    174171
    175     if (!FORCE_VISUAL && !pmVisualIsVisual()) return true;
     172    if (!pmVisualTestLevel("psphot.petro.stats", 2)) return true;
    176173
    177174    if (kapa2 == -1) {
     
    311308    Graphdata graphdata;
    312309
    313     if (!FORCE_VISUAL && !pmVisualIsVisual()) return true;
     310    if (!pmVisualTestLevel("psphot.petro.ellipse", 2)) return true;
    314311
    315312    if (kapa == -1) {
  • trunk/psphot/src/psphotRadiusChecks.c

    r28418 r29004  
    88                                        // and a per-object radius is calculated)
    99
    10 bool psphotInitRadiusPSF(const psMetadata *recipe, const psMetadata *analysis, const pmModelType type) {
     10bool psphotInitRadiusPSF(psMetadata *recipe, pmReadout *readout) {
    1111
    1212    bool status = true;
     
    1515    PSF_FIT_PADDING = psMetadataLookupF32(&status, recipe, "PSF_FIT_PADDING");
    1616
    17     PSF_FIT_RADIUS =  psMetadataLookupF32(&status, analysis, "PSF_FIT_RADIUS");
     17    PSF_FIT_RADIUS =  psMetadataLookupF32(&status, readout->analysis, "PSF_FIT_RADIUS");
    1818    if (!status) {
    1919        PSF_FIT_RADIUS = psMetadataLookupF32(&status, recipe, "PSF_FIT_RADIUS");
    2020    }
    2121
    22     PSF_APERTURE =  psMetadataLookupF32(&status, analysis, "PSF_APERTURE");
     22    PSF_APERTURE =  psMetadataLookupF32(&status, readout->analysis, "PSF_APERTURE");
    2323    if (!status) {
    2424        PSF_APERTURE =  psMetadataLookupF32(&status, recipe, "PSF_APERTURE");
     
    2828
    2929    if (PSF_FIT_RADIUS == 0.0) {
    30         float gaussSigma = psMetadataLookupF32(&status, analysis, "MOMENTS_GAUSS_SIGMA");
     30        float gaussSigma = psMetadataLookupF32(&status, readout->analysis, "MOMENTS_GAUSS_SIGMA");
    3131        if (!status) {
    3232            gaussSigma = psMetadataLookupF32(&status, recipe, "MOMENTS_GAUSS_SIGMA");
     
    3737
    3838    if (PSF_APERTURE == 0.0) {
    39         float gaussSigma = psMetadataLookupF32(&status, analysis, "MOMENTS_GAUSS_SIGMA");
     39        float gaussSigma = psMetadataLookupF32(&status, readout->analysis, "MOMENTS_GAUSS_SIGMA");
    4040        if (!status) {
    4141            gaussSigma = psMetadataLookupF32(&status, recipe, "MOMENTS_GAUSS_SIGMA");
     
    122122}
    123123
     124static float EXT_FIT_SKY_SIG;
    124125static float EXT_FIT_NSIGMA;
    125126static float EXT_FIT_PADDING;
    126127static float EXT_FIT_MAX_RADIUS;
    127128
    128 bool psphotInitRadiusEXT (psMetadata *recipe, pmModelType type) {
     129bool psphotInitRadiusEXT (psMetadata *recipe, pmReadout *readout) {
    129130
    130131    bool status;
     
    134135    EXT_FIT_MAX_RADIUS = psMetadataLookupF32 (&status, recipe, "EXT_FIT_MAX_RADIUS");
    135136
     137    float skyMean  = psMetadataLookupF32 (&status, readout->analysis, "SKY_MEAN");
     138    float skyStdev = psMetadataLookupF32 (&status, readout->analysis, "SKY_STDEV");
     139
     140    fprintf (stderr, "sky: %f +/- %f\n", skyMean, skyStdev);
     141
     142    EXT_FIT_SKY_SIG = skyStdev;
     143
    136144    return true;
    137145}
    138146
    139147// call this function whenever you (re)-define the EXT model
    140 float psphotSetRadiusEXT (pmReadout *readout, pmSource *source, psImageMaskType markVal) {
     148bool psphotSetRadiusFootprint (float *radius, pmReadout *readout, pmSource *source, psImageMaskType markVal, float factor) {
    141149
    142150    psAssert (source, "source not defined??");
     
    146154
    147155    // set the radius based on the footprint:
    148     if (!peak->footprint) goto escape;
     156    if (!peak->footprint) return false;
    149157    pmFootprint *footprint = peak->footprint;
    150     if (!footprint->spans) goto escape;
    151     if (footprint->spans->n < 1) goto escape;
     158    if (!footprint->spans) return false;
     159    if (footprint->spans->n < 1) return false;
    152160
    153161    // find the max radius
    154     float radius = 0.0;
     162    float rawRadius = 0.0;
    155163    for (int j = 0; j < footprint->spans->n; j++) {
    156164        pmSpan *span = footprint->spans->data[j];
     
    160168        float dX1 = span->x1 - peak->xf;
    161169
    162         radius = PS_MAX (radius, hypot(dY, dX0));
    163         radius = PS_MAX (radius, hypot(dY, dX1));
    164     }
    165 
    166     radius += EXT_FIT_PADDING;
    167     if (isnan(radius)) psAbort("error in radius");
    168 
    169     radius = PS_MIN (radius, EXT_FIT_MAX_RADIUS);
     170        rawRadius = PS_MAX (rawRadius, hypot(dY, dX0));
     171        rawRadius = PS_MAX (rawRadius, hypot(dY, dX1));
     172    }
     173    if (isnan(rawRadius)) return false;
     174    rawRadius = PS_MIN (factor*rawRadius + EXT_FIT_PADDING, EXT_FIT_MAX_RADIUS);
    170175
    171176    // redefine the pixels if needed
    172     pmSourceRedefinePixels (source, readout, peak->xf, peak->yf, radius);
    173 
    174     // set the mask to flag the excluded pixels
    175     psImageKeepCircle (source->maskObj, peak->xf, peak->yf, radius, "OR", markVal);
    176     return radius;
    177 
    178 escape:
    179     return NAN;
    180     // bool result = psphotCheckRadiusEXT (readout, source, model, markVal);
    181     // return result;
     177    pmSourceRedefinePixels (source, readout, peak->xf, peak->yf, rawRadius);
     178
     179    // set the mask to flag the excluded pixels
     180    psImageKeepCircle (source->maskObj, peak->xf, peak->yf, rawRadius, "OR", markVal);
     181
     182    *radius = rawRadius;
     183    return true;
    182184}
    183185
    184186// alternative EXT radius based on model guess (for use without footprints)
    185 bool psphotCheckRadiusEXT (pmReadout *readout, pmSource *source, pmModel *model, psImageMaskType markVal) {
    186 
    187     psAbort ("do not use this function");
     187bool psphotSetRadiusModel (pmModel *model, pmReadout *readout, pmSource *source, psImageMaskType markVal, bool deep) {
    188188
    189189    psF32 *PAR = model->params->data.F32;
     
    193193
    194194    // set the fit radius based on the object flux limit and the model
    195     float rawRadius = model->modelRadius (model->params, EXT_FIT_NSIGMA*moments->dSky);
    196 
    197     model->fitRadius = rawRadius + EXT_FIT_PADDING;
    198     if (isnan(model->fitRadius)) psAbort("error in radius");
     195    float flux = deep ? EXT_FIT_NSIGMA*EXT_FIT_SKY_SIG : 0.1 * model->params->data.F32[PM_PAR_I0];
     196
     197    float rawRadius = model->modelRadius (model->params, flux);
     198    if (isnan(rawRadius)) return false;
     199
     200    rawRadius = PS_MIN (rawRadius + EXT_FIT_PADDING, EXT_FIT_MAX_RADIUS);
     201    model->fitRadius = rawRadius;
    199202
    200203    // redefine the pixels if needed
    201     bool status = pmSourceRedefinePixels (source, readout, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius);
     204    pmSourceRedefinePixels (source, readout, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius);
    202205
    203206    // set the mask to flag the excluded pixels
    204207    psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius, "OR", markVal);
    205     return status;
    206 }
     208    return true;
     209}
  • trunk/psphot/src/psphotReadout.c

    r28398 r29004  
    5353    }
    5454
    55     // load the psf model, if suppled.  FWHM_X,FWHM_Y,etc are determined and saved on
    56     // readout->analysis XXX this function currently only works with a single PSPHOT.INPUT
     55    // load the psf model, if suppled.  FWHM_MAJ,FWHM_MIN,etc are determined and saved on
     56    // readout->analysis. XXX Note: this function currently only works with a single
     57    // PSPHOT.INPUT
    5758    if (!psphotLoadPSF (config, view)) { // ??? need to supply 2 ?
    5859        psError (PSPHOT_ERR_UNKNOWN, false, "error loading psf model");
  • trunk/psphot/src/psphotSetThreads.c

    r26894 r29004  
    1515    psFree(task);
    1616
    17     task = psThreadTaskAlloc("PSPHOT_PSF_WEIGHTS", 2);
     17    task = psThreadTaskAlloc("PSPHOT_PSF_WEIGHTS", 3);
    1818    task->function = &psphotPSFWeights_Threaded;
    1919    psThreadTaskAdd(task);
     
    3030    psFree(task);
    3131
    32     task = psThreadTaskAlloc("PSPHOT_BLEND_FIT", 9);
     32    task = psThreadTaskAlloc("PSPHOT_BLEND_FIT", 10);
    3333    task->function = &psphotBlendFit_Threaded;
     34    psThreadTaskAdd(task);
     35    psFree(task);
     36
     37    task = psThreadTaskAlloc("PSPHOT_EXTENDED_FIT", 12);
     38    task->function = &psphotExtendedSourceFits_Threaded;
    3439    psThreadTaskAdd(task);
    3540    psFree(task);
  • trunk/psphot/src/psphotSignificanceImage.c

    r28667 r29004  
    9797                smooth_im->data.F32[j][i] = 0.0;
    9898            } else {
    99                 smooth_im->data.F32[j][i] = factor * PS_SQR(value) / smooth_wt->data.F32[j][i];
     99                float v2 = value + PS_SQR(value/1000.0);
     100                smooth_im->data.F32[j][i] = factor * PS_SQR(v2) / smooth_wt->data.F32[j][i];
    100101            }
    101102        }
  • trunk/psphot/src/psphotSourceFits.c

    r26894 r29004  
    22
    33// given a source with an existing modelPSF, attempt a full PSF fit, subtract if successful
    4 // XXX this function does not call pmSourceFitModelInit : fix this?
    54
    65static int NfitPSF = 0;
     
    87static int NfitDBL = 0;
    98static int NfitEXT = 0;
     9static int NfitPCM = 0;
    1010
    1111bool psphotFitInit (int nThreads) {
     
    1818
    1919    psLogMsg ("psphot.pspsf", PS_LOG_INFO, "fitted %5d psf, %5d blend, %5d ext, %5d dbl : %6.2f sec\n",
    20              NfitPSF, NfitBlend, NfitEXT, NfitDBL, psTimerMark ("psphot.fits"));
    21     return true;
    22 }
    23 
    24 bool psphotFitBlend (pmReadout *readout, pmSource *source, pmPSF *psf, psImageMaskType maskVal, psImageMaskType markVal) {
     20              NfitPSF, NfitBlend, NfitEXT, NfitDBL, psTimerMark ("psphot.fits"));
     21    return true;
     22}
     23
     24bool psphotFitBlend (pmReadout *readout, pmSource *source, pmPSF *psf, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal) {
    2525
    2626    float x, y, dR;
     27
     28    pmSourceFitOptions options = *fitOptions;
    2729
    2830    // maskVal is used to test for rejected pixels, and must include markVal
     
    3133    // if this source is not a possible blend, just fit as PSF
    3234    if ((source->blends == NULL) || (source->mode & PM_SOURCE_MODE_SATSTAR)) {
    33         bool status = psphotFitPSF (readout, source, psf, maskVal, markVal);
     35        bool status = psphotFitPSF (readout, source, psf, fitOptions, maskVal, markVal);
    3436        return status;
    3537    }
     
    9193
    9294    // fit PSF model
    93     pmSourceFitSet (source, modelSet, PM_SOURCE_FIT_PSF, maskVal);
     95    options.mode = PM_SOURCE_FIT_PSF;
     96    pmSourceFitSet (source, modelSet, &options, maskVal);
    9497
    9598    // clear the circular mask
     
    154157}
    155158
    156 bool psphotFitPSF (pmReadout *readout, pmSource *source, pmPSF *psf, psImageMaskType maskVal, psImageMaskType markVal) {
     159bool psphotFitPSF (pmReadout *readout, pmSource *source, pmPSF *psf, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal) {
    157160
    158161    double chiTrend;
     162    pmSourceFitOptions options = *fitOptions;
    159163
    160164    // maskVal is used to test for rejected pixels, and must include markVal
     
    171175
    172176    // fit PSF model (set/unset the pixel mask)
    173     pmSourceFitModel (source, PSF, PM_SOURCE_FIT_PSF, maskVal);
     177    options.mode = PM_SOURCE_FIT_PSF;
     178    pmSourceFitModel (source, PSF, &options, maskVal);
    174179
    175180    if (!isfinite(PSF->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
     
    199204}
    200205
     206// save a local, static copy of the EXT model type so we don't have to lookup for each object
    201207static pmModelType modelTypeEXT;
    202208
    203 bool psphotInitLimitsEXT (psMetadata *recipe) {
     209bool psphotInitLimitsEXT (psMetadata *recipe, pmReadout *readout) {
    204210
    205211    bool status;
     
    208214    char *modelNameEXT = psMetadataLookupStr (&status, recipe, "EXT_MODEL");
    209215    modelTypeEXT = pmModelClassGetType (modelNameEXT);
    210     psphotInitRadiusEXT (recipe, modelTypeEXT);
    211 
    212     return true;
    213 }
    214 
    215 bool psphotFitBlob (pmReadout *readout, pmSource *source, psArray *newSources, pmPSF *psf, psImageMaskType maskVal, psImageMaskType markVal) {
    216 
     216
     217    psphotInitRadiusEXT (recipe, readout);
     218
     219    return true;
     220}
     221
     222bool psphotFitBlob (pmReadout *readout, pmSource *source, psArray *newSources, pmPSF *psf, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal) {
     223
     224    float radius;
    217225    bool okEXT, okDBL;
    218226    float chiEXT, chiDBL;
     
    222230    pmModel *EXT = NULL;
    223231    psArray *DBL = NULL;
     232    pmMoments psfMoments;
    224233
    225234    // skip the source if we don't think it is extended
     235    // XXX are these robust, or do we have better info from the source-size analysis??
    226236    if (source->type == PM_SOURCE_TYPE_UNKNOWN) return false;
    227237    if (source->type == PM_SOURCE_TYPE_DEFECT) return false;
     
    229239
    230240    // set the radius based on the footprint (also sets the mask pixels)
    231     float radius = psphotSetRadiusEXT (readout, source, markVal);
     241    if (!psphotSetRadiusFootprint(&radius, readout, source, markVal, 1.0)) return false;
    232242
    233243    // XXX note that this changes the source moments that are published...
     244    // XXX all published moments should use the same measurement
    234245    // recalculate the source moments using the larger extended-source moments radius
    235246    // at this stage, skip Gaussian windowing, and do not clip pixels by S/N
    236247    // this uses the footprint to judge both radius and aperture?
    237     if (!pmSourceMoments (source, radius, 0.0, 0.0, maskVal)) return false;
     248    // XXX save the psf-based moments for output
     249    psfMoments = *source->moments;
     250    if (!pmSourceMoments (source, radius, 0.0, 0.5, maskVal)) {
     251      *source->moments = psfMoments;
     252      return false;
     253    }
    238254
    239255    psTrace ("psphot", 5, "trying blob...\n");
     
    244260    // this temporary source is used as a place-holder by the psphotEval functions below
    245261    tmpSrc = pmSourceAlloc ();
    246 
    247     // XXX need to handle failures better here
    248     EXT = psphotFitEXT (readout, source, modelTypeEXT, maskVal, markVal);
    249     if (!EXT) goto escape;
    250     if (!isfinite(EXT->params->data.F32[PM_PAR_I0])) goto escape;
    251 
    252     okEXT = psphotEvalEXT (tmpSrc, EXT);
    253     chiEXT = EXT ? EXT->chisq / EXT->nDOF : NAN;
    254 
    255     // DBL will always be defined, but DBL->data[n] might not
    256     DBL = psphotFitDBL (readout, source, maskVal, markVal);
    257     if (!DBL) goto escape;
    258     if (!DBL->n) goto escape;
    259 
    260     okDBL  = psphotEvalDBL (tmpSrc, DBL->data[0]);
    261     okDBL &= psphotEvalDBL (tmpSrc, DBL->data[1]);
    262     // XXX should I keep / save the flags set in the eval functions?
     262    {
     263        // DBL will always be defined, but DBL->data[n] might not
     264        DBL = psphotFitDBL (readout, source, fitOptions, maskVal, markVal);
     265        if (!DBL) goto escape;
     266        if (!DBL->n) goto escape;
     267
     268        okDBL  = psphotEvalDBL (tmpSrc, DBL->data[0]);
     269        okDBL &= psphotEvalDBL (tmpSrc, DBL->data[1]);
     270        // XXX should I keep / save the flags set in the eval functions?
     271
     272        // correct first model chisqs for flux trend
     273        chiDBL = NAN;
     274        ONE = DBL->data[0];
     275        if (ONE) {
     276            if (!isfinite(ONE->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
     277            chiTrend = psPolynomial1DEval (psf->ChiTrend, ONE->params->data.F32[1]);
     278            ONE->chisqNorm = ONE->chisq / chiTrend;
     279            chiDBL = ONE->chisq / ONE->nDOF; // save chisq for double-star/galaxy comparison
     280            ONE->fitRadius = radius;
     281        }
     282
     283        // correct second model chisqs for flux trend
     284        ONE = DBL->data[1];
     285        if (ONE) {
     286            if (!isfinite(ONE->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
     287            chiTrend = psPolynomial1DEval (psf->ChiTrend, ONE->params->data.F32[1]);
     288            ONE->chisqNorm = ONE->chisq / chiTrend;
     289            ONE->fitRadius = radius;
     290        }
     291    }
     292
     293    {
     294        // XXX need to handle failures better here
     295        EXT = psphotFitEXT (readout, source, fitOptions, modelTypeEXT, maskVal, markVal);
     296        if (!EXT) goto escape;
     297        if (!isfinite(EXT->params->data.F32[PM_PAR_I0])) goto escape;
     298
     299        okEXT = psphotEvalEXT (tmpSrc, EXT);
     300        chiEXT = EXT ? EXT->chisq / EXT->nDOF : NAN;
     301    }
    263302
    264303    // clear the circular mask
    265304    psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
    266 
    267     // correct first model chisqs for flux trend
    268     chiDBL = NAN;
    269     ONE = DBL->data[0];
    270     if (ONE) {
    271         if (!isfinite(ONE->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
    272       chiTrend = psPolynomial1DEval (psf->ChiTrend, ONE->params->data.F32[1]);
    273       ONE->chisqNorm = ONE->chisq / chiTrend;
    274       chiDBL = ONE->chisq / ONE->nDOF; // save chisq for double-star/galaxy comparison
    275     }
    276 
    277     // correct second model chisqs for flux trend
    278     ONE = DBL->data[1];
    279     if (ONE) {
    280         if (!isfinite(ONE->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
    281       chiTrend = psPolynomial1DEval (psf->ChiTrend, ONE->params->data.F32[1]);
    282       ONE->chisqNorm = ONE->chisq / chiTrend;
    283     }
    284305
    285306    psFree (tmpSrc);
     
    298319
    299320    // both models failed; reject them both
    300     // XXX -- change type flags to psf in this case and keep original moments?
     321    // XXX -- change type flags to psf in this case, and make sure we subtract it?
     322    // reset the psf moments
     323    *source->moments = psfMoments;
     324
    301325    psFree (EXT);
    302326    psFree (DBL);
     
    308332
    309333    // save new model
     334    // XXX save the correct radius...
    310335    source->modelEXT = EXT;
    311     source->modelEXT->fitRadius = radius;
    312336    source->type = PM_SOURCE_TYPE_EXTENDED;
    313337    source->mode |= PM_SOURCE_MODE_EXTMODEL;
     
    327351# endif
    328352
     353    // reset the psf moments
     354    *source->moments = psfMoments;
    329355    return true;
    330356
     
    337363    source->modelPSF = psMemIncrRefCounter (DBL->data[0]);
    338364    source->mode     |= PM_SOURCE_MODE_PAIR;
    339     source->modelPSF->fitRadius = radius;
    340365
    341366    // copy most data from the primary source (modelEXT, blends stay NULL)
    342     pmSource *newSrc = pmSourceCopy (source);
     367    pmSource *newSrc = pmSourceCopyData (source);
    343368    newSrc->modelPSF = psMemIncrRefCounter (DBL->data[1]);
    344     newSrc->modelPSF->fitRadius = radius;
    345369
    346370    // build cached models and subtract
     
    365389# endif
    366390
     391    // reset the (original) psf moments
     392    *source->moments = psfMoments;
     393    *newSrc->moments = psfMoments;
     394
    367395    psArrayAdd (newSources, 100, newSrc);
    368396    psFree (newSrc);
     
    371399
    372400escape:
     401    // reset the psf moments
     402    *source->moments = psfMoments;
    373403    psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
    374404    psFree (tmpSrc);
     
    379409
    380410// fit a double PSF source to an extended blob
    381 psArray *psphotFitDBL (pmReadout *readout, pmSource *source, psImageMaskType maskVal, psImageMaskType markVal) {
     411psArray *psphotFitDBL (pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal) {
    382412
    383413    float dx, dy;
     
    387417    psEllipseMoments moments;
    388418    psArray *modelSet;
     419
     420    pmSourceFitOptions options = *fitOptions;
    389421
    390422    NfitDBL ++;
     
    403435    axes = psEllipseMomentsToAxes (moments, 20.0);
    404436
     437    if (isnan(axes.major)) return NULL;
     438    if (isnan(axes.minor)) return NULL;
     439    if (isnan(axes.theta)) return NULL;
     440
    405441    // XXX this is really arbitrary: 4 pixel separation?
    406442    dx = 2 * cos (axes.theta);
     
    426462
    427463    // fit PSF model (set/unset the pixel mask)
    428     pmSourceFitSet (source, modelSet, PM_SOURCE_FIT_PSF, maskVal);
     464    options.mode = PM_SOURCE_FIT_PSF;
     465    pmSourceFitSet (source, modelSet, &options, maskVal);
    429466    return (modelSet);
    430467}
    431468
    432 pmModel *psphotFitEXT (pmReadout *readout, pmSource *source, pmModelType modelType, psImageMaskType maskVal, psImageMaskType markVal) {
     469pmModel *psphotFitEXT (pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, pmModelType modelType, psImageMaskType maskVal, psImageMaskType markVal) {
     470
     471    if ((source->moments->Mxx < 1e-3) || (source->moments->Myy < 1e-3)) {
     472        psTrace ("psphot", 5, "problem source: moments: %f %f\n", source->moments->Mxx, source->moments->Myy);
     473    }
     474
     475    pmSourceFitOptions options = *fitOptions;
    433476
    434477    NfitEXT ++;
     
    438481
    439482    // use the source moments, etc to guess basic model parameters
    440     pmModel *EXT = pmSourceModelGuess (source, modelType);
    441     if (!EXT) {
     483    pmModel *model = pmSourceModelGuess (source, modelType);
     484    if (!model) {
    442485        psTrace ("psphot", 5, "failed to generate a model for source: moments: %f %f\n", source->moments->Mxx, source->moments->Myy);
    443486        return NULL;
    444487    }
    445488
     489    // for sersic models, use a grid search to choose an index, then float the params there
     490    if (modelType == pmModelClassGetType("PS_MODEL_SERSIC")) {
     491        // for the test fits, use a somewhat smaller radius
     492        psphotSetRadiusFootprint(&model->fitRadius, readout, source, markVal, 0.5);
     493        psphotFitSersicIndex (model, readout, source, fitOptions, maskVal, markVal);
     494    }
     495
     496    if (!psphotSetRadiusModel (model, readout, source, markVal, true)) {
     497        psphotSetRadiusFootprint(&model->fitRadius, readout, source, markVal, 1.0);
     498    }
     499
     500    if (modelType == pmModelClassGetType("PS_MODEL_SERSIC")) {
     501        options.mode = PM_SOURCE_FIT_NO_INDEX;
     502    } else {
     503        options.mode = PM_SOURCE_FIT_EXT;
     504    }
     505
     506    // psTraceSetLevel("psLib.math.psMinimizeLMChi2", 5);
     507    pmSourceFitModel (source, model, &options, maskVal);
     508    fprintf (stderr, "chisq: %f, nIter: %d, radius: %f, npix: %d\n\n", model->chisqNorm, model->nIter, model->fitRadius, model->nPix);
     509
     510    // psTraceSetLevel("psLib.math.psMinimizeLMChi2", 0);
     511    return (model);
     512}
     513
     514pmModel *psphotFitPCM (pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, pmModelType modelType, psImageMaskType maskVal, psImageMaskType markVal, int psfSize) {
     515
    446516    if ((source->moments->Mxx < 1e-3) || (source->moments->Myy < 1e-3)) {
    447517        psTrace ("psphot", 5, "problem source: moments: %f %f\n", source->moments->Mxx, source->moments->Myy);
    448518    }
    449519
     520    pmSourceFitOptions options = *fitOptions;
     521
     522    NfitPCM ++;
     523
     524    // maskVal is used to test for rejected pixels, and must include markVal
     525    maskVal |= markVal;
     526
     527    // allocate the model
     528    pmModel *model = pmModelAlloc(modelType);
     529    if (!model) {
     530        return NULL;
     531    }
     532
     533    pmPCMdata *pcm = pmPCMinit (source, &options, model, maskVal, psfSize);
     534    if (!pcm) {
     535        psTrace ("psphot", 5, "failed to generate a model for source: moments: %f %f\n", source->moments->Mxx, source->moments->Myy);
     536        model->flags |= PM_MODEL_STATUS_BADARGS; // XXX this is probably already set in pmPCMinit
     537        return model;
     538    }
     539
     540    // use the source moments, etc to guess basic model parameters
     541    if (!pmSourceModelGuessPCM (pcm, source, maskVal, markVal)) {
     542        psFree (pcm);
     543        model->flags |= PM_MODEL_STATUS_BADARGS;
     544        return model;
     545    }
     546
     547    // for sersic models, use a grid search to choose an index, then float the params there
     548    if (modelType == pmModelClassGetType("PS_MODEL_SERSIC")) {
     549        // for the test fits, use a somewhat smaller radius
     550        psphotSetRadiusFootprint(&model->fitRadius, readout, source, markVal, 0.5);
     551
     552        if (!psphotFitSersicIndexPCM (pcm, readout, source, fitOptions, maskVal, markVal, psfSize)) {
     553            model->flags |= PM_MODEL_STATUS_BADARGS;
     554            return model;
     555        }
     556    }
     557
     558    if (!psphotSetRadiusModel (model, readout, source, markVal, true)) {
     559        psphotSetRadiusFootprint(&model->fitRadius, readout, source, markVal, 1.0);
     560    }
     561
     562    if (modelType == pmModelClassGetType("PS_MODEL_SERSIC")) {
     563        options.mode = PM_SOURCE_FIT_NO_INDEX;
     564    } else {
     565        options.mode = PM_SOURCE_FIT_EXT;
     566    }
     567    // update the pcm elements if we have changed the circumstance (options.mode or source->pixels)
     568    pmPCMupdate(pcm, source, &options, model);
     569
     570    // psTraceSetLevel("psLib.math.psMinimizeLMChi2", 5);
     571    pmSourceFitPCM (pcm, source, &options, maskVal, markVal, psfSize);
     572    fprintf (stderr, "chisq: %f, nIter: %d, radius: %f, npix: %d\n\n", model->chisqNorm, model->nIter, model->fitRadius, model->nPix);
     573
     574    // psTraceSetLevel("psLib.math.psMinimizeLMChi2", 0);
     575    psFree (pcm);
     576
     577    return model;
     578}
     579
     580// note that these should be 1/2n of the standard sersic index
     581float indexGuess[] = {0.5, 0.33, 0.25, 0.167, 0.125, 0.083};
     582# define N_INDEX_GUESS 6
     583
     584// A sersic model is very sensitive to the index.  attempt to find the index first by grid search in just the index
     585// for a sersic model, attempt to fit just the index and normalization with a modest number of iterations
     586bool psphotFitSersicIndex (pmModel *model, pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal) {
     587
     588    assert (model->type == pmModelClassGetType("PS_MODEL_SERSIC"));
     589
     590    pmSourceFitOptions options = *fitOptions;
     591   
    450592    // fit EXT (not PSF) model (set/unset the pixel mask)
    451     pmSourceFitModel (source, EXT, PM_SOURCE_FIT_EXT, maskVal);
    452     return (EXT);
    453 }
     593    options.mode = PM_SOURCE_FIT_NO_INDEX;
     594    options.nIter = 4;
     595
     596    int iMin = -1;
     597    float xMin = NAN;
     598    float chiSquare[N_INDEX_GUESS];
     599
     600    for (int i = 0; i < N_INDEX_GUESS; i++) {
     601        model->params->data.F32[PM_PAR_7] = indexGuess[i];
     602
     603        if (!model->modelGuess(model, source)) {
     604            model->flags |= PM_MODEL_STATUS_BADARGS;
     605            return false;
     606        }
     607
     608        // each time we change the model guess, we need to adjust the radius
     609        // XXX this did not work : we do not need such a large radius -- just uses moments-based radius
     610        if (false && !psphotSetRadiusModel (model, readout, source, markVal, false)) {
     611            psphotSetRadiusFootprint(&model->fitRadius, readout, source, markVal, 0.5);
     612        }
     613       
     614        pmSourceFitModel (source, model, &options, maskVal);
     615        fprintf (stderr, "chisq: %f, nIter: %d, radius: %f, npix: %d\n", model->chisqNorm, model->nIter, model->fitRadius, model->nPix);
     616
     617        chiSquare[i] = model->chisqNorm;
     618        if (i == 0) {
     619            xMin = chiSquare[i];
     620            iMin = i;
     621        } else {
     622            if (chiSquare[i] < xMin) {
     623                xMin = chiSquare[i];
     624                iMin = i;
     625            }
     626        }
     627    }
     628    assert (iMin >= 0);
     629
     630    model->flags = PM_MODEL_STATUS_NONE; // do not attempt to handle failures here, let the next iteration deal with it
     631    model->params->data.F32[PM_PAR_7] = indexGuess[iMin];
     632    model->modelGuess(model, source);
     633
     634    // each time we change the model guess, we need to adjust the radius
     635    // if (!psphotSetRadiusModel (model, readout, source, markVal, true)) {
     636    //  psphotSetRadiusFootprint(&model->fitRadius, readout, source, markVal);
     637    // }
     638
     639    return true;
     640}
     641
     642// A sersic model is very sensitive to the index.  attempt to find the index first by grid search in just the index
     643// for a sersic model, attempt to fit just the index and normalization with a modest number of iterations
     644bool psphotFitSersicIndexPCM (pmPCMdata *pcm, pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal, int psfSize) {
     645
     646    pmModel *model = pcm->modelConv;
     647
     648    assert (model->type == pmModelClassGetType("PS_MODEL_SERSIC"));
     649
     650    pmSourceFitOptions options = *fitOptions;
     651   
     652    // fit EXT (not PSF) model (set/unset the pixel mask)
     653    options.mode = PM_SOURCE_FIT_NO_INDEX;
     654    options.nIter = 4;
     655
     656    // update the pcm elements if we have changed the circumstance (here, options.mode)
     657    pmPCMupdate(pcm, source, &options, model);
     658
     659    int iMin = -1;
     660    float xMin = NAN;
     661    float chiSquare[N_INDEX_GUESS];
     662
     663    for (int i = 0; i < N_INDEX_GUESS; i++) {
     664        model->params->data.F32[PM_PAR_7] = indexGuess[i];
     665       
     666        if (!model->modelGuess(model, source)) {
     667            model->flags |= PM_MODEL_STATUS_BADARGS;
     668            return false;
     669        }
     670
     671        // each time we change the model guess, we need to adjust the radius
     672        // XXX this did not work : we do not need such a large radius -- just uses moments-based radius
     673        if (false && !psphotSetRadiusModel (model, readout, source, markVal, false)) {
     674            psphotSetRadiusFootprint(&model->fitRadius, readout, source, markVal, 0.5);
     675        }
     676       
     677        pmSourceFitModel (source, model, &options, maskVal);
     678        fprintf (stderr, "chisq: %f, nIter: %d, radius: %f, npix: %d\n", model->chisqNorm, model->nIter, model->fitRadius, model->nPix);
     679
     680        // pmSourceModelGuessPCM(pcm, source, maskVal, markVal);
     681        // pmSourceFitPCM (pcm, source, &options, maskVal, markVal, psfSize);
     682
     683        chiSquare[i] = model->chisq;
     684        if (i == 0) {
     685            xMin = chiSquare[i];
     686            iMin = i;
     687        } else {
     688            if (chiSquare[i] < xMin) {
     689                xMin = chiSquare[i];
     690                iMin = i;
     691            }
     692        }
     693    }
     694    assert (iMin >= 0);
     695   
     696    model->flags = PM_MODEL_STATUS_NONE; // do not attempt to handle failures here, let the next iteration deal with it
     697    model->params->data.F32[PM_PAR_7] = indexGuess[iMin];
     698
     699    pmSourceModelGuessPCM(pcm, source, maskVal, markVal);
     700
     701    return true;
     702}
  • trunk/psphot/src/psphotSourceSize.c

    r28013 r29004  
    11# include "psphotInternal.h"
    22# include <gsl/gsl_sf_gamma.h>
     3
     4# define KRON 1
    35
    46typedef struct {
     
    168170    psVector *ApErr = psVectorAllocEmpty (100, PS_TYPE_F32);
    169171
     172    psImageMaskType markVal = options->markVal;
    170173    psImageMaskType maskVal = options->maskVal | options->markVal;
    171174
     
    189192
    190193        // XXX can we test if psfMag is set and calculate only if needed?
    191         pmSourceMagnitudes (source, psf, photMode, maskVal); // maskVal includes markVal
     194        pmSourceMagnitudes (source, psf, photMode, maskVal, markVal);
    192195
    193196        // clear the mask bit
     
    197200        pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal);
    198201
     202        // XXX test: switch to kron flux
     203# if (KRON)
     204        float apMag = -2.5*log10(source->moments->KronFlux);
     205# else
    199206        float apMag = -2.5*log10(source->moments->Sum);
     207# endif
    200208        float dMag = source->psfMag - apMag;
    201209
     
    288296    pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_WEIGHT;
    289297
     298    psImageMaskType markVal = options->markVal;
    290299    psImageMaskType maskVal = options->maskVal | options->markVal;
    291300
     
    335344
    336345        // XXX can we test if psfMag is set and calculate only if needed?
    337         pmSourceMagnitudes (source, psf, photMode, maskVal); // maskVal includes markVal
     346        pmSourceMagnitudes (source, psf, photMode, maskVal, markVal);
    338347
    339348        // clear the mask bit
     
    343352        pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal);
    344353
     354# if (KRON)
     355        float apMag = -2.5*log10(source->moments->KronFlux);
     356# else
    345357        float apMag = -2.5*log10(source->moments->Sum);
     358# endif
    346359        float dMag = source->psfMag - apMag;
    347360
    348361        // set nSigma to include both systematic and poisson error terms
    349362        // XXX the 'poisson error' contribution for size is probably wrong...
    350         float nSigmaMAG = (dMag - options->ApResid) / hypot(source->errMag, options->ApSysErr);
     363        // XXX add in a hard floor on the Ap Sys Err (to be a bit generous)
     364        float nSigmaMAG = (dMag - options->ApResid) / hypot(source->errMag, hypot(options->ApSysErr, 0.025));
    351365        float nSigmaMXX = (Mxx - psfClump->X) / hypot(psfClump->dX, psfClump->X*psfClump->X*source->errMag);
    352366        float nSigmaMYY = (Myy - psfClump->Y) / hypot(psfClump->dY, psfClump->Y*psfClump->Y*source->errMag);
    353367
    354         // partially-masked sources are more likely to be mis-measured PSFs
     368        fprintf (stderr, "%f %f : Mxx: %f, Myy: %f, dx: %f, dy: %f, psfMag: %f, apMag: %f, dMag: %f, errMag: %f, nSigmaMag: %f, nSigmaMxx: %f, nSigmaMyy: %f\n",
     369                 source->peak->xf, source->peak->yf, Mxx, Myy, source->peak->xf - source->moments->Mx, source->peak->yf - source->moments->My,
     370                 source->psfMag, apMag, dMag, source->errMag, nSigmaMAG, nSigmaMXX, nSigmaMYY);
     371
     372        // XXX double check on ths stuff!! partially-masked sources are more likely to be mis-measured PSFs
    355373        float sizeBias = 1.0;
    356         if (source->pixWeight < 0.9) {
     374        if (source->pixWeightNotBad < 0.9) {
     375            sizeBias = 3.0;
     376        }
     377        if (source->pixWeightNotPoor < 0.9) {
    357378            sizeBias = 3.0;
    358379        }
     
    389410        if (isCR) {
    390411            psTrace("psphotSourceClassRegion.CR",4,"CLASS: %g %g %f\t%g %g  %g %g  %g %g\t%g %g\t%g CR\t%g %g\n",
    391                     source->peak->xf,source->peak->yf,source->pixWeight,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG,
     412                    source->peak->xf,source->peak->yf,source->pixWeightNotBad,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG,
    392413                    options->nSigmaApResid,sizeBias*options->nSigmaMoments);
    393414            source->mode |= PM_SOURCE_MODE_DEFECT;
  • trunk/psphot/src/psphotSourceStats.c

    r28419 r29004  
    11# include "psphotInternal.h"
     2void pmSourceMomentsSetVerbose(bool state);
    23
    34// convert detections to sources and measure their basic properties (moments, local sky, sky
     
    369370    maskVal |= markVal;
    370371
     372    // XXX test : pmSourceMomentsSetVerbose(true);
     373
    371374    // threaded measurement of the sources moments
    372375    int Nfail = 0;
     
    408411        // measure basic source moments (no S/N clipping on input pixels)
    409412        status = pmSourceMoments (source, RADIUS, SIGMA, 0.0, maskVal);
     413        // XXX moments / aperture test:
     414        if (0) {
     415            // clear the mask bit and set the circular mask pixels
     416            psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
     417            psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, 4.0*source->moments->Mrf, "OR", markVal);
     418           
     419            float apMag = NAN;
     420            pmSourcePhotometryAper (&apMag, NULL, source->pixels, source->maskObj, maskVal);
     421            fprintf (stderr, "apMag: %f, kronMag: %f\n", apMag, -2.5*log10(source->moments->KronFlux));
     422
     423            // clear the mask bit
     424            psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
     425        }           
    410426        if (status) {
    411427            Nmoments ++;
     
    502518        psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DX", PS_META_REPLACE, "psf clump center", psfClump.dX);
    503519        psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DY", PS_META_REPLACE, "psf clump center", psfClump.dY);
    504         psphotVisualPlotMoments (recipe, analysis, sources);
     520        if (pmVisualTestLevel("psphot.moments.full", 2)) {
     521            psphotVisualPlotMoments (recipe, analysis, sources);
     522        }
    505523#endif
    506524
  • trunk/psphot/src/psphotVisual.c

    r28128 r29004  
    6666    int myKapa = psphotKapaChannel (channel);
    6767    if (!(strcasecmp (overlay, "all"))) {
    68       KiiEraseOverlay (myKapa, "red");
    69       KiiEraseOverlay (myKapa, "green");
    70       KiiEraseOverlay (myKapa, "blue");
    71       KiiEraseOverlay (myKapa, "yellow");
    72       return true;
     68        KiiEraseOverlay (myKapa, "red");
     69        KiiEraseOverlay (myKapa, "green");
     70        KiiEraseOverlay (myKapa, "blue");
     71        KiiEraseOverlay (myKapa, "yellow");
     72        return true;
    7373    }
    7474    KiiEraseOverlay (myKapa, overlay);
     
    182182bool psphotVisualShowImage (pmReadout *readout) {
    183183
    184     if (!pmVisualIsVisual()) return true;
     184    if (!pmVisualTestLevel("psphot.image", 1)) return true;
    185185
    186186    int kapa = psphotKapaChannel (1);
     
    199199    pmReadout *backgnd;
    200200
    201     if (!DEBUG && !pmVisualIsVisual()) return true;
     201    if (!pmVisualTestLevel("psphot.image.backgnd", 2)) return true;
    202202
    203203    int kapa = psphotKapaChannel (1);
     
    208208
    209209    if (file->mode == PM_FPA_MODE_INTERNAL) {
    210         backgnd = file->readout;
     210        backgnd = file->readout;
    211211    } else {
    212         backgnd = pmFPAviewThisReadout (view, file->fpa);
     212        backgnd = pmFPAviewThisReadout (view, file->fpa);
    213213    }
    214214
     
    222222bool psphotVisualShowSignificance (psImage *image, float min, float max) {
    223223
    224     if (!DEBUG && !pmVisualIsVisual()) return true;
     224    if (!pmVisualTestLevel("psphot.image.signif", 2)) return true;
    225225
    226226    int kapa = psphotKapaChannel (1);
     
    233233}
    234234
     235bool psphotVisualShowLogSignificance (psImage *image, float min, float max) {
     236
     237    if (!pmVisualTestLevel("psphot.image.logsignif", 3)) return true;
     238
     239    int kapa = psphotKapaChannel (1);
     240    if (kapa == -1) return false;
     241
     242    psImage *lsig = (psImage *) psUnaryOp (NULL, image, "log");
     243    psphotVisualRangeImage (kapa, lsig, "log-signif", 2, min, max);
     244    psFree (lsig);
     245
     246    pmVisualAskUser(NULL);
     247    return true;
     248}
     249
     250// XXX : requires psphotVisualShowImage
    235251bool psphotVisualShowPeaks (pmDetections *detections) {
    236252
     
    238254    KiiOverlay *overlay;
    239255
    240     if (!DEBUG && !pmVisualIsVisual()) return true;
     256    if (!pmVisualTestLevel("psphot.objects.peaks", 1)) return true;
    241257
    242258    int kapa = psphotKapaChannel (1);
     
    252268    for (int i = 0; i < peaks->n; i++) {
    253269
    254         pmPeak *peak = peaks->data[i];
    255         if (peak == NULL) continue;
    256 
    257         overlay[Noverlay].type = KII_OVERLAY_BOX;
    258         overlay[Noverlay].x = peak->xf;
    259         overlay[Noverlay].y = peak->yf;
    260         overlay[Noverlay].dx = 2.0;
    261         overlay[Noverlay].dy = 2.0;
    262         overlay[Noverlay].angle = 0.0;
    263         overlay[Noverlay].text = NULL;
    264         Noverlay ++;
     270        pmPeak *peak = peaks->data[i];
     271        if (peak == NULL) continue;
     272
     273        overlay[Noverlay].type = KII_OVERLAY_BOX;
     274        overlay[Noverlay].x = peak->xf;
     275        overlay[Noverlay].y = peak->yf;
     276        overlay[Noverlay].dx = 2.0;
     277        overlay[Noverlay].dy = 2.0;
     278        overlay[Noverlay].angle = 0.0;
     279        overlay[Noverlay].text = NULL;
     280        Noverlay ++;
    265281    }
    266282
     
    272288}
    273289
     290// XXX : requires psphotVisualShowImage
    274291bool psphotVisualShowFootprints (pmDetections *detections) {
    275292
     
    277294    KiiOverlay *overlay;
    278295
    279     if (!DEBUG && !pmVisualIsVisual()) return true;
     296    if (!pmVisualTestLevel("psphot.objects.footprints", 3)) return true;
    280297
    281298    int kapa = psphotKapaChannel (1);
     
    292309    for (int i = 0; i < footprints->n; i++) {
    293310
    294         pmSpan *span = NULL;
    295 
    296         pmFootprint *footprint = footprints->data[i];
    297         if (footprint == NULL) continue;
    298         if (footprint->spans == NULL) continue;
    299         if (footprint->spans->n < 1) continue;
    300 
    301         // draw the top
    302         // XXX need to allow top (and bottom) to have more than one span
    303         span = footprint->spans->data[0];
    304         overlay[Noverlay].type = KII_OVERLAY_LINE;
    305         overlay[Noverlay].x = span->x0;
    306         overlay[Noverlay].y = span->y;
    307         overlay[Noverlay].dx = span->x1 - span->x0;
    308         overlay[Noverlay].dy = 0;
    309         overlay[Noverlay].angle = 0.0;
    310         overlay[Noverlay].text = NULL;
    311         Noverlay ++;
    312         CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
    313 
    314         int ys = span->y;
    315         int x0s = span->x0;
    316         int x1s = span->x1;
    317 
    318         // draw the outer span edges
    319         for (int j = 1; j < footprint->spans->n; j++) {
    320             pmSpan *span1 = footprint->spans->data[j];
    321 
    322             int ye = span1->y;
    323             int x0e = span1->x0;
    324             int x1e = span1->x1;
    325 
    326             // we cannot have two discontinuous spans on the top or bottom, right? (no, probably not right)
    327             // find all of the spans in this row and generate x0e, x01:
    328             for (int k = j + 1; k < footprint->spans->n; k++) {
    329                 pmSpan *span2 = footprint->spans->data[k];
    330                 if (span2->y > span1->y) break;
    331                 x0e = PS_MIN (x0e, span2->x0);
    332                 x1e = PS_MAX (x1e, span2->x1);
    333                 j++;
    334             }
    335 
    336             overlay[Noverlay].type = KII_OVERLAY_LINE;
    337             overlay[Noverlay].x = x0s;
    338             overlay[Noverlay].y = ys;
    339             overlay[Noverlay].dx = x0e - x0s;
    340             overlay[Noverlay].dy = ye - ys;
    341             overlay[Noverlay].angle = 0.0;
    342             overlay[Noverlay].text = NULL;
    343             Noverlay ++;
    344             CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
    345 
    346             overlay[Noverlay].type = KII_OVERLAY_LINE;
    347             overlay[Noverlay].x = x1s;
    348             overlay[Noverlay].y = ys;
    349             overlay[Noverlay].dx = x1e - x1s;
    350             overlay[Noverlay].dy = ye - ys;
    351             overlay[Noverlay].angle = 0.0;
    352             overlay[Noverlay].text = NULL;
    353             Noverlay ++;
    354             CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
    355 
    356             ys = ye;
    357             x0s = x0e;
    358             x1s = x1e;
    359         }
    360 
    361         // draw the bottom
    362         span = footprint->spans->data[footprint->spans->n - 1];
    363         overlay[Noverlay].type = KII_OVERLAY_LINE;
    364         overlay[Noverlay].x = span->x0;
    365         overlay[Noverlay].y = span->y;
    366         overlay[Noverlay].dx = span->x1 - span->x0;
    367         overlay[Noverlay].dy = 0;
    368         overlay[Noverlay].angle = 0.0;
    369         overlay[Noverlay].text = NULL;
    370         Noverlay ++;
    371         CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
     311        pmSpan *span = NULL;
     312
     313        pmFootprint *footprint = footprints->data[i];
     314        if (footprint == NULL) continue;
     315        if (footprint->spans == NULL) continue;
     316        if (footprint->spans->n < 1) continue;
     317
     318        // draw the top
     319        // XXX need to allow top (and bottom) to have more than one span
     320        span = footprint->spans->data[0];
     321        overlay[Noverlay].type = KII_OVERLAY_LINE;
     322        overlay[Noverlay].x = span->x0;
     323        overlay[Noverlay].y = span->y;
     324        overlay[Noverlay].dx = span->x1 - span->x0;
     325        overlay[Noverlay].dy = 0;
     326        overlay[Noverlay].angle = 0.0;
     327        overlay[Noverlay].text = NULL;
     328        Noverlay ++;
     329        CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
     330
     331        int ys = span->y;
     332        int x0s = span->x0;
     333        int x1s = span->x1;
     334
     335        // draw the outer span edges
     336        for (int j = 1; j < footprint->spans->n; j++) {
     337            pmSpan *span1 = footprint->spans->data[j];
     338
     339            int ye = span1->y;
     340            int x0e = span1->x0;
     341            int x1e = span1->x1;
     342
     343            // we cannot have two discontinuous spans on the top or bottom, right? (no, probably not right)
     344            // find all of the spans in this row and generate x0e, x01:
     345            for (int k = j + 1; k < footprint->spans->n; k++) {
     346                pmSpan *span2 = footprint->spans->data[k];
     347                if (span2->y > span1->y) break;
     348                x0e = PS_MIN (x0e, span2->x0);
     349                x1e = PS_MAX (x1e, span2->x1);
     350                j++;
     351            }
     352
     353            overlay[Noverlay].type = KII_OVERLAY_LINE;
     354            overlay[Noverlay].x = x0s;
     355            overlay[Noverlay].y = ys;
     356            overlay[Noverlay].dx = x0e - x0s;
     357            overlay[Noverlay].dy = ye - ys;
     358            overlay[Noverlay].angle = 0.0;
     359            overlay[Noverlay].text = NULL;
     360            Noverlay ++;
     361            CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
     362
     363            overlay[Noverlay].type = KII_OVERLAY_LINE;
     364            overlay[Noverlay].x = x1s;
     365            overlay[Noverlay].y = ys;
     366            overlay[Noverlay].dx = x1e - x1s;
     367            overlay[Noverlay].dy = ye - ys;
     368            overlay[Noverlay].angle = 0.0;
     369            overlay[Noverlay].text = NULL;
     370            Noverlay ++;
     371            CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
     372
     373            ys = ye;
     374            x0s = x0e;
     375            x1s = x1e;
     376        }
     377
     378        // draw the bottom
     379        span = footprint->spans->data[footprint->spans->n - 1];
     380        overlay[Noverlay].type = KII_OVERLAY_LINE;
     381        overlay[Noverlay].x = span->x0;
     382        overlay[Noverlay].y = span->y;
     383        overlay[Noverlay].dx = span->x1 - span->x0;
     384        overlay[Noverlay].dy = 0;
     385        overlay[Noverlay].angle = 0.0;
     386        overlay[Noverlay].text = NULL;
     387        Noverlay ++;
     388        CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
    372389    }
    373390
     
    379396}
    380397
     398// XXX : requires psphotVisualShowImage
    381399bool psphotVisualShowMoments (psArray *sources) {
    382400
     
    387405    psEllipseAxes axes;
    388406
    389     if (!DEBUG && !pmVisualIsVisual()) return true;
     407    if (!pmVisualTestLevel("psphot.objects.moments", 2)) return true;
    390408
    391409    int kapa = psphotKapaChannel (1);
     
    401419    for (int i = 0; i < sources->n; i++) {
    402420
    403         pmSource *source = sources->data[i];
    404         if (source == NULL) continue;
    405 
    406         pmMoments *moments = source->moments;
    407         if (moments == NULL) continue;
    408 
    409         overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
    410         overlay[Noverlay].x = moments->Mx;
    411         overlay[Noverlay].y = moments->My;
    412 
    413         emoments.x2 = moments->Mxx;
    414         emoments.xy = moments->Mxy;
    415         emoments.y2 = moments->Myy;
    416 
    417         axes = psEllipseMomentsToAxes (emoments, 20.0);
    418 
    419         overlay[Noverlay].dx = 2.0*axes.major;
    420         overlay[Noverlay].dy = 2.0*axes.minor;
    421 
    422         overlay[Noverlay].angle = axes.theta * PS_DEG_RAD;
    423 
    424         overlay[Noverlay].text = NULL;
    425         Noverlay ++;
     421        pmSource *source = sources->data[i];
     422        if (source == NULL) continue;
     423
     424        pmMoments *moments = source->moments;
     425        if (moments == NULL) continue;
     426
     427        overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
     428        overlay[Noverlay].x = moments->Mx;
     429        overlay[Noverlay].y = moments->My;
     430
     431        emoments.x2 = moments->Mxx;
     432        emoments.xy = moments->Mxy;
     433        emoments.y2 = moments->Myy;
     434
     435        axes = psEllipseMomentsToAxes (emoments, 20.0);
     436
     437        overlay[Noverlay].dx = 2.0*axes.major;
     438        overlay[Noverlay].dy = 2.0*axes.minor;
     439
     440        overlay[Noverlay].angle = axes.theta * PS_DEG_RAD;
     441
     442        overlay[Noverlay].text = NULL;
     443        Noverlay ++;
    426444    }
    427445
     
    439457    KapaSection section;
    440458
    441     if (!DEBUG && !pmVisualIsVisual()) return true;
     459    if (!pmVisualTestLevel("psphot.moments", 1)) return true;
    442460
    443461    int myKapa = psphotKapaChannel (2);
     
    456474    float Ymin = 1000.0, Ymax = 0.0;
    457475    {
    458         int nRegions = psMetadataLookupS32 (&status, analysis, "PSF.CLUMP.NREGIONS");
    459         for (int n = 0; n < nRegions; n++) {
    460 
    461             char regionName[64];
    462             snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", n);
    463             psMetadata *regionMD = psMetadataLookupPtr (&status, analysis, regionName);
    464 
    465             float psfX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");
    466             float psfY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y");
    467             float psfdX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX");
    468             float psfdY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY");
    469 
    470             float X0 = psfX - 4.0*psfdX;
    471             float X1 = psfX + 4.0*psfdX;
    472             float Y0 = psfY - 4.0*psfdY;
    473             float Y1 = psfY + 4.0*psfdY;
    474 
    475             if (isfinite(X0)) { Xmin = PS_MIN(Xmin, X0); }
    476             if (isfinite(X1)) { Xmax = PS_MAX(Xmax, X1); }
    477             if (isfinite(Y0)) { Ymin = PS_MIN(Ymin, Y0); }
    478             if (isfinite(Y1)) { Ymax = PS_MAX(Ymax, Y1); }
    479         }
     476        int nRegions = psMetadataLookupS32 (&status, analysis, "PSF.CLUMP.NREGIONS");
     477        for (int n = 0; n < nRegions; n++) {
     478
     479            char regionName[64];
     480            snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", n);
     481            psMetadata *regionMD = psMetadataLookupPtr (&status, analysis, regionName);
     482
     483            float psfX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");
     484            float psfY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y");
     485            float psfdX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX");
     486            float psfdY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY");
     487
     488            float X0 = psfX - 4.0*psfdX;
     489            float X1 = psfX + 4.0*psfdX;
     490            float Y0 = psfY - 4.0*psfdY;
     491            float Y1 = psfY + 4.0*psfdY;
     492
     493            if (isfinite(X0)) { Xmin = PS_MIN(Xmin, X0); }
     494            if (isfinite(X1)) { Xmax = PS_MAX(Xmax, X1); }
     495            if (isfinite(Y0)) { Ymin = PS_MIN(Ymin, Y0); }
     496            if (isfinite(Y1)) { Ymax = PS_MAX(Ymax, Y1); }
     497        }
    480498    }
    481499    Xmin = PS_MAX(Xmin, -0.1);
     
    498516    int nF = 0;
    499517    for (int i = 0; i < sources->n; i++) {
    500         pmSource *source = sources->data[i];
    501         if (source->moments == NULL)
    502             continue;
    503 
    504         xFaint->data.F32[nF] = source->moments->Mxx;
    505         yFaint->data.F32[nF] = source->moments->Myy;
    506         mFaint->data.F32[nF] = -2.5*log10(source->moments->Sum);
    507         nF++;
    508 
    509         // XXX make this a user-defined cutoff
    510         if (source->moments->SN < SN_LIM)
    511             continue;
    512 
    513         xBright->data.F32[nB] = source->moments->Mxx;
    514         yBright->data.F32[nB] = source->moments->Myy;
    515         mBright->data.F32[nB] = -2.5*log10(source->moments->Sum);
    516         nB++;
     518        pmSource *source = sources->data[i];
     519        if (source->moments == NULL)
     520            continue;
     521
     522        xFaint->data.F32[nF] = source->moments->Mxx;
     523        yFaint->data.F32[nF] = source->moments->Myy;
     524        mFaint->data.F32[nF] = -2.5*log10(source->moments->Sum);
     525        nF++;
     526
     527        // XXX make this a user-defined cutoff
     528        if (source->moments->SN < SN_LIM)
     529            continue;
     530
     531        xBright->data.F32[nB] = source->moments->Mxx;
     532        yBright->data.F32[nB] = source->moments->Myy;
     533        mBright->data.F32[nB] = -2.5*log10(source->moments->Sum);
     534        nB++;
    517535    }
    518536    xFaint->n = nF;
     
    652670    // draw N circles to outline the clumps
    653671    {
    654         KapaSelectSection (myKapa, "MxxMyy");
    655 
    656         // draw a circle centered on psfX,Y with size of the psf limit
    657         psVector *xLimit  = psVectorAlloc (120, PS_TYPE_F32);
    658         psVector *yLimit  = psVectorAlloc (120, PS_TYPE_F32);
    659 
    660         int nRegions = psMetadataLookupS32 (&status, analysis, "PSF.CLUMP.NREGIONS");
    661         float PSF_CLUMP_NSIGMA = psMetadataLookupF32 (&status, recipe, "PSF_CLUMP_NSIGMA");
    662 
    663         graphdata.color = KapaColorByName ("blue");
    664         graphdata.style = 0;
    665 
    666         graphdata.xmin = Xmin;
    667         graphdata.ymin = Ymin;
    668         graphdata.xmax = Xmax;
    669         graphdata.ymax = Ymax;
    670         KapaSetLimits (myKapa, &graphdata);
    671 
    672         for (int n = 0; n < nRegions; n++) {
    673 
    674             char regionName[64];
    675             snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", n);
    676             psMetadata *regionMD = psMetadataLookupPtr (&status, analysis, regionName);
    677 
    678             float psfX  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");
    679             float psfY  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y");
    680             float psfdX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX");
    681             float psfdY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY");
    682             float Rx = psfdX * PSF_CLUMP_NSIGMA;
    683             float Ry = psfdY * PSF_CLUMP_NSIGMA;
    684 
    685             for (int i = 0; i < xLimit->n; i++) {
    686                 xLimit->data.F32[i] = Rx*cos(i*2.0*M_PI/120.0) + psfX;
    687                 yLimit->data.F32[i] = Ry*sin(i*2.0*M_PI/120.0) + psfY;
    688             }
    689             KapaPrepPlot (myKapa, xLimit->n, &graphdata);
    690             KapaPlotVector (myKapa, xLimit->n, xLimit->data.F32, "x");
    691             KapaPlotVector (myKapa, yLimit->n, yLimit->data.F32, "y");
    692         }
    693         psFree (xLimit);
    694         psFree (yLimit);
     672        KapaSelectSection (myKapa, "MxxMyy");
     673
     674        // draw a circle centered on psfX,Y with size of the psf limit
     675        psVector *xLimit  = psVectorAlloc (120, PS_TYPE_F32);
     676        psVector *yLimit  = psVectorAlloc (120, PS_TYPE_F32);
     677
     678        int nRegions = psMetadataLookupS32 (&status, analysis, "PSF.CLUMP.NREGIONS");
     679        float PSF_CLUMP_NSIGMA = psMetadataLookupF32 (&status, recipe, "PSF_CLUMP_NSIGMA");
     680
     681        graphdata.color = KapaColorByName ("blue");
     682        graphdata.style = 0;
     683
     684        graphdata.xmin = Xmin;
     685        graphdata.ymin = Ymin;
     686        graphdata.xmax = Xmax;
     687        graphdata.ymax = Ymax;
     688        KapaSetLimits (myKapa, &graphdata);
     689
     690        for (int n = 0; n < nRegions; n++) {
     691
     692            char regionName[64];
     693            snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", n);
     694            psMetadata *regionMD = psMetadataLookupPtr (&status, analysis, regionName);
     695
     696            float psfX  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");
     697            float psfY  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y");
     698            float psfdX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX");
     699            float psfdY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY");
     700            float Rx = psfdX * PSF_CLUMP_NSIGMA;
     701            float Ry = psfdY * PSF_CLUMP_NSIGMA;
     702
     703            for (int i = 0; i < xLimit->n; i++) {
     704                xLimit->data.F32[i] = Rx*cos(i*2.0*M_PI/120.0) + psfX;
     705                yLimit->data.F32[i] = Ry*sin(i*2.0*M_PI/120.0) + psfY;
     706            }
     707            KapaPrepPlot (myKapa, xLimit->n, &graphdata);
     708            KapaPlotVector (myKapa, xLimit->n, xLimit->data.F32, "x");
     709            KapaPlotVector (myKapa, yLimit->n, yLimit->data.F32, "y");
     710        }
     711        psFree (xLimit);
     712        psFree (yLimit);
    695713    }
    696714
     
    721739    for (int i = 0; i < sources->n; i++) {
    722740
    723         pmSource *source = sources->data[i];
    724         if (source == NULL) continue;
    725 
    726         if (source->type != type) continue;
    727         if (mode && !(source->mode & mode)) continue;
    728 
    729         pmMoments *moments = source->moments;
    730         if (moments == NULL) continue;
    731 
    732         overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
    733         overlay[Noverlay].x = moments->Mx;
    734         overlay[Noverlay].y = moments->My;
    735 
    736         emoments.x2 = moments->Mxx;
    737         emoments.y2 = moments->Myy;
    738         emoments.xy = moments->Mxy;
    739 
    740         axes = psEllipseMomentsToAxes (emoments, 20.0);
    741 
    742         overlay[Noverlay].dx = 2.0*axes.major;
    743         overlay[Noverlay].dy = 2.0*axes.minor;
    744         overlay[Noverlay].angle = axes.theta * PS_DEG_RAD;
    745         overlay[Noverlay].text = NULL;
    746         Noverlay ++;
     741        pmSource *source = sources->data[i];
     742        if (source == NULL) continue;
     743
     744        if (source->type != type) continue;
     745        if (mode && !(source->mode & mode)) continue;
     746
     747        pmMoments *moments = source->moments;
     748        if (moments == NULL) continue;
     749
     750        overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
     751        overlay[Noverlay].x = moments->Mx;
     752        overlay[Noverlay].y = moments->My;
     753
     754        emoments.x2 = moments->Mxx;
     755        emoments.y2 = moments->Myy;
     756        emoments.xy = moments->Mxy;
     757
     758        axes = psEllipseMomentsToAxes (emoments, 20.0);
     759
     760        overlay[Noverlay].dx = 2.0*axes.major;
     761        overlay[Noverlay].dy = 2.0*axes.minor;
     762        overlay[Noverlay].angle = axes.theta * PS_DEG_RAD;
     763        overlay[Noverlay].text = NULL;
     764        Noverlay ++;
    747765    }
    748766
     
    753771}
    754772
     773// XXX : requires psphotVisualShowImage
    755774bool psphotVisualShowRoughClass (psArray *sources) {
    756775
    757     if (!DEBUG && !pmVisualIsVisual()) return true;
     776    if (!pmVisualTestLevel("psphot.objects.size", 3)) return true;
    758777
    759778    int myKapa = psphotKapaChannel (1);
     
    776795bool psphotVisualShowPSFModel (pmReadout *readout, pmPSF *psf) {
    777796
    778     if (!DEBUG && !pmVisualIsVisual()) return true;
     797    if (!pmVisualTestLevel("psphot.psf.model", 1)) return true;
    779798
    780799    int myKapa = psphotKapaChannel (3);
     
    797816    // generate a fake model at each of the 3x3 image grid positions
    798817    for (int x = -2; x <= +2; x ++) {
    799         for (int y = -2; y <= +2; y ++) {
    800             // use the center of the center pixel of the image
    801             float xc = (int)((0.5 + 0.225*x)*readout->image->numCols) + readout->image->col0 + 0.5;
    802             float yc = (int)((0.5 + 0.225*y)*readout->image->numRows) + readout->image->row0 + 0.5;
    803 
    804             // assign the x and y coords to the image center
    805             // create an object with center intensity of 1000
    806             modelRef->params->data.F32[PM_PAR_SKY] = 0;
    807             modelRef->params->data.F32[PM_PAR_I0] = 1000;
    808             modelRef->params->data.F32[PM_PAR_XPOS] = xc;
    809             modelRef->params->data.F32[PM_PAR_YPOS] = yc;
    810 
    811             // create modelPSF from this model
    812             pmModel *model = pmModelFromPSF (modelRef, psf);
    813             if (!model) continue;
    814 
    815             // place the reference object in the image center
    816             // no need to mask the source here
    817             // XXX should we measure this for the analytical model only or the full model?
    818             pmModelAddWithOffset (psfMosaic, NULL, model, PM_MODEL_OP_FULL | PM_MODEL_OP_CENTER, 0, x*DX, y*DY);
    819             pmModelAddWithOffset (funMosaic, NULL, model, PM_MODEL_OP_FUNC | PM_MODEL_OP_CENTER, 0, x*DX, y*DY);
    820             pmModelAddWithOffset (resMosaic, NULL, model, PM_MODEL_OP_RES0 | PM_MODEL_OP_RES1 | PM_MODEL_OP_CENTER, 0, x*DX, y*DY);
    821             psFree (model);
    822         }
     818        for (int y = -2; y <= +2; y ++) {
     819            // use the center of the center pixel of the image
     820            float xc = (int)((0.5 + 0.225*x)*readout->image->numCols) + readout->image->col0 + 0.5;
     821            float yc = (int)((0.5 + 0.225*y)*readout->image->numRows) + readout->image->row0 + 0.5;
     822
     823            // assign the x and y coords to the image center
     824            // create an object with center intensity of 1000
     825            modelRef->params->data.F32[PM_PAR_SKY] = 0;
     826            modelRef->params->data.F32[PM_PAR_I0] = 1000;
     827            modelRef->params->data.F32[PM_PAR_XPOS] = xc;
     828            modelRef->params->data.F32[PM_PAR_YPOS] = yc;
     829
     830            // create modelPSF from this model
     831            pmModel *model = pmModelFromPSF (modelRef, psf);
     832            if (!model) continue;
     833
     834            // place the reference object in the image center
     835            // no need to mask the source here
     836            // XXX should we measure this for the analytical model only or the full model?
     837            pmModelAddWithOffset (psfMosaic, NULL, model, PM_MODEL_OP_FULL | PM_MODEL_OP_CENTER, 0, x*DX, y*DY);
     838            pmModelAddWithOffset (funMosaic, NULL, model, PM_MODEL_OP_FUNC | PM_MODEL_OP_CENTER, 0, x*DX, y*DY);
     839            pmModelAddWithOffset (resMosaic, NULL, model, PM_MODEL_OP_RES0 | PM_MODEL_OP_RES1 | PM_MODEL_OP_CENTER, 0, x*DX, y*DY);
     840            psFree (model);
     841        }
    823842    }
    824843
     
    842861    bool status;
    843862
    844     if (!DEBUG && !pmVisualIsVisual()) return true;
     863    if (!pmVisualTestLevel("psphot.psf.stars", 2)) return true;
    845864
    846865    int myKapa = psphotKapaChannel (3);
     
    871890    for (int i = 0; i < sources->n; i++) {
    872891
    873         pmSource *source = sources->data[i];
    874 
    875         bool keep = false;
    876         keep |= (source->mode & PM_SOURCE_MODE_PSFSTAR);
    877         if (!keep) continue;
    878 
    879         // how does this subimage get placed into the output image?
    880         // DX = source->pixels->numCols
    881         // DY = source->pixels->numRows
    882 
    883         if (dX + DX > NX) {
    884             // too wide for the rest of this row
    885             if (dX == 0) {
    886                 // alone on this row
    887                 NY += DY;
    888                 dX = 0;
    889                 dY = 0;
    890             } else {
    891                 // start the next row
    892                 NY += dY;
    893                 dX = DX;
    894                 dY = DY;
    895             }
    896         } else {
    897             // extend this row
    898             dX += DX;
    899             dY = PS_MAX (dY, DY);
    900         }
     892        pmSource *source = sources->data[i];
     893
     894        bool keep = false;
     895        keep |= (source->mode & PM_SOURCE_MODE_PSFSTAR);
     896        if (!keep) continue;
     897
     898        // how does this subimage get placed into the output image?
     899        // DX = source->pixels->numCols
     900        // DY = source->pixels->numRows
     901
     902        if (dX + DX > NX) {
     903            // too wide for the rest of this row
     904            if (dX == 0) {
     905                // alone on this row
     906                NY += DY;
     907                dX = 0;
     908                dY = 0;
     909            } else {
     910                // start the next row
     911                NY += dY;
     912                dX = DX;
     913                dY = DY;
     914            }
     915        } else {
     916            // extend this row
     917            dX += DX;
     918            dY = PS_MAX (dY, DY);
     919        }
    901920    }
    902921    NY += DY;
     
    918937    for (int i = 0; i < sources->n; i++) {
    919938
    920         pmSource *source = sources->data[i];
    921 
    922         bool keep = false;
    923         if (source->mode & PM_SOURCE_MODE_PSFSTAR) {
    924             nPSF ++;
    925             keep = true;
    926         }
    927         if (!keep) continue;
    928 
    929         if (Xo + DX > NX) {
    930             // too wide for the rest of this row
    931             if (Xo == 0) {
    932                 // place source alone on this row
    933                 bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
    934                 if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    935                 psphotMosaicSubimage (outpos, source, Xo, Yo, DX, DY, true);
    936 
    937                 pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    938                 psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
    939 
    940                 if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    941 
    942                 Yo += DY;
    943                 Xo = 0;
    944                 dY = 0;
    945             } else {
    946                 // start the next row
    947                 Yo += dY;
    948                 Xo = 0;
    949 
    950                 bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
    951                 if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    952                 psphotMosaicSubimage (outpos, source, Xo, Yo, DX, DY, true);
    953 
    954                 pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    955                 psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
    956 
    957                 if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    958 
    959                 Xo = DX;
    960                 dY = DY;
    961             }
    962         } else {
    963             // extend this row
    964             bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
    965             if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    966             psphotMosaicSubimage (outpos, source, Xo, Yo, DX, DY, true);
    967 
    968             pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    969             psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
    970             if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    971 
    972             Xo += DX;
    973             dY = PS_MAX (dY, DY);
    974         }
     939        pmSource *source = sources->data[i];
     940
     941        bool keep = false;
     942        if (source->mode & PM_SOURCE_MODE_PSFSTAR) {
     943            nPSF ++;
     944            keep = true;
     945        }
     946        if (!keep) continue;
     947
     948        if (Xo + DX > NX) {
     949            // too wide for the rest of this row
     950            if (Xo == 0) {
     951                // place source alone on this row
     952                bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     953                if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
     954                psphotMosaicSubimage (outpos, source, Xo, Yo, DX, DY, true);
     955
     956                pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
     957                psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
     958
     959                if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
     960
     961                Yo += DY;
     962                Xo = 0;
     963                dY = 0;
     964            } else {
     965                // start the next row
     966                Yo += dY;
     967                Xo = 0;
     968
     969                bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     970                if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
     971                psphotMosaicSubimage (outpos, source, Xo, Yo, DX, DY, true);
     972
     973                pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
     974                psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
     975
     976                if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
     977
     978                Xo = DX;
     979                dY = DY;
     980            }
     981        } else {
     982            // extend this row
     983            bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     984            if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
     985            psphotMosaicSubimage (outpos, source, Xo, Yo, DX, DY, true);
     986
     987            pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
     988            psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
     989            if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
     990
     991            Xo += DX;
     992            dY = PS_MAX (dY, DY);
     993        }
    975994    }
    976995
     
    9941013    bool status;
    9951014
    996     if (!DEBUG && !pmVisualIsVisual()) return true;
     1015    if (!pmVisualTestLevel("psphot.psf.sat", 3)) return true;
    9971016
    9981017    int myKapa = psphotKapaChannel (3);
     
    10231042    for (int i = 0; i < sources->n; i++) {
    10241043
    1025         pmSource *source = sources->data[i];
    1026 
    1027         // only show "real" saturated stars (not defects)
    1028         if (!(source->mode & PM_SOURCE_MODE_SATSTAR)) continue;;
    1029         if (source->mode & PM_SOURCE_MODE_DEFECT) continue;;
    1030 
    1031         // how does this subimage get placed into the output image?
    1032         // DX = source->pixels->numCols
    1033         // DY = source->pixels->numRows
    1034 
    1035         if (dX + DX > NX) {
    1036             // too wide for the rest of this row
    1037             if (dX == 0) {
    1038                 // alone on this row
    1039                 NY += DY;
    1040                 dX = 0;
    1041                 dY = 0;
    1042             } else {
    1043                 // start the next row
    1044                 NY += dY;
    1045                 dX = DX;
    1046                 dY = DY;
    1047             }
    1048         } else {
    1049             // extend this row
    1050             dX += DX;
    1051             dY = PS_MAX (dY, DY);
    1052         }
     1044        pmSource *source = sources->data[i];
     1045
     1046        // only show "real" saturated stars (not defects)
     1047        if (!(source->mode & PM_SOURCE_MODE_SATSTAR)) continue;;
     1048        if (source->mode & PM_SOURCE_MODE_DEFECT) continue;;
     1049
     1050        // how does this subimage get placed into the output image?
     1051        // DX = source->pixels->numCols
     1052        // DY = source->pixels->numRows
     1053
     1054        if (dX + DX > NX) {
     1055            // too wide for the rest of this row
     1056            if (dX == 0) {
     1057                // alone on this row
     1058                NY += DY;
     1059                dX = 0;
     1060                dY = 0;
     1061            } else {
     1062                // start the next row
     1063                NY += dY;
     1064                dX = DX;
     1065                dY = DY;
     1066            }
     1067        } else {
     1068            // extend this row
     1069            dX += DX;
     1070            dY = PS_MAX (dY, DY);
     1071        }
    10531072    }
    10541073    NY += DY;
     
    10681087    for (int i = 0; i < sources->n; i++) {
    10691088
    1070         pmSource *source = sources->data[i];
    1071 
    1072         // only show "real" saturated stars (not defects)
    1073         if (!(source->mode & PM_SOURCE_MODE_SATSTAR)) continue;;
    1074         if (source->mode & PM_SOURCE_MODE_DEFECT) continue;;
    1075         nSAT ++;
    1076 
    1077         if (Xo + DX > NX) {
    1078             // too wide for the rest of this row
    1079             if (Xo == 0) {
    1080                 // place source alone on this row
    1081                 bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
    1082                 if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    1083                 psphotMosaicSubimage (outsat, source, Xo, Yo, DX, DY, false);
    1084                 if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    1085 
    1086                 Yo += DY;
    1087                 Xo = 0;
    1088                 dY = 0;
    1089             } else {
    1090                 // start the next row
    1091                 Yo += dY;
    1092                 Xo = 0;
    1093 
    1094                 bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
    1095                 if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    1096                 psphotMosaicSubimage (outsat, source, Xo, Yo, DX, DY, false);
    1097                 if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    1098 
    1099                 Xo = DX;
    1100                 dY = DY;
    1101             }
    1102         } else {
    1103             // extend this row
    1104             bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
    1105             if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    1106             psphotMosaicSubimage (outsat, source, Xo, Yo, DX, DY, false);
    1107             if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    1108 
    1109             Xo += DX;
    1110             dY = PS_MAX (dY, DY);
    1111         }
     1089        pmSource *source = sources->data[i];
     1090
     1091        // only show "real" saturated stars (not defects)
     1092        if (!(source->mode & PM_SOURCE_MODE_SATSTAR)) continue;;
     1093        if (source->mode & PM_SOURCE_MODE_DEFECT) continue;;
     1094        nSAT ++;
     1095
     1096        if (Xo + DX > NX) {
     1097            // too wide for the rest of this row
     1098            if (Xo == 0) {
     1099                // place source alone on this row
     1100                bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     1101                if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
     1102                psphotMosaicSubimage (outsat, source, Xo, Yo, DX, DY, false);
     1103                if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
     1104
     1105                Yo += DY;
     1106                Xo = 0;
     1107                dY = 0;
     1108            } else {
     1109                // start the next row
     1110                Yo += dY;
     1111                Xo = 0;
     1112
     1113                bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     1114                if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
     1115                psphotMosaicSubimage (outsat, source, Xo, Yo, DX, DY, false);
     1116                if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
     1117
     1118                Xo = DX;
     1119                dY = DY;
     1120            }
     1121        } else {
     1122            // extend this row
     1123            bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     1124            if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
     1125            psphotMosaicSubimage (outsat, source, Xo, Yo, DX, DY, false);
     1126            if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
     1127
     1128            Xo += DX;
     1129            dY = PS_MAX (dY, DY);
     1130        }
    11121131    }
    11131132
     
    11511170    float Yo = source->modelPSF->params->data.F32[PM_PAR_YPOS] - source->pixels->row0;
    11521171    for (int iy = 0; iy < source->pixels->numRows; iy++) {
    1153         for (int ix = 0; ix < source->pixels->numCols; ix++) {
    1154             if (source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix]) {
    1155                 rb->data.F32[nb] = hypot (ix + 0.5 - Xo, iy + 0.5 - Yo) ;
    1156                 // rb->data.F32[nb] = hypot (ix - Xo, iy - Yo) ;
    1157                 Rb->data.F32[nb] = log10(rb->data.F32[nb]);
    1158                 fb->data.F32[nb] = log10(source->pixels->data.F32[iy][ix]);
    1159                 nb++;
    1160             } else {
    1161                 rg->data.F32[ng] = hypot (ix + 0.5 - Xo, iy + 0.5 - Yo) ;
    1162                 // rg->data.F32[ng] = hypot (ix - Xo, iy - Yo) ;
    1163                 Rg->data.F32[ng] = log10(rg->data.F32[ng]);
    1164                 fg->data.F32[ng] = log10(source->pixels->data.F32[iy][ix]);
    1165                 ng++;
    1166             }
    1167         }
     1172        for (int ix = 0; ix < source->pixels->numCols; ix++) {
     1173            if (source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix]) {
     1174                rb->data.F32[nb] = hypot (ix + 0.5 - Xo, iy + 0.5 - Yo) ;
     1175                // rb->data.F32[nb] = hypot (ix - Xo, iy - Yo) ;
     1176                Rb->data.F32[nb] = log10(rb->data.F32[nb]);
     1177                fb->data.F32[nb] = log10(source->pixels->data.F32[iy][ix]);
     1178                nb++;
     1179            } else {
     1180                rg->data.F32[ng] = hypot (ix + 0.5 - Xo, iy + 0.5 - Yo) ;
     1181                // rg->data.F32[ng] = hypot (ix - Xo, iy - Yo) ;
     1182                Rg->data.F32[ng] = log10(rg->data.F32[ng]);
     1183                fg->data.F32[ng] = log10(source->pixels->data.F32[iy][ix]);
     1184                ng++;
     1185            }
     1186        }
    11681187    }
    11691188
     
    13581377    KapaSection section;  // put the positive profile in one and the residuals in another?
    13591378
    1360     if (!DEBUG && !pmVisualIsVisual()) return true;
     1379    if (!pmVisualTestLevel("psphot.profiles", 3)) return true;
    13611380
    13621381    int myKapa = psphotKapaChannel (2);
     
    13941413    for (int i = 0; i < sources->n; i++) {
    13951414
    1396         pmSource *source = sources->data[i];
    1397         if (!(source->mode & PM_SOURCE_MODE_PSFSTAR)) continue;
    1398 
    1399         psphotVisualPlotRadialProfile (myKapa, source, maskVal);
    1400 
    1401         // pause and wait for user input:
    1402         // continue, save (provide name), ??
    1403         char key[10];
    1404         fprintf (stdout, "[e]rase and continue? [o]verplot and continue? [s]kip rest of stars? : ");
    1405         if (!fgets(key, 8, stdin)) {
    1406             psWarning("Unable to read option");
    1407         }
    1408         if (key[0] == 'e') {
    1409             KapaClearPlots (myKapa);
    1410         }
    1411         if (key[0] == 's') {
    1412             break;
    1413         }
     1415        pmSource *source = sources->data[i];
     1416        if (!(source->mode & PM_SOURCE_MODE_PSFSTAR)) continue;
     1417
     1418        psphotVisualPlotRadialProfile (myKapa, source, maskVal);
     1419
     1420        // pause and wait for user input:
     1421        // continue, save (provide name), ??
     1422        char key[10];
     1423        fprintf (stdout, "[e]rase and continue? [o]verplot and continue? [s]kip rest of stars? : ");
     1424        if (!fgets(key, 8, stdin)) {
     1425            psWarning("Unable to read option");
     1426        }
     1427        if (key[0] == 'e') {
     1428            KapaClearPlots (myKapa);
     1429        }
     1430        if (key[0] == 's') {
     1431            break;
     1432        }
    14141433    }
    14151434
     
    14291448    return true;
    14301449
    1431     if (!DEBUG && !pmVisualIsVisual()) return true;
     1450    if (!pmVisualTestLevel("psphot.objects.flags", 3)) return true;
    14321451
    14331452    int myKapa = psphotKapaChannel (1);
     
    14451464    for (int i = 0; i < sources->n; i++) {
    14461465
    1447         float Xo, Yo, Rmaj, Rmin, cs, sn;
    1448 
    1449         pmSource *source = sources->data[i];
    1450         if (source == NULL) continue;
    1451 
    1452         pmMoments *moments = source->moments;
    1453         if (0) {
    1454             emoments.x2 = moments->Mxx;
    1455             emoments.y2 = moments->Myy;
    1456             emoments.xy = moments->Mxy;
    1457             Xo = moments->Mx;
    1458             Yo = moments->My;
    1459 
    1460             axes = psEllipseMomentsToAxes (emoments, 20.0);
    1461             Rmaj = 2.0*axes.major;
    1462             Rmin = 2.0*axes.minor;
    1463             cs = cos(axes.theta);
    1464             sn = sin(axes.theta);
    1465         } else {
    1466             Rmaj = Rmin = 5.0;
    1467             cs = 1.0;
    1468             sn = 0.0;
    1469             Xo = source->peak->xf;
    1470             Yo = source->peak->yf;
    1471         }
    1472 
    1473         unsigned short int flagMask = 0x01;
    1474         for (int j = 0; j < 8; j++) {
    1475             if (source->mode & flagMask) {
    1476                 overlayE[NoverlayE].type = KII_OVERLAY_LINE;
    1477                 overlayE[NoverlayE].x = Xo;
    1478                 overlayE[NoverlayE].y = Yo;
    1479 
    1480                 float phi = j*M_PI/4.0;
    1481                 overlayE[NoverlayE].dx = +Rmaj*cos(phi)*cs - Rmin*sin(phi)*sn;
    1482                 overlayE[NoverlayE].dy = +Rmaj*cos(phi)*sn + Rmin*sin(phi)*cs;
    1483                 overlayE[NoverlayE].angle = 0;
    1484                 overlayE[NoverlayE].text = NULL;
    1485                 NoverlayE ++;
    1486                 CHECK_REALLOCATE (overlayE, KiiOverlay, NOVERLAYE, NoverlayE, 100);
    1487             }
    1488             flagMask <<= 1;
    1489 
    1490             if (source->mode & flagMask) {
    1491                 overlayO[NoverlayO].type = KII_OVERLAY_LINE;
    1492                 overlayO[NoverlayO].x = Xo + 1;
    1493                 overlayO[NoverlayO].y = Yo;
    1494 
    1495                 float phi = j*M_PI/4.0;
    1496                 overlayO[NoverlayO].dx = +Rmaj*cos(phi)*cs - Rmin*sin(phi)*sn;
    1497                 overlayO[NoverlayO].dy = +Rmaj*cos(phi)*sn + Rmin*sin(phi)*cs;
    1498                 overlayO[NoverlayO].angle = 0;
    1499                 overlayO[NoverlayO].text = NULL;
    1500                 NoverlayO ++;
    1501                 CHECK_REALLOCATE (overlayO, KiiOverlay, NOVERLAYO, NoverlayO, 100);
    1502             }
    1503             flagMask <<= 1;
    1504         }
     1466        float Xo, Yo, Rmaj, Rmin, cs, sn;
     1467
     1468        pmSource *source = sources->data[i];
     1469        if (source == NULL) continue;
     1470
     1471        pmMoments *moments = source->moments;
     1472        if (0) {
     1473            emoments.x2 = moments->Mxx;
     1474            emoments.y2 = moments->Myy;
     1475            emoments.xy = moments->Mxy;
     1476            Xo = moments->Mx;
     1477            Yo = moments->My;
     1478
     1479            axes = psEllipseMomentsToAxes (emoments, 20.0);
     1480            Rmaj = 2.0*axes.major;
     1481            Rmin = 2.0*axes.minor;
     1482            cs = cos(axes.theta);
     1483            sn = sin(axes.theta);
     1484        } else {
     1485            Rmaj = Rmin = 5.0;
     1486            cs = 1.0;
     1487            sn = 0.0;
     1488            Xo = source->peak->xf;
     1489            Yo = source->peak->yf;
     1490        }
     1491
     1492        unsigned short int flagMask = 0x01;
     1493        for (int j = 0; j < 8; j++) {
     1494            if (source->mode & flagMask) {
     1495                overlayE[NoverlayE].type = KII_OVERLAY_LINE;
     1496                overlayE[NoverlayE].x = Xo;
     1497                overlayE[NoverlayE].y = Yo;
     1498
     1499                float phi = j*M_PI/4.0;
     1500                overlayE[NoverlayE].dx = +Rmaj*cos(phi)*cs - Rmin*sin(phi)*sn;
     1501                overlayE[NoverlayE].dy = +Rmaj*cos(phi)*sn + Rmin*sin(phi)*cs;
     1502                overlayE[NoverlayE].angle = 0;
     1503                overlayE[NoverlayE].text = NULL;
     1504                NoverlayE ++;
     1505                CHECK_REALLOCATE (overlayE, KiiOverlay, NOVERLAYE, NoverlayE, 100);
     1506            }
     1507            flagMask <<= 1;
     1508
     1509            if (source->mode & flagMask) {
     1510                overlayO[NoverlayO].type = KII_OVERLAY_LINE;
     1511                overlayO[NoverlayO].x = Xo + 1;
     1512                overlayO[NoverlayO].y = Yo;
     1513
     1514                float phi = j*M_PI/4.0;
     1515                overlayO[NoverlayO].dx = +Rmaj*cos(phi)*cs - Rmin*sin(phi)*sn;
     1516                overlayO[NoverlayO].dy = +Rmaj*cos(phi)*sn + Rmin*sin(phi)*cs;
     1517                overlayO[NoverlayO].angle = 0;
     1518                overlayO[NoverlayO].text = NULL;
     1519                NoverlayO ++;
     1520                CHECK_REALLOCATE (overlayO, KiiOverlay, NOVERLAYO, NoverlayO, 100);
     1521            }
     1522            flagMask <<= 1;
     1523        }
    15051524    }
    15061525
     
    15311550    for (int i = 0; i < sources->n; i++) {
    15321551
    1533         pmSource *source = sources->data[i];
    1534         if (source == NULL) continue;
    1535 
    1536         if (mode) {
    1537             if (keep) {
    1538                 if (!(source->mode & mode)) continue;
    1539             } else {
    1540                 if (source->mode & mode) continue;
    1541             }
    1542         }
    1543 
    1544         pmMoments *moments = source->moments;
    1545         if (moments == NULL) continue;
    1546 
    1547         overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
    1548         overlay[Noverlay].x = moments->Mx;
    1549         overlay[Noverlay].y = moments->My;
    1550 
    1551         emoments.x2 = moments->Mxx;
    1552         emoments.y2 = moments->Myy;
    1553         emoments.xy = moments->Mxy;
    1554 
    1555         axes = psEllipseMomentsToAxes (emoments, 20.0);
    1556 
    1557         overlay[Noverlay].dx = scale*2.0*axes.major;
    1558         overlay[Noverlay].dy = scale*2.0*axes.minor;
    1559         overlay[Noverlay].angle = axes.theta * PS_DEG_RAD;
    1560         overlay[Noverlay].text = NULL;
    1561         Noverlay ++;
     1552        pmSource *source = sources->data[i];
     1553        if (source == NULL) continue;
     1554
     1555        if (mode) {
     1556            if (keep) {
     1557                if (!(source->mode & mode)) continue;
     1558            } else {
     1559                if (source->mode & mode) continue;
     1560            }
     1561        }
     1562
     1563        pmMoments *moments = source->moments;
     1564        if (moments == NULL) continue;
     1565
     1566        overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
     1567        overlay[Noverlay].x = moments->Mx;
     1568        overlay[Noverlay].y = moments->My;
     1569
     1570        emoments.x2 = moments->Mxx;
     1571        emoments.y2 = moments->Myy;
     1572        emoments.xy = moments->Mxy;
     1573
     1574        axes = psEllipseMomentsToAxes (emoments, 20.0);
     1575
     1576        overlay[Noverlay].dx = scale*2.0*axes.major;
     1577        overlay[Noverlay].dy = scale*2.0*axes.minor;
     1578        overlay[Noverlay].angle = axes.theta * PS_DEG_RAD;
     1579        overlay[Noverlay].text = NULL;
     1580        Noverlay ++;
    15621581    }
    15631582
     
    15701589bool psphotVisualShowSourceSize (pmReadout *readout, psArray *sources) {
    15711590
    1572     if (!DEBUG && !pmVisualIsVisual()) return true;
     1591    if (!pmVisualTestLevel("psphot.objects.size", 2)) return true;
    15731592
    15741593    int myKapa = psphotKapaChannel (1);
     
    15971616    KapaSection section;
    15981617
    1599     if (!DEBUG && !pmVisualIsVisual()) return true;
     1618    if (!pmVisualTestLevel("psphot.size", 2)) return true;
    16001619
    16011620    int myKapa = psphotKapaChannel (2);
     
    16121631    float Ymin = 1000.0, Ymax = 0.0;
    16131632    {
    1614         int nRegions = psMetadataLookupS32 (&status, analysis, "PSF.CLUMP.NREGIONS");
    1615         for (int n = 0; n < nRegions; n++) {
    1616 
    1617             char regionName[64];
    1618             snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", n);
    1619             psMetadata *regionMD = psMetadataLookupPtr (&status, analysis, regionName);
    1620 
    1621             float psfX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");
    1622             float psfY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y");
    1623             float psfdX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX");
    1624             float psfdY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY");
    1625 
    1626             float X0 = psfX - 10.0*psfdX;
    1627             float X1 = psfX + 10.0*psfdX;
    1628             float Y0 = psfY - 10.0*psfdY;
    1629             float Y1 = psfY + 10.0*psfdY;
    1630 
    1631             if (isfinite(X0)) { Xmin = PS_MIN(Xmin, X0); }
    1632             if (isfinite(X1)) { Xmax = PS_MAX(Xmax, X1); }
    1633             if (isfinite(Y0)) { Ymin = PS_MIN(Ymin, Y0); }
    1634             if (isfinite(Y1)) { Ymax = PS_MAX(Ymax, Y1); }
    1635         }
     1633        int nRegions = psMetadataLookupS32 (&status, analysis, "PSF.CLUMP.NREGIONS");
     1634        for (int n = 0; n < nRegions; n++) {
     1635
     1636            char regionName[64];
     1637            snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", n);
     1638            psMetadata *regionMD = psMetadataLookupPtr (&status, analysis, regionName);
     1639
     1640            float psfX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");
     1641            float psfY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y");
     1642            float psfdX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX");
     1643            float psfdY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY");
     1644
     1645            float X0 = psfX - 10.0*psfdX;
     1646            float X1 = psfX + 10.0*psfdX;
     1647            float Y0 = psfY - 10.0*psfdY;
     1648            float Y1 = psfY + 10.0*psfdY;
     1649
     1650            if (isfinite(X0)) { Xmin = PS_MIN(Xmin, X0); }
     1651            if (isfinite(X1)) { Xmax = PS_MAX(Xmax, X1); }
     1652            if (isfinite(Y0)) { Ymin = PS_MIN(Ymin, Y0); }
     1653            if (isfinite(Y1)) { Ymax = PS_MAX(Ymax, Y1); }
     1654        }
    16361655    }
    16371656    Xmin = PS_MAX(Xmin, -0.1);
     
    16771696    int nCR  = 0;
    16781697    for (int i = 0; i < sources->n; i++) {
    1679         pmSource *source = sources->data[i];
    1680         if (source->moments == NULL) continue;
     1698        pmSource *source = sources->data[i];
     1699        if (source->moments == NULL) continue;
    16811700
    16821701        // only plot the measured sources...
    1683         if (!(source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED)) continue;
    1684 
    1685         if (source->mode & PM_SOURCE_MODE_CR_LIMIT) {
    1686             xCR->data.F32[nCR] = source->moments->Mxx;
    1687             yCR->data.F32[nCR] = source->moments->Myy;
    1688             mCR->data.F32[nCR] = -2.5*log10(source->moments->Sum);
    1689             sCR->data.F32[nCR] = source->extNsigma;
    1690             nCR++;
    1691         }
    1692         if (source->mode & PM_SOURCE_MODE_SATSTAR) {
    1693             xSAT->data.F32[nSAT] = source->moments->Mxx;
    1694             ySAT->data.F32[nSAT] = source->moments->Myy;
    1695             mSAT->data.F32[nSAT] = -2.5*log10(source->moments->Sum);
    1696             sSAT->data.F32[nSAT] = source->extNsigma;
    1697             nSAT++;
    1698         }
    1699         if (source->mode & PM_SOURCE_MODE_EXT_LIMIT) {
    1700             xEXT->data.F32[nEXT] = source->moments->Mxx;
    1701             yEXT->data.F32[nEXT] = source->moments->Myy;
    1702             mEXT->data.F32[nEXT] = -2.5*log10(source->moments->Sum);
    1703             sEXT->data.F32[nEXT] = source->extNsigma;
    1704             nEXT++;
    1705             continue;
    1706         }
    1707         if (source->mode & PM_SOURCE_MODE_DEFECT) {
    1708             xDEF->data.F32[nDEF] = source->moments->Mxx;
    1709             yDEF->data.F32[nDEF] = source->moments->Myy;
    1710             mDEF->data.F32[nDEF] = -2.5*log10(source->moments->Sum);
    1711             sDEF->data.F32[nDEF] = source->extNsigma;
    1712             nDEF++;
    1713             continue;
    1714         }
    1715         if (source->errMag > 0.1) {
    1716             xLOW->data.F32[nLOW] = source->moments->Mxx;
    1717             yLOW->data.F32[nLOW] = source->moments->Myy;
    1718             mLOW->data.F32[nLOW] = -2.5*log10(source->moments->Sum);
    1719             sLOW->data.F32[nLOW] = source->extNsigma;
    1720             nLOW++;
    1721             continue;
    1722         }
    1723         xPSF->data.F32[nPSF] = source->moments->Mxx;
    1724         yPSF->data.F32[nPSF] = source->moments->Myy;
    1725         mPSF->data.F32[nPSF] = -2.5*log10(source->moments->Sum);
    1726         sPSF->data.F32[nPSF] = source->extNsigma;
    1727         nPSF++;
     1702        if (!(source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED)) continue;
     1703
     1704        if (source->mode & PM_SOURCE_MODE_CR_LIMIT) {
     1705            xCR->data.F32[nCR] = source->moments->Mxx;
     1706            yCR->data.F32[nCR] = source->moments->Myy;
     1707            mCR->data.F32[nCR] = -2.5*log10(source->moments->Sum);
     1708            sCR->data.F32[nCR] = source->extNsigma;
     1709            nCR++;
     1710        }
     1711        if (source->mode & PM_SOURCE_MODE_SATSTAR) {
     1712            xSAT->data.F32[nSAT] = source->moments->Mxx;
     1713            ySAT->data.F32[nSAT] = source->moments->Myy;
     1714            mSAT->data.F32[nSAT] = -2.5*log10(source->moments->Sum);
     1715            sSAT->data.F32[nSAT] = source->extNsigma;
     1716            nSAT++;
     1717        }
     1718        if (source->mode & PM_SOURCE_MODE_EXT_LIMIT) {
     1719            xEXT->data.F32[nEXT] = source->moments->Mxx;
     1720            yEXT->data.F32[nEXT] = source->moments->Myy;
     1721            mEXT->data.F32[nEXT] = -2.5*log10(source->moments->Sum);
     1722            sEXT->data.F32[nEXT] = source->extNsigma;
     1723            nEXT++;
     1724            continue;
     1725        }
     1726        if (source->mode & PM_SOURCE_MODE_DEFECT) {
     1727            xDEF->data.F32[nDEF] = source->moments->Mxx;
     1728            yDEF->data.F32[nDEF] = source->moments->Myy;
     1729            mDEF->data.F32[nDEF] = -2.5*log10(source->moments->Sum);
     1730            sDEF->data.F32[nDEF] = source->extNsigma;
     1731            nDEF++;
     1732            continue;
     1733        }
     1734        if (source->errMag > 0.1) {
     1735            xLOW->data.F32[nLOW] = source->moments->Mxx;
     1736            yLOW->data.F32[nLOW] = source->moments->Myy;
     1737            mLOW->data.F32[nLOW] = -2.5*log10(source->moments->Sum);
     1738            sLOW->data.F32[nLOW] = source->extNsigma;
     1739            nLOW++;
     1740            continue;
     1741        }
     1742        xPSF->data.F32[nPSF] = source->moments->Mxx;
     1743        yPSF->data.F32[nPSF] = source->moments->Myy;
     1744        mPSF->data.F32[nPSF] = -2.5*log10(source->moments->Sum);
     1745        sPSF->data.F32[nPSF] = source->extNsigma;
     1746        nPSF++;
    17281747    }
    17291748
     
    20292048    // draw N circles to outline the clumps
    20302049    {
    2031         KapaSelectSection (myKapa, "MxxMyy");
    2032 
    2033         // draw a circle centered on psfX,Y with size of the psf limit
    2034         psVector *xLimit  = psVectorAlloc (120, PS_TYPE_F32);
    2035         psVector *yLimit  = psVectorAlloc (120, PS_TYPE_F32);
    2036 
    2037         int nRegions = psMetadataLookupS32 (&status, analysis, "PSF.CLUMP.NREGIONS");
    2038         float PSF_CLUMP_NSIGMA = psMetadataLookupF32 (&status, recipe, "PSF_CLUMP_NSIGMA");
    2039 
    2040         graphdata.color = KapaColorByName ("blue");
    2041         graphdata.style = 0;
    2042 
    2043         graphdata.xmin = Xmin;
    2044         graphdata.ymin = Ymin;
    2045         graphdata.xmax = Xmax;
    2046         graphdata.ymax = Ymax;
    2047         KapaSetLimits (myKapa, &graphdata);
    2048 
    2049         for (int n = 0; n < nRegions; n++) {
    2050 
    2051             char regionName[64];
    2052             snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", n);
    2053             psMetadata *regionMD = psMetadataLookupPtr (&status, analysis, regionName);
    2054 
    2055             float psfX  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");
    2056             float psfY  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y");
    2057             float psfdX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX");
    2058             float psfdY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY");
    2059             float Rx = psfdX * PSF_CLUMP_NSIGMA;
    2060             float Ry = psfdY * PSF_CLUMP_NSIGMA;
    2061 
    2062             for (int i = 0; i < xLimit->n; i++) {
    2063                 xLimit->data.F32[i] = Rx*cos(i*2.0*M_PI/120.0) + psfX;
    2064                 yLimit->data.F32[i] = Ry*sin(i*2.0*M_PI/120.0) + psfY;
    2065             }
    2066             KapaPrepPlot (myKapa, xLimit->n, &graphdata);
    2067             KapaPlotVector (myKapa, xLimit->n, xLimit->data.F32, "x");
    2068             KapaPlotVector (myKapa, yLimit->n, yLimit->data.F32, "y");
    2069         }
    2070         psFree (xLimit);
    2071         psFree (yLimit);
     2050        KapaSelectSection (myKapa, "MxxMyy");
     2051
     2052        // draw a circle centered on psfX,Y with size of the psf limit
     2053        psVector *xLimit  = psVectorAlloc (120, PS_TYPE_F32);
     2054        psVector *yLimit  = psVectorAlloc (120, PS_TYPE_F32);
     2055
     2056        int nRegions = psMetadataLookupS32 (&status, analysis, "PSF.CLUMP.NREGIONS");
     2057        float PSF_CLUMP_NSIGMA = psMetadataLookupF32 (&status, recipe, "PSF_CLUMP_NSIGMA");
     2058
     2059        graphdata.color = KapaColorByName ("blue");
     2060        graphdata.style = 0;
     2061
     2062        graphdata.xmin = Xmin;
     2063        graphdata.ymin = Ymin;
     2064        graphdata.xmax = Xmax;
     2065        graphdata.ymax = Ymax;
     2066        KapaSetLimits (myKapa, &graphdata);
     2067
     2068        for (int n = 0; n < nRegions; n++) {
     2069
     2070            char regionName[64];
     2071            snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", n);
     2072            psMetadata *regionMD = psMetadataLookupPtr (&status, analysis, regionName);
     2073
     2074            float psfX  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");
     2075            float psfY  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y");
     2076            float psfdX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX");
     2077            float psfdY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY");
     2078            float Rx = psfdX * PSF_CLUMP_NSIGMA;
     2079            float Ry = psfdY * PSF_CLUMP_NSIGMA;
     2080
     2081            for (int i = 0; i < xLimit->n; i++) {
     2082                xLimit->data.F32[i] = Rx*cos(i*2.0*M_PI/120.0) + psfX;
     2083                yLimit->data.F32[i] = Ry*sin(i*2.0*M_PI/120.0) + psfY;
     2084            }
     2085            KapaPrepPlot (myKapa, xLimit->n, &graphdata);
     2086            KapaPlotVector (myKapa, xLimit->n, xLimit->data.F32, "x");
     2087            KapaPlotVector (myKapa, yLimit->n, yLimit->data.F32, "y");
     2088        }
     2089        psFree (xLimit);
     2090        psFree (yLimit);
    20722091    }
    20732092
     
    21082127bool psphotVisualShowResidualImage (pmReadout *readout) {
    21092128
    2110     if (!DEBUG && !pmVisualIsVisual()) return true;
     2129    if (!pmVisualTestLevel("psphot.image.resid", 2)) return true;
    21112130
    21122131    int myKapa = psphotKapaChannel (1);
     
    21242143    float lineX[2], lineY[2];
    21252144
    2126     if (!DEBUG && !pmVisualIsVisual()) return true;
     2145    if (!pmVisualTestLevel("psphot.apresid", 1)) return true;
    21272146
    21282147    int myKapa = psphotKapaChannel (2);
     
    21442163    int n = 0;
    21452164    for (int i = 0; i < sources->n; i++) {
    2146         pmSource *source = sources->data[i];
    2147         if (!source) continue;
    2148         if (source->type != PM_SOURCE_TYPE_STAR) continue;
    2149         if (!isfinite (source->apMag)) continue;
    2150         if (!isfinite (source->psfMag)) continue;
    2151 
    2152         x->data.F32[n] = source->psfMag;
    2153         y->data.F32[n] = source->apMag - source->psfMag;
    2154         dy->data.F32[n] = source->errMag;
    2155         graphdata.xmin = PS_MIN(graphdata.xmin, x->data.F32[n]);
    2156         graphdata.xmax = PS_MAX(graphdata.xmax, x->data.F32[n]);
    2157         graphdata.ymin = PS_MIN(graphdata.ymin, y->data.F32[n]);
    2158         graphdata.ymax = PS_MAX(graphdata.ymax, y->data.F32[n]);
    2159 
    2160         n++;
     2165        pmSource *source = sources->data[i];
     2166        if (!source) continue;
     2167        if (source->type != PM_SOURCE_TYPE_STAR) continue;
     2168        if (!isfinite (source->apMag)) continue;
     2169        if (!isfinite (source->psfMag)) continue;
     2170
     2171        x->data.F32[n] = source->psfMag;
     2172        y->data.F32[n] = source->apMag - source->psfMag;
     2173        dy->data.F32[n] = source->errMag;
     2174        graphdata.xmin = PS_MIN(graphdata.xmin, x->data.F32[n]);
     2175        graphdata.xmax = PS_MAX(graphdata.xmax, x->data.F32[n]);
     2176        graphdata.ymin = PS_MIN(graphdata.ymin, y->data.F32[n]);
     2177        graphdata.ymax = PS_MAX(graphdata.ymax, y->data.F32[n]);
     2178
     2179        n++;
    21612180    }
    21622181    x->n = y->n = dy->n = n;
     
    22422261    Graphdata graphdata;
    22432262
    2244     if (!DEBUG && !pmVisualIsVisual()) return true;
     2263    if (!pmVisualTestLevel("psphot.chisq", 1)) return true;
    22452264
    22462265    int myKapa = psphotKapaChannel (2);
     
    22632282    int n = 0;
    22642283    for (int i = 0; i < sources->n; i++) {
    2265         pmSource *source = sources->data[i];
    2266         if (!source) continue;
    2267         if (source->type != PM_SOURCE_TYPE_STAR) continue;
    2268         if (!source->moments) continue;
    2269         if (!isfinite(source->moments->Sum)) continue;
    2270         if (!source->modelPSF) continue;
    2271         if (!isfinite(source->modelPSF->chisq)) continue;
    2272 
    2273         x->data.F32[n] = -2.5*log10(source->moments->Sum);
    2274         y->data.F32[n] = source->modelPSF->chisq / source->modelPSF->nDOF;
    2275         graphdata.xmin = PS_MIN(graphdata.xmin, x->data.F32[n]);
    2276         graphdata.xmax = PS_MAX(graphdata.xmax, x->data.F32[n]);
    2277         graphdata.ymin = PS_MIN(graphdata.ymin, y->data.F32[n]);
    2278         graphdata.ymax = PS_MAX(graphdata.ymax, y->data.F32[n]);
    2279 
    2280         fprintf (f, "%d %d %f %f\n", i, n, x->data.F32[n], y->data.F32[n]);
    2281 
    2282         n++;
     2284        pmSource *source = sources->data[i];
     2285        if (!source) continue;
     2286        if (source->type != PM_SOURCE_TYPE_STAR) continue;
     2287        if (!source->moments) continue;
     2288        if (!isfinite(source->moments->Sum)) continue;
     2289        if (!source->modelPSF) continue;
     2290        if (!isfinite(source->modelPSF->chisq)) continue;
     2291
     2292        x->data.F32[n] = -2.5*log10(source->moments->Sum);
     2293        y->data.F32[n] = source->modelPSF->chisq / source->modelPSF->nDOF;
     2294        graphdata.xmin = PS_MIN(graphdata.xmin, x->data.F32[n]);
     2295        graphdata.xmax = PS_MAX(graphdata.xmax, x->data.F32[n]);
     2296        graphdata.ymin = PS_MIN(graphdata.ymin, y->data.F32[n]);
     2297        graphdata.ymax = PS_MAX(graphdata.ymax, y->data.F32[n]);
     2298
     2299        fprintf (f, "%d %d %f %f\n", i, n, x->data.F32[n], y->data.F32[n]);
     2300
     2301        n++;
    22832302    }
    22842303    x->n = y->n = n;
     
    23262345    KiiOverlay *overlay;
    23272346
    2328     if (!DEBUG && !pmVisualIsVisual()) return true;
     2347    if (!pmVisualTestLevel("psphot.objects.petro", 2)) return true;
    23292348
    23302349    int kapa = psphotKapaChannel (1);
     
    23362355
    23372356    for (int i = 0; i < sources->n; i++) {
    2338         pmSource *source = sources->data[i];
    2339 
    2340         if (!source) continue;
    2341         if (!source->extpars) continue;
    2342         if (!source->extpars->petProfile) continue;
    2343 
    2344         float petrosianRadius = source->extpars->petrosianRadius;
     2357        pmSource *source = sources->data[i];
     2358
     2359        if (!source) continue;
     2360        if (!source->extpars) continue;
     2361        if (!source->extpars->petProfile) continue;
     2362
     2363        float petrosianRadius = source->extpars->petrosianRadius;
    23452364        psEllipseAxes *axes = &source->extpars->axes;
    23462365
    2347         overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
    2348         overlay[Noverlay].x = source->peak->xf;
    2349         overlay[Noverlay].y = source->peak->yf;
    2350         overlay[Noverlay].dx = 1.0*petrosianRadius;
    2351         overlay[Noverlay].dy = 1.0*petrosianRadius*axes->minor/axes->major;
    2352         overlay[Noverlay].angle = axes->theta * PS_DEG_RAD;
    2353         overlay[Noverlay].text = NULL;
    2354         Noverlay ++;
    2355         CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
    2356 
    2357         // overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
    2358         // overlay[Noverlay].x = source->peak->xf;
    2359         // overlay[Noverlay].y = source->peak->yf;
    2360         // overlay[Noverlay].dx = 2.0*petrosianRadius;
    2361         // overlay[Noverlay].dy = 2.0*petrosianRadius*axes->minor/axes->major;
    2362         // overlay[Noverlay].angle = axes->theta * PS_DEG_RAD;
    2363         // overlay[Noverlay].text = NULL;
    2364         // Noverlay ++;
    2365         // CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
     2366        overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
     2367        overlay[Noverlay].x = source->peak->xf;
     2368        overlay[Noverlay].y = source->peak->yf;
     2369        overlay[Noverlay].dx = 1.0*petrosianRadius;
     2370        overlay[Noverlay].dy = 1.0*petrosianRadius*axes->minor/axes->major;
     2371        overlay[Noverlay].angle = axes->theta * PS_DEG_RAD;
     2372        overlay[Noverlay].text = NULL;
     2373        Noverlay ++;
     2374        CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
     2375
     2376        // overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
     2377        // overlay[Noverlay].x = source->peak->xf;
     2378        // overlay[Noverlay].y = source->peak->yf;
     2379        // overlay[Noverlay].dx = 2.0*petrosianRadius;
     2380        // overlay[Noverlay].dy = 2.0*petrosianRadius*axes->minor/axes->major;
     2381        // overlay[Noverlay].angle = axes->theta * PS_DEG_RAD;
     2382        // overlay[Noverlay].text = NULL;
     2383        // Noverlay ++;
     2384        // CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
    23662385    }
    23672386
Note: See TracChangeset for help on using the changeset viewer.