IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 26894


Ignore:
Timestamp:
Feb 10, 2010, 7:36:29 PM (16 years ago)
Author:
eugene
Message:

updates from eam_branches/20091201 (substantially changes to the psphotReadout APIs to support future stack photometry; improvements to the CR masking code)

Location:
trunk/psphot
Files:
49 edited
6 copied

Legend:

Unmodified
Added
Removed
  • trunk/psphot/doc/footprints.txt

    r17710 r26894  
     1
     22010.01.18
     3
     4  * we are having some problems with footprints being freed to early in the second pass
     5
     6  * footprint memory history:
     7
     8    * entering psphotFindFootprints, on the first pass, we have an
     9      array of detected peak in detections->peaks
     10
     11    * in pmFootprintsFind, footprints array owns allocated footprints
     12      footprints each own their spans
     13
     14    * from pmFootprintAssignPeaks:
     15      * the footprints have an array of peaks with valid memory references
     16      * the peaks have just the pointer to the corresponding footprint (not owned)
     17      * all peaks get assigned to a footprint
     18      * at end of pmFootprintAssignPeaks, only a single copy of each peak is/should be available from the collection of footprints
    119
    220pmFootprintCullPeaks is very expensive (15 - 30 msec per object) and
  • trunk/psphot/doc/stack.txt

    r24583 r26894  
     1
     220100126:
     3
     4  * watch out for psphotSetMomentsWindow & MOMENTS_SX_MAX,etc
     5  * watch out for psphotSignificanceImage.c:,psphotEfficiency using the FWHM_MAJ from psphotChoosePSF
     6    * ppSimDetections.c : SIGMA_SMOOTH
     7ppSmooth/src/ppSmoothReadout.c:    psMetadataAddF32(recipe, PS_LIST_TAIL, "EFFECTIVE_AREA", PS_META_REPLACE, "Effective Area", effArea);
     8ppSmooth/src/ppSmoothReadout.c:    psMetadataAddF32(recipe, PS_LIST_TAIL, "SIGNIFICANCE_SCALE_FACTOR", PS_META_REPLACE, "Signicance scale factor", factor);
     9
     10
     1120100120 : more stack processing mods:
     12
     13  there are a number of data collections generated during psphotReadout:
     14
     15  * detections (currently a structure containing multiple arrays)
     16  * sources (a psArray)
     17  * psf (the psf model structure)
     18 
     19  * new sources vs old sources:
     20    there is a sequence on the second pass in which we need to distinguish the sources
     21    from the first pass from those on the second pass:
     22
     23    - add noise (old sources only)
     24    - find detections
     25    - subtract noise (old sources only)
     26    - generate sources (new detections only)
     27    - source classifications (new sources only)
     28    - guess models (new sources only)
     29    - replace sources (old sources only)
     30    - merge sources (new + old -> sources)
     31
     32    currently we are distiguishing the old vs new based on different arrays.
     33    can we use the processing flags to distinguish the these cases and carry around
     34    only a single source list?
     35
     36    * detections->peaks holds the most recently detected set of peaks
     37      detections->oldPeaks holds the previous collection
     38
     39      detections->footprints holds the full set of merged footprints,
     40      including assigned peaks from the old and new set.
     41
     4220100107 : updates for stack processing
     43
     44  I am building a new version of psphot that operates on a set of
     45  images (eg, multi-filter or multi-epoch).  The assumptions are:
     46
     47  * each input image represents the same sky pixels : they are warped to a common frame.
     48  * each image has been previously processed, with the background
     49    subtracted (and the psf model determined?)
     50  * all planes are / can be loaded into memory at once (otherwise I
     51    need to add a lot of I/O layers)
     52
     53  psphot currently expects the pmFPAfile of interest to be available in
     54  config->files with the name PSPHOT.INPUT.  To update the code for
     55  stacks, I am extending this concept with the pmFPAfileSelectSingle
     56  API: config->files may contain multiple PSPHOT.INPUT entries, and
     57  functions which access this file / these files need to specify
     58  *which* image they want.  The number of PSPHOT.INPUT entries is
     59  saved in config->arguments as PSPHOT.INPUT.NUM (this can be
     60  generated from the filerule PSPHOT.INPUT for extension).
     61
     62  As a result, we need a number of wrapper functions which loop over
     63  all PSPHOT.INPUT.NUM entries and perform a particular operation on
     64  one of the entries.  Here are the functions which I have modified
     65  in this way (function -> child)
     66
     67  * psphotAddPhotcode -> psphotAddPhotcodeReadout
     68    * note that the photcode is now saved on readout->analysis
     69  * psphotSetMaskAndVariance -> psphotSetMaskAndVarianceReadout
     70  * psphotModelBackground -> psphotModelBackgroundReadoutFileIndex
     71  * psphotSubtractBackground -> psphotSubtractBackgroundReadout
     72
     73  side notes on
     74 
     75  * psphotModelBackground vs psphotBackgroundModel : I've renamed
     76    psphotBackgroundModel (used only by ppStack for now) to
     77    psphotModelBackgroundReadoutNoFile.  I've also named the
     78    single-readout version used by psphotModelBackground to
     79    psphotModelBackgroundReadoutFileIndex.  These two functions do the
     80    same thing, but psphotModelBackgroundReadoutNoFile does not save
     81    a pmFPAfile on config->files
     82
    183
    28420090606 : design notes on the multi-image photometry analysis
  • trunk/psphot/src/Makefile.am

    r25984 r26894  
    2525libpsphot_la_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
    2626
    27 bin_PROGRAMS = psphot psphotForced psphotMakePSF psphotTest psphotMomentsStudy
    28 # bin_PROGRAMS = psphotPetrosianStudy
    29 # bin_PROGRAMS = psphot
     27bin_PROGRAMS = psphot psphotForced psphotMakePSF
     28# bin_PROGRAMS = psphotPetrosianStudy psphotTest psphotMomentsStudy
    3029
    3130psphot_CFLAGS = $(PSPHOT_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
     
    4140psphotMakePSF_LDADD = libpsphot.la
    4241
    43 psphotTest_CFLAGS = $(PSPHOT_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
    44 psphotTest_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
    45 psphotTest_LDADD = libpsphot.la
    46 
    47 psphotMomentsStudy_CFLAGS = $(PSPHOT_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
    48 psphotMomentsStudy_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
    49 psphotMomentsStudy_LDADD = libpsphot.la
     42# psphotMomentsStudy_CFLAGS = $(PSPHOT_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
     43# psphotMomentsStudy_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
     44# psphotMomentsStudy_LDADD = libpsphot.la
    5045
    5146# psphotPetrosianStudy_CFLAGS = $(PSPHOT_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
    5247# psphotPetrosianStudy_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
    5348# psphotPetrosianStudy_LDADD = libpsphot.la
     49
     50# psphotTest_CFLAGS = $(PSPHOT_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
     51# psphotTest_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
     52# psphotTest_LDADD = libpsphot.la
    5453
    5554# standard psphot for generic photometry
     
    8281        psphotCleanup.c
    8382
    84 
    85 # psphot analysis of the detectability of specified positions
    86 psphotDetect_SOURCES =            \
    87         psphotDetect.c            \
    88         psphotDetectArguments.c   \
    89         psphotDetectParseCamera.c \
    90         psphotDetectImageLoop.c   \
    91         psphotDetectReadout.c     \
    92         psphotMosaicChip.c        \
    93         psphotCleanup.c
    94 
    95 psphotTest_SOURCES = \
    96         psphotTest.c
    97 
    98 psphotMomentsStudy_SOURCES = \
    99         psphotMomentsStudy.c
    100 
     83# # psphot analysis of the detectability of specified positions
     84# psphotDetect_SOURCES =            \
     85#         psphotDetect.c            \
     86#       psphotDetectArguments.c   \
     87#       psphotDetectParseCamera.c \
     88#       psphotDetectImageLoop.c   \
     89#       psphotDetectReadout.c     \
     90#       psphotMosaicChip.c        \
     91#       psphotCleanup.c
     92
     93# psphotTest_SOURCES = \
     94#         psphotTest.c
     95#
     96# psphotMomentsStudy_SOURCES = \
     97#         psphotMomentsStudy.c
     98#
    10199# psphotPetrosianStudy_SOURCES = \
    102100#         psphotPetrosianStudy.c
     
    146144        psphotKernelFromPSF.c          \
    147145        psphotPSFConvModel.c           \
    148         psphotModelTest.c              \
    149146        psphotFitSet.c                 \
    150147        psphotSourceFreePixels.c       \
     
    175172        psphotEfficiency.c
    176173
     174# XXX need to fix this for the new apis
     175#       psphotModelTest.c             
     176
    177177# re-instate these
    178178#       psphotIsophotal.c              \
  • trunk/psphot/src/psphot.h

    r25987 r26894  
    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
     16typedef struct {
     17    psImage *model;
     18    psArray *dmodels;
     19    psImage *modelConv;
     20    psArray *dmodelsConv;
     21} pmPCMData;
    1422
    1523// top-level psphot functions
     
    2937bool            psphotReadoutMinimal(pmConfig *config, const pmFPAview *view);
    3038
    31 bool            psphotReadoutCleanup (pmConfig *config, pmReadout *readout, psMetadata *recipe, pmDetections *detections, pmPSF *psf, psArray *sources);
     39bool            psphotReadoutCleanup (pmConfig *config, const pmFPAview *view);
     40bool            psphotReadoutCleanupReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe);
     41
    3242bool            psphotDefineFiles (pmConfig *config, pmFPAfile *input);
    3343void            psphotFilesActivate(pmConfig *config, bool state);
     
    3848// XXX test functions
    3949psArray        *psphotFakeSources (void);
     50bool            psphotMaskCosmicRayFootprintCheck (psArray *sources);
    4051
    4152// psphotReadout functions
    42 bool            psphotModelBackground (pmConfig *config, const pmFPAview *view, const char *filename);
    43 bool            psphotSubtractBackground (pmConfig *config, const pmFPAview *view, const char *filename) ;
    44 
    45 psImageBinning *psphotBackgroundBinning(const psImage *, const pmConfig *);
    46 
    47 pmDetections   *psphotFindDetections (pmDetections *detections, pmReadout *readout, psMetadata *recipe);
    48 
    49 bool            psphotRoughClass (pmReadout *readout, psArray *sources, psMetadata *recipe, const bool findPsfClump);
    50 bool            psphotBasicDeblend (psArray *sources, psMetadata *recipe);
    51 pmPSF          *psphotChoosePSF (pmReadout *readout, psArray *sources, psMetadata *recipe);
    52 bool            psphotPSFstats (pmReadout *readout, psMetadata *recipe, pmPSF *psf);
    53 bool            psphotMomentsStats (pmReadout *readout, psMetadata *recipe, psArray *sources);
    54 bool            psphotFitSourcesLinear (pmReadout *readout, psArray *sources, const psMetadata *recipe, const pmPSF *psf, bool final);
    55 bool            psphotReplaceUnfitSources (psArray *sources, psImageMaskType maskVal);
    56 
    57 bool            psphotReplaceAllSources (psArray *sources, psMetadata *recipe);
    58 bool            psphotRemoveAllSources (const psArray *sources, const psMetadata *recipe);
    59 
    60 bool            psphotBlendFit (pmConfig *config, pmReadout *readout, psArray *sources, pmPSF *psf);
     53bool            psphotAddPhotcode (pmConfig *config, const pmFPAview *view);
     54bool            psphotAddPhotcodeReadout (pmConfig *config, const pmFPAview *view, const char *filerule, int index);
     55
     56bool            psphotSetMaskAndVariance (pmConfig *config, const pmFPAview *view);
     57bool            psphotSetMaskAndVarianceReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe);
     58
     59bool            psphotModelBackground (pmConfig *config, const pmFPAview *view);
     60bool            psphotModelBackgroundReadoutFileIndex (pmConfig *config, const pmFPAview *view, const char *filename, int index);
     61
     62bool            psphotSubtractBackground (pmConfig *config, const pmFPAview *view);
     63bool            psphotSubtractBackgroundReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe);
     64
     65bool            psphotFindDetections (pmConfig *config, const pmFPAview *view, bool firstPass);
     66bool            psphotFindDetectionsReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe, bool firstPass);
     67
     68bool            psphotSourceStats (pmConfig *config, const pmFPAview *view, bool setWindow);
     69bool            psphotSourceStatsReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe, bool setWindow);
     70
     71bool            psphotDeblendSatstars (pmConfig *config, const pmFPAview *view);
     72bool            psphotDeblendSatstarsReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index);
     73
     74bool            psphotBasicDeblend (pmConfig *config, const pmFPAview *view);
     75bool            psphotBasicDeblendReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index);
     76
     77bool            psphotRoughClass (pmConfig *config, const pmFPAview *view);
     78bool            psphotRoughClassReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe);
     79bool            psphotRoughClassRegion (int nRegion, psRegion *region, psArray *sources, psMetadata *analysis, psMetadata *recipe, const bool havePSF);
     80
     81bool            psphotImageQuality (pmConfig *config, const pmFPAview *view);
     82bool            psphotImageQualityReadout(pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe);
     83
     84bool            psphotChoosePSF (pmConfig *config, const pmFPAview *view);
     85bool            psphotChoosePSFReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe);
     86
     87bool            psphotGuessModels (pmConfig *config, const pmFPAview *view);
     88bool            psphotGuessModelsReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index);
     89
     90bool            psphotMergeSources (pmConfig *config, const pmFPAview *view);
     91bool            psphotMergeSourcesReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index);
     92
     93bool            psphotFitSourcesLinear (pmConfig *config, const pmFPAview *view, bool final);
     94bool            psphotFitSourcesLinearReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, bool final);
     95
     96bool            psphotSourceSize (pmConfig *config, const pmFPAview *view, bool getPSFsize);
     97bool            psphotSourceSizeReadout(pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe, bool getPSFsize);
     98
     99bool            psphotBlendFit (pmConfig *config, const pmFPAview *view);
     100bool            psphotBlendFitReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe);
    61101bool            psphotBlendFit_Threaded (psThreadJob *job);
    62102
    63 bool            psphotSourceStatsUpdate (psArray *sources, pmConfig *config, pmReadout *readout);
    64 psArray        *psphotSourceStats (pmConfig *config, pmReadout *readout, pmDetections *detections, bool setWindow);
    65 bool            psphotSourceStats_Threaded (psThreadJob *job);
    66 
    67 bool            psphotGuessModels (pmConfig *config, pmReadout *readout, psArray *sources, pmPSF *psf);
    68 bool            psphotGuessModel_Threaded (psThreadJob *job);
    69 
    70 bool            psphotMagnitudes (pmConfig *config, pmReadout *readout, const pmFPAview *view, psArray *sources, const pmPSF *psf);
     103bool            psphotReplaceAllSources (pmConfig *config, const pmFPAview *view);
     104bool            psphotReplaceAllSourcesReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe);
     105
     106bool            psphotAddNoise (pmConfig *config, const pmFPAview *view);
     107bool            psphotSubNoise (pmConfig *config, const pmFPAview *view);
     108bool            psphotAddOrSubNoise (pmConfig *config, const pmFPAview *view, bool add);
     109bool            psphotAddOrSubNoiseReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe, bool add);
     110
     111bool            psphotExtendedSourceAnalysis (pmConfig *config, const pmFPAview *view);
     112bool            psphotExtendedSourceAnalysisReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe);
     113
     114bool            psphotExtendedSourceFits (pmConfig *config, const pmFPAview *view);
     115bool            psphotExtendedSourceFitsReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe);
     116
     117bool            psphotApResid (pmConfig *config, const pmFPAview *view);
     118bool            psphotApResidReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe);
     119
     120bool            psphotMagnitudes (pmConfig *config, const pmFPAview *view);
     121bool            psphotMagnitudesReadout(pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe);
    71122bool            psphotMagnitudes_Threaded (psThreadJob *job);
     123
     124bool            psphotEfficiency (pmConfig *config, const pmFPAview *view);
     125bool            psphotEfficiencyReadout(pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe);
    72126
    73127bool            psphotPSFWeights(pmConfig *config, pmReadout *readout, const pmFPAview *view, psArray *sources);
    74128bool            psphotPSFWeights_Threaded (psThreadJob *job);
    75129
    76 bool            psphotApResid (pmConfig *config, pmReadout *readout, psArray *sources, pmPSF *psf);
    77 
    78130bool            psphotSkyReplace (pmConfig *config, const pmFPAview *view);
    79 bool            psphotExtendedSourceAnalysis (pmReadout *readout, psArray *sources, psMetadata *recipe);
    80 bool            psphotExtendedSourceFits (pmReadout *readout, psArray *sources, psMetadata *recipe);
    81 bool            psphotEfficiency(pmConfig *config, pmReadout *readout, const pmFPAview *view, const pmPSF *psf, psMetadata *recipe, const psArray *realSources);
     131bool            psphotSkyReplaceReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index);
     132
     133bool            psphotSourceFreePixels (pmConfig *config, const pmFPAview *view);
     134bool            psphotSourceFreePixelsReadout(pmConfig *config, const pmFPAview *view, const char *filename, int index);
     135
     136// in psphotSourceStats.c:
     137bool            psphotSourceStats_Threaded (psThreadJob *job);
     138bool            psphotSourceStatsUpdate (psArray *sources, pmConfig *config, pmReadout *readout);
     139bool            psphotSetMomentsWindow (psMetadata *recipe, psMetadata *analysis, psArray *sources);
     140
     141// in psphotChoosePSF.c:
     142bool            psphotPSFstats (pmReadout *readout, pmPSF *psf);
     143bool            psphotMomentsStats (pmReadout *readout, psArray *sources);
     144
     145// in psphotGuessModel.c
     146bool            psphotGuessModel_Threaded (psThreadJob *job);
     147
     148// in psphotMergeSources.c:
     149bool            psphotLoadExtSources (pmConfig *config, const pmFPAview *view);
     150psArray        *psphotLoadPSFSources (pmConfig *config, const pmFPAview *view);
     151bool            psphotRepairLoadedSources (pmConfig *config, const pmFPAview *view);
     152bool            psphotCheckExtSources (pmConfig *config, const pmFPAview *view);
     153
     154// generate the detection structure for the supplied array of sources
     155bool            psphotDetectionsFromSources (pmConfig *config, const pmFPAview *view, psArray *sources);
     156
     157// generate the detection structure for the supplied array of sources
     158bool            psphotSetSourceParams (pmConfig *config, psArray *sources, pmPSF *psf);
     159
     160// in psphotModelBackground.c:
     161// Create a background model for a readout, without saving the result as a pmFPAfile on config->files.  Otherwise identical to psphotModelBackgroundFileIndex.
     162psImage        *psphotModelBackgroundReadoutNoFile(pmReadout *readout, const pmConfig *config);
     163psImageBinning *psphotBackgroundBinning(const psImage *image, const pmConfig *config);
     164
     165// in psphotReplaceUnfit.c:
     166bool            psphotRemoveAllSources (const psArray *sources, const psMetadata *recipe);
     167bool            psphotReplaceUnfitSources (psArray *sources, psImageMaskType maskVal);
    82168
    83169// thread-related:
     
    93179psErrorCode     psphotCullPeaks(const psImage *img, const psImage *weight, const psMetadata *recipe, psArray *footprints);
    94180
    95 // generate the detection structure for the supplied array of sources
    96 pmDetections   *psphotDetectionsFromSources (pmConfig *config, psArray *sources);
    97 
    98 // used by ApResid
     181// in psphotApResid.c:
    99182pmTrend2D      *psphotApResidTrend (float *apResidSysErr, pmReadout *readout, int Nx, int Ny, psVector *xPos, psVector *yPos, psVector *apResid, psVector *dMag);
    100183bool            psphotApResidMags_Threaded (psThreadJob *job);
     
    103186void            psphotModelClassInit (void);
    104187bool            psphotGrowthCurve (pmReadout *readout, pmPSF *psf, bool ignore, psImageMaskType maskVal);
    105 bool            psphotSetMaskAndVariance (pmConfig *config, pmReadout *readout, psMetadata *recipe);
    106 void            psphotSourceFreePixels (psArray *sources);
    107188
    108189// functions to set the correct source pixels
    109 bool            psphotInitRadiusPSF (const psMetadata *recipe, const pmModelType type);
     190bool            psphotInitRadiusPSF(const psMetadata *recipe, const psMetadata *analysis, const pmModelType type);
     191
    110192bool            psphotCheckRadiusPSF (pmReadout *readout, pmSource *source, pmModel *model, psImageMaskType markVal);
    111193bool            psphotCheckRadiusPSFBlend (pmReadout *readout, pmSource *source, pmModel *model, psImageMaskType markVal, float dR);
     
    114196float           psphotSetRadiusEXT (pmReadout *readout, pmSource *source, psImageMaskType markVal);
    115197
    116 // output functions
    117 bool            psphotAddPhotcode (psMetadata *recipe, pmConfig *config, const pmFPAview *view, const char *filerule);
    118198bool            psphotDumpMoments (psMetadata *recipe, psArray *sources);
    119199psMetadata     *psphotDefineHeader (psMetadata *recipe);
     
    146226bool            psphotFitSummary (void);
    147227
    148 bool            psphotMergeSources (psArray *oldSources, psArray *newSources);
    149 bool            psphotLoadExtSources (pmConfig *config, const pmFPAview *view, psArray *sources);
    150 psArray        *psphotLoadPSFSources (pmConfig *config, const pmFPAview *view);
    151 
    152 pmPSF          *psphotLoadPSF (pmConfig *config, const pmFPAview *view, psMetadata *recipe);
     228bool            psphotLoadPSF (pmConfig *config, const pmFPAview *view);
     229bool            psphotLoadPSFReadout (pmConfig *config, const pmFPAview *view, const char *outFilename, const char *inFilename, int index);
     230
    153231bool            psphotSetHeaderNstars (psMetadata *recipe, psArray *sources);
    154 bool            psphotAddNoise (pmReadout *readout, const psArray *sources, const psMetadata *recipe);
    155 bool            psphotSubNoise (pmReadout *readout, const psArray *sources, const psMetadata *recipe);
    156 bool            psphotAddOrSubNoise (pmReadout *readout, const psArray *sources, const psMetadata *recipe, bool add);
    157232bool            psphotRadialPlot (int *kapa, const char *filename, pmSource *source);
    158233bool            psphotSourcePlots (pmReadout *readout, psArray *sources, psMetadata *recipe);
    159234bool            psphotMosaicSubimage (psImage *outImage, pmSource *source, int Xo, int Yo, int DX, int DY, bool normalize);
    160235
    161 bool            psphotAddWithTest (pmSource *source, bool useState, psImageMaskType maskVal);
    162 bool            psphotSubWithTest (pmSource *source, bool useState, psImageMaskType maskVal);
    163 bool            psphotSetState (pmSource *source, bool curState, psImageMaskType maskVal);
    164 bool            psphotDeblendSatstars (pmReadout *readout, psArray *sources, psMetadata *recipe);
    165 bool            psphotSourceSize (pmConfig *config, pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, long first);
    166 
    167236bool            psphotMakeResiduals (psArray *sources, psMetadata *recipe, pmPSF *psf, psImageMaskType maskVal);
    168237
     
    172241
    173242// functions related to extended source analysis
    174 bool  psphotRadialProfile (pmSource *source, psMetadata *recipe, float skynoise, psImageMaskType maskVal);
    175 bool  psphotRadialProfilesByAngles (pmSource *source, int Nsec, float Rmax);
    176 float psphotRadiusFromProfile (pmSource *source, psVector *radius, psVector *flux, float fluxMin, float fluxMax);
    177 bool  psphotRadiiFromProfiles (pmSource *source, float fluxMin, float fluxMax);
    178 bool  psphotEllipticalProfile (pmSource *source);
    179 bool  psphotEllipticalContour (pmSource *source);
     243bool            psphotRadialProfile (pmSource *source, psMetadata *recipe, float skynoise, psImageMaskType maskVal);
     244bool            psphotRadialProfilesByAngles (pmSource *source, int Nsec, float Rmax);
     245float           psphotRadiusFromProfile (pmSource *source, psVector *radius, psVector *flux, float fluxMin, float fluxMax);
     246bool            psphotRadiiFromProfiles (pmSource *source, float fluxMin, float fluxMax);
     247bool            psphotEllipticalProfile (pmSource *source);
     248bool            psphotEllipticalContour (pmSource *source);
    180249
    181250// psphotVisual functions
    182 bool psphotVisualShowImage (pmReadout *readout);
    183 bool psphotVisualShowBackground (pmConfig *config, const pmFPAview *view, pmReadout *readout);
    184 bool psphotVisualShowSignificance (psImage *image);
    185 bool psphotVisualShowPeaks (pmDetections *detections);
    186 bool psphotVisualShowFootprints (pmDetections *detections);
    187 bool psphotVisualShowMoments (psArray *sources);
    188 bool psphotVisualPlotMoments (psMetadata *recipe, psMetadata *analysis, psArray *sources);
    189 bool psphotVisualShowRoughClass (psArray *sources);
    190 bool psphotVisualShowPSFStars (psMetadata *recipe, pmPSF *psf, psArray *sources);
    191 bool psphotVisualShowSatStars (psMetadata *recipe, pmPSF *psf, psArray *sources);
    192 bool psphotVisualShowPSFModel (pmReadout *readout, pmPSF *psf);
    193 bool psphotVisualPlotRadialProfile (int myKapa, pmSource *source, psImageMaskType maskVal);
    194 bool psphotVisualPlotRadialProfiles (psMetadata *recipe, psArray *sources);
    195 bool psphotVisualShowFlags (psArray *sources);
    196 bool psphotVisualShowSourceSize (pmReadout *readout, psArray *sources);
    197 bool psphotVisualShowResidualImage (pmReadout *readout);
    198 bool psphotVisualPlotApResid (psArray *sources, float mean, float error);
    199 bool psphotVisualPlotChisq (psArray *sources);
    200 bool psphotVisualPlotSourceSize (psMetadata *recipe, psMetadata *analysis, psArray *sources);
    201 bool psphotVisualShowPetrosians (psArray *sources);
    202 
    203 // bool psphotPetrosianAnalysis (pmReadout *readout, psArray *sources, psMetadata *recipe);
    204 // bool psphotPetrosianProfile (pmReadout *readout, pmSource *source, float skynoise);
     251bool            psphotVisualShowImage (pmReadout *readout);
     252bool            psphotVisualShowBackground (pmConfig *config, const pmFPAview *view, pmReadout *readout);
     253bool            psphotVisualShowSignificance (psImage *image, float min, float max);
     254bool            psphotVisualShowPeaks (pmDetections *detections);
     255bool            psphotVisualShowFootprints (pmDetections *detections);
     256bool            psphotVisualShowMoments (psArray *sources);
     257bool            psphotVisualPlotMoments (psMetadata *recipe, psMetadata *analysis, psArray *sources);
     258bool            psphotVisualShowRoughClass (psArray *sources);
     259bool            psphotVisualShowPSFStars (psMetadata *recipe, pmPSF *psf, psArray *sources);
     260bool            psphotVisualShowSatStars (psMetadata *recipe, pmPSF *psf, psArray *sources);
     261bool            psphotVisualShowPSFModel (pmReadout *readout, pmPSF *psf);
     262bool            psphotVisualPlotRadialProfile (int myKapa, pmSource *source, psImageMaskType maskVal);
     263bool            psphotVisualPlotRadialProfiles (psMetadata *recipe, psArray *sources);
     264bool            psphotVisualShowFlags (psArray *sources);
     265bool            psphotVisualShowSourceSize (pmReadout *readout, psArray *sources);
     266bool            psphotVisualShowResidualImage (pmReadout *readout);
     267bool            psphotVisualPlotApResid (psArray *sources, float mean, float error);
     268bool            psphotVisualPlotChisq (psArray *sources);
     269bool            psphotVisualPlotSourceSize (psMetadata *recipe, psMetadata *analysis, psArray *sources);
     270bool            psphotVisualShowPetrosians (psArray *sources);
     271bool            psphotVisualEraseOverlays (int channel, char *overlay);
    205272
    206273bool psphotPetrosian (pmSource *source, psMetadata *recipe, float skynoise, psImageMaskType maskVal);
     
    208275bool psphotPetrosianStats (pmSource *source);
    209276
    210 // XXX old versions, currently disabled
     277// currently disabled:
    211278// bool            psphotIsophotal (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
    212279// bool            psphotAnnuli (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
     
    223290//                               float petFlux, float radiusForFlux);
    224291
    225 bool psphotImageQuality (psMetadata *recipe, psArray *sources);
    226 
    227292// structures & functions to support psf-convolved model fitting
    228 
    229 // pmPCMData : PSF Convolved Model data storage structure
    230 typedef struct {
    231     psImage *model;
    232     psArray *dmodels;
    233     psImage *modelConv;
    234     psArray *dmodelsConv;
    235 } pmPCMData;
    236 
    237293
    238294// psf-convolved model fitting
     
    277333int psphotSupplementStars (psArray *stars, psArray *sources, psImageBinning *binning, int ix, int iy);
    278334
    279 
    280 // Create a background model for a readout
    281 // Essentially identical to psphotModelBackground, but with a more convenient API for outsiders.
    282 psImage *psphotBackgroundModel(pmReadout *ro, // Readout for which to generate background model
    283                                const pmConfig *config // Configuration
    284     );
    285 
    286335pmConfig *psphotForcedArguments(int argc, char **argv);
    287336bool psphotForcedImageLoop (pmConfig *config);
  • trunk/psphot/src/psphotAddNoise.c

    r25755 r26894  
    11# include "psphotInternal.h"
    22
    3 bool psphotAddNoise (pmReadout *readout, const psArray *sources, const psMetadata *recipe) {
    4   return psphotAddOrSubNoise (readout, sources, recipe, true);
     3bool psphotAddNoise (pmConfig *config, const pmFPAview *view) {
     4    return psphotAddOrSubNoise (config, view, true);
    55}
    66
    7 bool psphotSubNoise (pmReadout *readout, const psArray *sources, const psMetadata *recipe) {
    8   return psphotAddOrSubNoise (readout, sources, recipe, false);
     7bool psphotSubNoise (pmConfig *config, const pmFPAview *view) {
     8    return psphotAddOrSubNoise (config, view, false);
    99}
    1010
    11 bool psphotAddOrSubNoise (pmReadout *readout, const psArray *sources, const psMetadata *recipe, bool add) {
     11// for now, let's store the detections on the readout->analysis for each readout
     12bool psphotAddOrSubNoise (pmConfig *config, const pmFPAview *view, bool add)
     13{
     14    bool status = true;
     15
     16    // select the appropriate recipe information
     17    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     18    psAssert (recipe, "missing recipe?");
     19
     20    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     21    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     22
     23    // loop over the available readouts
     24    for (int i = 0; i < num; i++) {
     25        if (!psphotAddOrSubNoiseReadout (config, view, "PSPHOT.INPUT", i, recipe, add)) {
     26            psError (PSPHOT_ERR_CONFIG, false, "failed on to modify noise for PSPHOT.INPUT entry %d", i);
     27            return false;
     28        }
     29    }
     30    return true;
     31}
     32
     33bool psphotAddOrSubNoiseReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe, bool add) {
    1234
    1335    bool status = false;
     
    1638    psEllipseAxes axes;
    1739
    18     PS_ASSERT (readout, false);
    19     PS_ASSERT (readout->parent, false);
    20     PS_ASSERT (readout->parent->concepts, false);
     40    // find the currently selected readout
     41    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     42    psAssert (file, "missing file?");
     43
     44    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     45    psAssert (readout, "missing readout?");
     46    psAssert (readout->parent, "missing cell?");
     47    psAssert (readout->parent->concepts, "missing concepts?");
     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?");
    2154
    2255    psTimerStart ("psphot.noise");
     
    2457    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
    2558    psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
    26     assert (maskVal);
     59    psAssert (maskVal, "missing mask value?");
    2760
    2861    // increase variance by factor*(object noise):
  • trunk/psphot/src/psphotApResid.c

    r26261 r26894  
    44// measure the aperture residual statistics and 2D variations
    55
    6 bool psphotApResid (pmConfig *config, pmReadout *readout, psArray *sources, pmPSF *psf)
     6// for now, let's store the detections on the readout->analysis for each readout
     7bool psphotApResid (pmConfig *config, const pmFPAview *view)
     8{
     9    bool status = true;
     10
     11    // select the appropriate recipe information
     12    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     13    psAssert (recipe, "missing recipe?");
     14
     15    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     16    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     17
     18    // loop over the available readouts
     19    for (int i = 0; i < num; i++) {
     20        if (!psphotApResidReadout (config, view, "PSPHOT.INPUT", i, recipe)) {
     21            psError (PSPHOT_ERR_CONFIG, false, "failed to measure aperture residual for PSPHOT.INPUT entry %d", i);
     22            return false;
     23        }
     24    }
     25    return true;
     26}
     27
     28bool psphotApResidReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe)
    729{
    830    int Nfail = 0;
     
    1335    pmSource *source;
    1436
    15     PS_ASSERT_PTR_NON_NULL(config, false);
    16     PS_ASSERT_PTR_NON_NULL(readout, false);
    17     PS_ASSERT_PTR_NON_NULL(sources, false);
    18     PS_ASSERT_PTR_NON_NULL(psf, false);
    19 
    2037    psTimerStart ("psphot.apresid");
    2138
    22     // select the appropriate recipe information
    23     psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
    24     assert (recipe);
     39    // find the currently selected readout
     40    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     41    psAssert (file, "missing file?");
     42
     43    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     44    psAssert (readout, "missing readout?");
     45
     46    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     47    psAssert (detections, "missing detections?");
     48
     49    psArray *sources = detections->allSources;
     50    psAssert (sources, "missing sources?");
     51
     52    if (!sources->n) {
     53        psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping ap resid");
     54        return true;
     55    }
     56
     57    pmPSF *psf = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF");
     58    psAssert (psf, "missing psf?");
    2559
    2660    // determine the number of allowed threads
     
    3367    if (!measureAptrend) {
    3468        // save nan values since these were not calculated
    35         psMetadataAdd (recipe, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   NAN);
    36         psMetadataAdd (recipe, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", NAN);
    37         psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", 0);
    38         psMetadataAdd (recipe, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", NAN);
     69        psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   NAN);
     70        psMetadataAdd (readout->analysis, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", NAN);
     71        psMetadataAdd (readout->analysis, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", 0);
     72        psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", NAN);
    3973        return true;
    4074    }
     
    288322
    289323    // save results for later output
    290     psMetadataAdd (recipe, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   psf->ApResid);
    291     psMetadataAdd (recipe, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", psf->dApResid);
    292     psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", psf->nApResid);
    293     psMetadataAdd (recipe, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", psf->growth->apLoss);
     324    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   psf->ApResid);
     325    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", psf->dApResid);
     326    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", psf->nApResid);
     327    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", psf->growth->apLoss);
    294328
    295329    psLogMsg ("psphot.apresid", PS_LOG_DETAIL, "aperture residual: %f +/- %f\n", psf->ApResid, psf->dApResid);
     
    308342escape:
    309343    // save nan values since these were not calculated
    310     psMetadataAdd (recipe, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   NAN);
    311     psMetadataAdd (recipe, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", NAN);
    312     psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", 0);
    313     psMetadataAdd (recipe, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", NAN);
     344    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   NAN);
     345    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", NAN);
     346    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", 0);
     347    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", NAN);
    314348
    315349    psFree (xPos);
     
    318352    psFree (mag);
    319353    psFree (dMag);
    320     return false;
     354    return true;
     355    // this is a quality error, not a programming error
    321356}
    322357
  • trunk/psphot/src/psphotBasicDeblend.c

    r20453 r26894  
    11# include "psphotInternal.h"
    22
    3 bool psphotBasicDeblend (psArray *sources, psMetadata *recipe) {
     3// for now, let's store the detections on the readout->analysis for each readout
     4bool psphotBasicDeblend (pmConfig *config, const pmFPAview *view)
     5{
     6    bool status = true;
     7
     8    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     9    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     10
     11    // loop over the available readouts
     12    for (int i = 0; i < num; i++) {
     13        if (!psphotBasicDeblendReadout (config, view, "PSPHOT.INPUT", i)) {
     14            psError (PSPHOT_ERR_CONFIG, false, "failed on basic deblend analysis for PSPHOT.INPUT entry %d", i);
     15            return false;
     16        }
     17    }
     18    return true;
     19}
     20
     21bool psphotBasicDeblendReadout (pmConfig *config, const pmFPAview *view, const char *filename, int fileIndex) {
    422
    523    int N;
     
    826    pmSource *source, *testSource;
    927
     28    psTimerStart ("psphot.deblend.basic");
     29
    1030    int Nblend = 0;
    1131
    12     psTimerStart ("psphot.deblend.basic");
     32    // find the currently selected readout
     33    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, fileIndex); // File of interest
     34    psAssert (file, "missing file?");
     35
     36    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     37    psAssert (readout, "missing readout?");
     38
     39    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     40    psAssert (detections, "missing detections?");
     41
     42    psArray *sources = detections->newSources;
     43    psAssert (sources, "missing sources?");
     44
     45    if (!sources->n) {
     46        psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping basic deblend");
     47        return true;
     48    }
     49
     50    // select the appropriate recipe information
     51    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     52    psAssert (recipe, "missing recipe?");
    1353
    1454    float FRACTION = psMetadataLookupF32 (&status, recipe, "DEBLEND_PEAK_FRACTION");
  • trunk/psphot/src/psphotBlendFit.c

    r25755 r26894  
    11# include "psphotInternal.h"
    22
     3// for now, let's store the detections on the readout->analysis for each readout
     4bool psphotBlendFit (pmConfig *config, const pmFPAview *view)
     5{
     6    bool status = true;
     7
     8    // select the appropriate recipe information
     9    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     10    psAssert (recipe, "missing recipe?");
     11
     12    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     13    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     14
     15    // loop over the available readouts
     16    for (int i = 0; i < num; i++) {
     17        if (!psphotBlendFitReadout (config, view, "PSPHOT.INPUT", i, recipe)) {
     18            psError (PSPHOT_ERR_CONFIG, false, "failed to fit sources (non-linear) for PSPHOT.INPUT entry %d", i);
     19            return false;
     20        }
     21    }
     22    return true;
     23}
     24
    325// XXX I don't like this name
    4 bool psphotBlendFit (pmConfig *config, pmReadout *readout, psArray *sources, pmPSF *psf) {
     26bool psphotBlendFitReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe) {
    527
    628    int Nfit = 0;
     
    1234    psTimerStart ("psphot.fit.nonlinear");
    1335
    14     // select the appropriate recipe information
    15     psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
    16     assert (recipe);
     36    // find the currently selected readout
     37    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     38    psAssert (file, "missing file?");
     39
     40    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     41    psAssert (readout, "missing readout?");
     42
     43    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     44    psAssert (detections, "missing detections?");
     45
     46    psArray *sources = detections->allSources;
     47    psAssert (sources, "missing sources?");
     48
     49    if (!sources->n) {
     50        psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping blend fit");
     51        return true;
     52    }
     53
     54    pmPSF *psf = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF");
     55    psAssert (psf, "missing psf?");
    1756
    1857    // determine the number of allowed threads
     
    4079    psphotInitLimitsPSF (recipe, readout);
    4180    psphotInitLimitsEXT (recipe);
    42     psphotInitRadiusPSF (recipe, psf->type);
     81    psphotInitRadiusPSF (recipe, readout->analysis, psf->type);
    4382
    4483    // starts the timer, sets up the array of fitSets
     
    4786    // source analysis is done in S/N order (brightest first)
    4887    sources = psArraySort (sources, pmSourceSortBySN);
     88    if (!sources->n) {
     89        psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping blend");
     90        return true;
     91    }
    4992
    5093    // choose Cx, Cy (see psphotThreadTools.c for overview of the concepts)
     
    272315}
    273316
    274 # if (0)
    275 bool psphotBlendFit_Unthreaded (int *nfit, int *npsf, int *next, int *nfail, pmReadout *readout, psMetadata *recipe, psArray *sources, pmPSF *psf, psArray *newSources) {
    276 
    277     bool status = false;
    278     int Nfit = 0;
    279     int Npsf = 0;
    280     int Next = 0;
    281     int Nfail = 0;
    282 
    283     // bit-masks to test for good/bad pixels
    284     psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT");
    285     assert (maskVal);
    286 
    287     // bit-mask to mark pixels not used in analysis
    288     psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT");
    289     assert (markVal);
    290 
    291     // maskVal is used to test for rejected pixels, and must include markVal
    292     maskVal |= markVal;
    293 
    294     // S/N limit to perform full non-linear fits
    295     float FIT_SN_LIM = psMetadataLookupF32 (&status, recipe, "FULL_FIT_SN_LIM");
    296 
    297     // option to limit analysis to a specific region
    298     char *region = psMetadataLookupStr (&status, recipe, "ANALYSIS_REGION");
    299     psRegion AnalysisRegion = psRegionForImage (readout->image, psRegionFromString (region));
    300     if (psRegionIsNaN (AnalysisRegion)) psAbort("analysis region mis-defined");
    301 
    302     for (int i = 0; i < sources->n; i++) {
    303         pmSource *source = sources->data[i];
    304 
    305         // skip non-astronomical objects (very likely defects)
    306         if (source->mode &  PM_SOURCE_MODE_BLEND) continue;
    307         if (source->mode &  PM_SOURCE_MODE_CR_LIMIT) continue;
    308         if (source->type == PM_SOURCE_TYPE_DEFECT) continue;
    309         if (source->type == PM_SOURCE_TYPE_SATURATED) continue;
    310 
    311         // skip DBL second sources (ie, added by psphotFitBlob)
    312         if (source->mode &  PM_SOURCE_MODE_PAIR) continue;
    313 
    314         // limit selection to some SN limit
    315         if (source->peak->SN < FIT_SN_LIM) continue;
    316 
    317         // exclude sources outside optional analysis region
    318         if (source->peak->xf < AnalysisRegion.x0) continue;
    319         if (source->peak->yf < AnalysisRegion.y0) continue;
    320         if (source->peak->xf > AnalysisRegion.x1) continue;
    321         if (source->peak->yf > AnalysisRegion.y1) continue;
    322 
    323         // if model is NULL, we don't have a starting guess
    324         if (source->modelPSF == NULL) continue;
    325 
    326         // skip sources which are insignificant flux?
    327         // XXX this is somewhat ad-hoc
    328         if (source->modelPSF->params->data.F32[1] < 0.1) {
    329             psTrace ("psphot", 5, "skipping near-zero source: %f, %f : %f\n",
    330                      source->modelPSF->params->data.F32[1],
    331                      source->modelPSF->params->data.F32[2],
    332                      source->modelPSF->params->data.F32[3]);
    333             continue;
    334         }
    335 
    336         // replace object in image
    337         if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
    338             pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    339         }
    340         Nfit ++;
    341 
    342         // try fitting PSFs or extended sources depending on source->mode
    343         // these functions subtract the resulting fitted source
    344         if (source->mode & PM_SOURCE_MODE_EXT_LIMIT) {
    345             if (psphotFitBlob (readout, source, newSources, psf, maskVal, markVal)) {
    346                 source->type = PM_SOURCE_TYPE_EXTENDED;
    347                 psTrace ("psphot", 5, "source at %7.1f, %7.1f is ext", source->peak->xf, source->peak->yf);
    348                 Next ++;
    349                 continue;
    350             }
    351         } else {
    352             if (psphotFitBlend (readout, source, psf, maskVal, markVal)) {
    353                 source->type = PM_SOURCE_TYPE_STAR;
    354                 psTrace ("psphot", 5, "source at %7.1f, %7.1f is psf", source->peak->xf, source->peak->yf);
    355                 Npsf ++;
    356                 continue;
    357             }
    358         }
    359 
    360         psTrace ("psphot", 5, "source at %7.1f, %7.1f failed", source->peak->xf, source->peak->yf);
    361         Nfail ++;
    362 
    363         // re-subtract the object, leave local sky
    364         pmSourceCacheModel (source, maskVal);
    365         pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    366     }
    367 
    368     // change the value of a scalar on the array (wrap this and put it in psArray.h)
    369     *nfit  = Nfit;
    370     *npsf  = Npsf;
    371     *next  = Next;
    372     *nfail = Nfail;
    373 
    374     // moments are modified by the fit; re-display
    375     psphotVisualPlotMoments (recipe, sources);
    376     psphotVisualShowResidualImage (readout);
    377 
    378     return true;
    379 }
    380 # endif
  • trunk/psphot/src/psphotChoosePSF.c

    r26262 r26894  
    11# include "psphotInternal.h"
    22
     3// generate a PSF model for inputs without PSF models already loaded
     4bool psphotChoosePSF (pmConfig *config, const pmFPAview *view)
     5{
     6    bool status = true;
     7
     8    // select the appropriate recipe information
     9    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     10    psAssert (recipe, "missing recipe?");
     11
     12    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     13    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     14
     15    // loop over the available readouts
     16    for (int i = 0; i < num; i++) {
     17        if (!psphotChoosePSFReadout (config, view, "PSPHOT.INPUT", i, recipe)) {
     18            psError (PSPHOT_ERR_CONFIG, false, "failed to choose a psf model for PSPHOT.INPUT entry %d", i);
     19            return false;
     20        }
     21    }
     22    return true;
     23}
     24
    325// try PSF models and select best option
    4 pmPSF *psphotChoosePSF (pmReadout *readout, psArray *sources, psMetadata *recipe) {
     26bool psphotChoosePSFReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe) {
    527
    628    bool status;
    729
    830    psTimerStart ("psphot.choose.psf");
     31
     32    // find the currently selected readout
     33    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     34    psAssert (file, "missing file?");
     35
     36    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     37    psAssert (readout, "missing readout?");
     38
     39    // do not generate a PSF if we already were supplied one
     40    if (psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF")) {
     41        psLogMsg ("psphot", PS_LOG_DETAIL, "psf model supplied for input file %d", index);
     42        return true;
     43    }
     44
     45    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     46    psAssert (detections, "missing detections?");
     47
     48    psArray *sources = detections->newSources;
     49    psAssert (sources, "missing sources?");
     50
     51    if (!sources->n) {
     52        psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping PSF model");
     53        return true;
     54    }
    955
    1056    // bit-masks to test for good/bad pixels
    1157    psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT");
    12     assert (maskVal);
     58    psAssert (maskVal, "missing mask value?");
    1359
    1460    // bit-mask to mark pixels not used in analysis
    1561    psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT");
    16     assert (markVal);
     62    psAssert (markVal, "missing mark value?");
    1763
    1864    // maskVal is used to test for rejected pixels, and must include markVal
     
    61107    // assert (status);
    62108
    63     // We have calculated a Gaussian window function, use that for both the PSF fit radius and
    64     // the aperture radius (scaling SIGMA)
    65     float gaussSigma = psMetadataLookupF32(&status, recipe, "MOMENTS_GAUSS_SIGMA");
     109    // values on readout->analysis if we have calculated a Gaussian window function, use that
     110    // for both the PSF fit radius and the aperture radius (scaling SIGMA), otherwise base the value on the recipe value for MOMENTS_GAUSS_SIGMA
     111    float gaussSigma = psMetadataLookupF32 (&status, readout->analysis, "MOMENTS_GAUSS_SIGMA");
     112    if (!status) {
     113        gaussSigma = psMetadataLookupF32 (&status, recipe, "MOMENTS_GAUSS_SIGMA");
     114    }
    66115    float fitScale = psMetadataLookupF32(&status, recipe, "PSF_FIT_RADIUS_SCALE");
    67116    float apScale = psMetadataLookupF32(&status, recipe, "PSF_APERTURE_SCALE");
     
    70119
    71120    // XXX use the same radii for standard analysis as for the PSF creation
    72     psMetadataAddF32(recipe, PS_LIST_TAIL, "PSF_FIT_RADIUS", PS_META_REPLACE, "fit radius", options->fitRadius);
    73     psMetadataAddF32(recipe, PS_LIST_TAIL, "PSF_APERTURE", PS_META_REPLACE, "psf aperture", options->apRadius);
     121    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "PSF_FIT_RADIUS", PS_META_REPLACE, "fit radius", options->fitRadius);
     122    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "PSF_APERTURE", PS_META_REPLACE, "psf aperture", options->apRadius);
    74123
    75124    // dimensions of the field for which the PSF is defined
     
    158207        bool status = true;
    159208        status &= psphotMakeFluxScale (readout->image, recipe, psf);
    160         status &= psphotPSFstats (readout, recipe, psf);
     209        status &= psphotPSFstats (readout, psf);
    161210        if (!status) {
    162211            psError(PSPHOT_ERR_PSF, false, "Failed to fit any models when choosing PSF");
     
    233282        bool status = true;
    234283        status &= psphotMakeFluxScale (readout->image, recipe, psf);
    235         status &= psphotPSFstats (readout, recipe, psf);
     284        status &= psphotPSFstats (readout, psf);
    236285        if (!status) {
    237286            psError(PSPHOT_ERR_PSF, false, "Failed to fit any models when choosing PSF");
     
    290339    psFree (models);
    291340
    292     if (!psphotPSFstats (readout, recipe, psf)) {
     341    if (!psphotPSFstats (readout, psf)) {
    293342        psError(PSPHOT_ERR_PSF, false, "cannot measure PSF shape terms");
    294343        psFree(options);
     
    302351
    303352    psFree (options);
    304     return (psf);
     353
     354    // save PSF on readout->analysis
     355    if (!psMetadataAddPtr (readout->analysis, PS_LIST_TAIL, "PSPHOT.PSF", PS_META_REPLACE | PS_DATA_UNKNOWN, "psphot psf model", psf)) {
     356        psError (PSPHOT_ERR_UNKNOWN, false, "problem saving sources on readout");
     357        return false;
     358    }
     359    psFree (psf); // XXX double-check
     360
     361    // move into psphotChoosePSF
     362    psphotVisualShowPSFModel (readout, psf);
     363
     364    return true;
    305365}
    306366
    307367// measure average parameters of the PSF model
    308 bool psphotPSFstats (pmReadout *readout, psMetadata *recipe, pmPSF *psf) {
     368bool psphotPSFstats (pmReadout *readout, pmPSF *psf) {
    309369
    310370    psEllipseShape shape;
     
    312372
    313373    PS_ASSERT_PTR_NON_NULL(readout, false);
    314     PS_ASSERT_PTR_NON_NULL(recipe, false);
    315374    PS_ASSERT_PTR_NON_NULL(psf, false);
    316375
     
    362421    }
    363422
    364     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FWHM_MAJ",   PS_META_REPLACE, "PSF FWHM Major axis (mean)", stats->sampleMean);
    365     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MJ_SG",   PS_META_REPLACE, "PSF FWHM Major axis (sigma)", stats->sampleStdev);
    366     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MJ_LQ",   PS_META_REPLACE, "PSF FWHM Major axis (lower quartile)", stats->sampleLQ);
    367     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MJ_UQ",   PS_META_REPLACE, "PSF FWHM Major axis (upper quartile)", stats->sampleUQ);
     423    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FWHM_MAJ",   PS_META_REPLACE, "PSF FWHM Major axis (mean)", stats->sampleMean);
     424    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MJ_SG",   PS_META_REPLACE, "PSF FWHM Major axis (sigma)", stats->sampleStdev);
     425    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MJ_LQ",   PS_META_REPLACE, "PSF FWHM Major axis (lower quartile)", stats->sampleLQ);
     426    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MJ_UQ",   PS_META_REPLACE, "PSF FWHM Major axis (upper quartile)", stats->sampleUQ);
    368427
    369428    if (!psVectorStats (stats, fwhmMinor, NULL, NULL, 0)) {
     
    371430        return false;
    372431    }
    373     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FWHM_MIN",   PS_META_REPLACE, "PSF FWHM Minor axis (mean)", stats->sampleMean);
    374     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MN_SG",   PS_META_REPLACE, "PSF FWHM Minor axis (sigma)", stats->sampleStdev);
    375     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MN_LQ",   PS_META_REPLACE, "PSF FWHM Minor axis (lower quartile)", stats->sampleLQ);
    376     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MN_UQ",   PS_META_REPLACE, "PSF FWHM Minor axis (upper quartile)", stats->sampleUQ);
    377 
    378     psMetadataAddF32 (recipe, PS_LIST_TAIL, "ANGLE",    PS_META_REPLACE, "PSF angle",           axes.theta);
    379     psMetadataAddS32 (recipe, PS_LIST_TAIL, "NPSFSTAR", PS_META_REPLACE, "Number of stars used to make PSF", psf->nPSFstars);
    380     psMetadataAddBool(recipe, PS_LIST_TAIL, "PSFMODEL", PS_META_REPLACE, "Valid PSF Model?", true);
     432    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FWHM_MIN",   PS_META_REPLACE, "PSF FWHM Minor axis (mean)", stats->sampleMean);
     433    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MN_SG",   PS_META_REPLACE, "PSF FWHM Minor axis (sigma)", stats->sampleStdev);
     434    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MN_LQ",   PS_META_REPLACE, "PSF FWHM Minor axis (lower quartile)", stats->sampleLQ);
     435    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MN_UQ",   PS_META_REPLACE, "PSF FWHM Minor axis (upper quartile)", stats->sampleUQ);
     436
     437    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "ANGLE",    PS_META_REPLACE, "PSF angle",           axes.theta);
     438    psMetadataAddS32 (readout->analysis, PS_LIST_TAIL, "NPSFSTAR", PS_META_REPLACE, "Number of stars used to make PSF", psf->nPSFstars);
     439    psMetadataAddBool(readout->analysis, PS_LIST_TAIL, "PSFMODEL", PS_META_REPLACE, "Valid PSF Model?", true);
    381440
    382441    psFree (fwhmMajor);
     
    387446
    388447// determine approximate PSF shape parameters based on the moments
    389 bool psphotMomentsStats (pmReadout *readout, psMetadata *recipe, psArray *sources) {
     448bool psphotMomentsStats (pmReadout *readout, psArray *sources) {
    390449
    391450    // without the PSF model, we can only rely on the source->moments
     
    401460
    402461    PS_ASSERT_PTR_NON_NULL(readout, false);
    403     PS_ASSERT_PTR_NON_NULL(recipe, false);
    404462    PS_ASSERT_PTR_NON_NULL(sources, false);
    405463
     
    429487    FWHM_T /= FWHM_N;
    430488
    431     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FWHM_MAJ",   PS_META_REPLACE, "PSF FWHM Major axis (mean)", FWHM_X);
    432     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MJ_SG",   PS_META_REPLACE, "PSF FWHM Major axis (sigma)", 0);
    433     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MJ_LQ",   PS_META_REPLACE, "PSF FWHM Major axis (lower quartile)", 0);
    434     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MJ_UQ",   PS_META_REPLACE, "PSF FWHM Major axis (upper quartile)", 0);
    435 
    436     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FWHM_MIN",   PS_META_REPLACE, "PSF FWHM Minor axis (mean)", FWHM_Y);
    437     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MN_SG",   PS_META_REPLACE, "PSF FWHM Minor axis (sigma)", 0);
    438     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MN_LQ",   PS_META_REPLACE, "PSF FWHM Minor axis (lower quartile)", 0);
    439     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MN_UQ",   PS_META_REPLACE, "PSF FWHM Minor axis (upper quartile)", 0);
    440 
    441     psMetadataAddF32 (recipe, PS_LIST_TAIL, "ANGLE",    PS_META_REPLACE, "PSF angle",           FWHM_T);
    442     psMetadataAddS32 (recipe, PS_LIST_TAIL, "NPSFSTAR", PS_META_REPLACE, "Number of stars used to make PSF", 0);
    443     psMetadataAddBool(recipe, PS_LIST_TAIL, "PSFMODEL", PS_META_REPLACE, "Valid PSF Model?", false);
     489    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FWHM_MAJ",   PS_META_REPLACE, "PSF FWHM Major axis (mean)", FWHM_X);
     490    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MJ_SG",   PS_META_REPLACE, "PSF FWHM Major axis (sigma)", 0);
     491    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MJ_LQ",   PS_META_REPLACE, "PSF FWHM Major axis (lower quartile)", 0);
     492    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MJ_UQ",   PS_META_REPLACE, "PSF FWHM Major axis (upper quartile)", 0);
     493    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FWHM_MIN",   PS_META_REPLACE, "PSF FWHM Minor axis (mean)", FWHM_Y);
     494    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MN_SG",   PS_META_REPLACE, "PSF FWHM Minor axis (sigma)", 0);
     495    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MN_LQ",   PS_META_REPLACE, "PSF FWHM Minor axis (lower quartile)", 0);
     496    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MN_UQ",   PS_META_REPLACE, "PSF FWHM Minor axis (upper quartile)", 0);
     497    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "ANGLE",    PS_META_REPLACE, "PSF angle",           FWHM_T);
     498    psMetadataAddS32 (readout->analysis, PS_LIST_TAIL, "NPSFSTAR", PS_META_REPLACE, "Number of stars used to make PSF", 0);
     499    psMetadataAddBool(readout->analysis, PS_LIST_TAIL, "PSFMODEL", PS_META_REPLACE, "Valid PSF Model?", false);
    444500
    445501    return true;
  • trunk/psphot/src/psphotDeblendSatstars.c

    r25885 r26894  
    11# include "psphotInternal.h"
    22
    3 bool psphotDeblendSatstars (pmReadout *readout, psArray *sources, psMetadata *recipe) {
     3// for now, let's store the detections on the readout->analysis for each readout
     4bool psphotDeblendSatstars (pmConfig *config, const pmFPAview *view)
     5{
     6    bool status = true;
     7
     8    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     9    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     10
     11    // loop over the available readouts
     12    for (int i = 0; i < num; i++) {
     13        if (!psphotDeblendSatstarsReadout (config, view, "PSPHOT.INPUT", i)) {
     14            psError (PSPHOT_ERR_CONFIG, false, "failed on saturated star deblend analysis for PSPHOT.INPUT entry %d", i);
     15            return false;
     16        }
     17    }
     18    return true;
     19}
     20
     21bool psphotDeblendSatstarsReadout (pmConfig *config, const pmFPAview *view, const char *filename, int fileIndex) {
    422
    523    int N;
    624    pmSource *source;
     25    bool status;
    726
    827    psTimerStart ("psphot.deblend.sat");
     
    1130    float SAT_MIN_RADIUS = 5.0;
    1231
    13     bool status;
     32    // find the currently selected readout
     33    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, fileIndex); // File of interest
     34    psAssert (file, "missing file?");
     35
     36    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     37    psAssert (readout, "missing readout?");
     38
     39    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     40    psAssert (detections, "missing detections?");
     41
     42    psArray *sources = detections->newSources;
     43    psAssert (sources, "missing sources?");
     44
     45    if (!sources->n) {
     46        psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping satstar blend");
     47        return true;
     48    }
     49
     50    // select the appropriate recipe information
     51    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     52    psAssert (recipe, "missing recipe?");
     53
    1454    pmCell *cell = readout->parent;
    1555    float SATURATION = 0.75*psMetadataLookupF32 (&status, cell->concepts, "CELL.SATURATION");
  • trunk/psphot/src/psphotEfficiency.c

    r26453 r26894  
    66//#define TESTING
    77
     8
     9# if 0
    810
    911// Calculate the limiting magnitude for an image
     
    3335
    3436    psKernel *kernel = psImageSmoothKernel(smoothSigma, smoothNsigma); // Kernel used for smoothing
    35     psKernel *newCovar = psImageCovarianceCalculate(kernel, ro->covariance); // Covariance matrix
     37    *covarFactor = psImageCovarianceCalculateFactor(kernel, ro->covariance);
    3638    psFree(kernel);
    37     *covarFactor = psImageCovarianceFactor(newCovar); // Variance factor
    38     psFree(newCovar);
    3939
    4040    psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN); // Statistics for variance
     
    152152}
    153153
     154# endif
     155
     156bool psphotEfficiency (pmConfig *config, const pmFPAview *view)
     157{
     158    bool status = true;
     159
     160    // select the appropriate recipe information
     161    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     162    psAssert (recipe, "missing recipe?");
     163
     164    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     165    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     166
     167    // loop over the available readouts
     168    for (int i = 0; i < num; i++) {
     169        if (!psphotEfficiencyReadout (config, view, "PSPHOT.INPUT", i, recipe)) {
     170            psError (PSPHOT_ERR_CONFIG, false, "failed to measure detection efficiency for PSPHOT.INPUT entry %d", i);
     171            return false;
     172        }
     173    }
     174    return true;
     175}
    154176
    155177// Determine detection efficiency
    156 bool psphotEfficiency(pmConfig *config, pmReadout *readout, const pmFPAview *view, const pmPSF *psf,
    157                 psMetadata *recipe, const psArray *realSources)
     178bool psphotEfficiencyReadout(pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe)
    158179{
     180# if 0
     181    bool status = true;
     182
     183    psTimerStart("psphot.fake");
     184
     185    // find the currently selected readout
     186    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     187    psAssert (file, "missing file?");
     188
     189    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     190    psAssert (readout, "missing readout?");
     191
     192    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     193    psAssert (detections, "missing detections?");
     194
     195    psArray *realSources = detections->allSources;
     196    psAssert (realSources, "missing sources?");
     197
     198    // XXX do we need to skip this step if we do not have a psf?
     199    pmPSF *psf = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF");
     200    psAssert (psf, "missing psf?");
     201
    159202    PM_ASSERT_READOUT_NON_NULL(readout, false);
    160203    PM_ASSERT_READOUT_IMAGE(readout, false);
    161204    PS_ASSERT_PTR_NON_NULL(psf, false);
    162205    PS_ASSERT_METADATA_NON_NULL(recipe, false);
    163     PS_ASSERT_ARRAY_NON_NULL(realSources, false);
    164 
    165     psTimerStart("psphot.fake");
    166206
    167207    // Collect recipe information
     
    206246    // remove all sources, adding noise for subtracted sources
    207247    psphotRemoveAllSources(realSources, recipe);
    208     //    psphotAddNoise(readout, realSources, recipe);
     248    // psphotAddNoise(readout, realSources, recipe);
    209249
    210250
     
    480520    psLogMsg("psphot", PS_LOG_INFO, "Detection efficiency: %lf sec\n", psTimerClear("psphot.fake"));
    481521
     522# endif
    482523
    483524    return true;
  • trunk/psphot/src/psphotExtendedSourceAnalysis.c

    r25755 r26894  
    11# include "psphotInternal.h"
    22
     3// for now, let's store the detections on the readout->analysis for each readout
     4bool psphotExtendedSourceAnalysis (pmConfig *config, const pmFPAview *view)
     5{
     6    bool status = true;
     7
     8    // select the appropriate recipe information
     9    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     10    psAssert (recipe, "missing recipe?");
     11
     12    // perform full non-linear fits / extended source analysis?
     13    if (!psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANALYSIS")) {
     14        psLogMsg ("psphot", PS_LOG_INFO, "skipping extended source measurements\n");
     15        return true;
     16    }
     17
     18    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     19    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     20
     21    // loop over the available readouts
     22    for (int i = 0; i < num; i++) {
     23        if (!psphotExtendedSourceAnalysisReadout (config, view, "PSPHOT.INPUT", i, recipe)) {
     24            psError (PSPHOT_ERR_CONFIG, false, "failed on measure extended source aperture-like parameters for PSPHOT.INPUT entry %d", i);
     25            return false;
     26        }
     27    }
     28    return true;
     29}
     30
    331// aperture-like measurements for extended sources
    4 bool psphotExtendedSourceAnalysis (pmReadout *readout, psArray *sources, psMetadata *recipe) {
     32bool psphotExtendedSourceAnalysisReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe) {
    533
    634    bool status;
     
    1139    int Nkron = 0;
    1240
     41    // find the currently selected readout
     42    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     43    psAssert (file, "missing file?");
     44
     45    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     46    psAssert (readout, "missing readout?");
     47
     48    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     49    psAssert (detections, "missing detections?");
     50
     51    psArray *sources = detections->allSources;
     52    psAssert (sources, "missing sources?");
     53
     54    if (!sources->n) {
     55        psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping source size");
     56        return true;
     57    }
     58
    1359    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
    1460    psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
    1561    assert (maskVal);
    16 
    17     // perform full non-linear fits / extended source analysis?
    18     if (!psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANALYSIS")) {
    19         psLogMsg ("psphot", PS_LOG_INFO, "skipping extended source measurements\n");
    20         return true;
    21     }
    2262
    2363    // XXX require petrosian analysis for non-linear fits?
  • trunk/psphot/src/psphotExtendedSourceFits.c

    r25755 r26894  
    11# include "psphotInternal.h"
    22
     3// for now, let's store the detections on the readout->analysis for each readout
     4bool psphotExtendedSourceFits (pmConfig *config, const pmFPAview *view)
     5{
     6    bool status = true;
     7
     8    // select the appropriate recipe information
     9    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     10    psAssert (recipe, "missing recipe?");
     11
     12    // perform full extended source non-linear fits?
     13    if (!psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_FITS")) {
     14        psLogMsg ("psphot", PS_LOG_INFO, "skipping extended source measurements\n");
     15        return true;
     16    }
     17
     18    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     19    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     20
     21    // loop over the available readouts
     22    for (int i = 0; i < num; i++) {
     23        if (!psphotExtendedSourceFitsReadout (config, view, "PSPHOT.INPUT", i, recipe)) {
     24            psError (PSPHOT_ERR_CONFIG, false, "failed on to fit extended sources for PSPHOT.INPUT entry %d", i);
     25            return false;
     26        }
     27    }
     28    return true;
     29}
     30
    331// non-linear model fitting for extended sources
    4 bool psphotExtendedSourceFits (pmReadout *readout, psArray *sources, psMetadata *recipe) {
     32bool psphotExtendedSourceFitsReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe) {
    533
    634    bool status;
     
    1240    bool savePics = false;
    1341
     42    // find the currently selected readout
     43    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, 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
    1460    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
    1561    psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
     
    2167    // maskVal is used to test for rejected pixels, and must include markVal
    2268    maskVal |= markVal;
    23 
    24     // perform full extended source non-linear fits?
    25     if (!psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_FITS")) {
    26         psLogMsg ("psphot", PS_LOG_INFO, "skipping extended source measurements\n");
    27         return true;
    28     }
    2969
    3070    // select the collection of desired models
  • trunk/psphot/src/psphotFake.c

    r26266 r26894  
    2828    float smoothSigma  = 0.5*(FWHM_X + FWHM_Y) / (2.0*sqrtf(2.0*log(2.0)));
    2929    psKernel *kernel = psImageSmoothKernel(smoothSigma, smoothNsigma); // Kernel used for smoothing
    30     psKernel *newCovar = psImageCovarianceCalculate(kernel, readout->covariance); // Covariance matrix
     30    float factor = psImageCovarianceCalculateFactor(kernel, readout->covariance); // Covariance matrix
    3131    psFree(kernel);
    32     float factor = psImageCovarianceFactor(newCovar); // Variance factor
    33     psFree(newCovar);
    3432
    3533    psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN); // Statistics for variance
     
    213211
    214212    // Putting results on recipe because that appears to be the psphot standard, but it's not a good idea
    215     psMetadataAddVector(recipe, PS_LIST_TAIL, "FAKE.EFF", PS_META_REPLACE,
    216                         "Efficiency fractions", frac);
    217     psMetadataAddVector(recipe, PS_LIST_TAIL, "FAKE.MAG", PS_META_REPLACE,
    218                         "Efficiency magnitudes", magOffsets);
    219     psMetadataAddF32(recipe, PS_LIST_TAIL, "FAKE.REF", PS_META_REPLACE,
    220                      "Efficiency reference magnitude", magLim);
     213    psMetadataAddVector(readout->analysis, PS_LIST_TAIL, "FAKE.EFF", PS_META_REPLACE, "Efficiency fractions", frac);
     214    psMetadataAddVector(readout->analysis, PS_LIST_TAIL, "FAKE.MAG", PS_META_REPLACE, "Efficiency magnitudes", magOffsets);
     215    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "FAKE.REF", PS_META_REPLACE, "Efficiency reference magnitude", magLim);
    221216
    222217    psFree(frac);
  • trunk/psphot/src/psphotFindDetections.c

    r25755 r26894  
    11# include "psphotInternal.h"
    22
     3// we store the detections on the readout->analysis for each readout this function finds new
     4// peaks and new footprints.  any old peaks are saved on oldPeaks.  the resulting footprint set
     5// contains all footprints (old and new)
     6bool psphotFindDetections (pmConfig *config, const pmFPAview *view, bool firstPass)
     7{
     8    bool status = true;
     9
     10    // select the appropriate recipe information
     11    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     12    psAssert (recipe, "missing recipe?");
     13
     14    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     15    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     16
     17    // loop over the available readouts
     18    for (int i = 0; i < num; i++) {
     19        if (!psphotFindDetectionsReadout (config, view, "PSPHOT.INPUT", i, recipe, firstPass)) {
     20            psError (PSPHOT_ERR_CONFIG, false, "failed to find initial detections for PSPHOT.INPUT entry %d", i);
     21            return false;
     22        }
     23    }
     24    return true;
     25}
     26
    327// smooth the image, search for peaks, optionally define footprints based on the peaks
    4 pmDetections *psphotFindDetections (pmDetections *detections, pmReadout *readout, psMetadata *recipe) {
     28bool psphotFindDetectionsReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe, bool firstPass) {
    529
    630    bool status;
     
    933    int NMAX = 0;
    1034
     35    // find the currently selected readout
     36    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     37    psAssert (file, "missing file?");
     38
     39    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     40    psAssert (readout, "missing readout?");
     41
    1142    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
    1243    psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
    13     assert (maskVal);
     44    psAssert (maskVal, "missing mask value?");
    1445
    1546    // Use the new pmFootprints approach?
    1647    const bool useFootprints = psMetadataLookupBool(NULL, recipe, "USE_FOOTPRINTS");
    1748
    18     // on first pass, detections have not yet been allocated
     49    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     50    // on the initial pass, detections have not yet been allocated or saved on readout->analysis
    1951    if (!detections) {
     52        // create the container
    2053        detections = pmDetectionsAlloc();
     54       
     55        // save detections on the readout->analysis
     56        if (!psMetadataAddPtr (readout->analysis, PS_LIST_TAIL, "PSPHOT.DETECTIONS", PS_META_REPLACE | PS_DATA_UNKNOWN, "psphot detections", detections)) {
     57            psError (PSPHOT_ERR_CONFIG, false, "problem saving detections on readout");
     58            return false;
     59        }
     60    } else {
     61        psMemIncrRefCounter(detections); // so we can free the detections below
     62    }
     63
     64    if (firstPass) {
    2165        pass = 1;
    2266        NSIGMA_PEAK = psMetadataLookupF32 (&status, recipe, "PEAKS_NSIGMA_LIMIT"); PS_ASSERT (status, NULL);
     
    3074    float threshold = PS_SQR(NSIGMA_PEAK);
    3175
    32     // move the old peaks array (if it exists) to oldPeaks
    33     // XXX generically, we should be able to call this function an arbitrary number of times
     76    // move the old peaks array (if it exists) to oldPeaks XXX generically, we should be able
     77    // to call this function an arbitrary number of times the old peaks are saved so they can
     78    // be freed later -- the have to be freed after psphotFindFootprints is called below, since
     79    // they are also owned by the oldFootprints, which are in turn merged into the new
     80    // footprints.  (what about the source->peak entry?)
     81   
    3482    assert (detections->oldPeaks == NULL);
    3583    detections->oldPeaks = detections->peaks;
     
    3987    psImage *significance = psphotSignificanceImage (readout, recipe, pass, maskVal);
    4088
    41     // display the backsub and backgnd images
    42     psphotVisualShowSignificance (significance);
     89    // display the significance image
     90    psphotVisualShowSignificance (significance, -1.0, PS_SQR(3.0*NSIGMA_PEAK));
     91
     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    }   
    4398
    4499    // detect the peaks in the significance image
    45100    detections->peaks = psphotFindPeaks (significance, readout, recipe, threshold, NMAX);
    46     psMetadataAddF32  (recipe, PS_LIST_TAIL, "PEAK_THRESHOLD", PS_META_REPLACE, "Peak Detection Threshold", threshold);
     101    psMetadataAddF32  (readout->analysis, PS_LIST_TAIL, "PEAK_THRESHOLD", PS_META_REPLACE, "Peak Detection Threshold", threshold);
    47102    if (!detections->peaks) {
    48         // No peaks found
    49         return NULL;
     103        // we only get a NULL peaks array due to a programming or config error.
     104        // this will result in a failure.
     105        psFree (detections);
     106        psError (PSPHOT_ERR_CONFIG, false, "failed on peak search");
     107        return false;
    50108    }
    51109
    52110    // optionally merge peaks into footprints
    53111    if (useFootprints) {
    54         psphotFindFootprints (detections, significance, readout, recipe, threshold, pass, maskVal);
     112        psphotFindFootprints (detections, significance, readout, recipe, threshold, pass, maskVal);
    55113    }
    56114
     
    61119    psphotVisualShowFootprints (detections);
    62120
    63     return detections;
     121    psFree (detections);
     122
     123    return true;
    64124}
    65125
  • trunk/psphot/src/psphotFindFootprints.c

    r25755 r26894  
    4141    if (pass == 2) {
    4242        // merge in old peaks;
    43         const int includePeaks = 0x0 | 0x2; // i.e. just from newFootprints
    44 
    45         // XXX EAM : still not sure I understand this: are we double-couning or undercounting peaks
     43        const int includePeaks = 0x1 | 0x2; // i.e. both new and old footprints
    4644
    4745        psArray *mergedFootprints = pmFootprintArraysMerge(detections->footprints, footprints, includePeaks);
     
    5048        psFree(footprints);
    5149        psFree(detections->footprints);
     50
     51        // replace the merged footprints on the detection structure
    5252        detections->footprints = mergedFootprints;
    5353    } else {
     
    6161    return detections;
    6262}
     63
     64bool psphotCheckFootprints (pmDetections *detections) {
     65
     66    // check for messed up footprints in the old peaks
     67    for (int i = 0; i < detections->oldPeaks->n; i++) {
     68        pmPeak *peak = detections->oldPeaks->data[i];
     69        pmFootprint *footprint = peak->footprint;
     70        if (!footprint) continue;
     71        for (int j = 0; j < footprint->spans->n; j++) {
     72            pmSpan *sp = footprint->spans->data[j];
     73            psAssert (sp, "missing span");
     74        }
     75    }
     76    return true;
     77}
  • trunk/psphot/src/psphotFindPeaks.c

    r25755 r26894  
    1313    psArray *peaks = pmPeaksInImage (significance, threshold);
    1414    if (peaks == NULL) {
    15         // XXX should we be sending back an empty array instead of NULL?
    16         // XXX this may also be due to a programming or config error
     15        // we only get a NULL peaks array due to a programming or config error.
     16        // this will result in a failure.
     17        psError(PSPHOT_ERR_DATA, false, "no peaks found in this image");
     18        return NULL;
     19    }
     20
     21    if (peaks->n == 0) {
    1722        // XXX do we need to set something in the readout->analysis to indicate that
    1823        // we tried and failed to find peaks (something in the header data)
    19         psError(PSPHOT_ERR_DATA, false, "no peaks found in this image");
    20         return false;
     24        psLogMsg ("psphot", PS_LOG_INFO, "no peaks found in this image");
     25        return peaks;
    2126    }
    2227
  • trunk/psphot/src/psphotFitSourcesLinear.c

    r25990 r26894  
    1212static bool SetBorderMatrixElements (psSparseBorder *border, pmReadout *readout, psArray *sources, bool constant_weights, int SKY_FIT_ORDER, psImageMaskType markVal);
    1313
    14 bool psphotFitSourcesLinear (pmReadout *readout, psArray *sources, const psMetadata *recipe, const pmPSF *psf, bool final) {
     14// for now, let's store the detections on the readout->analysis for each readout
     15bool psphotFitSourcesLinear (pmConfig *config, const pmFPAview *view, bool final)
     16{
     17    bool status = true;
     18
     19    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     20    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     21
     22    // loop over the available readouts
     23    for (int i = 0; i < num; i++) {
     24        if (!psphotFitSourcesLinearReadout (config, view, "PSPHOT.INPUT", i, final)) {
     25            psError (PSPHOT_ERR_CONFIG, false, "failed to fit sources (linear) for PSPHOT.INPUT entry %d", i);
     26            return false;
     27        }
     28    }
     29    return true;
     30}
     31
     32bool psphotFitSourcesLinearReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, bool final) {
    1533
    1634    bool status;
     
    1937    float f;
    2038    // float r;
     39
     40    // select the appropriate recipe information
     41    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     42    assert (recipe);
     43
     44    // find the currently selected readout
     45    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     46    psAssert (file, "missing file?");
     47
     48    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     49    psAssert (readout, "missing readout?");
     50
     51    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     52    psAssert (detections, "missing detections?");
     53
     54    psArray *sources = detections->allSources;
     55    psAssert (sources, "missing sources?");
     56
     57    if (!sources->n) {
     58        psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping linear fit");
     59        return true;
     60    }
     61
     62    pmPSF *psf = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF");
     63    psAssert (sources, "missing psf?");
    2164
    2265    psTimerStart ("psphot.linear");
     
    248291    psphotVisualPlotChisq (sources);
    249292    // psphotVisualShowFlags (sources);
     293
     294    // We have to place this visualization here because the models are not realized until
     295    // psphotGuessModels or fitted until psphotFitSourcesLinear.
     296    psphotVisualShowPSFStars (recipe, psf, sources);
    250297
    251298    return true;
  • trunk/psphot/src/psphotForcedReadout.c

    r25981 r26894  
    2020
    2121    // set the photcode for this image
    22     if (!psphotAddPhotcode (recipe, config, view, "PSPHOT.INPUT")) {
     22    if (!psphotAddPhotcode (config, view)) {
    2323        psError (PSPHOT_ERR_CONFIG, false, "trouble defining the photcode");
    2424        return false;
    2525    }
    26 
    27     // find the currently selected readout
    28     pmReadout  *readout = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT");
    29     PS_ASSERT_PTR_NON_NULL (readout, false);
    3026
    3127    // optional break-point for processing
     
    3430
    3531    // Generate the mask and weight images, including the user-defined analysis region of interest
    36     psphotSetMaskAndVariance (config, readout, recipe);
     32    psphotSetMaskAndVariance (config, view);
    3733    if (!strcasecmp (breakPt, "NOTHING")) {
    38         return psphotReadoutCleanup(config, readout, recipe, NULL, NULL, NULL);
     34        return psphotReadoutCleanup(config, view);
    3935    }
    4036
    41     // display the image, weight, mask (ch 1,2,3)
    42     psphotVisualShowImage (readout);
    43 
    4437    // generate a background model (median, smoothed image)
    45     if (!psphotModelBackground (config, view, "PSPHOT.INPUT")) {
    46         return psphotReadoutCleanup (config, readout, recipe, NULL, NULL, NULL);
     38    if (!psphotModelBackground (config, view)) {
     39        return psphotReadoutCleanup (config, view);
    4740    }
    48     if (!psphotSubtractBackground (config, view, "PSPHOT.INPUT")) {
    49         return psphotReadoutCleanup (config, readout, recipe, NULL, NULL, NULL);
     41    if (!psphotSubtractBackground (config, view)) {
     42        return psphotReadoutCleanup (config, view);
    5043    }
    5144    if (!strcasecmp (breakPt, "BACKMDL")) {
    52         return psphotReadoutCleanup (config, readout, recipe, NULL, NULL, NULL);
     45        return psphotReadoutCleanup (config, view);
    5346    }
    5447
    55     // display the backsub and backgnd images
    56     psphotVisualShowBackground (config, view, readout);
    57 
    58     // load the psf model, if suppled.  FWHM_X,FWHM_Y,etc are saved in the recipe
    59     pmPSF *psf = psphotLoadPSF (config, view, recipe);
    60     if (!psf) {
    61         psError(PSPHOT_ERR_CONFIG, false, "unable to load psf model");
    62         return false;
     48    if (!psphotLoadPSF (config, view)) {
     49        // this only happens if we had a programming error in psphotLoadPSF
     50        psError (PSPHOT_ERR_UNKNOWN, false, "error loading psf model");
     51        return psphotReadoutCleanup (config, view);
    6352    }
    6453
    6554    // include externally-supplied sources
    66     psArray *sources = psArrayAllocEmpty(100);
    67     psphotLoadExtSources (config, view, sources);
     55    psphotLoadExtSources (config, view);
    6856
    6957    // construct an initial model for each object, set the radius to fitRadius, set circular fit mask
    70     psphotGuessModels (config, readout, sources, psf);
     58    psphotGuessModels (config, view);
    7159
    7260    // linear PSF fit to source peaks, subtract the models from the image (in PSF mask)
    73     psphotFitSourcesLinear (readout, sources, recipe, psf, FALSE);
     61    psphotFitSourcesLinear (config, view, false);
    7462
    7563    // identify CRs and extended sources
     
    7967
    8068    // calculate source magnitudes
    81     psphotMagnitudes(config, readout, view, sources, psf);
     69    psphotMagnitudes(config, view);
    8270
    8371    // XXX do I want to do this?
     
    9179
    9280    // drop the references to the image pixels held by each source
    93     psphotSourceFreePixels (sources);
     81    psphotSourceFreePixels (config, view);
    9482
    9583    // create the exported-metadata and free local data
    96     return psphotReadoutCleanup(config, readout, recipe, NULL, psf, sources);
     84    return psphotReadoutCleanup(config, view);
    9785}
  • trunk/psphot/src/psphotGuessModels.c

    r25755 r26894  
    33// XXX : the threading here is not great.  this may be due to blocks between elements, but
    44// the selection of the objects in a cell is not optimal.  To fix:
    5 // 1) define the boundaries of the cells up front 
     5// 1) define the boundaries of the cells up front
    66// 2) loop over the sources once and associate them with their cell
    77// 3) define the threaded function to work with sources for a given cell
    88
    9 // construct an initial PSF model for each object
    10 bool psphotGuessModels (pmConfig *config, pmReadout *readout, psArray *sources, pmPSF *psf) {
     9// for now, let's store the detections on the readout->analysis for each readout
     10bool psphotGuessModels (pmConfig *config, const pmFPAview *view)
     11{
     12    bool status = true;
     13
     14    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     15    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     16
     17    // loop over the available readouts
     18    for (int i = 0; i < num; i++) {
     19        if (!psphotGuessModelsReadout (config, view, "PSPHOT.INPUT", i)) {
     20            psError (PSPHOT_ERR_CONFIG, false, "failed on to guess models for PSPHOT.INPUT entry %d", i);
     21            return false;
     22        }
     23    }
     24    return true;
     25}
     26
     27// construct an initial PSF model for each object (new sources only)
     28bool psphotGuessModelsReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index) {
    1129
    1230    bool status;
    1331
    1432    psTimerStart ("psphot.models");
     33
     34    // find the currently selected readout
     35    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     36    psAssert (file, "missing file?");
     37
     38    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     39    psAssert (readout, "missing readout?");
     40
     41    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     42    psAssert (detections, "missing detections?");
     43
     44    psArray *sources = detections->newSources;
     45    psAssert (sources, "missing sources?");
     46
     47    if (!sources->n) {
     48        psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping model guess");
     49        return true;
     50    }
     51
     52    pmPSF *psf = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF");
     53    psAssert (psf, "missing psf?");
    1554
    1655    // select the appropriate recipe information
     
    2160    int nThreads = psMetadataLookupS32(&status, config->arguments, "NTHREADS"); // Number of threads
    2261    if (!status) {
    23         nThreads = 0;
     62        nThreads = 0;
    2463    }
    2564
     
    3675
    3776    // setup the PSF fit radius details
    38     psphotInitRadiusPSF (recipe, psf->type);
     77    psphotInitRadiusPSF (recipe, readout->analysis, psf->type);
    3978
    4079    // choose Cx, Cy (see psphotThreadTools.c for overview of the concepts)
     
    4685    for (int i = 0; i < cellGroups->n; i++) {
    4786
    48         psArray *cells = cellGroups->data[i];
    49 
    50         for (int j = 0; j < cells->n; j++) {
    51 
    52             // allocate a job -- if threads are not defined, this just runs the job
    53             psThreadJob *job = psThreadJobAlloc ("PSPHOT_GUESS_MODEL");
    54             psArrayAdd(job->args, 1, readout);
    55             psArrayAdd(job->args, 1, cells->data[j]); // sources
    56             psArrayAdd(job->args, 1, psf);
    57 
    58             // XXX change these to use abstract mask type info
    59             PS_ARRAY_ADD_SCALAR(job->args, maskVal,  PS_TYPE_IMAGE_MASK);
    60             PS_ARRAY_ADD_SCALAR(job->args, markVal,  PS_TYPE_IMAGE_MASK);
    61 
    62             if (!psThreadJobAddPending(job)) {
    63                 psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
    64                 psFree (job);
    65                 return false;
    66             }
    67             psFree(job);
    68         }
    69 
    70         // wait for the threads to finish and manage results
    71         // wait here for the threaded jobs to finish
    72         // fprintf (stderr, "wait for threads (%d, %d)\n", jx, jy);
    73         if (!psThreadPoolWait (false)) {
    74             psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
    75             return false;
    76         }
    77 
    78         // we have only supplied one type of job, so we can assume the types here
    79         psThreadJob *job = NULL;
    80         while ((job = psThreadJobGetDone()) != NULL) {
    81             // we have no returned data from this operation
    82             if (job->args->n < 1) {
    83                 fprintf (stderr, "error with job\n");
    84             }
    85             psFree(job);
    86         }
     87        psArray *cells = cellGroups->data[i];
     88
     89        for (int j = 0; j < cells->n; j++) {
     90
     91            // allocate a job -- if threads are not defined, this just runs the job
     92            psThreadJob *job = psThreadJobAlloc ("PSPHOT_GUESS_MODEL");
     93            psArrayAdd(job->args, 1, readout);
     94            psArrayAdd(job->args, 1, cells->data[j]); // sources
     95            psArrayAdd(job->args, 1, psf);
     96
     97            // XXX change these to use abstract mask type info
     98            PS_ARRAY_ADD_SCALAR(job->args, maskVal,  PS_TYPE_IMAGE_MASK);
     99            PS_ARRAY_ADD_SCALAR(job->args, markVal,  PS_TYPE_IMAGE_MASK);
     100
     101            if (!psThreadJobAddPending(job)) {
     102                psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
     103                psFree (job);
     104                return false;
     105            }
     106            psFree(job);
     107        }
     108
     109        // wait for the threads to finish and manage results
     110        // wait here for the threaded jobs to finish
     111        // fprintf (stderr, "wait for threads (%d, %d)\n", jx, jy);
     112        if (!psThreadPoolWait (false)) {
     113            psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
     114            return false;
     115        }
     116
     117        // we have only supplied one type of job, so we can assume the types here
     118        psThreadJob *job = NULL;
     119        while ((job = psThreadJobGetDone()) != NULL) {
     120            // we have no returned data from this operation
     121            if (job->args->n < 1) {
     122                fprintf (stderr, "error with job\n");
     123            }
     124            psFree(job);
     125        }
    87126    }
    88127
     
    90129    int nMiss = 0;
    91130    for (int i = 0; i < sources->n; i++) {
    92         pmSource *source = sources->data[i];
    93         if (source->tmpFlags & PM_SOURCE_TMPF_MODEL_GUESS) {
    94             continue;
    95         }
    96         nMiss ++;
     131        pmSource *source = sources->data[i];
     132        if (source->tmpFlags & PM_SOURCE_TMPF_MODEL_GUESS) {
     133            continue;
     134        }
     135        nMiss ++;
    97136    }
    98137    psAssert (nMiss == 0, "failed to attempt to build models for %d objects\n", nMiss);
     
    110149    psArray *sources   = job->args->data[1];
    111150    pmPSF *psf         = job->args->data[2];
    112    
     151
    113152    psImageMaskType maskVal = PS_SCALAR_VALUE(job->args->data[3],PS_TYPE_IMAGE_MASK_DATA);
    114153    psImageMaskType markVal = PS_SCALAR_VALUE(job->args->data[4],PS_TYPE_IMAGE_MASK_DATA);
     
    117156
    118157    for (int i = 0; i < sources->n; i++) {
    119         pmSource *source = sources->data[i];
    120 
    121         // this is used to mark sources for which the model is measured. We check later that
    122         // all are used.
    123         source->tmpFlags |= PM_SOURCE_TMPF_MODEL_GUESS;
    124 
    125         // skip non-astronomical objects (very likely defects)
    126         if (source->type == PM_SOURCE_TYPE_DEFECT) continue;
    127         if (source->type == PM_SOURCE_TYPE_SATURATED) continue;
    128         if (!source->peak) continue;
    129 
    130         nSrc ++;
    131        
    132         // the guess central intensity comes from the peak:
    133         float Io = source->peak->flux;
    134 
    135         // We have two options to get a guess for the object position: the position from the
    136         // peak and the position from the moments.  Use the peak position if (a) there are no
    137         // moments and (b) the sources is not saturated
    138 
    139         bool useMoments = false;
    140         useMoments = (source->mode & PM_SOURCE_MODE_SATSTAR);  // we only want to try if SATSTAR is set, but..
    141         useMoments = (useMoments && source->moments);          // can't if there are no moments
    142         useMoments = (useMoments && source->moments->nPixels); // can't if the moments were not measured
    143         useMoments = (useMoments && !(source->mode && PM_SOURCE_MODE_MOMENTS_FAILURE)); // can't if the moments failed...
    144 
    145         float Xo, Yo;
    146         if (useMoments) {
    147             Xo = source->moments->Mx;
    148             Yo = source->moments->My;
    149         } else {
    150             Xo = source->peak->xf;
    151             Yo = source->peak->yf;
    152         }
    153 
    154         // set PSF parameters for this model (apply 2D shape model to coordinates Xo, Yo)
    155         pmModel *modelPSF = pmModelFromPSFforXY(psf, Xo, Yo, Io);
    156 
    157         if (modelPSF == NULL) {
    158             psWarning ("Failed to determine PSF model at (%f,%f); trying image center", Xo, Yo);
    159 
    160             float Xc = 0.5*readout->image->numCols;
    161             float Yc = 0.5*readout->image->numRows;
    162             pmModel *modelPSF = pmModelFromPSFforXY(psf, Xc, Yc, Io);
    163             if (modelPSF == NULL) {
    164                 psError(PSPHOT_ERR_PSF, false, "Failed to determine PSF model at center of image");
    165                 return false;
    166             }
    167 
    168             // Now set the object position at the expected location:
    169             modelPSF->params->data.F32[PM_PAR_XPOS] = Xo;
    170             modelPSF->params->data.F32[PM_PAR_YPOS] = Yo;
    171             source->mode |= PM_SOURCE_MODE_BADPSF;
    172         }
    173 
    174         // set the fit radius based on the object flux limit and the model
    175         // this function affects the mask pixels
    176         psphotCheckRadiusPSF (readout, source, modelPSF, markVal);
    177 
    178         // set the source PSF model
    179         psAssert (source->modelPSF == NULL, "failed to free one of the models?");
    180         source->modelPSF = modelPSF;
    181         source->modelPSF->residuals = psf->residuals;
    182 
    183         pmSourceCacheModel (source, maskVal);  // ALLOC x14 (!)
     158        pmSource *source = sources->data[i];
     159
     160        // this is used to mark sources for which the model is measured. We check later that
     161        // all are used.
     162        source->tmpFlags |= PM_SOURCE_TMPF_MODEL_GUESS;
     163
     164        // skip non-astronomical objects (very likely defects)
     165        if (source->type == PM_SOURCE_TYPE_DEFECT) continue;
     166        if (source->type == PM_SOURCE_TYPE_SATURATED) continue;
     167        if (!source->peak) continue;
     168
     169        nSrc ++;
     170
     171        // the guess central intensity comes from the peak:
     172        float Io = source->peak->flux;
     173
     174        // We have two options to get a guess for the object position: the position from the
     175        // peak and the position from the moments.  Use the peak position if (a) there are no
     176        // moments and (b) the sources is not saturated
     177
     178        bool useMoments = false;
     179        useMoments = (source->mode & PM_SOURCE_MODE_SATSTAR);  // we only want to try if SATSTAR is set, but..
     180        useMoments = (useMoments && source->moments);          // can't if there are no moments
     181        useMoments = (useMoments && source->moments->nPixels); // can't if the moments were not measured
     182        useMoments = (useMoments && !(source->mode && PM_SOURCE_MODE_MOMENTS_FAILURE)); // can't if the moments failed...
     183
     184        float Xo, Yo;
     185        if (useMoments) {
     186            Xo = source->moments->Mx;
     187            Yo = source->moments->My;
     188        } else {
     189            Xo = source->peak->xf;
     190            Yo = source->peak->yf;
     191        }
     192
     193        // set PSF parameters for this model (apply 2D shape model to coordinates Xo, Yo)
     194        pmModel *modelPSF = pmModelFromPSFforXY(psf, Xo, Yo, Io);
     195
     196        if (modelPSF == NULL) {
     197            psWarning ("Failed to determine PSF model at (%f,%f); trying image center", Xo, Yo);
     198
     199            float Xc = 0.5*readout->image->numCols;
     200            float Yc = 0.5*readout->image->numRows;
     201            pmModel *modelPSF = pmModelFromPSFforXY(psf, Xc, Yc, Io);
     202            if (modelPSF == NULL) {
     203                psError(PSPHOT_ERR_PSF, false, "Failed to determine PSF model at center of image");
     204                return false;
     205            }
     206
     207            // Now set the object position at the expected location:
     208            modelPSF->params->data.F32[PM_PAR_XPOS] = Xo;
     209            modelPSF->params->data.F32[PM_PAR_YPOS] = Yo;
     210            source->mode |= PM_SOURCE_MODE_BADPSF;
     211        }
     212
     213        // set the fit radius based on the object flux limit and the model
     214        // this function affects the mask pixels
     215        psphotCheckRadiusPSF (readout, source, modelPSF, markVal);
     216
     217        // set the source PSF model
     218        psAssert (source->modelPSF == NULL, "failed to free one of the models?");
     219        source->modelPSF = modelPSF;
     220        source->modelPSF->residuals = psf->residuals;
     221
     222        pmSourceCacheModel (source, maskVal);  // ALLOC x14 (!)
    184223    }
    185224
  • trunk/psphot/src/psphotImageQuality.c

    r25755 r26894  
    44// XXX Lots of code duplication here
    55
     6// for now, let's store the detections on the readout->analysis for each readout
     7bool psphotImageQuality (pmConfig *config, const pmFPAview *view)
     8{
     9    bool status = true;
     10
     11    // select the appropriate recipe information
     12    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     13    psAssert (recipe, "missing recipe?");
     14
     15    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     16    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     17
     18    // loop over the available readouts
     19    for (int i = 0; i < num; i++) {
     20        if (!psphotImageQualityReadout (config, view, "PSPHOT.INPUT", i, recipe)) {
     21            psError (PSPHOT_ERR_CONFIG, false, "failed on to measure image quality for PSPHOT.INPUT entry %d", i);
     22            return false;
     23        }
     24    }
     25    return true;
     26}
     27
    628// selecting the 'good' stars (likely to be psf stars), measure the M_cn, M_sn terms for n = 2,3,4
    7 bool psphotImageQuality(psMetadata *recipe, psArray *sources)
     29bool psphotImageQualityReadout(pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe)
    830{
     31    bool status = true;
     32
     33    // find the currently selected readout
     34    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     35    psAssert (file, "missing file?");
     36
     37    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     38    psAssert (readout, "missing readout?");
     39
     40    // if we have a PSF, skip this analysis
     41    if (psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF")) {
     42        return true;
     43    }
     44
     45    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     46    psAssert (detections, "missing detections?");
     47
     48    psArray *sources = detections->newSources;
     49    psAssert (sources, "missing sources?");
     50
     51    if (!sources->n) {
     52        psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping image quality");
     53        return true;
     54    }
     55
    956    psVector *FWHM_MAJOR = psVectorAllocEmpty(100, PS_TYPE_F32);
    1057    psVector *FWHM_MINOR = psVectorAllocEmpty(100, PS_TYPE_F32);
     
    81128
    82129    if (num == 0) {
    83       psWarning("Unable to find sources from which to measure image quality");
    84       return false;
    85     }
    86 
    87     psMetadataAddS32(recipe, PS_LIST_TAIL, "IQ_NSTAR", PS_META_REPLACE,
    88                      "Number of stars used for IQ measurements", M2->n);
     130        psLogMsg ("psphot", PS_LOG_INFO, "no valid sources for image quality, skipping");
     131        return true;
     132    }
     133
     134    psMetadataAddS32(readout->analysis, PS_LIST_TAIL, "IQ_NSTAR", PS_META_REPLACE, "Number of stars used for IQ measurements", M2->n);
    89135
    90136// XXX make this a recipe option
     
    98144
    99145    float fwhm_major = stats->sampleMean;
    100     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_FW1",   PS_META_REPLACE,
    101                      "FWHM of Major Axis from moments", stats->sampleMean);
    102     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_FW1_E", PS_META_REPLACE,
    103                      "FWHM scatter (Major) from moments", stats->sampleStdev);
     146    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_FW1",   PS_META_REPLACE, "FWHM of Major Axis from moments", stats->sampleMean);
     147    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_FW1_E", PS_META_REPLACE, "FWHM scatter (Major) from moments", stats->sampleStdev);
    104148
    105149    if (!psVectorStats(stats, FWHM_MINOR, NULL, NULL, 0)) {
     
    108152    }
    109153    float fwhm_minor = stats->sampleMean;
    110     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_FW2",   PS_META_REPLACE,
    111                      "FWHM of Minor Axis from moments", stats->sampleMean);
    112     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_FW2_E", PS_META_REPLACE,
    113                      "FWHM scatter (Minor) from moments", stats->sampleStdev);
     154    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_FW2",   PS_META_REPLACE, "FWHM of Minor Axis from moments", stats->sampleMean);
     155    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_FW2_E", PS_META_REPLACE, "FWHM scatter (Minor) from moments", stats->sampleStdev);
    114156
    115157    if (!psVectorStats(stats, M2, NULL, NULL, 0)) {
     
    119161    float vM2 = stats->sampleMean;
    120162    float dM2 = stats->sampleStdev;
    121     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2",    PS_META_REPLACE,
    122                      "M_2 = sqrt (M_c2^2 + M_s2^2)", vM2);
    123     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2_ER", PS_META_REPLACE,
    124                      "Stdev of M_2", dM2);
    125     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2_LQ", PS_META_REPLACE,
    126                      "Lower Quartile of M_2", stats->sampleLQ);
    127     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2_UQ", PS_META_REPLACE,
    128                      "Upper Quartile of M_2", stats->sampleUQ);
     163    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2",    PS_META_REPLACE, "M_2 = sqrt (M_c2^2 + M_s2^2)", vM2);
     164    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2_ER", PS_META_REPLACE, "Stdev of M_2", dM2);
     165    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2_LQ", PS_META_REPLACE, "Lower Quartile of M_2", stats->sampleLQ);
     166    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2_UQ", PS_META_REPLACE, "Upper Quartile of M_2", stats->sampleUQ);
    129167
    130168    if (!psVectorStats(stats, M2c, NULL, NULL, 0)) {
     
    132170        goto FAIL;
    133171    }
    134     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2C",   PS_META_REPLACE,
    135                      "M_2c = sum f r^2 cos(2phi) / sum f", stats->sampleMean);
    136     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2C_E", PS_META_REPLACE,
    137                      "Stdev of M_2c", stats->sampleStdev);
    138     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2C_L", PS_META_REPLACE,
    139                      "Lower Quartile of M_2c", stats->sampleLQ);
    140     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2C_U", PS_META_REPLACE,
    141                      "Upper Quartile of M_2c", stats->sampleUQ);
     172    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2C",   PS_META_REPLACE, "M_2c = sum f r^2 cos(2phi) / sum f", stats->sampleMean);
     173    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2C_E", PS_META_REPLACE, "Stdev of M_2c", stats->sampleStdev);
     174    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2C_L", PS_META_REPLACE, "Lower Quartile of M_2c", stats->sampleLQ);
     175    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2C_U", PS_META_REPLACE, "Upper Quartile of M_2c", stats->sampleUQ);
    142176
    143177    if (!psVectorStats(stats, M2s, NULL, NULL, 0)) {
     
    145179        goto FAIL;
    146180    }
    147     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2S",   PS_META_REPLACE,
    148                      "M_2s = sum f r^2 cos(2phi) / sum f", stats->sampleMean);
    149     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2S_E", PS_META_REPLACE,
    150                      "Stdev of M_2s", stats->sampleStdev);
    151     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2S_L", PS_META_REPLACE,
    152                      "Lower Quartile of M_2s", stats->sampleLQ);
    153     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2S_U", PS_META_REPLACE,
    154                      "Upper Quartile of M_2s", stats->sampleUQ);
     181    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2S",   PS_META_REPLACE, "M_2s = sum f r^2 cos(2phi) / sum f", stats->sampleMean);
     182    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2S_E", PS_META_REPLACE, "Stdev of M_2s", stats->sampleStdev);
     183    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2S_L", PS_META_REPLACE, "Lower Quartile of M_2s", stats->sampleLQ);
     184    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2S_U", PS_META_REPLACE, "Upper Quartile of M_2s", stats->sampleUQ);
    155185
    156186    if (!psVectorStats(stats, M3, NULL, NULL, 0)) {
     
    160190    float vM3 = stats->sampleMean;
    161191    float dM3 = stats->sampleStdev;
    162     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M3",   PS_META_REPLACE,
    163                      "M_3 = sqrt (M_c3^2 + M_s3^2)", vM3);
    164     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M3_ER", PS_META_REPLACE,
    165                      "Stdev of M_3", dM3);
    166     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M3_LQ", PS_META_REPLACE,
    167                      "Lower Quartile of M_3", stats->sampleLQ);
    168     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M3_UQ", PS_META_REPLACE,
    169                      "Upper Quartile of M_3", stats->sampleUQ);
     192    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M3",   PS_META_REPLACE, "M_3 = sqrt (M_c3^2 + M_s3^2)", vM3);
     193    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M3_ER", PS_META_REPLACE, "Stdev of M_3", dM3);
     194    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M3_LQ", PS_META_REPLACE, "Lower Quartile of M_3", stats->sampleLQ);
     195    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M3_UQ", PS_META_REPLACE, "Upper Quartile of M_3", stats->sampleUQ);
    170196
    171197    if (!psVectorStats(stats, M4, NULL, NULL, 0)) {
     
    175201    float vM4 = stats->sampleMean;
    176202    float dM4 = stats->sampleStdev;
    177     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M4",   PS_META_REPLACE,
    178                      "M_4 = sqrt (M_c4^2 + M_s4^2)", vM4);
    179     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M4_ER", PS_META_REPLACE,
    180                      "Stdev of M_4", dM4);
    181     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M4_LQ", PS_META_REPLACE,
    182                      "Lower Quartile of M_4", stats->sampleLQ);
    183     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M4_UQ", PS_META_REPLACE,
    184                      "Upper Quartile of M_4", stats->sampleUQ);
     203    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M4",   PS_META_REPLACE, "M_4 = sqrt (M_c4^2 + M_s4^2)", vM4);
     204    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M4_ER", PS_META_REPLACE, "Stdev of M_4", dM4);
     205    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M4_LQ", PS_META_REPLACE, "Lower Quartile of M_4", stats->sampleLQ);
     206    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M4_UQ", PS_META_REPLACE, "Upper Quartile of M_4", stats->sampleUQ);
    185207
    186208#else
     
    192214    }
    193215    float fwhm_major = stats->robustMedian;
    194     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_FW1",   PS_META_REPLACE,
    195                      "FWHM of Major Axis from moments", stats->robustMedian);
    196     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_FW1_E", PS_META_REPLACE,
    197                      "FWHM scatter (Major) from moments", stats->robustStdev);
     216    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_FW1",   PS_META_REPLACE, "FWHM of Major Axis from moments", stats->robustMedian);
     217    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_FW1_E", PS_META_REPLACE, "FWHM scatter (Major) from moments", stats->robustStdev);
    198218
    199219    if (!psVectorStats(stats, FWHM_MINOR, NULL, NULL, 0)) {
     
    202222    }
    203223    float fwhm_minor = stats->robustMedian;
    204     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_FW2",   PS_META_REPLACE,
    205                      "FWHM of Minor Axis from moments", stats->robustMedian);
    206     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_FW2_E", PS_META_REPLACE,
    207                      "FWHM scatter (Minor) from moments", stats->robustStdev);
     224    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_FW2",   PS_META_REPLACE, "FWHM of Minor Axis from moments", stats->robustMedian);
     225    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_FW2_E", PS_META_REPLACE, "FWHM scatter (Minor) from moments", stats->robustStdev);
    208226
    209227    if (!psVectorStats(stats, M2, NULL, NULL, 0)) {
     
    213231    float vM2 = stats->robustMedian;
    214232    float dM2 = stats->robustStdev;
    215     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2",    PS_META_REPLACE,
    216                      "M_2 = sqrt (M_c2^2 + M_s2^2)", vM2);
    217     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2_ER", PS_META_REPLACE,
    218                      "Stdev of M_2", dM2);
    219     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2_LQ", PS_META_REPLACE,
    220                      "Lower Quartile of M_2", stats->robustLQ);
    221     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2_UQ", PS_META_REPLACE,
    222                      "Upper Quartile of M_2", stats->robustUQ);
     233    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2",    PS_META_REPLACE, "M_2 = sqrt (M_c2^2 + M_s2^2)", vM2);
     234    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2_ER", PS_META_REPLACE, "Stdev of M_2", dM2);
     235    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2_LQ", PS_META_REPLACE, "Lower Quartile of M_2", stats->robustLQ);
     236    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2_UQ", PS_META_REPLACE, "Upper Quartile of M_2", stats->robustUQ);
    223237
    224238    if (!psVectorStats(stats, M2c, NULL, NULL, 0)) {
     
    226240        goto FAIL;
    227241    }
    228     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2C",   PS_META_REPLACE,
    229                      "M_2c = sum f r^2 cos(2phi) / sum f", stats->robustMedian);
    230     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2C_E", PS_META_REPLACE,
    231                      "Stdev of M_2c", stats->robustStdev);
    232     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2C_L", PS_META_REPLACE,
    233                      "Lower Quartile of M_2c", stats->robustLQ);
    234     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2C_U", PS_META_REPLACE,
    235                      "Upper Quartile of M_2c", stats->robustUQ);
     242    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2C",   PS_META_REPLACE, "M_2c = sum f r^2 cos(2phi) / sum f", stats->robustMedian);
     243    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2C_E", PS_META_REPLACE, "Stdev of M_2c", stats->robustStdev);
     244    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2C_L", PS_META_REPLACE, "Lower Quartile of M_2c", stats->robustLQ);
     245    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2C_U", PS_META_REPLACE, "Upper Quartile of M_2c", stats->robustUQ);
    236246
    237247    if (!psVectorStats(stats, M2s, NULL, NULL, 0)) {
     
    239249        goto FAIL;
    240250    }
    241     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2S",   PS_META_REPLACE,
    242                      "M_2s = sum f r^2 cos(2phi) / sum f", stats->robustMedian);
    243     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2S_E", PS_META_REPLACE,
    244                      "Stdev of M_2s", stats->robustStdev);
    245     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2S_L", PS_META_REPLACE,
    246                      "Lower Quartile of M_2s", stats->robustLQ);
    247     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M2S_U", PS_META_REPLACE,
    248                      "Upper Quartile of M_2s", stats->robustUQ);
     251    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2S",   PS_META_REPLACE, "M_2s = sum f r^2 cos(2phi) / sum f", stats->robustMedian);
     252    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2S_E", PS_META_REPLACE, "Stdev of M_2s", stats->robustStdev);
     253    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2S_L", PS_META_REPLACE, "Lower Quartile of M_2s", stats->robustLQ);
     254    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2S_U", PS_META_REPLACE, "Upper Quartile of M_2s", stats->robustUQ);
    249255
    250256    if (!psVectorStats(stats, M3, NULL, NULL, 0)) {
     
    254260    float vM3 = stats->robustMedian;
    255261    float dM3 = stats->robustStdev;
    256     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M3",   PS_META_REPLACE,
    257                      "M_3 = sqrt (M_c3^2 + M_s3^2)", vM3);
    258     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M3_ER", PS_META_REPLACE,
    259                      "Stdev of M_3", dM3);
    260     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M3_LQ", PS_META_REPLACE,
    261                      "Lower Quartile of M_3", stats->robustLQ);
    262     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M3_UQ", PS_META_REPLACE,
    263                      "Upper Quartile of M_3", stats->robustUQ);
     262    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M3",   PS_META_REPLACE, "M_3 = sqrt (M_c3^2 + M_s3^2)", vM3);
     263    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M3_ER", PS_META_REPLACE, "Stdev of M_3", dM3);
     264    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M3_LQ", PS_META_REPLACE, "Lower Quartile of M_3", stats->robustLQ);
     265    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M3_UQ", PS_META_REPLACE, "Upper Quartile of M_3", stats->robustUQ);
    264266
    265267    if (!psVectorStats(stats, M4, NULL, NULL, 0)) {
     
    269271    float vM4 = stats->robustMedian;
    270272    float dM4 = stats->robustStdev;
    271     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M4",   PS_META_REPLACE,
    272                      "M_4 = sqrt (M_c4^2 + M_s4^2)", vM4);
    273     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M4_ER", PS_META_REPLACE,
    274                      "Stdev of M_4", dM4);
    275     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M4_LQ", PS_META_REPLACE,
    276                      "Lower Quartile of M_4", stats->robustLQ);
    277     psMetadataAddF32(recipe, PS_LIST_TAIL, "IQ_M4_UQ", PS_META_REPLACE,
    278                      "Upper Quartile of M_4", stats->robustUQ);
     273    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M4",   PS_META_REPLACE, "M_4 = sqrt (M_c4^2 + M_s4^2)", vM4);
     274    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M4_ER", PS_META_REPLACE, "Stdev of M_4", dM4);
     275    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M4_LQ", PS_META_REPLACE, "Lower Quartile of M_4", stats->robustLQ);
     276    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M4_UQ", PS_META_REPLACE, "Upper Quartile of M_4", stats->robustUQ);
    279277#endif
    280278
  • trunk/psphot/src/psphotLoadPSF.c

    r18002 r26894  
    11# include "psphotInternal.h"
    22
     3// NOTE : pmPSF_IO.c functions must load the psf model onto the chip->analysis metadata because
     4// the I/O operation likely occurs before the readout exists.  This implementation assumes that
     5// a single psf model is valid for the entire set of readouts (not valid for a time series of readouts)
     6
     7// XXX for now (2010.01.27), the supporting programs do not define multiple PSPHOT.PSF.LOAD
     8// files to go with multiple PSPHOT.INPUT files.  as a result, the implementation below is
     9// currently going to work for the case of a single input file, but will fail if we try with a
     10// stack of images.
     11
    312// load an externally supplied psf model
    4 pmPSF *psphotLoadPSF (pmConfig *config, const pmFPAview *view, psMetadata *recipe) {
     13bool psphotLoadPSFReadout (pmConfig *config, const pmFPAview *view, const char *outFilename, const char *inFilename, int index) {
     14
     15    bool status;
     16
     17    // find the currently selected readout
     18    pmFPAfile *inFile = pmFPAfileSelectSingle(config->files, inFilename, index); // File of interest
     19    if (inFile == NULL) {
     20        psLogMsg ("psphot", 3, "no psf supplied for this chip");
     21        return true;
     22    }
     23
     24    // find the currently selected readout
     25    pmFPAfile *outFile = pmFPAfileSelectSingle(config->files, outFilename, index); // File of interest
     26    if (outFile == NULL) {
     27        psLogMsg ("psphot", 3, "no psf supplied for this chip");
     28        return true;
     29    }
    530
    631    // find the currently selected chip
    7     pmChip *chip = pmFPAfileThisChip (config->files, view, "PSPHOT.PSF.LOAD");
    8     if (!chip) return NULL;
     32    pmChip *chip = pmFPAviewThisChip (view, inFile->fpa);
     33    if (!chip) return false;
    934
    1035    // find the currently selected readout
    11     pmReadout *readout = pmFPAfileThisReadout (config->files, view, "PSPHOT.PSF.LOAD");
    12     if (!readout) return NULL;
     36    pmReadout *readout = pmFPAviewThisReadout (view, outFile->fpa);
     37    if (!readout) return false;
    1338
    1439    // check if a PSF model is supplied by the user
    15     pmPSF *psf = psMetadataLookupPtr (NULL, chip->analysis, "PSPHOT.PSF");
     40    pmPSF *psf = psMetadataLookupPtr (&status, chip->analysis, "PSPHOT.PSF");
    1641    if (psf == NULL) {
    1742        psLogMsg ("psphot", 3, "no psf supplied for this chip");
    18         return NULL;
     43        return true;
    1944    }
    2045
    21     if (!psphotPSFstats (readout, recipe, psf)) psAbort("cannot measure PSF shape terms");
     46    if (!psphotPSFstats (readout, psf)) {
     47        psAbort("cannot measure PSF shape terms");
     48    }
    2249
    2350    psLogMsg ("psphot", 3, "using externally supplied PSF model for this readout");
    2451
    25     // we return a psf which can be free (and which may be removed from the metadata)
    26     psMemIncrRefCounter (psf);
    27     return psf;
     52    // save PSF on readout->analysis
     53    if (!psMetadataAddPtr (readout->analysis, PS_LIST_TAIL, "PSPHOT.PSF", PS_META_REPLACE | PS_DATA_UNKNOWN, "psphot psf model", psf)) {
     54        psError (PSPHOT_ERR_UNKNOWN, false, "problem saving sources on readout");
     55        return false;
     56    }
     57
     58    return true;
    2859}
     60
     61bool psphotLoadPSF (pmConfig *config, const pmFPAview *view) {
     62
     63    bool status = false;
     64
     65    // XXX PSPHOT.PSF.LOAD vs PSPHOT.INPUT -- see note at top
     66    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     67    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     68
     69    // loop over the available readouts
     70    for (int i = 0; i < num; i++) {
     71
     72        // Generate the mask and weight images, including the user-defined analysis region of interest
     73        if (!psphotLoadPSFReadout (config, view, "PSPHOT.INPUT", "PSPHOT.PSF.LOAD", i)) {
     74            psError (PSPHOT_ERR_CONFIG, false, "failed to load PSF model for PSPHOT.PSF.LOAD entry %d", i);
     75            return false;
     76        }
     77    }
     78    return true;
     79}
  • trunk/psphot/src/psphotMagnitudes.c

    r25755 r26894  
    11# include "psphotInternal.h"
    22
    3 bool psphotMagnitudes(pmConfig *config, pmReadout *readout, const pmFPAview *view, psArray *sources, const pmPSF *psf) {
     3bool psphotMagnitudes (pmConfig *config, const pmFPAview *view)
     4{
     5    bool status = true;
     6
     7    // select the appropriate recipe information
     8    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     9    psAssert (recipe, "missing recipe?");
     10
     11    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     12    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     13
     14    // loop over the available readouts
     15    for (int i = 0; i < num; i++) {
     16        if (!psphotMagnitudesReadout (config, view, "PSPHOT.INPUT", i, recipe)) {
     17            psError (PSPHOT_ERR_CONFIG, false, "failed to measure magnitudes for PSPHOT.INPUT entry %d", i);
     18            return false;
     19        }
     20    }
     21    return true;
     22}
     23
     24bool psphotMagnitudesReadout(pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe) {
    425
    526    bool status = false;
     
    829    psTimerStart ("psphot.mags");
    930
    10     // select the appropriate recipe information
    11     psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
    12     assert (recipe);
     31    // find the currently selected readout
     32    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     33    psAssert (file, "missing file?");
     34
     35    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     36    psAssert (readout, "missing readout?");
     37
     38    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     39    psAssert (detections, "missing detections?");
     40
     41    psArray *sources = detections->allSources;
     42    psAssert (sources, "missing sources?");
     43
     44    if (!sources->n) {
     45        psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping source size");
     46        return true;
     47    }
     48
     49    pmPSF *psf = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF");
     50    psAssert (psf, "missing psf?");
    1351
    1452    // determine the number of allowed threads
     
    64102
    65103            psArrayAdd(job->args, 1, cells->data[j]); // sources
    66             psArrayAdd(job->args, 1, (pmPSF*)psf);    // Casting away const
     104            psArrayAdd(job->args, 1, psf);
    67105            psArrayAdd(job->args, 1, binning);
    68106            psArrayAdd(job->args, 1, backModel);
     
    179217}
    180218
    181 # if (0)
    182 bool psphotMagnitudes_Unthreaded (int *nap, psArray *sources, pmPSF *psf, psImageBinning *binning, pmReadout *backModel, pmReadout *backStdev, pmSourcePhotometryMode photMode, psImageMaskType maskVal) {
    183 
    184     bool status;
    185     int Nap = 0;
    186 
    187     for (int i = 0; i < sources->n; i++) {
    188         pmSource *source = (pmSource *) sources->data[i];
    189         status = pmSourceMagnitudes (source, psf, photMode, maskVal);
    190         if (status && isfinite(source->apMag)) Nap ++;
    191 
    192         if (backModel) {
    193             psAssert (binning, "if backModel is defined, so should binning be");
    194             source->sky = psImageUnbinPixel(source->peak->x, source->peak->y, backModel->image, binning);
    195             if (isnan(source->sky) && false) {
    196                 psLogMsg ("psphot.magnitudes", PS_LOG_DETAIL, "error setting pmSource.sky");
    197             }
    198         } else {
    199             source->sky = NAN;
    200         }
    201 
    202         if (backStdev) {
    203             psAssert (binning, "if backStdev is defined, so should binning be");
    204             source->skyErr = psImageUnbinPixel(source->peak->x, source->peak->y, backStdev->image, binning);
    205             if (isnan(source->skyErr) && false) {
    206                 psLogMsg ("psphot.magnitudes", PS_LOG_DETAIL, "error setting pmSource.skyErr");
    207             }
    208         } else {
    209             source->skyErr = NAN;
    210         }
    211     }
    212 
    213     // change the value of a scalar on the array (wrap this and put it in psArray.h)
    214     *nap = Nap;
    215 
    216     return true;
    217 }
    218 # endif
    219 
    220219bool psphotPSFWeights(pmConfig *config, pmReadout *readout, const pmFPAview *view, psArray *sources) {
    221220
  • trunk/psphot/src/psphotMakePSFReadout.c

    r25982 r26894  
    1919
    2020    // set the photcode for this image
    21     if (!psphotAddPhotcode (recipe, config, view, "PSPHOT.INPUT")) {
     21    if (!psphotAddPhotcode (config, view)) {
    2222        psError (PSPHOT_ERR_CONFIG, false, "trouble defining the photcode");
    2323        return false;
    2424    }
    25 
    26     // find the currently selected readout
    27     pmReadout  *readout = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT");
    28     PS_ASSERT_PTR_NON_NULL (readout, false);
    2925
    3026    // optional break-point for processing
     
    3329
    3430    // Generate the mask and weight images, including the user-defined analysis region of interest
    35     psphotSetMaskAndVariance (config, readout, recipe);
     31    psphotSetMaskAndVariance (config, view);
    3632    if (!strcasecmp (breakPt, "NOTHING")) {
    37         return psphotReadoutCleanup(config, readout, recipe, NULL, NULL, NULL);
     33        return psphotReadoutCleanup(config, view);
    3834    }
    3935
    40     // display the image, weight, mask (ch 1,2,3)
    41     psphotVisualShowImage (readout);
    42 
    4336    // generate a background model (median, smoothed image)
    44     if (!psphotModelBackground (config, view, "PSPHOT.INPUT")) {
    45         return psphotReadoutCleanup (config, readout, recipe, NULL, NULL, NULL);
     37    if (!psphotModelBackground (config, view)) {
     38        return psphotReadoutCleanup (config, view);
    4639    }
    47     if (!psphotSubtractBackground (config, view, "PSPHOT.INPUT")) {
    48         return psphotReadoutCleanup (config, readout, recipe, NULL, NULL, NULL);
     40    if (!psphotSubtractBackground (config, view)) {
     41        return psphotReadoutCleanup (config, view);
    4942    }
    5043    if (!strcasecmp (breakPt, "BACKMDL")) {
    51         return psphotReadoutCleanup (config, readout, recipe, NULL, NULL, NULL);
     44        return psphotReadoutCleanup (config, view);
    5245    }
    5346
    54     // display the backsub and backgnd images
    55     psphotVisualShowBackground (config, view, readout);
     47    psphotLoadExtSources (config, view);
    5648
    57     pmDetections *detections = NULL;
    58 
    59     // If sources have been supplied, then these should be used to measure the PSF
    60     // include externally-supplied sources
    61 
    62     // XXX sources loaded from a text file have no valid SN values, but psphotChoosePSF
    63     // selected the top PSF_MAX_NSTARS to generate the PSF, excluding an arbitrary subset.
    64     psArray *sources = psArrayAllocEmpty(100);
    65     psphotLoadExtSources (config, view, sources);
    66     if (sources->n) {
    67         // the user wants to make the psf from these stars; define them as psf stars:
    68         for (int i = 0; i < sources->n; i++) {
    69             pmSource *source = sources->data[i];
    70             source->mode |= PM_SOURCE_MODE_PSFSTAR;
    71         }
    72         // force psphotChoosePSF to use all loaded sources
    73         psMetadataAddS32 (recipe, PS_LIST_TAIL, "PSF_MAX_NSTARS", PS_META_REPLACE, "fit radius", sources->n);
    74 
    75         // measure stats of externally specified sources
    76         if (!psphotSourceStatsUpdate (sources, config, readout)) {
    77             psError(PSPHOT_ERR_CONFIG, false, "failure to measure stats of existing sources");
    78             return false;
    79         }
    80 
    81     } else {
    82         // find the detections (by peak and/or footprint) in the image.
    83         detections = psphotFindDetections (NULL, readout, recipe);
    84         if (!detections) {
    85             psLogMsg ("psphot", 3, "unable to find detections in this image");
    86             return psphotReadoutCleanup (config, readout, recipe, detections, NULL, sources);
    87         }
    88 
    89         // construct sources and measure basic stats
    90         psFree (sources);
    91         sources = psphotSourceStats (config, readout, detections, true);
    92         if (!sources) return false;
    93 
    94         // find blended neighbors of very saturated stars
    95         // XXX merge this with Basic Deblend?
    96         psphotDeblendSatstars (readout, sources, recipe);
    97 
    98         // mark blended peaks PS_SOURCE_BLEND
    99         if (!psphotBasicDeblend (sources, recipe)) {
    100             psLogMsg ("psphot", 3, "failed on deblend analysis");
    101             return psphotReadoutCleanup (config, readout, recipe, detections, NULL, sources);
    102         }
    103 
    104         // classify sources based on moments, brightness
    105         if (!psphotRoughClass (readout, sources, recipe, false)) {
    106             psLogMsg ("psphot", 3, "failed to find a valid PSF clump for image");
    107             return psphotReadoutCleanup (config, readout, recipe, detections, NULL, sources);
    108         }
     49    // If sources have been supplied, then these should be used to measure the PSF include
     50    // externally-supplied sources; if not, we need to generate a set of possible PSF sources.
     51    // This function updates the SN entries for the loaded sources or generates a set of
     52    // detections from the image, if no external ones have been supplied.  Sources loaded from
     53    // a text file have no valid SN values, but psphotChoosePSF needs to select the top
     54    // PSF_MAX_NSTARS to generate the PSF.
     55    if (!psphotCheckExtSources (config, view)) {
     56        psLogMsg ("psphot", 3, "failure to select possible PSF sources (external or internal)");
     57        return psphotReadoutCleanup (config, view);
    10958    }
    11059
    111     // use bright stellar objects to measure PSF
    112     // XXX if we do not have enough stars to generate the PSF, build one
    113     // from the SEEING guess and model class
    114     pmPSF *psf = psphotChoosePSF (readout, sources, recipe);
    115     if (psf == NULL) {
     60    // Use bright stellar objects to measure PSF. If we do not have enough stars to generate
     61    // the PSF, build one from the SEEING guess and model class
     62    if (!psphotChoosePSF (config, view)) {
    11663        psLogMsg ("psphot", 3, "failure to construct a psf model");
    117         return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
     64        return psphotReadoutCleanup (config, view);
    11865    }
    119     psphotVisualShowPSFModel (readout, psf);
    120     return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
    121 }
    12266
    12367    // measure aperture photometry corrections
    124     // XXX isn't this part of the PSF??
    125     // if (!psphotApResid (config, readout, sources, psf)) {
    126     //     psLogMsg ("psphot", 3, "failed on psphotApResid");
    127     //     return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
    128     // }
     68# if 0
     69    if (!psphotApResid (config, view)) {
     70        psLogMsg ("psphot", 3, "failed on psphotApResid");
     71        return psphotReadoutCleanup (config, view);
     72    }
     73# endif
     74
     75    return psphotReadoutCleanup (config, view);
     76}
  • trunk/psphot/src/psphotMaskReadout.c

    r25755 r26894  
    11# include "psphotInternal.h"
    22
     3bool psphotSetMaskAndVariance (pmConfig *config, const pmFPAview *view) {
     4
     5    bool status = false;
     6
     7    // select the appropriate recipe information
     8    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     9    psAssert (recipe, "missing recipe?");
     10
     11    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     12    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     13
     14    // loop over the available readouts
     15    for (int i = 0; i < num; i++) {
     16
     17        // Generate the mask and weight images, including the user-defined analysis region of interest
     18        if (!psphotSetMaskAndVarianceReadout (config, view, "PSPHOT.INPUT", i, recipe)) {
     19            psError (PSPHOT_ERR_CONFIG, false, "failed to generate mask for PSPHOT.INPUT entry %d", i);
     20            return false;
     21        }
     22    }
     23    return true;
     24}
     25
    326// generate mask and variance if not defined, additional mask for restricted subregion
    4 bool psphotSetMaskAndVariance (pmConfig *config, pmReadout *readout, psMetadata *recipe) {
     27bool psphotSetMaskAndVarianceReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe) {
    528
    629    bool status;
    730
    8     // ** Interpret the mask values:
    9     // XXX drop the write to recipe and move config into psphotRoughClass?
    10     // XXX alternatively, define a function to set the psphot recipe masks
     31    pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PSPHOT.INPUT", index); // File of interest
     32    psAssert (file, "missing file?");
     33
     34    // find the currently selected readout
     35    pmReadout  *readout = pmFPAviewThisReadout (view, file->fpa);
     36    psAssert (readout, "missing readout?");
     37
     38    // save maskSat and maskBad on the psphot recipe (mostly for psphotRoughClass)
    1139    psImageMaskType maskSat  = pmConfigMaskGet("SAT", config); // Mask value for saturated pixels
    1240    psMetadataAddImageMask (recipe, PS_LIST_TAIL, "MASK.SAT", PS_META_REPLACE, "user-defined mask", maskSat);
     
    1442    psImageMaskType maskBad  = pmConfigMaskGet("LOW", config); // Mask value for low pixels
    1543    if (!maskBad) {
    16         // XXX: for backward compatability look up old name
     44        // for backward compatability look up old name
    1745        maskBad  = pmConfigMaskGet("BAD", config);
    1846    }
     
    73101    }
    74102
     103    // display the image, weight, mask (ch 1,2,3)
     104    psphotVisualShowImage (readout);
     105
    75106    return true;
    76107}
  • trunk/psphot/src/psphotMergeSources.c

    r25983 r26894  
    55                         PM_SOURCE_MODE_CR_LIMIT | PM_SOURCE_MODE_EXT_LIMIT) // Mask to apply for PSF sources
    66
    7 // merge the externally supplied sources with the existing sources.  mark them as having
    8 // mode PM_SOURCE_MODE_EXTERNAL
    9 bool psphotLoadExtSources (pmConfig *config, const pmFPAview *view, psArray *sources) {
    10 
    11     psArray *extSourcesCMF = NULL;
     7// for now, let's store the detections on the readout->analysis for each readout
     8bool psphotMergeSources (pmConfig *config, const pmFPAview *view)
     9{
     10    bool status = true;
     11
     12    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     13    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     14
     15    // loop over the available readouts
     16    for (int i = 0; i < num; i++) {
     17        if (!psphotMergeSourcesReadout (config, view, "PSPHOT.INPUT", i)) {
     18            psError (PSPHOT_ERR_CONFIG, false, "failed to merge sources for PSPHOT.INPUT entry %d", i);
     19            return false;
     20        }
     21    }
     22    return true;
     23}
     24
     25// add newly selected sources to the existing list of sources
     26bool psphotMergeSourcesReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index) {
     27
     28    bool status;
     29
     30    // find the currently selected readout
     31    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     32    psAssert (file, "missing file?");
     33
     34    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     35    psAssert (readout, "missing readout?");
     36
     37    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     38    psAssert (detections, "missing detections?");
     39
     40    psArray *newSources = detections->newSources;
     41    psAssert (newSources, "missing sources?");
     42
     43    // XXX TEST:
     44    if (detections->allSources) {
     45        psphotMaskCosmicRayFootprintCheck(detections->allSources);
     46    }
     47    if (detections->newSources) {
     48        psphotMaskCosmicRayFootprintCheck(detections->newSources);
     49    }
     50
     51    if (!detections->allSources) {
     52        detections->allSources = psArrayAllocEmpty(newSources->n);
     53    }
     54    psArray *allSources = detections->allSources;
     55
     56    for (int i = 0; i < newSources->n; i++) {
     57        pmSource *source = newSources->data[i];
     58        psArrayAdd (allSources, 100, source);
     59    }
     60
     61    psFree (detections->newSources);
     62    detections->newSources = NULL;
     63
     64    return true;
     65}
     66
     67// Merge the externally supplied sources with the existing sources.  Mark them as having mode
     68// PM_SOURCE_MODE_EXTERNAL.
     69
     70// XXX This function needs to be updated to loop over set of input files.  At the moment, we
     71// only expect a single entry for PSPHOT.INPUT.CMF and PSPHOT.SOURCES.TEXT, so we can only
     72// associate input sources with a single entry for PSPHOT.INPUT
     73bool psphotLoadExtSources (pmConfig *config, const pmFPAview *view) {
     74
     75    bool status;
     76    pmDetections *extCMF = NULL;
    1277    psArray *extSourcesTXT = NULL;
    1378
     79    // find the currently selected readout
     80    pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PSPHOT.INPUT", 0); // File of interest
     81    psAssert (file, "missing file?");
     82
     83    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     84    psAssert (readout, "missing readout?");
     85
     86    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     87    psAssert (detections, "missing detections?");
     88
     89    // XXX allSources or newSources?
     90    psArray *sources = detections->allSources;
     91    psAssert (sources, "missing sources?");
     92
    1493    // load data from input CMF file:
    15     {
    16         pmReadout *readoutCMF = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT.CMF");
    17         if (!readoutCMF) goto loadTXT;
    18 
    19         extSourcesCMF = psMetadataLookupPtr (NULL, readoutCMF->analysis, "PSPHOT.SOURCES");
    20         if (extSourcesCMF) {
    21             for (int i = 0; i < extSourcesCMF->n; i++) {
    22                 pmSource *source = extSourcesCMF->data[i];
    23                 source->mode |= PM_SOURCE_MODE_EXTERNAL;
    24 
    25                 // the supplied peak flux needs to be re-normalized
    26                 source->peak->flux = 1.0;
    27                 source->peak->value = 1.0;
    28 
    29                 // drop the loaded source modelPSF
    30                 psFree (source->modelPSF);
    31                 source->modelPSF = NULL;
    32             }
    33             psphotMergeSources (sources, extSourcesCMF);
    34         }
     94    {
     95        pmReadout *readoutCMF = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT.CMF");
     96        if (!readoutCMF) goto loadTXT;
     97
     98        extCMF = psMetadataLookupPtr (NULL, readoutCMF->analysis, "PSPHOT.DETECTIONS");
     99        if (extCMF) {
     100            for (int i = 0; i < extCMF->allSources->n; i++) {
     101                pmSource *source = extCMF->allSources->data[i];
     102                source->mode |= PM_SOURCE_MODE_EXTERNAL;
     103
     104                // the supplied peak flux needs to be re-normalized
     105                source->peak->flux = 1.0;
     106                source->peak->value = 1.0;
     107
     108                // drop the loaded source modelPSF
     109                psFree (source->modelPSF);
     110                source->modelPSF = NULL;
     111
     112                psArrayAdd (detections->allSources, 100, source);
     113            }
     114        }
    35115    }
    36116
     
    38118
    39119    // load data from input TXT file:
    40     {
    41         pmChip *chipTXT = pmFPAfileThisChip (config->files, view, "PSPHOT.INPUT");
    42         if (!chipTXT) goto finish;
    43 
    44         extSourcesTXT = psMetadataLookupPtr (NULL, chipTXT->analysis, "PSPHOT.SOURCES.TEXT");
    45         if (extSourcesTXT) {
    46             for (int i = 0; i < extSourcesTXT->n; i++) {
    47                 pmSource *source = extSourcesTXT->data[i];
    48                 source->mode |= PM_SOURCE_MODE_EXTERNAL;
    49 
    50                 // drop the loaded source modelPSF
    51                 psFree (source->modelPSF);
    52                 source->modelPSF = NULL;
    53             }
    54             psphotMergeSources (sources, extSourcesTXT);
    55         }
     120    {
     121        pmChip *chipTXT = pmFPAfileThisChip (config->files, view, "PSPHOT.INPUT");
     122        if (!chipTXT) goto finish;
     123
     124        extSourcesTXT = psMetadataLookupPtr (NULL, chipTXT->analysis, "PSPHOT.SOURCES.TEXT");
     125        if (extSourcesTXT) {
     126            for (int i = 0; i < extSourcesTXT->n; i++) {
     127                pmSource *source = extSourcesTXT->data[i];
     128                source->mode |= PM_SOURCE_MODE_EXTERNAL;
     129
     130                // drop the loaded source modelPSF
     131                psFree (source->modelPSF);
     132                source->modelPSF = NULL;
     133
     134                psArrayAdd (detections->allSources, 100, source);
     135            }
     136        }
    56137    }
    57138
    58139finish:
    59140
    60     if (!extSourcesTXT && !extSourcesTXT) {
     141    if (!extCMF && !extSourcesTXT) {
    61142        psLogMsg ("psphot", 3, "no external sources for this readout");
    62143        return true;
    63144    }
    64145
    65     int nCMF = extSourcesCMF ? extSourcesCMF->n : 0;
     146    int nCMF = extCMF        ? extCMF->allSources->n        : 0;
    66147    int nTXT = extSourcesTXT ? extSourcesTXT->n : 0;
    67148
    68     psLogMsg ("psphot", 3, "%d external sources (%d cmf, %d text) merged to yield %ld total sources",
    69               nCMF + nTXT, nCMF, nTXT, sources->n);
    70     return true;
    71 }
    72 
    73 // add newly selected sources to the existing list of sources
    74 bool psphotMergeSources (psArray *oldSources, psArray *newSources) {
    75 
    76     for (int i = 0; i < newSources->n; i++) {
    77         pmSource *source = newSources->data[i];
    78         psArrayAdd (oldSources, 100, source);
    79     }
     149    psLogMsg ("psphot", 3, "%d external sources (%d cmf, %d text) merged to yield %ld total sources",
     150              nCMF + nTXT, nCMF, nTXT, sources->n);
    80151    return true;
    81152}
    82153
    83154// extract the input sources corresponding to this readout
     155// XXX this function needs to be updated to work with the new context of pshot inputs
    84156psArray *psphotLoadPSFSources (pmConfig *config, const pmFPAview *view) {
     157
     158    bool status;
    85159
    86160    // find the currently selected readout
     
    91165    }
    92166
    93     psArray *sources = psMetadataLookupPtr (NULL, readout->analysis, "PSPHOT.SOURCES");
     167    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     168    if (!detections) {
     169        psLogMsg ("psphot", 3, "no psf sources for this readout");
     170        return NULL;
     171    }
     172
     173    psArray *sources = detections->allSources;
    94174    if (!sources) {
    95175        psLogMsg ("psphot", 3, "no psf sources for this readout");
     176        return NULL;
    96177    }
    97178
     
    99180}
    100181
     182// this function is used to fix sources which were loaded externally, but have passed from
     183// psphotDetectionsFromSources to psphotSourceStats and are now stored on
     184// detections->newSources.
     185bool psphotRepairLoadedSources (pmConfig *config, const pmFPAview *view) {
     186
     187    // find the currently selected readout
     188    pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PSPHOT.INPUT", 0); // File of interest
     189    psAssert (file, "missing file?");
     190
     191    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     192    psAssert (readout, "missing readout?");
     193
     194    pmDetections *detections = psMetadataLookupPtr (NULL, readout->analysis, "PSPHOT.DETECTIONS");
     195    if (!detections) {
     196        psError(PSPHOT_ERR_CONFIG, false, "missing detections");
     197        return false;
     198    }
     199
     200    psArray *sources = detections->newSources;
     201    psAssert (sources, "missing sources?");
     202
     203    // peak flux is wrong : set based on previous image
     204    // use the peak measured in the moments analysis:
     205    for (int i = 0; i < sources->n; i++) {
     206      pmSource *source = sources->data[i];
     207      source->peak->flux = source->moments->Peak;
     208    }
     209
     210    return true;
     211}
     212
    101213// generate the detection structure for the supplied array of sources
    102 pmDetections *psphotDetectionsFromSources (pmConfig *config, psArray *sources) {
     214// XXX this currently assumes there is a single input file
     215bool psphotDetectionsFromSources (pmConfig *config, const pmFPAview *view, psArray *sources) {
     216
     217    // find the currently selected readout
     218    pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PSPHOT.INPUT", 0); // File of interest
     219    psAssert (file, "missing file?");
     220
     221    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     222    psAssert (readout, "missing readout?");
    103223
    104224    pmDetections *detections = pmDetectionsAlloc();
     
    113233    float snMin = psMetadataLookupF32(NULL, recipe, "MOMENTS_SN_MIN");
    114234    if (!isfinite(snMin)) {
    115         return NULL;
     235        return false;
    116236    }
    117237
     
    121241
    122242        if (source->mode & PSF_SOURCE_MASK || !isfinite(source->psfMag)) {
     243            continue;
     244        }
     245
     246        // use the existing peak information, otherwise generate a new peak
     247        if (source->peak) {
     248            source->peak->assigned = false; // So the moments will be measured
     249            psArrayAdd (detections->peaks, 100, source->peak);
    123250            continue;
    124251        }
     
    133260        peak->flux = flux; // this are being set wrong, but does it matter?
    134261
    135         if (isfinite (source->errMag) && (source->errMag > 0.0)) {
    136           peak->SN = 1.0 / source->errMag;
    137         } else {
    138           peak->SN = 0.0;
    139         }
     262        if (isfinite (source->errMag) && (source->errMag > 0.0)) {
     263          peak->SN = 1.0 / source->errMag;
     264        } else {
     265          peak->SN = 0.0;
     266        }
    140267
    141268        psArrayAdd (detections->peaks, 100, peak);
     
    145272    psLogMsg ("psphot", 3, "%ld PSF sources loaded", detections->peaks->n);
    146273
    147     return detections;
     274    // save detections on the readout->analysis
     275    if (!psMetadataAddPtr (readout->analysis, PS_LIST_TAIL, "PSPHOT.DETECTIONS", PS_META_REPLACE | PS_DATA_UNKNOWN, "psphot detectinos", detections)) {
     276        psError (PSPHOT_ERR_CONFIG, false, "problem saving detections on readout");
     277        return false;
     278    }
     279    psFree (detections);
     280    return true;
    148281}
    149282
     
    174307        peak->flux = flux; // this are being set wrong, but does it matter?
    175308
    176         if (isfinite (source->errMag) && (source->errMag > 0.0)) {
    177           peak->SN = 1.0 / source->errMag;
    178         } else {
    179           peak->SN = 0.0;
    180         }
     309        if (isfinite (source->errMag) && (source->errMag > 0.0)) {
     310          peak->SN = 1.0 / source->errMag;
     311        } else {
     312          peak->SN = 0.0;
     313        }
    181314
    182315        source->peak = peak;
     
    187320    return true;
    188321}
     322
     323bool psphotCheckExtSources (pmConfig *config, const pmFPAview *view) {
     324
     325    bool status;
     326
     327    psMetadata *recipe = psMetadataLookupPtr (NULL, config->recipes, PSPHOT_RECIPE);
     328    psAssert (recipe, "missing recipe");
     329
     330    // find the currently selected readout
     331    pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PSPHOT.INPUT", 0); // File of interest
     332    psAssert (file, "missing file?");
     333
     334    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     335    psAssert (readout, "missing readout?");
     336
     337    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     338    psAssert (detections, "missing detections?");
     339
     340    // XXX allSources of newSources?
     341    psArray *sources = detections->allSources;
     342    psAssert (sources, "missing sources?");
     343
     344    if (sources->n) {
     345        // the user wants to make the psf from these stars; define them as psf stars:
     346        for (int i = 0; i < sources->n; i++) {
     347            pmSource *source = sources->data[i];
     348            source->mode |= PM_SOURCE_MODE_PSFSTAR;
     349        }
     350        // force psphotChoosePSF to use all loaded sources
     351        psMetadataAddS32 (recipe, PS_LIST_TAIL, "PSF_MAX_NSTARS", PS_META_REPLACE, "max number of sources for PSF model", sources->n);
     352
     353        // measure stats of externally specified sources
     354        if (!psphotSourceStatsUpdate (sources, config, readout)) {
     355            psError(PSPHOT_ERR_CONFIG, false, "failure to measure stats of existing sources");
     356            return false;
     357        }
     358    } else {
     359
     360        // find the detections (by peak and/or footprint) in the image.
     361        if (!psphotFindDetections (config, view, true)) {
     362            psError(PSPHOT_ERR_CONFIG, false, "unable to find detections in this image");
     363            return psphotReadoutCleanup (config, view);
     364        }
     365
     366        // construct sources and measure basic stats
     367        psphotSourceStats (config, view, true);
     368
     369        // find blended neighbors of very saturated stars
     370        psphotDeblendSatstars (config, view);
     371
     372        // mark blended peaks PS_SOURCE_BLEND
     373        if (!psphotBasicDeblend (config, view)) {
     374            psLogMsg ("psphot", 3, "failed on deblend analysis");
     375            return psphotReadoutCleanup (config, view);
     376        }
     377
     378        // classify sources based on moments, brightness
     379        if (!psphotRoughClass (config, view)) {
     380            psLogMsg ("psphot", 3, "failed to find a valid PSF clump for image");
     381            return psphotReadoutCleanup (config, view);
     382        }
     383    }
     384
     385    return true;
     386}
  • trunk/psphot/src/psphotModelBackground.c

    r26452 r26894  
    3030
    3131// Generate the background model
    32 static bool backgroundModel(psImage *model,  // Model image
    33                             psImage *modelStdev, // Model stdev image
    34                             psMetadata *analysis, // Analysis metadata for outputs
    35                             pmReadout *readout, // Readout for which to generate a background model
    36                             psImageBinning *binning, // Binning parameters
    37                             const pmConfig *config // Configuration
    38                             )
     32// generate the median in NxN boxes, clipping heavily
     33// linear interpolation to generate full-scale model
     34//
     35// NOTE that the 'analysis' metedata pass in here is used to store the binning information.
     36// This may be the analysis for this readout, but it may be the analysis for the pmFPAfile
     37// corresponding to the model.  Other information about the background model is saved on the
     38// readout->analysis
     39static bool psphotModelBackgroundReadout(psImage *model,  // Model image
     40                                  psImage *modelStdev, // Model stdev image
     41                                  psMetadata *analysis, // Analysis metadata for outputs
     42                                  pmReadout *readout, // Readout for which to generate a background model
     43                                  psImageBinning *binning, // Binning parameters
     44                                  const pmConfig *config // Configuration
     45    )
    3946{
    4047    psTimerStart ("psphot.background");
     
    138145
    139146    // we save the binning structure for use in psphotMagnitudes
    140     psMetadataAddPtr(analysis, PS_LIST_TAIL, "PSPHOT.BACKGROUND.BINNING",
    141                      PS_DATA_UNKNOWN | PS_META_REPLACE, "Background binning", binning);
     147    psMetadataAddPtr(analysis, PS_LIST_TAIL, "PSPHOT.BACKGROUND.BINNING", PS_DATA_UNKNOWN | PS_META_REPLACE, "Background binning", binning);
    142148
    143149    psF32 **modelData = model->data.F32;
     
    304310    psLogMsg ("psphot", PS_LOG_INFO, "built background image: %f sec\n", psTimerMark ("psphot.background"));
    305311
    306     psMetadataAddF32(recipe, PS_LIST_TAIL, "SKY_MEAN", PS_META_REPLACE, "sky mean", Value);
    307     psMetadataAddF32(recipe, PS_LIST_TAIL, "SKY_STDEV", PS_META_REPLACE, "sky stdev", ValueStdev);
     312    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "SKY_MEAN", PS_META_REPLACE, "sky mean", Value);
     313    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "SKY_STDEV", PS_META_REPLACE, "sky stdev", ValueStdev);
    308314    psLogMsg ("psphot", PS_LOG_INFO, "image sky : mean %f stdev %f", Value, ValueStdev);
    309315
     
    314320                                      PS_STAT_MAX);
    315321    psImageStats (statsBck, model, NULL, 0);
    316     psMetadataAddF32 (recipe, PS_LIST_TAIL, "MSKY_MN",
    317                       PS_META_REPLACE, "sky model mean",          statsBck->sampleMean);
    318     psMetadataAddF32 (recipe, PS_LIST_TAIL, "MSKY_SIG",
    319                       PS_META_REPLACE, "sky model stdev",         statsBck->sampleStdev);
    320     psMetadataAddF32 (recipe, PS_LIST_TAIL, "MSKY_MAX",
    321                       PS_META_REPLACE, "sky model maximum value", statsBck->max);
    322     psMetadataAddF32 (recipe, PS_LIST_TAIL, "MSKY_MIN",
    323                       PS_META_REPLACE, "sky model minimum value", statsBck->min);
    324     psMetadataAddS32 (recipe, PS_LIST_TAIL, "MSKY_NX",
    325                       PS_META_REPLACE, "sky model size (x)",      model->numCols);
    326     psMetadataAddS32 (recipe, PS_LIST_TAIL, "MSKY_NY",
    327                       PS_META_REPLACE, "sky model size (y)",      model->numRows);
     322    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "MSKY_MN", PS_META_REPLACE, "sky model mean",          statsBck->sampleMean);
     323    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "MSKY_SIG", PS_META_REPLACE, "sky model stdev",         statsBck->sampleStdev);
     324    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "MSKY_MAX", PS_META_REPLACE, "sky model maximum value", statsBck->max);
     325    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "MSKY_MIN", PS_META_REPLACE, "sky model minimum value", statsBck->min);
     326    psMetadataAddS32 (readout->analysis, PS_LIST_TAIL, "MSKY_NX", PS_META_REPLACE, "sky model size (x)",      model->numCols);
     327    psMetadataAddS32 (readout->analysis, PS_LIST_TAIL, "MSKY_NY", PS_META_REPLACE, "sky model size (y)",      model->numRows);
    328328    psLogMsg ("psphot", PS_LOG_INFO, "background sky : min %f mean %f max %f stdev %f",
    329329              statsBck->min, statsBck->sampleMean, statsBck->max, statsBck->sampleStdev);
     
    338338}
    339339
    340 
    341 
    342 psImage *psphotBackgroundModel(pmReadout *ro, const pmConfig *config)
     340// generate a background model for a single readout. do not save an associated pmFPAfile for possible output
     341psImage *psphotModelBackgroundReadoutNoFile(pmReadout *readout, const pmConfig *config)
    343342{
    344     PM_ASSERT_READOUT_NON_NULL(ro, NULL);
    345     PM_ASSERT_READOUT_IMAGE(ro, NULL);
     343    PM_ASSERT_READOUT_NON_NULL(readout, NULL);
     344    PM_ASSERT_READOUT_IMAGE(readout, NULL);
    346345    PS_ASSERT_PTR_NON_NULL(config, NULL);
    347346
    348     psImageBinning *binning = psphotBackgroundBinning(ro->image, config); // Image binning parameters
     347    psImageBinning *binning = psphotBackgroundBinning(readout->image, config); // Image binning parameters
    349348    psImage *model = psImageAlloc(binning->nXruff, binning->nYruff, PS_TYPE_F32); // Background model
    350349    psImage *modelStdev = psImageAlloc(binning->nXruff, binning->nYruff, PS_TYPE_F32); // Standard deviation
    351350
    352     if (!backgroundModel(model, modelStdev, ro->analysis, ro, binning, config)) {
     351    if (!psphotModelBackgroundReadout(model, modelStdev, readout->analysis, readout, binning, config)) {
    353352        psFree(model);
    354353        psFree(modelStdev);
     
    356355        return NULL;
    357356    }
    358 
    359357    psFree(modelStdev);
    360 
    361358    return model;
    362359}
    363360
    364 
    365 // generate the median in NxN boxes, clipping heavily
    366 // linear interpolation to generate full-scale model
    367 bool psphotModelBackground (pmConfig *config, const pmFPAview *view, const char *filename)
     361// generate a background model for readout number index; save an associated pmFPAfile for possible output
     362bool psphotModelBackgroundReadoutFileIndex (pmConfig *config, const pmFPAview *view, const char *filename, int index)
    368363{
    369     bool status = true;
    370 
    371364    // find the currently selected readout
    372     pmFPAfile *file = psMetadataLookupPtr (&status, config->files, filename);
     365    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     366    psAssert (file, "missing file?");
     367
    373368    pmFPA *inFPA = file->fpa;
    374369    pmReadout *readout = pmFPAviewThisReadout(view, inFPA);
     370    psAssert (readout, "missing readout?");
    375371
    376372    psImageBinning *binning = psphotBackgroundBinning(readout->image, config); // Image binning parameters
     
    378374    pmReadout *modelStdev = pmFPAGenerateReadout(config, view, "PSPHOT.BACKMDL.STDEV", inFPA, binning);
    379375
    380     if (!backgroundModel(model->image, modelStdev->image, model->analysis, readout, binning, config)) {
     376    if (!psphotModelBackgroundReadout(model->image, modelStdev->image, model->analysis, readout, binning, config)) {
    381377        psError(PS_ERR_UNKNOWN, false, "Unable to generate background model");
    382378        return false;
     
    386382    return true;
    387383}
     384
     385// XXX supply filename or keep PSPHOT.INPUT fixed?
     386bool psphotModelBackground (pmConfig *config, const pmFPAview *view)
     387{
     388    bool status = false;
     389
     390    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     391    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     392
     393    // loop over the available readouts
     394    for (int i = 0; i < num; i++) {
     395        if (!psphotModelBackgroundReadoutFileIndex(config, view, "PSPHOT.INPUT", i)) {
     396            psError (PSPHOT_ERR_CONFIG, false, "failed to model background for PSPHOT.INPUT entry %d", i);
     397            return false;
     398        }
     399    }
     400    return true;
     401}
  • trunk/psphot/src/psphotModelTest.c

    r24588 r26894  
    139139
    140140    // get the source moments
    141     status = pmSourceMoments (source, mRADIUS, 0.0, 1.0);
     141    status = pmSourceMoments (source, mRADIUS, 0.0, 1.0, maskVal);
    142142    if (!status) psAbort("psSourceMoments error");
    143143    source->peak->value = source->moments->Peak;
  • trunk/psphot/src/psphotMomentsStudy.c

    r24585 r26894  
    148148      pmSourceAdd(source, PM_MODEL_OP_FUNC, 0);
    149149
    150       pmSourceMoments (source, 32.0, sigWindow, 0.0);
     150      pmSourceMoments (source, 32.0, sigWindow, 0.0, 0xffff);
    151151      // fprintf (stderr, "sigOut : %f\n", sqrt(source->moments->Mxx));
    152152
  • trunk/psphot/src/psphotOutput.c

    r25755 r26894  
    126126}
    127127
    128 bool psphotAddPhotcode (psMetadata *recipe, pmConfig *config, const pmFPAview *view, const char *filerule) {
    129 
    130     bool status;
    131 
    132     pmFPAfile *input = psMetadataLookupPtr (&status, config->files, filerule);
    133     PS_ASSERT (status, false);
    134 
    135     // determine PHOTCODE from fpa & view, overwrite in recipe
    136     char *photcode = pmConceptsPhotcodeForView (input, view);
     128bool psphotAddPhotcode (pmConfig *config, const pmFPAview *view) {
     129
     130    bool status = false;
     131
     132    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     133    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     134
     135    // loop over the available readouts
     136    for (int i = 0; i < num; i++) {
     137        if (!psphotAddPhotcodeReadout (config, view, "PSPHOT.INPUT", i)) {
     138            psError (PSPHOT_ERR_CONFIG, false, "failed to add photcode to PSPHOT.INPUT entry %d", i);
     139            return false;
     140        }
     141    }
     142    return true;
     143}
     144
     145bool psphotAddPhotcodeReadout (pmConfig *config, const pmFPAview *view, const char *filerule, int index) {
     146
     147    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filerule, index); // File of interest
     148    PS_ASSERT (file, false);
     149
     150    pmReadout  *readout = pmFPAviewThisReadout (view, file->fpa);
     151
     152    // determine PHOTCODE from fpa & view, overwrite in readout->analysis
     153    char *photcode = pmConceptsPhotcodeForView (file, view);
    137154    PS_ASSERT (photcode, false);
    138155
    139     psMetadataAddStr (recipe, PS_LIST_TAIL, "PHOTCODE", PS_META_REPLACE, "photcode from FPA concepts", photcode);
     156    psMetadataAddStr (readout->analysis, PS_LIST_TAIL, "PHOTCODE", PS_META_REPLACE, "photcode from FPA concepts", photcode);
    140157    psLogMsg ("psphot", 3, "PHOTCODE is %s", photcode);
    141158
     
    144161}
    145162
    146 bool psphotSetHeaderNstars (psMetadata *recipe, psArray *sources) {
     163bool psphotSetHeaderNstars (psMetadata *header, psArray *sources) {
    147164
    148165    int nSrc = 0;
     
    173190    }
    174191
    175     psMetadataAddS32 (recipe, PS_LIST_TAIL, "NSTARS",   PS_META_REPLACE, "Number of sources", nSrc);
    176     psMetadataAddS32 (recipe, PS_LIST_TAIL, "NDET_EXT", PS_META_REPLACE, "Number of extended sources", nEXT);
    177     psMetadataAddS32 (recipe, PS_LIST_TAIL, "NDET_CR",  PS_META_REPLACE, "Number of cosmic rays", nCR);
    178     return true;
    179 }
    180 
    181 // these values are saved in an output header stub - they are added to either the
    182 // PHU header (CMP) or the MEF table header (CMF)
    183 psMetadata *psphotDefineHeader (psMetadata *recipe) {
     192    psMetadataAddS32 (header, PS_LIST_TAIL, "NSTARS",   PS_META_REPLACE, "Number of sources", nSrc);
     193    psMetadataAddS32 (header, PS_LIST_TAIL, "NDET_EXT", PS_META_REPLACE, "Number of extended sources", nEXT);
     194    psMetadataAddS32 (header, PS_LIST_TAIL, "NDET_CR",  PS_META_REPLACE, "Number of cosmic rays", nCR);
     195    return true;
     196}
     197
     198// these values are saved in an output header stub - they are added to either the PHU header
     199// (CMP) or the MEF table header (CMF).  before the header is created, each readout has these
     200// values stored on readout->analysis
     201psMetadata *psphotDefineHeader (psMetadata *analysis) {
     202
     203    bool status = true;
    184204
    185205    psMetadata *header = psMetadataAlloc ();
    186206
    187207    // write necessary information to output header
    188     psMetadataItemSupplement (header, recipe, "ZERO_PT");
    189     psMetadataItemSupplement (header, recipe, "PHOTCODE");
    190 
    191     psMetadataItemSupplement (header, recipe, "APMIFIT");
    192     psMetadataItemSupplement (header, recipe, "DAPMIFIT");
    193     psMetadataItemSupplement (header, recipe, "NAPMIFIT");
     208    psMetadataItemSupplement (&status, header, analysis, "ZERO_PT");
     209    psMetadataItemSupplement (&status, header, analysis, "PHOTCODE");
     210
     211    psMetadataItemSupplement (&status, header, analysis, "APMIFIT");
     212    psMetadataItemSupplement (&status, header, analysis, "DAPMIFIT");
     213    psMetadataItemSupplement (&status, header, analysis, "NAPMIFIT");
    194214
    195215    // PSF model parameters (shape values for image center)
    196     psMetadataItemSupplement (header, recipe, "NPSFSTAR");
    197     psMetadataItemSupplement (header, recipe, "APLOSS");
    198 
    199     psMetadataItemSupplement (header, recipe, "FWHM_MAJ");
    200     psMetadataItemSupplement (header, recipe, "FW_MJ_SG");
    201     psMetadataItemSupplement (header, recipe, "FW_MJ_LQ");
    202     psMetadataItemSupplement (header, recipe, "FW_MJ_UQ");
    203 
    204     psMetadataItemSupplement (header, recipe, "FWHM_MIN");
    205     psMetadataItemSupplement (header, recipe, "FW_MN_SG");
    206     psMetadataItemSupplement (header, recipe, "FW_MN_LQ");
    207     psMetadataItemSupplement (header, recipe, "FW_MN_UQ");
    208 
    209     psMetadataItemSupplement (header, recipe, "ANGLE");
     216    psMetadataItemSupplement (&status, header, analysis, "NPSFSTAR");
     217    psMetadataItemSupplement (&status, header, analysis, "APLOSS");
     218
     219    psMetadataItemSupplement (&status, header, analysis, "FWHM_MAJ");
     220    psMetadataItemSupplement (&status, header, analysis, "FW_MJ_SG");
     221    psMetadataItemSupplement (&status, header, analysis, "FW_MJ_LQ");
     222    psMetadataItemSupplement (&status, header, analysis, "FW_MJ_UQ");
     223
     224    psMetadataItemSupplement (&status, header, analysis, "FWHM_MIN");
     225    psMetadataItemSupplement (&status, header, analysis, "FW_MN_SG");
     226    psMetadataItemSupplement (&status, header, analysis, "FW_MN_LQ");
     227    psMetadataItemSupplement (&status, header, analysis, "FW_MN_UQ");
     228
     229    psMetadataItemSupplement (&status, header, analysis, "ANGLE");
    210230
    211231    // Image Quality measurements
    212     psMetadataItemSupplement (header, recipe, "IQ_NSTAR");
    213 
    214     psMetadataItemSupplement (header, recipe, "IQ_FW1");
    215     psMetadataItemSupplement (header, recipe, "IQ_FW1_E");
    216     psMetadataItemSupplement (header, recipe, "IQ_FW2");
    217     psMetadataItemSupplement (header, recipe, "IQ_FW2_E");
    218 
    219     psMetadataItemSupplement (header, recipe, "IQ_M2");
    220     psMetadataItemSupplement (header, recipe, "IQ_M2_ER");
    221     psMetadataItemSupplement (header, recipe, "IQ_M2_LQ");
    222     psMetadataItemSupplement (header, recipe, "IQ_M2_UQ");
    223 
    224     psMetadataItemSupplement (header, recipe, "IQ_M2C");
    225     psMetadataItemSupplement (header, recipe, "IQ_M2C_E");
    226     psMetadataItemSupplement (header, recipe, "IQ_M2C_L");
    227     psMetadataItemSupplement (header, recipe, "IQ_M2C_U");
    228 
    229     psMetadataItemSupplement (header, recipe, "IQ_M2S");
    230     psMetadataItemSupplement (header, recipe, "IQ_M2S_E");
    231     psMetadataItemSupplement (header, recipe, "IQ_M2S_L");
    232     psMetadataItemSupplement (header, recipe, "IQ_M2S_U");
    233 
    234     psMetadataItemSupplement (header, recipe, "IQ_M3");
    235     psMetadataItemSupplement (header, recipe, "IQ_M3_ER");
    236     psMetadataItemSupplement (header, recipe, "IQ_M3_LQ");
    237     psMetadataItemSupplement (header, recipe, "IQ_M3_UQ");
    238 
    239     psMetadataItemSupplement (header, recipe, "IQ_M4");
    240     psMetadataItemSupplement (header, recipe, "IQ_M4_ER");
    241     psMetadataItemSupplement (header, recipe, "IQ_M4_LQ");
    242     psMetadataItemSupplement (header, recipe, "IQ_M4_UQ");
     232    psMetadataItemSupplement (&status, header, analysis, "IQ_NSTAR");
     233
     234    psMetadataItemSupplement (&status, header, analysis, "IQ_FW1");
     235    psMetadataItemSupplement (&status, header, analysis, "IQ_FW1_E");
     236    psMetadataItemSupplement (&status, header, analysis, "IQ_FW2");
     237    psMetadataItemSupplement (&status, header, analysis, "IQ_FW2_E");
     238
     239    psMetadataItemSupplement (&status, header, analysis, "IQ_M2");
     240    psMetadataItemSupplement (&status, header, analysis, "IQ_M2_ER");
     241    psMetadataItemSupplement (&status, header, analysis, "IQ_M2_LQ");
     242    psMetadataItemSupplement (&status, header, analysis, "IQ_M2_UQ");
     243
     244    psMetadataItemSupplement (&status, header, analysis, "IQ_M2C");
     245    psMetadataItemSupplement (&status, header, analysis, "IQ_M2C_E");
     246    psMetadataItemSupplement (&status, header, analysis, "IQ_M2C_L");
     247    psMetadataItemSupplement (&status, header, analysis, "IQ_M2C_U");
     248
     249    psMetadataItemSupplement (&status, header, analysis, "IQ_M2S");
     250    psMetadataItemSupplement (&status, header, analysis, "IQ_M2S_E");
     251    psMetadataItemSupplement (&status, header, analysis, "IQ_M2S_L");
     252    psMetadataItemSupplement (&status, header, analysis, "IQ_M2S_U");
     253
     254    psMetadataItemSupplement (&status, header, analysis, "IQ_M3");
     255    psMetadataItemSupplement (&status, header, analysis, "IQ_M3_ER");
     256    psMetadataItemSupplement (&status, header, analysis, "IQ_M3_LQ");
     257    psMetadataItemSupplement (&status, header, analysis, "IQ_M3_UQ");
     258
     259    psMetadataItemSupplement (&status, header, analysis, "IQ_M4");
     260    psMetadataItemSupplement (&status, header, analysis, "IQ_M4_ER");
     261    psMetadataItemSupplement (&status, header, analysis, "IQ_M4_LQ");
     262    psMetadataItemSupplement (&status, header, analysis, "IQ_M4_UQ");
    243263
    244264    // XXX these need to be defined from elsewhere
    245265    psMetadataAdd (header, PS_LIST_TAIL, "FSATUR",   PS_DATA_F32 | PS_META_REPLACE, "SATURATION MAG",      0.0);
    246266    psMetadataAdd (header, PS_LIST_TAIL, "FLIMIT",   PS_DATA_F32 | PS_META_REPLACE, "COMPLETENESS MAG",    0.0);
    247     psMetadataItemSupplement (header, recipe, "NSTARS");
    248 
    249     psMetadataItemSupplement (header, recipe, "NDET_EXT");
    250     psMetadataItemSupplement (header, recipe, "NDET_CR");
     267    psMetadataItemSupplement (&status, header, analysis, "NSTARS");
     268
     269    psMetadataItemSupplement (&status, header, analysis, "NDET_EXT");
     270    psMetadataItemSupplement (&status, header, analysis, "NDET_CR");
    251271
    252272    // sky background model statistics
    253     psMetadataItemSupplement (header, recipe, "MSKY_MN");
    254     psMetadataItemSupplement (header, recipe, "MSKY_SIG");
    255     psMetadataItemSupplement (header, recipe, "MSKY_MIN");
    256     psMetadataItemSupplement (header, recipe, "MSKY_MAX");
    257     psMetadataItemSupplement (header, recipe, "MSKY_NX");
    258     psMetadataItemSupplement (header, recipe, "MSKY_NY");
     273    psMetadataItemSupplement (&status, header, analysis, "MSKY_MN");
     274    psMetadataItemSupplement (&status, header, analysis, "MSKY_SIG");
     275    psMetadataItemSupplement (&status, header, analysis, "MSKY_MIN");
     276    psMetadataItemSupplement (&status, header, analysis, "MSKY_MAX");
     277    psMetadataItemSupplement (&status, header, analysis, "MSKY_NX");
     278    psMetadataItemSupplement (&status, header, analysis, "MSKY_NY");
    259279
    260280    psMetadataAddF32 (header, PS_LIST_TAIL, "DT_PHOT", PS_META_REPLACE, "elapsed psphot time", psTimerMark ("psphotReadout"));
    261 
    262     // XXX : don't require any of these about values to exist
    263     psErrorClear ();
    264281
    265282    return header;
  • trunk/psphot/src/psphotPSFConvModel.c

    r25755 r26894  
    3939    // adjust the pixels based on the footprint
    4040    float radius = psphotSetRadiusEXT (readout, source, markVal);
    41     if (!pmSourceMoments (source, radius, 0.0, 0.0)) return false;
     41    if (!pmSourceMoments (source, radius, 0.0, 0.0, maskVal)) return false;
    4242
    4343    // XXX test : modify the Io, SXX, SYY terms based on the psf SXX, SYY terms:
  • trunk/psphot/src/psphotParseCamera.c

    r21458 r26894  
    3939        return NULL;
    4040    }
     41    // specify the number of psphot input images
     42    psMetadataAddS32 (config->arguments, PS_LIST_TAIL, "PSPHOT.INPUT.NUM", PS_META_REPLACE, "number of inputs", 1);
    4143
    4244    // define the additional input/output files associated with psphot
  • trunk/psphot/src/psphotRadiusChecks.c

    r25755 r26894  
    44static float PSF_FIT_NSIGMA;
    55static float PSF_FIT_PADDING;
     6static float PSF_APERTURE = 0;  // radius to use in PSF aperture mags
    67static float PSF_FIT_RADIUS = 0;        // radius to use in fitting (ignored if <= 0,
    78                                        // and a per-object radius is calculated)
    89
    9 static float PSF_APERTURE = 0;  // radius to use in PSF aperture mags
    10 
    11 
    12 bool psphotInitRadiusPSF(const psMetadata *recipe, const pmModelType type) {
     10bool psphotInitRadiusPSF(const psMetadata *recipe, const psMetadata *analysis, const pmModelType type) {
    1311
    1412    bool status = true;
    1513
    16     PSF_FIT_NSIGMA  = psMetadataLookupF32(&status, recipe, "PSF_FIT_NSIGMA");
     14    PSF_FIT_NSIGMA = psMetadataLookupF32(&status, recipe, "PSF_FIT_NSIGMA");
    1715    PSF_FIT_PADDING = psMetadataLookupF32(&status, recipe, "PSF_FIT_PADDING");
    18     PSF_FIT_RADIUS  =  psMetadataLookupF32(&status, recipe, "PSF_FIT_RADIUS");
    19     PSF_APERTURE    =  psMetadataLookupF32(&status, recipe, "PSF_APERTURE");
     16
     17    PSF_FIT_RADIUS =  psMetadataLookupF32(&status, analysis, "PSF_FIT_RADIUS");
     18    if (!status) {
     19        PSF_FIT_RADIUS = psMetadataLookupF32(&status, recipe, "PSF_FIT_RADIUS");
     20    }
     21
     22    PSF_APERTURE =  psMetadataLookupF32(&status, analysis, "PSF_APERTURE");
     23    if (!status) {
     24        PSF_APERTURE =  psMetadataLookupF32(&status, recipe, "PSF_APERTURE");
     25    }
    2026
    2127    return true;
  • trunk/psphot/src/psphotReadout.c

    r25755 r26894  
    33// this should be called by every program that links against libpsphot
    44bool psphotInit (void) {
    5 
    65    psphotErrorRegister();              // register our error codes/messages
    76    psphotModelClassInit ();            // load implementation-specific models
     
    1211bool psphotReadout(pmConfig *config, const pmFPAview *view) {
    1312
    14     // measure the total elapsed time in psphotReadout.  XXX the current threading plan
    15     // for psphot envisions threading within psphotReadout, not multiple threads calling
    16     // the same psphotReadout.  In the current plan, this dtime is the elapsed time used
    17     // jointly by the multiple threads, not the total time used by all threads.
     13    // measure the total elapsed time in psphotReadout.  dtime is the elapsed time used jointly
     14    // by the multiple threads, not the total time used by all threads.
    1815    psTimerStart ("psphotReadout");
    1916
     
    2623        return false;
    2724    }
     25    // optional break-point for processing
     26    char *breakPt = psMetadataLookupStr (NULL, recipe, "BREAK_POINT");
     27    psAssert (breakPt, "configuration error: set BREAK_POINT");
    2828
    2929    // set the photcode for this image
    30     if (!psphotAddPhotcode (recipe, config, view, "PSPHOT.INPUT")) {
     30    if (!psphotAddPhotcode (config, view)) {
    3131        psError (PSPHOT_ERR_CONFIG, false, "trouble defining the photcode");
    3232        return false;
    3333    }
    3434
    35     // find the currently selected readout
    36     pmReadout  *readout = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT");
    37     PS_ASSERT_PTR_NON_NULL (readout, false);
    38 
    39     // optional break-point for processing
    40     char *breakPt = psMetadataLookupStr (NULL, recipe, "BREAK_POINT");
    41     PS_ASSERT_PTR_NON_NULL (breakPt, false);
    42 
    4335    // Generate the mask and weight images, including the user-defined analysis region of interest
    44     psphotSetMaskAndVariance (config, readout, recipe);
     36    psphotSetMaskAndVariance (config, view);
    4537    if (!strcasecmp (breakPt, "NOTHING")) {
    46         return psphotReadoutCleanup(config, readout, recipe, NULL, NULL, NULL);
    47     }
    48 
    49     // display the image, weight, mask (ch 1,2,3)
    50     psphotVisualShowImage (readout);
     38        return psphotReadoutCleanup(config, view);
     39    }
    5140
    5241    // generate a background model (median, smoothed image)
    53     if (!psphotModelBackground (config, view, "PSPHOT.INPUT")) {
    54         return psphotReadoutCleanup (config, readout, recipe, NULL, NULL, NULL);
    55     }
    56     if (!psphotSubtractBackground (config, view, "PSPHOT.INPUT")) {
    57         return psphotReadoutCleanup (config, readout, recipe, NULL, NULL, NULL);
     42    if (!psphotModelBackground (config, view)) {
     43        return psphotReadoutCleanup (config, view);
     44    }
     45    if (!psphotSubtractBackground (config, view)) {
     46        return psphotReadoutCleanup (config, view);
    5847    }
    5948    if (!strcasecmp (breakPt, "BACKMDL")) {
    60         return psphotReadoutCleanup (config, readout, recipe, NULL, NULL, NULL);
    61     }
    62 
    63     // display the backsub and backgnd images
    64     psphotVisualShowBackground (config, view, readout);
    65 
    66     // run a single-model test if desired (exits from here if test is run)
    67     psphotModelTest (config, view, recipe);
    68 
    69     // load the psf model, if suppled.  FWHM_X,FWHM_Y,etc are saved in the recipe
    70     pmPSF *psf = psphotLoadPSF (config, view, recipe);
    71 
    72     // several functions below behave differently if we have a PSF model already
    73     bool havePSF = (psf != NULL);
     49        return psphotReadoutCleanup (config, view);
     50    }
     51
     52    // load the psf model, if suppled.  FWHM_X,FWHM_Y,etc are determined and saved on
     53    // readout->analysis XXX this function currently only works with a single PSPHOT.INPUT
     54    if (!psphotLoadPSF (config, view)) {
     55        psError (PSPHOT_ERR_UNKNOWN, false, "error loading psf model");
     56        return psphotReadoutCleanup (config, view);
     57    }
    7458
    7559    // find the detections (by peak and/or footprint) in the image.
    76     pmDetections *detections = psphotFindDetections (NULL, readout, recipe);
    77     if (!detections) {
    78         psLogMsg ("psphot", 3, "unable to find detections in this image");
    79         return psphotReadoutCleanup (config, readout, recipe, detections, psf, NULL);
    80     }
    81 
    82     // construct sources and measure basic stats
    83     psArray *sources = psphotSourceStats (config, readout, detections, true);
    84     if (!sources) return false;
     60    if (!psphotFindDetections (config, view, true)) { // pass 1
     61        // this only happens if we had an error in psphotFindDetections
     62        psError (PSPHOT_ERR_UNKNOWN, false, "failure in peak analysis");
     63        return psphotReadoutCleanup (config, view);
     64    }
     65
     66    // construct sources and measure basic stats (saved on detections->newSources)
     67    if (!psphotSourceStats (config, view, true)) { // pass 1
     68        psError(PSPHOT_ERR_UNKNOWN, false, "failure to generate sources");
     69        return psphotReadoutCleanup (config, view);
     70    }
    8571    if (!strcasecmp (breakPt, "PEAKS")) {
    86         return psphotReadoutCleanup(config, readout, recipe, detections, psf, sources);
    87     }
    88 
    89     // find blended neighbors of very saturated stars
    90     // XXX merge this with Basic Deblend?
    91     psphotDeblendSatstars (readout, sources, recipe);
    92 
    93     // mark blended peaks PS_SOURCE_BLEND
    94     if (!psphotBasicDeblend (sources, recipe)) {
    95         psLogMsg ("psphot", 3, "failed on deblend analysis");
    96         return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
    97     }
    98 
    99     // classify sources based on moments, brightness
    100     if (!psphotRoughClass (readout, sources, recipe, havePSF)) {
    101         psLogMsg ("psphot", 3, "failed to find a valid PSF clump for image");
    102         return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
     72        return psphotReadoutCleanup(config, view);
     73    }
     74
     75    // find blended neighbors of very saturated stars (detections->newSources)
     76    if (!psphotDeblendSatstars (config, view)) {
     77        psError (PSPHOT_ERR_UNKNOWN, false, "failed on satstar deblend analysis");
     78        return psphotReadoutCleanup (config, view);
     79    }
     80
     81    // mark blended peaks PS_SOURCE_BLEND (detections->newSources)
     82    if (!psphotBasicDeblend (config, view)) {
     83        psError (PSPHOT_ERR_UNKNOWN, false, "failed on deblend analysis");
     84        return psphotReadoutCleanup (config, view);
     85    }
     86
     87    // classify sources based on moments, brightness.  if a PSF model has been loaded, the PSF
     88    // clump defined for it is used not measured (detections->newSources)
     89    if (!psphotRoughClass (config, view)) { // pass 1
     90        psError (PSPHOT_ERR_UNKNOWN, false, "failed to determine rough classifications");
     91        return psphotReadoutCleanup (config, view);
    10392    }
    10493    if (!strcasecmp (breakPt, "MOMENTS")) {
    105         return psphotReadoutCleanup(config, readout, recipe, detections, psf, sources);
    106     }
    107 
    108     if (!havePSF && !psphotImageQuality (recipe, sources)) {
    109         psLogMsg("psphot", 3, "failed to measure image quality");
    110         return psphotReadoutCleanup(config, readout, recipe, detections, psf, sources);
    111     }
    112 
    113     // if we were not supplied a PSF, choose one here
    114     if (psf == NULL) {
    115         // use bright stellar objects to measure PSF
    116         // XXX if we do not have enough stars to generate the PSF, build one
    117         // from the SEEING guess and model class
    118         psf = psphotChoosePSF (readout, sources, recipe);
    119         if (psf == NULL) {
    120             psLogMsg ("psphot", 3, "failure to construct a psf model");
    121             return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
    122         }
    123         havePSF = true;
     94        return psphotReadoutCleanup(config, view);
     95    }
     96
     97    // if we were not supplied a PSF model, determine the IQ stats here (detections->newSources)
     98    if (!psphotImageQuality (config, view)) { // pass 1
     99        psError (PSPHOT_ERR_UNKNOWN, false, "failed to measure image quality");
     100        return psphotReadoutCleanup(config, view);
     101    }
     102
     103    // use bright stellar objects to measure PSF if we were supplied a PSF for any input file,
     104    // this step is skipped
     105    if (!psphotChoosePSF (config, view)) { // pass 1
     106        psLogMsg ("psphot", 3, "failure to construct a psf model");
     107        return psphotReadoutCleanup (config, view);
    124108    }
    125109    if (!strcasecmp (breakPt, "PSFMODEL")) {
    126         return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
    127     }
    128     psphotVisualShowPSFModel (readout, psf);
     110        return psphotReadoutCleanup (config, view);
     111    }
    129112
    130113    // include externally-supplied sources
    131     psphotLoadExtSources (config, view, sources);
    132 
    133     // construct an initial model for each object, set the radius to fitRadius, set circular fit mask
    134     psphotGuessModels (config, readout, sources, psf);
     114    // XXX fix this in the new multi-input context
     115    // psphotLoadExtSources (config, view); // pass 1
     116
     117    // construct an initial model for each object, set the radius to fitRadius, set circular
     118    // fit mask (detections->newSources)
     119    psphotGuessModels (config, view); // pass 1
     120
     121    // merge the newly selected sources into the existing list
     122    // NOTE: merge OLD and NEW
     123    psphotMergeSources (config, view);
    135124
    136125    // linear PSF fit to source peaks, subtract the models from the image (in PSF mask)
    137     psphotFitSourcesLinear (readout, sources, recipe, psf, FALSE);
    138 
    139     // We have to place these visualizations here because the models are not realized until
    140     // psphotGuessModels or fitted until psphotFitSourcesLinear.
    141     psphotVisualShowPSFStars (recipe, psf, sources);
    142 
    143     // identify CRs and extended sources
    144     psphotSourceSize (config, readout, sources, recipe, psf, 0);
     126    psphotFitSourcesLinear (config, view, false); // pass 1 (detections->allSources)
     127
     128    // identify CRs and extended sources (only unmeasured sources are measured)
     129    psphotSourceSize (config, view, true); // pass 1 (detections->allSources)
    145130    if (!strcasecmp (breakPt, "ENSEMBLE")) {
    146131        goto finish;
    147132    }
    148     psphotVisualShowSatStars (recipe, psf, sources);
    149133
    150134    // non-linear PSF and EXT fit to brighter sources
    151135    // replace model flux, adjust mask as needed, fit, subtract the models (full stamp)
    152     psphotBlendFit (config, readout, sources, psf);
     136    psphotBlendFit (config, view); // pass 1 (detections->allSources)
    153137
    154138    // replace all sources
    155     psphotReplaceAllSources (sources, recipe);
     139    psphotReplaceAllSources (config, view); // pass 1 (detections->allSources)
    156140
    157141    // linear fit to include all sources (subtract again)
    158     psphotFitSourcesLinear (readout, sources, recipe, psf, TRUE);
     142    // NOTE : apply to ALL sources (extended + psf)
     143    psphotFitSourcesLinear (config, view, true); // pass 2 (detections->allSources)
    159144
    160145    // if we only do one pass, skip to extended source analysis
    161     if (!strcasecmp (breakPt, "PASS1")) {
    162         goto pass1finish;
    163     }
    164     // NOTE: possibly re-measure background model here with objects subtracted
     146    if (!strcasecmp (breakPt, "PASS1")) goto pass1finish;
     147
     148    // NOTE: possibly re-measure background model here with objects subtracted / or masked
    165149
    166150    // add noise for subtracted objects
    167     psphotAddNoise (readout, sources, recipe);
    168 
    169     // find fainter sources (pass 2)
    170     detections = psphotFindDetections (detections, readout, recipe);
     151    psphotAddNoise (config, view); // pass 1 (detections->allSources)
     152
     153    // find fainter sources
     154    // NOTE: finds new peaks and new footprints, OLD and FULL set are saved on detections
     155    psphotFindDetections (config, view, false); // pass 2 (detections->peaks, detections->footprints)
    171156
    172157    // remove noise for subtracted objects (ie, return to normal noise level)
    173     psphotSubNoise (readout, sources, recipe);
     158    // NOTE: this needs to operate only on the OLD sources
     159    psphotSubNoise (config, view); // pass 1 (detections->allSources)
    174160
    175161    // define new sources based on only the new peaks
    176     psArray *newSources = psphotSourceStats (config, readout, detections, false);
     162    // NOTE: new sources are saved on detections->newSources
     163    psphotSourceStats (config, view, false); // pass 2 (detections->newSources)
    177164
    178165    // set source type
    179     if (!psphotRoughClass (readout, newSources, recipe, havePSF)) {
     166    // NOTE: apply only to detections->newSources
     167    if (!psphotRoughClass (config, view)) { // pass 2 (detections->newSources)
    180168        psLogMsg ("psphot", 3, "failed to find a valid PSF clump for image");
    181         return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
     169        return psphotReadoutCleanup (config, view);
    182170    }
    183171
    184172    // create full input models, set the radius to fitRadius, set circular fit mask
    185     psphotGuessModels (config, readout, newSources, psf);
     173    // NOTE: apply only to detections->newSources
     174    psphotGuessModels (config, view); // pass 2 (detections->newSources)
    186175
    187176    // replace all sources so fit below applies to all at once
    188     psphotReplaceAllSources (sources, recipe);
     177    // NOTE: apply only to OLD sources (which have been subtracted)
     178    psphotReplaceAllSources (config, view); // pass 2
    189179
    190180    // merge the newly selected sources into the existing list
    191     psphotMergeSources (sources, newSources);
    192     psFree (newSources);
    193 
    194     // linear fit to all sources
    195     psphotFitSourcesLinear (readout, sources, recipe, psf, TRUE);
     181    // NOTE: merge OLD and NEW
     182    // XXX check on free of sources...
     183    psphotMergeSources (config, view); // (detections->newSources + detections->allSources -> detections->allSources)
     184
     185    // NOTE: apply to ALL sources
     186    psphotFitSourcesLinear (config, view, true); // pass 3 (detections->allSources)
    196187
    197188pass1finish:
    198189
    199190    // measure source size for the remaining sources
    200     psphotSourceSize (config, readout, sources, recipe, psf, 0);
    201 
    202     psphotExtendedSourceAnalysis (readout, sources, recipe);
    203 
    204     psphotExtendedSourceFits (readout, sources, recipe);
     191    // NOTE: applies only to NEW (unmeasured) sources
     192    psphotSourceSize (config, view, false); // pass 2 (detections->allSources)
     193
     194    psphotExtendedSourceAnalysis (config, view); // pass 1 (detections->allSources)
     195    psphotExtendedSourceFits (config, view); // pass 1 (detections->allSources)
    205196
    206197finish:
     
    210201
    211202    // measure aperture photometry corrections
    212     if (!psphotApResid (config, readout, sources, psf)) {
     203    if (!psphotApResid (config, view)) { // pass 1 (detections->allSources)
    213204        psLogMsg ("psphot", 3, "failed on psphotApResid");
    214         return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
     205        return psphotReadoutCleanup (config, view);
    215206    }
    216207
    217208    // calculate source magnitudes
    218     psphotMagnitudes(config, readout, view, sources, psf);
    219 
    220     if (!psphotEfficiency(config, readout, view, psf, recipe, sources)) {
     209    psphotMagnitudes(config, view); // pass 1 (detections->allSources)
     210
     211    if (!psphotEfficiency(config, view)) { // pass 1
    221212        psErrorStackPrint(stderr, "Unable to determine detection efficiencies from fake sources");
    222213        psErrorClear();
     
    227218
    228219    // replace background in residual image
    229     psphotSkyReplace (config, view);
     220    psphotSkyReplace (config, view); // pass 1
    230221
    231222    // drop the references to the image pixels held by each source
    232     psphotSourceFreePixels (sources);
     223    psphotSourceFreePixels (config, view); // pass 1
    233224
    234225    // create the exported-metadata and free local data
    235     return psphotReadoutCleanup(config, readout, recipe, detections, psf, sources);
     226    return psphotReadoutCleanup(config, view);
    236227}
    237 
  • trunk/psphot/src/psphotReadoutCleanup.c

    r24203 r26894  
    11# include "psphotInternal.h"
    22
    3 // psphotReadoutCleanup is called on exit from psphotReadout.  If the last raised error is
    4 // not a DATA error, then there was a serious problem.  Only in this case, or if the fail
    5 // on the stats measurement, do we return false
    6 bool psphotReadoutCleanup (pmConfig *config, pmReadout *readout, psMetadata *recipe, pmDetections *detections, pmPSF *psf, psArray *sources) {
     3// for now, let's store the detections on the readout->analysis for each readout
     4bool psphotReadoutCleanup (pmConfig *config, const pmFPAview *view)
     5{
     6    bool status = true;
    77
    88    // remove internal pmFPAfiles, if created
     
    1212    }
    1313    if (psErrorCodeLast() != PS_ERR_NONE) {
    14         psFree (psf);
    15         psFree (sources);
    16         psFree (detections);
    1714        return false;
    1815    }
    1916
     17    // select the appropriate recipe information
     18    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     19    psAssert (recipe, "missing recipe?");
     20
     21    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     22    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     23
     24    // loop over the available readouts
     25    for (int i = 0; i < num; i++) {
     26        if (!psphotReadoutCleanupReadout (config, view, "PSPHOT.INPUT", i, recipe)) {
     27            psError (PSPHOT_ERR_CONFIG, false, "failed on psphotReadoutCleanup for PSPHOT.INPUT entry %d", i);
     28            return false;
     29        }
     30    }
     31
     32    // XXX move this to top of loop?
     33    pmKapaClose ();
     34
     35    return true;
     36}
     37
     38// psphotReadoutCleanup is called on exit from psphotReadout.  If the last raised error is
     39// not a DATA error, then there was a serious problem.  Only in this case, or if the fail
     40// on the stats measurement, do we return false
     41bool psphotReadoutCleanupReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe) {
     42
     43    bool status = true;
     44
     45    // find the currently selected readout
     46    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     47    psAssert (file, "missing file?");
     48
     49    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     50    psAssert (readout, "missing readout?");
     51
     52    // when psphotReadoutCleanup is called, these are not necessarily defined
     53    pmPSF        *psf        = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF");
     54    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     55    psArray      *sources    = detections->allSources;
     56    // XXX where do we free these, in here (psMetadataRemove?)
     57
    2058    // use the psf-model to measure FWHM stats
    2159    if (psf) {
    22         if (!psphotPSFstats (readout, recipe, psf)) {
     60        if (!psphotPSFstats (readout, psf)) {
    2361            psError(PSPHOT_ERR_PROG, false, "Failed to measure PSF shape parameters");
    24             psFree (psf);
    25             psFree (sources);
    26             psFree (detections);
    2762            return false;
    2863        }
     
    3065    // otherwise, use the source moments to measure FWHM stats
    3166    if (!psf && sources) {
    32         if (!psphotMomentsStats (readout, recipe, sources)) {
     67        if (!psphotMomentsStats (readout, sources)) {
    3368            psError(PSPHOT_ERR_PROG, false, "Failed to measure Moment shape parameters");
    34             psFree (psf);
    35             psFree (sources);
    36             psFree (detections);
    3769            return false;
    3870        }
     
    4072
    4173    // Check to see if the image quality was measured
     74    // XXX not sure we want / need this test
    4275    if (!psf) {
    4376        bool mdok;                      // Status of MD lookup
     
    4578        if (!mdok || nIQ <= 0) {
    4679            psError(PSPHOT_ERR_DATA, false, "Unable to measure image quality");
    47             psFree (psf);
    48             psFree (sources);
    49             psFree (detections);
    5080            return false;
    5181        }
    5282    }
    5383
     84    // create an output header with stats results currently saved on readout->analysis
     85    psMetadata *header = psphotDefineHeader (readout->analysis);
    5486
    5587    // write NSTARS to the image header
    56     psphotSetHeaderNstars (recipe, sources);
    57 
    58     // create an output header with stats results
    59     psMetadata *header = psphotDefineHeader (recipe);
     88    psphotSetHeaderNstars (header, sources);
    6089
    6190    // save the results of the analysis
     91    // this should happen way up stream (when needed?)
    6292    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "PSPHOT.HEADER",  PS_DATA_METADATA, "header stats", header);
    63     if (sources) {
    64         psMetadataAdd (readout->analysis, PS_LIST_TAIL, "PSPHOT.SOURCES", PS_DATA_ARRAY, "psphot sources", sources);
    65     }
     93
    6694    if (psf) {
     95        // XXX this seems a little silly : we saved the psf on readout->analysis above, but now
     96        // we are moving it to chip->analysis.
    6797        // save the psf for possible output.  if there was already an entry, it was loaded from external sources
    6898        // the new one may have been updated or modified, so replace the existing entry.  We
     
    79109    }
    80110
    81     // XXX move this to top of loop?
    82     pmKapaClose ();
    83 
    84     psFree (detections);
    85     psFree (psf);
    86111    psFree (header);
    87     psFree (sources);
    88 
    89112    return true;
    90113}
  • trunk/psphot/src/psphotReadoutFindPSF.c

    r25755 r26894  
    77    psTimerStart ("psphotReadout");
    88
    9     // select the current recipe
    10     psMetadata *recipe = psMetadataLookupPtr (NULL, config->recipes, PSPHOT_RECIPE);
    11     if (!recipe) {
    12         psError(PSPHOT_ERR_CONFIG, false, "missing recipe %s", PSPHOT_RECIPE);
    13         return false;
    14     }
    15 
    16     // set the photcode for this image
    17     if (!psphotAddPhotcode(recipe, config, view, "PSPHOT.INPUT")) {
     9    // set the photcode for the PSPHOT.INPUT
     10    if (!psphotAddPhotcode(config, view)) {
    1811        psError(PSPHOT_ERR_CONFIG, false, "trouble defining the photcode");
    1912        return false;
    2013    }
    2114
    22     // find the currently selected readout
    23     pmReadout  *readout = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT");
    24     PS_ASSERT_PTR_NON_NULL (readout, false);
    25 
    2615    // Generate the mask and variance images, including the user-defined analysis region of interest
    27     psphotSetMaskAndVariance (config, readout, recipe);
    28 
    29     // display the image, weight, mask (ch 1,2,3)
    30     psphotVisualShowImage (readout);
     16    psphotSetMaskAndVariance (config, view);
    3117
    3218    // Note that in this implementation, we do NOT model the background and we do not
     
    3420
    3521    // include externally-supplied sources (supplied as PSPHOT.INPUT.CMF)
    36     pmDetections *detections = psphotDetectionsFromSources (config, inSources);
    37     if (!detections || !detections->peaks) {
     22    // XXX we assume a single set of input sources is supplied
     23    if (!psphotDetectionsFromSources (config, view, inSources)) {
    3824        psError(PSPHOT_ERR_ARGUMENTS, true, "Can't find PSF stars");
    39         return psphotReadoutCleanup(config, readout, recipe, detections, NULL, NULL);
     25        return psphotReadoutCleanup(config, view);
    4026    }
    4127
    42     // construct sources and measure basic stats (moments, local sky)
    43     psArray *sources = psphotSourceStats(config, readout, detections, true);
    44     if (!sources) return false;
     28    // construct detections->newSources and measure basic stats (moments, local sky)
     29    if (!psphotSourceStats(config, view, true)) {
     30        psError(PSPHOT_ERR_UNKNOWN, false, "failure to generate sources");
     31        return false;
     32    }
    4533
    46     // peak flux is wrong : set based on previous image
    47     // use the peak measured in the moments analysis:
    48     for (int i = 0; i < sources->n; i++) {
    49       pmSource *source = sources->data[i];
    50       source->peak->flux = source->moments->Peak;
     34    // peak flux is wrong : use the peak measured in the moments analysis:
     35    if (!psphotRepairLoadedSources(config, view)) {
     36        psError(PSPHOT_ERR_UNKNOWN, false, "failure to repair sources");
     37        return false;
    5138    }
    5239
    5340    // classify sources based on moments, brightness (psf is not known)
    54     if (!psphotRoughClass (readout, sources, recipe, false)) {
    55         psLogMsg ("psphot", 3, "failed to find a valid PSF clump for image");
    56         return psphotReadoutCleanup (config, readout, recipe, detections, NULL, sources);
     41    if (!psphotRoughClass (config, view)) {
     42        psError (PSPHOT_ERR_UNKNOWN, false, "failed to determine rough source class");
     43        return psphotReadoutCleanup (config, view);
    5744    }
    5845
    59     pmPSF *psf = psphotChoosePSF(readout, sources, recipe);
    60     if (!psf) {
     46    if (!psphotImageQuality (config, view)) {
     47        psError (PSPHOT_ERR_UNKNOWN, false, "failed to measure image quality");
     48        return psphotReadoutCleanup(config, view);
     49    }
     50
     51    if (!psphotChoosePSF(config, view)) {
    6152        psError(PSPHOT_ERR_PSF, false, "Failed to construct a psf model");
    62         psFree(sources);
    63         return psphotReadoutCleanup(config, readout, recipe, detections, NULL, NULL);
     53        return psphotReadoutCleanup(config, view);
    6454    }
    65     psphotVisualShowPSFModel(readout, psf);
     55
     56# if 0
     57    // XXX if we want to determine the aperture residual correction here, we either
     58    // need to carry it out of the PSF determination analysis above, or save the model
     59    // fits from that analysis, or run the linear PSF fit for all objects currently in hand
     60    // construct an initial model for each object, set the radius to fitRadius, set circular fit mask
     61    psphotGuessModels (config, view);
     62# endif
     63
     64    // merge the newly selected sources into the existing list
     65    // NOTE: merge OLD and NEW
     66    psphotMergeSources (config, view);
     67
     68# if 0
     69    // measure aperture photometry corrections
     70    if (!psphotApResid (config, view)) {
     71        psLogMsg ("psphot", 3, "failed on psphotApResid");
     72        return psphotReadoutCleanup (config, view);
     73    }
     74# endif
    6675
    6776    // drop the references to the image pixels held by each source
    68     psphotSourceFreePixels(sources);
    69     psFree(sources);
     77    psphotSourceFreePixels(config, view);
    7078
    7179    // create the exported-metadata and free local data
    72     return psphotReadoutCleanup(config, readout, recipe, detections, psf, NULL);
     80    return psphotReadoutCleanup(config, view);
    7381}
  • trunk/psphot/src/psphotReadoutKnownSources.c

    r25755 r26894  
    11# include "psphotInternal.h"
    22
    3 // in this psphotReadout-variant, we are only measuring the photometry for known sources,
    4 // using a PSF generated from this observation those sources
     3// in this psphotReadout-variant, we are only measuring the photometry for known sources, using
     4// a PSF generated for this observation from those sources
    55bool psphotReadoutKnownSources(pmConfig *config, const pmFPAview *view, psArray *inSources) {
    66
    77    psTimerStart ("psphotReadout");
    88
    9     // select the current recipe
    10     psMetadata *recipe = psMetadataLookupPtr (NULL, config->recipes, PSPHOT_RECIPE);
    11     if (!recipe) {
    12         psError(PSPHOT_ERR_CONFIG, false, "missing recipe %s", PSPHOT_RECIPE);
    13         return false;
    14     }
    15 
    169    // set the photcode for this image
    17     if (!psphotAddPhotcode(recipe, config, view, "PSPHOT.INPUT")) {
     10    if (!psphotAddPhotcode(config, view)) {
    1811        psError(PSPHOT_ERR_CONFIG, false, "trouble defining the photcode");
    1912        return false;
    2013    }
    2114
    22     // find the currently selected readout
    23     pmReadout  *readout = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT");
    24     PS_ASSERT_PTR_NON_NULL (readout, false);
    25 
    2615    // Generate the mask and weight images, including the user-defined analysis region of interest
    27     psphotSetMaskAndVariance (config, readout, recipe);
    28 
    29     // display the image, weight, mask (ch 1,2,3)
    30     psphotVisualShowImage (readout);
     16    psphotSetMaskAndVariance (config, view);
    3117
    3218    // Note that in this implementation, we do NOT model the background and we do not
     
    3420
    3521    // include externally-supplied sources (supplied as PSPHOT.INPUT.CMF)
    36     pmDetections *detections = psphotDetectionsFromSources (config, inSources);
    37     if (!detections || !detections->peaks) {
     22    if (!psphotDetectionsFromSources (config, view, inSources)) {
    3823        psError(PSPHOT_ERR_ARGUMENTS, true, "Can't find PSF stars");
    39         return psphotReadoutCleanup(config, readout, recipe, detections, NULL, NULL);
     24        return psphotReadoutCleanup(config, view);
    4025    }
    4126
    4227    // construct sources and measure basic stats
    43     psArray *sources = psphotSourceStats (config, readout, detections, true);
    44     if (!sources) return false;
     28    if (!psphotSourceStats (config, view, true)) {
     29        psError(PSPHOT_ERR_UNKNOWN, false, "failure to generate sources");
     30        return false;
     31    }
    4532
    46     // peak flux is wrong : set based on previous image
    47     // use the peak measured in the moments analysis:
    48     for (int i = 0; i < sources->n; i++) {
    49         pmSource *source = sources->data[i];
    50         source->peak->flux = source->moments->Peak;
     33    // peak flux is wrong : use the peak measured in the moments analysis:
     34    if (!psphotRepairLoadedSources(config, view)) {
     35        psError(PSPHOT_ERR_UNKNOWN, false, "failure to repair sources");
     36        return false;
    5137    }
    5238
    5339    // classify sources based on moments, brightness (psf is not known)
    54     if (!psphotRoughClass (readout, sources, recipe, false)) {
    55         psLogMsg ("psphot", 3, "failed to find a valid PSF clump for image");
    56         return psphotReadoutCleanup (config, readout, recipe, detections, NULL, sources);
     40    if (!psphotRoughClass (config, view)) {
     41        psError (PSPHOT_ERR_UNKNOWN, false, "failed to determine rough source class");
     42        return psphotReadoutCleanup(config, view);
    5743    }
    5844
    59     pmPSF *psf = psphotChoosePSF (readout, sources, recipe);
    60     if (!psf) {
    61         psLogMsg ("psphot", 3, "failure to construct a psf model");
    62         return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
     45    if (!psphotChoosePSF (config, view)) {
     46        psError(PSPHOT_ERR_PSF, false, "Failed to construct a psf model");
     47        return psphotReadoutCleanup(config, view);
    6348    }
    64     psphotVisualShowPSFModel (readout, psf);
    6549
    6650    // construct an initial model for each object
    67     psphotGuessModels (config, readout, sources, psf);
     51    psphotGuessModels (config, view);
     52
     53    // merge the newly selected sources into the existing list
     54    // NOTE: merge OLD and NEW
     55    psphotMergeSources (config, view);
    6856
    6957    // linear PSF fit to source peaks
    70     psphotFitSourcesLinear (readout, sources, recipe, psf, FALSE);
    71 
    72     // We have to place these visualizations here because the models are not realized until
    73     // psphotGuessModels or fitted until psphotFitSourcesLinear.
    74     psphotVisualShowPSFStars (recipe, psf, sources);
    75     psphotVisualShowSatStars (recipe, psf, sources);
     58    psphotFitSourcesLinear (config, view, false);
    7659
    7760    // measure aperture photometry corrections
    78     if (!psphotApResid (config, readout, sources, psf)) {
     61    if (!psphotApResid (config, view)) {
    7962        psLogMsg ("psphot", 3, "failed on psphotApResid");
    80         return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
     63        return psphotReadoutCleanup(config, view);
    8164    }
    8265
    8366    // calculate source magnitudes
    84     psphotMagnitudes(config, readout, view, sources, psf);
     67    psphotMagnitudes(config, view);
    8568
    8669    // drop the references to the image pixels held by each source
    87     psphotSourceFreePixels (sources);
     70    psphotSourceFreePixels (config, view);
    8871
    8972    // create the exported-metadata and free local data
    90     return psphotReadoutCleanup(config, readout, recipe, detections, psf, sources);
     73    return psphotReadoutCleanup(config, view);
    9174}
  • trunk/psphot/src/psphotReadoutMinimal.c

    r25755 r26894  
    11# include "psphotInternal.h"
    22
    3 // this badly-named function performs photometry assuming (a) a supplied PSF, (b)
    4 // background subtraction, (c) linear psf-model fits only.  it is currently only being
    5 // used by ppSub.
     3// this badly-named function performs photometry assuming (a) a supplied PSF, (b) background
     4// subtraction, (c) linear psf-model fits only, (d) a prior analysis has supplied the moments
     5// window parameters.  It is currently only being used by ppSub.
    66
    77// NOTE: ppSub needs to perform extended source analysis for comets and trails.
     
    1717    pmModelClassSetLimits(PM_MODEL_LIMITS_LAX);
    1818
    19     // select the current recipe
    20     psMetadata *recipe = psMetadataLookupPtr (NULL, config->recipes, PSPHOT_RECIPE);
    21     if (!recipe) {
    22         psError(PSPHOT_ERR_CONFIG, false, "missing recipe %s", PSPHOT_RECIPE);
    23         return false;
    24     }
    25 
    2619    // set the photcode for this image
    27     if (!psphotAddPhotcode(recipe, config, view, "PSPHOT.INPUT")) {
     20    if (!psphotAddPhotcode(config, view)) {
    2821        psError(PSPHOT_ERR_CONFIG, false, "trouble defining the photcode");
    2922        return false;
    3023    }
    3124
    32     // find the currently selected readout
    33     pmReadout  *readout = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT");
    34     PS_ASSERT_PTR_NON_NULL (readout, false);
     25    // Generate the mask and weight images, including the user-defined analysis region of interest
     26    psphotSetMaskAndVariance (config, view);
    3527
    36     // Generate the mask and weight images, including the user-defined analysis region of interest
    37     psphotSetMaskAndVariance (config, readout, recipe);
    38 
    39     // display the image, weight, mask (ch 1,2,3)
    40     psphotVisualShowImage (readout);
    41 
    42     // load the psf model, if suppled.  FWHM_X,FWHM_Y,etc are saved in the recipe
    43     pmPSF *psf = psphotLoadPSF (config, view, recipe);
    44     if (!psf) {
     28    // load the psf model, if suppled.  FWHM_X,FWHM_Y,etc are saved on readout->analysis
     29    if (!psphotLoadPSF (config, view)) {
    4530      psError (PSPHOT_ERR_CONFIG, false, "missing psf model");
    46       return psphotReadoutCleanup (config, readout, recipe, NULL, NULL, NULL);
     31      return psphotReadoutCleanup (config, view);
    4732    }
    4833
    49     // find the detections (by peak and/or footprint) in the image.
    50     pmDetections *detections = pmDetectionsAlloc(); // New detections; allocated to ensure pass=2
    51     detections = psphotFindDetections(detections, readout, recipe);
    52     if (!detections) {
    53         psLogMsg ("psphot", 3, "unable to find detections in this image");
    54         return psphotReadoutCleanup (config, readout, recipe, detections, psf, NULL);
     34    // find the detections (by peak and/or footprint) in the image. (final pass)
     35    if (!psphotFindDetections(config, view, false)) {
     36        psError (PSPHOT_ERR_UNKNOWN, false, "failure in peak analysis");
     37        return psphotReadoutCleanup (config, view);
    5538    }
    5639
    57     // construct sources and measure basic stats
    58     psArray *sources = psphotSourceStats (config, readout, detections, true);
    59     if (!sources) return false;
     40    // construct sources and measure basic stats (saved on detections->newSources)
     41    if (!psphotSourceStats (config, view, false)) { // pass 1
     42        psError(PSPHOT_ERR_UNKNOWN, false, "failure to generate sources");
     43        return psphotReadoutCleanup (config, view);
     44    }
    6045
    6146    // find blended neighbors of very saturated stars
    62     // XXX merge this with Basic Deblend?
    63     psphotDeblendSatstars (readout, sources, recipe);
     47    psphotDeblendSatstars (config, view);
    6448
    6549    // mark blended peaks PS_SOURCE_BLEND
    66     if (!psphotBasicDeblend (sources, recipe)) {
     50    if (!psphotBasicDeblend (config, view)) {
    6751        psLogMsg ("psphot", 3, "failed on deblend analysis");
    68         return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
     52        return psphotReadoutCleanup (config, view);
    6953    }
    7054
    7155    // classify sources based on moments, brightness (use supplied psf shape parameters)
    72     if (!psphotRoughClass (readout, sources, recipe, true)) {
     56    if (!psphotRoughClass (config, view)) {
    7357        psLogMsg ("psphot", 3, "failed to find a valid PSF clump for image");
    74         return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
     58        return psphotReadoutCleanup (config, view);
    7559    }
    7660
    7761    // construct an initial model for each object
    78     psphotGuessModels (config, readout, sources, psf);
     62    psphotGuessModels (config, view);
     63
     64    // merge the newly selected sources into the existing list
     65    psphotMergeSources (config, view);
    7966
    8067    // linear PSF fit to source peaks
    81     psphotFitSourcesLinear (readout, sources, recipe, psf, FALSE);
    82 
    83     // We have to place these visualizations here because the models are not realized until
    84     // psphotGuessModels or fitted until psphotFitSourcesLinear.
    85     psphotVisualShowPSFStars (recipe, psf, sources);
    86     psphotVisualShowSatStars (recipe, psf, sources);
     68    psphotFitSourcesLinear (config, view, false);
    8769
    8870// XXX eventually, add the extended source fits here
    8971# if (0)
    9072    // measure source size for the remaining sources
    91     psphotSourceSize (config, readout, sources, recipe, 0);
     73    psphotSourceSize (config, view);
    9274
    93     psphotExtendedSourceAnalysis (readout, sources, recipe);
     75    psphotExtendedSourceAnalysis (config, view);
    9476
    95     psphotExtendedSourceFits (readout, sources, recipe);
     77    psphotExtendedSourceFits (config, view);
    9678# endif
    9779
    9880    // calculate source magnitudes
    99     psphotMagnitudes(config, readout, view, sources, psf);
     81    psphotMagnitudes(config, view);
    10082
    101     if (!psphotEfficiency(config, readout, view, psf, recipe, sources)) {
     83    // XXX ensure this is measured if the analysis succeeds (even if quality is low)
     84    if (!psphotEfficiency(config, view)) {
    10285        psErrorStackPrint(stderr, "Unable to determine detection efficiencies from fake sources");
    10386        psErrorClear();
     
    10588
    10689    // drop the references to the image pixels held by each source
    107     psphotSourceFreePixels (sources);
     90    psphotSourceFreePixels (config, view);
    10891
    10992    // create the exported-metadata and free local data
    110     return psphotReadoutCleanup(config, readout, recipe, detections, psf, sources);
     93    return psphotReadoutCleanup(config, view);
    11194}
  • trunk/psphot/src/psphotReplaceUnfit.c

    r25755 r26894  
    2222}
    2323
    24 bool psphotReplaceAllSources (psArray *sources, psMetadata *recipe) {
     24// for now, let's store the detections on the readout->analysis for each readout
     25bool psphotReplaceAllSources (pmConfig *config, const pmFPAview *view)
     26{
     27    bool status = true;
     28
     29    // select the appropriate recipe information
     30    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     31    psAssert (recipe, "missing recipe?");
     32
     33    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     34    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     35
     36    // loop over the available readouts
     37    for (int i = 0; i < num; i++) {
     38        if (!psphotReplaceAllSourcesReadout (config, view, "PSPHOT.INPUT", i, recipe)) {
     39            psError (PSPHOT_ERR_CONFIG, false, "failed to replace all sources for PSPHOT.INPUT entry %d", i);
     40            return false;
     41        }
     42    }
     43    return true;
     44}
     45
     46bool psphotReplaceAllSourcesReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe) {
    2547
    2648    bool status;
     
    2951    psTimerStart ("psphot.replace");
    3052
     53    // find the currently selected readout
     54    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     55    psAssert (file, "missing file?");
     56
     57    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     58    psAssert (readout, "missing readout?");
     59
     60    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     61    psAssert (detections, "missing detections?");
     62
     63    psArray *sources = detections->allSources;
     64    psAssert (sources, "missing sources?");
     65
    3166    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
    3267    psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
    33     assert (maskVal);
     68    psAssert (maskVal, "missing mask value?");
    3469
    3570    for (int i = 0; i < sources->n; i++) {
     
    67102    return true;
    68103}
    69 
    70 # if (0)
    71 // add source, if the source has been subtracted; do not modify state
    72 bool psphotAddWithTest (pmSource *source, bool useState, psImageMaskType maskVal) {
    73 
    74     // what is current state? (true : add; false : sub)
    75     bool state = !(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
    76     if (state && useState) return true;
    77 
    78     pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    79     return true;
    80 }
    81 
    82 // sub source, if the source has been added; do not modify state
    83 bool psphotSubWithTest (pmSource *source, bool useState, psImageMaskType maskVal) {
    84 
    85     // what is current state? (true : sub; false : add)
    86     bool state = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
    87     if (state && useState) return true;
    88 
    89     pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    90     return true;
    91 }
    92 
    93 // add or sub source to match recorded state: supply current state as true (add) or false (sub)
    94 bool psphotSetState (pmSource *source, bool curState, psImageMaskType maskVal) {
    95 
    96     // what is desired state? (true : add; false : sub)
    97     bool newState = !(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
    98     if (curState == newState) return true;
    99 
    100     if (curState && !newState) {
    101         pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    102     }
    103     if (newState && !curState) {
    104         pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    105     }
    106     return true;
    107 }
    108 # endif
  • trunk/psphot/src/psphotRoughClass.c

    r25989 r26894  
    77        } }
    88
    9 bool psphotRoughClassRegion (int nRegion, psRegion *region, psArray *sources, psMetadata *target, psMetadata *recipe, const bool havePSF);
     9// for now, let's store the detections on the readout->analysis for each readout
     10bool psphotRoughClass (pmConfig *config, const pmFPAview *view)
     11{
     12    bool status = true;
    1013
    11 // 2006.02.02 : no leaks
    12 bool psphotRoughClass (pmReadout *readout, psArray *sources, psMetadata *recipe, const bool havePSF) {
     14    // select the appropriate recipe information
     15    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     16    psAssert (recipe, "missing recipe?");
     17
     18    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     19    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     20
     21    // loop over the available readouts
     22    for (int i = 0; i < num; i++) {
     23        if (!psphotRoughClassReadout (config, view, "PSPHOT.INPUT", i, recipe)) {
     24            psError (PSPHOT_ERR_CONFIG, false, "failed on rough classification for PSPHOT.INPUT entry %d", i);
     25            return false;
     26        }
     27    }
     28    return true;
     29}
     30
     31bool psphotRoughClassReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe) {
    1332
    1433    bool status;
    1534
    1635    psTimerStart ("psphot.rough");
     36
     37    // find the currently selected readout
     38    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     39    psAssert (file, "missing file?");
     40
     41    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     42    psAssert (readout, "missing readout?");
     43
     44    // if we have a PSF, use the existing PSF clump region below
     45    bool havePSF = false;
     46    if (psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF")) {
     47        havePSF = true;
     48    }
     49
     50    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     51    psAssert (detections, "missing detections?");
     52
     53    psArray *sources = detections->newSources;
     54    psAssert (sources, "missing sources?");
     55
     56    if (!sources->n) {
     57        psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping rough classification");
     58        return true;
     59    }
    1760
    1861    // we make this measurement on a NxM grid of regions across the readout
     
    75118        // determine the PSF parameters from the source moment values
    76119        // XXX why not save the psfClump as a PTR?
    77         psfClump = pmSourcePSFClump (region, sources, recipe);
     120
     121        float PSF_SN_LIM = psMetadataLookupF32(&status, recipe, "PSF_SN_LIM"); psAssert (status, "missing PSF_SN_LIM");
     122        float MOMENTS_AR_MAX = psMetadataLookupF32(&status, recipe, "MOMENTS_AR_MAX"); psAssert (status, "missing MOMENTS_AR_MAX");
     123
     124        float PSF_CLUMP_GRID_SCALE = psMetadataLookupF32(&status, analysis, "PSF_CLUMP_GRID_SCALE");
     125        if (!status) {
     126            PSF_CLUMP_GRID_SCALE = psMetadataLookupF32(&status, recipe, "PSF_CLUMP_GRID_SCALE");
     127            psAssert (status, "missing PSF_CLUMP_GRID_SCALE");
     128        }
     129        float MOMENTS_SX_MAX = psMetadataLookupF32(&status, analysis, "MOMENTS_SX_MAX");
     130        if (!status) {
     131            MOMENTS_SX_MAX = psMetadataLookupF32(&status, recipe, "MOMENTS_SX_MAX");
     132            psAssert (status, "missing MOMENTS_SX_MAX");
     133        }
     134        float MOMENTS_SY_MAX = psMetadataLookupF32(&status, analysis, "MOMENTS_SY_MAX");
     135        if (!status) {
     136            MOMENTS_SY_MAX = psMetadataLookupF32(&status, recipe, "MOMENTS_SY_MAX");
     137            psAssert (status, "missing MOMENTS_SY_MAX");
     138        }
     139
     140        psfClump = pmSourcePSFClump (NULL, region, sources, PSF_SN_LIM, PSF_CLUMP_GRID_SCALE, MOMENTS_SX_MAX, MOMENTS_SY_MAX, MOMENTS_AR_MAX);
     141
    78142        psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.X",  PS_META_REPLACE, "psf clump center", psfClump.X);
    79143        psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.Y",  PS_META_REPLACE, "psf clump center", psfClump.Y);
     
    103167    psLogMsg ("psphot", 3, "psf clump DX, DY: %f, %f\n", psfClump.dX, psfClump.dY);
    104168
     169    // get basic parameters, or set defaults
     170    float PSF_SN_LIM = psMetadataLookupF32 (&status, recipe, "PSF_SN_LIM"); psAssert (status, "missing PSF_SN_LIM");
     171    float PSF_CLUMP_NSIGMA = psMetadataLookupF32 (&status, recipe, "PSF_CLUMP_NSIGMA"); psAssert (status, "missing PSF_CLUMP_NSIGMA");
     172
    105173    // group into STAR, COSMIC, EXTENDED, SATURATED, etc.
    106     if (!pmSourceRoughClass (region, sources, recipe, psfClump, maskSat)) {
     174    if (!pmSourceRoughClass (region, sources, PSF_SN_LIM, PSF_CLUMP_NSIGMA, psfClump, maskSat)) {
    107175        psError(PSPHOT_ERR_PROG, false, "programming error calling pmSourceRoughClass");
    108176        return false;
  • trunk/psphot/src/psphotSetThreads.c

    r25755 r26894  
    2525    psFree(task);
    2626
    27     task = psThreadTaskAlloc("PSPHOT_SOURCE_STATS", 5);
     27    task = psThreadTaskAlloc("PSPHOT_SOURCE_STATS", 10);
    2828    task->function = &psphotSourceStats_Threaded;
    2929    psThreadTaskAdd(task);
  • trunk/psphot/src/psphotSignificanceImage.c

    r25383 r26894  
    2222    }
    2323
     24    // if we have already determined the PSF model, then we have a better idea how to smooth this image
    2425    bool statusMajor, statusMinor;
    25     float fwhmMajor = psMetadataLookupF32(&statusMajor, recipe, "FWHM_MAJ");
    26     float fwhmMinor = psMetadataLookupF32(&statusMinor, recipe, "FWHM_MIN");
     26    float fwhmMajor = psMetadataLookupF32(&statusMajor, readout->analysis, "FWHM_MAJ");
     27    float fwhmMinor = psMetadataLookupF32(&statusMinor, readout->analysis, "FWHM_MIN");
    2728    if (statusMajor && statusMinor) {
    2829        // if we know the FHWM, use that to set the smoothing kernel (XXX allow an optional override?)
     
    4344    }
    4445    // record the actual smoothing sigma
    45     psMetadataAddF32(recipe, PS_LIST_TAIL, "SIGMA_SMOOTH", PS_META_REPLACE, "Smoothing sigma for detections",
    46                      SIGMA_SMTH);
     46    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "SIGMA_SMOOTH", PS_META_REPLACE, "Smoothing sigma for detections", SIGMA_SMTH);
    4747
    4848    // smooth the image, applying the mask as we go
     
    5959    // effective per-pixel variance is maintained.
    6060    psImage *smooth_wt = psImageCopy(NULL, readout->variance, PS_TYPE_F32);
    61     psImageSmoothMask_Threaded(smooth_wt, smooth_wt, readout->mask, maskVal, SIGMA_SMTH * M_SQRT1_2,
    62                       NSIGMA_SMTH, minGauss);
     61    psImageSmoothMask_Threaded(smooth_wt, smooth_wt, readout->mask, maskVal, SIGMA_SMTH * M_SQRT1_2, NSIGMA_SMTH, minGauss);
    6362    psLogMsg("psphot", PS_LOG_MINUTIA, "smooth variance: %f sec\n", psTimerMark("psphot.smooth"));
    6463
     
    7776    // Calculate correction factor for the covariance produced by the (potentially multiple) smoothing
    7877    psKernel *kernel = psImageSmoothKernel(SIGMA_SMTH, NSIGMA_SMTH); // Kernel used for smoothing
    79     psKernel *covar = psImageCovarianceCalculate(kernel, readout->covariance); // Covariance matrix
     78    float factor = 1.0 / psImageCovarianceCalculateFactor(kernel, readout->covariance);
    8079    psFree(kernel);
    81     float factor = 1.0 / psImageCovarianceFactor(covar);
    82     psFree(covar);
    8380
    8481    // record the effective area and significance scaling factor
    8582    float effArea = 8.0 * M_PI * PS_SQR(SIGMA_SMTH);
    86     psMetadataAddF32(recipe, PS_LIST_TAIL, "EFFECTIVE_AREA", PS_META_REPLACE, "Effective Area", effArea);
    87     psMetadataAddF32(recipe, PS_LIST_TAIL, "SIGNIFICANCE_SCALE_FACTOR", PS_META_REPLACE,
    88                      "Signicance scale factor", factor);
     83    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "EFFECTIVE_AREA", PS_META_REPLACE, "Effective Area", effArea);
     84    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "SIGNIFICANCE_SCALE_FACTOR", PS_META_REPLACE, "Signicance scale factor", factor);
    8985
    9086    // XXX multithread this if needed
  • trunk/psphot/src/psphotSkyReplace.c

    r21183 r26894  
    11# include "psphotInternal.h"
     2
     3bool psphotSkyReplace (pmConfig *config, const pmFPAview *view)
     4{
     5    bool status = true;
     6
     7    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     8    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     9
     10    // loop over the available readouts
     11    for (int i = 0; i < num; i++) {
     12        if (!psphotSkyReplaceReadout (config, view, "PSPHOT.INPUT", i)) {
     13            psError (PSPHOT_ERR_CONFIG, false, "failed to replace sky for PSPHOT.INPUT entry %d", i);
     14            return false;
     15        }
     16    }
     17    return true;
     18}
    219
    320// XXX make this an option?
    421// in order to  successfully replace the sky, we must define a corresponding file...
    5 bool psphotSkyReplace (pmConfig *config, const pmFPAview *view) {
     22bool psphotSkyReplaceReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index) {
    623
    724    psTimerStart ("psphot.skyreplace");
    825
    926    // find the currently selected readout
    10     pmReadout *readout = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT");
    11     if (readout == NULL) psAbort("input not defined");
     27    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     28    psAssert (file, "missing file?");
     29
     30    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     31    psAssert (readout, "missing readout?");
    1232
    1333    // select background pixels, from output background file, or create
  • trunk/psphot/src/psphotSourceFits.c

    r25755 r26894  
    219219    double chiTrend;
    220220    pmModel *ONE = NULL;
     221    pmSource *tmpSrc = NULL;
     222    pmModel *EXT = NULL;
     223    psArray *DBL = NULL;
    221224
    222225    // skip the source if we don't think it is extended
     
    232235    // at this stage, skip Gaussian windowing, and do not clip pixels by S/N
    233236    // this uses the footprint to judge both radius and aperture?
    234     if (!pmSourceMoments (source, radius, 0.0, 0.0)) return false;
     237    if (!pmSourceMoments (source, radius, 0.0, 0.0, maskVal)) return false;
    235238
    236239    psTrace ("psphot", 5, "trying blob...\n");
     
    240243
    241244    // this temporary source is used as a place-holder by the psphotEval functions below
    242     pmSource *tmpSrc = pmSourceAlloc ();
     245    tmpSrc = pmSourceAlloc ();
    243246
    244247    // XXX need to handle failures better here
    245     pmModel *EXT = psphotFitEXT (readout, source, modelTypeEXT, maskVal, markVal);
    246     if (!isfinite(EXT->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
     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;
    247251
    248252    okEXT = psphotEvalEXT (tmpSrc, EXT);
     
    250254
    251255    // DBL will always be defined, but DBL->data[n] might not
    252     psArray *DBL = psphotFitDBL (readout, source, maskVal, markVal);
     256    DBL = psphotFitDBL (readout, source, maskVal, markVal);
     257    if (!DBL) goto escape;
     258    if (!DBL->n) goto escape;
     259
    253260    okDBL  = psphotEvalDBL (tmpSrc, DBL->data[0]);
    254261    okDBL &= psphotEvalDBL (tmpSrc, DBL->data[1]);
     
    362369    psFree (DBL);
    363370    return true;
     371
     372escape:
     373    psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
     374    psFree (tmpSrc);
     375    psFree (EXT);
     376    psFree (DBL);
     377    return false;
    364378}
    365379
     
    425439    // use the source moments, etc to guess basic model parameters
    426440    pmModel *EXT = pmSourceModelGuess (source, modelType);
    427     PS_ASSERT (EXT, NULL);
     441    if (!EXT) {
     442        psTrace ("psphot", 5, "failed to generate a model for source: moments: %f %f\n", source->moments->Mxx, source->moments->Myy);
     443        return NULL;
     444    }
    428445
    429446    if ((source->moments->Mxx < 1e-3) || (source->moments->Myy < 1e-3)) {
  • trunk/psphot/src/psphotSourceFreePixels.c

    r12792 r26894  
    11# include "psphotInternal.h"
    22
    3 void psphotSourceFreePixels (psArray *sources) {
     3bool psphotSourceFreePixels (pmConfig *config, const pmFPAview *view)
     4{
     5    bool status = true;
    46
    5     if (!sources) return;
     7    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     8    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     9
     10    // loop over the available readouts
     11    for (int i = 0; i < num; i++) {
     12        if (!psphotSourceFreePixelsReadout (config, view, "PSPHOT.INPUT", i)) {
     13            psError (PSPHOT_ERR_CONFIG, false, "failed to free source pixels for PSPHOT.INPUT entry %d", i);
     14            return false;
     15        }
     16    }
     17    return true;
     18}
     19
     20bool psphotSourceFreePixelsReadout(pmConfig *config, const pmFPAview *view, const char *filename, int index) {
     21
     22    bool status;
     23
     24    // find the currently selected readout
     25    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     26    psAssert (file, "missing file?");
     27
     28    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     29    psAssert (readout, "missing readout?");
     30
     31    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     32    psAssert (detections, "missing detections?");
     33
     34    psArray *sources = detections->allSources;
     35    psAssert (sources, "missing sources?");
    636
    737    for (int i = 0; i < sources->n; i++) {
     
    939        pmSourceFreePixels (source);
    1040    }
    11     return;
     41    return true;
    1242}
  • trunk/psphot/src/psphotSourceSize.c

    r26618 r26894  
    1515} psphotSourceSizeOptions;
    1616
     17// local functions:
    1718bool psphotSourceSizePSF (psphotSourceSizeOptions *options, psArray *sources, pmPSF *psf);
    1819bool psphotSourceClass (pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options);
    1920bool psphotSourceClassRegion (psRegion *region, pmPSFClump *psfClump, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options);
    2021bool psphotSourceSizeCR (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options);
    21 bool psphotMaskCosmicRay (psImage *mask, pmSource *source, psImageMaskType maskVal, psImageMaskType crMask);
    22 bool psphotMaskCosmicRayIsophot (pmSource *source, psImageMaskType maskVal, psImageMaskType crMask);
     22bool psphotMaskCosmicRay (pmReadout *readout, pmSource *source, psImageMaskType maskVal);
     23bool psphotMaskCosmicRayFootprintCheck (psArray *sources);
    2324
    2425// we need to call this function after sources have been fitted to the PSF model and
     
    2829// deviation from the psf model at the r = FWHM/2 position
    2930
    30 // XXX use an internal flag to mark sources which have already been measured
    31 bool psphotSourceSize(pmConfig *config, pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, long first)
     31// for now, let's store the detections on the readout->analysis for each readout
     32bool psphotSourceSize (pmConfig *config, const pmFPAview *view, bool getPSFsize)
     33{
     34    bool status = true;
     35
     36    // select the appropriate recipe information
     37    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     38    psAssert (recipe, "missing recipe?");
     39
     40    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     41    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     42
     43    // loop over the available readouts
     44    for (int i = 0; i < num; i++) {
     45        if (!psphotSourceSizeReadout (config, view, "PSPHOT.INPUT", i, recipe, getPSFsize)) {
     46            psError (PSPHOT_ERR_CONFIG, false, "failed on source size analysis for PSPHOT.INPUT entry %d", i);
     47            return false;
     48        }
     49    }
     50    return true;
     51}
     52
     53// this function use an internal flag to mark sources which have already been measured
     54bool psphotSourceSizeReadout(pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe, bool getPSFsize)
    3255{
    3356    bool status;
     
    3558
    3659    psTimerStart ("psphot.size");
     60
     61    // find the currently selected readout
     62    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     63    psAssert (file, "missing file?");
     64
     65    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     66    psAssert (readout, "missing readout?");
     67
     68    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     69    psAssert (detections, "missing detections?");
     70
     71    psArray *sources = detections->allSources;
     72    psAssert (sources, "missing sources?");
     73
     74    if (!sources->n) {
     75        psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping source size");
     76        return true;
     77    }
     78
     79    pmPSF *psf = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF");
     80    psAssert (psf, "missing psf?");
    3781
    3882    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
     
    70114
    71115    // We are using the value psfMag - 2.5*log10(moment.Sum) as a measure of the extendedness
    72     // of and object.  We need to model this distribution for the PSF stars before we can test
     116    // of an object.  We need to model this distribution for the PSF stars before we can test
    73117    // the significance for a specific object
    74118    // XXX move this to the code that generates the PSF?
    75119    // XXX store the results on pmPSF?
    76     psphotSourceSizePSF (&options, sources, psf);
     120
     121    // XXX this should only be done on the first pass (ie, if we have newSources or allSources?)
     122    if (getPSFsize) {
     123        psphotSourceSizePSF (&options, sources, psf);
     124    }
    77125
    78126    // classify the sources based on ApResid and Moments (extended sources)
     127    // NOTE: only sources not already measured !(source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED)
    79128    psphotSourceClass(readout, sources, recipe, psf, &options);
    80129
     130    // NOTE: only sources not already measured !(source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED)
    81131    psphotSourceSizeCR (readout, sources, &options);
    82132
    83     psLogMsg ("psphot.size", PS_LOG_INFO, "measure source sizes for %ld sources: %f sec\n", sources->n - first, psTimerMark ("psphot.size"));
     133    // XXX fix this (was source->n  - first)
     134    psLogMsg ("psphot.size", PS_LOG_INFO, "measure source sizes for %ld sources: %f sec\n", sources->n, psTimerMark ("psphot.size"));
    84135
    85136    psphotVisualPlotSourceSize (recipe, readout->analysis, sources);
    86137    psphotVisualShowSourceSize (readout, sources);
    87138    psphotVisualPlotApResid (sources, options.ApResid, options.ApSysErr);
    88 
    89     return true;
    90 }
    91 
    92 bool psphotMaskCosmicRay (psImage *mask, pmSource *source, psImageMaskType maskVal, psImageMaskType crMask) {
     139    psphotVisualShowSatStars (recipe, psf, sources);
     140
     141    return true;
     142}
     143
     144// model the apmifit distribution for the psf stars:
     145bool psphotSourceSizePSF (psphotSourceSizeOptions *options, psArray *sources, pmPSF *psf) {
     146
     147    // select stats from the psf stars
     148    psVector *Ap = psVectorAllocEmpty (100, PS_TYPE_F32);
     149    psVector *ApErr = psVectorAllocEmpty (100, PS_TYPE_F32);
     150
     151    psImageMaskType maskVal = options->maskVal | options->markVal;
     152
     153    // XXX  why PHOT_WEIGHT??
     154    pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_WEIGHT;
     155
     156    for (int i = 0; i < sources->n; i++) {
     157        pmSource *source = sources->data[i];
     158        if (!(source->mode & PM_SOURCE_MODE_PSFSTAR)) continue;
     159
     160        // replace object in image
     161        if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
     162            pmSourceAdd (source, PM_MODEL_OP_FULL, options->maskVal);
     163        }
     164
     165        // clear the mask bit and set the circular mask pixels
     166        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));
     167        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", options->markVal);
     168
     169        // XXX can we test if psfMag is set and calculate only if needed?
     170        pmSourceMagnitudes (source, psf, photMode, maskVal); // maskVal includes markVal
     171
     172        // clear the mask bit
     173        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));
     174
     175        // re-subtract the object, leave local sky
     176        pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal);
     177
     178        float apMag = -2.5*log10(source->moments->Sum);
     179        float dMag = source->psfMag - apMag;
     180
     181        psVectorAppend (Ap, dMag);
     182        psVectorAppend (ApErr, source->errMag);
     183    }
     184
     185    // model the distribution as a mean or median value and a systematic error from that value:
     186    psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN);
     187    psVectorStats (stats, Ap, NULL, NULL, 0);
     188
     189    psVector *dAp = psVectorAlloc (Ap->n, PS_TYPE_F32);
     190    for (int i = 0; i < Ap->n; i++) {
     191        dAp->data.F32[i] = Ap->data.F32[i] - stats->robustMedian;
     192    }
     193
     194    options->ApResid = stats->robustMedian;
     195    options->ApSysErr = psVectorSystematicError(dAp, ApErr, 0.05);
     196    // XXX this is quite arbitrary...
     197    if (!isfinite(options->ApSysErr)) options->ApSysErr = 0.01;
     198    psLogMsg ("psphot", PS_LOG_DETAIL, "psf - Sum: %f +/- %f\n", options->ApResid, options->ApSysErr);
     199
     200    psFree (Ap);
     201    psFree (ApErr);
     202    psFree (stats);
     203    psFree (dAp);
     204
     205    return true;
     206}
     207
     208// classify sources based on the combination of psf-mag, Mxx, Myy
     209bool psphotSourceClass (pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options) {
     210
     211    bool status;
     212    pmPSFClump psfClump;
     213    char regionName[64];
     214
     215    psLogMsg("psModules.objects", PS_LOG_INFO, "Source Size classifications: %4s %4s %4s %4s %4s %4s", "Npsf", "Next", "Nsat", "Ncr", "Nmiss", "Nskip");
     216
     217    int nRegions = psMetadataLookupS32 (&status, readout->analysis, "PSF.CLUMP.NREGIONS");
     218    for (int i = 0; i < nRegions; i ++) {
     219        snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", i);
     220        psMetadata *regionMD = psMetadataLookupPtr (&status, readout->analysis, regionName);
     221        psAssert (regionMD, "regions must be defined by earlier call to psphotRoughClassRegion");
     222
     223        psRegion *region = psMetadataLookupPtr (&status, regionMD, "REGION");
     224        psAssert (region, "regions must be defined by earlier call to psphotRoughClassRegion");
     225
     226        // pull FWHM_X,Y from the recipe, use to define psfClump.X,Y
     227        psfClump.X  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");   psAssert (status, "missing PSF.CLUMP.X");
     228        psfClump.Y  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y");   psAssert (status, "missing PSF.CLUMP.Y");
     229        psfClump.dX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX");  psAssert (status, "missing PSF.CLUMP.DX");
     230        psfClump.dY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY");  psAssert (status, "missing PSF.CLUMP.DY");
     231
     232        if ((psfClump.X < 0) || (psfClump.Y < 0) || !psfClump.X || !psfClump.Y || isnan(psfClump.X) || isnan(psfClump.Y)) {
     233            psLogMsg ("psphot", 4, "Failed to find a valid PSF clump for region %f,%f - %f,%f\n", region->x0, region->y0, region->x1, region->y1);
     234            continue;
     235        }
     236
     237        if (!psphotSourceClassRegion (region, &psfClump, sources, recipe, psf, options)) {
     238            psLogMsg ("psphot", 4, "Failed to determine source classification for region %f,%f - %f,%f\n", region->x0, region->y0, region->x1, region->y1);
     239            continue;
     240        }
     241    }
     242
     243    return true;
     244}
     245
     246bool psphotSourceClassRegion (psRegion *region, pmPSFClump *psfClump, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options) {
     247
     248    PS_ASSERT_PTR_NON_NULL(sources, false);
     249    PS_ASSERT_PTR_NON_NULL(recipe, false);
     250
     251    int Nsat  = 0;
     252    int Next  = 0;
     253    int Npsf  = 0;
     254    int Ncr   = 0;
     255    int Nmiss = 0;
     256    int Nskip = 0;
     257
     258    pmSourceMode noMoments = PM_SOURCE_MODE_MOMENTS_FAILURE | PM_SOURCE_MODE_SKYVAR_FAILURE | PM_SOURCE_MODE_SKY_FAILURE | PM_SOURCE_MODE_BELOW_MOMENTS_SN;
     259    pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_WEIGHT;
     260
     261    psImageMaskType maskVal = options->maskVal | options->markVal;
     262
     263    for (psS32 i = 0 ; i < sources->n ; i++) {
     264
     265        pmSource *source = (pmSource *) sources->data[i];
     266
     267        // psfClumps are found for image subregions:
     268        // skip sources not in this region
     269        if (source->peak->x <  region->x0) continue;
     270        if (source->peak->x >= region->x1) continue;
     271        if (source->peak->y <  region->y0) continue;
     272        if (source->peak->y >= region->y1) continue;
     273
     274        // skip source if it was already measured
     275        if (source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED) {
     276            psTrace("psphot", 7, "Not calculating source size since it has already been measured\n");
     277            continue;
     278        }
     279
     280        // source must have been subtracted
     281        if (!(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED)) {
     282            source->mode |= PM_SOURCE_MODE_SIZE_SKIPPED;
     283            psTrace("psphot", 7, "Not calculating source size since source is not subtracted\n");
     284            continue;
     285        }
     286
     287        // we are basically classifying by moments; use the default if not found
     288        psAssert (source->moments, "why is this source missing moments?");
     289        if (source->mode & noMoments) {
     290            Nskip ++;
     291            continue;
     292        }
     293
     294        psF32 Mxx = source->moments->Mxx;
     295        psF32 Myy = source->moments->Myy;
     296
     297        // replace object in image
     298        if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
     299            pmSourceAdd (source, PM_MODEL_OP_FULL, options->maskVal);
     300        }
     301
     302        // clear the mask bit and set the circular mask pixels
     303        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));
     304        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", options->markVal);
     305
     306        // XXX can we test if psfMag is set and calculate only if needed?
     307        pmSourceMagnitudes (source, psf, photMode, maskVal); // maskVal includes markVal
     308
     309        // clear the mask bit
     310        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));
     311
     312        // re-subtract the object, leave local sky
     313        pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal);
     314
     315        float apMag = -2.5*log10(source->moments->Sum);
     316        float dMag = source->psfMag - apMag;
     317        float nSigma = (dMag - options->ApResid) / hypot(source->errMag, options->ApSysErr);
     318
     319        source->extNsigma = nSigma;
     320        source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;
     321
     322        // Anything within this region is a probably PSF-like object. Saturated stars may land
     323        // in this region, but are detected elsewhere on the basis of their peak value.
     324        bool isPSF = ((fabs(nSigma) < options->nSigmaApResid) &&
     325                      (fabs(Mxx - psfClump->X) < options->nSigmaMoments*psfClump->dX) &&
     326                      (fabs(Myy - psfClump->Y) < options->nSigmaMoments*psfClump->dY));
     327        if (isPSF) {
     328          psTrace("psphot.czw",4,"CLASS: %g %g\t%g %g  %g %g  %g %g\t%g %g\t%g PSF\t%g %g\n",
     329                  source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigma,
     330                  options->nSigmaApResid,options->nSigmaMoments);
     331          Npsf ++;
     332          continue;
     333        }
     334
     335        // Defects may not always match CRs from peak curvature analysis
     336        // Defects may also be marked as SATSTAR -- XXX deactivate this flag?
     337        // XXX this rule is not great
     338        if ((Mxx < psfClump->X) || (Myy < psfClump->Y)) {
     339
     340          psTrace("psphot.czw",4,"CLASS: %g %g\t%g %g  %g %g  %g %g\t%g %g\t%g CR\t%g %g\n",
     341                  source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigma,
     342                  options->nSigmaApResid,options->nSigmaMoments);
     343            source->mode |= PM_SOURCE_MODE_DEFECT;
     344            Ncr ++;
     345            continue;
     346        }
     347
     348        // saturated star (determined in PSF fit).  These may also be saturated galaxies, or
     349        // just large saturated regions.
     350        if (source->mode & PM_SOURCE_MODE_SATSTAR) {
     351          psTrace("psphot.czw",4,"CLASS: %g %g\t%g %g  %g %g  %g %g\t%g %g\t%g SAT\t%g %g\n",
     352                  source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigma,
     353                  options->nSigmaApResid,options->nSigmaMoments);
     354         
     355            Nsat ++;
     356            continue;
     357        }
     358
     359        // XXX allow the Mxx, Myy to be less than psfClump->X,Y (by some nSigma)?
     360        bool isEXT = (nSigma > options->nSigmaApResid) || ((Mxx > psfClump->X) && (Myy > psfClump->Y));
     361        if (isEXT) {
     362          psTrace("psphot.czw",4,"CLASS: %g %g\t%g %g  %g %g  %g %g\t%g %g\t%g Ext\t%g %g\n",
     363                  source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigma,
     364                  options->nSigmaApResid,options->nSigmaMoments);
     365         
     366            source->mode |= PM_SOURCE_MODE_EXT_LIMIT;
     367            Next ++;
     368            continue;
     369        }
     370        psTrace("psphot.czw",4,"CLASS: %g %g\t%g %g  %g %g  %g %g\t%g %g\t%g Unk\t%g %g\n",
     371                source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigma,
     372                options->nSigmaApResid,options->nSigmaMoments);
     373       
     374        psWarning ("sourse size was missed for %f,%f : %f %f -- %f\n", source->peak->xf, source->peak->yf, Mxx, Myy, nSigma);
     375        Nmiss ++;
     376    }
     377
     378    psLogMsg("psModules.objects", PS_LOG_INFO, "Source Size classifications: %4d %4d %4d %4d %4d %4d", Npsf, Next, Nsat, Ncr, Nmiss, Nskip);
     379
     380    return true;
     381}
     382
     383// given an object suspected to be a defect, generate a pixel mask using the Lapacian transform
     384// if enough of the object is detected as 'sharp', consider the object a cosmic ray
     385bool psphotSourceSizeCR (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options) {
     386
     387    for (int i = 0; i < sources->n; i++) {
     388        pmSource *source = sources->data[i];
     389
     390        // skip source if it was already measured
     391        if (source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED) {
     392            psTrace("psphot", 7, "Not calculating source size since it has already been measured\n");
     393            continue;
     394        }
     395
     396        // Integer position of peak
     397        int xPeak = source->peak->xf - source->pixels->col0 + 0.5;
     398        int yPeak = source->peak->yf - source->pixels->row0 + 0.5;
     399
     400        // Skip sources which are too close to a boundary.  These are mostly caught as DEFECT
     401        if (xPeak < 1 || xPeak > source->pixels->numCols - 2 ||
     402            yPeak < 1 || yPeak > source->pixels->numRows - 2) {
     403            psTrace("psphot", 7, "Not calculating crNsigma due to edge\n");
     404            //      psTrace("psphot.czw", 2, "Not calculating crNsigma due to edge\n");
     405            continue;
     406        }
     407       
     408        // this source is thought to be a cosmic ray.  flag the detection and mask the pixels
     409        if (source->mode & PM_SOURCE_MODE_DEFECT) {
     410            // XXX this is running slowly and is too agressive, but it more-or-less works
     411            // psphotMaskCosmicRayCZW(readout, source, options->crMask);
     412           
     413            // XXX these are the old versions which we are not using
     414            // psphotMaskCosmicRay (readout->mask, source, maskVal, crMask);
     415            // psphotMaskCosmicRay_Old (source, maskVal, crMask);
     416        }
     417    }
     418   
     419    // now that we have masked pixels associated with CRs, we can grow the mask
     420    if (options->grow > 0) {
     421        bool oldThreads = psImageConvolveSetThreads(true); // Old value of threading for psImageConvolveMask
     422        psImage *newMask = psImageConvolveMask(NULL, readout->mask, options->crMask, options->crMask, -options->grow, options->grow, -options->grow, options->grow);
     423        psImageConvolveSetThreads(oldThreads);
     424        if (!newMask) {
     425            psError(PS_ERR_UNKNOWN, false, "Unable to grow CR mask");
     426            return false;
     427        }
     428        psFree(readout->mask);
     429        readout->mask = newMask;
     430    }
     431
     432    // XXX test : save the mask image
     433    if (0) {
     434        psphotSaveImage (NULL, readout->mask,   "mask.fits");
     435    }
     436    return true;
     437}
     438
     439// Comments by CZW 20091209 : Mechanics of how to identify CR pixels taken from "Cosmic-Ray
     440// Rejection by Laplacian Edge Detection" by Pieter van Dokkum, arXiv:astro-ph/0108003.  This
     441// does no repair or recovery of the CR pixels, it only masks them out.  My test code can be
     442// found at /data/ipp031.0/watersc1/psphot.20091209/algo_check.c
     443bool psphotMaskCosmicRay (pmReadout *readout, pmSource *source, psImageMaskType maskVal) {
     444
     445    // Get the actual images and information about the peak.
     446    psImage *mask = readout->mask;
     447    pmPeak *peak = source->peak;
     448    pmFootprint *footprint = peak->footprint;
     449
     450    int xm = footprint->bbox.x0;
     451    int xM = footprint->bbox.x1;
     452    int ym = footprint->bbox.y0;
     453    int yM = footprint->bbox.y1;
     454
     455    if (xm < 0) { xm = 0; }
     456    if (ym < 0) { ym = 0; }
     457    if (xM > mask->numCols) { xM = mask->numCols; }
     458    if (yM > mask->numRows) { yM = mask->numRows; }
     459    int dx = xM - xm;
     460    int dy = yM - ym;
     461
     462    // Bounding boxes are inclusive of final pixel
     463    // XXX ensure dx,dy do not become too large here
     464    dx++;
     465    dy++;
     466
     467    psImage *image= readout->image;
     468    psImage *variance = readout->variance;
     469     
     470    int binning = 1;
     471    float sigma_thresh = 2.0;
     472    int iteration = 0;
     473    int max_iter = 5;
     474    float noise_factor = 5.0 / 4.0;  // Intrinsic to the Laplacian making noise spikes spikier.
     475
     476    // Temporary images.
     477    psImage *mypix  = psImageAlloc(dx,dy,image->type.type);
     478    psImage *myvar  = psImageAlloc(dx,dy,image->type.type);
     479    psImage *binned = psImageAlloc(dx * binning,dy * binning,image->type.type);
     480    psImage *conved = psImageAlloc(dx * binning,dy * binning,image->type.type);
     481    psImage *edges  = psImageAlloc(dx,dy,image->type.type);
     482    psImage *mymask = psImageAlloc(dx,dy,PS_TYPE_IMAGE_MASK);
     483     
     484    int x,y;
     485    // Load my copy of things.
     486    for (x = 0; x < dx; x++) {
     487        for (y = 0; y < dy; y++) {
     488            psImageSet(mypix,x,y,psImageGet(image,x+xm,y+ym));
     489            psImageSet(myvar,x,y,psImageGet(variance,x+xm,y+ym));
     490            mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = 0x00;
     491        }
     492    }
     493    // Mask so I can see on the output image where the footprint is.
     494    for (int i = 0; i < footprint->spans->n; i++) {
     495        pmSpan *sp = footprint->spans->data[i];
     496        for (int j = sp->x0; j <= sp->x1; j++) {
     497            y = sp->y - ym;
     498            x = j - xm;
     499            mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] |= 0x01;
     500        }
     501    }
     502
     503    int CRpix_count = 0;     
     504    do {
     505        CRpix_count = 0;
     506        // Zero out my temp images.
     507        for (x = 0; x < binning * dx; x++) {
     508            for (y = 0; y < binning * dy; y++) {
     509                psImageSet(binned,x,y,0.0);
     510                psImageSet(conved,x,y,0.0);
     511                psImageSet(edges,x/binning,y/ binning,0.0);
     512            }
     513        }     
     514        // Make subsampled image. Maybe this should be called "unbinned" or something
     515        for (x = 0; x < binning * dx; x++) {
     516            for (y = 0; y < binning * dy; y++) {
     517                psImageSet(binned,x,y,psImageGet(mypix,x / binning,y / binning));
     518            }
     519        }
     520        // Apply Laplace transform (kernel = [[0 -0.25 0][-0.25 1 -0.25][0 -0.25 0]]), clipping at zero
     521        for (x = 1; x < dx - 1; x++) {
     522            for (y = 1; y < dy - 1; y++) {
     523                psImageSet(conved,x,y,psImageGet(binned,x,y) - 0.25 *
     524                           (psImageGet(binned,x-1,y) + psImageGet(binned,x+1,y) +
     525                            psImageGet(binned,x,y-1) + psImageGet(binned,x,y+1)));
     526                if (psImageGet(conved,x,y) < 0.0) {
     527                    psImageSet(conved,x,y,0.0);
     528                }
     529            }
     530        }
     531        // Create an edge map by rebinning
     532        for (x = 0; x < binning * dx; x++) {
     533            for (y = 0; y < binning * dy; y++) {
     534                psImageSet(edges,x / binning, y / binning,
     535                           psImageGet(edges, x / binning, y / binning) +
     536                           psImageGet(conved,x,y));
     537            }
     538        }
     539        // Modify my mask if we're above the significance threshold
     540        for (x = 0; x < dx; x++) {
     541            for (y = 0; y < dy; y++) {
     542                if ( psImageGet(edges,x,y) / (binning * sqrt(noise_factor * psImageGet(myvar,x,y))) > sigma_thresh ) {
     543                    if (mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & 0x01) {
     544                        mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] |= 0x40;
     545                        CRpix_count++;
     546                    }
     547                }
     548            }
     549        }
     550
     551        // "Repair" Masked pixels for the next round.
     552        for (x = 1; x < dx - 1; x++) {
     553            for (y = 1; y < dy - 1; y++) {
     554                if (mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & 0x40) {
     555                    psImageSet(mypix,x,y,0.25 *
     556                               (psImageGet(mypix,x-1,y) + psImageGet(mypix,x+1,y) +
     557                                psImageGet(mypix,x,y-1) + psImageGet(mypix,x,y+1)));
     558                }
     559            }
     560        }
     561       
     562# if 0
     563        if ((psTraceGetLevel("psphot.czw") >= 2)&&(abs(xm - 2770) < 5)&&(abs(ym - 2581) < 5)&&(iteration == 0)) {
     564          psTrace("psphot.czw",2,"TRACEMOTRON %d %d %d %d %d\n",xm,ym,dx,dy,iteration);
     565          psphotSaveImage (NULL, mypix,   "czw.pix.fits");
     566          psphotSaveImage (NULL, myvar,   "czw.var.fits");
     567          psphotSaveImage (NULL, binned,  "czw.binn.fits");
     568          psphotSaveImage (NULL, conved,  "czw.conv.fits");
     569          psphotSaveImage (NULL, edges,   "czw.edge.fits");
     570          psphotSaveImage (NULL, mymask,  "czw.mask.fits");
     571        }
     572# endif
     573
     574        psTrace("psphot.czw",2,"Iter: %d Count: %d",iteration,CRpix_count);
     575        iteration++;
     576    } while ((iteration < max_iter)&&(CRpix_count > 0));
     577
     578    // A solitary masked pixel is likely a lie. Remove those.
     579    for (x = 0; x < dx; x++) {
     580        for (y = 0; y < dy; y++) {
     581            if (mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & 0x40) {
     582                if ((x-1 >= 0)&&(mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x-1] & 0x40)) {
     583                    continue;
     584                }
     585                if ((y-1 >= 0)&&(mymask->data.PS_TYPE_IMAGE_MASK_DATA[y-1][x] & 0x40)) {
     586                    continue;
     587                }
     588                if ((x+1 < dx)&&(mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x+1] & 0x40)) {
     589                    continue;
     590                }
     591                if ((y+1 < dy)&&(mymask->data.PS_TYPE_IMAGE_MASK_DATA[y+1][x] & 0x40)) {
     592                    continue;
     593                }
     594                mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] ^= 0x40;
     595            }
     596        }
     597    }
     598
     599    // transfer temporary mask to real mask
     600    for (x = 0; x < dx; x++) {
     601        for (y = 0; y < dy; y++) {
     602            if (mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & 0x40) {
     603                mask->data.PS_TYPE_IMAGE_MASK_DATA[y+ym+mask->row0][x+xm+mask->col0] |= maskVal;
     604            }
     605        }
     606    }
     607     
     608    // XXX if we decide this REALLY is a cosmic ray, set the CR_LIMIT bit
     609    source->mode |= PM_SOURCE_MODE_CR_LIMIT;
     610
     611    psFree(mypix);
     612    psFree(myvar);
     613    psFree(binned);
     614    psFree(conved);
     615    psFree(edges);
     616    psFree(mymask);
     617     
     618    return true;
     619}
     620
     621bool psphotMaskCosmicRayFootprintCheck (psArray *sources) {
     622
     623    for (int i = 0; i < sources->n; i++) {
     624        pmSource *source = sources->data[i];
     625        pmPeak *peak = source->peak;
     626        pmFootprint *footprint = peak->footprint;
     627        if (!footprint) continue;
     628        for (int j = 0; j < footprint->spans->n; j++) {
     629            pmSpan *sp = footprint->spans->data[j];
     630            psAssert (sp, "missing span");
     631        }
     632    }
     633    return true;
     634}
     635
     636/**** ------ old versions of cosmic ray masking ----- ****/
     637
     638bool psphotMaskCosmicRayIsophot (pmSource *source, psImageMaskType maskVal, psImageMaskType crMask);
     639
     640// This attempt to mask the cosmic rays used the isophotal boundary
     641bool psphotMaskCosmicRay_V1 (psImage *mask, pmSource *source, psImageMaskType maskVal, psImageMaskType crMask) {
    93642
    94643    // replace the source flux
     
    103652    pmFootprint *footprint = peak->footprint;
    104653    if (!footprint) {
     654      psTrace("psphot.czw",2,"Using isophot CR mask code.");
     655     
    105656        // if we have not footprint, use the old code to mask by isophot
    106657        psphotMaskCosmicRayIsophot (source, maskVal, crMask);
     
    109660
    110661    if (!footprint->spans) {
     662      psTrace("psphot.czw",2,"Using isophot CR mask code.");
     663     
    111664        // if we have no footprint, use the old code to mask by isophot
    112665        psphotMaskCosmicRayIsophot (source, maskVal, crMask);
    113666        return true;
    114667    }
    115 
     668    psphotMaskCosmicRayIsophot (source, maskVal, crMask);
    116669    // mask all of the pixels covered by the spans of the footprint
    117     for (int j = 1; j < footprint->spans->n; j++) {
    118         pmSpan *span1 = footprint->spans->data[j];
    119 
    120         int iy = span1->y;
    121         int xs = span1->x0;
    122         int xe = span1->x1;
    123 
    124         for (int ix = xs; ix < xe; ix++) {
    125             mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= crMask;
    126         }
    127     }
     670    for (int j = 1; j < footprint->spans->n; j++) { 
     671        pmSpan *span1 = footprint->spans->data[j];
     672
     673        int iy = span1->y;
     674        int xs = span1->x0;
     675        int xe = span1->x1;
     676
     677        for (int ix = xs; ix < xe; ix++) {
     678            mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= crMask;
     679        }
     680    } 
    128681    return true;
    129682}
     
    192745        }
    193746    }
    194     return true;
    195 }
    196 
    197 // model the apmifit distribution for the psf stars:
    198 bool psphotSourceSizePSF (psphotSourceSizeOptions *options, psArray *sources, pmPSF *psf) {
    199 
    200     // select stats from the psf stars
    201     psVector *Ap = psVectorAllocEmpty (100, PS_TYPE_F32);
    202     psVector *ApErr = psVectorAllocEmpty (100, PS_TYPE_F32);
    203 
    204     psImageMaskType maskVal = options->maskVal | options->markVal;
    205 
    206     // XXX  why PHOT_WEIGHT??
    207     pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_WEIGHT;
    208 
    209     for (int i = 0; i < sources->n; i++) {
    210         pmSource *source = sources->data[i];
    211         if (!(source->mode & PM_SOURCE_MODE_PSFSTAR)) continue;
    212 
    213         // replace object in image
    214         if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
    215             pmSourceAdd (source, PM_MODEL_OP_FULL, options->maskVal);
    216         }
    217 
    218         // clear the mask bit and set the circular mask pixels
    219         psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));
    220         psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", options->markVal);
    221 
    222         // XXX can we test if psfMag is set and calculate only if needed?
    223         pmSourceMagnitudes (source, psf, photMode, maskVal); // maskVal includes markVal
    224 
    225         // clear the mask bit
    226         psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));
    227 
    228         // re-subtract the object, leave local sky
    229         pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal);
    230 
    231         float apMag = -2.5*log10(source->moments->Sum);
    232         float dMag = source->psfMag - apMag;
    233 
    234         psVectorAppend (Ap, dMag);
    235         psVectorAppend (ApErr, source->errMag);
    236     }
    237 
    238     // model the distribution as a mean or median value and a systematic error from that value:
    239     psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN);
    240     psVectorStats (stats, Ap, NULL, NULL, 0);
    241 
    242     psVector *dAp = psVectorAlloc (Ap->n, PS_TYPE_F32);
    243     for (int i = 0; i < Ap->n; i++) {
    244         dAp->data.F32[i] = Ap->data.F32[i] - stats->robustMedian;
    245     }
    246 
    247     options->ApResid = stats->robustMedian;
    248     options->ApSysErr = psVectorSystematicError(dAp, ApErr, 0.05);
    249     // XXX this is quite arbitrary...
    250     if (!isfinite(options->ApSysErr)) options->ApSysErr = 0.01;
    251     psLogMsg ("psphot", PS_LOG_DETAIL, "psf - Sum: %f +/- %f\n", options->ApResid, options->ApSysErr);
    252 
    253     psFree (Ap);
    254     psFree (ApErr);
    255     psFree (stats);
    256     psFree (dAp);
    257 
    258     return true;
    259 }
    260 
    261 // classify sources based on the combination of psf-mag, Mxx, Myy
    262 bool psphotSourceClass (pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options) {
    263 
    264     bool status;
    265     pmPSFClump psfClump;
    266     char regionName[64];
    267 
    268     psLogMsg("psModules.objects", PS_LOG_INFO, "Source Size classifications: %4s %4s %4s %4s %4s %4s", "Npsf", "Next", "Nsat", "Ncr", "Nmiss", "Nskip");
    269 
    270     int nRegions = psMetadataLookupS32 (&status, readout->analysis, "PSF.CLUMP.NREGIONS");
    271     for (int i = 0; i < nRegions; i ++) {
    272         snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", i);
    273         psMetadata *regionMD = psMetadataLookupPtr (&status, readout->analysis, regionName);
    274         psAssert (regionMD, "regions must be defined by earlier call to psphotRoughClassRegion");
    275 
    276         psRegion *region = psMetadataLookupPtr (&status, regionMD, "REGION");
    277         psAssert (region, "regions must be defined by earlier call to psphotRoughClassRegion");
    278 
    279         // pull FWHM_X,Y from the recipe, use to define psfClump.X,Y
    280         psfClump.X  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");   psAssert (status, "missing PSF.CLUMP.X");
    281         psfClump.Y  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y");   psAssert (status, "missing PSF.CLUMP.Y");
    282         psfClump.dX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX");  psAssert (status, "missing PSF.CLUMP.DX");
    283         psfClump.dY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY");  psAssert (status, "missing PSF.CLUMP.DY");
    284 
    285         if ((psfClump.X < 0) || (psfClump.Y < 0) || !psfClump.X || !psfClump.Y || isnan(psfClump.X) || isnan(psfClump.Y)) {
    286             psLogMsg ("psphot", 4, "Failed to find a valid PSF clump for region %f,%f - %f,%f\n", region->x0, region->y0, region->x1, region->y1);
    287             continue;
    288         }
    289 
    290         if (!psphotSourceClassRegion (region, &psfClump, sources, recipe, psf, options)) {
    291             psLogMsg ("psphot", 4, "Failed to determine source classification for region %f,%f - %f,%f\n", region->x0, region->y0, region->x1, region->y1);
    292             continue;
    293         }
    294     }
    295 
    296     return true;
    297 }
    298 
    299 bool psphotSourceClassRegion (psRegion *region, pmPSFClump *psfClump, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options) {
    300 
    301     PS_ASSERT_PTR_NON_NULL(sources, false);
    302     PS_ASSERT_PTR_NON_NULL(recipe, false);
    303 
    304     int Nsat  = 0;
    305     int Next  = 0;
    306     int Npsf  = 0;
    307     int Ncr   = 0;
    308     int Nmiss = 0;
    309     int Nskip = 0;
    310 
    311     pmSourceMode noMoments = PM_SOURCE_MODE_MOMENTS_FAILURE | PM_SOURCE_MODE_SKYVAR_FAILURE | PM_SOURCE_MODE_SKY_FAILURE | PM_SOURCE_MODE_BELOW_MOMENTS_SN;
    312     pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_WEIGHT;
    313 
    314     psImageMaskType maskVal = options->maskVal | options->markVal;
    315 
    316     for (psS32 i = 0 ; i < sources->n ; i++) {
    317 
    318         pmSource *source = (pmSource *) sources->data[i];
    319 
    320         // psfClumps are found for image subregions:
    321         // skip sources not in this region
    322         if (source->peak->x <  region->x0) continue;
    323         if (source->peak->x >= region->x1) continue;
    324         if (source->peak->y <  region->y0) continue;
    325         if (source->peak->y >= region->y1) continue;
    326 
    327         // skip source if it was already measured
    328         if (source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED) {
    329             psTrace("psphot", 7, "Not calculating source size since it has already been measured\n");
    330             continue;
    331         }
    332 
    333         // source must have been subtracted
    334         if (!(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED)) {
    335             source->mode |= PM_SOURCE_MODE_SIZE_SKIPPED;
    336             psTrace("psphot", 7, "Not calculating source size since source is not subtracted\n");
    337             continue;
    338         }
    339 
    340         // we are basically classifying by moments; use the default if not found
    341         psAssert (source->moments, "why is this source missing moments?");
    342         if (source->mode & noMoments) {
    343             Nskip ++;
    344             continue;
    345         }
    346 
    347         psF32 Mxx = source->moments->Mxx;
    348         psF32 Myy = source->moments->Myy;
    349 
    350         // replace object in image
    351         if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
    352             pmSourceAdd (source, PM_MODEL_OP_FULL, options->maskVal);
    353         }
    354 
    355         // clear the mask bit and set the circular mask pixels
    356         psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));
    357         psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", options->markVal);
    358 
    359         // XXX can we test if psfMag is set and calculate only if needed?
    360         pmSourceMagnitudes (source, psf, photMode, maskVal); // maskVal includes markVal
    361 
    362         // clear the mask bit
    363         psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));
    364 
    365         // re-subtract the object, leave local sky
    366         pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal);
    367 
    368         float apMag = -2.5*log10(source->moments->Sum);
    369         float dMag = source->psfMag - apMag;
    370         float nSigma = (dMag - options->ApResid) / hypot(source->errMag, options->ApSysErr);
    371 
    372         source->extNsigma = nSigma;
    373         source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;
    374 
    375         // Anything within this region is a probably PSF-like object. Saturated stars may land
    376         // in this region, but are detected elsewhere on the basis of their peak value.
    377         bool isPSF = (fabs(nSigma) < options->nSigmaApResid) && (fabs(Mxx - psfClump->X) < options->nSigmaMoments*psfClump->dX) && (fabs(Myy - psfClump->Y) < options->nSigmaMoments*psfClump->dY);
    378         if (isPSF) {
    379             Npsf ++;
    380             continue;
    381         }
    382 
    383         // Defects may not always match CRs from peak curvature analysis
    384         // Defects may also be marked as SATSTAR -- XXX deactivate this flag?
    385         // XXX this rule is not great
    386         if ((Mxx < psfClump->X) || (Myy < psfClump->Y)) {
    387             source->mode |= PM_SOURCE_MODE_DEFECT;
    388             Ncr ++;
    389             continue;
    390         }
    391 
    392         // saturated star (determined in PSF fit).  These may also be saturated galaxies, or
    393         // just large saturated regions.
    394         if (source->mode & PM_SOURCE_MODE_SATSTAR) {
    395             Nsat ++;
    396             continue;
    397         }
    398 
    399         // XXX allow the Mxx, Myy to be less than psfClump->X,Y (by some nSigma)?
    400         bool isEXT = (nSigma > options->nSigmaApResid) || ((Mxx > psfClump->X) && (Myy > psfClump->Y));
    401         if (isEXT) {
    402             source->mode |= PM_SOURCE_MODE_EXT_LIMIT;
    403             Next ++;
    404             continue;
    405         }
    406 
    407         psWarning ("sourse size was missed for %f,%f : %f %f -- %f\n", source->peak->xf, source->peak->yf, Mxx, Myy, nSigma);
    408         Nmiss ++;
    409     }
    410 
    411     psLogMsg("psModules.objects", PS_LOG_INFO, "Source Size classifications: %4d %4d %4d %4d %4d %4d", Npsf, Next, Nsat, Ncr, Nmiss, Nskip);
    412 
    413747    return true;
    414748}
     
    488822}
    489823
    490 bool psphotSourceSizeCR (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options) {
     824// this was an old attempt to identify cosmic rays based on the peak curvature
     825bool psphotSourcePeakCurvature (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options) {
    491826
    492827    // classify the sources based on the CR test (place this in a function?)
     
    620955    return true;
    621956}
     957
  • trunk/psphot/src/psphotSourceStats.c

    r25988 r26894  
    11# include "psphotInternal.h"
    22
    3 bool psphotSetMomentsWindow (psMetadata *recipe, psMetadata *analysis, psArray *sources);
    4 
    5 psArray *psphotSourceStats (pmConfig *config, pmReadout *readout, pmDetections *detections, bool setWindow) {
     3// convert detections to sources and measure their basic properties (moments, local sky, sky
     4// variance) Note: this function only generates sources for the new peaks (peak->assigned)
     5bool psphotSourceStats (pmConfig *config, const pmFPAview *view, bool setWindow)
     6{
     7    bool status = true;
     8
     9    // select the appropriate recipe information
     10    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     11    psAssert (recipe, "missing recipe?");
     12
     13    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     14    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     15
     16    // loop over the available readouts
     17    for (int i = 0; i < num; i++) {
     18        if (!psphotSourceStatsReadout (config, view, "PSPHOT.INPUT", i, recipe, setWindow)) {
     19            psError (PSPHOT_ERR_CONFIG, false, "failed to find initial detections for PSPHOT.INPUT entry %d", i);
     20            return false;
     21        }
     22    }
     23    return true;
     24}
     25
     26bool psphotSourceStatsReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe, bool setWindow) {
    627
    728    bool status = false;
     
    1031    psTimerStart ("psphot.stats");
    1132
    12     // select the appropriate recipe information
    13     psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
    14     assert (recipe);
     33    // find the currently selected readout
     34    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     35    psAssert (file, "missing file?");
     36
     37    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     38    psAssert (readout, "missing readout?");
     39
     40    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     41    psAssert (detections, "missing detections?");
     42    psAssert (!detections->newSources, "new sources already defined?");
     43
     44    // XXX TEST:
     45    if (detections->allSources) {
     46        psphotMaskCosmicRayFootprintCheck(detections->allSources);
     47    }
     48    if (detections->newSources) {
     49        psphotMaskCosmicRayFootprintCheck(detections->newSources);
     50    }
    1551
    1652    // determine the number of allowed threads
     
    2157
    2258    // determine properties (sky, moments) of initial sources
    23     float OUTER    = psMetadataLookupF32 (&status, recipe, "SKY_OUTER_RADIUS");
    24     if (!status) return NULL;
    25 
     59    float OUTER = psMetadataLookupF32 (&status, recipe, "SKY_OUTER_RADIUS");
     60    psAssert (status, "missing SKY_OUTER_RADIUS in recipe?");
     61
     62    // XXX this seems like an arbitrary number...
    2663    OUTER = PS_MAX(OUTER, 20.0); // XXX Guarantee that we can encompass the max moments radius
    2764
    2865    char *breakPt  = psMetadataLookupStr (&status, recipe, "BREAK_POINT");
    29     if (!status) return NULL;
     66    psAssert (status, "missing BREAK_POINT?");
     67
     68    float INNER        = psMetadataLookupF32 (&status, recipe, "SKY_INNER_RADIUS"); psAssert (status, "missing SKY_INNER_RADIUS");
     69    float MIN_SN       = psMetadataLookupF32 (&status, recipe, "MOMENTS_SN_MIN"); psAssert (status, "missing MOMENTS_SN_MIN");
     70
     71    // bit-masks to test for good/bad pixels
     72    psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT");
     73    psAssert (maskVal, "missing MASK.PSPHOT");
     74
     75    // bit-mask to mark pixels not used in analysis
     76    psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT");
     77    psAssert (markVal, "missing MARK.PSPHOT");
    3078
    3179    psArray *peaks = detections->peaks;
    3280    if (!peaks) {
    3381        psError(PS_ERR_UNEXPECTED_NULL, false, "No peaks found!");
    34         return NULL;
     82        return false;
    3583    }
    3684
    3785    // generate the array of sources, define the associated pixel
    3886    sources = psArrayAllocEmpty (peaks->n);
     87
     88    // if there are no peaks, we save the empty source array and return
     89    if (!peaks->n) {
     90        // save the new sources on the detection structure:
     91        detections->newSources = sources;
     92        return true;
     93    }
    3994
    4095    for (int i = 0; i < peaks->n; i++) {
     
    58113        psArrayAdd (sources, 100, source);
    59114        psFree (source);
     115    }
     116
     117    if (!strcasecmp (breakPt, "PEAKS")) {
     118        psLogMsg ("psphot", PS_LOG_INFO, "%ld sources : %f sec\n", sources->n, psTimerMark ("psphot.stats"));
     119        psLogMsg ("psphot", PS_LOG_INFO, "break point PEAKS, skipping MOMENTS\n");
     120        psphotVisualShowMoments (sources);
     121        detections->newSources = sources;
     122        return true;
     123    }
     124
     125    if (setWindow) {
     126        if (!psphotSetMomentsWindow(recipe, readout->analysis, sources)) {
     127            psError(PS_ERR_UNEXPECTED_NULL, false, "Failed to determine Moments Window!");
     128            psFree(sources);
     129            return false;
     130        }
     131    }
     132
     133    // if we have measured the window, we will be saving the modified version of these recipe values on readout->analysis
     134    float SIGMA = psMetadataLookupF32 (&status, readout->analysis, "MOMENTS_GAUSS_SIGMA");
     135    if (!status) {
     136        SIGMA = psMetadataLookupF32 (&status, recipe, "MOMENTS_GAUSS_SIGMA");
     137    }
     138    float RADIUS = psMetadataLookupF32 (&status, readout->analysis, "PSF_MOMENTS_RADIUS");
     139    if (!status) {
     140        RADIUS = psMetadataLookupF32 (&status, recipe, "PSF_MOMENTS_RADIUS");
     141    }
     142
     143    // threaded measurement of the source magnitudes
     144    int Nfail = 0;
     145    int Nmoments = 0;
     146    int Nfaint = 0;
     147
     148    // choose Cx, Cy (see psphotThreadTools.c for overview of the concepts)
     149    int Cx = 1, Cy = 1;
     150    psphotChooseCellSizes (&Cx, &Cy, readout, nThreads);
     151
     152    psArray *cellGroups = psphotAssignSources (Cx, Cy, sources);
     153
     154    for (int i = 0; i < cellGroups->n; i++) {
     155
     156        psArray *cells = cellGroups->data[i];
     157
     158        for (int j = 0; j < cells->n; j++) {
     159
     160            // allocate a job -- if threads are not defined, this just runs the job
     161            psThreadJob *job = psThreadJobAlloc ("PSPHOT_SOURCE_STATS");
     162
     163            psArrayAdd(job->args, 1, cells->data[j]); // sources
     164
     165            PS_ARRAY_ADD_SCALAR(job->args, INNER,   PS_TYPE_F32);
     166            PS_ARRAY_ADD_SCALAR(job->args, MIN_SN,  PS_TYPE_F32);
     167            PS_ARRAY_ADD_SCALAR(job->args, RADIUS,  PS_TYPE_F32);
     168            PS_ARRAY_ADD_SCALAR(job->args, SIGMA,   PS_TYPE_F32);
     169
     170            PS_ARRAY_ADD_SCALAR(job->args, maskVal, PS_TYPE_IMAGE_MASK);
     171            PS_ARRAY_ADD_SCALAR(job->args, markVal, PS_TYPE_IMAGE_MASK);
     172
     173            PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nmoments
     174            PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nfail
     175            PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nfaint
     176
     177            if (!psThreadJobAddPending(job)) {
     178                psError(PS_ERR_UNKNOWN, false, "Unable to launch thread job PSPHOT_SOURCE_STATS");
     179                psFree (job);
     180                psFree(sources);
     181                return false;
     182            }
     183            psFree(job);
     184        }
     185
     186        // wait for the threads to finish and manage results
     187        if (!psThreadPoolWait (false)) {
     188            psError(PS_ERR_UNKNOWN, false, "Failure in thread job PSPHOT_SOURCE_STATS");
     189            psFree(sources);
     190            return false;
     191        }
     192
     193        // we have only supplied one type of job, so we can assume the types here
     194        psThreadJob *job = NULL;
     195        while ((job = psThreadJobGetDone()) != NULL) {
     196            if (job->args->n < 1) {
     197                fprintf (stderr, "error with job\n");
     198            } else {
     199                psScalar *scalar = NULL;
     200                scalar = job->args->data[7];
     201                Nmoments += scalar->data.S32;
     202                scalar = job->args->data[8];
     203                Nfail += scalar->data.S32;
     204                scalar = job->args->data[9];
     205                Nfaint += scalar->data.S32;
     206            }
     207            psFree(job);
     208        }
     209    }
     210
     211    psFree (cellGroups);
     212
     213    psLogMsg ("psphot", PS_LOG_INFO, "%ld sources, %d moments, %d faint, %d failed: %f sec\n", sources->n, Nmoments, Nfaint, Nfail, psTimerMark ("psphot.stats"));
     214
     215    psphotVisualShowMoments (sources);
     216
     217    // save the new sources on the detection structure:
     218    detections->newSources = sources;
     219
     220
     221    if (detections->allSources) {
     222        psphotMaskCosmicRayFootprintCheck(detections->allSources);
     223    }
     224    if (detections->newSources) {
     225        psphotMaskCosmicRayFootprintCheck(detections->newSources);
     226    }
     227
     228    return true;
     229}
     230
     231// this function is currently only called by psphotCheckExtSources
     232bool psphotSourceStatsUpdate (psArray *sources, pmConfig *config, pmReadout *readout) {
     233
     234    bool status = false;
     235
     236    psTimerStart ("psphot.stats");
     237
     238    // select the appropriate recipe information
     239    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     240    assert (recipe);
     241
     242    // determine the number of allowed threads
     243    int nThreads = psMetadataLookupS32(&status, config->arguments, "NTHREADS"); // Number of threads
     244    if (!status) {
     245        nThreads = 0;
     246    }
     247
     248    // determine properties (sky, moments) of initial sources
     249    float OUTER    = psMetadataLookupF32 (&status, recipe, "SKY_OUTER_RADIUS");
     250    if (!status) return false;
     251
     252    OUTER = PS_MAX(OUTER, 20.0); // XXX Guarantee that we can encompass the max moments radius
     253
     254    char *breakPt  = psMetadataLookupStr (&status, recipe, "BREAK_POINT");
     255    if (!status) return false;
     256
     257    for (int i = 0; i < sources->n; i++) {
     258
     259        pmSource *source = sources->data[i];
     260        if (!source->peak) continue; // XXX how can we have a peak-less source?
     261
     262        // allocate space for moments
     263        if (!source->moments) {
     264            source->moments = pmMomentsAlloc();
     265        }
     266
     267        // allocate image, weight, mask arrays for each peak (square of radius OUTER)
     268        pmSourceDefinePixels (source, readout, source->peak->x, source->peak->y, OUTER);
     269        source->peak->assigned = true;
    60270    }
    61271
     
    67277    }
    68278
    69     if (setWindow) {
    70         if (!psphotSetMomentsWindow(recipe, readout->analysis, sources)) {
    71             psError(PS_ERR_UNEXPECTED_NULL, false, "Failed to determine Moments Window!");
    72             return NULL;
    73         }
     279    // XXX how else could we get the window size in?
     280    if (!psphotSetMomentsWindow(recipe, readout->analysis, sources)) {
     281        psError(PS_ERR_UNEXPECTED_NULL, false, "Failed to determine Moments Window!");
     282        return NULL;
    74283    }
    75284
     
    94303            psThreadJob *job = psThreadJobAlloc ("PSPHOT_SOURCE_STATS");
    95304
     305            // XXX: this must match the above
    96306            psArrayAdd(job->args, 1, cells->data[j]); // sources
    97307            psArrayAdd(job->args, 1, recipe);
     
    141351}
    142352
    143 bool psphotSourceStatsUpdate (psArray *sources, pmConfig *config, pmReadout *readout) {
    144 
    145     bool status = false;
    146 
    147     psTimerStart ("psphot.stats");
    148 
    149     // select the appropriate recipe information
    150     psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
    151     assert (recipe);
    152 
    153     // determine the number of allowed threads
    154     int nThreads = psMetadataLookupS32(&status, config->arguments, "NTHREADS"); // Number of threads
    155     if (!status) {
    156         nThreads = 0;
    157     }
    158 
    159     // determine properties (sky, moments) of initial sources
    160     float OUTER    = psMetadataLookupF32 (&status, recipe, "SKY_OUTER_RADIUS");
    161     if (!status) return NULL;
    162 
    163     OUTER = PS_MAX(OUTER, 20.0); // XXX Guarantee that we can encompass the max moments radius
    164 
    165     char *breakPt  = psMetadataLookupStr (&status, recipe, "BREAK_POINT");
    166     if (!status) return NULL;
    167 
    168     for (int i = 0; i < sources->n; i++) {
    169 
    170         pmSource *source = sources->data[i];
    171         if (!source->peak) continue; // XXX how can we have a peak-less source?
    172 
    173         // allocate space for moments
    174         if (!source->moments) {
    175             source->moments = pmMomentsAlloc();
    176         }
    177 
    178         // allocate image, weight, mask arrays for each peak (square of radius OUTER)
    179         pmSourceDefinePixels (source, readout, source->peak->x, source->peak->y, OUTER);
    180         source->peak->assigned = true;
    181     }
    182 
    183     if (!strcasecmp (breakPt, "PEAKS")) {
    184         psLogMsg ("psphot", PS_LOG_INFO, "%ld sources : %f sec\n", sources->n, psTimerMark ("psphot.stats"));
    185         psLogMsg ("psphot", PS_LOG_INFO, "break point PEAKS, skipping MOMENTS\n");
    186         psphotVisualShowMoments (sources);
    187         return sources;
    188     }
    189 
    190     // XXX how else could we get the window size in?
    191     if (!psphotSetMomentsWindow(recipe, readout->analysis, sources)) {
    192         psError(PS_ERR_UNEXPECTED_NULL, false, "Failed to determine Moments Window!");
    193         return NULL;
    194     }
    195 
    196     // threaded measurement of the source magnitudes
    197     int Nfail = 0;
    198     int Nmoments = 0;
    199     int Nfaint = 0;
    200 
    201     // choose Cx, Cy (see psphotThreadTools.c for overview of the concepts)
    202     int Cx = 1, Cy = 1;
    203     psphotChooseCellSizes (&Cx, &Cy, readout, nThreads);
    204 
    205     psArray *cellGroups = psphotAssignSources (Cx, Cy, sources);
    206 
    207     for (int i = 0; i < cellGroups->n; i++) {
    208 
    209         psArray *cells = cellGroups->data[i];
    210 
    211         for (int j = 0; j < cells->n; j++) {
    212 
    213             // allocate a job -- if threads are not defined, this just runs the job
    214             psThreadJob *job = psThreadJobAlloc ("PSPHOT_SOURCE_STATS");
    215 
    216             psArrayAdd(job->args, 1, cells->data[j]); // sources
    217             psArrayAdd(job->args, 1, recipe);
    218             PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nmoments
    219             PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nfail
    220             PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nfaint
    221 
    222             if (!psThreadJobAddPending(job)) {
    223                 psError(PS_ERR_UNKNOWN, false, "Unable to launch thread job PSPHOT_SOURCE_STATS");
    224                 psFree (job);
    225                 return NULL;
    226             }
    227             psFree(job);
    228         }
    229 
    230         // wait for the threads to finish and manage results
    231         if (!psThreadPoolWait (false)) {
    232             psError(PS_ERR_UNKNOWN, false, "Failure in thread job PSPHOT_SOURCE_STATS");
    233             return NULL;
    234         }
    235 
    236         // we have only supplied one type of job, so we can assume the types here
    237         psThreadJob *job = NULL;
    238         while ((job = psThreadJobGetDone()) != NULL) {
    239             if (job->args->n < 1) {
    240                 fprintf (stderr, "error with job\n");
    241             } else {
    242                 psScalar *scalar = NULL;
    243                 scalar = job->args->data[2];
    244                 Nmoments += scalar->data.S32;
    245                 scalar = job->args->data[3];
    246                 Nfail += scalar->data.S32;
    247                 scalar = job->args->data[4];
    248                 Nfaint += scalar->data.S32;
    249             }
    250             psFree(job);
    251         }
    252     }
    253 
    254     psFree (cellGroups);
    255 
    256     psLogMsg ("psphot", PS_LOG_INFO, "%ld sources, %d moments, %d faint, %d failed: %f sec\n", sources->n, Nmoments, Nfaint, Nfail, psTimerMark ("psphot.stats"));
    257 
    258     psphotVisualShowMoments (sources);
    259 
    260     return (sources);
    261 }
    262 
    263353bool psphotSourceStats_Threaded (psThreadJob *job) {
    264354
     
    268358
    269359    psArray *sources                = job->args->data[0];
    270     psMetadata *recipe              = job->args->data[1];
    271 
    272     float INNER        = psMetadataLookupF32 (&status, recipe, "SKY_INNER_RADIUS");
    273     if (!status) return false;
    274     float MIN_SN       = psMetadataLookupF32 (&status, recipe, "MOMENTS_SN_MIN");
    275     if (!status) return false;
    276     float RADIUS       = psMetadataLookupF32 (&status, recipe, "PSF_MOMENTS_RADIUS");
    277     if (!status) return false;
    278     float SIGMA        = psMetadataLookupF32 (&status, recipe, "MOMENTS_GAUSS_SIGMA");
    279     if (!status) return false;
    280 
    281     // bit-masks to test for good/bad pixels
    282     psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT");
    283     assert (maskVal);
    284 
    285     // bit-mask to mark pixels not used in analysis
    286     psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT");
    287     assert (markVal);
     360
     361    float INNER                     = PS_SCALAR_VALUE(job->args->data[1],F32);
     362    float MIN_SN                    = PS_SCALAR_VALUE(job->args->data[2],F32);
     363    float RADIUS                    = PS_SCALAR_VALUE(job->args->data[3],F32);
     364    float SIGMA                     = PS_SCALAR_VALUE(job->args->data[4],F32);
     365
     366    psImageMaskType maskVal         = PS_SCALAR_VALUE(job->args->data[5],PS_TYPE_IMAGE_MASK_DATA);
     367    psImageMaskType markVal         = PS_SCALAR_VALUE(job->args->data[6],PS_TYPE_IMAGE_MASK_DATA);
    288368
    289369    // maskVal is used to test for rejected pixels, and must include markVal
     
    325405
    326406        // measure basic source moments (no S/N clipping on input pixels)
    327         status = pmSourceMoments (source, RADIUS, SIGMA, 0.0);
     407        status = pmSourceMoments (source, RADIUS, SIGMA, 0.0, maskVal);
    328408        if (status) {
    329409            Nmoments ++;
     
    335415        BIG_RADIUS = PS_MIN (INNER, 3*RADIUS);
    336416        psTrace ("psphot", 4, "retrying moments for %d, %d\n", source->peak->x, source->peak->y);
    337         status = pmSourceMoments (source, BIG_RADIUS, 3.0*SIGMA, 0.0);
     417        status = pmSourceMoments (source, BIG_RADIUS, 3.0*SIGMA, 0.0, maskVal);
    338418        if (status) {
    339419            source->mode |= PM_SOURCE_MODE_BIG_RADIUS;
     
    349429
    350430    // change the value of a scalar on the array (wrap this and put it in psArray.h)
    351     scalar = job->args->data[2];
     431    scalar = job->args->data[7];
    352432    scalar->data.S32 = Nmoments;
    353433
    354     scalar = job->args->data[3];
     434    scalar = job->args->data[8];
    355435    scalar->data.S32 = Nfail;
    356436
    357     scalar = job->args->data[4];
     437    scalar = job->args->data[9];
    358438    scalar->data.S32 = Nfaint;
    359439
     
    367447    bool status;
    368448
    369     float MIN_SN = psMetadataLookupF32 (&status, recipe, "MOMENTS_SN_MIN");
    370     if (!status) return false;
     449    float MIN_SN = psMetadataLookupF32 (&status, recipe, "MOMENTS_SN_MIN"); psAssert (status, "missing MOMENTS_SN_MIN");
     450    float PSF_SN_LIM = psMetadataLookupF32(&status, recipe, "PSF_SN_LIM"); psAssert (status, "missing PSF_SN_LIM");
     451    psF32 MOMENTS_AR_MAX = psMetadataLookupF32(&status, recipe, "MOMENTS_AR_MAX"); psAssert (status, "missing MOMENTS_AR_MAX");
    371452
    372453    // XXX move this to a config file?
     
    394475
    395476            // measure basic source moments (no S/N clipping on input pixels)
    396             status = pmSourceMoments (source, 4*sigma[i], sigma[i], 0.0);
     477            status = pmSourceMoments (source, 4*sigma[i], sigma[i], 0.0, 0xffff);
    397478        }
    398479
    399480        // choose a grid scale that is a fixed fraction of the psf sigma^2
    400         psMetadataAddF32(recipe, PS_LIST_TAIL, "PSF_CLUMP_GRID_SCALE", PS_META_REPLACE, "clump grid", 0.1*PS_SQR(sigma[i]));
    401         psMetadataAddF32(recipe, PS_LIST_TAIL, "MOMENTS_SX_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(sigma[i]));
    402         psMetadataAddF32(recipe, PS_LIST_TAIL, "MOMENTS_SY_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(sigma[i]));
     481        float PSF_CLUMP_GRID_SCALE = 0.1*PS_SQR(sigma[i]);
     482        float MOMENTS_SX_MAX = 2.0*PS_SQR(sigma[i]);
     483        float MOMENTS_SY_MAX = 2.0*PS_SQR(sigma[i]);
    403484
    404485        // determine the PSF parameters from the source moment values
    405         pmPSFClump psfClump = pmSourcePSFClump (NULL, sources, recipe);
     486        pmPSFClump psfClump = pmSourcePSFClump (NULL, NULL, sources, PSF_SN_LIM, PSF_CLUMP_GRID_SCALE, MOMENTS_SX_MAX, MOMENTS_SY_MAX, MOMENTS_AR_MAX);
    406487        psLogMsg ("psphot", 3, "radius %.1f, nStars: %d, nSigma: %5.2f, X,  Y: %f, %f (%f, %f)\n", sigma[i], psfClump.nStars, psfClump.nSigma, psfClump.X, psfClump.Y, sqrt(psfClump.X) / sigma[i], sqrt(psfClump.Y) / sigma[i]);
    407488
     
    418499        psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DY", PS_META_REPLACE, "psf clump center", psfClump.dY);
    419500
    420         // psphotVisualPlotMoments (recipe, sources);
     501        psphotVisualPlotMoments (recipe, analysis, sources);
    421502
    422503        Sout[i] = sqrt(0.5*(psfClump.X + psfClump.Y)) / sigma[i];
     
    442523
    443524    // choose a grid scale that is a fixed fraction of the psf sigma^2
    444     psMetadataAddF32(recipe, PS_LIST_TAIL, "PSF_CLUMP_GRID_SCALE", PS_META_REPLACE, "clump grid", 0.1*PS_SQR(Sigma));
    445     psMetadataAddF32(recipe, PS_LIST_TAIL, "MOMENTS_SX_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(Sigma));
    446     psMetadataAddF32(recipe, PS_LIST_TAIL, "MOMENTS_SY_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(Sigma));
    447     psMetadataAddF32(recipe, PS_LIST_TAIL, "MOMENTS_GAUSS_SIGMA", PS_META_REPLACE, "moments limit", Sigma);
    448     psMetadataAddF32(recipe, PS_LIST_TAIL, "PSF_MOMENTS_RADIUS", PS_META_REPLACE, "moments limit", 4.0*Sigma);
     525    psMetadataAddF32(analysis, PS_LIST_TAIL, "PSF_CLUMP_GRID_SCALE", PS_META_REPLACE, "clump grid", 0.1*PS_SQR(Sigma));
     526    psMetadataAddF32(analysis, PS_LIST_TAIL, "MOMENTS_SX_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(Sigma));
     527    psMetadataAddF32(analysis, PS_LIST_TAIL, "MOMENTS_SY_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(Sigma));
     528    psMetadataAddF32(analysis, PS_LIST_TAIL, "MOMENTS_GAUSS_SIGMA", PS_META_REPLACE, "moments limit", Sigma);
     529    psMetadataAddF32(analysis, PS_LIST_TAIL, "PSF_MOMENTS_RADIUS", PS_META_REPLACE, "moments limit", 4.0*Sigma);
    449530
    450531    psLogMsg ("psphot", 3, "using window function with sigma = %f\n", Sigma);
    451532    return true;
    452533}
     534
     535// if we use the footprints, the output peaks list contains both old and new peaks,
     536// otherwise it only contains the new peaks.
     537
  • trunk/psphot/src/psphotSubtractBackground.c

    r23287 r26894  
    44// generate the median in NxN boxes, clipping heavily
    55// linear interpolation to generate full-scale model
    6 bool psphotSubtractBackground (pmConfig *config, const pmFPAview *view, const char *filename)
     6bool psphotSubtractBackgroundReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe)
    77{
    88    bool status = true;
     
    1313
    1414    // find the currently selected readout
    15     pmFPAfile *file = psMetadataLookupPtr (&status, config->files, filename);
     15    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     16
    1617    pmFPA *inFPA = file->fpa;
    1718    pmReadout *readout = pmFPAviewThisReadout (view, inFPA);
     
    1920    psImage *mask  = readout->mask;
    2021
    21     // find the currently selected readout
    22     pmReadout *model = pmFPAfileThisReadout (config->files, view, "PSPHOT.BACKMDL");
     22    // find the currently selected readout (XXX note that the model is saved on PSPHOT.BACKMDL regardless of 'filename'
     23    pmFPAfile *modelFile = pmFPAfileSelectSingle(config->files, "PSPHOT.BACKMDL", index); // File of interest
     24    assert (modelFile);
     25    pmReadout *model = pmFPAviewThisReadout (view, modelFile->fpa);
    2326    assert (model);
    24 
    25     // select the appropriate recipe information
    26     psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
    27     assert (recipe);
    2827
    2928    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
     
    3534
    3635    // select background pixels, from output background file, or create
     36    // XXX for now, we will only allow a single background image to be generated
    3737    file = psMetadataLookupPtr (&status, config->files, "PSPHOT.BACKGND");
    3838    if (file) {
     
    6666
    6767    // back-sub image pixels, from output background file (don't create if not requested)
     68    // XXX for now, we will only allow a single background-subtracted image to be generated
    6869    file = psMetadataLookupPtr (&status, config->files, "PSPHOT.BACKSUB");
    6970    if (file) {
     
    109110    // the pmReadout selected in this function are all view on entries in config->files
    110111
     112    // display the backsub and backgnd images
     113    // move this inthe the subtract background loop
     114    psphotVisualShowBackground (config, view, readout);
     115
    111116    npass ++;
    112117    return true;
    113118}
     119
     120bool psphotSubtractBackground (pmConfig *config, const pmFPAview *view)
     121{
     122    bool status = false;
     123
     124    // select the appropriate recipe information
     125    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     126    psAssert (recipe, "missing recipe?");
     127
     128    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     129    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     130
     131    // loop over the available readouts
     132    for (int i = 0; i < num; i++) {
     133        if (!psphotSubtractBackgroundReadout (config, view, "PSPHOT.INPUT", i, recipe)) {
     134            psError (PSPHOT_ERR_CONFIG, false, "failed to subtract background for PSPHOT.INPUT entry %d", i);
     135            return false;
     136        }
     137    }
     138    return true;
     139}
  • trunk/psphot/src/psphotVisual.c

    r26003 r26894  
    6060}
    6161
     62bool psphotVisualEraseOverlays (int channel, char *overlay) {
     63
     64    int myKapa = psphotKapaChannel (channel);
     65    if (!(strcasecmp (overlay, "all"))) {
     66      KiiEraseOverlay (myKapa, "red");
     67      KiiEraseOverlay (myKapa, "green");
     68      KiiEraseOverlay (myKapa, "blue");
     69      KiiEraseOverlay (myKapa, "yellow");
     70      return true;
     71    }
     72    KiiEraseOverlay (myKapa, overlay);
     73    return true;
     74}
     75
    6276bool psphotVisualShowMask (int kapaFD, psImage *inImage, const char *name, int channel) {
    6377
     
    171185    if (kapa == -1) return false;
    172186
    173     // psphotVisualShowMask (kapa, readout->mask, "mask", 2);
     187    psphotVisualShowMask (kapa, readout->mask, "mask", 2);
    174188    psphotVisualScaleImage (kapa, readout->variance, readout->mask, "variance", 1);
    175189    psphotVisualScaleImage (kapa, readout->image, readout->mask, "image", 0);
     
    204218}
    205219
    206 bool psphotVisualShowSignificance (psImage *image) {
     220bool psphotVisualShowSignificance (psImage *image, float min, float max) {
    207221
    208222    if (!pmVisualIsVisual()) return true;
     
    211225    if (kapa == -1) return false;
    212226
    213     psphotVisualRangeImage (kapa, image, "signif", 2, -1.0, 25.0*25.0);
     227    psphotVisualRangeImage (kapa, image, "signif", 2, min, max);
    214228
    215229    pmVisualAskUser(NULL);
     
    247261        overlay[Noverlay].text = NULL;
    248262        Noverlay ++;
    249 
    250 # if (0)
    251         overlay[Noverlay].type = KII_OVERLAY_BOX;
    252         overlay[Noverlay].x = peak->x;
    253         overlay[Noverlay].y = peak->y;
    254         overlay[Noverlay].dx = 1.0;
    255         overlay[Noverlay].dy = 1.0;
    256         overlay[Noverlay].angle = 0.0;
    257         overlay[Noverlay].text = NULL;
    258         Noverlay ++;
    259 
    260         overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
    261         overlay[Noverlay].x = peak->xf;
    262         overlay[Noverlay].y = peak->yf;
    263         overlay[Noverlay].dx = 2.0;
    264         overlay[Noverlay].dy = 2.0;
    265         overlay[Noverlay].angle = 0.0;
    266         overlay[Noverlay].text = NULL;
    267         Noverlay ++;
    268 # endif
    269     }
    270 
    271 # if (1)
    272     overlay[Noverlay].type = KII_OVERLAY_BOX;
    273     overlay[Noverlay].x = 10.0;
    274     overlay[Noverlay].y = 10.0;
    275     overlay[Noverlay].dx = 1.0;
    276     overlay[Noverlay].dy = 1.0;
    277     overlay[Noverlay].angle = 0.0;
    278     overlay[Noverlay].text = NULL;
    279     Noverlay ++;
    280 # endif
     263    }
    281264
    282265    KiiLoadOverlay (kapa, overlay, Noverlay, "red");
     
    19051888    psFree (ySAT);
    19061889    psFree (mSAT);
     1890    psFree (sSAT);
    19071891
    19081892    psFree (xEXT);
    19091893    psFree (yEXT);
    19101894    psFree (mEXT);
     1895    psFree (sEXT);
    19111896
    19121897    psFree (xPSF);
    19131898    psFree (yPSF);
    19141899    psFree (mPSF);
     1900    psFree (sPSF);
    19151901
    19161902    psFree (xDEF);
    19171903    psFree (yDEF);
    19181904    psFree (mDEF);
     1905    psFree (sDEF);
    19191906
    19201907    psFree (xCR);
    19211908    psFree (yCR);
    19221909    psFree (mCR);
     1910    psFree (sCR);
    19231911
    19241912    pmVisualAskUser(NULL);
Note: See TracChangeset for help on using the changeset viewer.