Changeset 32347 for trunk/psModules/src/objects/models/pmModel_SERSIC.c
- Timestamp:
- Sep 6, 2011, 1:02:53 PM (15 years ago)
- Location:
- trunk/psModules/src/objects
- Files:
-
- 2 edited
-
. (modified) (1 prop)
-
models/pmModel_SERSIC.c (modified) (7 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psModules/src/objects
- Property svn:ignore
-
old new 5 5 *.la 6 6 *.lo 7 pmSourceIO_CMF_PS1_V1.c 8 pmSourceIO_CMF_PS1_V2.c 9 pmSourceIO_CMF_PS1_V3.c
-
- Property svn:ignore
-
trunk/psModules/src/objects/models/pmModel_SERSIC.c
r31451 r32347 13 13 * PM_PAR_XPOS 2 - X center of object 14 14 * 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)) 17 17 * PM_PAR_SXY 6 - X*Y term of elliptical contour 18 18 * 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) 19 25 20 26 note that a standard sersic model uses exp(-K*(z^(1/2n) - 1). the additional elements (K, … … 85 91 static bool limitsApply = true; // Apply limits? 86 92 93 # include "pmModel_SERSIC.CP.h" 94 87 95 psF32 PM_MODEL_FUNC (psVector *deriv, 88 96 const psVector *params, … … 97 105 psF32 z = PS_SQR(px) + PS_SQR(py) + PAR[PM_PAR_SXY]*X*Y; 98 106 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"); 105 111 106 112 float index = 0.5 / PAR[PM_PAR_7]; 113 float par7 = PAR[PM_PAR_7]; 107 114 float bn = 1.9992*index - 0.3271; 108 115 float Io = exp(bn); 109 116 110 psF32 f2 = bn*pow(z, PAR[PM_PAR_7]);117 psF32 f2 = bn*pow(z,par7); 111 118 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 112 192 psF32 z0 = PAR[PM_PAR_I0]*f1; 113 193 psF32 f0 = PAR[PM_PAR_SKY] + z0; … … 121 201 psF32 *dPAR = deriv->data.F32; 122 202 123 // gradient is infinite for z = 0; saturate at z = 0.01124 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 126 203 dPAR[PM_PAR_SKY] = +1.0; 127 204 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); 129 210 dPAR[PM_PAR_7] *= 3.0; 130 211 … … 269 350 float Io = exp(0.5*bn); 270 351 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 275 352 float Sxx = PS_MAX(0.5, shape.sx); 276 353 float Syy = PS_MAX(0.5, shape.sy); … … 294 371 } 295 372 373 // A sersic model has an integral flux which can be analytically represented 296 374 psF64 PM_MODEL_FLUX (const psVector *params) 297 375 { 298 float z, norm;299 376 psEllipseShape shape; 300 377 301 378 psF32 *PAR = params->data.F32; 302 379 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]; 305 382 shape.sxy = PAR[PM_PAR_SXY]; 306 383 307 // Area is equivalent to 2 pi sigma^2384 // for a non-circular Sersic, the flux of the Rmajor equivalent is scaled by the AspectRatio 308 385 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; 329 397 330 398 return(Flux); … … 346 414 return (1.0); 347 415 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]; 350 418 shape.sxy = PAR[PM_PAR_SXY]; 351 419
Note:
See TracChangeset
for help on using the changeset viewer.
