IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
May 3, 2010, 8:50:52 AM (16 years ago)
Author:
eugene
Message:

updates from trunk

Location:
branches/simtest_nebulous_branches
Files:
62 edited
29 copied

Legend:

Unmodified
Added
Removed
  • branches/simtest_nebulous_branches

  • branches/simtest_nebulous_branches/psphot

  • branches/simtest_nebulous_branches/psphot/src

    • Property svn:ignore
      •  

        old new  
        1818psphotVersionDefinitions.h
        1919psphotMomentsStudy
         20psphotPetrosianStudy
         21psphotForced
         22psphotMakePSF
         23psphotStack
  • branches/simtest_nebulous_branches/psphot/src/Makefile.am

    r24586 r27840  
    2525libpsphot_la_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
    2626
    27 bin_PROGRAMS = psphot psphotTest psphotMomentsStudy
     27bin_PROGRAMS = psphot psphotForced psphotMakePSF psphotStack
     28# bin_PROGRAMS = psphotPetrosianStudy psphotTest psphotMomentsStudy
    2829
    2930psphot_CFLAGS = $(PSPHOT_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
     
    3132psphot_LDADD = libpsphot.la
    3233
    33 psphotTest_CFLAGS = $(PSPHOT_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
    34 psphotTest_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
    35 psphotTest_LDADD = libpsphot.la
    36 
    37 psphotMomentsStudy_CFLAGS = $(PSPHOT_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
    38 psphotMomentsStudy_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
    39 psphotMomentsStudy_LDADD = libpsphot.la
    40 
     34psphotForced_CFLAGS = $(PSPHOT_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
     35psphotForced_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
     36psphotForced_LDADD = libpsphot.la
     37
     38psphotMakePSF_CFLAGS = $(PSPHOT_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
     39psphotMakePSF_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
     40psphotMakePSF_LDADD = libpsphot.la
     41
     42psphotStack_CFLAGS = $(PSPHOT_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
     43psphotStack_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
     44psphotStack_LDADD = libpsphot.la
     45
     46# psphotMomentsStudy_CFLAGS = $(PSPHOT_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
     47# psphotMomentsStudy_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
     48# psphotMomentsStudy_LDADD = libpsphot.la
     49
     50# psphotPetrosianStudy_CFLAGS = $(PSPHOT_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
     51# psphotPetrosianStudy_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
     52# psphotPetrosianStudy_LDADD = libpsphot.la
     53
     54# psphotTest_CFLAGS = $(PSPHOT_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
     55# psphotTest_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
     56# psphotTest_LDADD = libpsphot.la
     57
     58# standard psphot for generic photometry
    4159psphot_SOURCES = \
    4260        psphot.c                \
    4361        psphotArguments.c       \
    44         psphotCleanup.c         \
     62        psphotParseCamera.c     \
    4563        psphotImageLoop.c       \
    4664        psphotMosaicChip.c      \
    47         psphotParseCamera.c
    48 
    49 psphotDetect_SOURCES =            \
    50         psphotDetect.c            \
    51         psphotDetectArguments.c   \
    52         psphotDetectParseCamera.c \
    53         psphotDetectImageLoop.c   \
    54         psphotDetectReadout.c     \
    55         psphotMosaicChip.c        \
    56         psphotCleanup.c
    57 
    58 psphotTest_SOURCES = \
    59         psphotTest.c
    60 
    61 psphotMomentsStudy_SOURCES = \
    62         psphotMomentsStudy.c
     65        psphotCleanup.c
     66
     67# forced photometry of specified positions given a specified psf
     68psphotForced_SOURCES = \
     69        psphotForced.c             \
     70        psphotForcedArguments.c    \
     71        psphotForcedImageLoop.c    \
     72        psphotForcedReadout.c      \
     73        psphotParseCamera.c        \
     74        psphotMosaicChip.c         \
     75        psphotCleanup.c
     76
     77# a psphot-variant that simply generates the PSF model
     78psphotMakePSF_SOURCES = \
     79        psphotMakePSF.c            \
     80        psphotMakePSFArguments.c   \
     81        psphotMakePSFImageLoop.c   \
     82        psphotMakePSFReadout.c     \
     83        psphotParseCamera.c        \
     84        psphotMosaicChip.c         \
     85        psphotCleanup.c
     86
     87# a psphot-variant for stack photometry
     88psphotStack_SOURCES = \
     89        psphotStack.c                 \
     90        psphotStackArguments.c        \
     91        psphotStackParseCamera.c      \
     92        psphotStackImageLoop.c        \
     93        psphotStackReadout.c          \
     94        psphotStackChisqImage.c       \
     95        psphotFitSourcesLinearStack.c \
     96        psphotSourceMatch.c           \
     97        psphotCleanup.c
     98
     99
     100
     101# # psphot analysis of the detectability of specified positions
     102# psphotDetect_SOURCES =            \
     103#         psphotDetect.c            \
     104#       psphotDetectArguments.c   \
     105#       psphotDetectParseCamera.c \
     106#       psphotDetectImageLoop.c   \
     107#       psphotDetectReadout.c     \
     108#       psphotMosaicChip.c        \
     109#       psphotCleanup.c
     110
     111# psphotTest_SOURCES = \
     112#         psphotTest.c
     113#
     114# psphotMomentsStudy_SOURCES = \
     115#         psphotMomentsStudy.c
     116#
     117# psphotPetrosianStudy_SOURCES = \
     118#         psphotPetrosianStudy.c
    63119
    64120libpsphot_la_SOURCES = \
     
    104160        psphotExtendedSourceAnalysis.c \
    105161        psphotExtendedSourceFits.c     \
    106         psphotRadialProfile.c          \
    107         psphotPetrosian.c              \
    108         psphotIsophotal.c              \
    109         psphotAnnuli.c                 \
    110         psphotKron.c                   \
    111162        psphotKernelFromPSF.c          \
    112163        psphotPSFConvModel.c           \
    113         psphotModelTest.c              \
    114164        psphotFitSet.c                 \
    115165        psphotSourceFreePixels.c       \
     
    117167        psphotMergeSources.c           \
    118168        psphotLoadPSF.c                \
     169        psphotLoadSRCTEXT.c            \
    119170        psphotReadoutCleanup.c         \
    120171        psphotSourcePlots.c            \
     
    128179        psphotCheckStarDistribution.c  \
    129180        psphotThreadTools.c            \
    130         psphotAddNoise.c
    131 
    132 # dropped? psphotGrowthCurve.c
     181        psphotAddNoise.c               \
     182        psphotRadialProfile.c          \
     183        psphotRadialProfileByAngles.c  \
     184        psphotRadiiFromProfiles.c      \
     185        psphotEllipticalContour.c      \
     186        psphotEllipticalProfile.c      \
     187        psphotRadialBins.c             \
     188        psphotPetrosian.c              \
     189        psphotPetrosianRadialBins.c    \
     190        psphotPetrosianStats.c         \
     191        psphotPetrosianVisual.c        \
     192        psphotEfficiency.c
     193
     194# XXX need to fix this for the new apis
     195#       psphotModelTest.c             
     196
     197# re-instate these
     198#       psphotIsophotal.c              \
     199#       psphotAnnuli.c                 \
     200#       psphotKron.c                   \
     201#
     202
     203# test versions
     204#       psphotPetrosianProfile.c       \
     205#       psphotPetrosianAnalysis.c      \
     206#
    133207
    134208include_HEADERS = \
  • branches/simtest_nebulous_branches/psphot/src/psphot.h

    r24890 r27840  
    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 pmDetections   *psphotFindDetections (pmDetections *detections, pmReadout *readout, psMetadata *recipe);
    45 
    46 bool            psphotRoughClass (pmReadout *readout, psArray *sources, psMetadata *recipe, const bool findPsfClump);
    47 bool            psphotBasicDeblend (psArray *sources, psMetadata *recipe);
    48 pmPSF          *psphotChoosePSF (pmReadout *readout, psArray *sources, psMetadata *recipe);
    49 bool            psphotPSFstats (pmReadout *readout, psMetadata *recipe, pmPSF *psf);
    50 bool            psphotMomentsStats (pmReadout *readout, psMetadata *recipe, psArray *sources);
    51 bool            psphotFitSourcesLinear (pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, bool final);
    52 bool            psphotReplaceUnfitSources (psArray *sources, psImageMaskType maskVal);
    53 
    54 bool            psphotReplaceAllSources (psArray *sources, psMetadata *recipe);
    55 bool            psphotRemoveAllSources (psArray *sources, psMetadata *recipe);
    56 
    57 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 (psMetadata *recipe, pmReadout *readout, psArray *sources, pmPSF *psf, 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);
    58101bool            psphotBlendFit_Threaded (psThreadJob *job);
    59102
    60 psArray        *psphotSourceStats (pmConfig *config, pmReadout *readout, pmDetections *detections);
    61 bool            psphotSourceStats_Threaded (psThreadJob *job);
    62 
    63 bool            psphotGuessModels (pmConfig *config, pmReadout *readout, psArray *sources, pmPSF *psf);
    64 bool            psphotGuessModel_Threaded (psThreadJob *job);
    65 
    66 bool            psphotMagnitudes (pmConfig *config, pmReadout *readout, const pmFPAview *view, psArray *sources, 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, psMetadata *recipe, const pmFPAview *view, pmReadout *readout, psArray *sources, pmPSF *psf);
    67122bool            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);
    68126
    69127bool            psphotPSFWeights(pmConfig *config, pmReadout *readout, const pmFPAview *view, psArray *sources);
    70128bool            psphotPSFWeights_Threaded (psThreadJob *job);
    71129
    72 bool            psphotApResid (pmConfig *config, pmReadout *readout, psArray *sources, pmPSF *psf);
    73 bool            psphotApResidMags_Threaded (psThreadJob *job);
    74 
    75130bool            psphotSkyReplace (pmConfig *config, const pmFPAview *view);
    76 bool            psphotExtendedSourceAnalysis (pmReadout *readout, psArray *sources, psMetadata *recipe);
    77 bool            psphotExtendedSourceFits (pmReadout *readout, psArray *sources, psMetadata *recipe);
     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);
    78168
    79169// thread-related:
     
    86176psImage        *psphotSignificanceImage (pmReadout *readout, psMetadata *recipe, const int pass, psImageMaskType maskVal);
    87177psArray        *psphotFindPeaks (psImage *significance, pmReadout *readout, psMetadata *recipe, const float threshold, const int nMax);
    88 bool            psphotFindFootprints (pmDetections *detections, psImage *significance, pmReadout *readout, psMetadata *recipe, const int pass, psImageMaskType maskVal);
    89 psErrorCode     psphotCullPeaks(const psImage *img, const psImage *weight, const psMetadata *recipe, psArray *footprints);
    90 
    91 // generate the detection structure for the supplied array of sources
    92 pmDetections   *psphotDetectionsFromSources (pmConfig *config, psArray *sources);
    93 
    94 // used by ApResid
    95 bool            psphotMagErrorScale (float *errorScale, float *errorFloor, psVector *dMag, psVector *dap, psVector *mask, int nGroup);
    96 bool            psphotApResidTrend (pmReadout *readout, pmPSF *psf, int Npsf, int scale, float *errorScale, float *errorFloor, psVector *mask, psVector *xPos, psVector *yPos, psVector *apResid, psVector *dMag);
     178bool            psphotFindFootprints (pmDetections *detections, psImage *significance, pmReadout *readout, psMetadata *recipe, const float threshold, const int pass, psImageMaskType maskVal);
     179psErrorCode     psphotCullPeaks(const pmReadout *readout, const psMetadata *recipe, psArray *footprints);
     180
     181// in psphotApResid.c:
     182pmTrend2D      *psphotApResidTrend (float *apResidSysErr, pmReadout *readout, int Nx, int Ny, psVector *xPos, psVector *yPos, psVector *apResid, psVector *dMag);
     183bool            psphotApResidMags_Threaded (psThreadJob *job);
    97184
    98185// basic support functions
    99186void            psphotModelClassInit (void);
    100187bool            psphotGrowthCurve (pmReadout *readout, pmPSF *psf, bool ignore, psImageMaskType maskVal);
    101 bool            psphotSetMaskAndVariance (pmConfig *config, pmReadout *readout, psMetadata *recipe);
    102 void            psphotSourceFreePixels (psArray *sources);
    103188
    104189// functions to set the correct source pixels
    105 bool            psphotInitRadiusPSF (const psMetadata *recipe, const pmModelType type);
     190bool            psphotInitRadiusPSF(const psMetadata *recipe, const psMetadata *analysis, const pmModelType type);
     191
    106192bool            psphotCheckRadiusPSF (pmReadout *readout, pmSource *source, pmModel *model, psImageMaskType markVal);
    107193bool            psphotCheckRadiusPSFBlend (pmReadout *readout, pmSource *source, pmModel *model, psImageMaskType markVal, float dR);
    108194bool            psphotInitRadiusEXT (psMetadata *recipe, pmModelType type);
    109195bool            psphotCheckRadiusEXT (pmReadout *readout, pmSource *source, pmModel *model, psImageMaskType markVal);
    110 
    111 // output functions
    112 bool            psphotAddPhotcode (psMetadata *recipe, pmConfig *config, const pmFPAview *view, const char *filerule);
     196float           psphotSetRadiusEXT (pmReadout *readout, pmSource *source, psImageMaskType markVal);
     197
    113198bool            psphotDumpMoments (psMetadata *recipe, psArray *sources);
    114199psMetadata     *psphotDefineHeader (psMetadata *recipe);
     
    141226bool            psphotFitSummary (void);
    142227
    143 bool            psphotMergeSources (psArray *oldSources, psArray *newSources);
    144 bool            psphotLoadExtSources (pmConfig *config, const pmFPAview *view, psArray *sources);
    145 psArray        *psphotLoadPSFSources (pmConfig *config, const pmFPAview *view);
    146 
    147 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
    148231bool            psphotSetHeaderNstars (psMetadata *recipe, psArray *sources);
    149 bool            psphotAddNoise (pmReadout *readout, psArray *sources, psMetadata *recipe);
    150 bool            psphotSubNoise (pmReadout *readout, psArray *sources, psMetadata *recipe);
    151 bool            psphotAddOrSubNoise (pmReadout *readout, psArray *sources, psMetadata *recipe, bool add);
    152232bool            psphotRadialPlot (int *kapa, const char *filename, pmSource *source);
    153233bool            psphotSourcePlots (pmReadout *readout, psArray *sources, psMetadata *recipe);
    154234bool            psphotMosaicSubimage (psImage *outImage, pmSource *source, int Xo, int Yo, int DX, int DY, bool normalize);
    155235
    156 bool            psphotAddWithTest (pmSource *source, bool useState, psImageMaskType maskVal);
    157 bool            psphotSubWithTest (pmSource *source, bool useState, psImageMaskType maskVal);
    158 bool            psphotSetState (pmSource *source, bool curState, psImageMaskType maskVal);
    159 bool            psphotDeblendSatstars (pmReadout *readout, psArray *sources, psMetadata *recipe);
    160 bool            psphotSourceSize (pmConfig *config, pmReadout *readout, psArray *sources, psMetadata *recipe, long first);
    161 
    162236bool            psphotMakeResiduals (psArray *sources, psMetadata *recipe, pmPSF *psf, psImageMaskType maskVal);
    163237
     
    166240psKernel       *psphotKernelFromPSF (pmSource *source, int nPix);
    167241
    168 bool            psphotRadialProfile (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
    169 bool            psphotPetrosian (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
    170 bool            psphotIsophotal (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
    171 bool            psphotAnnuli (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
    172 bool            psphotKron (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
     242// functions related to extended source analysis
     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, bool RAW_RADIUS);
     248bool            psphotEllipticalContour (pmSource *source);
    173249
    174250// psphotVisual functions
    175 bool psphotVisualShowImage (pmReadout *readout);
    176 bool psphotVisualShowBackground (pmConfig *config, const pmFPAview *view, pmReadout *readout);
    177 bool psphotVisualShowSignificance (psImage *image);
    178 bool psphotVisualShowPeaks (pmDetections *detections);
    179 bool psphotVisualShowFootprints (pmDetections *detections);
    180 bool psphotVisualShowMoments (psArray *sources);
    181 bool psphotVisualPlotMoments (psMetadata *recipe, psArray *sources);
    182 bool psphotVisualShowRoughClass (psArray *sources);
    183 bool psphotVisualShowPSFStars (psMetadata *recipe, pmPSF *psf, psArray *sources);
    184 bool psphotVisualShowSatStars (psMetadata *recipe, pmPSF *psf, psArray *sources);
    185 bool psphotVisualShowPSFModel (pmReadout *readout, pmPSF *psf);
    186 bool psphotVisualPlotRadialProfile (int myKapa, pmSource *source, psImageMaskType maskVal);
    187 bool psphotVisualPlotRadialProfiles (psMetadata *recipe, psArray *sources);
    188 bool psphotVisualShowFlags (psArray *sources);
    189 bool psphotVisualShowSourceSize (pmReadout *readout, psArray *sources);
    190 bool psphotVisualShowResidualImage (pmReadout *readout);
    191 bool psphotVisualPlotApResid (psArray *sources);
    192 bool psphotVisualPlotSourceSize (psArray *sources);
    193 
    194 bool psphotImageQuality (psMetadata *recipe, psArray *sources);
     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);
     272
     273bool psphotPetrosian (pmSource *source, psMetadata *recipe, float skynoise, psImageMaskType maskVal);
     274bool psphotPetrosianRadialBins (pmSource *source, float radiusMax, float skynoise);
     275bool psphotPetrosianStats (pmSource *source);
     276
     277// currently disabled:
     278// bool            psphotIsophotal (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
     279// bool            psphotAnnuli (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
     280// bool            psphotKron (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
     281
     282// XXX visualization functions related to radial profiles (disabled)
     283bool psphotPetrosianVisualProfileByAngle (psVector *radius, psVector *flux);
     284bool psphotPetrosianVisualProfileRadii (psVector *radius, psVector *flux, psVector *radiusBin, psVector *fluxBin, float peakFlux, float RadiusRef);
     285bool psphotPetrosianVisualEllipticalContour (pmSourceRadialFlux *radFlux, pmSourceExtendedPars *extpars);
     286bool psphotPetrosianVisualStats (psVector *radBin, psVector *fluxBin,
     287                               psVector *refRadius, psVector *meanSB,
     288                               psVector *petRatio, psVector *petRatioErr, psVector *fluxSum,
     289                               float petRadius, float ratioForRadius,
     290                               float petFlux, float radiusForFlux);
     291
     292bool psphotRadialBins (psMetadata *recipe, pmSource *source, float radiusMax, float skynoise);
    195293
    196294// structures & functions to support psf-convolved model fitting
    197 
    198 // pmPCMData : PSF Convolved Model data storage structure
    199 typedef struct {
    200     psImage *model;
    201     psArray *dmodels;
    202     psImage *modelConv;
    203     psArray *dmodelsConv;
    204 } pmPCMData;
    205 
    206295
    207296// psf-convolved model fitting
     
    241330bool psphotDumpPSFStars (pmReadout *readout, pmPSFtry *try, float radius, psImageMaskType maskVal, psImageMaskType markVal);
    242331
     332bool psphotLoadSRCTEXT (pmFPA *fpa, pmConfig *config);
     333
    243334bool psphotCheckStarDistribution (psArray *sources, psArray *stars, pmPSFOptions *options);
    244335int psphotSupplementStars (psArray *stars, psArray *sources, psImageBinning *binning, int ix, int iy);
    245336
    246 
    247 // Create a background model for a readout
    248 // Essentially identical to psphotModelBackground, but with a more convenient API for outsiders.
    249 psImage *psphotBackgroundModel(pmReadout *ro, // Readout for which to generate background model
    250                                const pmConfig *config // Configuration
    251     );
    252 
     337pmConfig *psphotForcedArguments(int argc, char **argv);
     338bool psphotForcedImageLoop (pmConfig *config);
     339bool psphotForcedReadout(pmConfig *config, const pmFPAview *view);
     340
     341pmConfig *psphotMakePSFArguments(int argc, char **argv);
     342bool psphotMakePSFImageLoop (pmConfig *config);
     343bool psphotMakePSFReadout(pmConfig *config, const pmFPAview *view);
     344
     345/**** psphotStack prototypes ****/
     346
     347pmConfig *psphotStackArguments(int argc, char **argv);
     348bool psphotStackParseCamera (pmConfig *config);
     349bool psphotStackImageLoop (pmConfig *config);
     350bool psphotStackReadout (pmConfig *config, const pmFPAview *view);
     351bool psphotStackChisqImage (pmConfig *config, const pmFPAview *view);
     352bool psphotStackChisqImageAddReadout(const pmConfig *config, // Configuration
     353                                     const pmFPAview *view,
     354                                     pmReadout **chiReadout,
     355                                     char *filename,
     356                                     int index);
     357
     358bool psphotStackRemoveChisqFromInputs (pmConfig *config);
     359bool pmFPAfileRemoveSingle(psMetadata *files, const char *name, int num);
     360
     361psArray *psphotMatchSources (pmConfig *config, const pmFPAview *view);
     362bool psphotMatchSourcesReadout (psArray *objects, pmConfig *config, const pmFPAview *view, char *filename, int index);
     363bool psphotMatchSourcesToObjects (psArray *objects, psArray *sources, float RADIUS);
     364
     365bool psphotFitSourcesLinearStack (pmConfig *config, psArray *objects, bool final);
     366int pmPhotObjSortBySN (const void **a, const void **b);
     367int pmPhotObjSortByX (const void **a, const void **b);
    253368
    254369#endif
  • branches/simtest_nebulous_branches/psphot/src/psphotAddNoise.c

    r21519 r27840  
    11# include "psphotInternal.h"
    22
    3 bool psphotAddNoise (pmReadout *readout, psArray *sources, 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, psArray *sources, 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, psArray *sources, 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):
     
    4275    PS_ASSERT (status, false);
    4376    if (isfinite(GAIN)) {
    44         FACTOR /= GAIN;
     77        FACTOR /= GAIN;
    4578    }
    4679
     
    5083
    5184        // skip sources which were not subtracted
     85        // NOTE: this bit is not modified when pmSourceOp applies to noise
    5286        if (!(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED)) continue;
    5387
     
    70104        oldshape.sxy = PAR[PM_PAR_SXY];
    71105
    72         // XXX can this be done more intelligently?
    73         if (oldI0 == 0.0) continue;
    74         if (!isfinite(oldI0)) continue;
     106        // XXX can this be done more intelligently?
     107        if (oldI0 == 0.0) continue;
     108        if (!isfinite(oldI0)) continue;
    75109
    76110        // increase size and height of source
     
    79113        axes.minor *= SIZE;
    80114        newshape = psEllipseAxesToShape (axes);
    81         PAR[PM_PAR_I0]  = FACTOR*PS_SQR(oldI0);
     115        PAR[PM_PAR_I0]  = FACTOR*oldI0;
    82116        PAR[PM_PAR_SXX] = newshape.sx;
    83117        PAR[PM_PAR_SYY] = newshape.sy;
  • branches/simtest_nebulous_branches/psphot/src/psphotApResid.c

    r24878 r27840  
    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    // skip the chisq image (optionally?)
     19    int chisqNum = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.CHISQ.NUM");
     20    if (!status) chisqNum = -1;
     21
     22    // loop over the available readouts
     23    for (int i = 0; i < num; i++) {
     24        if (i == chisqNum) continue; // skip chisq image
     25        if (!psphotApResidReadout (config, view, "PSPHOT.INPUT", i, recipe)) {
     26            psError (PSPHOT_ERR_CONFIG, false, "failed to measure aperture residual for PSPHOT.INPUT entry %d", i);
     27            return false;
     28        }
     29    }
     30    return true;
     31}
     32
     33bool psphotApResidReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe)
    734{
    835    int Nfail = 0;
     
    1340    pmSource *source;
    1441
    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 
    2042    psTimerStart ("psphot.apresid");
    2143
    22     // select the appropriate recipe information
    23     psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
    24     assert (recipe);
     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 ap resid");
     59        return true;
     60    }
     61
     62    pmPSF *psf = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF");
     63    psAssert (psf, "missing psf?");
    2564
    2665    // determine the number of allowed threads
     
    3372    if (!measureAptrend) {
    3473        // save nan values since these were not calculated
    35         psMetadataAdd (recipe, PS_LIST_TAIL, "SKYBIAS",  PS_DATA_F32 | PS_META_REPLACE, "aperture sky bias",   NAN);
    36         psMetadataAdd (recipe, PS_LIST_TAIL, "SKYSAT",   PS_DATA_F32 | PS_META_REPLACE, "aperture-determined saturation",   NAN);
    37         psMetadataAdd (recipe, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   NAN);
    38         psMetadataAdd (recipe, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", NAN);
    39         psMetadataAdd (recipe, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", NAN);
    40         psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", 0);
     74        psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   NAN);
     75        psMetadataAdd (readout->analysis, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", NAN);
     76        psMetadataAdd (readout->analysis, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", 0);
     77        psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", NAN);
    4178        return true;
    4279    }
     
    5390    maskVal |= markVal;
    5491
    55     // S/N limit to perform full non-linear fits
     92    // clipping for extreme outliers
     93    // XXX this is not currently defined in the recipe
    5694    float MAX_AP_OFFSET = psMetadataLookupF32 (&status, recipe, "MAX_AP_OFFSET");
    5795
    58     // this is the smallest radius allowed: need to at least extend growth curve down to this...
     96    // options for how the photometry is calculated
     97    // XXX are these sensible?
    5998    bool IGNORE_GROWTH = psMetadataLookupBool (&status, recipe, "IGNORE_GROWTH");
    6099    bool INTERPOLATE_AP = psMetadataLookupBool (&status, recipe, "INTERPOLATE_AP");
     
    100139            PS_ARRAY_ADD_SCALAR(job->args, photMode, PS_TYPE_S32);
    101140            PS_ARRAY_ADD_SCALAR(job->args, maskVal,  PS_TYPE_IMAGE_MASK);
     141            PS_ARRAY_ADD_SCALAR(job->args, markVal,  PS_TYPE_IMAGE_MASK);
    102142
    103143            PS_ARRAY_ADD_SCALAR(job->args, 0,        PS_TYPE_S32); // this is used as a return value for Nskip
     
    110150            }
    111151            psFree(job);
    112 
    113 # if (0)
    114                 int nskip = 0;
    115                 int nfail = 0;
    116 
    117                 if (!psphotApResidMags_Unthreaded (&nskip, &nfail, sources, psf, photMode, maskVal)) {
    118                     psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
    119                     return false;
    120                 }
    121                 Nskip += nskip;
    122                 Nfail += nfail;
    123 # endif
    124 
    125152        }
    126153
     
    138165            } else {
    139166                psScalar *scalar = NULL;
    140                 scalar = job->args->data[4];
     167                scalar = job->args->data[5];
    141168                Nskip += scalar->data.S32;
    142                 scalar = job->args->data[5];
     169                scalar = job->args->data[6];
    143170                Nfail += scalar->data.S32;
    144171            }
     
    150177
    151178    // gather the stats to assess the aperture residuals
    152     psVector *mask    = psVectorAllocEmpty (300, PS_TYPE_VECTOR_MASK);
    153179    psVector *mag     = psVectorAllocEmpty (300, PS_TYPE_F32);
    154180    psVector *xPos    = psVectorAllocEmpty (300, PS_TYPE_F32);
     
    158184    Npsf = 0;
    159185
     186# ifdef DEBUG   
     187    FILE *f = fopen ("apresid.dat", "w");
     188    psAssert (f, "failed open");
     189# endif
     190
    160191    for (int i = 0; i < sources->n; i++) {
    161192        source = sources->data[i];
     
    170201        if (source->mode &  PM_SOURCE_MODE_EXT_LIMIT) SKIPSTAR ("EXTENDED");
    171202        if (source->mode &  PM_SOURCE_MODE_CR_LIMIT) SKIPSTAR ("COSMIC RAY");
     203        if (source->mode &  PM_SOURCE_MODE_DEFECT) SKIPSTAR ("DEFECT");
    172204           
    173205        if (!isfinite(source->apMag) || !isfinite(source->psfMag)) {
    174206            continue;
    175207        }
     208
     209        // XXX make this user-configurable?
     210        if (source->errMag > 0.01) continue;
    176211
    177212        // aperture residual for this source
     
    185220        }
    186221
    187         mag->data.F32[Npsf]     = source->psfMag;
    188         apResid->data.F32[Npsf] = dap;
    189         xPos->data.F32[Npsf]    = model->params->data.F32[PM_PAR_XPOS];
    190         yPos->data.F32[Npsf]    = model->params->data.F32[PM_PAR_YPOS];
    191 
    192         mask->data.PS_TYPE_VECTOR_MASK_DATA[Npsf] = 0;
    193 
    194         dMag->data.F32[Npsf] = model->dparams->data.F32[PM_PAR_I0] / model->params->data.F32[PM_PAR_I0];
    195 
    196         psVectorExtend (mag,     100, 1);
    197         psVectorExtend (mask,    100, 1);
    198         psVectorExtend (xPos,    100, 1);
    199         psVectorExtend (yPos,    100, 1);
    200         psVectorExtend (dMag,    100, 1);
    201         psVectorExtend (apResid, 100, 1);
     222# ifdef DEBUG
     223        fprintf (f, "%6.1f %6.1f : %6.1f %6.1f : %8.3f %8.3f %8.3f : %f : %f %f %f : %f\n",
     224                 source->peak->xf, source->peak->yf,
     225                 source->modelPSF->params->data.F32[PM_PAR_XPOS], source->modelPSF->params->data.F32[PM_PAR_YPOS],
     226                 source->psfMag, source->apMag, source->errMag,
     227                 source->modelPSF->params->data.F32[PM_PAR_I0],
     228                 source->modelPSF->params->data.F32[PM_PAR_SXX], source->modelPSF->params->data.F32[PM_PAR_SXY], source->modelPSF->params->data.F32[PM_PAR_SYY],
     229                 source->modelPSF->params->data.F32[PM_PAR_7]);
     230# endif
     231        if (!isfinite(source->psfMag)) psAbort ("nan in psfMag");
     232        if (!isfinite(source->errMag)) psAbort ("nan in errMag");
     233        if (!isfinite(source->apMag)) psAbort ("nan in apMag");
     234        if (!isfinite(model->params->data.F32[PM_PAR_XPOS])) psAbort ("nan in xPos");
     235        if (!isfinite(model->params->data.F32[PM_PAR_YPOS])) psAbort ("nan in yPos");
     236
     237        psVectorAppend (mag, source->psfMag);
     238        psVectorAppend (dMag,source->errMag);
     239        psVectorAppend (apResid, dap);
     240        psVectorAppend (xPos, model->params->data.F32[PM_PAR_XPOS]);
     241        psVectorAppend (yPos, model->params->data.F32[PM_PAR_YPOS]);
    202242        Npsf ++;
    203243    }
     
    205245    psLogMsg ("psphot.apresid", PS_LOG_DETAIL, "measure aperture residuals for %d objects (%d skipped, %d failed, %ld invalid)\n",
    206246              Npsf, Nskip, Nfail, sources->n - Npsf - Nskip - Nfail);
     247
     248# ifdef DEBUG
     249    fclose (f);
     250# endif
    207251
    208252    // XXX choose a better value here?
     
    212256    }
    213257
    214     // XXX deprecating the old code which allowed the ApResid to be fitted as a function of flux and r^2/flux
    215     // XXX is this asymmetric clipping still needed?  this analysis should come after neighbors are subtracted...
    216     // 3hi/1lo sigma clipping on the rflux vs metric fit
    217     // systematic error information
    218     float errorScale = 0.0;
    219     float errorFloor = 0.0;
    220 
     258    // this is a bit tricky, because we have two cases (MAP vs POLY), and they have a different
     259    // definition for 'order' (order_MAP = order_POLY + 1).  in addition, we have a
     260    // user-specified MAX order, which we should respect, regardless of the mode
     261
     262    // set the max order (0 = constant) which the number of psf stars can support:
     263    // rule of thumb: require 3 stars per 'cell' (order+1)^2
     264    int MaxOrderForStars = 0;
     265    if (Npsf >= 12) MaxOrderForStars = 1; // 4 cells
     266    if (Npsf >= 27) MaxOrderForStars = 2; // 9 cells
     267    if (Npsf >= 48) MaxOrderForStars = 3; // 16 cells
     268    if (Npsf >  75) MaxOrderForStars = 4; // 25 cells
     269
     270    pmTrend2DMode mode = PM_TREND_MAP;
     271    if (mode == PM_TREND_MAP) {
     272        MaxOrderForStars ++;
     273    }
     274    APTREND_ORDER_MAX = PS_MIN (APTREND_ORDER_MAX, MaxOrderForStars);
     275
     276    psFree (psf->ApTrend);
     277    psf->ApTrend = NULL;
    221278    float errorFloorMin = FLT_MAX;
    222     int entryMin = -1;
    223 
    224     // Fit out the dap vs mag trend, iterate over spatial scale until error Floor increases.
    225     // Stop if Npsf / (Nx * Ny) < 3
     279
     280    // as we loop over orders, we need to refer to the initial selection, but we modify the
     281    // option values to match the current guess: save the max values here:
     282    int NX = readout->image->numCols;
     283    int NY = readout->image->numRows;
    226284    for (int i = 1; i <= APTREND_ORDER_MAX; i++) {
    227 
    228         if (!psphotApResidTrend (readout, psf, Npsf, i, &errorScale, &errorFloor, mask, xPos, yPos, apResid, dMag)) {
    229             break;
    230         }
    231 
    232         // store the resulting errorFloor values and the scales, redo the best
     285       
     286        int Nx, Ny;
     287        if (NX > NY) {
     288            Nx = i;
     289            Ny = PS_MAX (1, (int)(i * (NY / (float)(NX)) + 0.5));
     290        } else {
     291            Ny = i;
     292            Nx = PS_MAX (1, (int)(i * (NX / (float)(NY)) + 0.5));
     293        }
     294
     295        float errorFloor;
     296        pmTrend2D *apTrend = psphotApResidTrend (&errorFloor, readout, Nx, Ny, xPos, yPos, apResid, dMag);
     297        if (!apTrend) {
     298            continue;
     299        }
     300
     301        // apply ApTrend results
     302        // float xc = 0.5*readout->image->numCols + readout->image->col0 + 0.5;
     303        // float yc = 0.5*readout->image->numRows + readout->image->row0 + 0.5;
     304        // float ApResid = pmTrend2DEval (psf->ApTrend, xc, yc); // ap-fit at chip center
     305        // if (!isfinite(ApResid)) psAbort("nan apresid @ center");
     306
     307        // store the minimum errorFloor and best ApTrend to keep
    233308        if (errorFloor < errorFloorMin) {
    234309            errorFloorMin = errorFloor;
    235             entryMin = i;
     310            psFree (psf->ApTrend);
     311            psf->ApTrend = psMemIncrRefCounter(apTrend);
    236312        }
    237     }
    238     if (entryMin == -1) {
     313        psFree (apTrend);
     314    }
     315    if (psf->ApTrend == NULL) {
    239316        psWarning("Failed to find a valid aperture residual value");
    240317        goto escape;
    241318    }
    242319
    243     // XXX catch error condition
    244     psphotApResidTrend (readout, psf, Npsf, entryMin, &errorScale, &errorFloor, mask, xPos, yPos, apResid, dMag);
     320    // apply ApTrend results
     321    float xc = 0.5*readout->image->numCols + readout->image->col0 + 0.5;
     322    float yc = 0.5*readout->image->numRows + readout->image->row0 + 0.5;
     323
     324    psf->ApResid  = pmTrend2DEval (psf->ApTrend, xc, yc); // ap-fit at chip center
     325    psf->dApResid = errorFloorMin;
     326    psf->nApResid = Npsf;
     327
     328    // save results for later output
     329    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   psf->ApResid);
     330    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", psf->dApResid);
     331    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", psf->nApResid);
     332    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", psf->growth->apLoss);
     333
     334    psLogMsg ("psphot.apresid", PS_LOG_DETAIL, "aperture residual: %f +/- %f\n", psf->ApResid, psf->dApResid);
     335    psLogMsg ("psphot.apresid", PS_LOG_INFO, "measure full-frame aperture residuals for %d sources: %f sec\n", Npsf, psTimerMark ("psphot.apresid"));
     336
     337    psFree (xPos);
     338    psFree (yPos);
     339    psFree (apResid);
     340    psFree (mag);
     341    psFree (dMag);
     342
     343    psphotVisualPlotApResid (sources, psf->ApResid, psf->dApResid);
     344
     345    return true;
     346
     347escape:
     348    // save nan values since these were not calculated
     349    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   NAN);
     350    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", NAN);
     351    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", 0);
     352    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", NAN);
     353
     354    psFree (xPos);
     355    psFree (yPos);
     356    psFree (apResid);
     357    psFree (mag);
     358    psFree (dMag);
     359    return true;
     360    // this is a quality error, not a programming error
     361}
     362
     363pmTrend2D *psphotApResidTrend (float *apResidSysErr, pmReadout *readout, int Nx, int Ny, psVector *xPos, psVector *yPos, psVector *apResid, psVector *dMag) {
     364
     365    // the mask marks the values not used to calculate the ApTrend
     366    psVector *mask = psVectorAlloc(xPos->n, PS_TYPE_VECTOR_MASK);
     367    psVectorInit (mask, 0);
     368
     369    // XXX allow user to set this optionally?
     370    psStats *stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN | PS_STAT_SAMPLE_STDEV);
     371
     372    // measure Trend2D for the current spatial scale
     373    pmTrend2D *apTrend = pmTrend2DAlloc (PM_TREND_MAP, readout->image, Nx, Ny, stats);
     374
     375    // XXX somewhat arbitrary: soften the errors so the few bright stars do not totally dominate:
     376    // XXX use this or not?  probably not, since this is the point of the systematic error analysis
     377    psVector *dMagSoft = psVectorAlloc (dMag->n, PS_TYPE_F32);
     378    for (int i = 0; i < dMag->n; i++) {
     379        dMagSoft->data.F32[i] = hypot(dMag->data.F32[i], 0.005);
     380    }
     381
     382    // XXX test for errors here
     383    if (!pmTrend2DFit (apTrend, mask, 0xff, xPos, yPos, apResid, dMagSoft)) {
     384        psWarning("Failed to fit trend for %d x %d map", Nx, Ny);
     385        psFree (apTrend);
     386        return NULL;
     387    }
     388    if (apTrend->mode == PM_TREND_MAP) {
     389        // p_psImagePrint (2, apTrend->map->map, "ApTrend Before"); // XXX TEST:
     390        psImageMapRepair (apTrend->map->map);
     391        // p_psImagePrint (2, apTrend->map->map, "ApTrend After"); // XXX TEST:
     392    }
    245393
    246394    // construct the fitted values and the residuals
    247     psVector *apResidFit = pmTrend2DEvalVector (psf->ApTrend, mask, 0xff, xPos, yPos);
     395    psVector *apResidFit = pmTrend2DEvalVector (apTrend, mask, 0xff, xPos, yPos);
    248396    psVector *apResidRes = (psVector *) psBinaryOp (NULL, (void *) apResid, "-", (void *) apResidFit);
    249     psVector *dMagSys = (psVector *) psBinaryOp (NULL, (void *) dMag, "*", (void *) psScalarAlloc(errorScale, PS_TYPE_F32));
    250 
    251     if (psTraceGetLevel("psphot") >= 2) {
    252         FILE *dumpFile = fopen ("apresid.dat", "w");
     397
     398    // measure systematic error
     399    *apResidSysErr = psVectorSystematicError (apResidRes, dMag, 0.10);
     400    if (!isfinite(*apResidSysErr)) {
     401        psWarning("Failed to find systematic error for %d x %d map", Nx, Ny);
     402        psFree (apTrend);
     403        return NULL;
     404    }
     405
     406    psLogMsg ("psphot.apresid", PS_LOG_INFO, "result of %d x %d grid\n", Nx, Ny);
     407    psLogMsg ("psphot.apresid", PS_LOG_INFO, "systematic scatter floor: %f\n", *apResidSysErr);
     408
     409    if (psTraceGetLevel("psphot") >= 4) {
     410        char filename[64];
     411        snprintf (filename, 64, "apresid.%dx%d.dat", Nx, Ny);
     412        FILE *dumpFile = fopen (filename, "w");
    253413        for (int i = 0; i < xPos->n; i++) {
    254             fprintf (dumpFile, "%f %f  %f %f %f %f %f  %x\n",
     414            fprintf (dumpFile, "%f %f  %f %f %f %f  %x\n",
    255415                     xPos->data.F32[i], yPos->data.F32[i],
    256                      mag->data.F32[i], dMag->data.F32[i], dMagSys->data.F32[i],
     416                     dMag->data.F32[i], hypot(dMag->data.F32[i], *apResidSysErr),
    257417                     apResid->data.F32[i], apResidRes->data.F32[i],
    258418                     mask->data.PS_TYPE_VECTOR_MASK_DATA[i]);
     
    261421    }
    262422
    263     // apply ApTrend results
    264     float xc = 0.5*readout->image->numCols + readout->image->col0 + 0.5;
    265     float yc = 0.5*readout->image->numRows + readout->image->row0 + 0.5;
    266 
    267     psf->ApResid  = pmTrend2DEval (psf->ApTrend, xc, yc); // ap-fit at chip center
    268     psf->dApResid = errorFloor;
    269     psf->nApResid = Npsf;
    270 
    271     // save results for later output
    272     psMetadataAdd (recipe, PS_LIST_TAIL, "SKYBIAS",  PS_DATA_F32 | PS_META_REPLACE, "aperture sky bias",   0.0);
    273     psMetadataAdd (recipe, PS_LIST_TAIL, "SKYSAT",   PS_DATA_F32 | PS_META_REPLACE, "aperture-determined saturation",   0.0);
    274     psMetadataAdd (recipe, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   psf->ApResid);
    275     psMetadataAdd (recipe, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", psf->dApResid);
    276     psMetadataAdd (recipe, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", psf->growth->apLoss);
    277     psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", psf->nApResid);
    278 
    279     psLogMsg ("psphot.apresid", PS_LOG_DETAIL, "aperture residual: %f +/- %f\n", psf->ApResid, psf->dApResid);
    280     psLogMsg ("psphot.apresid", PS_LOG_INFO, "measure full-frame aperture residuals for %d sources: %f sec\n", Npsf, psTimerMark ("psphot.apresid"));
    281 
    282     psFree (mag);
    283423    psFree (mask);
    284     psFree (xPos);
    285     psFree (yPos);
    286 
    287     psFree (apResid);
    288     psFree (apResidFit);
    289     psFree (apResidRes);
    290 
    291     psFree (dMagSys);
    292     psFree (dMag);
    293 
    294     psphotVisualPlotApResid (sources);
    295 
    296     return true;
    297 
    298 escape:
    299     // save nan values since these were not calculated
    300     psMetadataAdd (recipe, PS_LIST_TAIL, "SKYBIAS",  PS_DATA_F32 | PS_META_REPLACE, "aperture sky bias",   NAN);
    301     psMetadataAdd (recipe, PS_LIST_TAIL, "SKYSAT",   PS_DATA_F32 | PS_META_REPLACE, "aperture-determined saturation",   NAN);
    302     psMetadataAdd (recipe, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   NAN);
    303     psMetadataAdd (recipe, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", NAN);
    304     psMetadataAdd (recipe, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", NAN);
    305     psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", 0);
    306 
    307     psFree (mag);
    308     psFree (mask);
    309     psFree (xPos);
    310     psFree (yPos);
    311     psFree (apResid);
    312     psFree (dMag);
    313     return false;
    314 }
    315 
    316 /*
    317   (aprMag' - fitMag) = rflux*skyBias + ApTrend(x,y)
    318   (aprMag - rflux*skyBias) - fitMag = ApTrend(x,y)
    319   (aprMag - rflux*skyBias) = fitMag + ApTrend(x,y)
    320 */
    321 
    322 // XXX this still sucks...  need a better way to estimate the error floor...
    323 bool psphotMagErrorScale (float *errorScale, float *errorFloor, psVector *dMag, psVector *dap, psVector *mask, int nGroup) {
    324 
    325     psStats *statsS = psStatsAlloc (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV);
    326     psStats *statsM = psStatsAlloc (PS_STAT_SAMPLE_MEAN);
    327 
    328     // measure the trend in bins with 10 values each; if < 10 total, use them all
    329     int nBin = PS_MAX (dMag->n / nGroup, 1);
    330 
    331     // output vectors for ApResid trend
    332     psVector *dSo = psVectorAlloc (nBin, PS_TYPE_F32);
    333     psVector *dMo = psVectorAlloc (nBin, PS_TYPE_F32);
    334     psVector *dRo = psVectorAlloc (nBin, PS_TYPE_F32);
    335 
    336     // use dMag to group the dMag and dap vectors
    337     psVector *index = psVectorSortIndex (NULL, dMag);
    338 
    339     // subset vectors for dMag and dap values within the given range
    340     psVector *dMSubset = psVectorAllocEmpty (nGroup, PS_TYPE_F32);
    341     psVector *dASubset = psVectorAllocEmpty (nGroup, PS_TYPE_F32);
    342     psVector *mkSubset = psVectorAllocEmpty (nGroup, PS_TYPE_VECTOR_MASK);
    343 
    344     int n = 0;
    345     for (int i = 0; i < dMo->n; i++) {
    346         int j;
    347         for (j = 0; (j < nGroup) && (n < dMag->n); j++, n++) {
    348             int N = index->data.U32[n];
    349             dMSubset->data.F32[j] = dMag->data.F32[N];
    350             dASubset->data.F32[j] = dap->data.F32[N];
    351             mkSubset->data.PS_TYPE_VECTOR_MASK_DATA[j] = mask->data.PS_TYPE_VECTOR_MASK_DATA[N];
    352         }
    353         dMSubset->n = j;
    354         dASubset->n = j;
    355         mkSubset->n = j;
    356 
    357         psStatsInit (statsS);
    358         psStatsInit (statsM);
    359 
    360         if (j > 2) {
    361             if (!psVectorStats (statsS, dASubset, NULL, mkSubset, 0xff)) {
    362                 psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
    363                 return false;
    364             }
    365             if (!psVectorStats (statsM, dMSubset, NULL, mkSubset, 0xff)) {
    366                 psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
    367                 return false;
    368             }
    369             dSo->data.F32[i] = statsS->robustStdev;
    370             dMo->data.F32[i] = statsM->sampleMean;
    371             dRo->data.F32[i] = statsS->robustStdev / statsM->sampleMean;
    372         } else {
    373             dSo->data.F32[i] = NAN;
    374             dMo->data.F32[i] = NAN;
    375             dRo->data.F32[i] = NAN;
    376         }
    377     }
    378     psFree (dMSubset);
    379     psFree (dASubset);
    380     psFree (mkSubset);
    381 
    382     psStats *stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN);
    383     if (!psVectorStats (stats, dRo, NULL, NULL, 0)) {
    384         psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
    385         return false;
    386     }
    387 
    388     *errorScale = stats->sampleMedian;
    389     for (int i = 0; i < dSo->n; i++) {
    390         *errorFloor = dSo->data.F32[i];
    391         if (fabs(*errorFloor) <= FLT_EPSILON) continue;
    392         if (isfinite(*errorFloor)) break;
    393     }
    394 
    395     psFree (stats);
    396     psFree (index);
    397 
    398     psFree (dRo);
    399     psFree (dMo);
    400     psFree (dSo);
    401 
    402     psFree (statsS);
    403     psFree (statsM);
    404 
    405     return true;
    406 }
    407 
    408 bool psphotApResidTrend (pmReadout *readout, pmPSF *psf, int Npsf, int scale, float *errorScale, float *errorFloor, psVector *mask, psVector *xPos, psVector *yPos, psVector *apResid, psVector *dMag) {
    409 
    410     int Nx, Ny;
    411 
    412     if (readout->image->numCols > readout->image->numRows) {
    413         Nx = scale;
    414         float AR = readout->image->numRows / (float) readout->image->numCols;
    415         Ny = (int) (Nx * AR + 0.5);
    416         Ny = PS_MAX (1, Ny);
    417     } else {
    418         Ny = scale;
    419         float AR = readout->image->numRows / (float) readout->image->numCols;
    420         Nx = (int) (Ny * AR + 0.5);
    421         Nx = PS_MAX (1, Nx);
    422     }
    423 
    424     // require at least 10 stars per spatial bin
    425     if (Npsf < 10*Nx*Ny) {
    426         return false;
    427     }
    428 
    429     // the mask marks the values not used to calculate the ApTrend
    430     psVectorInit (mask, 0);
    431 
    432     // XXX stats structure for use by ApTrend : make parameters user setable
    433     psStats *stats = psStatsAlloc (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV);
    434     stats->min = 2.0;
    435     stats->max = 3.0;
    436 
    437     // measure Trend2D for the current spatial scale
    438     psFree (psf->ApTrend);
    439     psf->ApTrend = pmTrend2DAlloc (PM_TREND_MAP, readout->image, Nx, Ny, stats);
    440 
    441     // XXX somewhat arbitrary: soften the errors so the few bright stars do not totally dominate:
    442     psVector *dMagSoft = psVectorAlloc (dMag->n, PS_TYPE_F32);
    443     for (int i = 0; i < dMag->n; i++) {
    444         dMagSoft->data.F32[i] = hypot(dMag->data.F32[i], 0.01);
    445     }
    446 
    447     // XXX test for errors here
    448     pmTrend2DFit (psf->ApTrend, mask, 0xff, xPos, yPos, apResid, dMagSoft);
    449 
    450     // construct the fitted values and the residuals
    451     psVector *apResidFit = pmTrend2DEvalVector (psf->ApTrend, mask, 0xff, xPos, yPos);
    452     psVector *apResidRes = (psVector *) psBinaryOp (NULL, (void *) apResid, "-", (void *) apResidFit);
    453 
    454     // measure systematic errorFloor & systematic / photon scale factor
    455     // XXX this is a bit arbitrary, but it forces ~3 stars from the bright bin per spatial bin
    456     int nGroup = PS_MAX (3*Nx*Ny, 10);
    457     psphotMagErrorScale (errorScale, errorFloor, dMag, apResidRes, mask, nGroup);
    458 
    459     psLogMsg ("psphot.apresid", PS_LOG_INFO, "result of %d x %d grid (%d stars per bin)\n", Nx, Ny, nGroup);
    460     psLogMsg ("psphot.apresid", PS_LOG_INFO, "systematic error / photon error: %f\n", *errorScale);
    461     psLogMsg ("psphot.apresid", PS_LOG_INFO, "systematic scatter floor: %f\n", *errorFloor);
    462 
    463424    psFree (stats);
    464425    psFree (dMagSoft);
     
    466427    psFree (apResidRes);
    467428
    468     return true;
     429    return apTrend;
    469430}
    470431
     
    480441    pmSourcePhotometryMode photMode = PS_SCALAR_VALUE(job->args->data[2],S32);
    481442    psImageMaskType maskVal         = PS_SCALAR_VALUE(job->args->data[3],PS_TYPE_IMAGE_MASK_DATA);
     443    psImageMaskType markVal         = PS_SCALAR_VALUE(job->args->data[4],PS_TYPE_IMAGE_MASK_DATA);
    482444
    483445    for (int i = 0; i < sources->n; i++) {
     
    490452        if (source->mode &  PM_SOURCE_MODE_POOR) SKIPSTAR ("POOR STAR");
    491453
    492         if (!pmSourceMagnitudes (source, psf, photMode, maskVal)) {
    493             Nskip ++;
    494             psTrace ("psphot", 3, "skip : bad source mag");
    495             continue;
     454        // replace object in image
     455        if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
     456            pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    496457        }
    497458
    498         if (!isfinite(source->apMag) || !isfinite(source->psfMag)) {
    499             Nfail ++;
    500             psTrace ("psphot", 3, "fail : nan mags : %f %f", source->apMag, source->psfMag);
    501             continue;
    502         }
    503         source->mode |= PM_SOURCE_MODE_AP_MAGS;
     459        // clear the mask bit and set the circular mask pixels
     460        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
     461        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", markVal);
     462
     463        bool status = pmSourceMagnitudes (source, psf, photMode, maskVal);
     464
     465        // clear the mask bit
     466        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
     467
     468        // re-subtract the object, leave local sky
     469        pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
     470
     471        if (!status) {
     472            Nskip ++;
     473            psTrace ("psphot", 3, "skip : bad source mag");
     474            continue;
     475        }
     476   
     477        if (!isfinite(source->apMag) || !isfinite(source->psfMag)) {
     478            Nfail ++;
     479            psTrace ("psphot", 3, "fail : nan mags : %f %f", source->apMag, source->psfMag);
     480            continue;
     481        }
     482        source->mode |= PM_SOURCE_MODE_AP_MAGS;
    504483    }
    505484
    506485    // change the value of a scalar on the array (wrap this and put it in psArray.h)
    507     scalar = job->args->data[4];
     486    scalar = job->args->data[5];
    508487    scalar->data.S32 = Nskip;
    509488
    510     scalar = job->args->data[5];
     489    scalar = job->args->data[6];
    511490    scalar->data.S32 = Nfail;
    512491
    513492    return true;
    514493}
    515 
    516 # if (0)
    517 bool psphotApResidMags_Unthreaded (int *nskip, int *nfail, psArray *sources, pmPSF *psf, pmSourcePhotometryMode photMode, psImageMaskType maskVal) {
    518 
    519     int Nskip = 0;
    520     int Nfail = 0;
    521 
    522     for (int i = 0; i < sources->n; i++) {
    523         pmSource *source = (pmSource *) sources->data[i];
    524 
    525         if (source->type != PM_SOURCE_TYPE_STAR) SKIPSTAR ("NOT STAR");
    526         if (source->mode &  PM_SOURCE_MODE_SATSTAR) SKIPSTAR ("SATSTAR");
    527         if (source->mode &  PM_SOURCE_MODE_BLEND) SKIPSTAR ("BLEND");
    528         if (source->mode &  PM_SOURCE_MODE_FAIL) SKIPSTAR ("FAIL STAR");
    529         if (source->mode &  PM_SOURCE_MODE_POOR) SKIPSTAR ("POOR STAR");
    530 
    531         if (!pmSourceMagnitudes (source, psf, photMode, maskVal)) {
    532             Nskip ++;
    533             psTrace ("psphot", 3, "skip : bad source mag");
    534             continue;
    535         }
    536 
    537         if (!isfinite(source->apMag) || !isfinite(source->psfMag)) {
    538             Nfail ++;
    539             psTrace ("psphot", 3, "fail : nan mags : %f %f", source->apMag, source->psfMag);
    540             continue;
    541         }
    542     }
    543 
    544     // change the value of a scalar on the array (wrap this and put it in psArray.h)
    545     *nskip = Nskip;
    546     *nfail = Nfail;
    547 
    548     return true;
    549 }
    550 # endif
  • branches/simtest_nebulous_branches/psphot/src/psphotArguments.c

    r24587 r27840  
    218218    // override any configuration-specified source for these files
    219219    //
    220     pmConfigFileSetsMD (config->arguments, &argc, argv, "MASK",   "-mask",   "-masklist");
    221     pmConfigFileSetsMD (config->arguments, &argc, argv, "VARIANCE", "-variance", "-variancelist");
    222     pmConfigFileSetsMD (config->arguments, &argc, argv, "PSPHOT.PSF", "-psf", "-psflist");
    223     pmConfigFileSetsMD (config->arguments, &argc, argv, "SRC",    "-src",    "-srclist");
     220    pmConfigFileSetsMD (config->arguments, &argc, argv, "MASK",       "-mask",     "-masklist");
     221    pmConfigFileSetsMD (config->arguments, &argc, argv, "VARIANCE",   "-variance", "-variancelist");
     222    pmConfigFileSetsMD (config->arguments, &argc, argv, "PSPHOT.PSF", "-psf",      "-psflist");
     223    pmConfigFileSetsMD (config->arguments, &argc, argv, "SRC",        "-src",      "-srclist");
    224224
    225225    if (argc == 1) {
     
    228228    }
    229229
    230     if (psArgumentGet(argc, argv, "-help")
    231         || psArgumentGet(argc, argv, "-h"))
     230    if (psArgumentGet(argc, argv, "-help") ||
     231        psArgumentGet(argc, argv, "-h"))
    232232      writeHelpInfo(argv[0], config, stdout);
    233233     
  • branches/simtest_nebulous_branches/psphot/src/psphotBasicDeblend.c

    r20453 r27840  
    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");
  • branches/simtest_nebulous_branches/psphot/src/psphotBlendFit.c

    r24029 r27840  
    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)
     
    254297        pmSourceCacheModel (source, maskVal);
    255298        pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    256         source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
    257299    }
    258300
     
    273315}
    274316
    275 # if (0)
    276 bool psphotBlendFit_Unthreaded (int *nfit, int *npsf, int *next, int *nfail, pmReadout *readout, psMetadata *recipe, psArray *sources, pmPSF *psf, psArray *newSources) {
    277 
    278     bool status = false;
    279     int Nfit = 0;
    280     int Npsf = 0;
    281     int Next = 0;
    282     int Nfail = 0;
    283 
    284     // bit-masks to test for good/bad pixels
    285     psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT");
    286     assert (maskVal);
    287 
    288     // bit-mask to mark pixels not used in analysis
    289     psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT");
    290     assert (markVal);
    291 
    292     // maskVal is used to test for rejected pixels, and must include markVal
    293     maskVal |= markVal;
    294 
    295     // S/N limit to perform full non-linear fits
    296     float FIT_SN_LIM = psMetadataLookupF32 (&status, recipe, "FULL_FIT_SN_LIM");
    297 
    298     // option to limit analysis to a specific region
    299     char *region = psMetadataLookupStr (&status, recipe, "ANALYSIS_REGION");
    300     psRegion AnalysisRegion = psRegionForImage (readout->image, psRegionFromString (region));
    301     if (psRegionIsNaN (AnalysisRegion)) psAbort("analysis region mis-defined");
    302 
    303     for (int i = 0; i < sources->n; i++) {
    304         pmSource *source = sources->data[i];
    305 
    306         // skip non-astronomical objects (very likely defects)
    307         if (source->mode &  PM_SOURCE_MODE_BLEND) continue;
    308         if (source->mode &  PM_SOURCE_MODE_CR_LIMIT) continue;
    309         if (source->type == PM_SOURCE_TYPE_DEFECT) continue;
    310         if (source->type == PM_SOURCE_TYPE_SATURATED) continue;
    311 
    312         // skip DBL second sources (ie, added by psphotFitBlob)
    313         if (source->mode &  PM_SOURCE_MODE_PAIR) continue;
    314 
    315         // limit selection to some SN limit
    316         if (source->peak->SN < FIT_SN_LIM) continue;
    317 
    318         // exclude sources outside optional analysis region
    319         if (source->peak->xf < AnalysisRegion.x0) continue;
    320         if (source->peak->yf < AnalysisRegion.y0) continue;
    321         if (source->peak->xf > AnalysisRegion.x1) continue;
    322         if (source->peak->yf > AnalysisRegion.y1) continue;
    323 
    324         // if model is NULL, we don't have a starting guess
    325         if (source->modelPSF == NULL) continue;
    326 
    327         // skip sources which are insignificant flux?
    328         // XXX this is somewhat ad-hoc
    329         if (source->modelPSF->params->data.F32[1] < 0.1) {
    330             psTrace ("psphot", 5, "skipping near-zero source: %f, %f : %f\n",
    331                      source->modelPSF->params->data.F32[1],
    332                      source->modelPSF->params->data.F32[2],
    333                      source->modelPSF->params->data.F32[3]);
    334             continue;
    335         }
    336 
    337         // replace object in image
    338         if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
    339             pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    340         }
    341         Nfit ++;
    342 
    343         // try fitting PSFs or extended sources depending on source->mode
    344         // these functions subtract the resulting fitted source
    345         if (source->mode & PM_SOURCE_MODE_EXT_LIMIT) {
    346             if (psphotFitBlob (readout, source, newSources, psf, maskVal, markVal)) {
    347                 source->type = PM_SOURCE_TYPE_EXTENDED;
    348                 psTrace ("psphot", 5, "source at %7.1f, %7.1f is ext", source->peak->xf, source->peak->yf);
    349                 Next ++;
    350                 continue;
    351             }
    352         } else {
    353             if (psphotFitBlend (readout, source, psf, maskVal, markVal)) {
    354                 source->type = PM_SOURCE_TYPE_STAR;
    355                 psTrace ("psphot", 5, "source at %7.1f, %7.1f is psf", source->peak->xf, source->peak->yf);
    356                 Npsf ++;
    357                 continue;
    358             }
    359         }
    360 
    361         psTrace ("psphot", 5, "source at %7.1f, %7.1f failed", source->peak->xf, source->peak->yf);
    362         Nfail ++;
    363 
    364         // re-subtract the object, leave local sky
    365         pmSourceCacheModel (source, maskVal);
    366         pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    367         source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
    368     }
    369 
    370     // change the value of a scalar on the array (wrap this and put it in psArray.h)
    371     *nfit  = Nfit;
    372     *npsf  = Npsf;
    373     *next  = Next;
    374     *nfail = Nfail;
    375 
    376     return true;
    377 }
    378 # endif
  • branches/simtest_nebulous_branches/psphot/src/psphotChoosePSF.c

    r23989 r27840  
    11# include "psphotInternal.h"
    22
    3 void psphotCountPSFStars (psArray *sources) {
    4 
    5     int nPSF = 0;
    6 
    7     // select the candidate PSF stars (pointers to original sources)
    8     for (int i = 0; i < sources->n; i++) {
    9         pmSource *source = sources->data[i];
    10         if (source->mode & PM_SOURCE_MODE_PSFSTAR) {
    11             nPSF ++;
    12         }
    13     }
    14 
    15     fprintf (stderr, "N PSF: %d\n", nPSF);
     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    // skip the chisq image (optionally?)
     16    int chisqNum = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.CHISQ.NUM");
     17    if (!status) chisqNum = -1;
     18
     19    // loop over the available readouts
     20    for (int i = 0; i < num; i++) {
     21        if (i == chisqNum) continue; // skip chisq image
     22        if (!psphotChoosePSFReadout (config, view, "PSPHOT.INPUT", i, recipe)) {
     23            psError (PSPHOT_ERR_CONFIG, false, "failed to choose a psf model for PSPHOT.INPUT entry %d", i);
     24            return false;
     25        }
     26    }
     27    return true;
    1628}
    1729
    1830// try PSF models and select best option
    19 pmPSF *psphotChoosePSF (pmReadout *readout, psArray *sources, psMetadata *recipe) {
     31bool psphotChoosePSFReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe) {
    2032
    2133    bool status;
    2234
    2335    psTimerStart ("psphot.choose.psf");
     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    // do not generate a PSF if we already were supplied one
     45    if (psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF")) {
     46        psLogMsg ("psphot", PS_LOG_DETAIL, "psf model supplied for input file %d", index);
     47        return 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 PSF model");
     58        return false;
     59    }
    2460
    2561    // bit-masks to test for good/bad pixels
    2662    psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT");
    27     assert (maskVal);
     63    psAssert (maskVal, "missing mask value?");
    2864
    2965    // bit-mask to mark pixels not used in analysis
    3066    psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT");
    31     assert (markVal);
     67    psAssert (markVal, "missing mark value?");
    3268
    3369    // maskVal is used to test for rejected pixels, and must include markVal
     
    73109    // get the fixed PSF fit radius
    74110    // XXX check that PSF_FIT_RADIUS < SKY_OUTER_RADIUS
    75     options->radius = psMetadataLookupF32 (&status, recipe, "PSF_FIT_RADIUS");
    76     assert (status);
    77 
    78     // XXX ROBUST seems to be too agressive given the small numbers.
    79     // options->stats = psStatsAlloc (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV);
    80     options->stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN | PS_STAT_SAMPLE_STDEV);
     111    // options->radius = psMetadataLookupF32 (&status, recipe, "PSF_FIT_RADIUS");
     112    // assert (status);
     113
     114    // values on readout->analysis if we have calculated a Gaussian window function, use that
     115    // for both the PSF fit radius and the aperture radius (scaling SIGMA), otherwise base the value on the recipe value for MOMENTS_GAUSS_SIGMA
     116    float gaussSigma = psMetadataLookupF32 (&status, readout->analysis, "MOMENTS_GAUSS_SIGMA");
     117    if (!status) {
     118        gaussSigma = psMetadataLookupF32 (&status, recipe, "MOMENTS_GAUSS_SIGMA");
     119    }
     120    float fitScale = psMetadataLookupF32(&status, recipe, "PSF_FIT_RADIUS_SCALE");
     121    float apScale = psMetadataLookupF32(&status, recipe, "PSF_APERTURE_SCALE");
     122    options->fitRadius = (int)(fitScale*gaussSigma);
     123    options->apRadius = (int)(apScale*gaussSigma);
     124
     125    // XXX use the same radii for standard analysis as for the PSF creation
     126    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "PSF_FIT_RADIUS", PS_META_REPLACE, "fit radius", options->fitRadius);
     127    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "PSF_APERTURE", PS_META_REPLACE, "psf aperture", options->apRadius);
    81128
    82129    // dimensions of the field for which the PSF is defined
     
    99146
    100147    psArray *stars = psArrayAllocEmpty (sources->n);
    101 
    102     // psphotCountPSFStars (sources);
    103148
    104149    // select the candidate PSF stars (pointers to original sources)
     
    115160    }
    116161
    117     // psphotCountPSFStars (sources);
    118 
    119162    // check that the identified psf stars sufficiently cover the region; if not, extend the
    120163    // limits somewhat
    121164    psphotCheckStarDistribution (stars, sources, options);
    122165
    123     // psphotCountPSFStars (sources);
    124 
    125166    psLogMsg ("psphot.pspsf", PS_LOG_DETAIL, "selected candidate %ld PSF objects\n", stars->n);
     167
     168    if (stars->n < 50) {
     169        // ROBUST is too agressive if we only have a small number of PSF stars
     170        options->stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN | PS_STAT_SAMPLE_STDEV);
     171    } else {
     172        options->stats = psStatsAlloc (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV);
     173    }
    126174
    127175    // get the list pointers for the PSF_MODEL entries
     
    164212        bool status = true;
    165213        status &= psphotMakeFluxScale (readout->image, recipe, psf);
    166         status &= psphotPSFstats (readout, recipe, psf);
     214        status &= psphotPSFstats (readout, psf);
    167215        if (!status) {
    168216            psError(PSPHOT_ERR_PSF, false, "Failed to fit any models when choosing PSF");
     
    239287        bool status = true;
    240288        status &= psphotMakeFluxScale (readout->image, recipe, psf);
    241         status &= psphotPSFstats (readout, recipe, psf);
     289        status &= psphotPSFstats (readout, psf);
    242290        if (!status) {
    243291            psError(PSPHOT_ERR_PSF, false, "Failed to fit any models when choosing PSF");
     
    289337    // XXX test dump of psf star data and psf-subtracted image
    290338    if (psTraceGetLevel("psphot.psfstars") > 5) {
    291         psphotDumpPSFStars (readout, try, options->radius, maskVal, markVal);
     339        psphotDumpPSFStars (readout, try, options->fitRadius, maskVal, markVal);
    292340    }
    293341
    294342    // save only the best model;
    295     // XXX we are not saving the fitted sources
    296     // XXX do we want to keep them so we may optionally write them out?
    297343    pmPSF *psf = psMemIncrRefCounter(try->psf);
    298344    psFree (models);
    299345
    300     if (!psphotPSFstats (readout, recipe, psf)) {
     346    if (!psphotPSFstats (readout, psf)) {
    301347        psError(PSPHOT_ERR_PSF, false, "cannot measure PSF shape terms");
    302348        psFree(options);
     
    305351    }
    306352
    307     // psphotCountPSFStars (sources);
    308 
    309353    char *modelName = pmModelClassGetName (psf->type);
    310354    psLogMsg ("psphot.pspsf", PS_LOG_INFO, "select psf model: %f sec\n", psTimerMark ("psphot.choose.psf"));
     
    312356
    313357    psFree (options);
    314     return (psf);
     358
     359    // save PSF on readout->analysis
     360    if (!psMetadataAddPtr (readout->analysis, PS_LIST_TAIL, "PSPHOT.PSF", PS_META_REPLACE | PS_DATA_UNKNOWN, "psphot psf model", psf)) {
     361        psError (PSPHOT_ERR_UNKNOWN, false, "problem saving sources on readout");
     362        return false;
     363    }
     364    psFree (psf); // XXX double-check
     365
     366    // move into psphotChoosePSF
     367    psphotVisualShowPSFModel (readout, psf);
     368
     369    return true;
    315370}
    316371
    317372// measure average parameters of the PSF model
    318 bool psphotPSFstats (pmReadout *readout, psMetadata *recipe, pmPSF *psf) {
     373bool psphotPSFstats (pmReadout *readout, pmPSF *psf) {
    319374
    320375    psEllipseShape shape;
     
    322377
    323378    PS_ASSERT_PTR_NON_NULL(readout, false);
    324     PS_ASSERT_PTR_NON_NULL(recipe, false);
    325379    PS_ASSERT_PTR_NON_NULL(psf, false);
    326380
     
    341395            // create modelPSF from this model
    342396            pmModel *modelPSF = pmModelFromPSFforXY (psf, xc, yc, 1.0);
    343             if (!modelPSF) continue;
     397            if (!modelPSF) {
     398                fprintf (stderr, "?");
     399                continue;
     400            }
    344401
    345402            // get the model full-width at half-max
     
    354411
    355412            float FWHM_MINOR = FWHM_MAJOR * (axes.minor / axes.major);
    356             if (!isfinite(FWHM_MAJOR) || !isfinite(FWHM_MINOR)) continue;
     413            if (!isfinite(FWHM_MAJOR) || !isfinite(FWHM_MINOR)) {
     414                fprintf (stderr, "!");
     415                continue;
     416            }
    357417            psVectorAppend (fwhmMajor, FWHM_MAJOR);
    358418            psVectorAppend (fwhmMinor, FWHM_MINOR);
     
    366426    }
    367427
    368     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FWHM_MAJ",   PS_META_REPLACE, "PSF FWHM Major axis (mean)", stats->sampleMean);
    369     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MJ_SG",   PS_META_REPLACE, "PSF FWHM Major axis (sigma)", stats->sampleStdev);
    370     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MJ_LQ",   PS_META_REPLACE, "PSF FWHM Major axis (lower quartile)", stats->sampleLQ);
    371     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MJ_UQ",   PS_META_REPLACE, "PSF FWHM Major axis (upper quartile)", stats->sampleUQ);
     428    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FWHM_MAJ",   PS_META_REPLACE, "PSF FWHM Major axis (mean)", stats->sampleMean);
     429    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MJ_SG",   PS_META_REPLACE, "PSF FWHM Major axis (sigma)", stats->sampleStdev);
     430    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MJ_LQ",   PS_META_REPLACE, "PSF FWHM Major axis (lower quartile)", stats->sampleLQ);
     431    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MJ_UQ",   PS_META_REPLACE, "PSF FWHM Major axis (upper quartile)", stats->sampleUQ);
     432
     433    float fwhmMaj = stats->sampleMean;  // FWHM on major axis
    372434
    373435    if (!psVectorStats (stats, fwhmMinor, NULL, NULL, 0)) {
     
    375437        return false;
    376438    }
    377     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FWHM_MIN",   PS_META_REPLACE, "PSF FWHM Minor axis (mean)", stats->sampleMean);
    378     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MN_SG",   PS_META_REPLACE, "PSF FWHM Minor axis (sigma)", stats->sampleStdev);
    379     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MN_LQ",   PS_META_REPLACE, "PSF FWHM Minor axis (lower quartile)", stats->sampleLQ);
    380     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MN_UQ",   PS_META_REPLACE, "PSF FWHM Minor axis (upper quartile)", stats->sampleUQ);
    381 
    382     psMetadataAddF32 (recipe, PS_LIST_TAIL, "ANGLE",    PS_META_REPLACE, "PSF angle",           axes.theta);
    383     psMetadataAddS32 (recipe, PS_LIST_TAIL, "NPSFSTAR", PS_META_REPLACE, "Number of stars used to make PSF", psf->nPSFstars);
    384     psMetadataAddBool(recipe, PS_LIST_TAIL, "PSFMODEL", PS_META_REPLACE, "Valid PSF Model?", true);
     439    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FWHM_MIN",   PS_META_REPLACE, "PSF FWHM Minor axis (mean)", stats->sampleMean);
     440    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MN_SG",   PS_META_REPLACE, "PSF FWHM Minor axis (sigma)", stats->sampleStdev);
     441    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MN_LQ",   PS_META_REPLACE, "PSF FWHM Minor axis (lower quartile)", stats->sampleLQ);
     442    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MN_UQ",   PS_META_REPLACE, "PSF FWHM Minor axis (upper quartile)", stats->sampleUQ);
     443
     444    float fwhmMin = stats->sampleMean;  // FWHM on minor axis
     445    if (readout->parent) {
     446        pmChip *chip = readout->parent->parent; // Parent chip
     447        psAssert(chip, "Cell should be attached to a chip.");
     448        psMetadataItem *item = psMetadataLookup(chip->concepts, "CHIP.SEEING"); // Item with chip
     449        item->data.F32 = 0.5 * (fwhmMaj + fwhmMin);
     450    }
     451
     452    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "ANGLE",    PS_META_REPLACE, "PSF angle",           axes.theta);
     453    psMetadataAddS32 (readout->analysis, PS_LIST_TAIL, "NPSFSTAR", PS_META_REPLACE, "Number of stars used to make PSF", psf->nPSFstars);
     454    psMetadataAddBool(readout->analysis, PS_LIST_TAIL, "PSFMODEL", PS_META_REPLACE, "Valid PSF Model?", true);
    385455
    386456    psFree (fwhmMajor);
     
    391461
    392462// determine approximate PSF shape parameters based on the moments
    393 bool psphotMomentsStats (pmReadout *readout, psMetadata *recipe, psArray *sources) {
     463bool psphotMomentsStats (pmReadout *readout, psArray *sources) {
    394464
    395465    // without the PSF model, we can only rely on the source->moments
     
    405475
    406476    PS_ASSERT_PTR_NON_NULL(readout, false);
    407     PS_ASSERT_PTR_NON_NULL(recipe, false);
    408477    PS_ASSERT_PTR_NON_NULL(sources, false);
    409478
     
    433502    FWHM_T /= FWHM_N;
    434503
    435     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FWHM_MAJ",   PS_META_REPLACE, "PSF FWHM Major axis (mean)", FWHM_X);
    436     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MJ_SG",   PS_META_REPLACE, "PSF FWHM Major axis (sigma)", 0);
    437     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MJ_LQ",   PS_META_REPLACE, "PSF FWHM Major axis (lower quartile)", 0);
    438     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MJ_UQ",   PS_META_REPLACE, "PSF FWHM Major axis (upper quartile)", 0);
    439 
    440     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FWHM_MIN",   PS_META_REPLACE, "PSF FWHM Minor axis (mean)", FWHM_Y);
    441     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MN_SG",   PS_META_REPLACE, "PSF FWHM Minor axis (sigma)", 0);
    442     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MN_LQ",   PS_META_REPLACE, "PSF FWHM Minor axis (lower quartile)", 0);
    443     psMetadataAddF32 (recipe, PS_LIST_TAIL, "FW_MN_UQ",   PS_META_REPLACE, "PSF FWHM Minor axis (upper quartile)", 0);
    444 
    445     psMetadataAddF32 (recipe, PS_LIST_TAIL, "ANGLE",    PS_META_REPLACE, "PSF angle",           FWHM_T);
    446     psMetadataAddS32 (recipe, PS_LIST_TAIL, "NPSFSTAR", PS_META_REPLACE, "Number of stars used to make PSF", 0);
    447     psMetadataAddBool(recipe, PS_LIST_TAIL, "PSFMODEL", PS_META_REPLACE, "Valid PSF Model?", false);
     504    if (readout->parent) {
     505        pmChip *chip = readout->parent->parent; // Parent chip
     506        psAssert(chip, "Cell should be attached to a chip.");
     507        psMetadataItem *item = psMetadataLookup(chip->concepts, "CHIP.SEEING"); // Item with chip
     508        item->data.F32 = 0.5 * (FWHM_X + FWHM_Y);
     509    }
     510
     511    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FWHM_MAJ",   PS_META_REPLACE, "PSF FWHM Major axis (mean)", FWHM_X);
     512    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MJ_SG",   PS_META_REPLACE, "PSF FWHM Major axis (sigma)", 0);
     513    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MJ_LQ",   PS_META_REPLACE, "PSF FWHM Major axis (lower quartile)", 0);
     514    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MJ_UQ",   PS_META_REPLACE, "PSF FWHM Major axis (upper quartile)", 0);
     515    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FWHM_MIN",   PS_META_REPLACE, "PSF FWHM Minor axis (mean)", FWHM_Y);
     516    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MN_SG",   PS_META_REPLACE, "PSF FWHM Minor axis (sigma)", 0);
     517    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MN_LQ",   PS_META_REPLACE, "PSF FWHM Minor axis (lower quartile)", 0);
     518    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "FW_MN_UQ",   PS_META_REPLACE, "PSF FWHM Minor axis (upper quartile)", 0);
     519    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "ANGLE",    PS_META_REPLACE, "PSF angle",           FWHM_T);
     520    psMetadataAddS32 (readout->analysis, PS_LIST_TAIL, "NPSFSTAR", PS_META_REPLACE, "Number of stars used to make PSF", 0);
     521    psMetadataAddBool(readout->analysis, PS_LIST_TAIL, "PSFMODEL", PS_META_REPLACE, "Valid PSF Model?", false);
    448522
    449523    return true;
  • branches/simtest_nebulous_branches/psphot/src/psphotCleanup.c

    r24144 r27840  
    1414    psFree (config);
    1515
    16     psThreadPoolFinalize ();
    17     psTimerStop ();
    1816    psMemCheckCorruption (stderr, true);
    1917    pmModelClassCleanup ();
    20     psTimeFinalize ();
    2118    pmSourceFitSetDone ();
    2219    pmConceptsDone ();
  • branches/simtest_nebulous_branches/psphot/src/psphotCullPeaks.c

    r24877 r27840  
    55 */
    66psErrorCode
    7 psphotCullPeaks(const psImage *image,   // the image wherein lives the footprint
    8                 const psImage *weight,  // corresponding variance image
     7psphotCullPeaks(const pmReadout *readout,   // the image wherein lives the footprint
    98                const psMetadata *recipe,
    109                psArray *footprints) {  // array of pmFootprints
     10
    1111    bool status = false;
     12
    1213    float nsigma_delta = psMetadataLookupF32(&status, recipe, "FOOTPRINT_CULL_NSIGMA_DELTA");
    1314    if (!status) {
     
    2223        fPadding = 0;
    2324    }
    24     const float skyStdev = psMetadataLookupF32(NULL, recipe, "SKY_STDEV");
     25    const float skyStdev = psMetadataLookupF32(&status, readout->analysis, "SKY_STDEV");
     26    psAssert (status, "cannot find SKY_STDEV in readout->analysis");
     27
    2528    const float min_threshold = nsigma_min*skyStdev;
    2629   
    2730    for (int i = 0; i < footprints->n; i++) {
     31        // if (i % 50 == 0) fprintf (stderr, "cull %d\n", i);
    2832        pmFootprint *fp = footprints->data[i];
    29         if (pmFootprintCullPeaks(image, weight, fp, nsigma_delta, fPadding, min_threshold) != PS_ERR_NONE) {
     33        if (fp->npix > 30000) {
     34            fprintf (stderr, "big footprint: %f %f to %f %f (%d pix)\n", fp->bbox.x0, fp->bbox.y0, fp->bbox.x1, fp->bbox.y1, fp->npix);
     35        }
     36        psTimerStart ("psphot.cull.footprints");
     37        if (pmFootprintCullPeaks(readout->image, readout->variance, fp, nsigma_delta, fPadding, min_threshold) != PS_ERR_NONE) {
    3038            return psError(PS_ERR_UNKNOWN, false, "Culling pmFootprint %d", fp->id);
    3139        }
     40        float dtime = psTimerMark ("psphot.cull.footprints");
     41        if (dtime > 1.0) {
     42            fprintf (stderr, "slow cull for %d (%f sec)\n", i, dtime);
     43        }
    3244    }
    33    
    3445    return PS_ERR_NONE;
    3546}
     47
     48// psLogMsg ("psphot", PS_LOG_INFO, "%ld peaks, %ld total footprints: %f sec\n", detections->peaks->n, detections->footprints->n,
  • branches/simtest_nebulous_branches/psphot/src/psphotDeblendSatstars.c

    r24889 r27840  
    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");
     
    4989        psVector *xVec = contour->data[0];
    5090        psVector *yVec = contour->data[1];
    51         if (xVec->n < 5) continue;
     91        if (xVec->n < 5) {
     92            psFree(contour);
     93            continue;
     94        }
    5295
    5396        // find the center of the contour (let's just use mid[x,y])
  • branches/simtest_nebulous_branches/psphot/src/psphotDefineFiles.c

    r23688 r27840  
    126126    }
    127127
     128    if (psMetadataLookupPtr(NULL, config->arguments, "SRCTEXT")) {
     129        // XXX cannot use pmFPAfileDefineFromArgs: this is explicitly a FITS-based I/O function
     130        // supply the attach the
     131        if (!psphotLoadSRCTEXT(input->fpa, config)) {
     132            psError(PSPHOT_ERR_CONFIG, false, "Failed to load PSPHOT.INPUT.TEXT");
     133            return status;
     134        }
     135    }
     136
    128137    if (psMetadataLookupPtr(NULL, config->arguments, "PSPHOT.PSF")) {
    129138        pmFPAfileBindFromArgs(&status, input, config, "PSPHOT.PSF.LOAD", "PSPHOT.PSF");
  • branches/simtest_nebulous_branches/psphot/src/psphotDiagnosticPlots.c

    r23989 r27840  
    6868    if (!psVectorStats (stats, histogram->nums, NULL, NULL, 0)) {
    6969        psError(PS_ERR_UNKNOWN, false, "failure to measure stats for histogram");
     70        psFree(histogram);
    7071        return false;
    7172    }
     
    108109    if (!psVectorStats (stats, histogram->nums, NULL, NULL, 0)) {
    109110        psError(PS_ERR_UNKNOWN, false, "failure to measure stats for histogram");
     111        psFree(histogram);
    110112        return false;
    111113    }
  • branches/simtest_nebulous_branches/psphot/src/psphotErrorCodes.dat

    r11308 r27840  
    22# This file is used to generate psphotErrorClasses.h
    33#
     4BASE = 3000             First value we use
    45UNKNOWN                 Unknown PM error code
    56NOT_IMPLEMENTED         Desired feature is not yet implemented
  • branches/simtest_nebulous_branches/psphot/src/psphotExtendedSourceAnalysis.c

    r21519 r27840  
    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    psTimerStart ("psphot.extended");
     42
     43    // find the currently selected readout
     44    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     45    psAssert (file, "missing file?");
     46
     47    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     48    psAssert (readout, "missing readout?");
     49
     50    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     51    psAssert (detections, "missing detections?");
     52
     53    psArray *sources = detections->allSources;
     54    psAssert (sources, "missing sources?");
     55
     56    if (!sources->n) {
     57        psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping source size");
     58        return true;
     59    }
     60
    1361    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
    1462    psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
    1563    assert (maskVal);
    1664
    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     }
     65    // XXX require petrosian analysis for non-linear fits?
    2266
    23     // option to limit analysis to a specific region
    24     char *region = psMetadataLookupStr (&status, recipe, "ANALYSIS_REGION");
    25     psRegion AnalysisRegion = psRegionForImage (readout->image, psRegionFromString (region));
    26     if (psRegionIsNaN (AnalysisRegion)) psAbort("analysis region mis-defined");
     67    // XXX temporary user-supplied systematic sky noise measurement (derive from background model)
     68    float skynoise = psMetadataLookupF32 (&status, recipe, "SKY.NOISE");
    2769
    2870    // S/N limit to perform full non-linear fits
     
    3577    bool doKron         = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_KRON");
    3678
     79# if (0)
     80    // if backModel or backStdev are missing, the values of sky and/or skyErr will be set to NAN
     81    // XXX use this to set skynoise
     82    pmReadout *backModel = psphotSelectBackground (config, view);
     83    pmReadout *backStdev = psphotSelectBackgroundStdev (config, view);
     84# endif
     85
    3786    // source analysis is done in S/N order (brightest first)
    3887    sources = psArraySort (sources, pmSourceSortBySN);
    3988
    40     // XXX some init functions for the extended source recipe options?
     89    // option to limit analysis to a specific region
     90    char *region = psMetadataLookupStr (&status, recipe, "ANALYSIS_REGION");
     91    psRegion AnalysisRegion = psRegionForImage (readout->image, psRegionFromString (region));
     92    if (psRegionIsNaN (AnalysisRegion)) psAbort("analysis region mis-defined");
    4193
    4294    // choose the sources of interest
     
    49101        if (source->type == PM_SOURCE_TYPE_DEFECT) continue;
    50102        if (source->type == PM_SOURCE_TYPE_SATURATED) continue;
     103        if (source->mode & PM_SOURCE_MODE_DEFECT) continue;
     104        if (source->mode & PM_SOURCE_MODE_SATSTAR) continue;
     105        if (!(source->mode & PM_SOURCE_MODE_EXT_LIMIT)) continue;
    51106
    52107        // limit selection to some SN limit
     
    66121        Next ++;
    67122
     123        // force source image to be a bit larger...
     124        float radius = source->peak->xf - source->pixels->col0;
     125        radius = PS_MAX (radius, source->peak->yf - source->pixels->row0);
     126        radius = PS_MAX (radius, source->pixels->numRows - source->peak->yf + source->pixels->row0);
     127        radius = PS_MAX (radius, source->pixels->numCols - source->peak->xf + source->pixels->col0);
     128        pmSourceRedefinePixels (source, readout, source->peak->xf, source->peak->yf, 1.5*radius);
     129
    68130        // if we request any of these measurements, we require the radial profile
    69131        if (doPetrosian || doIsophotal || doAnnuli || doKron) {
    70             if (!psphotRadialProfile (source, recipe, maskVal)) {
     132            if (!psphotRadialProfile (source, recipe, skynoise, maskVal)) {
    71133                // all measurements below require the radial profile; skip them all
    72134                // re-subtract the object, leave local sky
    73135                psTrace ("psphot", 5, "failed to extract radial profile for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
    74136                pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    75                 source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
    76137                continue;
    77138            }
     
    79140        }
    80141
     142        // Petrosian Mags
     143        if (doPetrosian) {
     144            if (!psphotPetrosian (source, recipe, skynoise, maskVal)) {
     145                psTrace ("psphot", 5, "FAILED petrosian flux & radius for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
     146            } else {
     147                psTrace ("psphot", 5, "measured petrosian flux & radius for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
     148                Npetro ++;
     149                source->mode |= PM_SOURCE_MODE_EXTENDED_STATS;
     150            }
     151        }
     152
     153# if (0)
    81154        // Isophotal Mags
    82155        if (doIsophotal) {
     
    89162            }
    90163        }
    91 
    92         // Petrosian Mags
    93         if (doPetrosian) {
    94             if (!psphotPetrosian (source, recipe, maskVal)) {
    95                 psTrace ("psphot", 5, "measured petrosian flux & radius for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
    96             } else {
    97                 psTrace ("psphot", 5, "measured petrosian flux & radius for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
    98                 Npetro ++;
    99                 source->mode |= PM_SOURCE_MODE_EXTENDED_STATS;
    100             }
    101         }
    102 
    103164        // Kron Mags
    104165        if (doKron) {
     
    111172            }
    112173        }
    113 
    114         // Radial Annuli
    115         if (doAnnuli) {
    116             if (!psphotAnnuli (source, recipe, maskVal)) {
    117                 psError(PSPHOT_ERR_UNKNOWN, false, "failure in Annuli analysis");
    118                 return false;
    119             }
    120             psTrace ("psphot", 5, "measured annuli for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
    121             Nannuli ++;
    122             source->mode |= PM_SOURCE_MODE_EXTENDED_STATS;
    123         }
     174# endif
    124175
    125176        // re-subtract the object, leave local sky
    126177        pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    127         source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
     178
     179        if (source->extpars) {
     180            psFree(source->extpars->radFlux);
     181            psFree(source->extpars->ellipticalFlux);
     182        }
    128183    }
    129184
    130     psLogMsg ("psphot", PS_LOG_INFO, "extended source analysis: %f sec for %d objects\n", psTimerMark ("psphot"), Next);
     185    psLogMsg ("psphot", PS_LOG_INFO, "extended source analysis: %f sec for %d objects\n", psTimerMark ("psphot.extended"), Next);
    131186    psLogMsg ("psphot", PS_LOG_INFO, "  %d petrosian\n", Npetro);
    132187    psLogMsg ("psphot", PS_LOG_INFO, "  %d isophotal\n", Nisophot);
    133188    psLogMsg ("psphot", PS_LOG_INFO, "  %d annuli\n", Nannuli);
    134189    psLogMsg ("psphot", PS_LOG_INFO, "  %d kron\n", Nkron);
     190
     191    psphotVisualShowResidualImage (readout);
     192
     193    if (doPetrosian) {
     194        psphotVisualShowPetrosians (sources);
     195    }
     196
    135197    return true;
    136198}
  • branches/simtest_nebulous_branches/psphot/src/psphotExtendedSourceFits.c

    r21519 r27840  
    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
     
    226266
    227267          pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    228           source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
    229268
    230269          psFree (modelFluxes);
     
    253292        // subtract the best fit from the object, leave local sky
    254293        pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    255         source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
    256294
    257295        // the initial model flux is no longer needed
  • branches/simtest_nebulous_branches/psphot/src/psphotFindDetections.c

    r21183 r27840  
    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, 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
  • branches/simtest_nebulous_branches/psphot/src/psphotFindFootprints.c

    r24274 r27840  
    11# include "psphotInternal.h"
    22
    3 bool psphotFindFootprints (pmDetections *detections, psImage *significance, pmReadout *readout, psMetadata *recipe, const int pass, psImageMaskType maskVal) {
     3bool psphotFindFootprints (pmDetections *detections, psImage *significance, pmReadout *readout, psMetadata *recipe, const float threshold, const int pass, psImageMaskType maskVal) {
    44
    55    bool status;
     
    99    int npixMin = psMetadataLookupS32(&status, recipe, "FOOTPRINT_NPIXMIN");
    1010    PS_ASSERT (status, false);
    11 
    12     float FOOTPRINT_NSIGMA_LIMIT;
    13     if (pass == 1) {
    14         FOOTPRINT_NSIGMA_LIMIT = psMetadataLookupS32(&status, recipe, "FOOTPRINT_NSIGMA_LIMIT");
    15     } else {
    16         FOOTPRINT_NSIGMA_LIMIT = psMetadataLookupS32(&status, recipe, "FOOTPRINT_NSIGMA_LIMIT_2");
    17     }
    18     PS_ASSERT (status, false);
    19 
    20     // XXX do we need to use the same threshold here as for peaks?  does it make sense for
    21     // these to be different?
    22 
    23     float threshold = PS_SQR(FOOTPRINT_NSIGMA_LIMIT);
    2411
    2512    int growRadius = 0;
     
    5441    if (pass == 2) {
    5542        // merge in old peaks;
    56         const int includePeaks = 0x0 | 0x2; // i.e. just from newFootprints
    57 
    58         // 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
    5944
    6045        psArray *mergedFootprints = pmFootprintArraysMerge(detections->footprints, footprints, includePeaks);
     
    6348        psFree(footprints);
    6449        psFree(detections->footprints);
     50
     51        // replace the merged footprints on the detection structure
    6552        detections->footprints = mergedFootprints;
    6653    } else {
     
    6855    }
    6956
    70     psphotCullPeaks(readout->image, readout->variance, recipe, detections->footprints);
     57    psphotCullPeaks(readout, recipe, detections->footprints);
    7158    detections->peaks = pmFootprintArrayToPeaks(detections->footprints);
    7259    psLogMsg ("psphot", PS_LOG_INFO, "%ld peaks, %ld total footprints: %f sec\n", detections->peaks->n, detections->footprints->n, psTimerMark ("psphot.footprints"));
     
    7461    return detections;
    7562}
     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}
  • branches/simtest_nebulous_branches/psphot/src/psphotFindPeaks.c

    r21519 r27840  
    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
     
    3136        peak->SN = sqrt(peak->value);
    3237        peak->flux = readout->image->data.F32[peak->y-row0][peak->x-col0];
     38        // if (peak->flux / peak->value > 5.0/12.0) {
     39        //     psWarning ("odd peak levels (1)");
     40        // }
     41        // if (peak->value / peak->flux > 5*12.0) {
     42        //     psWarning ("odd peak levels (2)");
     43        // }
    3344        if (readout->variance && isfinite (peak->dx)) {
    3445            peak->dx *= sqrt(readout->variance->data.F32[peak->y-row0][peak->x-col0]);
  • branches/simtest_nebulous_branches/psphot/src/psphotFitSourcesLinear.c

    r23445 r27840  
    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, psMetadata *recipe, 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    // select the appropriate recipe information
     20    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     21    assert (recipe);
     22
     23    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     24    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     25
     26    // loop over the available readouts
     27    for (int i = 0; i < num; i++) {
     28
     29        // find the currently selected readout
     30        pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PSPHOT.INPUT", i); // File of interest
     31        psAssert (file, "missing file?");
     32
     33        pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     34        psAssert (readout, "missing readout?");
     35
     36        pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     37        psAssert (detections, "missing detections?");
     38
     39        psArray *sources = detections->allSources;
     40        psAssert (sources, "missing sources?");
     41
     42        pmPSF *psf = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF");
     43        psAssert (psf, "missing psf?");
     44
     45        if (!psphotFitSourcesLinearReadout (recipe, readout, sources, psf, final)) {
     46            psError (PSPHOT_ERR_CONFIG, false, "failed to fit sources (linear) for PSPHOT.INPUT entry %d", i);
     47            return false;
     48        }
     49    }
     50    return true;
     51}
     52
     53bool psphotFitSourcesLinearReadout (psMetadata *recipe, pmReadout *readout, psArray *sources, pmPSF *psf, bool final) {
    1554
    1655    bool status;
     
    1857    float y;
    1958    float f;
    20     // float r;
     59
     60    if (!sources->n) {
     61        psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping linear fit");
     62        return true;
     63    }
    2164
    2265    psTimerStart ("psphot.linear");
     
    59102    }
    60103
     104    // XXX test: choose a larger-than expected radius:
     105    float covarFactor = psImageCovarianceFactorForAperture(readout->covariance, 10.0); // Covariance matrix
     106    psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "covariance factor: %f\n", covarFactor);
     107
     108    // XXX do not apply covarFactor for the moment...
     109    // covarFactor = 1.0;
     110
    61111    // select the sources which will be used for the fitting analysis
    62112    for (int i = 0; i < sources->n; i++) {
     
    76126            if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) continue;
    77127        } else {
    78             if (source->mode & PM_SOURCE_MODE_BLEND) continue;
     128            // if (source->mode & PM_SOURCE_MODE_BLEND) continue;
    79129        }
    80130
     
    120170
    121171        // diagonal elements of the sparse matrix (auto-cross-product)
    122         f = pmSourceModelDotModel (SRCi, SRCi, CONSTANT_PHOTOMETRIC_WEIGHTS);
     172        f = pmSourceModelDotModel (SRCi, SRCi, CONSTANT_PHOTOMETRIC_WEIGHTS, covarFactor);
    123173        psSparseMatrixElement (sparse, i, i, f);
    124174
    125175        // the formal error depends on the weighting scheme
    126176        if (CONSTANT_PHOTOMETRIC_WEIGHTS) {
    127             float var = pmSourceModelDotModel (SRCi, SRCi, false);
     177            float var = pmSourceModelDotModel (SRCi, SRCi, false, covarFactor);
    128178            errors->data.F32[i] = 1.0 / sqrt(var);
    129179        } else {
     
    133183
    134184        // find the image x model value
    135         f = pmSourceDataDotModel (SRCi, SRCi, CONSTANT_PHOTOMETRIC_WEIGHTS);
     185        f = pmSourceDataDotModel (SRCi, SRCi, CONSTANT_PHOTOMETRIC_WEIGHTS, covarFactor);
    136186        psSparseVectorElement (sparse, i, f);
    137187
     
    139189        switch (SKY_FIT_ORDER) {
    140190          case 1:
    141             f = pmSourceModelWeight (SRCi, 1, CONSTANT_PHOTOMETRIC_WEIGHTS);
     191            f = pmSourceModelWeight (SRCi, 1, CONSTANT_PHOTOMETRIC_WEIGHTS, covarFactor);
    142192            psSparseBorderElementB (border, i, 1, f);
    143             f = pmSourceModelWeight (SRCi, 2, CONSTANT_PHOTOMETRIC_WEIGHTS);
     193            f = pmSourceModelWeight (SRCi, 2, CONSTANT_PHOTOMETRIC_WEIGHTS, covarFactor);
    144194            psSparseBorderElementB (border, i, 2, f);
    145195
    146196          case 0:
    147             f = pmSourceModelWeight (SRCi, 0, CONSTANT_PHOTOMETRIC_WEIGHTS);
     197            f = pmSourceModelWeight (SRCi, 0, CONSTANT_PHOTOMETRIC_WEIGHTS, covarFactor);
    148198            psSparseBorderElementB (border, i, 0, f);
    149199            break;
     
    165215
    166216            // got an overlap; calculate cross-product and add to output array
    167             f = pmSourceModelDotModel (SRCi, SRCj, CONSTANT_PHOTOMETRIC_WEIGHTS);
     217            f = pmSourceModelDotModel (SRCi, SRCj, CONSTANT_PHOTOMETRIC_WEIGHTS, covarFactor);
    168218            psSparseMatrixElement (sparse, j, i, f);
    169219        }
     
    186236    if (SKY_FIT_LINEAR) {
    187237        psSparseBorderSolve (&norm, &skyfit, constraint, border, 5);
    188         fprintf (stderr, "skyfit: %f\n", skyfit->data.F32[0]);
     238        psLogMsg ("psphot", PS_LOG_MINUTIA, "skyfit: %f\n", skyfit->data.F32[0]);
    189239    } else {
    190240        norm = psSparseSolve (NULL, constraint, sparse, 5);
     
    215265        // subtract object
    216266        pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    217         source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
    218267    }
    219268    psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "sub models: %f sec (%d elements)\n", psTimerMark ("psphot.linear"), sparse->Nelem);
    220269
    221270    // measure chisq for each source
    222     for (int i = 0; final && (i < fitSources->n); i++) {
     271    // for (int i = 0; final && (i < fitSources->n); i++) {
     272    for (int i = 0; i < fitSources->n; i++) {
    223273        pmSource *source = fitSources->data[i];
    224274        if (source->mode & PM_SOURCE_MODE_NONLINEAR_FIT) continue;
    225275        pmModel *model = pmSourceGetModel (NULL, source);
    226         pmSourceChisq (model, source->pixels, source->maskObj, source->variance, maskVal);
     276        pmSourceChisq (model, source->pixels, source->maskObj, source->variance, maskVal, covarFactor);
    227277    }
    228278    psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "get chisqs: %f sec (%d elements)\n", psTimerMark ("psphot.linear"), sparse->Nelem);
     
    239289
    240290    psphotVisualShowResidualImage (readout);
    241     psphotVisualShowFlags (sources);
     291    psphotVisualPlotChisq (sources);
     292    // 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);
    242297
    243298    return true;
     
    245300
    246301// XXX do we need this?
     302// XXX disallow the simultaneous sky fit and remove this code...
    247303
    248304// Calculate the weight terms for the sky fit component of the matrix.  This function operates
     
    264320        float x = model->params->data.F32[PM_PAR_XPOS];
    265321        float y = model->params->data.F32[PM_PAR_YPOS];
    266         psImageMaskCircle (source->maskView, x, y, model->radiusFit, "AND", PS_NOT_IMAGE_MASK(markVal));
     322        psImageMaskCircle (source->maskView, x, y, model->fitRadius, "AND", PS_NOT_IMAGE_MASK(markVal));
    267323    }
    268324
  • branches/simtest_nebulous_branches/psphot/src/psphotFitSourcesLinearStack.c

    r24584 r27840  
    11# include "psphotInternal.h"
     2// XXX need array of covar factors for each image
     3// XXX define the 'good' / 'bad' flags?
    24
    3 // fit flux (and optionally sky model) to all reasonable sources
    4 // with the linear fitting process.  sources must have an associated
    5 // model with selected pixels, and the fit radius must be defined
     5# define COVAR_FACTOR 1.0
    66
    7 // given the set of sources, each of which points to the pixels in the
    8 // science image, we construct a set of simulated sources with their own pixels.
    9 // these are used to determine the simultaneous linear fit of fluxes.
    10 // the analysis is performed wrt the simulated pixel values
    11 
    12 static bool SetBorderMatrixElements (psSparseBorder *border, pmReadout *readout, psArray *sources, bool constant_weights, psImageMaskType markVal);
    13 
    14 bool psphotFitSourcesLinear (pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, bool final) {
     7bool psphotFitSourcesLinearStack (pmConfig *config, psArray *objects, bool final) {
    158
    169    bool status;
    17     float x;
    18     float y;
    1910    float f;
    20     // float r;
     11
     12    // select the appropriate recipe information
     13    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     14    assert (recipe);
    2115
    2216    psTimerStart ("psphot.linear");
     
    3327    maskVal |= markVal;
    3428
    35     // source analysis is done in spatial order
    36     sources = psArraySort (sources, pmSourceSortByY);
     29    // analysis is done in spatial order (to speed up overlap search)
     30    // sort by first element in each source list
     31    objects = psArraySort (objects, pmPhotObjSortByX);
    3732
    3833    // storage array for fitSources
    39     psArray *fitSources = psArrayAllocEmpty (sources->n);
     34    psArray *fitSources = psArrayAllocEmpty (objects->n);
    4035
    41     bool CONSTANT_PHOTOMETRIC_WEIGHTS =
    42         psMetadataLookupBool(&status, recipe, "CONSTANT_PHOTOMETRIC_WEIGHTS");
    43     if (!status) {
    44         psAbort("You must provide a value for the BOOL recipe CONSTANT_PHOTOMETRIC_WEIGHTS");
    45     }
     36    bool CONSTANT_PHOTOMETRIC_WEIGHTS = psMetadataLookupBool(&status, recipe, "CONSTANT_PHOTOMETRIC_WEIGHTS");
     37    psAssert (status, "You must provide a value for the BOOL recipe CONSTANT_PHOTOMETRIC_WEIGHTS");
     38
     39    // XXX store a local static array of covar factors for each of the images (by image ID)
     40    // float covarFactor = psImageCovarianceFactorForAperture(readout->covariance, 10.0); // Covariance matrix
     41    // psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "covariance factor: %f\n", covarFactor);
    4642
    4743    // select the sources which will be used for the fitting analysis
    48     for (int i = 0; i < sources->n; i++) {
    49         pmSource *source = sources->data[i];
     44    for (int i = 0; i < objects->n; i++) {
     45        pmPhotObj *object = objects->data[i];
     46        if (!object) continue;
     47        if (!object->sources) continue;
    5048
    51         // turn this bit off and turn it on again if we pass this test
    52         source->mode &= ~PM_SOURCE_MODE_LINEAR_FIT;
     49        // XXX check an element of the group to see if we should use it
     50        // if (!object->flags & PM_PHOT_OBJ_BAD) continue;
    5351
    54         // skip non-astronomical objects (very likely defects)
    55         if (source->type == PM_SOURCE_TYPE_DEFECT) continue;
    56         if (source->type == PM_SOURCE_TYPE_SATURATED) continue;
     52        for (int j = 0; j < object->sources->n; j++) {
     53          pmSource *source = object->sources->data[j];
     54          if (!source) continue;
    5755
    58         // do not include CRs in the full ensemble fit
    59         if (source->mode & PM_SOURCE_MODE_CR_LIMIT) continue;
     56          // turn this bit off and turn it on again if we keep this source
     57          source->mode &= ~PM_SOURCE_MODE_LINEAR_FIT;
    6058
    61         if (final) {
    62             if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) continue;
    63         } else {
    64             if (source->mode & PM_SOURCE_MODE_BLEND) continue;
    65         }
     59          // generate model for sources without, or skip if we can't
     60          if (!source->modelFlux) {
     61            if (!pmSourceCacheModel (source, maskVal)) continue;
     62          }
    6663
    67         // generate model for sources without, or skip if we can't
    68         if (!source->modelFlux) {
    69             if (!pmSourceCacheModel (source, maskVal)) continue;
    70         }
    71 
    72         source->mode |= PM_SOURCE_MODE_LINEAR_FIT;
    73         psArrayAdd (fitSources, 100, source);
     64          source->mode |= PM_SOURCE_MODE_LINEAR_FIT;
     65          psArrayAdd (fitSources, 100, source);
     66        }
    7467    }
    75     psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "built fitSources: %f sec (%ld objects)\n", psTimerMark ("psphot.linear"), sources->n);
     68    psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "built fitSources: %f sec (%ld objects)\n", psTimerMark ("psphot.linear"), objects->n);
    7669
    7770    if (fitSources->n == 0) {
     
    8376    psVector *errors = psVectorAlloc (fitSources->n, PS_TYPE_F32);
    8477
    85     // create the border matrix (includes the sparse matrix)
    86     // for just sky: 1 row; for x,y terms: 3 rows
     78    // create the sparse matrix
    8779    psSparse *sparse = psSparseAlloc (fitSources->n, 100);
    88     psSparseBorder *border = psSparseBorderAlloc (sparse, 1);
    8980
    9081    // fill out the sparse matrix elements and border elements (B)
     
    9586
    9687        // diagonal elements of the sparse matrix (auto-cross-product)
    97         f = pmSourceModelDotModel (SRCi, SRCi, CONSTANT_PHOTOMETRIC_WEIGHTS);
     88        f = pmSourceModelDotModel (SRCi, SRCi, CONSTANT_PHOTOMETRIC_WEIGHTS, COVAR_FACTOR);
    9889        psSparseMatrixElement (sparse, i, i, f);
    9990
    10091        // the formal error depends on the weighting scheme
    10192        if (CONSTANT_PHOTOMETRIC_WEIGHTS) {
    102             float var = pmSourceModelDotModel (SRCi, SRCi, false);
     93            float var = pmSourceModelDotModel (SRCi, SRCi, false, COVAR_FACTOR);
    10394            errors->data.F32[i] = 1.0 / sqrt(var);
    10495        } else {
     
    10697        }
    10798
    108 
    10999        // find the image x model value
    110         f = pmSourceDataDotModel (SRCi, SRCi, CONSTANT_PHOTOMETRIC_WEIGHTS);
     100        f = pmSourceDataDotModel (SRCi, SRCi, CONSTANT_PHOTOMETRIC_WEIGHTS, COVAR_FACTOR);
    111101        psSparseVectorElement (sparse, i, f);
    112 
    113         f = pmSourceModelWeight (SRCi, 0, CONSTANT_PHOTOMETRIC_WEIGHTS);
    114         psSparseBorderElementB (border, i, 0, f);
    115102
    116103        // loop over all other stars following this one
     
    118105            pmSource *SRCj = fitSources->data[j];
    119106
     107            // we only need to generate dot terms for source on the same image
     108            if (SRCj->imageID != SRCi->imageID) { continue; }
     109
    120110            // skip over disjoint source images, break after last possible overlap
    121             if (SRCi->pixels->row0 + SRCi->pixels->numRows < SRCj->pixels->row0) break;
    122             if (SRCj->pixels->row0 + SRCj->pixels->numRows < SRCi->pixels->row0) continue;
    123             if (SRCi->pixels->col0 + SRCi->pixels->numCols < SRCj->pixels->col0) continue;
    124             if (SRCj->pixels->col0 + SRCj->pixels->numCols < SRCi->pixels->col0) continue;
     111            if (SRCj->pixels->row0 + SRCj->pixels->numRows < SRCi->pixels->row0) continue;  // source(i) is above source(j)
     112            if (SRCi->pixels->row0 + SRCi->pixels->numRows < SRCj->pixels->row0) continue;  // source(i) is below source(j)
     113            if (SRCj->pixels->col0 + SRCj->pixels->numCols < SRCi->pixels->col0) continue;  // source(i) is right of source(j)
     114            if (SRCi->pixels->col0 + SRCi->pixels->numCols < SRCj->pixels->col0) break;     // source(i) is left of source(j) [no other source(j) can overlap source(i)]
    125115
    126116            // got an overlap; calculate cross-product and add to output array
    127             f = pmSourceModelDotModel (SRCi, SRCj, CONSTANT_PHOTOMETRIC_WEIGHTS);
     117            f = pmSourceModelDotModel (SRCi, SRCj, CONSTANT_PHOTOMETRIC_WEIGHTS, COVAR_FACTOR);
    128118            psSparseMatrixElement (sparse, j, i, f);
    129119        }
     
    133123    psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "built matrix: %f sec (%d elements)\n", psTimerMark ("psphot.linear"), sparse->Nelem);
    134124
    135     // set the sky, sky_x, sky_y components of border matrix
    136     SetBorderMatrixElements (border, readout, fitSources, CONSTANT_PHOTOMETRIC_WEIGHTS, SKY_FIT_ORDER, markVal);
    137 
    138125    psSparseConstraint constraint;
    139126    constraint.paramMin   = 0.0;
     
    142129
    143130    // solve for normalization terms (need include local sky?)
    144     psVector *norm = psSparseSolve (NULL, constraint, sparse, 5);
    145 
     131    psVector *norm = NULL;
     132    norm = psSparseSolve (NULL, constraint, sparse, 5);
    146133    psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "solve matrix: %f sec (%d elements)\n", psTimerMark ("psphot.linear"), sparse->Nelem);
    147 
    148     // XXXX **** philosophical question:
    149     // we measure bright objects in three passes: 1) linear fit; 2) non-linear fit; 3) linear fit:
    150     // should retain the chisq and errors from the intermediate non-linear fit?
    151     // the non-linear fit provides better values for the position errors, and for
    152     // extended sources, the shape errors
    153134
    154135    // adjust I0 for fitSources and subtract
     
    164145        model->params->data.F32[PM_PAR_I0] = norm->data.F32[i];
    165146        model->dparams->data.F32[PM_PAR_I0] = errors->data.F32[i];
    166         // XXX is the value of 'errors' modified by the sky fit?
    167147
    168148        // subtract object
    169149        pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    170         source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
    171150    }
    172151    psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "sub models: %f sec (%d elements)\n", psTimerMark ("psphot.linear"), sparse->Nelem);
    173152
    174153    // measure chisq for each source
    175     for (int i = 0; final && (i < fitSources->n); i++) {
     154    // for (int i = 0; final && (i < fitSources->n); i++) {
     155    for (int i = 0; i < fitSources->n; i++) {
    176156        pmSource *source = fitSources->data[i];
    177157        if (source->mode & PM_SOURCE_MODE_NONLINEAR_FIT) continue;
    178158        pmModel *model = pmSourceGetModel (NULL, source);
    179         pmSourceChisq (model, source->pixels, source->maskObj, source->variance, maskVal);
     159        pmSourceChisq (model, source->pixels, source->maskObj, source->variance, maskVal, COVAR_FACTOR);
    180160    }
    181161    psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "get chisqs: %f sec (%d elements)\n", psTimerMark ("psphot.linear"), sparse->Nelem);
     
    186166    psFree (norm);
    187167    psFree (errors);
    188     psFree (border);
    189168
    190169    psLogMsg ("psphot.ensemble", PS_LOG_INFO, "measure ensemble of PSFs: %f sec\n", psTimerMark ("psphot.linear"));
    191 
    192     psphotVisualShowResidualImage (readout);
    193     psphotVisualShowFlags (sources);
    194170
    195171    return true;
    196172}
    197173
    198 // Calculate the weight terms for the sky fit component of the matrix.  This function operates
    199 // on the pixels which correspond to all of the sources of interest.  These elements fill in
    200 // the border matrix components in the sparse matrix equation.
    201 static bool SetBorderMatrixElements (psSparseBorder *border, pmReadout *readout, psArray *sources, bool constant_weights, psImageMaskType markVal) {
     174// sort by X (ascending)
     175int pmPhotObjSortByX (const void **a, const void **b)
     176{
     177    pmPhotObj *objA = *(pmPhotObj **)a;
     178    pmPhotObj *objB = *(pmPhotObj **)b;
    202179
    203     // generate the image-wide weight terms
    204     // turn on MARK for all image pixels
    205     psRegion fullArray = psRegionSet (0, 0, 0, 0);
    206     fullArray = psRegionForImage (readout->mask, fullArray);
    207     psImageMaskRegion (readout->mask, fullArray, "OR", markVal);
     180    psF32 fA = objA->x;
     181    psF32 fB = objB->x;
    208182
    209     // turn off MARK for all object pixels
    210     for (int i = 0; i < sources->n; i++) {
    211         pmSource *source = sources->data[i];
    212         pmModel *model = pmSourceGetModel (NULL, source);
    213         if (model == NULL) continue;
    214         float x = model->params->data.F32[PM_PAR_XPOS];
    215         float y = model->params->data.F32[PM_PAR_YPOS];
    216         psImageMaskCircle (source->maskView, x, y, model->radiusFit, "AND", PS_NOT_IMAGE_MASK(markVal));
    217     }
    218 
    219     // accumulate the image statistics from the masked regions
    220     psF32 **image  = readout->image->data.F32;
    221     psF32 **variance = readout->variance->data.F32;
    222     psImageMaskType  **mask   = readout->mask->data.PS_TYPE_IMAGE_MASK_DATA;
    223 
    224     double w, x, y, x2, xy, y2, xc, yc, wt, f, fo, fx, fy;
    225     w = x = y = x2 = xy = y2 = fo = fx = fy = 0;
    226 
    227     int col0 = readout->image->col0;
    228     int row0 = readout->image->row0;
    229 
    230     for (int j = 0; j < readout->image->numRows; j++) {
    231         for (int i = 0; i < readout->image->numCols; i++) {
    232             if (mask[j][i]) continue;
    233             if (constant_weights) {
    234                 wt = 1.0;
    235             } else {
    236                 wt = variance[j][i];
    237             }
    238             f = image[j][i];
    239             w   += 1/wt;
    240             fo  += f/wt;
    241         }
    242     }
    243 
    244     // turn off MARK for all image pixels
    245     psImageMaskRegion (readout->mask, fullArray, "AND", PS_NOT_IMAGE_MASK(markVal));
    246 
    247     // set the Border T elements
    248     psSparseBorderElementG (border, 0, fo);
    249     psSparseBorderElementT (border, 0, 0, w);
    250 
    251     return true;
     183    psF32 diff = fA - fB;
     184    if (diff > FLT_EPSILON) return (+1);
     185    if (diff < FLT_EPSILON) return (-1);
     186    return (0);
    252187}
  • branches/simtest_nebulous_branches/psphot/src/psphotGuessModels.c

    r24876 r27840  
    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    // skip the chisq image (optionally?)
     18    int chisqNum = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.CHISQ.NUM");
     19    if (!status) chisqNum = -1;
     20
     21    // loop over the available readouts
     22    for (int i = 0; i < num; i++) {
     23        if (i == chisqNum) continue; // skip chisq image
     24        if (!psphotGuessModelsReadout (config, view, "PSPHOT.INPUT", i)) {
     25            psError (PSPHOT_ERR_CONFIG, false, "failed on to guess models for PSPHOT.INPUT entry %d", i);
     26            return false;
     27        }
     28    }
     29    return true;
     30}
     31
     32// construct an initial PSF model for each object (new sources only)
     33bool psphotGuessModelsReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index) {
    1134
    1235    bool status;
    1336
    1437    psTimerStart ("psphot.models");
     38
     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->newSources;
     50    psAssert (sources, "missing sources?");
     51
     52    if (!sources->n) {
     53        psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping model guess");
     54        return true;
     55    }
     56
     57    pmPSF *psf = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF");
     58    psAssert (psf, "missing psf?");
    1559
    1660    // select the appropriate recipe information
     
    2165    int nThreads = psMetadataLookupS32(&status, config->arguments, "NTHREADS"); // Number of threads
    2266    if (!status) {
    23         nThreads = 0;
     67        nThreads = 0;
    2468    }
    2569
     
    3680
    3781    // setup the PSF fit radius details
    38     psphotInitRadiusPSF (recipe, psf->type);
     82    psphotInitRadiusPSF (recipe, readout->analysis, psf->type);
    3983
    4084    // choose Cx, Cy (see psphotThreadTools.c for overview of the concepts)
     
    4690    for (int i = 0; i < cellGroups->n; i++) {
    4791
    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         }
     92        psArray *cells = cellGroups->data[i];
     93
     94        for (int j = 0; j < cells->n; j++) {
     95
     96            // allocate a job -- if threads are not defined, this just runs the job
     97            psThreadJob *job = psThreadJobAlloc ("PSPHOT_GUESS_MODEL");
     98            psArrayAdd(job->args, 1, readout);
     99            psArrayAdd(job->args, 1, cells->data[j]); // sources
     100            psArrayAdd(job->args, 1, psf);
     101
     102            // XXX change these to use abstract mask type info
     103            PS_ARRAY_ADD_SCALAR(job->args, maskVal,  PS_TYPE_IMAGE_MASK);
     104            PS_ARRAY_ADD_SCALAR(job->args, markVal,  PS_TYPE_IMAGE_MASK);
     105
     106            if (!psThreadJobAddPending(job)) {
     107                psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
     108                psFree (job);
     109                return false;
     110            }
     111            psFree(job);
     112        }
     113
     114        // wait for the threads to finish and manage results
     115        // wait here for the threaded jobs to finish
     116        // fprintf (stderr, "wait for threads (%d, %d)\n", jx, jy);
     117        if (!psThreadPoolWait (false)) {
     118            psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
     119            return false;
     120        }
     121
     122        // we have only supplied one type of job, so we can assume the types here
     123        psThreadJob *job = NULL;
     124        while ((job = psThreadJobGetDone()) != NULL) {
     125            // we have no returned data from this operation
     126            if (job->args->n < 1) {
     127                fprintf (stderr, "error with job\n");
     128            }
     129            psFree(job);
     130        }
    87131    }
    88132
     
    90134    int nMiss = 0;
    91135    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 ++;
     136        pmSource *source = sources->data[i];
     137        if (source->tmpFlags & PM_SOURCE_TMPF_MODEL_GUESS) {
     138            continue;
     139        }
     140        nMiss ++;
    97141    }
    98142    psAssert (nMiss == 0, "failed to attempt to build models for %d objects\n", nMiss);
     
    110154    psArray *sources   = job->args->data[1];
    111155    pmPSF *psf         = job->args->data[2];
    112    
     156
    113157    psImageMaskType maskVal = PS_SCALAR_VALUE(job->args->data[3],PS_TYPE_IMAGE_MASK_DATA);
    114158    psImageMaskType markVal = PS_SCALAR_VALUE(job->args->data[4],PS_TYPE_IMAGE_MASK_DATA);
     
    117161
    118162    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         source->modelPSF = modelPSF;
    180         source->modelPSF->residuals = psf->residuals;
    181 
    182         pmSourceCacheModel (source, maskVal);  // ALLOC x14 (!)
    183 
     163        pmSource *source = sources->data[i];
     164
     165        // this is used to mark sources for which the model is measured. We check later that
     166        // all are used.
     167        source->tmpFlags |= PM_SOURCE_TMPF_MODEL_GUESS;
     168
     169        // skip non-astronomical objects (very likely defects)
     170        if (source->type == PM_SOURCE_TYPE_DEFECT) continue;
     171        if (source->type == PM_SOURCE_TYPE_SATURATED) continue;
     172        if (!source->peak) continue;
     173
     174        nSrc ++;
     175
     176        // the guess central intensity comes from the peak:
     177        float Io = source->peak->flux;
     178
     179        // We have two options to get a guess for the object position: the position from the
     180        // peak and the position from the moments.  Use the peak position if (a) there are no
     181        // moments and (b) the sources is not saturated
     182
     183        bool useMoments = false;
     184        useMoments = (source->mode & PM_SOURCE_MODE_SATSTAR);  // we only want to try if SATSTAR is set, but..
     185        useMoments = (useMoments && source->moments);          // can't if there are no moments
     186        useMoments = (useMoments && source->moments->nPixels); // can't if the moments were not measured
     187        useMoments = (useMoments && !(source->mode && PM_SOURCE_MODE_MOMENTS_FAILURE)); // can't if the moments failed...
     188
     189        float Xo, Yo;
     190        if (useMoments) {
     191            Xo = source->moments->Mx;
     192            Yo = source->moments->My;
     193        } else {
     194            Xo = source->peak->xf;
     195            Yo = source->peak->yf;
     196        }
     197
     198        // set PSF parameters for this model (apply 2D shape model to coordinates Xo, Yo)
     199        pmModel *modelPSF = pmModelFromPSFforXY(psf, Xo, Yo, Io);
     200
     201        if (modelPSF == NULL) {
     202            psWarning ("Failed to determine PSF model at (%f,%f); trying image center", Xo, Yo);
     203
     204            float Xc = 0.5*readout->image->numCols;
     205            float Yc = 0.5*readout->image->numRows;
     206            pmModel *modelPSF = pmModelFromPSFforXY(psf, Xc, Yc, Io);
     207            if (modelPSF == NULL) {
     208                psError(PSPHOT_ERR_PSF, false, "Failed to determine PSF model at center of image");
     209                return false;
     210            }
     211
     212            // Now set the object position at the expected location:
     213            modelPSF->params->data.F32[PM_PAR_XPOS] = Xo;
     214            modelPSF->params->data.F32[PM_PAR_YPOS] = Yo;
     215            source->mode |= PM_SOURCE_MODE_BADPSF;
     216        }
     217
     218        // set the fit radius based on the object flux limit and the model
     219        // this function affects the mask pixels
     220        psphotCheckRadiusPSF (readout, source, modelPSF, markVal);
     221
     222        // set the source PSF model
     223        psAssert (source->modelPSF == NULL, "failed to free one of the models?");
     224        source->modelPSF = modelPSF;
     225        source->modelPSF->residuals = psf->residuals;
     226
     227        pmSourceCacheModel (source, maskVal);  // ALLOC x14 (!)
    184228    }
    185229
  • branches/simtest_nebulous_branches/psphot/src/psphotImageLoop.c

    r23957 r27840  
    6767
    6868                // Update the header
    69                 {
    70                     pmHDU *hdu = pmHDUGetHighest(input->fpa, chip, cell);
    71                     if (hdu && hdu != lastHDU) {
    72                         psphotVersionHeaderFull(hdu->header);
    73                         lastHDU = hdu;
    74                     }
     69                pmHDU *hdu = pmHDUGetHighest(input->fpa, chip, cell);
     70                if (hdu && hdu != lastHDU) {
     71                    psphotVersionHeaderFull(hdu->header);
     72                    lastHDU = hdu;
    7573                }
    7674
    77                 psImageMaskType maskSat = pmConfigMaskGet("SAT", config); // Mask value for saturated pixels
    78                 if (!pmReadoutMaskNonfinite(readout, maskSat)) {
    79                     psError(psErrorCodeLast(), false, "Unable to mask non-finite pixels.");
    80                     psFree(view);
    81                     return false;
    82                 }
     75                // if an external mask is supplied, ensure that NAN pixels are also masked
     76                if (readout->mask) {
     77                    psImageMaskType maskSat = pmConfigMaskGet("SAT", config); // Mask value for saturated pixels
     78                    if (!pmReadoutMaskNonfinite(readout, maskSat)) {
     79                        psError(psErrorCodeLast(), false, "Unable to mask non-finite pixels.");
     80                        psFree(view);
     81                        return false;
     82                    }
     83                }
    8384
    8485                // run the actual photometry analysis on this chip/cell/readout
     
    9091            }
    9192
    92             status = true;
    93             status &= pmFPAfileDropInternal (config->files, "PSPHOT.BACKMDL");
    94             status &= pmFPAfileDropInternal (config->files, "PSPHOT.BACKMDL.STDEV");
    95             status &= pmFPAfileDropInternal (config->files, "PSPHOT.BACKGND");
    96             if (!status) {
    97                 psError(PSPHOT_ERR_PROG, false, "trouble dropping internal files");
    98                 psFree (view);
    99                 return false;
    100             }
     93            // drop all versions of the internal files
     94            status = true;
     95            status &= pmFPAfileDropInternal (config->files, "PSPHOT.BACKMDL");
     96            status &= pmFPAfileDropInternal (config->files, "PSPHOT.BACKMDL.STDEV");
     97            status &= pmFPAfileDropInternal (config->files, "PSPHOT.BACKGND");
     98            if (!status) {
     99                psError(PSPHOT_ERR_PROG, false, "trouble dropping internal files");
     100                psFree (view);
     101                return false;
     102            }
    101103        }
    102 
    103104        // save output which is saved at the chip level
    104105        if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) ESCAPE ("failed output for Chip in psphot.");
  • branches/simtest_nebulous_branches/psphot/src/psphotImageQuality.c

    r23989 r27840  
    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    // skip the chisq image (optionally?)
     19    int chisqNum = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.CHISQ.NUM");
     20    if (!status) chisqNum = -1;
     21
     22    // loop over the available readouts
     23    for (int i = 0; i < num; i++) {
     24        if (i == chisqNum) continue; // skip chisq image
     25        if (!psphotImageQualityReadout (config, view, "PSPHOT.INPUT", i, recipe)) {
     26            psError (PSPHOT_ERR_CONFIG, false, "failed on to measure image quality for PSPHOT.INPUT entry %d", i);
     27            return false;
     28        }
     29    }
     30    return true;
     31}
     32
    633// 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)
     34bool psphotImageQualityReadout(pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe)
    835{
     36    bool status = true;
     37
     38    // find the currently selected readout
     39    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     40    psAssert (file, "missing file?");
     41
     42    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     43    psAssert (readout, "missing readout?");
     44
     45    // if we have a PSF, skip this analysis
     46    if (psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF")) {
     47        return 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 image quality");
     58        return true;
     59    }
     60
    961    psVector *FWHM_MAJOR = psVectorAllocEmpty(100, PS_TYPE_F32);
    1062    psVector *FWHM_MINOR = psVectorAllocEmpty(100, PS_TYPE_F32);
     
    81133
    82134    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);
     135        psLogMsg ("psphot", PS_LOG_INFO, "no valid sources for image quality, skipping");
     136        return true;
     137    }
     138
     139    psMetadataAddS32(readout->analysis, PS_LIST_TAIL, "IQ_NSTAR", PS_META_REPLACE, "Number of stars used for IQ measurements", M2->n);
    89140
    90141// XXX make this a recipe option
     
    98149
    99150    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);
     151    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_FW1",   PS_META_REPLACE, "FWHM of Major Axis from moments", stats->sampleMean);
     152    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_FW1_E", PS_META_REPLACE, "FWHM scatter (Major) from moments", stats->sampleStdev);
    104153
    105154    if (!psVectorStats(stats, FWHM_MINOR, NULL, NULL, 0)) {
     
    108157    }
    109158    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);
     159    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_FW2",   PS_META_REPLACE, "FWHM of Minor Axis from moments", stats->sampleMean);
     160    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_FW2_E", PS_META_REPLACE, "FWHM scatter (Minor) from moments", stats->sampleStdev);
    114161
    115162    if (!psVectorStats(stats, M2, NULL, NULL, 0)) {
     
    119166    float vM2 = stats->sampleMean;
    120167    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);
     168    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2",    PS_META_REPLACE, "M_2 = sqrt (M_c2^2 + M_s2^2)", vM2);
     169    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2_ER", PS_META_REPLACE, "Stdev of M_2", dM2);
     170    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2_LQ", PS_META_REPLACE, "Lower Quartile of M_2", stats->sampleLQ);
     171    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2_UQ", PS_META_REPLACE, "Upper Quartile of M_2", stats->sampleUQ);
    129172
    130173    if (!psVectorStats(stats, M2c, NULL, NULL, 0)) {
     
    132175        goto FAIL;
    133176    }
    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);
     177    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2C",   PS_META_REPLACE, "M_2c = sum f r^2 cos(2phi) / sum f", stats->sampleMean);
     178    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2C_E", PS_META_REPLACE, "Stdev of M_2c", stats->sampleStdev);
     179    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2C_L", PS_META_REPLACE, "Lower Quartile of M_2c", stats->sampleLQ);
     180    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2C_U", PS_META_REPLACE, "Upper Quartile of M_2c", stats->sampleUQ);
    142181
    143182    if (!psVectorStats(stats, M2s, NULL, NULL, 0)) {
     
    145184        goto FAIL;
    146185    }
    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);
     186    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2S",   PS_META_REPLACE, "M_2s = sum f r^2 cos(2phi) / sum f", stats->sampleMean);
     187    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2S_E", PS_META_REPLACE, "Stdev of M_2s", stats->sampleStdev);
     188    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2S_L", PS_META_REPLACE, "Lower Quartile of M_2s", stats->sampleLQ);
     189    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2S_U", PS_META_REPLACE, "Upper Quartile of M_2s", stats->sampleUQ);
    155190
    156191    if (!psVectorStats(stats, M3, NULL, NULL, 0)) {
     
    160195    float vM3 = stats->sampleMean;
    161196    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);
     197    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M3",   PS_META_REPLACE, "M_3 = sqrt (M_c3^2 + M_s3^2)", vM3);
     198    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M3_ER", PS_META_REPLACE, "Stdev of M_3", dM3);
     199    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M3_LQ", PS_META_REPLACE, "Lower Quartile of M_3", stats->sampleLQ);
     200    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M3_UQ", PS_META_REPLACE, "Upper Quartile of M_3", stats->sampleUQ);
    170201
    171202    if (!psVectorStats(stats, M4, NULL, NULL, 0)) {
     
    175206    float vM4 = stats->sampleMean;
    176207    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);
     208    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M4",   PS_META_REPLACE, "M_4 = sqrt (M_c4^2 + M_s4^2)", vM4);
     209    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M4_ER", PS_META_REPLACE, "Stdev of M_4", dM4);
     210    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M4_LQ", PS_META_REPLACE, "Lower Quartile of M_4", stats->sampleLQ);
     211    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M4_UQ", PS_META_REPLACE, "Upper Quartile of M_4", stats->sampleUQ);
    185212
    186213#else
     
    192219    }
    193220    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);
     221    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_FW1",   PS_META_REPLACE, "FWHM of Major Axis from moments", stats->robustMedian);
     222    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_FW1_E", PS_META_REPLACE, "FWHM scatter (Major) from moments", stats->robustStdev);
    198223
    199224    if (!psVectorStats(stats, FWHM_MINOR, NULL, NULL, 0)) {
     
    202227    }
    203228    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);
     229    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_FW2",   PS_META_REPLACE, "FWHM of Minor Axis from moments", stats->robustMedian);
     230    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_FW2_E", PS_META_REPLACE, "FWHM scatter (Minor) from moments", stats->robustStdev);
    208231
    209232    if (!psVectorStats(stats, M2, NULL, NULL, 0)) {
     
    213236    float vM2 = stats->robustMedian;
    214237    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);
     238    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2",    PS_META_REPLACE, "M_2 = sqrt (M_c2^2 + M_s2^2)", vM2);
     239    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2_ER", PS_META_REPLACE, "Stdev of M_2", dM2);
     240    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2_LQ", PS_META_REPLACE, "Lower Quartile of M_2", stats->robustLQ);
     241    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2_UQ", PS_META_REPLACE, "Upper Quartile of M_2", stats->robustUQ);
    223242
    224243    if (!psVectorStats(stats, M2c, NULL, NULL, 0)) {
     
    226245        goto FAIL;
    227246    }
    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);
     247    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2C",   PS_META_REPLACE, "M_2c = sum f r^2 cos(2phi) / sum f", stats->robustMedian);
     248    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2C_E", PS_META_REPLACE, "Stdev of M_2c", stats->robustStdev);
     249    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2C_L", PS_META_REPLACE, "Lower Quartile of M_2c", stats->robustLQ);
     250    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2C_U", PS_META_REPLACE, "Upper Quartile of M_2c", stats->robustUQ);
    236251
    237252    if (!psVectorStats(stats, M2s, NULL, NULL, 0)) {
     
    239254        goto FAIL;
    240255    }
    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);
     256    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2S",   PS_META_REPLACE, "M_2s = sum f r^2 cos(2phi) / sum f", stats->robustMedian);
     257    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2S_E", PS_META_REPLACE, "Stdev of M_2s", stats->robustStdev);
     258    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2S_L", PS_META_REPLACE, "Lower Quartile of M_2s", stats->robustLQ);
     259    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M2S_U", PS_META_REPLACE, "Upper Quartile of M_2s", stats->robustUQ);
    249260
    250261    if (!psVectorStats(stats, M3, NULL, NULL, 0)) {
     
    254265    float vM3 = stats->robustMedian;
    255266    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);
     267    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M3",   PS_META_REPLACE, "M_3 = sqrt (M_c3^2 + M_s3^2)", vM3);
     268    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M3_ER", PS_META_REPLACE, "Stdev of M_3", dM3);
     269    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M3_LQ", PS_META_REPLACE, "Lower Quartile of M_3", stats->robustLQ);
     270    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M3_UQ", PS_META_REPLACE, "Upper Quartile of M_3", stats->robustUQ);
    264271
    265272    if (!psVectorStats(stats, M4, NULL, NULL, 0)) {
     
    269276    float vM4 = stats->robustMedian;
    270277    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);
     278    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M4",   PS_META_REPLACE, "M_4 = sqrt (M_c4^2 + M_s4^2)", vM4);
     279    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M4_ER", PS_META_REPLACE, "Stdev of M_4", dM4);
     280    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M4_LQ", PS_META_REPLACE, "Lower Quartile of M_4", stats->robustLQ);
     281    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "IQ_M4_UQ", PS_META_REPLACE, "Upper Quartile of M_4", stats->robustUQ);
    279282#endif
    280283
    281     psLogMsg ("psphot", PS_LOG_INFO, "Image Quality Stats from %ld psf stars : FWHM (major, minor) : %f, %f\n",
     284    psLogMsg ("psphot", PS_LOG_INFO, "Image Quality Stats from %ld psf stars : FWHM (major, minor) [pixels]: %f, %f\n",
    282285              M2->n, fwhm_major, fwhm_minor);
    283286
    284     psLogMsg ("psphot", PS_LOG_INFO, "M_2 : %f +/- %f, M_3 : %f +/- %f, M_4 : %f +/- %f\n",
     287    psLogMsg ("psphot", PS_LOG_INFO, "M_2 : %f +/- %f, M_3 : %f +/- %f, M_4 : %f +/- %f  [pixels^n]\n",
    285288              vM2, dM2, vM3, dM3, vM4, dM4);
    286289
  • branches/simtest_nebulous_branches/psphot/src/psphotKernelFromPSF.c

    r17396 r27840  
    44
    55    assert (source);
    6     assert (source->psfFlux); // XXX build if needed?
     6    assert (source->psfImage); // XXX build if needed?
    77
    8     int x0 = source->peak->xf - source->psfFlux->col0;
    9     int y0 = source->peak->yf - source->psfFlux->row0;
     8    int x0 = source->peak->xf - source->psfImage->col0;
     9    int y0 = source->peak->yf - source->psfImage->row0;
    1010
    1111    // need to decide on the size: dynamically? statically?
     
    1717    // if the realized PSF for this object does not cover the full kernel, give up for now
    1818    if (x0 + psf->xMin < 0) goto escape;
    19     if (x0 + psf->xMax >= source->psfFlux->numCols) goto escape;
     19    if (x0 + psf->xMax >= source->psfImage->numCols) goto escape;
    2020    if (y0 + psf->yMin < 0) goto escape;
    21     if (y0 + psf->yMax >= source->psfFlux->numRows) goto escape;
     21    if (y0 + psf->yMax >= source->psfImage->numRows) goto escape;
    2222
    2323    double sum = 0.0;
    2424    for (int j = psf->yMin; j <= psf->yMax; j++) {
    2525        for (int i = psf->xMin; i <= psf->xMax; i++) {
    26             double value = source->psfFlux->data.F32[y0 + j][x0 + i];
     26            double value = source->psfImage->data.F32[y0 + j][x0 + i];
    2727            psf->kernel[j][i] = value;
    2828            sum += value;
  • branches/simtest_nebulous_branches/psphot/src/psphotLoadPSF.c

    r18002 r27840  
    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}
  • branches/simtest_nebulous_branches/psphot/src/psphotMagnitudes.c

    r23349 r27840  
    11# include "psphotInternal.h"
    22
    3 bool psphotMagnitudes(pmConfig *config, pmReadout *readout, const pmFPAview *view, psArray *sources, 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    // skip the chisq image (optionally?)
     15    int chisqNum = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.CHISQ.NUM");
     16    if (!status) chisqNum = -1;
     17
     18    // loop over the available readouts
     19    for (int i = 0; i < num; i++) {
     20        if (i == chisqNum) continue; // skip chisq image
     21
     22        // find the currently selected readout
     23        pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PSPHOT.INPUT", i); // File of interest
     24        psAssert (file, "missing file?");
     25
     26        pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     27        psAssert (readout, "missing readout?");
     28
     29        pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     30        psAssert (detections, "missing detections?");
     31
     32        psArray *sources = detections->allSources;
     33        psAssert (sources, "missing sources?");
     34
     35        pmPSF *psf = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF");
     36        psAssert (psf, "missing psf?");
     37
     38        if (!psphotMagnitudesReadout (config, recipe, view, readout, sources, psf)) {
     39            psError (PSPHOT_ERR_CONFIG, false, "failed to measure magnitudes for PSPHOT.INPUT entry %d", i);
     40            return false;
     41        }
     42    }
     43    return true;
     44}
     45
     46bool psphotMagnitudesReadout(pmConfig *config, psMetadata *recipe, const pmFPAview *view, pmReadout *readout, psArray *sources, pmPSF *psf) {
    447
    548    bool status = false;
    649    int Nap = 0;
    750
     51    if (!sources->n) {
     52        psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping source magnitudes");
     53        return true;
     54    }
     55       
    856    psTimerStart ("psphot.mags");
    9 
    10     // select the appropriate recipe information
    11     psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
    12     assert (recipe);
    1357
    1458    // determine the number of allowed threads
     
    4185    }
    4286
    43     bool IGNORE_GROWTH = psMetadataLookupBool (&status, recipe, "IGNORE_GROWTH");
     87    bool IGNORE_GROWTH  = psMetadataLookupBool (&status, recipe, "IGNORE_GROWTH");
    4488    bool INTERPOLATE_AP = psMetadataLookupBool (&status, recipe, "INTERPOLATE_AP");
     89    bool DIFF_STATS     = psMetadataLookupBool (&status, recipe, "INTERPOLATE_AP");
    4590
    4691    pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_APCORR | PM_SOURCE_PHOT_WEIGHT;
    4792    if (!IGNORE_GROWTH) photMode |= PM_SOURCE_PHOT_GROWTH;
    4893    if (INTERPOLATE_AP) photMode |= PM_SOURCE_PHOT_INTERP;
     94    if (DIFF_STATS)     photMode |= PM_SOURCE_PHOT_DIFFSTATS;
    4995
    5096    // choose Cx, Cy (see psphotThreadTools.c for overview of the concepts)
     
    71117            PS_ARRAY_ADD_SCALAR(job->args, photMode, PS_TYPE_S32);
    72118            PS_ARRAY_ADD_SCALAR(job->args, maskVal,  PS_TYPE_IMAGE_MASK);
     119            PS_ARRAY_ADD_SCALAR(job->args, markVal,  PS_TYPE_IMAGE_MASK);
    73120            PS_ARRAY_ADD_SCALAR(job->args, 0,        PS_TYPE_S32); // this is used as a return value for nAp
    74121
     
    102149                fprintf (stderr, "error with job\n");
    103150            } else {
    104                 psScalar *scalar = job->args->data[7];
     151                psScalar *scalar = job->args->data[8];
    105152                Nap += scalar->data.S32;
    106153            }
     
    127174    pmSourcePhotometryMode photMode = PS_SCALAR_VALUE(job->args->data[5],S32);
    128175    psImageMaskType maskVal         = PS_SCALAR_VALUE(job->args->data[6],PS_TYPE_IMAGE_MASK_DATA);
     176    psImageMaskType markVal         = PS_SCALAR_VALUE(job->args->data[7],PS_TYPE_IMAGE_MASK_DATA);
    129177
    130178    for (int i = 0; i < sources->n; i++) {
    131179        pmSource *source = (pmSource *) sources->data[i];
    132         status = pmSourceMagnitudes (source, psf, photMode, maskVal);
     180
     181        // replace object in image
     182        if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
     183            pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
     184        }
     185
     186        // clear the mask bit and set the circular mask pixels
     187        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
     188        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", markVal);
     189
     190        status = pmSourceMagnitudes (source, psf, photMode, maskVal); // maskVal includes markVal
    133191        if (status && isfinite(source->apMag)) Nap ++;
     192
     193        // clear the mask bit
     194        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
     195
     196        // re-subtract the object, leave local sky
     197        pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    134198
    135199        if (backModel) {
     
    155219
    156220    // change the value of a scalar on the array (wrap this and put it in psArray.h)
    157     psScalar *scalar = job->args->data[7];
     221    psScalar *scalar = job->args->data[8];
    158222    scalar->data.S32 = Nap;
    159223
    160224    return true;
    161225}
    162 
    163 # if (0)
    164 bool psphotMagnitudes_Unthreaded (int *nap, psArray *sources, pmPSF *psf, psImageBinning *binning, pmReadout *backModel, pmReadout *backStdev, pmSourcePhotometryMode photMode, psImageMaskType maskVal) {
    165 
    166     bool status;
    167     int Nap = 0;
    168 
    169     for (int i = 0; i < sources->n; i++) {
    170         pmSource *source = (pmSource *) sources->data[i];
    171         status = pmSourceMagnitudes (source, psf, photMode, maskVal);
    172         if (status && isfinite(source->apMag)) Nap ++;
    173 
    174         if (backModel) {
    175             psAssert (binning, "if backModel is defined, so should binning be");
    176             source->sky = psImageUnbinPixel(source->peak->x, source->peak->y, backModel->image, binning);
    177             if (isnan(source->sky) && false) {
    178                 psLogMsg ("psphot.magnitudes", PS_LOG_DETAIL, "error setting pmSource.sky");
    179             }
    180         } else {
    181             source->sky = NAN;
    182         }
    183 
    184         if (backStdev) {
    185             psAssert (binning, "if backStdev is defined, so should binning be");
    186             source->skyErr = psImageUnbinPixel(source->peak->x, source->peak->y, backStdev->image, binning);
    187             if (isnan(source->skyErr) && false) {
    188                 psLogMsg ("psphot.magnitudes", PS_LOG_DETAIL, "error setting pmSource.skyErr");
    189             }
    190         } else {
    191             source->skyErr = NAN;
    192         }
    193     }
    194 
    195     // change the value of a scalar on the array (wrap this and put it in psArray.h)
    196     *nap = Nap;
    197 
    198     return true;
    199 }
    200 # endif
    201226
    202227bool psphotPSFWeights(pmConfig *config, pmReadout *readout, const pmFPAview *view, psArray *sources) {
  • branches/simtest_nebulous_branches/psphot/src/psphotMakeFluxScale.c

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

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

    r24484 r27840  
    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    }
     
    3361    }
    3462
     63    bool softenVariance = psMetadataLookupBool (&status, recipe, "SOFTEN.VARIANCE");
     64    float softenFraction = psMetadataLookupF32 (&status, recipe, "SOFTEN.VARIANCE.FRACTION");
     65
    3566    // make this an option via the recipe
    36     if (0) {
     67    if (softenVariance) {
    3768      psImage *im = readout->image;
    3869      psImage *wt = readout->variance;
    39       psImage *mk = readout->mask;
    4070      for (int j = 0; j < im->numRows; j++) {
    4171        for (int i = 0; i < im->numCols; i++) {
    42           if (isfinite(im->data.F32[j][i]) && isfinite(wt->data.F32[j][i])) continue;
    43           mk->data.PS_TYPE_IMAGE_MASK_DATA[j][i] |= maskBad;
     72            if (!isfinite(im->data.F32[j][i])) continue;
     73            if (!isfinite(wt->data.F32[j][i])) continue;
     74            float sysError = softenFraction * im->data.F32[j][i];
     75            wt->data.F32[j][i] += PS_SQR(sysError);
    4476        }
    4577      }
     
    69101    }
    70102
     103    // display the image, weight, mask (ch 1,2,3)
     104    psphotVisualShowImage (readout);
     105
    71106    return true;
    72107}
  • branches/simtest_nebulous_branches/psphot/src/psphotMergeSources.c

    r21519 r27840  
    55                         PM_SOURCE_MODE_CR_LIMIT | PM_SOURCE_MODE_EXT_LIMIT) // Mask to apply for PSF sources
    66
     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
    725// add newly selected sources to the existing list of sources
    8 bool psphotMergeSources (psArray *oldSources, psArray *newSources) {
     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;
    955
    1056    for (int i = 0; i < newSources->n; i++) {
    1157        pmSource *source = newSources->data[i];
    12         psArrayAdd (oldSources, 100, source);
    13     }
    14     return true;
    15 }
    16 
    17 // merge the externally supplied sources with the existing sources.  mark them as having
    18 // mode PM_SOURCE_MODE_EXTERNAL
    19 bool psphotLoadExtSources (pmConfig *config, const pmFPAview *view, psArray *sources) {
    20 
    21     // find the currently selected readout
    22     pmReadout  *readout = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT.CMF");
    23     if (!readout) {
    24         psLogMsg ("psphot", 3, "no external sources supplied");
    25         return true;
    26     }
    27 
    28     psArray *extSources = psMetadataLookupPtr (NULL, readout->analysis, "PSPHOT.SOURCES");
    29     if (!extSources) {
     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;
     77    psArray *extSourcesTXT = NULL;
     78    int index = 0;
     79
     80    // find the currently selected readout
     81    pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PSPHOT.INPUT", index); // File of interest
     82    psAssert (file, "missing file?");
     83
     84    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     85    psAssert (readout, "missing readout?");
     86
     87    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     88    if (!detections) {
     89        detections = pmDetectionsAlloc();
     90        detections->newSources = psArrayAllocEmpty (100);
     91        // save detections on the readout->analysis
     92        if (!psMetadataAddPtr (readout->analysis, PS_LIST_TAIL, "PSPHOT.DETECTIONS", PS_META_REPLACE | PS_DATA_UNKNOWN, "psphot detections", detections)) {
     93            psError (PSPHOT_ERR_CONFIG, false, "problem saving detections on readout");
     94            return false;
     95        }
     96    } else {
     97        psMemIncrRefCounter(detections); // so we can free the detections below
     98    }
     99
     100    psArray *sources = detections->newSources;
     101    psAssert (sources, "missing sources?");
     102
     103    // load data from input CMF file:
     104    {
     105        pmReadout *readoutCMF = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT.CMF");
     106        if (!readoutCMF) goto loadTXT;
     107
     108        extCMF = psMetadataLookupPtr (NULL, readoutCMF->analysis, "PSPHOT.DETECTIONS");
     109        if (extCMF) {
     110            for (int i = 0; i < extCMF->allSources->n; i++) {
     111                pmSource *source = extCMF->allSources->data[i];
     112                source->mode |= PM_SOURCE_MODE_EXTERNAL;
     113
     114                // the supplied peak flux needs to be re-normalized
     115                source->peak->flux = 1.0;
     116                source->peak->value = 1.0;
     117
     118                // drop the loaded source modelPSF
     119                psFree (source->modelPSF);
     120                source->modelPSF = NULL;
     121                source->imageID = index;
     122
     123                psArrayAdd (detections->newSources, 100, source);
     124            }
     125        }
     126    }
     127
     128loadTXT:
     129
     130    // load data from input TXT file:
     131    {
     132        pmChip *chipTXT = pmFPAfileThisChip (config->files, view, "PSPHOT.INPUT");
     133        if (!chipTXT) goto finish;
     134
     135        extSourcesTXT = psMetadataLookupPtr (NULL, chipTXT->analysis, "PSPHOT.SOURCES.TEXT");
     136        if (extSourcesTXT) {
     137            for (int i = 0; i < extSourcesTXT->n; i++) {
     138                pmSource *source = extSourcesTXT->data[i];
     139                source->mode |= PM_SOURCE_MODE_EXTERNAL;
     140
     141                // drop the loaded source modelPSF
     142                psFree (source->modelPSF);
     143                source->modelPSF = NULL;
     144                source->imageID = index;
     145
     146                psArrayAdd (detections->newSources, 100, source);
     147            }
     148        }
     149    }
     150
     151finish:
     152
     153    psFree (detections);
     154
     155    if (!extCMF && !extSourcesTXT) {
    30156        psLogMsg ("psphot", 3, "no external sources for this readout");
    31157        return true;
    32158    }
    33159
    34     for (int i = 0; i < extSources->n; i++) {
    35         pmSource *source = extSources->data[i];
    36         source->mode |= PM_SOURCE_MODE_EXTERNAL;
    37         pmModel *model = source->modelPSF;
    38 
    39         float xpos = model->params->data.F32[PM_PAR_XPOS];
    40         float ypos = model->params->data.F32[PM_PAR_YPOS];
    41 
    42         source->peak = pmPeakAlloc(xpos, ypos, 1.0, PM_PEAK_LONE);
    43         source->peak->xf = xpos;
    44         source->peak->yf = ypos;
    45         source->peak->flux = 1.0;
    46 
    47         // drop the loaded source modelPSF
    48         psFree (source->modelPSF);
    49         source->modelPSF = NULL;
    50     }
    51 
    52     psphotMergeSources (sources, extSources);
    53     psLogMsg ("psphot", 3, "%ld external sources merged to yield %ld total sources", extSources->n, sources->n);
    54 
     160    int nCMF = extCMF        ? extCMF->allSources->n        : 0;
     161    int nTXT = extSourcesTXT ? extSourcesTXT->n : 0;
     162
     163    psLogMsg ("psphot", 3, "%d external sources (%d cmf, %d text) merged to yield %ld total sources",
     164              nCMF + nTXT, nCMF, nTXT, sources->n);
    55165    return true;
    56166}
    57167
    58168// extract the input sources corresponding to this readout
     169// XXX this function needs to be updated to work with the new context of pshot inputs
    59170psArray *psphotLoadPSFSources (pmConfig *config, const pmFPAview *view) {
     171
     172    bool status;
    60173
    61174    // find the currently selected readout
     
    66179    }
    67180
    68     psArray *sources = psMetadataLookupPtr (NULL, readout->analysis, "PSPHOT.SOURCES");
     181    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     182    if (!detections) {
     183        psLogMsg ("psphot", 3, "no psf sources for this readout");
     184        return NULL;
     185    }
     186
     187    psArray *sources = detections->allSources;
    69188    if (!sources) {
    70189        psLogMsg ("psphot", 3, "no psf sources for this readout");
     190        return NULL;
    71191    }
    72192
     
    74194}
    75195
     196// this function is used to fix sources which were loaded externally, but have passed from
     197// psphotDetectionsFromSources to psphotSourceStats and are now stored on
     198// detections->newSources.
     199bool psphotRepairLoadedSources (pmConfig *config, const pmFPAview *view) {
     200
     201    // find the currently selected readout
     202    pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PSPHOT.INPUT", 0); // File of interest
     203    psAssert (file, "missing file?");
     204
     205    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     206    psAssert (readout, "missing readout?");
     207
     208    pmDetections *detections = psMetadataLookupPtr (NULL, readout->analysis, "PSPHOT.DETECTIONS");
     209    if (!detections) {
     210        psError(PSPHOT_ERR_CONFIG, false, "missing detections");
     211        return false;
     212    }
     213
     214    psArray *sources = detections->newSources;
     215    psAssert (sources, "missing sources?");
     216
     217    // peak flux is wrong : set based on previous image
     218    // use the peak measured in the moments analysis:
     219    for (int i = 0; i < sources->n; i++) {
     220      pmSource *source = sources->data[i];
     221      source->peak->flux = source->moments->Peak;
     222    }
     223
     224    return true;
     225}
     226
    76227// generate the detection structure for the supplied array of sources
    77 pmDetections *psphotDetectionsFromSources (pmConfig *config, psArray *sources) {
     228// XXX this currently assumes there is a single input file
     229bool psphotDetectionsFromSources (pmConfig *config, const pmFPAview *view, psArray *sources) {
     230
     231    // find the currently selected readout
     232    pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PSPHOT.INPUT", 0); // File of interest
     233    psAssert (file, "missing file?");
     234
     235    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     236    psAssert (readout, "missing readout?");
    78237
    79238    pmDetections *detections = pmDetectionsAlloc();
     
    88247    float snMin = psMetadataLookupF32(NULL, recipe, "MOMENTS_SN_MIN");
    89248    if (!isfinite(snMin)) {
    90         return NULL;
     249        return false;
    91250    }
    92251
     
    96255
    97256        if (source->mode & PSF_SOURCE_MASK || !isfinite(source->psfMag)) {
     257            continue;
     258        }
     259
     260        // use the existing peak information, otherwise generate a new peak
     261        if (source->peak) {
     262            source->peak->assigned = false; // So the moments will be measured
     263            psArrayAdd (detections->peaks, 100, source->peak);
    98264            continue;
    99265        }
     
    108274        peak->flux = flux; // this are being set wrong, but does it matter?
    109275
    110         if (isfinite (source->errMag) && (source->errMag > 0.0)) {
    111           peak->SN = 1.0 / source->errMag;
    112         } else {
    113           peak->SN = 0.0;
    114         }
     276        if (isfinite (source->errMag) && (source->errMag > 0.0)) {
     277          peak->SN = 1.0 / source->errMag;
     278        } else {
     279          peak->SN = 0.0;
     280        }
    115281
    116282        psArrayAdd (detections->peaks, 100, peak);
     
    120286    psLogMsg ("psphot", 3, "%ld PSF sources loaded", detections->peaks->n);
    121287
    122     return detections;
     288    // save detections on the readout->analysis
     289    if (!psMetadataAddPtr (readout->analysis, PS_LIST_TAIL, "PSPHOT.DETECTIONS", PS_META_REPLACE | PS_DATA_UNKNOWN, "psphot detectinos", detections)) {
     290        psError (PSPHOT_ERR_CONFIG, false, "problem saving detections on readout");
     291        return false;
     292    }
     293    psFree (detections);
     294    return true;
    123295}
    124296
     
    149321        peak->flux = flux; // this are being set wrong, but does it matter?
    150322
    151         if (isfinite (source->errMag) && (source->errMag > 0.0)) {
    152           peak->SN = 1.0 / source->errMag;
    153         } else {
    154           peak->SN = 0.0;
    155         }
     323        if (isfinite (source->errMag) && (source->errMag > 0.0)) {
     324          peak->SN = 1.0 / source->errMag;
     325        } else {
     326          peak->SN = 0.0;
     327        }
    156328
    157329        source->peak = peak;
     
    162334    return true;
    163335}
     336
     337bool psphotCheckExtSources (pmConfig *config, const pmFPAview *view) {
     338
     339    bool status;
     340
     341    psMetadata *recipe = psMetadataLookupPtr (NULL, config->recipes, PSPHOT_RECIPE);
     342    psAssert (recipe, "missing recipe");
     343
     344    // find the currently selected readout
     345    pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PSPHOT.INPUT", 0); // File of interest
     346    psAssert (file, "missing file?");
     347
     348    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     349    psAssert (readout, "missing readout?");
     350
     351    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     352    psAssert (detections, "missing detections?");
     353
     354    // XXX allSources of newSources?
     355    psArray *sources = detections->allSources;
     356    psAssert (sources, "missing sources?");
     357
     358    if (sources->n) {
     359        // the user wants to make the psf from these stars; define them as psf stars:
     360        for (int i = 0; i < sources->n; i++) {
     361            pmSource *source = sources->data[i];
     362            source->mode |= PM_SOURCE_MODE_PSFSTAR;
     363        }
     364        // force psphotChoosePSF to use all loaded sources
     365        psMetadataAddS32 (recipe, PS_LIST_TAIL, "PSF_MAX_NSTARS", PS_META_REPLACE, "max number of sources for PSF model", sources->n);
     366
     367        // measure stats of externally specified sources
     368        if (!psphotSourceStatsUpdate (sources, config, readout)) {
     369            psError(PSPHOT_ERR_CONFIG, false, "failure to measure stats of existing sources");
     370            return false;
     371        }
     372    } else {
     373
     374        // find the detections (by peak and/or footprint) in the image.
     375        if (!psphotFindDetections (config, view, true)) {
     376            psError(PSPHOT_ERR_CONFIG, false, "unable to find detections in this image");
     377            return psphotReadoutCleanup (config, view);
     378        }
     379
     380        // construct sources and measure basic stats
     381        psphotSourceStats (config, view, true);
     382
     383        // find blended neighbors of very saturated stars
     384        psphotDeblendSatstars (config, view);
     385
     386        // mark blended peaks PS_SOURCE_BLEND
     387        if (!psphotBasicDeblend (config, view)) {
     388            psLogMsg ("psphot", 3, "failed on deblend analysis");
     389            return psphotReadoutCleanup (config, view);
     390        }
     391
     392        // classify sources based on moments, brightness
     393        if (!psphotRoughClass (config, view)) {
     394            psLogMsg ("psphot", 3, "failed to find a valid PSF clump for image");
     395            return psphotReadoutCleanup (config, view);
     396        }
     397    }
     398
     399    return true;
     400}
  • branches/simtest_nebulous_branches/psphot/src/psphotModelBackground.c

    r24188 r27840  
    55// Determine the binning characteristics for the background model
    66// Sets the ruff image size and skip based on recipe values for the binning
    7 static psImageBinning *backgroundBinning(const psImage *image, // Image for which to generate a bg model
     7psImageBinning *psphotBackgroundBinning(const psImage *image, // Image for which to generate a bg model
    88                                         const pmConfig *config // Configuration
    99                                         )
     
    2828}
    2929
     30
    3031// Generate the background model
    31 static bool backgroundModel(psImage *model,  // Model image
    32                             psImage *modelStdev, // Model stdev image
    33                             psMetadata *analysis, // Analysis metadata for outputs
    34                             pmReadout *readout, // Readout for which to generate a background model
    35                             psImageBinning *binning, // Binning parameters
    36                             const pmConfig *config // Configuration
    37                             )
     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    )
    3846{
    3947    psTimerStart ("psphot.background");
     
    137145
    138146    // we save the binning structure for use in psphotMagnitudes
    139     psMetadataAddPtr(analysis, PS_LIST_TAIL, "PSPHOT.BACKGROUND.BINNING",
    140                      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);
    141148
    142149    psF32 **modelData = model->data.F32;
     
    144151
    145152    // XXXX we can thread this here by running blocks in parallel
     153
     154    int nFailures = 0;
     155    psImageBackgroundInit();
    146156
    147157    // measure clipped median for subimages
     
    211221                stats->options = PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV;
    212222                if (!psImageBackground(stats, &sample, subset, submask, maskVal, rng)) {
    213                     psLogMsg ("psphot", PS_LOG_WARN, "Failed to estimate background using ROBUST_MEDIAN for "
    214                                "(%dx%d, (row0,col0) = (%d,%d)",
    215                                subset->numRows, subset->numCols, subset->row0, subset->col0);
     223                    if ((nFailures < 3) || (nFailures % 100 == 0)) {
     224                        psLogMsg ("psphot", PS_LOG_WARN, "Failed to estimate background using ROBUST_MEDIAN for "
     225                                  "(%dx%d, (row0,col0) = (%d,%d)",
     226                                  subset->numRows, subset->numCols, subset->row0, subset->col0);
     227                    }
     228                    nFailures ++;
    216229                    modelData[iy][ix] = modelStdevData[iy][ix] = NAN;
    217230                } else {
     
    232245            psFree (submask);
    233246        }
     247    }
     248
     249    if (nFailures) {
     250        psLogMsg ("psphot", PS_LOG_WARN, "Failed to estimate background for %d of %d subimages", nFailures, (model->numRows*model->numCols));
    234251    }
    235252
     
    293310    psLogMsg ("psphot", PS_LOG_INFO, "built background image: %f sec\n", psTimerMark ("psphot.background"));
    294311
    295     psMetadataAddF32(recipe, PS_LIST_TAIL, "SKY_MEAN", PS_META_REPLACE, "sky mean", Value);
    296     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);
    297314    psLogMsg ("psphot", PS_LOG_INFO, "image sky : mean %f stdev %f", Value, ValueStdev);
    298315
     
    303320                                      PS_STAT_MAX);
    304321    psImageStats (statsBck, model, NULL, 0);
    305     psMetadataAddF32 (recipe, PS_LIST_TAIL, "MSKY_MN",
    306                       PS_META_REPLACE, "sky model mean",          statsBck->sampleMean);
    307     psMetadataAddF32 (recipe, PS_LIST_TAIL, "MSKY_SIG",
    308                       PS_META_REPLACE, "sky model stdev",         statsBck->sampleStdev);
    309     psMetadataAddF32 (recipe, PS_LIST_TAIL, "MSKY_MAX",
    310                       PS_META_REPLACE, "sky model maximum value", statsBck->max);
    311     psMetadataAddF32 (recipe, PS_LIST_TAIL, "MSKY_MIN",
    312                       PS_META_REPLACE, "sky model minimum value", statsBck->min);
    313     psMetadataAddS32 (recipe, PS_LIST_TAIL, "MSKY_NX",
    314                       PS_META_REPLACE, "sky model size (x)",      model->numCols);
    315     psMetadataAddS32 (recipe, PS_LIST_TAIL, "MSKY_NY",
    316                       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);
    317328    psLogMsg ("psphot", PS_LOG_INFO, "background sky : min %f mean %f max %f stdev %f",
    318329              statsBck->min, statsBck->sampleMean, statsBck->max, statsBck->sampleStdev);
     
    327338}
    328339
    329 
    330 
    331 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)
    332342{
    333     PM_ASSERT_READOUT_NON_NULL(ro, NULL);
    334     PM_ASSERT_READOUT_IMAGE(ro, NULL);
     343    PM_ASSERT_READOUT_NON_NULL(readout, NULL);
     344    PM_ASSERT_READOUT_IMAGE(readout, NULL);
    335345    PS_ASSERT_PTR_NON_NULL(config, NULL);
    336346
    337     psImageBinning *binning = backgroundBinning(ro->image, config); // Image binning parameters
     347    psImageBinning *binning = psphotBackgroundBinning(readout->image, config); // Image binning parameters
    338348    psImage *model = psImageAlloc(binning->nXruff, binning->nYruff, PS_TYPE_F32); // Background model
    339349    psImage *modelStdev = psImageAlloc(binning->nXruff, binning->nYruff, PS_TYPE_F32); // Standard deviation
    340350
    341     if (!backgroundModel(model, modelStdev, ro->analysis, ro, binning, config)) {
     351    if (!psphotModelBackgroundReadout(model, modelStdev, readout->analysis, readout, binning, config)) {
    342352        psFree(model);
    343353        psFree(modelStdev);
     
    345355        return NULL;
    346356    }
    347 
    348357    psFree(modelStdev);
    349 
    350358    return model;
    351359}
    352360
    353 
    354 // generate the median in NxN boxes, clipping heavily
    355 // linear interpolation to generate full-scale model
    356 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)
    357363{
    358     bool status = true;
    359 
    360364    // find the currently selected readout
    361     pmFPAfile *file = psMetadataLookupPtr (&status, config->files, filename);
     365    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     366    psAssert (file, "missing file?");
     367
    362368    pmFPA *inFPA = file->fpa;
    363369    pmReadout *readout = pmFPAviewThisReadout(view, inFPA);
    364 
    365     psImageBinning *binning = backgroundBinning(readout->image, config); // Image binning parameters
    366     pmReadout *model = pmFPAGenerateReadout(config, view, "PSPHOT.BACKMDL", inFPA, binning);
    367     pmReadout *modelStdev = pmFPAGenerateReadout(config, view, "PSPHOT.BACKMDL.STDEV", inFPA, binning);
    368 
    369     if (!backgroundModel(model->image, modelStdev->image, model->analysis, readout, binning, config)) {
     370    psAssert (readout, "missing readout?");
     371
     372    psImageBinning *binning = psphotBackgroundBinning(readout->image, config); // Image binning parameters
     373    pmReadout *model = pmFPAGenerateReadout(config, view, "PSPHOT.BACKMDL", inFPA, binning, index);
     374    pmReadout *modelStdev = pmFPAGenerateReadout(config, view, "PSPHOT.BACKMDL.STDEV", inFPA, binning, index);
     375
     376    if (!psphotModelBackgroundReadout(model->image, modelStdev->image, model->analysis, readout, binning, config)) {
    370377        psError(PS_ERR_UNKNOWN, false, "Unable to generate background model");
    371378        return false;
     
    375382    return true;
    376383}
     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}
  • branches/simtest_nebulous_branches/psphot/src/psphotModelGroupInit.c

    r14655 r27840  
    11# include "psphotInternal.h"
    22
    3 // Add locally-defined models here.  As these mature, they can be moved to 
     3// Add locally-defined models here.  As these mature, they can be moved to
    44// psModule/src/objects/models
    55
     
    88
    99static pmModelClass userModels[] = {
    10     {"PS_MODEL_TEST1", 7, pmModelFunc_TEST1,  pmModelFlux_TEST1,  pmModelRadius_TEST1,  pmModelLimits_TEST1,  pmModelGuess_TEST1, pmModelFromPSF_TEST1, pmModelParamsFromPSF_TEST1, pmModelFitStatus_TEST1},
    11     {"PS_MODEL_STRAIL", 9, pmModelFunc_STRAIL,  pmModelFlux_STRAIL,  pmModelRadius_STRAIL,  pmModelLimits_STRAIL,  pmModelGuess_STRAIL, pmModelFromPSF_STRAIL, pmModelParamsFromPSF_STRAIL, pmModelFitStatus_STRAIL},
     10    {"PS_MODEL_TEST1", 7, pmModelFunc_TEST1,  pmModelFlux_TEST1,  pmModelRadius_TEST1,  pmModelLimits_TEST1,  pmModelGuess_TEST1, pmModelFromPSF_TEST1, pmModelParamsFromPSF_TEST1, pmModelFitStatus_TEST1, NULL},
     11    {"PS_MODEL_STRAIL", 9, pmModelFunc_STRAIL,  pmModelFlux_STRAIL,  pmModelRadius_STRAIL,  pmModelLimits_STRAIL,  pmModelGuess_STRAIL, pmModelFromPSF_STRAIL, pmModelParamsFromPSF_STRAIL, pmModelFitStatus_STRAIL, NULL},
    1212};
    1313
    14 void psphotModelClassInit (void) 
    15 { 
     14void psphotModelClassInit (void)
     15{
    1616
    1717    // if pmModelClassInit returns false, we have already init'ed
     
    2020    int Nmodels = sizeof (userModels) / sizeof (pmModelClass);
    2121    for (int i = 0; i < Nmodels; i++) {
    22         pmModelClassAdd (&userModels[i]);
     22        pmModelClassAdd (&userModels[i]);
    2323    }
    2424    return;
  • branches/simtest_nebulous_branches/psphot/src/psphotModelTest.c

    r24588 r27840  
    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;
  • branches/simtest_nebulous_branches/psphot/src/psphotMomentsStudy.c

    r24585 r27840  
    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
  • branches/simtest_nebulous_branches/psphot/src/psphotOutput.c

    r21366 r27840  
    3131    }
    3232    return background;
     33}
     34
     35// dump source stats for psf stars
     36bool psphotDumpStats (psArray *sources, char *stage) {
     37
     38    char filename[64];
     39    snprintf (filename, 64, "psf.%s.dat", stage);
     40    FILE *f = fopen (filename, "w");
     41    for (int i = 0; i < sources->n; i++) {
     42        pmSource *source = sources->data[i];
     43        if (!(source->mode & PM_SOURCE_MODE_PSFSTAR)) continue;
     44
     45        pmModel *model = source->modelPSF;
     46        if (!model) continue;
     47
     48        // int xc = source->peak->x - source->pixels->col0;
     49        // int yc = source->peak->y - source->pixels->row0;
     50        // float mcore = source->modelFlux ? source->modelFlux->data.F32[yc][xc] : NAN;
     51        // float mpeak = model ? model->params->data.F32[PM_PAR_I0] : NAN;
     52        // bool subtracted = source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED;
     53        // fprintf (stderr, "%d %d : %d : %f %f : %f %f\n", source->peak->x, source->peak->y, subtracted, source->peak->flux, source->pixels->data.F32[yc][xc], mcore, mpeak);
     54
     55        fprintf (f, "%6.1f %6.1f : %6.1f %6.1f : %8.3f %8.3f %8.3f : %f : %f %f %f : %f\n",
     56                 source->peak->xf, source->peak->yf,
     57                 model->params->data.F32[PM_PAR_XPOS], model->params->data.F32[PM_PAR_YPOS],
     58                 source->psfMag, source->apMag, source->errMag,
     59                 model->params->data.F32[PM_PAR_I0],
     60                 model->params->data.F32[PM_PAR_SXX], model->params->data.F32[PM_PAR_SXY], model->params->data.F32[PM_PAR_SYY],
     61                 model->params->data.F32[PM_PAR_7]);
     62    }
     63    fclose (f);
     64    return true;
    3365}
    3466
     
    94126}
    95127
    96 bool psphotAddPhotcode (psMetadata *recipe, pmConfig *config, const pmFPAview *view, const char *filerule) {
    97 
    98     bool status;
    99 
    100     pmFPAfile *input = psMetadataLookupPtr (&status, config->files, filerule);
    101     PS_ASSERT (status, false);
    102 
    103     // determine PHOTCODE from fpa & view, overwrite in recipe
    104     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);
    105154    PS_ASSERT (photcode, false);
    106155
    107     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);
    108157    psLogMsg ("psphot", 3, "PHOTCODE is %s", photcode);
    109158
     
    112161}
    113162
    114 bool psphotSetHeaderNstars (psMetadata *recipe, psArray *sources) {
     163bool psphotSetHeaderNstars (psMetadata *header, psArray *sources) {
    115164
    116165    int nSrc = 0;
     
    141190    }
    142191
    143     psMetadataAddS32 (recipe, PS_LIST_TAIL, "NSTARS",   PS_META_REPLACE, "Number of sources", nSrc);
    144     psMetadataAddS32 (recipe, PS_LIST_TAIL, "NDET_EXT", PS_META_REPLACE, "Number of extended sources", nEXT);
    145     psMetadataAddS32 (recipe, PS_LIST_TAIL, "NDET_CR",  PS_META_REPLACE, "Number of cosmic rays", nCR);
    146     return true;
    147 }
    148 
    149 // these values are saved in an output header stub - they are added to either the
    150 // PHU header (CMP) or the MEF table header (CMF)
    151 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;
    152204
    153205    psMetadata *header = psMetadataAlloc ();
    154206
    155207    // write necessary information to output header
    156     psMetadataItemSupplement (header, recipe, "ZERO_PT");
    157     psMetadataItemSupplement (header, recipe, "PHOTCODE");
    158 
    159     psMetadataItemSupplement (header, recipe, "APMIFIT");
    160     psMetadataItemSupplement (header, recipe, "DAPMIFIT");
    161     psMetadataItemSupplement (header, recipe, "NAPMIFIT");
    162     psMetadataItemSupplement (header, recipe, "SKYBIAS");
    163     psMetadataItemSupplement (header, recipe, "SKYSAT");
     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");
    164214
    165215    // PSF model parameters (shape values for image center)
    166     psMetadataItemSupplement (header, recipe, "NPSFSTAR");
    167     psMetadataItemSupplement (header, recipe, "APLOSS");
    168 
    169     psMetadataItemSupplement (header, recipe, "FWHM_MAJ");
    170     psMetadataItemSupplement (header, recipe, "FW_MJ_SG");
    171     psMetadataItemSupplement (header, recipe, "FW_MJ_LQ");
    172     psMetadataItemSupplement (header, recipe, "FW_MJ_UQ");
    173 
    174     psMetadataItemSupplement (header, recipe, "FWHM_MIN");
    175     psMetadataItemSupplement (header, recipe, "FW_MN_SG");
    176     psMetadataItemSupplement (header, recipe, "FW_MN_LQ");
    177     psMetadataItemSupplement (header, recipe, "FW_MN_UQ");
    178 
    179     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");
    180230
    181231    // Image Quality measurements
    182     psMetadataItemSupplement (header, recipe, "IQ_NSTAR");
    183 
    184     psMetadataItemSupplement (header, recipe, "IQ_FW1");
    185     psMetadataItemSupplement (header, recipe, "IQ_FW1_E");
    186     psMetadataItemSupplement (header, recipe, "IQ_FW2");
    187     psMetadataItemSupplement (header, recipe, "IQ_FW2_E");
    188 
    189     psMetadataItemSupplement (header, recipe, "IQ_M2");
    190     psMetadataItemSupplement (header, recipe, "IQ_M2_ER");
    191     psMetadataItemSupplement (header, recipe, "IQ_M2_LQ");
    192     psMetadataItemSupplement (header, recipe, "IQ_M2_UQ");
    193 
    194     psMetadataItemSupplement (header, recipe, "IQ_M2C");
    195     psMetadataItemSupplement (header, recipe, "IQ_M2C_E");
    196     psMetadataItemSupplement (header, recipe, "IQ_M2C_L");
    197     psMetadataItemSupplement (header, recipe, "IQ_M2C_U");
    198 
    199     psMetadataItemSupplement (header, recipe, "IQ_M2S");
    200     psMetadataItemSupplement (header, recipe, "IQ_M2S_E");
    201     psMetadataItemSupplement (header, recipe, "IQ_M2S_L");
    202     psMetadataItemSupplement (header, recipe, "IQ_M2S_U");
    203 
    204     psMetadataItemSupplement (header, recipe, "IQ_M3");
    205     psMetadataItemSupplement (header, recipe, "IQ_M3_ER");
    206     psMetadataItemSupplement (header, recipe, "IQ_M3_LQ");
    207     psMetadataItemSupplement (header, recipe, "IQ_M3_UQ");
    208 
    209     psMetadataItemSupplement (header, recipe, "IQ_M4");
    210     psMetadataItemSupplement (header, recipe, "IQ_M4_ER");
    211     psMetadataItemSupplement (header, recipe, "IQ_M4_LQ");
    212     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");
    213263
    214264    // XXX these need to be defined from elsewhere
    215265    psMetadataAdd (header, PS_LIST_TAIL, "FSATUR",   PS_DATA_F32 | PS_META_REPLACE, "SATURATION MAG",      0.0);
    216266    psMetadataAdd (header, PS_LIST_TAIL, "FLIMIT",   PS_DATA_F32 | PS_META_REPLACE, "COMPLETENESS MAG",    0.0);
    217     psMetadataItemSupplement (header, recipe, "NSTARS");
    218 
    219     psMetadataItemSupplement (header, recipe, "NDET_EXT");
    220     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");
    221271
    222272    // sky background model statistics
    223     psMetadataItemSupplement (header, recipe, "MSKY_MN");
    224     psMetadataItemSupplement (header, recipe, "MSKY_SIG");
    225     psMetadataItemSupplement (header, recipe, "MSKY_MIN");
    226     psMetadataItemSupplement (header, recipe, "MSKY_MAX");
    227     psMetadataItemSupplement (header, recipe, "MSKY_NX");
    228     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");
    229279
    230280    psMetadataAddF32 (header, PS_LIST_TAIL, "DT_PHOT", PS_META_REPLACE, "elapsed psphot time", psTimerMark ("psphotReadout"));
    231 
    232     // XXX : don't require any of these about values to exist
    233     psErrorClear ();
    234281
    235282    return header;
     
    256303        psImageKeepCircle (source->maskObj, x, y, radius, "OR", markVal);
    257304        pmModelSub (source->pixels, source->maskObj, source->modelPSF, PM_MODEL_OP_FULL, maskVal);
    258         psImageKeepCircle (source->maskObj, x, y, radius, "AND", PS_NOT_IMAGE_MASK(markVal));
     305        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
    259306    }
    260307
  • branches/simtest_nebulous_branches/psphot/src/psphotPSFConvModel.c

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

    r21458 r27840  
    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
  • branches/simtest_nebulous_branches/psphot/src/psphotPetrosian.c

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

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

    r21183 r27840  
    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 bool psphotInitRadiusPSF(const psMetadata *recipe, const pmModelType type) {
     10bool psphotInitRadiusPSF(const psMetadata *recipe, const psMetadata *analysis, const pmModelType type) {
    1011
    1112    bool status = true;
    1213
    13     PSF_FIT_NSIGMA  = psMetadataLookupF32(&status, recipe, "PSF_FIT_NSIGMA");
     14    PSF_FIT_NSIGMA = psMetadataLookupF32(&status, recipe, "PSF_FIT_NSIGMA");
    1415    PSF_FIT_PADDING = psMetadataLookupF32(&status, recipe, "PSF_FIT_PADDING");
    15     PSF_FIT_RADIUS =  psMetadataLookupF32(&status, recipe, "PSF_FIT_RADIUS");
     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    }
    1626
    1727    return true;
     
    3444            radiusFit = model->modelRadius(model->params, 1.0);
    3545        }
     46        model->fitRadius = (RADIUS_TYPE)(radiusFit + PSF_FIT_PADDING);
     47    } else {
     48        model->fitRadius = radiusFit;
    3649    }
    37     model->radiusFit = (RADIUS_TYPE)(radiusFit + PSF_FIT_PADDING);
    38 
    39     if (isnan(model->radiusFit)) psAbort("error in radius");
     50    if (isnan(model->fitRadius)) psAbort("error in radius");
    4051       
    4152    if (source->mode & PM_SOURCE_MODE_SATSTAR) {
    42         model->radiusFit *= 2;
     53        model->fitRadius *= 2;
    4354    }
    4455
    45     bool status = pmSourceRedefinePixels (source, readout, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit);
     56    // radius used to measure aperture photometry
     57    source->apRadius = PSF_APERTURE;
     58
     59    bool status = pmSourceRedefinePixels (source, readout, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius);
    4660
    4761    // set the mask to flag the excluded pixels
    48     psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit, "OR", markVal);
     62    psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius, "OR", markVal);
    4963    return status;
    5064}
     
    5872
    5973    // set the fit radius based on the object flux limit and the model
    60     model->radiusFit = (RADIUS_TYPE) (model->modelRadius (model->params, PSF_FIT_NSIGMA*moments->dSky) + dR + PSF_FIT_PADDING);
    61     if (isnan(model->radiusFit)) psAbort("error in radius");
    62        
     74    float radiusFit = PSF_FIT_RADIUS;
     75    if (radiusFit <= 0) {               // use fixed radius
     76        if (moments == NULL) {
     77            radiusFit = model->modelRadius(model->params, PSF_FIT_NSIGMA*moments->dSky);
     78        } else {
     79            radiusFit = model->modelRadius(model->params, 1.0);
     80        }
     81        model->fitRadius = (RADIUS_TYPE)(radiusFit + PSF_FIT_PADDING);
     82    } else {
     83        model->fitRadius = radiusFit;
     84    }
     85    if (isnan(model->fitRadius)) psAbort("error in radius");
     86
     87    // above sets a radius for a single star, bump by blend separation
     88    model->fitRadius += dR;
     89
    6390    if (source->mode &  PM_SOURCE_MODE_SATSTAR) {
    64         model->radiusFit *= 2;
     91        model->fitRadius *= 2;
    6592    }
    6693
    67     bool status = pmSourceRedefinePixels (source, readout, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit);
     94    // radius used to measure aperture photometry
     95    source->apRadius = PSF_APERTURE;
     96
     97    bool status = pmSourceRedefinePixels (source, readout, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius);
    6898
    6999    // set the mask to flag the excluded pixels
    70     psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit, "OR", markVal);
     100    psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius, "OR", markVal);
    71101    return status;
    72102}
     
    74104static float EXT_FIT_NSIGMA;
    75105static float EXT_FIT_PADDING;
     106static float EXT_FIT_MAX_RADIUS;
    76107
    77108bool psphotInitRadiusEXT (psMetadata *recipe, pmModelType type) {
     
    79110    bool status;
    80111
    81     EXT_FIT_NSIGMA   = psMetadataLookupF32 (&status, recipe, "EXT_FIT_NSIGMA");
    82     EXT_FIT_PADDING  = psMetadataLookupF32 (&status, recipe, "EXT_FIT_PADDING");
     112    EXT_FIT_NSIGMA     = psMetadataLookupF32 (&status, recipe, "EXT_FIT_NSIGMA");
     113    EXT_FIT_PADDING    = psMetadataLookupF32 (&status, recipe, "EXT_FIT_PADDING");
     114    EXT_FIT_MAX_RADIUS = psMetadataLookupF32 (&status, recipe, "EXT_FIT_MAX_RADIUS");
    83115
    84116    return true;
     
    86118
    87119// call this function whenever you (re)-define the EXT model
     120float psphotSetRadiusEXT (pmReadout *readout, pmSource *source, psImageMaskType markVal) {
     121
     122    psAssert (source, "source not defined??");
     123    psAssert (source->peak, "peak not defined??");
     124
     125    pmPeak *peak = source->peak;
     126
     127    // set the radius based on the footprint:
     128    if (!peak->footprint) goto escape;
     129    pmFootprint *footprint = peak->footprint;
     130    if (!footprint->spans) goto escape;
     131    if (footprint->spans->n < 1) goto escape;
     132
     133    // find the max radius
     134    float radius = 0.0;
     135    for (int j = 0; j < footprint->spans->n; j++) {
     136        pmSpan *span = footprint->spans->data[j];
     137
     138        float dY  = span->y  - peak->yf;
     139        float dX0 = span->x0 - peak->xf;
     140        float dX1 = span->x1 - peak->xf;
     141
     142        radius = PS_MAX (radius, hypot(dY, dX0));
     143        radius = PS_MAX (radius, hypot(dY, dX1));
     144    }
     145
     146    radius += EXT_FIT_PADDING;
     147    if (isnan(radius)) psAbort("error in radius");
     148
     149    radius = PS_MIN (radius, EXT_FIT_MAX_RADIUS);
     150
     151    // redefine the pixels if needed
     152    pmSourceRedefinePixels (source, readout, peak->xf, peak->yf, radius);
     153
     154    // set the mask to flag the excluded pixels
     155    psImageKeepCircle (source->maskObj, peak->xf, peak->yf, radius, "OR", markVal);
     156    return radius;
     157
     158escape:
     159    return NAN;
     160    // bool result = psphotCheckRadiusEXT (readout, source, model, markVal);
     161    // return result;
     162}
     163
     164// alternative EXT radius based on model guess (for use without footprints)
    88165bool psphotCheckRadiusEXT (pmReadout *readout, pmSource *source, pmModel *model, psImageMaskType markVal) {
     166
     167    psAbort ("do not use this function");
    89168
    90169    psF32 *PAR = model->params->data.F32;
     
    96175    float rawRadius = model->modelRadius (model->params, EXT_FIT_NSIGMA*moments->dSky);
    97176
    98     model->radiusFit = rawRadius + EXT_FIT_PADDING;
    99     if (isnan(model->radiusFit)) psAbort("error in radius");
     177    model->fitRadius = rawRadius + EXT_FIT_PADDING;
     178    if (isnan(model->fitRadius)) psAbort("error in radius");
    100179
    101180    // redefine the pixels if needed
    102     bool status = pmSourceRedefinePixels (source, readout, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit);
     181    bool status = pmSourceRedefinePixels (source, readout, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius);
    103182
    104183    // set the mask to flag the excluded pixels
    105     psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit, "OR", markVal);
     184    psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius, "OR", markVal);
    106185    return status;
    107186}
  • branches/simtest_nebulous_branches/psphot/src/psphotReadout.c

    r24890 r27840  
    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");
     16
     17    pmModelClassSetLimits(PM_MODEL_LIMITS_LAX);
    1918
    2019    // select the current recipe
     
    2423        return false;
    2524    }
     25    // optional break-point for processing
     26    char *breakPt = psMetadataLookupStr (NULL, recipe, "BREAK_POINT");
     27    psAssert (breakPt, "configuration error: set BREAK_POINT");
    2628
    2729    // set the photcode for this image
    28     if (!psphotAddPhotcode (recipe, config, view, "PSPHOT.INPUT")) {
     30    if (!psphotAddPhotcode (config, view)) {
    2931        psError (PSPHOT_ERR_CONFIG, false, "trouble defining the photcode");
    3032        return false;
    3133    }
    3234
    33     // find the currently selected readout
    34     pmReadout  *readout = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT");
    35     PS_ASSERT_PTR_NON_NULL (readout, false);
    36 
    37     // optional break-point for processing
    38     char *breakPt = psMetadataLookupStr (NULL, recipe, "BREAK_POINT");
    39     PS_ASSERT_PTR_NON_NULL (breakPt, false);
    40 
    4135    // Generate the mask and weight images, including the user-defined analysis region of interest
    42     psphotSetMaskAndVariance (config, readout, recipe);
     36    if (!psphotSetMaskAndVariance (config, view)) {
     37        return psphotReadoutCleanup(config, view);
     38    }
    4339    if (!strcasecmp (breakPt, "NOTHING")) {
    44         return psphotReadoutCleanup(config, readout, recipe, NULL, NULL, NULL);
    45     }
    46 
    47     // display the image, weight, mask (ch 1,2,3)
    48     psphotVisualShowImage (readout);
     40        return psphotReadoutCleanup(config, view);
     41    }
    4942
    5043    // generate a background model (median, smoothed image)
    51     if (!psphotModelBackground (config, view, "PSPHOT.INPUT")) {
    52         return psphotReadoutCleanup (config, readout, recipe, NULL, NULL, NULL);
    53     }
    54     if (!psphotSubtractBackground (config, view, "PSPHOT.INPUT")) {
    55         return psphotReadoutCleanup (config, readout, recipe, NULL, NULL, NULL);
     44    if (!psphotModelBackground (config, view)) {
     45        return psphotReadoutCleanup (config, view);
     46    }
     47    if (!psphotSubtractBackground (config, view)) {
     48        return psphotReadoutCleanup (config, view);
    5649    }
    5750    if (!strcasecmp (breakPt, "BACKMDL")) {
    58         return psphotReadoutCleanup (config, readout, recipe, NULL, NULL, NULL);
    59     }
    60 
    61     // display the backsub and backgnd images
    62     psphotVisualShowBackground (config, view, readout);
    63    
    64     // run a single-model test if desired (exits from here if test is run)
    65     psphotModelTest (config, view, recipe);
    66 
    67     // load the psf model, if suppled.  FWHM_X,FWHM_Y,etc are saved in the recipe
    68     pmPSF *psf = psphotLoadPSF (config, view, recipe);
    69 
    70     // several functions below behave differently if we have a PSF model already
    71     bool havePSF = (psf != NULL);
     51        return psphotReadoutCleanup (config, view);
     52    }
     53
     54    // load the psf model, if suppled.  FWHM_X,FWHM_Y,etc are determined and saved on
     55    // readout->analysis XXX this function currently only works with a single PSPHOT.INPUT
     56    if (!psphotLoadPSF (config, view)) {
     57        psError (PSPHOT_ERR_UNKNOWN, false, "error loading psf model");
     58        return psphotReadoutCleanup (config, view);
     59    }
    7260
    7361    // find the detections (by peak and/or footprint) in the image.
    74     pmDetections *detections = psphotFindDetections (NULL, readout, recipe);
    75     if (!detections) {
    76         psLogMsg ("psphot", 3, "unable to find detections in this image");
    77         return psphotReadoutCleanup (config, readout, recipe, detections, psf, NULL);
    78     }
    79 
    80     // construct sources and measure basic stats
    81     psArray *sources = psphotSourceStats (config, readout, detections);
    82     if (!sources) return false;
     62    if (!psphotFindDetections (config, view, true)) { // pass 1
     63        // this only happens if we had an error in psphotFindDetections
     64        psError (PSPHOT_ERR_UNKNOWN, false, "failure in peak analysis");
     65        return psphotReadoutCleanup (config, view);
     66    }
     67
     68    // construct sources and measure basic stats (saved on detections->newSources)
     69    if (!psphotSourceStats (config, view, true)) { // pass 1
     70        psError(PSPHOT_ERR_UNKNOWN, false, "failure to generate sources");
     71        return psphotReadoutCleanup (config, view);
     72    }
    8373    if (!strcasecmp (breakPt, "PEAKS")) {
    84         return psphotReadoutCleanup(config, readout, recipe, detections, psf, sources);
    85     }
    86 
    87     // find blended neighbors of very saturated stars
    88     // XXX merge this with Basic Deblend?
    89     psphotDeblendSatstars (readout, sources, recipe);
    90 
    91     // mark blended peaks PS_SOURCE_BLEND
    92     if (!psphotBasicDeblend (sources, recipe)) {
    93         psLogMsg ("psphot", 3, "failed on deblend analysis");
    94         return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
    95     }
    96 
    97     // classify sources based on moments, brightness
    98     if (!psphotRoughClass (readout, sources, recipe, havePSF)) {
    99         psLogMsg ("psphot", 3, "failed to find a valid PSF clump for image");
    100         return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
     74        return psphotReadoutCleanup(config, view);
     75    }
     76
     77    // find blended neighbors of very saturated stars (detections->newSources)
     78    if (!psphotDeblendSatstars (config, view)) {
     79        psError (PSPHOT_ERR_UNKNOWN, false, "failed on satstar deblend analysis");
     80        return psphotReadoutCleanup (config, view);
     81    }
     82
     83    // mark blended peaks PS_SOURCE_BLEND (detections->newSources)
     84    if (!psphotBasicDeblend (config, view)) {
     85        psError (PSPHOT_ERR_UNKNOWN, false, "failed on deblend analysis");
     86        return psphotReadoutCleanup (config, view);
     87    }
     88
     89    // classify sources based on moments, brightness.  if a PSF model has been loaded, the PSF
     90    // clump defined for it is used not measured (detections->newSources)
     91    if (!psphotRoughClass (config, view)) { // pass 1
     92        psError (PSPHOT_ERR_UNKNOWN, false, "failed to determine rough classifications");
     93        return psphotReadoutCleanup (config, view);
     94    }
     95    // if we were not supplied a PSF model, determine the IQ stats here (detections->newSources)
     96    if (!psphotImageQuality (config, view)) { // pass 1
     97        psError (PSPHOT_ERR_UNKNOWN, false, "failed to measure image quality");
     98        return psphotReadoutCleanup(config, view);
    10199    }
    102100    if (!strcasecmp (breakPt, "MOMENTS")) {
    103         return psphotReadoutCleanup(config, readout, recipe, detections, psf, sources);
    104     }
    105 
    106     if (!havePSF && !psphotImageQuality (recipe, sources)) {
    107         psLogMsg("psphot", 3, "failed to measure image quality");
    108         return psphotReadoutCleanup(config, readout, recipe, detections, psf, sources);
    109     }
    110 
    111     // if we were not supplied a PSF, choose one here
    112     if (psf == NULL) {
    113         // use bright stellar objects to measure PSF
    114         // XXX if we do not have enough stars to generate the PSF, build one
    115         // from the SEEING guess and model class
    116         psf = psphotChoosePSF (readout, sources, recipe);
    117         if (psf == NULL) {
    118             psLogMsg ("psphot", 3, "failure to construct a psf model");
    119             return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
    120         }
    121         havePSF = true;
     101        return psphotReadoutCleanup(config, view);
     102    }
     103
     104    // use bright stellar objects to measure PSF if we were supplied a PSF for any input file,
     105    // this step is skipped
     106    if (!psphotChoosePSF (config, view)) { // pass 1
     107        psLogMsg ("psphot", 3, "failure to construct a psf model");
     108        return psphotReadoutCleanup (config, view);
    122109    }
    123110    if (!strcasecmp (breakPt, "PSFMODEL")) {
    124         return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
    125     }
    126 
    127     psphotVisualShowPSFModel (readout, psf);
     111        return psphotReadoutCleanup (config, view);
     112    }
    128113
    129114    // include externally-supplied sources
    130     psphotLoadExtSources (config, view, sources);
    131 
    132     // construct an initial model for each object
    133     psphotGuessModels (config, readout, sources, psf);
    134 
    135     // XXX test output of models
    136     // psphotTestSourceOutput (readout, sources, recipe, psf);
    137 
    138     // linear PSF fit to source peaks
    139     psphotFitSourcesLinear (readout, sources, recipe, psf, FALSE);
    140 
    141     // We have to place these visualizations here because the models are not realized until
    142     // psphotGuessModels or fitted until psphotFitSourcesLinear.
    143     psphotVisualShowPSFStars (recipe, psf, sources);
    144     psphotVisualShowSatStars (recipe, psf, sources);
    145 
    146     // identify CRs and extended sources
    147     psphotSourceSize (config, readout, sources, recipe, 0);
     115    // XXX fix this in the new multi-input context
     116    // psphotLoadExtSources (config, view); // pass 1
     117
     118    // construct an initial model for each object, set the radius to fitRadius, set circular
     119    // fit mask (detections->newSources)
     120    psphotGuessModels (config, view); // pass 1
     121
     122    // merge the newly selected sources into the existing list
     123    // NOTE: merge OLD and NEW
     124    psphotMergeSources (config, view);
     125
     126    // linear PSF fit to source peaks, subtract the models from the image (in PSF mask)
     127    psphotFitSourcesLinear (config, view, false); // pass 1 (detections->allSources)
     128
     129    // identify CRs and extended sources (only unmeasured sources are measured)
     130    psphotSourceSize (config, view, true); // pass 1 (detections->allSources)
    148131    if (!strcasecmp (breakPt, "ENSEMBLE")) {
    149132        goto finish;
     
    151134
    152135    // non-linear PSF and EXT fit to brighter sources
    153     psphotBlendFit (config, readout, sources, psf);
     136    // replace model flux, adjust mask as needed, fit, subtract the models (full stamp)
     137    psphotBlendFit (config, view); // pass 1 (detections->allSources)
    154138
    155139    // replace all sources
    156     psphotReplaceAllSources (sources, recipe);
    157 
    158     // linear fit to include all sources
    159     psphotFitSourcesLinear (readout, sources, recipe, psf, TRUE);
     140    psphotReplaceAllSources (config, view); // pass 1 (detections->allSources)
     141
     142    // linear fit to include all sources (subtract again)
     143    // NOTE : apply to ALL sources (extended + psf)
     144    psphotFitSourcesLinear (config, view, true); // pass 2 (detections->allSources)
    160145
    161146    // if we only do one pass, skip to extended source analysis
    162     if (!strcasecmp (breakPt, "PASS1")) {
    163         goto pass1finish;
    164     }
    165 
    166     // XXX for the moment, drop the re-calc of the background (prove this works)
    167     // replace background in residual image
    168     // psphotSkyReplace (config, view);
    169     // re-measure background model (median, smoothed image)
    170     // psphotImageMedian (config, view);
     147    if (!strcasecmp (breakPt, "PASS1")) goto pass1finish;
     148
     149    // NOTE: possibly re-measure background model here with objects subtracted / or masked
    171150
    172151    // add noise for subtracted objects
    173     psphotAddNoise (readout, sources, recipe);
    174 
    175     // find fainter sources (pass 2)
    176     detections = psphotFindDetections (detections, readout, recipe);
     152    psphotAddNoise (config, view); // pass 1 (detections->allSources)
     153
     154    // find fainter sources
     155    // NOTE: finds new peaks and new footprints, OLD and FULL set are saved on detections
     156    psphotFindDetections (config, view, false); // pass 2 (detections->peaks, detections->footprints)
    177157
    178158    // remove noise for subtracted objects (ie, return to normal noise level)
    179     psphotSubNoise (readout, sources, recipe);
     159    // NOTE: this needs to operate only on the OLD sources
     160    psphotSubNoise (config, view); // pass 1 (detections->allSources)
    180161
    181162    // define new sources based on only the new peaks
    182     psArray *newSources = psphotSourceStats (config, readout, detections);
     163    // NOTE: new sources are saved on detections->newSources
     164    psphotSourceStats (config, view, false); // pass 2 (detections->newSources)
    183165
    184166    // set source type
    185     if (!psphotRoughClass (readout, newSources, recipe, havePSF)) {
     167    // NOTE: apply only to detections->newSources
     168    if (!psphotRoughClass (config, view)) { // pass 2 (detections->newSources)
    186169        psLogMsg ("psphot", 3, "failed to find a valid PSF clump for image");
    187         return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
    188     }
    189 
    190     // create full input models
    191     psphotGuessModels (config, readout, newSources, psf);
     170        return psphotReadoutCleanup (config, view);
     171    }
     172
     173    // create full input models, set the radius to fitRadius, set circular fit mask
     174    // NOTE: apply only to detections->newSources
     175    psphotGuessModels (config, view); // pass 2 (detections->newSources)
    192176
    193177    // replace all sources so fit below applies to all at once
    194     psphotReplaceAllSources (sources, recipe);
     178    // NOTE: apply only to OLD sources (which have been subtracted)
     179    psphotReplaceAllSources (config, view); // pass 2
    195180
    196181    // merge the newly selected sources into the existing list
    197     psphotMergeSources (sources, newSources);
    198     psFree (newSources);
    199 
    200     // linear fit to all sources
    201     psphotFitSourcesLinear (readout, sources, recipe, psf, TRUE);
     182    // NOTE: merge OLD and NEW
     183    // XXX check on free of sources...
     184    psphotMergeSources (config, view); // (detections->newSources + detections->allSources -> detections->allSources)
     185
     186    // NOTE: apply to ALL sources
     187    psphotFitSourcesLinear (config, view, true); // pass 3 (detections->allSources)
    202188
    203189pass1finish:
    204190
    205191    // measure source size for the remaining sources
    206     psphotSourceSize (config, readout, sources, recipe, 0);
    207 
    208     psphotExtendedSourceAnalysis (readout, sources, recipe);
    209 
    210     psphotExtendedSourceFits (readout, sources, recipe);
     192    // NOTE: applies only to NEW (unmeasured) sources
     193    psphotSourceSize (config, view, false); // pass 2 (detections->allSources)
     194
     195    psphotExtendedSourceAnalysis (config, view); // pass 1 (detections->allSources)
     196    psphotExtendedSourceFits (config, view); // pass 1 (detections->allSources)
    211197
    212198finish:
     
    216202
    217203    // measure aperture photometry corrections
    218     if (!psphotApResid (config, readout, sources, psf)) {
     204    if (!psphotApResid (config, view)) { // pass 1 (detections->allSources)
    219205        psLogMsg ("psphot", 3, "failed on psphotApResid");
    220         return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
     206        return psphotReadoutCleanup (config, view);
    221207    }
    222208
    223209    // calculate source magnitudes
    224     psphotMagnitudes(config, readout, view, sources, psf);
     210    psphotMagnitudes(config, view); // pass 1 (detections->allSources)
     211
     212    if (!psphotEfficiency(config, view)) { // pass 1
     213        psErrorStackPrint(stderr, "Unable to determine detection efficiencies from fake sources");
     214        psErrorClear();
     215    }
    225216
    226217    // replace failed sources?
     
    228219
    229220    // replace background in residual image
    230     psphotSkyReplace (config, view);
     221    psphotSkyReplace (config, view); // pass 1
    231222
    232223    // drop the references to the image pixels held by each source
    233     psphotSourceFreePixels (sources);
     224    psphotSourceFreePixels (config, view); // pass 1
    234225
    235226    // create the exported-metadata and free local data
    236     return psphotReadoutCleanup(config, readout, recipe, detections, psf, sources);
     227    return psphotReadoutCleanup(config, view);
    237228}
    238 
  • branches/simtest_nebulous_branches/psphot/src/psphotReadoutCleanup.c

    r24203 r27840  
    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 ? detections->allSources : NULL;
     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
    42     if (!psf) {
     74    // XXX not sure we want / need this test
     75    if (0 && !psf) {
    4376        bool mdok;                      // Status of MD lookup
    4477        int nIQ = psMetadataLookupS32(&mdok, recipe, "IQ_NSTAR"); // Number of stars for IQ measurement
    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}
  • branches/simtest_nebulous_branches/psphot/src/psphotReadoutFindPSF.c

    r23442 r27840  
    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);
    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}
  • branches/simtest_nebulous_branches/psphot/src/psphotReadoutKnownSources.c

    r23442 r27840  
    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);
    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}
  • branches/simtest_nebulous_branches/psphot/src/psphotReadoutMinimal.c

    r24890 r27840  
    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.
     
    1515    psTimerStart ("psphotReadout");
    1616
    17     // select the current recipe
    18     psMetadata *recipe = psMetadataLookupPtr (NULL, config->recipes, PSPHOT_RECIPE);
    19     if (!recipe) {
    20         psError(PSPHOT_ERR_CONFIG, false, "missing recipe %s", PSPHOT_RECIPE);
    21         return false;
    22     }
     17    pmModelClassSetLimits(PM_MODEL_LIMITS_LAX);
    2318
    2419    // set the photcode for this image
    25     if (!psphotAddPhotcode(recipe, config, view, "PSPHOT.INPUT")) {
     20    if (!psphotAddPhotcode(config, view)) {
    2621        psError(PSPHOT_ERR_CONFIG, false, "trouble defining the photcode");
    2722        return false;
    2823    }
    2924
    30     // find the currently selected readout
    31     pmReadout  *readout = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT");
    32     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);
    3327
    34     // Generate the mask and weight images, including the user-defined analysis region of interest
    35     psphotSetMaskAndVariance (config, readout, recipe);
    36 
    37     // display the image, weight, mask (ch 1,2,3)
    38     psphotVisualShowImage (readout);
    39 
    40     // load the psf model, if suppled.  FWHM_X,FWHM_Y,etc are saved in the recipe
    41     pmPSF *psf = psphotLoadPSF (config, view, recipe);
    42     if (!psf) {
     28    // load the psf model, if suppled.  FWHM_X,FWHM_Y,etc are saved on readout->analysis
     29    if (!psphotLoadPSF (config, view)) {
    4330      psError (PSPHOT_ERR_CONFIG, false, "missing psf model");
    44       return psphotReadoutCleanup (config, readout, recipe, NULL, NULL, NULL);
     31      return psphotReadoutCleanup (config, view);
    4532    }
    4633
    47     // find the detections (by peak and/or footprint) in the image.
    48     pmDetections *detections = pmDetectionsAlloc(); // New detections; allocated to ensure pass=2
    49     detections = psphotFindDetections(detections, readout, recipe);
    50     if (!detections) {
    51         psLogMsg ("psphot", 3, "unable to find detections in this image");
    52         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);
    5338    }
    5439
    55     // construct sources and measure basic stats
    56     psArray *sources = psphotSourceStats (config, readout, detections);
    57     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    }
    5845
    5946    // find blended neighbors of very saturated stars
    60     // XXX merge this with Basic Deblend?
    61     psphotDeblendSatstars (readout, sources, recipe);
     47    psphotDeblendSatstars (config, view);
    6248
    6349    // mark blended peaks PS_SOURCE_BLEND
    64     if (!psphotBasicDeblend (sources, recipe)) {
     50    if (!psphotBasicDeblend (config, view)) {
    6551        psLogMsg ("psphot", 3, "failed on deblend analysis");
    66         return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
     52        return psphotReadoutCleanup (config, view);
    6753    }
    6854
    6955    // classify sources based on moments, brightness (use supplied psf shape parameters)
    70     if (!psphotRoughClass (readout, sources, recipe, true)) {
     56    if (!psphotRoughClass (config, view)) {
    7157        psLogMsg ("psphot", 3, "failed to find a valid PSF clump for image");
    72         return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
     58        return psphotReadoutCleanup (config, view);
    7359    }
    7460
    7561    // construct an initial model for each object
    76     psphotGuessModels (config, readout, sources, psf);
     62    psphotGuessModels (config, view);
     63
     64    // merge the newly selected sources into the existing list
     65    psphotMergeSources (config, view);
    7766
    7867    // linear PSF fit to source peaks
    79     psphotFitSourcesLinear (readout, sources, recipe, psf, FALSE);
    80 
    81     // We have to place these visualizations here because the models are not realized until
    82     // psphotGuessModels or fitted until psphotFitSourcesLinear.
    83     psphotVisualShowPSFStars (recipe, psf, sources);
    84     psphotVisualShowSatStars (recipe, psf, sources);
     68    psphotFitSourcesLinear (config, view, false);
    8569
    8670// XXX eventually, add the extended source fits here
    8771# if (0)
    8872    // measure source size for the remaining sources
    89     psphotSourceSize (config, readout, sources, recipe, 0);
     73    psphotSourceSize (config, view);
    9074
    91     psphotExtendedSourceAnalysis (readout, sources, recipe);
     75    psphotExtendedSourceAnalysis (config, view);
    9276
    93     psphotExtendedSourceFits (readout, sources, recipe);
     77    psphotExtendedSourceFits (config, view);
    9478# endif
    9579
    9680    // calculate source magnitudes
    97     psphotMagnitudes(config, readout, view, sources, psf);
     81    psphotMagnitudes(config, view);
     82
     83    // XXX ensure this is measured if the analysis succeeds (even if quality is low)
     84    if (!psphotEfficiency(config, view)) {
     85        psErrorStackPrint(stderr, "Unable to determine detection efficiencies from fake sources");
     86        psErrorClear();
     87    }
    9888
    9989    // drop the references to the image pixels held by each source
    100     psphotSourceFreePixels (sources);
     90    psphotSourceFreePixels (config, view);
    10191
    10292    // create the exported-metadata and free local data
    103     return psphotReadoutCleanup(config, readout, recipe, detections, psf, sources);
     93    return psphotReadoutCleanup(config, view);
    10494}
  • branches/simtest_nebulous_branches/psphot/src/psphotReplaceUnfit.c

    r21519 r27840  
    1717    replace:
    1818        pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    19         source->tmpFlags &= ~PM_SOURCE_TMPF_SUBTRACTED;
    2019    }
    2120    psLogMsg ("psphot.replace", 3, "replace unfitted models: %f sec (%ld objects)\n", psTimerMark ("psphot.replace"), sources->n);
     
    2322}
    2423
    25 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) {
    2647
    2748    bool status;
     
    3051    psTimerStart ("psphot.replace");
    3152
     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
    3266    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
    3367    psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
    34     assert (maskVal);
     68    psAssert (maskVal, "missing mask value?");
    3569
    3670    for (int i = 0; i < sources->n; i++) {
     
    4175
    4276      pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    43       source->tmpFlags &= ~PM_SOURCE_TMPF_SUBTRACTED;
    4477    }
    4578    psLogMsg ("psphot.replace", PS_LOG_INFO, "replaced models for %ld objects: %f sec\n", sources->n, psTimerMark ("psphot.replace"));
     
    4780}
    4881
    49 bool psphotRemoveAllSources (psArray *sources, psMetadata *recipe) {
     82bool psphotRemoveAllSources (const psArray *sources, const psMetadata *recipe) {
    5083
    5184    bool status;
     
    6497      if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) continue;
    6598
    66       pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    67       source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
     99      pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    68100    }
    69101    psLogMsg ("psphot.replace", PS_LOG_INFO, "replaced models for %ld objects: %f sec\n", sources->n, psTimerMark ("psphot.replace"));
    70102    return true;
    71103}
    72 
    73 // add source, if the source has been subtracted; do not modify state
    74 bool psphotAddWithTest (pmSource *source, bool useState, psImageMaskType maskVal) {
    75 
    76     // what is current state? (true : add; false : sub)
    77     bool state = !(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
    78     if (state && useState) return true;
    79 
    80     pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    81     return true;
    82 }
    83 
    84 // sub source, if the source has been added; do not modify state
    85 bool psphotSubWithTest (pmSource *source, bool useState, psImageMaskType maskVal) {
    86 
    87     // what is current state? (true : sub; false : add)
    88     bool state = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
    89     if (state && useState) return true;
    90 
    91     pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    92     return true;
    93 }
    94 
    95 // add or sub source to match recorded state: supply current state as true (add) or false (sub)
    96 bool psphotSetState (pmSource *source, bool curState, psImageMaskType maskVal) {
    97 
    98     // what is desired state? (true : add; false : sub)
    99     bool newState = !(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
    100     if (curState == newState) return true;
    101 
    102     if (curState && !newState) {
    103         pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    104     }
    105     if (newState && !curState) {
    106         pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    107     }
    108     return true;
    109 }
  • branches/simtest_nebulous_branches/psphot/src/psphotRoughClass.c

    r23989 r27840  
    11# include "psphotInternal.h"
    22
    3 # define CHECK_STATUS(S,MSG) {                                          \
    4         if (!status) {                                                  \
    5             psError(PSPHOT_ERR_CONFIG, false, "missing PSF Clump entry: %s\n", MSG); \
    6             return false;                                               \
    7         } }
     3# define CHECK_STATUS(S,MSG) {                                          \
     4        if (!status) {                                                  \
     5            psError(PSPHOT_ERR_CONFIG, false, "missing PSF Clump entry: %s\n", MSG); \
     6            return false;                                               \
     7        } }
    88
    9 bool psphotRoughClassRegion (int nRegion, psRegion *region, psArray *sources, 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    // skip the chisq image (optionally?)
     22    int chisqNum = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.CHISQ.NUM");
     23    if (!status) chisqNum = -1;
     24
     25    // loop over the available readouts
     26    for (int i = 0; i < num; i++) {
     27        if (i == chisqNum) continue; // skip chisq image
     28        if (!psphotRoughClassReadout (config, view, "PSPHOT.INPUT", i, recipe)) {
     29            psError (PSPHOT_ERR_CONFIG, false, "failed on rough classification for PSPHOT.INPUT entry %d", i);
     30            return false;
     31        }
     32    }
     33    return true;
     34}
     35
     36bool psphotRoughClassReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe) {
    1337
    1438    bool status;
    1539
    1640    psTimerStart ("psphot.rough");
     41
     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    // if we have a PSF, use the existing PSF clump region below
     50    bool havePSF = false;
     51    if (psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF")) {
     52        havePSF = true;
     53    }
     54
     55    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     56    psAssert (detections, "missing detections?");
     57
     58    psArray *sources = detections->newSources;
     59    psAssert (sources, "missing sources?");
     60
     61    if (!sources->n) {
     62        psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping rough classification");
     63        return true;
     64    }
    1765
    1866    // we make this measurement on a NxM grid of regions across the readout
     
    2472    int nRegion = 0;
    2573    for (int ix = 0; ix < NX; ix ++) {
    26         for (int iy = 0; iy < NY; iy ++) {
     74        for (int iy = 0; iy < NY; iy ++) {
    2775
    28             psRegion region = psRegionSet (ix*dX, (ix + 1)*dX, iy*dY, (iy + 1)*dY);
    29             if (!psphotRoughClassRegion (nRegion, &region, sources, recipe, havePSF)) {
    30                 psLogMsg ("psphot", 4, "Failed to determine rough classification for region %f,%f - %f,%f\n",
    31                          region.x0, region.y0, region.x1, region.y1);
    32                 continue;
    33             }
    34            
    35             nRegion ++;
    36         }
     76            psRegion *region = psRegionAlloc (ix*dX, (ix + 1)*dX, iy*dY, (iy + 1)*dY);
     77            if (!psphotRoughClassRegion (nRegion, region, sources, readout->analysis, recipe, havePSF)) {
     78                psLogMsg ("psphot", 4, "Failed to determine rough classification for region %f,%f - %f,%f\n",
     79                         region->x0, region->y0, region->x1, region->y1);
     80                psFree (region);
     81                continue;
     82            }
     83            psFree (region);
     84            nRegion ++;
     85        }
    3786    }
    38     psMetadataAddS32 (recipe, PS_LIST_TAIL, "PSF.CLUMP.NREGIONS",  PS_META_REPLACE, "psf clump regions", nRegion);
     87    psMetadataAddS32 (readout->analysis, PS_LIST_TAIL, "PSF.CLUMP.NREGIONS",  PS_META_REPLACE, "psf clump regions", nRegion);
    3988
    4089    // optional printout of source moments only
     
    4392    psLogMsg ("psphot.roughclass", PS_LOG_INFO, "rough classification: %f sec\n", psTimerMark ("psphot.rough"));
    4493
    45     psphotVisualPlotMoments (recipe, sources);
     94    psphotVisualPlotMoments (recipe, readout->analysis, sources);
    4695    psphotVisualShowRoughClass (sources);
    47     psphotVisualShowFlags (sources);
     96    // XXX better visualization: psphotVisualShowFlags (sources);
    4897
    4998    return true;
    5099}
    51100
    52 bool psphotRoughClassRegion (int nRegion, psRegion *region, psArray *sources, psMetadata *recipe, const bool havePSF) {
     101bool psphotRoughClassRegion (int nRegion, psRegion *region, psArray *sources, psMetadata *analysis, psMetadata *recipe, const bool havePSF) {
    53102
    54103    bool status;
     
    60109    assert (maskSat);
    61110
     111    // the regions are saved on the readout->analysis metadata folder (passed to us as analysis)
    62112    snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", nRegion);
    63     psMetadata *regionMD = psMetadataLookupPtr (&status, recipe, regionName);
     113    psMetadata *regionMD = psMetadataLookupPtr (&status, analysis, regionName);
    64114    if (!regionMD) {
    65         regionMD = psMetadataAlloc();
    66         psMetadataAddMetadata (recipe, PS_LIST_TAIL, regionName, PS_META_REPLACE, "psf clump region", regionMD);
    67         psFree (regionMD);
     115        // allocate the region metadata folder and add this region to it.
     116        regionMD = psMetadataAlloc();
     117        psMetadataAddMetadata (analysis, PS_LIST_TAIL, regionName, PS_META_REPLACE, "psf clump region", regionMD);
     118        psFree (regionMD);
    68119    }
     120    psMetadataAddPtr (regionMD, PS_LIST_TAIL, "REGION", PS_DATA_REGION | PS_META_REPLACE, "psf clump region", region);
    69121
    70122    if (!havePSF) {
    71         // determine the PSF parameters from the source moment values
    72         psfClump = pmSourcePSFClump (region, sources, recipe);
    73         psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.X",  PS_META_REPLACE, "psf clump center", psfClump.X);
    74         psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.Y",  PS_META_REPLACE, "psf clump center", psfClump.Y);
    75         psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DX", PS_META_REPLACE, "psf clump center", psfClump.dX);
    76         psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DY", PS_META_REPLACE, "psf clump center", psfClump.dY);
     123        // determine the PSF parameters from the source moment values
     124        // XXX why not save the psfClump as a PTR?
     125
     126        float PSF_SN_LIM = psMetadataLookupF32(&status, recipe, "PSF_SN_LIM"); psAssert (status, "missing PSF_SN_LIM");
     127        float MOMENTS_AR_MAX = psMetadataLookupF32(&status, recipe, "MOMENTS_AR_MAX"); psAssert (status, "missing MOMENTS_AR_MAX");
     128
     129        float PSF_CLUMP_GRID_SCALE = psMetadataLookupF32(&status, analysis, "PSF_CLUMP_GRID_SCALE");
     130        if (!status) {
     131            PSF_CLUMP_GRID_SCALE = psMetadataLookupF32(&status, recipe, "PSF_CLUMP_GRID_SCALE");
     132            psAssert (status, "missing PSF_CLUMP_GRID_SCALE");
     133        }
     134        float MOMENTS_SX_MAX = psMetadataLookupF32(&status, analysis, "MOMENTS_SX_MAX");
     135        if (!status) {
     136            MOMENTS_SX_MAX = psMetadataLookupF32(&status, recipe, "MOMENTS_SX_MAX");
     137            psAssert (status, "missing MOMENTS_SX_MAX");
     138        }
     139        float MOMENTS_SY_MAX = psMetadataLookupF32(&status, analysis, "MOMENTS_SY_MAX");
     140        if (!status) {
     141            MOMENTS_SY_MAX = psMetadataLookupF32(&status, recipe, "MOMENTS_SY_MAX");
     142            psAssert (status, "missing MOMENTS_SY_MAX");
     143        }
     144
     145        psfClump = pmSourcePSFClump (NULL, region, sources, PSF_SN_LIM, PSF_CLUMP_GRID_SCALE, MOMENTS_SX_MAX, MOMENTS_SY_MAX, MOMENTS_AR_MAX);
     146
     147        psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.X",  PS_META_REPLACE, "psf clump center", psfClump.X);
     148        psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.Y",  PS_META_REPLACE, "psf clump center", psfClump.Y);
     149        psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DX", PS_META_REPLACE, "psf clump center", psfClump.dX);
     150        psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DY", PS_META_REPLACE, "psf clump center", psfClump.dY);
    77151    } else {
    78         // pull FWHM_X,Y from the recipe, use to define psfClump.X,Y
    79         psfClump.X  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");
    80         if (!status) {
    81             psLogMsg ("psphot", 4, "No PSF clump defined for region %f,%f - %f,%f\n", region->x0, region->y0, region->x1, region->y1);
    82             return false;
    83         }           
    84         psfClump.Y  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y");   psAssert (status, "missing PSF.CLUMP.Y");
    85         psfClump.dX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX");  psAssert (status, "missing PSF.CLUMP.DX");
    86         psfClump.dY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY");  psAssert (status, "missing PSF.CLUMP.DY");
     152        // pull FWHM_X,Y from the recipe, use to define psfClump.X,Y
     153        psfClump.X  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");
     154        if (!status) {
     155            psLogMsg ("psphot", 4, "No PSF clump defined for region %f,%f - %f,%f\n", region->x0, region->y0, region->x1, region->y1);
     156            return false;
     157        }
     158        psfClump.Y  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y");   psAssert (status, "missing PSF.CLUMP.Y");
     159        psfClump.dX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX");  psAssert (status, "missing PSF.CLUMP.DX");
     160        psfClump.dY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY");  psAssert (status, "missing PSF.CLUMP.DY");
    87161    }
    88162
    89163    if (psfClump.X < 0) {
    90         psError(PSPHOT_ERR_PROG, false, "programming error calling pmSourcePSFClump");
    91         return false;
     164        psError(PSPHOT_ERR_PROG, false, "programming error calling pmSourcePSFClump");
     165        return false;
    92166    }
    93167    if (!psfClump.X || !psfClump.Y || isnan(psfClump.X) || isnan(psfClump.Y)) {
    94         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);
    95         return false;
     168        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);
     169        return false;
    96170    }
    97171    psLogMsg ("psphot", 3, "psf clump  X,  Y: %f, %f\n", psfClump.X, psfClump.Y);
    98172    psLogMsg ("psphot", 3, "psf clump DX, DY: %f, %f\n", psfClump.dX, psfClump.dY);
    99173
     174    // get basic parameters, or set defaults
     175    float PSF_SN_LIM = psMetadataLookupF32 (&status, recipe, "PSF_SN_LIM"); psAssert (status, "missing PSF_SN_LIM");
     176    float PSF_CLUMP_NSIGMA = psMetadataLookupF32 (&status, recipe, "PSF_CLUMP_NSIGMA"); psAssert (status, "missing PSF_CLUMP_NSIGMA");
     177
    100178    // group into STAR, COSMIC, EXTENDED, SATURATED, etc.
    101     if (!pmSourceRoughClass (region, sources, recipe, psfClump, maskSat)) {
    102         psError(PSPHOT_ERR_PROG, false, "programming error calling pmSourceRoughClass");
    103         return false;
     179    if (!pmSourceRoughClass (region, sources, PSF_SN_LIM, PSF_CLUMP_NSIGMA, psfClump, maskSat)) {
     180        psError(PSPHOT_ERR_PROG, false, "programming error calling pmSourceRoughClass");
     181        return false;
    104182    }
    105183
  • branches/simtest_nebulous_branches/psphot/src/psphotSetThreads.c

    r23218 r27840  
    1010    psFree(task);
    1111
    12     task = psThreadTaskAlloc("PSPHOT_MAGNITUDES", 8);
     12    task = psThreadTaskAlloc("PSPHOT_MAGNITUDES", 9);
    1313    task->function = &psphotMagnitudes_Threaded;
    1414    psThreadTaskAdd(task);
     
    2020    psFree(task);
    2121
    22     task = psThreadTaskAlloc("PSPHOT_APRESID_MAGS", 6);
     22    task = psThreadTaskAlloc("PSPHOT_APRESID_MAGS", 7);
    2323    task->function = &psphotApResidMags_Threaded;
    2424    psThreadTaskAdd(task);
    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);
  • branches/simtest_nebulous_branches/psphot/src/psphotSignificanceImage.c

    r21407 r27840  
    2222    }
    2323
    24     bool status_x, status_y;
    25     float FWHM_X = psMetadataLookupF32 (&status_x, recipe, "FWHM_X");
    26     float FWHM_Y = psMetadataLookupF32 (&status_y, recipe, "FWHM_Y");
    27     if (status_x && status_y) {
    28       // if we know the FHWM, use that to set the smoothing kernel (XXX allow an optional override?)
    29       SIGMA_SMTH  = 0.5*(FWHM_X + FWHM_Y) / (2.0*sqrt(2.0*log(2.0)));
    30       NSIGMA_SMTH = psMetadataLookupF32 (&status, recipe, "PEAKS_SMOOTH_NSIGMA");
    31       guess = false;
     24    // if we have already determined the PSF model, then we have a better idea how to smooth this image
     25    bool statusMajor, statusMinor;
     26    float fwhmMajor = psMetadataLookupF32(&statusMajor, readout->analysis, "FWHM_MAJ");
     27    float fwhmMinor = psMetadataLookupF32(&statusMinor, readout->analysis, "FWHM_MIN");
     28    if (statusMajor && statusMinor) {
     29        // if we know the FHWM, use that to set the smoothing kernel (XXX allow an optional override?)
     30        if (!isfinite(fwhmMajor) || !isfinite(fwhmMinor) || fwhmMajor == 0.0 || fwhmMinor == 0.0) {
     31            psWarning("fwhmMajor (%f) or fwhmMinor (%f) is bad!", fwhmMajor, fwhmMinor);
     32        }
     33        SIGMA_SMTH  = 0.5*(fwhmMajor + fwhmMinor) / (2.0*sqrt(2.0*log(2.0)));
     34        NSIGMA_SMTH = psMetadataLookupF32 (&status, recipe, "PEAKS_SMOOTH_NSIGMA");
     35        guess = false;
    3236    } else {
    33       // if we do not know the FWHM, use the guess smoothing kernel supplied.
    34       // it is a configuration error if these are not supplied
    35       SIGMA_SMTH  = psMetadataLookupF32 (&status, recipe, "PEAKS_SMOOTH_SIGMA");
    36       PS_ASSERT (status, NULL);
    37       NSIGMA_SMTH = psMetadataLookupF32 (&status, recipe, "PEAKS_SMOOTH_NSIGMA");
    38       PS_ASSERT (status, NULL);
    39       guess = true;
     37        // if we do not know the FWHM, use the guess smoothing kernel supplied.
     38        // it is a configuration error if these are not supplied
     39        SIGMA_SMTH  = psMetadataLookupF32 (&status, recipe, "PEAKS_SMOOTH_SIGMA");
     40        PS_ASSERT (status, NULL);
     41        NSIGMA_SMTH = psMetadataLookupF32 (&status, recipe, "PEAKS_SMOOTH_NSIGMA");
     42        PS_ASSERT (status, NULL);
     43        guess = true;
    4044    }
    4145    // record the actual smoothing sigma
    42     psMetadataAddF32(recipe, PS_LIST_TAIL, "SIGMA_SMOOTH", PS_META_REPLACE, "Smoothing sigma for detections",
    43                      SIGMA_SMTH);
     46    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "SIGMA_SMOOTH", PS_META_REPLACE, "Smoothing sigma for detections", SIGMA_SMTH);
    4447
    4548    // smooth the image, applying the mask as we go
     
    5659    // effective per-pixel variance is maintained.
    5760    psImage *smooth_wt = psImageCopy(NULL, readout->variance, PS_TYPE_F32);
    58     psImageSmoothMask_Threaded(smooth_wt, smooth_wt, readout->mask, maskVal, SIGMA_SMTH * M_SQRT1_2,
    59                       NSIGMA_SMTH, minGauss);
     61    psImageSmoothMask_Threaded(smooth_wt, smooth_wt, readout->mask, maskVal, SIGMA_SMTH * M_SQRT1_2, NSIGMA_SMTH, minGauss);
    6062    psLogMsg("psphot", PS_LOG_MINUTIA, "smooth variance: %f sec\n", psTimerMark("psphot.smooth"));
    6163
     
    7476    // Calculate correction factor for the covariance produced by the (potentially multiple) smoothing
    7577    psKernel *kernel = psImageSmoothKernel(SIGMA_SMTH, NSIGMA_SMTH); // Kernel used for smoothing
    76     psKernel *covar = psImageCovarianceCalculate(kernel, readout->covariance); // Covariance matrix
     78    float factor = 1.0 / psImageCovarianceCalculateFactor(kernel, readout->covariance);
    7779    psFree(kernel);
    78     float factor = 1.0 / psImageCovarianceFactor(covar);
    79     psFree(covar);
    8080
    8181    // record the effective area and significance scaling factor
    8282    float effArea = 8.0 * M_PI * PS_SQR(SIGMA_SMTH);
    83     psMetadataAddF32(recipe, PS_LIST_TAIL, "EFFECTIVE_AREA", PS_META_REPLACE, "Effective Area", effArea);
    84     psMetadataAddF32(recipe, PS_LIST_TAIL, "SIGNIFICANCE_SCALE_FACTOR", PS_META_REPLACE,
    85                      "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);
    8685
    8786    // XXX multithread this if needed
  • branches/simtest_nebulous_branches/psphot/src/psphotSkyReplace.c

    r21183 r27840  
    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    // skip the chisq image (optionally?)
     11    int chisqNum = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.CHISQ.NUM");
     12    if (!status) chisqNum = -1;
     13
     14    // loop over the available readouts
     15    for (int i = 0; i < num; i++) {
     16        if (i == chisqNum) continue; // skip chisq image
     17        if (!psphotSkyReplaceReadout (config, view, "PSPHOT.INPUT", i)) {
     18            psError (PSPHOT_ERR_CONFIG, false, "failed to replace sky for PSPHOT.INPUT entry %d", i);
     19            return false;
     20        }
     21    }
     22    return true;
     23}
    224
    325// XXX make this an option?
    426// in order to  successfully replace the sky, we must define a corresponding file...
    5 bool psphotSkyReplace (pmConfig *config, const pmFPAview *view) {
     27bool psphotSkyReplaceReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index) {
    628
    729    psTimerStart ("psphot.skyreplace");
    830
    931    // find the currently selected readout
    10     pmReadout *readout = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT");
    11     if (readout == NULL) psAbort("input not defined");
     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?");
    1237
    1338    // select background pixels, from output background file, or create
  • branches/simtest_nebulous_branches/psphot/src/psphotSourceFits.c

    r24592 r27840  
    9090    psphotCheckRadiusPSFBlend (readout, source, PSF, markVal, dR);
    9191
    92     // fit PSF model (set/unset the pixel mask)
     92    // fit PSF model
    9393    pmSourceFitSet (source, modelSet, PM_SOURCE_FIT_PSF, maskVal);
     94
     95    // clear the circular mask
     96    psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
     97
     98    if (!isfinite(PSF->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
    9499
    95100    // correct model chisq for flux trend
     
    101106        pmSource *blend = sourceSet->data[i];
    102107        pmModel *model  = modelSet->data[i];
     108
     109        if (!isfinite(model->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
    103110
    104111        // correct model chisq for flux trend
     
    120127        pmSourceCacheModel (blend, maskVal);
    121128        pmSourceSub (blend, PM_MODEL_OP_FULL, maskVal);
    122         blend->tmpFlags |=  PM_SOURCE_TMPF_SUBTRACTED;
    123129        blend->mode |=  PM_SOURCE_MODE_BLEND_FIT;
    124130    }
     
    144150    pmSourceCacheModel (source, maskVal);
    145151    pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    146     source->tmpFlags |=  PM_SOURCE_TMPF_SUBTRACTED;
    147152    source->mode |=  PM_SOURCE_MODE_BLEND_FIT;
    148153    return true;
     
    167172    // fit PSF model (set/unset the pixel mask)
    168173    pmSourceFitModel (source, PSF, PM_SOURCE_FIT_PSF, maskVal);
     174
     175    if (!isfinite(PSF->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
     176
     177    // clear the circular mask
     178    psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
    169179
    170180    // correct model chisq for flux trend
     
    186196    pmSourceCacheModel (source, maskVal);
    187197    pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    188     source->tmpFlags |=  PM_SOURCE_TMPF_SUBTRACTED;
    189     return true;
    190 }
    191 
    192 static float EXT_MIN_SN;
    193 static float EXT_MOMENTS_RAD;
     198    return true;
     199}
     200
    194201static pmModelType modelTypeEXT;
    195202
     
    197204
    198205    bool status;
    199 
    200     // extended source model parameters
    201     EXT_MIN_SN       = psMetadataLookupF32 (&status, recipe, "EXT_MIN_SN");
    202     EXT_MOMENTS_RAD  = psMetadataLookupF32 (&status, recipe, "EXT_MOMENTS_RADIUS");
    203206
    204207    // extended source model descriptions
     
    216219    double chiTrend;
    217220    pmModel *ONE = NULL;
     221    pmSource *tmpSrc = NULL;
     222    pmModel *EXT = NULL;
     223    psArray *DBL = NULL;
    218224
    219225    // skip the source if we don't think it is extended
     
    221227    if (source->type == PM_SOURCE_TYPE_DEFECT) return false;
    222228    if (source->type == PM_SOURCE_TYPE_SATURATED) return false;
    223     if (source->peak->SN < EXT_MIN_SN) return false;
    224 
     229
     230    // set the radius based on the footprint (also sets the mask pixels)
     231    float radius = psphotSetRadiusEXT (readout, source, markVal);
     232
     233    // XXX note that this changes the source moments that are published...
    225234    // recalculate the source moments using the larger extended-source moments radius
    226235    // at this stage, skip Gaussian windowing, and do not clip pixels by S/N
    227     if (!pmSourceMoments (source, EXT_MOMENTS_RAD, 0.0, 0.0)) return false;
     236    // this uses the footprint to judge both radius and aperture?
     237    if (!pmSourceMoments (source, radius, 0.0, 0.0, maskVal)) return false;
    228238
    229239    psTrace ("psphot", 5, "trying blob...\n");
     
    233243
    234244    // this temporary source is used as a place-holder by the psphotEval functions below
    235     pmSource *tmpSrc = pmSourceAlloc ();
     245    tmpSrc = pmSourceAlloc ();
    236246
    237247    // XXX need to handle failures better here
    238     pmModel *EXT = psphotFitEXT (readout, source, modelTypeEXT, maskVal, markVal);
     248    EXT = psphotFitEXT (readout, source, modelTypeEXT, maskVal, markVal);
     249    if (!EXT) goto escape;
     250    if (!isfinite(EXT->params->data.F32[PM_PAR_I0])) goto escape;
     251
    239252    okEXT = psphotEvalEXT (tmpSrc, EXT);
    240253    chiEXT = EXT ? EXT->chisq / EXT->nDOF : NAN;
    241254
    242255    // DBL will always be defined, but DBL->data[n] might not
    243     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
    244260    okDBL  = psphotEvalDBL (tmpSrc, DBL->data[0]);
    245261    okDBL &= psphotEvalDBL (tmpSrc, DBL->data[1]);
    246262    // XXX should I keep / save the flags set in the eval functions?
     263
     264    // clear the circular mask
     265    psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
    247266
    248267    // correct first model chisqs for flux trend
     
    250269    ONE = DBL->data[0];
    251270    if (ONE) {
     271        if (!isfinite(ONE->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
    252272      chiTrend = psPolynomial1DEval (psf->ChiTrend, ONE->params->data.F32[1]);
    253273      ONE->chisqNorm = ONE->chisq / chiTrend;
     
    258278    ONE = DBL->data[1];
    259279    if (ONE) {
     280        if (!isfinite(ONE->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
    260281      chiTrend = psPolynomial1DEval (psf->ChiTrend, ONE->params->data.F32[1]);
    261282      ONE->chisqNorm = ONE->chisq / chiTrend;
     
    277298
    278299    // both models failed; reject them both
     300    // XXX -- change type flags to psf in this case and keep original moments?
    279301    psFree (EXT);
    280302    psFree (DBL);
     
    287309    // save new model
    288310    source->modelEXT = EXT;
     311    source->modelEXT->fitRadius = radius;
    289312    source->type = PM_SOURCE_TYPE_EXTENDED;
    290313    source->mode |= PM_SOURCE_MODE_EXTMODEL;
     
    293316    pmSourceCacheModel (source, maskVal);
    294317    pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    295     source->tmpFlags |=  PM_SOURCE_TMPF_SUBTRACTED;
     318
     319# if (PS_TRACE_ON)   
    296320    psTrace ("psphot", 5, "blob as EXT: %f %f\n", EXT->params->data.F32[PM_PAR_XPOS], EXT->params->data.F32[PM_PAR_YPOS]);
     321    if (psTraceGetLevel("psphot") >= 6) {
     322        psLogMsg ("psphot", 1, "source 2:\n");
     323        for (int i = 0; i < source->modelEXT->params->n; i++) {
     324            psLogMsg ("psphot", 1, "PAR %d : %f +/- %f\n", i, source->modelEXT->params->data.F32[i], source->modelEXT->dparams->data.F32[i]);
     325        }
     326    }
     327# endif
     328
    297329    return true;
    298330
     
    304336    psFree (source->modelPSF);
    305337    source->modelPSF = psMemIncrRefCounter (DBL->data[0]);
    306     source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
    307338    source->mode     |= PM_SOURCE_MODE_PAIR;
     339    source->modelPSF->fitRadius = radius;
    308340
    309341    // copy most data from the primary source (modelEXT, blends stay NULL)
    310     // XXX use pmSourceCopy?
    311342    pmSource *newSrc = pmSourceCopy (source);
    312343    newSrc->modelPSF = psMemIncrRefCounter (DBL->data[1]);
     344    newSrc->modelPSF->fitRadius = radius;
    313345
    314346    // build cached models and subtract
     
    317349    pmSourceCacheModel (newSrc, maskVal);
    318350    pmSourceSub (newSrc, PM_MODEL_OP_FULL, maskVal);
     351
     352# if (PS_TRACE_ON)   
    319353    psTrace ("psphot", 5, "blob as DBL: %f %f\n", ONE->params->data.F32[PM_PAR_XPOS], ONE->params->data.F32[PM_PAR_YPOS]);
     354    if (psTraceGetLevel("psphot") >= 6) {
     355        psLogMsg ("psphot", 1, "source 1:\n");
     356        for (int i = 0; i < newSrc->modelPSF->params->n; i++) {
     357            psLogMsg ("psphot", 1, "PAR %d : %f +/- %f\n", i, newSrc->modelPSF->params->data.F32[i], newSrc->modelPSF->dparams->data.F32[i]);
     358        }
     359        psLogMsg ("psphot", 1, "source 2:\n");
     360        for (int i = 0; i < source->modelPSF->params->n; i++) {
     361            psLogMsg ("psphot", 1, "PAR %d : %f +/- %f\n", i, source->modelPSF->params->data.F32[i], source->modelPSF->dparams->data.F32[i]);
     362        }
     363        psphotVisualShowResidualImage (readout);
     364    }
     365# endif
    320366
    321367    psArrayAdd (newSources, 100, newSrc);
     
    323369    psFree (DBL);
    324370    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;
    325378}
    326379
     
    356409    // save the PSF model from the Ensemble fit
    357410    PSF = source->modelPSF;
    358     psphotCheckRadiusPSFBlend (readout, source, PSF, markVal, 8.0);
    359411    if (isnan(PSF->params->data.F32[1])) psAbort("nan in dbl fit");
    360412
     
    387439    // use the source moments, etc to guess basic model parameters
    388440    pmModel *EXT = pmSourceModelGuess (source, modelType);
    389     PS_ASSERT (EXT, NULL);
    390 
    391     // if (isnan(EXT->params->data.F32[1])) psAbort("nan in ext fit");
    392 
    393     psphotCheckRadiusEXT (readout, source, EXT, markVal);
     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    }
    394445
    395446    if ((source->moments->Mxx < 1e-3) || (source->moments->Myy < 1e-3)) {
     
    401452    return (EXT);
    402453}
    403 
  • branches/simtest_nebulous_branches/psphot/src/psphotSourceFreePixels.c

    r12792 r27840  
    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}
  • branches/simtest_nebulous_branches/psphot/src/psphotSourcePlots.c

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

    r21519 r27840  
    22# include <gsl/gsl_sf_gamma.h>
    33
    4 static float psphotModelContour(const psImage *image, const psImage *variance, const psImage *mask,
    5                                 psImageMaskType maskVal, const pmModel *model, float Ro);
    6 
    7 bool psphotMaskCosmicRay_Old (pmSource *source, psImageMaskType maskVal, psImageMaskType crMask);
    8 bool psphotMaskCosmicRay_New (psImage *mask, pmSource *source, psImageMaskType maskVal, psImageMaskType crMask);
     4typedef struct {
     5    psImageMaskType maskVal;
     6    psImageMaskType markVal;
     7    psImageMaskType crMask;
     8    float ApResid;
     9    float ApSysErr;
     10    float nSigmaApResid;
     11    float nSigmaMoments;
     12    float nSigmaCR;
     13    float soft;
     14    int grow;
     15    int xtest, ytest;
     16    bool apply; // apply CR mask?
     17} psphotSourceSizeOptions;
     18
     19// local functions:
     20bool psphotSourceSizePSF (psphotSourceSizeOptions *options, psArray *sources, pmPSF *psf);
     21bool psphotSourceClass (pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options);
     22bool psphotSourceClassRegion (psRegion *region, pmPSFClump *psfClump, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options);
     23bool psphotSourceSizeCR (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options);
     24bool psphotMaskCosmicRay (pmReadout *readout, pmSource *source, psImageMaskType maskVal);
     25bool psphotMaskCosmicRayFootprintCheck (psArray *sources);
     26int  psphotMaskCosmicRayConnected (int xPeak, int yPeak, psImage *mymask, psImage *myvar, psImage *edges, int binning, float sigma_thresh);
    927
    1028// we need to call this function after sources have been fitted to the PSF model and
     
    1432// deviation from the psf model at the r = FWHM/2 position
    1533
    16 bool psphotSourceSize(pmConfig *config, pmReadout *readout, psArray *sources, psMetadata *recipe, long first)
     34// for now, let's store the detections on the readout->analysis for each readout
     35bool psphotSourceSize (pmConfig *config, const pmFPAview *view, bool getPSFsize)
     36{
     37    bool status = true;
     38
     39    // select the appropriate recipe information
     40    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     41    psAssert (recipe, "missing recipe?");
     42
     43    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     44    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     45
     46    // skip the chisq image (optionally?)
     47    int chisqNum = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.CHISQ.NUM");
     48    if (!status) chisqNum = -1;
     49
     50    // loop over the available readouts
     51    for (int i = 0; i < num; i++) {
     52        if (i == chisqNum) continue; // skip chisq image
     53        if (!psphotSourceSizeReadout (config, view, "PSPHOT.INPUT", i, recipe, getPSFsize)) {
     54            psError (PSPHOT_ERR_CONFIG, false, "failed on source size analysis for PSPHOT.INPUT entry %d", i);
     55            return false;
     56        }
     57    }
     58    return true;
     59}
     60
     61// this function use an internal flag to mark sources which have already been measured
     62bool psphotSourceSizeReadout(pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe, bool getPSFsize)
    1763{
    1864    bool status;
     65    psphotSourceSizeOptions options;
    1966
    2067    psTimerStart ("psphot.size");
    2168
     69    // find the currently selected readout
     70    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     71    psAssert (file, "missing file?");
     72
     73    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     74    psAssert (readout, "missing readout?");
     75
     76    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     77    psAssert (detections, "missing detections?");
     78
     79    psArray *sources = detections->allSources;
     80    psAssert (sources, "missing sources?");
     81
     82    if (!sources->n) {
     83        psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping source size");
     84        return true;
     85    }
     86
     87    pmPSF *psf = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF");
     88    psAssert (psf, "missing psf?");
     89
    2290    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
    23     psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
    24     assert (maskVal);
     91    options.maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
     92    assert (options.maskVal);
     93
     94    options.markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT"); // Mask value for bad pixels
     95    assert (options.markVal);
    2596
    2697    // bit to mask the cosmic-ray pixels
    27     psImageMaskType crMask  = pmConfigMaskGet("CR", config); // Mask value for cosmic rays
    28 
    29     float CR_NSIGMA_LIMIT = psMetadataLookupF32 (&status, recipe, "PSPHOT.CR.NSIGMA.LIMIT");
     98    options.crMask  = pmConfigMaskGet("CR", config); // Mask value for cosmic rays
     99
     100    options.nSigmaCR = psMetadataLookupF32 (&status, recipe, "PSPHOT.CR.NSIGMA.LIMIT");
    30101    assert (status);
    31102
    32     float EXT_NSIGMA_LIMIT = psMetadataLookupF32 (&status, recipe, "PSPHOT.EXT.NSIGMA.LIMIT");
     103    // XXX recipe name is not great
     104    options.nSigmaApResid = psMetadataLookupF32 (&status, recipe, "PSPHOT.EXT.NSIGMA.LIMIT");
    33105    assert (status);
    34106
    35     int grow = psMetadataLookupS32(&status, recipe, "PSPHOT.CR.GROW"); // Growth size for CRs
    36     if (!status || grow < 0) {
     107    // XXX recipe name is not great
     108    options.nSigmaMoments = psMetadataLookupF32 (&status, recipe, "PSPHOT.EXT.NSIGMA.MOMENTS");
     109    assert (status);
     110
     111    // XXX recipe name is not great
     112    options.xtest = psMetadataLookupS32 (&status, recipe, "PSPHOT.CRMASK.XTEST");
     113    options.ytest = psMetadataLookupS32 (&status, recipe, "PSPHOT.CRMASK.YTEST");
     114    assert (status);
     115
     116    options.grow = psMetadataLookupS32(&status, recipe, "PSPHOT.CR.GROW"); // Growth size for CRs
     117    if (!status || options.grow < 0) {
    37118        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "PSPHOT.CR.GROW is not positive.");
    38119        return false;
    39120    }
    40121
    41     float soft = psMetadataLookupF32(&status, recipe, "PSPHOT.CR.NSIGMA.SOFTEN"); // Softening parameter
    42     if (!status || !isfinite(soft) || soft < 0.0) {
     122    options.soft = psMetadataLookupF32(&status, recipe, "PSPHOT.CR.NSIGMA.SOFTEN"); // Softening parameter
     123    if (!status || !isfinite(options.soft) || options.soft < 0.0) {
    43124        psWarning("PSPHOT.CR.NSIGMA.SOFTEN not set; defaulting to zero.");
    44         soft = 0.0;
    45     }
    46 
    47     // loop over all source
    48     for (int i = first; i < sources->n; i++) {
     125        options.soft = 0.0;
     126    }
     127
     128    options.apply = psMetadataLookupBool(&status, recipe, "PSPHOT.CRMASK.APPLY"); // Growth size for CRs
     129    if (!status) {
     130        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "PSPHOT.CRMASK.APPLY is not defined.");
     131        return false;
     132    }
     133
     134    // We are using the value psfMag - 2.5*log10(moment.Sum) as a measure of the extendedness
     135    // of an object.  We need to model this distribution for the PSF stars before we can test
     136    // the significance for a specific object
     137    // XXX move this to the code that generates the PSF?
     138    // XXX store the results on pmPSF?
     139
     140    // XXX this should only be done on the first pass (ie, if we have newSources or allSources?)
     141    if (getPSFsize) {
     142        psphotSourceSizePSF (&options, sources, psf);
     143    }
     144
     145    // classify the sources based on ApResid and Moments (extended sources)
     146    // NOTE: only sources not already measured !(source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED)
     147    psphotSourceClass(readout, sources, recipe, psf, &options);
     148
     149    // NOTE: only sources not already measured !(source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED)
     150    psphotSourceSizeCR (readout, sources, &options);
     151
     152    // XXX fix this (was source->n  - first)
     153    psLogMsg ("psphot.size", PS_LOG_INFO, "measure source sizes for %ld sources: %f sec\n", sources->n, psTimerMark ("psphot.size"));
     154
     155    psphotVisualPlotSourceSize (recipe, readout->analysis, sources);
     156    psphotVisualShowSourceSize (readout, sources);
     157    psphotVisualPlotApResid (sources, options.ApResid, options.ApSysErr);
     158    psphotVisualShowSatStars (recipe, psf, sources);
     159
     160    return true;
     161}
     162
     163// model the apmifit distribution for the psf stars:
     164bool psphotSourceSizePSF (psphotSourceSizeOptions *options, psArray *sources, pmPSF *psf) {
     165
     166    // select stats from the psf stars
     167    psVector *Ap = psVectorAllocEmpty (100, PS_TYPE_F32);
     168    psVector *ApErr = psVectorAllocEmpty (100, PS_TYPE_F32);
     169
     170    psImageMaskType maskVal = options->maskVal | options->markVal;
     171
     172    // XXX  why PHOT_WEIGHT??
     173    pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_WEIGHT;
     174
     175    int num = 0;                        // Number of sources measured
     176    for (int i = 0; i < sources->n; i++) {
    49177        pmSource *source = sources->data[i];
     178        if (!(source->mode & PM_SOURCE_MODE_PSFSTAR)) continue;
     179        num++;
     180
     181        // replace object in image
     182        if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
     183            pmSourceAdd (source, PM_MODEL_OP_FULL, options->maskVal);
     184        }
     185
     186        // clear the mask bit and set the circular mask pixels
     187        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));
     188        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", options->markVal);
     189
     190        // XXX can we test if psfMag is set and calculate only if needed?
     191        pmSourceMagnitudes (source, psf, photMode, maskVal); // maskVal includes markVal
     192
     193        // clear the mask bit
     194        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));
     195
     196        // re-subtract the object, leave local sky
     197        pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal);
     198
     199        float apMag = -2.5*log10(source->moments->Sum);
     200        float dMag = source->psfMag - apMag;
     201
     202        psVectorAppend (Ap, dMag);
     203        psVectorAppend (ApErr, source->errMag);
     204    }
     205    if (num == 0) {
     206        // Not raising an error, because errors aren't being checked elsewhere in this function
     207        psFree(Ap);
     208        psFree(ApErr);
     209        return false;
     210    }
     211
     212    // model the distribution as a mean or median value and a systematic error from that value:
     213    psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN);
     214    psVectorStats (stats, Ap, NULL, NULL, 0);
     215
     216    psVector *dAp = psVectorAlloc (Ap->n, PS_TYPE_F32);
     217    for (int i = 0; i < Ap->n; i++) {
     218        dAp->data.F32[i] = Ap->data.F32[i] - stats->robustMedian;
     219    }
     220
     221    options->ApResid = stats->robustMedian;
     222    options->ApSysErr = psVectorSystematicError(dAp, ApErr, 0.05);
     223    // XXX this is quite arbitrary...
     224    if (!isfinite(options->ApSysErr)) options->ApSysErr = 0.01;
     225    psLogMsg ("psphot", PS_LOG_DETAIL, "psf - Sum: %f +/- %f\n", options->ApResid, options->ApSysErr);
     226
     227    psFree (Ap);
     228    psFree (ApErr);
     229    psFree (stats);
     230    psFree (dAp);
     231
     232    return true;
     233}
     234
     235// classify sources based on the combination of psf-mag, Mxx, Myy
     236bool psphotSourceClass (pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options) {
     237
     238    bool status;
     239    pmPSFClump psfClump;
     240    char regionName[64];
     241
     242    psLogMsg("psModules.objects", PS_LOG_INFO, "Source Size classifications: %4s %4s %4s %4s %4s %4s", "Npsf", "Next", "Nsat", "Ncr", "Nmiss", "Nskip");
     243
     244    int nRegions = psMetadataLookupS32 (&status, readout->analysis, "PSF.CLUMP.NREGIONS");
     245    for (int i = 0; i < nRegions; i ++) {
     246        snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", i);
     247        psMetadata *regionMD = psMetadataLookupPtr (&status, readout->analysis, regionName);
     248        psAssert (regionMD, "regions must be defined by earlier call to psphotRoughClassRegion");
     249
     250        psRegion *region = psMetadataLookupPtr (&status, regionMD, "REGION");
     251        psAssert (region, "regions must be defined by earlier call to psphotRoughClassRegion");
     252
     253        // pull FWHM_X,Y from the recipe, use to define psfClump.X,Y
     254        psfClump.X  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");   psAssert (status, "missing PSF.CLUMP.X");
     255        psfClump.Y  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y");   psAssert (status, "missing PSF.CLUMP.Y");
     256        psfClump.dX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX");  psAssert (status, "missing PSF.CLUMP.DX");
     257        psfClump.dY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY");  psAssert (status, "missing PSF.CLUMP.DY");
     258
     259        if ((psfClump.X < 0) || (psfClump.Y < 0) || !psfClump.X || !psfClump.Y || isnan(psfClump.X) || isnan(psfClump.Y)) {
     260            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);
     261            continue;
     262        }
     263
     264        if (!psphotSourceClassRegion (region, &psfClump, sources, recipe, psf, options)) {
     265            psLogMsg ("psphot", 4, "Failed to determine source classification for region %f,%f - %f,%f\n", region->x0, region->y0, region->x1, region->y1);
     266            continue;
     267        }
     268        // psphotVisualPlotSourceSize (recipe, readout->analysis, sources);
     269    }
     270
     271    return true;
     272}
     273
     274# define SIZE_SN_LIM 10
     275bool psphotSourceClassRegion (psRegion *region, pmPSFClump *psfClump, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options) {
     276
     277    PS_ASSERT_PTR_NON_NULL(sources, false);
     278    PS_ASSERT_PTR_NON_NULL(recipe, false);
     279
     280    int Nsat  = 0;
     281    int Next  = 0;
     282    int Npsf  = 0;
     283    int Ncr   = 0;
     284    int Nmiss = 0;
     285    int Nskip = 0;
     286
     287    pmSourceMode noMoments = PM_SOURCE_MODE_MOMENTS_FAILURE | PM_SOURCE_MODE_SKYVAR_FAILURE | PM_SOURCE_MODE_SKY_FAILURE | PM_SOURCE_MODE_BELOW_MOMENTS_SN;
     288    pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_WEIGHT;
     289
     290    psImageMaskType maskVal = options->maskVal | options->markVal;
     291
     292    for (psS32 i = 0 ; i < sources->n ; i++) {
     293
     294        pmSource *source = (pmSource *) sources->data[i];
     295
     296        // psfClumps are found for image subregions:
     297        // skip sources not in this region
     298        if (source->peak->x <  region->x0) continue;
     299        if (source->peak->x >= region->x1) continue;
     300        if (source->peak->y <  region->y0) continue;
     301        if (source->peak->y >= region->y1) continue;
    50302
    51303        // skip source if it was already measured
    52         if (isfinite(source->crNsigma)) {
    53             psTrace("psphot", 7, "Not calculating extNsigma,crNsigma since already measured\n");
     304        if (source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED) {
     305            psTrace("psphot", 7, "Not calculating source size since it has already been measured\n");
    54306            continue;
    55307        }
     
    57309        // source must have been subtracted
    58310        if (!(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED)) {
    59             source->mode |= PM_SOURCE_MODE_SIZE_SKIPPED;
    60             psTrace("psphot", 7, "Not calculating extNsigma,crNsigma since source is not subtracted\n");
    61             continue;
    62         }
    63 
    64         psF32 **resid  = source->pixels->data.F32;
    65         psF32 **variance = source->variance->data.F32;
    66         psImageMaskType **mask = source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA;
    67 
    68         // check for extendedness: measure the delta flux significance at the 1 sigma contour
    69         source->extNsigma = psphotModelContour(source->pixels, source->variance, source->maskObj, maskVal,
    70                                                source->modelPSF, 1.0);
    71 
    72         // XXX prevent a source from being both CR and EXT?
    73         if (source->extNsigma > EXT_NSIGMA_LIMIT) {
     311            source->mode |= PM_SOURCE_MODE_SIZE_SKIPPED;
     312            psTrace("psphot", 7, "Not calculating source size since source is not subtracted\n");
     313            continue;
     314        }
     315
     316        // we are basically classifying by moments
     317        psAssert (source->moments, "why is this source missing moments?");
     318        if (source->mode & noMoments) {
     319            Nskip ++;
     320            continue;
     321        }
     322
     323        // convert to Mmaj, Mmin:
     324        psF32 Mxx = source->moments->Mxx;
     325        psF32 Myy = source->moments->Myy;
     326
     327        // replace object in image
     328        if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
     329            pmSourceAdd (source, PM_MODEL_OP_FULL, options->maskVal);
     330        }
     331
     332        // clear the mask bit and set the circular mask pixels
     333        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));
     334        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", options->markVal);
     335
     336        // XXX can we test if psfMag is set and calculate only if needed?
     337        pmSourceMagnitudes (source, psf, photMode, maskVal); // maskVal includes markVal
     338
     339        // clear the mask bit
     340        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));
     341
     342        // re-subtract the object, leave local sky
     343        pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal);
     344
     345        float apMag = -2.5*log10(source->moments->Sum);
     346        float dMag = source->psfMag - apMag;
     347
     348        // set nSigma to include both systematic and poisson error terms
     349        // XXX the 'poisson error' contribution for size is probably wrong...
     350        float nSigmaMAG = (dMag - options->ApResid) / hypot(source->errMag, options->ApSysErr);
     351        float nSigmaMXX = (Mxx - psfClump->X) / hypot(psfClump->dX, psfClump->X*psfClump->X*source->errMag);
     352        float nSigmaMYY = (Myy - psfClump->Y) / hypot(psfClump->dY, psfClump->Y*psfClump->Y*source->errMag);
     353
     354        // partially-masked sources are more likely to be mis-measured PSFs
     355        float sizeBias = 1.0;
     356        if (source->pixWeight < 0.9) {
     357            sizeBias = 3.0;
     358        }
     359
     360        float minMxx = psfClump->X - sizeBias*options->nSigmaMoments*psfClump->dX;
     361        float minMyy = psfClump->Y - sizeBias*options->nSigmaMoments*psfClump->dY;
     362
     363        // include MAG, MXX, and MYY?
     364        source->extNsigma = nSigmaMAG;
     365
     366        // notes to clarify the source size classification rules:
     367        // * a defect should be functionally equivalent to a cosmic ray
     368        // * CR & defect should have a faintess limit (min S/N)
     369        // * SAT stars should not be faint, but defects may?
     370
     371        // Anything within this region is a probably PSF-like object. Saturated stars may land
     372        // in this region, but are detected elsewhere on the basis of their peak value.
     373        bool isPSF = (fabs(nSigmaMAG) < options->nSigmaApResid) && (fabs(nSigmaMXX) < sizeBias*options->nSigmaMoments) && (fabs(nSigmaMYY) < sizeBias*options->nSigmaMoments);
     374        if (isPSF) {
     375          psTrace("psphotSourceClassRegion.PSF",4,"CLASS: %g %g\t%g %g  %g %g  %g %g\t%g %g\t%g PSF\t%g %g\n",
     376                  source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG,
     377                  options->nSigmaApResid,sizeBias*options->nSigmaMoments);
     378          source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;
     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        // XXX only accept brightish detections as CRs
     387        // (nSigmaMAG < -options->nSigmaApResid) ||
     388        bool isCR = isCR = (source->errMag < 1.0 / SIZE_SN_LIM) && ((Mxx < minMxx) || (Myy < minMyy));
     389        if (isCR) {
     390            psTrace("psphotSourceClassRegion.CR",4,"CLASS: %g %g %f\t%g %g  %g %g  %g %g\t%g %g\t%g CR\t%g %g\n",
     391                    source->peak->xf,source->peak->yf,source->pixWeight,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG,
     392                    options->nSigmaApResid,sizeBias*options->nSigmaMoments);
     393            source->mode |= PM_SOURCE_MODE_DEFECT;
     394            source->tmpFlags |= PM_SOURCE_TMPF_SIZE_CR_CANDIDATE;
     395            Ncr ++;
     396            continue;
     397        }
     398
     399        // saturated star (determined in PSF fit).  These may also be saturated galaxies, or
     400        // just large saturated regions.
     401        if (source->mode & PM_SOURCE_MODE_SATSTAR) {
     402            psTrace("psphotSourceClassRegion.SAT",4,"CLASS: %g %g\t%g %g  %g %g  %g %g\t%g %g\t%g SAT\t%g %g\n",
     403                    source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG,
     404                    options->nSigmaApResid,sizeBias*options->nSigmaMoments);
     405            source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;
     406            Nsat ++;
     407            continue;
     408        }
     409
     410        // XXX allow the Mxx, Myy to be less than psfClump->X,Y (by some nSigma)?
     411        bool isEXT = (nSigmaMAG > options->nSigmaApResid) || (Mxx > minMxx) || (Myy > minMyy);
     412        if (isEXT) {
     413          psTrace("psphotSourceClassRegion.EXT",4,"CLASS: %g %g\t%g %g  %g %g  %g %g\t%g %g\t%g Ext\t%g %g\n",
     414                  source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG,
     415                  options->nSigmaApResid,sizeBias*options->nSigmaMoments);
     416
    74417            source->mode |= PM_SOURCE_MODE_EXT_LIMIT;
    75         }
     418            source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;
     419            Next ++;
     420            continue;
     421        }
     422        psTrace("psphotSourceClassRegion.MISS",4,"CLASS: %g %g\t%g %g  %g %g  %g %g\t%g %g\t%g Unk\t%g %g\n",
     423                source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG,
     424                options->nSigmaApResid,sizeBias*options->nSigmaMoments);
     425
     426        // sources that reach here are probably too faint for a reasonable source size measurement
     427        // psWarning ("sourse size was missed for %f,%f : %f %f -- %f\n", source->peak->xf, source->peak->yf, Mxx, Myy, nSigmaMAG);
     428        source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;
     429        Nmiss ++;
     430    }
     431
     432    psLogMsg("psModules.objects", PS_LOG_INFO, "Source Size classifications: %4d %4d %4d %4d %4d %4d", Npsf, Next, Nsat, Ncr, Nmiss, Nskip);
     433
     434    return true;
     435}
     436
     437// given an object suspected to be a defect, generate a pixel mask using the Lapacian transform
     438// if enough of the object is detected as 'sharp', consider the object a cosmic ray
     439bool psphotSourceSizeCR (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options) {
     440
     441    psTimerStart ("psphot.cr");
     442
     443    int nMasked = 0;
     444    for (int i = 0; i < sources->n; i++) {
     445        pmSource *source = sources->data[i];
     446
     447        // skip source if it was already measured
     448        if (source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED) {
     449            psTrace("psphot", 7, "Not calculating source size since it has already been measured\n");
     450            continue;
     451        }
     452
     453        // only check candidates marked above
     454        if (!(source->tmpFlags & PM_SOURCE_TMPF_SIZE_CR_CANDIDATE)) {
     455            psTrace("psphot", 7, "Not calculating source size since it has already been measured\n");
     456            continue;
     457        }
     458
     459        // skip unless this source is thought to be a cosmic ray.  flag the detection and mask the pixels
     460        // XXX this may be degenerate with the above test
     461        if (!(source->mode & PM_SOURCE_MODE_DEFECT)) continue;
    76462
    77463        // Integer position of peak
     
    79465        int yPeak = source->peak->yf - source->pixels->row0 + 0.5;
    80466
    81         // XXX for now, skip sources which are too close to a boundary
    82         // XXX raise a flag?
     467        // Skip sources which are too close to a boundary.  These are mostly caught as DEFECT
    83468        if (xPeak < 1 || xPeak > source->pixels->numCols - 2 ||
    84469            yPeak < 1 || yPeak > source->pixels->numRows - 2) {
    85             source->mode |= PM_SOURCE_MODE_SIZE_SKIPPED;
    86470            psTrace("psphot", 7, "Not calculating crNsigma due to edge\n");
    87471            continue;
    88472        }
    89473
    90         // XXX for now, just skip any sources with masked pixels
    91         // XXX raise a flag?
    92         bool keep = true;
    93         for (int iy = -1; (iy <= +1) && keep; iy++) {
    94             for (int ix = -1; (ix <= +1) && keep; ix++) {
    95                 if (mask[yPeak+iy][xPeak+ix] & maskVal) {
    96                     keep = false;
    97                 }
    98             }
    99         }
    100         if (!keep) {
    101             psTrace("psphot", 7, "Not calculating crNsigma due to masked pixels\n");
    102             source->mode |= PM_SOURCE_MODE_SIZE_SKIPPED;
    103             continue;
    104         }
    105 
    106         // Compare the central pixel with those on either side, for the four possible lines through it.
    107 
    108         // Soften variances (add systematic error)
    109         float softening = soft * PS_SQR(source->peak->flux); // Softening for variances
    110 
    111         // Across the middle: y = 0
    112         float cX = 2*resid[yPeak][xPeak]   - resid[yPeak+0][xPeak-1]  - resid[yPeak+0][xPeak+1];
    113         float dcX = 4*variance[yPeak][xPeak] + variance[yPeak+0][xPeak-1] + variance[yPeak+0][xPeak+1];
    114         float nX = cX / sqrtf(dcX + softening);
    115 
    116         // Up the centre: x = 0
    117         float cY = 2*resid[yPeak][xPeak]   - resid[yPeak-1][xPeak+0]  - resid[yPeak+1][xPeak+0];
    118         float dcY = 4*variance[yPeak][xPeak] + variance[yPeak-1][xPeak+0] + variance[yPeak+1][xPeak+0];
    119         float nY = cY / sqrtf(dcY + softening);
    120 
    121         // Diagonal: x = y
    122         float cL = 2*resid[yPeak][xPeak]   - resid[yPeak-1][xPeak-1]  - resid[yPeak+1][xPeak+1];
    123         float dcL = 4*variance[yPeak][xPeak] + variance[yPeak-1][xPeak-1] + variance[yPeak+1][xPeak+1];
    124         float nL = cL / sqrtf(dcL + softening);
    125 
    126         // Diagonal: x = - y
    127         float cR = 2*resid[yPeak][xPeak]   - resid[yPeak+1][xPeak-1]  - resid[yPeak-1][xPeak+1];
    128         float dcR = 4*variance[yPeak][xPeak] + variance[yPeak+1][xPeak-1] + variance[yPeak-1][xPeak+1];
    129         float nR = cR / sqrtf(dcR + softening);
    130 
    131         // P(chisq > chisq_obs; Ndof) = gamma_Q (Ndof/2, chisq/2)
    132         // Ndof = 4 ? (four measurements, no free parameters)
    133         // XXX this value is going to be biased low because of systematic errors.
    134         // we need to calibrate it somehow
    135         // source->psfProb = gsl_sf_gamma_inc_Q (2, 0.5*chisq);
    136 
    137         // not strictly accurate: overcounts the chisq contribution from the center pixel (by
    138         // factor of 4); also biases a bit low if any pixels are masked
    139         // XXX I am not sure I want to keep this value...
    140         source->psfChisq = PS_SQR(nX) + PS_SQR(nY) + PS_SQR(nL) + PS_SQR(nR);
    141 
    142         float fCR = 0.0;
    143         int nCR = 0;
    144         if (nX > 0.0) {
    145             fCR += nX;
    146             nCR ++;
    147         }
    148         if (nY > 0.0) {
    149             fCR += nY;
    150             nCR ++;
    151         }
    152         if (nL > 0.0) {
    153             fCR += nL;
    154             nCR ++;
    155         }
    156         if (nR > 0.0) {
    157             fCR += nR;
    158             nCR ++;
    159         }
    160         source->crNsigma  = (nCR > 0)  ? fCR / nCR : 0.0;
    161         if (!isfinite(source->crNsigma)) {
    162             continue;
    163         }
    164 
    165         // this source is thought to be a cosmic ray.  flag the detection and mask the pixels
    166         if (source->crNsigma > CR_NSIGMA_LIMIT) {
    167             // XXX still testing... : psphotMaskCosmicRay_New (readout->mask, source, maskVal, crMask);
    168             psphotMaskCosmicRay_Old (source, maskVal, crMask);
    169         }
     474        // XXX for testing, only CRMASK a single source:
     475        if (options->xtest && (fabs(source->peak->xf - options->xtest) > 5)) continue;
     476        if (options->ytest && (fabs(source->peak->yf - options->ytest) > 5)) continue;
     477
     478        // replace object in image
     479        if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
     480            pmSourceAdd (source, PM_MODEL_OP_FULL, options->maskVal);
     481        }
     482
     483        // XXX this is running slowly and is too agressive, but it more-or-less works
     484        psTrace("psphot", 6, "mask cosmic ray at %f, %f\n", source->peak->xf, source->peak->yf);
     485        if (options->apply) {
     486            psphotMaskCosmicRay(readout, source, options->crMask);
     487        } else {
     488            source->mode |= PM_SOURCE_MODE_CR_LIMIT;
     489        }
     490        nMasked ++;
     491
     492        // re-subtract the object, leave local sky
     493        pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal);
    170494    }
    171495
    172496    // now that we have masked pixels associated with CRs, we can grow the mask
    173     if (grow > 0) {
     497    if (options->grow > 0) {
    174498        bool oldThreads = psImageConvolveSetThreads(true); // Old value of threading for psImageConvolveMask
    175         psImage *newMask = psImageConvolveMask(NULL, readout->mask, crMask, crMask, -grow, grow, -grow, grow);
     499        psImage *newMask = psImageConvolveMask(NULL, readout->mask, options->crMask, options->crMask, -options->grow, options->grow, -options->grow, options->grow);
    176500        psImageConvolveSetThreads(oldThreads);
    177501        if (!newMask) {
     
    183507    }
    184508
    185     psLogMsg ("psphot.size", PS_LOG_INFO, "measure source sizes for %ld sources: %f sec\n",
    186               sources->n - first, psTimerMark ("psphot.size"));
    187 
    188     psphotVisualPlotSourceSize (sources);
    189     psphotVisualShowSourceSize (readout, sources);
    190 
     509    psLogMsg ("psphot.cr", PS_LOG_INFO, "mask CR: %d masked in %f sec\n", nMasked, psTimerMark ("psphot.cr"));
     510
     511    // XXX test : save the mask image
     512    if (0) {
     513        psphotSaveImage (NULL, readout->mask,   "mask.fits");
     514    }
     515
     516    return true;
     517}
     518
     519# define DUMPPICS 0
     520# define LIMIT_XRANGE(X, IMAGE) { X = PS_MIN(PS_MAX(0, X), IMAGE->numCols); }
     521# define LIMIT_YRANGE(Y, IMAGE) { Y = PS_MIN(PS_MAX(0, Y), IMAGE->numRows); }
     522
     523// Comments by CZW 20091209 : Mechanics of how to identify CR pixels taken from "Cosmic-Ray
     524// Rejection by Laplacian Edge Detection" by Pieter van Dokkum, arXiv:astro-ph/0108003.  This
     525// does no repair or recovery of the CR pixels, it only masks them out.  My test code can be
     526// found at /data/ipp031.0/watersc1/psphot.20091209/algo_check.c
     527bool psphotMaskCosmicRay (pmReadout *readout, pmSource *source, psImageMaskType maskVal) {
     528
     529    // Get the actual images and information about the peak.
     530    psImage *mask = readout->mask;
     531    pmPeak *peak = source->peak;
     532    pmFootprint *footprint = peak->footprint;
     533
     534    // Bounding boxes are inclusive of final pixel
     535    int xs = footprint->bbox.x0;
     536    int xe = footprint->bbox.x1 + 1;
     537    int ys = footprint->bbox.y0;
     538    int ye = footprint->bbox.y1 + 1;
     539
     540    LIMIT_XRANGE(xs, mask);
     541    LIMIT_XRANGE(xe, mask);
     542    LIMIT_YRANGE(ys, mask);
     543    LIMIT_YRANGE(ye, mask);
     544
     545    int dx = xe - xs;
     546    int dy = ye - ys;
     547
     548    psImage *image= readout->image;
     549    psImage *variance = readout->variance;
     550
     551    int binning = 2;
     552    float sigma_thresh = 3.0;
     553    int max_iter = 1; // XXX with isophot masking, we only want to do a single pass
     554
     555    // Temporary images.
     556    psImage *mypix  = psImageAlloc(dx,dy,image->type.type);
     557    psImage *myfix  = psImageAlloc(dx,dy,image->type.type);
     558    psImage *myvar  = psImageAlloc(dx,dy,image->type.type);
     559    psImage *binned = psImageAlloc(dx * binning,dy * binning,image->type.type);
     560    psImage *conved = psImageAlloc(dx * binning,dy * binning,image->type.type);
     561    psImage *edges  = psImageAlloc(dx,dy,image->type.type);
     562    psImage *mymask = psImageAlloc(dx,dy,PS_TYPE_IMAGE_MASK);
     563
     564    // Load my copy of things.
     565    for (int y = 0; y < dy; y++) {
     566        for (int x = 0; x < dx; x++) {
     567            mypix->data.F32[y][x] = image->data.F32[y+ys][x+xs];
     568            myvar->data.F32[y][x] = variance->data.F32[y+ys][x+xs];
     569            mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = 0x00;
     570        }
     571    }
     572    // Mask so I can see on the output image where the footprint is.
     573    for (int i = 0; i < footprint->spans->n; i++) {
     574        pmSpan *sp = footprint->spans->data[i];
     575        for (int j = sp->x0; j <= sp->x1; j++) {
     576            int y = sp->y - ys;
     577            int x = j - xs;
     578            mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] |= 0x01;
     579        }
     580    }
     581
     582    int nCRpix = 1; // force at least one pass...
     583    for (int iteration = 0; (iteration < max_iter) && (nCRpix > 0); iteration++) {
     584        nCRpix = 0;
     585        psImageInit (binned, 0.0);
     586        psImageInit (conved, 0.0);
     587        psImageInit (edges, 0.0);
     588
     589        // Make subsampled image. Maybe this should be called "unbinned" or something
     590        for (int y = 0; y < binning * dy; y++) {
     591            int yraw = y / binning;
     592            for (int x = 0; x < binning * dx; x++) {
     593                int xraw = x / binning;
     594                binned->data.F32[y][x] = mypix->data.F32[yraw][xraw];
     595            }
     596        }
     597
     598        // Apply Laplace transform (kernel = [[0 -0.25 0][-0.25 1 -0.25][0 -0.25 0]]), clipping at zero
     599        for (int y = 1; y < binning * dy - 1; y++) {
     600            for (int x = 1; x < binning * dx - 1; x++) {
     601                float value = binned->data.F32[y][x] - 0.25 *
     602                    (binned->data.F32[y+0][x-1] + binned->data.F32[y+0][x+1] +
     603                     binned->data.F32[y-1][x+0] + binned->data.F32[y+1][x+0]);
     604                value = PS_MAX(0.0, value);
     605
     606                conved->data.F32[y][x] = value;
     607            }
     608        }
     609
     610        // Create an edge map by rebinning
     611        for (int y = 0; y < binning * dy; y++) {
     612            int yraw = y / binning;
     613            for (int x = 0; x < binning * dx; x++) {
     614                int xraw = x / binning;
     615                edges->data.F32[yraw][xraw] += conved->data.F32[y][x];
     616            }
     617        }
     618
     619        // coordinate of peak in subimage pixels:
     620        int xPeak = peak->x - xs;
     621        int yPeak = peak->y - ys;
     622
     623        // Modify my mask if we're above the significance threshold, but only for connected pixels
     624        nCRpix = psphotMaskCosmicRayConnected (xPeak, yPeak, mymask, myvar, edges, binning, sigma_thresh);
     625
     626# if DUMPPICS
     627        psphotSaveImage (NULL, mypix,   "crmask.pix.fits");
     628# endif
     629
     630// XXX do not repair the pixels in isophot version
     631# if 0
     632        // "Repair" Masked pixels for the next round.
     633        for (int y = 1; y < dy - 1; y++) {
     634            for (int x = 1; x < dx - 1; x++) {
     635                if (!(mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & 0x40)) {
     636                    myfix->data.F32[y][x] = mypix->data.F32[y][x];
     637                    continue;
     638                }
     639                myfix->data.F32[y][x] = 0.25 *
     640                    (mypix->data.F32[y+0][x-1] + mypix->data.F32[y+0][x+1] +
     641                     mypix->data.F32[y-1][x+0] + mypix->data.F32[y+1][x+0]);
     642            }
     643        }
     644
     645        // "Repair" Masked pixels for the next round.
     646        for (int y = 1; y < dy - 1; y++) {
     647            for (int x = 1; x < dx - 1; x++) {
     648                mypix->data.F32[y][x] = myfix->data.F32[y][x];
     649            }
     650        }
     651# endif
     652
     653# if DUMPPICS
     654        fprintf (stderr, "CRMASK %d %d %d %d %d\n", xs, ys, dx, dy, iteration);
     655        psphotSaveImage (NULL, mypix,   "crmask.fix.fits");
     656        psphotSaveImage (NULL, myvar,   "crmask.var.fits");
     657        psphotSaveImage (NULL, binned,  "crmask.binn.fits");
     658        psphotSaveImage (NULL, conved,  "crmask.conv.fits");
     659        psphotSaveImage (NULL, edges,   "crmask.edge.fits");
     660        psphotSaveImage (NULL, mymask,  "crmask.mask.fits");
     661# endif
     662        psTrace("psphot.czw",2,"Iter: %d Count: %d",iteration, nCRpix);
     663    }
     664
     665# if 0
     666    // A solitary masked pixel is likely a lie. Remove those
     667    // XXX can't we use nCRpix == 1 to test for these?
     668    for (int x = 0; x < dx; x++) {
     669        for (int y = 0; y < dy; y++) {
     670            if (!(mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & 0x40)) continue;
     671            if ((x-1 >= 0) && (mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x-1] & 0x40)) {
     672                continue;
     673            }
     674            if ((y-1 >= 0) && (mymask->data.PS_TYPE_IMAGE_MASK_DATA[y-1][x] & 0x40)) {
     675                continue;
     676            }
     677            if ((x+1 < dx) && (mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x+1] & 0x40)) {
     678                continue;
     679            }
     680            if ((y+1 < dy) && (mymask->data.PS_TYPE_IMAGE_MASK_DATA[y+1][x] & 0x40)) {
     681                continue;
     682            }
     683            mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] ^= 0x40;
     684        }
     685    }
     686# endif
     687
     688    // transfer temporary mask to real mask & count masked pixels
     689    nCRpix = 0;
     690    for (int x = 0; x < dx; x++) {
     691        for (int y = 0; y < dy; y++) {
     692            if (mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & 0x40) {
     693                mask->data.PS_TYPE_IMAGE_MASK_DATA[y+ys+mask->row0][x+xs+mask->col0] |= maskVal;
     694                nCRpix ++;
     695            }
     696        }
     697    }
     698
     699    // XXX if we decide this REALLY is a cosmic ray, set the CR_LIMIT bit
     700    if (nCRpix > 1) {
     701        source->mode |= PM_SOURCE_MODE_CR_LIMIT;
     702        source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;
     703    }
     704    // fprintf (stderr, "CRMASK %d %d %d %d %d\n", peak->x, peak->y, dx, dy, nCRpix);
     705
     706    psFree(mypix);
     707    psFree(myfix);
     708    psFree(myvar);
     709    psFree(binned);
     710    psFree(conved);
     711    psFree(edges);
     712    psFree(mymask);
     713
     714    return true;
     715}
     716
     717bool psphotMaskCosmicRayFootprintCheck (psArray *sources) {
     718
     719    for (int i = 0; i < sources->n; i++) {
     720        pmSource *source = sources->data[i];
     721        pmPeak *peak = source->peak;
     722        pmFootprint *footprint = peak->footprint;
     723        if (!footprint) continue;
     724        for (int j = 0; j < footprint->spans->n; j++) {
     725            pmSpan *sp = footprint->spans->data[j];
     726            psAssert (sp, "missing span");
     727        }
     728    }
     729    return true;
     730}
     731
     732/**** ------ old versions of cosmic ray masking ----- ****/
     733
     734bool psphotMaskCosmicRayIsophot (pmSource *source, psImageMaskType maskVal, psImageMaskType crMask);
     735
     736// This attempt to mask the cosmic rays used the isophotal boundary
     737bool psphotMaskCosmicRay_V1 (psImage *mask, pmSource *source, psImageMaskType maskVal, psImageMaskType crMask) {
     738
     739    // replace the source flux
     740    pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
     741
     742    // flag this as a CR
     743    source->mode |= PM_SOURCE_MODE_CR_LIMIT;
     744    pmPeak *peak = source->peak;
     745    psAssert (peak, "NULL peak");
     746
     747    // grab the matching footprint
     748    pmFootprint *footprint = peak->footprint;
     749    if (!footprint) {
     750      psTrace("psphot.czw",2,"Using isophot CR mask code.");
     751
     752        // if we have not footprint, use the old code to mask by isophot
     753        psphotMaskCosmicRayIsophot (source, maskVal, crMask);
     754        return true;
     755    }
     756
     757    if (!footprint->spans) {
     758      psTrace("psphot.czw",2,"Using isophot CR mask code.");
     759
     760        // if we have no footprint, use the old code to mask by isophot
     761        psphotMaskCosmicRayIsophot (source, maskVal, crMask);
     762        return true;
     763    }
     764    psphotMaskCosmicRayIsophot (source, maskVal, crMask);
     765    // mask all of the pixels covered by the spans of the footprint
     766    for (int j = 1; j < footprint->spans->n; j++) {
     767        pmSpan *span1 = footprint->spans->data[j];
     768
     769        int iy = span1->y;
     770        int xs = span1->x0;
     771        int xe = span1->x1;
     772
     773        for (int ix = xs; ix < xe; ix++) {
     774            mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= crMask;
     775        }
     776    }
     777    return true;
     778}
     779
     780# define VERBOSE 0
     781int psphotMaskCosmicRayConnected (int xPeak, int yPeak, psImage *mymask, psImage *myvar, psImage *edges, int binning, float sigma_thresh) {
     782
     783    int xLo, xRo;
     784    int nCRpix = 0;
     785
     786    float noise_factor = 5.0 / 4.0;  // Intrinsic to the Laplacian making noise spikes spikier.
     787
     788    // mark the pixels in this row to the left, then the right. stay within footprint
     789    int xL = xPeak; // find the range of valid pixels in this row
     790    int xR = xPeak;
     791    for (int ix = xPeak; (ix >= 0) && (mymask->data.PS_TYPE_IMAGE_MASK_DATA[yPeak][ix] & 0x01); ix--) {
     792        float noise = binning * sqrt(noise_factor * myvar->data.F32[yPeak][ix]);
     793        float value = edges->data.F32[yPeak][ix] / noise;
     794        if (value < sigma_thresh ) break;
     795        mymask->data.PS_TYPE_IMAGE_MASK_DATA[yPeak][ix] |= 0x40;
     796        xL = ix;
     797        nCRpix ++;
     798        if (VERBOSE) fprintf (stderr, "mark %d,%d (%d) : %d - %d\n", ix, yPeak, nCRpix, xL, xR);
     799    }
     800    for (int ix = xPeak; (ix < mymask->numCols) && (mymask->data.PS_TYPE_IMAGE_MASK_DATA[yPeak][ix] & 0x01); ix++) {
     801        float noise = binning * sqrt(noise_factor * myvar->data.F32[yPeak][ix]);
     802        float value = edges->data.F32[yPeak][ix] / noise;
     803        if (value < sigma_thresh ) break;
     804        mymask->data.PS_TYPE_IMAGE_MASK_DATA[yPeak][ix] |= 0x40;
     805        xR = ix;
     806        nCRpix ++;
     807        if (VERBOSE) fprintf (stderr, "mark %d,%d (%d) : %d - %d\n", ix, yPeak, nCRpix, xL, xR);
     808    }
     809    // xL and xR mark the first and last valid pixel in the row
     810
     811    // for each of the neighboring rows, mark the high pixels if they touch the range xL to xR
     812    xLo = PS_MAX(xL - 1, 0);
     813    xRo = PS_MIN(xR + 1, mymask->numCols);
     814
     815    // first go down:
     816    for (int iy = yPeak - 1; iy >= 0; iy--) {
     817
     818        int xLn = -1;
     819        int xRn = -1;
     820        int newPix = 0;
     821
     822        // mark the pixels in the good range
     823        for (int ix = xLo; ix < xRo; ix++) {
     824            if (!(mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & 0x01)) continue; // only use pixels in the footprint
     825            float noise = binning * sqrt(noise_factor * myvar->data.F32[iy][ix]);
     826            float value = edges->data.F32[iy][ix] / noise;
     827            if (value < sigma_thresh ) continue;
     828            mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= 0x40;
     829            if (xLn == -1) xLn = ix; // first valid pixel in this row
     830            xRn = ix;                // last valid pixel in this row
     831            nCRpix ++;
     832            newPix ++;
     833            if (VERBOSE) fprintf (stderr, "mark C %d,%d (%d) : %d - %d | %d - %d | %d - %d \n", ix, iy, nCRpix, xL, xR, xLo, xRo, xLn, xRn);
     834        }
     835
     836        // mark the pixels to the left of the good range
     837        for (int ix = xLo; (ix >= 0) && (mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & 0x01); ix--) {
     838            float noise = binning * sqrt(noise_factor * myvar->data.F32[iy][ix]);
     839            float value = edges->data.F32[iy][ix] / noise;
     840            if (value < sigma_thresh ) break;
     841            mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= 0x40;
     842            if (xRn == -1) xRn = ix; // last valid pixel in this row
     843            xLn = ix;
     844            nCRpix ++;
     845            newPix ++;
     846            if (VERBOSE) fprintf (stderr, "mark L %d,%d (%d) : %d - %d | %d - %d | %d - %d \n", ix, iy, nCRpix, xL, xR, xLo, xRo, xLn, xRn);
     847        }
     848
     849        // mark the pixels to the right of the good range
     850        for (int ix = xRo; (ix < mymask->numCols) && (mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & 0x01); ix++) {
     851            float noise = binning * sqrt(noise_factor * myvar->data.F32[iy][ix]);
     852            float value = edges->data.F32[iy][ix] / noise;
     853            if (value < sigma_thresh ) break;
     854            mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= 0x40;
     855            if (xLn == -1) xLn = ix; // first valid pixel in this row
     856            xRn = ix;
     857            nCRpix ++;
     858            newPix ++;
     859            if (VERBOSE) fprintf (stderr, "mark R %d,%d (%d) : %d - %d | %d - %d | %d - %d \n", ix, iy, nCRpix, xL, xR, xLo, xRo, xLn, xRn);
     860        }
     861        if (newPix == 0) break;
     862        xLo = PS_MAX(xLn - 1, 0);
     863        xRo = PS_MIN(xRn + 1, mymask->numCols);
     864    }
     865
     866    xLo = PS_MAX(xL - 1, 0);
     867    xRo = PS_MIN(xR + 1, mymask->numCols);
     868
     869    // next go up:
     870    for (int iy = yPeak + 1; iy < mymask->numRows; iy++) {
     871
     872        int xLn = -1;
     873        int xRn = -1;
     874        int newPix = 0;
     875
     876        // mark the pixels in the good range
     877        for (int ix = xLo; ix < xRo; ix++) {
     878            if (!(mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & 0x01)) continue; // only use pixels in the footprint
     879            float noise = binning * sqrt(noise_factor * myvar->data.F32[iy][ix]);
     880            float value = edges->data.F32[iy][ix] / noise;
     881            if (value < sigma_thresh ) continue;
     882            mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= 0x40;
     883            if (xLn == -1) xLn = ix; // first valid pixel in this row
     884            xRn = ix;                // last valid pixel in this row
     885            nCRpix ++;
     886            newPix ++;
     887            if (VERBOSE) fprintf (stderr, "mark C %d,%d (%d) : %d - %d | %d - %d | %d - %d \n", ix, iy, nCRpix, xL, xR, xLo, xRo, xLn, xRn);
     888        }
     889
     890        // mark the pixels to the left of the good range
     891        for (int ix = xLo; (ix >= 0) && (mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & 0x01); ix--) {
     892            float noise = binning * sqrt(noise_factor * myvar->data.F32[iy][ix]);
     893            float value = edges->data.F32[iy][ix] / noise;
     894            if (value < sigma_thresh ) break;
     895            mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= 0x40;
     896            if (xRn == -1) xRn = ix; // last valid pixel in this row
     897            xLn = ix;
     898            nCRpix ++;
     899            newPix ++;
     900            if (VERBOSE) fprintf (stderr, "mark L %d,%d (%d) : %d - %d | %d - %d | %d - %d \n", ix, iy, nCRpix, xL, xR, xLo, xRo, xLn, xRn);
     901        }
     902
     903        // mark the pixels to the right of the good range
     904        for (int ix = xRo; (ix < mymask->numCols) && (mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & 0x01); ix++) {
     905            float noise = binning * sqrt(noise_factor * myvar->data.F32[iy][ix]);
     906            float value = edges->data.F32[iy][ix] / noise;
     907            if (value < sigma_thresh ) break;
     908            mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= 0x40;
     909            if (xLn == -1) xLn = ix; // first valid pixel in this row
     910            xRn = ix;
     911            nCRpix ++;
     912            newPix ++;
     913            if (VERBOSE) fprintf (stderr, "mark R %d,%d (%d) : %d - %d | %d - %d | %d - %d \n", ix, iy, nCRpix, xL, xR, xLo, xRo, xLn, xRn);
     914        }
     915        if (newPix == 0) break;
     916        xLo = PS_MAX(xLn - 1, 0);
     917        xRo = PS_MIN(xRn + 1, mymask->numCols);
     918    }
     919
     920    return nCRpix;
     921}
     922
     923bool psphotMaskCosmicRayIsophot (pmSource *source, psImageMaskType maskVal, psImageMaskType crMask) {
     924
     925    source->mode |= PM_SOURCE_MODE_CR_LIMIT;
     926    pmPeak *peak = source->peak;
     927    psAssert (peak, "NULL peak");
     928
     929    psImage *mask   = source->maskView;
     930    psImage *pixels = source->pixels;
     931    psImage *variance = source->variance;
     932
     933    // XXX This should be a recipe variable
     934# define SN_LIMIT 5.0
     935
     936    int xo = peak->x - pixels->col0;
     937    int yo = peak->y - pixels->row0;
     938
     939    // mark the pixels in this row to the left, then the right
     940    for (int ix = xo; ix >= 0; ix--) {
     941        float SN = pixels->data.F32[yo][ix] / sqrt(variance->data.F32[yo][ix]);
     942        if (SN > SN_LIMIT) {
     943            mask->data.PS_TYPE_IMAGE_MASK_DATA[yo][ix] |= crMask;
     944        }
     945    }
     946    for (int ix = xo + 1; ix < pixels->numCols; ix++) {
     947        float SN = pixels->data.F32[yo][ix] / sqrt(variance->data.F32[yo][ix]);
     948        if (SN > SN_LIMIT) {
     949            mask->data.PS_TYPE_IMAGE_MASK_DATA[yo][ix] |= crMask;
     950        }
     951    }
     952
     953    // for each of the neighboring rows, mark the high pixels if they have a marked neighbor
     954    // first go up:
     955    for (int iy = PS_MIN(yo, mask->numRows-2); iy >= 0; iy--) {
     956        // mark the pixels in this row to the left, then the right
     957        for (int ix = 0; ix < pixels->numCols; ix++) {
     958            float SN = pixels->data.F32[iy][ix] / sqrt(variance->data.F32[iy][ix]);
     959            if (SN < SN_LIMIT) continue;
     960
     961            bool valid = false;
     962            valid |= (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy+1][ix] & crMask);
     963            valid |= (ix > 0) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy+1][ix-1] & crMask) : 0;
     964            valid |= (ix <= mask->numCols) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy+1][ix+1] & crMask) : 0;
     965
     966            if (!valid) continue;
     967            mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= crMask;
     968        }
     969    }
     970    // next go down:
     971    for (int iy = PS_MIN(yo+1, mask->numRows-1); iy < pixels->numRows; iy++) {
     972        // mark the pixels in this row to the left, then the right
     973        for (int ix = 0; ix < pixels->numCols; ix++) {
     974            float SN = pixels->data.F32[iy][ix] / sqrt(variance->data.F32[iy][ix]);
     975            if (SN < SN_LIMIT) continue;
     976
     977            bool valid = false;
     978            valid |= (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy-1][ix] & crMask);
     979            valid |= (ix > 0) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy-1][ix-1] & crMask) : 0;
     980            valid |= (ix <= mask->numCols) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy-1][ix+1] & crMask) : 0;
     981
     982            if (!valid) continue;
     983            mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= crMask;
     984        }
     985    }
    191986    return true;
    192987}
     
    194989// given the PSF ellipse parameters, navigate around the 1sigma contour, return the total
    195990// deviation in sigmas.  This is measured on the residual image - should we ignore negative
    196 // deviations?
    197 static float psphotModelContour(const psImage *image, const psImage *variance, const psImage *mask,
    198                                 psImageMaskType maskVal, const pmModel *model, float Ro)
     991// deviations?  NOTE: This function was an early attempt to classify extended objects, and is
     992// no longer used by psphot.
     993float psphotModelContour(const psImage *image, const psImage *variance, const psImage *mask,
     994                         psImageMaskType maskVal, const pmModel *model, float Ro)
    199995{
    200996    psF32 *PAR = model->params->data.F32; // Model parameters
     
    2651061}
    2661062
    267 bool psphotMaskCosmicRay_New (psImage *mask, pmSource *source, psImageMaskType maskVal, psImageMaskType crMask) {
    268 
    269     // replace the source flux
    270     pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    271     source->tmpFlags &= ~PM_SOURCE_TMPF_SUBTRACTED;
    272 
    273     // flag this as a CR
    274     source->mode |= PM_SOURCE_MODE_CR_LIMIT;
    275     pmPeak *peak = source->peak;
    276     psAssert (peak, "NULL peak");
    277 
    278     // grab the matching footprint
    279     pmFootprint *footprint = peak->footprint;
    280     if (!footprint) {
    281         // if we have not footprint, use the old code to mask by isophot
    282         psphotMaskCosmicRay_Old (source, maskVal, crMask);
    283         return true;
    284     }
    285 
    286     if (!footprint->spans) {
    287         // if we have not footprint, use the old code to mask by isophot
    288         psphotMaskCosmicRay_Old (source, maskVal, crMask);
    289         return true;
    290     }
    291 
    292     // mask all of the pixels covered by the spans of the footprint
    293     for (int j = 1; j < footprint->spans->n; j++) {
    294         pmSpan *span1 = footprint->spans->data[j];
    295 
    296         int iy = span1->y;
    297         int xs = span1->x0;
    298         int xe = span1->x1;
    299 
    300         for (int ix = xs; ix < xe; ix++) {
    301             mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= crMask;
    302         }
     1063// this was an old attempt to identify cosmic rays based on the peak curvature
     1064bool psphotSourcePeakCurvature (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options) {
     1065
     1066    // classify the sources based on the CR test (place this in a function?)
     1067    // XXX use an internal flag to mark sources which have already been measured
     1068    for (int i = 0; i < sources->n; i++) {
     1069        pmSource *source = sources->data[i];
     1070
     1071        // skip source if it was already measured
     1072        if (source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED) {
     1073            psTrace("psphot", 7, "Not calculating source size since it has already been measured\n");
     1074            continue;
     1075        }
     1076
     1077        // source must have been subtracted
     1078        if (!(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED)) {
     1079            source->mode |= PM_SOURCE_MODE_SIZE_SKIPPED;
     1080            psTrace("psphot", 7, "Not calculating source size since source is not subtracted\n");
     1081            continue;
     1082        }
     1083
     1084        psF32 **resid  = source->pixels->data.F32;
     1085        psF32 **variance = source->variance->data.F32;
     1086        psImageMaskType **mask = source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA;
     1087
     1088        // Integer position of peak
     1089        int xPeak = source->peak->xf - source->pixels->col0 + 0.5;
     1090        int yPeak = source->peak->yf - source->pixels->row0 + 0.5;
     1091
     1092        // Skip sources which are too close to a boundary.  These are mostly caught as DEFECT
     1093        if (xPeak < 1 || xPeak > source->pixels->numCols - 2 ||
     1094            yPeak < 1 || yPeak > source->pixels->numRows - 2) {
     1095            psTrace("psphot", 7, "Not calculating crNsigma due to edge\n");
     1096            continue;
     1097        }
     1098
     1099        // Skip sources with masked pixels.  These are mostly caught as DEFECT
     1100        bool keep = true;
     1101        for (int iy = -1; (iy <= +1) && keep; iy++) {
     1102            for (int ix = -1; (ix <= +1) && keep; ix++) {
     1103                if (mask[yPeak+iy][xPeak+ix] & options->maskVal) {
     1104                    keep = false;
     1105                }
     1106            }
     1107        }
     1108        if (!keep) {
     1109            psTrace("psphot", 7, "Not calculating crNsigma due to masked pixels\n");
     1110            continue;
     1111        }
     1112
     1113        // Compare the central pixel with those on either side, for the four possible lines through it.
     1114
     1115        // Soften variances (add systematic error)
     1116        float softening = options->soft * PS_SQR(source->peak->flux); // Softening for variances
     1117
     1118        // Across the middle: y = 0
     1119        float cX = 2*resid[yPeak][xPeak]   - resid[yPeak+0][xPeak-1]  - resid[yPeak+0][xPeak+1];
     1120        float dcX = 4*variance[yPeak][xPeak] + variance[yPeak+0][xPeak-1] + variance[yPeak+0][xPeak+1];
     1121        float nX = cX / sqrtf(dcX + softening);
     1122
     1123        // Up the centre: x = 0
     1124        float cY = 2*resid[yPeak][xPeak]   - resid[yPeak-1][xPeak+0]  - resid[yPeak+1][xPeak+0];
     1125        float dcY = 4*variance[yPeak][xPeak] + variance[yPeak-1][xPeak+0] + variance[yPeak+1][xPeak+0];
     1126        float nY = cY / sqrtf(dcY + softening);
     1127
     1128        // Diagonal: x = y
     1129        float cL = 2*resid[yPeak][xPeak]   - resid[yPeak-1][xPeak-1]  - resid[yPeak+1][xPeak+1];
     1130        float dcL = 4*variance[yPeak][xPeak] + variance[yPeak-1][xPeak-1] + variance[yPeak+1][xPeak+1];
     1131        float nL = cL / sqrtf(dcL + softening);
     1132
     1133        // Diagonal: x = - y
     1134        float cR = 2*resid[yPeak][xPeak]   - resid[yPeak+1][xPeak-1]  - resid[yPeak-1][xPeak+1];
     1135        float dcR = 4*variance[yPeak][xPeak] + variance[yPeak+1][xPeak-1] + variance[yPeak-1][xPeak+1];
     1136        float nR = cR / sqrtf(dcR + softening);
     1137
     1138        // P(chisq > chisq_obs; Ndof) = gamma_Q (Ndof/2, chisq/2)
     1139        // Ndof = 4 ? (four measurements, no free parameters)
     1140        // XXX this value is going to be biased low because of systematic errors.
     1141        // we need to calibrate it somehow
     1142        // source->psfProb = gsl_sf_gamma_inc_Q (2, 0.5*chisq);
     1143
     1144        // not strictly accurate: overcounts the chisq contribution from the center pixel (by
     1145        // factor of 4); also biases a bit low if any pixels are masked
     1146        // XXX I am not sure I want to keep this value...
     1147        source->psfChisq = PS_SQR(nX) + PS_SQR(nY) + PS_SQR(nL) + PS_SQR(nR);
     1148
     1149        float fCR = 0.0;
     1150        int nCR = 0;
     1151        if (nX > 0.0) {
     1152            fCR += nX;
     1153            nCR ++;
     1154        }
     1155        if (nY > 0.0) {
     1156            fCR += nY;
     1157            nCR ++;
     1158        }
     1159        if (nL > 0.0) {
     1160            fCR += nL;
     1161            nCR ++;
     1162        }
     1163        if (nR > 0.0) {
     1164            fCR += nR;
     1165            nCR ++;
     1166        }
     1167        source->crNsigma  = (nCR > 0)  ? fCR / nCR : 0.0;
     1168        source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;
     1169
     1170        if (!isfinite(source->crNsigma)) {
     1171            continue;
     1172        }
     1173
     1174        // this source is thought to be a cosmic ray.  flag the detection and mask the pixels
     1175        if (source->crNsigma > options->nSigmaCR) {
     1176            source->mode |= PM_SOURCE_MODE_CR_LIMIT;
     1177            // XXX still testing... : psphotMaskCosmicRay (readout->mask, source, maskVal, crMask);
     1178            // XXX acting strange... psphotMaskCosmicRay_Old (source, maskVal, crMask);
     1179        }
     1180    }
     1181
     1182    // now that we have masked pixels associated with CRs, we can grow the mask
     1183    if (options->grow > 0) {
     1184        bool oldThreads = psImageConvolveSetThreads(true); // Old value of threading for psImageConvolveMask
     1185        psImage *newMask = psImageConvolveMask(NULL, readout->mask, options->crMask, options->crMask, -options->grow, options->grow, -options->grow, options->grow);
     1186        psImageConvolveSetThreads(oldThreads);
     1187        if (!newMask) {
     1188            psError(PS_ERR_UNKNOWN, false, "Unable to grow CR mask");
     1189            return false;
     1190        }
     1191        psFree(readout->mask);
     1192        readout->mask = newMask;
    3031193    }
    3041194    return true;
    3051195}
    3061196
    307 bool psphotMaskCosmicRay_Old (pmSource *source, psImageMaskType maskVal, psImageMaskType crMask) {
    308 
    309     source->mode |= PM_SOURCE_MODE_CR_LIMIT;
    310     pmPeak *peak = source->peak;
    311     psAssert (peak, "NULL peak");
    312 
    313     psImage *mask   = source->maskView;
    314     psImage *pixels = source->pixels;
    315     psImage *variance = source->variance;
    316 
    317     // XXX This should be a recipe variable
    318 # define SN_LIMIT 5.0
    319 
    320     int xo = peak->x - pixels->col0;
    321     int yo = peak->y - pixels->row0;
    322 
    323     // mark the pixels in this row to the left, then the right
    324     for (int ix = xo; ix >= 0; ix--) {
    325         float SN = pixels->data.F32[yo][ix] / sqrt(variance->data.F32[yo][ix]);
    326         if (SN > SN_LIMIT) {
    327             mask->data.PS_TYPE_IMAGE_MASK_DATA[yo][ix] |= crMask;
    328         }
    329     }
    330     for (int ix = xo + 1; ix < pixels->numCols; ix++) {
    331         float SN = pixels->data.F32[yo][ix] / sqrt(variance->data.F32[yo][ix]);
    332         if (SN > SN_LIMIT) {
    333             mask->data.PS_TYPE_IMAGE_MASK_DATA[yo][ix] |= crMask;
    334         }
    335     }
    336 
    337     // for each of the neighboring rows, mark the high pixels if they have a marked neighbor
    338     // first go up:
    339     for (int iy = PS_MIN(yo, mask->numRows-2); iy >= 0; iy--) {
    340         // mark the pixels in this row to the left, then the right
    341         for (int ix = 0; ix < pixels->numCols; ix++) {
    342             float SN = pixels->data.F32[iy][ix] / sqrt(variance->data.F32[iy][ix]);
    343             if (SN < SN_LIMIT) continue;
    344 
    345             bool valid = false;
    346             valid |= (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy+1][ix] & crMask);
    347             valid |= (ix > 0) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy+1][ix-1] & crMask) : 0;
    348             valid |= (ix <= mask->numCols) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy+1][ix+1] & crMask) : 0;
    349 
    350             if (!valid) continue;
    351             mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= crMask;
    352         }
    353     }
    354     // next go down:
    355     for (int iy = PS_MIN(yo+1, mask->numRows-1); iy < pixels->numRows; iy++) {
    356         // mark the pixels in this row to the left, then the right
    357         for (int ix = 0; ix < pixels->numCols; ix++) {
    358             float SN = pixels->data.F32[iy][ix] / sqrt(variance->data.F32[iy][ix]);
    359             if (SN < SN_LIMIT) continue;
    360 
    361             bool valid = false;
    362             valid |= (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy-1][ix] & crMask);
    363             valid |= (ix > 0) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy-1][ix-1] & crMask) : 0;
    364             valid |= (ix <= mask->numCols) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy-1][ix+1] & crMask) : 0;
    365 
    366             if (!valid) continue;
    367             mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= crMask;
    368         }
    369     }
    370     return true;
    371 }
  • branches/simtest_nebulous_branches/psphot/src/psphotSourceStats.c

    r24589 r27840  
    11# include "psphotInternal.h"
    22
    3 psArray *psphotSourceStats (pmConfig *config, pmReadout *readout, pmDetections *detections) {
     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).
     5// The new sources are added to any existing sources on detections->newSources.  The sources
     6// on detections->allSources are ignored.
     7bool psphotSourceStats (pmConfig *config, const pmFPAview *view, bool setWindow)
     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 (!psphotSourceStatsReadout (config, view, "PSPHOT.INPUT", i, recipe, setWindow)) {
     21            psError (PSPHOT_ERR_CONFIG, false, "failed to find initial detections for PSPHOT.INPUT entry %d", i);
     22            return false;
     23        }
     24    }
     25    return true;
     26}
     27
     28bool psphotSourceStatsReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe, bool setWindow) {
    429
    530    bool status = false;
     
    833    psTimerStart ("psphot.stats");
    934
    10     // select the appropriate recipe information
    11     psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
    12     assert (recipe);
     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
     42    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     43    psAssert (detections, "missing detections?");
     44
     45    // XXX TEST:
     46    if (detections->allSources) {
     47        psphotMaskCosmicRayFootprintCheck(detections->allSources);
     48    }
     49    if (detections->newSources) {
     50        psphotMaskCosmicRayFootprintCheck(detections->newSources);
     51    }
    1352
    1453    // determine the number of allowed threads
     
    1958
    2059    // determine properties (sky, moments) of initial sources
    21     float OUTER    = psMetadataLookupF32 (&status, recipe, "SKY_OUTER_RADIUS");
    22     if (!status) return NULL;
     60    float OUTER = psMetadataLookupF32 (&status, recipe, "SKY_OUTER_RADIUS");
     61    psAssert (status, "missing SKY_OUTER_RADIUS in recipe?");
     62
     63    // XXX this seems like an arbitrary number...
     64    OUTER = PS_MAX(OUTER, 20.0); // XXX Guarantee that we can encompass the max moments radius
     65
    2366    char *breakPt  = psMetadataLookupStr (&status, recipe, "BREAK_POINT");
    24     if (!status) return NULL;
     67    psAssert (status, "missing BREAK_POINT?");
     68
     69    float INNER        = psMetadataLookupF32 (&status, recipe, "SKY_INNER_RADIUS"); psAssert (status, "missing SKY_INNER_RADIUS");
     70    float MIN_SN       = psMetadataLookupF32 (&status, recipe, "MOMENTS_SN_MIN"); psAssert (status, "missing MOMENTS_SN_MIN");
     71
     72    // bit-masks to test for good/bad pixels
     73    psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT");
     74    psAssert (maskVal, "missing MASK.PSPHOT");
     75
     76    // bit-mask to mark pixels not used in analysis
     77    psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT");
     78    psAssert (markVal, "missing MARK.PSPHOT");
    2579
    2680    psArray *peaks = detections->peaks;
    2781    if (!peaks) {
    2882        psError(PS_ERR_UNEXPECTED_NULL, false, "No peaks found!");
    29         return NULL;
     83        return false;
    3084    }
    3185
    3286    // generate the array of sources, define the associated pixel
    33     sources = psArrayAllocEmpty (peaks->n);
     87    if (!detections->newSources) {
     88        detections->newSources = psArrayAllocEmpty (peaks->n);
     89    }
     90    sources = detections->newSources;
     91
     92    // if there are no peaks, we save the empty source array and return
     93    if (!peaks->n) {
     94        return true;
     95    }
    3496
    3597    for (int i = 0; i < peaks->n; i++) {
     
    40102        // create a new source
    41103        pmSource *source = pmSourceAlloc();
     104        source->imageID = index;
    42105
    43106        // add the peak
     
    53116        psArrayAdd (sources, 100, source);
    54117        psFree (source);
     118    }
     119
     120    if (!strcasecmp (breakPt, "PEAKS")) {
     121        psLogMsg ("psphot", PS_LOG_INFO, "%ld sources : %f sec\n", sources->n, psTimerMark ("psphot.stats"));
     122        psLogMsg ("psphot", PS_LOG_INFO, "break point PEAKS, skipping MOMENTS\n");
     123        psphotVisualShowMoments (sources);
     124        return true;
     125    }
     126
     127    if (setWindow) {
     128        if (!psphotSetMomentsWindow(recipe, readout->analysis, sources)) {
     129            psError(PS_ERR_UNEXPECTED_NULL, false, "Failed to determine Moments Window!");
     130            psFree(detections->newSources);
     131            return false;
     132        }
     133    }
     134
     135    // if we have measured the window, we will be saving the modified version of these recipe values on readout->analysis
     136    float SIGMA = psMetadataLookupF32 (&status, readout->analysis, "MOMENTS_GAUSS_SIGMA");
     137    if (!status) {
     138        SIGMA = psMetadataLookupF32 (&status, recipe, "MOMENTS_GAUSS_SIGMA");
     139    }
     140    float RADIUS = psMetadataLookupF32 (&status, readout->analysis, "PSF_MOMENTS_RADIUS");
     141    if (!status) {
     142        RADIUS = psMetadataLookupF32 (&status, recipe, "PSF_MOMENTS_RADIUS");
     143    }
     144
     145    // threaded measurement of the source magnitudes
     146    int Nfail = 0;
     147    int Nmoments = 0;
     148    int Nfaint = 0;
     149
     150    // choose Cx, Cy (see psphotThreadTools.c for overview of the concepts)
     151    int Cx = 1, Cy = 1;
     152    psphotChooseCellSizes (&Cx, &Cy, readout, nThreads);
     153
     154    psArray *cellGroups = psphotAssignSources (Cx, Cy, sources);
     155
     156    for (int i = 0; i < cellGroups->n; i++) {
     157
     158        psArray *cells = cellGroups->data[i];
     159
     160        for (int j = 0; j < cells->n; j++) {
     161
     162            // allocate a job -- if threads are not defined, this just runs the job
     163            psThreadJob *job = psThreadJobAlloc ("PSPHOT_SOURCE_STATS");
     164
     165            psArrayAdd(job->args, 1, cells->data[j]); // sources
     166
     167            PS_ARRAY_ADD_SCALAR(job->args, INNER,   PS_TYPE_F32);
     168            PS_ARRAY_ADD_SCALAR(job->args, MIN_SN,  PS_TYPE_F32);
     169            PS_ARRAY_ADD_SCALAR(job->args, RADIUS,  PS_TYPE_F32);
     170            PS_ARRAY_ADD_SCALAR(job->args, SIGMA,   PS_TYPE_F32);
     171
     172            PS_ARRAY_ADD_SCALAR(job->args, maskVal, PS_TYPE_IMAGE_MASK);
     173            PS_ARRAY_ADD_SCALAR(job->args, markVal, PS_TYPE_IMAGE_MASK);
     174
     175            PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nmoments
     176            PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nfail
     177            PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nfaint
     178
     179            if (!psThreadJobAddPending(job)) {
     180                psError(PS_ERR_UNKNOWN, false, "Unable to launch thread job PSPHOT_SOURCE_STATS");
     181                psFree (job);
     182                psFree(detections->newSources);
     183                return false;
     184            }
     185            psFree(job);
     186        }
     187
     188        // wait for the threads to finish and manage results
     189        if (!psThreadPoolWait (false)) {
     190            psError(PS_ERR_UNKNOWN, false, "Failure in thread job PSPHOT_SOURCE_STATS");
     191            psFree(detections->newSources);
     192            return false;
     193        }
     194
     195        // we have only supplied one type of job, so we can assume the types here
     196        psThreadJob *job = NULL;
     197        while ((job = psThreadJobGetDone()) != NULL) {
     198            if (job->args->n < 1) {
     199                fprintf (stderr, "error with job\n");
     200            } else {
     201                psScalar *scalar = NULL;
     202                scalar = job->args->data[7];
     203                Nmoments += scalar->data.S32;
     204                scalar = job->args->data[8];
     205                Nfail += scalar->data.S32;
     206                scalar = job->args->data[9];
     207                Nfaint += scalar->data.S32;
     208            }
     209            psFree(job);
     210        }
     211    }
     212
     213    psFree (cellGroups);
     214
     215    psLogMsg ("psphot", PS_LOG_INFO, "%ld sources, %d moments, %d faint, %d failed: %f sec\n", sources->n, Nmoments, Nfaint, Nfail, psTimerMark ("psphot.stats"));
     216
     217    psphotVisualShowMoments (sources);
     218
     219    if (detections->allSources) {
     220        psphotMaskCosmicRayFootprintCheck(detections->allSources);
     221    }
     222    if (detections->newSources) {
     223        psphotMaskCosmicRayFootprintCheck(detections->newSources);
     224    }
     225
     226    return true;
     227}
     228
     229// this function is currently only called by psphotCheckExtSources
     230bool psphotSourceStatsUpdate (psArray *sources, pmConfig *config, pmReadout *readout) {
     231
     232    bool status = false;
     233
     234    psTimerStart ("psphot.stats");
     235
     236    // select the appropriate recipe information
     237    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     238    assert (recipe);
     239
     240    // determine the number of allowed threads
     241    int nThreads = psMetadataLookupS32(&status, config->arguments, "NTHREADS"); // Number of threads
     242    if (!status) {
     243        nThreads = 0;
     244    }
     245
     246    // determine properties (sky, moments) of initial sources
     247    float OUTER    = psMetadataLookupF32 (&status, recipe, "SKY_OUTER_RADIUS");
     248    if (!status) return false;
     249
     250    OUTER = PS_MAX(OUTER, 20.0); // XXX Guarantee that we can encompass the max moments radius
     251
     252    char *breakPt  = psMetadataLookupStr (&status, recipe, "BREAK_POINT");
     253    if (!status) return false;
     254
     255    for (int i = 0; i < sources->n; i++) {
     256
     257        pmSource *source = sources->data[i];
     258        if (!source->peak) continue; // XXX how can we have a peak-less source?
     259
     260        // allocate space for moments
     261        if (!source->moments) {
     262            source->moments = pmMomentsAlloc();
     263        }
     264
     265        // allocate image, weight, mask arrays for each peak (square of radius OUTER)
     266        pmSourceDefinePixels (source, readout, source->peak->x, source->peak->y, OUTER);
     267        source->peak->assigned = true;
    55268    }
    56269
     
    62275    }
    63276
     277    // XXX how else could we get the window size in?
     278    if (!psphotSetMomentsWindow(recipe, readout->analysis, sources)) {
     279        psError(PS_ERR_UNEXPECTED_NULL, false, "Failed to determine Moments Window!");
     280        return NULL;
     281    }
     282
    64283    // threaded measurement of the source magnitudes
    65284    int Nfail = 0;
     
    82301            psThreadJob *job = psThreadJobAlloc ("PSPHOT_SOURCE_STATS");
    83302
     303            // XXX: this must match the above
    84304            psArrayAdd(job->args, 1, cells->data[j]); // sources
    85305            psArrayAdd(job->args, 1, recipe);
     
    136356
    137357    psArray *sources                = job->args->data[0];
    138     psMetadata *recipe              = job->args->data[1];
    139 
    140     float INNER        = psMetadataLookupF32 (&status, recipe, "SKY_INNER_RADIUS");
    141     if (!status) return false;
    142     float MIN_SN       = psMetadataLookupF32 (&status, recipe, "MOMENTS_SN_MIN");
    143     if (!status) return false;
    144     float RADIUS       = psMetadataLookupF32 (&status, recipe, "PSF_MOMENTS_RADIUS");
    145     if (!status) return false;
    146     float MIN_PIXEL_SN = psMetadataLookupF32 (&status, recipe, "MOMENTS_MIN_PIXEL_SN");
    147     if (!status) return false;
    148     float SIGMA        = psMetadataLookupF32 (&status, recipe, "MOMENTS_GAUSS_SIGMA");
    149     if (!status) return false;
    150 
    151     // bit-masks to test for good/bad pixels
    152     psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT");
    153     assert (maskVal);
    154 
    155     // bit-mask to mark pixels not used in analysis
    156     psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT");
    157     assert (markVal);
     358
     359    float INNER                     = PS_SCALAR_VALUE(job->args->data[1],F32);
     360    float MIN_SN                    = PS_SCALAR_VALUE(job->args->data[2],F32);
     361    float RADIUS                    = PS_SCALAR_VALUE(job->args->data[3],F32);
     362    float SIGMA                     = PS_SCALAR_VALUE(job->args->data[4],F32);
     363
     364    psImageMaskType maskVal         = PS_SCALAR_VALUE(job->args->data[5],PS_TYPE_IMAGE_MASK_DATA);
     365    psImageMaskType markVal         = PS_SCALAR_VALUE(job->args->data[6],PS_TYPE_IMAGE_MASK_DATA);
    158366
    159367    // maskVal is used to test for rejected pixels, and must include markVal
     
    166374    for (int i = 0; i < sources->n; i++) {
    167375        pmSource *source = sources->data[i];
     376
     377        if (source->tmpFlags & PM_SOURCE_TMPF_MOMENTS_MEASURED) continue;
     378        source->tmpFlags |= PM_SOURCE_TMPF_MOMENTS_MEASURED;
    168379
    169380        // skip faint sources for moments measurement
     
    194405        }
    195406
    196         // measure basic source moments
    197         status = pmSourceMoments (source, RADIUS, SIGMA, MIN_PIXEL_SN);
     407        // measure basic source moments (no S/N clipping on input pixels)
     408        status = pmSourceMoments (source, RADIUS, SIGMA, 0.0, maskVal);
    198409        if (status) {
    199410            Nmoments ++;
     
    205416        BIG_RADIUS = PS_MIN (INNER, 3*RADIUS);
    206417        psTrace ("psphot", 4, "retrying moments for %d, %d\n", source->peak->x, source->peak->y);
    207         status = pmSourceMoments (source, BIG_RADIUS, 3.0*SIGMA, MIN_PIXEL_SN);
     418        status = pmSourceMoments (source, BIG_RADIUS, 3.0*SIGMA, 0.0, maskVal);
    208419        if (status) {
    209420            source->mode |= PM_SOURCE_MODE_BIG_RADIUS;
     
    219430
    220431    // change the value of a scalar on the array (wrap this and put it in psArray.h)
    221     scalar = job->args->data[2];
     432    scalar = job->args->data[7];
    222433    scalar->data.S32 = Nmoments;
    223434
    224     scalar = job->args->data[3];
     435    scalar = job->args->data[8];
    225436    scalar->data.S32 = Nfail;
    226437
    227     scalar = job->args->data[4];
     438    scalar = job->args->data[9];
    228439    scalar->data.S32 = Nfaint;
    229440
     
    231442}
    232443
    233 # if (0)
    234 bool psphotSourceStats_Unthreaded (int *nfail, int *nmoments, psArray *sources, psMetadata *recipe) {
    235 
    236     bool status = false;
    237     float BIG_RADIUS;
    238 
    239     float INNER    = psMetadataLookupF32 (&status, recipe, "SKY_INNER_RADIUS");
    240     if (!status) return false;
    241     float MIN_SN   = psMetadataLookupF32 (&status, recipe, "MOMENTS_SN_MIN");
    242     if (!status) return false;
    243     float RADIUS   = psMetadataLookupF32 (&status, recipe, "PSF_MOMENTS_RADIUS");
    244     if (!status) return false;
    245 
    246     // bit-masks to test for good/bad pixels
    247     psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT");
    248     assert (maskVal);
    249 
    250     // bit-mask to mark pixels not used in analysis
    251     psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT");
    252     assert (markVal);
    253 
    254     // maskVal is used to test for rejected pixels, and must include markVal
    255     maskVal |= markVal;
    256 
    257     // threaded measurement of the sources moments
    258     int Nfail = 0;
    259     int Nmoments = 0;
    260     for (int i = 0; i < sources->n; i++) {
    261         pmSource *source = sources->data[i];
    262 
    263         // skip faint sources for moments measurement
    264         if (source->peak->SN < MIN_SN) {
    265             continue;
    266         }
    267 
    268         // measure a local sky value
    269         // the local sky is now ignored; kept here for reference only
    270         status = pmSourceLocalSky (source, PS_STAT_SAMPLE_MEDIAN, INNER, maskVal, markVal);
    271         if (!status) {
    272             psErrorClear(); // XXX re-consider the errors raised here
    273             Nfail ++;
    274             continue;
    275         }
    276 
    277         // measure the local sky variance (needed if noise is not sqrt(signal))
    278         // XXX EAM : this should use ROBUST not SAMPLE median, but it is broken
    279         status = pmSourceLocalSkyVariance (source, PS_STAT_SAMPLE_MEDIAN, INNER, maskVal, markVal);
    280         if (!status) {
    281             Nfail ++;
    282             psErrorClear();
    283             continue;
    284         }
    285 
    286         // measure basic source moments
    287         status = pmSourceMoments (source, RADIUS, SIGMA, MIN_PIXEL_SN);
    288         if (status) {
    289             Nmoments ++;
    290             continue;
    291         }
    292 
    293         // if no valid pixels, or massive swing, likely saturated source,
    294         // try a much larger box
    295         BIG_RADIUS = PS_MIN (INNER, 3*RADIUS);
    296         psTrace ("psphot", 4, "retrying moments for %d, %d\n", source->peak->x, source->peak->y);
    297         status = pmSourceMoments (source, BIG_RADIUS, 3.0*SIGMA, MIN_PIXEL_SN);
    298         if (status) {
    299             Nmoments ++;
    300             continue;
    301         }
    302 
    303         Nfail ++;
    304         psErrorClear();
    305         continue;
    306     }
    307 
    308     // change the value of a scalar on the array (wrap this and put it in psArray.h)
    309     *nmoments = Nmoments;
    310     *nfail = Nfail;
    311 
     444// this function attempts to iteratively determine the best value for sigma of the moments weighting Gaussian
     445// this function modifies the recipe values MOMENTS_SX_MAX, MOMENTS_SY_MAX, and PSF_CLUMP_GRID_SCALE, used by pmSourcePSFClump
     446bool psphotSetMomentsWindow (psMetadata *recipe, psMetadata *analysis, psArray *sources) {
     447
     448    bool status;
     449
     450    float MIN_SN = psMetadataLookupF32 (&status, recipe, "MOMENTS_SN_MIN"); psAssert (status, "missing MOMENTS_SN_MIN");
     451    float PSF_SN_LIM = psMetadataLookupF32(&status, recipe, "PSF_SN_LIM"); psAssert (status, "missing PSF_SN_LIM");
     452    psF32 MOMENTS_AR_MAX = psMetadataLookupF32(&status, recipe, "MOMENTS_AR_MAX"); psAssert (status, "missing MOMENTS_AR_MAX");
     453
     454    // XXX move this to a config file?
     455    # define NSIGMA 8
     456    float sigma[NSIGMA] = {1.0, 2.0, 3.0, 4.5, 6.0, 9.0, 12.0, 18.0};
     457    float Sout[NSIGMA];
     458
     459    // this sorts by peak->SN
     460    sources = psArraySort (sources, pmSourceSortBySN);
     461
     462    // loop over radii:
     463    for (int i = 0; i < NSIGMA; i++) {
     464
     465        // XXX move max source number to config
     466        for (int j = 0; (j < sources->n) && (j < 400); j++) {
     467
     468            pmSource *source = sources->data[j];
     469            psAssert (source->moments, "force moments to exist");
     470            source->moments->nPixels = 0;
     471
     472            // skip faint sources for moments measurement
     473            if (source->peak->SN < MIN_SN) {
     474                continue;
     475            }
     476
     477            // measure basic source moments (no S/N clipping on input pixels)
     478            status = pmSourceMoments (source, 4*sigma[i], sigma[i], 0.0, 0xffff);
     479        }
     480
     481        // choose a grid scale that is a fixed fraction of the psf sigma^2
     482        float PSF_CLUMP_GRID_SCALE = 0.1*PS_SQR(sigma[i]);
     483        float MOMENTS_SX_MAX = 2.0*PS_SQR(sigma[i]);
     484        float MOMENTS_SY_MAX = 2.0*PS_SQR(sigma[i]);
     485
     486        // determine the PSF parameters from the source moment values
     487        pmPSFClump psfClump = pmSourcePSFClump (NULL, NULL, sources, PSF_SN_LIM, PSF_CLUMP_GRID_SCALE, MOMENTS_SX_MAX, MOMENTS_SY_MAX, MOMENTS_AR_MAX);
     488        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]);
     489
     490        psMetadataAddS32 (analysis, PS_LIST_TAIL, "PSF.CLUMP.NREGIONS",  PS_META_REPLACE, "psf clump regions", 1);
     491        psMetadata *regionMD = psMetadataLookupPtr (&status, analysis, "PSF.CLUMP.REGION.000");
     492        if (!regionMD) {
     493            regionMD = psMetadataAlloc();
     494            psMetadataAddMetadata (analysis, PS_LIST_TAIL, "PSF.CLUMP.REGION.000", PS_META_REPLACE, "psf clump region", regionMD);
     495            psFree (regionMD);
     496        }
     497        psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.X",  PS_META_REPLACE, "psf clump center", psfClump.X);
     498        psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.Y",  PS_META_REPLACE, "psf clump center", psfClump.Y);
     499        psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DX", PS_META_REPLACE, "psf clump center", psfClump.dX);
     500        psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DY", PS_META_REPLACE, "psf clump center", psfClump.dY);
     501
     502        psphotVisualPlotMoments (recipe, analysis, sources);
     503
     504        Sout[i] = sqrt(0.5*(psfClump.X + psfClump.Y)) / sigma[i];
     505    }
     506
     507    // we are looking for sigma for which Sout = 0.65 (or some other value)
     508    float Sigma = NAN;
     509    float minS = Sout[0];
     510    float maxS = Sout[0];
     511    for (int i = 0; i < NSIGMA; i++) {
     512        minS = PS_MIN(Sout[i], minS);
     513        maxS = PS_MAX(Sout[i], maxS);
     514    }
     515    if (minS > 0.65) Sigma = sigma[NSIGMA-1];
     516    if (maxS < 0.65) Sigma = sigma[0];
     517
     518    for (int i = 0; i < NSIGMA - 1 && isnan(Sigma); i++) {
     519        if (!isfinite(Sout[i]) || !isfinite(Sout[i+1])) continue;
     520        if ((Sout[i] > 0.65) && (Sout[i+1] > 0.65)) continue;
     521        if ((Sout[i] < 0.65) && (Sout[i+1] < 0.65)) continue;
     522        Sigma = sigma[i] + (0.65 - Sout[i])*(sigma[i+1] - sigma[i])/(Sout[i+1] - Sout[i]);
     523    }
     524    psAssert (isfinite(Sigma), "did we miss a case?");
     525
     526    // choose a grid scale that is a fixed fraction of the psf sigma^2
     527    psMetadataAddF32(analysis, PS_LIST_TAIL, "PSF_CLUMP_GRID_SCALE", PS_META_REPLACE, "clump grid", 0.1*PS_SQR(Sigma));
     528    psMetadataAddF32(analysis, PS_LIST_TAIL, "MOMENTS_SX_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(Sigma));
     529    psMetadataAddF32(analysis, PS_LIST_TAIL, "MOMENTS_SY_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(Sigma));
     530    psMetadataAddF32(analysis, PS_LIST_TAIL, "MOMENTS_GAUSS_SIGMA", PS_META_REPLACE, "moments limit", Sigma);
     531    psMetadataAddF32(analysis, PS_LIST_TAIL, "PSF_MOMENTS_RADIUS", PS_META_REPLACE, "moments limit", 4.0*Sigma);
     532
     533    psLogMsg ("psphot", 3, "using window function with sigma = %f\n", Sigma);
    312534    return true;
    313535}
    314 # endif
     536
     537// if we use the footprints, the output peaks list contains both old and new peaks,
     538// otherwise it only contains the new peaks.
     539
  • branches/simtest_nebulous_branches/psphot/src/psphotSubtractBackground.c

    r23287 r27840  
    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
     26    pmReadout *model = NULL;
     27    if (modelFile->mode == PM_FPA_MODE_INTERNAL) {
     28        model = modelFile->readout;
     29    } else {
     30        model = pmFPAviewThisReadout (view, modelFile->fpa);
     31    }
    2332    assert (model);
    24 
    25     // select the appropriate recipe information
    26     psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
    27     assert (recipe);
    2833
    2934    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
     
    3540
    3641    // select background pixels, from output background file, or create
     42    // XXX for now, we will only allow a single background image to be generated
    3743    file = psMetadataLookupPtr (&status, config->files, "PSPHOT.BACKGND");
    3844    if (file) {
     
    6672
    6773    // back-sub image pixels, from output background file (don't create if not requested)
     74    // XXX for now, we will only allow a single background-subtracted image to be generated
    6875    file = psMetadataLookupPtr (&status, config->files, "PSPHOT.BACKSUB");
    6976    if (file) {
     
    109116    // the pmReadout selected in this function are all view on entries in config->files
    110117
     118    // display the backsub and backgnd images
     119    // move this inthe the subtract background loop
     120    psphotVisualShowBackground (config, view, readout);
     121
    111122    npass ++;
    112123    return true;
    113124}
     125
     126bool psphotSubtractBackground (pmConfig *config, const pmFPAview *view)
     127{
     128    bool status = false;
     129
     130    // select the appropriate recipe information
     131    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     132    psAssert (recipe, "missing recipe?");
     133
     134    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     135    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     136
     137    // loop over the available readouts
     138    for (int i = 0; i < num; i++) {
     139        if (!psphotSubtractBackgroundReadout (config, view, "PSPHOT.INPUT", i, recipe)) {
     140            psError (PSPHOT_ERR_CONFIG, false, "failed to subtract background for PSPHOT.INPUT entry %d", i);
     141            return false;
     142        }
     143    }
     144    return true;
     145}
  • branches/simtest_nebulous_branches/psphot/src/psphotVersion.c

    r23805 r27840  
    3030psString psphotVersionLong(void)
    3131{
    32     psString version = psLibVersion();  // Version, to return
    33     psString source = psLibSource();    // Source
     32    psString version = psphotVersion();  // Version, to return
     33    psString source = psphotSource();    // Source
    3434
    3535    psStringPrepend(&version, "psphot ");
  • branches/simtest_nebulous_branches/psphot/src/psphotVisual.c

    r24636 r27840  
    1515# include <kapa.h>
    1616
     17bool pmVisualLimitsFromVectors (Graphdata *graphdata, psVector *xVec, psVector *yVec);
     18
    1719// functions used to visualize the analysis as it goes
    1820// these are invoked by the -visual options
    1921
    20 static int kapa = -1;
     22static int kapa1 = -1;
    2123static int kapa2 = -1;
    2224static int kapa3 = -1;
    2325
     26int psphotKapaChannel (int channel) {
     27
     28    switch (channel) {
     29      case 1:
     30        if (kapa1 == -1) {
     31            kapa1 = KapaOpenNamedSocket ("kapa", "psphot:images");
     32            if (kapa1 == -1) {
     33                fprintf (stderr, "failure to open kapa; visual mode disabled\n");
     34                pmVisualSetVisual(false);
     35            }
     36        }
     37        return kapa1;
     38      case 2:
     39        if (kapa2 == -1) {
     40            kapa2 = KapaOpenNamedSocket ("kapa", "psphot:plots");
     41            if (kapa2 == -1) {
     42                fprintf (stderr, "failure to open kapa; visual mode disabled\n");
     43                pmVisualSetVisual(false);
     44            }
     45        }
     46        return kapa2;
     47      case 3:
     48        if (kapa3 == -1) {
     49            kapa3 = KapaOpenNamedSocket ("kapa", "psphot:stamps");
     50            if (kapa3 == -1) {
     51                fprintf (stderr, "failure to open kapa; visual mode disabled\n");
     52                pmVisualSetVisual(false);
     53            }
     54        }
     55        return kapa3;
     56      default:
     57        psAbort ("unknown kapa channel");
     58    }
     59    psAbort ("unknown kapa channel");
     60}
     61
     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}
    2475
    2576bool psphotVisualShowMask (int kapaFD, psImage *inImage, const char *name, int channel) {
     
    69120}
    70121
    71 bool psphotVisualScaleImage (int kapaFD, psImage *inImage, const char *name, int channel) {
     122bool psphotVisualScaleImage (int kapaFD, psImage *inImage, psImage *inMask, const char *name, int channel) {
    72123
    73124    KiiImage image;
     
    79130    psStats *stats = psStatsAlloc (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV);
    80131    psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS);
    81     if (!psImageBackground(stats, NULL, inImage, NULL, 0, rng)) {
     132    if (!psImageBackground(stats, NULL, inImage, inMask, 0xffff, rng)) {
    82133        fprintf (stderr, "failed to get background values\n");
    83134        return false;
     
    131182    if (!pmVisualIsVisual()) return true;
    132183
    133     if (kapa == -1) {
    134         kapa = KapaOpenNamedSocket ("kapa", "psphot:images");
    135         if (kapa == -1) {
    136             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    137             pmVisualSetVisual(false);
    138             return false;
    139         }
    140     }
    141 
    142     // psphotVisualShowMask (kapa, readout->mask, "mask", 2);
    143     psphotVisualScaleImage (kapa, readout->variance, "variance", 1);
    144     psphotVisualScaleImage (kapa, readout->image, "image", 0);
    145 
    146     // pause and wait for user input:
    147     // continue, save (provide name), ??
    148     char key[10];
    149     fprintf (stdout, "[c]ontinue? ");
    150     if (!fgets(key, 8, stdin)) {
    151         psWarning("Unable to read option");
    152     }
     184    int kapa = psphotKapaChannel (1);
     185    if (kapa == -1) return false;
     186
     187    psphotVisualShowMask (kapa, readout->mask, "mask", 2);
     188    psphotVisualScaleImage (kapa, readout->variance, readout->mask, "variance", 1);
     189    psphotVisualScaleImage (kapa, readout->image, readout->mask, "image", 0);
     190
     191    pmVisualAskUser(NULL);
    153192    return true;
    154193}
     
    160199    if (!pmVisualIsVisual()) return true;
    161200
    162     if (kapa == -1) {
    163         kapa = KapaOpenNamedSocket ("kapa", "psphot:images");
    164         if (kapa == -1) {
    165             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    166             pmVisualSetVisual(false);
    167             return false;
    168         }
    169     }
     201    int kapa = psphotKapaChannel (1);
     202    if (kapa == -1) return false;
    170203
    171204    bool status = false;
     
    178211    }
    179212
    180     psphotVisualScaleImage (kapa, backgnd->image, "backgnd", 2);
    181     psphotVisualScaleImage (kapa, readout->image, "backsub", 0);
    182 
    183     // pause and wait for user input:
    184     // continue, save (provide name), ??
    185     char key[10];
    186     fprintf (stdout, "[c]ontinue? ");
    187     if (!fgets(key, 8, stdin)) {
    188         psWarning("Unable to read option");
    189     }
    190     return true;
    191 }
    192 
    193 bool psphotVisualShowSignificance (psImage *image) {
     213    psphotVisualScaleImage (kapa, backgnd->image, readout->mask, "backgnd", 2);
     214    psphotVisualScaleImage (kapa, readout->image, readout->mask, "backsub", 0);
     215
     216    pmVisualAskUser(NULL);
     217    return true;
     218}
     219
     220bool psphotVisualShowSignificance (psImage *image, float min, float max) {
    194221
    195222    if (!pmVisualIsVisual()) return true;
    196223
    197     if (kapa == -1) {
    198         kapa = KapaOpenNamedSocket ("kapa", "psphot:images");
    199         if (kapa == -1) {
    200             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    201             pmVisualSetVisual(false);
    202             return false;
    203         }
    204     }
    205 
    206     // XXX test: image->data.F32[10][10] = 10000;
    207     psphotVisualRangeImage (kapa, image, "signif", 2, -1.0, 25.0*25.0);
    208 
    209     // pause and wait for user input:
    210     // continue, save (provide name), ??
    211     char key[10];
    212     fprintf (stdout, "[c]ontinue? ");
    213     if (!fgets(key, 8, stdin)) {
    214         psWarning("Unable to read option");
    215     }
     224    int kapa = psphotKapaChannel (1);
     225    if (kapa == -1) return false;
     226
     227    psphotVisualRangeImage (kapa, image, "signif", 2, min, max);
     228
     229    pmVisualAskUser(NULL);
    216230    return true;
    217231}
     
    224238    if (!pmVisualIsVisual()) return true;
    225239
    226     if (kapa == -1) {
    227         fprintf (stderr, "kapa not opened, skipping\n");
    228         return false;
    229     }
     240    int kapa = psphotKapaChannel (1);
     241    if (kapa == -1) return false;
    230242
    231243    psArray *peaks = detections->peaks;
     
    233245    // note: this uses the Ohana allocation tools:
    234246    // ALLOCATE (overlay, KiiOverlay, 3*peaks->n + 1);
    235     ALLOCATE (overlay, KiiOverlay, peaks->n);
     247    ALLOCATE (overlay, KiiOverlay, peaks->n + 2);
    236248
    237249    Noverlay = 0;
     
    249261        overlay[Noverlay].text = NULL;
    250262        Noverlay ++;
    251 
    252 # if (0)
    253         overlay[Noverlay].type = KII_OVERLAY_BOX;
    254         overlay[Noverlay].x = peak->x;
    255         overlay[Noverlay].y = peak->y;
    256         overlay[Noverlay].dx = 1.0;
    257         overlay[Noverlay].dy = 1.0;
    258         overlay[Noverlay].angle = 0.0;
    259         overlay[Noverlay].text = NULL;
    260         Noverlay ++;
    261 
    262         overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
    263         overlay[Noverlay].x = peak->xf;
    264         overlay[Noverlay].y = peak->yf;
    265         overlay[Noverlay].dx = 2.0;
    266         overlay[Noverlay].dy = 2.0;
    267         overlay[Noverlay].angle = 0.0;
    268         overlay[Noverlay].text = NULL;
    269         Noverlay ++;
    270 # endif
    271     }
    272 
    273 # if (0)
    274     overlay[Noverlay].type = KII_OVERLAY_BOX;
    275     overlay[Noverlay].x = 10.0;
    276     overlay[Noverlay].y = 10.0;
    277     overlay[Noverlay].dx = 0.5;
    278     overlay[Noverlay].dy = 0.5;
    279     overlay[Noverlay].angle = 0.0;
    280     overlay[Noverlay].text = NULL;
    281     Noverlay ++;
    282 # endif
     263    }
    283264
    284265    KiiLoadOverlay (kapa, overlay, Noverlay, "red");
    285266    FREE (overlay);
    286267
    287     // pause and wait for user input:
    288     // continue, save (provide name), ??
    289     char key[10];
    290     fprintf (stdout, "[c]ontinue? ");
    291     if (!fgets(key, 8, stdin)) {
    292         psWarning("Unable to read option");
    293     }
     268    pmVisualAskUser(NULL);
    294269    return true;
    295270}
     
    302277    if (!pmVisualIsVisual()) return true;
    303278
    304     if (kapa == -1) {
    305         fprintf (stderr, "kapa not opened, skipping\n");
    306         return false;
    307     }
     279    int kapa = psphotKapaChannel (1);
     280    if (kapa == -1) return false;
    308281
    309282    psArray *footprints = detections->footprints;
     
    325298
    326299        // draw the top
     300        // XXX need to allow top (and bottom) to have more than one span
    327301        span = footprint->spans->data[0];
    328302        overlay[Noverlay].type = KII_OVERLAY_LINE;
     
    399373    FREE (overlay);
    400374
    401     // pause and wait for user input:
    402     // continue, save (provide name), ??
    403     char key[10];
    404     fprintf (stdout, "[c]ontinue? ");
    405     if (!fgets(key, 8, stdin)) {
    406         psWarning("Unable to read option");
    407     }
     375    pmVisualAskUser(NULL);
    408376    return true;
    409377}
     
    419387    if (!pmVisualIsVisual()) return true;
    420388
    421     if (kapa == -1) {
    422         fprintf (stderr, "kapa not opened, skipping\n");
    423         return false;
    424     }
     389    int kapa = psphotKapaChannel (1);
     390    if (kapa == -1) return false;
     391
     392    // XXX mark the different source classes with different color/shape dots
     393    // XXX are moments S/N and peak S/N consistent?
    425394
    426395    // note: this uses the Ohana allocation tools:
     
    448417        overlay[Noverlay].dx = 2.0*axes.major;
    449418        overlay[Noverlay].dy = 2.0*axes.minor;
    450         overlay[Noverlay].angle = -axes.theta * PS_DEG_RAD;  // XXXXXXXX the axes angle is negative to display of object on kapa
     419
     420        overlay[Noverlay].angle = axes.theta * PS_DEG_RAD;
     421
    451422        overlay[Noverlay].text = NULL;
    452423        Noverlay ++;
     
    456427    FREE (overlay);
    457428
    458     // pause and wait for user input:
    459     // continue, save (provide name), ??
    460     char key[10];
    461     fprintf (stdout, "[c]ontinue? ");
    462     if (!fgets(key, 8, stdin)) {
    463         psWarning("Unable to read option");
    464     }
    465 
    466     return true;
    467 }
    468 
    469 bool psphotVisualPlotMoments (psMetadata *recipe, psArray *sources) {
     429    pmVisualAskUser(NULL);
     430    return true;
     431}
     432
     433bool psphotVisualPlotMoments (psMetadata *recipe, psMetadata *analysis, psArray *sources) {
    470434
    471435    bool status;
     
    475439    if (!pmVisualIsVisual()) return true;
    476440
    477     if (kapa3 == -1) {
    478         kapa3 = KapaOpenNamedSocket ("kapa", "psphot:plots");
    479         if (kapa3 == -1) {
    480             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    481             pmVisualSetVisual(false);
    482             return false;
    483         }
    484     }
    485 
    486     KapaClearPlots (kapa3);
     441    int myKapa = psphotKapaChannel (2);
     442    if (myKapa == -1) return false;
     443
     444    KapaClearPlots (myKapa);
    487445    KapaInitGraph (&graphdata);
    488     KapaSetFont (kapa3, "courier", 14);
     446    KapaSetFont (myKapa, "courier", 14);
     447
     448    section.bg = KapaColorByName ("none"); // XXX probably should be 'none'
    489449
    490450    float SN_LIM = psMetadataLookupF32(&status, recipe, "PSF_SN_LIM");
    491451
    492452    // select the max psfX,Y values for the plot limits
    493     float Xmin = 0.0, Xmax = 0.0;
    494     float Ymin = 0.0, Ymax = 0.0;
     453    float Xmin = 1000.0, Xmax = 0.0;
     454    float Ymin = 1000.0, Ymax = 0.0;
    495455    {
    496         int nRegions = psMetadataLookupS32 (&status, recipe, "PSF.CLUMP.NREGIONS");
     456        int nRegions = psMetadataLookupS32 (&status, analysis, "PSF.CLUMP.NREGIONS");
    497457        for (int n = 0; n < nRegions; n++) {
    498458
    499459            char regionName[64];
    500460            snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", n);
    501             psMetadata *regionMD = psMetadataLookupPtr (&status, recipe, regionName);
    502 
    503             float psfX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");
     461            psMetadata *regionMD = psMetadataLookupPtr (&status, analysis, regionName);
     462
     463            float psfX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");
    504464            float psfY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y");
    505465            float psfdX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX");
    506466            float psfdY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY");
    507467
    508             float X0 = psfX - 4.0*psfdX;
    509             float X1 = psfX + 4.0*psfdX;
    510             float Y0 = psfY - 4.0*psfdY;
    511             float Y1 = psfY + 4.0*psfdY;
    512 
    513             if (isfinite(X0)) { Xmin = PS_MAX(Xmin, X0); }
    514             if (isfinite(X1)) { Xmax = PS_MAX(Xmax, X1); }
    515             if (isfinite(Y0)) { Ymin = PS_MAX(Ymin, Y0); }
    516             if (isfinite(Y1)) { Ymax = PS_MAX(Ymax, Y1); }
    517         }
    518     }
     468            float X0 = psfX - 4.0*psfdX;
     469            float X1 = psfX + 4.0*psfdX;
     470            float Y0 = psfY - 4.0*psfdY;
     471            float Y1 = psfY + 4.0*psfdY;
     472
     473            if (isfinite(X0)) { Xmin = PS_MIN(Xmin, X0); }
     474            if (isfinite(X1)) { Xmax = PS_MAX(Xmax, X1); }
     475            if (isfinite(Y0)) { Ymin = PS_MIN(Ymin, Y0); }
     476            if (isfinite(Y1)) { Ymax = PS_MAX(Ymax, Y1); }
     477        }
     478    }
     479    Xmin = PS_MAX(Xmin, -0.1);
     480    Ymin = PS_MAX(Ymin, -0.1);
     481
     482    // XXX test: hardwire plot limits
     483    // Xmin = -0.1; Ymin = -0.1;
     484    // Xmax = 20.1; Ymax = 20.1;
    519485
    520486    // storage vectors for data to be plotted
     
    564530    section.y  = 0.00;
    565531    section.name = psStringCopy ("MxxMyy");
    566     KapaSetSection (kapa3, &section);
     532    KapaSetSection (myKapa, &section);
    567533    psFree (section.name);
    568534
     
    572538    graphdata.xmax = Xmax;
    573539    graphdata.ymax = Ymax;
    574     KapaSetLimits (kapa3, &graphdata);
    575 
    576     KapaBox (kapa3, &graphdata);
    577     KapaSendLabel (kapa3, "M_xx| (pixels)", KAPA_LABEL_XM);
    578     KapaSendLabel (kapa3, "M_yy| (pixels)", KAPA_LABEL_YM);
     540    KapaSetLimits (myKapa, &graphdata);
     541
     542    graphdata.padXm = NAN;
     543    graphdata.padYm = NAN;
     544    graphdata.padXp = 0.5;
     545    graphdata.padYp = 0.5;
     546    KapaBox (myKapa, &graphdata);
     547
     548    KapaSendLabel (myKapa, "M_xx| (pixels)", KAPA_LABEL_XM);
     549    KapaSendLabel (myKapa, "M_yy| (pixels)", KAPA_LABEL_YM);
    579550
    580551    graphdata.color = KapaColorByName ("black");
     
    582553    graphdata.size = 0.3;
    583554    graphdata.style = 2;
    584     KapaPrepPlot (kapa3, nF, &graphdata);
    585     KapaPlotVector (kapa3, nF, xFaint->data.F32, "x");
    586     KapaPlotVector (kapa3, nF, yFaint->data.F32, "y");
     555    KapaPrepPlot (myKapa, nF, &graphdata);
     556
     557    KapaPlotVector (myKapa, nF, xFaint->data.F32, "x");
     558    KapaPlotVector (myKapa, nF, yFaint->data.F32, "y");
    587559
    588560    graphdata.color = KapaColorByName ("red");
     
    590562    graphdata.size = 0.5;
    591563    graphdata.style = 2;
    592     KapaPrepPlot (kapa3, nB, &graphdata);
    593     KapaPlotVector (kapa3, nB, xBright->data.F32, "x");
    594     KapaPlotVector (kapa3, nB, yBright->data.F32, "y");
     564    KapaPrepPlot (myKapa, nB, &graphdata);
     565    KapaPlotVector (myKapa, nB, xBright->data.F32, "x");
     566    KapaPlotVector (myKapa, nB, yBright->data.F32, "y");
    595567
    596568    // second section: MagMyy
     
    598570    section.dy = 0.25;
    599571    section.x  = 0.00;
    600     section.y  = 0.80;
     572    section.y  = 0.75;
    601573    section.name = psStringCopy ("MagMyy");
    602     KapaSetSection (kapa3, &section);
     574    KapaSetSection (myKapa, &section);
    603575    psFree (section.name);
    604576
     
    608580    graphdata.ymin = Ymin;
    609581    graphdata.ymax = Ymax;
    610     KapaSetLimits (kapa3, &graphdata);
    611 
     582    KapaSetLimits (myKapa, &graphdata);
     583
     584    graphdata.padXm = 0.5;
     585    graphdata.padYm = NAN;
     586    graphdata.padXp = NAN;
     587    graphdata.padYp = 0.5;
    612588    strcpy (graphdata.labels, "0210");
    613     KapaBox (kapa3, &graphdata);
    614     KapaSendLabel (kapa3, "inst mag", KAPA_LABEL_XP);
    615     KapaSendLabel (kapa3, "M_yy| (pixels)", KAPA_LABEL_YM);
     589    KapaBox (myKapa, &graphdata);
     590    KapaSendLabel (myKapa, "inst mag", KAPA_LABEL_XP);
     591    KapaSendLabel (myKapa, "M_yy| (pixels)", KAPA_LABEL_YM);
    616592
    617593    graphdata.color = KapaColorByName ("black");
     
    619595    graphdata.size = 0.3;
    620596    graphdata.style = 2;
    621     KapaPrepPlot (kapa3, nF, &graphdata);
    622     KapaPlotVector (kapa3, nF, mFaint->data.F32, "x");
    623     KapaPlotVector (kapa3, nF, yFaint->data.F32, "y");
     597    KapaPrepPlot (myKapa, nF, &graphdata);
     598    KapaPlotVector (myKapa, nF, mFaint->data.F32, "x");
     599    KapaPlotVector (myKapa, nF, yFaint->data.F32, "y");
    624600
    625601    graphdata.color = KapaColorByName ("red");
     
    627603    graphdata.size = 0.5;
    628604    graphdata.style = 2;
    629     KapaPrepPlot (kapa3, nB, &graphdata);
    630     KapaPlotVector (kapa3, nB, mBright->data.F32, "x");
    631     KapaPlotVector (kapa3, nB, yBright->data.F32, "y");
     605    KapaPrepPlot (myKapa, nB, &graphdata);
     606    KapaPlotVector (myKapa, nB, mBright->data.F32, "x");
     607    KapaPlotVector (myKapa, nB, yBright->data.F32, "y");
    632608
    633609    // third section: MagMxx
    634610    section.dx = 0.25;
    635611    section.dy = 0.75;
    636     section.x  = 0.80;
     612    section.x  = 0.75;
    637613    section.y  = 0.00;
    638614    section.name = psStringCopy ("MagMxx");
    639     KapaSetSection (kapa3, &section);
     615    KapaSetSection (myKapa, &section);
    640616    psFree (section.name);
    641617
     
    645621    graphdata.ymin =  -7.9;
    646622    graphdata.ymax = -17.1;
    647     KapaSetLimits (kapa3, &graphdata);
    648 
     623    KapaSetLimits (myKapa, &graphdata);
     624
     625    graphdata.padXm = NAN;
     626    graphdata.padYm = 0.5;
     627    graphdata.padXp = 0.5;
     628    graphdata.padYp = NAN;
    649629    strcpy (graphdata.labels, "2001");
    650     KapaBox (kapa3, &graphdata);
    651     KapaSendLabel (kapa3, "M_xx| (pixels)", KAPA_LABEL_XM);
    652     KapaSendLabel (kapa3, "inst mag", KAPA_LABEL_YP);
     630    KapaBox (myKapa, &graphdata);
     631    KapaSendLabel (myKapa, "M_xx| (pixels)", KAPA_LABEL_XM);
     632    KapaSendLabel (myKapa, "inst mag", KAPA_LABEL_YP);
    653633
    654634    graphdata.color = KapaColorByName ("black");
     
    656636    graphdata.size = 0.3;
    657637    graphdata.style = 2;
    658     KapaPrepPlot (kapa3, nF, &graphdata);
    659     KapaPlotVector (kapa3, nF, xFaint->data.F32, "x");
    660     KapaPlotVector (kapa3, nF, mFaint->data.F32, "y");
     638    KapaPrepPlot (myKapa, nF, &graphdata);
     639    KapaPlotVector (myKapa, nF, xFaint->data.F32, "x");
     640    KapaPlotVector (myKapa, nF, mFaint->data.F32, "y");
    661641
    662642    graphdata.color = KapaColorByName ("red");
     
    664644    graphdata.size = 0.5;
    665645    graphdata.style = 2;
    666     KapaPrepPlot (kapa3, nB, &graphdata);
    667     KapaPlotVector (kapa3, nB, xBright->data.F32, "x");
    668     KapaPlotVector (kapa3, nB, mBright->data.F32, "y");
     646    KapaPrepPlot (myKapa, nB, &graphdata);
     647    KapaPlotVector (myKapa, nB, xBright->data.F32, "x");
     648    KapaPlotVector (myKapa, nB, mBright->data.F32, "y");
    669649
    670650    // draw N circles to outline the clumps
    671651    {
    672         KapaSelectSection (kapa3, "MxxMyy");
     652        KapaSelectSection (myKapa, "MxxMyy");
    673653
    674654        // draw a circle centered on psfX,Y with size of the psf limit
     
    676656        psVector *yLimit  = psVectorAlloc (120, PS_TYPE_F32);
    677657
    678         int nRegions = psMetadataLookupS32 (&status, recipe, "PSF.CLUMP.NREGIONS");
     658        int nRegions = psMetadataLookupS32 (&status, analysis, "PSF.CLUMP.NREGIONS");
    679659        float PSF_CLUMP_NSIGMA = psMetadataLookupF32 (&status, recipe, "PSF_CLUMP_NSIGMA");
    680660
     
    682662        graphdata.style = 0;
    683663
    684         graphdata.xmin = Xmin;
    685         graphdata.ymin = Ymin;
    686         graphdata.xmax = Xmax;
    687         graphdata.ymax = Ymax;
    688         KapaSetLimits (kapa3, &graphdata);
     664        graphdata.xmin = Xmin;
     665        graphdata.ymin = Ymin;
     666        graphdata.xmax = Xmax;
     667        graphdata.ymax = Ymax;
     668        KapaSetLimits (myKapa, &graphdata);
    689669
    690670        for (int n = 0; n < nRegions; n++) {
     
    692672            char regionName[64];
    693673            snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", n);
    694             psMetadata *regionMD = psMetadataLookupPtr (&status, recipe, regionName);
     674            psMetadata *regionMD = psMetadataLookupPtr (&status, analysis, regionName);
    695675
    696676            float psfX  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");
     
    705685                yLimit->data.F32[i] = Ry*sin(i*2.0*M_PI/120.0) + psfY;
    706686            }
    707             KapaPrepPlot (kapa3, xLimit->n, &graphdata);
    708             KapaPlotVector (kapa3, xLimit->n, xLimit->data.F32, "x");
    709             KapaPlotVector (kapa3, yLimit->n, yLimit->data.F32, "y");
     687            KapaPrepPlot (myKapa, xLimit->n, &graphdata);
     688            KapaPlotVector (myKapa, xLimit->n, xLimit->data.F32, "x");
     689            KapaPlotVector (myKapa, yLimit->n, yLimit->data.F32, "y");
    710690        }
    711691        psFree (xLimit);
    712692        psFree (yLimit);
    713693    }
    714 
    715 # if (0)
    716     // *** make a histogram of the source counts in the x and y directions
    717     psHistogram *nX = psHistogramAlloc (graphdata.xmin, graphdata.xmax, 50.0);
    718     psHistogram *nY = psHistogramAlloc (graphdata.ymin, graphdata.ymax, 50.0);
    719     psVectorHistogram (nX, xFaint, NULL, NULL, 0);
    720     psVectorHistogram (nY, yFaint, NULL, NULL, 0);
    721     psVector *dX = psVectorAlloc (nX->nums->n, PS_TYPE_F32);
    722     psVector *vX = psVectorAlloc (nX->nums->n, PS_TYPE_F32);
    723     psVector *dY = psVectorAlloc (nY->nums->n, PS_TYPE_F32);
    724     psVector *vY = psVectorAlloc (nY->nums->n, PS_TYPE_F32);
    725     for (int i = 0; i < nX->nums->n; i++) {
    726         dX->data.F32[i] = nX->nums->data.S32[i];
    727         vX->data.F32[i] = 0.5*(nX->bounds->data.F32[i] + nX->bounds->data.F32[i+1]);
    728     }
    729     for (int i = 0; i < nY->nums->n; i++) {
    730         dY->data.F32[i] = nY->nums->data.S32[i];
    731         vY->data.F32[i] = 0.5*(nY->bounds->data.F32[i] + nY->bounds->data.F32[i+1]);
    732     }
    733 
    734     graphdata.color = KapaColorByName ("black");
    735     graphdata.ptype = 0;
    736     graphdata.size = 0.0;
    737     graphdata.style = 0;
    738     KapaPrepPlot (kapa3, dX->n, &graphdata);
    739     KapaPlotVector (kapa3, dX->n, dX->data.F32, "x");
    740     KapaPlotVector (kapa3, vX->n, vX->data.F32, "y");
    741 
    742     psFree (nX);
    743     psFree (dX);
    744     psFree (vX);
    745 
    746     psFree (nY);
    747     psFree (dY);
    748     psFree (vY);
    749 # endif
    750694
    751695    psFree (xBright);
     
    756700    psFree (mFaint);
    757701
    758     // pause and wait for user input:
    759     // continue, save (provide name), ??
    760     char key[10];
    761     fprintf (stdout, "[c]ontinue? ");
    762     if (!fgets(key, 8, stdin)) {
    763         psWarning("Unable to read option");
    764     }
     702    pmVisualAskUser(NULL);
    765703    return true;
    766704}
    767705
    768706// assumes 'kapa' value is checked and set
    769 bool psphotVisualShowRoughClass_Single (psArray *sources, pmSourceType type, pmSourceMode mode, char *color) {
     707bool psphotVisualShowRoughClass_Single (int myKapa, psArray *sources, pmSourceType type, pmSourceMode mode, char *color) {
    770708
    771709    int Noverlay;
     
    802740        overlay[Noverlay].dx = 2.0*axes.major;
    803741        overlay[Noverlay].dy = 2.0*axes.minor;
    804         overlay[Noverlay].angle = -axes.theta * PS_DEG_RAD;
     742        overlay[Noverlay].angle = axes.theta * PS_DEG_RAD;
    805743        overlay[Noverlay].text = NULL;
    806744        Noverlay ++;
    807745    }
    808746
    809     KiiLoadOverlay (kapa, overlay, Noverlay, color);
     747    KiiLoadOverlay (myKapa, overlay, Noverlay, color);
    810748    FREE (overlay);
    811749
     
    817755    if (!pmVisualIsVisual()) return true;
    818756
    819     if (kapa == -1) {
    820         fprintf (stderr, "kapa not opened, skipping\n");
    821         return false;
    822     }
    823 
    824     KiiEraseOverlay (kapa, "yellow"); // moments
    825 
    826     psphotVisualShowRoughClass_Single (sources, PM_SOURCE_TYPE_STAR, 0, "red");
    827     psphotVisualShowRoughClass_Single (sources, PM_SOURCE_TYPE_EXTENDED, 0, "blue");
    828     psphotVisualShowRoughClass_Single (sources, PM_SOURCE_TYPE_DEFECT, 0, "blue");
    829     psphotVisualShowRoughClass_Single (sources, PM_SOURCE_TYPE_SATURATED, 0, "red");
    830     psphotVisualShowRoughClass_Single (sources, PM_SOURCE_TYPE_STAR, PM_SOURCE_MODE_PSFSTAR, "yellow");
    831     psphotVisualShowRoughClass_Single (sources, PM_SOURCE_TYPE_STAR, PM_SOURCE_MODE_SATSTAR, "green");
    832 
    833     // pause and wait for user input:
    834     // continue, save (provide name), ??
    835     char key[10];
     757    int myKapa = psphotKapaChannel (1);
     758    if (myKapa == -1) return false;
     759
     760    KiiEraseOverlay (myKapa, "yellow"); // moments
     761
     762    psphotVisualShowRoughClass_Single (myKapa, sources, PM_SOURCE_TYPE_STAR, 0, "red");
     763    psphotVisualShowRoughClass_Single (myKapa, sources, PM_SOURCE_TYPE_EXTENDED, 0, "blue");
     764    psphotVisualShowRoughClass_Single (myKapa, sources, PM_SOURCE_TYPE_DEFECT, 0, "blue");
     765    psphotVisualShowRoughClass_Single (myKapa, sources, PM_SOURCE_TYPE_SATURATED, 0, "red");
     766    psphotVisualShowRoughClass_Single (myKapa, sources, PM_SOURCE_TYPE_STAR, PM_SOURCE_MODE_PSFSTAR, "yellow");
     767    psphotVisualShowRoughClass_Single (myKapa, sources, PM_SOURCE_TYPE_STAR, PM_SOURCE_MODE_SATSTAR, "green");
     768
    836769    fprintf (stdout, "red: STAR or SAT AREA; blue: EXTENDED or DEFECT; green: SATSTAR; yellow: PSFSTAR\n");
    837     fprintf (stdout, "[c]ontinue? ");
    838     if (!fgets(key, 8, stdin)) {
    839         psWarning("Unable to read option");
    840     }
     770    pmVisualAskUser(NULL);
    841771    return true;
    842772}
     
    846776    if (!pmVisualIsVisual()) return true;
    847777
    848     if (kapa2 == -1) {
    849         kapa2 = KapaOpenNamedSocket ("kapa", "psphot:psfstars");
    850         if (kapa2 == -1) {
    851             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    852             pmVisualSetVisual(false);
    853             return false;
    854         }
    855     }
     778    int myKapa = psphotKapaChannel (3);
     779    if (myKapa == -1) return false;
    856780
    857781    int DX = 64;
     
    898822
    899823    psImage *psfLogFlux = (psImage *) psUnaryOp (NULL, psfMosaic, "log");
    900     psphotVisualRangeImage (kapa2, psfLogFlux, "psf_mosaic",    0, -2.0, 3.0);
    901     psphotVisualRangeImage (kapa2, funMosaic, "psf_analytical", 1, -10.0, 100.0);
    902     psphotVisualRangeImage (kapa2, resMosaic, "psf_residual",   2, -10.0, 100.0);
     824    psphotVisualRangeImage (myKapa, psfLogFlux, "psf_mosaic",    0, -2.0, 3.0);
     825    psphotVisualRangeImage (myKapa, funMosaic, "psf_analytical", 1, -10.0, 100.0);
     826    psphotVisualRangeImage (myKapa, resMosaic, "psf_residual",   2, -10.0, 100.0);
    903827
    904828    psFree (psfMosaic);
     
    908832    psFree (modelRef);
    909833
    910     // pause and wait for user input:
    911     // continue, save (provide name), ??
    912     char key[10];
    913     fprintf (stdout, "[c]ontinue? ");
    914     if (!fgets(key, 8, stdin)) {
    915         psWarning("Unable to read option");
    916     }
     834    pmVisualAskUser(NULL);
    917835    return true;
    918836}
     
    924842    if (!pmVisualIsVisual()) return true;
    925843
    926     if (kapa2 == -1) {
    927         kapa2 = KapaOpenNamedSocket ("kapa", "psphot:psfstars");
    928         if (kapa2 == -1) {
    929             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    930             pmVisualSetVisual(false);
    931             return false;
    932         }
    933     }
     844    int myKapa = psphotKapaChannel (3);
     845    if (myKapa == -1) return false;
    934846
    935847    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
     
    1017929            if (Xo == 0) {
    1018930                // place source alone on this row
    1019                 psphotAddWithTest (source, true, maskVal); // replace source if subtracted
     931                bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     932                if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    1020933                psphotMosaicSubimage (outpos, source, Xo, Yo, DX, DY, true);
    1021934
    1022                 psphotSubWithTest (source, false, maskVal); // remove source (force)
     935                pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    1023936                psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
    1024                 psphotSetState (source, false, maskVal); // reset source Add/Sub state to recorded
     937
     938                if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    1025939
    1026940                Yo += DY;
     
    1032946                Xo = 0;
    1033947
    1034                 psphotAddWithTest (source, true, maskVal); // replace source if subtracted
     948                bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     949                if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    1035950                psphotMosaicSubimage (outpos, source, Xo, Yo, DX, DY, true);
    1036951
    1037                 psphotSubWithTest (source, false, maskVal); // remove source (force)
     952                pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    1038953                psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
    1039                 psphotSetState (source, false, maskVal); // replace source (has been subtracted)
     954
     955                if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    1040956
    1041957                Xo = DX;
     
    1044960        } else {
    1045961            // extend this row
    1046             psphotAddWithTest (source, true, maskVal); // replace source if subtracted
     962            bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     963            if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    1047964            psphotMosaicSubimage (outpos, source, Xo, Yo, DX, DY, true);
    1048965
    1049             psphotSubWithTest (source, false, maskVal); // remove source (force)
     966            pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    1050967            psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
    1051             psphotSetState (source, false, maskVal); // replace source (has been subtracted)
     968            if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    1052969
    1053970            Xo += DX;
     
    1056973    }
    1057974
    1058     psphotVisualRangeImage (kapa2, outpos, "psfpos", 0, -0.05, 0.95);
    1059     psphotVisualRangeImage (kapa2, outsub, "psfsub", 1, -0.05, 0.95);
    1060 
    1061     // pause and wait for user input:
    1062     // continue, save (provide name), ??
    1063     char key[10];
    1064     fprintf (stdout, "[c]ontinue? ");
    1065     if (!fgets(key, 8, stdin)) {
    1066         psWarning("Unable to read option");
    1067     }
    1068 
     975    psphotVisualRangeImage (myKapa, outpos, "psfpos", 0, -0.05, 0.95);
     976    psphotVisualRangeImage (myKapa, outsub, "psfsub", 1, -0.05, 0.95);
     977
     978    pmVisualAskUser(NULL);
    1069979    psFree (outpos);
    1070980    psFree (outsub);
     
    1084994    if (!pmVisualIsVisual()) return true;
    1085995
    1086     if (kapa2 == -1) {
    1087         kapa2 = KapaOpenNamedSocket ("kapa", "psphot:images");
    1088         if (kapa2 == -1) {
    1089             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    1090             pmVisualSetVisual(false);
    1091             return false;
    1092         }
    1093     }
     996    int myKapa = psphotKapaChannel (3);
     997    if (myKapa == -1) return false;
    1094998
    1095999    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
     
    11191023        pmSource *source = sources->data[i];
    11201024
    1121         bool keep = false;
    1122         keep |= (source->mode & PM_SOURCE_MODE_SATSTAR);
    1123         if (!keep) continue;
     1025        // only show "real" saturated stars (not defects)
     1026        if (!(source->mode & PM_SOURCE_MODE_SATSTAR)) continue;;
     1027        if (source->mode & PM_SOURCE_MODE_DEFECT) continue;;
    11241028
    11251029        // how does this subimage get placed into the output image?
     
    11641068        pmSource *source = sources->data[i];
    11651069
    1166         bool keep = false;
    1167         if (source->mode & PM_SOURCE_MODE_SATSTAR) {
    1168             nSAT ++;
    1169             keep = true;
    1170         }
    1171         if (!keep) continue;
     1070        // only show "real" saturated stars (not defects)
     1071        if (!(source->mode & PM_SOURCE_MODE_SATSTAR)) continue;;
     1072        if (source->mode & PM_SOURCE_MODE_DEFECT) continue;;
     1073        nSAT ++;
    11721074
    11731075        if (Xo + DX > NX) {
     
    11751077            if (Xo == 0) {
    11761078                // place source alone on this row
    1177                 psphotAddWithTest (source, true, maskVal); // replace source if subtracted
     1079                bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     1080                if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    11781081                psphotMosaicSubimage (outsat, source, Xo, Yo, DX, DY, false);
    1179                 psphotSetState (source, true, maskVal); // reset source Add/Sub state to recorded
     1082                if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    11801083
    11811084                Yo += DY;
     
    11861089                Yo += dY;
    11871090                Xo = 0;
    1188                 psphotAddWithTest (source, true, maskVal); // replace source if subtracted
     1091
     1092                bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     1093                if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    11891094                psphotMosaicSubimage (outsat, source, Xo, Yo, DX, DY, false);
    1190                 psphotSetState (source, true, maskVal); // replace source (has been subtracted)
     1095                if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    11911096
    11921097                Xo = DX;
     
    11951100        } else {
    11961101            // extend this row
    1197             psphotAddWithTest (source, true, maskVal); // replace source if subtracted
     1102            bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     1103            if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    11981104            psphotMosaicSubimage (outsat, source, Xo, Yo, DX, DY, false);
    1199             psphotSetState (source, true, maskVal); // replace source (has been subtracted)
     1105            if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    12001106
    12011107            Xo += DX;
     
    12041110    }
    12051111
    1206     psphotVisualScaleImage (kapa2, outsat, "satstar", 2);
    1207 
    1208     // pause and wait for user input:
    1209     // continue, save (provide name), ??
    1210     char key[10];
    1211     fprintf (stdout, "[c]ontinue? ");
    1212     if (!fgets(key, 8, stdin)) {
    1213         psWarning("Unable to read option");
    1214     }
    1215 
     1112    psphotVisualScaleImage (myKapa, outsat, NULL, "satstar", 2);
     1113
     1114    pmVisualAskUser(NULL);
    12161115    psFree (outsat);
    12171116    return true;
    12181117}
    12191118
     1119static void plotline (int myKapa, Graphdata *graphdata, float x0, float y0, float x1, float y1)
     1120{
     1121    float x[2], y[2];
     1122    x[0] = x0;
     1123    x[1] = x1;
     1124    y[0] = y0;
     1125    y[1] = y1;
     1126    KapaPrepPlot   (myKapa, 2, graphdata);
     1127    KapaPlotVector (myKapa, 2, x, "x");
     1128    KapaPlotVector (myKapa, 2, y, "y");
     1129}
     1130
    12201131bool psphotVisualPlotRadialProfile (int myKapa, pmSource *source, psImageMaskType maskVal) {
    12211132
    12221133    Graphdata graphdata;
    12231134
    1224     bool state = !(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
    1225     psphotAddWithTest (source, true, maskVal); // replace source if subtracted
     1135    bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
     1136    if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    12261137
    12271138    int nPts = source->pixels->numRows * source->pixels->numCols;
     
    12401151        for (int ix = 0; ix < source->pixels->numCols; ix++) {
    12411152            if (source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix]) {
    1242                 // rb->data.F32[nb] = hypot (ix + 0.5 - Xo, iy + 0.5 - Yo) ;
    1243                 rb->data.F32[nb] = hypot (ix - Xo, iy - Yo) ;
     1153                rb->data.F32[nb] = hypot (ix + 0.5 - Xo, iy + 0.5 - Yo) ;
     1154                // rb->data.F32[nb] = hypot (ix - Xo, iy - Yo) ;
    12441155                Rb->data.F32[nb] = log10(rb->data.F32[nb]);
    12451156                fb->data.F32[nb] = log10(source->pixels->data.F32[iy][ix]);
    12461157                nb++;
    12471158            } else {
    1248                 // rg->data.F32[ng] = hypot (ix + 0.5 - Xo, iy + 0.5 - Yo) ;
    1249                 rg->data.F32[ng] = hypot (ix - Xo, iy - Yo) ;
     1159                rg->data.F32[ng] = hypot (ix + 0.5 - Xo, iy + 0.5 - Yo) ;
     1160                // rg->data.F32[ng] = hypot (ix - Xo, iy - Yo) ;
    12501161                Rg->data.F32[ng] = log10(rg->data.F32[ng]);
    12511162                fg->data.F32[ng] = log10(source->pixels->data.F32[iy][ix]);
     
    12551166    }
    12561167
     1168    // generate model profiles (major and minor axis):
     1169    // create a model with theta = 0.0 so major and minor axes are equiv to x and y:
     1170    psEllipseShape rawShape, rotShape;
     1171
     1172    rawShape.sx  = source->modelPSF->params->data.F32[PM_PAR_SXX] / M_SQRT2;
     1173    rawShape.sy  = source->modelPSF->params->data.F32[PM_PAR_SYY] / M_SQRT2;
     1174    rawShape.sxy = source->modelPSF->params->data.F32[PM_PAR_SXY];
     1175
     1176    psEllipseAxes axes = psEllipseShapeToAxes (rawShape, 20.0);
     1177
     1178    axes.theta = 0.0;
     1179
     1180    rotShape = psEllipseAxesToShape (axes);
     1181
     1182    psVector *params = psVectorAlloc(source->modelPSF->params->n, PS_TYPE_F32);
     1183    for (int i = 0; i < source->modelPSF->params->n; i++) {
     1184        params->data.F32[i] = source->modelPSF->params->data.F32[i];
     1185    }
     1186    params->data.F32[PM_PAR_SXX] = rotShape.sx * M_SQRT2;
     1187    params->data.F32[PM_PAR_SYY] = rotShape.sy * M_SQRT2;
     1188    params->data.F32[PM_PAR_SXY] = rotShape.sxy;
     1189    params->data.F32[PM_PAR_XPOS] = 0.0;
     1190    params->data.F32[PM_PAR_YPOS] = 0.0;
     1191
     1192    psVector *rmod = psVectorAlloc(300, PS_TYPE_F32);
     1193    psVector *fmaj = psVectorAlloc(300, PS_TYPE_F32);
     1194    psVector *fmin = psVectorAlloc(300, PS_TYPE_F32);
     1195
     1196    psVector *coord = psVectorAlloc(2, PS_TYPE_F32);
     1197
     1198    float r = 0.0;
     1199    for (int i = 0; i < rmod->n; i++) {
     1200        r = i*0.1;
     1201        rmod->data.F32[i] = r;
     1202
     1203        coord->data.F32[1] = r;
     1204        coord->data.F32[0] = 0.0;
     1205        fmaj->data.F32[i] = log10(source->modelPSF->modelFunc (NULL, params, coord));
     1206
     1207        coord->data.F32[0] = r;
     1208        coord->data.F32[1] = 0.0;
     1209        fmin->data.F32[i] = log10(source->modelPSF->modelFunc (NULL, params, coord));
     1210    }
     1211    psFree (coord);
     1212    psFree (params);
     1213
     1214    float FWHM_MAJOR = 2.0*source->modelPSF->modelRadius (source->modelPSF->params, 0.5*source->modelPSF->params->data.F32[PM_PAR_I0]);
     1215    float FWHM_MINOR = FWHM_MAJOR * (axes.minor / axes.major);
     1216    if (FWHM_MAJOR < FWHM_MINOR) PS_SWAP (FWHM_MAJOR, FWHM_MINOR);
     1217
     1218    psEllipseMoments emoments;
     1219    emoments.x2 = source->moments->Mxx;
     1220    emoments.xy = source->moments->Mxy;
     1221    emoments.y2 = source->moments->Myy;
     1222    axes = psEllipseMomentsToAxes (emoments, 20.0);
     1223    float MOMENTS_MAJOR = 2.355*axes.major;
     1224    float MOMENTS_MINOR = 2.355*axes.minor;
     1225
     1226    float logHM = log10(0.5*source->modelPSF->params->data.F32[PM_PAR_I0]);
     1227
    12571228    // reset source Add/Sub state to recorded
    1258     psphotSetState (source, state, maskVal);
     1229    if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
    12591230
    12601231    KapaInitGraph (&graphdata);
     
    12911262    KapaPlotVector (myKapa, nb, fb->data.F32, "y");
    12921263
     1264    graphdata.color = KapaColorByName ("blue");
     1265    graphdata.ptype = 0;
     1266    graphdata.size = 0.0;
     1267    graphdata.style = 0;
     1268    KapaPrepPlot   (myKapa, rmod->n, &graphdata);
     1269    KapaPlotVector (myKapa, rmod->n, rmod->data.F32, "x");
     1270    KapaPlotVector (myKapa, rmod->n, fmin->data.F32, "y");
     1271    plotline (myKapa, &graphdata, 0.0, logHM, 30.0, logHM);
     1272    plotline (myKapa, &graphdata, 0.5*FWHM_MINOR, 0.0, 0.5*FWHM_MINOR, 5.0);
     1273    graphdata.ltype = 1;
     1274    plotline (myKapa, &graphdata, 0.5*MOMENTS_MINOR, 0.0, 0.5*MOMENTS_MINOR, 5.0);
     1275    graphdata.ltype = 0;
     1276       
     1277    graphdata.color = KapaColorByName ("green");
     1278    graphdata.ptype = 0;
     1279    graphdata.size = 0.0;
     1280    graphdata.style = 0;
     1281    KapaPrepPlot   (myKapa, rmod->n, &graphdata);
     1282    KapaPlotVector (myKapa, rmod->n, rmod->data.F32, "x");
     1283    KapaPlotVector (myKapa, rmod->n, fmaj->data.F32, "y");
     1284    plotline (myKapa, &graphdata, 0.5*FWHM_MAJOR, 0.0, 0.5*FWHM_MAJOR, 5.0);
     1285    graphdata.ltype = 1;
     1286    plotline (myKapa, &graphdata, 0.5*MOMENTS_MAJOR, 0.0, 0.5*MOMENTS_MAJOR, 5.0);
     1287    graphdata.ltype = 0;
     1288       
     1289    for (int i = 0; i < rmod->n; i++) {
     1290        rmod->data.F32[i] = log10(rmod->data.F32[i]);
     1291    }
     1292
    12931293    // ** loglog **
    12941294    KapaSelectSection (myKapa, "loglog");
     
    12991299    graphdata.ymin = -0.05;
    13001300    graphdata.ymax = +5.05;
     1301    graphdata.color = KapaColorByName ("black");
    13011302    KapaSetLimits (myKapa, &graphdata);
    13021303
     
    13211322    KapaPlotVector (myKapa, nb, Rb->data.F32, "x");
    13221323    KapaPlotVector (myKapa, nb, fb->data.F32, "y");
     1324
     1325    graphdata.color = KapaColorByName ("blue");
     1326    graphdata.ptype = 0;
     1327    graphdata.size = 0.0;
     1328    graphdata.style = 0;
     1329    KapaPrepPlot   (myKapa, rmod->n, &graphdata);
     1330    KapaPlotVector (myKapa, rmod->n, rmod->data.F32, "x");
     1331    KapaPlotVector (myKapa, rmod->n, fmin->data.F32, "y");
     1332
     1333    graphdata.color = KapaColorByName ("green");
     1334    graphdata.ptype = 0;
     1335    graphdata.size = 0.0;
     1336    graphdata.style = 0;
     1337    KapaPrepPlot   (myKapa, rmod->n, &graphdata);
     1338    KapaPlotVector (myKapa, rmod->n, rmod->data.F32, "x");
     1339    KapaPlotVector (myKapa, rmod->n, fmaj->data.F32, "y");
     1340
     1341    psFree (rmod);
     1342    psFree (fmin);
     1343    psFree (fmaj);
    13231344
    13241345    psFree (rg);
     
    13371358    if (!pmVisualIsVisual()) return true;
    13381359
    1339     if (kapa3 == -1) {
    1340         kapa3 = KapaOpenNamedSocket ("kapa", "psphot:plots");
    1341         if (kapa3 == -1) {
    1342             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    1343             pmVisualSetVisual(false);
    1344             return false;
    1345         }
    1346     }
     1360    int myKapa = psphotKapaChannel (2);
     1361    if (myKapa == -1) return false;
    13471362
    13481363    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
     
    13511366    assert (maskVal);
    13521367
    1353     KapaClearPlots (kapa3);
     1368    section.bg  = KapaColorByName ("none"); // XXX probably should be 'none'
     1369
     1370    KapaClearPlots (myKapa);
    13541371    // first section : mag vs CR nSigma
    13551372    section.dx = 1.0;
     
    13591376    section.name = NULL;
    13601377    psStringAppend (&section.name, "linlog");
    1361     KapaSetSection (kapa3, &section);
     1378    KapaSetSection (myKapa, &section);
    13621379    psFree (section.name);
    13631380
     
    13691386    section.name = NULL;
    13701387    psStringAppend (&section.name, "loglog");
    1371     KapaSetSection (kapa3, &section);
     1388    KapaSetSection (myKapa, &section);
    13721389    psFree (section.name);
    13731390
     
    13781395        if (!(source->mode & PM_SOURCE_MODE_PSFSTAR)) continue;
    13791396
    1380         psphotVisualPlotRadialProfile (kapa3, source, maskVal);
     1397        psphotVisualPlotRadialProfile (myKapa, source, maskVal);
    13811398
    13821399        // pause and wait for user input:
     
    13881405        }
    13891406        if (key[0] == 'e') {
    1390             KapaClearPlots (kapa3);
     1407            KapaClearPlots (myKapa);
    13911408        }
    13921409        if (key[0] == 's') {
     
    14071424    psEllipseAxes axes;
    14081425
     1426    // XXX skip this for now: it is not very clear
     1427    return true;
     1428
    14091429    if (!pmVisualIsVisual()) return true;
    14101430
    1411     if (kapa == -1) {
    1412         fprintf (stderr, "kapa not opened, skipping\n");
    1413         return false;
    1414     }
     1431    int myKapa = psphotKapaChannel (1);
     1432    if (myKapa == -1) return false;
    14151433
    14161434    // note: this uses the Ohana allocation tools:
     
    14851503    }
    14861504
    1487     KiiLoadOverlay (kapa, overlayE, NoverlayE, "red");
    1488     KiiLoadOverlay (kapa, overlayO, NoverlayO, "yellow");
     1505    KiiLoadOverlay (myKapa, overlayE, NoverlayE, "red");
     1506    KiiLoadOverlay (myKapa, overlayO, NoverlayO, "yellow");
    14891507    FREE (overlayE);
    14901508    FREE (overlayO);
    14911509
    1492     // pause and wait for user input:
    1493     // continue, save (provide name), ??
    1494     char key[10];
    14951510    fprintf (stdout, "even bits (0x0001, 0x0004, ... : red\n");
    14961511    fprintf (stdout, "odd bits (0x0002, 0x0008, ... : yellow\n");
    1497     fprintf (stdout, "[c]ontinue? ");
    1498     if (!fgets(key, 8, stdin)) {
    1499         psWarning("Unable to read option");
    1500     }
    1501 
    1502     return true;
    1503 }
    1504 
    1505 bool psphotVisualShowSourceSize (pmReadout *readout, psArray *sources) {
    1506 
    1507     int Noverlay, NOVERLAY;
     1512    pmVisualAskUser(NULL);
     1513
     1514    return true;
     1515}
     1516
     1517bool psphotVisualShowSourceSize_Single (int myKapa, psArray *sources, pmSourceMode mode, bool keep, float scale, char *color) {
     1518
     1519    int Noverlay;
    15081520    KiiOverlay *overlay;
    15091521
    1510     if (!pmVisualIsVisual()) return true;
    1511 
    1512     if (kapa == -1) {
    1513         fprintf (stderr, "kapa not opened, skipping\n");
    1514         return false;
    1515     }
     1522    psEllipseMoments emoments;
     1523    psEllipseAxes axes;
    15161524
    15171525    // note: this uses the Ohana allocation tools:
     1526    ALLOCATE (overlay, KiiOverlay, sources->n);
     1527
    15181528    Noverlay = 0;
    1519     NOVERLAY = 100;
    1520     ALLOCATE (overlay, KiiOverlay, sources->n);
    1521 
    1522     // mark CRs with red boxes
    15231529    for (int i = 0; i < sources->n; i++) {
    15241530
     
    15261532        if (source == NULL) continue;
    15271533
    1528         if (!(source->mode & PM_SOURCE_MODE_CR_LIMIT)) continue;
    1529 
    1530         overlay[Noverlay].type = KII_OVERLAY_BOX;
    1531         overlay[Noverlay].x = source->peak->xf;
    1532         overlay[Noverlay].y = source->peak->yf;
    1533 
    1534         overlay[Noverlay].dx = 4;
    1535         overlay[Noverlay].dy = 4;
    1536         overlay[Noverlay].angle = 0;
     1534        if (mode) {
     1535            if (keep) {
     1536                if (!(source->mode & mode)) continue;
     1537            } else {
     1538                if (source->mode & mode) continue;
     1539            }
     1540        }
     1541
     1542        pmMoments *moments = source->moments;
     1543        if (moments == NULL) continue;
     1544
     1545        overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
     1546        overlay[Noverlay].x = moments->Mx;
     1547        overlay[Noverlay].y = moments->My;
     1548
     1549        emoments.x2 = moments->Mxx;
     1550        emoments.y2 = moments->Myy;
     1551        emoments.xy = moments->Mxy;
     1552
     1553        axes = psEllipseMomentsToAxes (emoments, 20.0);
     1554
     1555        overlay[Noverlay].dx = scale*2.0*axes.major;
     1556        overlay[Noverlay].dy = scale*2.0*axes.minor;
     1557        overlay[Noverlay].angle = axes.theta * PS_DEG_RAD;
    15371558        overlay[Noverlay].text = NULL;
    15381559        Noverlay ++;
    1539         CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
    1540     }
    1541     KiiLoadOverlay (kapa, overlay, Noverlay, "red");
    1542 
    1543 
    1544     Noverlay = 0;
    1545     for (int i = 0; i < sources->n; i++) {
    1546 
    1547         pmSource *source = sources->data[i];
    1548         if (source == NULL) continue;
    1549 
    1550         // mark EXTs with yellow circles
    1551         if (!(source->mode & PM_SOURCE_MODE_EXT_LIMIT)) continue;
    1552 
    1553         overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
    1554         overlay[Noverlay].x = source->peak->xf;
    1555         overlay[Noverlay].y = source->peak->yf;
    1556 
    1557         overlay[Noverlay].dx = 10;
    1558         overlay[Noverlay].dy = 10;
    1559         overlay[Noverlay].angle = 0;
    1560         overlay[Noverlay].text = NULL;
    1561         Noverlay ++;
    1562         CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
    1563     }
    1564 
    1565     KiiLoadOverlay (kapa, overlay, Noverlay, "blue");
     1560    }
     1561
     1562    KiiLoadOverlay (myKapa, overlay, Noverlay, color);
    15661563    FREE (overlay);
    15671564
    1568     psphotVisualShowMask (kapa, readout->mask, "mask", 2);
    1569 
    1570     // pause and wait for user input:
    1571     // continue, save (provide name), ??
    1572     char key[10];
    1573     fprintf (stdout, "CR: 4pix red BOX; EXT: 10pix blue circle\n");
    1574     fprintf (stdout, "[c]ontinue? ");
    1575     if (!fgets(key, 8, stdin)) {
    1576         psWarning("Unable to read option");
    1577     }
    1578 
    1579     return true;
    1580 }
    1581 
    1582 bool psphotVisualPlotSourceSize (psArray *sources) {
    1583 
     1565    return true;
     1566}
     1567
     1568bool psphotVisualShowSourceSize (pmReadout *readout, psArray *sources) {
     1569
     1570    if (!pmVisualIsVisual()) return true;
     1571
     1572    int myKapa = psphotKapaChannel (1);
     1573    if (myKapa == -1) return false;
     1574
     1575    KiiEraseOverlay (myKapa, "red");
     1576    KiiEraseOverlay (myKapa, "blue");
     1577    KiiEraseOverlay (myKapa, "green");
     1578    KiiEraseOverlay (myKapa, "yellow");
     1579
     1580    psphotVisualShowSourceSize_Single (myKapa, sources, PM_SOURCE_MODE_EXT_LIMIT | PM_SOURCE_MODE_DEFECT | PM_SOURCE_MODE_CR_LIMIT | PM_SOURCE_MODE_SATSTAR, 0, 1.0, "green");
     1581    psphotVisualShowSourceSize_Single (myKapa, sources, PM_SOURCE_MODE_EXT_LIMIT, 1, 1.0, "blue");
     1582    psphotVisualShowSourceSize_Single (myKapa, sources, PM_SOURCE_MODE_CR_LIMIT, 1, 1.0, "red");
     1583    psphotVisualShowSourceSize_Single (myKapa, sources, PM_SOURCE_MODE_DEFECT, 1, 2.0, "red");
     1584    psphotVisualShowSourceSize_Single (myKapa, sources, PM_SOURCE_MODE_SATSTAR, 1, 1.0, "yellow");
     1585
     1586    fprintf (stdout, "red: CR; blue: EXTENDED; green: PSF-like; yellow: SATSTAR\n");
     1587    pmVisualAskUser(NULL);
     1588    return true;
     1589}
     1590
     1591bool psphotVisualPlotSourceSize (psMetadata *recipe, psMetadata *analysis, psArray *sources) {
     1592
     1593    bool status;
    15841594    Graphdata graphdata;
    15851595    KapaSection section;
     
    15871597    if (!pmVisualIsVisual()) return true;
    15881598
    1589     if (kapa3 == -1) {
    1590         kapa3 = KapaOpenNamedSocket ("kapa", "psphot:plots");
    1591         if (kapa3 == -1) {
    1592             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    1593             pmVisualSetVisual(false);
    1594             return false;
    1595         }
    1596     }
    1597 
    1598     KapaClearPlots (kapa3);
     1599    int myKapa = psphotKapaChannel (2);
     1600    if (myKapa == -1) return false;
     1601
     1602    KapaClearPlots (myKapa);
    15991603    KapaInitGraph (&graphdata);
    1600 
    1601     // first section : mag vs CR nSigma
    1602     section.dx = 1.0;
    1603     section.dy = 0.5;
    1604     section.x = 0.0;
    1605     section.y = 0.0;
    1606     section.name = NULL;
    1607     psStringAppend (&section.name, "a1");
    1608     KapaSetSection (kapa3, &section);
     1604    KapaSetFont (myKapa, "courier", 14);
     1605
     1606    section.bg  = KapaColorByName ("none"); // XXX probably should be 'none'
     1607
     1608    // select the max psfX,Y values for the plot limits
     1609    float Xmin = 1000.0, Xmax = 0.0;
     1610    float Ymin = 1000.0, Ymax = 0.0;
     1611    {
     1612        int nRegions = psMetadataLookupS32 (&status, analysis, "PSF.CLUMP.NREGIONS");
     1613        for (int n = 0; n < nRegions; n++) {
     1614
     1615            char regionName[64];
     1616            snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", n);
     1617            psMetadata *regionMD = psMetadataLookupPtr (&status, analysis, regionName);
     1618
     1619            float psfX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");
     1620            float psfY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y");
     1621            float psfdX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX");
     1622            float psfdY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY");
     1623
     1624            float X0 = psfX - 10.0*psfdX;
     1625            float X1 = psfX + 10.0*psfdX;
     1626            float Y0 = psfY - 10.0*psfdY;
     1627            float Y1 = psfY + 10.0*psfdY;
     1628
     1629            if (isfinite(X0)) { Xmin = PS_MIN(Xmin, X0); }
     1630            if (isfinite(X1)) { Xmax = PS_MAX(Xmax, X1); }
     1631            if (isfinite(Y0)) { Ymin = PS_MIN(Ymin, Y0); }
     1632            if (isfinite(Y1)) { Ymax = PS_MAX(Ymax, Y1); }
     1633        }
     1634    }
     1635    Xmin = PS_MAX(Xmin, -0.1);
     1636    Ymin = PS_MAX(Ymin, -0.1);
     1637
     1638    // storage vectors for data to be plotted
     1639    psVector *xSAT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1640    psVector *ySAT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1641    psVector *mSAT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1642    psVector *sSAT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1643
     1644    psVector *xPSF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1645    psVector *yPSF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1646    psVector *mPSF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1647    psVector *sPSF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1648
     1649    psVector *xEXT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1650    psVector *yEXT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1651    psVector *mEXT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1652    psVector *sEXT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1653
     1654    psVector *xDEF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1655    psVector *yDEF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1656    psVector *mDEF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1657    psVector *sDEF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1658
     1659    psVector *xLOW = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1660    psVector *yLOW = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1661    psVector *mLOW = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1662    psVector *sLOW = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1663
     1664    psVector *xCR = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1665    psVector *yCR = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1666    psVector *mCR = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1667    psVector *sCR = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     1668
     1669    // construct the vectors
     1670    int nSAT = 0;
     1671    int nEXT = 0;
     1672    int nPSF = 0;
     1673    int nDEF = 0;
     1674    int nLOW = 0;
     1675    int nCR  = 0;
     1676    for (int i = 0; i < sources->n; i++) {
     1677        pmSource *source = sources->data[i];
     1678        if (source->moments == NULL) continue;
     1679
     1680        // only plot the measured sources...
     1681        if (!(source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED)) continue;
     1682
     1683        if (source->mode & PM_SOURCE_MODE_CR_LIMIT) {
     1684            xCR->data.F32[nCR] = source->moments->Mxx;
     1685            yCR->data.F32[nCR] = source->moments->Myy;
     1686            mCR->data.F32[nCR] = -2.5*log10(source->moments->Sum);
     1687            sCR->data.F32[nCR] = source->extNsigma;
     1688            nCR++;
     1689        }
     1690        if (source->mode & PM_SOURCE_MODE_SATSTAR) {
     1691            xSAT->data.F32[nSAT] = source->moments->Mxx;
     1692            ySAT->data.F32[nSAT] = source->moments->Myy;
     1693            mSAT->data.F32[nSAT] = -2.5*log10(source->moments->Sum);
     1694            sSAT->data.F32[nSAT] = source->extNsigma;
     1695            nSAT++;
     1696        }
     1697        if (source->mode & PM_SOURCE_MODE_EXT_LIMIT) {
     1698            xEXT->data.F32[nEXT] = source->moments->Mxx;
     1699            yEXT->data.F32[nEXT] = source->moments->Myy;
     1700            mEXT->data.F32[nEXT] = -2.5*log10(source->moments->Sum);
     1701            sEXT->data.F32[nEXT] = source->extNsigma;
     1702            nEXT++;
     1703            continue;
     1704        }
     1705        if (source->mode & PM_SOURCE_MODE_DEFECT) {
     1706            xDEF->data.F32[nDEF] = source->moments->Mxx;
     1707            yDEF->data.F32[nDEF] = source->moments->Myy;
     1708            mDEF->data.F32[nDEF] = -2.5*log10(source->moments->Sum);
     1709            sDEF->data.F32[nDEF] = source->extNsigma;
     1710            nDEF++;
     1711            continue;
     1712        }
     1713        if (source->errMag > 0.1) {
     1714            xLOW->data.F32[nLOW] = source->moments->Mxx;
     1715            yLOW->data.F32[nLOW] = source->moments->Myy;
     1716            mLOW->data.F32[nLOW] = -2.5*log10(source->moments->Sum);
     1717            sLOW->data.F32[nLOW] = source->extNsigma;
     1718            nLOW++;
     1719            continue;
     1720        }
     1721        xPSF->data.F32[nPSF] = source->moments->Mxx;
     1722        yPSF->data.F32[nPSF] = source->moments->Myy;
     1723        mPSF->data.F32[nPSF] = -2.5*log10(source->moments->Sum);
     1724        sPSF->data.F32[nPSF] = source->extNsigma;
     1725        nPSF++;
     1726    }
     1727
     1728    xSAT->n = nSAT;
     1729    ySAT->n = nSAT;
     1730    mSAT->n = nSAT;
     1731    sSAT->n = nSAT;
     1732
     1733    xPSF->n = nPSF;
     1734    yPSF->n = nPSF;
     1735    mPSF->n = nPSF;
     1736    sPSF->n = nPSF;
     1737
     1738    xEXT->n = nEXT;
     1739    yEXT->n = nEXT;
     1740    mEXT->n = nEXT;
     1741    sEXT->n = nEXT;
     1742
     1743    xCR->n = nCR;
     1744    yCR->n = nCR;
     1745    mCR->n = nCR;
     1746    sCR->n = nCR;
     1747
     1748    xDEF->n = nDEF;
     1749    yDEF->n = nDEF;
     1750    mDEF->n = nDEF;
     1751    sDEF->n = nDEF;
     1752
     1753    xLOW->n = nLOW;
     1754    yLOW->n = nLOW;
     1755    mLOW->n = nLOW;
     1756    sLOW->n = nLOW;
     1757
     1758    // four sections: MxxMyy, MagMxx, MagMyy, MagSigma
     1759
     1760    // first section: MxxMyy
     1761    section.dx = 0.75;
     1762    section.dy = 0.60;
     1763    section.x  = 0.00;
     1764    section.y  = 0.00;
     1765    section.name = psStringCopy ("MxxMyy");
     1766    KapaSetSection (myKapa, &section);
    16091767    psFree (section.name);
     1768
     1769    graphdata.color = KapaColorByName ("black");
     1770    graphdata.xmin = Xmin;
     1771    graphdata.ymin = Ymin;
     1772    graphdata.xmax = Xmax;
     1773    graphdata.ymax = Ymax;
     1774    KapaSetLimits (myKapa, &graphdata);
     1775
     1776    graphdata.padXm = NAN;
     1777    graphdata.padYm = NAN;
     1778    graphdata.padXp = 0.5;
     1779    graphdata.padYp = 0.5;
     1780    KapaBox (myKapa, &graphdata);
     1781    KapaSendLabel (myKapa, "M_xx| (pixels)", KAPA_LABEL_XM);
     1782    KapaSendLabel (myKapa, "M_yy| (pixels)", KAPA_LABEL_YM);
     1783
     1784    graphdata.color = KapaColorByName ("black");
     1785    graphdata.ptype = 0;
     1786    graphdata.size = 0.5;
     1787    graphdata.style = 2;
     1788    KapaPrepPlot   (myKapa, nPSF, &graphdata);
     1789    KapaPlotVector (myKapa, nPSF, xPSF->data.F32, "x");
     1790    KapaPlotVector (myKapa, nPSF, yPSF->data.F32, "y");
     1791
     1792    graphdata.color = KapaColorByName ("blue");
     1793    graphdata.ptype = 0;
     1794    graphdata.size = 0.5;
     1795    graphdata.style = 2;
     1796    KapaPrepPlot   (myKapa, nEXT, &graphdata);
     1797    KapaPlotVector (myKapa, nEXT, xEXT->data.F32, "x");
     1798    KapaPlotVector (myKapa, nEXT, yEXT->data.F32, "y");
     1799
     1800    graphdata.color = KapaColorByName ("red");
     1801    graphdata.ptype = 0;
     1802    graphdata.size = 0.5;
     1803    graphdata.style = 2;
     1804    KapaPrepPlot   (myKapa, nDEF, &graphdata);
     1805    KapaPlotVector (myKapa, nDEF, xDEF->data.F32, "x");
     1806    KapaPlotVector (myKapa, nDEF, yDEF->data.F32, "y");
     1807
     1808    graphdata.color = KapaColorByName ("red");
     1809    graphdata.ptype = 7;
     1810    graphdata.size = 1.0;
     1811    graphdata.style = 2;
     1812    KapaPrepPlot   (myKapa, nCR, &graphdata);
     1813    KapaPlotVector (myKapa, nCR, xCR->data.F32, "x");
     1814    KapaPlotVector (myKapa, nCR, yCR->data.F32, "y");
     1815
     1816    graphdata.color = KapaColorByName ("blue");
     1817    graphdata.ptype = 7;
     1818    graphdata.size = 1.0;
     1819    graphdata.style = 2;
     1820    KapaPrepPlot   (myKapa, nSAT, &graphdata);
     1821    KapaPlotVector (myKapa, nSAT, xSAT->data.F32, "x");
     1822    KapaPlotVector (myKapa, nSAT, ySAT->data.F32, "y");
     1823
     1824    graphdata.color = KapaColorByName ("black");
     1825    graphdata.ptype = 7;
     1826    graphdata.size = 1.0;
     1827    graphdata.style = 2;
     1828    KapaPrepPlot   (myKapa, nLOW, &graphdata);
     1829    KapaPlotVector (myKapa, nLOW, xLOW->data.F32, "x");
     1830    KapaPlotVector (myKapa, nLOW, yLOW->data.F32, "y");
     1831
     1832    // second section: MagMyy
     1833    section.dx = 0.75;
     1834    section.dy = 0.20;
     1835    section.x  = 0.00;
     1836    section.y  = 0.80;
     1837    section.name = psStringCopy ("MagMyy");
     1838    KapaSetSection (myKapa, &section);
     1839    psFree (section.name);
     1840
     1841    graphdata.color = KapaColorByName ("black");
     1842    graphdata.xmin = -17.1;
     1843    graphdata.xmax =  -6.9;
     1844    graphdata.ymin = Ymin;
     1845    graphdata.ymax = Ymax;
     1846    KapaSetLimits (myKapa, &graphdata);
     1847
     1848    graphdata.padXm = 0.5;
     1849    graphdata.padYm = NAN;
     1850    graphdata.padXp = NAN;
     1851    graphdata.padYp = 0.5;
     1852    strcpy (graphdata.labels, "0210");
     1853    KapaBox (myKapa, &graphdata);
     1854    KapaSendLabel (myKapa, "inst mag", KAPA_LABEL_XP);
     1855    KapaSendLabel (myKapa, "M_yy| (pixels)", KAPA_LABEL_YM);
     1856
     1857    graphdata.color = KapaColorByName ("black");
     1858    graphdata.ptype = 0;
     1859    graphdata.size = 0.5;
     1860    graphdata.style = 2;
     1861    KapaPrepPlot   (myKapa, nPSF, &graphdata);
     1862    KapaPlotVector (myKapa, nPSF, mPSF->data.F32, "x");
     1863    KapaPlotVector (myKapa, nPSF, yPSF->data.F32, "y");
     1864
     1865    graphdata.color = KapaColorByName ("blue");
     1866    graphdata.ptype = 0;
     1867    graphdata.size = 0.5;
     1868    graphdata.style = 2;
     1869    KapaPrepPlot   (myKapa, nEXT, &graphdata);
     1870    KapaPlotVector (myKapa, nEXT, mEXT->data.F32, "x");
     1871    KapaPlotVector (myKapa, nEXT, yEXT->data.F32, "y");
     1872
     1873    graphdata.color = KapaColorByName ("red");
     1874    graphdata.ptype = 0;
     1875    graphdata.size = 0.5;
     1876    graphdata.style = 2;
     1877    KapaPrepPlot   (myKapa, nDEF, &graphdata);
     1878    KapaPlotVector (myKapa, nDEF, mDEF->data.F32, "x");
     1879    KapaPlotVector (myKapa, nDEF, yDEF->data.F32, "y");
     1880
     1881    graphdata.color = KapaColorByName ("red");
     1882    graphdata.ptype = 7;
     1883    graphdata.size = 1.0;
     1884    graphdata.style = 2;
     1885    KapaPrepPlot   (myKapa, nCR, &graphdata);
     1886    KapaPlotVector (myKapa, nCR, mCR->data.F32, "x");
     1887    KapaPlotVector (myKapa, nCR, yCR->data.F32, "y");
     1888
     1889    graphdata.color = KapaColorByName ("blue");
     1890    graphdata.ptype = 7;
     1891    graphdata.size = 1.0;
     1892    graphdata.style = 2;
     1893    KapaPrepPlot   (myKapa, nSAT, &graphdata);
     1894    KapaPlotVector (myKapa, nSAT, mSAT->data.F32, "x");
     1895    KapaPlotVector (myKapa, nSAT, ySAT->data.F32, "y");
     1896
     1897    // third section: MagMxx
     1898    section.dx = 0.25;
     1899    section.dy = 0.60;
     1900    section.x  = 0.75;
     1901    section.y  = 0.00;
     1902    section.name = psStringCopy ("MagMxx");
     1903    KapaSetSection (myKapa, &section);
     1904    psFree (section.name);
     1905
     1906    graphdata.color = KapaColorByName ("black");
     1907    graphdata.xmin = Xmin;
     1908    graphdata.xmax = Xmax;
     1909    graphdata.ymin =  -6.9;
     1910    graphdata.ymax = -17.1;
     1911    KapaSetLimits (myKapa, &graphdata);
     1912
     1913    graphdata.padXm = NAN;
     1914    graphdata.padYm = 0.5;
     1915    graphdata.padXp = 0.5;
     1916    graphdata.padYp = NAN;
     1917    strcpy (graphdata.labels, "2001");
     1918    KapaBox (myKapa, &graphdata);
     1919    KapaSendLabel (myKapa, "M_xx| (pixels)", KAPA_LABEL_XM);
     1920    KapaSendLabel (myKapa, "inst mag", KAPA_LABEL_YP);
     1921
     1922    graphdata.color = KapaColorByName ("black");
     1923    graphdata.ptype = 0;
     1924    graphdata.size = 0.5;
     1925    graphdata.style = 2;
     1926    KapaPrepPlot   (myKapa, nPSF, &graphdata);
     1927    KapaPlotVector (myKapa, nPSF, xPSF->data.F32, "x");
     1928    KapaPlotVector (myKapa, nPSF, mPSF->data.F32, "y");
     1929
     1930    graphdata.color = KapaColorByName ("blue");
     1931    graphdata.ptype = 0;
     1932    graphdata.size = 0.5;
     1933    graphdata.style = 2;
     1934    KapaPrepPlot   (myKapa, nEXT, &graphdata);
     1935    KapaPlotVector (myKapa, nEXT, xEXT->data.F32, "x");
     1936    KapaPlotVector (myKapa, nEXT, mEXT->data.F32, "y");
     1937
     1938    graphdata.color = KapaColorByName ("red");
     1939    graphdata.ptype = 0;
     1940    graphdata.size = 0.5;
     1941    graphdata.style = 2;
     1942    KapaPrepPlot   (myKapa, nDEF, &graphdata);
     1943    KapaPlotVector (myKapa, nDEF, xDEF->data.F32, "x");
     1944    KapaPlotVector (myKapa, nDEF, mDEF->data.F32, "y");
     1945
     1946    graphdata.color = KapaColorByName ("red");
     1947    graphdata.ptype = 7;
     1948    graphdata.size = 1.0;
     1949    graphdata.style = 2;
     1950    KapaPrepPlot   (myKapa, nCR, &graphdata);
     1951    KapaPlotVector (myKapa, nCR, xCR->data.F32, "x");
     1952    KapaPlotVector (myKapa, nCR, mCR->data.F32, "y");
     1953
     1954    graphdata.color = KapaColorByName ("blue");
     1955    graphdata.ptype = 7;
     1956    graphdata.size = 1.0;
     1957    graphdata.style = 2;
     1958    KapaPrepPlot   (myKapa, nSAT, &graphdata);
     1959    KapaPlotVector (myKapa, nSAT, xSAT->data.F32, "x");
     1960    KapaPlotVector (myKapa, nSAT, mSAT->data.F32, "y");
     1961
     1962    // fourth section: MagSigma
     1963    section.dx = 0.75;
     1964    section.dy = 0.20;
     1965    section.x  = 0.00;
     1966    section.y  = 0.60;
     1967    section.name = psStringCopy ("MagSigma");
     1968    KapaSetSection (myKapa, &section);
     1969    psFree (section.name);
     1970
     1971    graphdata.color = KapaColorByName ("black");
     1972    graphdata.xmax =  -6.9;
     1973    graphdata.xmin = -17.1;
     1974    graphdata.ymin = -20.1;
     1975    graphdata.ymax = +20.1;
     1976    KapaSetLimits (myKapa, &graphdata);
     1977
     1978    graphdata.padXm = 0.5;
     1979    graphdata.padYm = NAN;
     1980    graphdata.padXp = 0.5;
     1981    graphdata.padYp = 0.5;
     1982    strcpy (graphdata.labels, "0100");
     1983    KapaBox (myKapa, &graphdata);
     1984    // KapaSendLabel (myKapa, "inst mag", KAPA_LABEL_XM);
     1985    KapaSendLabel (myKapa, "EXT&ss&c", KAPA_LABEL_YM);
     1986
     1987    graphdata.color = KapaColorByName ("black");
     1988    graphdata.ptype = 0;
     1989    graphdata.size = 0.5;
     1990    graphdata.style = 2;
     1991    KapaPrepPlot   (myKapa, nPSF, &graphdata);
     1992    KapaPlotVector (myKapa, nPSF, mPSF->data.F32, "x");
     1993    KapaPlotVector (myKapa, nPSF, sPSF->data.F32, "y");
     1994
     1995    graphdata.color = KapaColorByName ("blue");
     1996    graphdata.ptype = 0;
     1997    graphdata.size = 0.5;
     1998    graphdata.style = 2;
     1999    KapaPrepPlot   (myKapa, nEXT, &graphdata);
     2000    KapaPlotVector (myKapa, nEXT, mEXT->data.F32, "x");
     2001    KapaPlotVector (myKapa, nEXT, sEXT->data.F32, "y");
     2002
     2003    graphdata.color = KapaColorByName ("red");
     2004    graphdata.ptype = 0;
     2005    graphdata.size = 0.5;
     2006    graphdata.style = 2;
     2007    KapaPrepPlot   (myKapa, nDEF, &graphdata);
     2008    KapaPlotVector (myKapa, nDEF, mDEF->data.F32, "x");
     2009    KapaPlotVector (myKapa, nDEF, sDEF->data.F32, "y");
     2010
     2011    graphdata.color = KapaColorByName ("red");
     2012    graphdata.ptype = 7;
     2013    graphdata.size = 1.0;
     2014    graphdata.style = 2;
     2015    KapaPrepPlot   (myKapa, nCR, &graphdata);
     2016    KapaPlotVector (myKapa, nCR, mCR->data.F32, "x");
     2017    KapaPlotVector (myKapa, nCR, sCR->data.F32, "y");
     2018
     2019    graphdata.color = KapaColorByName ("blue");
     2020    graphdata.ptype = 7;
     2021    graphdata.size = 1.0;
     2022    graphdata.style = 2;
     2023    KapaPrepPlot   (myKapa, nSAT, &graphdata);
     2024    KapaPlotVector (myKapa, nSAT, mSAT->data.F32, "x");
     2025    KapaPlotVector (myKapa, nSAT, sSAT->data.F32, "y");
     2026
     2027    // draw N circles to outline the clumps
     2028    {
     2029        KapaSelectSection (myKapa, "MxxMyy");
     2030
     2031        // draw a circle centered on psfX,Y with size of the psf limit
     2032        psVector *xLimit  = psVectorAlloc (120, PS_TYPE_F32);
     2033        psVector *yLimit  = psVectorAlloc (120, PS_TYPE_F32);
     2034
     2035        int nRegions = psMetadataLookupS32 (&status, analysis, "PSF.CLUMP.NREGIONS");
     2036        float PSF_CLUMP_NSIGMA = psMetadataLookupF32 (&status, recipe, "PSF_CLUMP_NSIGMA");
     2037
     2038        graphdata.color = KapaColorByName ("blue");
     2039        graphdata.style = 0;
     2040
     2041        graphdata.xmin = Xmin;
     2042        graphdata.ymin = Ymin;
     2043        graphdata.xmax = Xmax;
     2044        graphdata.ymax = Ymax;
     2045        KapaSetLimits (myKapa, &graphdata);
     2046
     2047        for (int n = 0; n < nRegions; n++) {
     2048
     2049            char regionName[64];
     2050            snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", n);
     2051            psMetadata *regionMD = psMetadataLookupPtr (&status, analysis, regionName);
     2052
     2053            float psfX  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");
     2054            float psfY  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y");
     2055            float psfdX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX");
     2056            float psfdY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY");
     2057            float Rx = psfdX * PSF_CLUMP_NSIGMA;
     2058            float Ry = psfdY * PSF_CLUMP_NSIGMA;
     2059
     2060            for (int i = 0; i < xLimit->n; i++) {
     2061                xLimit->data.F32[i] = Rx*cos(i*2.0*M_PI/120.0) + psfX;
     2062                yLimit->data.F32[i] = Ry*sin(i*2.0*M_PI/120.0) + psfY;
     2063            }
     2064            KapaPrepPlot (myKapa, xLimit->n, &graphdata);
     2065            KapaPlotVector (myKapa, xLimit->n, xLimit->data.F32, "x");
     2066            KapaPlotVector (myKapa, yLimit->n, yLimit->data.F32, "y");
     2067        }
     2068        psFree (xLimit);
     2069        psFree (yLimit);
     2070    }
     2071
     2072    psFree (xSAT);
     2073    psFree (ySAT);
     2074    psFree (mSAT);
     2075    psFree (sSAT);
     2076
     2077    psFree (xEXT);
     2078    psFree (yEXT);
     2079    psFree (mEXT);
     2080    psFree (sEXT);
     2081
     2082    psFree (xPSF);
     2083    psFree (yPSF);
     2084    psFree (mPSF);
     2085    psFree (sPSF);
     2086
     2087    psFree (xDEF);
     2088    psFree (yDEF);
     2089    psFree (mDEF);
     2090    psFree (sDEF);
     2091
     2092    psFree (xLOW);
     2093    psFree (yLOW);
     2094    psFree (mLOW);
     2095    psFree (sLOW);
     2096
     2097    psFree (xCR);
     2098    psFree (yCR);
     2099    psFree (mCR);
     2100    psFree (sCR);
     2101
     2102    pmVisualAskUser(NULL);
     2103    return true;
     2104}
     2105
     2106bool psphotVisualShowResidualImage (pmReadout *readout) {
     2107
     2108    if (!pmVisualIsVisual()) return true;
     2109
     2110    int myKapa = psphotKapaChannel (1);
     2111    if (myKapa == -1) return false;
     2112
     2113    psphotVisualScaleImage (myKapa, readout->image, readout->mask, "resid", 1);
     2114
     2115    pmVisualAskUser(NULL);
     2116    return true;
     2117}
     2118
     2119bool psphotVisualPlotApResid (psArray *sources, float mean, float error) {
     2120
     2121    Graphdata graphdata;
     2122    float lineX[2], lineY[2];
     2123
     2124    if (!pmVisualIsVisual()) return true;
     2125
     2126    int myKapa = psphotKapaChannel (2);
     2127    if (myKapa == -1) return false;
     2128
     2129    KapaClearPlots (myKapa);
     2130    KapaInitGraph (&graphdata);
    16102131
    16112132    psVector *x = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
    16122133    psVector *y = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
    1613 
    1614     graphdata.xmin = +32.0;
    1615     graphdata.xmax = -32.0;
    1616     graphdata.ymin = +32.0;
    1617     graphdata.ymax = -32.0;
    1618 
    1619     // construct the plot vectors
    1620     int n = 0;
    1621     for (int i = 0; i < sources->n; i++) {
    1622         pmSource *source = sources->data[i];
    1623         if (!source) continue;
    1624         if (source->type != PM_SOURCE_TYPE_STAR) continue;
    1625         if (!isfinite (source->crNsigma)) continue;
    1626 
    1627         x->data.F32[n] = -2.5*log10(source->peak->flux);
    1628         y->data.F32[n] = source->crNsigma;
    1629         graphdata.xmin = PS_MIN(graphdata.xmin, x->data.F32[n]);
    1630         graphdata.xmax = PS_MAX(graphdata.xmax, x->data.F32[n]);
    1631         graphdata.ymin = -0.5;
    1632         graphdata.ymax = 10.0;
    1633 
    1634         n++;
    1635     }
    1636     x->n = y->n = n;
    1637 
    1638     float range;
    1639     range = graphdata.xmax - graphdata.xmin;
    1640     graphdata.xmax += 0.05*range;
    1641     graphdata.xmin -= 0.05*range;
    1642 
    1643     // XXX set the plot range to match the image
    1644     KapaSetLimits (kapa3, &graphdata);
    1645 
    1646     KapaSetFont (kapa3, "helvetica", 14);
    1647     KapaBox (kapa3, &graphdata);
    1648     KapaSendLabel (kapa3, "Peak as Mag", KAPA_LABEL_XM);
    1649     KapaSendLabel (kapa3, "CR N Sigma", KAPA_LABEL_YM);
    1650 
    1651     graphdata.color = KapaColorByName ("black");
    1652     graphdata.ptype = 2;
    1653     graphdata.size = 0.5;
    1654     graphdata.style = 2;
    1655     KapaPrepPlot (kapa3, n, &graphdata);
    1656     KapaPlotVector (kapa3, n, x->data.F32, "x");
    1657     KapaPlotVector (kapa3, n, y->data.F32, "y");
    1658 
    1659     // second section : mag vs EXT nSigma
    1660     section.dx = 1.0;
    1661     section.dy = 0.5;
    1662     section.x = 0.0;
    1663     section.y = 0.5;
    1664     section.name = NULL;
    1665     psStringAppend (&section.name, "a2");
    1666     KapaSetSection (kapa3, &section);
    1667     psFree (section.name);
    1668 
    1669     graphdata.xmin = +32.0;
    1670     graphdata.xmax = -32.0;
    1671     graphdata.ymin = +32.0;
    1672     graphdata.ymax = -32.0;
    1673 
    1674     // construct the plot vectors
    1675     n = 0;
    1676     for (int i = 0; i < sources->n; i++) {
    1677         pmSource *source = sources->data[i];
    1678         if (!source) continue;
    1679         if (source->type != PM_SOURCE_TYPE_STAR) continue;
    1680         if (!isfinite (source->extNsigma)) continue;
    1681 
    1682         x->data.F32[n] = -2.5*log10(source->peak->flux);
    1683         y->data.F32[n] = source->extNsigma;
    1684         graphdata.xmin = PS_MIN(graphdata.xmin, x->data.F32[n]);
    1685         graphdata.xmax = PS_MAX(graphdata.xmax, x->data.F32[n]);
    1686         graphdata.ymin = -0.5;
    1687         graphdata.ymax = 10.0;
    1688 
    1689         n++;
    1690     }
    1691     x->n = y->n = n;
    1692 
    1693     range = graphdata.xmax - graphdata.xmin;
    1694     graphdata.xmax += 0.05*range;
    1695     graphdata.xmin -= 0.05*range;
    1696 
    1697     // XXX set the plot range to match the image
    1698     KapaSetLimits (kapa3, &graphdata);
    1699 
    1700     KapaSetFont (kapa3, "helvetica", 14);
    1701     KapaBox (kapa3, &graphdata);
    1702     KapaSendLabel (kapa3, "EXT N Sigma", KAPA_LABEL_YM);
    1703 
    1704     graphdata.color = KapaColorByName ("black");
    1705     graphdata.ptype = 2;
    1706     graphdata.size = 0.5;
    1707     graphdata.style = 2;
    1708     KapaPrepPlot (kapa3, n, &graphdata);
    1709     KapaPlotVector (kapa3, n, x->data.F32, "x");
    1710     KapaPlotVector (kapa3, n, y->data.F32, "y");
    1711 
    1712     psFree (x);
    1713     psFree (y);
    1714 
    1715     // pause and wait for user input:
    1716     // continue, save (provide name), ??
    1717     char key[10];
    1718     fprintf (stdout, "[c]ontinue? ");
    1719     if (!fgets(key, 8, stdin)) {
    1720         psWarning("Unable to read option");
    1721     }
    1722     return true;
    1723 }
    1724 
    1725 bool psphotVisualShowResidualImage (pmReadout *readout) {
    1726 
    1727     if (!pmVisualIsVisual()) return true;
    1728 
    1729     if (kapa == -1) {
    1730         kapa = KapaOpenNamedSocket ("kapa", "psphot:images");
    1731         if (kapa == -1) {
    1732             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    1733             pmVisualSetVisual(false);
    1734             return false;
    1735         }
    1736     }
    1737 
    1738     psphotVisualScaleImage (kapa, readout->image, "resid", 1);
    1739 
    1740     // pause and wait for user input:
    1741     // continue, save (provide name), ??
    1742     char key[10];
    1743     fprintf (stdout, "[c]ontinue? ");
    1744     if (!fgets(key, 8, stdin)) {
    1745         psWarning("Unable to read option");
    1746     }
    1747     return true;
    1748 }
    1749 
    1750 bool psphotVisualPlotApResid (psArray *sources) {
    1751 
    1752     Graphdata graphdata;
    1753 
    1754     if (!pmVisualIsVisual()) return true;
    1755 
    1756     if (kapa3 == -1) {
    1757         kapa3 = KapaOpenNamedSocket ("kapa", "psphot:plots");
    1758         if (kapa3 == -1) {
    1759             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    1760             pmVisualSetVisual(false);
    1761             return false;
    1762         }
    1763     }
    1764 
    1765     KapaClearPlots (kapa3);
    1766     KapaInitGraph (&graphdata);
    1767 
    1768     psVector *x = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
    1769     psVector *y = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     2134    psVector *dy = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
    17702135
    17712136    graphdata.xmin = +32.0;
     
    17852150        x->data.F32[n] = source->psfMag;
    17862151        y->data.F32[n] = source->apMag - source->psfMag;
     2152        dy->data.F32[n] = source->errMag;
    17872153        graphdata.xmin = PS_MIN(graphdata.xmin, x->data.F32[n]);
    17882154        graphdata.xmax = PS_MAX(graphdata.xmax, x->data.F32[n]);
     
    17922158        n++;
    17932159    }
    1794     x->n = y->n = n;
     2160    x->n = y->n = dy->n = n;
    17952161
    17962162    float range;
     
    18022168    graphdata.ymin -= 0.05*range;
    18032169
    1804     // XXX set the plot range to match the image
    1805     KapaSetLimits (kapa3, &graphdata);
    1806 
    1807     KapaSetFont (kapa3, "helvetica", 14);
    1808     KapaBox (kapa3, &graphdata);
    1809     KapaSendLabel (kapa3, "PSF Mag", KAPA_LABEL_XM);
    1810     KapaSendLabel (kapa3, "Ap Mag - PSF Mag", KAPA_LABEL_YM);
     2170    // XXX test
     2171    graphdata.xmin = -17.0;
     2172    graphdata.xmax =  -9.0;
     2173    graphdata.ymin = -0.31;
     2174    graphdata.ymax = +0.31;
     2175
     2176    KapaSetLimits (myKapa, &graphdata);
     2177
     2178    KapaSetFont (myKapa, "helvetica", 14);
     2179    KapaBox (myKapa, &graphdata);
     2180    KapaSendLabel (myKapa, "PSF Mag", KAPA_LABEL_XM);
     2181    KapaSendLabel (myKapa, "Ap Mag - PSF Mag", KAPA_LABEL_YM);
    18112182
    18122183    graphdata.color = KapaColorByName ("black");
     
    18142185    graphdata.size = 0.5;
    18152186    graphdata.style = 2;
    1816     KapaPrepPlot (kapa3, n, &graphdata);
    1817     KapaPlotVector (kapa3, n, x->data.F32, "x");
    1818     KapaPlotVector (kapa3, n, y->data.F32, "y");
     2187    graphdata.etype |= 0x01;
     2188    KapaPrepPlot (myKapa, n, &graphdata);
     2189    KapaPlotVector (myKapa, n, x->data.F32, "x");
     2190    KapaPlotVector (myKapa, n, y->data.F32, "y");
     2191    KapaPlotVector (myKapa, n, dy->data.F32, "dym");
     2192    KapaPlotVector (myKapa, n, dy->data.F32, "dyp");
     2193
     2194    graphdata.color = KapaColorByName ("blue");
     2195    graphdata.ptype = 0;
     2196    graphdata.size = 0.5;
     2197    graphdata.style = 0;
     2198    graphdata.etype = 0;
     2199    lineX[0] = graphdata.xmin;
     2200    lineX[1] = graphdata.xmax;
     2201    lineY[0] = lineY[1] = mean;
     2202    KapaPrepPlot (myKapa, 2, &graphdata);
     2203    KapaPlotVector (myKapa, 2, lineX, "x");
     2204    KapaPlotVector (myKapa, 2, lineY, "y");
     2205
     2206    graphdata.color = KapaColorByName ("red");
     2207    graphdata.ptype = 0;
     2208    graphdata.size = 0.5;
     2209    graphdata.style = 0;
     2210    graphdata.etype = 0;
     2211    lineX[0] = graphdata.xmin;
     2212    lineX[1] = graphdata.xmax;
     2213    lineY[0] = lineY[1] = mean + error;
     2214    KapaPrepPlot (myKapa, 2, &graphdata);
     2215    KapaPlotVector (myKapa, 2, lineX, "x");
     2216    KapaPlotVector (myKapa, 2, lineY, "y");
     2217
     2218    graphdata.color = KapaColorByName ("red");
     2219    graphdata.ptype = 0;
     2220    graphdata.size = 0.5;
     2221    graphdata.style = 0;
     2222    graphdata.etype = 0;
     2223    lineX[0] = graphdata.xmin;
     2224    lineX[1] = graphdata.xmax;
     2225    lineY[0] = lineY[1] = mean - error;
     2226    KapaPrepPlot (myKapa, 2, &graphdata);
     2227    KapaPlotVector (myKapa, 2, lineX, "x");
     2228    KapaPlotVector (myKapa, 2, lineY, "y");
    18192229
    18202230    psFree (x);
    18212231    psFree (y);
    1822 
    1823     // pause and wait for user input:
    1824     // continue, save (provide name), ??
    1825     char key[10];
    1826     fprintf (stdout, "[c]ontinue? ");
    1827     if (!fgets(key, 8, stdin)) {
    1828         psWarning("Unable to read option");
    1829     }
     2232    psFree (dy);
     2233
     2234    pmVisualAskUser(NULL);
     2235    return true;
     2236}
     2237
     2238bool psphotVisualPlotChisq (psArray *sources) {
     2239
     2240    Graphdata graphdata;
     2241
     2242    if (!pmVisualIsVisual()) return true;
     2243
     2244    int myKapa = psphotKapaChannel (2);
     2245    if (myKapa == -1) return false;
     2246
     2247    KapaClearPlots (myKapa);
     2248    KapaInitGraph (&graphdata);
     2249
     2250    psVector *x = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     2251    psVector *y = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     2252
     2253    graphdata.xmin = +32.0;
     2254    graphdata.xmax = -32.0;
     2255    graphdata.ymin = +32.0;
     2256    graphdata.ymax = -32.0;
     2257
     2258    FILE *f = fopen ("chisq.dat", "w");
     2259
     2260    // construct the plot vectors
     2261    int n = 0;
     2262    for (int i = 0; i < sources->n; i++) {
     2263        pmSource *source = sources->data[i];
     2264        if (!source) continue;
     2265        if (source->type != PM_SOURCE_TYPE_STAR) continue;
     2266        if (!source->moments) continue;
     2267        if (!isfinite(source->moments->Sum)) continue;
     2268        if (!source->modelPSF) continue;
     2269        if (!isfinite(source->modelPSF->chisq)) continue;
     2270
     2271        x->data.F32[n] = -2.5*log10(source->moments->Sum);
     2272        y->data.F32[n] = source->modelPSF->chisq / source->modelPSF->nDOF;
     2273        graphdata.xmin = PS_MIN(graphdata.xmin, x->data.F32[n]);
     2274        graphdata.xmax = PS_MAX(graphdata.xmax, x->data.F32[n]);
     2275        graphdata.ymin = PS_MIN(graphdata.ymin, y->data.F32[n]);
     2276        graphdata.ymax = PS_MAX(graphdata.ymax, y->data.F32[n]);
     2277
     2278        fprintf (f, "%d %d %f %f\n", i, n, x->data.F32[n], y->data.F32[n]);
     2279
     2280        n++;
     2281    }
     2282    x->n = y->n = n;
     2283    fclose (f);
     2284
     2285    float range;
     2286    range = graphdata.xmax - graphdata.xmin;
     2287    graphdata.xmax += 0.05*range;
     2288    graphdata.xmin -= 0.05*range;
     2289    range = graphdata.ymax - graphdata.ymin;
     2290    graphdata.ymax += 0.05*range;
     2291    graphdata.ymin -= 0.05*range;
     2292
     2293    // XXX test
     2294    graphdata.xmin = -17.0;
     2295    graphdata.xmax =  -3.0;
     2296    graphdata.ymin =  -0.1;
     2297    graphdata.ymax = +10.1;
     2298
     2299    KapaSetLimits (myKapa, &graphdata);
     2300
     2301    KapaSetFont (myKapa, "helvetica", 14);
     2302    KapaBox (myKapa, &graphdata);
     2303    KapaSendLabel (myKapa, "PSF Mag", KAPA_LABEL_XM);
     2304    KapaSendLabel (myKapa, "ChiSq", KAPA_LABEL_YM);
     2305
     2306    graphdata.color = KapaColorByName ("black");
     2307    graphdata.ptype = 2;
     2308    graphdata.size = 0.5;
     2309    graphdata.style = 2;
     2310    KapaPrepPlot (myKapa, n, &graphdata);
     2311    KapaPlotVector (myKapa, n, x->data.F32, "x");
     2312    KapaPlotVector (myKapa, n, y->data.F32, "y");
     2313
     2314    psFree (x);
     2315    psFree (y);
     2316
     2317    pmVisualAskUser(NULL);
     2318    return true;
     2319}
     2320
     2321bool psphotVisualShowPetrosians (psArray *sources) {
     2322
     2323    int Noverlay, NOVERLAY;
     2324    KiiOverlay *overlay;
     2325
     2326    if (!pmVisualIsVisual()) return true;
     2327
     2328    int kapa = psphotKapaChannel (1);
     2329    if (kapa == -1) return false;
     2330
     2331    Noverlay = 0;
     2332    NOVERLAY = 100;
     2333    ALLOCATE (overlay, KiiOverlay, NOVERLAY);
     2334
     2335    for (int i = 0; i < sources->n; i++) {
     2336        pmSource *source = sources->data[i];
     2337
     2338        if (!source) continue;
     2339        if (!source->extpars) continue;
     2340        if (!source->extpars->petProfile) continue;
     2341
     2342        float petrosianRadius = source->extpars->petrosianRadius;
     2343        psEllipseAxes *axes = &source->extpars->axes;
     2344
     2345        overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
     2346        overlay[Noverlay].x = source->peak->xf;
     2347        overlay[Noverlay].y = source->peak->yf;
     2348        overlay[Noverlay].dx = 1.0*petrosianRadius;
     2349        overlay[Noverlay].dy = 1.0*petrosianRadius*axes->minor/axes->major;
     2350        overlay[Noverlay].angle = axes->theta * PS_DEG_RAD;
     2351        overlay[Noverlay].text = NULL;
     2352        Noverlay ++;
     2353        CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
     2354
     2355        // overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
     2356        // overlay[Noverlay].x = source->peak->xf;
     2357        // overlay[Noverlay].y = source->peak->yf;
     2358        // overlay[Noverlay].dx = 2.0*petrosianRadius;
     2359        // overlay[Noverlay].dy = 2.0*petrosianRadius*axes->minor/axes->major;
     2360        // overlay[Noverlay].angle = axes->theta * PS_DEG_RAD;
     2361        // overlay[Noverlay].text = NULL;
     2362        // Noverlay ++;
     2363        // CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
     2364    }
     2365
     2366    KiiLoadOverlay (kapa, overlay, Noverlay, "red");
     2367    FREE (overlay);
     2368
     2369    pmVisualAskUser(NULL);
    18302370    return true;
    18312371}
     
    18502390
    18512391# endif
     2392
     2393# if (0)
     2394// *** make a histogram of the source counts in the x and y directions
     2395psHistogram *nX = psHistogramAlloc (graphdata.xmin, graphdata.xmax, 50.0);
     2396psHistogram *nY = psHistogramAlloc (graphdata.ymin, graphdata.ymax, 50.0);
     2397psVectorHistogram (nX, xFaint, NULL, NULL, 0);
     2398psVectorHistogram (nY, yFaint, NULL, NULL, 0);
     2399psVector *dX = psVectorAlloc (nX->nums->n, PS_TYPE_F32);
     2400psVector *vX = psVectorAlloc (nX->nums->n, PS_TYPE_F32);
     2401psVector *dY = psVectorAlloc (nY->nums->n, PS_TYPE_F32);
     2402psVector *vY = psVectorAlloc (nY->nums->n, PS_TYPE_F32);
     2403for (int i = 0; i < nX->nums->n; i++) {
     2404    dX->data.F32[i] = nX->nums->data.S32[i];
     2405    vX->data.F32[i] = 0.5*(nX->bounds->data.F32[i] + nX->bounds->data.F32[i+1]);
     2406}
     2407for (int i = 0; i < nY->nums->n; i++) {
     2408    dY->data.F32[i] = nY->nums->data.S32[i];
     2409    vY->data.F32[i] = 0.5*(nY->bounds->data.F32[i] + nY->bounds->data.F32[i+1]);
     2410}
     2411
     2412graphdata.color = KapaColorByName ("black");
     2413graphdata.ptype = 0;
     2414graphdata.size = 0.0;
     2415graphdata.style = 0;
     2416KapaPrepPlot (myKapa, dX->n, &graphdata);
     2417KapaPlotVector (myKapa, dX->n, dX->data.F32, "x");
     2418KapaPlotVector (myKapa, vX->n, vX->data.F32, "y");
     2419
     2420psFree (nX);
     2421psFree (dX);
     2422psFree (vX);
     2423
     2424psFree (nY);
     2425psFree (dY);
     2426psFree (vY);
     2427
     2428# endif
     2429
Note: See TracChangeset for help on using the changeset viewer.