Newer
Older
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
{
maskt = mask;
nmaskt = nmask;
startt = start;
pixout = pixout0;
for (j=nyout; j--; pixout+=profit->objnaxisn[0])
{
dpixin = dpixin0+*(startt++);
val = 0.0;
for (i=*(nmaskt++); i--;)
val += *(maskt++)**(dpixin++);
*pixout = (PIXTYPE)(factor*val);
}
}
/* Free memory */
free(pixinout);
free(mask);
free(nmask);
free(start);
return RETURN_OK;
}
/****** profit_convolve *******************************************************
PROTO void profit_convolve(profitstruct *profit, float *modpix)
PURPOSE Convolve a model image with the local PSF.
INPUT Pointer to the profit structure,
Pointer to the image raster.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 15/09/2008
***/
void profit_convolve(profitstruct *profit, float *modpix)
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
{
if (!profit->psfdft)
profit_makedft(profit);
fft_conv(modpix, profit->psfdft, profit->modnaxisn);
return;
}
/****** profit_makedft *******************************************************
PROTO void profit_makedft(profitstruct *profit)
PURPOSE Create the Fourier transform of the descrambled PSF component.
INPUT Pointer to the profit structure.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 22/04/2008
***/
void profit_makedft(profitstruct *profit)
{
psfstruct *psf;
float *mask,*maskt, *ppix;
float dx,dy, r,r2,rmin,rmin2,rmax,rmax2,rsig,invrsig2;
int width,height,npix,offset, psfwidth,psfheight,psfnpix,
cpwidth, cpheight,hcpwidth,hcpheight, i,j,x,y;
if (!(psf=profit->psf))
return;
psfwidth = profit->modnaxisn[0];
psfheight = profit->modnaxisn[1];
psfnpix = psfwidth*psfheight;
width = profit->modnaxisn[0];
height = profit->modnaxisn[1];
npix = width*height;
QCALLOC(mask, float, npix);
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
cpwidth = (width>psfwidth)?psfwidth:width;
hcpwidth = cpwidth>>1;
cpwidth = hcpwidth<<1;
offset = width - cpwidth;
cpheight = (height>psfheight)?psfheight:height;
hcpheight = cpheight>>1;
cpheight = hcpheight<<1;
/* Frame and descramble the PSF data */
ppix = profit->psfpix + (psfheight/2)*psfwidth + psfwidth/2;
maskt = mask;
for (j=hcpheight; j--; ppix+=psfwidth)
{
for (i=hcpwidth; i--;)
*(maskt++) = *(ppix++);
ppix -= cpwidth;
maskt += offset;
for (i=hcpwidth; i--;)
*(maskt++) = *(ppix++);
}
ppix = profit->psfpix + ((psfheight/2)-hcpheight)*psfwidth + psfwidth/2;
maskt += width*(height-cpheight);
for (j=hcpheight; j--; ppix+=psfwidth)
{
for (i=hcpwidth; i--;)
*(maskt++) = *(ppix++);
ppix -= cpwidth;
maskt += offset;
for (i=hcpwidth; i--;)
*(maskt++) = *(ppix++);
}
/* Truncate to a disk that has diameter = (box width) */
rmax = cpwidth - 1.0 - hcpwidth;
if (rmax > (r=hcpwidth))
rmax = r;
if (rmax > (r=cpheight-1.0-hcpheight))
rmax = r;
if (rmax > (r=hcpheight))
rmax = r;
if (rmax<1.0)
rmax = 1.0;
rmax2 = rmax*rmax;
rsig = psf->fwhm/profit->pixstep;
invrsig2 = 1/(2*rsig*rsig);
rmin = rmax - (3*rsig); /* 3 sigma annulus (almost no aliasing) */
rmin2 = rmin*rmin;
maskt = mask;
dy = 0.0;
for (y=hcpheight; y--; dy+=1.0)
{
dx = 0.0;
for (x=hcpwidth; x--; dx+=1.0, maskt++)
if ((r2=dx*dx+dy*dy)>rmin2)
*maskt *= (r2>rmax2)?0.0:expf((2*rmin*sqrtf(r2)-r2-rmin2)*invrsig2);
dx = -hcpwidth;
maskt += offset;
for (x=hcpwidth; x--; dx+=1.0, maskt++)
if ((r2=dx*dx+dy*dy)>rmin2)
*maskt *= (r2>rmax2)?0.0:expf((2*rmin*sqrtf(r2)-r2-rmin2)*invrsig2);
}
dy = -hcpheight;
maskt += width*(height-cpheight);
for (y=hcpheight; y--; dy+=1.0)
{
dx = 0.0;
for (x=hcpwidth; x--; dx+=1.0, maskt++)
if ((r2=dx*dx+dy*dy)>rmin2)
*maskt *= (r2>rmax2)?0.0:expf((2*rmin*sqrtf(r2)-r2-rmin2)*invrsig2);
dx = -hcpwidth;
maskt += offset;
for (x=hcpwidth; x--; dx+=1.0, maskt++)
if ((r2=dx*dx+dy*dy)>rmin2)
*maskt *= (r2>rmax2)?0.0:expf((2*rmin*sqrtf(r2)-r2-rmin2)*invrsig2);
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
}
/* Finally move to Fourier space */
profit->psfdft = fft_rtf(mask, profit->modnaxisn);
free(mask);
return;
}
/****** profit_copyobjpix *****************************************************
PROTO int profit_copyobjpix(profitstruct *profit, picstruct *field,
picstruct *wfield)
PURPOSE Copy a piece of the input field image to a profit structure.
INPUT Pointer to the profit structure,
Pointer to the field structure,
Pointer to the field weight structure.
OUTPUT The number of valid pixels copied.
NOTES Global preferences are used.
AUTHOR E. Bertin (IAP)
Emmanuel Bertin
committed
VERSION 01/12/2009
***/
int profit_copyobjpix(profitstruct *profit, picstruct *field,
picstruct *wfield)
{
Emmanuel Bertin
committed
float dx, dy2, dr2, rad2;
PIXTYPE *pixin,*spixin, *wpixin,*swpixin, *pixout,*wpixout,
backnoise2, invgain, satlevel, wthresh, pix,spix, wpix,swpix;
int i,x,y, xmin,xmax,ymin,ymax, w,h,dw, npix, off, gainflag,
Emmanuel Bertin
committed
badflag, sflag, sx,sy,sn,sw, ix,iy;
/* First put the image background to -BIG */
pixout = profit->objpix;
wpixout = profit->objweight;
Emmanuel Bertin
committed
for (i=profit->objnaxisn[0]*profit->objnaxisn[1]; i--;)
{
*(pixout++) = -BIG;
*(wpixout++) = 0.0;
}
/* Don't go further if out of frame!! */
ix = profit->ix;
iy = profit->iy;
if (ix<0 || ix>=field->width || iy<field->ymin || iy>=field->ymax)
return 0;
backnoise2 = field->backsig*field->backsig;
sn = (int)profit->subsamp;
Emmanuel Bertin
committed
sflag = (sn>1);
w = profit->objnaxisn[0]*sn;
h = profit->objnaxisn[1]*sn;
if (sflag)
backnoise2 *= (PIXTYPE)sn;
invgain = (field->gain > 0.0) ? 1.0/field->gain : 0.0;
satlevel = field->satur_level - profit->obj->bkg;
rad2 = h/2.0;
if (rad2 > w/2.0)
rad2 = w/2.0;
rad2 *= rad2;
/* Set the image boundaries */
pixout = profit->objpix;
wpixout = profit->objweight;
ymin = iy-h/2;
ymax = ymin + h;
if (ymin<field->ymin)
{
Emmanuel Bertin
committed
off = (field->ymin-ymin-1)/sn + 1;
pixout += off*profit->objnaxisn[0];
wpixout += off*profit->objnaxisn[0];
ymin += off*sn;
Emmanuel Bertin
committed
ymax -= ((ymax-field->ymax-1)/sn + 1)*sn;
Emmanuel Bertin
committed
dw = 0;
Emmanuel Bertin
committed
off = (xmax-field->width-1)/sn + 1;
dw += off;
xmax -= off*sn;
Emmanuel Bertin
committed
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
off = (-xmin-1)/sn + 1;
pixout += off;
wpixout += off;
dw += off;
xmin += off*sn;
}
/* Make sure the input frame size is a multiple of the subsampling step */
if (sflag)
{
/*
if (((rem=ymax-ymin)%sn))
{
ymin += rem/2;
ymax -= (rem-rem/2);
}
if (((rem=xmax-xmin)%sn))
{
xmin += rem/2;
pixout += rem/2;
wpixout += rem/2;
dw += rem;
xmax -= (rem-rem/2);
}
*/
sw = field->width;
}
/* Copy the right pixels to the destination */
npix = 0;
if (wfield)
{
wthresh = wfield->weight_thresh;
gainflag = prefs.weightgain_flag;
Emmanuel Bertin
committed
if (sflag)
Emmanuel Bertin
committed
/*---- Sub-sampling case */
for (y=ymin; y<ymax; y+=sn, pixout+=dw,wpixout+=dw)
Emmanuel Bertin
committed
for (x=xmin; x<xmax; x+=sn)
Emmanuel Bertin
committed
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
pix = wpix = 0.0;
badflag = 0;
for (sy=0; sy<sn; sy++)
{
dy2 = (y+sy-iy);
dy2 *= dy2;
dx = (x-ix);
spixin = &PIX(field, x, y+sy);
swpixin = &PIX(wfield, x, y+sy);
for (sx=sn; sx--;)
{
dr2 = dy2 + dx*dx;
dx++;
spix = *(spixin++);
swpix = *(swpixin++);
if (dr2<rad2 && spix>-BIG && spix<satlevel && swpix<wthresh)
{
pix += spix;
wpix += swpix;
}
else
badflag=1;
}
}
*(pixout++) = pix;
if (!badflag) /* A single bad pixel ruins is all (saturation, etc.)*/
{
*(wpixout++) = 1.0 / sqrt(wpix+(pix>0.0?
(gainflag? pix*wpix/backnoise2:pix)*invgain : 0.0));
Emmanuel Bertin
committed
npix++;
}
else
*(wpixout++) = 0.0;
Emmanuel Bertin
committed
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
else
for (y=ymin; y<ymax; y++, pixout+=dw,wpixout+=dw)
{
dy2 = y-iy;
dy2 *= dy2;
pixin = &PIX(field, xmin, y);
wpixin = &PIX(wfield, xmin, y);
for (x=xmin; x<xmax; x++)
{
dx = x-ix;
dr2 = dy2 + dx*dx;
pix = *(pixin++);
wpix = *(wpixin++);
if (dr2<rad2 && pix>-BIG && pix<satlevel && wpix<wthresh)
{
*(pixout++) = pix;
*(wpixout++) = 1.0 / sqrt(wpix+(pix>0.0?
(gainflag? pix*wpix/backnoise2:pix)*invgain : 0.0));
npix++;
}
else
*(pixout++) = *(wpixout++) = 0.0;
}
}
Emmanuel Bertin
committed
{
if (sflag)
Emmanuel Bertin
committed
/*---- Sub-sampling case */
for (y=ymin; y<ymax; y+=sn, pixout+=dw, wpixout+=dw)
Emmanuel Bertin
committed
for (x=xmin; x<xmax; x+=sn)
Emmanuel Bertin
committed
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
pix = 0.0;
badflag = 0;
for (sy=0; sy<sn; sy++)
{
dy2 = y+sy-iy;
dy2 *= dy2;
dx = x-ix;
spixin = &PIX(field, x, y+sy);
for (sx=sn; sx--;)
{
dr2 = dy2 + dx*dx;
dx++;
spix = *(spixin++);
if (dr2<rad2 && spix>-BIG && spix<satlevel)
pix += spix;
else
badflag=1;
}
}
*(pixout++) = pix;
if (!badflag) /* A single bad pixel ruins is all (saturation, etc.)*/
{
*(wpixout++) = 1.0 / sqrt(backnoise2 + (pix>0.0?pix*invgain:0.0));
npix++;
}
else
*(wpixout++) = 0.0;
Emmanuel Bertin
committed
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
else
for (y=ymin; y<ymax; y++, pixout+=dw,wpixout+=dw)
{
dy2 = y-iy;
dy2 *= dy2;
pixin = &PIX(field, xmin, y);
for (x=xmin; x<xmax; x++)
{
dx = x-ix;
dr2 = dy2 + dx*dx;
pix = *(pixin++);
if (dr2<rad2 && pix>-BIG && pix<satlevel)
{
*(pixout++) = pix;
*(wpixout++) = 1.0 / sqrt(backnoise2 + (pix>0.0?pix*invgain : 0.0));
npix++;
}
else
*(pixout++) = *(wpixout++) = 0.0;
}
}
}
return npix;
}
/****** profit_spiralindex ****************************************************
PROTO float profit_spiralindex(profitstruct *profit)
PURPOSE Compute the spiral index of a galaxy image (positive for arms
extending counter-clockwise and negative for arms extending CW, 0 for
no spiral pattern).
INPUT Profile-fitting structure.
OUTPUT Vector of residuals.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 12/07/2012
float profit_spiralindex(profitstruct *profit)
{
objstruct *obj;
obj2struct *obj2;
float *dx,*dy, *fdx,*fdy, *gdx,*gdy, *gdxt,*gdyt, *pix,
fwhm, invtwosigma2, hw,hh, ohw,ohh, x,y,xstart, tx,ty,txstart,
gx,gy, r2, spirindex, invsig, val, sep;
PIXTYPE *fpix;
int i,j, npix;
npix = profit->objnaxisn[0]*profit->objnaxisn[1];
obj = profit->obj;
obj2 = profit->obj2;
/* Compute simple derivative vectors at a fraction of the object scale */
Emmanuel Bertin
committed
fwhm = profit->guessradius * 2.0 / 4.0;
if (fwhm < 2.0)
fwhm = 2.0;
sep = 2.0;
invtwosigma2 = -(2.35*2.35/(2.0*fwhm*fwhm));
hw = (float)(profit->objnaxisn[0]/2);
hh = (float)(profit->objnaxisn[1]/2);
ohh = profit->objnaxisn[1] - hh;
txstart = -hw;
ty = -hh;
QMALLOC(dx, float, npix);
pix = dx;
for (j=profit->objnaxisn[1]; j--; ty+=1.0)
{
tx = txstart;
y = ty < -0.5? ty + hh : ty - ohh;
for (i=profit->objnaxisn[0]; i--; tx+=1.0)
{
x = tx < -0.5? tx + hw : tx - ohw;
*(pix++) = exp(invtwosigma2*((x+sep)*(x+sep)+y*y))
- exp(invtwosigma2*((x-sep)*(x-sep)+y*y));
}
}
QMALLOC(dy, float, npix);
pix = dy;
ty = -hh;
for (j=profit->objnaxisn[1]; j--; ty+=1.0)
{
tx = txstart;
y = ty < -0.5? ty + hh : ty - ohh;
for (i=profit->objnaxisn[0]; i--; tx+=1.0)
{
x = tx < -0.5? tx + hw : tx - ohw;
*(pix++) = exp(invtwosigma2*(x*x+(y+sep)*(y+sep)))
- exp(invtwosigma2*(x*x+(y-sep)*(y-sep)));
}
}
QMALLOC(gdx, float, npix);
gdxt = gdx;
fpix = profit->objpix;
invsig = npix/profit->sigma;
for (i=npix; i--; fpix++)
{
val = *fpix > -1e29? *fpix*invsig : 0.0;
*(gdxt++) = (val>0.0? log(1.0+val) : -log(1.0-val));
}
gdy = NULL; /* to avoid gcc -Wall warnings */
QMEMCPY(gdx, gdy, float, npix);
fdx = fft_rtf(dx, profit->objnaxisn);
fft_conv(gdx, fdx, profit->objnaxisn);
fdy = fft_rtf(dy, profit->objnaxisn);
fft_conv(gdy, fdy, profit->objnaxisn);
/* Compute estimator */
Emmanuel Bertin
committed
invtwosigma2 = -1.18*1.18 / (2.0*profit->guessradius*profit->guessradius);
xstart = -hw - obj->mx + (int)(obj->mx+0.49999);
y = -hh - obj->my + (int)(obj->my+0.49999);;
spirindex = 0.0;
gdxt = gdx;
gdyt = gdy;
for (j=profit->objnaxisn[1]; j--; y+=1.0)
{
x = xstart;
for (i=profit->objnaxisn[0]; i--; x+=1.0)
{
gx = *(gdxt++);
gy = *(gdyt++);
if ((r2=x*x+y*y)>0.0)
spirindex += (x*y*(gx*gx-gy*gy)+gx*gy*(y*y-x*x))/r2
* exp(invtwosigma2*r2);
}
}
free(dx);
free(dy);
QFFTWF_FREE(fdx);
QFFTWF_FREE(fdy);
free(gdx);
free(gdy);
return spirindex;
}
/****** profit_moments ****************************************************
PROTO void profit_moments(profitstruct *profit, obj2struct *obj2)
PURPOSE Compute the 2nd order moments from the unconvolved object model.
INPUT Profile-fitting structure,
Pointer to obj2 structure.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 22/04/2011
void profit_moments(profitstruct *profit, obj2struct *obj2)
double dpdmx2[6], cov[4],
*jac,*jact, *pjac,*pjact, *dcovar,*dcovart,
*dmx2,*dmy2,*dmxy,
m0,invm0, mx2,my2,mxy, den,invden,
temp, temp2,invtemp2,invstemp2,
pmx2,theta, flux, dval;
float *covart;
int findex[MODEL_NMAX],
i,j,p, nparam;
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
/* hw = (float)(profit->modnaxisn[0]/2);*/
/* hh = (float)(profit->modnaxisn[1]/2);*/
/* r2max = hw<hh? hw*hw : hh*hh;*/
/* xstart = -hw;*/
/* y = -hh;*/
/* pix = profit->modpix;*/
/* mx2 = my2 = mxy = mx = my = sum = 0.0;*/
/* for (iy=profit->modnaxisn[1]; iy--; y+=1.0)*/
/* {*/
/* x = xstart;*/
/* for (ix=profit->modnaxisn[0]; ix--; x+=1.0)*/
/* if (y*y+x*x <= r2max)*/
/* {*/
/* val = *(pix++);*/
/* sum += val;*/
/* mx += val*x;*/
/* my += val*y;*/
/* mx2 += val*x*x;*/
/* mxy += val*x*y;*/
/* my2 += val*y*y;*/
/* }*/
/* else*/
/* pix++;*/
/* }*/
/* if (sum <= 1.0/BIG)*/
/* sum = 1.0;*/
/* mx /= sum;*/
/* my /= sum;*/
/* obj2->prof_mx2 = mx2 = mx2/sum - mx*mx;*/
/* obj2->prof_my2 = my2 = my2/sum - my*my;*/
/* obj2->prof_mxy = mxy = mxy/sum - mx*my;*/
nparam = profit->nparam;
{
/*-- Set up Jacobian matrices */
QCALLOC(jac, double, nparam*3);
QMALLOC(pjac, double, (nparam<2? 6 : nparam*3));
QMALLOC(dcovar, double, nparam*nparam);
dcovart = dcovar;
covart = profit->covar;
for (i=nparam*nparam; i--;)
*(dcovart++) = (double)(*(covart++));
dmx2 = jac;
dmy2 = jac+nparam;
dmxy = jac+2*nparam;
}
else
m0 = mx2 = my2 = mxy = 0.0;
for (p=0; p<profit->nprof; p++)
prof = profit->prof[p];
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
findex[p] = prof_moments(profit, prof, pjac);
flux = *prof->flux;
m0 += flux;
mx2 += prof->mx2*flux;
my2 += prof->my2*flux;
mxy += prof->mxy*flux;
if (jac)
{
jact = jac;
pjact = pjac;
for (j=nparam*3; j--;)
*(jact++) += flux * *(pjact++);
}
}
invm0 = 1.0 / m0;
obj2->prof_mx2 = (mx2 *= invm0);
obj2->prof_my2 = (my2 *= invm0);
obj2->prof_mxy = (mxy *= invm0);
/* Complete the flux derivative of moments */
if (jac)
{
for (p=0; p<profit->nprof; p++)
{
prof = profit->prof[p];
dmx2[findex[p]] = prof->mx2 - mx2;
dmy2[findex[p]] = prof->my2 - my2;
dmxy[findex[p]] = prof->mxy - mxy;
}
jact = jac;
for (j=nparam*3; j--;)
*(jact++) *= invm0;
/* Handle fully correlated profiles (which cause a singularity...) */
if ((temp2=mx2*my2-mxy*mxy)<0.00694)
mx2 += 0.0833333;
my2 += 0.0833333;
temp2 = mx2*my2-mxy*mxy;
}
/* Use the Jacobians to compute the moment covariance matrix */
if (jac)
propagate_covar(dcovar, jac, obj2->prof_mx2cov, nparam, 3,
pjac); /* We re-use pjac */
if (FLAG(obj2.prof_pol1))
if (mx2+my2 > 1.0/BIG)
{
obj2->prof_pol1 = (mx2 - my2) / (mx2+my2);
obj2->prof_pol2 = 2.0*mxy / (mx2 + my2);
/*------ Compute the Jacobian of polarisation */
invden = 1.0/(mx2+my2);
dpdmx2[0] = 2.0*my2*invden*invden;
dpdmx2[1] = -2.0*mx2*invden*invden;
dpdmx2[2] = 0.0;
dpdmx2[3] = -2.0*mxy*invden*invden;
dpdmx2[4] = -2.0*mxy*invden*invden;
dpdmx2[5] = 2.0*invden;
/*------ Use the Jacobian to compute the polarisation covariance matrix */
propagate_covar(obj2->prof_mx2cov, dpdmx2, cov, 3, 2,
pjac); /* We re-use pjac */
obj2->prof_pol1err = (float)sqrt(cov[0]<0.0? 0.0: cov[0]);
obj2->prof_pol2err = (float)sqrt(cov[3]<0.0? 0.0: cov[3]);
obj2->prof_pol12corr = (dval=cov[0]*cov[3]) > 0.0?
(float)(cov[1]/sqrt(dval)) : 0.0;
}
}
else
obj2->prof_pol1 = obj2->prof_pol2
= obj2->prof_pol1err = obj2->prof_pol2err = obj2->prof_pol12corr = 0.0;
}
if (FLAG(obj2.prof_e1))
{
if (mx2+my2 > 1.0/BIG)
{
den = (temp2>=0.0) ? mx2+my2+2.0*sqrt(temp2) : mx2+my2;
invden = 1.0/den;
obj2->prof_e1 = (float)(invden * (mx2 - my2));
obj2->prof_e2 = (float)(2.0 * invden * mxy);
invstemp2 = (temp2>=0.0) ? 1.0/sqrt(temp2) : 0.0;
dpdmx2[0] = ( den - (1.0+my2*invstemp2)*(mx2-my2))*invden*invden;
dpdmx2[1] = (-den - (1.0+mx2*invstemp2)*(mx2-my2))*invden*invden;
dpdmx2[2] = 2.0*mxy*invstemp2*(mx2-my2)*invden*invden;
dpdmx2[3] = -2.0*mxy*(1.0+my2*invstemp2)*invden*invden;
dpdmx2[4] = -2.0*mxy*(1.0+mx2*invstemp2)*invden*invden;
dpdmx2[5] = (2.0*den+4.0*mxy*mxy*invstemp2)*invden*invden;
/*------ Use the Jacobian to compute the ellipticity covariance matrix */
propagate_covar(obj2->prof_mx2cov, dpdmx2, cov, 3, 2,
pjac); /* We re-use pjac */
obj2->prof_e1err = (float)sqrt(cov[0]<0.0? 0.0: cov[0]);
obj2->prof_e2err = (float)sqrt(cov[3]<0.0? 0.0: cov[3]);
obj2->prof_e12corr = (dval=cov[0]*cov[3]) > 0.0?
(float)(cov[1]/sqrt(dval)) : 0.0;
obj2->prof_e1 = obj2->prof_e2
= obj2->prof_e1err = obj2->prof_e2err = obj2->prof_e12corr = 0.0;
if (FLAG(obj2.prof_cxx))
{
invtemp2 = (temp2>=0.0) ? 1.0/temp2 : 0.0;
obj2->prof_cxx = (float)(my2*invtemp2);
obj2->prof_cyy = (float)(mx2*invtemp2);
obj2->prof_cxy = (float)(-2*mxy*invtemp2);
}
if (FLAG(obj2.prof_a))
{
if ((fabs(temp=mx2-my2)) > 0.0)
theta = atan2(2.0 * mxy,temp) / 2.0;
else
theta = PI/4.0;
temp = sqrt(0.25*temp*temp+mxy*mxy);
pmx2 = 0.5*(mx2+my2);
obj2->prof_a = (float)sqrt(pmx2 + temp);
obj2->prof_b = (float)sqrt(pmx2 - temp);
obj2->prof_theta = theta*180.0/PI;
}
/* Free memory used by Jacobians */
free(jac);
free(pjac);
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
/****** profit_convmoments ****************************************************
PROTO void profit_convmoments(profitstruct *profit, obj2struct *obj2)
PURPOSE Compute the 2nd order moments of the convolved object model.
INPUT Profile-fitting structure,
Pointer to obj2 structure.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 12/04/2011
***/
void profit_convmoments(profitstruct *profit, obj2struct *obj2)
{
double hw,hh, r2max, x,xstart,y, mx2,my2,mxy,mx,my,sum, dval,
temp,temp2,invtemp2, pmx2, theta;
PIXTYPE *pix;
int ix,iy, w,h;
w = profit->modnaxisn[0];
h = profit->modnaxisn[1];
hw = (double)(w/2);
hh = (double)(h/2);
r2max = hw<hh? hw*hw : hh*hh;
xstart = -hw;
y = -hh;
pix = profit->cmodpix;
mx2 = my2 = mxy = mx = my = sum = 0.0;
for (iy=h; iy--; y+=1.0)
{
x = xstart;
for (ix=w; ix--; x+=1.0)
if (y*y+x*x <= r2max)
{
dval = *(pix++);
sum += dval;
mx += dval*x;
my += dval*y;
mx2 += dval*x*x;
mxy += dval*x*y;
my2 += dval*y*y;
}
else
pix++;
}
if (sum <= 1.0/BIG)
sum = 1.0;
mx /= sum;
my /= sum;
obj2->prof_convmx2 = (mx2 = mx2/sum - mx*mx)*profit->pixstep*profit->pixstep;
obj2->prof_convmy2 = (my2 = my2/sum - my*my)*profit->pixstep*profit->pixstep;
obj2->prof_convmxy = (mxy = mxy/sum - mx*my)*profit->pixstep*profit->pixstep;
/* Handle fully correlated profiles (which cause a singularity...) */
if ((temp2=mx2*my2-mxy*mxy)<0.00694)
{
mx2 += 0.0833333;
my2 += 0.0833333;
temp2 = mx2*my2-mxy*mxy;
}
temp2 *= profit->pixstep*profit->pixstep;
if (FLAG(obj2.prof_convcxx))
{
invtemp2 = (temp2>=0.0) ? 1.0/temp2 : 0.0;
obj2->prof_convcxx = (float)(my2*invtemp2);
obj2->prof_convcyy = (float)(mx2*invtemp2);
obj2->prof_convcxy = (float)(-2*mxy*invtemp2);
}
if (1 /*FLAG(obj2.prof_conva)*/)
{
if ((fabs(temp=mx2-my2)) > 0.0)
theta = atan2(2.0 * mxy,temp) / 2.0;
else
theta = PI/4.0;
temp = sqrt(0.25*temp*temp+mxy*mxy);
pmx2 = 0.5*(mx2+my2);
obj2->prof_conva = (float)sqrt(pmx2 + temp)*profit->pixstep;
obj2->prof_convb = (float)sqrt(pmx2 - temp)*profit->pixstep;
obj2->prof_convtheta = theta/DEG;
}
return;
}
/****** profit_surface ****************************************************
PROTO void profit_surface(profitstruct *profit, obj2struct *obj2)
PURPOSE Compute surface brightnesses from the unconvolved object model.
INPUT Pointer to the profile-fitting structure,
Pointer to obj2 structure.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
Emmanuel Bertin
committed
VERSION 06/09/2011
***/
void profit_surface(profitstruct *profit, obj2struct *obj2)
{
profitstruct hdprofit;
double dsum,dhsum,dsumoff, dhval, frac, seff;
float *spix, *spixt,
val,vmax,
scalefac, imsizefac, flux, lost, sum, lostfluxfrac;
int i,p, imax, npix, neff;
/* Allocate "high-definition" raster only to make measurements */
hdprofit.modnaxisn[0] = hdprofit.modnaxisn[1] = PROFIT_HIDEFRES;
npix = hdprofit.nmodpix = hdprofit.modnaxisn[0]*hdprofit.modnaxisn[1];
/* Find best image size factor from fitting results */
imsizefac = 2.0*profit_minradius(profit, PROFIT_REFFFAC)/profit->pixstep
/ (float)profit->modnaxisn[0];
if (imsizefac<0.01)
imsizefac = 0.01;
else if (imsizefac>100.0)
imsizefac = 100.0;
scalefac = (float)hdprofit.modnaxisn[0] / (float)profit->modnaxisn[0]
/ imsizefac;
hdprofit.pixstep = profit->pixstep / scalefac;
Emmanuel Bertin
committed
hdprofit.fluxfac = 1.0/(hdprofit.pixstep*hdprofit.pixstep);
QCALLOC(hdprofit.modpix, float,npix*sizeof(float));
for (p=0; p<profit->nparam; p++)
profit->param[p] = profit->paraminit[p];
lost = sum = 0.0;
for (p=0; p<profit->nprof; p++)
{
sum += (flux = prof_add(&hdprofit, profit->prof[p],0));
lost += flux*profit->prof[p]->lostfluxfrac;
}
lostfluxfrac = sum > 0.0? lost / sum : 0.0;
/*
char filename[256];
Emmanuel Bertin
committed
checkstruct *check;
sprintf(filename, "raster_%02d.fits", the_gal);
check=initcheck(filename, CHECK_OTHER, 0);
check->width = hdprofit.modnaxisn[0];
check->height = hdprofit.modnaxisn[1];
reinitcheck(the_field, check);
memcpy(check->pix,hdprofit.modpix,check->npix*sizeof(float));
reendcheck(the_field, check);
endcheck(check);
*/
if (FLAG(obj2.fluxeff_prof))
{
/*-- Sort model pixel values */
spix = NULL; /* to avoid gcc -Wall warnings */
QMEMCPY(hdprofit.modpix, spix, float, npix);
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
/*-- Build a cumulative distribution */
dsum = 0.0;
spixt = spix;
for (i=npix; i--;)
dsum += (double)*(spixt++);
/*-- Find matching surface brightness */
if (lostfluxfrac > 1.0)
lostfluxfrac = 0.0;
dhsum = 0.5 * dsum / (1.0-lostfluxfrac);
dsum = lostfluxfrac * dsum / (1.0-lostfluxfrac);
neff = 0;
spixt = spix;
for (i=npix; i--;)
if ((dsum += (double)*(spixt++)) >= dhsum)
{
neff = i;
break;
}
dhval = (double)*(spixt-1);
seff = neff;
dsumoff = 0.0;
if (spixt>=spix+2)
if (dhval > 0.0 && (frac = (dsum - dhsum) / dhval) < 1.0)
{
seff += frac;
dsumoff = frac*dhval;
dhval = dsumoff + (1.0 - frac)*(double)*(spixt-2);
}
obj2->fluxeff_prof = dhval;
if (FLAG(obj2.fluxmean_prof))
{
dsum = dsumoff;
for (i=neff; i--;)
dsum += (double)*(spixt++);
obj2->fluxmean_prof = seff > 0.0? dsum / seff : 0.0;
}
free(spix);
}
Emmanuel Bertin
committed
/* Compute model peak */
if (FLAG(obj2.peak_prof))
{
/*-- Find position of maximum pixel in current hi-def raster */
imax = 0;
vmax = -BIG;
spixt = hdprofit.modpix;
for (i=npix; i--;)
if ((val=*(spixt++))>vmax)
{
vmax = val;
imax = i;
}
imax = npix-1 - imax;
obj2->peak_prof = hdprofit.modpix[imax];
}
/* Free hi-def model raster */
free(hdprofit.modpix);
return;
}
/****** profit_addparam *******************************************************
PROTO void profit_addparam(profitstruct *profit, paramenum paramindex,
PURPOSE Add a profile parameter to the list of fitted items.
INPUT Pointer to the profit structure,
Parameter index,
Pointer to the parameter pointer.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
***/
void profit_addparam(profitstruct *profit, paramenum paramindex,
{
/* Check whether the parameter has already be registered */
if (profit->paramlist[paramindex])
/*-- Yes */
*param = profit->paramlist[paramindex];
else
/*-- No */
{
*param = profit->paramlist[paramindex] = &profit->param[profit->nparam];
profit->paramindex[paramindex] = profit->nparam;
profit->paramrevindex[profit->nparam++] = paramindex;
}
return;
}
/****** profit_resetparam ****************************************************
PROTO void profit_resetparam(profitstruct *profit, paramenum paramtype)
PURPOSE Set the initial, lower and upper boundary values of a profile parameter.
INPUT Pointer to the profit structure,
Parameter index.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 03/11/2011
***/
void profit_resetparam(profitstruct *profit, paramenum paramtype)
{
obj2struct *obj2;
float param, parammin,parammax, range;
Emmanuel Bertin
committed
parfitenum fittype;