Commit 3b348a94 authored by Emmanuel Bertin's avatar Emmanuel Bertin
Browse files

Changed trunk directory name

parents
/*
photom.h
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: SExtractor
*
* Author: E.BERTIN, IAP & Leiden observatory
*
* Contents: Include file for photom.h.
*
* Last modify: 22/10/2004
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
/*----------------------------- Internal constants --------------------------*/
#define APER_OVERSAMP 5 /* oversampling in each dimension (MAG_APER) */
#define KRON_NSIG 3*MARGIN_SCALE /* MAG_AUTO analysis range (number */
/* of sigma) */
#define PETRO_NSIG 3*MARGIN_SCALE /* MAG_PETRO analysis range (number */
/* of sigma) */
#define CROWD_THRESHOLD 0.1 /* The OBJ_CROWDED flag is set if photometric*/
/* contamination may exceed this fraction of */
/* flux */
/* NOTES:
One must have: APER_OVERSAMP >= 1
KRON_NSIG > 0.0
PETRO_NSIG > 0.0
CROWD_THRESHOLD >= 0
*/
/*------------------------------- functions ---------------------------------*/
extern void computeaperflux(picstruct *, picstruct *, objstruct *, int),
computeautoflux(picstruct *, picstruct *, picstruct *,
picstruct *, objstruct *),
computeisocorflux(picstruct *, objstruct *),
computemags(picstruct *, objstruct *),
computepetroflux(picstruct *, picstruct *, picstruct *,
picstruct *, objstruct *);
/*
plist.c
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: SExtractor
*
* Author: E.BERTIN (IAP)
*
* Contents: functions dealing with the handling of pixel lists.
*
* Last modify: 29/11/2005
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include "define.h"
#include "globals.h"
#include "prefs.h"
#include "plist.h"
/******************************** createblank *******************************
PROTO int createblank(int no, objliststruct *objlist)
PURPOSE Create pixel map for BLANKing.
INPUT objlist number,
objlist pointer,
OUTPUT RETURN_OK if success, RETURN_FATAL_ERROR otherwise (memory overflow).
NOTES -.
AUTHOR E. Bertin (IAP & Leiden & ESO)
VERSION 27/11/2003
***/
int createblank(objliststruct *objlist, int no)
{
objstruct *obj;
pliststruct *pixel, *pixt;
int i, n, pos, xmin,ymin, w, dflag;
PIXTYPE *pix, *dpix, *pt;
obj = objlist->obj+no;
pixel = objlist->plist;
dpix = NULL; /* To avoid gcc -Wall warnings */
dflag = prefs.dimage_flag;
obj->subx = xmin = obj->xmin;
obj->suby = ymin = obj->ymin;
obj->subw = w = obj->xmax - xmin + 1;
obj->subh = obj->ymax - ymin + 1;
n = w*obj->subh;
if (!(obj->blank = pix = (PIXTYPE *)malloc(n*sizeof(PIXTYPE))))
return RETURN_FATAL_ERROR;
pt = pix;
for (i=n; i--;)
*(pt++) = -BIG;
if (dflag)
{
if (!(obj->dblank = dpix = (PIXTYPE *)malloc(n*sizeof(PIXTYPE))))
{
free(pix);
return RETURN_FATAL_ERROR;
}
pt = dpix;
for (i=n; i--;)
*(pt++) = -BIG;
}
else
obj->dblank = NULL;
for (i=obj->firstpix; i!=-1; i=PLIST(pixt,nextpix))
{
pixt = pixel+i;
pos = (PLIST(pixt,x)-xmin) + (PLIST(pixt,y)-ymin)*w;
*(pix+pos) = PLIST(pixt, value);
if (dflag)
*(dpix+pos) = PLISTPIX(pixt, dvalue);
}
return RETURN_OK;
}
/******************************** createsubmap *******************************
PROTO int createpixmap(int no, objliststruct *objlist)
PURPOSE Create pixel-index submap for deblending.
INPUT objlist number,
objlist pointer,
OUTPUT RETURN_OK if success, RETURN_FATAL_ERROR otherwise (memory overflow).
NOTES -.
AUTHOR E. Bertin (IAP & Leiden & ESO)
VERSION 08/10/97
***/
int createsubmap(objliststruct *objlist, int no)
{
objstruct *obj;
pliststruct *pixel, *pixt;
int i, n, xmin,ymin, w, *pix, *pt;
obj = objlist->obj+no;
pixel = objlist->plist;
obj->subx = xmin = obj->xmin;
obj->suby = ymin = obj->ymin;
obj->subw = w = obj->xmax - xmin + 1;
obj->subh = obj->ymax - ymin + 1;
n = w*obj->subh;
if (!(obj->submap = pix = (int *)malloc(n*sizeof(int))))
return RETURN_FATAL_ERROR;
pt = pix;
for (i=n; i--;)
*(pt++) = -1;
for (i=obj->firstpix; i!=-1; i=PLIST(pixt,nextpix))
{
pixt = pixel+i;
*(pix+(PLIST(pixt,x)-xmin) + (PLIST(pixt,y)-ymin)*w) = i;
}
return RETURN_OK;
}
/****************************** init_plist ************************************
PROTO pliststruct *init_plist(void)
PURPOSE initialize a pixel-list and its components.
INPUT -.
OUTPUT -.
NOTES The preparation of components relies on the preferences.
AUTHOR E. Bertin (IAP, Leiden observatory & ESO)
VERSION 29/11/2005
***/
void init_plist(void)
{
pbliststruct *pbdum = NULL;
int i;
plistsize = sizeof(pbliststruct);
plistoff_value = (char *)&pbdum->value - (char *)pbdum;
if (prefs.dimage_flag)
{
plistexist_dvalue = 1;
plistoff_dvalue = plistsize;
plistsize += sizeof(PIXTYPE);
}
else
{
plistexist_dvalue = 0;
plistoff_dvalue = plistoff_value;
}
if (prefs.filter_flag)
{
plistexist_cdvalue = 1;
plistoff_cdvalue = plistsize;
plistsize += sizeof(PIXTYPE);
}
else
{
plistexist_cdvalue = 0;
plistoff_cdvalue = plistoff_dvalue;
}
if (VECFLAG(obj.imaflag))
{
plistexist_flag = 1;
for (i=0; i<prefs.nimaisoflag; i++)
{
plistoff_flag[i] = plistsize;
plistsize += sizeof(FLAGTYPE);
}
}
else
plistexist_flag = 0;
if (FLAG(obj.wflag))
{
plistexist_wflag = 1;
plistoff_wflag = plistsize;
plistsize += sizeof(FLAGTYPE);
}
else
plistexist_wflag = 0;
if (prefs.weight_flag)
{
plistexist_var = 1;
plistoff_var = plistsize;
plistsize += sizeof(PIXTYPE);
}
else
plistexist_var = 0;
if (prefs.dweight_flag)
{
plistexist_dthresh = 1;
plistoff_dthresh = plistsize;
plistsize += sizeof(PIXTYPE);
}
else
plistexist_dthresh = 0;
return;
}
/*
plist.h
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: SExtractor
*
* Author: E.BERTIN, (IAP)
*
* Contents: functions dealing with the handling of pixel lists.
*
* Last modify: 29/11/2005
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
/*------------------------------- definitions -------------------------------*/
#define PLIST(ptr, elem) (((pbliststruct *)(ptr))->elem)
#define PLISTEXIST(elem) (plistexist_##elem)
#define PLISTPIX(ptr, elem) (*((PIXTYPE *)((ptr)+plistoff_##elem)))
#define PLISTFLAG(ptr, elem) (*((FLAGTYPE *)((ptr)+plistoff_##elem)))
/*------------------------------- structures --------------------------------*/
typedef struct
{
int nextpix;
int x, y;
PIXTYPE value;
} pbliststruct;
/*-------------------------------- globals ----------------------------------*/
int plistexist_value, plistexist_dvalue, plistexist_cdvalue,
plistexist_flag, plistexist_wflag, plistexist_dthresh, plistexist_var,
plistoff_value, plistoff_dvalue, plistoff_cdvalue,
plistoff_flag[MAXFLAG], plistoff_wflag, plistoff_dthresh, plistoff_var,
plistsize;
/*------------------------------- functions ---------------------------------*/
void init_plist(void);
int createblank(objliststruct *objlist, int n),
createsubmap(objliststruct *objlist, int n);
/*
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);
/*
preflist.h
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: SExtractor
*
* Author: E.BERTIN (IAP)
*
* Contents: Keywords for the configuration file.
*
* Last modify: 31/07/2007
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
#include "key.h"
#ifndef _XML_H_
#include "xml.h"
#endif
#ifdef USE_THREADS
#define THREADS_PREFMAX THREADS_NMAX
#else
#define THREADS_PREFMAX 65535
#endif
/*-------------------------------- initialization ---------------------------*/
int idummy;
pkeystruct key[] =
{
{"ANALYSIS_THRESH", P_FLOATLIST, prefs.thresh, 0,0, -BIG, BIG,
{""}, 1, 2, &prefs.nthresh},
{"ASSOC_DATA", P_INTLIST, prefs.assoc_data, 0, 1000000,0.0,0.0,
{""}, 1,MAXLIST, &prefs.nassoc_data},
{"ASSOC_NAME", P_STRING, prefs.assoc_name},
{"ASSOC_PARAMS", P_INTLIST, prefs.assoc_param, 1, 1000000,0.0,0.0,
{""}, 2,3, &prefs.nassoc_param},
{"ASSOC_RADIUS", P_FLOAT, &prefs.assoc_radius, 0,0, 1e-10,1e+10},
{"ASSOC_TYPE", P_KEY, &prefs.assoc_type, 0,0, 0.0,0.0,
{"FIRST", "NEAREST", "MEAN", "MAG_MEAN", "SUM", "MAG_SUM",
"MIN", "MAX", ""}},
{"ASSOCSELEC_TYPE", P_KEY, &prefs.assocselec_type, 0,0, 0.0,0.0,
{"ALL","MATCHED","-MATCHED",""}},
{"BACK_FILTERSIZE", P_INTLIST, prefs.backfsize, 1,11, 0.0,0.0,
{""}, 1,2, &prefs.nbackfsize},
{"BACK_FILTTHRESH", P_FLOAT, &prefs.backfthresh, 0,0, 0.0,BIG},
{"BACKPHOTO_THICK", P_INT, &prefs.pback_size, 1, 256},
{"BACKPHOTO_TYPE", P_KEY, &prefs.pback_type, 0,0, 0.0,0.0,
{"GLOBAL","LOCAL",""}},
{"BACK_SIZE", P_INTLIST, prefs.backsize, 1,2000000000, 0.0,0.0,
{""}, 1,2, &prefs.nbacksize},
{"BACK_TYPE", P_KEYLIST, prefs.back_type, 0,0, 0.0,0.0,
{"AUTO","MANUAL",""},
1, 2, &prefs.nback_type},
{"BACK_VALUE", P_FLOATLIST, prefs.back_val, 0,0, -BIG,BIG,
{""}, 1, 2, &prefs.nback_val},
{"CATALOG_NAME", P_STRING, prefs.cat_name},
{"CATALOG_TYPE", P_KEY, &prefs.cat_type, 0,0, 0.0,0.0,
{"NONE", "ASCII","ASCII_HEAD", "ASCII_SKYCAT", "ASCII_VOTABLE",
"FITS_LDAC", "FITS_TPX", "FITS_1.0",""}},
{"CHECKIMAGE_NAME", P_STRINGLIST, prefs.check_name, 0,0,0.0,0.0,
{""}, 0, MAXCHECK, &prefs.ncheck_name},
{"CHECKIMAGE_TYPE", P_KEYLIST, prefs.check_type, 0,0, 0.0,0.0,
{"NONE", "IDENTICAL",
"BACKGROUND", "BACKGROUND_RMS", "MINIBACKGROUND",
"MINIBACK_RMS", "-BACKGROUND",
"FILTERED", "OBJECTS", "APERTURES", "SEGMENTATION", "ASSOC",
"-OBJECTS", "-PSF_PROTOS", "PSF_PROTOS",
"-PC_CONVPROTOS", "PC_CONVPROTOS", "PC_PROTOS", ""},
0, 17, &prefs.ncheck_type},
{"CLEAN", P_BOOL, &prefs.clean_flag},
{"CLEAN_PARAM", P_FLOAT, &prefs.clean_param, 0,0, 0.1,10.0},
{"DEBLEND_MINCONT", P_FLOAT, &prefs.deblend_mincont, 0,0, 0.0,1.0},
{"DEBLEND_NTHRESH", P_INT, &prefs.deblend_nthresh, 1,64},
{"DETECT_MINAREA", P_INT, &prefs.ext_minarea, 1,1000000},
{"DETECT_THRESH", P_FLOATLIST, prefs.dthresh, 0,0, -BIG, BIG,
{""}, 1, 2, &prefs.ndthresh},
{"DETECT_TYPE", P_KEY, &prefs.detect_type, 0,0, 0.0,0.0,
{"CCD","PHOTO",""}},
{"FILTER", P_BOOL, &prefs.filter_flag},
{"FILTER_NAME", P_STRING, prefs.filter_name},
{"FILTER_THRESH", P_FLOATLIST, prefs.filter_thresh, 0,0,-BIG,BIG,
{""}, 0, 2, &prefs.nfilter_thresh},
{"FITS_UNSIGNED", P_BOOL, &prefs.fitsunsigned_flag},
{"FLAG_IMAGE", P_STRINGLIST, prefs.fimage_name, 0,0,0.0,0.0,
{""}, 0, MAXFLAG, &prefs.nfimage_name},
{"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,
{""}, 1, 2, &prefs.ninterp_ytimeout},
{"INTERP_TYPE", P_KEYLIST, prefs.interp_type, 0,0, 0.0,0.0,
{"NONE","VAR_ONLY","ALL",""}, 1, 2, &prefs.ninterp_type},
{"MAG_GAMMA", P_FLOAT, &prefs.mag_gamma, 0,0, 1e-10,1e+30},
{"MAG_ZEROPOINT", P_FLOAT, &prefs.mag_zeropoint, 0,0, -100.0, 100.0},
{"MASK_TYPE", P_KEY, &prefs.mask_type, 0,0, 0.0,0.0,
{"NONE","BLANK","CORRECT",""}},
{"MEMORY_BUFSIZE", P_INT, &prefs.mem_bufsize, 8, 65534},
{"MEMORY_OBJSTACK", P_INT, &prefs.clean_stacksize, 16,65536},
{"MEMORY_PIXSTACK", P_INT, &prefs.mem_pixstack, 1000, 10000000},
{"NTHREADS", P_INT, &prefs.nthreads, 0, THREADS_PREFMAX},
{"PARAMETERS_NAME", P_STRING, prefs.param_name},
{"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,
{""}, 2,2, &prefs.nautoparam},
{"PHOT_AUTOAPERS", P_FLOATLIST, prefs.autoaper, 0,0, 0.0,1e6,
{""}, 2,2, &prefs.nautoaper},
{"PHOT_FLUXFRAC", P_FLOATLIST, prefs.flux_frac, 0,0, 1e-6, 1.0,
{""}, 1, MAXNAPER, &prefs.nflux_frac},
{"PHOT_PETROPARAMS", P_FLOATLIST, prefs.petroparam, 0,0, 0.0,10.0,
{""}, 2,2, &prefs.npetroparam},
{"PIXEL_SCALE", P_FLOAT, &prefs.pixel_scale, 0,0, 0.0, 1e+10},
{"PSF_NAME", P_STRINGLIST, prefs.psf_name, 0,0, 0.0,0.0,
{""}, 1, 2, &prefs.npsf_name}, /*?*/
{"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_LEVEL", P_FLOAT, &prefs.satur_level, 0,0, -1e+30, 1e+30},
{"SATUR_KEY", P_STRING, prefs.satur_key},
{"SEEING_FWHM", P_FLOAT, &prefs.seeing_fwhm, 0,0, 1e-10, 1e+10},
{"SOM_NAME", P_STRING, prefs.som_name},
{"STARNNW_NAME", P_STRING, prefs.nnw_name},
{"THRESH_TYPE", P_KEYLIST, prefs.thresh_type, 0,0, 0.0,0.0,
{"RELATIVE","ABSOLUTE"},
1, 2, &prefs.nthresh_type},
{"VERBOSE_TYPE", P_KEY, &prefs.verbose_type, 0,0, 0.0,0.0,
{"QUIET","NORMAL", "EXTRA_WARNINGS", "FULL",""}},
{"WEIGHT_GAIN", P_BOOL, &prefs.weightgain_flag},
{"WEIGHT_IMAGE", P_STRINGLIST, prefs.wimage_name, 0,0,0.0,0.0,
{""}, 0, MAXIMAGE, &prefs.nwimage_name},
{"WEIGHT_THRESH", P_FLOATLIST, prefs.weight_thresh, 0,0, 0.0, BIG,
{""}, 0, 2, &prefs.nweight_thresh},
{"WEIGHT_TYPE", P_KEYLIST, prefs.weight_type, 0,0, 0.0,0.0,
{"NONE","BACKGROUND", "MAP_RMS", "MAP_VAR","MAP_WEIGHT", ""},
0, MAXIMAGE, &prefs.nweight_type},
{"WRITE_XML", P_BOOL, &prefs.xml_flag},
{"XML_NAME", P_STRING, prefs.xml_name},
{"XSL_URL", P_STRING, prefs.xsl_name},
{""}
};
char keylist[sizeof(key)/sizeof(pkeystruct)][32];
const char notokstr[] = {" \t=,;\n\r\""};
char *default_prefs[] =
{
"# Default configuration file for " BANNER " " MYVERSION,
"# EB " DATE,
"#",
" ",
"#-------------------------------- Catalog ------------------------------------",
" ",
"CATALOG_NAME test.cat # name of the output catalog",
"CATALOG_TYPE ASCII_HEAD # NONE,ASCII,ASCII_HEAD, ASCII_SKYCAT,",
" # ASCII_VOTABLE, FITS_1.0 or FITS_LDAC",
"PARAMETERS_NAME default.param # name of the file containing catalog contents",
" ",
"#------------------------------- Extraction ----------------------------------",
" ",
"DETECT_TYPE CCD # CCD (linear) or PHOTO (with gamma correction)",
"DETECT_MINAREA 5 # minimum number of pixels above threshold",
"*THRESH_TYPE RELATIVE # threshold type: RELATIVE (in sigmas)",
"* # or ABSOLUTE (in ADUs)",
"DETECT_THRESH 1.5 # <sigmas> or <threshold>,<ZP> in mag.arcsec-2",
"ANALYSIS_THRESH 1.5 # <sigmas> or <threshold>,<ZP> in mag.arcsec-2",
" ",
"FILTER Y # apply filter for detection (Y or N)?",
"FILTER_NAME default.conv # name of the file containing the filter",
"*FILTER_THRESH # Threshold[s] for retina filtering",
" ",
"DEBLEND_NTHRESH 32 # Number of deblending sub-thresholds",
"DEBLEND_MINCONT 0.005 # Minimum contrast parameter for deblending",
" ",
"CLEAN Y # Clean spurious detections? (Y or N)?",
"CLEAN_PARAM 1.0 # Cleaning efficiency",
" ",
"MASK_TYPE CORRECT # type of detection MASKing: can be one of",
" # NONE, BLANK or CORRECT",
" ",
"*#-------------------------------- WEIGHTing ----------------------------------",
"*",
"*WEIGHT_TYPE NONE # type of WEIGHTing: NONE, BACKGROUND,",
"* # MAP_RMS, MAP_VAR or MAP_WEIGHT",
"*WEIGHT_IMAGE weight.fits # weight-map filename",
"*WEIGHT_GAIN Y # modulate gain (E/ADU) with weights? (Y/N)",
"*WEIGHT_THRESH # weight threshold[s] for bad pixels",
"*",
"*#-------------------------------- FLAGging -----------------------------------",
"*",
"*FLAG_IMAGE flag.fits # filename for an input FLAG-image",
"*FLAG_TYPE OR # flag pixel combination: OR, AND, MIN, MAX",
"* # or MOST",
"*",
"#------------------------------ Photometry -----------------------------------",
" ",
"PHOT_APERTURES 5 # MAG_APER aperture diameter(s) in pixels",
"PHOT_AUTOPARAMS 2.5, 3.5 # MAG_AUTO parameters: <Kron_fact>,<min_radius>",
"PHOT_PETROPARAMS 2.0, 3.5 # MAG_PETRO parameters: <Petrosian_fact>,",
" # <min_radius>",
"*PHOT_AUTOAPERS 0.0,0.0 # <estimation>,<measurement> minimum apertures",
"* # for MAG_AUTO and MAG_PETRO",
"*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 ----------------------------",
" ",
"SEEING_FWHM 1.2 # stellar FWHM in arcsec",
"STARNNW_NAME default.nnw # Neural-Network_Weight table filename",
" ",
"#------------------------------ Background -----------------------------------",
" ",
"*BACK_TYPE AUTO # AUTO or MANUAL",
"*BACK_VALUE 0.0 # Default background value in MANUAL mode",
"BACK_SIZE 64 # Background mesh: <size> or <width>,<height>",
"BACK_FILTERSIZE 3 # Background filter: <size> or <width>,<height>",
" ",
"BACKPHOTO_TYPE GLOBAL # can be GLOBAL or LOCAL",
"*BACKPHOTO_THICK 24 # thickness of the background LOCAL annulus",
"*BACK_FILTTHRESH 0.0 # Threshold above which the background-",
"* # map filter operates",
" ",
"#------------------------------ Check Image ----------------------------------",
" ",
"CHECKIMAGE_TYPE NONE # can be NONE, BACKGROUND, BACKGROUND_RMS,",
" # MINIBACKGROUND, MINIBACK_RMS, -BACKGROUND,",
" # FILTERED, OBJECTS, -OBJECTS, SEGMENTATION,",
" # or APERTURES",
"CHECKIMAGE_NAME check.fits # Filename for the check-image",
" ",
"#--------------------- Memory (change with caution!) -------------------------",
" ",
"MEMORY_OBJSTACK 3000 # number of objects in stack",
"MEMORY_PIXSTACK 300000 # number of pixels in stack",
"MEMORY_BUFSIZE 1024 # number of lines in buffer",
" ",
"*#------------------------------- ASSOCiation ---------------------------------",
"*",
"*ASSOC_NAME sky.list # name of the ASCII file to ASSOCiate",
"*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,",
"* # MAG_MEAN, SUM, MAG_SUM, MIN or MAX",
"*ASSOCSELEC_TYPE MATCHED # ASSOC selection type: ALL, MATCHED or -MATCHED",
"*",
"#----------------------------- Miscellaneous ---------------------------------",
" ",
"VERBOSE_TYPE NORMAL # can be QUIET, NORMAL or FULL",
"WRITE_XML N # Write XML file (Y/N)?",
"XML_NAME sex.xml # Filename for XML output",
"*XSL_URL " XSL_URL,
"* # Filename for XSL style-sheet",
#ifdef USE_THREADS
"*NTHREADS 0 # Number of simultaneous threads for",
"* # the SMP version of " BANNER,
"* # 0 = automatic",
#else
"*NTHREADS 1 # 1 single thread",
#endif
"*",
"*FITS_UNSIGNED N # Treat FITS integer values as unsigned (Y/N)?",
"*INTERP_MAXXLAG 16 # Max. lag along X for 0-weight interpolation",
"*INTERP_MAXYLAG 16 # Max. lag along Y for 0-weight interpolation",
"*INTERP_TYPE ALL # Interpolation type: NONE, VAR_ONLY or ALL",
"*",
"*#--------------------------- Experimental Stuff -----------------------------",
"*",
"*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",
"*SOM_NAME default.som # File containing Self-Organizing Map weights",
""
};
/*
prefs.c
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: SExtractor
*
* Author: E.BERTIN (IAP)
*
* Contents: Functions to handle the configuration file.
*
* Last modify: 10/04/2007
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "define.h"
#include "globals.h"
#include "prefs.h"
#include "preflist.h"
#include "fits/fitscat.h"
/********************************* dumpprefs ********************************/
/*
Print the default preference parameters.
*/
void dumpprefs(int state)
{
char **dp;
dp = default_prefs;
while (**dp)
if (**dp != '*')
printf("%s\n",*(dp++));
else if (state)
printf("%s\n",*(dp++)+1);
else
dp++;
return;
}
/********************************* readprefs ********************************/
/*
Read a configuration file in ``standard'' format (see the SExtractor
documentation)
*/
void readprefs(char *filename, char **argkey, char **argval, int narg)
{
FILE *infile;
char *cp, str[MAXCHARL], *keyword, *value, **dp;
int i, ival, nkey, warn, argi, flagc, flagd, flage, flagz;
float dval;
#ifndef NO_ENVVAR
static char value2[MAXCHARL],envname[MAXCHAR];
char *dolpos;
#endif
if ((infile = fopen(filename,"r")) == NULL)
{
flage = 1;
warning(filename, " not found, using internal defaults");
}
else
flage = 0;
/*Build the keyword-list from pkeystruct-array */
for (i=0; key[i].name[0]; i++)
strcpy(keylist[i], key[i].name);
keylist[i][0] = '\0';
/*Scan the configuration file*/
argi=0;
flagc = 0;
flagd = 1;
dp = default_prefs;
for (warn=0;;)
{
if (flagd)
{
if (**dp)
{
if (**dp=='*')
strcpy(str, *(dp++)+1);
else
strcpy(str, *(dp++));
}
else
flagd = 0;
}
if (!flagc && !flagd)
if (flage || !fgets(str, MAXCHARL, infile))
flagc=1;
if (flagc)
{
if (argi<narg)
{
sprintf(str, "%s %s", argkey[argi], argval[argi]);
argi++;
}
else
break;
}
keyword = strtok(str, notokstr);
if (keyword && keyword[0]!=0 && keyword[0]!=(char)'#')
{
if (warn>=10)
error(EXIT_FAILURE, "*Error*: No valid keyword found in ", filename);
nkey = findkeys(keyword, keylist, FIND_STRICT);
if (nkey!=RETURN_ERROR)
{
value = strtok((char *)NULL, notokstr);
#ifndef NO_ENVVAR
/*------ Expansion of environment variables (preceded by '$') */
if (value && (dolpos=strchr(value, '$')))
{
int nc;
char *valuet,*value2t, *envval;
value2t = value2;
valuet = value;
while (dolpos)
{
while (valuet<dolpos)
*(value2t++) = *(valuet++); /* verbatim copy before '$' */
if (*(++valuet) == (char)'{')
valuet++;
strncpy(envname, valuet, nc=strcspn(valuet,"}/:\"\'\\"));
*(envname+nc) = (char)'\0';
if (*(valuet+=nc) == (char)'}')
valuet++;
if (!(envval=getenv(envname)))
error(EXIT_FAILURE, "Environment variable not found: ",
envname);
while(*envval) /* Copy the ENV content */
*(value2t++) = *(envval++);
while(*valuet && *valuet!=(char)'$')/* Continue verbatim copy */
*(value2t++) = *(valuet++);
if (*valuet)
dolpos = valuet;
else
{
dolpos = NULL;
*value2t = (char)'\0';
}
}
value = value2;
}
#endif
switch(key[nkey].type)
{
case P_FLOAT:
if (!value || value[0]==(char)'#')
error(EXIT_FAILURE, keyword," keyword has no value!");
dval = atof(value);
if (dval>=key[nkey].dmin && dval<=key[nkey].dmax)
*(double *)(key[nkey].ptr) = dval;
else
error(EXIT_FAILURE, keyword," keyword out of range");
break;
case P_INT:
if (!value || value[0]==(char)'#')
error(EXIT_FAILURE, keyword," keyword has no value!");
ival = atoi(value);
if (ival>=key[nkey].imin && ival<=key[nkey].imax)
*(int *)(key[nkey].ptr) = ival;
else
error(EXIT_FAILURE, keyword, " keyword out of range");
break;
case P_STRING:
if (!value || value[0]==(char)'#')
error(EXIT_FAILURE, keyword," string is empty!");
strcpy((char *)key[nkey].ptr, value);
break;
case P_BOOL:
if (!value || value[0]==(char)'#')
error(EXIT_FAILURE, keyword," keyword has no value!");
if ((cp = strchr("yYnN", (int)value[0])))
*(int *)(key[nkey].ptr) = (tolower((int)*cp)=='y')?1:0;
else
error(EXIT_FAILURE, keyword, " value must be Y or N");
break;
case P_KEY:
if (!value || value[0]==(char)'#')
error(EXIT_FAILURE, keyword," keyword has no value!");
if ((ival = findkeys(value, key[nkey].keylist,FIND_STRICT))
!= RETURN_ERROR)
*(int *)(key[nkey].ptr) = ival;
else
error(EXIT_FAILURE, keyword, " set to an unknown keyword");
break;
case P_BOOLLIST:
for (i=0; i<MAXLIST&&value&&value[0]!=(char)'#'; i++)
{
if (i>=key[nkey].nlistmax)
error(EXIT_FAILURE, keyword, " has too many members");
if ((cp = strchr("yYnN", (int)value[0])))
((int *)(key[nkey].ptr))[i] = (tolower((int)*cp)=='y')?1:0;
else
error(EXIT_FAILURE, keyword, " value must be Y or N");
value = strtok((char *)NULL, notokstr);
}
if (i<key[nkey].nlistmin)
error(EXIT_FAILURE, keyword, " list has not enough members");
*(key[nkey].nlistptr) = i;
break;
case P_INTLIST:
for (i=0; i<MAXLIST&&value&&value[0]!=(char)'#'; i++)
{
if (i>=key[nkey].nlistmax)
error(EXIT_FAILURE, keyword, " has too many members");
ival = strtol(value, NULL, 0);
if (ival>=key[nkey].imin && ival<=key[nkey].imax)
((int *)key[nkey].ptr)[i] = ival;
else
error(EXIT_FAILURE, keyword, " keyword out of range");
value = strtok((char *)NULL, notokstr);
}
if (i<key[nkey].nlistmin)
error(EXIT_FAILURE, keyword, " list has not enough members");
*(key[nkey].nlistptr) = i;
break;
case P_FLOATLIST:
for (i=0; i<MAXLIST&&value&&value[0]!=(char)'#'; i++)
{
if (i>=key[nkey].nlistmax)
error(EXIT_FAILURE, keyword, " has too many members");
dval = atof(value);
if (dval>=key[nkey].dmin && dval<=key[nkey].dmax)
((double *)key[nkey].ptr)[i] = dval;
else
error(EXIT_FAILURE, keyword, " keyword out of range");
value = strtok((char *)NULL, notokstr);
}
if (i<key[nkey].nlistmin)
error(EXIT_FAILURE, keyword, " list has not enough members");
*(key[nkey].nlistptr) = i;
break;
case P_KEYLIST:
for (i=0; i<MAXLIST && value && value[0]!=(char)'#'; i++)
{
if (i>=key[nkey].nlistmax)
error(EXIT_FAILURE, keyword, " has too many members");
if ((ival = findkeys(value, key[nkey].keylist, FIND_STRICT))
!= RETURN_ERROR)
((int *)(key[nkey].ptr))[i] = ival;
else
error(EXIT_FAILURE, keyword, " set to an unknown keyword");
value = strtok((char *)NULL, notokstr);
}
if (i<key[nkey].nlistmin)
error(EXIT_FAILURE, keyword, " list has not enough members");
*(key[nkey].nlistptr) = i;
break;
case P_STRINGLIST:
if (!value || value[0]==(char)'#')
{
value = "";
flagz = 1;
}
else
flagz = 0;
for (i=0; i<MAXLIST && value && value[0]!=(char)'#'; i++)
{
if (i>=key[nkey].nlistmax)
error(EXIT_FAILURE, keyword, " has too many members");
free(((char **)key[nkey].ptr)[i]);
QMALLOC(((char **)key[nkey].ptr)[i], char, MAXCHAR);
strcpy(((char **)key[nkey].ptr)[i], value);
value = strtok((char *)NULL, notokstr);
}
if (i<key[nkey].nlistmin)
error(EXIT_FAILURE, keyword, " list has not enough members");
*(key[nkey].nlistptr) = flagz?0:i;
break;
default:
error(EXIT_FAILURE, "*Internal ERROR*: Type Unknown",
" in readprefs()");
break;
}
key[nkey].flag = 1;
}
else
{
warning(keyword, " keyword unknown");
warn++;
}
}
}
for (i=0; key[i].name[0]; i++)
if (!key[i].flag)
error(EXIT_FAILURE, key[i].name, " configuration keyword missing");
if (!flage)
fclose(infile);
return;
}
/********************************** findkeys **********************************/
/*
find an item within a list of keywords, SExtractor version.
*/
int findkeys(char *str, char keyw[][32], int mode)
{
int i;
for (i=0; keyw[i][0]; i++)
if (!cistrcmp(str, keyw[i], mode))
return i;
return RETURN_ERROR;
}
/******************************* cistrcmp ***********************************/
/*
case-insensitive strcmp.
*/
int cistrcmp(char *cs, char *ct, int mode)
{
int i, diff;
if (mode)
{
for (i=0; cs[i]&&ct[i]; i++)
if ((diff=tolower((int)cs[i])-tolower((int)ct[i])))
return diff;
}
else
{
for (i=0; cs[i]||ct[i]; i++)
if ((diff=tolower((int)cs[i])-tolower((int)ct[i])))
return diff;
}
return 0;
}
/********************************* useprefs **********************************/
/*
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);
/*--------------------------------- ASSOC ----------------------------------*/
prefs.assoc_flag = FLAG(obj2.assoc) || FLAG(obj2.assoc_number);
/*-------------------------------- Extracting ------------------------------*/
if (prefs.nthresh_type<2)
prefs.thresh_type[1] = prefs.thresh_type[0];
/*-------------------------------- Deblending ------------------------------*/
prefs.deb_maxarea = (prefs.ext_minarea<MAXDEBAREA ?
prefs.ext_minarea:MAXDEBAREA);
/*-------------------------------- Astrometry ------------------------------*/
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.poserr_mx2w) || FLAG(obj2.winposerr_mx2w)
|| FLAG(obj2.npixw) || FLAG(obj2.fdnpixw)
|| FLAG(obj2.fwhmw);
/* Default astrometric settings */
strcpy(prefs.coosys, "ICRS");
prefs.epoch = 2000.0;
/*-------------------------------- Photometry ------------------------------*/
/* Find the largest APERture-photometry vector */
if (FLAG(obj2.flux_aper))
{
naper = prefs.flux_apersize;
if (prefs.fluxerr_apersize>naper)
naper = prefs.fluxerr_apersize;
if (prefs.mag_apersize>naper)
naper = prefs.mag_apersize;
if (prefs.magerr_apersize>naper)
naper = prefs.magerr_apersize;
if (naper>prefs.naper)
{
warning("Not enough apertures provided in config.:\n",
" some APER photometric values will remain blank ");
naper = prefs.naper;
}
else
prefs.naper = naper;
}
else
naper = 0; /* To avoid gcc -Wall warnings */
/* Find the largest "minimum margin" necessary for apertures */
prefs.cleanmargin = 0;
if (FLAG(obj2.vignet)
&& (margin=(prefs.vignetsize[1]+1)/2) > prefs.cleanmargin)
prefs.cleanmargin = margin;
if (FLAG(obj2.vigshift)
&& (margin=(prefs.vigshiftsize[1]+1)/2+3)>prefs.cleanmargin)
prefs.cleanmargin = margin;
if (FLAG(obj2.flux_aper))
for (i=0; i<naper; i++)
if ((margin=(int)((prefs.apert[i]+1)/2)+1) > prefs.cleanmargin)
prefs.cleanmargin = margin;
/* Growth-curve flag */
if (FLAG(obj2.flux_growth)
|| FLAG(obj2.mag_growth)
|| FLAG(obj2.flux_radius)
|| FLAG(obj2.hl_radius)
|| FLAG(obj2.flux_growthstep)
|| FLAG(obj2.mag_growthstep))
prefs.growth_flag = 1;
if (FLAG(obj2.flux_radius) && prefs.flux_radiussize)
if (prefs.nflux_frac>prefs.flux_radiussize)
prefs.nflux_frac = prefs.flux_radiussize;
/*------------------------------- MASKing ----------------------------------*/
prefs.blank_flag = (prefs.mask_type!=MASK_NONE);
/*--------------------------- SOM-fitting ----------------------------------*/
prefs.somfit_flag = FLAG(obj2.flux_somfit);
/*------------------------------ Background --------------------------------*/
if (prefs.nbacksize<2)
prefs.backsize[1] = prefs.backsize[0];
if (prefs.nbackfsize<2)
prefs.backfsize[1] = prefs.backfsize[0];
if (prefs.nback_type<2)
prefs.back_type[1] = prefs.back_type[0];
/*------------------------------ FLAG-images -------------------------------*/
prefs.nimaisoflag = (prefs.imaflag_size > prefs.imanflag_size) ?
prefs.imaflag_size : prefs.imanflag_size;
prefs.nimaflag = (prefs.nimaisoflag < prefs.nfimage_name) ?
prefs.nimaisoflag : prefs.nfimage_name;
/*----------------------------- CHECK-images -------------------------------*/
prefs.check_flag = 0;
for (i=0; i<prefs.ncheck_type; i++)
if (prefs.check_type[i] != CHECK_NONE) /* at least 1 is not NONE */
prefs.check_flag = 1;
if (prefs.check_flag && prefs.ncheck_name!=prefs.ncheck_type)
error(EXIT_FAILURE, "*Error*: CHECKIMAGE_NAME(s) and CHECKIMAGE_TYPE(s)",
" are not in equal number");
/*---------------------------- PSF-fitting ---------------------------------*/
if (FLAG(obj2.flux_psf) )
{
prefs.psf_flag = 1;
prefs.dpsf_flag = (prefs.npsf_name>1); /*?*/
}
if (prefs.check_flag)
for (i=0; i<prefs.ncheck_type; i++)
if (prefs.check_type[i] == CHECK_SUBPSFPROTOS
|| prefs.check_type[i] == CHECK_PSFPROTOS)
prefs.psf_flag = 1;
/*---------------------------- PC-fitting ----------------------------------*/
/* PC-fitting is possible only if a PSF file is loaded */
if (prefs.psf_flag)
{
prefs.pc_flag = FLAG(obj2.mx2_pc);
if (prefs.check_flag)
for (i=0; i<prefs.ncheck_type; i++)
if (prefs.check_type[i] == CHECK_SUBPCPROTOS
|| prefs.check_type[i] == CHECK_PCPROTOS
|| prefs.check_type[i] == CHECK_PCOPROTOS)
prefs.pc_flag = 1;
}
/*----------------------------- WEIGHT-images ------------------------------*/
if (prefs.nweight_type<2)
prefs.weight_type[1] = prefs.weight_type[0];
prefs.dweight_flag = (prefs.weight_type[0]!= WEIGHT_NONE);
prefs.weight_flag = (prefs.weight_type[1]!= WEIGHT_NONE);
if (prefs.dweight_flag || prefs.weight_flag)
{
/*-- Handle the default weight-threshold values */
if (prefs.nweight_thresh<2)
for (i=2; --i >= prefs.nweight_thresh;)
prefs.weight_thresh[i] = (prefs.weight_type[i]==WEIGHT_FROMWEIGHTMAP)?
0.0 : BIG;
/*-- Check WEIGHT_IMAGE parameter(s) */
if ((!prefs.nwimage_name
&& ((prefs.weight_type[0]!=WEIGHT_FROMBACK
&& prefs.weight_type[0]!=WEIGHT_NONE)
|| (prefs.weight_type[1]!=WEIGHT_FROMBACK
&& prefs.weight_type[1]!=WEIGHT_NONE)))
|| (prefs.nwimage_name<2
&& prefs.weight_type[0]!=WEIGHT_FROMBACK
&& prefs.weight_type[0]!=WEIGHT_NONE
&& prefs.weight_type[1]!=WEIGHT_FROMBACK
&& prefs.weight_type[1]!=WEIGHT_NONE
&& prefs.weight_type[0]!=prefs.weight_type[1]))
error(EXIT_FAILURE, "*Error*: WEIGHT_IMAGE missing","");
if (prefs.nwimage_name && prefs.nwimage_name<2)
prefs.wimage_name[1] = prefs.wimage_name[0];
if (prefs.nwimage_name==2 && prefs.nweight_type==1)
prefs.nweight_type = 2;
/*-- If detection-only interpolation is needed with 1 Weight image... */
/*-- ...pretend we're using 2, with only one being interpolated */
if (prefs.nweight_type==1
&& prefs.nwimage_name && prefs.wimage_name[1]==prefs.wimage_name[0]
&& prefs.interp_type[0]==INTERP_VARONLY )
{
prefs.nweight_type = 2;
prefs.weight_type[1] = prefs.weight_type[0];
prefs.weight_type[0] = WEIGHT_FROMINTERP;
prefs.wimage_name[1] = prefs.wimage_name[0];
prefs.interp_type[1] = INTERP_NONE;
prefs.dweight_flag = 1;
if (prefs.nweight_thresh<2)
{
prefs.nweight_thresh = 2;
prefs.weight_thresh[1] = prefs.weight_thresh[0];
}
}
}
/*------------------------------ Catalogue ---------------------------------*/
if (!strcmp(prefs.cat_name, "STDOUT"))
prefs.pipe_flag = 1;
if ((str=strrchr(prefs.filter_name, '/')))
strcpy(thecat.filter_name, str+1);
else
strcpy(thecat.filter_name, prefs.filter_name);
if ((str=strrchr(prefs.prefs_name, '/')))
strcpy(thecat.prefs_name, str+1);
else
strcpy(thecat.prefs_name, prefs.prefs_name);
if ((str=strrchr(prefs.nnw_name, '/')))
strcpy(thecat.nnw_name, str+1);
else
strcpy(thecat.nnw_name, prefs.nnw_name);
if ((str=strrchr(prefs.image_name[prefs.nimage_name-1], '/')))
strcpy(thecat.image_name, str+1);
else
strcpy(thecat.image_name, prefs.image_name[prefs.nimage_name-1]);
sprintf(thecat.soft_name, "%s %s", BANNER, VERSION);
return;
}
/********************************* 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;
}
/*
prefs.h
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: SExtractor
*
* Author: E.BERTIN (IAP)
*
* Contents: Keywords for the configuration file.
*
* Last modify: 31/07/2007
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
#ifndef _PREFS_H_
#define _PREFS_H_
/*----------------------------- Internal constants --------------------------*/
#define MAXLIST 32 /* max. nb of list members */
/* NOTES:
One must have: MAXLIST >= 1 (preferably >= 16!)
*/
/*------------------------------- preferences -------------------------------*/
typedef struct
{
char **command_line; /* Command line */
int ncommand_line; /* nb of params */
char prefs_name[MAXCHAR]; /* prefs filename*/
char *(image_name[2]); /* image filenames */
int nimage_name; /* nb of params */
char cat_name[MAXCHAR]; /* catalog filename*/
/*----- thresholding */
double dthresh[2]; /* detect. threshold */
int ndthresh; /* (1 or 2 entries) */
double thresh[2]; /* analysis thresh. */
int nthresh; /* (1 or 2 entries) */
enum {THRESH_RELATIVE, THRESH_ABSOLUTE}
thresh_type[2]; /* bkgnd type */
int nthresh_type; /* nb of params */
/*----- extraction */
int dimage_flag; /* detect. image ? */
int ext_minarea; /* min area in pix. */
int deb_maxarea; /* max deblend. area */
int filter_flag; /* smoothing on/off */
char filter_name[MAXCHAR]; /* mask filename */
double filter_thresh[2]; /* Filter thresholds */
int nfilter_thresh; /* nb of params */
int deblend_nthresh; /* threshold number */
double deblend_mincont; /* minimum contrast */
double satur_level; /* saturation level */
char satur_key[8]; /* saturation keyword */
enum {CCD, PHOTO} detect_type; /* detection type */
/*----- Flagging */
char *(fimage_name[MAXFLAG]); /* flagmap filenames */
int nfimage_name; /* nb of params */
enum {FLAG_OR, FLAG_AND, FLAG_MIN, FLAG_MAX, FLAG_MOST}
flag_type[MAXFLAG]; /* flag combination */
int imaflag_size; /* requested iso nb1 */
int imanflag_size; /* requested iso nb2 */
int nimaisoflag; /* effective iso nb */
int nimaflag; /* effective ima nb */
/*----- cleaning */
int clean_flag; /* allow cleaning ? */
double clean_param; /* cleaning effic. */
/*----- Weighting */
char *(wimage_name[2]); /* weight filenames */
int nwimage_name; /* nb of params */
weightenum weight_type[2]; /* weighting scheme */
int nweight_type; /* nb of params */
int weight_flag; /* do we weight ? */
int dweight_flag; /* detection weight? */
int weightgain_flag; /* weight gain? */
/*----- photometry */
enum {CAT_NONE, ASCII, ASCII_HEAD, ASCII_SKYCAT, ASCII_VO,
FITS_LDAC, FITS_TPX, FITS_10}
cat_type; /* type of catalog */
enum {PNONE, FIXED, AUTO} apert_type; /* type of aperture */
double apert[MAXNAPER]; /* apert size (pix) */
int naper; /* effective apert. */
int flux_apersize, fluxerr_apersize; /* requested apert. */
int mag_apersize, magerr_apersize; /* requested apert. */
double autoparam[2]; /* Kron parameters */
int nautoparam; /* nb of Kron params */
double petroparam[2]; /* Kron parameters */
int npetroparam; /* nb of Kron params */
double autoaper[2]; /* minimum apertures */
int nautoaper; /* nb of min. aperts */
double mag_zeropoint; /* magnitude offsets */
double mag_gamma; /* for emulsions */
double gain; /* only for CCD */
char gain_key[8]; /* gain keyword
only for CCD */
/*----- S/G separation */
double pixel_scale; /* in arcsec */
double seeing_fwhm; /* in arcsec */
char nnw_name[MAXCHAR]; /* nnw filename */
/*----- background */
enum {IMAGE, AFILE} back_origin; /* origin of bkgnd */
char back_name[MAXCHAR]; /* bkgnd filename */
backenum back_type[2]; /* bkgnd type */
int nback_type; /* nb of params */
double back_val[2]; /* user-def. bkg */
int nback_val; /* nb of params */
int backsize[2]; /* bkgnd mesh size */
int nbacksize; /* nb of params */
int backfsize[2]; /* bkgnd filt. size */
int nbackfsize; /* nb of params */
double backfthresh; /* bkgnd fil. thresh */
enum {GLOBAL, LOCAL} pback_type; /* phot. bkgnd type */
int pback_size; /* rect. ann. width */
/*----- memory */
int clean_stacksize; /* size of buffer */
int mem_pixstack; /* pixel stack size */
int mem_bufsize; /* strip height */
/*----- catalog output */
char param_name[MAXCHAR]; /* param. filename */
/*----- miscellaneous */
int pipe_flag; /* allow piping ? */
enum {QUIET, NORM, WARN, FULL} verbose_type; /* display type */
int xml_flag; /* Write XML file? */
char xml_name[MAXCHAR]; /* XML file name */
char xsl_name[MAXCHAR]; /* XSL file name (or URL) */
char sdate_start[12]; /* SCAMP start date */
char stime_start[12]; /* SCAMP start time */
char sdate_end[12]; /* SCAMP end date */
char stime_end[12]; /* SCAMP end time */
double time_diff; /* Execution time */
/*----- CHECK-images */
int check_flag; /* CHECK-image flag */
checkenum check_type[MAXCHECK]; /* check-image types */
int ncheck_type; /* nb of params */
char *(check_name[MAXCHECK]); /* check-image names */
int ncheck_name; /* nb of params */
struct structcheck *(check[MAXCHECK]); /* check-image ptrs */
/*----- ASSOCiation */
int assoc_flag; /* ASSOCiation flag */
char assoc_name[MAXCHAR]; /* ASSOC-list name */
int assoc_param[3]; /* ASSOC param cols */
int nassoc_param; /* nb of params */
int assoc_data[MAXNASSOC]; /* ASSOC data cols */
int nassoc_data; /* nb of params */
enum {ASSOC_FIRST, ASSOC_NEAREST, ASSOC_MEAN, ASSOC_MAGMEAN,
ASSOC_SUM, ASSOC_MAGSUM, ASSOC_MIN, ASSOC_MAX}
assoc_type; /* type of assoc. */
enum {ASSOCSELEC_ALL, ASSOCSELEC_MATCHED, ASSOCSELEC_NOMATCHED}
assocselec_type; /* type of assoc. */
double assoc_radius; /* ASSOC range */
int assoc_size; /* nb of parameters */
char retina_name[MAXCHAR]; /* retina filename */
int vignetsize[2]; /* vignet size */
int vigshiftsize[2]; /* shift-vignet size */
int cleanmargin; /* CLEANing margin */
char som_name[MAXCHAR]; /* SOM filename */
int somfit_flag; /* ASSOCiation flag */
int somfit_vectorsize; /* SOMfit vec. size */
/*----- masking */
enum {MASK_NONE, MASK_BLANK, MASK_CORRECT}
mask_type; /* type of masking */
int blank_flag; /* BLANKing flag */
double weight_thresh[2]; /* weight threshlds */
int nweight_thresh; /* nb of params */
/*----- interpolation */
enum {INTERP_NONE, INTERP_VARONLY, INTERP_ALL}
interp_type[2]; /* interpolat. type */
int ninterp_type; /* nb of params */
int interp_xtimeout[2]; /* interp. x timeout */
int ninterp_xtimeout; /* nb of params */
int interp_ytimeout[2]; /* interp. y timeout */
int ninterp_ytimeout; /* nb of params */
/*----- astrometry */
int world_flag; /* WORLD required */
char coosys[16]; /* VOTable coord.sys */
double epoch; /* VOTable epoch */
/*----- growth curve */
int growth_flag; /* gr. curve needed */
int flux_growthsize; /* number of elem. */
int mag_growthsize; /* number of elem. */
int flux_radiussize; /* number of elem. */
double growth_step; /* step size (pix) */
double flux_frac[MAXNAPER]; /* for FLUX_RADIUS */
int nflux_frac; /* number of elem. */
/*----- PSF-fitting */
int psf_flag; /* PSF-fit needed */
int dpsf_flag; /* dual image PSF-fit */
char *(psf_name[2]); /* PSF filename */
int npsf_name; /* nb of params */
int psf_npsfmax; /* Max # of PSFs */
enum {PSFDISPLAY_SPLIT, PSFDISPLAY_VECTOR}
psfdisplay_type; /* PSF display type */
int psf_xsize,psf_ysize; /* nb of params */
int psf_xwsize,psf_ywsize; /* nb of params */
int psf_alphassize,psf_deltassize; /* nb of params */
int psf_alpha2000size,psf_delta2000size; /* nb of params */
int psf_alpha1950size,psf_delta1950size; /* nb of params */
int psf_fluxsize; /* nb of params */
int psf_fluxerrsize; /* nb of params */
int psf_magsize; /* nb of params */
int psf_magerrsize; /* nb of params */
int pc_flag; /* PC-fit needed */
int pc_vectorsize; /* nb of params */
/*----- customize */
int fitsunsigned_flag; /* Force unsign FITS */
int next; /* Number of extensions in file */
/* Multithreading */
int nthreads; /* Number of active threads */
} prefstruct;
prefstruct prefs;
/*-------------------------------- protos -----------------------------------*/
extern int cistrcmp(char *cs, char *ct, int mode);
extern void dumpprefs(int state),
endprefs(void),
readprefs(char *filename,char **argkey,char **argval,int narg),
useprefs(void);
#endif
/*
psf.c
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: SExtractor
*
* Authors: E.BERTIN (IAP)
* P.DELORME (LAOG)
*
* Contents: Fit the PSF to a detection.
*
* Last modify: 12/01/2006
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
#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 "prefs.h"
#include "fits/fitscat.h"
#include "check.h"
#include "filter.h"
#include "image.h"
#include "poly.h"
#include "psf.h"
/*------------------------------- variables ---------------------------------*/
extern keystruct objkey[];
extern objstruct outobj;
/********************************* psf_init **********************************/
/*
Allocate memory and stuff for the PSF-fitting.
*/
void psf_init(psfstruct *psf)
{
QMALLOC(thepsfit, psfitstruct, 1);
QMALLOC(thepsfit->x, float, prefs.psf_npsfmax);
QMALLOC(thepsfit->y, float, prefs.psf_npsfmax);
QMALLOC(thepsfit->flux, float, prefs.psf_npsfmax);
QMALLOC(ppsfit, psfitstruct, 1); /*?*/
QMALLOC(ppsfit->x, float, prefs.psf_npsfmax);
QMALLOC(ppsfit->y, float, prefs.psf_npsfmax);
QMALLOC(ppsfit->flux, float, prefs.psf_npsfmax);
return;
}
/********************************* psf_end ***********************************/
/*
Free memory occupied by the PSF-fitting stuff.
*/
void psf_end(psfstruct *psf, psfitstruct *psfit)
{
int d, ndim;
if (psf->pc)
pc_end(psf->pc);
ndim = psf->poly->ndim;
for (d=0; d<ndim; d++)
free(psf->contextname[d]);
free(psf->context);
free(psf->contextname);
free(psf->contextoffset);
free(psf->contextscale);
free(psf->contexttyp);
poly_end(psf->poly);
free(psf->maskcomp);
free(psf->maskloc);
free(psf->masksize);
free(psf);
free(psfit->x);
free(psfit->y);
free(psfit->flux);
free(psfit);
return;
}
/********************************* psf_load *********************************/
/*
Read the PSF data from a FITS file.
*/
psfstruct *psf_load(char *filename)
{
static objstruct saveobj;
static obj2struct saveobj2;
psfstruct *psf;
catstruct *cat;
tabstruct *tab;
keystruct *key;
char *head, *ci,*co;
int deg[POLY_MAXDIM], group[POLY_MAXDIM], ndim, ngroup,
i,k;
/* Open the cat (well it is not a "cat", but simply a FITS file */
if (!(cat = read_cat(filename)))
error(EXIT_FAILURE, "*Error*: PSF file not found: ", filename);
/* OK, we now allocate memory for the PSF structure itself */
QCALLOC(psf, psfstruct, 1);
/* Store a short copy of the PSF filename */
if ((ci=strrchr(filename, '/')))
strcpy(psf->name, ci+1);
else
strcpy(psf->name, filename);
if (!(tab = name_to_tab(cat, "PSF_DATA", 0)))
error(EXIT_FAILURE, "*Error*: PSF_DATA table not found in catalog ",
filename);
head = tab->headbuf;
/*-- Dimension of the polynomial */
if (fitsread(head, "POLNAXIS", &ndim, H_INT,T_LONG) == RETURN_OK
&& ndim)
{
/*-- So we have a polynomial description of the PSF variations */
if (ndim > POLY_MAXDIM)
{
sprintf(gstr, "*Error*: The POLNAXIS parameter in %s exceeds %d",
psf->name, POLY_MAXDIM);
error(EXIT_FAILURE, gstr, "");
}
QMALLOC(psf->contextname, char *, ndim);
QMALLOC(psf->context, double *, ndim);
QMALLOC(psf->contexttyp, t_type, ndim);
QMALLOC(psf->contextoffset, double, ndim);
QMALLOC(psf->contextscale, double, ndim);
/*-- We will have to use the outobj structs, so we first save their content */
saveobj = outobj;
saveobj2 = outobj2;
/*-- outobj's are used as FLAG arrays, so we initialize them to 0 */
memset(&outobj, 0, sizeof(outobj));
memset(&outobj2, 0, sizeof(outobj2));
for (i=0; i<ndim; i++)
{
/*---- Polynomial groups */
sprintf(gstr, "POLGRP%1d", i+1);
if (fitsread(head, gstr, &group[i], H_INT,T_LONG) != RETURN_OK)
goto headerror;
/*---- Contexts */
QMALLOC(psf->contextname[i], char, 80);
sprintf(gstr, "POLNAME%1d", i+1);
if (fitsread(head,gstr,psf->contextname[i],H_STRING,T_STRING)!=RETURN_OK)
goto headerror;
if (*psf->contextname[i]==(char)':')
/*------ It seems we're facing a FITS header parameter */
psf->context[i] = NULL; /* This is to tell we'll have to load */
/* a FITS header context later on */
else
/*------ The context element is a dynamic object parameter */
{
if ((k = findkey(psf->contextname[i], (char *)objkey,
sizeof(keystruct)))==RETURN_ERROR)
{
sprintf(gstr, "*Error*: %s CONTEXT parameter in %s unknown",
psf->contextname[i], psf->name);
error(EXIT_FAILURE, gstr, "");
}
key = objkey+k;
psf->context[i] = key->ptr;
psf->contexttyp[i] = key->ttype;
/*------ Declare the parameter "active" to trigger computation by SExtractor */
*((char *)key->ptr) = (char)'\1';
}
/*---- Scaling of the context parameter */
sprintf(gstr, "POLZERO%1d", i+1);
if (fitsread(head, gstr, &psf->contextoffset[i], H_EXPO, T_DOUBLE)
!=RETURN_OK)
goto headerror;
sprintf(gstr, "POLSCAL%1d", i+1);
if (fitsread(head, gstr, &psf->contextscale[i], H_EXPO, T_DOUBLE)
!=RETURN_OK)
goto headerror;
}
/*-- Number of groups */
if (fitsread(head, "POLNGRP ", &ngroup, H_INT, T_LONG) != RETURN_OK)
goto headerror;
for (i=0; i<ngroup; i++)
{
/*---- Polynomial degree for each group */
sprintf(gstr, "POLDEG%1d", i+1);
if (fitsread(head, gstr, &deg[i], H_INT,T_LONG) != RETURN_OK)
goto headerror;
}
psf->poly = poly_init(group, ndim, deg, ngroup);
/*-- Update the permanent FLAG arrays (that is, perform an "OR" on them) */
for (ci=(char *)&outobj,co=(char *)&flagobj,i=sizeof(objstruct); i--;)
*(co++) |= *(ci++);
for (ci=(char *)&outobj2,co=(char *)&flagobj2,i=sizeof(obj2struct); i--;)
*(co++) |= *(ci++);
/*-- Restore previous outobj contents */
outobj = saveobj;
outobj2 = saveobj2;
}
else
{
/*-- This is a simple, constant PSF */
psf->poly = poly_init(group, 0, deg, 0);
psf->context = NULL;
}
/* Dimensionality of the PSF mask */
if (fitsread(head, "PSFNAXIS", &psf->maskdim, H_INT, T_LONG) != RETURN_OK)
goto headerror;
if (psf->maskdim<2 || psf->maskdim>3)
error(EXIT_FAILURE, "*Error*: wrong dimensionality for the PSF "
"mask in ", filename);
QMALLOC(psf->masksize, int, psf->maskdim);
for (i=0; i<psf->maskdim; i++)
psf->masksize[i] = 1;
psf->masknpix = 1;
for (i=0; i<psf->maskdim; i++)
{
sprintf(gstr, "PSFAXIS%1d", i+1);
if (fitsread(head, gstr, &psf->masksize[i], H_INT,T_LONG) != RETURN_OK)
goto headerror;
psf->masknpix *= psf->masksize[i];
}
/* PSF FWHM: defaulted to 3 pixels */
if (fitsread(head, "PSF_FWHM", &psf->fwhm, H_FLOAT,T_DOUBLE) != RETURN_OK)
psf->fwhm = 3.0;
/* PSF oversampling: defaulted to 1 */
if (fitsread(head, "PSF_SAMP", &psf->pixstep,H_FLOAT,T_FLOAT) != RETURN_OK)
psf->pixstep = 1.0;
/* Load the PSF mask data */
key = read_key(tab, "PSF_MASK");
psf->maskcomp = key->ptr;
psf->pc = pc_load(cat);
QMALLOC(psf->maskloc, double, psf->masksize[0]*psf->masksize[1]);
/* But don't touch my arrays!! */
blank_keys(tab);
free_cat(&cat, 1);
return psf;
headerror:
error(EXIT_FAILURE, "*Error*: Incorrect or obsolete PSF data in ", filename);
return NULL;
}
/***************************** psf_readcontext *******************************/
/*
Read the PSF context parameters in the FITS header.
*/
void psf_readcontext(psfstruct *psf, picstruct *field)
{
static double contextval[POLY_MAXDIM];
int i, ndim;
ndim = psf->poly->ndim;
for (i=0; i<ndim; i++)
if (!psf->context[i])
{
psf->context[i] = &contextval[i];
psf->contexttyp[i] = T_DOUBLE;
if (fitsread(field->fitshead, psf->contextname[i]+1, &contextval[i],
H_FLOAT,T_DOUBLE) == RETURN_ERROR)
{
sprintf(gstr, "*Error*: %s parameter not found in the header of ",
psf->contextname[i]+1);
error(EXIT_FAILURE, gstr, field->rfilename);
}
}
return;
}
/******************************** psf_fit ***********************************/
/* standart PSF fit for one component */
/****************************************************************************/
void psf_fit(psfstruct *psf, picstruct *field, picstruct *wfield,
objstruct *obj)
{
checkstruct *check;
static obj2struct *obj2 = &outobj2;
static double x2[PSF_NPSFMAX],y2[PSF_NPSFMAX],xy[PSF_NPSFMAX],
deltax[PSF_NPSFMAX],
deltay[PSF_NPSFMAX],flux[PSF_NPSFMAX],
deltaxb[PSF_NPSFMAX],deltayb[PSF_NPSFMAX],
fluxb[PSF_NPSFMAX],
sol[PSF_NTOT], covmat[PSF_NTOT*PSF_NTOT],
vmat[PSF_NTOT*PSF_NTOT], wmat[PSF_NTOT];
double **psfmasks, **psfmaskx,**psfmasky,
*data, *data2, *data3, *weight, *mat, *checkdata,
*d, *m, *w, *ps, *var,
dx,dy,
pix,pix2, wthresh,val,
backnoise2, gain, radmin2,radmax2,satlevel,chi2,
r2, valmax, psf_fwhm;
float *dh, *wh, pixstep,fluxerr;
PIXTYPE *datah, *weighth, *cpix;
int i,j,p, npsf,npsfmax, npix, nppix, ix,iy,niter,
width, height, pwidth,pheight, x,y,
xmax,ymax, wbad, gainflag, convflag, npsfflag,
ival,kill=0;
checkdata = NULL; /* To avoid gcc -Wall warnings */
dx = dy = 0.0;
niter = 0;
npsfmax = prefs.psf_npsfmax;
pixstep = 1.0/psf->pixstep;
gain = prefs.gain;
backnoise2 = field->backsig*field->backsig;
satlevel = prefs.satur_level - obj->bkg;
wthresh = wfield?wfield->weight_thresh:BIG;
gainflag = prefs.weightgain_flag;
psf_fwhm = psf->fwhm*psf->pixstep;
/* Initialize outputs */
thepsfit->niter = 0;
thepsfit->npsf = 0;
for (j=0; j<npsfmax; j++)
{
thepsfit->x[j] = obj2->posx;
thepsfit->y[j] = obj2->posy;
thepsfit->flux[j] = 0.0;
}
/* Scale data area with object "size" */
ix = (obj->xmax+obj->xmin+1)/2;
iy = (obj->ymax+obj->ymin+1)/2;
width = obj->xmax-obj->xmin+1+psf_fwhm;
if (width < (ival=(int)(psf_fwhm*2)))
width = ival;
height = obj->ymax-obj->ymin+1+psf_fwhm;
if (height < (ival=(int)(psf_fwhm*2)))
height = ival;
npix = width*height;
radmin2 = PSF_MINSHIFT*PSF_MINSHIFT;
radmax2 = npix/2.0;
fluxerr = 0.0;
/* Scale total area with PSF FWHM */
pwidth = (int)(psf->masksize[0]*psf->pixstep)+width;;
pheight = (int)(psf->masksize[1]*psf->pixstep)+height;
nppix = pwidth*pheight;
/* Allocate working space */
if (prefs.psf_flag==1)
if (prefs.dpsf_flag!=1)
if(!FLAG(obj2.fluxerr_psf))
QMALLOC(obj2->fluxerr_psf, float, prefs.psf_npsfmax);
QMALLOC(weighth, PIXTYPE, npix);
QMALLOC(weight, double, npix);
QMALLOC(datah, PIXTYPE, npix);
QMALLOC(data, double, npix);
QMALLOC(data2, double, npix);
QMALLOC(data3, double, npix);
QMALLOC(mat, double, npix*PSF_NTOT);
if (prefs.check[CHECK_SUBPSFPROTOS] || prefs.check[CHECK_PSFPROTOS]
|| prefs.check[CHECK_SUBPCPROTOS] || prefs.check[CHECK_PCPROTOS]
|| prefs.check[CHECK_PCOPROTOS])
{
QMALLOC(checkdata, double, nppix);
QMALLOC(checkmask, PIXTYPE, nppix);
}
QMALLOC(psfmasks, double *, npsfmax);
QMALLOC(psfmaskx, double *, npsfmax);
QMALLOC(psfmasky, double *, npsfmax);
for (i=0; i<npsfmax; i++)
{
QMALLOC(psfmasks[i], double, npix);
QMALLOC(psfmaskx[i], double, npix);
QMALLOC(psfmasky[i], double, npix);
}
copyimage(field, datah, width, height, ix, iy);
/* Compute weights */
wbad = 0;
if (wfield)
{
copyimage(wfield, weighth, width, height, ix, iy);
for (wh=weighth, w=weight, dh=datah,p=npix; p--;)
if ((pix=*(wh++)) < wthresh && pix>0
&& (pix2=*(dh++))>-BIG
&& pix2<satlevel)
*(w++) = 1/sqrt(pix+(pix2>0.0?
(gainflag? pix2*pix/backnoise2:pix2)/gain
:0.0));
else
{
*(w++) = 0.0;
wbad++;
}
}
else
for (w=weight, dh=datah, p=npix; p--;)
if ((pix=*(dh++))>-BIG && pix<satlevel)
*(w++) = 1.0/sqrt(backnoise2+(pix>0.0?pix/gain:0.0));
else
{
*(w++) = 0.0;
wbad++;
}
/* Special action if most of the weights are zero!! */
if (wbad>=npix-3)
return;
/* Weight the data */
dh = datah;
val = obj->dbkg; /* Take into account a local background change */
d = data;
w = weight;
for (p=npix; p--;)
*(d++) = (*(dh++)-val)**(w++);
/* Get the local PSF */
psf_build(psf);
npsfflag = 1;
r2 = psf_fwhm*psf_fwhm/2.0;
fluxb[0] = deltaxb[0] = deltayb[0] = 0.0;
for (npsf=1; npsf<=npsfmax && npsfflag; npsf++)
{
kill=0;
/*-- First compute an optimum initial guess for the positions of components */
if (npsf>1)
{
/*---- Subtract previously fitted components */
d = data2;
dh = datah;
for (p=npix; p--;)
*(d++) = (double)*(dh++);
for (j=0; j<npsf-1; j++)
{
d = data2;
ps = psfmasks[j];
for (p=npix; p--;)
*(d++) -= flux[j]**(ps++);
}
convolve_image(field, data2, data3, width,height);
/*---- Ignore regions too close to stellar cores */
for (j=0; j<npsf-1; j++)
{
d = data3;
dy = -((double)(height/2)+deltay[j]);
for (y=height; y--; dy += 1.0)
{
dx = -((double)(width/2)+deltax[j]);
for (x=width; x--; dx+= 1.0, d++)
if (dx*dx+dy*dy<r2)
*d = -BIG;
}
}
/*---- Now find the brightest pixel (poor man's guess, to be refined later) */
d = data3;
valmax = -BIG;
xmax = width/2;
ymax = height/2;
for (y=0; y<height; y++)
for (x=0; x<width; x++)
{
if ((val = *(d++))>valmax)
{
valmax = val;
xmax = x;
ymax = y;
}
}
deltax[npsf-1] = (double)(xmax - width/2);
deltay[npsf-1] = (double)(ymax - height/2);
}
else
{
/*---- Only one component to fit: simply use the barycenter as a guess */
deltax[npsf-1] = obj->mx - ix;
deltay[npsf-1] = obj->my - iy;
}
niter = 0;
convflag = 1;
for (i=0; i<PSF_NITER && convflag; i++)
{
convflag = 0,niter++,m=mat;
for (j=0; j<npsf; j++)
{
/*------ Resample the PSFs here for the 1st iteration */
vignet_resample(psf->maskloc, psf->masksize[0], psf->masksize[1],
psfmasks[j], width, height,
-deltax[j]*pixstep, -deltay[j]*pixstep,
pixstep);
m=compute_gradient(weight,width,height,
psfmasks[j],psfmaskx[j],psfmasky[j],m);
}
svdfit(mat, data, npix, npsf*PSF_NA, sol, vmat, wmat);
compute_pos( &npsf, &convflag, &npsfflag,radmin2,radmax2,
r2, sol,flux, deltax, deltay,&dx,&dy);
}
for (j=0; j<npsf; j++)
{
/*-- Compute variances and covariances */
svdvar(vmat, wmat, npsf*PSF_NA, covmat);
var = covmat;
/*---- First, the error on the flux estimate */
fluxerr = sqrt(*var)>0.0? sqrt(*var):999999.0;
//if (flux[j]<12*fluxerr && j>0)
// npsfmax--,flux[j]=0;
if (flux[j]<12*fluxerr && j>0)
{
flux[j]=0,kill++,npsfmax--;
//if(j==npsfmax-1)
// kill++;
}
}
if (npsfflag)
{
/*--- If we reach this point we know the data are worth backuping */
for (j=0; j<npsf; j++)
{
deltaxb[j] = deltax[j];
deltayb[j] = deltay[j];
fluxb[j] = flux[j];
obj2->fluxerr_psf[j]=fluxerr;
}
}
}
npsf=npsf-1-kill;
/* Now keep only fitted stars that fall within the current detection area */
i = 0;
for (j=0; j<npsf; j++)
{
x = (int)(deltaxb[j]+0.4999)+width/2;
y = (int)(deltayb[j]+0.4999)+height/2;
if (x<0 || x>=width || y<0 || y>=height)
continue;
if (weight[y*width+x] < 1/BIG)
continue;
if (10*fluxb[j]<fluxb[0] )
continue;
if (fluxb[j]<=0 )
continue;
if (FLAG(obj2.poserrmx2_psf))
{
compute_poserr(j,var,sol,obj2,x2,y2,xy);
}
else
var += 3*PSF_NA+3;
deltax[i] = deltaxb[j];
deltay[i] = deltayb[j];
flux[i++] = fluxb[j];
}
npsf = i;
/* Compute chi2 if asked to
if (FLAG(obj2.chi2_psf))
{
for (j=0; j<npsf; j++)
{
chi2 = 0.0;
for (d=data,w=weight,p=0; p<npix; w++,p++)
{
pix = *(d++);
pix -= psfmasks[j][p]*flux[j]**w;
chi2 += pix*pix;
if (chi2>1E29) chi2=1E28;
}
obj2->chi2_psf = obj->sigbkg>0.?
chi2/((npix - 3*npsf)*obj->sigbkg*obj->sigbkg):999999;
}
}*/
/* Compute relative chi2 if asked to */
if (FLAG(obj2.chi2_psf))
{
for (j=0; j<npsf; j++)
{
chi2 = 0.0;
for (d=data,w=weight,p=0; p<npix; w++,p++)
{
pix = *(d++)/flux[j];
pix -= psfmasks[j][p]**w;
chi2 += pix*pix;
if (chi2>1E29) chi2=1E28;
}
obj2->chi2_psf = flux[j]>0?
chi2/((npix - 3*npsf)*obj->sigbkg*obj->sigbkg):999999;
}
}
/* CHECK images */
if (prefs.check[CHECK_SUBPSFPROTOS] || prefs.check[CHECK_PSFPROTOS])
for (j=0; j<npsf; j++)
{
vignet_resample(psf->maskloc, psf->masksize[0], psf->masksize[1],
checkdata, pwidth, pheight,
-deltax[j]*pixstep, -deltay[j]*pixstep, pixstep);
cpix = checkmask;
d = checkdata;
for (p=nppix; p--;)
*(cpix++) = (PIXTYPE)*(d++);
if ((check = prefs.check[CHECK_SUBPSFPROTOS]))
addcheck(check, checkmask, pwidth,pheight, ix,iy,-flux[j]);
if ((check = prefs.check[CHECK_PSFPROTOS]))
addcheck(check, checkmask, pwidth,pheight, ix,iy,flux[j]);
}
thepsfit->niter = niter;
thepsfit->npsf = npsf;
for (j=0; j<npsf; j++)
{
thepsfit->x[j] = ix+deltax[j]+1.0;
thepsfit->y[j] = iy+deltay[j]+1.0;
thepsfit->flux[j] = flux[j];
}
/* Now the morphology stuff */
if (prefs.pc_flag)
{
width = pwidth-1;
height = pheight-1;
npix = width*height;
copyimage(field, datah, width, height, ix, iy);
/*-- Re-compute weights */
if (wfield)
{
copyimage(wfield, weighth, width, height, ix, iy);
for (wh=weighth ,w=weight, p=npix; p--;)
*(w++) = (pix=*(wh++))<wthresh? sqrt(pix): 0.0;
}
else
for (w=weight, dh=datah, p=npix; p--;)
*(w++) = ((pix = *(dh++))>-BIG && pix<satlevel)?
1.0/sqrt(backnoise2+(pix>0.0?pix/gain:0.0))
:0.0;
/*-- Weight the data */
dh = datah;
d = data;
w = weight;
for (p=npix; p--;)
*(d++) = *(dh++)*(*(w++));
pc_fit(psf, data, weight, width, height, ix,iy, dx,dy, npix,
field->backsig);
}
for (i=0; i<prefs.psf_npsfmax; i++)
{
QFREE(psfmasks[i]);
QFREE(psfmaskx[i]);
QFREE(psfmasky[i]);
}
QFREE(psfmasks);
QFREE(psfmaskx);
QFREE(psfmasky);
QFREE(datah);
QFREE(data);
QFREE(data2);
QFREE(data3);
QFREE(weighth);
QFREE(weight);
QFREE(data);
QFREE(mat);
if (prefs.check[CHECK_SUBPSFPROTOS] || prefs.check[CHECK_PSFPROTOS]
|| prefs.check[CHECK_SUBPCPROTOS] || prefs.check[CHECK_PCPROTOS]
|| prefs.check[CHECK_PCOPROTOS])
{
QFREE(checkdata);
QFREE(checkmask);
}
return;
}
/******************************** double_psf_fit *******************************
****/
/* double fit to make the psf detection on one image and the photometry on anoth
er */
/*******************************************************************************
****/
void double_psf_fit(psfstruct *ppsf, picstruct *pfield, picstruct *pwfield,
objstruct *obj, psfstruct *psf, picstruct *field,
picstruct *wfield)
{
static double /* sum[PSF_NPSFMAX]*/ pdeltax[PSF_NPSFMAX],
pdeltay[PSF_NPSFMAX],psol[PSF_NPSFMAX], pcovmat[PSF_NPSFMAX*PSF_NPSFMAX],
pvmat[PSF_NPSFMAX*PSF_NPSFMAX], pwmat[PSF_NPSFMAX],pflux[PSF_NPSFMAX];
double **ppsfmasks, **ppsfmaskx,**ppsfmasky,
*pmat, *checkdata,
*pdata, *pdata2, *pdata3,
*pm,*pd, *pw, *pps,*pweight,/* *pps, *px, *py,*/
dx,dy,pdx,pdy, /* x1,y1, mx,my,mflux, */
val, ppix,ppix2, /* dflux, */
gain, radmin2,radmax2,satlevel
,chi2,pwthresh,pbacknoise2, /* mr, */
r2=0, psf_fwhm,ppsf_fwhm ;
float *pdh, *pwh, pixstep,ppixstep;
PIXTYPE *pdatah, *pweighth;
int i,j,k,p, npsf, npix,ix,iy,
width, height, /* hw,hh, */
x,y, /* yb, */
wbad, gainflag,
ival,npsfmax;
double *pvar;
static obj2struct *obj2 = &outobj2;
checkdata = NULL; /* To avoid gcc -Wall warnings */
pdx = pdy =dx = dy = 0.0;
ppixstep = 1.0/ppsf->pixstep;
pixstep = 1.0/psf->pixstep;
gain = prefs.gain;
npsfmax=prefs.psf_npsfmax;
pbacknoise2 = pfield->backsig*pfield->backsig;
satlevel = prefs.satur_level - obj->bkg;
gainflag = prefs.weightgain_flag;
psf_fwhm = psf->fwhm*psf->pixstep;
ppsf_fwhm = ppsf->fwhm*ppsf->pixstep;
pwthresh = pwfield?pwfield->weight_thresh:BIG;
/* Initialize outputs */
ppsfit->niter = 0;
ppsfit->npsf = 0;
if(!FLAG(obj2.fluxerr_psf))
QMALLOC(obj2->fluxerr_psf, float, npsfmax);
for (j=0; j<npsfmax; j++)
{
ppsfit->x[j] = 999999.0;
ppsfit->y[j] = 999999.0;
ppsfit->flux[j] = 0.0;
obj2->fluxerr_psf[j] = 0.0;
pdeltax[j]= pdeltay[j]=psol[j]= pwmat[j]=pflux[j]=0.0;
}
ix = (obj->xmax+obj->xmin+1)/2;
iy = (obj->ymax+obj->ymin+1)/2;
width = obj->xmax-obj->xmin+1+psf_fwhm;
if (width < (ival=(int)(psf_fwhm*2)))
width = ival;
height = obj->ymax-obj->ymin+1+psf_fwhm;
if (height < (ival=(int)(psf_fwhm*2)))
height = ival;
npix = width*height;
radmin2 = PSF_MINSHIFT*PSF_MINSHIFT;
radmax2 = npix/2.0;
psf_fit(psf,field, wfield,obj);
npsf=thepsfit->npsf;
QMALLOC(ppsfmasks,double *,npsfmax);
QMALLOC(ppsfmaskx,double *,npsfmax);
QMALLOC(ppsfmasky,double *,npsfmax);
for (i=0; i<npsfmax; i++)
{
QMALLOC(ppsfmasks[i],double,npix);
QMALLOC(ppsfmaskx[i],double,npix);
QMALLOC(ppsfmasky[i],double,npix);
}
QMALLOC(pweighth, PIXTYPE, npix);
QMALLOC(pweight, double, npix);
QMALLOC(pdatah, PIXTYPE, npix);
QMALLOC(pdata, double, npix);
QMALLOC(pdata2, double, npix);
QMALLOC(pdata3, double, npix);
QMALLOC(pmat, double, npix*npsfmax);
for (j=0; j<npsf; j++)
{
pdeltax[j] =thepsfit->x[j]-ix-1 ;
pdeltay[j] =thepsfit->y[j]-iy-1 ;
ppsfit->flux[j] = 0;
}
/*------------------- Now the photometry fit ---------------------*/
copyimage(pfield, pdatah, width, height, ix, iy);
/* Compute photometry weights */
wbad = 0;
if (pwfield)
{
copyimage(pwfield, pweighth, width, height, ix, iy);
for (pwh=pweighth, pw=pweight, pdh=pdatah,p=npix; p--;)
{
if ((ppix=*(pwh++)) < pwthresh && ppix>0
&& (ppix2=*(pdh++))>-BIG && ppix2<satlevel)
{
*(pw++) = 1/sqrt(ppix+(ppix2>0.0?
(gainflag? ppix2*ppix/pbacknoise2:ppix2)/gain : 0.0));
}
else
{
*(pw++) = 0.0;
wbad++;
}
}
}
else
for (pw=pweight, pdh=pdatah, p=npix; p--;)
if ((ppix=*(pdh++))>-BIG && ppix<satlevel)
{
*(pw++) = 1.0/sqrt(pbacknoise2+(ppix>0.0?ppix/gain:0.0));
}
else
{
*(pw++) = 0.0;
wbad++;
}
/* Special action if most of the weights are zero!! */
if (wbad>=npix-3)
return;
/* Weight the data */
pdh = pdatah;
pd = pdata;
pw = pweight;
val = obj->dbkg;
for (p=npix; p--;)
*(pd++) = (*(pdh++)-val)**(pw++);
/* Get the photmetry PSF */
psf_build(ppsf);
for (j=1; j<=npsf; j++)
{
if (j>1)
{
/*---- Subtract //previously fitted components in photometry image */
pd = pdata2;
pdh = pdatah;
for (p=npix; p--;)
*(pd++) = (double)*(pdh++);
for (k=0; k<j-1; k++)
{
pd = pdata2;
pps = ppsfmasks[k];
for (p=npix; p--;)
*(pd++) -= pflux[k]**(pps++);
}
convolve_image(pfield, pdata2, pdata3, width,height);
/*---- Ignore regions too close to stellar cores */
for (k=0; k<j-1; k++)
{
pd = pdata3;
dy = -((double)(height/2)+pdeltay[k]);
for (y=height; y--; dy += 1.0)
{
dx = -((double)(width/2)+pdeltax[k]);
for (x=width; x--; dx+= 1.0, pd++)
if (dx*dx+dy*dy<r2) /*?*/
*pd = -BIG;
}
}
}
pm=pmat;
for (k=0; k<j; k++)
{
/*------ Resample the PSFs here for the 1st iteration */
vignet_resample(ppsf->maskloc,
ppsf->masksize[0], ppsf->masksize[1],
ppsfmasks[k], width, height,
-pdeltax[k]*ppixstep, -pdeltay[k]*ppixstep,
ppixstep);
pm=compute_gradient_phot(pweight,width,height, ppsfmasks[k],pm);
}
svdfit(pmat, pdata, npix, j, psol, pvmat, pwmat);
compute_pos_phot( &j, psol,pflux);
for (k=0; k<j; k++)
{
svdvar(pvmat, pwmat, j, pcovmat);
pvar = pcovmat;
obj2->fluxerr_psf[k]= sqrt(*pvar)>0.0 && sqrt(*pvar)<99?
sqrt(*pvar):99;
}
}
/* Compute chi2 if asked to
if (FLAG(obj2.chi2_psf))
{
for (j=0; j<npsf; j++)
{
chi2 = 0.0;
for (pd=pdata,pw=pweight,p=0; p<npix; pw++,p++)
{
ppix = *(pd++);
ppix -= ppsfmasks[j][p]*pflux[j]**pw;
chi2 += ppix*ppix;
if (chi2>1E29) chi2=1E28;
}
obj2->chi2_psf = obj->sigbkg>0.?
chi2/((npix - 3*npsf)*obj->sigbkg*obj->sigbkg):999999;
}
}
*/
/* Compute relative error if asked to */
if (FLAG(obj2.chi2_psf))
{
for (j=0; j<npsf; j++)
{
chi2 = 0.0;
for (pd=pdata,pw=pweight,p=0; p<npix; pw++,p++)
{
ppix = *(pd++)/pflux[j];
ppix -= ppsfmasks[j][p]**pw;
chi2 += ppix*ppix;
if (chi2>1E29) chi2=1E28;
}
obj2->chi2_psf = pflux[j]>0?
chi2/((npix - 3*npsf)*obj->sigbkg*obj->sigbkg):999999;
}
}
ppsfit->niter = thepsfit->niter;
ppsfit->npsf = npsf;
for (j=0; j<npsf; j++)
{
thepsfit->x[j] = ix+pdeltax[j]+1.0;
thepsfit->y[j] = iy+pdeltay[j]+1.0;
thepsfit->flux[j] = pflux[j];
ppsfit->x[j] = ix+pdeltax[j]+1.0;
ppsfit->y[j] = iy+pdeltay[j]+1.0;
ppsfit->flux[j] = pflux[j];
}
for (i=0; i<npsfmax; i++)
{
QFREE(ppsfmasks[i]);
QFREE(ppsfmaskx[i]);
QFREE(ppsfmasky[i]);
}
QFREE(ppsfmasks);
QFREE(ppsfmaskx);
QFREE(ppsfmasky);
QFREE(pdatah);
QFREE(pdata);
QFREE(pdata2);
QFREE(pdata3);
QFREE(pweighth);
QFREE(pweight);
QFREE(pdata);
QFREE(pmat);
if (prefs.check[CHECK_SUBPSFPROTOS] || prefs.check[CHECK_PSFPROTOS]
|| prefs.check[CHECK_SUBPCPROTOS] || prefs.check[CHECK_PCPROTOS]
|| prefs.check[CHECK_PCOPROTOS])
{
QFREE(checkdata);
QFREE(checkmask);
}
return;
}
/******************************* psf_build **********************************/
/*
Build the local PSF (function of "context").
*/
void psf_build(psfstruct *psf)
{
static double pos[POLY_MAXDIM];
double *pl, *basis, fac;
float *ppc;
int i,n,p, ndim, npix;
npix = psf->masksize[0]*psf->masksize[1];
/* Reset the Local PSF mask */
memset(psf->maskloc, 0, npix*sizeof(double));
/* Grab the context vector */
ndim = psf->poly->ndim;
for (i=0; i<ndim; i++)
{
ttypeconv(psf->context[i], &pos[i], psf->contexttyp[i],T_DOUBLE);
pos[i] = (pos[i] - psf->contextoffset[i]) / psf->contextscale[i];
}
poly_func(psf->poly, pos);
basis = psf->poly->basis;
ppc = psf->maskcomp;
/* Sum each component */
for (n = (psf->maskdim>2?psf->masksize[2]:1); n--;)
{
pl = psf->maskloc;
fac = *(basis++);
for (p=npix; p--;)
*(pl++) += fac**(ppc++);
}
return;
}
/*****************************compute_gradient*********************************/
double *compute_gradient(double *weight,int width, int height,
double *masks,double *maskx,double *masky
,double *m)
{
int x,y;
double *w,*ps,*px,*py;
/*------ copy of the (weighted) PSF, with outer ring set to zero */
ps = masks;
w = weight;
for (y=0; y<height; y++)
for (x=0; x<width; x++, ps++, w++)
*(m++) = y?(y>=(height-1)?0:(x?(x>=(width-1)?0:*ps**w):0)):0;
/*------ (weighted) PSF gradient in x (kernel for first moment in x) */
ps = masks;
px = maskx;
w = weight;
for (y=0; y<height; y++)
for (x=0; x<width; x++, ps++, w++)
*(m++) = ((*px++) = (x?(x>=(width-1)?0:*(ps+1)-*(ps-1)):0))**w/2;
/*------ (weighted) PSF gradient in y (kernel for first moment in y) */
ps = masks;
py = masky;
w = weight;
for (y=0; y<height; y++)
for (x=0; x<width; x++, ps++, w++)
*(m++) = (*(py++)=(y?(y>=(height-1)?0:*(ps+width)-*(ps-width)):0))
**w/2;
return m;
}
/*****************************compute_gradient_phot*****************************
****/
double *compute_gradient_phot(double *pweight,int width, int height,
double *pmasks,double *pm)
{
int x,y;
double *pw,*pps;
/*------ copy of the (weighted) PSF, with outer ring set to zero */
pps = pmasks;
pw = pweight;
for (y=0; y<height; y++)
for (x=0; x<width; x++, pps++, pw++)
*(pm++) = y?(y>=(height-1)?0:(x?(x>=(width-1)?0:*pps**pw):0)):0;
return pm;
}
/**************************compute_pos********************************/
void compute_pos(int *pnpsf,int *pconvflag,int *pnpsfflag,double radmin2,
double radmax2,double r2,double *sol,double *flux
,double *deltax,double *deltay,double *pdx,double *pdy)
{
int j,k,convflag,npsfflag,npsf;
double dx,dy;
dx=*pdx;
dy=*pdy;
convflag=*pconvflag;
npsfflag=*pnpsfflag;
npsf=*pnpsf;
for (j=0; j<npsf; j++)
{
flux[j] = sol[j*PSF_NA];
/*------ Update the PSF shifts */
if (fabs(flux[j])>0.0)
{
dx = -sol[j*PSF_NA+1]/((npsf>1?2:1)*flux[j]);
dy = -sol[j*PSF_NA+2]/((npsf>1?2:1)*flux[j]);
}
deltax[j] += dx;
deltay[j] += dy;
/*------ Continue until all PSFs have come to a complete stop */
if ((dx*dx+dy*dy) > radmin2)
convflag = 1;
}
for (j=0; j<npsf; j++)
{
/*------ Exit if too much decentering or negative flux */
for (k=j+1; k<npsf; k++)
{
dx = deltax[j]-deltax[k];
dy = deltay[j]-deltay[k];
if (dx*dx+dy*dy<r2/4.0)
{
flux[j] = -BIG;
break;
}
}
if (flux[j]<0.0
|| (deltax[j]*deltax[j] + deltay[j]*deltay[j]) > radmax2)
{
npsfflag = 0;
convflag = 0;
npsf--;
break;
}
}
*pdx=dx;
*pdy=dy;
*pconvflag=convflag;
*pnpsfflag= npsfflag;
*pnpsf=npsf;
return;
}
/**************************compute_pos_phot********************************/
void compute_pos_phot(int *pnpsf,double *sol,double *flux)
{
int j,npsf;
npsf=*pnpsf;
for (j=0; j<npsf; j++)
{
flux[j] = sol[j];
}
*pnpsf=npsf;
return;
}
/************************************compute_poserr*****************************
*********/
void compute_poserr( int j,double *var,double *sol,obj2struct *obj2,double *x2,
double *y2,double *xy)
{
double vara,covab,varb;
/*------ Variances and covariance along x and y */
vara = *(var += PSF_NA+1);
covab = *(++var);
varb = *(var += PSF_NA);
var += PSF_NA+1;
obj2->poserrmx2_psf = (vara*x2[j]*x2[j]+varb*xy[j]*xy[j]
+2*covab*x2[j]*xy[j])/(sol[0]*sol[0]);
obj2->poserrmy2_psf = (varb*y2[j]*y2[j]+vara*xy[j]*xy[j]
+2*covab*y2[j]*xy[j])/(sol[0]*sol[0]);
obj2->poserrmxy_psf = (vara*x2[j]*xy[j]+varb*y2[j]*xy[j]
+covab*(x2[j]*y2[j]+xy[j]*xy[j]))
/(sol[0]*sol[0]);
/*------ If requested, translate variances to major and minor error axes... */
if (FLAG(obj2.poserra_psf))
{
double pmx2,pmy2,temp,theta;
if (fabs(temp=obj2->poserrmx2_psf-obj2->poserrmy2_psf) > 0.0)
theta = atan2(2.0 * obj2->poserrmxy_psf,temp) / 2.0;
else
theta = PI/4.0;
temp = sqrt(0.25*temp*temp+obj2->poserrmxy_psf*obj2->poserrmxy_psf);
pmy2 = pmx2 = 0.5*(obj2->poserrmx2_psf+obj2->poserrmy2_psf);
pmx2+=temp;
pmy2-=temp;
obj2->poserra_psf = (float)sqrt(pmx2);
obj2->poserrb_psf = (float)sqrt(pmy2);
obj2->poserrtheta_psf = theta*180.0/PI;
}
/*------ ...Or ellipse parameters */
if (FLAG(obj2.poserr_cxx))
{
double xm2,ym2, xym, temp;
xm2 = obj2->poserrmx2_psf;
ym2 = obj2->poserrmy2_psf;
xym = obj2->poserrmxy_psf;
obj2->poserrcxx_psf = (float)(ym2/(temp=xm2*ym2-xym*xym));
obj2->poserrcyy_psf = (float)(xm2/temp);
obj2->poserrcxy_psf = (float)(-2*xym/temp);
}
return;
}
/******************************** svdfit ************************************/
/*
General least-square fit A.x = b, based on Singular Value Decomposition (SVD).
Loosely adapted from Numerical Recipes in C, 2nd Ed. (p. 671).
Note: the a and v matrices are transposed with respect to the N.R. convention.
*/
void svdfit(double *a, double *b, int m, int n, double *sol,
double *vmat, double *wmat)
{
#define MAX(a,b) (maxarg1=(a),maxarg2=(b),(maxarg1) > (maxarg2) ?\
(maxarg1) : (maxarg2))
#define PYTHAG(a,b) ((at=fabs(a)) > (bt=fabs(b)) ? \
(ct=bt/at,at*sqrt(1.0+ct*ct)) \
: (bt ? (ct=at/bt,bt*sqrt(1.0+ct*ct)): 0.0))
#define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
#define TOL 1.0e-11
int flag,i,its,j,jj,k,l,nm,mmi,nml;
double c,f,h,s,x,y,z,
anorm, g, scale,
at,bt,ct,maxarg1,maxarg2,
thresh, wmax,
*w,*ap,*ap0,*ap1,*ap10,*rv1p,*vp,*vp0,*vp1,*vp10,
*bp,*tmpp, *rv1,*tmp;
anorm = g = scale = 0.0;
if (m < n)
error(EXIT_FAILURE, "*Error*: Not enough rows for solving the system ",
"in svdfit()");
QMALLOC(rv1, double, n);
QMALLOC(tmp, double, n);
l = nm = nml = 0; /* To avoid gcc -Wall warnings */
for (i=0;i<n;i++)
{
l = i+1;
nml = n-l;
rv1[i] = scale*g;
g = s = scale = 0.0;
if ((mmi = m - i) > 0)
{
ap = ap0 = a+i*(m+1);
for (k=mmi;k--;)
scale += fabs(*(ap++));
if (scale)
{
for (ap=ap0,k=mmi; k--; ap++)
{
*ap /= scale;
s += *ap**ap;
}
f = *ap0;
g = -SIGN(sqrt(s),f);
h = f*g-s;
*ap0 = f-g;
ap10 = a+l*m+i;
for (j=nml;j--; ap10+=m)
{
for (s=0.0,ap=ap0,ap1=ap10,k=mmi; k--;)
s += *(ap1++)**(ap++);
f = s/h;
for (ap=ap0,ap1=ap10,k=mmi; k--;)
*(ap1++) += f**(ap++);
}
for (ap=ap0,k=mmi; k--;)
*(ap++) *= scale;
}
}
wmat[i] = scale*g;
g = s = scale = 0.0;
if (i < m && i+1 != n)
{
ap = ap0 = a+i+m*l;
for (k=nml;k--; ap+=m)
scale += fabs(*ap);
if (scale)
{
for (ap=ap0,k=nml;k--; ap+=m)
{
*ap /= scale;
s += *ap**ap;
}
f=*ap0;
g = -SIGN(sqrt(s),f);
h=f*g-s;
*ap0=f-g;
rv1p = rv1+l;
for (ap=ap0,k=nml;k--; ap+=m)
*(rv1p++) = *ap/h;
ap10 = a+l+m*l;
for (j=m-l; j--; ap10++)
{
for (s=0.0,ap=ap0,ap1=ap10,k=nml; k--; ap+=m,ap1+=m)
s += *ap1**ap;
rv1p = rv1+l;
for (ap1=ap10,k=nml;k--; ap1+=m)
*ap1 += s**(rv1p++);
}
for (ap=ap0,k=nml;k--; ap+=m)
*ap *= scale;
}
}
anorm=MAX(anorm,(fabs(wmat[i])+fabs(rv1[i])));
}
for (i=n-1;i>=0;i--)
{
if (i < n-1)
{
if (g)
{
ap0 = a+l*m+i;
vp0 = vmat+i*n+l;
vp10 = vmat+l*n+l;
g *= *ap0;
for (ap=ap0,vp=vp0,j=nml; j--; ap+=m)
*(vp++) = *ap/g;
for (j=nml; j--; vp10+=n)
{
for (s=0.0,ap=ap0,vp1=vp10,k=nml; k--; ap+=m)
s += *ap**(vp1++);
for (vp=vp0,vp1=vp10,k=nml; k--;)
*(vp1++) += s**(vp++);
}
}
vp = vmat+l*n+i;
vp1 = vmat+i*n+l;
for (j=nml; j--; vp+=n)
*vp = *(vp1++) = 0.0;
}
vmat[i*n+i]=1.0;
g=rv1[i];
l=i;
nml = n-l;
}
for (i=(m<n?m:n); --i>=0;)
{
l=i+1;
nml = n-l;
mmi=m-i;
g=wmat[i];
ap0 = a+i*m+i;
ap10 = ap0 + m;
for (ap=ap10,j=nml;j--;ap+=m)
*ap=0.0;
if (g)
{
g=1.0/g;
for (j=nml;j--; ap10+=m)
{
for (s=0.0,ap=ap0,ap1=ap10,k=mmi; --k;)
s += *(++ap)**(++ap1);
f = (s/(*ap0))*g;
for (ap=ap0,ap1=ap10,k=mmi;k--;)
*(ap1++) += f**(ap++);
}
for (ap=ap0,j=mmi;j--;)
*(ap++) *= g;
}
else
for (ap=ap0,j=mmi;j--;)
*(ap++)=0.0;
++(*ap0);
}
for (k=n; --k>=0;)
{
for (its=0;its<100;its++)
{
flag=1;
for (l=k;l>=0;l--)
{
nm=l-1;
if (fabs(rv1[l])+anorm == anorm)
{
flag=0;
break;
}
if (fabs(wmat[nm])+anorm == anorm)
break;
}
if (flag)
{
c=0.0;
s=1.0;
ap0 = a+nm*m;
ap10 = a+l*m;
for (i=l; i<=k; i++,ap10+=m)
{
f=s*rv1[i];
if (fabs(f)+anorm == anorm)
break;
g=wmat[i];
h=PYTHAG(f,g);
wmat[i]=h;
h=1.0/h;
c=g*h;
s=(-f*h);
for (ap=ap0,ap1=ap10,j=m; j--;)
{
z = *ap1;
y = *ap;
*(ap++) = y*c+z*s;
*(ap1++) = z*c-y*s;
}
}
}
z=wmat[k];
if (l == k)
{
if (z < 0.0)
{
wmat[k] = -z;
vp = vmat+k*n;
for (j=n; j--; vp++)
*vp = (-*vp);
}
break;
}
if (its == 99)
error(EXIT_FAILURE, "*Error*: No convergence in 100 SVD iterations ",
"in svdfit()");
x=wmat[l];
nm=k-1;
y=wmat[nm];
g=rv1[nm];
h=rv1[k];
f=((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y);
g=PYTHAG(f,1.0);
f=((x-z)*(x+z)+h*((y/(f+SIGN(g,f)))-h))/x;
c=s=1.0;
ap10 = a+l*m;
vp10 = vmat+l*n;
for (j=l;j<=nm;j++,ap10+=m,vp10+=n)
{
i=j+1;
g=rv1[i];
y=wmat[i];
h=s*g;
g=c*g;
z=PYTHAG(f,h);
rv1[j]=z;
c=f/z;
s=h/z;
f=x*c+g*s;
g=g*c-x*s;
h=y*s;
y=y*c;
for (vp=(vp1=vp10)+n,jj=n; jj--;)
{
z = *vp;
x = *vp1;
*(vp1++) = x*c+z*s;
*(vp++) = z*c-x*s;
}
z=PYTHAG(f,h);
wmat[j]=z;
if (z)
{
z=1.0/z;
c=f*z;
s=h*z;
}
f=c*g+s*y;
x=c*y-s*g;
for (ap=(ap1=ap10)+m,jj=m; jj--;)
{
z = *ap;
y = *ap1;
*(ap1++) = y*c+z*s;
*(ap++) = z*c-y*s;
}
}
rv1[l]=0.0;
rv1[k]=f;
wmat[k]=x;
}
}
wmax=0.0;
w = wmat;
for (j=n;j--; w++)
if (*w > wmax)
wmax=*w;
thresh=TOL*wmax;
w = wmat;
for (j=n;j--; w++)
if (*w < thresh)
*w = 0.0;
w = wmat;
ap = a;
tmpp = tmp;
for (j=n; j--; w++)
{
s=0.0;
if (*w)
{
bp = b;
for (i=m; i--;)
s += *(ap++)**(bp++);
s /= *w;
}
else
ap += m;
*(tmpp++) = s;
}
vp0 = vmat;
for (j=0; j<n; j++,vp0++)
{
s=0.0;
tmpp = tmp;
for (vp=vp0,jj=n; jj--; vp+=n)
s += *vp**(tmpp++);
sol[j]=s;
}
/* Free temporary arrays */
free(tmp);
free(rv1);
return;
}
#undef SIGN
#undef MAX
#undef PYTHAG
#undef TOL
/******************************** svdvar ************************************/
/*
Computation of the covariance matrix from the SVD vmat and wmat matrices.A
dapted from Numerical Recipes in C, 2nd Ed. (p. 679).
*/
void svdvar(double *v, double *w, int n, double *cov)
{
static double wti[PSF_NTOT];
double sum;
int i,j,k;
for (i=0; i<n; i++)
wti[i] = w[i]? 1.0/(w[i]*w[i]) : 0.0;
for (i=0; i<n; i++)
for (j=0; j<=i; j++)
{
for (sum=0.0,k=0; k<n; k++)
sum += v[k*n+i]*v[k*n+j]*wti[k];
cov[j*n+i] = cov[i*n+j] = sum;
}
return;
}
/*
psf.h
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: SExtractor
*
* Authors: E.BERTIN (IAP)
* P.DELORME (LAOG)
*
* Contents: Include file for psffit.c.
*
* Last modify: 12/01/2006
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
/*----------------------------- Internal constants --------------------------*/
#define PSF_MAXSHIFT 20.0 /* Max shift from initial guess (pixels)*/
#define PSF_MINSHIFT 1e-3 /* Min shift from previous guess (pixels)*/
#define PSF_NITER 20 /* Maximum number of iterations in fit */
#define PSF_NA 3 /* Number of fitted parameters per component */
#define PSF_NTOT (PSF_NA*PSF_NPSFMAX) /* Number of fitted parameters*/
#define PSF_DOUBLETOT ((PSF_NA+1)*PSF_NPSFMAX)/* Nb of fitted parameters */
#define PC_NITER 1 /* Maximum number of iterations in PC fit */
/* NOTES:
One must have: PSF_MAXSHIFT > 0.0
PSF_NPSF >= 1
PSF_NITER >= 1
*/
/*--------------------------- structure definitions -------------------------*/
typedef struct code
{
float *pc;
float **param;
int *parammod;
int ncode;
int nparam;
} codestruct;
typedef struct pc
{
char name[MAXCHAR]; /* PC filename */
int npc; /* Number of Principal Components */
int maskdim; /* Dimensionality of the tabulated data */
int *masksize; /* PC mask dimensions */
int masknpix; /* Total number of involved PC pixels */
float *maskcomp; /* Convolved pix data (principal components) */
int omaskdim; /* Dimensionality of the tabulated data */
int *omasksize; /* PC mask dimensions */
int omasknpix; /* Total number of involved PC pixels */
float *omaskcomp; /* Original pix data (principal components) */
double *maskcurr; /* Current model */
double *mx2,*my2,*mxy; /* 2nd order moments for each component */
double *flux; /* Flux of each component */
double *bt; /* B/T for each component */
codestruct *code;
} pcstruct;
typedef struct
{
char name[MAXCHAR]; /* Name of the file containing the PSF data */
int maskdim; /* Dimensionality of the tabulated data */
int *masksize; /* PSF mask dimensions */
int masknpix; /* Total number of involved PSF pixels */
float *maskcomp; /* Complete pix. data (PSF components) */
double *maskloc; /* Local PSF */
double **context; /* Contexts */
t_type *contexttyp; /* Context types */
char **contextname; /* Array of context key-names */
double *contextoffset; /* Offset to apply to context data */
double *contextscale; /* Scaling to apply to context data */
struct poly *poly; /* Polynom describing the PSF variations */
pcstruct *pc; /* PC components */
double fwhm; /* Typical PSF FWHM */
float pixstep; /* PSF sampling step */
} psfstruct;
typedef struct
{
int niter; /* Number of iterations required */
int npsf; /* Number of fitted stars for this detection */
float *x,*y; /* Position derived from the PSF-fitting */
float *flux; /* Flux derived from the PSF-fitting */
} psfitstruct;
/*----------------------------- Global variables ----------------------------*/
psfstruct *psf,*ppsf,*thepsf;
psfitstruct *thepsfit,*ppsfit,*psfit;
PIXTYPE *checkmask;
/*-------------------------------- functions --------------------------------*/
extern void compute_pos(int *pnpsf,int *pconvflag,int *pnpsfflag,
double radmin2, double radmax2,double r2, double *sol,
double *flux , double *deltax,double *deltay,
double *pdx,double *pdy),
compute_pos_phot(int *pnpsf,double *sol,double *flux),
compute_poserr(int j,double *var,double *sol,obj2struct *obj2,
double *x2, double *y2,double *xy),
psf_build(psfstruct *psf),
psf_end(psfstruct *psf, psfitstruct *psfit),
psf_init(psfstruct *psf),
svdfit(double *a, double *b, int m, int n, double *sol,
double *vmat, double *wmat),
svdvar(double *vmat, double *wmat, int n, double *covmat);
extern double *compute_gradient (double *weight,int width, int height,
double *masks, double *maskx, double *masky,
double *mat),
*compute_gradient_phot(double *weight,int width, int height,
double *masks, double *pm);
extern psfstruct *psf_load(char *filename);
extern void pc_end(pcstruct *pc),
pc_fit(psfstruct *psf, double *data, double *weight,
int width, int height, int ix, int iy, double dx, double dy,
int npc, float backrms),
double_psf_fit(psfstruct *psf, picstruct *field,
picstruct *wfield, objstruct *obj,
psfstruct *dpsf, picstruct *dfield, picstruct *dwfield),
psf_fit(psfstruct *psf, picstruct *field, picstruct *wfield,
objstruct *obj),
psf_readcontext(psfstruct *psf, picstruct *field);
extern pcstruct *pc_load(catstruct *cat);
/*
readimage.c
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: SExtractor
*
* Author: E.BERTIN (IAP)
*
* Contents: functions for input of image data.
*
* Last modify: 13/07/2006
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wcs/wcs.h"
#include "define.h"
#include "globals.h"
#include "prefs.h"
#include "check.h"
#include "field.h"
#include "fits/fitscat.h"
#include "interpolate.h"
#include "back.h"
#include "astrom.h"
#include "weight.h"
#include "wcs/tnx.h"
/******************************* loadstrip ***********************************/
/*
Load a new strip of pixel data into the buffer.
*/
void *loadstrip(picstruct *field, picstruct *wfield)
{
checkstruct *check;
int y, w, flags, interpflag;
PIXTYPE *data, *wdata, *rmsdata;
w = field->width;
flags = field->flags;
interpflag = (wfield && wfield->interp_flag);
wdata = NULL; /* To avoid gcc -Wall warnings */
if (!field->y)
{
/*- First strip */
int nbpix;
nbpix = w*field->stripheight;
if (flags ^ FLAG_FIELD)
{
/*---- Allocate space for the frame-buffer */
if (!(field->strip=(PIXTYPE *)malloc(field->stripheight*field->width
*sizeof(PIXTYPE))))
error(EXIT_FAILURE,"Not enough memory for the image buffer of ",
field->rfilename);
data = field->strip;
/*---- We assume weight data have been read just before */
if (interpflag)
wdata = wfield->strip;
if (flags & BACKRMS_FIELD)
for (y=0, rmsdata=data; y<field->stripheight; y++, rmsdata += w)
backrmsline(field, y, rmsdata);
else if (flags & INTERP_FIELD)
copydata(field, 0, nbpix);
else
readdata(field, 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]))
writecheck(check, data, nbpix);
for (y=0; y<field->stripheight; y++, data += w)
{
/*------ This is the only place where one can pick-up safely the current bkg */
if (flags & (MEASURE_FIELD|DETECT_FIELD))
subbackline(field, y, data);
/*------ Go to interpolation process */
if (interpflag)
{
interpolate(field,wfield, data, wdata);
wdata += w;
}
/*------ Check-image stuff */
if (prefs.check_flag)
{
if (flags & MEASURE_FIELD)
{
if ((check = prefs.check[CHECK_BACKGROUND]))
writecheck(check, field->backline, w);
if ((check = prefs.check[CHECK_SUBTRACTED]))
writecheck(check, data, w);
if ((check = prefs.check[CHECK_APERTURES]))
writecheck(check, data, w);
if ((check = prefs.check[CHECK_SUBPSFPROTOS]))
writecheck(check, data, w);
if ((check = prefs.check[CHECK_SUBPCPROTOS]))
writecheck(check, data, w);
}
if ((flags&DETECT_FIELD) && (check=prefs.check[CHECK_BACKRMS]))
{
backrmsline(field, y, (PIXTYPE *)check->pix);
writecheck(check, check->pix, w);
}
}
}
}
else
{
if (!(field->fstrip=(FLAGTYPE *)malloc(field->stripheight*field->width
*sizeof(FLAGTYPE))))
error(EXIT_FAILURE,"Not enough memory for the flag buffer of ",
field->rfilename);
readidata(field, field->fstrip, nbpix);
}
field->ymax = field->stripheight;
if (field->ymax < field->height)
field->stripysclim = field->stripheight - field->stripmargin;
}
else
{
/*- other strips */
if (flags ^ FLAG_FIELD)
{
data = field->strip + field->stripylim*w;
/*---- We assume weight data have been read just before */
if (interpflag)
wdata = wfield->strip + field->stripylim*w;
/*---- copy to Check-image the "oldest" line before it is replaced */
if ((flags & MEASURE_FIELD) && (check=prefs.check[CHECK_SUBOBJECTS]))
writecheck(check, data, w);
if (flags & BACKRMS_FIELD)
backrmsline(field, field->ymax, data);
else if (flags & INTERP_FIELD)
copydata(field, field->stripylim*w, w);
else
readdata(field, data, w);
if (flags & (WEIGHT_FIELD|RMS_FIELD|BACKRMS_FIELD|VAR_FIELD))
weight_to_var(field, data, w);
if ((flags & MEASURE_FIELD) && (check=prefs.check[CHECK_IDENTICAL]))
writecheck(check, data, w);
/*---- Interpolate and subtract the background at current line */
if (flags & (MEASURE_FIELD|DETECT_FIELD))
subbackline(field, field->ymax, data);
if (interpflag)
interpolate(field,wfield, data, wdata);
/*---- Check-image stuff */
if (prefs.check_flag)
{
if (flags & MEASURE_FIELD)
{
if ((check = prefs.check[CHECK_BACKGROUND]))
writecheck(check, field->backline, w);
if ((check = prefs.check[CHECK_SUBTRACTED]))
writecheck(check, data, w);
if ((check = prefs.check[CHECK_APERTURES]))
writecheck(check, data, w);
if ((check = prefs.check[CHECK_SUBPSFPROTOS]))
writecheck(check, data, w);
if ((check = prefs.check[CHECK_SUBPCPROTOS]))
writecheck(check, data, w);
}
if ((flags&DETECT_FIELD) && (check=prefs.check[CHECK_BACKRMS]))
{
backrmsline(field, field->ymax, (PIXTYPE *)check->pix);
writecheck(check, check->pix, w);
}
}
}
else
readidata(field, field->fstrip + field->stripylim*w, w);
field->stripylim = (++field->ymin)%field->stripheight;
if ((++field->ymax)<field->height)
field->stripysclim = (++field->stripysclim)%field->stripheight;
}
return (flags ^ FLAG_FIELD)?
(void *)(field->strip + field->stripy*w)
: (void *)(field->fstrip + field->stripy*w);
}
/******************************** copydata **********************************/
/*
Copy image data from one field to the other.
*/
void copydata(picstruct *field, int offset, int size)
{
memcpy(field->strip+offset, field->reffield->strip+offset,
size*sizeof(PIXTYPE));
return;
}
/******************************** 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)
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)
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->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;
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);
}
/*----------------------------- 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;
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;
return;
}
/******************************* 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;
}
/*
refine.c
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: SExtractor
*
* Author: E.BERTIN (IAP)
*
* Contents: functions to refine extraction of objects.
*
* Last modify: 27/11/2003
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "define.h"
#include "globals.h"
#include "prefs.h"
#include "plist.h"
#include "extract.h"
#ifndef RAND_MAX
#define RAND_MAX 2147483647
#endif
#define NSONMAX 1024 /* max. number per level */
#define NBRANCH 16 /* starting number per branch */
static objliststruct *objlist;
static short *son, *ok;
/******************************** parcelout **********************************
PROTO parcelout(objliststruct *objlistin, objliststruct *objlistout)
PURPOSE Divide a list of isophotal detections in several parts (deblending).
INPUT input objlist,
output objlist,
OUTPUT RETURN_OK if success, RETURN_FATAL_ERROR otherwise (memory overflow).
NOTES Even if the object is not deblended, the output objlist threshold is
recomputed if a variable threshold is used.
AUTHOR E. Bertin (IAP, Leiden & ESO)
VERSION 15/03/98
***/
int parcelout(objliststruct *objlistin, objliststruct *objlistout)
{
objstruct *obj;
static objliststruct debobjlist, debobjlist2;
double dthresh, dthresh0, value0;
int h,i,j,k,l,m,
xn,
nbm = NBRANCH,
out;
out = RETURN_OK;
xn = prefs.deblend_nthresh;
/* ---- initialize lists of objects */
debobjlist.obj = debobjlist2.obj = NULL;
debobjlist.plist = debobjlist2.plist = NULL;
debobjlist.nobj = debobjlist2.nobj = 0;
debobjlist.npix = debobjlist2.npix = 0;
objlistout->thresh = debobjlist2.thresh = objlistin->thresh;
memset(objlist, 0, (size_t)xn*sizeof(objliststruct));
for (l=0; l<objlistin->nobj && out==RETURN_OK; l++)
{
dthresh0 = objlistin->obj[l].dthresh;
objlistout->dthresh = debobjlist2.dthresh = dthresh0;
if ((out = addobj(l, objlistin, &objlist[0])) == RETURN_FATAL_ERROR)
goto exit_parcelout;
if ((out = addobj(l, objlistin, &debobjlist2)) == RETURN_FATAL_ERROR)
goto exit_parcelout;
value0 = objlist[0].obj[0].fdflux*prefs.deblend_mincont;
ok[0] = (short)1;
for (k=1; k<xn; k++)
{
/*------ Calculate threshold */
dthresh = objlistin->obj[l].fdpeak;
if (dthresh>0.0)
{
if (prefs.detect_type == PHOTO)
debobjlist.dthresh= dthresh0 + (dthresh-dthresh0) * (double)k/xn;
else
debobjlist.dthresh = dthresh0 * pow(dthresh/dthresh0,(double)k/xn);
}
else
debobjlist.dthresh = dthresh0;
/*--------- Build tree (bottom->up) */
if (objlist[k-1].nobj>=NSONMAX)
{
out = RETURN_FATAL_ERROR;
goto exit_parcelout;
}
for (i=0; i<objlist[k-1].nobj; i++)
{
if ((out=lutz(objlistin,l,&objlist[k-1].obj[i], &debobjlist))
==RETURN_FATAL_ERROR)
goto exit_parcelout;
for (j=h=0; j<debobjlist.nobj; j++)
if (belong(j, &debobjlist, i, &objlist[k-1]))
{
debobjlist.obj[j].dthresh = debobjlist.dthresh;
m = addobj(j, &debobjlist, &objlist[k]);
if (m==RETURN_FATAL_ERROR || m>=NSONMAX)
{
out = RETURN_FATAL_ERROR;
goto exit_parcelout;
}
if (h>=nbm-1)
if (!(son = (short *)realloc(son,
xn*NSONMAX*(nbm+=16)*sizeof(short))))
{
out = RETURN_FATAL_ERROR;
goto exit_parcelout;
}
son[k-1+xn*(i+NSONMAX*(h++))] = (short)m;
ok[k+xn*m] = (short)1;
}
son[k-1+xn*(i+NSONMAX*h)] = (short)-1;
}
}
/*------- cut the right branches (top->down) */
for (k = xn-2; k>=0; k--)
{
obj = objlist[k+1].obj;
for (i=0; i<objlist[k].nobj; i++)
{
for (m=h=0; (j=(int)son[k+xn*(i+NSONMAX*h)])!=-1; h++)
{
if (obj[j].fdflux - obj[j].dthresh*obj[j].fdnpix > value0)
m++;
ok[k+xn*i] &= ok[k+1+xn*j];
}
if (m>1)
{
for (h=0; (j=(int)son[k+xn*(i+NSONMAX*h)])!=-1; h++)
if (ok[k+1+xn*j] && obj[j].fdflux-obj[j].dthresh*obj[j].fdnpix
> value0)
{
objlist[k+1].obj[j].flag |= OBJ_MERGED /* Merge flag on */
| ((OBJ_ISO_PB|OBJ_APERT_PB|OBJ_OVERFLOW)
&debobjlist2.obj[0].flag);
if ((out = addobj(j, &objlist[k+1], &debobjlist2))
== RETURN_FATAL_ERROR)
goto exit_parcelout;
}
ok[k+xn*i] = (short)0;
}
}
}
if (ok[0])
out = addobj(0, &debobjlist2, objlistout);
else
out = gatherup(&debobjlist2, objlistout);
exit_parcelout:
free(debobjlist2.obj);
free(debobjlist2.plist);
for (k=0; k<xn; k++)
{
free(objlist[k].obj);
free(objlist[k].plist);
}
}
free(debobjlist.obj);
free(debobjlist.plist);
return out;
}
/******************************* allocparcelout ******************************/
/*
Allocate the memory allocated by global pointers in refine.c
*/
void allocparcelout(void)
{
QMALLOC(son, short, prefs.deblend_nthresh*NSONMAX*NBRANCH);
QMALLOC(ok, short, prefs.deblend_nthresh*NSONMAX);
QMALLOC(objlist, objliststruct, prefs.deblend_nthresh);
return;
}
/******************************* freeparcelout *******************************/
/*
Free the memory allocated by global pointers in refine.c
*/
void freeparcelout(void)
{
QFREE(son);
QFREE(ok);
QFREE(objlist);
return;
}
/********************************* gatherup **********************************/
/*
Collect faint remaining pixels and allocate them to their most probable
progenitor.
*/
int gatherup(objliststruct *objlistin, objliststruct *objlistout)
{
char *bmp;
float *amp, *p, dx,dy, drand, dist, distmin;
objstruct *objin = objlistin->obj, *objout, *objt;
pliststruct *pixelin = objlistin->plist, *pixelout, *pixt,*pixt2;
int i,k,l, *n, iclst, npix, bmwidth,
nobj = objlistin->nobj, xs,ys, x,y, out;
out = RETURN_OK;
objlistout->dthresh = objlistin->dthresh;
objlistout->thresh = objlistin->thresh;
QMALLOC(amp, float, nobj);
QMALLOC(p, float, nobj);
QMALLOC(n, int, nobj);
for (i=1; i<nobj; i++)
preanalyse(i, objlistin, ANALYSE_FULL);
p[0] = 0.0;
bmwidth = objin->xmax - (xs=objin->xmin) + 1;
npix = bmwidth * (objin->ymax - (ys=objin->ymin) + 1);
if (!(bmp = (char *)calloc(1, npix*sizeof(char))))
{
bmp = 0;
out = RETURN_FATAL_ERROR;
goto exit_gatherup;
}
for (objt = objin+(i=1); i<nobj; i++, objt++)
{
/*-- Now we have passed the deblending section, reset thresholds */
objt->dthresh = objlistin->dthresh;
objt->thresh = objlistin->thresh;
/* ------------ flag pixels which are already allocated */
for (pixt=pixelin+objin[i].firstpix; pixt>=pixelin;
pixt=pixelin+PLIST(pixt,nextpix))
bmp[(PLIST(pixt,x)-xs) + (PLIST(pixt,y)-ys)*bmwidth] = '\1';
if ((n[i] = addobj(i, objlistin, objlistout)) == RETURN_FATAL_ERROR)
{
out = RETURN_FATAL_ERROR;
goto exit_gatherup;
}
dist = objt->fdnpix/(2*PI*objt->abcor*objt->a*objt->b);
amp[i] = dist<70.0? objt->thresh*exp(dist) : 4.0*objt->fdpeak;
/* ------------ limitate expansion ! */
if (amp[i]>4.0*objt->fdpeak)
amp[i] = 4.0*objt->fdpeak;
}
objout = objlistout->obj; /* DO NOT MOVE !!! */
if (!(pixelout=(pliststruct *)realloc(objlistout->plist,
(objlistout->npix + npix)*plistsize)))
{
out = RETURN_FATAL_ERROR;
goto exit_gatherup;
}
objlistout->plist = pixelout;
k = objlistout->npix;
iclst = 0; /* To avoid gcc -Wall warnings */
for (pixt=pixelin+objin->firstpix; pixt>=pixelin;
pixt=pixelin+PLIST(pixt,nextpix))
{
x = PLIST(pixt,x);
y = PLIST(pixt,y);
if (!bmp[(x-xs) + (y-ys)*bmwidth])
{
pixt2 = pixelout + (l=(k++*plistsize));
memcpy(pixt2, pixt, (size_t)plistsize);
PLIST(pixt2, nextpix) = -1;
distmin = 1e+31;
for (objt = objin+(i=1); i<nobj; i++, objt++)
{
dx = x - objt->mx;
dy = y - objt->my;
dist=0.5*(objt->cxx*dx*dx+objt->cyy*dy*dy+objt->cxy*dx*dy)/objt->abcor;
p[i] = p[i-1] + (dist<70.0?amp[i]*exp(-dist) : 0.0);
if (dist<distmin)
{
distmin = dist;
iclst = i;
}
}
if (p[nobj-1] > 1.0e-31)
{
drand = p[nobj-1]*rand()/RAND_MAX;
for (i=1; p[i]<drand; i++);
}
else
i = iclst;
objout[n[i]].lastpix=PLIST(pixelout+objout[n[i]].lastpix,nextpix)=l;
}
}
objlistout->npix = k;
if (!(objlistout->plist = (pliststruct *)realloc(pixelout,
objlistout->npix*plistsize)))
error (-1, "Not enough memory to update pixel list in ", "gatherup()");
exit_gatherup:
free(bmp);
free(amp);
free(p);
free(n);
return out;
}
/*
retina.c
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: SExtractor
*
* Author: E.BERTIN (IAP)
*
* Contents: functions dealing with retinal analysis of the data.
*
* 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 "fits/fitscat.h"
#include "bpro.h"
#include "image.h"
#include "retina.h"
/******************************** readretina *********************************/
/*
Return the response of the retina at a given image position.
*/
float readretina(picstruct *field, retistruct *retina, float x, float y)
{
float *pix, resp, norm;
int i, ix,iy;
ix = (int)(x+0.499999);
iy = (int)(y+0.499999);
if (ix>=0 && ix<field->width && iy>=field->ymin && iy<field->ymax)
norm = field->strip[ix+(iy%field->stripheight)*field->width];
else
norm = retina->minnorm;
if (norm<retina->minnorm)
norm = retina->minnorm;
/* Copy the right pixels to the retina */
pix = retina->pix;
copyimage(field, pix, retina->width, retina->height, ix,iy);
for (i=retina->npix; i--;)
*(pix++) /= norm;
*pix = -2.5*log10(norm/retina->minnorm);
play_bpann(retina->bpann, retina->pix, &resp);
return resp;
}
/********************************** getretina ********************************/
/*
Read an ANN retina file.
*/
retistruct *getretina(char *filename)
{
#define FILTEST(x) \
if (x != RETURN_OK) \
error(EXIT_FAILURE, "*Error*: RETINA header in ", filename)
retistruct *retina;
catstruct *fcat;
tabstruct *ftab;
int ival;
QMALLOC(retina, retistruct, 1);
/* We first map the catalog */
if (!(fcat = read_cat(filename)))
error(EXIT_FAILURE, "*Error*: retina file not found: ", filename);
/* Test if the requested table is present */
if (!(ftab = name_to_tab(fcat, "BP-ANN", 0)))
error(EXIT_FAILURE, "*Error*: no BP-ANN info found in ", filename);
FILTEST(fitsread(ftab->headbuf, "BPTYPE ", gstr,H_STRING,T_STRING));
if (strcmp(gstr, "RETINA_2D"))
error(EXIT_FAILURE, "*Error*: not a suitable retina in ", filename);
FILTEST(fitsread(ftab->headbuf, "RENAXIS ", &ival ,H_INT, T_LONG));
if (ival != 2)
error(EXIT_FAILURE, "*Error*: not a 2D retina in ", filename);
FILTEST(fitsread(ftab->headbuf, "RENAXIS1", &retina->width ,H_INT, T_LONG));
FILTEST(fitsread(ftab->headbuf, "RENAXIS2", &retina->height ,H_INT, T_LONG));
retina->npix = retina->width*retina->height;
FILTEST(fitsread(ftab->headbuf, "RENORM ",&retina->minnorm,H_FLOAT,T_FLOAT));
retina->bpann = loadtab_bpann(ftab, filename);
QMALLOC(retina->pix, float, retina->bpann->nn[0]);
close_cat(fcat);
free_cat(&fcat,1);
return retina;
}
/********************************** endretina ********************************/
/*
Free a retina structure.
*/
void endretina(retistruct *retina)
{
free(retina->pix);
free_bpann(retina->bpann);
free(retina);
return;
}
/*
retina.h
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: SExtractor
*
* Author: E.BERTIN, IAP & Leiden Sterrewacht.
*
* Contents: include file related to retina.c.
*
* Last modify: 07/12/96
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
/*------------------------------- structures --------------------------------*/
typedef struct structreti
{
/*---- convolution */
float *pix; /* Pointer to the copy of the pixel array */
int width, height; /* x,y size of the mask */
int npix; /* Number of pixels in the retina */
float minnorm; /* Minimum normalisation factor */
struct structbpann *bpann; /* The neural network */
} retistruct;
retistruct *theretina;
/*------------------------------- functions ---------------------------------*/
retistruct *getretina(char *filename);
float readretina(picstruct *, retistruct *, float, float);
void endretina(retistruct *retina);
/*
scan.c
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: SExtractor
*
* Author: E.BERTIN (IAP)
*
* Contents: functions for extraction of connected pixels from
* a pixmap.
*
* Last modify: 29/11/2005
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
#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 "prefs.h"
#include "back.h"
#include "check.h"
#include "clean.h"
#include "extract.h"
#include "filter.h"
#include "image.h"
#include "plist.h"
/****************************** scanimage ************************************
PROTO void scanimage(picstruct *field, picstruct *dfield, picstruct *ffield,
picstruct *wfield, picstruct *dwfield)
PURPOSE Scan of the large pixmap(s). Main loop and heart of the program.
INPUT Measurement field pointer,
Detection field pointer,
Flag field pointer,
Measurement weight-map field pointer,
Detection weight-map field pointer,
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP)
VERSION 29/11/2005
***/
void scanimage(picstruct *field, picstruct *dfield, picstruct **pffield,
int nffield, picstruct *wfield, picstruct *dwfield)
{
static infostruct curpixinfo, *info, *store,
initinfo, freeinfo, *victim;
picstruct *ffield;
checkstruct *check;
objliststruct objlist;
objstruct *cleanobj;
pliststruct *pixel, *pixt;
picstruct *cfield, *cdwfield;
char *marker, newmarker, *blankpad, *bpt,*bpt0;
int co, i,j, flag, luflag,pstop, xl,xl2,yl, cn,
nposize, stacksize, w, h, blankh, maxpixnb,
varthreshflag;
short trunflag;
PIXTYPE thresh, relthresh, cdnewsymbol, cdvar,
*scan,*dscan,*cdscan,*dwscan,*cdwscan,*cdwscanp,
*scant, *wscan,*wscanp;
FLAGTYPE *pfscan[MAXFLAG];
status cs, ps, *psstack;
int *start, *end, ymax;
/* Avoid gcc -Wall warnings */
scan = dscan = cdscan = cdwscan = cdwscanp = wscan = wscanp = NULL;
victim = NULL; /* Avoid gcc -Wall warnings */
blankh = 0; /* Avoid gcc -Wall warnings */
/*----- Beginning of the main loop: Initialisations */
thecat.ntotal = thecat.ndetect = 0;
/* cfield is the detection field in any case */
cfield = dfield? dfield:field;
/* cdwfield is the detection weight-field if available */
cdwfield = dwfield? dwfield:(prefs.dweight_flag?wfield:NULL);
/* If WEIGHTing and no absolute thresholding, activate threshold scaling */
varthreshflag = (cdwfield && prefs.thresh_type[0]!=THRESH_ABSOLUTE);
relthresh = varthreshflag ? prefs.dthresh[0] : 0.0;/* To avoid gcc warnings*/
w = cfield->width;
h = cfield->height;
objlist.dthresh = cfield->dthresh;
objlist.thresh = cfield->thresh;
cfield->yblank = 1;
field->y = field->stripy = 0;
field->ymin = field->stripylim = 0;
field->stripysclim = 0;
if (dfield)
{
dfield->y = dfield->stripy = 0;
dfield->ymin = dfield->stripylim = 0;
dfield->stripysclim = 0;
}
if (nffield)
for (i=0; i<nffield; i++)
{
ffield = pffield[i];
ffield->y = ffield->stripy = 0;
ffield->ymin = ffield->stripylim = 0;
ffield->stripysclim = 0;
}
if (wfield)
{
wfield->y = wfield->stripy = 0;
wfield->ymin = wfield->stripylim = 0;
wfield->stripysclim = 0;
}
if (dwfield)
{
dwfield->y = dwfield->stripy = 0;
dwfield->ymin = dwfield->stripylim = 0;
dwfield->stripysclim = 0;
}
/*Allocate memory for buffers */
stacksize = w+1;
QMALLOC(info, infostruct, stacksize);
QMALLOC(store, infostruct, stacksize);
QMALLOC(marker, char, stacksize);
QMALLOC(dumscan, PIXTYPE, stacksize);
QMALLOC(psstack, status, stacksize);
QMALLOC(start, int, stacksize);
QMALLOC(end, int, stacksize);
blankpad = bpt = NULL;
lutzalloc(w,h);
allocparcelout();
if (prefs.filter_flag)
{
QMALLOC(cdscan, PIXTYPE, stacksize);
if (cdwfield)
{
QCALLOC(cdwscan, PIXTYPE, stacksize);
if (PLISTEXIST(wflag))
{
QMALLOC(cdwscanp, PIXTYPE, stacksize);
}
}
/*-- One needs a buffer to protect filtering if source-blanking applies */
if (prefs.blank_flag)
{
blankh = thefilter->convh/2+1;
QMALLOC(blankpad, char, w*blankh);
cfield->yblank -= blankh;
if (dfield)
field->yblank = cfield->yblank;
bpt = blankpad;
}
}
/* Some initializations */
thresh = objlist.dthresh;
initinfo.pixnb = 0;
initinfo.flag = 0;
initinfo.firstpix = initinfo.lastpix = -1;
for (xl=0; xl<stacksize; xl++)
{
marker[xl] = 0 ;
dumscan[xl] = -BIG ;
}
co = pstop = 0;
objlist.nobj = 1;
curpixinfo.pixnb = 1;
/* Init cleaning procedure */
initclean();
/*----- Allocate memory for the pixel list */
init_plist();
if (!(pixel = objlist.plist = malloc(nposize=prefs.mem_pixstack*plistsize)))
error(EXIT_FAILURE, "Not enough memory to store the pixel stack:\n",
" Try to decrease MEMORY_PIXSTACK");
/*----- at the beginning, "free" object fills the whole pixel list */
freeinfo.firstpix = 0;
freeinfo.lastpix = nposize-plistsize;
pixt = pixel;
for (i=plistsize; i<nposize; i += plistsize, pixt += plistsize)
PLIST(pixt, nextpix) = i;
PLIST(pixt, nextpix) = -1;
/*----- Here we go */
for (yl=0; yl<=h;)
{
ps = COMPLETE;
cs = NONOBJECT;
if (yl==h)
{
/*---- Need an empty line for Lutz' algorithm to end gracely */
if (prefs.filter_flag)
{
free(cdscan);
if (cdwfield)
{
free(cdwscan);
if (PLISTEXIST(wflag))
free(cdwscanp);
}
}
cdwscan = cdwscanp = cdscan = dumscan;
}
else
{
if (nffield)
for (i=0; i<nffield; i++)
{
ffield = pffield[i];
pfscan[i] = (ffield->stripy==ffield->stripysclim)?
(FLAGTYPE *)loadstrip(ffield, (picstruct *)NULL)
: &ffield->fstrip[ffield->stripy*ffield->width];
}
if (wfield)
{
/*------ Copy the previous weight line to track bad pixel limits */
wscan = (wfield->stripy==wfield->stripysclim)?
(PIXTYPE *)loadstrip(wfield, (picstruct *)NULL)
: &wfield->strip[wfield->stripy*wfield->width];
if (yl && PLISTEXIST(wflag))
wscanp = &wfield->strip[((yl-1)%wfield->stripheight)*wfield->width];
}
else
wscan = NULL;
scan = (field->stripy==field->stripysclim)?
(PIXTYPE *)loadstrip(field, wfield)
: &field->strip[field->stripy*field->width];
if (dwfield)
dwscan = (dwfield->stripy==dwfield->stripysclim)?
(PIXTYPE *)loadstrip(dwfield,
dfield?(picstruct *)NULL:dwfield)
: &dwfield->strip[dwfield->stripy*dwfield->width];
else
dwscan = wscan;
if (dfield)
dscan = (dfield->stripy==dfield->stripysclim)?
(PIXTYPE *)loadstrip(dfield, dwfield)
: &dfield->strip[dfield->stripy*dfield->width];
else
dscan = scan;
if (PLISTEXIST(wflag) && cdwfield)
/*------ Copy the previous filtered weight line to track bad pixel limits */
memcpy(cdwscanp, cdwscan, wfield->width*sizeof(PIXTYPE));
if (prefs.filter_flag)
{
filter(cfield, cdscan);
if (cdwfield)
filter(cdwfield, cdwscan);
}
else
{
cdscan = dscan;
cdwscan = dwscan;
}
if ((check=prefs.check[CHECK_FILTERED]))
writecheck(check, cdscan, w);
}
trunflag = (yl==0 || yl==h-1)? OBJ_TRUNC:0;
for (xl=0; xl<=w; xl++)
{
if (xl == w)
cdnewsymbol = -BIG;
else
cdnewsymbol = cdscan[xl];
newmarker = marker[xl];
marker[xl] = 0;
curpixinfo.flag = trunflag;
if (varthreshflag)
thresh = relthresh*sqrt(cdvar = ((xl==w || yl==h)? 0.0:cdwscan[xl]));
luflag = cdnewsymbol > thresh?1:0;
if (luflag)
{
if (xl==0 || xl==w-1)
curpixinfo.flag |= OBJ_TRUNC;
pixt = pixel + (cn=freeinfo.firstpix);
freeinfo.firstpix = PLIST(pixt, nextpix);
/*------- Running out of pixels, the largest object becomes a "victim" ------*/
if (freeinfo.firstpix==freeinfo.lastpix)
{
sprintf(gstr, "%d,%d", xl+1, yl+1);
warning("Pixel stack overflow at position ", gstr);
maxpixnb = 0;
for (i=0; i<=w; i++)
if (store[i].pixnb>maxpixnb)
if (marker[i]=='S' || (newmarker=='S' && i==xl))
{
flag = 0;
if (i<xl)
for (j=0; j<=co; j++)
flag |= (start[j]==i);
if (!flag)
maxpixnb = (victim = &store[i])->pixnb;
}
for (j=1; j<=co; j++)
if (info[j].pixnb>maxpixnb)
maxpixnb = (victim = &info[j])->pixnb;
if (!maxpixnb)
error(EXIT_FAILURE, "*Fatal Error*: something is badly bugged in ",
"scanimage()!");
if (maxpixnb <= 1)
error(EXIT_FAILURE, "Pixel stack overflow in ", "scanimage()");
freeinfo.firstpix = PLIST(pixel+victim->firstpix, nextpix);
PLIST(pixel+victim->lastpix, nextpix) = freeinfo.lastpix;
PLIST(pixel+(victim->lastpix=victim->firstpix), nextpix) = -1;
victim->pixnb = 1;
victim->flag |= OBJ_OVERFLOW;
}
/*---------------------------------------------------------------------------*/
curpixinfo.lastpix = curpixinfo.firstpix = cn;
PLIST(pixt, nextpix) = -1;
PLIST(pixt, x) = xl;
PLIST(pixt, y) = yl;
PLIST(pixt, value) = scan[xl];
if (PLISTEXIST(dvalue))
PLISTPIX(pixt, dvalue) = dscan[xl];
if (PLISTEXIST(cdvalue))
PLISTPIX(pixt, cdvalue) = cdnewsymbol;
if (PLISTEXIST(flag))
for (i=0; i<nffield; i++)
PLISTFLAG(pixt, flag[i]) = pfscan[i][xl];
if (PLISTEXIST(wflag) && wscan)
{
PLISTFLAG(pixt, wflag) = 0;
if (xl>0)
{
if (wscan[xl-1] >= BIG)
PLISTFLAG(pixt, wflag) |= OBJ_WEIGHTZERO;
if (cdwscan[xl-1] >= BIG)
PLISTFLAG(pixt, wflag) = OBJ_DWEIGHTZERO;
}
PLISTFLAG(pixt, wflag) = 0;
if (xl<w-1)
{
if (wscan[xl+1] >= BIG)
PLISTFLAG(pixt, wflag) |= OBJ_WEIGHTZERO;
if (cdwscan[xl+1] >= BIG)
PLISTFLAG(pixt, wflag) = OBJ_DWEIGHTZERO;
}
if (yl>0)
{
if (wscanp[xl] >= BIG)
PLISTFLAG(pixt, wflag) |= OBJ_WEIGHTZERO;
if (cdwscanp[xl] >= BIG)
PLISTFLAG(pixt, wflag) = OBJ_DWEIGHTZERO;
}
}
if (PLISTEXIST(dthresh))
PLISTPIX(pixt, dthresh) = thresh;
if (PLISTEXIST(var))
PLISTPIX(pixt, var) = wscan[xl];
if (cs != OBJECT)
/*------------------------------- Start Segment -----------------------------*/
{
cs = OBJECT;
if (ps == OBJECT)
{
if (start[co] == UNKNOWN)
{
marker[xl] = 'S';
start[co] = xl;
}
else
marker[xl] = 's';
}
else
{
psstack[pstop++] = ps;
marker[xl] = 'S';
start[++co] = xl;
ps = COMPLETE;
info[co] = initinfo;
}
}
/*---------------------------------------------------------------------------*/
}
if (newmarker)
/*---------------------------- Process New Marker ---------------------------*/
{
if (newmarker == 'S')
{
psstack[pstop++] = ps;
if (cs == NONOBJECT)
{
psstack[pstop++] = COMPLETE;
info[++co] = store[xl];
start[co] = UNKNOWN;
}
else
update (&info[co],&store[xl], pixel);
ps = OBJECT;
}
else if (newmarker == 's')
{
if ((cs == OBJECT) && (ps == COMPLETE))
{
pstop--;
xl2 = start[co];
update (&info[co-1],&info[co], pixel);
if (start[--co] == UNKNOWN)
start[co] = xl2;
else
marker[xl2] = 's';
}
ps = OBJECT;
}
else if (newmarker == 'f')
ps = INCOMPLETE;
else if (newmarker == 'F')
{
ps = psstack[--pstop];
if ((cs == NONOBJECT) && (ps == COMPLETE))
{
if (start[co] == UNKNOWN)
{
if ((int)info[co].pixnb >= prefs.ext_minarea)
{
sortit(field, dfield, wfield, cdwfield, &info[co], &objlist,
cdwscan, wscan);
}
/* ------------------------------------ free the chain-list */
PLIST(pixel+info[co].lastpix, nextpix) = freeinfo.firstpix;
freeinfo.firstpix = info[co].firstpix;
}
else
{
marker[end[co]] = 'F';
store[start[co]] = info[co];
}
co--;
ps = psstack[--pstop];
}
}
}
/*---------------------------------------------------------------------------*/
if (luflag)
update (&info[co],&curpixinfo, pixel);
else
{
if (cs == OBJECT)
/*-------------------------------- End Segment ------------------------------*/
{
cs = NONOBJECT;
if (ps != COMPLETE)
{
marker[xl] = 'f';
end[co] = xl;
}
else
{
ps = psstack[--pstop];
marker[xl] = 'F';
store[start[co]] = info[co];
co--;
}
}
}
if (prefs.blank_flag && xl<w)
{
if (prefs.filter_flag)
*(bpt++) = (luflag)?1:0;
else if (luflag)
dscan[xl] = -BIG;
if (dfield && luflag)
scan[xl] = -BIG;
}
/*--------------------- End of the loop over the x's -----------------------*/
}
/* Detected pixel removal at the end of each line */
if (prefs.blank_flag && yl<h)
{
if (prefs.filter_flag)
{
bpt = bpt0 = blankpad + w*((yl+1)%blankh);
if (cfield->yblank >= 0)
{
scant = &PIX(cfield, 0, cfield->yblank);
for (i=w; i--; scant++)
if (*(bpt++))
*scant = -BIG;
if (dfield)
{
bpt = bpt0;
scant = &PIX(field, 0, cfield->yblank);
for (i=w; i--; scant++)
if (*(bpt++))
*scant = -BIG;
}
bpt = bpt0;
}
}
cfield->yblank++;
if (dfield)
field->yblank = cfield->yblank;
}
/*-- Prepare markers for the next line */
yl++;
field->stripy = (field->y=yl)%field->stripheight;
if (dfield)
dfield->stripy = (dfield->y=yl)%dfield->stripheight;
if (nffield)
for (i=0; i<nffield; i++)
{
ffield = pffield[i];
ffield->stripy = (ffield->y=yl)%ffield->stripheight;
}
if (wfield)
wfield->stripy = (wfield->y=yl)%wfield->stripheight;
if (dwfield)
dwfield->stripy = (dwfield->y=yl)%dwfield->stripheight;
/*-- Remove objects close to the ymin limit if ymin is ready to increase */
if (cfield->stripy==cfield->stripysclim)
{
cleanobj = cleanobjlist->obj+cleanobjlist->nobj-1;
for (i=cleanobjlist->nobj; i--; cleanobj--)
{
if (cleanobj->ycmin <= cfield->ymin)
{
/*-------- Warn if there is a possibility for any aperture to be truncated */
if ((ymax=cleanobj->ycmax) > cfield->ymax)
{
sprintf(gstr, "Object at position %.0f,%.0f ",
cleanobj->mx+1, cleanobj->my+1);
QWARNING(gstr, "may have some apertures truncated:\n"
" You might want to increase MEMORY_BUFSIZE");
}
else if (ymax>cfield->yblank && prefs.blank_flag)
{
sprintf(gstr, "Object at position %.0f,%.0f ",
cleanobj->mx+1, cleanobj->my+1);
QWARNING(gstr, "may have some unBLANKed neighbours:\n"
" You might want to increase MEMORY_PIXSTACK");
}
endobject(field, dfield, wfield, cdwfield, i, cleanobjlist);
subcleanobj(i);
cleanobj = cleanobjlist->obj+i; /* realloc in subcleanobj() */
}
}
}
if (!((yl+1)%16))
NPRINTF(OUTPUT, "\33[1M> Line:%5d "
"Objects: %8d detected / %8d sextracted\n\33[1A",
yl+1, thecat.ndetect, thecat.ntotal);
/*--------------------- End of the loop over the y's -----------------------*/
}
/* Removal or the remaining pixels */
if (prefs.blank_flag && prefs.filter_flag && (cfield->yblank >= 0))
for (j=blankh-1; j--; yl++)
{
bpt = bpt0 = blankpad + w*(yl%blankh);
scant = &PIX(cfield, 0, cfield->yblank);
for (i=w; i--; scant++)
if (*(bpt++))
*scant = -BIG;
if (dfield)
{
bpt = bpt0;
scant = &PIX(field, 0, cfield->yblank);
for (i=w; i--; scant++)
if (*(bpt++))
*scant = -BIG;
}
cfield->yblank++;
if (dfield)
field->yblank = cfield->yblank;
}
/* Now that all "detected" pixels have been removed, analyse detections */
for (j=cleanobjlist->nobj; j--;)
{
endobject(field, dfield, wfield, cdwfield, 0, cleanobjlist);
subcleanobj(0);
}
endclean();
/*Free memory */
freeparcelout();
free(pixel);
lutzfree();
free(info);
free(store);
free(marker);
free(dumscan);
free(psstack);
free(start);
free(end);
if (prefs.blank_flag && prefs.filter_flag)
free(blankpad);
return;
}
/********************************* update ************************************/
/*
update object's properties each time one of its pixels is scanned by lutz()
*/
void update(infostruct *infoptr1, infostruct *infoptr2, pliststruct *pixel)
{
infoptr1->pixnb += infoptr2->pixnb;
infoptr1->flag |= infoptr2->flag;
if (infoptr1->firstpix == -1)
{
infoptr1->firstpix = infoptr2->firstpix;
infoptr1->lastpix = infoptr2->lastpix;
}
else if (infoptr2->lastpix != -1)
{
PLIST(pixel+infoptr1->lastpix, nextpix) = infoptr2->firstpix;
infoptr1->lastpix = infoptr2->lastpix;
}
return;
}
/********************************* sortit ************************************/
/*
build the object structure.
*/
void sortit(picstruct *field, picstruct *dfield, picstruct *wfield,
picstruct *dwfield, infostruct *info, objliststruct *objlist,
PIXTYPE *cdwscan, PIXTYPE *wscan)
{
picstruct *cfield;
objliststruct objlistout, *objlist2;
static objstruct obj;
objstruct *cobj;
pliststruct *pixel;
int i,j,n;
cfield = dfield? dfield: field;
pixel = objlist->plist;
objlistout.obj = NULL;
objlistout.plist = NULL;
objlistout.nobj = objlistout.npix = 0;
/*----- Allocate memory to store object data */
objlist->obj = &obj;
objlist->nobj = 1;
memset(&obj, 0, (size_t)sizeof(objstruct));
objlist->npix = info->pixnb;
obj.firstpix = info->firstpix;
obj.lastpix = info->lastpix;
obj.flag = info->flag;
obj.dthresh = objlist->dthresh;
obj.thresh = objlist->thresh;
preanalyse(0, objlist, ANALYSE_FAST);
/*----- Check if the current strip contains the lower isophote... */
if ((int)obj.ymin < cfield->ymin)
obj.flag |= OBJ_ISO_PB;
if (!(obj.flag & OBJ_OVERFLOW) && (createsubmap(objlist, 0) == RETURN_OK))
{
if (parcelout(objlist, &objlistout) == RETURN_OK)
objlist2 = &objlistout;
else
{
objlist2 = objlist;
for (i=0; i<objlist2->nobj; i++)
objlist2->obj[i].flag |= OBJ_DOVERFLOW;
sprintf(gstr, "%.0f,%.0f", obj.mx+1, obj.my+1);
warning("Deblending overflow for detection at ", gstr);
}
free(obj.submap);
}
else
objlist2 = objlist;
for (i=0; i<objlist2->nobj; i++)
{
preanalyse(i, objlist2, ANALYSE_FULL|ANALYSE_ROBUST);
analyse(field, dfield, i, objlist2);
cobj = objlist2->obj + i;
if (prefs.blank_flag)
{
if (createblank(objlist2,i) != RETURN_OK)
{
/*------ Not enough mem. for the BLANK vignet: flag the object now */
cobj->flag |= OBJ_OVERFLOW;
cobj->blank = cobj->dblank = NULL;
sprintf(gstr, "%.0f,%.0f", cobj->mx+1, cobj->my+1);
warning("Memory overflow during masking for detection at ", gstr);
}
}
if ((n=cleanobjlist->nobj) >= prefs.clean_stacksize)
{
objstruct *cleanobj;
int ymin, ymax, victim=0;
ymin = 2000000000; /* No image is expected to be that tall ! */
cleanobj = cleanobjlist->obj;
for (j=0; j<n; j++, cleanobj++)
if (cleanobj->ycmax < ymin)
{
victim = j;
ymin = cleanobj->ycmax;
}
/*---- Warn if there is a possibility for any aperture to be truncated */
if (field->ymax < field->height)
{
cleanobj = &cleanobjlist->obj[victim];
if ((ymax=cleanobj->ycmax) > field->ymax)
{
sprintf(gstr, "Object at position %.0f,%.0f ",
cleanobj->mx+1, cleanobj->my+1);
QWARNING(gstr, "may have some apertures truncated:\n"
" You might want to increase MEMORY_OBJSTACK");
}
else if (ymax>field->yblank && prefs.blank_flag)
{
sprintf(gstr, "Object at position %.0f,%.0f ",
cleanobj->mx+1, cleanobj->my+1);
QWARNING(gstr, "may have some unBLANKed neighbours\n"
" You might want to increase MEMORY_OBJSTACK");
}
}
endobject(field, dfield, wfield, dwfield, victim, cleanobjlist);
subcleanobj(victim);
}
/* Only add the object if it is not swallowed by cleaning */
if (!prefs.clean_flag || clean(field, dfield, i, objlist2))
addcleanobj(cobj);
}
free(objlistout.plist);
free(objlistout.obj);
return;
}
/******************************** preanalyse *********************************
PROTO void preanalyse(int no, objliststruct *objlist, int analyse_type)
PURPOSE Compute basic image parameters from the pixel-list for each detection.
INPUT objlist number,
objlist pointer,
analysis switch flag.
OUTPUT -.
NOTES -.
AUTHOR E. Bertin (IAP & Leiden & ESO)
VERSION 28/11/2003
***/
void preanalyse(int no, objliststruct *objlist, int analyse_type)
{
objstruct *obj = &objlist->obj[no];
pliststruct *pixel = objlist->plist, *pixt;
PIXTYPE peak, cpeak, val, cval, minthresh, thresht;
double thresh,thresh2, t1t2,darea,
mx,my, mx2,my2,mxy, rv, tv,
xm,ym, xm2,ym2,xym,
temp,temp2, theta,pmx2,pmy2;
int x, y, xmin,xmax, ymin,ymax,area2, fdnpix, dnpix;
/*----- initialize stacks and bounds */
thresh = obj->dthresh;
if (PLISTEXIST(dthresh))
minthresh = BIG;
else
minthresh = 0.0;
fdnpix = dnpix = 0;
rv = 0.0;
peak = cpeak = -BIG;
ymin = xmin = 2*MAXPICSIZE; /* to be really sure!! */
ymax = xmax = 0;
/*----- integrate results */
for (pixt=pixel+obj->firstpix; pixt>=pixel; pixt=pixel+PLIST(pixt,nextpix))
{
x = PLIST(pixt, x);
y = PLIST(pixt, y);
val=PLISTPIX(pixt, dvalue);
if (cpeak < (cval=PLISTPIX(pixt, cdvalue)))
cpeak = cval;
if (PLISTEXIST(dthresh) && (thresht=PLISTPIX(pixt, dthresh))<minthresh)
minthresh = thresht;
if (peak < val)
peak = val;
rv += cval;
if (xmin > x)
xmin = x;
if (xmax < x)
xmax = x;
if (ymin > y)
ymin = y;
if (ymax < y)
ymax = y;
fdnpix++;
}
if (PLISTEXIST(dthresh))
obj->dthresh = thresh = minthresh;
/* copy some data to "obj" structure */
obj->fdnpix = (LONG)fdnpix;
obj->fdflux = (float)rv;
obj->fdpeak = cpeak;
obj->dpeak = peak;
obj->xmin = xmin;
obj->xmax = xmax;
obj->ymin = ymin;
obj->ymax = ymax;
if (analyse_type & ANALYSE_FULL)
{
mx = my = tv = 0.0;
mx2 = my2 = mxy = 0.0;
thresh2 = (thresh + peak)/2.0;
area2 = 0;
for (pixt=pixel+obj->firstpix; pixt>=pixel; pixt=pixel+PLIST(pixt,nextpix))
{
x = PLIST(pixt,x)-xmin; /* avoid roundoff errors on big images */
y = PLIST(pixt,y)-ymin; /* avoid roundoff errors on big images */
cval = PLISTPIX(pixt, cdvalue);
tv += (val = PLISTPIX(pixt, dvalue));
if (val>thresh)
dnpix++;
if (val > thresh2)
area2++;
mx += cval * x;
my += cval * y;
mx2 += cval * x*x;
my2 += cval * y*y;
mxy += cval * x*y;
}
/*----- compute object's properties */
xm = mx / rv; /* mean x */
ym = my / rv; /* mean y */
/*-- In case of blending, use previous barycenters */
if ((analyse_type&ANALYSE_ROBUST) && (obj->flag&OBJ_MERGED))
{
double xn,yn;
xn = obj->mx-xmin;
yn = obj->my-ymin;
xm2 = mx2 / rv + xn*xn - 2*xm*xn;
ym2 = my2 / rv + yn*yn - 2*ym*yn;
xym = mxy / rv + xn*yn - xm*yn - xn*ym;
xm = xn;
ym = yn;
}
else
{
xm2 = mx2 / rv - xm * xm; /* variance of x */
ym2 = my2 / rv - ym * ym; /* variance of y */
xym = mxy / rv - xm * ym; /* covariance */
}
/* Handle fully correlated x/y (which cause a singularity...) */
if ((temp2=xm2*ym2-xym*xym)<0.00694)
{
xm2 += 0.0833333;
ym2 += 0.0833333;
temp2 = xm2*ym2-xym*xym;
obj->singuflag = 1;
}
else
obj->singuflag = 0;
if ((fabs(temp=xm2-ym2)) > 0.0)
theta = atan2(2.0 * xym,temp) / 2.0;
else
theta = PI/4.0;
temp = sqrt(0.25*temp*temp+xym*xym);
pmy2 = pmx2 = 0.5*(xm2+ym2);
pmx2+=temp;
pmy2-=temp;
obj->dnpix = (obj->flag & OBJ_OVERFLOW)? obj->fdnpix:(LONG)dnpix;
obj->dflux = tv;
obj->mx = xm+xmin; /* add back xmin */
obj->my = ym+ymin; /* add back ymin */
obj->mx2 = xm2;
obj->my2 = ym2;
obj->mxy = xym;
obj->a = (float)sqrt(pmx2);
obj->b = (float)sqrt(pmy2);
obj->theta = theta*180.0/PI;
obj->cxx = (float)(ym2/temp2);
obj->cyy = (float)(xm2/temp2);
obj->cxy = (float)(-2*xym/temp2);
darea = (double)area2 - dnpix;
t1t2 = thresh/thresh2;
if (t1t2>0.0 && !prefs.dweight_flag)
{
obj->abcor = (darea<0.0?darea:-1.0)/(2*PI*log(t1t2<1.0?t1t2:0.99)
*obj->a*obj->b);
if (obj->abcor>1.0)
obj->abcor = 1.0;
}
else
obj->abcor = 1.0;
}
return;
}
/*
sexhead.h
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: SExtractor
*
* Author: E.BERTIN (IAP)
*
* Contents: header structure and templates for catalog data.
*
* Last modify: 13/12/2004
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
keystruct headkey[] = {
{"FITSFILE", "File name of the analysed image",
thecat.image_name, H_STRING, T_STRING, "%-18s"},
{"FITSEXT ", "FITS Extension number",
&thecat.currext, H_INT, T_LONG, "%3d"},
{"FITSNEXT", "Number of FITS image extensions in file",
&thecat.next, H_INT, T_LONG, "3d"},
{"SEXVERS ", "Extraction software",
thecat.soft_name, H_STRING, T_STRING, "%-18s"},
{"SEXDATE ", "Extraction date",
thecat.ext_date, H_STRING, T_STRING, "%-18s"},
{"SEXTIME ", "Extraction time",
thecat.ext_time, H_STRING, T_STRING, "%-18s"},
{"SEXELAPS", "Elapsed time during extraction (s)",
&thecat.ext_elapsed, H_FLOAT, T_DOUBLE, "%7.1f"},
{"SEXBKGND", "Median background level (ADU)",
&thefield1.backmean, H_EXPO, T_FLOAT, "%-13G"},
{"SEXBKDEV", "Median background RMS (ADU)",
&thefield1.backsig, H_EXPO, T_FLOAT, "%-13G"},
{"SEXTHLD ", "Extraction threshold (ADU)",
&thefield2.dthresh, H_EXPO, T_FLOAT, "%-15G"},
{"SEXATHLD", "Analysis threshold (ADU)",
&thefield1.thresh, H_EXPO, T_FLOAT, "%-15G"},
{"SEXNDET ", "Number of raw detections",
&thecat.ndetect, H_INT, T_LONG, "%9d"},
{"SEXNFIN ", "Final number of extracted sources",
&thecat.ntotal, H_INT, T_LONG, "%9d"},
{"SEXNPARA", "Number of parameters per source",
&thecat.nparam, H_INT, T_LONG, "%3d"},
{"SEXPXSCL", "Pixel scale used for measurements (arcsec)",
&thefield1.pixscale, H_EXPO, T_DOUBLE, "%-15G"},
{"SEXSFWHM", "Source FWHM used for measurements (arcsec)",
&prefs.seeing_fwhm, H_EXPO, T_DOUBLE, "%-13G"},
{"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"},
{"SEXFLTR ", "Detection filtering activated (flag)",
&prefs.filter_flag, H_BOOL, T_LONG, "%1s"},
{"SEXFILTN", "Filter filename",
thecat.filter_name, H_STRING, T_STRING, "%-18s"},
/*
{"SEXDETT ", "Detection type",
&prefs.detect_type, H_STRING, T_STRING, "%-18s"},
*/
{"SEXMINAR", "Minimum area used for detection (pixels)",
&prefs.ext_minarea, H_INT, T_LONG, "%5d"},
{"SEXDBLDN", "Number of deblending thresholds",
&prefs.deblend_nthresh, H_INT, T_LONG, "%3d"},
{"SEXDBLDC", "Minimum contrast used for deblending",
&prefs.deblend_mincont, H_FLOAT, T_DOUBLE, "%8f"},
{"SEXCLN ", "Cleaning activated (flag)",
&prefs.clean_flag, H_BOOL, T_LONG, "%1s"},
{"SEXCLNPA", "Cleaning parameter",
&prefs.clean_param, H_FLOAT, T_DOUBLE, "%5.2f"},
{"SEXCLNST", "Cleaning stack-size",
&prefs.clean_stacksize, H_INT, T_LONG, "%6d"},
{"SEXAPED1", "Fixed photometric aperture #1 (pixels)",
&prefs.apert[0], H_FLOAT, T_DOUBLE, "%7.1f"},
{"SEXAPED2", "Fixed photometric aperture #2 (pixels)",
&prefs.apert[1], H_FLOAT, T_DOUBLE, "%7.1f"},
{"SEXAPED3", "Fixed photometric aperture #3 (pixels)",
&prefs.apert[2], H_FLOAT, T_DOUBLE, "%7.1f"},
{"SEXAPED4", "Fixed photometric aperture #4 (pixels)",
&prefs.apert[3], H_FLOAT, T_DOUBLE, "%7.1f"},
{"SEXAUTP1", "Parameter #1 used for automatic magnitudes",
&prefs.autoparam[0], H_FLOAT, T_DOUBLE, "%4.1f"},
{"SEXAUTP2", "Parameter #2 used for automatic magnitudes",
&prefs.autoparam[1], H_FLOAT, T_DOUBLE, "%4.1f"},
{"SEXPETP1", "Parameter #1 used for Petronsian magnitudes",
&prefs.autoparam[0], H_FLOAT, T_DOUBLE, "%4.1f"},
{"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"},
{"SEXMGZPT", "Zero-point used for magnitudes",
&prefs.mag_zeropoint, H_FLOAT, T_DOUBLE, "%8.4f"},
{"SEXMGGAM", "Gamma used for photographic photometry",
&prefs.mag_gamma, H_FLOAT, T_DOUBLE, "%4.2f"},
{"SEXBKGSX", "Mesh width used for background mapping (pixels)",
&thefield1.backw, H_INT, T_LONG, "%5d"},
{"SEXBKGSY", "Mesh height used for background mapping (pixels)",
&thefield1.backh, H_INT, T_LONG, "%5d"},
{"SEXBKGFX", "Mask width used for background map filtering",
&thefield1.nbackfx, H_INT, T_LONG, "%3d"},
{"SEXBKGFY", "Mask height used for background map filtering",
&thefield1.nbackfy, H_INT, T_LONG, "%3d"},
/*
{"SEXPBKGT", "Background type for photometry",
&prefs.pback_type, H_STRING, T_STRING, "-18s"},
*/
{"SEXPBKGS", "Thickness used for local background (pixels)",
&prefs.pback_size, H_INT, T_LONG, "%3d"},
{"SEXPIXSK", "Pixel stack-size (pixels)",
&prefs.mem_pixstack, H_INT, T_LONG, "%8d"},
{"SEXFBUFS", "Image-buffer height (scanlines)",
&prefs.mem_bufsize, H_INT, T_LONG, "%5d"},
{"SEXMWSCL", "Measurement-weight re-scaling factor",
&thewfield1.sigfac, H_EXPO, T_FLOAT, "%-13G"},
{"SEXDWSCL", "Detection-weight re-scaling factor",
&thewfield2.sigfac, H_EXPO, T_FLOAT, "%-13G"},
{""}};
/*
sexhead1.h
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: SExtractor
*
* Author: E.BERTIN (IAP)
*
* Contents: header (FITS format #1) and templates for catalog data.
*
* Last modify: 16/12/2002
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
int idummy;
double ddummy;
keystruct headkey1[] = {
{"EPOCH ", "",
&thefield1.epoch, H_FLOAT, T_DOUBLE, "%7.2f"},
{"OBJECT ", "",
thefield1.ident, H_STRING, T_STRING, "%18s"},
{"ORIGIN ", "",
"SExtractor", H_STRING, T_STRING, "%18s"},
{"CRVAL1", "WORLD X COORD. OF REFERENCE PIXEL",
&ddummy, H_EXPO, T_DOUBLE, "%15G"},
{"CRVAL2", "WORLD Y COORD. OF REFERENCE PIXEL",
&ddummy, H_EXPO, T_DOUBLE, "%15G"},
{"CRPIX1", "IMAGE X COORD. OF REFERENCE PIXEL",
&idummy, H_INT, T_LONG, "%5d"},
{"CRPIX2", "IMAGE Y COORD. OF REFERENCE PIXEL",
&idummy, H_INT, T_LONG, "%5d"},
{"CDELT1", "WORLD PIXEL STEP ALONG X",
&ddummy, H_EXPO, T_DOUBLE, "%15G"},
{"CDELT2", "WORLD PIXEL STEP ALONG Y",
&ddummy, H_EXPO, T_DOUBLE, "%15G"},
{"CROTA1", "CCW ANGLE FROM X-IMAGE TO X-WORLD",
&ddummy, H_EXPO, T_DOUBLE, "%15G"},
{"CROTA2", "CCW ANGLE FROM Y-IMAGE TO Y-WORLD",
&ddummy, H_EXPO, T_DOUBLE, "%15G"},
{"FITSFILE", "File name of the analysed image",
thecat.image_name, H_STRING, T_STRING, "%-18s"},
{"FITSEXT ", "FITS Extension number",
&thecat.currext, H_INT, T_LONG, "%3d"},
{"FITSNEXT", "Number of FITS image extensions in file",
&thecat.next, H_INT, T_LONG, "3d"},
{"SEXIMASX", "IMAGE WIDTH (PIXELS)",
&thefield1.width, H_INT, T_LONG, "%10d"},
{"SEXIMASY", "IMAGE HEIGHT (PIXELS)",
&thefield1.height, H_INT, T_LONG, "%10d"},
{"SEXSTRSY", "STRIP HEIGHT (LINES)",
&thefield1.stripheight, H_INT, T_LONG, "%10d"},
{"SEXIMABP", "FITS IMAGE BITPIX",
&thefield1.bitpix, H_INT, T_LONG, "%3d"},
{"SEXPIXS", "PIXEL SCALE (ARCSEC)",
&thefield1.pixscale, H_EXPO, T_DOUBLE, "%12G"},
{"SEXSFWHM", "SEEING FWHM (ARCSEC)",
&prefs.seeing_fwhm, H_EXPO, T_DOUBLE, "%12G"},
{"SEXNNWF ", "CLASSIFICATION NNW FILENAME",
thecat.nnw_name, H_STRING, T_STRING, "%18s"},
{"SEXGAIN ", "GAIN (IN E- PER ADU)",
&prefs.gain, H_EXPO, T_DOUBLE, "%7.3F"},
{"SEXBKGND", "MEDIAN BACKGROUND (ADU)",
&thefield1.backmean, H_EXPO, T_FLOAT, "%12G"},
{"SEXBKDEV", "MEDIAN RMS (ADU)",
&thefield1.backsig, H_EXPO, T_FLOAT, "%12G"},
{"SEXBKTHD", "EXTRACTION THRESHOLD (ADU)",
&thefield2.thresh, H_EXPO, T_FLOAT, "%12G"},
{"SEXCONFF", "CONFIGURATION FILENAME",
thecat.prefs_name, H_STRING, T_STRING, "%18s"},
{"SEXDETT ", "DETECTION TYPE",
"CCD", H_STRING, T_STRING, "%s"},
{"SEXTHLDT", "THRESHOLD TYPE",
"SIGMA", H_STRING, T_STRING, "%s"},
{"SEXTHLD ", "THRESHOLD",
&prefs.dthresh[0], H_EXPO, T_DOUBLE, "%12G"},
{"SEXMINAR", "EXTRACTION MINIMUM AREA (PIXELS)",
&prefs.ext_minarea, H_INT, T_LONG, "%6d"},
{"SEXCONV ", "CONVOLUTION FLAG",
&prefs.filter_flag, H_BOOL, T_LONG, "%1s"},
{"SEXCONVN", "CONVOLUTION NORM. FLAG",
&prefs.filter_flag, H_BOOL, T_LONG, "%1s"},
{"SEXCONVF", "CONVOLUTION FILENAME",
thecat.filter_name, H_STRING, T_STRING, "%18s"},
{"SEXDBLDN", "NUMBER OF SUB-THRESHOLDS",
&prefs.deblend_nthresh, H_INT, T_LONG, "%3d"},
{"SEXDBLDC", "CONTRAST PARAMETER",
&prefs.deblend_mincont, H_FLOAT, T_DOUBLE, "%8f"},
{"SEXCLN ", "CLEANING FLAG",
&prefs.clean_flag, H_BOOL, T_LONG, "%1s"},
{"SEXCLNPA", "CLEANING PARAMETER",
&prefs.clean_param, H_FLOAT, T_DOUBLE, "%8f"},
{"SEXCLNST", "CLEANING OBJECT-STACK",
&prefs.deblend_nthresh, H_INT, T_LONG, "%6d"},
{"SEXAPERD", "APERTURE DIAMETER (PIXELS)",
&prefs.apert[0], H_INT, T_LONG, "%7.1f"},
{"SEXAPEK1", "KRON PARAMETER",
&prefs.autoparam[0], H_FLOAT, T_DOUBLE, "%4.1f"},
{"SEXAPEK2", "KRON ANALYSIS RADIUS",
&prefs.autoparam[0], H_FLOAT, T_DOUBLE, "%4.1f"},
{"SEXAPEK3", "KRON MINIMUM RADIUS",
&prefs.autoparam[1], H_FLOAT, T_DOUBLE, "%4.1f"},
{"SEXSATLV", "SATURATION LEVEL (ADU)",
&prefs.satur_level, H_EXPO, T_DOUBLE, "%12G"},
{"SEXMGZPT", "MAGNITUDE ZERO-POINT",
&prefs.mag_zeropoint, H_FLOAT, T_DOUBLE, "%8.4f"},
{"SEXMGGAM", "MAGNITUDE GAMMA",
&prefs.mag_gamma, H_FLOAT, T_DOUBLE, "%4.2f"},
{"SEXBKGSX", "BACKGROUND MESH WIDTH (PIXELS)",
&thefield1.backw, H_INT, T_LONG, "%5d"},
{"SEXBKGSY", "BACKGROUND MESH HEIGHT (PIXELS)",
&thefield1.backh, H_INT, T_LONG, "%5d"},
{"SEXBKGFX", "BACKGROUND FILTER WIDTH",
&thefield1.nbackfx, H_INT, T_LONG, "%3d"},
{"SEXBKGFY", "BACKGROUND FILTER HEIGHT",
&thefield1.nbackfy, H_INT, T_LONG, "%3d"},
{"SEXPBKGT", "PHOTOM BACKGROUND TYPE",
"GLOBAL", H_STRING, T_STRING, "%s"},
{"SEXPBKGS", "LOCAL AREA THICKNESS (PIXELS)",
&prefs.pback_size, H_INT, T_LONG, "%3d"},
{"SEXPIXSK", "PIXEL STACKSIZE (PIXELS)",
&prefs.mem_pixstack, H_INT, T_LONG, "%8d"},
{"SEXFBUFS", "FRAME-BUFFER SIZE (LINES)",
&prefs.mem_bufsize, H_INT, T_LONG, "%5d"},
{"SEXISAPR", "ISO-APER RATIO",
&ddummy, H_FLOAT, T_DOUBLE, "%4.2f"},
{"SEXNDET ", "NB OF DETECTIONS",
&thecat.ndetect, H_INT, T_LONG, "%9d"},
{"SEXNFIN ", "NB OF FINAL EXTRACTED OBJECTS",
&thecat.ntotal, H_INT, T_LONG, "%9d"},
{"SEXNPARA", "NB OF PARAMETERS PER OBJECT",
&thecat.nparam, H_INT, T_LONG, "%3d"},
{""}};
/*
sexheadsc.h
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: SExtractor
*
* Author: E.BERTIN, DeNIS/LDAC.
*
* Contents: header structure and templates for SkyCat output.
*
* Last modify: 02/09/97
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
char skycathead[] = "QueryResult\n\n"
"# Config entry for original catalog server:\n"
"serv_type: catalog\n"
"long_name: SExtractor catalog\n"
"short_name: SExCat\n"
"symbol: id diamond %4.1f\n"
"# End config entry\n\n"
"id\tra\tdec\tmag";
char skycattail[] = "[EOD]";
/*
som.c
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: A program using neural networks.
*
* Author: E.BERTIN (IAP)
*
* Contents: Implementation of Kohonen's Self Organizing Map (V3.0).
*
* Last modify: 28/11/2003
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
#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 "fits/fitscat.h"
#include "prefs.h"
#include "som.h"
/********************************* som_phot **********************************/
/*
Perform SOM-fitting on a detected source: returns node number of the
best-fitting prototype.
*/
void som_phot(somstruct *som, float back, float backnoise, float gain,
float dx0, float dy0, float *vector, float clip)
{
float err, errmin, *xnt;
int i,j,nd,jmin, *nx, *mul;
nd = som->neurdim;
/* First we compute the error map */
if (clip!=0.0)
if (!som_mkweight(som, back, backnoise, gain))
{
/*---- If all weights to zero, don't go further! */
som->stderror = -1.0;
som->amp = som->sigamp = 0.0;
if (vector)
{
xnt = som->vector;
for (i=nd; i--;)
*(vector++) = 99.0;
}
return;
}
/* Use a sound starting point for the gradient search */
/*
i = nd-1;
som->vector[i--] = (dy0+0.5)*som->neursize[i]+0.4999;
som->vector[i] = (dx0+0.5)*som->neursize[i]+0.4999;
while (i--)
som->vector[i] = (som->neursize[i]-1)/2.0;
*/
errmin=BIG;
jmin = 0;
for (j=0; j<som->nneur; j++)
{
if ((err=som_err(som, (float)j, SOM_NODE))<errmin)
{
errmin = err;
jmin = j;
}
}
mul = som->neurstep;
nx = som->neursize;
xnt = som->vector;
for (i=nd; i--;)
*(xnt++) = (float)((jmin/(*(mul++)))%(*(nx++)));
/* Gradient search */
som_conjgrad(som, 1e-6);
/* Now perform the true photometry */
som->stderror = (float)sqrt(som_err(som, 0.0, SOM_PHOTOM));
/* Store final position vector if requested */
if (vector)
{
xnt = som->vector;
for (i=nd; i--;)
*(vector++) = *(xnt++);
}
if (clip>0.0)
{
/*-- Clip deviant pixels if requested */
float *input, *inputw, *proto, diff;
proto = som->proto;
input = som->input;
inputw = som->inputw;
for (i=som->ninput-som->nextrainput;i--; inputw++)
{
diff = *(input++)-*(proto++);
if (*inputw>0.0 && (diff*diff>clip/(*inputw)))
*inputw /= clip;
}
}
return;
}
/****************************** som_mkweight *********************************/
/*
Compute weights associated to pixels in a vignet.
*/
int som_mkweight(somstruct *som, float back, float backnoise, float gain)
{
float *yt, *wt, wstiff, pix, llim,hlim;
int i, nima, ngood;
yt = som->input;
wt = som->inputw;
nima = som->ninput-som->nextrainput;
llim = -5.0*backnoise;
hlim = prefs.satur_level-back;
backnoise *= backnoise;
ngood = 0;
for (i=nima; i--;)
{
pix = *(yt++);
/*-- look if pixel is in the "reasonable" range */
if (pix>llim && pix<hlim)
{
*(wt++) = 1/((pix>0.0?pix/gain:0.0)+backnoise);
ngood++;
}
else
*(wt++) = 0.0;
}
wstiff = 1/(som->xy_stiff*som->xy_stiff);
for (i=som->nextrainput; i--;)
*(wt++) = wstiff;
return ngood;
}
/********************************** som_err **********************************/
/*
Return the reduced RMS error at some (non-integer) position in the SOM.
1 degree of freedom is left: the amplitude of the prototype.
*/
float som_err(somstruct *som, float dist, int flags)
{
static float dx[SOM_MAXDIM];
double s,sx,sxx,sy,syy,sxy,b,err,ds;
float *psft, *dxt, *wt,*xt,*yt,xi,yi,wi,wxi,wyi, diff,dd;
int i,j,k,n, nd, *nx, *mult, ix, pos,post, nima;
yt = NULL; /* To avoid gcc -Wall warnings */
n = nd = pos = 0; /* To avoid gcc -Wall warnings */
/* Is the requested position lying on a node? */
if (flags & SOM_NODE)
/*-- Yes: just use the prototype at that node */
xt = som->weight+som->ninput*(int)dist;
else
{
/*-- ...No: compute offsets and fractional parts for each dimension */
nd = som->neurdim;
nx = som->neursize;
xt = som->vector;
if (flags & SOM_LINE)
yt = som->dvector;
pos = 0;
dxt = dx;
mult = som->neurstep;
for (i=nd; i--; nx++)
{
xi = *(xt++);
if (flags & SOM_LINE)
xi += dist**(yt++);
ix = (int)xi;
if (ix<0)
ix = 0;
else if (ix>=*nx-1)
ix = *nx-2;
if (ix<0)
{
ix = 0;
*(dxt++) = 0.0;
}
else
*(dxt++) = xi - ix;
pos += ix**(mult++);
}
memset(som->proto, 0, som->ninput*sizeof(float));
n = 1<<nd; /* OK until the SOM has less than 32 dimensions... */
for (j=0; j<n; j++)
{
post = pos;
dd = 1.0;
dxt = dx;
nx = som->neursize;
mult = som->neurstep;
for (i=0; i<nd; mult++, nx++)
{
if (((1<<(i++)) & j) && *nx>1)
{
post += *mult;
dd *= *(dxt++);
}
else
dd *= (1-*(dxt++));
}
psft = som->proto;
wt = som->weight + som->ninput*post;
for (i=som->ninput; i--;)
*(psft++) += dd**(wt++);
}
xt = som->proto;
}
yt = som->input;
wt = som->inputw;
nima = som->ninput-som->nextrainput;
/* Test if we need to derive photometry, or just compute the error */
if (flags & SOM_PHOTOM)
{
/*-- Yes: photometry */
s = sx = sy = sxx = syy = sxy = 0.0;
for (i=nima; i--;)
{
s += (wi = *(wt++));
sx += (wxi = wi*(xi=*(xt++)));
sxx += wxi*xi;
sy += (wyi = wi*(yi=*(yt++)));
syy += wyi*yi;
sxy += wxi*yi;
}
/*-- First, the error from the image-fitting */
som->amp = b = sxy/sxx;
err = nima*(b*b*sxx + syy - 2.0*b*sxy)/s;
/*
err = (syy - b*sxy)/(nima-1);
*/
som->sigamp = sqrt(err*s/(s*sxx-sx*sx));
/*-- Second, the error of non-pixel parameters */
for (i=som->nextrainput; i--;)
{
diff = *(yt++) - *(xt++);
err += (diff*diff*(double)*(wt++))/(double)som->nextrainput;
}
}
else
{
/*-- No: just an estimate of error */
sxx = sxy = 0.0;
for (i=nima; i--;)
{
sxy += (wxi = *(wt++)*(xi=*(xt++)))**(yt++);
sxx += wxi*xi;
}
/*-- First, the error from the image-fitting */
err = -sxy*sxy/sxx/(nima-1);
/*-- Second, the error of non-pixel parameters */
for (i=som->nextrainput; i--;)
{
diff = *(yt++) - *(xt++);
err += (diff*diff*(double)*(wt++))/(double)som->nextrainput;
}
}
/* Compute error gradients if requested */
if (flags & SOM_GRADIENT)
{
for (k=0; k<nd; k++)
{
memset(som->dproto, 0, som->ninput*sizeof(float));
for (j=0; j<n; j++)
{
dd = 1.0;
post = pos;
dxt = dx;
mult = som->neurstep;
nx = som->neursize;
for (i=0; i<nd; mult++, dxt++, nx++)
{
if (((1<<i) & j) && *nx>1)
{
post += *mult;
if ((i++)!=k)
dd *= *dxt;
}
else
dd *= ((i++)==k ? (*nx>1?-1.0:0.0) : (1-*dxt));
}
psft = som->dproto;
wt = som->weight + som->ninput*post;
for (i=som->ninput; i--;)
*(psft++) += dd**(wt++);
}
ds = 0.0;
psft = som->dproto;
xt = som->proto;
yt = som->input;
wt = som->inputw;
for (i=nima; i--;)
ds += *(wt++)*(sxy**(xt++)-sxx**(yt++))**(psft++);
ds *= 2*sxy/(sxx*sxx)/(nima-1);
for (i=som->nextrainput; i--;)
ds += 2**(wt++)**(psft++)*(*(xt++)-*(yt++))/(double)som->nextrainput;
som->dvector[k] = (float)ds;
}
}
return (float)err;
}
/******************************** som_linmin *********************************/
/*
Perform minimisation through line-search using two routines from Numerical
Recipes in C: mnbrak() and brent() (pp. 297 and 301).
*/
#define SHFT(a,b,c,d) {(a)=(b);(b)=(c);(c)=(d);} /* For line-search */
#define SIGN(a,b) ((b)>0.0? fabs(a) : -fabs(a)) /* For line-search */
#define GOLD 1.6180340 /* Golden section for line-search */
#define CGOLD 0.3819660 /* Complement to the golden section */
#define TINY 1e-20 /* Almost nothing */
#define GLIMIT 100.0 /* Max. magnification in line-search */
#define ITMAX 100 /* Max. nb of iter. in line-search */
#define TOL 1e-1 /* Fract. tolerance in line-search */
float som_linmin(somstruct *som)
{
float ax,bx,cx, fa,fb,fc, u,r,q,fu,dum,ulim, qmr, a,b,d,e,etemp,
fv,fw,fx, p, tol1,tol2,v,w,x,xm, *vt,*dvt;
int i,iter;
/* Normalize the gradient */
/*
dvt = som->dvector;
for (i=som->neurdim; i--; dvt++)
dum += *dvt**dvt;
if (dum>0.0)
{
dum = sqrt(dum);
dvt = som->dvector;
for (i=som->neurdim; i--;)
*(dvt++) /= dum;
}
*/
d = 0.0; /* To avoid gcc -Wall warnings */
/* Begin by bracketing a minimum of the function */
ax = 0.0; /* Initial guesses */
bx = 1.0;
if ((fb=som_err(som, bx, SOM_LINE)) > (fa=som_err(som, ax, SOM_LINE)))
{
SHFT(dum, ax, bx, dum);
SHFT(dum, fb, fa, dum);
}
fc = som_err(som, cx = bx+GOLD*(bx-ax), SOM_LINE);
while (fb > fc)
{
r = (bx-ax)*(fb-fc);
q = (bx-cx)*(fb-fa);
if (fabs(qmr = q-r)<TINY)
qmr = qmr>0.0?TINY:-TINY;
u = bx-((bx-cx)*q - (bx-ax)*r) / (2.0*qmr);
ulim= bx + GLIMIT*(cx-bx);
if ((bx-u)*(u-cx) > 0.0)
{
if ((fu=som_err(som, u, SOM_LINE)) < fc)
{
ax = bx;
bx = u;
fa = fb;
fb = fu;
break;
}
else if (fu > fb)
{
cx = u;
fc = fu;
break;
}
fu = som_err(som, u = cx + GOLD*(cx-bx), SOM_LINE);
}
else if ((cx-u)*(u-ulim) > 0.0)
{
if ((fu=som_err(som, u, SOM_LINE)) < fc)
{
SHFT(bx, cx, u, cx+GOLD*(cx-bx));
SHFT(fb, fc, fu, som_err(som, u, SOM_LINE));
}
}
else if ((u-ulim)*(ulim-cx) >= 0.0)
fu = som_err(som, u=ulim, SOM_LINE);
else
fu = som_err(som, u = cx + GOLD*(cx-bx), SOM_LINE);
SHFT(ax, bx, cx, u);
SHFT(fa, fb, fc, fu);
}
/* Now we step to Brent's algorithm for finding the minimum */
e = 0.0;
a = (ax < cx) ? ax : cx;
b = (ax > cx) ? ax : cx;
x = w = v = bx;
fw = fv = fx = som_err(som, x, SOM_LINE);
for (iter=ITMAX; iter--;)
{
xm = 0.5*(a+b);
tol2 = 2 * (tol1=TOL*fabs(x)+TINY);
if (fabs(x-xm) <= (tol2-0.5*(b-a)))
goto linmin_end;
if (fabs(e) > tol1)
{
r = (x-w) * (fx-fv);
q = (x-v) * (fx-fw);
p = (x-v)*q - (x-w)*r;
q = 2*(q-r);
if (q > 0.0)
p = -p;
q = fabs(q);
etemp = e;
e = d;
if (fabs(p) >= fabs(0.5*q*etemp) || p <= q*(a-x) || p >= q*(b-x))
d = CGOLD*(e=(x >= xm ? a-x : b-x));
else
{
d = p/q;
u = x+d;
if (u-a < tol2 || b-u < tol2)
d = SIGN(tol1,xm-x);
}
}
else
d = CGOLD*(e=(x >= xm ? a-x : b-x));
u = (fabs(d) >= tol1 ? x+d : x+SIGN(tol1,d));
if ((fu=som_err(som, u, SOM_LINE)) <= fx)
{
if (u >= x)
a = x;
else
b = x;
SHFT(v, w, x, u);
SHFT(fv, fw, fx, fu);
}
else
{
if (u < x)
a = u;
else
b = u;
if (fu <= fw || w == x)
{
v = w;
w = u;
fv = fw;
fw = fu;
}
else if (fu <= fv || v == x || v == w)
{
v = u;
fv = fu;
}
}
}
warning("Too many iterations in ", "som_linmin()");
/* Finally we set the SOM vector to the new minimum */
linmin_end:
vt = som->vector;
dvt = som->dvector;
for (i=som->neurdim; i--;)
*(vt++) += x**(dvt++);
return fx;
}
#undef SHFT
#undef SIGN
#undef GOLD
#undef CGOLD
#undef TINY
#undef GLIMIT
#undef ITMAX
#undef TOL
/******************************** som_conjgrad *******************************/
/*
Perform Polak-Ribiere minimization (adapted from Numerical Recipes in C,p.432).
*/
#define ITMAX 100
#define EPS 1.0e-10
void som_conjgrad(somstruct *som, float ftol)
{
static float g[SOM_MAXDIM], h[SOM_MAXDIM];
int j, nd, its;
float *xi, *xit,*gt,*ht,tmp,tmp2,
gg,gam,fp,fret,dgg;
nd = som->neurdim;
xi = som->dvector;
fp = som_err(som, 0.0, SOM_GRADIENT);
gt = g;
xit = xi;
ht = h;
for (j=nd;j--;)
tmp = -*xit, *(xit++) = *(ht++)= *(gt++) = tmp;
for (its=ITMAX;its--;)
{
fret = som_linmin(som);
if (2.0*fabs(fret-fp) <= ftol*(fabs(fret)+fabs(fp)+EPS))
return;
fp=som_err(som, 0.0, SOM_GRADIENT);
dgg=gg=0.0;
gt = g;
xit = xi;
for (j=nd;j--; xit++)
{
gg += *gt**gt;
dgg += (*xit+*(gt++))**xit;
}
if (gg == 0.0)
return;
gam=dgg/gg;
gt = g;
xit = xi;
ht = h;
for (j=nd;j--;)
tmp = -*xit,tmp2 = *ht, *(xit++) = *(ht++) = (*(gt++) = tmp) + gam*tmp2;
}
warning("Too many iterations during SOM-Fitting","");
}
#undef ITMAX
#undef EPS
/********************************* som_end ***********************************/
/*
Terminate SOM.
*/
void som_end(somstruct *som)
{
/* Free memory*/
free(som->weight);
free(som->input);
free(som->inputw);
free(som->proto);
free(som->dproto);
free(som->vector);
free(som->dvector);
free(som->freq);
free(som->inputsize);
free(som->neursize);
free(som->neurstep);
free(som);
/* locals */
return;
}
/********************************* som_load **********************************/
/*
Read the SOM weights in a FITS file.
*/
somstruct *som_load(char *filename)
{
somstruct *som;
catstruct *cat;
tabstruct *tab;
keystruct *key;
char *head, str[80];
int i;
/* Open the cat (well it is not a "cat", but simply a FITS file */
if (!(cat = read_cat(filename)))
error(EXIT_FAILURE, "*Error*: SOM file not found: ", filename);
if (!(tab = name_to_tab(cat, "SOM", 0)))
error(EXIT_FAILURE, "*Error*: SOM table not found in catalog ",
filename);
/* OK, we now allocate memory for the SOM structure itself */
QCALLOC(som, somstruct, 1);
/* Load important scalars (which are stored as FITS keywords) */
head = tab->headbuf;
/* Dimensionality of the input */
if (fitsread(head, "INPNAXIS", &som->inputdim, H_INT, T_LONG) != RETURN_OK)
goto headerror;
if (som->inputdim>INPUT_MAXDIM)
{
sprintf(str, "%d", INPUT_MAXDIM);
error(EXIT_FAILURE, "*Error*: This package is presently limited to inputs"
"with dimensionality less or equal to ", str);
}
QMALLOC(som->inputsize, int, INPUT_MAXDIM);
for (i=0; i<INPUT_MAXDIM; i++)
som->inputsize[i] = 1;
som->ninput = 1;
for (i=0; i<som->inputdim; i++)
{
sprintf(str, "INPAXIS%1d", i+1);
if (fitsread(head, str, &som->inputsize[i], H_INT,T_LONG) != RETURN_OK)
goto headerror;
som->ninput *= som->inputsize[i];
}
if (fitsread(head,"INPNEXTR",&som->nextrainput,H_INT,T_LONG) != RETURN_OK)
som->nextrainput = 0;
som->ninput += som->nextrainput;
/* Dimensionality of the SOM */
if (fitsread(head, "SOMNAXIS", &som->neurdim, H_INT, T_LONG) != RETURN_OK)
goto headerror;
QMALLOC(som->neursize, int, som->neurdim);
QMALLOC(som->neurstep, int, som->neurdim);
QCALLOC(som->vector, float, som->neurdim);
QCALLOC(som->dvector, float, som->neurdim);
for (i=0; i<som->neurdim; i++)
som->neursize[i] = 1;
som->nneur = 1;
for (i=0; i<som->neurdim; i++)
{
sprintf(str, "SOMAXIS%1d", i+1);
if (fitsread(head, str, &som->neursize[i], H_INT,T_LONG) != RETURN_OK)
goto headerror;
som->neurstep[i] = som->nneur;
som->nneur *= som->neursize[i];
}
/* Other scalars */
if (fitsread(head, "SOMLRATE", &som->learnrate,H_FLOAT,T_FLOAT) != RETURN_OK)
goto headerror;
som->clearnrate = som->learnrate;
if (fitsread(head, "SOMKERNW", &som->kernw, H_FLOAT,T_FLOAT) != RETURN_OK)
goto headerror;
som->ckernw = som->kernw;
if (fitsread(head, "SOMNPASS", &som->ntrain , H_INT, T_LONG) != RETURN_OK)
goto headerror;
if (fitsread(head, "SOMNSWEE", &som->nsweep , H_INT, T_LONG) != RETURN_OK)
goto headerror;
som->nweight = som->nneur*som->ninput;
QMALLOC(som->weight, float, som->nneur*som->ninput);
QMALLOC(som->input, float, som->ninput);
QMALLOC(som->inputw, float, som->ninput);
QMALLOC(som->proto, float, som->ninput);
QMALLOC(som->dproto, float, som->ninput);
QCALLOC(som->freq, int, som->nneur);
/* Locals */
/* Load the weight vector */
key = read_key(tab, "WEIGHTS");
som->weight = key->ptr;
/* But don't touch my arrays!! */
blank_keys(tab);
free_cat(&cat, 1);
return som;
headerror:
error(EXIT_FAILURE, "*Error*: Incorrect or obsolete SOM data in ", filename);
return NULL;
}
/*
som.h
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* Part of: A program using neural networks.
*
* Author: E.BERTIN, IAP & Leiden observatory.
*
* Contents: Include for Kohonen's Self Organizing Map (V2.0).
*
* Last modify: 17/12/97
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
/*--------------------------------- constants ------------------------------*/
#define INPUT_MAXDIM 9 /* Maximum dimensionality of input */
#define SOM_MAXDIM 6 /* Maximum dimensionality of the SOM */
/*------------------------------- SOM flags --------------------------------*/
#define SOM_NODE 0x01 /* Compute at some exact node pos */
#define SOM_PHOTOM 0x02 /* Do photometry */
#define SOM_GRADIENT 0x04 /* Compute interpolated SOM gradient */
#define SOM_LINE 0x08 /* Proceed along a specific line */
/*--------------------------- structure definitions -------------------------*/
typedef struct
{
int inputdim; /* Dimensionality of input vector */
int *inputsize; /* Dimensions of the input vector */
int ninput; /* Total number of inputs */
int nextrainput; /* Number of extra inputs */
int neurdim; /* Dimensionality of the SOM */
int *neursize; /* Dimensions of the SOM */
int nneur; /* Total number of neurons */
int *neurstep; /* Stepping through the SOM */
float *weight; /* Weights */
int nweight; /* Total number of weights */
float *input; /* Input data */
float *inputw; /* Input data weighting */
float *proto; /* Current composite prototype */
float *dproto; /* Current composite gradients */
float *vector; /* Current SOM coordinates */
float *dvector; /* Current SOM search direction */
float learnrate, clearnrate; /* Starting and current learn. rates */
float learndecay; /* Learning decay rate */
float kernw, ckernw; /* Starting and current kernel width */
float kernwdecay; /* Kernel width decay rate */
float xy_stiff; /* Stiffness of the X/Y mapping */
int *freq; /* Number of winning times per node */
int ntrain; /* # of training examples so far */
int nsweep; /* # of sweeps through the whole set */
float amp, sigamp; /* Best fitting amplitude and error */
float stderror; /* Global reduced error */
} somstruct;
somstruct *thesom;
/*---------------------------------- protos --------------------------------*/
extern somstruct *som_load(char *filename);
extern float som_err(somstruct *som, float dist, int flag),
som_linmin(somstruct *som);
extern int som_mkweight(somstruct *som,float back,float backnoise,
float gain);
extern void som_conjgrad(somstruct *som, float ftol),
som_end(somstruct *som),
som_phot(somstruct *som, float back,float backnoise,
float gain, float dx, float dy,
float *vector, float clip),
som_start(somstruct *som, float *context,
int ncontext, float x, float y);
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