Commit ece261cd authored by Emmanuel Bertin's avatar Emmanuel Bertin
Browse files

merged with SExFIGI branch

parent 5ae55cd0
......@@ -9,7 +9,7 @@
*
* Contents: main program.
*
* Last modify: 14/07/2006
* Last modify: 20/11/2008
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
......@@ -31,16 +31,22 @@
#include "assoc.h"
#include "back.h"
#include "check.h"
#include "fft.h"
#include "field.h"
#include "filter.h"
#include "growth.h"
#include "interpolate.h"
#include "pattern.h"
#include "psf.h"
#include "profit.h"
#include "som.h"
#include "weight.h"
#include "xml.h"
time_t thetimet, thetimet2;
static int selectext(char *filename);
time_t thetimet, thetimet2;
extern profitstruct *theprofit;
extern char profname[][32];
/******************************** makeit *************************************/
/*
......@@ -53,9 +59,12 @@ void makeit()
picstruct *dfield, *field,*pffield[MAXFLAG], *wfield,*dwfield;
catstruct *imacat;
tabstruct *imatab;
patternstruct *pattern;
static time_t thetime1, thetime2;
struct tm *tm;
int i, nok, ntab, next;
int nflag[MAXFLAG],
i, nok, ntab, next, ntabmax, forcextflag,
nima0,nima1, nweight0,nweight1, npat;
/* Install error logging */
error_installfunc(write_error);
......@@ -84,7 +93,7 @@ void makeit()
readcatparams(prefs.param_name);
useprefs(); /* update things accor. to prefs parameters */
if (prefs.psf_flag)
if (prefs.psf_flag || prefs.prof_flag)
{
NFPRINTF(OUTPUT, "Reading PSF information");
thepsf = psf_load(prefs.psf_name[0]);
......@@ -95,6 +104,51 @@ void makeit()
useprefs();
}
if (prefs.prof_flag)
{
fft_init();
/* Create profiles at full resolution */
NFPRINTF(OUTPUT, "Preparing profile models");
theprofit = profit_init(thepsf);
changecatparamarrays("VECTOR_PROF", &theprofit->nparam, 1);
changecatparamarrays("VECTOR_PROFERR", &theprofit->nparam, 1);
if (prefs.pattern_flag)
{
npat = prefs.prof_disk_patternvectorsize;
if (npat<prefs.prof_disk_patternmodvectorsize)
npat = prefs.prof_disk_patternmodvectorsize;
if (npat<prefs.prof_disk_patternargvectorsize)
npat = prefs.prof_disk_patternargvectorsize;
/*---- Do a copy of the original number of pattern components */
prefs.prof_disk_patternncomp = npat;
pattern = pattern_init(theprofit, prefs.pattern_type, npat);
if (FLAG(obj2.prof_disk_patternvector))
{
npat = pattern->size[2];
changecatparamarrays("DISK_PATTERN_VECTOR", &npat, 1);
}
if (FLAG(obj2.prof_disk_patternmodvector))
{
npat = pattern->ncomp*pattern->nfreq;
changecatparamarrays("DISK_PATTERNMOD_VECTOR", &npat, 1);
}
if (FLAG(obj2.prof_disk_patternargvector))
{
npat = pattern->ncomp*pattern->nfreq;
changecatparamarrays("DISK_PATTERNARG_VECTOR", &npat, 1);
}
pattern_end(pattern);
}
QPRINTF(OUTPUT, "Fitting model: ");
for (i=0; i<theprofit->nprof; i++)
{
if (i)
QPRINTF(OUTPUT, "+");
QPRINTF(OUTPUT, "%s", profname[theprofit->prof[i]->code]);
}
QPRINTF(OUTPUT, "\n");
}
if (prefs.filter_flag)
{
NFPRINTF(OUTPUT, "Reading detection filter");
......@@ -128,21 +182,47 @@ void makeit()
if (prefs.growth_flag)
initgrowth();
/* Compute the number of valid input extensions */
/* Allocate memory for multidimensional catalog parameter arrays */
alloccatparams();
useprefs();
/* Check if a specific extension should be loaded */
if ((nima0=selectext(prefs.image_name[0])) != RETURN_ERROR)
{
forcextflag = 1;
ntabmax = next = 1;
}
else
forcextflag = 0;
if (!(imacat = read_cat(prefs.image_name[0])))
error(EXIT_FAILURE, "*Error*: cannot open ", prefs.image_name[0]);
close_cat(imacat);
imatab = imacat->tab;
next = 0;
for (ntab = 0 ; ntab<imacat->ntab; ntab++, imatab = imatab->nexttab)
if (!forcextflag)
{
/*-- Check for the next valid image extension */
if ((imatab->naxis < 2)
ntabmax = imacat->ntab;
/*-- Compute the number of valid input extensions */
next = 0;
for (ntab = 0 ; ntab<imacat->ntab; ntab++, imatab = imatab->nexttab)
{
/*---- Check for the next valid image extension */
if ((imatab->naxis < 2)
|| !strncmp(imatab->xtension, "BINTABLE", 8)
|| !strncmp(imatab->xtension, "ASCTABLE", 8))
continue;
next++;
continue;
next++;
}
}
/* Do the same for other data (but do not force single extension mode) */
nima1 = selectext(prefs.image_name[1]);
nweight0 = selectext(prefs.wimage_name[0]);
nweight1 = selectext(prefs.wimage_name[1]);
for (i=0; i<prefs.nfimage_name; i++)
nflag[i] = selectext(prefs.fimage_name[i]);
thecat.next = next;
/*-- Init the CHECK-images */
......@@ -152,15 +232,14 @@ void makeit()
NFPRINTF(OUTPUT, "Initializing check-image(s)");
for (i=0; i<prefs.ncheck_type; i++)
if ((c=prefs.check_type[i]) != CHECK_NONE)
{
if (prefs.check[c])
error(EXIT_FAILURE,"*Error*: 2 CHECK_IMAGEs cannot have the same ",
if ((c=prefs.check_type[i]) != CHECK_NONE)
{
if (prefs.check[c])
error(EXIT_FAILURE,"*Error*: 2 CHECK_IMAGEs cannot have the same ",
" CHECK_IMAGE_TYPE");
prefs.check[c] = initcheck(prefs.check_name[i], prefs.check_type[i],
prefs.check[c] = initcheck(prefs.check_name[i], prefs.check_type[i],
next);
free(prefs.check_name[i]);
}
}
}
NFPRINTF(OUTPUT, "Initializing catalog");
......@@ -172,12 +251,12 @@ void makeit()
/* Go through all images */
nok = -1;
for (ntab = 0 ; ntab<imacat->ntab; ntab++, imatab = imatab->nexttab)
for (ntab = 0 ; ntab<ntabmax; ntab++, imatab = imatab->nexttab)
{
/*-- Check for the next valid image extension */
if ((imatab->naxis < 2)
if (!forcextflag && ((imatab->naxis < 2)
|| !strncmp(imatab->xtension, "BINTABLE", 8)
|| !strncmp(imatab->xtension, "ASCTABLE", 8))
|| !strncmp(imatab->xtension, "ASCTABLE", 8)))
continue;
nok++;
......@@ -190,8 +269,10 @@ void makeit()
if (prefs.dimage_flag)
{
/*---- Init the Detection and Measurement-images */
dfield = newfield(prefs.image_name[0], DETECT_FIELD, nok);
field = newfield(prefs.image_name[1], MEASURE_FIELD, nok);
dfield = newfield(prefs.image_name[0], DETECT_FIELD,
nima0<0? nok:nima0);
field = newfield(prefs.image_name[1], MEASURE_FIELD,
nima1<0? nok:nima1);
if ((field->width!=dfield->width) || (field->height!=dfield->height))
error(EXIT_FAILURE, "*Error*: Frames have different sizes","");
/*---- Prepare interpolation */
......@@ -202,7 +283,9 @@ void makeit()
}
else
{
field = newfield(prefs.image_name[0], DETECT_FIELD | MEASURE_FIELD, nok);
field = newfield(prefs.image_name[0], DETECT_FIELD | MEASURE_FIELD,
nima0<0? nok:nima0);
/*-- Prepare interpolation */
if ((prefs.dweight_flag || prefs.weight_flag)
&& prefs.interp_type[0] == INTERP_ALL)
......@@ -222,7 +305,7 @@ void makeit()
{
/*-------- First: the "measurement" weights */
wfield = newweight(prefs.wimage_name[1],field,prefs.weight_type[1],
nok);
nweight1<0? nok:nweight1);
wtype = prefs.weight_type[1];
interpthresh = prefs.weight_thresh[1];
/*-------- Convert the interpolation threshold to variance units */
......@@ -239,13 +322,13 @@ void makeit()
if (prefs.weight_type[0] == WEIGHT_FROMINTERP)
{
dwfield=newweight(prefs.wimage_name[0],wfield,prefs.weight_type[0],
nok);
nweight0<0? nok:nweight0);
weight_to_var(wfield, &interpthresh, 1);
}
else
{
dwfield = newweight(prefs.wimage_name[0], dfield?dfield:field,
prefs.weight_type[0], nok);
prefs.weight_type[0], nweight0<0? nok:nweight0);
weight_to_var(dwfield, &interpthresh, 1);
}
dwfield->weight_thresh = interpthresh;
......@@ -258,7 +341,7 @@ void makeit()
{
/*------ Single-weight-map mode */
wfield = newweight(prefs.wimage_name[0], dfield?dfield:field,
prefs.weight_type[0], nok);
prefs.weight_type[0], nweight0<0? nok:nweight0);
wtype = prefs.weight_type[0];
interpthresh = prefs.weight_thresh[0];
/*------ Convert the interpolation threshold to variance units */
......@@ -273,7 +356,8 @@ void makeit()
/*-- Init the FLAG-images */
for (i=0; i<prefs.nimaflag; i++)
{
pffield[i] = newfield(prefs.fimage_name[i], FLAG_FIELD, nok);
pffield[i] = newfield(prefs.fimage_name[i], FLAG_FIELD,
nflag[i]<0? nok:nflag[i]);
if ((pffield[i]->width!=field->width)
|| (pffield[i]->height!=field->height))
error(EXIT_FAILURE,
......@@ -424,7 +508,13 @@ void makeit()
if (prefs.growth_flag)
endgrowth();
if (prefs.psf_flag)
if (prefs.prof_flag)
{
profit_end(theprofit);
fft_end();
}
if (prefs.psf_flag || prefs.prof_flag)
psf_end(thepsf,thepsfit); /*?*/
if (prefs.dpsf_flag)
......@@ -474,6 +564,34 @@ void initglob()
}
/****** selectext ************************************************************
PROTO int selectext(char *filename)
PURPOSE Return the user-selected extension number [%d] from the file name.
INPUT Filename character string.
OUTPUT Extension number, or RETURN_ERROR if nos extension specified.
NOTES The bracket and its extension number are removed from the filename if
found.
AUTHOR E. Bertin (IAP)
VERSION 08/10/2007
***/
static int selectext(char *filename)
{
char *bracl,*bracr;
int next;
if (filename && (bracl=strrchr(filename, '[')))
{
*bracl = '\0';
if ((bracr=strrchr(bracl+1, ']')))
*bracr = '\0';
next = strtol(bracl+1, NULL, 0);
return next;
}
return RETURN_ERROR;
}
/****** write_error ********************************************************
PROTO int write_error(char *msg1, char *msg2)
PURPOSE Manage files in case of a catched error
......
......@@ -9,7 +9,7 @@
*
* Contents: parameter list for catalog data.
*
* Last modify: 28/09/2006
* Last modify: 18/05/2008
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
......@@ -103,19 +103,6 @@ keystruct objkey[] = {
&outobj2.magerr_best, H_FLOAT, T_FLOAT, "%8.4f", "mag",
"stat.stdev;phot.mag", "mag"},
{"FLUX_PROFILE", "Flux weighted by the FILTERed profile",
&outobj2.flux_prof, H_FLOAT, T_FLOAT, "%12.7g", "count"
"phot.flux", "ct"},
{"FLUXERR_PROFILE", "RMS error for PROFILE flux",
&outobj2.fluxerr_prof, H_FLOAT, T_FLOAT, "%12.7g", "count",
"stat.stdev;phot.flux", "ct"},
{"MAG_PROFILE", "Magnitude weighted by the FILTERed profile",
&outobj2.mag_prof, H_FLOAT, T_FLOAT, "%8.4f", "mag",
"phot.mag", "mag"},
{"MAGERR_PROFILE", "RMS error for MAG_PROFILE",
&outobj2.magerr_prof, H_FLOAT, T_FLOAT, "%8.4f", "mag",
"stat.stdev;phot.mag", "mag"},
{"FLUX_WIN", "Gaussian-weighted flux",
&outobj2.flux_win, H_FLOAT, T_FLOAT, "%12.7g", "count",
"phot.flux", "ct"},
......@@ -413,7 +400,7 @@ keystruct objkey[] = {
"src.impactParam;pos.errorEllipse", "deg-2"},
{"ERRA_IMAGE", "RMS position error along major axis",
&outobj2.poserr_a, H_FLOAT, T_FLOAT, "%8.4f", "pixel"
&outobj2.poserr_a, H_FLOAT, T_FLOAT, "%8.4f", "pixel",
"stat.stdev;stat.max;pos.errorEllipse;instr.det;meta.main", "pix"},
{"ERRB_IMAGE", "RMS position error along minor axis",
&outobj2.poserr_b, H_FLOAT, T_FLOAT, "%8.4f", "pixel",
......@@ -473,7 +460,8 @@ keystruct objkey[] = {
"pos.eq.ra", "deg"},
{"DELTAWIN_B1950", "Windowed declination (B1950)",
&outobj2.winpos_delta1950, H_FLOAT, T_DOUBLE, "%+11.7f", "deg",
"pos.eq.deg", "deg"},
"pos.eq.dec", "deg"},
{"X2WIN_IMAGE", "Windowed variance along x",
&outobj2.win_mx2, H_EXPO, T_DOUBLE, "%15.10e", "pixel**2",
"src.impactParam;instr.det", "pix2"},
......@@ -865,9 +853,9 @@ keystruct objkey[] = {
{"PC", "Principal components",
&outobj2.vector_pc, H_FLOAT, T_FLOAT, "%15.10e", "",
"src.morph.param", "", 1, &prefs.pc_vectorsize},
/*
{"RETINOUT", T_FLOAT, &outobj.retinout, "%13g "},
*/
#include "paramprofit.h"
{""}
};
/*
paramprofit.h
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: SExtractor
*
* Author: E.BERTIN (IAP)
*
* Contents: Model-fitting parameter list for catalog data.
*
* Last modify: 25/09/2008
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
{"VECTOR_MODEL", "Model-fitting coefficients",
&outobj2.prof_vector, H_FLOAT, T_FLOAT, "%12.4g", "",
"stat.fit.param;src.morph.param", "", 1, &prefs.prof_vectorsize},
{"VECTOR_MODELERR", "Model-fitting coefficient uncertainties",
&outobj2.prof_errvector, H_FLOAT, T_FLOAT, "%12.4g", "",
"stat.stdev;stat.fit;src.morph.param", "", 1,
&prefs.prof_errvectorsize},
{"CHI2_MODEL", "Reduced Chi2 of the fit",
&outobj2.prof_chi2, H_FLOAT, T_FLOAT, "%12.7g", "",
"stat.fit.chi2;src.morph", ""},
{"FLAGS_MODEL", "Model-fitting flags",
&outobj2.prof_flag, H_INT, T_BYTE, "%3d", "",
"meta.code;stat.fit;src.morph", ""},
{"NITER_MODEL", "Number of iterations for model-fitting",
&outobj2.prof_niter, H_INT, T_SHORT, "%3d", "",
"meta.number;stat.fit;src.morph", ""},
{"FLUX_MODEL", "Flux from model-fitting",
&outobj2.flux_prof, H_FLOAT, T_FLOAT, "%12.7g", "count",
"phot.count;stat.fit.param", "ct"},
{"FLUXERR_MODEL", "RMS error on model-fitting flux",
&outobj2.fluxerr_prof, H_FLOAT, T_FLOAT, "%12.7g", "count",
"stat.error;phot.count;stat.fit.param", "ct"},
{"MAG_MODEL", "Magnitude from model-fitting",
&outobj2.mag_prof, H_FLOAT, T_FLOAT, "%8.4f", "mag",
"phot.mag;stat.fit.param", "mag"},
{"MAGERR_MODEL", "RMS error on model-fitting magnitude",
&outobj2.mag_prof, H_FLOAT, T_FLOAT, "%8.4f", "mag",
"stat.error;phot.mag;stat.fit.param", "mag"},
{"XMODEL_IMAGE", "X coordinate from model-fitting",
&outobj2.x_prof, H_FLOAT, T_FLOAT, "%10.3f", "pixel",
"pos.cartesian.x;stat.fit.param;instr.det;meta.main", "pix"},
{"YMODEL_IMAGE", "Y coordinate from model-fitting",
&outobj2.y_prof, H_FLOAT, T_FLOAT, "%10.3f", "pixel",
"pos.cartesian.y;stat.fit.param;instr.det;meta.main", "pix"},
{"XMODEL_WORLD", "Fitted position along world x axis",
&outobj2.xw_prof, H_FLOAT, T_DOUBLE, "%15.10e", "deg",
"pos.eq.ra;stat.fit.param", "deg"},
{"YMODEL_WORLD", "Fitted position along world y axis",
&outobj2.yw_prof, H_FLOAT, T_DOUBLE, "%15.10e", "deg",
"pos.eq.dec;stat.fit.param", "deg"},
{"ALPHAMODEL_SKY", "Fitted position along right ascension (native)",
&outobj2.alphas_prof, H_FLOAT, T_DOUBLE, "%11.7f", "deg",
"pos.eq.ra;stat.fit.param", "deg"},
{"DELTAMODEL_SKY", "Fitted position along declination (native)",
&outobj2.deltas_prof, H_FLOAT, T_DOUBLE, "%+11.7f", "deg",
"pos.eq.dec;stat.fit.param", "deg"},
{"ALPHAMODEL_J2000", "Fitted position along right ascension (J2000)",
&outobj2.alpha2000_prof, H_FLOAT, T_DOUBLE, "%11.7f", "deg",
"pos.eq.ra;stat.fit.param", "deg"},
{"DELTAMODEL_J2000", "Fitted position along declination (J2000)",
&outobj2.delta2000_prof, H_FLOAT, T_DOUBLE, "%+11.7f", "deg",
"pos.eq.dec;stat.fit.param", "deg"},
{"ALPHAMODEL_B1950", "Fitted position along right ascension (B1950)",
&outobj2.alpha1950_prof, H_FLOAT, T_DOUBLE, "%11.7f", "deg",
"pos.eq.ra;stat.fit.param", "deg"},
{"DELTAMODEL_B1950", "Fitted position along declination (B1950)",
&outobj2.delta1950_prof, H_FLOAT, T_DOUBLE, "%+11.7f", "deg",
"pos.eq.dec;stat.fit.param", "deg"},
{"ERRX2MODEL_IMAGE", "Variance of fitted position along x",
&outobj2.poserrmx2_prof, H_EXPO, T_DOUBLE, "%15.10e", "pixel**2",
"stat.variance;pos.errorEllipse;stat.fit.param;instr.det", "pix2"},
{"ERRY2MODEL_IMAGE", "Variance of fitted position along y",
&outobj2.poserrmy2_prof, H_EXPO, T_DOUBLE, "%15.10e", "pixel**2",
"stat.variance;pos.errorEllipse;stat.fit.param;instr.det", "pix2"},
{"ERRXYMODEL_IMAGE", "Covariance of fitted position between x and y",
&outobj2.poserrmxy_prof, H_EXPO, T_DOUBLE, "%15.10e", "pixel**2",
"stat.covariance;pos.errorEllipse;stat.fit.param;instr.det", "pix2"},
{"ERRX2MODEL_WORLD", "Variance of fitted position along X-WORLD (alpha)",
&outobj2.poserrmx2w_prof, H_EXPO, T_DOUBLE, "%15.10e", "deg**2",
"stat.variance;pos.errorEllipse;stat.fit.param", "deg2"},
{"ERRY2MODEL_WORLD", "Variance of fitted position along Y-WORLD (delta)",
&outobj2.poserrmy2w_prof, H_EXPO, T_DOUBLE, "%15.10e", "deg**2",
"stat.variance;pos.errorEllipse;stat.fit.param", "deg2"},
{"ERRXYMODEL_WORLD", "Covariance of fitted position X-WORLD/Y-WORLD",
&outobj2.poserrmxyw_prof, H_EXPO, T_DOUBLE, "%15.10e", "deg**2",
"stat.covariance;pos.errorEllipse;stat.fit.param", "deg2"},
{"ERRCXXMODEL_IMAGE", "Cxx error ellipse parameter of fitted position",
&outobj2.poserrcxx_prof, H_EXPO, T_FLOAT, "%12.7g", "pixel**(-2)",
"src.impactParam;pos.errorEllipse;stat.fit.param;instr.det", "pix-2"},
{"ERRCYYMODEL_IMAGE", "Cyy error ellipse parameter of fitted position",
&outobj2.poserrcyy_prof, H_EXPO, T_FLOAT, "%12.7g", "pixel**(-2)",
"src.impactParam;pos.errorEllipse;stat.fit.param;instr.det", "pix-2"},
{"ERRCXYMODEL_IMAGE", "Cxy error ellipse parameter of fitted position",
&outobj2.poserrcxy_prof, H_EXPO, T_FLOAT, "%12.7g", "pixel**(-2)",
"src.impactParam;pos.errorEllipse;stat.fit.param;instr.det", "pix-2"},
{"ERRCXXMODEL_WORLD", "Cxx fitted error ellipse parameter (WORLD units)",
&outobj2.poserrcxxw_prof, H_EXPO, T_FLOAT, "%12.7g", "deg**(-2)",
"src.impactParam;pos.errorEllipse;stat.fit.param", "deg-2"},
{"ERRCYYMODEL_WORLD", "Cyy fitted error ellipse parameter (WORLD units)",
&outobj2.poserrcyyw_prof, H_EXPO, T_FLOAT, "%12.7g", "deg**(-2)",
"src.impactParam;pos.errorEllipse;stat.fit.param", "deg-2"},
{"ERRCXYMODEL_WORLD", "Cxy fitted error ellipse parameter (WORLD units)",
&outobj2.poserrcxyw_prof, H_EXPO, T_FLOAT, "%12.7g", "deg**(-2)",
"src.impactParam;pos.errorEllipsestat.fit.param", "deg-2"},
{"ERRAMODEL_IMAGE", "RMS error of fitted position along major axis",
&outobj2.poserra_prof, H_FLOAT, T_FLOAT, "%8.4f", "pixel",
"stat.stdev;stat.max;pos.errorEllipse;stat.fit.param;instr.det", "pix"},
{"ERRBMODEL_IMAGE", "RMS error of fitted position along minor axis",
&outobj2.poserrb_prof, H_FLOAT, T_FLOAT, "%8.4f", "pixel",
"stat.stdev;stat.min;pos.errorEllipse;stat.fit.param;instr.det", "pix"},
{"ERRTHETAMODEL_IMAGE", "Error ellipse pos.angle of fitted position (CCW/x)",
&outobj2.poserrtheta_prof, H_FLOAT, T_FLOAT, "%5.1f", "deg",
"pos.posAng;pos.errorEllipse;stat.fit.param;instr.det", "deg"},
{"ERRAMODEL_WORLD", "World RMS error of fitted position along major axis",
&outobj2.poserraw_prof, H_FLOAT, T_FLOAT, "%12.7g", "deg",
"stat.stdev;stat.max;pos.errorEllipse;stat.fit.param", "deg"},
{"ERRBMODEL_WORLD", "World RMS error of fitted position along minor axis",
&outobj2.poserrbw_prof, H_FLOAT, T_FLOAT, "%12.7g", "deg",
"stat.stdev;stat.min;pos.errorEllipse;stat.fit.param", "deg"},
{"ERRTHETAMODEL_WORLD", "Error ellipse pos.angle of fitted position (CCW/world-x)",
&outobj2.poserrthetaw_prof, H_FLOAT, T_FLOAT, "%5.1f", "deg",
"pos.posAng;pos.errorEllipse;stat.fit.param", "deg"},
{"ERRTHETAMODEL_SKY", "Native fitted error ellipse pos. angle (east of north)",
&outobj2.poserrthetas_prof, H_FLOAT, T_FLOAT, "%5.1f", "deg",
"pos.posAng;pos.errorEllipse;stat.fit.param", "deg"},
{"ERRTHETAMODEL_J2000", "J2000 fitted error ellipse pos. angle (east of north)",
&outobj2.poserrtheta2000_prof, H_FLOAT, T_FLOAT, "%5.1f", "deg",
"pos.posAng;pos.errorEllipse;stat.fit.param", "deg"},
{"ERRTHETAMODEL_B1950", "B1950 fitted error ellipse pos. angle (east of north)",
&outobj2.poserrtheta1950_prof, H_FLOAT, T_FLOAT, "%5.1f", "deg",
"pos.posAng;pos.errorEllipse;stat.fit.param", "deg"},
{"X2MODEL_IMAGE", "Variance along x from model-fitting",
&outobj2.prof_mx2, H_EXPO, T_DOUBLE, "%15.10e", "pixel**2",
"src.impactParam;stat.fit;instr.det", "pix2"},
{"Y2MODEL_IMAGE", "Variance along y from model-fitting",
&outobj2.prof_my2, H_EXPO, T_DOUBLE, "%15.10e", "pixel**2",
"src.impactParam;stat.fit;instr.det", "pix2"},
{"XYMODEL_IMAGE", "Covariance between x and y from model-fitting",
&outobj2.prof_mxy, H_EXPO, T_DOUBLE, "%15.10e", "pixel**2",
"src.impactParam;stat.fit;instr.det", "pix2"},
{"E1MODEL_IMAGE", "Ellipticity component from model-fitting",
&outobj2.prof_e1, H_FLOAT, T_FLOAT, "%10.6f", "",
"src.ellipticity;stat.fit;instr.det", ""},
{"E2MODEL_IMAGE", "Ellipticity component from model-fitting",
&outobj2.prof_e2, H_FLOAT, T_FLOAT, "%10.6f", "",
"src.ellipticity;stat.fit;instr.det", ""},
{"EPS1MODEL_IMAGE", "Ellipticity component (quadratic) from model-fitting",
&outobj2.prof_eps1, H_FLOAT, T_FLOAT, "%10.6f", "",
"src.ellipticity;stat.fit;instr.det", ""},
{"EPS2MODEL_IMAGE", "Ellipticity component (quadratic) from model-fitting",
&outobj2.prof_eps2, H_FLOAT, T_FLOAT, "%10.6f", "",
"src.ellipticity;stat.fit;instr.det", ""},
{"FLUX_BACKOFFSET", "Background offset from fitting",
&outobj2.prof_offset_flux, H_FLOAT, T_FLOAT, "%12.7g", "count",
"instr.skyLevel;arith.diff;stat.fit.param", "ct"},
{"FLUXERR_BACKOFFSET", "RMS error on fitted background offset",
&outobj2.prof_offset_fluxerr, H_FLOAT, T_FLOAT, "%12.7g", "count",
"stat.error;instr.skyLevel;arith.diff;stat.fit.param", "ct"},
{"FLUX_SPHEROID", "Spheroid total flux from fitting",
&outobj2.prof_spheroid_flux, H_FLOAT, T_FLOAT, "%12.7g", "count",
"phot.count;stat.fit.param", "ct"},
{"FLUXERR_SPHEROID", "RMS error on fitted spheroid total flux",
&outobj2.prof_spheroid_fluxerr, H_FLOAT, T_FLOAT, "%12.7g", "count",
"stat.error;phot.count;stat.fit.param", "ct"},
{"MAG_SPHEROID", "Spheroid total magnitude from fitting",
&outobj2.prof_spheroid_mag, H_FLOAT, T_FLOAT, "%8.4f", "mag",
"phot.mag;stat.fit.param", "mag"},
{"MAGERR_SPHEROID", "RMS error on fitted spheroid total magnitude",
&outobj2.prof_spheroid_magerr, H_FLOAT, T_FLOAT, "%8.4f", "mag",
"stat.error;phot.mag;stat.fit.param", "mag"},
{"SPHEROID_REFF_IMAGE", "Spheroid effective radius from fitting",
&outobj2.prof_spheroid_reff, H_FLOAT, T_FLOAT, "%10.4f", "pixel",
"src.morph.scLength;stat.fit.param;instr.det", "pix"},
{"SPHEROID_REFFERR_IMAGE", "RMS error on fitted spheroid effective radius",
&outobj2.prof_spheroid_refferr, H_FLOAT, T_FLOAT, "%10.4f", "pixel",
"stat.error;src.morph.scLength;stat.fit.param;instr.det", "pix"},
{"SPHEROID_REFF_WORLD", "Spheroid effective radius from fitting",
&outobj2.prof_spheroid_reffw, H_FLOAT, T_FLOAT, "%12.7g", "deg",
"src.morph.scLength;stat.fit.param", "deg"},
{"SPHEROID_REFFERR_WORLD", "RMS error on fitted spheroid effective radius",
&outobj2.prof_spheroid_refferrw, H_FLOAT, T_FLOAT, "%12.7g", "deg",
"stat.error;src.morph.scLength;stat.fit.param", "deg"},
{"SPHEROID_ASPECT_IMAGE", "Spheroid aspect ratio from fitting",
&outobj2.prof_spheroid_aspect, H_FLOAT, T_FLOAT, "%6.4f", "",
"phys.size.axisRatio;src.morph;stat.fit.param;instr.det", ""},
{"SPHEROID_ASPECTERR_IMAGE", "RMS error on fitted spheroid aspect ratio",
&outobj2.prof_spheroid_aspecterr, H_FLOAT, T_FLOAT, "%6.4f", "",
"stat.error;phys.size.axisRatio;src.morph;stat.fit.param;instr.det", ""},
{"SPHEROID_ASPECT_WORLD", "Spheroid aspect ratio from fitting",
&outobj2.prof_spheroid_aspectw, H_FLOAT, T_FLOAT, "%6.4f", "",
"phys.size.axisRatio;src.morph;stat.fit.param", ""},
{"SPHEROID_ASPECTERR_WORLD", "RMS error on fitted spheroid aspect ratio",
&outobj2.prof_spheroid_aspecterrw, H_FLOAT, T_FLOAT, "%6.4f", "",
"stat.error;phys.size.axisRatio;src.morph;stat.fit.param", ""},
{"SPHEROID_THETA_IMAGE", "Spheroid position angle (CCW/x) from fitting",
&outobj2.prof_spheroid_theta, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"pos.posAng;src.morph;stat.fit.param;instr.det", "deg"},
{"SPHEROID_THETAERR_IMAGE", "RMS error on spheroid position angle",
&outobj2.prof_spheroid_thetaerr, H_FLOAT, T_FLOAT, "%7.3f", "deg",
"stat.error;pos.posAng;src.morph;stat.fit.param;instr.det", "deg"},
{"SPHEROID_THETA_WORLD", "Spheroid position angle (CCW/world-x)",
&outobj2.prof_spheroid_thetaw, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"pos.posAng;src.morph;stat.fit.param", "deg"},
{"SPHEROID_THETAERR_WORLD", "RMS error on spheroid position angle",
&outobj2.prof_spheroid_thetaerrw, H_FLOAT, T_FLOAT, "%7.3f", "deg",
"stat.error;pos.posAng;src.morph;stat.fit.param", "deg"},
{"SPHEROID_THETA_SKY", "Spheroid position angle (east of north, native)",
&outobj2.prof_spheroid_thetas, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"pos.posAng;src.morph;stat.fit.param", "deg"},
{"SPHEROID_THETA_J2000", "Spheroid position angle (east of north, J2000)",
&outobj2.prof_spheroid_theta2000, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"pos.posAng;src.morph;stat.fit.param", "deg"},
{"SPHEROID_THETA_B1950", "Spheroid position angle (east of north, B1950)",
&outobj2.prof_spheroid_theta1950, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"pos.posAng;src.morph;stat.fit.param", "deg"},
{"SPHEROID_SERSICN", "Spheroid Sersic index from fitting",
&outobj2.prof_spheroid_sersicn, H_FLOAT, T_FLOAT, "%6.3f", "",
"src.morph;stat.fit.param", ""},
{"SPHEROID_SERSICNERR", "RMS error on fitted spheroid Sersic index",
&outobj2.prof_spheroid_sersicnerr, H_FLOAT, T_FLOAT, "%6.3f", "",
"stat.error;src.morph;stat.fit.param", ""},
{"FLUX_DISK", "Disk total flux from fitting",
&outobj2.prof_disk_flux, H_FLOAT, T_FLOAT, "%12.7g", "count",
"phot.count;stat.fit.param", "ct"},
{"FLUXERR_DISK", "RMS error on fitted disk total flux",
&outobj2.prof_disk_fluxerr, H_FLOAT, T_FLOAT, "%12.7g", "count",
"stat.error;phot.count;stat.fit.param", "ct"},
{"MAG_DISK", "Disk total magnitude from fitting",
&outobj2.prof_disk_mag, H_FLOAT, T_FLOAT, "%8.4f", "mag",
"phot.mag;stat.fit.param", "mag"},
{"MAGERR_DISK", "RMS error on fitted disk total magnitude",
&outobj2.prof_disk_magerr, H_FLOAT, T_FLOAT, "%8.4f", "mag",
"stat.error;phot.mag;stat.fit.param", "mag"},
{"DISK_SCALE_IMAGE", "Disk scalelength from fitting",
&outobj2.prof_disk_scale, H_FLOAT, T_FLOAT, "%10.4f", "pixel",
"src.morph.scLength;stat.fit.param;instr.det", "pix"},
{"DISK_SCALEERR_IMAGE", "RMS error on fitted disk scalelength",
&outobj2.prof_disk_scaleerr, H_FLOAT, T_FLOAT, "%10.4f", "pixel",
"stat.error;src.morph.scLength;stat.fit.param;instr.det", "pix"},
{"DISK_SCALE_WORLD", "Disk scalelength from fitting (world coords)",
&outobj2.prof_disk_scalew, H_FLOAT, T_FLOAT, "%12.7g", "deg",
"src.morph.scLength;stat.fit.param", "deg"},
{"DISK_SCALEERR_WORLD", "RMS error on fitted disk scalelength (world coords)",
&outobj2.prof_disk_scaleerrw, H_FLOAT, T_FLOAT, "%12.7g", "deg",
"stat.error;src.morph.scLength;stat.fit.param", "deg"},
{"DISK_ASPECT_IMAGE", "Disk aspect ratio from fitting",
&outobj2.prof_disk_aspect, H_FLOAT, T_FLOAT, "%6.4f", "",
"phys.size.axisRatio;src.morph;stat.fit.param;instr.det", ""},
{"DISK_ASPECTERR_IMAGE", "RMS error on fitted disk aspect ratio",
&outobj2.prof_disk_aspecterr, H_FLOAT, T_FLOAT, "%6.4f", "",
"stat.error;phys.size.axisRatio;src.morph;stat.fit.param;instr.det", ""},
{"DISK_ASPECT_WORLD", "Disk aspect ratio from fitting",
&outobj2.prof_disk_aspectw, H_FLOAT, T_FLOAT, "%6.4f", "",
"phys.size.axisRatio;src.morph;stat.fit.param", ""},
{"DISK_ASPECTERR_WORLD", "RMS error on disk aspect ratio",
&outobj2.prof_disk_aspecterrw, H_FLOAT, T_FLOAT, "%6.4f", "",
"stat.error;phys.size.axisRatio;src.morph;stat.fit.param", ""},
{"DISK_INCLINATION", "Disk inclination from fitting",
&outobj2.prof_disk_inclination, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"src.morph;stat.fit.param;instr.det", "deg"},
{"DISK_INCLINATIONERR", "RMS error on disk inclination from fitting",
&outobj2.prof_disk_inclinationerr, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"stat.error;src.morph;stat.fit.param;instr.det", "deg"},
{"DISK_THETA_IMAGE", "Disk position angle (CCW/x) from fitting",
&outobj2.prof_disk_theta, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"pos.posAng;src.morph;stat.fit.param;instr.det", "deg"},
{"DISK_THETAERR_IMAGE", "RMS error on fitted disk position angle",
&outobj2.prof_disk_thetaerr, H_FLOAT, T_FLOAT, "%7.3f", "deg",
"stat.error;pos.posAng;src.morph;stat.fit.param;instr.det", "deg"},
{"DISK_THETA_WORLD", "Disk position angle (CCW/world-x)",
&outobj2.prof_disk_thetaw, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"pos.posAng;src.morph;stat.fit.param", "deg"},
{"DISK_THETAERR_WORLD", "RMS error on disk position angle",
&outobj2.prof_disk_thetaerrw, H_FLOAT, T_FLOAT, "%7.3f", "deg",
"stat.error;pos.posAng;src.morph;stat.fit.param", "deg"},
{"DISK_THETA_SKY", "Disk position angle (east of north, native)",
&outobj2.prof_disk_thetas, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"pos.posAng;src.morph;stat.fit.param", "deg"},
{"DISK_THETA_J2000", "Disk position angle (east of north, J2000)",
&outobj2.prof_disk_theta2000, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"pos.posAng;src.morph;stat.fit.param", "deg"},
{"DISK_THETA_B1950", "Disk position angle (east of north, B1950)",
&outobj2.prof_disk_theta1950, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"pos.posAng;src.morph;stat.fit.param", "deg"},
{"DISK_PATTERN_VECTOR", "Disk pattern fitted coefficients",
&outobj2.prof_disk_patternvector, H_FLOAT, T_FLOAT, "%12.4g", "",
"stat.fit.param;src.morph.param", "", 1,
&prefs.prof_disk_patternvectorsize},
{"DISK_PATTERNMOD_VECTOR", "Disk pattern fitted moduli",
&outobj2.prof_disk_patternmodvector, H_FLOAT, T_FLOAT, "%12.4g", "",
"stat.fit.param;src.morph.param", "", 1,
&prefs.prof_disk_patternmodvectorsize},
{"DISK_PATTERNARG_VECTOR", "Disk pattern fitted arguments",
&outobj2.prof_disk_patternargvector, H_FLOAT, T_FLOAT, "%12.4g", "deg",
"stat.fit.param;src.morph.param", "deg", 1,
&prefs.prof_disk_patternargvectorsize},
{"DISK_PATTERN_SPIRAL", "Disk pattern spiral index",
&outobj2.prof_disk_patternspiral, H_FLOAT, T_FLOAT, "%12.4g", "",
"stat.fit.param;src.morph.param", ""},
{"FLUX_BAR", "Bar total flux from fitting",
&outobj2.prof_bar_flux, H_FLOAT, T_FLOAT, "%12.g", "count",
"phot.count;stat.fit.param", "ct"},
{"FLUXERR_BAR", "RMS error on fitted total bar flux",
&outobj2.prof_bar_fluxerr, H_FLOAT, T_FLOAT, "%12.g", "count",
"stat.error;phot.count;stat.fit.param", "ct"},
{"MAG_BAR", "Bar total magnitude from fitting",
&outobj2.prof_bar_mag, H_FLOAT, T_FLOAT, "%8.4f", "mag",
"phot.mag;stat.fit.param", "mag"},
{"MAGERR_BAR", "RMS error on fitted total bar magnitude",
&outobj2.prof_bar_magerr, H_FLOAT, T_FLOAT, "%8.4f", "mag",
"stat.error;phot.mag;stat.fit.param", "mag"},
{"BAR_LENGTH_IMAGE", "Bar length from fitting",
&outobj2.prof_bar_length, H_FLOAT, T_FLOAT, "%10.4f", "pixel",
"src.morph.scLength;stat.fit.param;instr.det", "pix"},
{"BAR_LENGTHERR_IMAGE", "RMS error on fitted bar length",
&outobj2.prof_bar_lengtherr, H_FLOAT, T_FLOAT, "%10.4f", "pixel",
"stat.error;src.morph.scLength;stat.fit.param;instr.det", "pix"},
{"BAR_LENGTH_WORLD", "Bar length from fitting",
&outobj2.prof_bar_lengthw, H_FLOAT, T_FLOAT, "%12.7g", "deg",
"src.morph.scLength;stat.fit.param", "deg"},
{"BAR_LENGTHERR_WORLD", "RMS error on fitted bar length (world coords)",
&outobj2.prof_bar_lengtherrw, H_FLOAT, T_FLOAT, "%12.7g", "deg",
"stat.error;src.morph.scLength;stat.fit.param", "deg"},
{"BAR_ASPECT_IMAGE", "Bar aspect ratio from fitting",
&outobj2.prof_bar_aspect, H_FLOAT, T_FLOAT, "%6.4f", "",
"phys.size.axisRatio;src.morph;stat.fit.param;instr.det", ""},
{"BAR_ASPECTERR_IMAGE", "RMS error on fitted bar aspect ratio",
&outobj2.prof_bar_aspecterr, H_FLOAT, T_FLOAT, "%6.4f", "",
"stat.error;phys.size.axisRatio;src.morph;stat.fit.param;instr.det", ""},
{"BAR_ASPECT_WORLD", "Bar aspect ratio from fitting",
&outobj2.prof_bar_aspectw, H_FLOAT, T_FLOAT, "%12.7g", "",
"phys.size.axisRatio;src.morph;stat.fit.param", ""},
{"BAR_ASPECTERR_WORLD", "RMS error on fitted bar aspect ratio",
&outobj2.prof_bar_aspecterrw, H_FLOAT, T_FLOAT, "%12.7g", "",
"stat.error;phys.size.axisRatio;src.morph;stat.fit.param", ""},
{"BAR_POSANG", "Bar true position angle (CCW/disk maj.axis) from fitting",
&outobj2.prof_bar_posang, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"pos.bodyrc.long;src.morph;stat.fit.param", "deg"},
{"BAR_POSANGERR", "RMS error on fitted true bar position angle",
&outobj2.prof_bar_posangerr, H_FLOAT, T_FLOAT, "%7.3f", "deg",
"stat.error;pos.bodyrc.long;src.morph;stat.fit.param", "deg"},
{"BAR_THETA_IMAGE", "Bar projected angle (CCW/x) from fitting",
&outobj2.prof_bar_theta, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"pos.posAng;src.morph;stat.fit.param;instr.det", "deg"},
{"BAR_THETAERR_IMAGE", "RMS error on fitted bar projected angle",
&outobj2.prof_bar_thetaerr, H_FLOAT, T_FLOAT, "%7.3f", "deg",
"stat.error;pos.posAng;src.morph;stat.fit.param;instr.det", "deg"},
{"BAR_THETA_WORLD", "Bar projected angle (CCW/world-x) from fitting",
&outobj2.prof_bar_thetaw, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"pos.posAng;src.morph;stat.fit.param", "deg"},
{"BAR_THETAERR_WORLD", "RMS error on fitted bar projected angle",
&outobj2.prof_bar_thetaerrw, H_FLOAT, T_FLOAT, "%7.3f", "deg",
"stat.error;pos.posAng;src.morph;stat.fit.param", "deg"},
{"BAR_THETA_SKY", "Bar projected angle (east of north, native) from fitting",
&outobj2.prof_bar_thetas, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"pos.posAng;src.morph;stat.fit.param", "deg"},
{"BAR_THETA_J2000", "Bar projected angle (east of north, J2000) from fitting",
&outobj2.prof_bar_theta2000, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"pos.posAng;src.morph;stat.fit.param", "deg"},
{"BAR_THETA_B1950", "Bar projected angle (east of north, B1950) from fitting",
&outobj2.prof_bar_theta1950, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"pos.posAng;src.morph;stat.fit.param", "deg"},
{"FLUX_ARMS", "Total flux in spiral arms from fitting",
&outobj2.prof_arms_flux, H_FLOAT, T_FLOAT, "%12.g", "count",
"phot.count;stat.fit.param", "ct"},
{"FLUXERR_ARMS", "RMS error on fitted total flux in spiral arms",
&outobj2.prof_arms_fluxerr, H_FLOAT, T_FLOAT, "%12.g", "count",
"stat.error;phot.count;stat.fit.param", "ct"},
{"MAG_ARMS", "Total magnitude in spiral arms from fitting",
&outobj2.prof_arms_mag, H_FLOAT, T_FLOAT, "%8.4f", "mag",
"phot.mag;stat.fit.param", "mag"},
{"MAGERR_ARMS", "RMS error on fitted total magnitude in spiral arms",
&outobj2.prof_arms_magerr, H_FLOAT, T_FLOAT, "%8.4f", "mag",
"stat.error;phot.mag;stat.fit.param", "mag"},
{"ARMS_SCALE_IMAGE", "Spiral arms scale length from fitting",
&outobj2.prof_arms_scale, H_FLOAT, T_FLOAT, "%10.4f", "pixel",
"src.morph.scLength;stat.fit.param;instr.det", "pix"},
{"ARMS_SCALEERR_IMAGE", "RMS error on fitted spiral arms scale length",
&outobj2.prof_arms_scaleerr, H_FLOAT, T_FLOAT, "%10.4f", "pixel",
"stat.error;src.morph.scLength;stat.fit.param;instr.det", "pix"},
{"ARMS_SCALE_WORLD", "Spiral arms scale length from fitting",
&outobj2.prof_arms_scalew, H_FLOAT, T_FLOAT, "%12.7g", "deg",
"src.morph.scLength;stat.fit.param", "deg"},
{"ARMS_SCALEERR_WORLD", "RMS error on fitted spiral arm scale length",
&outobj2.prof_arms_scaleerrw, H_FLOAT, T_FLOAT, "%12.7g", "deg",
"stat.error;src.morph.scLength;stat.fit.param", "deg"},
{"ARMS_POSANG", "Pos. angle (CCW/disk maj.axis) of spiral arms from fitting",
&outobj2.prof_arms_posang, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"pos.bodyrc.long;src.morph;stat.fit.param", "deg"},
{"ARMS_POSANGERR", "RMS error on fitted spiral arm position angle",
&outobj2.prof_arms_posangerr, H_FLOAT, T_FLOAT, "%7.3f", "deg",
"stat.error;pos.bodyrc.long;src.morph;stat.fit.param", "deg"},
/*
{"ARMS_THETA_WORLD", "Pos. angle (CCW/world-x) of spiral arms",
&outobj2.prof_arms_thetaw, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"pos.posAng;src.morph;stat.fit.param", "deg"},
{"ARMS_THETA_SKY", "Pos. angle (east of north, native) of spiral arms",
&outobj2.prof_arms_thetas, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"pos.posAng;src.morph;stat.fit.param", "deg"},
{"ARMS_THETA_J2000", "Pos. angle (east of north, J2000) of spiral arms",
&outobj2.prof_arms_theta2000, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"pos.posAng;src.morph;stat.fit.param", "deg"},
{"ARMS_THETA_B1950", "Pos. angle (east of north, B1950) of spiral arms",
&outobj2.prof_arms_theta1950, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"pos.posAng;src.morph;stat.fit.param", "deg"},
*/
{"ARMS_PITCH", "Pitch angle of spiral arms from fitting",
&outobj2.prof_arms_pitch, H_FLOAT, T_FLOAT, "%+7.3f", "deg",
"pos.posAng;src.morph;stat.fit.param;instr.det", "deg"},
{"ARMS_PITCHERR", "RMS error on fitted spiral arm pitch angle",
&outobj2.prof_arms_pitcherr, H_FLOAT, T_FLOAT, "%7.3f", "deg",
"stat.error;pos.posAng;src.morph;stat.fit.param;instr.det", "deg"},
{"ARMS_START_IMAGE", "Starting radius of spiral arms from fitting",
&outobj2.prof_arms_start, H_FLOAT, T_FLOAT, "%10.4f", "pixel",
"pos.distance;src.morph;stat.fit.param;instr.det", "pix"},
{"ARMS_STARTERR_IMAGE", "RMS error on fitted spiral arm starting radius",
&outobj2.prof_arms_starterr, H_FLOAT, T_FLOAT, "%10.4f", "pixel",
"stat.error;pos.distance;src.morph;stat.fit.param;instr.det", "pix"},
{"ARMS_START_WORLD", "Starting radius of spiral arms from fitting",
&outobj2.prof_arms_startw, H_FLOAT, T_FLOAT, "%12.7g", "deg",
"pos.distance;src.morph;stat.fit.param", "deg"},
{"ARMS_STARTERR_WORLD", "RMS error on spiral arm starting radius",
&outobj2.prof_arms_starterrw, H_FLOAT, T_FLOAT, "%12.7g", "deg",
"stat.error;pos.distance;src.morph;stat.fit.param", "deg"},
{"ARMS_QUADFRAC", "Fraction of spiral arms in quadrature from fitting",
&outobj2.prof_arms_quadfrac, H_FLOAT, T_FLOAT, "%6.4f", "deg",
"phot.count;arith.ratio;src.morph;stat.fit.param", "deg"},
{"ARMS_QUADFRACERR", "RMS error on fitted spiral arms quadrature fraction",
&outobj2.prof_arms_quadfracerr, H_FLOAT, T_FLOAT, "%6.4f", "deg",
"stat.error;phot.count;arith.ratio;src.morph;stat.fit.param", "deg"},
/*
pattern.c
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: SExtractor
*
* Authors: E.BERTIN (IAP)
*
* Contents: Generate and handle image patterns for image fitting.
*
* Last modify: 20/11/2008
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_MATHIMF_H
#include <mathimf.h>
#else
#define _GNU_SOURCE
#include <math.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include ATLAS_LAPACK_H
#include "define.h"
#include "globals.h"
#include "prefs.h"
#include "fits/fitscat.h"
#include "fitswcs.h"
#include "check.h"
#include "pattern.h"
#include "profit.h"
static double psf_laguerre(double x, int p, int q);
/*------------------------------- variables ---------------------------------*/
/****** pattern_init ***********************************************************
PROTO patternstruct pattern_init(profitstruct *profit, pattern_type ptype,
int ncomp)
PURPOSE Allocate and initialize a new pattern structure.
INPUT Pointer to a profit structure,
Pattern type,
Number of independent components.
OUTPUT Pointer to the new pattern structure.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 19/11/2008
***/
patternstruct *pattern_init(profitstruct *profit, pattypenum ptype, int ncomp)
{
patternstruct *pattern;
int ninpix, noutpix;
if (!ncomp)
ncomp = PATTERN_NCOMP;
QCALLOC(pattern, patternstruct, 1);
pattern->type = ptype;
pattern->ncomp = ncomp;
pattern->size[0] = profit->modnaxisn[0];
pattern->size[1] = profit->modnaxisn[1];
switch(pattern->type)
{
case PATTERN_QUADRUPOLE:
case PATTERN_OCTOPOLE:
pattern->nmodes = 2;
pattern->nfreq = 1;
pattern->size[2] = ncomp*pattern->nmodes;
break;
case PATTERN_POLARFOURIER:
pattern->nfreq = PATTERN_FMAX+1;
pattern->nmodes = 2*PATTERN_FMAX+1;
pattern->size[2] = ncomp*pattern->nmodes;
break;
case PATTERN_POLARSHAPELETS:
pattern->nfreq = 0;
pattern->nmodes = 0;
pattern->size[2] = (ncomp+1)*(ncomp+2)/2;
break;
default:
error(EXIT_FAILURE, "*Internal Error*: Unknown Pattern type","");
}
ninpix = pattern->size[0]*pattern->size[1] * pattern->size[2];
noutpix = profit->objnaxisn[0]*profit->objnaxisn[1] * pattern->size[2];
QMALLOC(pattern->coeff, double, pattern->size[2]);
QMALLOC(pattern->norm, double, pattern->size[2]);
QMALLOC(pattern->modpix, double, ninpix);
QMALLOC(pattern->lmodpix, PIXTYPE, noutpix);
if (pattern->ncomp)
{
QMALLOC(pattern->r, double, pattern->ncomp);
}
if (pattern->nfreq)
{
QMALLOC(pattern->mcoeff, double, ncomp*pattern->nfreq);
QMALLOC(pattern->acoeff, double, ncomp*pattern->nfreq);
}
return pattern;
}
/****** pattern_end ***********************************************************
PROTO void pattern_end(patternstruct *pattern)
PURPOSE End (deallocate) a pattern structure.
INPUT Pattern structure.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 02/10/2008
***/
void pattern_end(patternstruct *pattern)
{
free(pattern->norm);
free(pattern->r);
free(pattern->modpix);
free(pattern->lmodpix);
free(pattern->coeff);
free(pattern->mcoeff);
free(pattern->acoeff);
free(pattern);
return;
}
/****** pattern_fit ******************************************************
PROTO void pattern_resample(patternstruct *pattern)
PURPOSE Resample a pattern structure.
INPUT Pointer to pattern structure.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 01/10/2008
***/
void pattern_fit(patternstruct *pattern, profitstruct *profit)
{
checkstruct *check;
double *inpix, *doutpix1, *alpha,*beta,
dval, dprod;
PIXTYPE *outpix,*outpix1,*outpix2;
PIXTYPE *weightpix;
int n,p,p2, nvec, ninpix, noutpix;
nvec = pattern->size[2];
pattern_create(pattern, profit);
QMALLOC(alpha, double, nvec*nvec);
beta = pattern->coeff;
inpix = pattern->modpix;
ninpix = pattern->size[0]*pattern->size[1];
outpix = pattern->lmodpix;
noutpix = profit->objnaxisn[0]*profit->objnaxisn[1];
for (p=0; p<nvec; p++)
{
profit_convolve(profit, inpix);
profit_resample(profit, inpix, outpix);
outpix1 = pattern->lmodpix;
for (p2=0; p2<=p; p2++)
{
weightpix = profit->objweight;
outpix2 = outpix;
dval = 0.0;
for (n=noutpix; n--;)
{
dprod = *(outpix1++)**(outpix2++);
if (*(weightpix++)>0.0)
dval += dprod;
}
alpha[p*nvec+p2] = alpha[p2*nvec+p] = dval;
}
weightpix = profit->objweight;
doutpix1 = profit->resi;
outpix2 = outpix;
dval = 0.0;
for (n=noutpix; n--;)
{
dprod = *doutpix1**(outpix2++);
if (*(weightpix++)>0.0)
{
dval += dprod;
doutpix1++;
}
}
alpha[p*(nvec+1)] += 0.2;
beta[p] = dval;
inpix += ninpix;
outpix += noutpix;
}
/* Solve the system */
clapack_dpotrf(CblasRowMajor,CblasUpper,nvec,alpha,nvec);
clapack_dpotrs(CblasRowMajor,CblasUpper,nvec,1,alpha,nvec,beta,nvec);
pattern_compmodarg(pattern, profit);
free(alpha);
if ((check = prefs.check[CHECK_PATTERNS]))
{
QCALLOC(outpix, PIXTYPE, noutpix);
outpix2 = pattern->lmodpix;
for (p=0; p<nvec; p++)
{
dval = pattern->coeff[p];
outpix1 = outpix;
for (n=noutpix; n--;)
*(outpix1++) += dval**(outpix2++);
}
addcheck(check, outpix, profit->objnaxisn[0],profit->objnaxisn[1],
profit->ix, profit->iy, 1.0);
free(outpix);
}
/*
{
catstruct *cat;
char name[MAXCHAR];
static int number;
int nout;
nout = nvec;
QCALLOC(outpix, PIXTYPE, ninpix*nout);
outpix1 = outpix;
doutpix1 = pattern->modpix;
for (p=0; p<nvec; p++)
{
dval = pattern->coeff[p];
for (n=ninpix; n--; )
*(outpix1++) += dval**(doutpix1++);
if (pattern->type==PATTERN_POLARFOURIER)
{
if ((p%pattern->nmodes)%2)
outpix1 -= ninpix;
}
else if (pattern->type==PATTERN_POLARSHAPELETS)
{
}
else if (!(p%2))
outpix1 -= noutpix;
}
cat=new_cat(1);
init_cat(cat);
cat->tab->naxis=3;
QMALLOC(cat->tab->naxisn, int, 3);
cat->tab->naxisn[0]=profit->modnaxisn[0];
cat->tab->naxisn[1]=profit->modnaxisn[1];
cat->tab->naxisn[2]=nout;
cat->tab->bitpix=BP_FLOAT;
cat->tab->bytepix=4;
cat->tab->bodybuf=(char *)outpix;
cat->tab->tabsize=cat->tab->naxisn[0]*cat->tab->naxisn[1]*cat->tab->naxisn[2]*sizeof(PIXTYPE);
sprintf(name, "tata_%02d.fits", ++number);
save_cat(cat, name);
cat->tab->bodybuf=NULL;
free_cat(&cat, 1);
free(outpix);
}
*/
return;
}
/****** pattern_compmodarg ****************************************************
PROTO void pattern_comparg(patternstruct *pattern, profitstruct *profit)
PURPOSE Compute modulus and argument for each pair of Fourier components.
INPUT Pointer to pattern structure,
pointer to profit structure.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 20/11/2008
***/
void pattern_compmodarg(patternstruct *pattern, profitstruct *profit)
{
double *coeff,*mcoeff,*acoeff, *normt,
arg,argo,darg, ima,rea;
int f,p, nfreq;
if (pattern->type == PATTERN_POLARSHAPELETS)
return;
coeff = pattern->coeff;
mcoeff = pattern->mcoeff;
acoeff = pattern->acoeff;
nfreq = pattern->nfreq;
normt = pattern->norm;
argo = 0.0; /* To avoid gcc -Wall warnings */
for (p=0; p<pattern->ncomp; p++)
{
for (f=0; f<nfreq; f++)
{
if (pattern->type == PATTERN_POLARFOURIER && !f)
{
*(mcoeff++) = fabs(*coeff) * *(normt++);
*(acoeff++) = *(coeff++)<0.0? 180.0 : 0.0;
}
else
{
rea = *(coeff++) * *(normt++);
ima = *(coeff++) * *(normt++);
*(mcoeff++) = sqrt(rea*rea + ima*ima);
arg = atan2(ima, rea)/DEG;
if (p>0)
{
argo = *(acoeff-nfreq);
darg = arg - fmod(argo+180.0, 360.0) + 180.0;;
/*-------- disambiguate increasing or decreasing phase angles */
if (darg > 180.0)
darg -= 360.0;
else if (darg < -180.0)
darg += 360.0;
*acoeff = argo + darg;
acoeff++;
}
else
*(acoeff++) = arg;
argo = arg;
}
}
}
return;
}
/****** pattern_spiral ******************************************************
PROTO float pattern_spiral(patternstruct *pattern)
PURPOSE Compute a pattern spiral index.
INPUT Pointer to pattern structure.
OUTPUT Spiral index.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 14/10/2008
***/
float pattern_spiral(patternstruct *pattern)
{
double w,x,y, s,sx,sy,sxx,sxy;
int f,i,p, pstart;
if (pattern->ncomp<2)
return 0.0;
pstart = (int)(pattern->ncomp/pattern->rmax+0.4999) - 1;
if (pstart<0)
pstart = 0;
else if (pstart>pattern->ncomp-2)
pstart = pattern->ncomp-2;
s = sx = sy = sxx = sxy = 0.0;
for (p=pstart; p<pattern->ncomp; p++)
{
w = y = 0.0;
for (f=0; f<pattern->nfreq; f++)
{
if (pattern->type == PATTERN_POLARFOURIER && (!f || f==1 || f==3))
continue;
i = p*pattern->nfreq + f;
w += pattern->mcoeff[i];
y += pattern->mcoeff[i]*pattern->acoeff[i]/f;
}
x = (double)(p - pstart);
if (w>0.0)
y /= w;
s += w;
sx += w*x;
sy += w*y;
sxx += w*x*x;
sxy += w*x*y;
}
return (s*sxy - sx*sy)/(s*sxx - sx*sx);
}
/****** pattern_create ******************************************************
PROTO void pattern_create(patternstruct *pattern, profitstruct *profit)
PURPOSE create a pattern basis.
INPUT Pointer to pattern structure,
pointer to the profit structure.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 20/11/2008
***/
void pattern_create(patternstruct *pattern, profitstruct *profit)
{
double *scbuf[PATTERN_FMAX],*scpix[PATTERN_FMAX],
*scpixt,*cpix,*spix, *pix, *r2buf,*r2pix,*modpix,
*normt, *pmodpix,
x1,x2, x1t,x2t, r,r2,r2min,r2max,
mod,ang,ang0, cosang,sinang, angcoeff, posangle,flux,
ctheta,stheta, saspect,xscale,yscale, scale, aspect,
cd11,cd12,cd21,cd22, x1cout,x2cout, cmod,smod,
cnorm,snorm,norm,norm0, dval, det, rad, dnrad,
cpnorm,spnorm,pnorm, rl,rl2,rh,rh2,r0,r02, sbd,
bt, wb, omwb, bflux, margin2, dposangle;
int f,i,p, ix1,ix2, nrad, npix;
double *fr2,*fr2t,*fexpr2,*fexpr2t,*ftheta,*fthetat,
dm,fac, beta, invbeta2;
int m,n, nmax, kmax,hnmm;
/* Compute Profile CD matrix */
aspect = fabs(*profit->paramlist[PARAM_DISK_ASPECT]);
posangle = fmod_m90_p90(*profit->paramlist[PARAM_DISK_POSANG])*DEG;
scale = fabs(*profit->paramlist[PARAM_DISK_SCALE]/profit->pixstep);
flux = fabs(*profit->paramlist[PARAM_DISK_FLUX])*1.67835;
bflux = fabs(*profit->paramlist[PARAM_SPHEROID_FLUX]);
bt = bflux / (bflux+flux);
if (bt > PATTERN_BTMAX)
{
wb = (bt - PATTERN_BTMAX) / (1.0 - PATTERN_BTMAX);
if (wb > 1.0)
wb = 1.0;
omwb = 1.0 - wb;
flux = wb*bflux + omwb*flux;
scale = omwb*scale
+ wb*fabs(*profit->paramlist[PARAM_SPHEROID_REFF]/profit->pixstep)*1.5;
aspect = omwb*aspect
+ wb*fabs(*profit->paramlist[PARAM_SPHEROID_ASPECT]);
posangle /= DEG;
dposangle = fmod_m90_p90(*profit->paramlist[PARAM_SPHEROID_POSANG])
- posangle;
if (dposangle > 90.0)
dposangle -= 180.0;
else if (dposangle < -90.0)
dposangle += 180.0;
posangle = fmod_m90_p90(posangle + wb*dposangle)*DEG;
}
ctheta = cos(posangle);
stheta = sin(posangle);
saspect = fabs(aspect);
xscale = (scale==0.0)? 0.0 : 1.0/scale;
yscale = (scale*saspect == 0.0)? 0.0 : 1.0/(scale*saspect);
cd11 = xscale*ctheta;
cd12 = xscale*stheta;
cd21 = -yscale*stheta;
cd22 = yscale*ctheta;
x1cout = (double)(pattern->size[0]/2);
x2cout = (double)(pattern->size[1]/2);
/* Determinant of the change of coordinate system */
det = xscale*yscale;
sbd = fabs(flux)*det/(2.0*PI);
r2min = det/10.0;
/* Stay within an ellipse contained in the pattern raster, both in x and y */
r2max = PATTERN_SCALE*PATTERN_SCALE;
margin2 = (1.0-PATTERN_MARGIN)*(1.0-PATTERN_MARGIN);
if (r2max > (dval = margin2
* x1cout*x1cout * det*det / (cd12*cd12+cd22*cd22)))
r2max = dval;
if (r2max > (dval = margin2
* x2cout*x2cout * det*det / (cd21*cd21+cd11*cd11)))
r2max = dval;
/* Set the limit of the pattern extent */
// rad = 4.0*profit->obj->a*xscale;
/* The pattern limit does not exceed 90% of the mapped ellipse "radius" */
// if (rad*rad > 0.9*0.9*r2max)
nrad = pattern->ncomp;
pattern->rmax = rad = sqrt(r2max);
if (!nrad)
error(EXIT_FAILURE,
"*Error*: insufficient number of vector elements",
" for generating the pattern basis");
dnrad = (double)nrad;
npix = pattern->size[0]*pattern->size[1];
normt = pattern->norm;
switch(pattern->type)
{
case PATTERN_QUADRUPOLE:
case PATTERN_OCTOPOLE:
cpix = pattern->modpix;
spix = pattern->modpix+npix;
angcoeff = (pattern->type==PATTERN_OCTOPOLE)? 4.0 : 2.0;
for (p=0; p<nrad; p++, cpix+=npix, spix+=npix)
{
x1 = -x1cout;
x2 = -x2cout;
cnorm = snorm = cpnorm = spnorm = 0.0;
rl = p*rad/dnrad;
rl2 = rl*rl;
pattern->r[p] = r0 = (p+1)*rad/dnrad;
r02 = r0*r0;
rh = (p+2)*rad/dnrad;
rh2 = rh*rh;
pmodpix = profit->modpix;
for (ix2=pattern->size[1]; ix2--; x2+=1.0)
{
x1t = cd12*x2 + cd11*x1;
x2t = cd22*x2 + cd21*x1;
for (ix1=pattern->size[0]; ix1--; pmodpix++)
{
r2 = x1t*x1t+x2t*x2t;
if (r2>rl2 && r2<rh2)
{
r = sqrt(r2);
dval = (r<r0) ? (r-rl)/(r0-rl) : (rh-r)/(rh-r0);
mod = (dval<0.5)? 2.0*dval*dval : 1.0-2.0*(1.0-dval)*(1.0-dval);
ang = angcoeff*atan2(x2t,x1t);
#ifdef HAVE_SINCOS
sincos(ang, &sinang, &cosang);
#else
sinang = sin(ang);
cosang = cos(ang);
#endif
*(cpix++) = cmod = mod*cosang;
*(spix++) = smod = mod*sinang;
cnorm += cmod*cmod;
snorm += smod*smod;
cpnorm += cmod*cmod**pmodpix**pmodpix;
spnorm += smod*smod**pmodpix**pmodpix;
}
else
*(cpix++) = *(spix++) = 0.0;
x1t += cd11;
x2t += cd21;
}
}
cpix -= npix;
cnorm = (cnorm > 0.0? 1.0/sqrt(cnorm) : 1.0);
*(normt++) = cnorm*sqrt(cpnorm);
for (i=npix; i--;)
*(cpix++) *= cnorm;
spix -= npix;
snorm = (snorm > 0.0? 1.0/sqrt(snorm) : 1.0);
*(normt++) = snorm*sqrt(spnorm);
for (i=npix; i--;)
*(spix++) *= snorm;
}
break;
case PATTERN_POLARFOURIER:
/*---- Pre-compute radii and quadrupoles to speed up computations later */
QMALLOC(r2buf, double, npix);
r2pix = r2buf;
for (f=0; f<PATTERN_FMAX; f++)
{
QMALLOC(scbuf[f], double, 2*npix);
scpix[f] = scbuf[f];
}
x1 = -x1cout;
x2 = -x2cout;
for (ix2=pattern->size[1]; ix2--; x2+=1.0)
{
x1t = cd12*x2 + cd11*x1;
x2t = cd22*x2 + cd21*x1;
for (ix1=pattern->size[0]; ix1--;)
{
*(r2pix++) = x1t*x1t+x2t*x2t;
ang = ang0 = atan2(x2t,x1t);
for (f=0; f<PATTERN_FMAX; f++)
{
#ifdef HAVE_SINCOS
sincos(ang, scpix[f]+npix, scpix[f]);
scpix[f]++;
#else
*(scpix[f]) = cos(ang);
*(scpix[f]+++npix) = sin(ang);
#endif
ang+=ang0;
}
x1t += cd11;
x2t += cd21;
}
}
modpix = NULL; /* To avoid gcc -Wall warnings */
pix = pattern->modpix;
for (p=0; p<nrad; p++)
{
rl = p*rad/dnrad;
rl2 = rl*rl;
pattern->r[p] = r0 = (p+1)*rad/dnrad;
r02 = r0*r0;
rh = (p+2)*rad/dnrad;
rh2 = rh*rh;
for (f=0; f<=PATTERN_FMAX; f++)
{
norm = pnorm = 0.0;
r2pix = r2buf;
pmodpix = profit->modpix;
if (!f)
{
for (i=npix; i--; pmodpix++)
{
r2 = *(r2pix++);
if (r2>rl2 && r2<rh2)
{
r = sqrt(r2);
dval = (r<r0) ? (r-rl)/(r0-rl) : (rh-r)/(rh-r0);
*(pix++) = dval = (dval<0.5)?
2.0*dval*dval : 1.0-2.0*(1.0-dval)*(1.0-dval);
norm += dval*dval;
}
else
*(pix++) = 0.0;
}
pix -= npix;
pnorm = norm*sbd*sbd;
norm0 = norm = (norm > 1.0/BIG? 1.0/sqrt(norm) : 1.0);
*(normt++) = pnorm > 1.0/BIG? 1.0/sqrt(pnorm) : 0.0;
for (i=npix; i--;)
*(pix++) *= norm;
modpix = pix;
}
else
{
modpix -= npix;
scpixt = scbuf[f-1];
for (i=npix; i--; pmodpix++)
{
*(pix++) = dval = *(modpix++)**(scpixt++);
norm += dval*dval;
pnorm += dval*dval**pmodpix**pmodpix;
}
pix -= npix;
pnorm = norm*sbd*sbd;
norm = (norm > 0.0? 1.0/sqrt(norm) : 1.0);
*(normt++) = pnorm > 1.0/BIG? norm0/sqrt(pnorm) : 0.0;
for (i=npix; i--;)
*(pix++) *= norm;
modpix -= npix;
norm = pnorm = 0.0;
pmodpix = profit->modpix;
for (i=npix; i--; pmodpix++)
{
*(pix++) = dval = *(modpix++)**(scpixt++);
norm += dval*dval;
pnorm += dval*dval**pmodpix**pmodpix;
}
pix -= npix;
pnorm = norm*sbd*sbd;
norm = (norm > 0.0? 1.0/sqrt(norm) : 1.0);
*(normt++) = pnorm > 1.0/BIG? norm0/sqrt(pnorm) : 0.0;
for (i=npix; i--;)
*(pix++) *= norm;
}
}
}
free(r2buf);
for (f=0; f<PATTERN_FMAX; f++)
free(scbuf[f]);
break;
case PATTERN_POLARSHAPELETS:
nmax = pattern->ncomp;
kmax = (nmax+1)*(nmax+2)/2;
beta = 0.667;
invbeta2 = 1.0/(beta*beta);
/*---- Precompute some slow functions */
QMALLOC(fr2, double, npix);
QMALLOC(fexpr2, double, npix);
QMALLOC(ftheta, double, npix);
fr2t = fr2;
fexpr2t = fexpr2;
fthetat = ftheta;
x1 = -x1cout;
x2 = -x2cout;
for (ix2=pattern->size[1]; ix2--; x2+=1.0)
{
x1t = cd12*x2 + cd11*x1;
x2t = cd22*x2 + cd21*x1;
for (ix1=pattern->size[0]; ix1--;)
{
*(fr2t++) = r2 = (x1t*x1t+x2t*x2t)*invbeta2;
*(fexpr2t++) = exp(-r2/2.0);
*(fthetat++) = atan2(x2t,x1t);
x1t += cd11;
x2t += cd21;
}
}
pix = pattern->modpix;
for (n=0; n<=nmax; n++)
{
for (m=n%2; m<=n; m+=2)
{
dm = (double)m;
/*-------- Compute ((n+m)/2)!/((n-m)/2)! */
hnmm = (n-m)/2;
fac = 1.0;
// for (p=(n+m)/2; p>=hnmm; p--)
// if (p)
// fac *= (double)p;
// fac = sqrt(1.0/(PI*fac))/beta;
if ((hnmm%2))
fac = -fac;
fr2t = fr2;
fexpr2t = fexpr2;
fthetat = ftheta;
norm = 0.0;
for (i=npix; i--;fr2t++)
{
*(pix++) = dval = fac*pow(*fr2t, dm/2.0)
*psf_laguerre(*fr2t, hnmm, m)
**(fexpr2t++)*cos(dm**(fthetat++));
norm += dval*dval;
}
pix -= npix;
pnorm = norm*sbd*sbd;
norm = (norm > 0.0? 1.0/sqrt(norm) : 1.0);
*(normt++) = pnorm > 1.0/BIG? norm0/sqrt(pnorm) : 0.0;
for (i=npix; i--;)
*(pix++) *= norm;
if (m!=0)
{
fr2t = fr2;
fexpr2t = fexpr2;
fthetat = ftheta;
norm = 0.0;
for (i=npix; i--; fr2t++)
{
*(pix++) = dval = fac*pow(*fr2t, dm/2.0)
*psf_laguerre(*fr2t, hnmm, m)
**(fexpr2t++)*sin(dm**(fthetat++));
norm += dval*dval;
}
pix -= npix;
pnorm = norm*sbd*sbd;
norm = (norm > 0.0? 1.0/sqrt(norm) : 1.0);
*(normt++) = pnorm > 1.0/BIG? norm0/sqrt(pnorm) : 0.0;
for (i=npix; i--;)
*(pix++) *= norm;
}
}
}
free(fr2);
free(fexpr2);
free(ftheta);
break;
default:
error(EXIT_FAILURE, "*Internal Error*: Unknown Pattern type","");
}
return;
}
/****** psf_laguerre **********************************************************
PROTO double psf_laguerre(double x, int p, int q)
PURPOSE Return Laguerre polynomial value.
INPUT x,
p,
q.
OUTPUT Value of the Laguerre polynomial.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 12/11/2007
***/
static double psf_laguerre(double x, int p, int q)
{
double dn,dq, lpm1,lpm2, l;
int n;
dq = q - 1.0;
if (p==0)
return 1.0;
else if (p==1)
return (2.0 - x + dq);
else
{
l = 0.0;
lpm2 = 1.0;
lpm1 = 2.0 - x + dq;
dn = 2.0;
for (n=p-1; n--; dn+=1.0)
{
l = (2.0+(dq-x)/dn)*lpm1 - (1.0+dq/dn)*lpm2;
lpm2 = lpm1;
lpm1 = l;
}
}
return l;
}
/*
pattern.h
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: SExtractor
*
* Authors: E.BERTIN (IAP)
*
* Contents: Include file for pattern.c.
*
* Last modify: 19/11/2008
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
#ifndef _PROFIT_H_
#include "profit.h"
#endif
#ifndef _PATTERN_H_
#define _PATTERN_H_
/*-------------------------------- flags ------------------------------------*/
/*-------------------------------- macros -----------------------------------*/
/*----------------------------- Internal constants --------------------------*/
#define PATTERN_FMAX 4 /* Maximum pattern angular frequency */
#define PATTERN_NCOMP 16 /* Default number of components (radii) */
#define PATTERN_SCALE 5.0 /* Pattern scale in units of r_eff */
#define PATTERN_MARGIN 0.2 /* Pattern margin in fractions of radius */
#define PATTERN_BTMAX 0.6 /* Maximum B/T for pure disk scaling */
/* NOTES:
One must have: PATTERN_SIZE > 1
PATTERN_SCALE > 0.0
PATTERN_BTMAX < 1.0
*/
/*--------------------------------- typedefs --------------------------------*/
typedef enum {PATTERN_QUADRUPOLE, PATTERN_OCTOPOLE,
PATTERN_POLARFOURIER, PATTERN_POLARSHAPELETS,
PATTERN_NPATTERNS}
pattypenum; /* Pattern code */
/*--------------------------- structure definitions -------------------------*/
typedef struct
{
pattypenum type; /* Pattern code */
int ncomp; /* Number of independent components */
int nmodes; /* Number of modes per component */
int nfreq; /* Number of waves per component */
double x[2]; /* Coordinate vector */
double rmax; /* Largest radius in units of scale */
double *r; /* Reduced radius */
double *norm; /* Pattern vector norm */
double *coeff; /* Fitted pattern coefficients */
double *mcoeff; /* Modulus from pattern coefficients */
double *acoeff; /* Argument from pattern coefficients */
double *modpix; /* Pattern pixmaps */
PIXTYPE *lmodpix; /* Low resolution pattern pixmaps */
int size[3]; /* Pixmap size for each axis */
} patternstruct;
/*----------------------------- Global variables ----------------------------*/
/*-------------------------------- functions --------------------------------*/
patternstruct *pattern_init(profitstruct *profit, pattypenum ptype, int nvec);
float pattern_spiral(patternstruct *pattern);
void pattern_compmodarg(patternstruct *pattern,profitstruct *profit),
pattern_create(patternstruct *pattern, profitstruct *profit),
pattern_end(patternstruct *pattern),
pattern_fit(patternstruct *pattern, profitstruct *profit);
#endif
......@@ -9,7 +9,7 @@
*
* Contents: Stuff related to Principal Component Analysis (PCA).
*
* Last modify: 27/11/2003
* Last modify: 11/10/2007
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
......@@ -29,7 +29,7 @@
#include "fits/fitscat.h"
#include "check.h"
#include "image.h"
#include "poly.h"
#include "wcs/poly.h"
#include "psf.h"
static obj2struct *obj2 = &outobj2;
......
......@@ -9,7 +9,7 @@
*
* Contents: Compute magnitudes and other photometrical parameters.
*
* Last modify: 24/08/2005
* Last modify: 02/05/2008
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
......@@ -61,7 +61,7 @@ void computeaperflux(picstruct *field, picstruct *wfield,
corrflag = (prefs.mask_type==MASK_CORRECT);
gainflag = wfield && prefs.weightgain_flag;
var = backnoise2 = field->backsig*field->backsig;
gain = prefs.gain;
gain = field->gain;
/* Integration radius */
raper = prefs.apert[i]/2.0;
raper2 = raper*raper;
......@@ -235,7 +235,7 @@ void computepetroflux(picstruct *field, picstruct *dfield, picstruct *wfield,
mx = obj->mx;
my = obj->my;
var = backnoise2 = field->backsig*field->backsig;
gain = prefs.gain;
gain = field->gain;
pflag = (prefs.detect_type==PHOTO)? 1:0;
corrflag = (prefs.mask_type==MASK_CORRECT);
gainflag = wfield && prefs.weightgain_flag;
......@@ -534,7 +534,7 @@ void computeautoflux(picstruct *field, picstruct *dfield, picstruct *wfield,
mx = obj->mx;
my = obj->my;
var = backnoise2 = field->backsig*field->backsig;
gain = prefs.gain;
gain = field->gain;
pflag = (prefs.detect_type==PHOTO)? 1:0;
corrflag = (prefs.mask_type==MASK_CORRECT);
gainflag = wfield && prefs.weightgain_flag;
......@@ -865,7 +865,7 @@ void computemags(picstruct *field, objstruct *obj)
1.086*obj2->fluxerr_somfit/obj2->flux_somfit
:99.0;
/* Mag. PROFILE */
/* Mag. models */
if (FLAG(obj2.mag_prof))
obj2->mag_prof = obj2->flux_prof>0.0?
-2.5*log10(obj2->flux_prof) + prefs.mag_zeropoint
......@@ -875,6 +875,50 @@ void computemags(picstruct *field, objstruct *obj)
1.086*obj2->fluxerr_prof/obj2->flux_prof
:99.0;
if (FLAG(obj2.prof_spheroid_mag))
obj2->prof_spheroid_mag = obj2->prof_spheroid_flux>0.0?
-2.5*log10(obj2->prof_spheroid_flux)
+ prefs.mag_zeropoint
:99.0;
if (FLAG(obj2.prof_spheroid_magerr))
obj2->prof_spheroid_magerr = obj2->prof_spheroid_flux>0.0?
1.086*obj2->prof_spheroid_fluxerr
/ obj2->prof_spheroid_flux
:99.0;
if (FLAG(obj2.prof_disk_mag))
obj2->prof_disk_mag = obj2->prof_disk_flux>0.0?
-2.5*log10(obj2->prof_disk_flux)
+ prefs.mag_zeropoint
:99.0;
if (FLAG(obj2.prof_disk_magerr))
obj2->prof_disk_magerr = obj2->prof_disk_flux>0.0?
1.086*obj2->prof_disk_fluxerr
/ obj2->prof_disk_flux
:99.0;
if (FLAG(obj2.prof_bar_mag))
obj2->prof_bar_mag = obj2->prof_bar_flux>0.0?
-2.5*log10(obj2->prof_bar_flux)
+ prefs.mag_zeropoint
:99.0;
if (FLAG(obj2.prof_bar_magerr))
obj2->prof_bar_magerr = obj2->prof_bar_flux>0.0?
1.086*obj2->prof_bar_fluxerr
/obj2->prof_bar_flux
:99.0;
if (FLAG(obj2.prof_arms_mag))
obj2->prof_arms_mag = obj2->prof_arms_flux>0.0?
-2.5*log10(obj2->prof_arms_flux)
+ prefs.mag_zeropoint
:99.0;
if (FLAG(obj2.prof_arms_magerr))
obj2->prof_arms_magerr = obj2->prof_arms_flux>0.0?
1.086*obj2->prof_arms_fluxerr
/obj2->prof_arms_flux
:99.0;
/* Mag. WINdowed */
if (FLAG(obj2.mag_win))
obj2->mag_win = obj2->flux_win>0.0?
......
/*
poly.c
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: A program using Polynomials
*
* Author: E.BERTIN (IAP)
*
* Contents: Polynomial fitting
*
* Last modify: 13/12/2002
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "define.h"
#include "globals.h"
#include "poly.h"
/****** poly_init ************************************************************
PROTO polystruct *poly_init(int *group, int ndim, int *degree, int ngroup)
PURPOSE Allocate and initialize a polynom structure.
INPUT 1D array containing the group for each parameter,
number of dimensions (parameters),
1D array with the polynomial degree for each group,
number of groups.
OUTPUT polystruct pointer.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 11/02/99
***/
polystruct *poly_init(int *group, int ndim, int *degree, int ngroup)
{
polystruct *poly;
char str[MAXCHAR];
static int nd[POLY_MAXDIM];
int *groupt,
d,g,n,num,den;
QCALLOC(poly, polystruct, 1);
if ((poly->ndim=ndim) > POLY_MAXDIM)
{
sprintf(str, "The dimensionality of the polynom (%d) exceeds the maximum\n"
"allowed one (%d)", ndim, POLY_MAXDIM);
error(EXIT_FAILURE, "*Error*: ", str);
}
if (ndim)
QMALLOC(poly->group, int, poly->ndim);
for (groupt=poly->group, d=ndim; d--;)
*(groupt++) = *(group++)-1;
poly->ngroup = ngroup;
if (ngroup)
{
group = poly->group; /* Forget the original *group */
QMALLOC(poly->degree, int, poly->ngroup);
/*-- Compute the number of context parameters for each group */
memset(nd, 0, ngroup*sizeof(int));
for (d=0; d<ndim; d++)
{
if ((g=group[d])>ngroup)
error(EXIT_FAILURE, "*Error*: polynomial GROUP out of range", "");
nd[g]++;
}
}
/* Compute the total number of coefficients */
poly->ncoeff = 1;
for (g=0; g<ngroup; g++)
{
if ((d=poly->degree[g]=*(degree++))>POLY_MAXDEGREE)
{
sprintf(str, "The degree of the polynom (%d) exceeds the maximum\n"
"allowed one (%d)", poly->degree[g], POLY_MAXDEGREE);
error(EXIT_FAILURE, "*Error*: ", str);
}
/*-- There are (n+d)!/(n!d!) coeffs per group, that is Prod_(i<=d) (n+i)/i */
for (num=den=1, n=nd[g]; d; num*=(n+d), den*=d--);
poly->ncoeff *= num/den;
}
QMALLOC(poly->basis, double, poly->ncoeff);
QCALLOC(poly->coeff, double, poly->ncoeff);
return poly;
}
/****** poly_end *************************************************************
PROTO void poly_end(polystruct *poly)
PURPOSE Free a polynom structure and everything it contains.
INPUT polystruct pointer.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP, Leiden observatory & ESO)
VERSION 28/01/99
***/
void poly_end(polystruct *poly)
{
free(poly->coeff);
free(poly->basis);
free(poly->degree);
free(poly->group);
free(poly);
}
/****** poly_func ************************************************************
PROTO double poly_func(polystruct *poly, double *pos)
PURPOSE Evaluate a multidimensional polynom.
INPUT polystruct pointer,
pointer to the 1D array of input vector data.
OUTPUT Polynom value.
NOTES Values of the basis functions are updated in poly->basis.
AUTHOR E. Bertin (IAP)
VERSION 11/02/99
***/
double poly_func(polystruct *poly, double *pos)
{
static double xpol[POLY_MAXDIM+1];
double *post, *xpolt, *basis, *coeff, val, xval;
static int expo[POLY_MAXDIM+1], gexpo[POLY_MAXDIM+1];
int *expot, *degree,*degreet, *group,*groupt, *gexpot,
d,g,t, ndim;
/* Prepare the vectors and counters */
ndim = poly->ndim;
basis = poly->basis;
coeff = poly->coeff;
group = poly->group;
degree = poly->degree;
if (ndim)
{
for (xpolt=xpol, expot=expo, post=pos, d=ndim; --d;)
{
*(++xpolt) = 1.0;
*(++expot) = 0;
}
for (gexpot=gexpo, degreet=degree, g=poly->ngroup; g--;)
*(gexpot++) = *(degreet++);
if (gexpo[*group])
gexpo[*group]--;
}
/*
*pos=1.001;*(pos+1)=1.0001;*(pos+2)=1.00001;
*/
/* The constant term is handled separately */
val = *(coeff++);
*(basis++) = 1.0;
*expo = 1;
*xpol = *pos;
/* Compute the rest of the polynom */
for (t=poly->ncoeff; --t; )
{
/*-- xpol[0] contains the current product of the x^n's */
val += (*(basis++)=*xpol)**(coeff++);
/*-- A complex recursion between terms of the polynom speeds up computations */
post = pos;
groupt = group;
expot = expo;
xpolt = xpol;
/*
printf("%d%d%d %7.5f %7.5f %7.5f %d %d\n",
*expo, *(expo+1), *(expo+2), *xpol,
*(xpol+1), *(xpol+2) , *gexpo, *(gexpo+1));
*/
for (d=0; d<ndim; d++, groupt++)
if (gexpo[*groupt]--)
{
++*(expot++);
xval = (*(xpolt--) *= *post);
while (d--)
*(xpolt--) = xval;
break;
}
else
{
gexpo[*groupt] = *expot;
*(expot++) = 0;
*(xpolt++) = 1.0;
post++;
}
}
return val;
}
/****** poly_fit *************************************************************
PROTO double poly_fit(polystruct *poly, double *x, double *y, double *w,
int ndata, double *extbasis)
PURPOSE Least-Square fit of a multidimensional polynom to weighted data.
INPUT polystruct pointer,
pointer to the (pseudo)2D array of inputs to basis functions,
pointer to the 1D array of data values,
pointer to the 1D array of data weights,
number of data points,
pointer to a (pseudo)2D array of computed basis function values.
OUTPUT Chi2 of the fit.
NOTES If different from NULL, extbasis can be provided to store the
values of the basis functions. If x==NULL and extbasis!=NULL, the
precomputed basis functions stored in extbasis are used (which saves
CPU).
AUTHOR E. Bertin (IAP, Leiden observatory & ESO)
VERSION 05/04/99
***/
void poly_fit(polystruct *poly, double *x, double *y, double *w, int ndata,
double *extbasis)
{
double *alpha,*alphat, *beta,*betat, *basis,*basis1,*basis2, *coeff,
*extbasist,
val,wval,yval;
int ncoeff, ndim, matsize,
i,j,n;
if (!x && !extbasis)
error(EXIT_FAILURE, "*Internal Error*: One of x or extbasis should be "
"different from NULL\nin ", "poly_func()");
ncoeff = poly->ncoeff;
ndim = poly->ndim;
matsize = ncoeff*ncoeff;
basis = poly->basis;
extbasist = extbasis;
QCALLOC(alpha, double, matsize);
QCALLOC(beta, double, ncoeff);
/* Build the covariance matrix */
for (n=ndata; n--;)
{
if (x)
{
/*---- If x!=NULL, compute the basis functions */
poly_func(poly, x);
x+=ndim;
/*---- If, in addition, extbasis is provided, then fill it */
if (extbasis)
for (basis1=basis,j=ncoeff; j--;)
*(extbasist++) = *(basis1++);
}
else
/*---- If x==NULL, then rely on pre-computed basis functions */
for (basis1=basis,j=ncoeff; j--;)
*(basis1++) = *(extbasist++);
basis1 = basis;
wval = *(w++);
yval = *(y++);
betat = beta;
alphat = alpha;
for (j=ncoeff; j--;)
{
val = *(basis1++)*wval;
*(betat++) += val*yval;
for (basis2=basis,i=ncoeff; i--;)
*(alphat++) += val**(basis2++);
}
}
/* Solve the system */
cholsolve(alpha,beta,ncoeff);
free(alpha);
/* Now fill the coeff array with the result of the fit */
betat = beta;
coeff = poly->coeff;
for (j=ncoeff; j--;)
*(coeff++) = *(betat++);
free(beta);
return;
}
/****** cholsolve *************************************************************
PROTO void cholsolve(double *a, double *b, int n)
PURPOSE Solve a system of linear equations, using Cholesky decomposition.
INPUT Pointer to the (pseudo 2D) matrix of coefficients,
pointer to the 1D column vector,
matrix size.
OUTPUT -.
NOTES Based on Numerical Recipes, 2nd ed. (Chap 2.9). The matrix of
coefficients must be symmetric and positive definite.
AUTHOR E. Bertin (IAP, Leiden observatory & ESO)
VERSION 13/12/98
***/
void cholsolve(double *a, double *b, int n)
{
double *p, *x, sum;
int i,j,k;
/* Allocate memory to store the diagonal elements */
QMALLOC(p, double, n);
/* Cholesky decomposition */
for (i=0; i<n; i++)
for (j=i; j<n; j++)
{
for (sum=a[i*n+j],k=i-1; k>=0; k--)
sum -= a[i*n+k]*a[j*n+k];
if (i==j)
{
if (sum <= 0.0)
error(EXIT_FAILURE, "*Error*: Non positive definite matrix in ",
"cholsolve()");
p[i] = sqrt(sum);
}
else
a[j*n+i] = sum/p[i];
}
/* Solve the system */
x = b; /* Just to save memory: the solution replaces b */
for (i=0; i<n; i++)
{
for (sum=b[i],k=i-1; k>=0; k--)
sum -= a[i*n+k]*x[k];
x[i] = sum/p[i];
}
for (i=n-1; i>=0; i--)
{
for (sum=x[i],k=i+1; k<n; k++)
sum -= a[k*n+i]*x[k];
x[i] = sum/p[i];
}
free(p);
return;
}
/*
poly.h
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: A program using polynomial fits
*
* Author: E.BERTIN (IAP)
*
* Contents: Include for poly.c
*
* Last modify: 05/04/99
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
/*--------------------------------- constants -------------------------------*/
#define POLY_MAXDIM 4 /* Max dimensionality of polynom */
#define POLY_MAXDEGREE 10 /* Max degree of the polynom */
/*---------------------------------- macros ---------------------------------*/
/*--------------------------- structure definitions -------------------------*/
typedef struct poly
{
double *basis; /* Current values of the basis functions */
double *coeff; /* Polynom coefficients */
int ncoeff; /* Number of coefficients */
int *group; /* Groups */
int ndim; /* dimensionality of the polynom */
int *degree; /* Degree in each group */
int ngroup; /* Number of different groups */
} polystruct;
/*---------------------------------- protos --------------------------------*/
extern polystruct *poly_init(int *group,int ndim,int *degree,int ngroup);
extern double poly_func(polystruct *poly, double *pos);
extern void cholsolve(double *a, double *b, int n),
poly_end(polystruct *poly),
poly_fit(polystruct *poly, double *x, double *y,
double *w, int ndata, double *extbasis);
......@@ -9,7 +9,7 @@
*
* Contents: Keywords for the configuration file.
*
* Last modify: 14/07/2006
* Last modify: 20/11/2008
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
......@@ -69,8 +69,9 @@
"BACKGROUND", "BACKGROUND_RMS", "MINIBACKGROUND",
"MINIBACK_RMS", "-BACKGROUND",
"FILTERED", "OBJECTS", "APERTURES", "SEGMENTATION", "ASSOC",
"-OBJECTS", "-PSF_PROTOS", "PSF_PROTOS",
"-PC_CONVPROTOS", "PC_CONVPROTOS", "PC_PROTOS", ""},
"-OBJECTS", "-PSFS", "PSFS",
"-PC_CONVPROTOS", "PC_CONVPROTOS", "PC_PROTOS",
"MAP_SOM", "-MODELS", "MODELS", "PATTERNS", ""},
0, 17, &prefs.ncheck_type},
{"CLEAN", P_BOOL, &prefs.clean_flag},
{"CLEAN_PARAM", P_FLOAT, &prefs.clean_param, 0,0, 0.1,10.0},
......@@ -91,6 +92,7 @@
{"FLAG_TYPE", P_KEYLIST, prefs.flag_type, 0,0, 0.0,0.0,
{"OR","AND","MIN", "MAX", "MOST",""}, 0, MAXFLAG, &idummy},
{"GAIN", P_FLOAT, &prefs.gain, 0,0, 0.0, 1e+30},
{"GAIN_KEY", P_STRING, prefs.gain_key},
{"INTERP_MAXXLAG", P_INTLIST, prefs.interp_xtimeout, 1,1000000, 0.0,0.0,
{""}, 1, 2, &prefs.ninterp_xtimeout},
{"INTERP_MAXYLAG", P_INTLIST, prefs.interp_ytimeout, 1,1000000, 0.0,0.0,
......@@ -106,6 +108,9 @@
{"MEMORY_PIXSTACK", P_INT, &prefs.mem_pixstack, 1000, 10000000},
{"NTHREADS", P_INT, &prefs.nthreads, 0, THREADS_PREFMAX},
{"PARAMETERS_NAME", P_STRING, prefs.param_name},
{"PATTERN_TYPE", P_KEY, &prefs.pattern_type, 0,0, 0.0,0.0,
{"RINGS-QUADPOLE", "RINGS-OCTOPOLE", "RINGS-HARMONIC", "GAUSS-LAGUERRE",
""}},
{"PHOT_APERTURES", P_FLOATLIST, prefs.apert, 0,0, 0.0,2*MAXPICSIZE,
{""}, 1, MAXNAPER, &prefs.naper},
{"PHOT_AUTOPARAMS", P_FLOATLIST, prefs.autoparam, 0,0, 0.0,10.0,
......@@ -122,6 +127,7 @@
{"PSF_NMAX", P_INT, &prefs.psf_npsfmax, 1, PSF_NPSFMAX},
{"PSFDISPLAY_TYPE", P_KEY, &prefs.psfdisplay_type, 0,0, 0.0,0.0,
{"SPLIT","VECTOR",""}},
{"SATUR_KEY", P_STRING, prefs.satur_key},
{"SATUR_LEVEL", P_FLOAT, &prefs.satur_level, 0,0, -1e+30, 1e+30},
{"SEEING_FWHM", P_FLOAT, &prefs.seeing_fwhm, 0,0, 1e-10, 1e+10},
{"SOM_NAME", P_STRING, prefs.som_name},
......@@ -209,10 +215,12 @@ char *default_prefs[] =
"*PHOT_FLUXFRAC 0.5 # flux fraction[s] used for FLUX_RADIUS",
" ",
"SATUR_LEVEL 50000.0 # level (in ADUs) at which arises saturation",
"SATUR_KEY SATURATE # keyword for saturation level (in ADUs)",
" ",
"MAG_ZEROPOINT 0.0 # magnitude zero-point",
"MAG_GAMMA 4.0 # gamma of emulsion (for photographic scans)",
"GAIN 0.0 # detector gain in e-/ADU",
"GAIN_KEY GAIN # keyword for detector gain in e-/ADU",
"PIXEL_SCALE 1.0 # size of pixel in arcsec (0=use FITS WCS info)",
" ",
"#------------------------- Star/Galaxy Separation ----------------------------",
......@@ -252,7 +260,7 @@ char *default_prefs[] =
"*ASSOC_DATA 2,3,4 # columns of the data to replicate (0=all)",
"*ASSOC_PARAMS 2,3,4 # columns of xpos,ypos[,mag]",
"*ASSOC_RADIUS 2.0 # cross-matching radius (pixels)",
"*ASSOC_TYPE MAG_SUM # ASSOCiation method: FIRST, NEAREST, MEAN,",
"*ASSOC_TYPE NEAREST # ASSOCiation method: FIRST, NEAREST, MEAN,",
"* # MAG_MEAN, SUM, MAG_SUM, MIN or MAX",
"*ASSOCSELEC_TYPE MATCHED # ASSOC selection type: ALL, MATCHED or -MATCHED",
"*",
......@@ -264,7 +272,7 @@ char *default_prefs[] =
"*XSL_URL " XSL_URL,
"* # Filename for XSL style-sheet",
#ifdef USE_THREADS
"*NTHREADS 0 # Number of simultaneous threads for",
"NTHREADS 0 # Number of simultaneous threads for",
"* # the SMP version of " BANNER,
"* # 0 = automatic",
#else
......@@ -281,6 +289,8 @@ char *default_prefs[] =
"*PSF_NAME default.psf # File containing the PSF model",
"*PSF_NMAX 9 # Max.number of PSFs fitted simultaneously",
"*PSFDISPLAY_TYPE SPLIT # Catalog type for PSF-fitting: SPLIT or VECTOR",
"*PATTERN_TYPE RINGS-HARMONIC # can RINGS-QUADPOLE, RINGS-OCTOPOLE,",
"* # RINGS-HARMONICS or GAUSS-LAGUERRE",
"*SOM_NAME default.som # File containing Self-Organizing Map weights",
""
};
......@@ -9,7 +9,7 @@
*
* Contents: Functions to handle the configuration file.
*
* Last modify: 12/01/2006
* Last modify: 19/09/2008
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
......@@ -23,6 +23,14 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#if defined(USE_THREADS) \
&& (defined(__APPLE__) || defined(FREEBSD) || defined(NETBSD)) /* BSD, Apple */
#include <sys/types.h>
#include <sys/sysctl.h>
#elif defined(USE_THREADS) && defined(HAVE_MPCTL) /* HP/UX */
#include <sys/mpctl.h>
#endif
#include "define.h"
#include "globals.h"
......@@ -370,6 +378,68 @@ int cistrcmp(char *cs, char *ct, int mode)
}
/********************************* preprefs **********************************/
/*
Set number of threads and endianity.
*/
void preprefs()
{
unsigned short ashort=1;
#ifdef USE_THREADS
int nproc;
#endif
/* Test if byteswapping will be needed */
bswapflag = *((char *)&ashort);
/* Multithreading */
#ifdef USE_THREADS
if (!prefs.nthreads)
{
/*-- Get the number of processors for parallel builds */
/*-- See, e.g. http://ndevilla.free.fr/threads */
nproc = -1;
#if defined(_SC_NPROCESSORS_ONLN) /* AIX, Solaris, Linux */
nproc = (int)sysconf(_SC_NPROCESSORS_ONLN);
#elif defined(_SC_NPROCESSORS_CONF)
nproc = (int)sysconf(_SC_NPROCESSORS_CONF);
#elif defined(__APPLE__) || defined(FREEBSD) || defined(NETBSD) /* BSD, Apple */
{
int mib[2];
size_t len;
mib[0] = CTL_HW;
mib[1] = HW_NCPU;
len = sizeof(nproc);
sysctl(mib, 2, &nproc, &len, NULL, 0);
}
#elif defined (_SC_NPROC_ONLN) /* SGI IRIX */
nproc = sysconf(_SC_NPROC_ONLN);
#elif defined(HAVE_MPCTL) /* HP/UX */
nproc = mpctl(MPC_GETNUMSPUS_SYS, 0, 0);
#endif
if (nproc>0)
prefs.nthreads = nproc;
else
{
prefs.nthreads = 2;
warning("Cannot find the number of CPUs on this system:",
"NTHREADS defaulted to 2");
}
}
#else
if (prefs.nthreads != 1)
{
prefs.nthreads = 1;
warning("NTHREADS != 1 ignored: ",
"this build of " BANNER " is single-threaded");
}
#endif
}
/********************************* useprefs **********************************/
/*
Update various structures according to the prefs.
......@@ -377,13 +447,9 @@ Update various structures according to the prefs.
void useprefs()
{
unsigned short ashort=1;
int i, margin, naper;
char *str;
/* Test if byteswapping will be needed */
bswapflag = *((char *)&ashort);
/*-------------------------------- Images ----------------------------------*/
prefs.dimage_flag = (prefs.nimage_name>1);
......@@ -402,9 +468,10 @@ void useprefs()
prefs.world_flag = FLAG(obj2.mxw) || FLAG(obj2.mamaposx)
|| FLAG(obj2.peakxw) || FLAG(obj2.winpos_xw)
|| FLAG(obj2.mx2w) || FLAG(obj2.win_mx2w)
|| FLAG(obj2.xw_prof) || FLAG(obj2.poserrmx2w_prof)
|| FLAG(obj2.poserr_mx2w) || FLAG(obj2.winposerr_mx2w)
|| FLAG(obj2.npixw) || FLAG(obj2.fdnpixw)
|| FLAG(obj2.fwhmw);
|| FLAG(obj2.fwhmw) || FLAG(obj2.prof_flagw);
/* Default astrometric settings */
strcpy(prefs.coosys, "ICRS");
prefs.epoch = 2000.0;
......@@ -514,6 +581,20 @@ void useprefs()
prefs.pc_flag = 1;
}
/*-------------------------- Profile-fitting -------------------------------*/
if (prefs.check_flag)
for (i=0; i<prefs.ncheck_type; i++)
if (prefs.check_type[i] == CHECK_SUBPROFILES
|| prefs.check_type[i] == CHECK_PROFILES)
prefs.prof_flag = 1;
/*-------------------------- Pattern-fitting -------------------------------*/
/* Profile-fitting is possible only if a PSF file is loaded */
if (prefs.check_flag)
for (i=0; i<prefs.ncheck_type; i++)
if (prefs.check_type[i] == CHECK_PATTERNS)
prefs.pattern_flag = 1;
/*----------------------------- WEIGHT-images ------------------------------*/
if (prefs.nweight_type<2)
prefs.weight_type[1] = prefs.weight_type[0];
......@@ -598,3 +679,23 @@ void useprefs()
}
/********************************* endprefs *********************************/
/*
Mostly free memory allocate for static arrays.
*/
void endprefs(void)
{
int i;
for (i=0; i<prefs.nfimage_name; i++)
free(prefs.fimage_name[i]);
for (i=0; i<prefs.nwimage_name; i++)
free(prefs.wimage_name[i]);
for (i=0; i<prefs.npsf_name; i++)
free(prefs.psf_name[i]);
for (i=0; i<prefs.ncheck_name; i++)
free(prefs.check_name[i]);
return;
}
......@@ -9,11 +9,20 @@
*
* Contents: Keywords for the configuration file.
*
* Last modify: 13/07/2006
* Last modify: 20/11/2008
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
#ifndef _PROFIT_H_
#include "profit.h"
#endif
#ifndef _PATTERN_H_
#include "pattern.h"
#endif
#ifndef _PREFS_H_
#define _PREFS_H_
......@@ -51,6 +60,7 @@ typedef struct
int nfilter_thresh; /* nb of params */
int deblend_nthresh; /* threshold number */
double deblend_mincont; /* minimum contrast */
char satur_key[8]; /* saturation keyword */
double satur_level; /* saturation level */
enum {CCD, PHOTO} detect_type; /* detection type */
/*----- Flagging */
......@@ -91,6 +101,7 @@ typedef struct
double mag_zeropoint; /* magnitude offsets */
double mag_gamma; /* for emulsions */
double gain; /* only for CCD */
char gain_key[8]; /* gain keyword */
/*----- S/G separation */
double pixel_scale; /* in arcsec */
double seeing_fwhm; /* in arcsec */
......@@ -199,6 +210,19 @@ typedef struct
int psf_magerrsize; /* nb of params */
int pc_flag; /* PC-fit needed */
int pc_vectorsize; /* nb of params */
int prof_flag; /* Profile-fitting */
int pattern_flag; /* Pattern-fitting */
/*----- Profile-fitting */
int prof_vectorsize; /* nb of params */
int prof_errvectorsize; /* nb of params */
int prof_disk_patternvectorsize; /* nb of params */
int prof_disk_patternncomp; /* nb of params */
int prof_disk_patternmodvectorsize; /* nb of params */
int prof_disk_patternmodncomp; /* nb of params */
int prof_disk_patternargvectorsize; /* nb of params */
int prof_disk_patternargncomp; /* nb of params */
/*----- Pattern-fitting */
pattypenum pattern_type; /* Disk pattern type */
/*----- customize */
int fitsunsigned_flag; /* Force unsign FITS */
int next; /* Number of extensions in file */
......@@ -212,6 +236,8 @@ typedef struct
extern int cistrcmp(char *cs, char *ct, int mode);
extern void dumpprefs(int state),
endprefs(void),
preprefs(void),
readprefs(char *filename,char **argkey,char **argval,int narg),
useprefs(void);
#endif
/*
profit.c
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: SExtractor
*
* Authors: E.BERTIN (IAP)
*
* Contents: Fit an arbitrary profile combination to a detection.
*
* Last modify: 20/11/2008
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_MATHIMF_H
#include <mathimf.h>
#else
#define _GNU_SOURCE
#include <math.h>
#endif
#ifdef HAVE_LOGF
#define LOGF logf
#else
#define LOGF log
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "define.h"
#include "globals.h"
#include "prefs.h"
#include "fits/fitscat.h"
#include "levmar/lm.h"
#include "fft.h"
#include "fitswcs.h"
#include "check.h"
#include "pattern.h"
#include "psf.h"
#include "profit.h"
static double prof_interpolate(profstruct *prof, double *posin);
static double interpolate_pix(double *posin, double *pix, int *naxisn,
interpenum interptype);
static void make_kernel(double pos, double *kernel, interpenum interptype);
/*------------------------------- variables ---------------------------------*/
char profname[][32]={"background offset", "Sersic spheroid",
"De Vaucouleurs spheroid", "exponential disk", "spiral arms",
"bar", "inner ring", "outer ring", "tabulated model",
""};
int interp_kernwidth[5]={1,2,4,6,8};
int theniter, the_gal;
/* "Local" global variables; it seems dirty but it simplifies a lot */
/* interfacing to the LM routines */
static picstruct *the_field, *the_wfield;
profitstruct *theprofit;
/****** profit_init ***********************************************************
PROTO profitstruct profit_init(psfstruct *psf)
PURPOSE Allocate and initialize a new profile-fitting structure.
INPUT Pointer to PSF structure.
OUTPUT A pointer to an allocated profit structure.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 26/04/2008
***/
profitstruct *profit_init(psfstruct *psf)
{
profitstruct *profit;
int p, nprof,
backflag, spheroidflag, diskflag, barflag, armsflag;
QCALLOC(profit, profitstruct, 1);
profit->psf = psf;
profit->psfdft = NULL;
profit->nparam = 0;
QMALLOC(profit->prof, profstruct *, PROF_NPROF);
backflag = spheroidflag = diskflag = barflag = armsflag = 0;
nprof = 0;
for (p=0; p<PROF_NPROF; p++)
if (!backflag && FLAG(obj2.prof_offset_flux))
{
profit->prof[p] = prof_init(profit, PROF_BACK);
backflag = 1;
nprof++;
}
else if (!spheroidflag && FLAG(obj2.prof_spheroid_flux))
{
profit->prof[p] = prof_init(profit,
FLAG(obj2.prof_spheroid_sersicn)? PROF_SERSIC : PROF_DEVAUCOULEURS);
spheroidflag = 1;
nprof++;
}
else if (!diskflag && FLAG(obj2.prof_disk_flux))
{
profit->prof[p] = prof_init(profit, PROF_EXPONENTIAL);
diskflag = 1;
nprof++;
}
else if (diskflag && !barflag && FLAG(obj2.prof_bar_flux))
{
profit->prof[p] = prof_init(profit, PROF_BAR);
barflag = 1;
nprof++;
}
else if (barflag && !armsflag && FLAG(obj2.prof_arms_flux))
{
profit->prof[p] = prof_init(profit, PROF_ARMS);
armsflag = 1;
nprof++;
}
QMALLOC(profit->covar, double, profit->nparam*profit->nparam);
profit->nprof = nprof;
return profit;
}
/****** profit_end ************************************************************
PROTO void prof_end(profstruct *prof)
PURPOSE End (deallocate) a profile-fitting structure.
INPUT Prof structure.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 26/04/2008
***/
void profit_end(profitstruct *profit)
{
int p;
for (p=0; p<profit->nprof; p++)
prof_end(profit->prof[p]);
free(profit->prof);
free(profit->covar);
free(profit->psfdft);
free(profit);
return;
}
/****** profit_fit ************************************************************
PROTO void profit_fit(profitstruct *profit, picstruct *field,
picstruct *wfield, objstruct *obj, obj2struct *obj2)
PURPOSE Fit profile(s) convolved with the PSF to a detected object.
INPUT Array of profile structures,
Number of profiles,
Pointer to the profile-fitting structure,
Pointer to the field,
Pointer to the field weight,
Pointer to the obj.
OUTPUT Pointer to an allocated fit structure (containing details about the
fit).
NOTES It is a modified version of the lm_minimize() of lmfit.
AUTHOR E. Bertin (IAP)
VERSION 20/11/2008
***/
void profit_fit(profitstruct *profit,
picstruct *field, picstruct *wfield,
objstruct *obj, obj2struct *obj2)
{
patternstruct *pattern;
psfstruct *psf;
checkstruct *check;
double *oldparaminit,
psf_fwhm, oldchi2, a , cp,sp, emx2,emy2,emxy;
int i,j,p, oldniter, nparam, ncomp;
nparam = profit->nparam;
if (profit->psfdft)
{
QFREE(profit->psfdft);
}
psf = profit->psf;
profit->pixstep = psf->pixstep;
/* Create pixmaps at image resolution */
psf_fwhm = psf->masksize[0]*psf->pixstep;
profit->objnaxisn[0] = (((int)((obj->xmax-obj->xmin+1) + psf_fwhm + 0.499)
*1.2)/2)*2 + 1;
profit->objnaxisn[1] = (((int)((obj->ymax-obj->ymin+1) + psf_fwhm + 0.499)
*1.2)/2)*2 + 1;
profit->ix = (int)(obj->mx + 0.49999);/* internal convention: 1st pix = 0 */
profit->iy = (int)(obj->my + 0.49999);/* internal convention: 1st pix = 0 */
if (profit->objnaxisn[1]<profit->objnaxisn[0])
profit->objnaxisn[1] = profit->objnaxisn[0];
else
profit->objnaxisn[0] = profit->objnaxisn[1];
/* Use (dirty) global variables to interface with lmfit */
the_field = field;
the_wfield = wfield;
theprofit = profit;
profit->obj = obj;
profit->obj2 = obj2;
QMALLOC(profit->objpix, PIXTYPE, profit->objnaxisn[0]*profit->objnaxisn[1]);
QMALLOC(profit->objweight, PIXTYPE,profit->objnaxisn[0]*profit->objnaxisn[1]);
QMALLOC(profit->lmodpix, PIXTYPE, profit->objnaxisn[0]*profit->objnaxisn[1]);
profit->nresi = profit_copyobjpix(profit, field, wfield);
if (profit->nresi < nparam)
{
for (p=0; p<nparam; p++)
obj2->prof_vector[p] = 0.0;
obj2->prof_niter = 0;
return;
}
QMALLOC(profit->resi, double, profit->nresi);
/* Create pixmap at PSF resolution */
profit->modnaxisn[0] =
((int)(profit->objnaxisn[0]/profit->pixstep +0.4999)/2+1)*2;
profit->modnaxisn[1] =
((int)(profit->objnaxisn[1]/profit->pixstep +0.4999)/2+1)*2;
if (profit->modnaxisn[1] < profit->modnaxisn[0])
profit->modnaxisn[1] = profit->modnaxisn[0];
else
profit->modnaxisn[0] = profit->modnaxisn[1];
/* Allocate memory for the complete model */
QCALLOC(profit->modpix, double, profit->modnaxisn[0]*profit->modnaxisn[1]);
QMALLOC(profit->psfpix, double, profit->modnaxisn[0]*profit->modnaxisn[1]);
/* Allocate memory for the partial model */
QMALLOC(profit->pmodpix, float, profit->modnaxisn[0]*profit->modnaxisn[1]);
/* Compute the local PSF */
profit_psf(profit);
/* Set initial guesses and boundaries */
obj2->prof_flag = 0;
profit->sigma = obj->sigbkg;
profit_resetparams(profit);
//for (p=0; p<nparam; p++)
//printf("%g ", profit->paraminit[p]);
//printf("\n");
the_gal++;
/* Actual minimisation */
profit->niter = profit_minimize(profit, PROFIT_MAXITER);
QMEMCPY(profit->paraminit, oldparaminit, double, nparam);
if (profit_setparam(profit, PARAM_ARMS_PITCH, 160.0, 130.0, 175.0)==RETURN_OK)
{
oldchi2 = profit->chi2;
oldniter = profit->niter;
profit_resetparams(profit);
profit_setparam(profit, PARAM_ARMS_PITCH, 160.0, 130.0, 175.0);
profit->niter = profit_minimize(profit, PROFIT_MAXITER);
if (profit->chi2 > oldchi2)
{
memcpy(profit->paraminit, oldparaminit, nparam*sizeof(double));
profit->chi2 = oldchi2;
profit->niter = oldniter;
}
else
obj2->prof_flag |= PROFIT_FLIPPED;
}
/* Convert covariance matrix to bound space */
profit_covarunboundtobound(profit);
for (p=0; p<nparam; p++)
profit->paramerr[p]= sqrt(profit->covar[p*(nparam+1)]);
/* Equate param and paraminit vectors to avoid confusion later on */
for (p=0; p<profit->nparam; p++)
profit->param[p] = profit->paraminit[p];
//printf("--> ");
//for (p=0; p<profit->nparam; p++)
//printf("%g %g %g\n", profit->param[p], profit->parammin[p], profit->parammax[p]);
//printf("(%d)\n", profit->niter);
/* CHECK-Images */
if ((check = prefs.check[CHECK_SUBPROFILES]))
{
profit_residuals(profit,field,wfield,profit->param,profit->resi);
addcheck(check, profit->lmodpix, profit->objnaxisn[0],profit->objnaxisn[1],
profit->ix,profit->iy, -1.0);
}
if ((check = prefs.check[CHECK_PROFILES]))
{
profit_residuals(profit,field,wfield,profit->param,profit->resi);
addcheck(check, profit->lmodpix, profit->objnaxisn[0],profit->objnaxisn[1],
profit->ix,profit->iy, 1.0);
}
/* Fill measurement parameters */
if (FLAG(obj2.prof_vector))
{
for (p=0; p<nparam; p++)
obj2->prof_vector[p]= profit->param[p];
}
if (FLAG(obj2.prof_errvector))
{
for (p=0; p<nparam; p++)
obj2->prof_errvector[p]= profit->paramerr[p];
}
obj2->prof_niter = profit->niter;
obj2->flux_prof = profit->flux;
obj2->prof_chi2 = profit->chi2;
if (FLAG(obj2.x_prof))
{
i = profit->paramindex[PARAM_X];
j = profit->paramindex[PARAM_Y];
/*-- Model coordinates follow the FITS convention (first pixel at 1,1) */
obj2->x_prof = profit->ix + *profit->paramlist[PARAM_X] + 1.0;
obj2->y_prof = profit->iy + *profit->paramlist[PARAM_Y] + 1.0;
obj2->poserrmx2_prof = emx2 = profit->covar[i*(nparam+1)];
obj2->poserrmy2_prof = emy2 = profit->covar[j*(nparam+1)];
obj2->poserrmxy_prof = emxy = profit->covar[i+j*nparam];
/*-- Error ellipse parameters */
if (FLAG(obj2.poserra_prof))
{
double pmx2,pmy2,temp,theta;
if (fabs(temp=emx2-emy2) > 0.0)
theta = atan2(2.0 * emxy,temp) / 2.0;
else
theta = PI/4.0;
temp = sqrt(0.25*temp*temp+ emxy*emxy);
pmy2 = pmx2 = 0.5*(emx2+emy2);
pmx2+=temp;
pmy2-=temp;
obj2->poserra_prof = (float)sqrt(pmx2);
obj2->poserrb_prof = (float)sqrt(pmy2);
obj2->poserrtheta_prof = theta*180.0/PI;
}
if (FLAG(obj2.poserrcxx_prof))
{
double temp;
obj2->poserrcxx_prof = (float)(emy2/(temp=emx2*emy2-emxy*emxy));
obj2->poserrcyy_prof = (float)(emx2/temp);
obj2->poserrcxy_prof = (float)(-2*emxy/temp);
}
}
if (FLAG(obj2.prof_mx2))
{
memset(profit->modpix, 0,
profit->modnaxisn[0]*profit->modnaxisn[1]*sizeof(double));
for (p=0; p<profit->nprof; p++)
prof_add(profit->prof[p], profit);
profit_moments(profit);
}
/* Bulge */
if (FLAG(obj2.prof_spheroid_flux))
{
obj2->prof_spheroid_flux = *profit->paramlist[PARAM_SPHEROID_FLUX];
obj2->prof_spheroid_fluxerr =
profit->paramerr[profit->paramindex[PARAM_SPHEROID_FLUX]];
obj2->prof_spheroid_reff = *profit->paramlist[PARAM_SPHEROID_REFF];
obj2->prof_spheroid_refferr =
profit->paramerr[profit->paramindex[PARAM_SPHEROID_REFF]];
obj2->prof_spheroid_aspect = *profit->paramlist[PARAM_SPHEROID_ASPECT];
obj2->prof_spheroid_aspecterr =
profit->paramerr[profit->paramindex[PARAM_SPHEROID_ASPECT]];
obj2->prof_spheroid_theta =
fmod_m90_p90(*profit->paramlist[PARAM_SPHEROID_POSANG]);
obj2->prof_spheroid_thetaerr =
profit->paramerr[profit->paramindex[PARAM_SPHEROID_POSANG]];
if (FLAG(obj2.prof_spheroid_sersicn))
{
obj2->prof_spheroid_sersicn = *profit->paramlist[PARAM_SPHEROID_SERSICN];
obj2->prof_spheroid_sersicnerr =
profit->paramerr[profit->paramindex[PARAM_SPHEROID_SERSICN]];
}
}
/* Disk */
if (FLAG(obj2.prof_disk_flux))
{
obj2->prof_disk_flux = *profit->paramlist[PARAM_DISK_FLUX];
obj2->prof_disk_fluxerr =
profit->paramerr[profit->paramindex[PARAM_DISK_FLUX]];
obj2->prof_disk_scale = *profit->paramlist[PARAM_DISK_SCALE];
obj2->prof_disk_scaleerr =
profit->paramerr[profit->paramindex[PARAM_DISK_SCALE]];
obj2->prof_disk_aspect = *profit->paramlist[PARAM_DISK_ASPECT];
obj2->prof_disk_aspecterr =
profit->paramerr[profit->paramindex[PARAM_DISK_ASPECT]];
obj2->prof_disk_theta = fmod_m90_p90(*profit->paramlist[PARAM_DISK_POSANG]);
obj2->prof_disk_thetaerr =
profit->paramerr[profit->paramindex[PARAM_DISK_POSANG]];
if (FLAG(obj2.prof_disk_inclination))
{
obj2->prof_disk_inclination = acos(obj2->prof_disk_aspect) / DEG;
if (FLAG(obj2.prof_disk_inclinationerr))
{
a = sqrt(1.0-obj2->prof_disk_aspect*obj2->prof_disk_aspect);
obj2->prof_disk_inclinationerr = obj2->prof_disk_aspecterr
/(a>0.1? a : 0.1)/DEG;
}
}
/* Disk pattern */
if (prefs.pattern_flag)
{
profit_residuals(profit,field,wfield,profit->param,profit->resi);
pattern = pattern_init(profit, prefs.pattern_type,
prefs.prof_disk_patternncomp);
pattern_fit(pattern, profit);
if (FLAG(obj2.prof_disk_patternspiral))
obj2->prof_disk_patternspiral = pattern_spiral(pattern);
if (FLAG(obj2.prof_disk_patternvector))
{
ncomp = pattern->size[2];
for (p=0; p<ncomp; p++)
obj2->prof_disk_patternvector[p] = (float)pattern->coeff[p];
}
if (FLAG(obj2.prof_disk_patternmodvector))
{
ncomp = pattern->ncomp*pattern->nfreq;
for (p=0; p<ncomp; p++)
obj2->prof_disk_patternmodvector[p] = (float)pattern->mcoeff[p];
}
if (FLAG(obj2.prof_disk_patternargvector))
{
ncomp = pattern->ncomp*pattern->nfreq;
for (p=0; p<ncomp; p++)
obj2->prof_disk_patternargvector[p] = (float)pattern->acoeff[p];
}
pattern_end(pattern);
}
/* Bar */
if (FLAG(obj2.prof_bar_flux))
{
obj2->prof_bar_flux = *profit->paramlist[PARAM_BAR_FLUX];
obj2->prof_bar_fluxerr =
profit->paramerr[profit->paramindex[PARAM_BAR_FLUX]];
obj2->prof_bar_length = *profit->paramlist[PARAM_ARMS_START]
**profit->paramlist[PARAM_DISK_SCALE];
obj2->prof_bar_lengtherr = *profit->paramlist[PARAM_ARMS_START]
* profit->paramerr[profit->paramindex[PARAM_DISK_SCALE]]
+ *profit->paramlist[PARAM_DISK_SCALE]
* profit->paramerr[profit->paramindex[PARAM_ARMS_START]];
obj2->prof_bar_aspect = *profit->paramlist[PARAM_BAR_ASPECT];
obj2->prof_bar_aspecterr =
profit->paramerr[profit->paramindex[PARAM_BAR_ASPECT]];
obj2->prof_bar_posang =
fmod_m90_p90(*profit->paramlist[PARAM_ARMS_POSANG]);
obj2->prof_bar_posangerr =
profit->paramerr[profit->paramindex[PARAM_ARMS_POSANG]];
if (FLAG(obj2.prof_bar_theta))
{
cp = cos(obj2->prof_bar_posang*DEG);
sp = sin(obj2->prof_bar_posang*DEG);
a = obj2->prof_disk_aspect;
obj2->prof_bar_theta = fmod_m90_p90(atan2(a*sp,cp)/DEG
+ obj2->prof_disk_theta);
obj2->prof_bar_thetaerr = obj2->prof_bar_posangerr*a/(cp*cp+a*a*sp*sp);
}
/* Arms */
if (FLAG(obj2.prof_arms_flux))
{
obj2->prof_arms_flux = *profit->paramlist[PARAM_ARMS_FLUX];
obj2->prof_arms_fluxerr =
profit->paramerr[profit->paramindex[PARAM_ARMS_FLUX]];
obj2->prof_arms_pitch =
fmod_m90_p90(*profit->paramlist[PARAM_ARMS_PITCH]);
obj2->prof_arms_pitcherr =
profit->paramerr[profit->paramindex[PARAM_ARMS_PITCH]];
obj2->prof_arms_start = *profit->paramlist[PARAM_ARMS_START]
**profit->paramlist[PARAM_DISK_SCALE];
obj2->prof_arms_starterr = *profit->paramlist[PARAM_ARMS_START]
* profit->paramerr[profit->paramindex[PARAM_DISK_SCALE]]
+ *profit->paramlist[PARAM_DISK_SCALE]
* profit->paramerr[profit->paramindex[PARAM_ARMS_START]];
obj2->prof_arms_quadfrac = *profit->paramlist[PARAM_ARMS_QUADFRAC];
obj2->prof_arms_quadfracerr =
profit->paramerr[profit->paramindex[PARAM_ARMS_QUADFRAC]];
obj2->prof_arms_posang =
fmod_m90_p90(*profit->paramlist[PARAM_ARMS_POSANG]);
obj2->prof_arms_posangerr =
profit->paramerr[profit->paramindex[PARAM_ARMS_POSANG]];
}
}
}
/* clean up. */
free(profit->modpix);
free(profit->psfpix);
free(profit->pmodpix);
free(profit->lmodpix);
free(profit->objpix);
free(profit->objweight);
free(profit->resi);
free(oldparaminit);
//for (ix=0; ix<profit->nparam;ix++)
//printf("%10.5f ", sqrt(profit->covar[ix*profit->nparam+ix]));
//printf("\n");
return;
}
/****** profit_psf ************************************************************
PROTO void profit_psf(profitstruct *profit)
PURPOSE Build the local PSF at a given resolution.
INPUT Profile-fitting structure.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 22/10/2008
***/
void profit_psf(profitstruct *profit)
{
double posin[2], posout[2], dnaxisn[2],
*pixout,
xcout,ycout, xcin,ycin, invpixstep, flux, norm;
int d,i;
psf = profit->psf;
psf_build(psf);
xcout = (double)(profit->modnaxisn[0]/2) + 1.0; /* FITS convention */
ycout = (double)(profit->modnaxisn[1]/2) + 1.0; /* FITS convention */
xcin = (psf->masksize[0]/2) + 1.0; /* FITS convention */
ycin = (psf->masksize[1]/2) + 1.0; /* FITS convention */
invpixstep = profit->pixstep / psf->pixstep;
/* Initialize multi-dimensional counters */
for (d=0; d<2; d++)
{
posout[d] = 1.0; /* FITS convention */
dnaxisn[d] = profit->modnaxisn[d]+0.5;
}
/* Remap each pixel */
pixout = profit->psfpix;
flux = 0.0;
for (i=profit->modnaxisn[0]*profit->modnaxisn[1]; i--;)
{
posin[0] = (posout[0] - xcout)*invpixstep + xcin;
posin[1] = (posout[1] - ycout)*invpixstep + ycin;
flux += ((*(pixout++) = interpolate_pix(posin, psf->maskloc,
psf->masksize, INTERP_LANCZOS3)));
for (d=0; d<2; d++)
if ((posout[d]+=1.0) < dnaxisn[d])
break;
else
posout[d] = 1.0;
}
/* Normalize PSF flux (just in case...) */
flux *= psf->pixstep*psf->pixstep;
if (fabs(flux) > 0.0)
{
norm = 1.0/flux;
pixout = profit->psfpix;
for (i=profit->modnaxisn[0]*profit->modnaxisn[1]; i--;)
*(pixout++) *= norm;
}
return;
}
/****** profit_findinit *******************************************************
PROTO void profit_findinit(profitstruct *profit)
PURPOSE Find a suitable set of initialisation parameters
INPUT Pointer to the profit structure involved in the fit.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 16/04/2008
***/
void profit_findinit(profitstruct *profit)
{
int p;
for (p=0; p<profit->nprof; p++)
switch (profit->prof[p]->code)
{
default:
break;
}
return;
}
/****** profit_minimize *******************************************************
PROTO void profit_minimize(profitstruct *profit)
PURPOSE Provide a function returning residuals to lmfit.
INPUT Pointer to the profit structure involved in the fit,
maximum number of iterations.
OUTPUT Number of iterations used.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 23/05/2008
***/
int profit_minimize(profitstruct *profit, int niter)
{
double lm_opts[5], info[LM_INFO_SZ];
int m,n;
/* Allocate work space */
n = profit->nparam;
m = profit->nresi;
memset(profit->resi, 0, profit->nresi*sizeof(double));
memset(profit->covar, 0, profit->nparam*profit->nparam*sizeof(double));
profit_boundtounbound(profit, profit->paraminit);
/* Perform fit */
lm_opts[0] = 1.0e-3;
lm_opts[1] = 1.0e-17;
lm_opts[2] = 1.0e-17;
lm_opts[3] = 1.0e-17;
lm_opts[4] = 1.0e-6;
niter = dlevmar_dif(profit_evaluate, profit->paraminit, profit->resi,
n, m, niter, lm_opts, info, NULL, profit->covar, profit);
profit_unboundtobound(profit, profit->paraminit);
return niter;
}
/****** profit_printout *******************************************************
PROTO void profit_printout(int n_par, double* par, int m_dat, double* fvec,
void *data, int iflag, int iter, int nfev )
PURPOSE Provide a function to print out results to lmfit.
INPUT Number of fitted parameters,
pointer to the vector of parameters,
number of data points,
pointer to the vector of residuals (output),
pointer to the data structure (unused),
0 (init) 1 (outer loop) 2(inner loop) -1(terminated),
outer loop counter,
number of calls to evaluate().
OUTPUT -.
NOTES Input arguments are there only for compatibility purposes (unused)
AUTHOR E. Bertin (IAP)
VERSION 17/09/2008
***/
void profit_printout(int n_par, double* par, int m_dat, double* fvec,
void *data, int iflag, int iter, int nfev )
{
checkstruct *check;
profitstruct *profit;
char filename[256];
static int itero;
profit = (profitstruct *)data;
if (0 && (iter!=itero || iter<0))
{
if (iter<0)
itero++;
else
itero = iter;
sprintf(filename, "check_%d_%04d.fits", the_gal, itero);
check=initcheck(filename, CHECK_PROFILES, 0);
reinitcheck(the_field, check);
addcheck(check, profit->lmodpix, profit->objnaxisn[0],profit->objnaxisn[1],
profit->ix,profit->iy, 1.0);
reendcheck(the_field, check);
endcheck(check);
}
return;
}
/****** profit_evaluate ******************************************************
PROTO void profit_evaluate(double *par, double *fvec, int m, int n,
void *adata)
PURPOSE Provide a function returning residuals to levmar.
INPUT Pointer to the vector of parameters,
pointer to the vector of residuals (output),
number of model parameters,
number of data points,
pointer to a data structure (unused).
OUTPUT -.
NOTES Input arguments are there only for compatibility purposes (unused)
AUTHOR E. Bertin (IAP)
VERSION 18/09/2008
***/
void profit_evaluate(double *par, double *fvec, int m, int n,
void *adata)
{
profitstruct *profit;
profit = (profitstruct *)adata;
profit_unboundtobound(profit, par);
profit_residuals(profit, the_field, the_wfield, par, fvec);
profit_boundtounbound(profit, par);
profit_printout(m, par, n, fvec, adata, 0, -1, 0 );
return;
}
/****** profit_residuals ******************************************************
PROTO double *prof_residuals(profitstruct *profit, picstruct *field,
picstruct *wfield, double *param, double *resi)
PURPOSE Compute the vector of residuals between the data and the galaxy
profile model.
INPUT Profile-fitting structure,
pointer to the field,
pointer to the field weight,
pointer to the obj,
pointer to the model parameters (output),
pointer to the computed residuals (output).
OUTPUT Vector of residuals.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 15/09/2008
***/
double *profit_residuals(profitstruct *profit, picstruct *field,
picstruct *wfield, double *param, double *resi)
{
int p;
memset(profit->modpix, 0,
profit->modnaxisn[0]*profit->modnaxisn[1]*sizeof(double));
for (p=0; p<profit->nparam; p++)
profit->param[p] = param[p];
for (p=0; p<profit->nprof; p++)
prof_add(profit->prof[p], profit);
profit_convolve(profit, profit->modpix);
profit_resample(profit, profit->modpix, profit->lmodpix);
profit_compresi(profit, resi);
return resi;
}
/****** profit_compresi ******************************************************
PROTO double *prof_compresi(profitstruct *profit, double *resi)
PURPOSE Compute the vector of residuals between the data and the galaxy
profile model.
INPUT Profile-fitting structure,
pointer to the obj,
vector of residuals (output).
OUTPUT Vector of residuals.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 18/09/2008
***/
double *profit_compresi(profitstruct *profit, double *resi)
{
double *resit,
error, x1c,x1,x2,rmin;
PIXTYPE *objpix, *objweight, *lmodpix,
val,val2,wval, invsig;
int npix, ix1,ix2;
/* Compute vector of residuals */
npix = profit->objnaxisn[0]*profit->objnaxisn[1];
resit = resi;
objpix = profit->objpix;
objweight = profit->objweight;
lmodpix = profit->lmodpix;
invsig = 1.0/PROFIT_DYNPARAM;
error = 0.0;
x1c = (double)(profit->objnaxisn[0]/2);
rmin = profit->obj2->hl_radius / 2.0;
x2 = -(double)(profit->objnaxisn[1]/2);
for (ix2=profit->objnaxisn[1]; ix2--; x2+=1.0)
{
x1 = -x1c;
for (ix1=profit->objnaxisn[0]; ix1--; x1+=1.0, lmodpix++)
{
val = *(objpix++);
if ((wval=*(objweight++))>0.0)
{
val2 = (double)(val - *lmodpix)*wval*invsig;
val2 = val2>0.0? LOGF(1.0+val2) : -LOGF(1.0-val2);
*(resit++) = val2*PROFIT_DYNPARAM;
// *(resit++) = val2*(rmin/(sqrt(r2)+rmin));
error += val2*val2;
}
}
}
profit->chi2 = PROFIT_DYNPARAM*PROFIT_DYNPARAM*error/npix;
return resi;
}
/****** profit_resample ******************************************************
PROTO void prof_resample(profitstruct *profit, double *inpix,
PIXTYPE *outpix)
PURPOSE Resample the current full resolution model to image resolution.
INPUT Profile-fitting structure.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 15/09/2008
***/
void profit_resample(profitstruct *profit, double *inpix, PIXTYPE *outpix)
{
double posin[2], posout[2], dnaxisn[2],
*dx,*dy,
xcout,ycout, xcin,ycin, invpixstep, flux;
int d,i;
xcout = (double)(profit->objnaxisn[0]/2) + 1.0; /* FITS convention */
if ((dx=(profit->paramlist[PARAM_X])))
xcout += *dx;
ycout = (double)(profit->objnaxisn[1]/2) + 1.0; /* FITS convention */
if ((dy=(profit->paramlist[PARAM_Y])))
ycout += *dy;
xcin = (profit->modnaxisn[0]/2) + 1.0; /* FITS convention */
ycin = (profit->modnaxisn[1]/2) + 1.0; /* FITS convention */
invpixstep = 1.0/profit->pixstep;
/* Initialize multi-dimensional counters */
for (d=0; d<2; d++)
{
posout[d] = 1.0; /* FITS convention */
dnaxisn[d] = profit->objnaxisn[d]+0.5;
}
/* Remap each pixel */
flux = 0.0;
for (i=profit->objnaxisn[0]*profit->objnaxisn[1]; i--;)
{
posin[0] = (posout[0] - xcout)*invpixstep + xcin;
posin[1] = (posout[1] - ycout)*invpixstep + ycin;
flux += ((*(outpix++) = (PIXTYPE)(interpolate_pix(posin, inpix,
profit->modnaxisn, INTERP_LANCZOS3))));
for (d=0; d<2; d++)
if ((posout[d]+=1.0) < dnaxisn[d])
break;
else
posout[d] = 1.0;
}
profit->flux = flux;
return;
}
/****** profit_convolve *******************************************************
PROTO void profit_convolve(profitstruct *profit, double *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, double *modpix)
{
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;
double *mask,*maskt, *ppix;
double 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, double, npix);
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:exp((2*rmin*sqrt(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:exp((2*rmin*sqrt(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:exp((2*rmin*sqrt(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:exp((2*rmin*sqrt(r2)-r2-rmin2)*invrsig2);
}
/* 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)
VERSION 18/09/2008
***/
int profit_copyobjpix(profitstruct *profit, picstruct *field,
picstruct *wfield)
{
double dx2, dy2, dr2, rad2;
PIXTYPE *pixin,*pixout, *wpixin,*wpixout,
backnoise2, invgain, satlevel, wthresh, pix, wpix;
int i,x,y, xmin,xmax,ymin,ymax, w,h,w2,dw, npix, off, gainflag,
ix,iy;
/* First put the image background to -BIG */
pixout = profit->objpix;
wpixout = profit->objweight;
w = profit->objnaxisn[0];
h = profit->objnaxisn[1];
for (i=w*h; 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;
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)
{
off = (field->ymin-ymin)*w;
pixout += off;
wpixout += off;
ymin = field->ymin;
}
if (ymax>field->ymax)
ymax = field->ymax;
xmin = ix-w/2;
xmax = xmin + w;
w2 = w;
if (xmax>field->width)
{
w2 -= xmax-field->width;
xmax = field->width;
}
if (xmin<0)
{
pixout -= xmin;
wpixout -= xmin;
w2 += xmin;
xmin = 0;
}
/* Copy the right pixels to the destination */
dw = w - w2;
npix = 0;
if (wfield)
{
wthresh = wfield->weight_thresh;
gainflag = prefs.weightgain_flag;
/*-- Do the same for the weights */
npix = 0;
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++)
{
dx2 = (x-ix);
dr2 = dy2 + dx2*dx2;
pix = *(pixout++) = *(pixin++);
if (dr2<rad2 && pix>-BIG && pix<satlevel && (wpix=*(wpixin++))<wthresh)
{
*(wpixout++) = 1.0 / sqrt(wpix+(pix>0.0?
(gainflag? pix*wpix/backnoise2:pix)*invgain : 0.0));
npix++;
}
else
*(wpixout++) = 0.0;
}
}
}
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++)
{
dx2 = (x-ix);
dr2 = dy2 + dx2*dx2;
pix = *(pixout++) = *(pixin++);
if (dr2<rad2 && pix>-BIG)
{
*(wpixout++) = 1.0 / sqrt(backnoise2 + (pix>0.0?pix*invgain : 0.0));
npix++;
}
else
*(wpixout++) = 0.0;
}
}
return npix;
}
/****** profit_spiralindex ****************************************************
PROTO double 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 18/09/2008
***/
double profit_spiralindex(profitstruct *profit)
{
objstruct *obj;
obj2struct *obj2;
double *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 */
fwhm = obj2->hl_radius * 2.0 / 4.0;
if (fwhm < 2.0)
fwhm = 2.0;
sep = 2.0;
invtwosigma2 = -(2.35*2.35/(2.0*fwhm*fwhm));
hw = (double)(profit->objnaxisn[0]/2);
ohw = profit->objnaxisn[0] - hw;
hh = (double)(profit->objnaxisn[1]/2);
ohh = profit->objnaxisn[1] - hh;
txstart = -hw;
ty = -hh;
QMALLOC(dx, double, 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, double, 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, double, 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, double, 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 */
invtwosigma2 = -1.18*1.18 / (2.0*obj2->hl_radius*obj2->hl_radius);
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);
free(fdx);
free(fdy);
free(gdx);
free(gdy);
return spirindex;
}
/****** profit_moments ****************************************************
PROTO void profit_moments(profitstruct *profit)
PURPOSE Compute the 2nd order moments from the unconvolved object model.
INPUT Profile-fitting structure.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 18/09/2008
***/
void profit_moments(profitstruct *profit)
{
objstruct *obj;
obj2struct *obj2;
double *pix,
hw,hh, x,y, xstart, val,
mx,my, sum, mx2,my2,mxy, den;
int ix,iy;
obj = profit->obj;
obj2 = profit->obj2;
hw = (double)(profit->modnaxisn[0]/2);
hh = (double)(profit->modnaxisn[1]/2);
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)
{
val = *(pix++);
sum += val;
mx += val*x;
my += val*y;
mx2 += val*x*x;
mxy += val*x*y;
my2 += val*y*y;
}
}
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;
if (mx2+my2 > 1.0/BIG)
{
obj2->prof_eps1 = (mx2 - my2) / (mx2+my2);
obj2->prof_eps2 = 2.0*mxy / (mx2 + my2);
den = mx2+my2-mxy*mxy;
if (den>=0.0)
den = mx2+my2+2.0*sqrt(den);
else
den = mx2+my2;
obj2->prof_e1 = (mx2 - my2) / den;
obj2->prof_e2 = 2.0*mxy / den;
}
else
obj2->prof_eps1 = obj2->prof_eps2 = obj2->prof_e1 = obj2->prof_e2 = 0.0;
return;
}
/****** profit_addparam *******************************************************
PROTO void profit_addparam(profitstruct *profit, paramenum paramindex,
double **param)
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)
VERSION 29/03/2007
***/
void profit_addparam(profitstruct *profit, paramenum paramindex,
double **param)
{
/* 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++;
}
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 25/09/2008
***/
void profit_resetparam(profitstruct *profit, paramenum paramtype)
{
objstruct *obj;
obj2struct *obj2;
double param, parammin,parammax;
obj = profit->obj;
obj2 = profit->obj2;
param = parammin = parammax = 0.0; /* Avoid gcc -Wall warnings*/
switch(paramtype)
{
case PARAM_BACK:
param = 0.0;
parammin = -6.0*obj->sigbkg;
parammax = 6.0*obj->sigbkg;
break;
case PARAM_X:
param = obj->mx - (int)(obj->mx+0.49999);
parammin = -obj2->hl_radius*4;
parammax = obj2->hl_radius*4;
break;
case PARAM_Y:
param = obj->my - (int)(obj->my+0.49999);
parammin = -obj2->hl_radius*4;
parammax = obj2->hl_radius*4;
break;
case PARAM_SPHEROID_FLUX:
param = obj2->flux_auto/2.0;
parammin = -obj2->flux_auto/1000.0;
parammax = 2*obj2->flux_auto;
break;
case PARAM_SPHEROID_REFF:
param = obj2->hl_radius;
parammin = 0.1;
parammax = param * 4.0;
break;
case PARAM_SPHEROID_ASPECT:
param = FLAG(obj2.prof_disk_flux)? 1.0 : obj->b/obj->a;
parammin = FLAG(obj2.prof_disk_flux)? 0.5 : 0.01;
parammax = 1.0;
break;
case PARAM_SPHEROID_POSANG:
param = obj->theta;
parammin = 0.0;
parammax = 0.0;
break;
case PARAM_SPHEROID_SERSICN:
param = 4.0;
parammin = 1.0;
parammax = 10.0;
break;
case PARAM_DISK_FLUX:
param = obj2->flux_auto/2.0;
parammin = -obj2->flux_auto/1000.0;
parammax = 2*obj2->flux_auto;
break;
case PARAM_DISK_SCALE: /* From scalelength to Re */
param = obj2->hl_radius/1.67835*sqrt(obj->a/obj->b);
parammin = param / 4.0;
parammax = param * 4.0;
break;
case PARAM_DISK_ASPECT:
param = obj->b/obj->a;
parammin = 0.01;
parammax = 1.0;
break;
case PARAM_DISK_POSANG:
param = obj->theta;
parammin = 0.0;
parammax = 0.0;
break;
case PARAM_ARMS_FLUX:
param = obj2->flux_auto/2.0;
parammin = 0.0;
parammax = obj2->flux_auto*2.0;
break;
case PARAM_ARMS_QUADFRAC:
param = 0.5;
parammin = 0.0;
parammax = 1.0;
break;
case PARAM_ARMS_SCALE:
param = 1.0;
parammin = 0.5;
parammax = 10.0;
break;
case PARAM_ARMS_START:
param = 0.5;
parammin = 0.0;
parammax = 3.0;
break;
case PARAM_ARMS_PITCH:
param = 20.0;
parammin = 5.0;
parammax = 50.0;
break;
case PARAM_ARMS_PITCHVAR:
param = 0.0;
parammin = -1.0;
parammax = 1.0;
break;
// if ((profit->spirindex=profit_spiralindex(profit, obj, obj2)) > 0.0)
// {
// param = -param;
// parammin = -parammax;
// parammax = -parammin;
// }
// printf("spiral index: %g \n", profit->spirindex);
// break;
case PARAM_ARMS_POSANG:
param = 0.0;
parammin = 0.0;
parammax = 0.0;
break;
case PARAM_ARMS_WIDTH:
param = 3.0;
parammin = 1.5;
parammax = 11.0;
break;
case PARAM_BAR_FLUX:
param = obj2->flux_auto/10.0;
parammin = 0.0;
parammax = 2.0*obj2->flux_auto;
break;
case PARAM_BAR_ASPECT:
param = 0.3;
parammin = 0.2;
parammax = 0.5;
break;
case PARAM_BAR_POSANG:
param = 0.0;
parammin = 0.0;
parammax = 0.0;
break;
case PARAM_INRING_FLUX:
param = obj2->flux_auto/10.0;
parammin = 0.0;
parammax = 2.0*obj2->flux_auto;
break;
case PARAM_INRING_WIDTH:
param = 0.3;
parammin = 0.0;
parammax = 0.5;
break;
case PARAM_INRING_ASPECT:
param = 0.8;
parammin = 0.4;
parammax = 1.0;
break;
case PARAM_OUTRING_FLUX:
param = obj2->flux_auto/10.0;
parammin = 0.0;
parammax = 2.0*obj2->flux_auto;
break;
case PARAM_OUTRING_START:
param = 4.0;
parammin = 3.5;
parammax = 6.0;
break;
case PARAM_OUTRING_WIDTH:
param = 0.3;
parammin = 0.0;
parammax = 0.5;
break;
default:
error(EXIT_FAILURE, "*Internal Error*: Unknown profile parameter in ",
"profit_resetparam()");
break;
}
if (parammin!=parammax && (param<=parammin || param>=parammax))
param = (parammin+parammax)/2.0;
profit_setparam(profit, paramtype, param, parammin, parammax);
return;
}
/****** profit_resetparams ****************************************************
PROTO void profit_resetparams(profitstruct *profit)
PURPOSE Set the initial, lower and upper boundary values of profile parameters.
INPUT Pointer to the profit structure.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 18/09/2008
***/
void profit_resetparams(profitstruct *profit)
{
int p;
for (p=0; p<PARAM_NPARAM; p++)
profit_resetparam(profit, (paramenum)p);
return;
}
/****** profit_setparam ****************************************************
PROTO void profit_setparam(profitstruct *profit, paramenum paramtype,
double param, double parammin, double parammax)
PURPOSE Set the actual, lower and upper boundary values of a profile parameter.
INPUT Pointer to the profit structure,
Parameter index,
Actual value,
Lower boundary to the parameter,
Upper boundary to the parameter.
OUTPUT RETURN_OK if the parameter is registered, RETURN_ERROR otherwise.
AUTHOR E. Bertin (IAP)
VERSION 16/04/2008
***/
int profit_setparam(profitstruct *profit, paramenum paramtype,
double param, double parammin, double parammax)
{
double *paramptr;
int index;
/* Check whether the parameter has already be registered */
if ((paramptr=profit->paramlist[(int)paramtype]))
{
index = paramptr - profit->param;
profit->paraminit[index] = param;
profit->parammin[index] = parammin;
profit->parammax[index] = parammax;
return RETURN_OK;
}
else
return RETURN_ERROR;
}
/****** profit_boundtounbound *************************************************
PROTO void profit_boundtounbound(profitstruct *profit, double *param)
PURPOSE Convert parameters from bounded to unbounded space.
INPUT Pointer to the profit structure.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 25/05/2007
***/
void profit_boundtounbound(profitstruct *profit, double *param)
{
double num,den;
int p;
for (p=0; p<profit->nparam; p++)
if (profit->parammin[p]!=profit->parammax[p])
{
num = param[p] - profit->parammin[p];
den = profit->parammax[p] - param[p];
param[p] = num>1e-100? (den>1e-100? log(num/den): 200.0) : -200.0;
}
return;
}
/****** profit_unboundtobound *************************************************
PROTO void profit_unboundtobound(profitstruct *profit, double *param)
PURPOSE Convert parameters from unbounded to bounded space.
INPUT Pointer to the profit structure.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 18/05/2007
***/
void profit_unboundtobound(profitstruct *profit, double *param)
{
int p;
for (p=0; p<profit->nparam; p++)
if (profit->parammin[p]!=profit->parammax[p])
param[p] = (profit->parammax[p] - profit->parammin[p])
/ (1.0 + exp(-(param[p]>200.0? 200.0 : param[p])))
+ profit->parammin[p];
return;
}
/****** profit_covarunboundtobound ********************************************
PROTO void profit_covarunboundtobound(profitstruct *profit)
PURPOSE Convert covariance matrix from unbounded to bounded space.
INPUT Pointer to the profit structure.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 30/04/2008
***/
void profit_covarunboundtobound(profitstruct *profit)
{
double *covar, *dxdy,*x,*xmin,*xmax,
dxmin, dxmax;
int p,p1,p2, nparam;
nparam = profit->nparam;
QMALLOC(dxdy, double, nparam);
x = profit->paraminit;
xmin = profit->parammin;
xmax = profit->parammax;
for (p=0; p<profit->nparam; p++)
if (xmin[p]!=xmax[p])
{
dxmin = x[p] - xmin[p];
dxmax= xmax[p] - x[p];
dxdy[p] = (fabs(dxmin) < 1.0/BIG && fabs(dxmax) < 1.0/BIG) ?
0.0 : dxmin*dxmax/(dxmin+dxmax);
}
else
dxdy[p] = 1.0;
covar = profit->covar;
for (p2=0; p2<nparam; p2++)
for (p1=0; p1<nparam; p1++)
*(covar++) *= dxdy[p1]*dxdy[p2];
free(dxdy);
return;
}
/****** prof_init *************************************************************
PROTO profstruct prof_init(profitstruct *profit, proftypenum profcode)
PURPOSE Allocate and initialize a new profile structure.
INPUT Pointer to the profile-fitting structure,
profile type.
OUTPUT A pointer to an allocated prof structure.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 22/04/2008
***/
profstruct *prof_init(profitstruct *profit, proftypenum profcode)
{
profstruct *prof;
double *pix,
rmax2, re2, dy2,r2, scale, zero, k,n, hinvn;
int width,height, ixc,iyc, ix,iy, nsub,
d,s;
QCALLOC(prof, profstruct, 1);
prof->code = profcode;
switch(profcode)
{
case PROF_BACK:
prof->naxis = 2;
prof->pix = NULL;
profit_addparam(profit, PARAM_BACK, &prof->flux);
prof->typscale = 1.0;
break;
case PROF_SERSIC:
prof->naxis = 3;
prof->pix = NULL;
prof->typscale = 1.0;
profit_addparam(profit, PARAM_X, &prof->x[0]);
profit_addparam(profit, PARAM_Y, &prof->x[1]);
profit_addparam(profit, PARAM_SPHEROID_FLUX, &prof->flux);
profit_addparam(profit, PARAM_SPHEROID_REFF, &prof->scale);
profit_addparam(profit, PARAM_SPHEROID_ASPECT, &prof->aspect);
profit_addparam(profit, PARAM_SPHEROID_POSANG, &prof->posangle);
profit_addparam(profit, PARAM_SPHEROID_SERSICN, &prof->extra[0]);
break;
case PROF_DEVAUCOULEURS:
prof->naxis = 2;
prof->pix = NULL;
prof->typscale = 1.0;
profit_addparam(profit, PARAM_X, &prof->x[0]);
profit_addparam(profit, PARAM_Y, &prof->x[1]);
profit_addparam(profit, PARAM_SPHEROID_FLUX, &prof->flux);
profit_addparam(profit, PARAM_SPHEROID_REFF, &prof->scale);
profit_addparam(profit, PARAM_SPHEROID_ASPECT, &prof->aspect);
profit_addparam(profit, PARAM_SPHEROID_POSANG, &prof->posangle);
break;
case PROF_EXPONENTIAL:
prof->naxis = 2;
prof->pix = NULL;
prof->typscale = 1.0;
profit_addparam(profit, PARAM_X, &prof->x[0]);
profit_addparam(profit, PARAM_Y, &prof->x[1]);
profit_addparam(profit, PARAM_DISK_FLUX, &prof->flux);
profit_addparam(profit, PARAM_DISK_SCALE, &prof->scale);
profit_addparam(profit, PARAM_DISK_ASPECT, &prof->aspect);
profit_addparam(profit, PARAM_DISK_POSANG, &prof->posangle);
break;
case PROF_ARMS:
prof->naxis = 2;
prof->pix = NULL;
prof->typscale = 1.0;
profit_addparam(profit, PARAM_X, &prof->x[0]);
profit_addparam(profit, PARAM_Y, &prof->x[1]);
profit_addparam(profit, PARAM_DISK_SCALE, &prof->scale);
profit_addparam(profit, PARAM_DISK_ASPECT, &prof->aspect);
profit_addparam(profit, PARAM_DISK_POSANG, &prof->posangle);
profit_addparam(profit, PARAM_ARMS_FLUX, &prof->flux);
profit_addparam(profit, PARAM_ARMS_QUADFRAC, &prof->featfrac);
// profit_addparam(profit, PARAM_ARMS_SCALE, &prof->featscale);
profit_addparam(profit, PARAM_ARMS_START, &prof->featstart);
profit_addparam(profit, PARAM_ARMS_PITCH, &prof->featpitch);
// profit_addparam(profit, PARAM_ARMS_PITCHVAR, &prof->featpitchvar);
profit_addparam(profit, PARAM_ARMS_POSANG, &prof->featposang);
// profit_addparam(profit, PARAM_ARMS_WIDTH, &prof->featwidth);
break;
case PROF_BAR:
prof->naxis = 2;
prof->pix = NULL;
prof->typscale = 1.0;
profit_addparam(profit, PARAM_X, &prof->x[0]);
profit_addparam(profit, PARAM_Y, &prof->x[1]);
profit_addparam(profit, PARAM_DISK_SCALE, &prof->scale);
profit_addparam(profit, PARAM_DISK_ASPECT, &prof->aspect);
profit_addparam(profit, PARAM_DISK_POSANG, &prof->posangle);
profit_addparam(profit, PARAM_ARMS_START, &prof->featstart);
profit_addparam(profit, PARAM_BAR_FLUX, &prof->flux);
profit_addparam(profit, PARAM_BAR_ASPECT, &prof->feataspect);
profit_addparam(profit, PARAM_ARMS_POSANG, &prof->featposang);
break;
case PROF_INRING:
prof->naxis = 2;
prof->pix = NULL;
prof->typscale = 1.0;
profit_addparam(profit, PARAM_X, &prof->x[0]);
profit_addparam(profit, PARAM_Y, &prof->x[1]);
profit_addparam(profit, PARAM_DISK_SCALE, &prof->scale);
profit_addparam(profit, PARAM_DISK_ASPECT, &prof->aspect);
profit_addparam(profit, PARAM_DISK_POSANG, &prof->posangle);
profit_addparam(profit, PARAM_ARMS_START, &prof->featstart);
profit_addparam(profit, PARAM_INRING_FLUX, &prof->flux);
profit_addparam(profit, PARAM_INRING_WIDTH, &prof->featwidth);
profit_addparam(profit, PARAM_INRING_ASPECT, &prof->feataspect);
break;
case PROF_OUTRING:
prof->naxis = 2;
prof->pix = NULL;
prof->typscale = 1.0;
profit_addparam(profit, PARAM_X, &prof->x[0]);
profit_addparam(profit, PARAM_Y, &prof->x[1]);
profit_addparam(profit, PARAM_DISK_SCALE, &prof->scale);
profit_addparam(profit, PARAM_DISK_ASPECT, &prof->aspect);
profit_addparam(profit, PARAM_DISK_POSANG, &prof->posangle);
profit_addparam(profit, PARAM_OUTRING_START, &prof->featstart);
profit_addparam(profit, PARAM_OUTRING_FLUX, &prof->flux);
profit_addparam(profit, PARAM_OUTRING_WIDTH, &prof->featwidth);
break;
case PROF_SERSIC_TABEX: /* An example of tabulated profile */
prof->naxis = 3;
width = prof->naxisn[0] = PROFIT_PROFRES;
height = prof->naxisn[1] = PROFIT_PROFRES;
nsub = prof->naxisn[2] = PROFIT_PROFSRES;
QCALLOC(prof->pix, double, width*height*nsub);
ixc = width/2;
iyc = height/2;
rmax2 = (ixc - 1.0)*(ixc - 1.0);
re2 = width/64.0;
prof->typscale = re2;
re2 *= re2;
zero = prof->extrazero[0] = 0.2;
scale = prof->extrascale[0]= 8.0/PROFIT_PROFSRES;
pix = prof->pix;
for (s=0; s<nsub; s++)
{
n = s*scale + zero;
hinvn = 0.5/n;
k = -1.0/3.0 + 2.0*n + 4.0/(405.0*n) + 46.0/(25515.0*n*n)
+ 131.0/(1148175*n*n*n);
for (iy=0; iy<height; iy++)
{
dy2 = (iy-iyc)*(iy-iyc);
for (ix=0; ix<width; ix++)
{
r2 = dy2 + (ix-ixc)*(ix-ixc);
*(pix++) = (r2<rmax2)? exp(-k*pow(r2/re2,hinvn)) : 0.0;
}
}
}
profit_addparam(profit, PARAM_X, &prof->x[0]);
profit_addparam(profit, PARAM_Y, &prof->x[1]);
profit_addparam(profit, PARAM_SPHEROID_FLUX, &prof->flux);
profit_addparam(profit, PARAM_SPHEROID_REFF, &prof->scale);
profit_addparam(profit, PARAM_SPHEROID_ASPECT, &prof->aspect);
profit_addparam(profit, PARAM_SPHEROID_POSANG, &prof->posangle);
profit_addparam(profit, PARAM_SPHEROID_SERSICN, &prof->extra[0]);
break;
default:
error(EXIT_FAILURE, "*Internal Error*: Unknown profile in ",
"prof_init()");
break;
}
if (prof->pix)
{
prof->kernelnlines = 1;
for (d=0; d<prof->naxis; d++)
{
prof->interptype[d] = INTERP_BILINEAR;
prof->kernelnlines *=
(prof->kernelwidth[d] = interp_kernwidth[prof->interptype[d]]);
}
prof->kernelnlines /= prof->kernelwidth[0];
QMALLOC(prof->kernelbuf, double, prof->kernelnlines);
}
return prof;
}
/****** prof_end **************************************************************
PROTO void prof_end(profstruct *prof)
PURPOSE End (deallocate) a profile structure.
INPUT Prof structure.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 09/04/2007
***/
void prof_end(profstruct *prof)
{
if (prof->pix)
{
free(prof->pix);
free(prof->kernelbuf);
}
free(prof);
return;
}
/****** prof_add **************************************************************
PROTO void prof_add(profstruct *prof, profitstruct *profit)
PURPOSE Add a model profile to an image.
INPUT Profile structure,
profile-fitting structure.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 03/10/2008
***/
void prof_add(profstruct *prof, profitstruct *profit)
{
double posin[PROFIT_MAXEXTRA], posout[2], dnaxisn[2],
*pixout,
flux,fluxfac, scaling;
float *pixin,
amp,ctheta,stheta,cd11,cd12,cd21,cd22, dcd11,dcd21, dx1,dx2,
x1,x10,x2, x1cin,x2cin, x1cout,x2cout, xscale,yscale, saspect,
x1in,x2in, odx, ostep,
n,k, hinvn, x1t,x2t, ca,sa, u,umin,
armamp,arm2amp, armrdphidr, armrdphidrvar, posang,
width, invwidth2,
r,r2,rmin,r2min, r2minxin,r2minxout, rmax, r2max, invr2xdif,
val, theta, thresh, ra,rb;
int npix, noversamp,
d,e,i, ix1,ix2, idx1,idx2;
npix = profit->modnaxisn[0]*profit->modnaxisn[1];
if (prof->code==PROF_BACK)
{
amp = fabs(*prof->flux);
pixout = profit->modpix;
for (i=npix; i--;)
*(pixout++) += amp;
return;
}
scaling = profit->pixstep / prof->typscale;
/* Compute Profile CD matrix */
ctheta = cos(*prof->posangle*DEG);
stheta = sin(*prof->posangle*DEG);
saspect = fabs(*prof->aspect);
xscale = (*prof->scale==0.0)?
0.0 : fabs(scaling / (*prof->scale*prof->typscale));
yscale = (*prof->scale*saspect == 0.0)?
0.0 : fabs(scaling / (*prof->scale*prof->typscale*saspect));
cd11 = xscale*ctheta;
cd12 = xscale*stheta;
cd21 = -yscale*stheta;
cd22 = yscale*ctheta;
dx1 = 0.0; /* Shifting operations have been moved to profit_resample() */
dx2 = 0.0; /* Shifting operations have been moved to profit_resample() */
x1cout = (double)(profit->modnaxisn[0]/2);
x2cout = (double)(profit->modnaxisn[1]/2);
switch(prof->code)
{
case PROF_SERSIC:
n = fabs(*prof->extra[0]);
k = 1.0/3.0 - 2.0*n - 4.0/(405.0*n) - 46.0/(25515.0*n*n)
- 131.0/(1148175*n*n*n);
hinvn = 0.5/n;
/*---- The consequence of sampling on flux is compensated by PSF normalisation*/
x10 = -x1cout - dx1;
x2 = -x2cout - dx2;
pixin = profit->pmodpix;
for (ix2=profit->modnaxisn[1]; ix2--; x2+=1.0)
{
x1 = x10;
for (ix1=profit->modnaxisn[0]; ix1--; x1+=1.0)
{
x1in = cd12*x2 + cd11*x1;
x2in = cd22*x2 + cd21*x1;
ra = x1in*x1in+x2in*x2in;
val = expf(k*PROFIT_POWF(ra,hinvn));
noversamp = (int)(val*PROFIT_OVERSAMP+0.1);
if (noversamp < 2)
*(pixin++) = val;
else
{
ostep = 1.0/noversamp;
dcd11 = cd11*ostep;
dcd21 = cd21*ostep;
odx = 0.5*(ostep-1.0);
x1t = x1+odx;
val = 0.0;
for (idx2=noversamp; idx2--; odx+=ostep)
{
x1in = cd12*(x2+odx) + cd11*x1t;
x2in = cd22*(x2+odx) + cd21*x1t;
for (idx1=noversamp; idx1--;)
{
ra = x1in*x1in+x2in*x2in;
val += expf(k*PROFIT_POWF(ra,hinvn));
x1in += dcd11;
x2in += dcd21;
}
}
*(pixin++) = val*ostep*ostep;
}
}
}
break;
case PROF_DEVAUCOULEURS:
/*---- The consequence of sampling on flux is compensated by PSF normalisation*/
x10 = -x1cout - dx1;
x2 = -x2cout - dx2;
pixin = profit->pmodpix;
for (ix2=profit->modnaxisn[1]; ix2--; x2+=1.0)
{
x1 = x10;
for (ix1=profit->modnaxisn[0]; ix1--; x1+=1.0)
{
x1in = cd12*x2 + cd11*x1;
x2in = cd22*x2 + cd21*x1;
ra = x1in*x1in+x2in*x2in;
val = expf(-7.6692f*PROFIT_POWF(ra,0.125));
noversamp = (int)(sqrt(val)*PROFIT_OVERSAMP+0.1);
if (noversamp < 2)
*(pixin++) = val;
else
{
ostep = 1.0/noversamp;
dcd11 = cd11*ostep;
dcd21 = cd21*ostep;
odx = 0.5*(ostep-1.0);
x1t = x1+odx;
val = 0.0;
for (idx2=noversamp; idx2--; odx+=ostep)
{
x1in = cd12*(x2+odx) + cd11*x1t;
x2in = cd22*(x2+odx) + cd21*x1t;
for (idx1=noversamp; idx1--;)
{
ra = x1in*x1in+x2in*x2in;
val += expf(-7.6692f*PROFIT_POWF(ra,0.125));
x1in += dcd11;
x2in += dcd21;
}
}
*(pixin++) = val*ostep*ostep;
}
}
}
break;
case PROF_EXPONENTIAL:
x1 = -x1cout - dx1;
x2 = -x2cout - dx2;
pixin = profit->pmodpix;
for (ix2=profit->modnaxisn[1]; ix2--; x2+=1.0)
{
x1in = cd12*x2 + cd11*x1;
x2in = cd22*x2 + cd21*x1;
for (ix1=profit->modnaxisn[0]; ix1--;)
{
*(pixin++) = exp(-sqrt(x1in*x1in+x2in*x2in));
x1in += cd11;
x2in += cd21;
}
}
break;
case PROF_ARMS:
r2min = *prof->featstart**prof->featstart;
r2minxin = r2min * (1.0 - PROFIT_BARXFADE) * (1.0 - PROFIT_BARXFADE);
r2minxout = r2min * (1.0 + PROFIT_BARXFADE) * (1.0 + PROFIT_BARXFADE);
if ((invr2xdif = (r2minxout - r2minxin)) > 0.0)
invr2xdif = 1.0 / invr2xdif;
else
invr2xdif = 1.0;
umin = 0.5*logf(r2minxin + 0.00001);
arm2amp = *prof->featfrac;
armamp = 1.0 - arm2amp;
armrdphidr = 1.0/tan(*prof->featpitch*DEG);
armrdphidrvar = 0.0 /**prof->featpitchvar*/;
posang = *prof->featposang*DEG;
width = fabs(*prof->featwidth);
width = 3.0;
x1 = -x1cout - dx1;
x2 = -x2cout - dx2;
pixin = profit->pmodpix;
for (ix2=profit->modnaxisn[1]; ix2--; x2+=1.0)
{
x1t = cd12*x2 + cd11*x1;
x2t = cd22*x2 + cd21*x1;
for (ix1=profit->modnaxisn[0]; ix1--;)
{
r2 = x1t*x1t+x2t*x2t;
if (r2>r2minxin)
{
u = 0.5*logf(r2 + 0.00001);
theta = (armrdphidr+armrdphidrvar*(u-umin))*u+posang;
ca = cosf(theta);
sa = sinf(theta);
x1in = (x1t*ca - x2t*sa);
x2in = (x1t*sa + x2t*ca);
amp = expf(-sqrtf(x1t*x1t+x2t*x2t));
if (r2<r2minxout)
amp *= (r2 - r2minxin)*invr2xdif;
ra = x1in*x1in/r2;
rb = x2in*x2in/r2;
*(pixin++) = amp * (armamp*PROFIT_POWF(ra,width)
+ arm2amp*PROFIT_POWF(rb,width));
}
else
*(pixin++) = 0.0;
x1t += cd11;
x2t += cd21;
}
}
break;
case PROF_BAR:
r2min = *prof->featstart**prof->featstart;
r2minxin = r2min * (1.0 - PROFIT_BARXFADE) * (1.0 - PROFIT_BARXFADE);
r2minxout = r2min * (1.0 + PROFIT_BARXFADE) * (1.0 + PROFIT_BARXFADE);
if ((invr2xdif = (r2minxout - r2minxin)) > 0.0)
invr2xdif = 1.0 / invr2xdif;
else
invr2xdif = 1.0;
invwidth2 = fabs(1.0 / (*prof->featstart**prof->feataspect));
posang = *prof->featposang*DEG;
ca = cosf(posang);
sa = sinf(posang);
x1 = -x1cout - dx1;
x2 = -x2cout - dx2;
pixin = profit->pmodpix;
for (ix2=profit->modnaxisn[1]; ix2--; x2+=1.0)
{
x1t = cd12*x2 + cd11*x1;
x2t = cd22*x2 + cd21*x1;
for (ix1=profit->modnaxisn[0]; ix1--;)
{
r2 = x1t*x1t+x2t*x2t;
if (r2<r2minxout)
{
x1in = x1t*ca - x2t*sa;
x2in = invwidth2*(x1t*sa + x2t*ca);
*(pixin++) = (r2>r2minxin) ?
(r2minxout - r2)*invr2xdif*expf(-x2in*x2in)
: expf(-x2in*x2in);
}
else
*(pixin++) = 0.0;
x1t += cd11;
x2t += cd21;
}
}
break;
case PROF_INRING:
rmin = *prof->featstart;
r2minxin = *prof->featstart-4.0**prof->featwidth;
if (r2minxin < 0.0)
r2minxin = 0.0;
r2minxin *= r2minxin;
r2minxout = *prof->featstart+4.0**prof->featwidth;
r2minxout *= r2minxout;
invwidth2 = 0.5 / (*prof->featwidth**prof->featwidth);
cd22 /= *prof->feataspect;
cd21 /= *prof->feataspect;
x1 = -x1cout - dx1;
x2 = -x2cout - dx2;
pixin = profit->pmodpix;
for (ix2=profit->modnaxisn[1]; ix2--; x2+=1.0)
{
x1t = cd12*x2 + cd11*x1;
x2t = cd22*x2 + cd21*x1;
for (ix1=profit->modnaxisn[0]; ix1--;)
{
r2 = x1t*x1t+x2t*x2t;
if (r2>r2minxin && r2<r2minxout)
{
r = sqrt(r2) - rmin;
*(pixin++) = expf(-invwidth2*r*r);
}
else
*(pixin++) = 0.0;
x1t += cd11;
x2t += cd21;
}
}
break;
case PROF_OUTRING:
rmin = *prof->featstart;
r2minxin = *prof->featstart-4.0**prof->featwidth;
if (r2minxin < 0.0)
r2minxin = 0.0;
r2minxin *= r2minxin;
r2minxout = *prof->featstart+4.0**prof->featwidth;
r2minxout *= r2minxout;
invwidth2 = 0.5 / (*prof->featwidth**prof->featwidth);
x1 = -x1cout - dx1;
x2 = -x2cout - dx2;
pixin = profit->pmodpix;
for (ix2=profit->modnaxisn[1]; ix2--; x2+=1.0)
{
x1t = cd12*x2 + cd11*x1;
x2t = cd22*x2 + cd21*x1;
for (ix1=profit->modnaxisn[0]; ix1--;)
{
r2 = x1t*x1t+x2t*x2t;
if (r2>r2minxin && r2<r2minxout)
{
r = sqrt(r2) - rmin;
*(pixin++) = expf(-invwidth2*r*r);
}
else
*(pixin++) = 0.0;
x1t += cd11;
x2t += cd21;
}
}
break;
default:
/*---- Tabulated profile: remap each pixel */
/*---- Initialize multi-dimensional counters */
for (d=0; d<2; d++)
{
posout[d] = 1.0; /* FITS convention */
dnaxisn[d] = profit->modnaxisn[d] + 0.99999;
}
for (e=0; e<prof->naxis - 2; e++)
{
d = 2+e;
/*------ Compute position along axis */
posin[d] = (*prof->extra[e]-prof->extrazero[e])/prof->extrascale[e]+1.0;
/*------ Keep position within boundaries and let interpolation do the rest */
if (posin[d] < 0.99999)
{
if (prof->extracycleflag[e])
posin[d] += (double)prof->naxisn[d];
else
posin[d] = 1.0;
}
else if (posin[d] > (double)prof->naxisn[d])
{
if (prof->extracycleflag[e])
posin[d] = (prof->extracycleflag[e])?
fmod(posin[d], (double)prof->naxisn[d])
: (double)prof->naxisn[d];
}
}
x1cin = (double)(prof->naxisn[0]/2);
x2cin = (double)(prof->naxisn[1]/2);
pixin = profit->pmodpix;
for (i=npix; i--;)
{
x1 = posout[0] - x1cout - 1.0 - dx1;
x2 = posout[1] - x2cout - 1.0 - dx2;
posin[0] = cd11*x1 + cd12*x2 + x1cin + 1.0;
posin[1] = cd21*x1 + cd22*x2 + x2cin + 1.0;
*(pixin++) = prof_interpolate(prof, posin);
for (d=0; d<2; d++)
if ((posout[d]+=1.0) < dnaxisn[d])
break;
else
posout[d] = 1.0;
}
break;
}
/* Now find truncation threshold */
/* Find the shortest distance to a vignet border */
rmax = x1cout;
if (rmax > (r = x2cout))
rmax = r;
rmax += 0.01;
if (rmax<1.0)
rmax = 1.0;
r2max = rmax*rmax;
rmin = rmax - 1.0;
r2min = rmin*rmin;
/* Find best threshold (the max around the circle with radius rmax */
dx2 = -x2cout;
pixin = profit->pmodpix;
thresh = -BIG;
for (ix2=profit->modnaxisn[1]; ix2--; dx2 += 1.0)
{
dx1 = -x1cout;
for (ix1=profit->modnaxisn[0]; ix1--; dx1 += 1.0)
if ((val=*(pixin++))>thresh && (r2=dx1*dx1+dx2*dx2)>r2min && r2<r2max)
thresh = val;
}
/* Threshold and measure the flux */
flux = 0.0;
pixin = profit->pmodpix;
for (n=npix; n--; pixin++)
if (*pixin >= thresh)
flux += *pixin;
else
*pixin = 0.0;
/* Correct final flux */
fluxfac = fabs(flux)>0.0? *prof->flux / flux : 1.0;
prof->fluxfac = fluxfac;
pixin = profit->pmodpix;
pixout = profit->modpix;
for (n=npix; n--;)
*(pixout++) += fluxfac * *(pixin++);
return;
}
/****** prof_interpolate ******************************************************
PROTO double prof_interpolate(profstruct *prof, double *posin)
PURPOSE Interpolate a multidimensional model profile at a given position.
INPUT Profile structure,
input position vector.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 10/12/2006
***/
static double prof_interpolate(profstruct *prof, double *posin)
{
double dpos[2+PROFIT_MAXEXTRA],
kernel_vector[INTERP_MAXKERNELWIDTH],
*kvector, *pixin,*pixout,
val;
long step[2+PROFIT_MAXEXTRA],
start, fac;
int linecount[2+PROFIT_MAXEXTRA],
*naxisn,
i,j,n, ival, nlines, kwidth,width, badpixflag, naxis;
naxis = prof->naxis;
naxisn = prof->naxisn;
start = 0;
fac = 1;
for (n=0; n<naxis; n++)
{
val = *(posin++);
width = *(naxisn++);
/*-- Get the integer part of the current coordinate or nearest neighbour */
ival = (prof->interptype[n]==INTERP_NEARESTNEIGHBOUR)?
(int)(val-0.50001):(int)val;
/*-- Store the fractional part of the current coordinate */
dpos[n] = val - ival;
/*-- Check if interpolation start/end exceed image boundary... */
kwidth = prof->kernelwidth[n];
ival-=kwidth/2;
if (ival<0 || ival+kwidth<=0 || ival+kwidth>width)
return 0.0;
/*-- Update starting pointer */
start += ival*fac;
/*-- Update step between interpolated regions */
step[n] = fac*(width-kwidth);
linecount[n] = 0.0;
fac *= width;
}
/* Update Interpolation kernel vectors */
make_kernel(*dpos, kernel_vector, prof->interptype[0]);
kwidth = prof->kernelwidth[0];
nlines = prof->kernelnlines;
/* First step: interpolate along NAXIS1 from the data themselves */
badpixflag = 0;
pixin = prof->pix+start;
pixout = prof->kernelbuf;
for (j=nlines; j--;)
{
val = 0.0;
kvector = kernel_vector;
for (i=kwidth; i--;)
val += *(kvector++)**(pixin++);
*(pixout++) = val;
for (n=1; n<naxis; n++)
{
pixin+=step[n-1];
if (++linecount[n]<prof->kernelwidth[n])
break;
else
linecount[n] = 0; /* No need to initialize it to 0! */
}
}
/* Second step: interpolate along other axes from the interpolation buffer */
for (n=1; n<naxis; n++)
{
make_kernel(dpos[n], kernel_vector, prof->interptype[n]);
kwidth = prof->kernelwidth[n];
pixout = pixin = prof->kernelbuf;
for (j = (nlines/=kwidth); j--;)
{
val = 0.0;
kvector = kernel_vector;
for (i=kwidth; i--;)
val += *(kvector++)**(pixin++);
*(pixout++) = val;
}
}
return prof->kernelbuf[0];
}
/****** interpolate_pix ******************************************************
PROTO void interpolate_pix(double *posin, double *pix, int naxisn,
interpenum interptype)
PURPOSE Interpolate a model profile at a given position.
INPUT Profile structure,
input position vector,
input pixmap dimension vector,
interpolation type.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 07/12/2006
***/
static double interpolate_pix(double *posin, double *pix, int *naxisn,
interpenum interptype)
{
double buffer[INTERP_MAXKERNELWIDTH],
kernel[INTERP_MAXKERNELWIDTH], dpos[2],
*kvector, *pixin, *pixout,
val;
int fac, ival, kwidth, start, width, step,
i,j, n;
kwidth = interp_kernwidth[interptype];
start = 0;
fac = 1;
for (n=0; n<2; n++)
{
val = *(posin++);
width = naxisn[n];
/*-- Get the integer part of the current coordinate or nearest neighbour */
ival = (interptype==INTERP_NEARESTNEIGHBOUR)? (int)(val-0.50001):(int)val;
/*-- Store the fractional part of the current coordinate */
dpos[n] = val - ival;
/*-- Check if interpolation start/end exceed image boundary... */
ival-=kwidth/2;
if (ival<0 || ival+kwidth<=0 || ival+kwidth>width)
return 0.0;
/*-- Update starting pointer */
start += ival*fac;
/*-- Update step between interpolated regions */
fac *= width;
}
/* First step: interpolate along NAXIS1 from the data themselves */
make_kernel(dpos[0], kernel, interptype);
step = naxisn[0]-kwidth;
pixin = pix+start;
pixout = buffer;
for (j=kwidth; j--;)
{
val = 0.0;
kvector = kernel;
for (i=kwidth; i--;)
val += *(kvector++)**(pixin++);
*(pixout++) = val;
pixin += step;
}
/* Second step: interpolate along NAXIS2 from the interpolation buffer */
make_kernel(dpos[1], kernel, interptype);
pixin = buffer;
val = 0.0;
kvector = kernel;
for (i=kwidth; i--;)
val += *(kvector++)**(pixin++);
return val;
}
/****** make_kernel **********************************************************
PROTO void make_kernel(double pos, double *kernel, interpenum interptype)
PURPOSE Conpute interpolation-kernel data
INPUT Position,
Pointer to the output kernel data,
Interpolation method.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 11/04/2008
***/
void make_kernel(double pos, double *kernel, interpenum interptype)
{
double x, val, sinx1,sinx2,sinx3,cosx1;
if (interptype == INTERP_NEARESTNEIGHBOUR)
*kernel = 1;
else if (interptype == INTERP_BILINEAR)
{
*(kernel++) = 1.0-pos;
*kernel = pos;
}
else if (interptype == INTERP_LANCZOS2)
{
if (pos<1e-5 && pos>-1e5)
{
*(kernel++) = 0.0;
*(kernel++) = 1.0;
*(kernel++) = 0.0;
*kernel = 0.0;
}
else
{
x = -PI/2.0*(pos+1.0);
#ifdef HAVE_SINCOS
sincos(x, &sinx1, &cosx1);
#else
sinx1 = sin(x);
cosx1 = cos(x);
#endif
val = (*(kernel++) = sinx1/(x*x));
x += PI/2.0;
val += (*(kernel++) = -cosx1/(x*x));
x += PI/2.0;
val += (*(kernel++) = -sinx1/(x*x));
x += PI/2.0;
val += (*kernel = cosx1/(x*x));
val = 1.0/val;
*(kernel--) *= val;
*(kernel--) *= val;
*(kernel--) *= val;
*kernel *= val;
}
}
else if (interptype == INTERP_LANCZOS3)
{
if (pos<1e-5 && pos>-1e5)
{
*(kernel++) = 0.0;
*(kernel++) = 0.0;
*(kernel++) = 1.0;
*(kernel++) = 0.0;
*(kernel++) = 0.0;
*kernel = 0.0;
}
else
{
x = -PI/3.0*(pos+2.0);
#ifdef HAVE_SINCOS
sincos(x, &sinx1, &cosx1);
#else
sinx1 = sin(x);
cosx1 = cos(x);
#endif
val = (*(kernel++) = sinx1/(x*x));
x += PI/3.0;
val += (*(kernel++) = (sinx2=-0.5*sinx1-0.866025403785*cosx1)
/ (x*x));
x += PI/3.0;
val += (*(kernel++) = (sinx3=-0.5*sinx1+0.866025403785*cosx1)
/(x*x));
x += PI/3.0;
val += (*(kernel++) = sinx1/(x*x));
x += PI/3.0;
val += (*(kernel++) = sinx2/(x*x));
x += PI/3.0;
val += (*kernel = sinx3/(x*x));
val = 1.0/val;
*(kernel--) *= val;
*(kernel--) *= val;
*(kernel--) *= val;
*(kernel--) *= val;
*(kernel--) *= val;
*kernel *= val;
}
}
else if (interptype == INTERP_LANCZOS4)
{
if (pos<1e-5 && pos>-1e5)
{
*(kernel++) = 0.0;
*(kernel++) = 0.0;
*(kernel++) = 0.0;
*(kernel++) = 1.0;
*(kernel++) = 0.0;
*(kernel++) = 0.0;
*(kernel++) = 0.0;
*kernel = 0.0;
}
else
{
x = -PI/4.0*(pos+3.0);
#ifdef HAVE_SINCOS
sincos(x, &sinx1, &cosx1);
#else
sinx1 = sin(x);
cosx1 = cos(x);
#endif
val = (*(kernel++) = sinx1/(x*x));
x += PI/4.0;
val +=(*(kernel++) = -(sinx2=0.707106781186*(sinx1+cosx1))
/(x*x));
x += PI/4.0;
val += (*(kernel++) = cosx1/(x*x));
x += PI/4.0;
val += (*(kernel++) = -(sinx3=0.707106781186*(cosx1-sinx1))/(x*x));
x += PI/4.0;
val += (*(kernel++) = -sinx1/(x*x));
x += PI/4.0;
val += (*(kernel++) = sinx2/(x*x));
x += PI/4.0;
val += (*(kernel++) = -cosx1/(x*x));
x += PI/4.0;
val += (*kernel = sinx3/(x*x));
val = 1.0/val;
*(kernel--) *= val;
*(kernel--) *= val;
*(kernel--) *= val;
*(kernel--) *= val;
*(kernel--) *= val;
*(kernel--) *= val;
*(kernel--) *= val;
*kernel *= val;
}
}
else
error(EXIT_FAILURE, "*Internal Error*: Unknown interpolation type in ",
"make_kernel()");
return;
}
/*
profit.h
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: SExtractor
*
* Authors: E.BERTIN (IAP)
*
* Contents: Include file for profit.c.
*
* Last modify: 03/10/2008
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
#ifndef _PROFIT_H_
#define _PROFIT_H_
/*-------------------------------- flags ------------------------------------*/
#define PROFIT_FLIPPED 0x0001
/*-------------------------------- macros -----------------------------------*/
#define PROFIT_POW(x,a) (x>0.01? exp(a*log(x)) : pow(x,a))
#define PROFIT_POWF(x,a) (x>0.01? expf(a*logf(x)) : powf(x,a))
/*----------------------------- Internal constants --------------------------*/
#define PROFIT_MAXITER 1000 /* Max. nb of iterations in profile fitting */
#define PROFIT_OVERSAMP 5 /* Max. profile oversamp. factor on each axis */
#define PROFIT_MAXPROF 8 /* Max. nb of profile components */
#define PROFIT_DYNPARAM 100.0 /* Dynamic compression param. in sigma units */
#define PROFIT_BARXFADE 0.1 /* Fract. of bar length crossfaded with arms */
#define PROFIT_MAXEXTRA 2 /* Max. nb of extra free params of profiles */
#define PROFIT_PROFRES 256 /* Pixmap size of model components */
#define PROFIT_PROFSRES 64 /* Number of model subcomponents */
#define INTERP_MAXKERNELWIDTH 8 /* Max. range of kernel (pixels) */
/* NOTES:
One must have: PROFIT_NITER > 0
PROFIT_MAXEXTRA > 0
*/
/*--------------------------------- typedefs --------------------------------*/
typedef enum {PROF_BACK, PROF_SERSIC, PROF_DEVAUCOULEURS,
PROF_EXPONENTIAL, PROF_ARMS, PROF_BAR, PROF_INRING,
PROF_OUTRING, PROF_SERSIC_TABEX, PROF_NPROF}
proftypenum; /* Profile code */
typedef enum {INTERP_NEARESTNEIGHBOUR, INTERP_BILINEAR, INTERP_LANCZOS2,
INTERP_LANCZOS3, INTERP_LANCZOS4} interpenum;
typedef enum {PARAM_BACK, PARAM_X, PARAM_Y,
PARAM_SPHEROID_FLUX, PARAM_SPHEROID_REFF, PARAM_SPHEROID_ASPECT,
PARAM_SPHEROID_POSANG, PARAM_SPHEROID_SERSICN,
PARAM_DISK_FLUX, PARAM_DISK_SCALE, PARAM_DISK_ASPECT,
PARAM_DISK_POSANG,
PARAM_ARMS_FLUX, PARAM_ARMS_QUADFRAC, PARAM_ARMS_SCALE,
PARAM_ARMS_START, PARAM_ARMS_POSANG, PARAM_ARMS_PITCH,
PARAM_ARMS_PITCHVAR, PARAM_ARMS_WIDTH,
PARAM_BAR_FLUX, PARAM_BAR_ASPECT, PARAM_BAR_POSANG,
PARAM_INRING_FLUX, PARAM_INRING_WIDTH, PARAM_INRING_ASPECT,
PARAM_OUTRING_FLUX, PARAM_OUTRING_START, PARAM_OUTRING_WIDTH,
PARAM_NPARAM} paramenum;
/*--------------------------- structure definitions -------------------------*/
typedef struct
{
proftypenum code; /* Model code */
double *pix; /* Full pixmap of the model */
int naxis; /* Number of pixmap dimensions */
int naxisn[3]; /* Pixmap size for each axis */
double typscale; /* Typical scale in prof pixels */
double fluxfac; /* Flux normalisation factor */
/* Generic presentation parameters */
double *flux; /* Integrated flux */
double *x[2]; /* Coordinate vector */
double *scale; /* Scaling vector */
double *aspect; /* Aspect ratio */
double *posangle; /* Position angle (CCW/NAXIS1)*/
double *featfrac; /* Feature flux fraction */
double *featscale; /* Feature relative scalelength */
double *featstart; /* Feature relative starting radius */
double *featposang; /* Feature position angle */
double *featpitch; /* Feature pitch */
double *featpitchvar; /* Feature pitch variation */
double *featwidth; /* Feature width */
double *feataspect; /* Feature aspect ratio */
double *extra[PROFIT_MAXEXTRA];/* Parameters along extra-dimension */
double extrazero[PROFIT_MAXEXTRA]; /* Zero-point along extra-dim. */
double extrascale[PROFIT_MAXEXTRA]; /* Scaling along extra-dim. */
int extracycleflag[PROFIT_MAXEXTRA]; /* !=0 for cycling dim. */
interpenum interptype[2+PROFIT_MAXEXTRA]; /* Interpolation type */
int kernelwidth[2+PROFIT_MAXEXTRA]; /* Kernel size */
double *kernelbuf; /* Kernel buffer */
int kernelnlines; /* Number of interp kernel lines */
} profstruct;
typedef struct
{
objstruct *obj; /* Current object */
obj2struct *obj2; /* Current object */
int nparam; /* Number of parameters to be fitted */
double *paramlist[PARAM_NPARAM]; /* flat parameter list */
int paramindex[PARAM_NPARAM];/* Vector of parameter indices */
double param[PARAM_NPARAM]; /* Vector of parameters to be fitted */
double paraminit[PARAM_NPARAM];/* Parameter initial guesses */
double parammin[PARAM_NPARAM]; /* Parameter lower limits */
double parammax[PARAM_NPARAM]; /* Parameter upper limits */
double *covar; /* Covariance matrix */
double paramerr[PARAM_NPARAM]; /* Std deviations of parameters */
int niter; /* Number of iterations */
profstruct **prof; /* Array of pointers to profiles */
int nprof; /* Number of profiles to consider */
struct psf *psf; /* PSF */
double pixstep; /* Model/PSF sampling step */
double *psfdft; /* Compressed Fourier Transform of the PSF */
double *psfpix; /* Full res. pixmap of the PSF */
double *modpix; /* Full res. pixmap of the complete model */
float *pmodpix; /* Full res. pixmap of the partial model */
int modnaxisn[3]; /* Dimensions along each axis */
PIXTYPE *lmodpix; /* Low resolution pixmap of the model */
PIXTYPE *objpix; /* Copy of object pixmap */
PIXTYPE *objweight; /* Copy of object weight-map */
int objnaxisn[2]; /* Dimensions along each axis */
int ix, iy; /* Integer coordinates of object pixmap */
double *resi; /* Vector of residuals */
int nresi; /* Number of residual elements */
double chi2; /* Std error per residual element */
double sigma; /* Standard deviation of the pixel values */
double flux; /* Total flux in final convolved model */
double spirindex; /* Spiral index (>0 for CCW) */
} profitstruct;
/*----------------------------- Global variables ----------------------------*/
/*-------------------------------- functions --------------------------------*/
profitstruct *profit_init(struct psf *psf);
profstruct *prof_init(profitstruct *profit, proftypenum profcode);
double *profit_compresi(profitstruct *profit, double *resi),
*profit_residuals(profitstruct *profit, picstruct *field,
picstruct *wfield, double *param, double *resi),
profit_spiralindex(profitstruct *profit);
int profit_copyobjpix(profitstruct *profit, picstruct *field,
picstruct *wfield),
profit_minimize(profitstruct *profit, int niter),
profit_setparam(profitstruct *profit, paramenum paramtype,
double param, double parammin, double parammax);
void prof_add(profstruct *prof, profitstruct *profit),
prof_end(profstruct *prof),
profit_addparam(profitstruct *profit, paramenum paramindex,
double **param),
profit_boundtounbound(profitstruct *profit, double *param),
profit_fit(profitstruct *profit,
picstruct *field, picstruct *wfield,
objstruct *obj, obj2struct *obj2),
profit_convolve(profitstruct *profit, double *modpix),
profit_covarunboundtobound(profitstruct *profit),
profit_end(profitstruct *profit),
profit_evaluate(double *par, double *fvec, int m, int n,
void *adata),
profit_makedft(profitstruct *profit),
profit_moments(profitstruct *profit),
profit_printout(int n_par, double* par, int m_dat, double* fvec,
void *data, int iflag, int iter, int nfev ),
profit_psf(profitstruct *profit),
profit_resample(profitstruct *profit, double *inpix,
PIXTYPE *outpix),
profit_resetparam(profitstruct *profit, paramenum paramtype),
profit_resetparams(profitstruct *profit),
profit_unboundtobound(profitstruct *profit, double *param);
#endif
......@@ -10,7 +10,7 @@
*
* Contents: Fit the PSF to a detection.
*
* Last modify: 12/01/2006
* Last modify: 19/12/2007
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
......@@ -31,7 +31,7 @@
#include "check.h"
#include "filter.h"
#include "image.h"
#include "poly.h"
#include "wcs/poly.h"
#include "psf.h"
/*------------------------------- variables ---------------------------------*/
......@@ -84,10 +84,13 @@ void psf_end(psfstruct *psf, psfitstruct *psfit)
free(psf->masksize);
free(psf);
free(psfit->x);
free(psfit->y);
free(psfit->flux);
free(psfit);
if (psfit)
{
free(psfit->x);
free(psfit->y);
free(psfit->flux);
free(psfit);
}
return;
}
......@@ -288,7 +291,7 @@ void psf_readcontext(psfstruct *psf, picstruct *field)
{
psf->context[i] = &contextval[i];
psf->contexttyp[i] = T_DOUBLE;
if (fitsread(field->fitshead, psf->contextname[i]+1, &contextval[i],
if (fitsread(field->tab->headbuf, psf->contextname[i]+1, &contextval[i],
H_FLOAT,T_DOUBLE) == RETURN_ERROR)
{
sprintf(gstr, "*Error*: %s parameter not found in the header of ",
......@@ -336,9 +339,9 @@ void psf_fit(psfstruct *psf, picstruct *field, picstruct *wfield,
niter = 0;
npsfmax = prefs.psf_npsfmax;
pixstep = 1.0/psf->pixstep;
gain = prefs.gain;
gain = field->gain;
backnoise2 = field->backsig*field->backsig;
satlevel = prefs.satur_level - obj->bkg;
satlevel = field->satur_level - obj->bkg;
wthresh = wfield?wfield->weight_thresh:BIG;
gainflag = prefs.weightgain_flag;
psf_fwhm = psf->fwhm*psf->pixstep;
......@@ -760,10 +763,10 @@ void double_psf_fit(psfstruct *ppsf, picstruct *pfield, picstruct *pwfield,
pdx = pdy =dx = dy = 0.0;
ppixstep = 1.0/ppsf->pixstep;
pixstep = 1.0/psf->pixstep;
gain = prefs.gain;
gain = field->gain;
npsfmax=prefs.psf_npsfmax;
pbacknoise2 = pfield->backsig*pfield->backsig;
satlevel = prefs.satur_level - obj->bkg;
satlevel = field->satur_level - obj->bkg;
gainflag = prefs.weightgain_flag;
psf_fwhm = psf->fwhm*psf->pixstep;
ppsf_fwhm = ppsf->fwhm*ppsf->pixstep;
......
......@@ -61,7 +61,7 @@ typedef struct pc
codestruct *code;
} pcstruct;
typedef struct
typedef struct psf
{
char name[MAXCHAR]; /* Name of the file containing the PSF data */
int maskdim; /* Dimensionality of the tabulated data */
......
......@@ -9,7 +9,7 @@
*
* Contents: functions for input of image data.
*
* Last modify: 13/07/2006
* Last modify: 11/10/2007
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
......@@ -30,6 +30,7 @@
#include "check.h"
#include "field.h"
#include "fits/fitscat.h"
#include "fitswcs.h"
#include "interpolate.h"
#include "back.h"
#include "astrom.h"
......@@ -43,10 +44,12 @@ Load a new strip of pixel data into the buffer.
void *loadstrip(picstruct *field, picstruct *wfield)
{
tabstruct *tab;
checkstruct *check;
int y, w, flags, interpflag;
PIXTYPE *data, *wdata, *rmsdata;
tab = field->tab;
w = field->width;
flags = field->flags;
interpflag = (wfield && wfield->interp_flag);
......@@ -77,7 +80,7 @@ void *loadstrip(picstruct *field, picstruct *wfield)
else if (flags & INTERP_FIELD)
copydata(field, 0, nbpix);
else
readdata(field, data, nbpix);
read_body(tab, data, nbpix);
if (flags & (WEIGHT_FIELD|RMS_FIELD|BACKRMS_FIELD|VAR_FIELD))
weight_to_var(field, data, nbpix);
if ((flags & MEASURE_FIELD) && (check=prefs.check[CHECK_IDENTICAL]))
......@@ -108,6 +111,8 @@ void *loadstrip(picstruct *field, picstruct *wfield)
writecheck(check, data, w);
if ((check = prefs.check[CHECK_SUBPCPROTOS]))
writecheck(check, data, w);
if ((check = prefs.check[CHECK_SUBPROFILES]))
writecheck(check, data, w);
}
if ((flags&DETECT_FIELD) && (check=prefs.check[CHECK_BACKRMS]))
{
......@@ -123,7 +128,7 @@ void *loadstrip(picstruct *field, picstruct *wfield)
*sizeof(FLAGTYPE))))
error(EXIT_FAILURE,"Not enough memory for the flag buffer of ",
field->rfilename);
readidata(field, field->fstrip, nbpix);
read_ibody(field->tab, field->fstrip, nbpix);
}
field->ymax = field->stripheight;
......@@ -149,7 +154,7 @@ void *loadstrip(picstruct *field, picstruct *wfield)
else if (flags & INTERP_FIELD)
copydata(field, field->stripylim*w, w);
else
readdata(field, data, w);
read_body(tab, data, w);
if (flags & (WEIGHT_FIELD|RMS_FIELD|BACKRMS_FIELD|VAR_FIELD))
weight_to_var(field, data, w);
......@@ -175,6 +180,8 @@ void *loadstrip(picstruct *field, picstruct *wfield)
writecheck(check, data, w);
if ((check = prefs.check[CHECK_SUBPCPROTOS]))
writecheck(check, data, w);
if ((check = prefs.check[CHECK_SUBPROFILES]))
writecheck(check, data, w);
}
if ((flags&DETECT_FIELD) && (check=prefs.check[CHECK_BACKRMS]))
{
......@@ -184,7 +191,7 @@ void *loadstrip(picstruct *field, picstruct *wfield)
}
}
else
readidata(field, field->fstrip + field->stripylim*w, w);
read_ibody(tab, field->fstrip + field->stripylim*w, w);
field->stripylim = (++field->ymin)%field->stripheight;
if ((++field->ymax)<field->height)
......@@ -209,664 +216,51 @@ void copydata(picstruct *field, int offset, int size)
}
/******************************** readdata **********************************/
/*
read and convert input data stream in PIXTYPE (float) format.
*/
void readdata(picstruct *field, PIXTYPE *ptr, int size)
{
static char bufdata0[DATA_BUFSIZE];
char *bufdata;
short val16;
int i, bowl, spoonful, npix, curval, dval;
PIXTYPE bs,bz;
bs = (PIXTYPE)field->bscale;
bz = (PIXTYPE)field->bzero;
switch(field->compress_type)
{
/*-- Uncompressed image */
case ICOMPRESS_NONE:
bowl = DATA_BUFSIZE/field->bytepix;
spoonful = size<bowl?size:bowl;
for(; size>0; size -= spoonful)
{
if (spoonful>size)
spoonful = size;
bufdata = bufdata0;
QFREAD(bufdata, spoonful*field->bytepix, field->file,field->filename);
switch(field->bitpix)
{
case BP_BYTE:
if (field->bitsgn)
for (i=spoonful; i--;)
*(ptr++) = *(bufdata++)*bs + bz;
else
for (i=spoonful; i--;)
*(ptr++) = *((unsigned char *)bufdata++)*bs + bz;
break;
case BP_SHORT:
if (bswapflag)
swapbytes(bufdata, 2, spoonful);
if (field->bitsgn)
for (i=spoonful; i--; bufdata += sizeof(short))
*(ptr++) = *((short *)bufdata)*bs + bz;
else
for (i=spoonful; i--; bufdata += sizeof(USHORT))
*(ptr++) = *((USHORT *)bufdata)*bs + bz;
break;
case BP_LONG:
if (bswapflag)
swapbytes(bufdata, 4, spoonful);
if (field->bitsgn)
for (i=spoonful; i--; bufdata += sizeof(LONG))
*(ptr++) = *((LONG *)bufdata)*bs + bz;
else
for (i=spoonful; i--; bufdata += sizeof(ULONG))
*(ptr++) = *((ULONG *)bufdata)*bs + bz;
break;
case BP_FLOAT:
if (bswapflag)
swapbytes(bufdata, 4, spoonful);
for (i=spoonful; i--; bufdata += sizeof(float))
*(ptr++) = *((float *)bufdata)*bs + bz;
break;
case BP_DOUBLE:
if (bswapflag)
swapbytes(bufdata, 8, spoonful);
for (i=spoonful; i--; bufdata += sizeof(double))
*(ptr++) = *((double *)bufdata)*bs + bz;
break;
default:
error(EXIT_FAILURE,"*FATAL ERROR*: unknown BITPIX type in ",
"readdata()");
break;
}
}
break;
/*-- Compressed image */
case ICOMPRESS_BASEBYTE:
bufdata = field->compress_bufptr;
curval = field->compress_curval;
npix = field->compress_npix;
while (size--)
{
if (!(npix--))
{
if (curval != field->compress_checkval)
error(EXIT_FAILURE, "*Error*: invalid BASEBYTE checksum in ",
field->filename);
bufdata = field->compress_buf;
QFREAD(bufdata, FBSIZE, field->file, field->filename);
curval = 0;
if (bswapflag)
swapbytes(bufdata, 4, 1);
field->compress_checkval = *((int *)bufdata);
bufdata += 4;
if (bswapflag)
swapbytes(bufdata, 2, 1);
npix = (int)(*((short *)bufdata))-1;
bufdata+=2;
}
if ((dval=(int)*(bufdata++))==-128)
{
if (bswapflag)
swapbytes(bufdata, 2, 1);
memcpy(&val16, bufdata, 2);
dval = (int)val16;
if (dval==-32768)
{
bufdata += 2;
if (bswapflag)
swapbytes(bufdata, 4, 1);
memcpy(&dval,bufdata,4);
bufdata += 4;
}
else
bufdata += 2;
}
*(ptr++) = dval*bs + bz;
curval += dval;
}
field->compress_curval = curval;
field->compress_bufptr = bufdata;
field->compress_npix = npix;
break;
case ICOMPRESS_PREVPIX:
bufdata = field->compress_bufptr;
curval = field->compress_curval;
npix = field->compress_npix;
while (size--)
{
if (!(npix--))
{
if (curval != field->compress_checkval)
error(EXIT_FAILURE, "*Error*: invalid PREV_PIX checksum in ",
field->filename);
bufdata = field->compress_buf;
QFREAD(bufdata, FBSIZE, field->file, field->filename);
if (bswapflag)
swapbytes(bufdata, 2, 3);
curval = (int)*(short *)bufdata;
npix = (int)*(short *)(bufdata+=2)-1;
field->compress_checkval = (int)(*(short *)(bufdata+=2));
bufdata+=4;
}
if ((dval=(int)*(bufdata++))==-128)
{
if (bswapflag)
swapbytes(bufdata, 2, 1);
memcpy(&val16, bufdata, 2);
curval = (int)val16;
bufdata += 2;
}
else
curval += dval;
*(ptr++) = curval*bs + bz;
}
field->compress_curval = curval;
field->compress_bufptr = bufdata;
field->compress_npix = npix;
break;
default:
error(EXIT_FAILURE,"*Internal Error*: unknown compression mode in ",
"readdata()");
}
return;
}
/******************************** readidata *********************************/
/*
read and convert input data stream in FLAGTYPE (unsigned int) format.
*/
void readidata(picstruct *field, FLAGTYPE *ptr, int size)
{
static char bufdata0[DATA_BUFSIZE];
char *bufdata;
short val16;
int i, bowl, spoonful, npix, curval, dval;
switch(field->compress_type)
{
/*-- Uncompressed image */
case ICOMPRESS_NONE:
bowl = DATA_BUFSIZE/field->bytepix;
spoonful = size<bowl?size:bowl;
for(; size>0; size -= spoonful)
{
if (spoonful>size)
spoonful = size;
bufdata = bufdata0;
QFREAD(bufdata, spoonful*field->bytepix, field->file, field->filename);
switch(field->bitpix)
{
case BP_BYTE:
for (i=spoonful; i--;)
*(ptr++) = (FLAGTYPE)*((unsigned char *)bufdata++);
break;
case BP_SHORT:
if (bswapflag)
swapbytes(bufdata, 2, spoonful);
for (i=spoonful; i--; bufdata += sizeof(USHORT))
*(ptr++) = (FLAGTYPE)*((USHORT *)bufdata);
break;
case BP_LONG:
if (bswapflag)
swapbytes(bufdata, 4, spoonful);
for (i=spoonful; i--; bufdata += sizeof(ULONG))
*(ptr++) = (FLAGTYPE)*((ULONG *)bufdata);
break;
case BP_FLOAT:
case BP_DOUBLE:
error(EXIT_FAILURE,"*Error*: I was expecting integers in ",
field->filename);
break;
default:
error(EXIT_FAILURE,"*FATAL ERROR*: unknown BITPIX type in ",
"readdata()");
break;
}
}
break;
/*-- Compressed image */
case ICOMPRESS_BASEBYTE:
bufdata = field->compress_bufptr;
curval = field->compress_curval;
npix = field->compress_npix;
while (size--)
{
if (!(npix--))
{
if (curval != field->compress_checkval)
error(EXIT_FAILURE, "*Error*: invalid BASEBYTE checksum in ",
field->filename);
bufdata = field->compress_buf;
QFREAD(bufdata, FBSIZE, field->file, field->filename);
curval = 0;
if (bswapflag)
swapbytes(bufdata, 4, 1);
field->compress_checkval = *((int *)bufdata);
bufdata += 4;
if (bswapflag)
swapbytes(bufdata, 2, 1);
npix = (int)(*((short *)bufdata))-1;
bufdata+=2;
}
if ((dval=(int)*(bufdata++))==-128)
{
if (bswapflag)
swapbytes(bufdata, 2, 1);
memcpy(&val16, bufdata, 2);
dval = (int)val16;
if (dval==-32768)
{
bufdata += 2;
if (bswapflag)
swapbytes(bufdata, 4, 1);
memcpy(&dval,bufdata,4);
bufdata += 4;
}
else
bufdata += 2;
}
*(ptr++) = (FLAGTYPE)dval;
curval += dval;
}
field->compress_curval = curval;
field->compress_bufptr = bufdata;
field->compress_npix = npix;
break;
case ICOMPRESS_PREVPIX:
bufdata = field->compress_bufptr;
curval = field->compress_curval;
npix = field->compress_npix;
while (size--)
{
if (!(npix--))
{
if (curval != field->compress_checkval)
error(EXIT_FAILURE, "*Error*: invalid PREV_PIX checksum in ",
field->filename);
bufdata = field->compress_buf;
QFREAD(bufdata, FBSIZE, field->file, field->filename);
if (bswapflag)
swapbytes(bufdata, 2, 3);
curval = (int)*(short *)bufdata;
npix = (int)*(short *)(bufdata+=2)-1;
field->compress_checkval = (int)(*(short *)(bufdata+=2));
bufdata+=4;
}
if ((dval=(int)*(bufdata++))==-128)
{
if (bswapflag)
swapbytes(bufdata, 2, 1);
memcpy(&val16, bufdata, 2);
curval = (int)val16;
bufdata += 2;
}
else
curval += dval;
*(ptr++) = (FLAGTYPE)curval;
}
field->compress_curval = curval;
field->compress_bufptr = bufdata;
field->compress_npix = npix;
break;
default:
error(EXIT_FAILURE,"*Internal Error*: unknown compression mode in ",
"readdata()");
}
return;
}
/******************************* readimagehead *******************************/
/*
extract some data from the FITS-file header
*/
void readimagehead(picstruct *field)
{
int j,l, n;
char wstr1[TNX_MAXCHARS], wstr2[TNX_MAXCHARS],
st[80], str[80],
*buf, *point;
/* Open the file */
if (!(field->file = fopen(field->filename, "rb")))
error(EXIT_FAILURE,"*Error*: cannot open ", field->filename);
/* Go directly to the right extension */
if (field->mefpos)
{
QFSEEK(field->file, field->mefpos, SEEK_SET, field->filename);
}
buf = readfitshead(field->file, field->filename, &n);
if(FITSTOI("NAXIS ", 0) < 2)
#define FITSREADS(buf, k, str, def) \
{if (fitsread(buf,k,str, H_STRING,T_STRING) != RETURN_OK) \
strcpy(str, (def)); \
}
tabstruct *tab;
tab = field->tab;
if(tab->naxis < 2)
error(EXIT_FAILURE, field->filename, " does NOT contain 2D-data!");
/*---------------------------- Basic keywords ------------------------------*/
field->bitpix = FITSTOI("BITPIX ", 0);
if (field->bitpix != BP_BYTE
&& field->bitpix != BP_SHORT
&& field->bitpix != BP_LONG
&& field->bitpix != BP_FLOAT
&& field->bitpix != BP_DOUBLE)
if (tab->bitpix != BP_BYTE
&& tab->bitpix != BP_SHORT
&& tab->bitpix != BP_LONG
&& tab->bitpix != BP_FLOAT
&& tab->bitpix != BP_DOUBLE)
error(EXIT_FAILURE, "Sorry, I don't know that kind of data.", "");
field->bytepix = (field->bitpix>0?field->bitpix:-field->bitpix)>>3;
field->width = FITSTOI("NAXIS1 ", 0);
field->height = FITSTOI("NAXIS2 ", 0);
field->width = tab->naxisn[0];
field->height = tab->naxisn[1];
field->npix = (KINGSIZE_T)field->width*field->height;
field->bscale = FITSTOF("BSCALE ", 1.0);
field->bzero = FITSTOF("BZERO ", 0.0);
field->bitsgn = FITSTOI("BITSGN ", 1);
if (field->bitsgn && prefs.fitsunsigned_flag)
field->bitsgn = 0;
if (tab->bitsgn && prefs.fitsunsigned_flag)
tab->bitsgn = 0;
FITSTOS("OBJECT ", field->ident, "Unnamed");
/*----------------------------- Compression --------------------------------*/
if (fitsread(buf, "IMAGECOD", st, H_STRING, T_STRING)==RETURN_OK)
{
if (!strcmp(st, "NONE"))
field->compress_type = ICOMPRESS_NONE;
else if (!strcmp(st, "BASEBYTE"))
field->compress_type = ICOMPRESS_BASEBYTE;
else if (!strcmp(st, "PREV_PIX"))
field->compress_type = ICOMPRESS_PREVPIX;
else
warning("Compression skipped: unknown IMAGECOD parameter:", st);
}
FITSREADS(tab->headbuf, "OBJECT ", field->ident, "Unnamed");
/*----------------------------- Astrometry ---------------------------------*/
/* Presently, astrometry is done only on the measurement and detect images */
if (field->flags&(MEASURE_FIELD|DETECT_FIELD))
{
astromstruct *as;
double drota, s;
int naxis;
field->wcs = read_wcs(tab);
QCALLOC(as, astromstruct, 1);
field->astrom = as;
naxis = as->naxis = 2;
for (l=0; l<naxis; l++)
{
sprintf(str, "CTYPE%-3d", l+1);
FITSTOS(str, str, "");
strncpy(as->ctype[l], str, 8);
sprintf(str, "CUNIT%-3d", l+1);
FITSTOS(str, str, "deg");
strncpy(as->cunit[l], str, 32);
sprintf(str, "CRVAL%-3d", l+1);
as->crval[l] = FITSTOF(str, 0.0);
sprintf(str, "CRPIX%-3d", l+1);
as->crpix[l] = FITSTOF(str, 1.0);
sprintf(str, "CDELT%-3d", l+1);
as->cdelt[l] = FITSTOF(str, 1.0);
if (fabs(as->cdelt[l]) < 1/BIG)
error(EXIT_FAILURE, "*Error*: CDELT parameters out of range in ",
field->filename);
}
if (fitsnfind(buf, "CD1_1", n))
{
/*---- If CD keywords exist, use them for the linear mapping terms... */
for (l=0; l<naxis; l++)
for (j=0; j<naxis; j++)
{
sprintf(str, "CD%d_%d", l+1, j+1);
as->pc[l*naxis+j] = FITSTOF(str, l==j?1.0:0.0)/as->cdelt[l];
}
}
else if (fitsnfind(buf, "PC001001", n))
/*---- ...If PC keywords exist, use them for the linear mapping terms... */
for (l=0; l<naxis; l++)
for (j=0; j<naxis; j++)
{
sprintf(str, "PC%03d%03d", l+1, j+1);
as->pc[l*naxis+j] = FITSTOF(str, l==j?1.0:0.0);
}
else
{
/*---- ...otherwise take the obsolete CROTA2 parameter */
s = as->cdelt[1]/as->cdelt[0];
drota = FITSTOF("CROTA2 ", 0.0);
as->pc[3] = as->pc[0] = cos(drota*DEG);
as->pc[1] = -(as->pc[2] = sin(drota*DEG));
as->pc[1] *= s;
as->pc[2] /= s;
}
QMALLOC(as->wcs, struct wcsprm, 1);
/*-- Test if the WCS is recognized and a celestial pair is found */
if (prefs.world_flag
&& !wcsset(as->naxis,(const char(*)[9])as->ctype, as->wcs)
&& as->wcs->flag<999)
{
char *pstr;
double date;
int biss, dpar[3];
as->wcs_flag = 1;
/*---- Coordinate reference frame */
/*---- Search for an observation date expressed in Julian days */
date = FITSTOF("MJD-OBS ", -1.0);
/*---- Precession date (defined from Ephemerides du Bureau des Longitudes) */
/*---- in Julian years from 2000.0 */
if (date>0.0)
as->equinox = 2000.0 - (MJD2000 - date)/365.25;
else
{
/*------ Search for an observation date expressed in "civil" format */
FITSTOS("DATE-OBS", str, "");
if (*str)
{
/*-------- Decode DATE-OBS format: DD/MM/YY or YYYY-MM-DD */
for (l=0; l<3 && (pstr = strtok(l?NULL:str,"/- ")); l++)
dpar[l] = atoi(pstr);
if (l<3 || !dpar[0] || !dpar[1] || !dpar[2])
{
/*---------- If DATE-OBS value corrupted or incomplete, assume 2000-1-1 */
warning("Invalid DATE-OBS value in header: ", str);
dpar[0] = 2000; dpar[1] = 1; dpar[2] = 1;
}
else if (strchr(str, '/') && dpar[0]<32 && dpar[2]<100)
{
j = dpar[0];
dpar[0] = dpar[2]+1900;
dpar[2] = j;
}
biss = (dpar[0]%4)?0:1;
/*-------- Convert date to MJD */
date = -678956 + (365*dpar[0]+dpar[0]/4) - biss
+ ((dpar[1]>2?((int)((dpar[1]+1)*30.6)-63+biss)
:((dpar[1]-1)*(63+biss))/2) + dpar[2]);
as->equinox = 2000.0 - (MJD2000 - date)/365.25;
}
else
/*-------- Well if really no date is found */
as->equinox = 2000.0;
}
if (field->flags&MEASURE_FIELD)
prefs.epoch = as->equinox;
FITSTOS("RADECSYS", str, as->equinox<1984.0?
"FK4": (as->equinox<1999.9999? "FK5" : "ICRS"));
if (!strcmp(str, "ICRS"))
{
as->radecsys = RDSYS_ICRS;
as->equinox = FITSTOF("EQUINOX ", 2000.0);
}
else if (!strcmp(str, "FK5"))
{
as->radecsys = RDSYS_FK5;
as->equinox = FITSTOF("EQUINOX ", FITSTOF("EPOCH ", 2000.0));
if (field->flags&MEASURE_FIELD)
sprintf(prefs.coosys, "eq_FK5");
}
else if (!strcmp(str, "FK4"))
{
if (as->equinox == 2000.0)
as->equinox = FITSTOF("EQUINOX ", FITSTOF("EPOCH ", 1950.0));
as->radecsys = RDSYS_FK4;
warning("FK4 precession formulae not yet implemented:\n",
" Astrometry may be slightly inaccurate");
}
else if (!strcmp(str, "FK4-NO-E"))
{
if (as->equinox == 2000.0)
as->equinox = FITSTOF("EQUINOX ", FITSTOF("EPOCH ", 1950.0));
as->radecsys = RDSYS_FK4_NO_E;
warning("FK4 precession formulae not yet implemented:\n",
" Astrometry may be slightly inaccurate");
}
else if (!strcmp(str, "GAPPT"))
{
as->radecsys = RDSYS_GAPPT;
warning("GAPPT reference frame not yet implemented:\n",
" Astrometry may be slightly inaccurate");
}
else
{
warning("Using ICRS instead of unknown astrometric reference frame: ",
str);
as->radecsys = RDSYS_ICRS;
as->equinox = FITSTOF("EQUINOX ", 2000.0);
}
/*---- Projection parameters */
if (!strcmp(as->wcs->pcode, "TNX"))
{
/*---- IRAF's TNX projection: decode these #$!?@#!! WAT parameters */
if (fitsfind(buf, "WAT?????") != RETURN_ERROR)
{
/*-------- First we need to concatenate strings */
pstr = wstr1;
sprintf(str, "WAT1_001");
for (j=2; fitsread(buf,str,pstr,H_STRINGS,T_STRING)==RETURN_OK; j++)
{
sprintf(str, "WAT1_%03d", j);
pstr += strlen(pstr);
}
pstr = wstr2;
sprintf(str, "WAT2_001");
for (j=2; fitsread(buf,str,pstr,H_STRINGS,T_STRING)==RETURN_OK; j++)
{
sprintf(str, "WAT2_%03d", j);
pstr += strlen(pstr);
}
/*-------- LONGPOLE defaulted to 180 deg if not found */
if ((pstr = strstr(wstr1, "longpole"))
|| (pstr = strstr(wstr2, "longpole")))
pstr = strpbrk(pstr, "1234567890-+.");
as->longpole = pstr? atof(pstr) : 999.0;
as->latpole = 999.0;
/*-------- RO defaulted to 180/PI if not found */
if ((pstr = strstr(wstr1, "ro"))
|| (pstr = strstr(wstr2, "ro")))
pstr = strpbrk(pstr, "1234567890-+.");
as->r0 = pstr? atof(pstr) : 0.0;
/*-------- Read the remaining TNX parameters */
if ((pstr = strstr(wstr1, "lngcor"))
|| (pstr = strstr(wstr2, "lngcor")))
as->tnx_lngcor = read_tnxaxis(pstr);
if (!as->tnx_lngcor)
error(EXIT_FAILURE, "*Error*: incorrect TNX parameters in ",
field->filename);
if ((pstr = strstr(wstr1, "latcor"))
|| (pstr = strstr(wstr2, "latcor")))
as->tnx_latcor = read_tnxaxis(pstr);
if (!as->tnx_latcor)
error(EXIT_FAILURE, "*Error*: incorrect TNX parameters in ",
field->filename);
}
}
else
{
as->longpole = FITSTOF("LONGPOLE", 999.0);
as->latpole = FITSTOF("LATPOLE ", 999.0);
if (fitsnfind(buf, "PROJP1 ", n))
for (l=0; l<10; l++)
{
sprintf(str, "PROJP%-3d", l);
as->projp[l] = FITSTOF(str, 0.0);
}
}
}
else
{
/*---- No need to keep memory allocated for a useless WCS structure */
free(as->wcs);
as->wcs_flag = 0;
}
}
/*---------------------------------------------------------------------------*/
field->fitshead = buf;
field->fitsheadsize = n*FBSIZE;
QFSEEK(field->file, tab->bodypos, SEEK_SET, field->filename);
return;
}
#undef FITSREADS
/******************************* readfitshead ********************************/
/*
read data from the FITS-file header
*/
char *readfitshead(FILE *file, char *filename, int *nblock)
{
int n;
char *buf;
if (!(buf=(char *)malloc((size_t)FBSIZE)))
error(EXIT_FAILURE, "*Error*: Not enough memory in ", "readfitshead()");
/* Find the number of FITS blocks of the header while reading it */
QFREAD(buf, FBSIZE, file, filename);
if (strncmp(buf, "SIMPLE ", 8))
{
/* Ugly but necessary patch to handle this stupid DeNIS compressed format! */
if (strncmp(buf, "XTENSION", 8))
error(EXIT_FAILURE, filename, " is NOT a FITS file!");
/*
else
{
memset(buf, ' ', 80);
strncpy(buf,
"SIMPLE = T / Decompressed by SExtractor", 59);
}
*/
}
for (n=1; !fitsnfind(buf,"END ", n); n++)
{
if (!(buf=(char *)realloc(buf, (size_t)(FBSIZE*(n+1)))))
error(EXIT_FAILURE, "*Error*: Not enough memory in ", "readfitshead()");
QFREAD(buf+n*FBSIZE, FBSIZE, file, filename);
}
*nblock = n;
return buf;
}
......@@ -9,7 +9,7 @@
*
* Contents: functions to refine extraction of objects.
*
* Last modify: 27/11/2003
* Last modify: 10/01/2008
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
......@@ -315,7 +315,9 @@ int gatherup(objliststruct *objlistin, objliststruct *objlistout)
if (p[nobj-1] > 1.0e-31)
{
drand = p[nobj-1]*rand()/RAND_MAX;
for (i=1; p[i]<drand; i++);
for (i=1; i<nobj && p[i]<drand; i++);
if (i==nobj)
i=iclst;
}
else
i = iclst;
......
......@@ -10,7 +10,7 @@
* Contents: functions for extraction of connected pixels from
* a pixmap.
*
* Last modify: 29/11/2005
* Last modify: 11/01/2008
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
......@@ -47,7 +47,7 @@ INPUT Measurement field pointer,
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 29/11/2005
VERSION 11/01/2008
***/
void scanimage(picstruct *field, picstruct *dfield, picstruct **pffield,
int nffield, picstruct *wfield, picstruct *dwfield)
......@@ -128,11 +128,11 @@ void scanimage(picstruct *field, picstruct *dfield, picstruct **pffield,
/*Allocate memory for buffers */
stacksize = w+1;
QMALLOC(info, infostruct, stacksize);
QMALLOC(store, infostruct, stacksize);
QCALLOC(store, infostruct, stacksize);
QMALLOC(marker, char, stacksize);
QMALLOC(dumscan, PIXTYPE, stacksize);
QMALLOC(psstack, status, stacksize);
QMALLOC(start, int, stacksize);
QCALLOC(start, int, stacksize);
QMALLOC(end, int, stacksize);
blankpad = bpt = NULL;
lutzalloc(w,h);
......
......@@ -50,7 +50,7 @@ keystruct headkey[] = {
{"SEXNNWF ", "S/G classification NNW filename",
thecat.nnw_name, H_STRING, T_STRING, "%-18s"},
{"SEXGAIN ", "Gain used (e-/ADU)",
&prefs.gain, H_EXPO, T_DOUBLE, "%6.2f"},
&thefield2.gain, H_EXPO, T_DOUBLE, "%6.2f"},
{"SEXFLTR ", "Detection filtering activated (flag)",
&prefs.filter_flag, H_BOOL, T_LONG, "%1s"},
{"SEXFILTN", "Filter filename",
......@@ -88,7 +88,7 @@ keystruct headkey[] = {
{"SEXPETP2", "Parameter #2 used for Petrosian magnitudes",
&prefs.autoparam[1], H_FLOAT, T_DOUBLE, "%4.1f"},
{"SEXSATLV", "Saturation level used for flagging (ADU)",
&prefs.satur_level, H_EXPO, T_DOUBLE, "%-13G"},
&thefield2.satur_level, H_EXPO, T_DOUBLE, "%-13G"},
{"SEXMGZPT", "Zero-point used for magnitudes",
&prefs.mag_zeropoint, H_FLOAT, T_DOUBLE, "%8.4f"},
{"SEXMGGAM", "Gamma used for photographic photometry",
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment