/* @(#)cstacen.c 17.1.1.1 (ESO-DMD) 01/25/02 17:40:32 */ /*=========================================================================== Copyright (C) 1995 European Southern Observatory (ESO) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. Correspondence concerning ESO-MIDAS should be addressed as follows: Internet e-mail: midas@eso.org Postal address: European Southern Observatory Data Management Division Karl-Schwarzschild-Strasse 2 D 85748 Garching bei Muenchen GERMANY ===========================================================================*/ /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .COPYRIGHT: Copyright (c) 1994 European Southern Observatory, all rights reserved .IDENT Cstacen .LANGUAGE C .AUTHOR H. Waldthausen, K. Banse, M. Peron IPG-ESO Garching .KEYWORDS photometry .PURPOSE calculates the center position of an object .ALGORITHM according to P.B.Stetson for GAUSS-method and H.Waldthausen for MOM-method (= DEFAULT) .INPUT/OUTPUT call as stat = Cstacen( meth, p_img, npix, image, xypos, xyerr, xysig, xyval ) input: char *meth : method of centering: MOM (moment centering) GAU (gaussian centering) float *p_img : pointer to image int npix[2] : number of pixels in image int image[4] : image size in pixel coordinates (F77 indexing) output: float xypos[2] : center position (x,y) (C indexing) float xyerr[2] : error estimate of xypos (x,y) float xysig[2] : width of source (x,y) float *xyval : central value .RETURNS status: 0 O.K. 1 crowded, or weak source 2 no pos. source found 3 iteration failed .COMMENTS This module contains the following statistic functions: - for the moment centering: Ckapsig - for the gaussian centering: Crhox Crhoy Cserch LSQFIT <- GAUSDE <- GAUSFU <- ERFCC <- MATINV <- GAUSFU <- ERFCC <- FCHIS .ENVIRONment MIDAS #include Prototypes for MIDAS interfaces .VERSIONS 3.00 940526 F2C from CENTSUBS.FOR R.M. van Hees 3.10 940825 make it work like the Fortran version KB 000522 ------------------------------------------------------------*/ /* Define _POSIX_SOURCE to indicate that this is a POSIX program */ #define _POSIX_SOURCE 1 /* definition of the used functions in this module */ #include #include /* define some macros and constants */ #ifndef PI #define PI 3.14159265358979325e0 #endif #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif /* Constants used by the moment centering */ #define MINVAL 1.0e-37 #define MMXITER 8 #define SMALL 1.0e-20 /* Constants used by the gaussian centering */ #define MAXPAR 4 #define IGNORE 2 #define NOCONV -1 #define OUTSIDE -2 #define GMXITER 50 #define GCHIMAX 5.0e+16 #define GCHIFND 0.005 #define MYMIN(a,b) ((a) > (b) ? (b) : (a)) #define MYMAX(a,b) ((b) > (a) ? (b) : (a)) /* */ /*++++++++++++++++++++++++++++++ .IDENTIFIER Ckapsig .PURPOSE selects a constant mean through a kap*sig clipping .ALGORITHM 1.) calculate mean and rms 2.) delete pixels beyond AKAP*RMS from mean 3.) GO TO 1.) .INPUT/OUTPUT input: float *val : input values int nval : number of input values int iter : number of iterations (min = 1) float akap : AKAP * RMS output: float cons : derived mean value float rms : RMS of mean value int npts : number of points used to derive the mean value .RETURNS status : 0 O.K. : -1 NVAL .LT. 2 ------------------------------*/ #ifdef __STDC__ static int Ckapsig( float *val, int nval, int iter, float akap, float *cons, float *rms, int *npts ) #else static int Ckapsig( val, nval, iter, akap, cons, rms, npts ) int nval, iter, *npts; float akap, *val, *cons, *rms; #endif { register int ii, it, nr; int nr_old; float clip, dels, delv, mean, msq, sum, *vsq; if ( nval < 2 ) return (-1); /* initialize mean value */ mean = 0.0; for (ii=0; ii rowmax ) { rowmax = fabs( matrix[ii][jj] ); row = ii; } } if (fabs(matrix[row][jj]) < SMALL) /* determinant is zero! */ return (1); if ( row > jj ) /* if largest element not ...*/ { for ( kk = 0; kk < nfree; kk++ ) /* on diagonal, then ... */ { even = matrix[jj][kk]; /* permutate rows. */ matrix[jj][kk] = matrix[row][kk]; matrix[row][kk] = even; } evin = per[jj]; /* keep track of permutation */ per[jj] = per[row]; per[row] = evin; } even = 1.0 / matrix[jj][jj]; /* modify column */ for (ii=0; ii= 0.0 ? ans : 2.0 - ans); } /* */ /*++++++++++++++++++++++++++++++ .IDENTIFIER GAUSFU .PURPOSE .INPUT/OUTPUT input: double xx : data point of independent variable float gpar[MAXPAR] : function parameters .RETURNS .COMMENTS static function ------------------------------*/ #ifdef __STDC__ static double GAUSFU( double xx, double *gpar ) #else static double GAUSFU( xx, gpar ) double xx, *gpar; #endif { double rc, dd; static int init = TRUE; static double sqrt_2, rc1; if ( init ) { sqrt_2 = sqrt( 2.0 ); rc1 = sqrt(PI)/sqrt_2; init = FALSE; } rc = 1.0 / (sqrt_2 * gpar[2]); dd = xx - gpar[1]; dd = ERFCC(rc * (dd - 0.5)) - ERFCC(rc * (dd + 0.5)); return ( gpar[3] + rc1 * gpar[0] * gpar[2] * dd ); } /* */ /*++++++++++++++++++++++++++++++ .IDENTIFIER GAUSDE .PURPOSE evaluates derivatives of function for least squares search with shape of a gaussian distribution .INPUT/OUTPUT input: double *xdat : data point of independent variable double gpar[MAXPAR] : parameters of the gaussian distribution output: double deriv[MAXPAR]: derivatives of function .RETURNS .COMMENTS static function ------------------------------*/ #ifdef __STDC__ static void GAUSDE( double xdat, double *gpar, double *deriv ) #else static void GAUSDE( xdat, gpar, deriv ) double xdat, *gpar, *deriv; #endif { register int jj; double temp, tempp, x1, x2, zz; static int init = TRUE; static double sqrt_2; if ( init ) { sqrt_2 = sqrt( 2.0 ); init = FALSE; } temp = sqrt_2 * gpar[2]; tempp = xdat - gpar[1]; x1 = (tempp - 0.5) / temp; x2 = (tempp + 0.5) / temp; zz = tempp / gpar[2] ; if ( ((zz * zz) - 50.0) < 0.0 ) { deriv[0] = (GAUSFU( xdat, gpar ) - gpar[3]) / gpar[0]; deriv[1] = gpar[0] * (exp( -x1 * x1 ) - exp( -x2 * x2 )); deriv[2] = deriv[1] * zz; } else for (jj=0; jj<3; jj++) deriv[jj] = 0.0; deriv[3] = 1.0; } /* */ /*++++++++++++++++++++++++++++++ .IDENTIFIER FCHIS .PURPOSE evaluate reduced chi square for fit to data .INPUT/OUTPUT input: double *data : input data int ndim : dimension of input data int nfree : number of degrees of freedom int mode : determines method of weighting least-squares fit: 0 = no weighting 1 = with weighting output: double *dfit : array with the fit for data .RETURNS sum( (y-yfit)**2 / sigma**2 ) / nfree .COMMENTS static function ------------------------------*/ #ifdef __STDC__ static float FCHIS( double *data, int ndim, int nfree, int mode, double *dfit ) #else static float FCHIS( data, ndim, nfree, mode, dfit ) int nfree, mode, ndim; double *data, *dfit; #endif { register int ii; double diff, weight, chisq; if ( nfree > 0 ) { chisq = 0.0; for (ii=0; ii 0.0 */ *sigma = MYMAX( 0.0, alpha[1][1] ); } else /* evaluate chi square at starting point */ { for (ii=0; ii image[0-3] IXE = IMAP(2) IYA = IMAP(3) JYA = IYA + JY - 1 JY => lnew[0] JYE = IYA + LY - 1 LY => lnew[1] M = 1 DO 200 J=IXA,IXE ISUM = 0.D0 DO 100 K=JYA,JYE ISUM = ISUM + AIMG(J,K) 100 CONTINUE KRX(M) = ISUM M = M + 1 200 CONTINUE */ nrx = image[1] - image[0] + 1; nry = lnew[1] - lnew[0] + 1; nxdim = *npix; p_img += nxdim * (image[2] + lnew[0]); for (ix=0; ix image[0-3] IYA = IMAP(3) IYE = IMAP(4) JXA = IXA + JX - 1 JX => lnew[0] JXE = IXA + LX - 1 LX => lnew[1] M = 1 DO 200 J=IYA,IYE ISUM = 0.D0 DO 100 K=JXA,JXE ISUM = ISUM + AIMG(K,J) 100 CONTINUE KRY(M) = ISUM M = M + 1 200 CONTINUE */ nrx = lnew[1] - lnew[0] + 1; nry = image[3] - image[2] + 1; nxdim = *npix; p_img += (nxdim * image[2]) + (image[0] + lnew[0]); for (iy=0; iy= drmx ) { drmx = work[ii]; imax = ii; } if ( work[ii] <= drmn ) { drmn = work[ii]; imin = ii; } } /* crowded ? */ icrowd = 0; if (imin <= imax ) /* bright source to the left, compute right a new minima */ { if ( ndim - imax > imin ) { icrowd = -1; drmn = drmx; for ( ii = imax+1; ii < iend; ii++ ) { if ( work[ii] < drmn ) { drmn = work[ii]; imin = ii; } } } else /* bright source to the right, compute left a new maxima */ { icrowd = 1; drmx = drmn; for ( ii = ibgn; ii < imin; ii++ ) { if ( work[ii] >= drmx ) { drmx = work[ii]; imax = ii; } } } } /* compute estimates of image centre and width */ *s_cent = ((float)(imax + imin)) * 0.5; *s_width = imin - imax; sum = 0.0; for ( ii = imax; ii <= imin; ii++ ) sum += work[ii]; diff = drmx - drmn; if ( fabs(diff) > SMALL) { dxk = sum * *s_width / ( (*s_width+1.0)*diff ); *s_cent += dxk; } *s_width /= 2; indx = CGN_NINT(*s_cent); if (indx < 0) { *s_cent = 0.0; indx = 0; } else if (indx >= ndim) { *s_cent = (float)(ndim-1); indx = ndim-1; } /* find low- (left-) side local minimum */ ql = indx - 2; *lmin = 0; if (ql < 2) goto next_step; low_loop: ql --; if (ql <= 0 ) goto next_step; if (ql == 1) goto lo5; if (ql == 2) goto lo4; if (ql == 3) goto lo3; if (marg[ql] > marg[ql-4]) goto low_loop; lo3: if (marg[ql] > marg[ql-3]) goto low_loop; lo4: if (marg[ql] > marg[ql-2]) goto low_loop; lo5: if (marg[ql] > marg[ql-1]) goto low_loop; *lmin = ql + 1; /* find high- (right-) side local minimum */ next_step: ql = indx + 2; *lmax = ndim - 1; ii = ndim - ql; if (ii < 3) goto end_of_it; hi_loop: ql ++ ; ii = ndim - ql; if (ii == 1 ) goto end_of_it; if (ii == 2) goto hi5; if (ii == 3) goto hi4; if (ii == 4) goto hi3; if (marg[ql] > marg[ql+4]) goto hi_loop; hi3: if (marg[ql] > marg[ql+3]) goto hi_loop; hi4: if (marg[ql] > marg[ql+2]) goto hi_loop; hi5: if (marg[ql] > marg[ql+1]) goto hi_loop; *lmax = ql - 1; end_of_it: (void) osmmfree( (char *) work ); return (icrowd); } /* */ /* ------------------------------------------*/ /* here starts the code of the main function */ /* ------------------------------------------*/ int Cstacen( meth, p_img, npix, image, xypos, xyerr, xysig, xyval ) char *meth; int *npix, *image; float *p_img, *xypos, *xyerr, *xysig, *xyval; { register int it, ix, iy; int bgnr, indx, indy, istat, nrx, nry, nval, ifram[4]; float bgval, clip, rms, xmom, ymom, source, sumi, xold, yold; float *p_bgn, *p_edge; istat = 0; /* initialize */ p_bgn = p_img; for (ix=0; ix<4; ix++) ifram[ix] = image[ix] + 1; /* 1 ---> ndim */ nrx = ifram[1] - ifram[0] + 1; nry = ifram[3] - ifram[2] + 1; xypos[0] = (ifram[0] + ifram[1]) * 0.5; /* init to center pixel */ xypos[1] = (ifram[2] + ifram[3]) * 0.5; xyerr[0] = xyerr[1] = 0.0; xysig[0] = xysig[1] = 0.0; *xyval = 0.0; /* MOMENT centering */ if ( *meth != 'G' && *meth != 'g' ) { int kk, istr, iend; xold = yold = -1.0; /* find bgval and rms from edge pixels */ p_img += (ifram[0] - 1) + (npix[0] * (ifram[2] - 1)); /* collect edge pixels */ if (nry > 1) { nval = (2 * nrx) + (2 * (nry-2)); p_edge = (float *) osmmget( nval * sizeof( float )); for (ix=0; ix 3 * RMS above BGVAL */ clip = 3.0 * rms; for (it=0; it clip ) { sumi += source; xmom += source * (ifram[0] + ix); ymom += source * (ifram[2] + iy); } } p_img += npix[0]; } p_img = p_bgn; /* reset to start of array */ if ((nrx < 3) || (nry < 3)) { xysig[0] = nrx; xysig[1] = nry; istat = 1; if ( sumi > 0.0 ) { xypos[0] = xmom / sumi; xypos[1] = ymom / sumi; } else { istat = 2; xypos[0] = (ifram[0] + ifram[1]) * 0.5; xypos[1] = (ifram[2] + ifram[3]) * 0.5; } indx = CGN_NINT(xypos[0]-1); indy = CGN_NINT(xypos[1]-1); *xyval = p_img[indx + ((*npix) * indy)]; goto end_of_iter; /* EXIT iteration loop */ } if (sumi > 0.0) /* only positive sources */ { xypos[0] = xmom / sumi; xypos[1] = ymom / sumi; xysig[0] = nrx; xysig[1] = nry; if ( xold == xypos[0] && yold == xypos[1] ) { int nr = 0; double xdif, ydif, xrms, yrms; xrms = yrms = sumi = 0.0; p_img += ifram[0] - 1 + (npix[0] * (ifram[2] - 1)); for (iy=0; iy clip ) { xdif = (ifram[0] + ix) - xypos[0]; ydif = (ifram[2] + iy) - xypos[1]; xrms += fabs( source * xdif *xdif ); yrms += fabs( source * ydif *ydif ); sumi += source; nr++; } } p_img += npix[0]; } p_img = p_bgn; indx = CGN_NINT(xypos[0]-1) + (npix[0] * CGN_NINT(xypos[1]-1)); *xyval = p_img[indx]; xysig[0] = (float) sqrt(xrms /(sumi+ *xyval - bgval)); xysig[1] = (float) sqrt(yrms /(sumi+ *xyval - bgval)); xyerr[0] = (float) (xysig[0] / sqrt( (double) (nr - 1))); xyerr[1] = (float) (xysig[1] / sqrt( (double) (nr - 1))); goto end_of_iter; /* succesful return */ } xold = xypos[0]; yold = xypos[1]; } else { istat = 2; xypos[0] = (ifram[0] + ifram[1]) * 0.5; xypos[1] = (ifram[2] + ifram[3]) * 0.5; indx = CGN_NINT(xypos[0]-1); indy = CGN_NINT(xypos[1]-1); *xyval = p_img[indx + ((*npix) * indy)]; goto end_of_iter; /* EXIT iteration loop */ } /* crowded or weak source conditions */ indx = CGN_NINT(xypos[0]-1) + (npix[0] * CGN_NINT(xypos[1]-1)); if ( (*xyval = p_img[indx] - bgval) <= clip ) { xysig[0] = xysig[1] = 0.0; istat = 1; goto end_of_iter; /* EXIT iteration loop */ } /* find extent of source i.e. delete spikes, etc. */ ix = CGN_NINT( xypos[0] ); /* ix, iy = 1,2,... */ iy = CGN_NINT( xypos[1] ); kk = npix[0] * (iy - 1); istr = ifram[0]; source = p_img[ix-1 + kk] - bgval; while ( source > clip && ix >= istr ) { ifram[0] = ix; source = p_img[ix-1 + kk] - bgval; ix --; } ix = CGN_NINT( xypos[0] ); iend = ifram[1]; source = p_img[ix-1 + kk] - bgval; while ( source > clip && ix <= iend ) { ifram[1] = ix; source = p_img[ix-1 + kk] -bgval; ix ++; } ix = CGN_NINT( xypos[0] ); istr = ifram[2]; source = p_img[ix-1 + kk] - bgval; while ( source > clip && iy >= istr ) { ifram[2] = iy; source = p_img[ix-1 + (*npix *(iy-1))] -bgval; iy --; } iy = CGN_NINT( xypos[1] ); iend = ifram[3]; source = p_img[ix-1 + kk] - bgval; while ( source > clip && iy <= iend ) { ifram[3] = iy; source = p_img[ix-1 + (*npix *(iy-1))] -bgval; iy++; } nrx = ifram[1] - ifram[0] + 1; nry = ifram[3] - ifram[2] + 1; } istat = 3; /* iteration failed */ end_of_iter: xypos[0] --; xypos[1] --; } /* GAUSSIAN centering */ else { register int ii; int found, ierr, xlim[2], ylim[2], lnew[2]; float lamda, xcent, ycent, xwidth, ywidth; double chisqr, oldchi, sigma, *krx, *kry, *gfit, *xpos, *yfit, gpar[MAXPAR]; /* construct two marginal distibutions (in pixel coordinates!) */ lnew[0] = (nry / 4); /* in C notation, from 0 ... */ lnew[1] = nry - (nry / 4) - 1; /* Take care of 1-dim case */ if (nry == 1) { krx = (double *) osmmget(nrx * sizeof(double)); Crhox(p_img,npix,image,lnew,krx); ierr = Cserch(krx,nrx,IGNORE,xlim,xlim+1,&xcent,&xwidth); /* store the data of the fit */ nval = xlim[1] - xlim[0] + 1; xpos = (double *) osmmget( nval * sizeof( double )); yfit = (double *) osmmget( nval * sizeof( double )); gfit = (double *) osmmget( nval * sizeof( double )); for (ii=0; ii= *npix ) { found = OUTSIDE; istat = 2; } } (void) osmmfree( (char *) xpos ); (void) osmmfree( (char *) yfit ); (void) osmmfree( (char *) gfit ); if ( found == TRUE ) { xypos[0] = sumi; xypos[1] = 0; xysig[0] = (float) gpar[2]; xyerr[0] = (float) sqrt( sigma * chisqr ); indx = CGN_NINT( xypos[0]); *xyval = p_img[indx]; } } /* Take care of 2-dim case */ else { krx = (double *) osmmget( nrx * sizeof( double )); kry = (double *) osmmget( nry * sizeof( double )); /* Compute and search X-marginal & Y-marginal */ Crhox( p_img, npix, image, lnew, krx ); ierr = Cserch( krx, nrx, IGNORE, xlim, xlim+1, &xcent, &xwidth ); lnew[0] = MYMAX( xlim[0], CGN_NINT(xcent - (2 * xwidth))); lnew[1] = MYMIN( xlim[1], CGN_NINT(xcent + (2 * xwidth))); Crhoy( p_img, npix, image, lnew, kry ); ierr = Cserch( kry, nry, IGNORE, ylim, ylim+1, &ycent, &ywidth ); lnew[0] = MYMAX( ylim[0], CGN_NINT(ycent - (2 * ywidth))); lnew[1] = MYMIN( ylim[1], CGN_NINT(ycent + (2 * ywidth))); Crhox( p_img, npix, image, lnew, krx ); ierr = Cserch( krx, nrx, IGNORE, xlim, xlim+1, &xcent, &xwidth ); lnew[0] = MYMAX( xlim[0], CGN_NINT(xcent - (2 * xwidth))); lnew[1] = MYMIN( xlim[1], CGN_NINT(xcent + (2 * xwidth))); Crhoy( p_img, npix, image, lnew, kry ); ierr = Cserch( kry, nry, IGNORE, ylim, ylim+1, &ycent, &ywidth ); /* fit a gaussian to the source along the X-axis */ nval = xlim[1] - xlim[0] + 1; xpos = (double *) osmmget( nval * sizeof( double )); yfit = (double *) osmmget( nval * sizeof( double )); gfit = (double *) osmmget( nval * sizeof( double )); for (ii=0; ii= *npix ) { found = OUTSIDE; istat = 2; } } (void) osmmfree( (char *) xpos ); (void) osmmfree( (char *) yfit ); (void) osmmfree( (char *) gfit ); if ( found == TRUE ) { xypos[0] = sumi; xysig[0] = (float) gpar[2]; xyerr[0] = (float) sqrt( sigma * chisqr ); /* x-dir o.k. - now fit a gaussian to the source along the Y-axis */ nval = ylim[1] - ylim[0] + 1; xpos = (double *) osmmget( nval * sizeof( double )); yfit = (double *) osmmget( nval * sizeof( double )); gfit = (double *) osmmget( nval * sizeof( double )); for (ii=0; ii= npix[1] ) { found = OUTSIDE; istat = 2; } else indx += (*npix) * indy; } (void) osmmfree( (char *) xpos ); (void) osmmfree( (char *) yfit ); (void) osmmfree( (char *) gfit ); if ( found == TRUE ) { xypos[1] = sumi; xysig[1] = (float) gpar[2]; xyerr[1] = (float) sqrt( sigma * chisqr ); *xyval = p_img[indx]; } } (void) osmmfree( ( char *) kry ); } } return istat; }