IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 32347


Ignore:
Timestamp:
Sep 6, 2011, 1:02:53 PM (15 years ago)
Author:
eugene
Message:
  • add concept of saddlePoints to peaks (not actually used in the end)
  • add tmp flags to mark sources for analysis or not in psphotStack
  • autocode the pmSourceIO_CMF_PS1_* functions
  • use 1D gauss approx for convolution in PCM fitting
  • added pmSourceExtFitPars (not actually used)
  • in model guess, use 1st radial moments to define size (if it exists)
  • include PSF_INST_MAG, AP_MAG, KRON_MAG in xfit output
  • fix the position for extended source fits (avoid instability)
  • Sersic-like models (incl. Exp and Dev) use Reff, not sigma; conversion tools need to respect this
  • only use a single pass on the centroid (unwindowed, but limited to 1.5 sigma radius) - this avoids moving the centroid because of nearby neighbors
  • use symmetrical averaging (geometric mean) to calculated 1st radial moment (and avoid neighbor biases), do not use symm. averaging for the flux
  • fix the integration of the sersic, pgauss, and related model functions.
  • fix the central pixel to have the full flux for sersic-like models (interpolated value)
Location:
trunk/psModules/src
Files:
3 deleted
44 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/psModules/src/camera/pmReadoutFake.c

    r29004 r32347  
    5151
    5252    psF32 *params = model->params->data.F32; // Model parameters
    53     psEllipseAxes axes = pmPSF_ModelToAxes(params, MAX_AXIS_RATIO); // Ellipse axes
     53    psEllipseAxes axes = pmPSF_ModelToAxes(params, MAX_AXIS_RATIO, model->type); // Ellipse axes
    5454    // Curiously, the minor axis can be larger than the major axis, so need to check.
    5555    if (axes.major >= axes.minor) {
     
    5858        axes.major = axes.minor;
    5959    }
    60     return pmPSF_AxesToModel(params, axes);
     60    return pmPSF_AxesToModel(params, axes, model->type);
    6161}
    6262
  • trunk/psModules/src/objects

    • Property svn:ignore
      •  

        old new  
        55*.la
        66*.lo
         7pmSourceIO_CMF_PS1_V1.c
         8pmSourceIO_CMF_PS1_V2.c
         9pmSourceIO_CMF_PS1_V3.c
  • trunk/psModules/src/objects/Makefile.am

    r31670 r32347  
    130130
    131131# pmSourceID_CMF_* functions use a common framework
    132 BUILT_SOURCES = pmSourceIO_CMF_PS1_V1.v1.c pmSourceIO_CMF_PS1_V2.v1.c pmSourceIO_CMF_PS1_V3.v1.c
     132BUILT_SOURCES = pmSourceIO_CMF_PS1_V1.c pmSourceIO_CMF_PS1_V2.c pmSourceIO_CMF_PS1_V3.c
    133133
    134 pmSourceIO_CMF_PS1_V1.v1.c : pmSourceIO_CMF.c.in mksource.pl
    135         mksource.pl pmSourceIO_CMF.c.in PS1_V1 pmSourceIO_CMF_PS1_V1.v1.c
     134pmSourceIO_CMF_PS1_V1.c : pmSourceIO_CMF.c.in mksource.pl
     135        mksource.pl pmSourceIO_CMF.c.in PS1_V1 pmSourceIO_CMF_PS1_V1.c
    136136
    137 pmSourceIO_CMF_PS1_V2.v1.c : pmSourceIO_CMF.c.in mksource.pl
    138         mksource.pl pmSourceIO_CMF.c.in PS1_V2 pmSourceIO_CMF_PS1_V2.v1.c
     137pmSourceIO_CMF_PS1_V2.c : pmSourceIO_CMF.c.in mksource.pl
     138        mksource.pl pmSourceIO_CMF.c.in PS1_V2 pmSourceIO_CMF_PS1_V2.c
    139139
    140 pmSourceIO_CMF_PS1_V3.v1.c : pmSourceIO_CMF.c.in mksource.pl
    141         mksource.pl pmSourceIO_CMF.c.in PS1_V2 pmSourceIO_CMF_PS1_V3.v1.c
     140pmSourceIO_CMF_PS1_V3.c : pmSourceIO_CMF.c.in mksource.pl
     141        mksource.pl pmSourceIO_CMF.c.in PS1_V3 pmSourceIO_CMF_PS1_V3.c
    142142
    143143# EXTRA_DIST = pmErrorCodes.h.in pmErrorCodes.dat pmErrorCodes.c.in
  • trunk/psModules/src/objects/mksource.pl

    r31670 r32347  
    1414
    1515# see if we can add in PS1_DV* and PS1_SV* as well...
    16 @cmfmodes = ("PS1_V1", 1,
     16%cmfmodes = ("PS1_V1", 1,
    1717             "PS1_V2", 2,
    1818             "PS1_V3", 3);
     19
     20print "1: $cmfmodes{1}\n";
     21print "PS1_V1: $cmfmodes{'PS1_V1'}\n";
    1922
    2023open (FILE, "$template") || die "failed to open template $template\n";
     
    5053
    5154    if ($gtMode) {
     55        # print "gtMode : $line\n";
    5256        $thisLevel = $cmfmodes{$gtMode};
    5357        $myLevel = $cmfmodes{$cmfmode};
    54         if ($thisLevel <= $myLevel) { next; }
    55         $line =~ s|\@<\S*\@\s*||;
     58        print "gtMode : $gtMode vs $cmfmode, $thisLevel, $myLevel\n";
     59        if ($myLevel <= $thisLevel) { next; }
     60        $line =~ s|\@>\S*\@\s*||;
    5661    }
    5762
    5863    if ($ltMode) {
     64        # print "ltMode : $line\n";
    5965        $thisLevel = $cmfmodes{$ltMode};
    6066        $myLevel = $cmfmodes{$cmfmode};
    61         if ($thisLevel >= $myLevel) { next; }
    62         $line =~ s|\@>\S*\@\s*||;
     67        print "ltMode : $ltMode vs $cmfmode, $thisLevel, $myLevel\n";
     68        if ($myLevel >= $thisLevel) { next; }
     69        $line =~ s|\@<\S*\@\s*||;
    6370    }
    6471
  • trunk/psModules/src/objects/models/pmModel_DEV.c

    r31451 r32347  
    8989static bool limitsApply = true;         // Apply limits?
    9090
     91# include "pmModel_SERSIC.CP.h"
     92
    9193psF32 PM_MODEL_FUNC (psVector *deriv,
    9294                     const psVector *params,
     
    9496{
    9597    psF32 *PAR = params->data.F32;
    96 
    97     float index = 0.5 / ALPHA;
    98     float bn = 1.9992*index - 0.3271;
    99     float Io = exp(bn);
    10098
    10199    psF32 X  = pixcoord->data.F32[0] - PAR[PM_PAR_XPOS];
     
    105103    psF32 z  = (PS_SQR(px) + PS_SQR(py) + PAR[PM_PAR_SXY]*X*Y);
    106104
    107     assert (z >= 0);
     105    // If the elliptical contour is defined in a valid way, we should never trigger this
     106    // assert.  Other models (like PGAUSS) don't use fractional powers, and thus do not have
     107    // NaN values for negative values of z
     108    psAssert (z >= 0, "do not allow negative z values in model");
     109
     110    float index = 0.5 / ALPHA;
     111    float par7 = ALPHA;
     112    float bn = 1.9992*index - 0.3271;
     113    float Io = exp(bn);
    108114
    109115    psF32 f2 = bn*pow(z,ALPHA);
    110116    psF32 f1 = Io*exp(-f2);
     117
     118    psF32 radius = hypot(X, Y);
     119    if (radius < 1.0) {
     120
     121        // ** use bilinear interpolation to the given location from the 4 surrounding pixels centered on the object center
     122
     123        // first, use Rmajor and index to find the central pixel flux (fraction of total flux)
     124        psEllipseShape shape;
     125
     126        shape.sx  = PAR[PM_PAR_SXX];
     127        shape.sy  = PAR[PM_PAR_SYY];
     128        shape.sxy = PAR[PM_PAR_SXY];
     129
     130        // for a non-circular Sersic, the flux of the Rmajor equivalent is scaled by the AspectRatio
     131        psEllipseAxes axes = psEllipseShapeToAxes (shape, 20.0);
     132
     133        // get the central pixel flux from the lookup table
     134        float xPix = (axes.major - centralPixelXo) / centralPixeldX;
     135        xPix = PS_MIN (PS_MAX(xPix, 0), centralPixelNX - 1);
     136        float yPix = (index - centralPixelYo) / centralPixeldY;
     137        yPix = PS_MIN (PS_MAX(yPix, 0), centralPixelNY - 1);
     138
     139        // the integral of a Sersic has an analytical form as follows:
     140        float logGamma = lgamma(2.0*index);
     141        float bnFactor = pow(bn, 2.0*index);
     142        float norm = 2.0 * M_PI * PS_SQR(axes.major) * index * exp(bn) * exp(logGamma) / bnFactor;
     143
     144        // XXX interpolate to get the value
     145        // XXX for the moment, just integerize
     146        // XXX I need to multiply by the integrated flux to get the flux in the central pixel
     147        float Vcenter = centralPixel[(int)yPix][(int)xPix] * norm;
     148       
     149        float px1 = 1.0 / PAR[PM_PAR_SXX];
     150        float py1 = 1.0 / PAR[PM_PAR_SYY];
     151        float z10 = PS_SQR(px1);
     152        float z01 = PS_SQR(py1);
     153
     154        // which pixels do we need for this interpolation?
     155        // (I do not keep state information, so I don't know anything about other evaluations of nearby pixels...)
     156        if ((X >= 0) && (Y >= 0)) {
     157            float z11 = z10 + z01 + PAR[PM_PAR_SXY]; // X * Y positive
     158            float V00 = Vcenter;
     159            float V10 = Io*exp(-bn*pow(z10,par7));
     160            float V01 = Io*exp(-bn*pow(z01,par7));
     161            float V11 = Io*exp(-bn*pow(z11,par7));
     162            f1 = interpolatePixels(V00, V10, V01, V11, X, Y);
     163        }
     164        if ((X < 0) && (Y >= 0)) {
     165            float z11 = z10 + z01 - PAR[PM_PAR_SXY]; // X * Y negative
     166            float V00 = Io*exp(-bn*pow(z10,par7));
     167            float V10 = Vcenter;
     168            float V01 = Io*exp(-bn*pow(z11,par7));
     169            float V11 = Io*exp(-bn*pow(z01,par7));
     170            f1 = interpolatePixels(V00, V10, V01, V11, (1.0 + X), Y);
     171        }
     172        if ((X >= 0) && (Y < 0)) {
     173            float z11 = z10 + z01 - PAR[PM_PAR_SXY]; // X * Y negative
     174            float V00 = Io*exp(-bn*pow(z01,par7));
     175            float V10 = Io*exp(-bn*pow(z11,par7));
     176            float V01 = Vcenter;
     177            float V11 = Io*exp(-bn*pow(z10,par7));
     178            f1 = interpolatePixels(V00, V10, V01, V11, X, (1.0 + Y));
     179        }
     180        if ((X < 0) && (Y < 0)) {
     181            float z11 = z10 + z01 + PAR[PM_PAR_SXY]; // X * Y positive
     182            float V00 = Io*exp(-bn*pow(z11,par7));
     183            float V10 = Io*exp(-bn*pow(z10,par7));
     184            float V01 = Io*exp(-bn*pow(z01,par7));
     185            float V11 = Vcenter;
     186            f1 = interpolatePixels(V00, V10, V01, V11, (1.0 + X), (1.0 + Y));
     187        }
     188    }   
     189
    111190    psF32 z0 = PAR[PM_PAR_I0]*f1;
    112191    psF32 f0 = PAR[PM_PAR_SKY] + z0;
     
    120199        psF32 *dPAR = deriv->data.F32;
    121200
     201        dPAR[PM_PAR_SKY]  = +1.0;
     202        dPAR[PM_PAR_I0]   = +2.0*f1; // XXX extra damping..
     203
    122204        // gradient is infinite for z = 0; saturate at z = 0.01
    123205        psF32 z1 = (z < 0.01) ? z0*bn*ALPHA*pow(0.01,ALPHA - 1.0) : z0*bn*ALPHA*pow(z,ALPHA - 1.0);
    124 
    125         dPAR[PM_PAR_SKY]  = +1.0;
    126         dPAR[PM_PAR_I0]   = +2.0*f1;
    127206
    128207        assert (isfinite(z1));
     
    223302
    224303    // set the shape parameters
     304    // XXX adjust this?
    225305    if (!pmModelSetShape(&PAR[PM_PAR_SXX], &PAR[PM_PAR_SXY], &PAR[PM_PAR_SYY], source->moments)) {
    226306      return false;
     
    246326}
    247327
     328// A DeVaucouleur model is equivalent to a Sersic with index = 4.0
    248329psF64 PM_MODEL_FLUX (const psVector *params)
    249330{
    250     float z, norm;
    251331    psEllipseShape shape;
    252332
    253333    psF32 *PAR = params->data.F32;
    254334
    255     shape.sx  = PAR[PM_PAR_SXX] / M_SQRT2;
    256     shape.sy  = PAR[PM_PAR_SYY] / M_SQRT2;
     335    shape.sx  = PAR[PM_PAR_SXX];
     336    shape.sy  = PAR[PM_PAR_SYY];
    257337    shape.sxy = PAR[PM_PAR_SXY];
    258338
    259     // Area is equivalent to 2 pi sigma^2
     339    // for a non-circular DeVaucouleur, the flux of the Rmajor equivalent is scaled by the AspectRatio
    260340    psEllipseAxes axes = psEllipseShapeToAxes (shape, 20.0);
    261     psF64 Area = 2.0 * M_PI * axes.major * axes.minor;
    262 
    263     // the area needs to be multiplied by the integral of f(z)
    264     norm = 0.0;
    265 
    266     # define DZ 0.25
    267 
    268     float f0 = 1.0;
    269     float f1, f2;
    270     for (z = DZ; z < 150; z += DZ) {
    271         f1 = exp(-pow(z,ALPHA));
    272         z += DZ;
    273         f2 = exp(-pow(z,ALPHA));
    274         norm += f0 + 4*f1 + f2;
    275         f0 = f2;
    276     }
    277     norm *= DZ / 3.0;
    278 
    279     psF64 Flux = PAR[PM_PAR_I0] * Area * norm;
     341    float AspectRatio = axes.minor / axes.major;
     342
     343    float index = 4.0;
     344    float bn = 1.9992*index - 0.3271;
     345
     346    // the integral of a Sersic has an analytical form as follows:
     347    float logGamma = lgamma(2.0*index);
     348    float bnFactor = pow(bn, 2.0*index);
     349    float norm = 2.0 * M_PI * PS_SQR(axes.major) * index * exp(bn) * exp(logGamma) / bnFactor;
     350   
     351    psF64 Flux = PAR[PM_PAR_I0] * norm * AspectRatio;
    280352
    281353    return(Flux);
     
    297369        return (1.0);
    298370
    299     shape.sx  = PAR[PM_PAR_SXX] / M_SQRT2;
    300     shape.sy  = PAR[PM_PAR_SYY] / M_SQRT2;
     371    shape.sx  = PAR[PM_PAR_SXX];
     372    shape.sy  = PAR[PM_PAR_SYY];
    301373    shape.sxy = PAR[PM_PAR_SXY];
    302374
  • trunk/psModules/src/objects/models/pmModel_EXP.c

    r31451 r32347  
    8181static bool limitsApply = true;         // Apply limits?
    8282
     83# include "pmModel_SERSIC.CP.h"
     84
    8385psF32 PM_MODEL_FUNC (psVector *deriv,
    8486                     const psVector *params,
     
    9395    psF32 z  = PS_SQR(px) + PS_SQR(py) + PAR[PM_PAR_SXY]*X*Y;
    9496
    95     // XXX if the elliptical contour is defined in valid way, this step should not be required.
    96     // other models (like PGAUSS) don't use fractional powers, and thus do not have NaN values
    97     // for negative values of z
    98     // XXX use an assert here to force the elliptical parameters to be correctly determined
    99     // if (z < 0) z = 0;
    100     assert (z >= 0);
    101 
    102     psF32 f2 = sqrt(z);
    103     psF32 f1 = exp(-f2);
     97    // If the elliptical contour is defined in a valid way, we should never trigger this
     98    // assert.  Other models (like PGAUSS) don't use fractional powers, and thus do not have
     99    // NaN values for negative values of z
     100    psAssert (z >= 0, "do not allow negative z values in model");
     101
     102    float index = 1.0;
     103    float par7 = 0.5;
     104    float bn = 1.9992*index - 0.3271;
     105    float Io = exp(bn);
     106
     107    psF32 f2 = bn*sqrt(z);
     108    psF32 f1 = Io*exp(-f2);
     109
     110    psF32 radius = hypot(X, Y);
     111    if (radius < 1.0) {
     112
     113        // ** use bilinear interpolation to the given location from the 4 surrounding pixels centered on the object center
     114
     115        // first, use Rmajor and index to find the central pixel flux (fraction of total flux)
     116        psEllipseShape shape;
     117
     118        shape.sx  = PAR[PM_PAR_SXX];
     119        shape.sy  = PAR[PM_PAR_SYY];
     120        shape.sxy = PAR[PM_PAR_SXY];
     121
     122        // for a non-circular Sersic, the flux of the Rmajor equivalent is scaled by the AspectRatio
     123        psEllipseAxes axes = psEllipseShapeToAxes (shape, 20.0);
     124
     125        // get the central pixel flux from the lookup table
     126        float xPix = (axes.major - centralPixelXo) / centralPixeldX;
     127        xPix = PS_MIN (PS_MAX(xPix, 0), centralPixelNX - 1);
     128        float yPix = (index - centralPixelYo) / centralPixeldY;
     129        yPix = PS_MIN (PS_MAX(yPix, 0), centralPixelNY - 1);
     130
     131        // the integral of a Sersic has an analytical form as follows:
     132        float logGamma = lgamma(2.0*index);
     133        float bnFactor = pow(bn, 2.0*index);
     134        float norm = 2.0 * M_PI * PS_SQR(axes.major) * index * exp(bn) * exp(logGamma) / bnFactor;
     135
     136        // XXX interpolate to get the value
     137        // XXX for the moment, just integerize
     138        // XXX I need to multiply by the integrated flux to get the flux in the central pixel
     139        float Vcenter = centralPixel[(int)yPix][(int)xPix] * norm;
     140       
     141        float px1 = 1.0 / PAR[PM_PAR_SXX];
     142        float py1 = 1.0 / PAR[PM_PAR_SYY];
     143        float z10 = PS_SQR(px1);
     144        float z01 = PS_SQR(py1);
     145
     146        // which pixels do we need for this interpolation?
     147        // (I do not keep state information, so I don't know anything about other evaluations of nearby pixels...)
     148        if ((X >= 0) && (Y >= 0)) {
     149            float z11 = z10 + z01 + PAR[PM_PAR_SXY]; // X * Y positive
     150            float V00 = Vcenter;
     151            float V10 = Io*exp(-bn*pow(z10,par7));
     152            float V01 = Io*exp(-bn*pow(z01,par7));
     153            float V11 = Io*exp(-bn*pow(z11,par7));
     154            f1 = interpolatePixels(V00, V10, V01, V11, X, Y);
     155        }
     156        if ((X < 0) && (Y >= 0)) {
     157            float z11 = z10 + z01 - PAR[PM_PAR_SXY]; // X * Y negative
     158            float V00 = Io*exp(-bn*pow(z10,par7));
     159            float V10 = Vcenter;
     160            float V01 = Io*exp(-bn*pow(z11,par7));
     161            float V11 = Io*exp(-bn*pow(z01,par7));
     162            f1 = interpolatePixels(V00, V10, V01, V11, (1.0 + X), Y);
     163        }
     164        if ((X >= 0) && (Y < 0)) {
     165            float z11 = z10 + z01 - PAR[PM_PAR_SXY]; // X * Y negative
     166            float V00 = Io*exp(-bn*pow(z01,par7));
     167            float V10 = Io*exp(-bn*pow(z11,par7));
     168            float V01 = Vcenter;
     169            float V11 = Io*exp(-bn*pow(z10,par7));
     170            f1 = interpolatePixels(V00, V10, V01, V11, X, (1.0 + Y));
     171        }
     172        if ((X < 0) && (Y < 0)) {
     173            float z11 = z10 + z01 + PAR[PM_PAR_SXY]; // X * Y positive
     174            float V00 = Io*exp(-bn*pow(z11,par7));
     175            float V10 = Io*exp(-bn*pow(z10,par7));
     176            float V01 = Io*exp(-bn*pow(z01,par7));
     177            float V11 = Vcenter;
     178            f1 = interpolatePixels(V00, V10, V01, V11, (1.0 + X), (1.0 + Y));
     179        }
     180    }   
     181
    104182    psF32 z0 = PAR[PM_PAR_I0]*f1;
    105183    psF32 f0 = PAR[PM_PAR_SKY] + z0;
     
    118196        // gradient is infinite for z = 0; saturate at z = 0.01
    119197        // z1 is -df/dz (the negative sign is canceled by most of dz/dPAR[i]
    120         psF32 z1 = (z < 0.01) ? 0.5*z0/sqrt(0.01) : 0.5*z0/sqrt(z);
     198        psF32 z1 = (z < 0.01) ? 0.5*bn*z0/sqrt(0.01) : 0.5*bn*z0/sqrt(z);
    121199
    122200        // XXX dampen SXX and SYY as in GAUSS?
     
    216294
    217295    // set the shape parameters
     296    // XXX adjust this?
    218297    if (!pmModelSetShape(&PAR[PM_PAR_SXX], &PAR[PM_PAR_SXY], &PAR[PM_PAR_SYY], source->moments)) {
    219298      return false;
     
    233312}
    234313
     314// An exponential model is equivalent to a Sersic with index = 1.0
    235315psF64 PM_MODEL_FLUX (const psVector *params)
    236316{
    237     float z, norm;
    238317    psEllipseShape shape;
    239318
    240319    psF32 *PAR = params->data.F32;
    241320
    242     shape.sx  = PAR[PM_PAR_SXX] / M_SQRT2;
    243     shape.sy  = PAR[PM_PAR_SYY] / M_SQRT2;
     321    shape.sx  = PAR[PM_PAR_SXX];
     322    shape.sy  = PAR[PM_PAR_SYY];
    244323    shape.sxy = PAR[PM_PAR_SXY];
    245324
    246     // Area is equivalent to 2 pi sigma^2
     325    // for a non-circular Exponential, the flux of the Rmajor equivalent is scaled by the AspectRatio
    247326    psEllipseAxes axes = psEllipseShapeToAxes (shape, 20.0);
    248     psF64 Area = 2.0 * M_PI * axes.major * axes.minor;
    249 
    250     // the area needs to be multiplied by the integral of f(z) = exp(-sqrt(z)) [0 to infinity]
    251     norm = 0.0;
    252 
    253     # define DZ 0.25
    254 
    255     float f0 = 1.0;
    256     float f1, f2;
    257     for (z = DZ; z < 150; z += DZ) {
    258         f1 = exp(-sqrt(z));
    259         z += DZ;
    260         f2 = exp(-sqrt(z));
    261         norm += f0 + 4*f1 + f2;
    262         f0 = f2;
    263     }
    264     norm *= DZ / 3.0;
    265 
    266     psF64 Flux = PAR[PM_PAR_I0] * Area * norm;
     327    float AspectRatio = axes.minor / axes.major;
     328
     329    float index = 1.0;
     330    float bn = 1.9992*index - 0.3271;
     331
     332    // the integral of a Sersic has an analytical form as follows:
     333    float logGamma = lgamma(2.0*index);
     334    float bnFactor = pow(bn, 2.0*index);
     335    float norm = 2.0 * M_PI * PS_SQR(axes.major) * index * exp(bn) * exp(logGamma) / bnFactor;
     336   
     337    psF64 Flux = PAR[PM_PAR_I0] * norm * AspectRatio;
    267338
    268339    return(Flux);
     
    284355        return (1.0);
    285356
    286     shape.sx  = PAR[PM_PAR_SXX] / M_SQRT2;
    287     shape.sy  = PAR[PM_PAR_SYY] / M_SQRT2;
     357    shape.sx  = PAR[PM_PAR_SXX];
     358    shape.sy  = PAR[PM_PAR_SYY];
    288359    shape.sxy = PAR[PM_PAR_SXY];
    289360
  • trunk/psModules/src/objects/models/pmModel_PGAUSS.c

    r31451 r32347  
    217217}
    218218
    219 psF64 PM_MODEL_FLUX(const psVector *params)
    220 {
    221     float norm, z;
     219// integrate the model to get the full flux
     220psF64 PM_MODEL_FLUX (const psVector *params)
     221{
     222    float z, norm;
    222223    psEllipseShape shape;
    223224
     
    228229    shape.sxy = PAR[PM_PAR_SXY];
    229230
    230     // Area is equivalent to 2 pi sigma^2
    231231    psEllipseAxes axes = psEllipseShapeToAxes (shape, 20.0);
    232     psF64 Area = 2.0 * M_PI * axes.major * axes.minor;
    233 
    234     // the area needs to be multiplied by the integral of f(z)
     232    float AspectRatio = axes.minor / axes.major;
     233
     234    // flux = 2 \pi \int f(r) r dr
    235235    norm = 0.0;
    236236
    237     # define DZ 0.25
    238 
    239     float f0 = 1.0;
     237    # define DR 0.25
     238
     239    // f = f(r) * r
     240    float f0 = 0.0;
    240241    float f1, f2;
    241     for (z = DZ; z < 150; z += DZ) {
    242         f1 = 1.0 / (1 + z + z*z/2.0 + z*z*z/6.0);
    243         z += DZ;
    244         f2 = 1.0 / (1 + z + z*z/2.0 + z*z*z/6.0);
     242    for (float r = DR; r < 150; r += DR) {
     243        z = 0.5 * PS_SQR(r / axes.major);
     244        f1 = r / (1 + z + z*z/2.0 + z*z*z/6.0);
     245        r += DR;
     246        z = 0.5 * PS_SQR(r / axes.major);
     247        f2 = r / (1 + z + z*z/2.0 + z*z*z/6.0);
    245248        norm += f0 + 4*f1 + f2;
    246249        f0 = f2;
    247250    }
    248     norm *= DZ / 3.0;
    249 
    250     psF64 Flux = PAR[PM_PAR_I0] * Area * norm;
     251    norm *= DR / 3.0;
     252
     253    psF64 Flux = PAR[PM_PAR_I0] * norm * 2.0 * M_PI * AspectRatio;
    251254
    252255    return(Flux);
  • trunk/psModules/src/objects/models/pmModel_PS1_V1.c

    r31670 r32347  
    1414   * PM_PAR_XPOS 2  - X center of object
    1515   * PM_PAR_YPOS 3  - Y center of object
    16    * PM_PAR_SXX 4   - X^2 term of elliptical contour (sqrt(2) / SigmaX)
    17    * PM_PAR_SYY 5   - Y^2 term of elliptical contour (sqrt(2) / SigmaY)
     16   * PM_PAR_SXX 4   - X^2 term of elliptical contour (SigmaX / sqrt(2))
     17   * PM_PAR_SYY 5   - Y^2 term of elliptical contour (SigmaY / sqrt(2))
    1818   * PM_PAR_SXY 6   - X*Y term of elliptical contour
    1919   * PM_PAR_7   7   - amplitude of the linear component (k)
     
    239239}
    240240
     241// integrate the model to get the full flux
    241242psF64 PM_MODEL_FLUX (const psVector *params)
    242243{
     
    250251    shape.sxy = PAR[PM_PAR_SXY];
    251252
    252     // Area is equivalent to 2 pi sigma^2
    253253    psEllipseAxes axes = psEllipseShapeToAxes (shape, 20.0);
    254     psF64 Area = 2.0 * M_PI * axes.major * axes.minor;
    255 
    256     // the area needs to be multiplied by the integral of f(z)
     254    float AspectRatio = axes.minor / axes.major;
     255
     256    // flux = 2 \pi \int f(r) r dr
    257257    norm = 0.0;
    258258
    259     # define DZ 0.25
    260 
    261     float f0 = 1.0;
     259    # define DR 0.25
     260
     261    // f = f(r) * r
     262    float f0 = 0.0;
    262263    float f1, f2;
    263     for (z = DZ; z < 150; z += DZ) {
    264         f1 = 1.0 / (1 + PAR[PM_PAR_7]*z + pow(z, ALPHA));
    265         z += DZ;
    266         f2 = 1.0 / (1 + PAR[PM_PAR_7]*z + pow(z, ALPHA));
     264    for (float r = DR; r < 150; r += DR) {
     265        z = 0.5 * PS_SQR(r / axes.major);
     266        f1 = r / (1 + PAR[PM_PAR_7]*z + pow(z, ALPHA));
     267        r += DR;
     268        z = 0.5 * PS_SQR(r / axes.major);
     269        f2 = r / (1 + PAR[PM_PAR_7]*z + pow(z, ALPHA));
    267270        norm += f0 + 4*f1 + f2;
    268271        f0 = f2;
    269272    }
    270     norm *= DZ / 3.0;
    271 
    272     psF64 Flux = PAR[PM_PAR_I0] * Area * norm;
     273    norm *= DR / 3.0;
     274
     275    psF64 Flux = PAR[PM_PAR_I0] * norm * 2.0 * M_PI * AspectRatio;
    273276
    274277    return(Flux);
  • trunk/psModules/src/objects/models/pmModel_QGAUSS.c

    r31670 r32347  
    240240}
    241241
     242// integrate the model to get the full flux
    242243psF64 PM_MODEL_FLUX (const psVector *params)
    243244{
     
    251252    shape.sxy = PAR[PM_PAR_SXY];
    252253
    253     // Area is equivalent to 2 pi sigma^2
    254254    psEllipseAxes axes = psEllipseShapeToAxes (shape, 20.0);
    255     psF64 Area = 2.0 * M_PI * axes.major * axes.minor;
    256 
    257     // the area needs to be multiplied by the integral of f(z)
     255    float AspectRatio = axes.minor / axes.major;
     256
     257    // flux = 2 \pi \int f(r) r dr
    258258    norm = 0.0;
    259259
    260     # define DZ 0.25
    261 
    262     float f0 = 1.0;
     260    # define DR 0.25
     261
     262    // f = f(r) * r
     263    float f0 = 0.0;
    263264    float f1, f2;
    264     for (z = DZ; z < 150; z += DZ) {
    265         f1 = 1.0 / (1 + PAR[PM_PAR_7]*z + pow(z, ALPHA));
    266         z += DZ;
    267         f2 = 1.0 / (1 + PAR[PM_PAR_7]*z + pow(z, ALPHA));
     265    for (float r = DR; r < 150; r += DR) {
     266        z = 0.5 * PS_SQR(r / axes.major);
     267        f1 = r / (1 + PAR[PM_PAR_7]*z + pow(z, ALPHA));
     268        r += DR;
     269        z = 0.5 * PS_SQR(r / axes.major);
     270        f2 = r / (1 + PAR[PM_PAR_7]*z + pow(z, ALPHA));
    268271        norm += f0 + 4*f1 + f2;
    269272        f0 = f2;
    270273    }
    271     norm *= DZ / 3.0;
    272 
    273     psF64 Flux = PAR[PM_PAR_I0] * Area * norm;
     274    norm *= DR / 3.0;
     275
     276    psF64 Flux = PAR[PM_PAR_I0] * norm * 2.0 * M_PI * AspectRatio;
    274277
    275278    return(Flux);
  • trunk/psModules/src/objects/models/pmModel_RGAUSS.c

    r31451 r32347  
    229229}
    230230
     231// integrate the model to get the full flux
    231232psF64 PM_MODEL_FLUX (const psVector *params)
    232233{
    233     float norm, z;
     234    float z, norm;
    234235    psEllipseShape shape;
    235236
     
    240241    shape.sxy = PAR[PM_PAR_SXY];
    241242
    242     // Area is equivalent to 2 pi sigma^2
    243243    psEllipseAxes axes = psEllipseShapeToAxes (shape, 20.0);
    244     psF64 Area = 2.0 * M_PI * axes.major * axes.minor;
    245 
    246     // the area needs to be multiplied by the integral of f(z)
     244    float AspectRatio = axes.minor / axes.major;
     245
     246    // flux = 2 \pi \int f(r) r dr
    247247    norm = 0.0;
    248248
    249     # define DZ 0.25
    250 
    251     float f0 = 1.0;
     249    # define DR 0.25
     250
     251    // f = f(r) * r
     252    float f0 = 0.0;
    252253    float f1, f2;
    253     for (z = DZ; z < 150; z += DZ) {
    254         f1 = 1.0 / (1 + z + pow(z, PAR[PM_PAR_7]));
    255         z += DZ;
    256         f2 = 1.0 / (1 + z + pow(z, PAR[PM_PAR_7]));
     254    for (float r = DR; r < 150; r += DR) {
     255        z = 0.5 * PS_SQR(r / axes.major);
     256        f1 = r / (1 + z + pow(z, PAR[PM_PAR_7]));
     257        r += DR;
     258        z = 0.5 * PS_SQR(r / axes.major);
     259        f2 = r / (1 + z + pow(z, PAR[PM_PAR_7]));
    257260        norm += f0 + 4*f1 + f2;
    258261        f0 = f2;
    259262    }
    260     norm *= DZ / 3.0;
    261 
    262     psF64 Flux = PAR[PM_PAR_I0] * Area * norm;
     263    norm *= DR / 3.0;
     264
     265    psF64 Flux = PAR[PM_PAR_I0] * norm * 2.0 * M_PI * AspectRatio;
    263266
    264267    return(Flux);
  • trunk/psModules/src/objects/models/pmModel_SERSIC.c

    r31451 r32347  
    1313   * PM_PAR_XPOS 2  - X center of object
    1414   * PM_PAR_YPOS 3  - Y center of object
    15    * PM_PAR_SXX 4   - X^2 term of elliptical contour (sqrt(2) / SigmaX)
    16    * PM_PAR_SYY 5   - Y^2 term of elliptical contour (sqrt(2) / SigmaY)
     15   * PM_PAR_SXX 4   - X^2 term of elliptical contour (SigmaX / sqrt(2))
     16   * PM_PAR_SYY 5   - Y^2 term of elliptical contour (SigmaY / sqrt(2))
    1717   * PM_PAR_SXY 6   - X*Y term of elliptical contour
    1818   * PM_PAR_7   7   - normalized sersic parameter
     19
     20   * note that a Sersic model is usually defined in terms of R_e, the half-light radius.  This
     21     construction does not include a factor of 2 in the X^2 term, etc, like for a Gaussian.
     22     Conversion from SXX, SYY, SXY to R_major, R_minor, theta can be done by using setting:
     23     shape.sx = SXX / sqrt(2), shape.sy = SYY / sqrt(2), shape.sxy = SXY, then calling
     24     psEllipseShapeToAxes, and multiplying the values of axes.major, axes.minor by sqrt(2)
    1925
    2026   note that a standard sersic model uses exp(-K*(z^(1/2n) - 1).  the additional elements (K,
     
    8591static bool limitsApply = true;         // Apply limits?
    8692
     93# include "pmModel_SERSIC.CP.h"
     94
    8795psF32 PM_MODEL_FUNC (psVector *deriv,
    8896                     const psVector *params,
     
    97105    psF32 z  = PS_SQR(px) + PS_SQR(py) + PAR[PM_PAR_SXY]*X*Y;
    98106
    99     // XXX if the elliptical contour is defined in valid way, this step should not be required.
    100     // other models (like PGAUSS) don't use fractional powers, and thus do not have NaN values
    101     // for negative values of z
    102     // XXX use an assert here to force the elliptical parameters to be correctly determined
    103     // if (z < 0) z = 0;
    104     assert (z >= 0);
     107    // If the elliptical contour is defined in a valid way, we should never trigger this
     108    // assert.  Other models (like PGAUSS) don't use fractional powers, and thus do not have
     109    // NaN values for negative values of z
     110    psAssert (z >= 0, "do not allow negative z values in model");
    105111
    106112    float index = 0.5 / PAR[PM_PAR_7];
     113    float par7 = PAR[PM_PAR_7];
    107114    float bn = 1.9992*index - 0.3271;
    108115    float Io = exp(bn);
    109116
    110     psF32 f2 = bn*pow(z,PAR[PM_PAR_7]);
     117    psF32 f2 = bn*pow(z,par7);
    111118    psF32 f1 = Io*exp(-f2);
     119
     120    psF32 radius = hypot(X, Y);
     121    if (radius < 1.0) {
     122
     123        // ** use bilinear interpolation to the given location from the 4 surrounding pixels centered on the object center
     124
     125        // first, use Rmajor and index to find the central pixel flux (fraction of total flux)
     126        psEllipseShape shape;
     127
     128        shape.sx  = PAR[PM_PAR_SXX];
     129        shape.sy  = PAR[PM_PAR_SYY];
     130        shape.sxy = PAR[PM_PAR_SXY];
     131
     132        // for a non-circular Sersic, the flux of the Rmajor equivalent is scaled by the AspectRatio
     133        psEllipseAxes axes = psEllipseShapeToAxes (shape, 20.0);
     134
     135        // get the central pixel flux from the lookup table
     136        float xPix = (axes.major - centralPixelXo) / centralPixeldX;
     137        xPix = PS_MIN (PS_MAX(xPix, 0), centralPixelNX - 1);
     138        float yPix = (index - centralPixelYo) / centralPixeldY;
     139        yPix = PS_MIN (PS_MAX(yPix, 0), centralPixelNY - 1);
     140
     141        // the integral of a Sersic has an analytical form as follows:
     142        float logGamma = lgamma(2.0*index);
     143        float bnFactor = pow(bn, 2.0*index);
     144        float norm = 2.0 * M_PI * PS_SQR(axes.major) * index * exp(bn) * exp(logGamma) / bnFactor;
     145
     146        // XXX interpolate to get the value
     147        // XXX for the moment, just integerize
     148        // XXX I need to multiply by the integrated flux to get the flux in the central pixel
     149        float Vcenter = centralPixel[(int)yPix][(int)xPix] * norm;
     150       
     151        float px1 = 1.0 / PAR[PM_PAR_SXX];
     152        float py1 = 1.0 / PAR[PM_PAR_SYY];
     153        float z10 = PS_SQR(px1);
     154        float z01 = PS_SQR(py1);
     155
     156        // which pixels do we need for this interpolation?
     157        // (I do not keep state information, so I don't know anything about other evaluations of nearby pixels...)
     158        if ((X >= 0) && (Y >= 0)) {
     159            float z11 = z10 + z01 + PAR[PM_PAR_SXY]; // X * Y positive
     160            float V00 = Vcenter;
     161            float V10 = Io*exp(-bn*pow(z10,par7));
     162            float V01 = Io*exp(-bn*pow(z01,par7));
     163            float V11 = Io*exp(-bn*pow(z11,par7));
     164            f1 = interpolatePixels(V00, V10, V01, V11, X, Y);
     165        }
     166        if ((X < 0) && (Y >= 0)) {
     167            float z11 = z10 + z01 - PAR[PM_PAR_SXY]; // X * Y negative
     168            float V00 = Io*exp(-bn*pow(z10,par7));
     169            float V10 = Vcenter;
     170            float V01 = Io*exp(-bn*pow(z11,par7));
     171            float V11 = Io*exp(-bn*pow(z01,par7));
     172            f1 = interpolatePixels(V00, V10, V01, V11, (1.0 + X), Y);
     173        }
     174        if ((X >= 0) && (Y < 0)) {
     175            float z11 = z10 + z01 - PAR[PM_PAR_SXY]; // X * Y negative
     176            float V00 = Io*exp(-bn*pow(z01,par7));
     177            float V10 = Io*exp(-bn*pow(z11,par7));
     178            float V01 = Vcenter;
     179            float V11 = Io*exp(-bn*pow(z10,par7));
     180            f1 = interpolatePixels(V00, V10, V01, V11, X, (1.0 + Y));
     181        }
     182        if ((X < 0) && (Y < 0)) {
     183            float z11 = z10 + z01 + PAR[PM_PAR_SXY]; // X * Y positive
     184            float V00 = Io*exp(-bn*pow(z11,par7));
     185            float V10 = Io*exp(-bn*pow(z10,par7));
     186            float V01 = Io*exp(-bn*pow(z01,par7));
     187            float V11 = Vcenter;
     188            f1 = interpolatePixels(V00, V10, V01, V11, (1.0 + X), (1.0 + Y));
     189        }
     190    }   
     191
    112192    psF32 z0 = PAR[PM_PAR_I0]*f1;
    113193    psF32 f0 = PAR[PM_PAR_SKY] + z0;
     
    121201        psF32 *dPAR = deriv->data.F32;
    122202
    123         // gradient is infinite for z = 0; saturate at z = 0.01
    124         psF32 z1 = (z < 0.01) ? z0*bn*PAR[PM_PAR_7]*pow(0.01,PAR[PM_PAR_7] - 1.0) : z0*bn*PAR[PM_PAR_7]*pow(z,PAR[PM_PAR_7] - 1.0);
    125 
    126203        dPAR[PM_PAR_SKY]  = +1.0;
    127204        dPAR[PM_PAR_I0]   = +f1;
    128         dPAR[PM_PAR_7]    = (z < 0.01) ? -z0*pow(0.01,PAR[PM_PAR_7])*log(0.01) : -z0*f2*log(z);
     205
     206        // gradient is infinite for z = 0; saturate at z = 0.01
     207        psF32 z1 = (z < 0.01) ? z0*bn*par7*pow(0.01,par7 - 1.0) : z0*bn*par7*pow(z,par7 - 1.0);
     208
     209        dPAR[PM_PAR_7]    = (z < 0.01) ? -z0*pow(0.01,par7)*log(0.01) : -z0*f2*log(z);
    129210        dPAR[PM_PAR_7]   *= 3.0;
    130211
     
    269350    float Io = exp(0.5*bn);
    270351
    271     // XXX do we need this factor of sqrt(2)?
    272     // float Sxx = PS_MAX(0.5, M_SQRT2*shape.sx);
    273     // float Syy = PS_MAX(0.5, M_SQRT2*shape.sy);
    274 
    275352    float Sxx = PS_MAX(0.5, shape.sx);
    276353    float Syy = PS_MAX(0.5, shape.sy);
     
    294371}
    295372
     373// A sersic model has an integral flux which can be analytically represented
    296374psF64 PM_MODEL_FLUX (const psVector *params)
    297375{
    298     float z, norm;
    299376    psEllipseShape shape;
    300377
    301378    psF32 *PAR = params->data.F32;
    302379
    303     shape.sx  = PAR[PM_PAR_SXX] / M_SQRT2;
    304     shape.sy  = PAR[PM_PAR_SYY] / M_SQRT2;
     380    shape.sx  = PAR[PM_PAR_SXX];
     381    shape.sy  = PAR[PM_PAR_SYY];
    305382    shape.sxy = PAR[PM_PAR_SXY];
    306383
    307     // Area is equivalent to 2 pi sigma^2
     384    // for a non-circular Sersic, the flux of the Rmajor equivalent is scaled by the AspectRatio
    308385    psEllipseAxes axes = psEllipseShapeToAxes (shape, 20.0);
    309     psF64 Area = 2.0 * M_PI * axes.major * axes.minor;
    310 
    311     // the area needs to be multiplied by the integral of f(z)
    312     norm = 0.0;
    313 
    314     # define DZ 0.25
    315 
    316     float f0 = 1.0;
    317     float f1, f2;
    318     for (z = DZ; z < 150; z += DZ) {
    319         // f1 = 1.0 / (1 + PAR[PM_PAR_7]*z + pow(z, 2.25));
    320         f1 = exp(-pow(z,PAR[PM_PAR_7]));
    321         z += DZ;
    322         f2 = exp(-pow(z,PAR[PM_PAR_7]));
    323         norm += f0 + 4*f1 + f2;
    324         f0 = f2;
    325     }
    326     norm *= DZ / 3.0;
    327 
    328     psF64 Flux = PAR[PM_PAR_I0] * Area * norm;
     386    float AspectRatio = axes.minor / axes.major;
     387
     388    float index = 0.5 / PAR[PM_PAR_7];
     389    float bn = 1.9992*index - 0.3271;
     390
     391    // the integral of a Sersic has an analytical form as follows:
     392    float logGamma = lgamma(2.0*index);
     393    float bnFactor = pow(bn, 2.0*index);
     394    float norm = 2.0 * M_PI * PS_SQR(axes.major) * index * exp(bn) * exp(logGamma) / bnFactor;
     395   
     396    psF64 Flux = PAR[PM_PAR_I0] * norm * AspectRatio;
    329397
    330398    return(Flux);
     
    346414        return (1.0);
    347415
    348     shape.sx  = PAR[PM_PAR_SXX] / M_SQRT2;
    349     shape.sy  = PAR[PM_PAR_SYY] / M_SQRT2;
     416    shape.sx  = PAR[PM_PAR_SXX];
     417    shape.sy  = PAR[PM_PAR_SYY];
    350418    shape.sxy = PAR[PM_PAR_SXY];
    351419
  • trunk/psModules/src/objects/pmFootprintCullPeaks.c

    r31263 r32347  
    181181            if (!myFP->n) {
    182182                psWarning ("empty footprint?");
     183                psFree (myFP);
    183184                continue;
    184185            }
  • trunk/psModules/src/objects/pmModelUtils.c

    r31153 r32347  
    122122    if (!isfinite(axes.theta)) return false;
    123123
     124    // Mxx, Mxy, Myy define the elliptical shape, but Mrf defines the width
     125    float scale = (isfinite(moments->Mrf) && (moments->Mrf > 0.0)) ? moments->Mrf / axes.major : 1.0;
     126    axes.major *= scale;
     127    axes.minor *= scale;
     128
    124129    psEllipseShape shape = psEllipseAxesToShape (axes);
    125130
  • trunk/psModules/src/objects/pmMoments.c

    r29004 r32347  
    3232    tmp->Mrf = 0.0;
    3333    tmp->Mrh = 0.0;
     34
     35    tmp->KronCore = 0.0;
     36    tmp->KronCoreErr = 0.0;
     37
    3438    tmp->KronFlux = 0.0;
    3539    tmp->KronFluxErr = 0.0;
     
    3741    tmp->KronFinner = 0.0;
    3842    tmp->KronFouter = 0.0;
     43
     44    tmp->KronFluxPSF = 0.0;
     45    tmp->KronFluxPSFErr = 0.0;
     46    tmp->KronRadiusPSF = 0.0;
    3947
    4048    tmp->Mx = 0.0;
  • trunk/psModules/src/objects/pmMoments.h

    r31153 r32347  
    5151    int nPixels;  ///< Number of pixels used.
    5252
     53    float KronFluxPSF; ///< Kron Flux using PSF-optimized window
     54    float KronFluxPSFErr; ///< Kron Flux Error using PSF-optimized window
     55    float KronRadiusPSF; ///< Kron Radius using PSF-optimized window (Flux in 2.5 Radius)
     56
    5357    float KronCore;    ///< flux in r < 1.0*Mrf
    5458    float KronCoreErr;    ///< error on flux in r < 1.0*Mrf
  • trunk/psModules/src/objects/pmPCM_MinimizeChisq.c

    r29012 r32347  
    4545# define USE_FFT 1
    4646# define PRE_CONVOLVE 1
     47# define TESTCOPY 0
    4748
    4849bool pmPCM_MinimizeChisq (
     
    9394        psFree (pcm->psfFFT);
    9495    }
    95     pcm->psfFFT = psImageConvolveKernelInit(pcm->modelFlux, pcm->psf);
     96# if (!TESTCOPY)
     97    if (!pcm->use1Dgauss) {
     98        pcm->psfFFT = psImageConvolveKernelInit(pcm->modelFlux, pcm->psf);
     99    }
     100# endif
    96101# endif   
    97102
     
    285290
    286291            // Convert i/j to image space:
    287             coord->data.F32[0] = (psF32) (j + source->pixels->col0);
    288             coord->data.F32[1] = (psF32) (i + source->pixels->row0);
     292            coord->data.F32[0] = (psF32) (j + 0.5 + source->pixels->col0);
     293            coord->data.F32[1] = (psF32) (i + 0.5 + source->pixels->row0);
    289294
    290295            pcm->modelFlux->data.F32[i][j] = pcm->modelConv->modelFunc (deriv, params, coord);
     
    309314# if (PRE_CONVOLVE)
    310315    // convolve model image and derivative images with pre-convolved kernel
    311     psImageConvolveKernel (pcm->modelConvFlux, pcm->modelFlux, NULL, 0, pcm->psfFFT);
     316
     317// XXX for a test, just copy, rather than convolve
     318# if (TESTCOPY)
     319    psImageCopy (pcm->modelConvFlux, pcm->modelFlux, pcm->modelFlux->type.type);
     320# else
     321    if (pcm->use1Dgauss) {
     322        // do not use the threaded, mask-aware version of this code (psImageSmoothMaskPixelsThread):
     323        // * the model flux is not masked
     324        // * threading takes place above this level
     325        pcm->modelConvFlux = psImageCopy (pcm->modelConvFlux, pcm->modelFlux, pcm->modelFlux->type.type);
     326        psImageSmooth (pcm->modelConvFlux, pcm->sigma, pcm->nsigma);
     327    } else {
     328        psImageConvolveKernel (pcm->modelConvFlux, pcm->modelFlux, NULL, 0, pcm->psfFFT);
     329    }
     330# endif
     331
    312332    for (int n = 0; n < pcm->dmodelsFlux->n; n++) {
    313333        if (pcm->dmodelsFlux->data[n] == NULL) continue;
     
    315335        psImage *dmodel = pcm->dmodelsFlux->data[n];
    316336        psImage *dmodelConv = pcm->dmodelsConvFlux->data[n];
    317         psImageConvolveKernel (dmodelConv, dmodel, NULL, 0, pcm->psfFFT);
     337# if (TESTCOPY)
     338        psImageCopy (dmodelConv, dmodel, dmodel->type.type);
     339# else
     340        if (pcm->use1Dgauss) {
     341            // do not use the threaded, mask-aware version of this code (psImageSmoothMaskPixelsThread):
     342            // * the model flux is not masked
     343            // * threading takes place above this level
     344            dmodelConv = psImageCopy (dmodelConv, dmodel, dmodel->type.type);
     345            psImageSmooth (dmodelConv, pcm->sigma, pcm->nsigma);
     346        } else {
     347            psImageConvolveKernel (dmodelConv, dmodel, NULL, 0, pcm->psfFFT);
     348        }
     349# endif
    318350    }
    319351# else
     
    325357        psImage *dmodel = pcm->dmodelsFlux->data[n];
    326358        psImage *dmodelConv = pcm->dmodelsConvFlux->data[n];
    327         psImageConvolveFFT (dmodelConv, dmodel, NULL, 0, pcm->psf);
     359
     360        if (pcm->use1Dgauss) {
     361            // do not use the threaded, mask-aware version of this code (psImageSmoothMaskPixelsThread):
     362            // * the model flux is not masked
     363            // * threading takes place above this level
     364            dmodelConv = psImageCopy (dmodelConv, dmodel, dmodel->type.type);
     365            psImageSmooth (dmodelConv, pcm->sigma, pcm->nsigma);
     366        } else {
     367            psImageConvolveFFT (dmodelConv, dmodel, NULL, 0, pcm->psf);
     368        }
    328369    }
    329370# endif // PRE-CONVOLVE
  • trunk/psModules/src/objects/pmPCMdata.c

    r31451 r32347  
    4141#include "pmPCMdata.h"
    4242
     43# define USE_DELTA_PSF 0
     44# define USE_1D_GAUSS 1
     45
    4346static void pmPCMdataFree (pmPCMdata *pcm) {
    4447
     
    8891    pcm->constraint = NULL;
    8992    pcm->nDOF = 0;
     93
     94    // full convolution with the PSF is expensive.  if we have to save time, we can do a 1D
     95    // convolution with a Gaussian approximation to the kernel
     96    pcm->use1Dgauss = false;
     97    pcm->nsigma = 3.0;
     98    pcm->sigma = 1.0; // this should be set to something sensible when the psf is known
    9099
    91100    return pcm;
     
    257266    pcm->nDOF = nPix - nParams;
    258267
     268# if (USE_1D_GAUSS)
     269    pmModel *modelPSF = source->modelPSF;
     270    psAssert (modelPSF, "psf model must be defined");
     271   
     272    psEllipseShape shape;
     273    psEllipseAxes axes;
     274
     275    shape.sx  = modelPSF->params->data.F32[PM_PAR_SXX];
     276    shape.sy  = modelPSF->params->data.F32[PM_PAR_SYY];
     277    shape.sxy = modelPSF->params->data.F32[PM_PAR_SXY];
     278    axes = psEllipseShapeToAxes (shape, 20.0);
     279   
     280    float FWHM_MAJOR = 2*modelPSF->modelRadius (modelPSF->params, 0.5*modelPSF->params->data.F32[PM_PAR_I0]);
     281    float FWHM_MINOR = FWHM_MAJOR * (axes.minor / axes.major);
     282
     283    pcm->use1Dgauss = true;
     284    pcm->sigma = 0.5 * (FWHM_MAJOR + FWHM_MINOR) / 2.35;
     285    pcm->nsigma = 2.0;
     286# endif
     287
    259288    return pcm;
    260289}
     
    368397    return true;
    369398}
     399
     400// construct a realization of the source model
     401bool pmPCMCacheModel (pmSource *source, psImageMaskType maskVal, int psfSize) {
     402
     403    PS_ASSERT_PTR_NON_NULL(source, false);
     404
     405    // select appropriate model
     406    pmModel *model = pmSourceGetModel (NULL, source);
     407    if (model == NULL) return false;  // model must be defined
     408
     409    // if we already have a cached image, re-use that memory
     410    source->modelFlux = psImageCopy (source->modelFlux, source->pixels, PS_TYPE_F32);
     411    psImageInit (source->modelFlux, 0.0);
     412
     413    // modelFlux always has unity normalization (I0 = 1.0)
     414    pmModelAdd (source->modelFlux, source->maskObj, model, PM_MODEL_OP_FULL | PM_MODEL_OP_NORM, maskVal);
     415
     416    // convolve the model image with the PSF
     417    if (USE_1D_GAUSS) {
     418        // do not use the threaded, mask-aware version of this code (psImageSmoothMaskPixelsThread):
     419        // * the model flux is not masked
     420        // * threading takes place above this level
     421       
     422        // define the Gauss parameters from the psf
     423        pmModel *modelPSF = source->modelPSF;
     424        psAssert (modelPSF, "psf model must be defined");
     425   
     426        psEllipseShape shape;
     427        psEllipseAxes axes;
     428
     429        shape.sx  = modelPSF->params->data.F32[PM_PAR_SXX];
     430        shape.sy  = modelPSF->params->data.F32[PM_PAR_SYY];
     431        shape.sxy = modelPSF->params->data.F32[PM_PAR_SXY];
     432        axes = psEllipseShapeToAxes (shape, 20.0);
     433   
     434        float FWHM_MAJOR = 2*modelPSF->modelRadius (modelPSF->params, 0.5*modelPSF->params->data.F32[PM_PAR_I0]);
     435        float FWHM_MINOR = FWHM_MAJOR * (axes.minor / axes.major);
     436
     437        float sigma = 0.5 * (FWHM_MAJOR + FWHM_MINOR) / 2.35;
     438        float nsigma = 2.0;
     439
     440        psImageSmooth (source->modelFlux, sigma, nsigma);
     441    } else {
     442        // make sure we save a cached copy of the psf flux
     443        pmSourceCachePSF (source, maskVal);
     444
     445        // convert the cached cached psf model for this source to a psKernel
     446        psKernel *psf = pmPCMkernelFromPSF (source, psfSize);
     447        if (!psf) {
     448            // NOTE: this only happens if the source is too close to an edge
     449            model->flags |= PM_MODEL_STATUS_BADARGS;
     450            return NULL;
     451        }
     452
     453        // XXX not sure if I can place the output on top of the input
     454        psImageConvolveFFT (source->modelFlux, source->modelFlux, NULL, 0, psf);
     455    }
     456    return true;
     457}
     458
  • trunk/psModules/src/objects/pmPCMdata.h

    r31153 r32347  
    3535    int nPar;
    3636    int nDOF;
     37
     38    bool use1Dgauss;
     39    float sigma;
     40    float nsigma;
    3741} pmPCMdata;
    3842
     
    9094bool pmSourceFitPCM (pmPCMdata *pcm, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal, int psfSize);
    9195
     96bool pmPCMCacheModel (pmSource *source, psImageMaskType maskVal, int psfSize);
    9297
    9398/// @}
  • trunk/psModules/src/objects/pmPSF.c

    r31451 r32347  
    281281// convert the parameters used in the fitted source model
    282282// to the parameters used in the 2D PSF model
     283// XXX this function may be invalid for SERSIC, DEV, EXP models (SQRT2 not used?)
    283284bool pmPSF_FitToModel (psF32 *fittedPar, float minMinorAxis)
    284285{
     
    307308// convert the PSF parameters used in the 2D PSF model fit into the
    308309// parameters used in the source model
     310// XXX this function may be invalid for SERSIC, DEV, EXP models (SQRT2 not used?)
    309311psEllipsePol pmPSF_ModelToFit (psF32 *modelPar)
    310312{
     
    329331// convert the parameters used in the fitted source model to the psEllipseAxes representation
    330332// (major,minor,theta)
    331 psEllipseAxes pmPSF_ModelToAxes (psF32 *modelPar, double maxAR)
     333psEllipseAxes pmPSF_ModelToAxes (psF32 *modelPar, double maxAR, pmModelType type)
    332334{
    333335    psEllipseShape shape;
     
    336338    axes.minor = NAN;
    337339    axes.theta = NAN;
    338 //   XXX: must assert non-NULL input parameter
     340    //   XXX: must assert non-NULL input parameter
    339341    PS_ASSERT_PTR_NON_NULL(modelPar, axes);
    340342
    341     shape.sx  = modelPar[PM_PAR_SXX] / M_SQRT2;
    342     shape.sy  = modelPar[PM_PAR_SYY] / M_SQRT2;
    343     shape.sxy = modelPar[PM_PAR_SXY];
     343    bool useReff = true;
     344    useReff |= (type == pmModelClassGetType ("PS_MODEL_SERSIC"));
     345    useReff |= (type == pmModelClassGetType ("PS_MODEL_DEV"));
     346    useReff |= (type == pmModelClassGetType ("PS_MODEL_EXP"));
     347
     348    if (useReff) {
     349        shape.sx  = modelPar[PM_PAR_SXX];
     350        shape.sy  = modelPar[PM_PAR_SYY];
     351        shape.sxy = modelPar[PM_PAR_SXY];
     352    } else {
     353        shape.sx  = modelPar[PM_PAR_SXX] / M_SQRT2;
     354        shape.sy  = modelPar[PM_PAR_SYY] / M_SQRT2;
     355        shape.sxy = modelPar[PM_PAR_SXY];
     356    }
    344357
    345358    if ((shape.sx == 0) || (shape.sy == 0)) {
     
    357370// convert the psEllipseAxes representation (major,minor,theta) to the parameters used in the
    358371// fitted source model
    359 bool pmPSF_AxesToModel (psF32 *modelPar, psEllipseAxes axes)
     372bool pmPSF_AxesToModel (psF32 *modelPar, psEllipseAxes axes, pmModelType type)
    360373{
    361374    PS_ASSERT_PTR_NON_NULL(modelPar, false);
     
    370383    psEllipseShape shape = psEllipseAxesToShape (axes);
    371384
    372     modelPar[PM_PAR_SXX] = shape.sx * M_SQRT2;
    373     modelPar[PM_PAR_SYY] = shape.sy * M_SQRT2;
    374     modelPar[PM_PAR_SXY] = shape.sxy;
    375 
     385    bool useReff = true;
     386    useReff |= pmModelClassGetType ("PS_MODEL_SERSIC");
     387    useReff |= pmModelClassGetType ("PS_MODEL_DEV");
     388    useReff |= pmModelClassGetType ("PS_MODEL_EXP");
     389
     390    if (useReff) {
     391        modelPar[PM_PAR_SXX] = shape.sx;
     392        modelPar[PM_PAR_SYY] = shape.sy;
     393        modelPar[PM_PAR_SXY] = shape.sxy;
     394    } else {
     395        modelPar[PM_PAR_SXX] = shape.sx * M_SQRT2;
     396        modelPar[PM_PAR_SYY] = shape.sy * M_SQRT2;
     397        modelPar[PM_PAR_SXY] = shape.sxy;
     398    }
    376399    return true;
    377400}
     
    438461# if (0)
    439462    psF32 *params = model->params->data.F32; // Model parameters
    440     psEllipseAxes axes = pmPSF_ModelToAxes(params, MAX_AXIS_RATIO); // Ellipse axes
     463    psEllipseAxes axes = pmPSF_ModelToAxes(params, MAX_AXIS_RATIO, model->type); // Ellipse axes
    441464
    442465    // Curiously, the minor axis can be larger than the major axis, so need to check.
  • trunk/psModules/src/objects/pmPSF.h

    r31451 r32347  
    106106pmPSF *pmPSFBuildSimple (char *typeName, float sxx, float syy, float sxy, ...);
    107107
    108 bool pmPSF_AxesToModel (psF32 *modelPar, psEllipseAxes axes);
     108bool pmPSF_AxesToModel (psF32 *modelPar, psEllipseAxes axes, pmModelType type);
    109109bool pmPSF_FitToModel (psF32 *fittedPar, float minMinorAxis);
    110110
    111111psEllipsePol pmPSF_ModelToFit (psF32 *modelPar);
    112 psEllipseAxes pmPSF_ModelToAxes (psF32 *modelPar, double maxAR);
     112psEllipseAxes pmPSF_ModelToAxes (psF32 *modelPar, double maxAR, pmModelType type);
    113113
    114114/// Calculate FWHM value from a PSF
  • trunk/psModules/src/objects/pmPeaks.c

    r31451 r32347  
    137137*****************************************************************************/
    138138static void peakFree(pmPeak *tmp)
    139 {} //
     139{
     140    if (!tmp) return;
     141    psFree (tmp->saddlePoints);
     142    return;
     143}
    140144
    141145pmPeak *pmPeakAlloc(psS32 x,
     
    162166    tmp->type = type;
    163167    tmp->footprint = NULL;
     168    tmp->saddlePoints = NULL;
    164169
    165170    psMemSetDeallocator(tmp, (psFreeFunc) peakFree);
  • trunk/psModules/src/objects/pmPeaks.h

    r31451 r32347  
    7272    pmPeakType type;                    ///< Description of peak.
    7373    pmFootprint *footprint;             ///< reference to containing footprint
     74    psArray *saddlePoints;              ///< set of saddle points between this peak and near neighbors
    7475}
    7576pmPeak;
  • trunk/psModules/src/objects/pmSource.c

    r31670 r32347  
    5858    psFree(tmp->modelEXT);
    5959    psFree(tmp->modelFits);
     60    psFree(tmp->extFitPars);
    6061    psFree(tmp->extpars);
    6162    psFree(tmp->moments);
     
    119120    source->modelEXT = NULL;
    120121    source->modelFits = NULL;
     122    source->extFitPars = NULL;
    121123    source->type = PM_SOURCE_TYPE_UNKNOWN;
    122124    source->mode = PM_SOURCE_MODE_DEFAULT;
     
    196198    // NOTE : because of the const id element, we cannot just assign *source = *in
    197199
     200    source->imageID          = in->imageID;
    198201    source->type             = in->type;
    199202    source->mode             = in->mode;
  • trunk/psModules/src/objects/pmSource.h

    r31670 r32347  
    3636    PM_SOURCE_TMPF_MOMENTS_MEASURED  = 0x0010,
    3737    PM_SOURCE_TMPF_CANDIDATE_PSFSTAR = 0x0020,
     38    PM_SOURCE_TMPF_STACK_KEEP        = 0x0040,
     39    PM_SOURCE_TMPF_STACK_SKIP        = 0x0080,
    3840} pmSourceTmpF;
    3941
     
    7678    pmModel *modelEXT;                  ///< EXT Model fit used for subtraction (parameters and type)
    7779    psArray *modelFits;                 ///< collection of extended source models (best == modelEXT)
     80    psArray *extFitPars;                ///< extra extended fit parameters
    7881    pmSourceType type;                  ///< Best identification of object.
    7982    pmSourceMode mode;                  ///< analysis flags set for object.
  • trunk/psModules/src/objects/pmSourceExtendedPars.c

    r31153 r32347  
    258258    return ( psMemGetDeallocator(ptr) == (psFreeFunc) pmSourceExtendedFluxFree);
    259259}
     260
     261// *** pmSourceExtFitPars describes extra metadata related to an extended fit
     262static void pmSourceExtFitParsFree (pmSourceExtFitPars *pars) {
     263    return;
     264}
     265
     266pmSourceExtFitPars *pmSourceExtFitParsAlloc (void) {
     267
     268    pmSourceExtFitPars *pars = (pmSourceExtFitPars *) psAlloc(sizeof(pmSourceExtFitPars));
     269    psMemSetDeallocator(pars, (psFreeFunc) pmSourceExtFitParsFree);
     270
     271    pars->Mxx = NAN;
     272    pars->Mxy = NAN;
     273    pars->Myy = NAN;
     274
     275    pars->Mrf    = NAN;
     276    pars->Mrh    = NAN;
     277
     278    pars->apMag  = NAN;
     279    pars->krMag  = NAN;
     280    pars->psfMag = NAN;
     281    pars->peakMag = NAN;
     282
     283    return pars;
     284}
  • trunk/psModules/src/objects/pmSourceExtendedPars.h

    r31153 r32347  
    6767} pmSourceExtendedPars;
    6868
     69// additional measurements related to the model fits
     70typedef struct {
     71    float Mxx;
     72    float Mxy;
     73    float Myy;
     74   
     75    float Mrf;
     76    float Mrh;
     77
     78    float apMag;
     79    float krMag;
     80    float psfMag;
     81    float peakMag;
     82} pmSourceExtFitPars;
     83
    6984pmSourceRadialFlux *pmSourceRadialFluxAlloc();
    7085bool psMemCheckSourceRadialFlux(psPtr ptr);
     
    92107bool pmSourceRadialProfileSortPair(psVector *index, psVector *extra);
    93108
    94 
     109pmSourceExtFitPars *pmSourceExtFitParsAlloc (void);
    95110
    96111/// @}
  • trunk/psModules/src/objects/pmSourceFitModel.c

    r31153 r32347  
    176176        break;
    177177      case PM_SOURCE_FIT_EXT:
    178         // EXT model fits all params (except sky)
    179         nParams = params->n - 1;
     178        // EXT model fits all shape params and Io (not Xo, Yo, sky)
     179        nParams = params->n - 3;
    180180        psVectorInit (constraint->paramMask, 0);
     181        constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_XPOS] = 1;
     182        constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_YPOS] = 1;
    181183        constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_SKY] = 1;
    182184        break;
     
    193195        break;
    194196      case PM_SOURCE_FIT_NO_INDEX:
    195         // PSF model only fits Io, index (PAR7) -- only Io for models with < 8 params
     197        // PSF model only fits Io, Sxx, Sxy, Syy
    196198        psVectorInit (constraint->paramMask, 0);
     199        constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_XPOS] = 1;
     200        constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_YPOS] = 1;
    197201        constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_SKY] = 1;
    198202        if (params->n == 7) {
    199             nParams = params->n - 1;
     203            nParams = params->n - 3;
    200204        } else {
    201             nParams = params->n - 2;
     205            nParams = params->n - 4;
    202206            constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_7] = 1;
    203207        }
  • trunk/psModules/src/objects/pmSourceFitPCM.c

    r31153 r32347  
    4848// convolved model image.
    4949
     50# define TIMING 0
     51
    5052bool pmSourceFitPCM (pmPCMdata *pcm, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal, int psfSize) {
    5153   
     54    if (TIMING) { psTimerStart ("pmSourceFitPCM"); }
     55
    5256    psVector *params  = pcm->modelConv->params;
    5357    psVector *dparams  = pcm->modelConv->dparams;
     
    6468    psImage *covar = psImageAlloc (params->n, params->n, PS_TYPE_F32);
    6569
     70    float t1, t2, t3, t4, t5;
     71    if (TIMING) { t1 = psTimerMark ("pmSourceFitPCM"); }
     72
    6673    bool fitStatus = pmPCM_MinimizeChisq (myMin, covar, params, source, pcm);
     74    if (TIMING) { t2 = psTimerMark ("pmSourceFitPCM"); }
     75
    6776    for (int i = 0; i < dparams->n; i++) {
    6877        if ((pcm->constraint->paramMask != NULL) && pcm->constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[i])
     
    7685    }
    7786    psTrace ("psphot", 4, "niter: %d, chisq: %f", myMin->iter, myMin->value);
     87    if (TIMING) { t3 = psTimerMark ("pmSourceFitPCM"); }
    7888
    7989    // renormalize output model image (generated by fitting process)
     
    97107        pmSourceChisqUnsubtracted (source, pcm->modelConv, maskVal);
    98108    }
     109    if (TIMING) { t4 = psTimerMark ("pmSourceFitPCM"); }
    99110
    100111    // set the model success or failure status
     
    114125
    115126    source->mode |= PM_SOURCE_MODE_FITTED; // XXX is this needed?
     127    if (TIMING) { t5 = psTimerMark ("pmSourceFitPCM"); }
     128
     129     if (TIMING) {
     130        fprintf (stderr, "nIter: %2d, npix: %5d, t1: %6.4f, t2: %6.4f, t3: %6.4f, t4: %6.4f, t5: %6.4f\n", myMin->iter, pcm->nPix, t1, t2, t3, t4, t5);
     131     }
    116132
    117133    psFree(myMin);
     
    121137}
    122138
     139// XXX deprecate this function or merge with the empirical model
    123140bool pmSourceModelGuessPCM (pmPCMdata *pcm, pmSource *source, psImageMaskType maskVal, psImageMaskType markVal) {
    124141
  • trunk/psModules/src/objects/pmSourceIO_CMF.c.in

    r31670 r32347  
    5555// followed by a zero-size matrix, followed by the table data
    5656
    57 // # define MODE @CMFMODE@
    5857bool pmSourcesWrite_CMF_@CMFMODE@ (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe)
    5958{
     
    171170        @=PS1_V3@ psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_OUTER",  PS_DATA_F32, "Kron Flux (in 2.5 R1)",                      moments.Kouter);
    172171
     172        // XXX do not keep this long term, just a TEST:
     173        // @=PS1_V3@ psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_PSF",    PS_DATA_F32, "Kron Flux",                                  moments.KronPSF);
     174        // @=PS1_V3@ psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_PSF_SIG",PS_DATA_F32, "Kron Flux",                                  moments.KronPSFErr);
    173175        // Do NOT write these : not consistent with the definition of PS1_V3 in Ohana/src/libautocode/dev/cmf-ps1-v3.d
    174176        // psMetadataAdd (row, PS_LIST_TAIL, "KRON_CORE_FLUX",   PS_DATA_F32, "Kron Flux (in 1.0 R1)",                      moments.KronCore);
    175177        // psMetadataAdd (row, PS_LIST_TAIL, "KRON_CORE_ERROR",  PS_DATA_F32, "Kron Error (in 1.0 R1)",                     moments.KronCoreErr);
     178
    176179        @ALL@     psMetadataAdd (row, PS_LIST_TAIL, "FLAGS",            PS_DATA_U32, "psphot analysis flags",                      source->mode);
    177180        @=PS1_V3@ psMetadataAdd (row, PS_LIST_TAIL, "FLAGS2",           PS_DATA_U32, "psphot analysis flags",                      source->mode2);
     
    222225
    223226// read in a readout from the fits file
    224 psArray *pmSourcesRead_CMF_PS1_V3 (psFits *fits, psMetadata *header)
     227psArray *pmSourcesRead_CMF_@CMFMODE@ (psFits *fits, psMetadata *header)
    225228{
    226229    PS_ASSERT_PTR_NON_NULL(fits, false);
     
    281284        // XXX use these to determine PAR[PM_PAR_I0]?
    282285        @ALL@     source->psfMag    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG");
    283         @ALL@     source->psfMagErr    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG");
     286        @ALL@     source->psfMagErr = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG");
    284287        @ALL@     source->apMag     = psMetadataLookupF32 (&status, row, "AP_MAG");
     288        @=PS1_V3@ source->apMagRaw  = psMetadataLookupF32 (&status, row, "AP_MAG_RAW");
     289
     290        // XXX use these to determine PAR[PM_PAR_I0] if they exist?
     291        @=PS1_V3@ source->psfFlux   = psMetadataLookupF32 (&status, row, "PSF_INST_FLUX");
     292        @=PS1_V3@ source->psfFluxErr= psMetadataLookupF32 (&status, row, "PSF_INST_FLUX_SIG");
    285293
    286294        // XXX this scaling is incorrect: does not include the 2 \pi AREA factor
     
    288296        @ALL@     dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->psfMagErr : NAN;
    289297
    290         pmPSF_AxesToModel (PAR, axes);
     298        pmPSF_AxesToModel (PAR, axes, modelType);
    291299
    292300        @ALL@     float peakMag     = psMetadataLookupF32 (&status, row, "PEAK_FLUX_AS_MAG");
     
    353361}
    354362
    355 bool pmSourcesWrite_CMF_PS1_V3_XSRC (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
     363bool pmSourcesWrite_CMF_@CMFMODE@_XSRC (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
    356364{
    357365    bool status;
     
    541549
    542550// XXX this layout is still the same as PS1_DEV_1
    543 bool pmSourcesWrite_CMF_PS1_V3_XFIT (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname)
     551bool pmSourcesWrite_CMF_@CMFMODE@_XFIT (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname)
    544552{
    545553
     
    590598            assert (model);
    591599
     600            // pmSourceExtFitPars *extPars = source->extFitPars->data[j];
     601            // assert (extPars);
     602
    592603            // skip models which were not actually fitted
    593604            if (model->flags & PM_MODEL_STATUS_BADARGS) continue;
     
    600611            yErr = dPAR[PM_PAR_YPOS];
    601612
    602             axes = pmPSF_ModelToAxes (PAR, 20.0);
     613            axes = pmPSF_ModelToAxes (PAR, 20.0, model->type);
     614
     615            float kronFlux = source->moments ? source->moments->KronFlux : NAN;
     616            float kronMag = isfinite(kronFlux) ? -2.5*log10(kronFlux) : NAN;
    603617
    604618            row = psMetadataAlloc ();
     
    612626            psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_INST_MAG",     0, "EXT fit instrumental magnitude",             model->mag);
    613627            psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_INST_MAG_SIG", 0, "Sigma of PSF instrumental magnitude",        model->magErr);
     628
     629            // psMetadataAddF32 (row, PS_LIST_TAIL, "MOMENTS_XX",       0, "second moment in x",                      extPars->Mxx);
     630            // psMetadataAddF32 (row, PS_LIST_TAIL, "MOMENTS_XY",       0, "second moment in x,y",                    extPars->Mxy);
     631            // psMetadataAddF32 (row, PS_LIST_TAIL, "MOMENTS_YY",       0, "second moment in y",                      extPars->Myy);
     632            // psMetadataAddF32 (row, PS_LIST_TAIL, "MOMENTS_R1",       0, "first radial moment",                     extPars->Mrf);
     633            // psMetadataAddF32 (row, PS_LIST_TAIL, "MOMENTS_RH",       0, "half radial moment",                      extPars->Mrh);
     634
     635            psMetadataAddF32 (row, PS_LIST_TAIL, "PSF_INST_MAG",     0, "PSF fit instrumental magnitude",             source->psfMag);
     636            psMetadataAddF32 (row, PS_LIST_TAIL, "AP_MAG",           0, "PSF-sized aperture magnitude",               source->apMag);
     637            psMetadataAddF32 (row, PS_LIST_TAIL, "KRON_MAG",         0, "Kron Mag",                                   kronMag);
    614638
    615639            psMetadataAddF32 (row, PS_LIST_TAIL, "NPARAMS",          0, "number of model parameters",                 model->params->n);
     
    673697}
    674698
    675 bool pmSourcesWrite_CMF_PS1_V3_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
     699bool pmSourcesWrite_CMF_@CMFMODE@_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
    676700{
    677701    return true;
  • trunk/psModules/src/objects/pmSourceIO_CMF_PS1_DV1.c

    r31451 r32347  
    263263        dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->psfMagErr : NAN;
    264264
    265         pmPSF_AxesToModel (PAR, axes);
     265        pmPSF_AxesToModel (PAR, axes, modelType);
    266266
    267267        float peakMag     = psMetadataLookupF32 (&status, row, "PEAK_FLUX_AS_MAG");
     
    547547            yErr = dPAR[PM_PAR_YPOS];
    548548
    549             axes = pmPSF_ModelToAxes (PAR, 20.0);
     549            axes = pmPSF_ModelToAxes (PAR, 20.0, model->type);
    550550
    551551            row = psMetadataAlloc ();
  • trunk/psModules/src/objects/pmSourceIO_CMF_PS1_DV2.c

    r31451 r32347  
    281281        dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->psfMagErr : NAN;
    282282
    283         pmPSF_AxesToModel (PAR, axes);
     283        pmPSF_AxesToModel (PAR, axes, modelType);
    284284
    285285        float peakMag     = psMetadataLookupF32 (&status, row, "PEAK_FLUX_AS_MAG");
     
    572572            yErr = dPAR[PM_PAR_YPOS];
    573573
    574             axes = pmPSF_ModelToAxes (PAR, 20.0);
     574            axes = pmPSF_ModelToAxes (PAR, 20.0, model->type);
    575575
    576576            row = psMetadataAlloc ();
  • trunk/psModules/src/objects/pmSourceIO_CMF_PS1_SV1.c

    r31451 r32347  
    280280        dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->psfMagErr : NAN;
    281281
    282         pmPSF_AxesToModel (PAR, axes);
     282        pmPSF_AxesToModel (PAR, axes, modelType);
    283283
    284284        float peakMag     = psMetadataLookupF32 (&status, row, "PEAK_FLUX_AS_MAG");
     
    607607            yErr = dPAR[PM_PAR_YPOS];
    608608
    609             axes = pmPSF_ModelToAxes (PAR, 20.0);
     609            axes = pmPSF_ModelToAxes (PAR, 20.0, model->type);
    610610
    611611            row = psMetadataAlloc ();
  • trunk/psModules/src/objects/pmSourceIO_CMP.c

    r31451 r32347  
    135135        lsky = (source->sky < 1.0) ? 0.0 : log10(source->sky);
    136136
    137         axes = pmPSF_ModelToAxes (PAR, 20.0);
     137        axes = pmPSF_ModelToAxes (PAR, 20.0, model->type);
    138138
    139139        float psfMagErr = isfinite(source->psfMagErr) ? source->psfMagErr : 999;
     
    293293                goto skip_source;
    294294
    295             pmPSF_AxesToModel (PAR, axes);
     295            pmPSF_AxesToModel (PAR, axes, modelType);
    296296
    297297            psArrayAdd (sources, 100, source);
  • trunk/psModules/src/objects/pmSourceIO_OBJ.c

    r29004 r32347  
    9191        }
    9292
    93         axes = pmPSF_ModelToAxes (PAR, 20.0);
     93        axes = pmPSF_ModelToAxes (PAR, 20.0, model->type);
    9494
    9595        psLineInit (line);
  • trunk/psModules/src/objects/pmSourceIO_PS1_CAL_0.c

    r31451 r32347  
    113113            yErr = dPAR[PM_PAR_YPOS];
    114114            if (isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX])) {
    115                 axes = pmPSF_ModelToAxes (PAR, 20.0);
     115                axes = pmPSF_ModelToAxes (PAR, 20.0, model->type);
    116116            } else {
    117117                axes.major = NAN;
     
    288288        dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->psfMagErr : NAN;
    289289
    290         pmPSF_AxesToModel (PAR, axes);
     290        pmPSF_AxesToModel (PAR, axes, modelType);
    291291
    292292        float peakMag     = psMetadataLookupF32 (&status, row, "PEAK_FLUX_AS_MAG");
     
    618618            yErr = dPAR[PM_PAR_YPOS];
    619619
    620             axes = pmPSF_ModelToAxes (PAR, 20.0);
     620            axes = pmPSF_ModelToAxes (PAR, 20.0, model->type);
    621621
    622622            // generate RA,DEC
  • trunk/psModules/src/objects/pmSourceIO_PS1_DEV_0.c

    r31451 r32347  
    8989            yErr = dPAR[PM_PAR_YPOS];
    9090
    91             axes = pmPSF_ModelToAxes (PAR, 20.0);
     91            axes = pmPSF_ModelToAxes (PAR, 20.0, model->type);
    9292        } else {
    9393            // XXX: This code seg faults if source->peak is NULL.
     
    214214        source->psfMagErr    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG");
    215215
    216         pmPSF_AxesToModel (PAR, axes);
     216        pmPSF_AxesToModel (PAR, axes, modelType);
    217217
    218218        float peakMag = psMetadataLookupF32 (&status, row, "PEAK_FLUX_AS_MAG");
  • trunk/psModules/src/objects/pmSourceIO_PS1_DEV_1.c

    r31451 r32347  
    9595            yErr = dPAR[PM_PAR_YPOS];
    9696            if (isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX])) {
    97                 axes = pmPSF_ModelToAxes (PAR, 20.0);
     97                axes = pmPSF_ModelToAxes (PAR, 20.0, model->type);
    9898            } else {
    9999                axes.major = NAN;
     
    257257        dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->psfMagErr : NAN;
    258258
    259         pmPSF_AxesToModel (PAR, axes);
     259        pmPSF_AxesToModel (PAR, axes, modelType);
    260260
    261261        float peakMag     = psMetadataLookupF32 (&status, row, "PEAK_FLUX_AS_MAG");
     
    522522            yErr = dPAR[PM_PAR_YPOS];
    523523
    524             axes = pmPSF_ModelToAxes (PAR, 20.0);
     524            axes = pmPSF_ModelToAxes (PAR, 20.0, model->type);
    525525
    526526            row = psMetadataAlloc ();
  • trunk/psModules/src/objects/pmSourceIO_SMPDATA.c

    r31451 r32347  
    9292            lsky = (source->sky < 1.0) ? 0.0 : log10(source->sky);
    9393
    94             axes = pmPSF_ModelToAxes (PAR, 20.0);
     94            axes = pmPSF_ModelToAxes (PAR, 20.0, model->type);
    9595
    9696        } else {
     
    190190        axes.theta       = psMetadataLookupF32 (&status, row, "THETA");
    191191
    192         pmPSF_AxesToModel (PAR, axes);
     192        pmPSF_AxesToModel (PAR, axes, modelType);
    193193
    194194        source->psfMag = psMetadataLookupF32 (&status, row, "MAG_RAW") - ZERO_POINT;
  • trunk/psModules/src/objects/pmSourceIO_SX.c

    r31451 r32347  
    8181        // pmSourceSextractType (source, &type, &flags);
    8282
    83         axes = pmPSF_ModelToAxes (PAR, 20.0);
     83        axes = pmPSF_ModelToAxes (PAR, 20.0, model->type);
    8484
    8585        psLineInit (line);
  • trunk/psModules/src/objects/pmSourceMoments.c

    r31670 r32347  
    9696    // (int) so they can be used in the image index below.
    9797
    98     // do 2 passes : the first pass should use a somewhat smaller radius and no sigma window to
    99     // get an unbiased (but probably noisy) centroid
    100     if (!pmSourceMomentsGetCentroid (source, 0.75*radius, 0.0, minSN, maskVal, source->peak->xf, source->peak->yf)) {
    101         return false;
    102     }
    103     // second pass applies the Gaussian window and uses the centroid from the first pass
    104     if (!pmSourceMomentsGetCentroid (source, radius, sigma, minSN, maskVal, source->moments->Mx, source->moments->My)) {
     98    // XXX // do 2 passes : the first pass should use a somewhat smaller radius and no sigma window to
     99    // XXX // get an unbiased (but probably noisy) centroid
     100    // XXX if (!pmSourceMomentsGetCentroid (source, 0.75*radius, 0.0, minSN, maskVal, source->peak->xf, source->peak->yf)) {
     101    // XXX      return false;
     102    // XXX }
     103    // XXX // second pass applies the Gaussian window and uses the centroid from the first pass
     104    // XXX if (!pmSourceMomentsGetCentroid (source, radius, sigma, minSN, maskVal, source->moments->Mx, source->moments->My)) {
     105    // XXX      return false;
     106    // XXX }
     107
     108    // If we use a large radius for the centroid, it will be biased by any neighbors.  The flux
     109    // of any object drops pretty quickly outside 1-2 sigmas.  (The exception is bright
     110    // saturated stars, for which we need to use a very large radius here)
     111    if (!pmSourceMomentsGetCentroid (source, 1.5*sigma, 0.0, minSN, maskVal, source->peak->xf, source->peak->yf)) {
    105112        return false;
    106113    }
     
    108115    // Now calculate higher-order moments, using the above-calculated first moments to adjust coordinates
    109116    // Xn  = SUM (x - xc)^n * (z - sky)
    110 
    111     float RFW = 0.0;
    112     float RHW = 0.0;
    113 
    114     float RF = 0.0;
    115     float RH = 0.0;
    116     float RS = 0.0;
    117117    float XX = 0.0;
    118118    float XY = 0.0;
     
    143143    float yCM = Yo - 0.5 - source->pixels->row0; // coord of peak in subimage
    144144
     145    // calculate the higher-order moments using Xo,Yo
    145146    for (psS32 row = 0; row < source->pixels->numRows ; row++) {
    146147
     
    194195            Sum += pDiff;
    195196
    196             // Kron Flux uses the 1st radial moment (NOT Gaussian windowed?)
    197197            float r = sqrt(r2);
    198             float rf = r * fDiff;
    199             float rh = sqrt(r) * fDiff;
    200             float rs = fDiff;
    201 
    202             float rfw = r * pDiff;
    203             float rhw = sqrt(r) * pDiff;
    204198
    205199            float x = xDiff * pDiff;
     
    221215            float yyyy = yDiff * yyy / r2;
    222216
    223             RF  += rf;
    224             RH  += rh;
    225             RS  += rs;
    226 
    227             RFW  += rfw;
    228             RHW  += rhw;
    229 
    230217            XX  += xx;
    231218            XY  += xy;
     
    242229            XYYY  += xyyy;
    243230            YYYY  += yyyy;
     231
     232            // Kron Flux uses the 1st radial moment (NOT Gaussian windowed?)
     233            // XXX float r = sqrt(r2);
     234            // XXX float rf = r * fDiff;
     235            // XXX float rh = sqrt(r) * fDiff;
     236            // XXX float rs = fDiff;
     237            // XXX
     238            // XXX float rfw = r * pDiff;
     239            // XXX float rhw = sqrt(r) * pDiff;
     240            // XXX
     241            // XXX RF  += rf;
     242            // XXX RH  += rh;
     243            // XXX RS  += rs;
     244            // XXX
     245            // XXX RFW  += rfw;
     246            // XXX RHW  += rhw;
    244247        }
    245248    }
    246 
    247     source->moments->Mrf = RF/RS;
    248     source->moments->Mrh = RH/RS;
    249 
    250249    source->moments->Mxx = XX/Sum;
    251250    source->moments->Mxy = XY/Sum;
     
    262261    source->moments->Mxyyy = XYYY/Sum;
    263262    source->moments->Myyyy = YYYY/Sum;
     263
     264    // *** now calculate the 1st radial moment (for kron flux) -- symmetrical averaging
     265
     266    float **vPix = source->pixels->data.F32;
     267    float **vWgt = source->variance->data.F32;
     268    psImageMaskType  **vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA;
     269
     270    float RF = 0.0;
     271    float RH = 0.0;
     272    float RS = 0.0;
     273
     274    for (psS32 row = 0; row < source->pixels->numRows ; row++) {
     275
     276        float yDiff = row - yCM;
     277        if (fabs(yDiff) > radius) continue;
     278
     279        // coordinate of mirror pixel
     280        int yFlip = yCM - yDiff;
     281        if (yFlip < 0) continue;
     282        if (yFlip >= source->pixels->numRows) continue;
     283
     284        for (psS32 col = 0; col < source->pixels->numCols ; col++) {
     285            // check mask and value for this pixel
     286            if (vMsk && (vMsk[row][col] & maskVal)) continue;
     287            if (isnan(vPix[row][col])) continue;
     288
     289            float xDiff = col - xCM;
     290            if (fabs(xDiff) > radius) continue;
     291
     292            // coordinate of mirror pixel
     293            int xFlip = xCM - xDiff;
     294            if (xFlip < 0) continue;
     295            if (xFlip >= source->pixels->numCols) continue;
     296
     297            // check mask and value for mirror pixel
     298            if (vMsk && (vMsk[yFlip][xFlip] & maskVal)) continue;
     299            if (isnan(vPix[yFlip][xFlip])) continue;
     300
     301            // radius is just a function of (xDiff, yDiff)
     302            float r2  = PS_SQR(xDiff) + PS_SQR(yDiff);
     303            if (r2 > R2) continue;
     304
     305            float fDiff1 = vPix[row][col] - sky;
     306            float fDiff2 = vPix[yFlip][xFlip] - sky;
     307            float pDiff = (fDiff1 > 0.0) ? sqrt(fabs(fDiff1*fDiff2)) : -sqrt(fabs(fDiff1*fDiff2));
     308
     309            // Kron Flux uses the 1st radial moment (NOT Gaussian windowed?)
     310            float r = sqrt(r2);
     311            float rf = r * pDiff;
     312            float rh = sqrt(r) * pDiff;
     313            float rs = 0.5 * (fDiff1 + fDiff2);
     314
     315            RF  += rf;
     316            RH  += rh;
     317            RS  += rs;
     318        }
     319    }
     320
     321    source->moments->Mrf = RF/RS;
     322    source->moments->Mrh = RH/RS;
    264323
    265324    // if Mrf (first radial moment) is very small, we are getting into low-significance
     
    270329        kronRefRadius = MIN(radius, kronRefRadius);
    271330    }
     331
     332    // *** now calculate the kron flux values using the 1st radial moment
    272333
    273334    float radKinner = 1.0*kronRefRadius;
     
    283344    float SumOuter = 0.0;
    284345
     346    // calculate the Kron flux, and related fluxes (NO symmetrical averaging)
    285347    for (psS32 row = 0; row < source->pixels->numRows ; row++) {
    286 
     348       
    287349        float yDiff = row - yCM;
    288350        if (fabs(yDiff) > radKouter) continue;
     351       
     352        for (psS32 col = 0; col < source->pixels->numCols ; col++) {
     353            // check mask and value for this pixel
     354            if (vMsk && (vMsk[row][col] & maskVal)) continue;
     355            if (isnan(vPix[row][col])) continue;
     356           
     357            float xDiff = col - xCM;
     358            if (fabs(xDiff) > radKouter) continue;
     359           
     360            // radKron is just a function of (xDiff, yDiff)
     361            float r2  = PS_SQR(xDiff) + PS_SQR(yDiff);
     362
     363            float fDiff1 = vPix[row][col] - sky;
     364            float pDiff = fDiff1;
     365            float wDiff = vWgt[row][col];
     366                                   
     367            // skip pixels below specified significance level.  this is allowed, but should be
     368            // avoided -- the over-weights the wings of bright stars compared to those of faint
     369            // stars.
     370            if (PS_SQR(pDiff) < minSN2*wDiff) continue;
     371           
     372            float r  = sqrt(r2);
     373            if (r < radKron) {
     374                Sum += pDiff;
     375                Var += wDiff;
     376                nKronPix ++;
     377                // if (beVerbose) fprintf (stderr, "mome: %d %d  %f  %f  %f\n", col, row, sky, *vPix, Sum);
     378            }
     379
     380            // use sigma (fixed by psf) not a radKron based value
     381            if (r < sigma) {
     382                SumCore += pDiff;
     383                VarCore += wDiff;
     384                nCorePix ++;
     385            }
     386
     387            if ((r > radKinner) && (r < radKron)) {
     388                SumInner += pDiff;
     389                nInner ++;
     390            }
     391            if ((r > radKron)  && (r < radKouter)) {
     392                SumOuter += pDiff;
     393                nOuter ++;
     394            }
     395        }
     396    }
     397    // *** should I rescale these fluxes by pi R^2 / nNpix?
     398    // XXX source->moments->KronCore    = SumCore       * M_PI * PS_SQR(sigma) / nCorePix;
     399    // XXX source->moments->KronCoreErr = sqrt(VarCore) * M_PI * PS_SQR(sigma) / nCorePix;
     400    // XXX source->moments->KronFlux    = Sum       * M_PI * PS_SQR(radKron) / nKronPix;
     401    // XXX source->moments->KronFluxErr = sqrt(Var) * M_PI * PS_SQR(radKron) / nKronPix;
     402    // XXX source->moments->KronFinner = SumInner * M_PI * (PS_SQR(radKron)   - PS_SQR(radKinner)) / nInner;
     403    // XXX source->moments->KronFouter = SumOuter * M_PI * (PS_SQR(radKouter) -   PS_SQR(radKron)) / nOuter;
     404
     405    source->moments->KronCore    = SumCore;
     406    source->moments->KronCoreErr = sqrt(VarCore);
     407    source->moments->KronFlux    = Sum;
     408    source->moments->KronFluxErr = sqrt(Var);
     409    source->moments->KronFinner = SumInner;
     410    source->moments->KronFouter = SumOuter;
     411
     412    // XXX not sure I should save this here...
     413    source->moments->KronFluxPSF    = source->moments->KronFlux;
     414    source->moments->KronFluxPSFErr = source->moments->KronFluxErr;
     415    source->moments->KronRadiusPSF  = source->moments->Mrf;
     416
     417    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",
     418             source->moments->Mrf,   source->moments->KronFlux,
     419             source->moments->Mxx,   source->moments->Mxy,   source->moments->Myy,
     420             source->moments->Mxxx,  source->moments->Mxxy,  source->moments->Mxyy,  source->moments->Myyy,
     421             source->moments->Mxxxx, source->moments->Mxxxy, source->moments->Mxxyy, source->moments->Mxyyy, source->moments->Myyyy);
     422
     423    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",
     424             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);
     425
     426    return(true);
     427}
     428
     429bool pmSourceMomentsGetCentroid(pmSource *source, float radius, float sigma, float minSN, psImageMaskType maskVal, float xGuess, float yGuess) {
     430
     431    // First Pass: calculate the first moments (these are subtracted from the coordinates below)
     432    // Sum = SUM (z - sky)
     433    // X1  = SUM (x - xc)*(z - sky)
     434    // .. etc
     435
     436    float sky = 0.0;
     437
     438    float peakPixel = -PS_MAX_F32;
     439    psS32 numPixels = 0;
     440    float Sum = 0.0;
     441    float Var = 0.0;
     442    float X1 = 0.0;
     443    float Y1 = 0.0;
     444    float R2 = PS_SQR(radius);
     445    float minSN2 = PS_SQR(minSN);
     446    float rsigma2 = 0.5 / PS_SQR(sigma);
     447
     448    float xPeak = xGuess - source->pixels->col0; // coord of peak in subimage
     449    float yPeak = yGuess - source->pixels->row0; // coord of peak in subimage
     450
     451    // we are guaranteed to have a valid pixel and variance at this location (right? right?)
     452    // float weightNorm = source->pixels->data.F32[yPeak][xPeak] / sqrt (source->variance->data.F32[yPeak][xPeak]);
     453    // psAssert (isfinite(source->pixels->data.F32[yPeak][xPeak]), "peak must be on valid pixel");
     454    // psAssert (isfinite(source->variance->data.F32[yPeak][xPeak]), "peak must be on valid pixel");
     455    // psAssert (source->variance->data.F32[yPeak][xPeak] > 0, "peak must be on valid pixel");
     456
     457    // the moments [Sum(x*f) / Sum(f)] are calculated in pixel index values, and should
     458    // not depend on the fractional pixel location of the source.  However, the aperture
     459    // (radius) and the Gaussian window (sigma) depend subtly on the fractional pixel
     460    // position of the expected centroid
     461
     462    for (psS32 row = 0; row < source->pixels->numRows ; row++) {
     463
     464        float yDiff = row + 0.5 - yPeak;
     465        if (fabs(yDiff) > radius) continue;
    289466
    290467        float *vPix = source->pixels->data.F32[row];
    291468        float *vWgt = source->variance->data.F32[row];
    292469
    293         psImageMaskType  *vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[row];
    294         // psImageMaskType  *vMsk = (source->maskView == NULL) ? NULL : source->maskView->data.PS_TYPE_IMAGE_MASK_DATA[row];
     470        psImageMaskType *vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[row];
     471        // psImageMaskType *vMsk = (source->maskView == NULL) ? NULL : source->maskView->data.PS_TYPE_IMAGE_MASK_DATA[row];
    295472
    296473        for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) {
     
    304481            if (isnan(*vPix)) continue;
    305482
    306             float xDiff = col - xCM;
    307             if (fabs(xDiff) > radKouter) continue;
    308 
    309             // radKron is just a function of (xDiff, yDiff)
    310             float r2  = PS_SQR(xDiff) + PS_SQR(yDiff);
    311 
    312             float pDiff = *vPix - sky;
    313             float wDiff = *vWgt;
    314 
    315             // skip pixels below specified significance level.  this is allowed, but should be
    316             // avoided -- the over-weights the wings of bright stars compared to those of faint
    317             // stars.
    318             if (PS_SQR(pDiff) < minSN2*wDiff) continue;
    319 
    320             float r  = sqrt(r2);
    321             if (r < radKron) {
    322                 Sum += pDiff;
    323                 Var += wDiff;
    324                 nKronPix ++;
    325                 // if (beVerbose) fprintf (stderr, "mome: %d %d  %f  %f  %f\n", col, row, sky, *vPix, Sum);
    326             }
    327 
    328             // use sigma (fixed by psf) not a radKron based value
    329             if (r < sigma) {
    330                 SumCore += pDiff;
    331                 VarCore += wDiff;
    332                 nCorePix ++;
    333             }
    334 
    335             if ((r > radKinner) && (r < radKron)) {
    336                 SumInner += pDiff;
    337                 nInner ++;
    338             }
    339             if ((r > radKron)  && (r < radKouter)) {
    340                 SumOuter += pDiff;
    341                 nOuter ++;
    342             }
    343         }
    344     }
    345     // *** should I rescale these fluxes by pi R^2 / nNpix?
    346     source->moments->KronCore    = SumCore       * M_PI * PS_SQR(sigma) / nCorePix;
    347     source->moments->KronCoreErr = sqrt(VarCore) * M_PI * PS_SQR(sigma) / nCorePix;
    348     source->moments->KronFlux    = Sum       * M_PI * PS_SQR(radKron) / nKronPix;
    349     source->moments->KronFluxErr = sqrt(Var) * M_PI * PS_SQR(radKron) / nKronPix;
    350     source->moments->KronFinner = SumInner * M_PI * (PS_SQR(radKron)   - PS_SQR(radKinner)) / nInner;
    351     source->moments->KronFouter = SumOuter * M_PI * (PS_SQR(radKouter) -   PS_SQR(radKron)) / nOuter;
    352 
    353     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",
    354              source->moments->Mrf,   source->moments->KronFlux,
    355              source->moments->Mxx,   source->moments->Mxy,   source->moments->Myy,
    356              source->moments->Mxxx,  source->moments->Mxxy,  source->moments->Mxyy,  source->moments->Myyy,
    357              source->moments->Mxxxx, source->moments->Mxxxy, source->moments->Mxxyy, source->moments->Mxyyy, source->moments->Myyyy);
    358 
    359     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",
    360              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);
    361 
    362     return(true);
    363 }
    364 
    365 bool pmSourceMomentsGetCentroid(pmSource *source, float radius, float sigma, float minSN, psImageMaskType maskVal, float xGuess, float yGuess) {
    366 
    367     // First Pass: calculate the first moments (these are subtracted from the coordinates below)
    368     // Sum = SUM (z - sky)
    369     // X1  = SUM (x - xc)*(z - sky)
    370     // .. etc
    371 
    372     float sky = 0.0;
    373 
    374     float peakPixel = -PS_MAX_F32;
    375     psS32 numPixels = 0;
    376     float Sum = 0.0;
    377     float Var = 0.0;
    378     float X1 = 0.0;
    379     float Y1 = 0.0;
    380     float R2 = PS_SQR(radius);
    381     float minSN2 = PS_SQR(minSN);
    382     float rsigma2 = 0.5 / PS_SQR(sigma);
    383 
    384     float xPeak = xGuess - source->pixels->col0; // coord of peak in subimage
    385     float yPeak = yGuess - source->pixels->row0; // coord of peak in subimage
    386 
    387     // we are guaranteed to have a valid pixel and variance at this location (right? right?)
    388     // float weightNorm = source->pixels->data.F32[yPeak][xPeak] / sqrt (source->variance->data.F32[yPeak][xPeak]);
    389     // psAssert (isfinite(source->pixels->data.F32[yPeak][xPeak]), "peak must be on valid pixel");
    390     // psAssert (isfinite(source->variance->data.F32[yPeak][xPeak]), "peak must be on valid pixel");
    391     // psAssert (source->variance->data.F32[yPeak][xPeak] > 0, "peak must be on valid pixel");
    392 
    393     // the moments [Sum(x*f) / Sum(f)] are calculated in pixel index values, and should
    394     // not depend on the fractional pixel location of the source.  However, the aperture
    395     // (radius) and the Gaussian window (sigma) depend subtly on the fractional pixel
    396     // position of the expected centroid
    397 
    398     for (psS32 row = 0; row < source->pixels->numRows ; row++) {
    399 
    400         float yDiff = row + 0.5 - yPeak;
    401         if (fabs(yDiff) > radius) continue;
    402 
    403         float *vPix = source->pixels->data.F32[row];
    404         float *vWgt = source->variance->data.F32[row];
    405 
    406         psImageMaskType *vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[row];
    407         // psImageMaskType *vMsk = (source->maskView == NULL) ? NULL : source->maskView->data.PS_TYPE_IMAGE_MASK_DATA[row];
    408 
    409         for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) {
    410             if (vMsk) {
    411                 if (*vMsk & maskVal) {
    412                     vMsk++;
    413                     continue;
    414                 }
    415                 vMsk++;
    416             }
    417             if (isnan(*vPix)) continue;
    418 
    419483            float xDiff = col + 0.5 - xPeak;
    420484            if (fabs(xDiff) > radius) continue;
  • trunk/psModules/src/objects/pmSourceOutputs.c

    r31451 r32347  
    107107        }
    108108        if (isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXY]) && isfinite(PAR[PM_PAR_SYY])) {
    109             axes = pmPSF_ModelToAxes (PAR, 20.0);
     109            axes = pmPSF_ModelToAxes (PAR, 20.0, model->type);
    110110            outputs->psfMajor = axes.major;
    111111            outputs->psfMinor = axes.minor;
     
    178178    moments->KronCore    = source->moments ? source->moments->KronCore : NAN;
    179179    moments->KronCoreErr = source->moments ? source->moments->KronCoreErr : NAN;
    180 
    181     return true;
    182 }
     180    moments->KronPSF    = source->moments ? source->moments->KronFluxPSF : NAN;
     181    moments->KronPSFErr = source->moments ? source->moments->KronFluxPSFErr : NAN;
     182
     183    return true;
     184}
     185
     186bool pmSourceLocalAstrometry (psSphere *ptSky, float *posAngle, float *pltScale, pmChip *chip, float xPos, float yPos) {
     187
     188    pmFPA *fpa = chip->parent;
     189
     190    if (!chip->toFPA) goto escape;
     191    if (!fpa->toTPA) goto escape;
     192    if (!fpa->toSky) goto escape;
     193
     194    // generate RA,DEC
     195    psPlane ptCH, ptFP, ptTP_o, ptTP_x, ptTP_y;
     196
     197    // calculate the astrometry for the coordinate of interest
     198    ptCH.x = xPos;
     199    ptCH.y = yPos;
     200    psPlaneTransformApply (&ptFP, chip->toFPA, &ptCH);
     201    psPlaneTransformApply (&ptTP_o, fpa->toTPA, &ptFP);
     202    psDeproject (ptSky, &ptTP_o, fpa->toSky);
     203
     204    // calculate the astrometry for the coordinate + 1pix in X
     205    ptCH.x = xPos + 1.0;
     206    ptCH.y = yPos;
     207    psPlaneTransformApply (&ptFP, chip->toFPA, &ptCH);
     208    psPlaneTransformApply (&ptTP_x, fpa->toTPA, &ptFP);
     209
     210    // calculate the astrometry for the coordinate + 1pix in Y
     211    ptCH.x = xPos;
     212    ptCH.y = yPos + 1.0;
     213    psPlaneTransformApply (&ptFP, chip->toFPA, &ptCH);
     214    psPlaneTransformApply (&ptTP_y, fpa->toTPA, &ptFP);
     215
     216    // the resulting Tangent Plane coordinates are in TP pixels; convert to local Tangent Plane
     217    // degrees
     218
     219    float dTPx_dCHx = fpa->toSky->Xs * (ptTP_x.x - ptTP_o.x);
     220    float dTPy_dCHx = fpa->toSky->Ys * (ptTP_x.y - ptTP_o.y);
     221
     222    float dTPx_dCHy = fpa->toSky->Xs * (ptTP_y.x - ptTP_o.x);
     223    float dTPy_dCHy = fpa->toSky->Ys * (ptTP_y.y - ptTP_o.y);
     224
     225    float pltScale_x = hypot(dTPx_dCHx, dTPy_dCHx);
     226    float pltScale_y = hypot(dTPx_dCHy, dTPy_dCHy);
     227    *pltScale = 0.5*(pltScale_x + pltScale_y);
     228
     229    float posAngle_x = atan2 (+dTPy_dCHx, +dTPx_dCHx);
     230    float posAngle_y = atan2 (-dTPy_dCHy, +dTPx_dCHy);
     231    *posAngle = 0.5*(posAngle_x + posAngle_y);
     232
     233    return true;
     234
     235escape:
     236    // no astrometry calibration, give up
     237    ptSky->r = NAN;
     238    ptSky->d = NAN;
     239    *posAngle = NAN;
     240    *pltScale = NAN;
     241
     242    return false;
     243}
     244
  • trunk/psModules/src/objects/pmSourceOutputs.h

    r31153 r32347  
    5252    float KronCore;
    5353    float KronCoreErr;
     54    float KronPSF;
     55    float KronPSFErr;
    5456} pmSourceOutputsMoments;
    5557
  • trunk/psModules/src/objects/pmSourcePhotometry.c

    r31670 r32347  
    9494{
    9595    PS_ASSERT_PTR_NON_NULL(source, false);
    96     PS_ASSERT_PTR_NON_NULL(psf, false);
     96    // PS_ASSERT_PTR_NON_NULL(psf, false);
    9797
    9898    int status = false;
  • trunk/psModules/src/objects/pmSourcePlotPSFModel.c

    r29004 r32347  
    145145        // force the axis ratio to be < 20.0
    146146        psEllipseAxes axes_mnt = psEllipseMomentsToAxes (moments, 20.0);
    147         psEllipseAxes axes_psf = pmPSF_ModelToAxes (PAR, 20.0);
     147        psEllipseAxes axes_psf = pmPSF_ModelToAxes (PAR, 20.0, model->type);
    148148
    149149        // moments major axis
Note: See TracChangeset for help on using the changeset viewer.