/* * psf.c * * Fit a PSF model to an image. * *%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% * * This file part of: SExtractor * * Copyright: (C) 1998-2011 Emmanuel Bertin -- IAP/CNRS/UPMC * * License: GNU General Public License * * SExtractor 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 3 of the License, or * (at your option) any later version. * SExtractor 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 SExtractor. If not, see . * * Last modified: 26/10/2011 * *%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include "define.h" #include "globals.h" #include "prefs.h" #include "fits/fitscat.h" #include "check.h" #include "filter.h" #include "image.h" #include "wcs/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(void) { QMALLOC(thepsfit, psfitstruct, 1); QMALLOC(thepsfit->x, double, prefs.psf_npsfmax); QMALLOC(thepsfit->y, double, prefs.psf_npsfmax); QMALLOC(thepsfit->flux, float, prefs.psf_npsfmax); QMALLOC(thepsfit->fluxerr, float, prefs.psf_npsfmax); if (prefs.dpsf_flag) { QMALLOC(thedpsfit, psfitstruct, 1); QMALLOC(thedpsfit->x, double, prefs.psf_npsfmax); QMALLOC(thedpsfit->y, double, prefs.psf_npsfmax); QMALLOC(thedpsfit->flux, float, prefs.psf_npsfmax); QMALLOC(thedpsfit->fluxerr, 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; dcontextname[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); if (psfit) { free(psfit->x); free(psfit->y); free(psfit->flux); free(psfit->fluxerr); 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; icontextname[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; ipoly = 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; imaskdim; i++) psf->masksize[i] = 1; psf->masknpix = 1; for (i=0; imaskdim; 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 <= 0.0) 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, float, 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; icontext[i]) { psf->context[i] = &contextval[i]; psf->contexttyp[i] = T_DOUBLE; if (fitsread(field->tab->headbuf, psf->contextname[i]+1, &contextval[i], H_FLOAT,T_DOUBLE) == RETURN_ERROR) { sprintf(gstr, "*Error*: %s parameter not found in the header of ", psf->contextname[i]+1); error(EXIT_FAILURE, gstr, field->rfilename); } } return; } /******************************** psf_fit ***********************************/ /* standard 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],fluxerr[PSF_NPSFMAX], deltaxb[PSF_NPSFMAX],deltayb[PSF_NPSFMAX], fluxb[PSF_NPSFMAX],fluxerrb[PSF_NPSFMAX], sol[PSF_NTOT], covmat[PSF_NTOT*PSF_NTOT], vmat[PSF_NTOT*PSF_NTOT], wmat[PSF_NTOT]; float *data, *data2, *data3, *weight, *d, *w; double *mat, *m, *var, dx,dy, pix,pix2, wthresh,val, backnoise2, gain, radmin2,radmax2,satlevel,chi2, r2, valmax, psf_fwhm; float **psfmasks, **psfmaskx,**psfmasky, *ps, *dh, *wh, pixstep; PIXTYPE *datah, *weighth; 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; dx = dy = 0.0; niter = 0; npsfmax = prefs.psf_npsfmax; pixstep = 1.0/psf->pixstep; gain = (field->gain >0.0? field->gain: 1e30); backnoise2 = field->backsig*field->backsig; satlevel = field->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; jx[j] = obj2->posx; thepsfit->y[j] = obj2->posy; thepsfit->flux[j] = 0.0; thepsfit->fluxerr[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; /* 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; QMALLOC(weighth, PIXTYPE, npix); QMALLOC(weight, float, npix); QMALLOC(datah, PIXTYPE, npix); QMALLOC(data, float, npix); QMALLOC(data2, float, npix); QMALLOC(data3, float, 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(checkmask, PIXTYPE, nppix); } QMALLOC(psfmasks, float *, npsfmax); QMALLOC(psfmaskx, float *, npsfmax); QMALLOC(psfmasky, float *, npsfmax); for (i=0; i0 && (pix2=*(dh++))>-BIG && pix20.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 && pix0.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] = fluxerrb[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; jvalmax) { 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; imaskloc, 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); } /*-- Compute variances and covariances */ svdvar(vmat, wmat, npsf*PSF_NA, covmat); var = covmat; for (j=0; j0.0? sqrt(*var):999999.0; //if (flux[j]<12*fluxerr && j>0) // npsfmax--,flux[j]=0; if (flux[j]<12*fluxerr[j] && 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=width || y<0 || y>=height) continue; if (weight[y*width+x] < 1/BIG) continue; if (10*fluxb[j]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; j1E29) 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; jmaskloc, psf->masksize[0], psf->masksize[1], checkmask, pwidth, pheight, -deltax[j]*pixstep, -deltay[j]*pixstep, pixstep); 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; jx[j] = ix+deltax[j]+1.0; thepsfit->y[j] = iy+deltay[j]+1.0; thepsfit->flux[j] = flux[j]; thepsfit->fluxerr[j] = fluxerr[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++))-BIG && pix0.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; ipixstep; pixstep = 1.0/dpsf->pixstep; gain = (dfield->gain >0.0? dfield->gain: 1e30); npsfmax=prefs.psf_npsfmax; pbacknoise2 = field->backsig*field->backsig; satlevel = dfield->satur_level - obj->bkg; gainflag = prefs.weightgain_flag; dpsf_fwhm = dpsf->fwhm*dpsf->pixstep; psf_fwhm = psf->fwhm*psf->pixstep; pwthresh = wfield?wfield->weight_thresh:BIG; /* Initialize outputs */ thepsfit->niter = 0; thepsfit->npsf = 0; for (j=0; jx[j] = 999999.0; thepsfit->y[j] = 999999.0; thepsfit->flux[j] = 0.0; thepsfit->fluxerr[j] = 0.0; pdeltax[j]= pdeltay[j]=psol[j]= pwmat[j]=pflux[j]=pfluxerr[j]=0.0; } ix = (obj->xmax+obj->xmin+1)/2; iy = (obj->ymax+obj->ymin+1)/2; width = obj->xmax-obj->xmin+1+dpsf_fwhm; if (width < (ival=(int)(dpsf_fwhm*2))) width = ival; height = obj->ymax-obj->ymin+1+dpsf_fwhm; if (height < (ival=(int)(dpsf_fwhm*2))) height = ival; npix = width*height; radmin2 = PSF_MINSHIFT*PSF_MINSHIFT; radmax2 = npix/2.0; psf_fit(dpsf,dfield, dwfield,obj); npsf=thedpsfit->npsf; QMALLOC(psfmasks,float *,npsfmax); QMALLOC(psfmaskx,float *,npsfmax); QMALLOC(psfmasky,float *,npsfmax); for (i=0; ix[j]-ix-1 ; pdeltay[j] =thedpsfit->y[j]-iy-1 ; thepsfit->flux[j] = 0; thepsfit->fluxerr[j] = 0; } /*------------------- Now the photometry fit ---------------------*/ copyimage(field, pdatah, width, height, ix, iy); /* Compute photometry weights */ wbad = 0; if (wfield) { copyimage(wfield, pweighth, width, height, ix, iy); for (pwh=pweighth, pw=pweight, pdh=pdatah,p=npix; p--;) { if ((ppix=*(pwh++)) < pwthresh && ppix>0 && (ppix2=*(pdh++))>-BIG && ppix20.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 && ppix0.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(psf); 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; kmaskloc, psf->masksize[0], psf->masksize[1], psfmasks[k], width, height, -pdeltax[k]*ppixstep, -pdeltay[k]*ppixstep, ppixstep); pm=compute_gradient_phot(pweight,width,height, psfmasks[k],pm); } svdfit(pmat, pdata, npix, j, psol, pvmat, pwmat); compute_pos_phot( &j, psol,pflux); for (k=0; k0.0 && sqrt(*pvar)<99? sqrt(*pvar):99; } } /* Compute chi2 if asked to if (FLAG(obj2.chi2_psf)) { for (j=0; j1E29) 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; j1E29) chi2=1E28; } obj2->chi2_psf = pflux[j]>0? chi2/((npix - 3*npsf)*obj->sigbkg*obj->sigbkg):999999; } } thepsfit->niter = thedpsfit->niter; thepsfit->npsf = npsf; for (j=0; jx[j] = ix+pdeltax[j]+1.0; thedpsfit->y[j] = iy+pdeltay[j]+1.0; thedpsfit->flux[j] = pflux[j]; thedpsfit->fluxerr[j] = pfluxerr[j]; thepsfit->x[j] = ix+pdeltax[j]+1.0; thepsfit->y[j] = iy+pdeltay[j]+1.0; thepsfit->flux[j] = pflux[j]; thepsfit->fluxerr[j] = pfluxerr[j]; } for (i=0; ibuild_flag) return; npix = psf->masksize[0]*psf->masksize[1]; /* Reset the Local PSF mask */ memset(psf->maskloc, 0, npix*sizeof(float)); /* Grab the context vector */ ndim = psf->poly->ndim; for (i=0; icontext[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++); } psf->build_flag = 1; return; } /******************************** psf_fwhm **********************************/ /* Return the local PSF FWHM. */ double psf_fwhm(psfstruct *psf) { float *pl, val, max; int n,p, npix; if (!psf->build_flag) psf_build(psf); npix = psf->masksize[0]*psf->masksize[1]; max = -BIG; pl = psf->maskloc; for (p=npix; p--;) if ((val=*(pl++)) > max) max = val; pl = psf->maskloc; max /= 2.0; n = 0; for (p=npix; p--;) if (*(pl++) >= max) n++; return 2.0*sqrt(n/PI)*psf->pixstep; } /*****************************compute_gradient*********************************/ double *compute_gradient(float *weight,int width, int height, float *masks,float *maskx,float *masky ,double *m) { int x,y; float *w, *ps,*px,*py; /*------ copy of the (weighted) PSF, with outer ring set to zero */ ps = masks; w = weight; for (y=0; 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=(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-1)?0:*(ps+width)-*(ps-width)):0)) **w/2; return m; } /*****************************compute_gradient_phot***************************** ****/ double *compute_gradient_phot(float *pweight,int width, int height, float *pmasks,double *pm) { int x,y; float *pw, *pps; /*------ copy of the (weighted) PSF, with outer ring set to zero */ pps = pmasks; pw = pweight; for (y=0; 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; j0.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 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; jposerrmx2_psf = vara/f2; obj2->poserrmy2_psf = varb/f2; obj2->poserrmxy_psf = covab/f2; /*------ 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, float *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, *tmpp, *rv1,*tmp; float *bp; 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 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=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