IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

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/objects
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • 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/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
Note: See TracChangeset for help on using the changeset viewer.