IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 36375 for trunk/psModules


Ignore:
Timestamp:
Dec 10, 2013, 2:55:11 PM (12 years ago)
Author:
eugene
Message:

merge changes from eam_branches/ipp-20130904

Location:
trunk
Files:
36 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/psModules

  • trunk/psModules/src/camera/pmFPAfile.c

    r33913 r36375  
    491491    if (!strcasecmp(type, "CMF"))     {
    492492        return PM_FPA_FILE_CMF;
     493    }
     494    if (!strcasecmp(type, "CFF"))     {
     495        return PM_FPA_FILE_CFF;
    493496    }
    494497    if (!strcasecmp(type, "WCS"))     {
  • trunk/psModules/src/camera/pmFPAfile.h

    r33913 r36375  
    3434    PM_FPA_FILE_CMP,
    3535    PM_FPA_FILE_CMF,
     36    PM_FPA_FILE_CFF,
    3637    PM_FPA_FILE_WCS,
    3738    PM_FPA_FILE_RAW,
  • trunk/psModules/src/camera/pmFPAfileDefine.c

    r35561 r36375  
    103103
    104104    type = psMetadataLookupStr(&status, data, "FILE.TYPE");
     105    if (!type) {
     106        psError(PM_ERR_CONFIG, true, "FILE.TYPE is not defined for %s\n", name);
     107        psFree(file);
     108        return NULL;
     109    }
     110
    105111    file->type = pmFPAfileTypeFromString(type);
    106112    if (file->type == PM_FPA_FILE_NONE) {
    107         psError(PM_ERR_CONFIG, true, "FILE.TYPE is not defined for %s\n", name);
     113        psError(PM_ERR_CONFIG, true, "FILE.TYPE %s is not registered in pmFPAfile.c:pmFPAfileTypeFromString\n", type);
    108114        psFree(file);
    109115        return NULL;
  • trunk/psModules/src/camera/pmFPAfileIO.c

    r35561 r36375  
    222222      case PM_FPA_FILE_CMP:
    223223      case PM_FPA_FILE_CMF:
     224      case PM_FPA_FILE_CFF:
    224225      case PM_FPA_FILE_WCS:
    225226      case PM_FPA_FILE_SRCTEXT:
     
    317318      case PM_FPA_FILE_CMP:
    318319      case PM_FPA_FILE_CMF:
     320      case PM_FPA_FILE_CFF:
    319321      case PM_FPA_FILE_WCS:
    320322      case PM_FPA_FILE_PSF:
     
    483485      case PM_FPA_FILE_CMP:
    484486      case PM_FPA_FILE_CMF:
     487      case PM_FPA_FILE_CFF:
    485488        status = pmFPAviewWriteObjects (view, file, config);
    486489        break;
     
    567570      case PM_FPA_FILE_PATTERN:
    568571      case PM_FPA_FILE_CMF:
     572      case PM_FPA_FILE_CFF:
    569573      case PM_FPA_FILE_WCS:
    570574      case PM_FPA_FILE_PSF:
     
    643647      case PM_FPA_FILE_CMP:
    644648      case PM_FPA_FILE_CMF:
     649      case PM_FPA_FILE_CFF:
    645650      case PM_FPA_FILE_WCS:
    646651      case PM_FPA_FILE_PSF:
     
    804809      case PM_FPA_FILE_PATTERN:
    805810      case PM_FPA_FILE_CMF:
     811      case PM_FPA_FILE_CFF:
    806812      case PM_FPA_FILE_WCS:
    807813      case PM_FPA_FILE_PSF:
     
    10161022      case PM_FPA_FILE_CMP:
    10171023      case PM_FPA_FILE_WCS:
     1024      case PM_FPA_FILE_CFF:
    10181025      case PM_FPA_FILE_JPEG:
    10191026      case PM_FPA_FILE_KAPA:
  • trunk/psModules/src/config/pmConfig.c

    r34234 r36375  
    18601860    }
    18611861
    1862     return psMetadataLookupMetadata(NULL, filerules, realname);
     1862    return psMetadataLookupMetadata(&mdok, filerules, realname);
    18631863}
    18641864
  • trunk/psModules/src/objects/Makefile.am

    r36085 r36375  
    4040        pmSourceIO_SX.c \
    4141        pmSourceIO_CMP.c \
     42        pmSourceIO_CFF.c \
    4243        pmSourceIO_SMPDATA.c \
    4344        pmSourceIO_PS1_DEV_0.c \
  • trunk/psModules/src/objects/models/pmModel_DEV.c

    r36106 r36375  
    269269
    270270    // Mxx, Mxy, Myy define the elliptical shape, but Mrf defines the width
    271     float scale = moments->Mrf / axes.major;
     271    // the factor of 2.3 comes from Table 1 of Graham and Driver (2005)
     272    float scale = moments->Mrf / axes.major / 2.3;
    272273    axes.major *= scale;
    273274    axes.minor *= scale;
  • trunk/psModules/src/objects/models/pmModel_EXP.c

    r36106 r36375  
    6363// 0.5 PIX: the parameters are defined in terms of pixel coords, so the incoming pixcoords
    6464// values need to be pixel coords
     65//
     66
     67// Notes on changing kappa value from 1.70056 to 1.678
     68// I'm using a functional form f(x,y) = Io exp(-kappa (r / r_e)). 
     69// The article by Graham & Driver (2005) uses a form Ie exp(-bn [(r / r_e) -1])
     70// which is equal to Ie exp(-bn (r / r_e)) exp(bn). 
     71// Thus, my Io = Ie exp(bn) and my kappa is their bn.
     72// My value of kappa is 1.700, their value for bn is 1.678., so I am off by a small amount there (1.5%). 
     73
     74
     75#define KAPPA_EXP 1.678
     76#define OLD_KAPP_EXP 1.70056
     77
    6578
    6679// Lax parameter limits
     
    109122    // for EXP, we can hard-wire kappa(1):
    110123    // float index = 1.0;
    111     float kappa = 1.70056;
     124    float kappa = KAPPA_EXP;
    112125
    113126    // sqrt(z) is r
     
    318331
    319332    // static value for EXP:
    320     float kappa = 1.70056;
     333    float kappa = KAPPA_EXP;
    321334
    322335    // f = Io exp(-kappa*sqrt(z)) -> sqrt(z) = ln(Io/f) / kappa
  • trunk/psModules/src/objects/models/pmModel_SERSIC.c

    r36085 r36375  
    7575
    7676// Lax parameter limits
    77 static float paramsMinLax[] = { -1.0e3, 1.0e-2, -100, -100, 0.001, 0.001, -1.0, 0.1 };
     77static float paramsMinLax[] = { -1.0e3, 1.0e-2, -100, -100, 0.001, 0.001, -1.0, 0.0625 };
    7878static float paramsMaxLax[] = { 1.0e5, 1.0e9, 1.0e5, 1.0e5, 100, 100, 1.0, 1.0 };
    7979
  • trunk/psModules/src/objects/pmModel.c

    r34498 r36375  
    217217    // the options allow us to modify various aspects of the model
    218218    if (mode & PM_MODEL_OP_NORM) {
     219        // if we are including the sky, renormalizing should force use to normalized down the sky flux
     220        params->data.F32[PM_PAR_SKY] /= params->data.F32[PM_PAR_I0];
    219221        params->data.F32[PM_PAR_I0] = 1.0;
    220222    }
    221223    if (!(mode & PM_MODEL_OP_SKY)) {
    222224        params->data.F32[PM_PAR_SKY] = 0.0;
    223     }
     225    } 
    224226    if (mode & PM_MODEL_OP_CENTER) {
    225227        params->data.F32[PM_PAR_XPOS] = image->col0 + 0.5*image->numCols;
  • trunk/psModules/src/objects/pmModelFuncs.h

    r35560 r36375  
    3636
    3737typedef enum {
    38     PM_MODEL_STATUS_NONE         = 0x00, ///< model fit not yet attempted, no other info
    39     PM_MODEL_STATUS_FITTED       = 0x01, ///< model fit completed
    40     PM_MODEL_STATUS_NONCONVERGE  = 0x02, ///< model fit did not converge
    41     PM_MODEL_STATUS_OFFIMAGE     = 0x04, ///< model fit drove out of range
    42     PM_MODEL_STATUS_BADARGS      = 0x08, ///< model fit called with invalid args
    43     PM_MODEL_STATUS_LIMITS       = 0x10, ///< model parameters hit limits
    44     PM_MODEL_STATUS_WEAK_FIT     = 0x20, ///< model fit met loose tolerance, but not tight tolerance
     38    PM_MODEL_STATUS_NONE           = 0x000, ///< model fit not yet attempted, no other info
     39    PM_MODEL_STATUS_FITTED         = 0x001, ///< model fit completed
     40    PM_MODEL_STATUS_NONCONVERGE    = 0x002, ///< model fit did not converge
     41    PM_MODEL_STATUS_OFFIMAGE       = 0x004, ///< model fit drove out of range
     42    PM_MODEL_STATUS_BADARGS        = 0x008, ///< model fit called with invalid args
     43    PM_MODEL_STATUS_LIMITS         = 0x010, ///< model parameters hit limits
     44    PM_MODEL_STATUS_WEAK_FIT       = 0x020, ///< model fit met loose tolerance, but not tight tolerance
     45    PM_MODEL_STATUS_NAN_CHISQ      = 0x040, ///< model fit failed with a NAN chisq
     46    PM_MODEL_SERSIC_PCM_FAIL_GUESS = 0x080, ///< sersic model fit failed on the initial moments-based guess
     47    PM_MODEL_SERSIC_PCM_FAIL_GRID  = 0x100, ///< sersic model fit failed on the grid search
     48    PM_MODEL_PCM_FAIL_GUESS        = 0x200, ///< non-sersic model fit failed on the initial moments-based guess
     49    PM_MODEL_BEST_FIT              = 0x400, ///< this model was the best fit and was subtracted
    4550} pmModelStatus;
    4651
  • trunk/psModules/src/objects/pmModelUtils.c

    r36287 r36375  
    129129bool pmModelAxesToParams (float *Sxx, float *Sxy, float *Syy, psEllipseAxes axes, bool useReff)  {
    130130
     131    // restrict axex to 0.5 here not below
     132    if (axes.minor < 0.2) axes.minor = 0.2;
     133    if (axes.major < 0.2) axes.major = 0.2;
     134
    131135    psEllipseShape shape = psEllipseAxesToShape (axes);
    132136
     
    137141    // set the shape parameters
    138142    if (useReff) {
    139         *Sxx  = PS_MAX(0.5, shape.sx);
    140         *Syy  = PS_MAX(0.5, shape.sy);
     143        // *Sxx  = PS_MAX(0.5, shape.sx);
     144        // *Syy  = PS_MAX(0.5, shape.sy);
     145        *Sxx  = shape.sx;
     146        *Syy  = shape.sy;
    141147        *Sxy  = shape.sxy * 2.0;
    142148    } else {
    143         *Sxx  = PS_MAX(0.5, M_SQRT2*shape.sx);
    144         *Syy  = PS_MAX(0.5, M_SQRT2*shape.sy);
     149        // *Sxx  = PS_MAX(0.5, M_SQRT2*shape.sx);
     150        // *Syy  = PS_MAX(0.5, M_SQRT2*shape.sy);
     151        *Sxx  = M_SQRT2*shape.sx;
     152        *Syy  = M_SQRT2*shape.sy;
    145153        *Sxy  = shape.sxy;
    146154    }
     
    193201    if (!isfinite(axes.minor)) return false;
    194202    if (!isfinite(axes.theta)) return false;
     203    if (axes.major == 0) return false;
    195204
    196205    // Mxx, Mxy, Myy define the elliptical shape, but Mrf defines the width
  • trunk/psModules/src/objects/pmModel_CentralPixel.c

    r36085 r36375  
    695695    int   npix = 0;
    696696
    697     float kappa = -0.275552 + 1.972625*Sindex + 0.003487 * PS_SQR(Sindex);
     697    // -0.275552 + 1.972625*Sindex + 0.003487 * PS_SQR(Sindex);
     698    float kappa = pmSersicKappa (Sindex);
    698699    float rindex = 0.5 / Sindex;
    699700
     
    703704
    704705    float delta = 1.0 / (float) Nsub;
    705     float off = -Nsub2 * delta;
    706     for (float ix = off; ix < 0.5; ix += delta) {
    707         for (float iy = off; iy < 0.5; iy += delta) {
    708 
    709             float dX = dx + ix;
    710             float dY = dy + iy;
     706    // float off = -Nsub2 * delta;
     707
     708    int Sx = (int) floor(dx / delta);
     709    int Sy = (int) floor(dy / delta);
     710
     711    for (int ix = -Nsub2; ix <= Nsub2; ix++) {
     712      float dX = delta * (Sx + ix);
     713      for (int iy = -Nsub2; iy <= Nsub2; iy++) {
     714        float dY = delta * (Sy + iy);
    711715            float z = PS_SQR(dX / Rxx) + PS_SQR(dY / Ryy) + dX * dY * Rxy;
    712716
    713717            float q = pow (z, rindex);
    714718            float f = exp(-kappa*q);
     719
     720            // if ((ix == 0) && (iy == 0)) {
     721            //   // fprintf (stderr, "this: %f  %f  %f  --  full : %f %f\n", z, q, f, flux, (float) npix);
     722            // }
    715723
    716724            flux += f;
  • trunk/psModules/src/objects/pmPCM_MinimizeChisq.c

    r36085 r36375  
    135135        }
    136136
     137        if (min->isInteractive) {
     138            fprintf (stderr, "%d : ", min->iter);
     139            for (int ti = 0; ti < params->n; ti++) {
     140                fprintf (stderr, "%f  ", params->data.F32[ti]);
     141            }
     142            fprintf (stderr, " : %f\n", min->value);
     143        }
     144
    137145        char key[10]; // used for interactive responses
    138146        bool testValue = false;
     
    140148        // set a new guess for Alpha, Beta, Params
    141149        if (!psMinLM_GuessABP(Alpha, Beta, Params, alpha, beta, params, paramMask, checkLimits, lambda, &dLinear)) {
    142             if (min->isInteractive) {
     150            if (false && min->isInteractive) {
    143151                fprintf (stdout, "guess failed (singular matrix or NaN values), continue? [Y,n] ");
    144152                if (!fgets(key, 8, stdin)) {
     
    167175        }
    168176
    169         if (min->isInteractive) {
     177        if (false && min->isInteractive) {
    170178            p_psVectorPrint(psTraceGetDestination(), Params, "current parameters: ");
    171179            fprintf (stdout, "last chisq : %f\n", min->value);
     
    473481# else
    474482    if (pcm->use1Dgauss) {
    475         // do not use the threaded, mask-aware version of this code (psImageSmoothMaskPixelsThread):
    476         // * the model flux is not masked
    477         // * threading takes place above this level
    478         pcm->modelConvFlux = psImageCopy (pcm->modelConvFlux, pcm->modelFlux, pcm->modelFlux->type.type);
    479         psImageSmooth_PreAlloc_F32 (pcm->modelConvFlux, pcm->smdata);
    480         // psImageSmooth (pcm->modelConvFlux, pcm->sigma, pcm->nsigma);
     483
     484        if (USE_1D_CACHE) {
     485            // do not use the threaded, mask-aware version of this code (psImageSmoothMaskPixelsThread):
     486            // * the model flux is not masked
     487            // * threading takes place above this level
     488            pcm->modelConvFlux = psImageCopy (pcm->modelConvFlux, pcm->modelFlux, pcm->modelFlux->type.type);
     489            psImageSmoothCache_F32 (pcm->modelConvFlux, pcm->smdata);
     490        } else {
     491            pcm->modelConvFlux = psImageCopy (pcm->modelConvFlux, pcm->modelFlux, pcm->modelFlux->type.type);
     492            psImageSmooth2dCache_F32 (pcm->modelConvFlux, pcm->smdata2d);
     493        }
    481494    } else {
    482495        psImageConvolveKernel (pcm->modelConvFlux, pcm->modelFlux, NULL, 0, pcm->psfFFT);
     
    493506# else
    494507        if (pcm->use1Dgauss) {
    495             // do not use the threaded, mask-aware version of this code (psImageSmoothMaskPixelsThread):
    496             // * the model flux is not masked
    497             // * threading takes place above this level
    498             dmodelConv = psImageCopy (dmodelConv, dmodel, dmodel->type.type);
    499             psImageSmooth_PreAlloc_F32 (dmodelConv, pcm->smdata);
    500             // psImageSmooth (dmodelConv, pcm->sigma, pcm->nsigma);
     508            if (USE_1D_CACHE) {
     509                // do not use the threaded, mask-aware version of this code (psImageSmoothMaskPixelsThread):
     510                // * the model flux is not masked
     511                // * threading takes place above this level
     512                dmodelConv = psImageCopy (dmodelConv, dmodel, dmodel->type.type);
     513                psImageSmoothCache_F32 (dmodelConv, pcm->smdata);
     514            } else {
     515                dmodelConv = psImageCopy (dmodelConv, dmodel, dmodel->type.type);
     516                psImageSmooth2dCache_F32 (dmodelConv, pcm->smdata2d);
     517            }
    501518        } else {
    502519            psImageConvolveKernel (dmodelConv, dmodel, NULL, 0, pcm->psfFFT);
     
    514531
    515532        if (pcm->use1Dgauss) {
    516             // do not use the threaded, mask-aware version of this code (psImageSmoothMaskPixelsThread):
    517             // * the model flux is not masked
    518             // * threading takes place above this level
    519             dmodelConv = psImageCopy (dmodelConv, dmodel, dmodel->type.type);
    520             psImageSmooth_PreAlloc_F32 (dmodelConv, pcm->smdata);
    521             // psImageSmooth (dmodelConv, pcm->sigma, pcm->nsigma);
     533            if (USE_1D_CACHE) {
     534                // do not use the threaded, mask-aware version of this code (psImageSmoothMaskPixelsThread):
     535                // * the model flux is not masked
     536                // * threading takes place above this level
     537                dmodelConv = psImageCopy (dmodelConv, dmodel, dmodel->type.type);
     538                psImageSmoothCache_F32 (dmodelConv, pcm->smdata);
     539            } else {
     540                dmodelConv = psImageCopy (dmodelConv, dmodel, dmodel->type.type);
     541                psImageSmooth2dCache_F32 (dmodelConv, pcm->smdata2d);
     542            }
    522543        } else {
    523544            psImageConvolveFFT (dmodelConv, dmodel, NULL, 0, pcm->psf);
     
    541562    static int Npass = 0;
    542563    char name[128];
    543     snprintf (name, 128, "psf.%03d.fits", Npass); psphotSaveImage (NULL, pcm->psf->image, name);
     564    if (!pcm->use1Dgauss) {
     565      snprintf (name, 128, "psf.%03d.fits", Npass); psphotSaveImage (NULL, pcm->psf->image, name);
     566    }
    544567    snprintf (name, 128, "mod.%03d.fits", Npass); psphotSaveImage (NULL, pcm->modelFlux, name);
    545568    snprintf (name, 128, "cnv.%03d.fits", Npass); psphotSaveImage (NULL, pcm->modelConvFlux, name);
     
    579602
    580603            float ymodel  = pcm->modelConvFlux->data.F32[i][j];
    581             float yweight = 1.0 / source->variance->data.F32[i][j];
     604
     605            // XXXX note this point here:::
     606            float yweight = pcm->poissonErrors ? 1.0 / source->variance->data.F32[i][j] : 1.0;
    582607            float delta = ymodel - source->pixels->data.F32[i][j];
    583608
  • trunk/psModules/src/objects/pmPCMdata.c

    r36089 r36375  
    4343
    4444# define USE_DELTA_PSF 0
    45 # define USE_1D_GAUSS 1
    4645
    4746static void pmPCMdataFree (pmPCMdata *pcm) {
     
    5857    psFree (pcm->psfFFT);
    5958    psFree (pcm->constraint);
     59
    6060    psFree (pcm->smdata); // pre-allocated data for psImageSmooth_PreAlloc
     61    psFree (pcm->smdata2d); // pre-allocated data for psImageSmooth_PreAlloc
    6162    return;
    6263}
     
    8889    }
    8990
     91    pcm->smdata = NULL;
     92    pcm->smdata2d = NULL;
     93
    9094    pcm->modelConv = NULL;
    9195    pcm->psf = NULL;
     
    9498    pcm->nDOF = 0;
    9599
     100    pcm->poissonErrors = true;
     101
    96102    // full convolution with the PSF is expensive.  if we have to save time, we can do a 1D
    97103    // convolution with a Gaussian approximation to the kernel
    98104    pcm->use1Dgauss = false;
    99     pcm->nsigma = 3.0;
     105    pcm->nsigma = NAN; // this is set to something defined by the user
    100106    pcm->sigma = 1.0; // this should be set to something sensible when the psf is known
    101107
     
    248254}
    249255
     256static int modelType_GAUSS = -1;
     257static int modelType_PS1_V1 = -1;
     258
     259// generate a Gaussian smoothing kernel for supplied sigma.  sigma here does not need to match
     260// that used to allocate the structure, but it is recommended
     261bool psImageSmoothCacheKernel_PS1_V1 (psImageSmoothCacheData *smdata, float sigma, float kappa) {
     262    // check for NULL structure elements?
     263
     264    int size = smdata->Nrange;
     265
     266    psFree (smdata->kernel);
     267    smdata->kernel = psVectorAlloc(2 * smdata->Nrange + 1, PS_TYPE_F32);
     268
     269    double sum = 0.0;                   // Sum of Gaussian, for normalization
     270    double factor = 1.0 / (sigma * M_SQRT2);    // Multiplier for i -> z
     271
     272    // PS1_V1 is a power-law with fitted linear term:
     273    // 1 / (1 + kappa z + z^1.666)  where z = (r/sigma)^2
     274
     275    // generate the kernel (not normalized)
     276    for (int i = -size, j = 0; i <= size; i++, j++) {
     277        float z = PS_SQR(i * factor);
     278        sum += smdata->kernel->data.F32[j] = 1.0 / (1 + kappa * z + pow(z,1.666));
     279    }
     280
     281    // renormalize kernel to integral of 1.0
     282    for (int i = 0; i < 2 * size + 1; i++) {
     283        smdata->kernel->data.F32[i] /= sum;
     284    }
     285
     286    return true;
     287}
     288
     289psImageSmoothCacheData *psImageSmoothCacheSetKernel (float *sigma, float *kappa, float nsigma, psImage *flux, pmModel *modelPSF) {
     290
     291    psAssert (modelPSF, "psf model must be defined");
     292   
     293    psEllipseAxes axes;
     294    bool useReff = pmModelUseReff (modelPSF->type);
     295    psF32 *PAR = modelPSF->params->data.F32;
     296    pmModelParamsToAxes (&axes, PAR[PM_PAR_SXX], PAR[PM_PAR_SXY], PAR[PM_PAR_SYY], useReff);
     297   
     298    *sigma = NAN;
     299    *kappa = NAN;
     300
     301    // XXX need to do this more carefully
     302    if (modelPSF->type == modelType_GAUSS) {
     303        float FWHM_MAJOR = 2*modelPSF->modelRadius (modelPSF->params, 0.5*PAR[PM_PAR_I0]);
     304        float FWHM_MINOR = FWHM_MAJOR * (axes.minor / axes.major);
     305        *sigma = 0.50 * (FWHM_MAJOR + FWHM_MINOR) / 2.35;
     306    }
     307    if (modelPSF->type == modelType_PS1_V1) {
     308        *sigma = 0.5 * (axes.major + axes.minor);
     309        *kappa = PAR[PM_PAR_7];
     310    }
     311    psAssert (isfinite(*sigma), "invalid model type");
     312
     313    // psImageSmoothCacheAlloc generates a structure but does not assign the smoothing vector
     314    psImageSmoothCacheData *smdata = psImageSmoothCacheAlloc (flux, *sigma, nsigma);
     315
     316    if (modelPSF->type == modelType_GAUSS) {
     317        psImageSmoothCacheKernel_Gauss (smdata, *sigma);
     318    }
     319    if (modelPSF->type == modelType_PS1_V1) {
     320        psImageSmoothCacheKernel_PS1_V1 (smdata, *sigma, *kappa);
     321    }
     322
     323    return smdata;
     324}
     325
     326psImageSmooth2dCacheData *psImageSmooth2dCacheSetKernel (float *sigma, float *kappa, float nsigma, psImage *flux, pmModel *modelPSF) {
     327
     328    psAssert (modelPSF, "psf model must be defined");
     329   
     330    psEllipseAxes axes;
     331    bool useReff = pmModelUseReff (modelPSF->type);
     332    psF32 *PAR = modelPSF->params->data.F32;
     333    pmModelParamsToAxes (&axes, PAR[PM_PAR_SXX], PAR[PM_PAR_SXY], PAR[PM_PAR_SYY], useReff);
     334   
     335    *sigma = NAN;
     336    *kappa = NAN;
     337
     338    // XXX need to do this more carefully
     339    if (modelPSF->type == modelType_GAUSS) {
     340        float FWHM_MAJOR = 2*modelPSF->modelRadius (modelPSF->params, 0.5*PAR[PM_PAR_I0]);
     341        float FWHM_MINOR = FWHM_MAJOR * (axes.minor / axes.major);
     342        *sigma = 0.50 * (FWHM_MAJOR + FWHM_MINOR) / 2.35;
     343    }
     344    if (modelPSF->type == modelType_PS1_V1) {
     345        *sigma = 0.5 * (axes.major + axes.minor);
     346        *kappa = PAR[PM_PAR_7];
     347    }
     348    psAssert (isfinite(*sigma), "invalid model type");
     349
     350    // psImageSmoothCacheAlloc generates a structure but does not assign the smoothing vector
     351    psImageSmooth2dCacheData *smdata = psImageSmooth2dCacheAlloc (nsigma);
     352
     353    if (modelPSF->type == modelType_GAUSS) {
     354        psImageSmooth2dCacheKernel_Gauss (smdata, *sigma);
     355    }
     356    if (modelPSF->type == modelType_PS1_V1) {
     357        psImageSmooth2dCacheKernel_PS1_V1 (smdata, *sigma, *kappa);
     358    }
     359
     360    return smdata;
     361}
     362
    250363pmPCMdata *pmPCMinit(pmSource *source, pmSourceFitOptions *fitOptions, pmModel *model, psImageMaskType maskVal, float psfSize) {
    251364
    252     // make sure we save a cached copy of the psf flux
    253     pmSourceCachePSF (source, maskVal);
    254 
    255     // convert the cached cached psf model for this source to a psKernel
    256     psKernel *psf = pmPCMkernelFromPSF (source, psfSize);
    257     if (!psf) {
    258         // NOTE: this only happens if the source is too close to an edge
    259         model->flags |= PM_MODEL_STATUS_BADARGS;
    260         return NULL;
    261     }
    262 
    263 # if (USE_DELTA_PSF)
    264     psImageInit (psf->image, 0.0);
    265     psf->image->data.F32[(int)(0.5*psf->image->numRows)][(int)(0.5*psf->image->numCols)] = 1.0;
    266 # endif
     365    modelType_GAUSS = pmModelClassGetType ("PS_MODEL_GAUSS");
     366    modelType_PS1_V1 = pmModelClassGetType ("PS_MODEL_PS1_V1");
    267367
    268368    // count the number of unmasked pixels:
     
    298398    if (nPix <  nParams + 1) {
    299399        psTrace ("psModules.objects", 4, "insufficient valid pixels\n");
    300         psFree (psf);
    301400        psFree (constraint);
    302401        model->flags |= PM_MODEL_STATUS_BADARGS;
     
    306405    // generate PCM data storage structure
    307406    pmPCMdata *pcm = pmPCMdataAlloc (params, constraint->paramMask, source);
    308 
    309     pcm->psf = psf;
    310407    pcm->modelConv = psMemIncrRefCounter(model);
    311408    pcm->constraint = constraint;
     409
     410    pcm->poissonErrors = fitOptions->poissonErrors;
     411    pcm->nsigma = fitOptions->nsigma;
    312412
    313413    pcm->nPix = nPix;
     
    316416
    317417# if (USE_1D_GAUSS)
    318     pmModel *modelPSF = source->modelPSF;
    319     psAssert (modelPSF, "psf model must be defined");
    320    
    321     psEllipseAxes axes;
    322     bool useReff = pmModelUseReff (modelPSF->type);
    323     psF32 *PAR = modelPSF->params->data.F32;
    324     pmModelParamsToAxes (&axes, PAR[PM_PAR_SXX], PAR[PM_PAR_SXY], PAR[PM_PAR_SYY], useReff);
    325    
    326     float FWHM_MAJOR = 2*modelPSF->modelRadius (modelPSF->params, 0.5*PAR[PM_PAR_I0]);
    327     float FWHM_MINOR = FWHM_MAJOR * (axes.minor / axes.major);
    328418
    329419    pcm->use1Dgauss = true;
    330     pcm->sigma = 0.5 * (FWHM_MAJOR + FWHM_MINOR) / 2.35;
    331     pcm->nsigma = 2.0;
    332 
    333     pcm->smdata = psImageSmooth_PreAlloc_DataAlloc (source->pixels, pcm->sigma, pcm->nsigma);
     420    if (USE_1D_CACHE) {
     421        pcm->smdata = psImageSmoothCacheSetKernel (&pcm->sigma, &pcm->kappa, pcm->nsigma, source->pixels, source->modelPSF);
     422    } else {
     423        pcm->smdata2d = psImageSmooth2dCacheSetKernel (&pcm->sigma, &pcm->kappa, pcm->nsigma, source->pixels, source->modelPSF);
     424    }
     425
    334426# else
     427    // make sure we save a cached copy of the psf flux
     428    pmSourceCachePSF (source, maskVal);
     429
     430    // convert the cached cached psf model for this source to a psKernel
     431    psKernel *psf = pmPCMkernelFromPSF (source, psfSize);
     432    if (!psf) {
     433        // NOTE: this only happens if the source is too close to an edge
     434        model->flags |= PM_MODEL_STATUS_BADARGS;
     435        return NULL;
     436    }
     437
     438# if (USE_DELTA_PSF)
     439    psImageInit (psf->image, 0.0);
     440    psf->image->data.F32[(int)(0.5*psf->image->numRows)][(int)(0.5*psf->image->numCols)] = 1.0;
     441# endif
     442    pcm->psf = psf;
    335443    pcm->smdata = NULL;
    336444# endif
     
    395503            pcm->dmodelsConvFlux->data[n] = psImageCopy (pcm->dmodelsConvFlux->data[n], source->pixels, PS_TYPE_F32);
    396504        }
    397         psFree(pcm->smdata);
    398         pcm->smdata = psImageSmooth_PreAlloc_DataAlloc (source->pixels, pcm->sigma, pcm->nsigma);
     505
     506        // If we have changed the window, we need to redefine the smoothing target vectors (but pcm->sigma,kappa,nsigma remain)
     507        if (USE_1D_CACHE) {
     508            psFree(pcm->smdata);
     509            pcm->smdata = psImageSmoothCacheAlloc (source->pixels, pcm->sigma, pcm->nsigma);
     510
     511            pmModel *modelPSF = source->modelPSF;
     512            if (modelPSF->type == modelType_GAUSS) {
     513                psImageSmoothCacheKernel_Gauss (pcm->smdata, pcm->sigma);
     514            }
     515            if (modelPSF->type == modelType_PS1_V1) {
     516                psImageSmoothCacheKernel_PS1_V1 (pcm->smdata, pcm->sigma, pcm->kappa);
     517            }
     518        } else {
     519            psFree(pcm->smdata2d);
     520            pcm->smdata2d = psImageSmooth2dCacheAlloc (pcm->nsigma);
     521
     522            pmModel *modelPSF = source->modelPSF;
     523            if (modelPSF->type == modelType_GAUSS) {
     524                // psImageSmooth2dCacheKernel_Gauss (pcm->smdata2d, pcm->sigma);
     525            }
     526            if (modelPSF->type == modelType_PS1_V1) {
     527                psImageSmooth2dCacheKernel_PS1_V1 (pcm->smdata2d, pcm->sigma, pcm->kappa);
     528            }
     529        }
    399530    }
    400531
     
    403534
    404535// construct a realization of the source model
    405 bool pmPCMCacheModel (pmSource *source, psImageMaskType maskVal, int psfSize) {
     536bool pmPCMCacheModel (pmSource *source, psImageMaskType maskVal, int psfSize, float nsigma) {
    406537
    407538    PS_ASSERT_PTR_NON_NULL(source, false);
     
    420551    // convolve the model image with the PSF
    421552    if (USE_1D_GAUSS) {
    422         // do not use the threaded, mask-aware version of this code (psImageSmoothMaskPixelsThread):
    423         // * the model flux is not masked
    424         // * threading takes place above this level
    425553       
    426         // define the Gauss parameters from the psf
    427         pmModel *modelPSF = source->modelPSF;
    428         psAssert (modelPSF, "psf model must be defined");
    429    
    430         psEllipseAxes axes;
    431         bool useReff = pmModelUseReff (modelPSF->type);
    432         psF32 *PAR = modelPSF->params->data.F32;
    433         pmModelParamsToAxes (&axes, PAR[PM_PAR_SXX], PAR[PM_PAR_SXY], PAR[PM_PAR_SYY], useReff);
    434    
    435         float FWHM_MAJOR = 2*modelPSF->modelRadius (modelPSF->params, 0.5*PAR[PM_PAR_I0]);
    436         float FWHM_MINOR = FWHM_MAJOR * (axes.minor / axes.major);
    437 
    438         float sigma = 0.5 * (FWHM_MAJOR + FWHM_MINOR) / 2.35;
    439         float nsigma = 2.0;
    440 
    441         psImageSmooth (source->modelFlux, sigma, nsigma);
     554        float sigma = NAN;
     555        float kappa = NAN;
     556
     557        if (USE_1D_CACHE) {
     558            psImageSmoothCacheData *smdata = psImageSmoothCacheSetKernel (&sigma, &kappa, nsigma, source->modelFlux, source->modelPSF);
     559            psImageSmoothCache_F32 (source->modelFlux, smdata);
     560            psFree (smdata);
     561        } else {
     562            psImageSmooth2dCacheData *smdata = psImageSmooth2dCacheSetKernel (&sigma, &kappa, nsigma, source->modelFlux, source->modelPSF);
     563            psImageSmooth2dCache_F32 (source->modelFlux, smdata);
     564            psFree (smdata);
     565        }
     566        // old call: psImageSmooth (source->modelFlux, sigma, nsigma);
    442567    } else {
    443568        // make sure we save a cached copy of the psf flux
     
    459584
    460585// construct a realization of the source model
    461 bool pmPCMMakeModel (pmSource *source, pmModel *model, psImageMaskType maskVal, int psfSize) {
     586bool pmPCMMakeModel (pmSource *source, pmModel *model, float Nsigma, psImageMaskType maskVal, int psfSize) {
    462587
    463588    PS_ASSERT_PTR_NON_NULL(source, false);
     
    468593
    469594    // modelFlux always has unity normalization (I0 = 1.0)
    470     pmModelAdd (source->modelFlux, source->maskObj, model, PM_MODEL_OP_FULL | PM_MODEL_OP_NORM, maskVal);
     595    // pmModelAdd (source->modelFlux, source->maskObj, model, PM_MODEL_OP_FULL | PM_MODEL_OP_NORM, maskVal);
     596    pmModelAdd (source->modelFlux, NULL, model, PM_MODEL_OP_FULL | PM_MODEL_OP_SKY | PM_MODEL_OP_NORM, maskVal);
    471597
    472598    // convolve the model image with the PSF
    473599    if (USE_1D_GAUSS) {
    474         // do not use the threaded, mask-aware version of this code (psImageSmoothMaskPixelsThread):
    475         // * the model flux is not masked
    476         // * threading takes place above this level
    477        
    478         // define the Gauss parameters from the psf
    479         pmModel *modelPSF = source->modelPSF;
    480         psAssert (modelPSF, "psf model must be defined");
    481    
    482         psEllipseAxes axes;
    483         bool useReff = pmModelUseReff (modelPSF->type);
    484         psF32 *PAR = modelPSF->params->data.F32;
    485         pmModelParamsToAxes (&axes, PAR[PM_PAR_SXX], PAR[PM_PAR_SXY], PAR[PM_PAR_SYY], useReff);
    486    
    487         float FWHM_MAJOR = 2*modelPSF->modelRadius (modelPSF->params, 0.5*PAR[PM_PAR_I0]);
    488         float FWHM_MINOR = FWHM_MAJOR * (axes.minor / axes.major);
    489 
    490         float sigma = 0.5 * (FWHM_MAJOR + FWHM_MINOR) / 2.35;
    491         float nsigma = 2.0;
    492 
    493         psImageSmooth (source->modelFlux, sigma, nsigma);
     600
     601        float sigma = NAN;
     602        float kappa = NAN;
     603
     604        if (USE_1D_CACHE) {
     605            psImageSmoothCacheData *smdata = psImageSmoothCacheSetKernel (&sigma, &kappa, Nsigma, source->modelFlux, source->modelPSF);
     606            psImageSmoothCache_F32 (source->modelFlux, smdata);
     607            psFree (smdata);
     608        } else {
     609            psImageSmooth2dCacheData *smdata = psImageSmooth2dCacheSetKernel (&sigma, &kappa, Nsigma, source->modelFlux, source->modelPSF);
     610            psImageSmooth2dCache_F32 (source->modelFlux, smdata);
     611            psFree (smdata);
     612        }
     613        // old call: psImageSmooth (source->modelFlux, sigma, nsigma);
    494614    } else {
    495615        // make sure we save a cached copy of the psf flux
     
    509629    return true;
    510630}
    511 
  • trunk/psModules/src/objects/pmPCMdata.h

    r36085 r36375  
    1414/// @addtogroup Objects Object Detection / Analysis Functions
    1515/// @{
     16
     17// XXX this is basically for testing -- when I am happy with the convolution process, I'll strip this out
     18# define USE_1D_CACHE 0
     19# define USE_1D_GAUSS 1
    1620
    1721/** pmPCMdata : PSF Convolved Model data storage structure
     
    3640    int nDOF;
    3741
     42    bool poissonErrors;
     43
    3844    bool use1Dgauss;
     45    float kappa;
    3946    float sigma;
    4047    float nsigma;
    4148
    42     psImageSmooth_PreAlloc_Data *smdata;
     49    // psArray *smdata;
     50    psImageSmoothCacheData *smdata;
     51    psImageSmooth2dCacheData *smdata2d;
    4352} pmPCMdata;
    4453
     
    96105bool pmSourceFitPCM (pmPCMdata *pcm, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal, int psfSize);
    97106
    98 bool pmPCMCacheModel (pmSource *source, psImageMaskType maskVal, int psfSize);
     107bool pmPCMCacheModel (pmSource *source, psImageMaskType maskVal, int psfSize, float nsigma);
    99108
    100 bool pmPCMMakeModel (pmSource *source, pmModel *model, psImageMaskType maskVal, int psfSize);
     109bool pmPCMMakeModel (pmSource *source, pmModel *model, float Nsigma, psImageMaskType maskVal, int psfSize);
    101110
    102111/// @}
  • trunk/psModules/src/objects/pmSource.c

    r35768 r36375  
    6666    psFree(tmp->extpars);
    6767    psFree(tmp->diffStats);
     68    psFree(tmp->galaxyFits);
    6869    psFree(tmp->radialAper);
    6970    psTrace("psModules.objects", 10, "---- end ----\n");
     
    164165    source->extpars = NULL;
    165166    source->diffStats = NULL;
     167    source->galaxyFits = NULL;
    166168    source->radialAper = NULL;
    167169    source->parent = NULL;
     
    690692            // why do we recalculate moments here?
    691693            // we already attempt to do this in psphotSourceStats
    692             // pmSourceMoments (source, INNER_RADIUS);
    693694            Nsatstar ++;
    694695            continue;
     
    804805    return true;
    805806}
    806 
    807 /******************************************************************************
    808 pmSourceMoments(source, radius): this function takes a subImage defined in the
    809 pmSource data structure, along with the peak location, and determines the
    810 various moments associated with that peak.
    811 
    812 Requires the following to have been created:
    813     pmSource
    814     pmSource->peak
    815     pmSource->pixels
    816     pmSource->variance
    817     pmSource->mask
    818 
    819 XXX: The peak calculations are done in image coords, not subImage coords.
    820 
    821 XXX EAM : this version clips input pixels on S/N
    822 XXX EAM : this version returns false for several reasons
    823 *****************************************************************************/
    824 # define VALID_RADIUS(X,Y,RAD2) (((RAD2) >= (PS_SQR(X) + PS_SQR(Y))) ? 1 : 0)
    825 
    826 /*** this been moved to pmSourceMoments.c ***/
    827 # if (0)
    828 bool pmSourceMoments(pmSource *source,
    829                      psF32 radius)
    830 {
    831     psTrace("psModules.objects", 10, "---- begin ----\n");
    832     PS_ASSERT_PTR_NON_NULL(source, false);
    833     PS_ASSERT_PTR_NON_NULL(source->peak, false);
    834     PS_ASSERT_PTR_NON_NULL(source->pixels, false);
    835     PS_ASSERT_FLOAT_LARGER_THAN(radius, 0.0, false);
    836 
    837     //
    838     // XXX: Verify the setting for sky if source->moments == NULL.
    839     //
    840     psF32 sky = 0.0;
    841     if (source->moments == NULL) {
    842         source->moments = pmMomentsAlloc();
    843     } else {
    844         sky = source->moments->Sky;
    845     }
    846 
    847     //
    848     // Sum = SUM (z - sky)
    849     // X1  = SUM (x - xc)*(z - sky)
    850     // X2  = SUM (x - xc)^2 * (z - sky)
    851     // XY  = SUM (x - xc)*(y - yc)*(z - sky)
    852     //
    853     psF32 peakPixel = -PS_MAX_F32;
    854     psS32 numPixels = 0;
    855     psF32 Sum = 0.0;
    856     psF32 Var = 0.0;
    857     psF32 X1 = 0.0;
    858     psF32 Y1 = 0.0;
    859     psF32 X2 = 0.0;
    860     psF32 Y2 = 0.0;
    861     psF32 XY = 0.0;
    862     psF32 x  = 0;
    863     psF32 y  = 0;
    864     psF32 R2 = PS_SQR(radius);
    865 
    866     psF32 xPeak = source->peak->x;
    867     psF32 yPeak = source->peak->y;
    868     psF32 xOff = source->pixels->col0 - source->peak->x;
    869     psF32 yOff = source->pixels->row0 - source->peak->y;
    870 
    871     // XXX why do I get different results for these two methods of finding Sx?
    872     // XXX Sx, Sy would be better measured if we clip pixels close to sky
    873     // XXX Sx, Sy can still be imaginary, so we probably need to keep Sx^2?
    874     // We loop through all pixels in this subimage (source->pixels), and for each
    875     // pixel that is not masked, AND within the radius of the peak pixel, we
    876     // proceed with the moments calculation.  need to do two loops for a
    877     // numerically stable result.  first loop: get the sums.
    878     // XXX EAM : mask == 0 is valid
    879 
    880     for (psS32 row = 0; row < source->pixels->numRows ; row++) {
    881 
    882         psF32 *vPix = source->pixels->data.F32[row];
    883         psF32 *vWgt = source->variance->data.F32[row];
    884         psImageMaskType *vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[row];
    885 
    886         for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) {
    887             if (vMsk) {
    888                 if (*vMsk) {
    889                     vMsk++;
    890                     psTrace("psModules.objects", 10, "Ignoring pixel %d,%d due to mask: %d\n",
    891                             col, row, (int)*vMsk);
    892                     continue;
    893                 }
    894                 vMsk++;
    895             }
    896             if (isnan(*vPix)) continue;
    897 
    898             psF32 xDiff = col + xOff;
    899             psF32 yDiff = row + yOff;
    900 
    901             // radius is just a function of (xDiff, yDiff)
    902             if (!VALID_RADIUS(xDiff, yDiff, R2)) {
    903 #if 1
    904                 psTrace("psModules.objects", 10, "Ignoring pixel %d,%d due to position: %f %f\n",
    905                         col, row, xDiff, yDiff);
    906 #endif
    907                 continue;
    908             }
    909 
    910             psF32 pDiff = *vPix - sky;
    911             psF32 wDiff = *vWgt;
    912 
    913             // XXX EAM : check for valid S/N in pixel
    914             // XXX EAM : should this limit be user-defined?
    915 #if 1
    916             if (PS_SQR(pDiff) < wDiff) {
    917                 psTrace("psModules.objects", 10, "Ignoring pixel %d,%d due to insignificance: %f, %f\n",
    918                         col, row, pDiff, wDiff);
    919                 continue;
    920             }
    921 #endif
    922 
    923             Var += wDiff;
    924             Sum += pDiff;
    925 
    926             psF32 xWght = xDiff * pDiff;
    927             psF32 yWght = yDiff * pDiff;
    928 
    929             X1  += xWght;
    930             Y1  += yWght;
    931 
    932             XY  += xDiff * yWght;
    933             X2  += xDiff * xWght;
    934             Y2  += yDiff * yWght;
    935 
    936             peakPixel = PS_MAX (*vPix, peakPixel);
    937             numPixels++;
    938         }
    939     }
    940 
    941     // if we have less than (1/4) of the possible pixels, force a retry
    942     // XXX EAM - the limit is a bit arbitrary.  make it user defined?
    943     if ((numPixels < 0.75*R2) || (Sum <= 0)) {
    944         psTrace ("psModules.objects", 3, "insufficient valid pixels (%d vs %d; %f) for source\n",
    945                  numPixels, (int)(0.75*R2), Sum);
    946         psTrace("psModules.objects", 10, "---- end (false) ----\n");
    947         return (false);
    948     }
    949 
    950     psTrace ("psModules.objects", 4, "sky: %f  Sum: %f  X1: %f  Y1: %f  X2: %f  Y2: %f  XY: %f  Npix: %d\n",
    951              sky, Sum, X1, Y1, X2, Y2, XY, numPixels);
    952 
    953     //
    954     // first moment X  = X1/Sum + xc
    955     // second moment X = sqrt (X2/Sum - (X1/Sum)^2)
    956     // Sxy             = XY / Sum
    957     //
    958     x = X1/Sum;
    959     y = Y1/Sum;
    960     if ((fabs(x) > radius) || (fabs(y) > radius)) {
    961         psTrace ("psModules.objects", 3, "large centroid swing; invalid peak %d, %d\n",
    962                  source->peak->x, source->peak->y);
    963         psTrace("psModules.objects", 10, "---- end(false)  ----\n");
    964         return (false);
    965     }
    966 
    967     source->moments->Mx = x + xPeak;
    968     source->moments->My = y + yPeak;
    969 
    970     // XXX EAM : Sxy needs to have x*y subtracted
    971     source->moments->Mxy = XY/Sum - x*y;
    972     source->moments->Sum = Sum;
    973     source->moments->SN  = Sum / sqrt(Var);
    974     source->moments->Peak = peakPixel;
    975     source->moments->nPixels = numPixels;
    976 
    977     // XXX EAM : these values can be negative, so we need to limit the range
    978     // XXX EAM : make the use of this consistent: should this be the second moment or sqrt?
    979     // source->moments->Mxx = sqrt(PS_MAX(X2/Sum - PS_SQR(x), 0));
    980     // source->moments->Myy = sqrt(PS_MAX(Y2/Sum - PS_SQR(y), 0));
    981     source->moments->Mxx = PS_MAX(X2/Sum - PS_SQR(x), 0);
    982     source->moments->Myy = PS_MAX(Y2/Sum - PS_SQR(y), 0);
    983 
    984     psTrace ("psModules.objects", 4,
    985              "sky: %f  Sum: %f  Mx: %f  My: %f  Mxx: %f  Myy: %f  Mxy: %f\n",
    986              sky, Sum, source->moments->Mx, source->moments->My,
    987              source->moments->Mxx, source->moments->Myy, source->moments->Mxy);
    988 
    989     psTrace("psModules.objects", 10, "---- end ----\n");
    990     return(true);
    991 }
    992 # endif
    993807
    994808// construct a realization of the source model
  • trunk/psModules/src/objects/pmSource.h

    r34403 r36375  
    4040    PM_SOURCE_TMPF_PETRO_KEEP        = 0x0100,
    4141    PM_SOURCE_TMPF_PETRO_SKIP        = 0x0200,
     42    PM_SOURCE_TMPF_EXT_FIT           = 0x0400,  // not just galaxies (trails as well)
     43    PM_SOURCE_TMPF_PETRO             = 0x0800,
    4244} pmSourceTmpF;
    4345
     
    117119    pmSourceExtendedPars *extpars;      ///< extended source parameters
    118120    pmSourceDiffStats *diffStats;       ///< extra parameters for difference detections
     121    pmSourceGalaxyFits *galaxyFits;     ///< fits to galaxy models (psphotFullForce only)
    119122    psArray *radialAper;                ///< radial flux in circular apertures
    120123    pmSource *parent;                   ///< reference to the master source from which this is derived
  • trunk/psModules/src/objects/pmSourceExtendedPars.c

    r34403 r36375  
    286286    return pars;
    287287}
     288
     289// *** pmSourceExtFitPars describes extra metadata related to an extended fit
     290static void pmSourceGalaxyFitsFree (pmSourceGalaxyFits *tmp) {
     291 
     292    psFree (tmp->Flux);
     293    psFree (tmp->dFlux);
     294    psFree (tmp->chisq);
     295
     296    return;
     297}
     298
     299pmSourceGalaxyFits *pmSourceGalaxyFitsAlloc (void) {
     300
     301    pmSourceGalaxyFits *tmp = (pmSourceGalaxyFits *) psAlloc(sizeof(pmSourceGalaxyFits));
     302    psMemSetDeallocator(tmp, (psFreeFunc) pmSourceGalaxyFitsFree);
     303
     304    tmp->Flux  = psVectorAllocEmpty (25, PS_TYPE_F32);
     305    tmp->dFlux = psVectorAllocEmpty (25, PS_TYPE_F32);
     306    tmp->chisq = psVectorAllocEmpty (25, PS_TYPE_F32);
     307    tmp->nPix = 0;
     308
     309    return tmp;
     310}
  • trunk/psModules/src/objects/pmSourceExtendedPars.h

    r32347 r36375  
    8282} pmSourceExtFitPars;
    8383
     84typedef struct {
     85  psVector *Flux;
     86  psVector *dFlux;
     87  psVector *chisq;
     88  int nPix;
     89} pmSourceGalaxyFits;
     90
    8491pmSourceRadialFlux *pmSourceRadialFluxAlloc();
    8592bool psMemCheckSourceRadialFlux(psPtr ptr);
     
    109116pmSourceExtFitPars *pmSourceExtFitParsAlloc (void);
    110117
     118pmSourceGalaxyFits *pmSourceGalaxyFitsAlloc (void);
     119
     120
    111121/// @}
    112122# endif /* PM_SOURCE_H */
  • trunk/psModules/src/objects/pmSourceFitModel.c

    r36085 r36375  
    5959    opt->maxTol = 1.00;
    6060    opt->weight = 1.00;
     61    opt->nsigma = 5.00;
    6162    opt->maxChisqDOF = NAN;
    6263    opt->poissonErrors = true;
     
    281282    // set the model success or failure status
    282283    model->flags |= PM_MODEL_STATUS_FITTED;
    283     if (!fitStatus) model->flags |= PM_MODEL_STATUS_NONCONVERGE;
     284    if (!fitStatus) {
     285        if (isnan(myMin->value)) {
     286          model->flags |= PM_MODEL_STATUS_NAN_CHISQ;
     287        } else {
     288          model->flags |= PM_MODEL_STATUS_NONCONVERGE;
     289        }
     290    }
    284291
    285292    if (myMin->chisqConvergence) {
  • trunk/psModules/src/objects/pmSourceFitModel.h

    r36085 r36375  
    3434    float weight;                       ///< use this weight for constant-weight fits
    3535    float covarFactor;                  ///< covariance factor for calculating the chisq
     36    float nsigma;                       ///< how far out to convolve
    3637    bool poissonErrors;                 ///< use poisson errors for fits?
    3738    bool saveCovariance;
  • trunk/psModules/src/objects/pmSourceFitPCM.c

    r36085 r36375  
    5151# define TIMING 0
    5252
     53bool pmSourceChisqModelFlux (pmSource *source, pmModel *model, psImageMaskType maskVal);
     54
    5355bool pmSourceFitPCM (pmPCMdata *pcm, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal, int psfSize) {
    5456   
     
    113115    } else {
    114116        // xxx this is wrong because it does not convolve with the psf
    115         pmSourceChisqUnsubtracted (source, pcm->modelConv, maskVal);
     117        pmPCMMakeModel (source, pcm->modelConv, pcm->nsigma, maskVal, psfSize);
     118        pmSourceChisqModelFlux (source, pcm->modelConv, maskVal);
    116119    }
    117120    if (TIMING) { t4 = psTimerMark ("pmSourceFitPCM"); }
     
    119122    // set the model success or failure status
    120123    pcm->modelConv->flags |= PM_MODEL_STATUS_FITTED;
    121     if (!fitStatus) pcm->modelConv->flags |= PM_MODEL_STATUS_NONCONVERGE;
     124
     125    if (!fitStatus) {
     126        if (isnan(myMin->value)) {
     127            pcm->modelConv->flags |= PM_MODEL_STATUS_NAN_CHISQ;
     128        } else {
     129            pcm->modelConv->flags |= PM_MODEL_STATUS_NONCONVERGE;
     130        }
     131    }
    122132
    123133    if (myMin->chisqConvergence) {
  • trunk/psModules/src/objects/pmSourceFitSet.c

    r36085 r36375  
    352352        // set the model success or failure status
    353353        model->flags |= PM_MODEL_STATUS_FITTED;
    354         if (!fitStatus) model->flags |= PM_MODEL_STATUS_NONCONVERGE;
     354        if (!fitStatus) {
     355          if (isnan(myMin->value)) {
     356            model->flags |= PM_MODEL_STATUS_NAN_CHISQ;
     357          } else {
     358            model->flags |= PM_MODEL_STATUS_NONCONVERGE;
     359          }
     360        }
    355361
    356362        // models can go insane: reject these
  • trunk/psModules/src/objects/pmSourceIO.c

    r35610 r36375  
    6969                        psString *xfitname,    // Extension name for extended fitted measurements
    7070                        psString *xradname,    // Extension name for radial apertures
     71                        psString *xgalname,    // Extension name for galaxy shapes
    7172                        const pmFPAfile *file, // File of interest
    7273                        const pmFPAview *view  // View to level of interest
     
    140141        }
    141142        *xradname = pmFPAfileNameFromRule (rule, file, view);
     143    }
     144
     145    // EXTNAME for radial apertures
     146    if (xgalname) {
     147        const char *rule = psMetadataLookupStr(&status, menu, "CMF.XGAL");
     148        if (!rule) {
     149            psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.XGAL in EXTNAME.RULES in camera.config");
     150            return false;
     151        }
     152        *xgalname = pmFPAfileNameFromRule (rule, file, view);
    142153    }
    143154
     
    362373            status &= pmSourcesWrite_##TYPE##_XRAD (file->fits, readout, sources, file->header, xradname, recipe); \
    363374        }                                                               \
     375        if (xgalname) {                                                 \
     376            status &= pmSourcesWrite_##TYPE##_XGAL (file->fits, sources, xgalname, recipe); \
     377        }                                                               \
    364378    }
    365379
     
    464478        }
    465479
    466         // if this is not TRUE, the output files only contain the psf measurements.
    467         bool XSRC_OUTPUT = psMetadataLookupBool(&status, recipe, "EXTENDED_SOURCE_ANALYSIS");
     480        // if none of these are TRUE, the output files only contain the psf measurements.
     481        bool doPetrosian = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_PETROSIAN");
     482        bool doAnnuli    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANNULI");
     483        bool XSRC_OUTPUT = doPetrosian || doAnnuli;
    468484        bool XFIT_OUTPUT = psMetadataLookupBool(&status, recipe, "EXTENDED_SOURCE_FITS");
    469485        bool XRAD_OUTPUT = psMetadataLookupBool(&status, recipe, "RADIAL_APERTURES");
     486        bool XGAL_OUTPUT = psMetadataLookupBool(&status, recipe, "GALAXY_SHAPES");
    470487
    471488        // define the EXTNAME values for the different data segments:
     
    476493        psString xfitname = NULL;
    477494        psString xradname = NULL;
     495        psString xgalname = NULL;
    478496        if (!pmSourceIOextnames(&headname, &dataname, &deteffname,
    479497                                XSRC_OUTPUT ? &xsrcname : NULL,
    480498                                XFIT_OUTPUT ? &xfitname : NULL,
    481499                                XRAD_OUTPUT ? &xradname : NULL,
     500                                XGAL_OUTPUT ? &xgalname : NULL,
    482501                                file, view)) {
    483502            return false;
     
    563582                psMetadataAddStr (outhead, PS_LIST_TAIL, "XRADNAME", PS_META_REPLACE, "name of XRAD table extension", xradname);
    564583            }
     584            if (xgalname) {
     585                psMetadataAddStr (outhead, PS_LIST_TAIL, "XGALNAME", PS_META_REPLACE, "name of XGAL table extension", xgalname);
     586            }
    565587
    566588            // these are case-sensitive since the EXTYPE is case-sensitive
     
    609631        psFree (xfitname);
    610632        psFree (xradname);
     633        psFree (xgalname);
    611634        psFree (deteffname);
    612635
     
    620643        psFree (xfitname);
    621644        psFree (xradname);
     645        psFree (xgalname);
    622646        psFree (deteffname);
    623647        return false;
    624648
     649      case PM_FPA_FILE_CFF: {
     650        // determine the output table format
     651        psMetadata *recipe = psMetadataLookupMetadata(&status, config->recipes, "PSPHOT");
     652        if (!status) {
     653            psError(PS_ERR_UNKNOWN, true, "missing recipe PSPHOT in config data");
     654            return false;
     655        }
     656
     657        hdu = pmFPAviewThisHDU (view, fpa);
     658        pmConfigConformHeader(hdu->header, file->format);
     659        psFitsWriteBlank (file->fits, hdu->header, NULL);
     660        file->header = hdu->header;
     661        file->wrote_phu = true;
     662        if (!pmSourcesWrite_CFF(readout, file->fits, sources, hdu->header, recipe)) {
     663            psError(PS_ERR_UNKNOWN, false, "failed to write CFF");
     664            return false;
     665        }
     666        break;
     667      }
     668       
    625669      default:
    626670        fprintf (stderr, "warning: type mismatch\n");
     
    914958    psArray *sources = NULL;
    915959    pmHDU *hdu;
     960
     961    // define the EXTNAME values for the different data segments:
     962    psString headname = NULL;
     963    psString dataname = NULL;
     964    psString deteffname = NULL;
     965    psString xsrcname = NULL;
     966    psString xfitname = NULL;
     967    psString xradname = NULL;
     968    psString xgalname = NULL;
     969
     970    psMetadata *tableHeader = NULL;
     971    char *xtension = NULL;
    916972
    917973    switch (file->type) {
     
    9631019        hdu = pmFPAviewThisHDU (view, file->fpa);
    9641020
    965         // define the EXTNAME values for the different data segments:
    966         psString headname = NULL;
    967         psString dataname = NULL;
    968         psString deteffname = NULL;
    969         psString xsrcname = NULL;
    970         psString xfitname = NULL;
    971         psString xradname = NULL;
    972 
    9731021        // determine the output table format. Assume if we need to output extendend source
    9741022        // parameters that they may exist in the input.
     
    9811029        }
    9821030
    983         // if this is not TRUE, the output files only contain the psf measurements.
    984         bool XSRC_OUTPUT = psMetadataLookupBool(&status, recipe, "EXTENDED_SOURCE_ANALYSIS");
     1031        // if none of these are TRUE, we only read the psf measurements
     1032        // XXX: shouldn't we look for these extensions and read the regardless of the recipe values?
     1033        bool doPetrosian = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_PETROSIAN");
     1034        bool doAnnuli    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANNULI");
     1035        bool XSRC_OUTPUT = doPetrosian || doAnnuli;
    9851036        bool XFIT_OUTPUT = psMetadataLookupBool(&status, recipe, "EXTENDED_SOURCE_FITS");
    9861037        bool XRAD_OUTPUT = psMetadataLookupBool(&status, recipe, "RADIAL_APERTURES");
     1038        bool XGAL_OUTPUT = false; // psMetadataLookupBool(&status, recipe, "GALAXY_SHAPES");
    9871039
    9881040        if (!pmSourceIOextnames(&headname, &dataname, &deteffname,
     
    9901042                XFIT_OUTPUT ? &xfitname : NULL,
    9911043                XRAD_OUTPUT ? &xradname : NULL,
     1044                XGAL_OUTPUT ? &xgalname : NULL,
    9921045                file, view)) {
    9931046            return false;
     
    10331086        }
    10341087
    1035         psMetadata *tableHeader = psFitsReadHeader(NULL, file->fits); // The FITS header
     1088        tableHeader = psFitsReadHeader(NULL, file->fits); // The FITS header
    10361089        if (!tableHeader) psAbort("cannot read table header");
    10371090
    1038         char *xtension = psMetadataLookupStr (NULL, tableHeader, "XTENSION");
     1091        xtension = psMetadataLookupStr (NULL, tableHeader, "XTENSION");
    10391092        if (!xtension) psAbort("cannot read table type");
    10401093        if (strcmp (xtension, "BINTABLE")) {
     
    11321185        break;
    11331186
     1187      case PM_FPA_FILE_CFF:
     1188        // read in header, if not yet loaded
     1189        hdu = pmFPAviewThisHDU (view, file->fpa);
     1190
     1191        // look these up in the camera config?
     1192        // headrule = {CHIP.NAME}.hdr
     1193        // datarule = {CHIP.NAME}.cff
     1194
     1195        // define the EXTNAME values for the different data segments:
     1196        headname = pmFPAfileNameFromRule("{CHIP.NAME}.hdr", file, view);
     1197        dataname = pmFPAfileNameFromRule("{CHIP.NAME}.cff", file, view);
     1198
     1199        // advance to the IMAGE HEADER extension
     1200        if (hdu->header == NULL) {
     1201            // if the IMAGE header does not exist, we have no data for this view
     1202            if (!psFitsMoveExtNameClean (file->fits, headname)) {
     1203                readout->data_exists = false;
     1204                psFree (headname);
     1205                psFree (dataname);
     1206                return true;
     1207            }
     1208            hdu->header = psFitsReadHeader (NULL, file->fits);
     1209        }
     1210
     1211        // advance to the table data extension
     1212        // since we have read the IMAGE header, the TABLE header should exist
     1213        if (!psFitsMoveExtName (file->fits, dataname)) {
     1214            psAbort("cannot find data extension %s in %s", dataname, file->filename);
     1215        }
     1216
     1217        tableHeader = psFitsReadHeader(NULL, file->fits); // The FITS header
     1218        if (!tableHeader) psAbort("cannot read table header");
     1219
     1220        // verify this is a binary table
     1221        char *xtension = psMetadataLookupStr (NULL, tableHeader, "XTENSION");
     1222        if (!xtension) psAbort("cannot read table type");
     1223        if (strcmp (xtension, "BINTABLE")) {
     1224            psWarning ("no binary table in extension %s, skipping\n", dataname);
     1225            psFree(tableHeader);
     1226            return false;
     1227        }
     1228
     1229        sources = pmSourcesRead_CFF(file->fits, hdu->header);
     1230
     1231        psTrace("psModules.objects", 6, "read CMF table from %s : %s : %s", file->filename, headname, dataname);
     1232        psFree (headname);
     1233        psFree (dataname);
     1234        psFree (tableHeader);
     1235        break;
     1236
    11341237      default:
    11351238        fprintf (stderr, "warning: type mismatch\n");
  • trunk/psModules/src/objects/pmSourceIO.h

    r35610 r36375  
    2121  bool pmSourcesWrite_##TYPE##_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname); \
    2222  bool pmSourcesWrite_##TYPE##_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe); \
     23  bool pmSourcesWrite_##TYPE##_XGAL(psFits *fits, psArray *sources, char *extname, psMetadata *recipe); \
    2324  psArray *pmSourcesRead_##TYPE (psFits *fits, psMetadata *header); \
    2425  bool pmSourcesRead_##TYPE##_XSRC (psFits *fits, pmReadout *readout, psMetadata *header, psMetadata *tableHeader, psArray *sources, long *index); \
     
    5253
    5354psArray *pmSourcesReadCMP (char *filename, psMetadata *header);
     55psArray *pmSourcesRead_CFF (psFits *fits, psMetadata *header);
     56bool pmSourcesWrite_CFF (pmReadout *readout, psFits *fits, psArray *sources, psMetadata *header, psMetadata *recipe);
    5457
    5558bool pmSourcesWritePSFs (psArray *sources, char *filename);
  • trunk/psModules/src/objects/pmSourceIO_CMF.c.in

    r35768 r36375  
    789789    char name[64];
    790790
     791    pmModelType modelTypeTrail = pmModelClassGetType("PS_MODEL_TRAIL");
     792
    791793    // create a header to hold the output data
    792794    psMetadata *outhead = psMetadataAlloc ();
     
    798800    sources = psArraySort (sources, pmSourceSortByFlux);
    799801
    800     @>PS1_DV2@ float magOffset;
    801     @>PS1_DV2@ float zeroptErr;
    802     @>PS1_DV2@ float fwhmMajor;
    803     @>PS1_DV2@ float fwhmMinor;
    804     @>PS1_DV2@ pmSourceOutputsCommonValues (&magOffset, &zeroptErr, &fwhmMajor, &fwhmMinor, readout, imageHeader);
     802    float magOffset;
     803    float zeroptErr;
     804    float fwhmMajor;
     805    float fwhmMinor;
     806    pmSourceOutputsCommonValues (&magOffset, &zeroptErr, &fwhmMajor, &fwhmMinor, readout, imageHeader);
    805807
    806808    // we are writing one row per model; we need to write out same number of columns for each row: find the max Nparams
     
    823825    @>PS1_DV2@ pmChip *chip = readout->parent->parent;
    824826
     827    pmModelStatus badModel = PM_MODEL_STATUS_NONE;
     828    badModel |= PM_MODEL_STATUS_BADARGS;
     829    badModel |= PM_MODEL_STATUS_OFFIMAGE;
     830    badModel |= PM_MODEL_STATUS_NAN_CHISQ;
     831    badModel |= PM_MODEL_SERSIC_PCM_FAIL_GUESS;
     832    badModel |= PM_MODEL_SERSIC_PCM_FAIL_GRID;
     833    badModel |= PM_MODEL_PCM_FAIL_GUESS;
     834
    825835    table = psArrayAllocEmpty (sources->n);
    826836
     
    847857
    848858            // skip models which were not actually fitted
    849             if (model->flags & PM_MODEL_STATUS_BADARGS) continue;
     859            // XXX
     860            if (model->flags & badModel) continue;
    850861
    851862            PAR = model->params->data.F32;
     
    853864            xPos = PAR[PM_PAR_XPOS];
    854865            yPos = PAR[PM_PAR_YPOS];
    855             xErr = dPAR[PM_PAR_XPOS];
    856             yErr = dPAR[PM_PAR_YPOS];
     866
     867            // for the extended source models, we do not always fit the centroid in the non-linear fitting process
     868            // current situation (hard-wired into psphotSourceFits.c:psphotFitPCM,
     869            // SERSIC, DEV, EXP : X,Y not fitted (PCM and not PCM)
     870            // TRAIL : X,Y are fitted
     871            //
     872           
     873            // XXX this should be based on what happened, not on the model type
     874            if (model->type == modelTypeTrail) {
     875                xErr = dPAR[PM_PAR_XPOS];
     876                yErr = dPAR[PM_PAR_YPOS];
     877            } else {
     878                // this is definitely an underestimate since it does not
     879                // account for the extent of the source
     880                xErr = fwhmMajor * model->magErr / 2.35;
     881                yErr = fwhmMinor * model->magErr / 2.35;
     882            }
    857883
    858884            @>PS1_DV2@ psSphere ptSky = {0.0, 0.0, 0.0, 0.0};
     
    870896            row = psMetadataAlloc ();
    871897
    872             // XXX we are not writing out the mode (flags) or the type (psf, ext, etc)
    873898            // the psMetadataAdd entry and the double quotes are used by grep to select the output fields for automatic documentation
    874899            // This set of psMetadataAdd Entries marks the "----" "Start of the XFIT segment"
     
    888913            @>PS1_DV2@ float calMag = isfinite(magOffset) ? model->mag + magOffset : NAN;
    889914            @>PS1_DV2@ psMetadataAdd (row, PS_LIST_TAIL, "EXT_CAL_MAG", PS_DATA_F32, "EXT Magnitude using supplied calibration",   calMag);
    890             @>PS1_DV2@ psMetadataAdd (row, PS_LIST_TAIL, "EXT_CHISQ",   PS_DATA_F32, "EXT Magnitude using supplied calibration",   model->chisq);
    891             @>PS1_DV2@ psMetadataAdd (row, PS_LIST_TAIL, "EXT_NDOF",    PS_DATA_S32, "EXT Magnitude using supplied calibration",   model->nDOF);
     915            @>PS1_DV2,PS1_SV?@ psMetadataAdd (row, PS_LIST_TAIL, "EXT_CHISQ",   PS_DATA_F32, "EXT Model Chisq",   model->chisq);
     916            @>PS1_DV2,PS1_SV?@ psMetadataAdd (row, PS_LIST_TAIL, "EXT_NDOF",    PS_DATA_S32, "EXT Model num degrees of freedom",   model->nDOF);
     917            @>PS1_SV1,PS1_SV?@ psMetadataAdd (row, PS_LIST_TAIL, "EXT_MODEL_TYPE",    PS_DATA_S32, "type for chosen EXT_MODEL",   source->modelEXT ? source->modelEXT->type : -1);
     918
     919            // EAM : adding for PV2 outputs:
     920            @>PS1_SV1@ psMetadataAdd (row, PS_LIST_TAIL, "EXT_FLAGS", PS_DATA_S16, "model fit flags (pmModelStatus)", source->modelEXT ? source->modelEXT->flags : 0);
    892921
    893922            @>PS1_DV2@ psMetadataAddF32 (row, PS_LIST_TAIL, "POSANGLE",   0, "position angle at source (degrees)",         posAngle);
     
    946975
    947976                snprintf (name, 64, "EXT_PAR_%02d", k);
    948 
     977               
    949978                if (k < model->params->n) {
    950979                    psMetadataAddF32 (row, PS_LIST_TAIL, name, 0, "", model->params->data.F32[k]);
     
    956985            // optionally, write out the covariance matrix values
    957986            // XXX do I need to pad this to match the biggest covar matrix?
    958             if (model->covar) {
     987            if (false && model->covar) {
    959988                for (int iy = 0; iy < model->covar->numCols; iy++) {
    960989                    for (int ix = iy; ix < model->covar->numCols; ix++) {
     
    10581087        model->magErr = psMetadataLookupF32(&status, row, "EXT_INST_MAG_SIG");
    10591088
     1089        model->chisq = psMetadataLookupF32(&status, row, "EXT_CHISQ");
     1090        model->nDOF = psMetadataLookupF32(&status, row, "EXT_NDOF");
     1091
     1092        // EXT_MODEL_TYPE gives the model chosen by psphot as the best.
     1093        // Putting this into the XFIT table makes 3 copies of it (one for each model)
     1094        // but since we have many fewer XFIT rows than psf rows that is cheaper than putting it
     1095        // in the psf table.
     1096        psS32 extModelType = psMetadataLookupS32(&status, row, "EXT_MODEL_TYPE");
     1097        if (!status) {
     1098            // older cmfs don't have this column
     1099            extModelType = -1;
     1100        }
     1101
    10601102        psEllipseAxes axes;
    10611103        axes.major = psMetadataLookupF32(&status, row, "EXT_WIDTH_MAJ");
     
    10721114        if (model->params->n > 7) {
    10731115            PAR[7] = psMetadataLookupF32(&status, row, "EXT_PAR_07");
    1074         }
    1075         // read the covariance matrix
    1076         int nparams = model->params->n;
    1077         psImage *covar = psImageAlloc(nparams, nparams, PS_TYPE_F32);
    1078         for (int y = 0; y < nparams; y++) {
    1079             for (int x = 0; x < nparams; x++) {
    1080                 char name[64];
    1081                 snprintf(name, 64, "EXT_COVAR_%02d_%02d", y, x);
    1082                 covar->data.F32[y][x] = psMetadataLookupF32(&status, row, name);
     1116            // XXX add an error:
     1117            // dPAR[7] = psMetadataLookupF32(&status, row, "EXT_PAR_07_");
     1118        }
     1119
     1120        // XXX : make this depend on what is in the cmf
     1121        if (0) {
     1122            // read the covariance matrix
     1123            int nparams = model->params->n;
     1124            psImage *covar = psImageAlloc(nparams, nparams, PS_TYPE_F32);
     1125            for (int y = 0; y < nparams; y++) {
     1126                for (int x = 0; x < nparams; x++) {
     1127                    char name[64];
     1128                    snprintf(name, 64, "EXT_COVAR_%02d_%02d", y, x);
     1129                    covar->data.F32[y][x] = psMetadataLookupF32(&status, row, name);
     1130                }
     1131            }
     1132            model->covar = covar;
     1133        }
     1134
     1135        if (modelType == extModelType) {
     1136            // The software that created this source picked this model as the best of the fits.
     1137            // Set the extModel to point to it.
     1138            // This is important for programs like psastro (skycal) so that its output cmfs
     1139            // will have valid EXT_MODEL_TYPE
     1140            psFree(source->modelEXT);
     1141            source->modelEXT = psMemIncrRefCounter(model);
     1142            source->type = PM_SOURCE_TYPE_EXTENDED;
     1143            if (0) {
     1144                // since FLAGS were read we don't need to do this
     1145                source->mode |= PM_SOURCE_MODE_EXTMODEL;
     1146                source->mode |= PM_SOURCE_MODE_NONLINEAR_FIT;
    10831147            }
    10841148        }
    1085         model->covar = covar;
    10861149
    10871150        psArrayAdd(source->modelFits, 1, model);
    10881151        psFree(model);
    1089 
    10901152        psFree(row);
    10911153    }
     
    12091271
    12101272        write_annuli:
    1211             psMetadataAdd (row, PS_LIST_TAIL, "APER_FLUX",       PS_DATA_VECTOR, "flux within annuli",       radFlux);
    1212             psMetadataAdd (row, PS_LIST_TAIL, "APER_FLUX_ERR",   PS_DATA_VECTOR, "flux error in annuli",     radFluxErr);
    1213             psMetadataAdd (row, PS_LIST_TAIL, "APER_FLUX_STDEV", PS_DATA_VECTOR, "flux standard deviation",  radFluxStdev);
    1214             psMetadataAdd (row, PS_LIST_TAIL, "APER_FILL",       PS_DATA_VECTOR, "fill factor of annuli",    radFill);
     1273            psMetadataAddVector (row, PS_LIST_TAIL, "APER_FLUX",       PS_META_REPLACE, "flux within annuli",       radFlux);
     1274            psMetadataAddVector (row, PS_LIST_TAIL, "APER_FLUX_ERR",   PS_META_REPLACE, "flux error in annuli",     radFluxErr);
     1275            psMetadataAddVector (row, PS_LIST_TAIL, "APER_FLUX_STDEV", PS_META_REPLACE, "flux standard deviation",  radFluxStdev);
     1276            psMetadataAddVector (row, PS_LIST_TAIL, "APER_FILL",       PS_META_REPLACE, "fill factor of annuli",    radFill);
    12151277            psFree (radFlux);
    12161278            psFree (radFluxErr);
     
    13431405    return true;
    13441406}
     1407
     1408// XXX where should I record the number of columns??
     1409bool pmSourcesWrite_CMF_@CMFMODE@_XGAL (psFits *fits, psArray *sources, char *extname, psMetadata *recipe)
     1410{
     1411    bool status = false;
     1412
     1413    // perform full non-linear fits / extended source analysis?
     1414    if (!psMetadataLookupBool (&status, recipe, "GALAXY_SHAPES")) {
     1415        psLogMsg ("psphot", PS_LOG_INFO, "galaxy shapes were not measured, skipping\n");
     1416        return true;
     1417    }
     1418
     1419    // create a header to hold the output data
     1420    psMetadata *outhead = psMetadataAlloc ();
     1421
     1422    // write the links to the image header
     1423    psMetadataAddStr (outhead, PS_LIST_TAIL, "EXTNAME", PS_META_REPLACE, "galaxy table extension", extname);
     1424
     1425    // let's write these out in S/N order
     1426    sources = psArraySort (sources, pmSourceSortByFlux);
     1427
     1428    psArray *table = psArrayAllocEmpty (sources->n);
     1429
     1430    for (int i = 0; i < sources->n; i++) {
     1431
     1432        pmSource *thisSource = sources->data[i];
     1433
     1434        // this is the "real" version of this source
     1435        pmSource *source = thisSource->parent ? thisSource->parent : thisSource;
     1436
     1437        // if we did not fit the galaxy model, modelFits will be NULL
     1438        if (source->modelFits == NULL) continue;
     1439
     1440        // if we did not fit the galaxy model, galaxyFits will also be NULL
     1441        if (source->galaxyFits == NULL) continue;
     1442
     1443        pmModel *model = source->modelFits->data[0];
     1444        if (!model) return false;
     1445
     1446        // X,Y coordinates are stored with the model parameters
     1447        psF32 *PAR = model->params->data.F32;
     1448
     1449        psMetadata *row = psMetadataAlloc ();
     1450
     1451        // we write out the x,y positions so people can link to the psf either way (position or ID)
     1452        psMetadataAddU32 (row, PS_LIST_TAIL, "IPP_IDET",         0, "IPP detection identifier index", source->seq);
     1453        psMetadataAddF32 (row, PS_LIST_TAIL, "X_FIT",            0, "model x coordinate",             PAR[PM_PAR_XPOS]);
     1454        psMetadataAddF32 (row, PS_LIST_TAIL, "Y_FIT",            0, "model y coordinate",             PAR[PM_PAR_YPOS]);
     1455        psMetadataAddF32 (row, PS_LIST_TAIL, "NPIX",             0, "number of pixels for fits",      source->galaxyFits->nPix);
     1456
     1457        psVector *Flux = source->galaxyFits->Flux;
     1458        psVector *dFlux = source->galaxyFits->dFlux;
     1459        psVector *chisq = source->galaxyFits->chisq;
     1460
     1461        psMetadataAddVector (row, PS_LIST_TAIL, "GAL_FLUX",     PS_META_REPLACE, "normalization for galaxy flux", Flux);
     1462        psMetadataAddVector (row, PS_LIST_TAIL, "GAL_FLUX_ERR", PS_META_REPLACE, "error on normalization", dFlux);
     1463        psMetadataAddVector (row, PS_LIST_TAIL, "GAL_CHISQ",    PS_META_REPLACE, "galaxy fit chisq", chisq);
     1464
     1465        psArrayAdd (table, 100, row);
     1466        psFree (row);
     1467    }
     1468
     1469    if (table->n == 0) {
     1470        if (!psFitsWriteBlank (fits, outhead, extname)) {
     1471            psError(psErrorCodeLast(), false, "Unable to write empty sources file.");
     1472            psFree(outhead);
     1473            psFree(table);
     1474            return false;
     1475        }
     1476        psFree (outhead);
     1477        psFree (table);
     1478        return true;
     1479    }
     1480
     1481    psTrace ("pmFPAfile", 5, "writing galaxy data %s\n", extname);
     1482    if (!psFitsWriteTable (fits, outhead, table, extname)) {
     1483        psError(psErrorCodeLast(), false, "writing galaxy data %s\n", extname);
     1484        psFree (outhead);
     1485        psFree(table);
     1486        return false;
     1487    }
     1488    psFree (outhead);
     1489    psFree (table);
     1490    return true;
     1491}
     1492
  • trunk/psModules/src/objects/pmSourceIO_PS1_CAL_0.c

    r35768 r36375  
    713713    return true;
    714714}
     715
     716bool pmSourcesWrite_PS1_CAL_0_XGAL (psFits *fits, psArray *sources, char *extname, psMetadata *recipe)
     717{
     718    return true;
     719}
  • trunk/psModules/src/objects/pmSourceIO_PS1_DEV_0.c

    r35768 r36375  
    255255    return true;
    256256}
     257
     258bool pmSourcesWrite_PS1_DEV_0_XGAL(psFits *fits, psArray *sources, char *extname, psMetadata *recipe)
     259{
     260    return true;
     261}
  • trunk/psModules/src/objects/pmSourceIO_PS1_DEV_1.c

    r35768 r36375  
    595595    return true;
    596596}
     597
     598bool pmSourcesWrite_PS1_DEV_1_XGAL(psFits *fits, psArray *sources, char *extname, psMetadata *recipe)
     599{
     600    return true;
     601}
  • trunk/psModules/src/objects/pmSourceIO_SMPDATA.c

    r35768 r36375  
    225225    return true;
    226226}
     227
     228bool pmSourcesWrite_SMPDATA_XGAL(psFits *fits, psArray *sources, char *extname, psMetadata *recipe)
     229{
     230    return true;
     231}
  • trunk/psModules/src/objects/pmSourceMasks.h

    r34403 r36375  
    5656    PM_SOURCE_MODE2_DIFF_SELF_MATCH       = 0x00000800, ///< positive detection match is probably this source
    5757    PM_SOURCE_MODE2_SATSTAR_PROFILE       = 0x00001000, ///< saturated source is modeled with a radial profile
     58
     59    PM_SOURCE_MODE2_ECONTOUR_FEW_PTS      = 0x00002000, ///< too few points to measure the elliptical contour
     60    PM_SOURCE_MODE2_RADBIN_NAN_CENTER     = 0x00004000, ///< radial bins failed with too many NaN center bin
     61    PM_SOURCE_MODE2_PETRO_NAN_CENTER      = 0x00008000, ///< petrosian radial bins failed with too many NaN center bin
     62    PM_SOURCE_MODE2_PETRO_NO_PROFILE      = 0x00010000, ///< petrosian not build because radial bins missing
     63
     64    PM_SOURCE_MODE2_PETRO_INSIG_RATIO     = 0x00020000, ///< insignificant measurement of petrosian ratio
     65    PM_SOURCE_MODE2_PETRO_RATIO_ZEROBIN   = 0x00040000, ///< petrosian ratio in the 0th bin (likely bad)
     66   
     67    PM_SOURCE_MODE2_EXT_FITS_RUN          = 0x00080000, ///< we attempted to run extended fits on this source
     68    PM_SOURCE_MODE2_EXT_FITS_FAIL         = 0x00100000, ///< at least one of the model fits failed
     69    PM_SOURCE_MODE2_EXT_FITS_RETRY        = 0x00200000, ///< one of the model fits was re-tried with new window
     70    PM_SOURCE_MODE2_EXT_FITS_NONE         = 0x00400000, ///< ALL of the model fits failed
     71   
     72   
    5873} pmSourceMode2;
    5974
  • trunk/psModules/src/objects/pmSourceMoments.c

    r35560 r36375  
    6565void pmSourceMomentsSetVerbose(bool state){ beVerbose = state; }
    6666
     67bool pmSourceMomentsHighOrder    (pmSource *source, float radius, float sigma, float minSN, psImageMaskType maskVal);
     68bool pmSourceMomentsRadialMoment (pmSource *source, float radius, float minKronRadius, psImageMaskType maskVal);
     69bool pmSourceMomentsKronFluxes   (pmSource *source, float sigma,  float minSN, psImageMaskType maskVal);
     70
    6771// if mode & EXTERNAL or mode2 & MATCHED, do not re-calculate the centroid (use peak as centroid)
    68 
    6972bool pmSourceMoments(pmSource *source, float radius, float sigma, float minSN, float minKronRadius, psImageMaskType maskVal)
    7073{
     
    7477    PS_ASSERT_FLOAT_LARGER_THAN(radius, 0.0, false);
    7578
    76     // this function assumes the sky has been well-subtracted for the image
    77     float sky = 0.0;
    78 
    7979    if (source->moments == NULL) {
    8080      source->moments = pmMomentsAlloc();
    8181    }
    82 
    83     float Sum = 0.0;
    84     float Var = 0.0;
    85     float SumCore = 0.0;
    86     float VarCore = 0.0;
    87     float R2 = PS_SQR(radius);
    88     float minSN2 = PS_SQR(minSN);
    89     float rsigma2 = 0.5 / PS_SQR(sigma);
    9082
    9183    // a note about coordinates: coordinates of objects throughout psphot refer to the primary
     
    110102    // of any object drops pretty quickly outside 1-2 sigmas.  (The exception is bright
    111103    // saturated stars, for which we need to use a very large radius here)
     104    // NOTE: if (mode & EXTERNAL) or (mode2 & MATCHED), do not re-calculate the centroid (use peak as centroid)
     105    // (we still call this function because it sets moments->Sum,SN,Peak,nPixels
    112106    if (!pmSourceMomentsGetCentroid (source, 1.5*sigma, 0.0, minSN, maskVal, source->peak->xf, source->peak->yf)) {
    113107        return false;
    114108    }
    115109
     110    pmSourceMomentsHighOrder (source, radius, sigma, minSN, maskVal);
     111
     112    // now calculate the 1st radial moment (for kron flux) using symmetrical averaging
     113    pmSourceMomentsRadialMoment (source, radius, minKronRadius, maskVal);
     114
     115    // now calculate the kron flux values using the 1st radial moment
     116    pmSourceMomentsKronFluxes (source, sigma, minSN, maskVal);
     117
     118    psTrace ("psModules.objects", 4, "Mrf: %f  KronFlux: %f  Mxx: %f  Mxy: %f  Myy: %f  Mxxx: %f  Mxxy: %f  Mxyy: %f  Myyy: %f  Mxxxx: %f  Mxxxy: %f  Mxxyy: %f  Mxyyy: %f  Mxyyy: %f\n",
     119             source->moments->Mrf,   source->moments->KronFlux,
     120             source->moments->Mxx,   source->moments->Mxy,   source->moments->Myy,
     121             source->moments->Mxxx,  source->moments->Mxxy,  source->moments->Mxyy,  source->moments->Myyy,
     122             source->moments->Mxxxx, source->moments->Mxxxy, source->moments->Mxxyy, source->moments->Mxyyy, source->moments->Myyyy);
     123
     124    psTrace ("psModules.objects", 3, "peak %f %f (%f = %f) Mx: %f  My: %f  Sum: %f  Mxx: %f  Mxy: %f  Myy: %f  Npix: %d\n",
     125             source->peak->xf, source->peak->yf,
     126             source->peak->rawFlux, sqrt(source->peak->detValue),
     127             source->moments->Mx, source->moments->My,
     128             source->moments->Sum,
     129             source->moments->Mxx, source->moments->Mxy, source->moments->Myy,
     130             source->moments->nPixels);
     131
     132    return(true);
     133}
     134
     135bool pmSourceMomentsGetCentroid(pmSource *source, float radius, float sigma, float minSN, psImageMaskType maskVal, float xGuess, float yGuess) {
     136
     137    // First Pass: calculate the first moments (these are subtracted from the coordinates below)
     138    // Sum = SUM (z - sky)
     139    // X1  = SUM (x - xc)*(z - sky)
     140    // .. etc
     141
     142    float sky = 0.0;
     143
     144    float peakPixel = -PS_MAX_F32;
     145    psS32 numPixels = 0;
     146    float Sum = 0.0;
     147    float Var = 0.0;
     148    float X1 = 0.0;
     149    float Y1 = 0.0;
     150    float R2 = PS_SQR(radius);
     151    float minSN2 = PS_SQR(minSN);
     152    float rsigma2 = 0.5 / PS_SQR(sigma);
     153
     154    float xPeak = xGuess - source->pixels->col0; // coord of peak in subimage
     155    float yPeak = yGuess - source->pixels->row0; // coord of peak in subimage
     156
     157    // we are guaranteed to have a valid pixel and variance at this location (right? right?)
     158    // float weightNorm = source->pixels->data.F32[yPeak][xPeak] / sqrt (source->variance->data.F32[yPeak][xPeak]);
     159    // psAssert (isfinite(source->pixels->data.F32[yPeak][xPeak]), "peak must be on valid pixel");
     160    // psAssert (isfinite(source->variance->data.F32[yPeak][xPeak]), "peak must be on valid pixel");
     161    // psAssert (source->variance->data.F32[yPeak][xPeak] > 0, "peak must be on valid pixel");
     162
     163    // the moments [Sum(x*f) / Sum(f)] are calculated in pixel index values, and should
     164    // not depend on the fractional pixel location of the source.  However, the aperture
     165    // (radius) and the Gaussian window (sigma) depend subtly on the fractional pixel
     166    // position of the expected centroid
     167
     168    for (psS32 row = 0; row < source->pixels->numRows ; row++) {
     169
     170        float yDiff = row + 0.5 - yPeak;
     171        if (fabs(yDiff) > radius) continue;
     172
     173        float *vPix = source->pixels->data.F32[row];
     174        float *vWgt = source->variance ? source->variance->data.F32[row] : source->pixels->data.F32[row];
     175
     176        psImageMaskType *vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[row];
     177        // psImageMaskType *vMsk = (source->maskView == NULL) ? NULL : source->maskView->data.PS_TYPE_IMAGE_MASK_DATA[row];
     178
     179        for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) {
     180            if (vMsk) {
     181                if (*vMsk & maskVal) {
     182                    vMsk++;
     183                    continue;
     184                }
     185                vMsk++;
     186            }
     187            if (isnan(*vPix)) continue;
     188
     189            float xDiff = col + 0.5 - xPeak;
     190            if (fabs(xDiff) > radius) continue;
     191
     192            // radius is just a function of (xDiff, yDiff)
     193            float r2  = PS_SQR(xDiff) + PS_SQR(yDiff);
     194            if (r2 > R2) continue;
     195
     196            float pDiff = *vPix - sky;
     197            float wDiff = *vWgt;
     198
     199            // skip pixels below specified significance level.  for a PSFs, this
     200            // over-weights the wings of bright stars compared to those of faint stars.
     201            // for the estimator used for extended source analysis (where the window
     202            // function is allowed to be arbitrarily large), we need to clip to avoid
     203            // negative second moments.
     204            if (PS_SQR(pDiff) < minSN2*wDiff) continue; //
     205            if ((minSN > 0.0) && (pDiff < 0)) continue; //
     206
     207            // Apply a Gaussian window function.  Be careful with the window function.  S/N
     208            // weighting over weights the sky for faint sources
     209            if (sigma > 0.0) {
     210                float z  = r2*rsigma2;
     211                assert (z >= 0.0);
     212                float weight  = exp(-z);
     213
     214                wDiff *= weight;
     215                pDiff *= weight;
     216            }
     217
     218            Var += wDiff;
     219            Sum += pDiff;
     220
     221            float xWght = xDiff * pDiff;
     222            float yWght = yDiff * pDiff;
     223
     224            X1  += xWght;
     225            Y1  += yWght;
     226
     227            peakPixel = PS_MAX (*vPix, peakPixel);
     228            numPixels++;
     229        }
     230    }
     231
     232    // if we have less than (1/4) of the possible pixels (in circle or box), force a retry
     233    int minPixels = PS_MIN(0.75*R2, source->pixels->numCols*source->pixels->numRows/4.0);
     234
     235    // XXX EAM - the limit is a bit arbitrary.  make it user defined?
     236    if ((numPixels < minPixels) || (Sum <= 0)) {
     237        psTrace ("psModules.objects", 3, "insufficient valid pixels (%d vs %d; %f) for source\n", numPixels, minPixels, Sum);
     238        return (false);
     239    }
     240
     241    // calculate the first moment.
     242    float Mx = X1/Sum;
     243    float My = Y1/Sum;
     244    if ((fabs(Mx) > radius) || (fabs(My) > radius)) {
     245        psTrace ("psModules.objects", 3, "extreme centroid swing; invalid peak %d, %d\n", source->peak->x, source->peak->y);
     246        return (false);
     247    }
     248    if ((fabs(Mx) > 2.0) || (fabs(My) > 2.0)) {
     249        psTrace ("psModules.objects", 3, " big centroid swing; ok peak? %d, %d\n", source->peak->x, source->peak->y);
     250    }
     251
     252    psTrace ("psModules.objects", 5, "id: %d, sky: %f  Mx: %f  My: %f  Sum: %f  X1: %f  Y1: %f  Npix: %d\n", source->id, sky, Mx, My, Sum, X1, Y1, numPixels);
     253
     254    // add back offset of peak in primary image
     255    // also offset from pixel index to pixel coordinate
     256    // (the calculation above uses pixel index instead of coordinate)
     257    // 0.5 PIX: moments are calculated using the pixel index and converted here to pixel coords
     258
     259    // we only update the centroid if the position is not supplied from elsewhere
     260    bool skipCentroid = false;
     261    skipCentroid |= (source->mode  & PM_SOURCE_MODE_EXTERNAL); // skip externally supplied positions
     262    skipCentroid |= (source->mode2 & PM_SOURCE_MODE2_MATCHED); // skip sources defined by other image positions
     263
     264    if (skipCentroid) {
     265        source->moments->Mx = source->peak->xf;
     266        source->moments->My = source->peak->yf;
     267    } else {
     268        source->moments->Mx = Mx + xGuess;
     269        source->moments->My = My + yGuess;
     270    }
     271
     272    source->moments->Sum = Sum;
     273    source->moments->SN  = Sum / sqrt(Var);
     274    source->moments->Peak = peakPixel;
     275    source->moments->nPixels = numPixels;
     276
     277    return true;
     278}
     279
     280float pmSourceMinKronRadius(psArray *sources, float PSF_SN_LIM) {
     281
     282    psVector *radii = psVectorAllocEmpty(100, PS_TYPE_F32);
     283
     284    for (int i = 0; i < sources->n; i++) {
     285        pmSource *src = sources->data[i]; // Source of interest
     286        if (!src || !src->moments) {
     287            continue;
     288        }
     289
     290        if (src->mode & PM_SOURCE_MODE_BLEND) {
     291            continue;
     292        }
     293
     294        if (!src->moments->nPixels) continue;
     295
     296        if (src->moments->SN < PSF_SN_LIM) continue;
     297
     298        // XXX put in Mxx,Myy cut based on clump location
     299
     300        psVectorAppend(radii, src->moments->Mrf);
     301    }
     302
     303    // find the peak in this image
     304    psStats *stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN);
     305
     306    if (!psVectorStats (stats, radii, NULL, NULL, 0)) {
     307        psError(PS_ERR_UNKNOWN, false, "Unable to get image statistics.\n");
     308        psFree(stats);
     309        return NAN;
     310    }
     311
     312    float minRadius = stats->sampleMedian;
     313
     314    psFree(radii);
     315    psFree(stats);
     316    return minRadius;
     317}
     318
     319bool pmSourceMomentsHighOrder (pmSource *source, float radius, float sigma, float minSN, psImageMaskType maskVal) {
     320
     321    // this function assumes the sky has been well-subtracted for the image
     322    float Sum = 0.0;
     323    float R2 = PS_SQR(radius);
     324    float minSN2 = PS_SQR(minSN);
     325    float rsigma2 = 0.5 / PS_SQR(sigma);
     326
    116327    // Now calculate higher-order moments, using the above-calculated first moments to adjust coordinates
    117     // Xn  = SUM (x - xc)^n * (z - sky)
     328    // Xn  = SUM (x - xc)^n * (z - sky) -- note that sky is 0.0 by definition here
    118329    float XX = 0.0;
    119330    float XY = 0.0;
     
    129340    float YYYY = 0.0;
    130341
    131     Sum = 0.0;  // the second pass may include slightly different pixels, re-determine Sum
    132 
    133     // float dX = source->moments->Mx - source->peak->xf;
    134     // float dY = source->moments->My - source->peak->yf;
    135     // float dR = hypot(dX, dY);
    136     // float Xo = (dR < 2.0) ? source->moments->Mx : source->peak->xf;
    137     // float Yo = (dR < 2.0) ? source->moments->My : source->peak->yf;
    138342    float Xo = source->moments->Mx;
    139343    float Yo = source->moments->My;
     
    154358
    155359        psImageMaskType  *vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[row];
    156         // psImageMaskType  *vMsk = (source->maskView == NULL) ? NULL : source->maskView->data.PS_TYPE_IMAGE_MASK_DATA[row];
    157360
    158361        for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) {
     
    173376            if (r2 > R2) continue;
    174377
    175             float fDiff = *vPix - sky;
     378            float fDiff = *vPix;
    176379            float pDiff = fDiff;
    177380            float wDiff = *vWgt;
     
    181384            // stars.
    182385            if (PS_SQR(pDiff) < minSN2*wDiff) continue;
    183             if ((minSN > 0.0) && (pDiff < 0)) continue; //
     386            if ((minSN > 0.0) && (pDiff < 0)) continue;
    184387
    185388            // Apply a Gaussian window function.  Be careful with the window function.  S/N
    186             // weighting over weights the sky for faint sources
     389            // weighting over-weights the sky for faint sources
    187390            if (sigma > 0.0) {
    188391                float z = r2 * rsigma2;
     
    230433            XYYY  += xyyy;
    231434            YYYY  += yyyy;
    232 
    233             // Kron Flux uses the 1st radial moment (NOT Gaussian windowed?)
    234             // XXX float r = sqrt(r2);
    235             // XXX float rf = r * fDiff;
    236             // XXX float rh = sqrt(r) * fDiff;
    237             // XXX float rs = fDiff;
    238             // XXX
    239             // XXX float rfw = r * pDiff;
    240             // XXX float rhw = sqrt(r) * pDiff;
    241             // XXX
    242             // XXX RF  += rf;
    243             // XXX RH  += rh;
    244             // XXX RS  += rs;
    245             // XXX
    246             // XXX RFW  += rfw;
    247             // XXX RHW  += rhw;
    248435        }
    249436    }
     
    263450    source->moments->Myyyy = YYYY/Sum;
    264451
    265     // *** now calculate the 1st radial moment (for kron flux) -- symmetrical averaging
     452    return true;
     453}
     454
     455bool pmSourceMomentsRadialMoment (pmSource *source, float radius, float minKronRadius, psImageMaskType maskVal) {
     456
    266457
    267458    float **vPix = source->pixels->data.F32;
    268     float **vWgt = source->variance ? source->variance->data.F32 : source->pixels->data.F32;
    269459    psImageMaskType **vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA;
    270460
     
    272462    float RH = 0.0;
    273463    float RS = 0.0;
     464
     465    // centroid around which to calculate the moments
     466    float Xo = source->moments->Mx;
     467    float Yo = source->moments->My;
     468
     469    // center of mass in subimage.  Note: the calculation below uses pixel index, so we correct
     470    // xCM, yCM from pixel coords to pixel index here.
     471    float xCM = Xo - 0.5 - source->pixels->col0; // coord of peak in subimage
     472    float yCM = Yo - 0.5 - source->pixels->row0; // coord of peak in subimage
     473
     474    float R2 = PS_SQR(radius);
    274475
    275476    for (psS32 row = 0; row < source->pixels->numRows ; row++) {
     
    304505            if (r2 > R2) continue;
    305506
    306             float fDiff1 = vPix[row][col] - sky;
    307             float fDiff2 = vPix[yFlip][xFlip] - sky;
     507            float fDiff1 = vPix[row][col];
     508            float fDiff2 = vPix[yFlip][xFlip];
    308509            float pDiff = (fDiff1 > 0.0) ? sqrt(fabs(fDiff1*fDiff2)) : -sqrt(fabs(fDiff1*fDiff2));
    309510
     
    329530        kronRefRadius = MIN(radius, kronRefRadius);
    330531    }
    331     source->moments->Mrf = kronRefRadius;
    332 
    333     // *** now calculate the kron flux values using the 1st radial moment
    334 
    335     float radKinner = 1.0*kronRefRadius;
    336     float radKron   = 2.5*kronRefRadius;
    337     float radKouter = 4.0*kronRefRadius;
     532
     533    // if source is externally supplied and it already has a finite Mrf do not change it
     534    if (! ((source->mode & PM_SOURCE_MODE_EXTERNAL) && isfinite(source->moments->Mrf))) {
     535        source->moments->Mrf = kronRefRadius;
     536    }
     537
     538    return true;
     539}
     540
     541bool pmSourceMomentsKronFluxes (pmSource *source, float sigma, float minSN, psImageMaskType maskVal) {
     542
     543    float **vPix = source->pixels->data.F32;
     544    float **vWgt = source->variance ? source->variance->data.F32 : source->pixels->data.F32;
     545    psImageMaskType **vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA;
     546
     547    float radKinner = 1.0*source->moments->Mrf;
     548    float radKron   = 2.5*source->moments->Mrf;
     549    float radKouter = 4.0*source->moments->Mrf;
    338550
    339551    int nKronPix = 0;
     
    341553    int nInner = 0;
    342554    int nOuter = 0;
    343     Sum = Var = 0.0;
     555   
     556    float Sum = 0.0;
     557    float Var = 0.0;
     558    float SumCore = 0.0;
     559    float VarCore = 0.0;
    344560    float SumInner = 0.0;
    345561    float SumOuter = 0.0;
     562
     563    // centroid around which to calculate the moments
     564    float Xo = source->moments->Mx;
     565    float Yo = source->moments->My;
     566
     567    // center of mass in subimage.  Note: the calculation below uses pixel index, so we correct
     568    // xCM, yCM from pixel coords to pixel index here.
     569    float xCM = Xo - 0.5 - source->pixels->col0; // coord of peak in subimage
     570    float yCM = Yo - 0.5 - source->pixels->row0; // coord of peak in subimage
     571
     572    float minSN2 = PS_SQR(minSN);
    346573
    347574    // calculate the Kron flux, and related fluxes (NO symmetrical averaging)
     
    362589            float r2  = PS_SQR(xDiff) + PS_SQR(yDiff);
    363590
    364             float fDiff1 = vPix[row][col] - sky;
     591            float fDiff1 = vPix[row][col];
    365592            float pDiff = fDiff1;
    366593            float wDiff = vWgt[row][col];
     
    376603                Var += wDiff;
    377604                nKronPix ++;
    378                 // if (beVerbose) fprintf (stderr, "mome: %d %d  %f  %f  %f\n", col, row, sky, *vPix, Sum);
    379605            }
    380606
     
    397623    }
    398624    // *** should I rescale these fluxes by pi R^2 / nNpix?
    399     // XXX source->moments->KronCore    = SumCore       * M_PI * PS_SQR(sigma) / nCorePix;
    400     // XXX source->moments->KronCoreErr = sqrt(VarCore) * M_PI * PS_SQR(sigma) / nCorePix;
    401     // XXX source->moments->KronFlux    = Sum       * M_PI * PS_SQR(radKron) / nKronPix;
    402     // XXX source->moments->KronFluxErr = sqrt(Var) * M_PI * PS_SQR(radKron) / nKronPix;
    403     // XXX source->moments->KronFinner = SumInner * M_PI * (PS_SQR(radKron)   - PS_SQR(radKinner)) / nInner;
    404     // XXX source->moments->KronFouter = SumOuter * M_PI * (PS_SQR(radKouter) -   PS_SQR(radKron)) / nOuter;
     625    // XXX source->moments->KronCore    = SumCore       * M_PI *  PS_SQR(sigma) / nCorePix;
     626    // XXX source->moments->KronCoreErr = sqrt(VarCore) * M_PI *  PS_SQR(sigma) / nCorePix;
     627    // XXX source->moments->KronFlux    = Sum           * M_PI * PS_SQR(radKron) / nKronPix;
     628    // XXX source->moments->KronFluxErr = sqrt(Var)     * M_PI * PS_SQR(radKron) / nKronPix;
     629    // XXX source->moments->KronFinner  = SumInner      * M_PI * (PS_SQR(radKron)   - PS_SQR(radKinner)) / nInner;
     630    // XXX source->moments->KronFouter  = SumOuter      * M_PI * (PS_SQR(radKouter) -   PS_SQR(radKron)) / nOuter;
    405631
    406632    source->moments->KronCore    = SumCore;
     
    408634    source->moments->KronFlux    = Sum;
    409635    source->moments->KronFluxErr = sqrt(Var);
    410     source->moments->KronFinner = SumInner;
    411     source->moments->KronFouter = SumOuter;
     636    source->moments->KronFinner  = SumInner;
     637    source->moments->KronFouter  = SumOuter;
    412638
    413639    // XXX not sure I should save this here...
     
    416642    source->moments->KronRadiusPSF  = source->moments->Mrf;
    417643
    418     psTrace ("psModules.objects", 4, "Mrf: %f  KronFlux: %f  Mxx: %f  Mxy: %f  Myy: %f  Mxxx: %f  Mxxy: %f  Mxyy: %f  Myyy: %f  Mxxxx: %f  Mxxxy: %f  Mxxyy: %f  Mxyyy: %f  Mxyyy: %f\n",
    419              source->moments->Mrf,   source->moments->KronFlux,
    420              source->moments->Mxx,   source->moments->Mxy,   source->moments->Myy,
    421              source->moments->Mxxx,  source->moments->Mxxy,  source->moments->Mxyy,  source->moments->Myyy,
    422              source->moments->Mxxxx, source->moments->Mxxxy, source->moments->Mxxyy, source->moments->Mxyyy, source->moments->Myyyy);
    423 
    424     psTrace ("psModules.objects", 3, "peak %f %f (%f = %f) Mx: %f  My: %f  Sum: %f  Mxx: %f  Mxy: %f  Myy: %f  sky: %f  Npix: %d\n",
    425              source->peak->xf, source->peak->yf, source->peak->rawFlux, sqrt(source->peak->detValue), source->moments->Mx,   source->moments->My, Sum, source->moments->Mxx,   source->moments->Mxy,   source->moments->Myy, sky, source->moments->nPixels);
    426 
    427     return(true);
    428 }
    429 
    430 bool pmSourceMomentsGetCentroid(pmSource *source, float radius, float sigma, float minSN, psImageMaskType maskVal, float xGuess, float yGuess) {
    431 
    432     // First Pass: calculate the first moments (these are subtracted from the coordinates below)
    433     // Sum = SUM (z - sky)
    434     // X1  = SUM (x - xc)*(z - sky)
    435     // .. etc
    436 
    437     float sky = 0.0;
    438 
    439     float peakPixel = -PS_MAX_F32;
    440     psS32 numPixels = 0;
    441     float Sum = 0.0;
    442     float Var = 0.0;
    443     float X1 = 0.0;
    444     float Y1 = 0.0;
    445     float R2 = PS_SQR(radius);
    446     float minSN2 = PS_SQR(minSN);
    447     float rsigma2 = 0.5 / PS_SQR(sigma);
    448 
    449     float xPeak = xGuess - source->pixels->col0; // coord of peak in subimage
    450     float yPeak = yGuess - source->pixels->row0; // coord of peak in subimage
    451 
    452     // we are guaranteed to have a valid pixel and variance at this location (right? right?)
    453     // float weightNorm = source->pixels->data.F32[yPeak][xPeak] / sqrt (source->variance->data.F32[yPeak][xPeak]);
    454     // psAssert (isfinite(source->pixels->data.F32[yPeak][xPeak]), "peak must be on valid pixel");
    455     // psAssert (isfinite(source->variance->data.F32[yPeak][xPeak]), "peak must be on valid pixel");
    456     // psAssert (source->variance->data.F32[yPeak][xPeak] > 0, "peak must be on valid pixel");
    457 
    458     // the moments [Sum(x*f) / Sum(f)] are calculated in pixel index values, and should
    459     // not depend on the fractional pixel location of the source.  However, the aperture
    460     // (radius) and the Gaussian window (sigma) depend subtly on the fractional pixel
    461     // position of the expected centroid
    462 
    463     for (psS32 row = 0; row < source->pixels->numRows ; row++) {
    464 
    465         float yDiff = row + 0.5 - yPeak;
    466         if (fabs(yDiff) > radius) continue;
    467 
    468         float *vPix = source->pixels->data.F32[row];
    469         float *vWgt = source->variance ? source->variance->data.F32[row] : source->pixels->data.F32[row];
    470 
    471         psImageMaskType *vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[row];
    472         // psImageMaskType *vMsk = (source->maskView == NULL) ? NULL : source->maskView->data.PS_TYPE_IMAGE_MASK_DATA[row];
    473 
    474         for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) {
    475             if (vMsk) {
    476                 if (*vMsk & maskVal) {
    477                     vMsk++;
    478                     continue;
    479                 }
    480                 vMsk++;
    481             }
    482             if (isnan(*vPix)) continue;
    483 
    484             float xDiff = col + 0.5 - xPeak;
    485             if (fabs(xDiff) > radius) continue;
    486 
    487             // radius is just a function of (xDiff, yDiff)
    488             float r2  = PS_SQR(xDiff) + PS_SQR(yDiff);
    489             if (r2 > R2) continue;
    490 
    491             float pDiff = *vPix - sky;
    492             float wDiff = *vWgt;
    493 
    494             // skip pixels below specified significance level.  for a PSFs, this
    495             // over-weights the wings of bright stars compared to those of faint stars.
    496             // for the estimator used for extended source analysis (where the window
    497             // function is allowed to be arbitrarily large), we need to clip to avoid
    498             // negative second moments.
    499             if (PS_SQR(pDiff) < minSN2*wDiff) continue; //
    500             if ((minSN > 0.0) && (pDiff < 0)) continue; //
    501 
    502             // Apply a Gaussian window function.  Be careful with the window function.  S/N
    503             // weighting over weights the sky for faint sources
    504             if (sigma > 0.0) {
    505                 float z  = r2*rsigma2;
    506                 assert (z >= 0.0);
    507                 float weight  = exp(-z);
    508 
    509                 wDiff *= weight;
    510                 pDiff *= weight;
    511             }
    512 
    513             Var += wDiff;
    514             Sum += pDiff;
    515 
    516             float xWght = xDiff * pDiff;
    517             float yWght = yDiff * pDiff;
    518 
    519             X1  += xWght;
    520             Y1  += yWght;
    521 
    522             peakPixel = PS_MAX (*vPix, peakPixel);
    523             numPixels++;
    524         }
    525     }
    526 
    527     // if we have less than (1/4) of the possible pixels (in circle or box), force a retry
    528     int minPixels = PS_MIN(0.75*R2, source->pixels->numCols*source->pixels->numRows/4.0);
    529 
    530     // XXX EAM - the limit is a bit arbitrary.  make it user defined?
    531     if ((numPixels < minPixels) || (Sum <= 0)) {
    532         psTrace ("psModules.objects", 3, "insufficient valid pixels (%d vs %d; %f) for source\n", numPixels, minPixels, Sum);
    533         return (false);
    534     }
    535 
    536     // calculate the first moment.
    537     float Mx = X1/Sum;
    538     float My = Y1/Sum;
    539     if ((fabs(Mx) > radius) || (fabs(My) > radius)) {
    540         psTrace ("psModules.objects", 3, "extreme centroid swing; invalid peak %d, %d\n", source->peak->x, source->peak->y);
    541         return (false);
    542     }
    543     if ((fabs(Mx) > 2.0) || (fabs(My) > 2.0)) {
    544         psTrace ("psModules.objects", 3, " big centroid swing; ok peak? %d, %d\n", source->peak->x, source->peak->y);
    545     }
    546 
    547     psTrace ("psModules.objects", 5, "id: %d, sky: %f  Mx: %f  My: %f  Sum: %f  X1: %f  Y1: %f  Npix: %d\n", source->id, sky, Mx, My, Sum, X1, Y1, numPixels);
    548 
    549     // add back offset of peak in primary image
    550     // also offset from pixel index to pixel coordinate
    551     // (the calculation above uses pixel index instead of coordinate)
    552     // 0.5 PIX: moments are calculated using the pixel index and converted here to pixel coords
    553 
    554     // we only update the centroid if the position is not supplied from elsewhere
    555     bool skipCentroid = false;
    556     skipCentroid |= (source->mode  & PM_SOURCE_MODE_EXTERNAL); // skip externally supplied positions
    557     skipCentroid |= (source->mode2 & PM_SOURCE_MODE2_MATCHED); // skip sources defined by other image positions
    558 
    559     if (skipCentroid) {
    560         source->moments->Mx = source->peak->xf;
    561         source->moments->My = source->peak->yf;
    562     } else {
    563         source->moments->Mx = Mx + xGuess;
    564         source->moments->My = My + yGuess;
    565     }
    566 
    567     source->moments->Sum = Sum;
    568     source->moments->SN  = Sum / sqrt(Var);
    569     source->moments->Peak = peakPixel;
    570     source->moments->nPixels = numPixels;
    571 
    572644    return true;
    573645}
    574 
    575 float pmSourceMinKronRadius(psArray *sources, float PSF_SN_LIM) {
    576 
    577     psVector *radii = psVectorAllocEmpty(100, PS_TYPE_F32);
    578 
    579     for (int i = 0; i < sources->n; i++) {
    580         pmSource *src = sources->data[i]; // Source of interest
    581         if (!src || !src->moments) {
    582             continue;
    583         }
    584 
    585         if (src->mode & PM_SOURCE_MODE_BLEND) {
    586             continue;
    587         }
    588 
    589         if (!src->moments->nPixels) continue;
    590 
    591         if (src->moments->SN < PSF_SN_LIM) continue;
    592 
    593         // XXX put in Mxx,Myy cut based on clump location
    594 
    595         psVectorAppend(radii, src->moments->Mrf);
    596     }
    597 
    598     // find the peak in this image
    599     psStats *stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN);
    600 
    601     if (!psVectorStats (stats, radii, NULL, NULL, 0)) {
    602         psError(PS_ERR_UNKNOWN, false, "Unable to get image statistics.\n");
    603         psFree(stats);
    604         return NAN;
    605     }
    606 
    607     float minRadius = stats->sampleMedian;
    608 
    609     psFree(radii);
    610     psFree(stats);
    611     return minRadius;
    612 }
    613 
  • trunk/psModules/src/objects/pmSourcePhotometry.c

    r34498 r36375  
    113113    source->apFluxErr = NAN;
    114114
     115    pmModelStatus badModel = PM_MODEL_STATUS_NONE;
     116    badModel |= PM_MODEL_STATUS_BADARGS;
     117    badModel |= PM_MODEL_STATUS_OFFIMAGE;
     118    badModel |= PM_MODEL_STATUS_NAN_CHISQ;
     119    badModel |= PM_MODEL_SERSIC_PCM_FAIL_GUESS;
     120    badModel |= PM_MODEL_SERSIC_PCM_FAIL_GRID;
     121    badModel |= PM_MODEL_PCM_FAIL_GUESS;
     122
    115123    // XXXXXX review:
    116124    // Select the 'best' model -- this is used for PSF_QF,_PERFECT & ???. isPSF is true if this
     
    162170        for (int i = 0; i < source->modelFits->n; i++) {
    163171            pmModel *model = source->modelFits->data[i];
    164             if (model->flags & PM_MODEL_STATUS_BADARGS) continue;
     172            if (model->flags & badModel) continue;
    165173            status = pmSourcePhotometryModel (&model->mag, NULL, model);
    166174            if (model == source->modelEXT) foundEXT = true;
     
    902910}
    903911
     912bool pmSourceChisqModelFlux (pmSource *source, pmModel *model, psImageMaskType maskVal)
     913{
     914    PS_ASSERT_PTR_NON_NULL(source, false);
     915    PS_ASSERT_PTR_NON_NULL(model, false);
     916
     917    float dC = 0.0;
     918    int Npix = 0;
     919
     920    psVector *params = model->params;
     921    psImage  *image = source->pixels;
     922    psImage  *modelFlux = source->modelFlux;
     923    psImage  *mask = source->maskObj;
     924    psImage  *variance = source->variance;
     925
     926    float Io = params->data.F32[PM_PAR_I0];
     927
     928    for (int iy = 0; iy < image->numRows; iy++) {
     929        for (int ix = 0; ix < image->numCols; ix++) {
     930
     931            // skip pixels which are masked
     932            if (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & maskVal) continue;
     933
     934            if (variance->data.F32[iy][ix] <= 0) continue;
     935
     936            dC += PS_SQR (image->data.F32[iy][ix] - Io*modelFlux->data.F32[iy][ix]) / variance->data.F32[iy][ix];
     937            Npix ++;
     938        }
     939    }
     940    model->nPix = Npix;
     941    model->nDOF = Npix - model->nPar;
     942    model->chisq = dC;
     943    model->chisqNorm = dC / model->nDOF;
     944
     945    return (true);
     946}
     947
    904948double pmSourceModelWeight(const pmSource *Mi, int term, const pmSourceFitVarMode fitVarMode, const float covarFactor, psImageMaskType maskVal)
    905949{
Note: See TracChangeset for help on using the changeset viewer.