VIRCAM Pipeline  2.3.12
imcore_phopt.c
1 /* $Id: imcore_phopt.c,v 1.3 2015/08/12 11:16:55 jim Exp $
2  *
3  * This file is part of the CASU Pipeline utilities
4  * Copyright (C) 2015 European Southern Observatory
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: jim $
23  * $Date: 2015/08/12 11:16:55 $
24  * $Revision: 1.3 $
25  * $Name: $
26  */
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <math.h>
31 
32 #include <cpl.h>
33 
34 #include "floatmath.h"
35 #include "util.h"
36 #include "imcore.h"
37 #include "ap.h"
38 
39 /* Function Prototypes */
40 
41 static void dchole (double a[IMNUM+1][IMNUM+1], double b[IMNUM+1], int n);
42 static float fraction (float x, float y, float r_out);
43 
44 /* does multiple profile fitting to determine intensities */
45 
48 /*---------------------------------------------------------------------------*/
89 /*---------------------------------------------------------------------------*/
90 
91 extern void imcore_phopt(ap_t *ap, float parm[IMNUM][NPAR], int nbit,
92  int naper, float apertures[], float cflux[],
93  float badpix[], int nrcore, float avconf[]) {
94  double aa[IMNUM+1][IMNUM+1],bb[IMNUM+1];
95  float d,arg,*map,rcirc,ff;
96  float cn,parrad,xmin,xmax,xi,yi,ymin,ymax;
97  float t,xj,yj,cnsq,tj,xk,yk,tk;
98  int i,ii,j,kk,ix1,ix2,iy1,iy2,nx,ny,k,iaper;
99  unsigned char *mflag,mf;
100  int *conf;
101 
102  /* Set up some local variables */
103 
104  map = ap->indata;
105  conf = ap->confdata;
106  mflag = ap->mflag;
107  nx = ap->lsiz;
108  ny = ap->csiz;
109 
110  /* Loop for each of the apertures */
111 
112  for (iaper = 0; iaper < naper; iaper++) {
113  rcirc = apertures[iaper];
114  parrad = rcirc + 0.5;
115  cn = 1.0/(CPL_MATH_PI*rcirc*rcirc); /* profile normalising constant */
116  cnsq = cn*cn;
117 
118  /* set up covariance matrix - analytic special case for cores */
119 
120  for(i = 0; i < nbit; i++) {
121  aa[i][i] = cn; /* overlaps totally area=pi*r**2 */
122  if(nbit > 1) {
123  xi = parm[i][1];
124  yi = parm[i][2];
125  for(j = i+1; j < nbit; j++) {
126  d = sqrtf((xi-parm[j][1])*(xi-parm[j][1])
127  + (yi-parm[j][2])*(yi-parm[j][2]));
128  if(d >= 2.0*rcirc) {
129  aa[j][i] = 0.0;
130  aa[i][j] = aa[j][i];
131  } else {
132  arg = d/(2.0*rcirc);
133  aa[j][i] = cnsq*2.0*rcirc*rcirc*
134  (acosf(arg)-arg*(sqrtf(1.0-arg*arg)));
135  aa[i][j] = aa[j][i];
136  }
137  }
138  }
139  }
140 
141  /* clear accumulators */
142 
143  for(i = 0; i < nbit; i++)
144  bb[i] = 0.0;
145 
146  /* generate image-blend outer boundaries */
147 
148  xmin = 1.0e6;
149  xmax = -1.0e6;
150  ymin = 1.0e6;
151  ymax = -1.0e6;
152  for(i = 0; i < nbit; i++) {
153  xi = parm[i][1];
154  yi = parm[i][2];
155  xmin = MIN(xmin, xi);
156  xmax = MAX(xmax, xi);
157  ymin = MIN(ymin, yi);
158  ymax = MAX(ymax, yi);
159  }
160  ix1 = MAX(0,(int)(xmin-parrad)-1);
161  ix2 = MIN(nx-1,(int)(xmax+parrad));
162  iy1 = MAX(0,(int)(ymin-parrad)-1);
163  iy2 = MIN(ny-1,(int)(ymax+parrad));
164 
165  /* now go through pixel region */
166 
167  for(ii = iy1; ii <= iy2; ii++) {
168  kk = ii*nx;
169  for(i = ix1; i <= ix2; i++) {
170  mf = mflag[kk+i];
171  if (mf == MF_ZEROCONF || mf == MF_STUPID_VALUE) {
172  for (j = 0; j < nbit; j++) {
173  xj = i - parm[j][1] + 1.0;
174  yj = ii - parm[j][2] + 1.0;
175  tj = fraction(xj,yj,rcirc);
176  aa[j][j] -= tj*tj*cnsq;
177  for (k = j + 1; k < nbit; k++) {
178  xk = i - parm[k][1] + 1.0;
179  yk = ii - parm[k][2] + 1.0;
180  tk = fraction(xk,yk,rcirc);
181  aa[k][j] -= tk*tj*cnsq;
182  aa[j][k] = aa[k][j];
183  }
184  if (iaper == nrcore)
185  badpix[j] += tj;
186  }
187  } else if (mf == MF_CLEANPIX || mf == MF_OBJPIX ||
188  mf == MF_SATURATED) {
189  t = map[kk+i];
190  for(j = 0; j < nbit; j++) {
191  xj = i - parm[j][1] + 1.0;
192  yj = ii - parm[j][2] + 1.0;
193  ff = fraction(xj,yj,rcirc);
194  bb[j] += ff*t;
195  if (iaper == nrcore)
196  avconf[j] += ff*(float)conf[kk+i];
197  }
198  }
199  }
200  }
201 
202  /* Trivial solution for single object */
203 
204  if (nbit == 1) {
205  cflux[iaper] = bb[0];
206 
207  /* solve for profile intensities */
208 
209  } else {
210  for (i = 0; i < nbit; i++)
211  aa[i][i] = MAX(aa[i][i],cnsq);
212  dchole(aa,bb,nbit);
213  for(i = 0; i < nbit; i++)
214  cflux[i*naper+iaper] = cn*bb[i];
215  }
216  }
217 }
218 
221 /* CHOLEsky decomposition of +ve definite symmetric matrix to solve Ax = b */
222 
223 static void dchole (double a[IMNUM+1][IMNUM+1], double b[IMNUM+1], int n) {
224  double sum, l[IMNUM+1][IMNUM+1], y[IMNUM+1];
225  double aveigv, offset;
226  int i, j, k;
227 
228 restart:
229  l[0][0] = sqrt(a[0][0]);
230 
231  for(k = 1; k < n; k++) {
232  for(j = 0; j <= k-1; j++) {
233  sum = a[j][k];
234  if(j != 0)
235  for(i = 0; i <= j-1; i++)
236  sum -= l[i][k]*l[i][j];
237  l[j][k] = sum/l[j][j];
238  }
239  sum = a[k][k];
240  for(i = 0; i <= k-1; i++)
241  sum -= l[i][k]*l[i][k];
242  if(sum <= 0.0) {
243 /* fprintf(stderr, "dchole: warning: matrix ill-conditioned\n"); */
244  aveigv = a[0][0];
245  for(i = 1; i < n; i++)
246  aveigv += a[i][i];
247  /* max eigenvalue < trace */
248  offset = 0.1*aveigv/((double) n);
249  for(i = 0; i < n; i++)
250  a[i][i] += offset;
251 /* fprintf(stderr, "dchole: Offset added to diagonal = %f\n", offset); */
252  goto restart;
253  }
254  l[k][k] = sqrt(sum);
255  }
256 
257  /* solve Ly = b */
258 
259  y[0] = b[0]/l[0][0];
260  for(i = 1; i < n; i++) {
261  sum = b[i];
262  for(k = 0; k <= i-1; k++)
263  sum -= l[k][i]*y[k];
264  y[i] = sum/l[i][i];
265  }
266 
267  /* solve L(T)x = y */
268 
269  b[n-1] = y[n-1]/l[n-1][n-1];
270  for(i = n-2; i >= 0; i--) {
271  sum = y[i];
272  for(k = i+1; k < n; k++)
273  sum -= l[i][k]*b[k];
274  b[i] = sum/l[i][i];
275  }
276 }
277 
278 /* returns fraction of pixel bounded by 0 - r_out
279  * x,y coordinates relative to centre
280  * Uses linear approximation ok if pixel located >>1 away from centre */
281 
282 static float fraction (float x, float y, float r_out) {
283  float r,t,x_a,x_b,frac,tanao2,cosa,tanp2a,sqrt2o2;
284 
285  r = sqrtf(x*x + y*y);
286  sqrt2o2 = 0.5*CPL_MATH_SQRT2;
287 
288  /* is it worth bothering? */
289 
290  if(r > r_out+sqrt2o2)
291  return(0.0);
292 
293  /* is it trivially all in? */
294 
295  if(r < r_out-sqrt2o2)
296  return(1.0);
297 
298  /* bugger - have to do some work then ... ok first ...
299  * use 8-fold symmetry to convert to 0-45 degree range */
300 
301  x = fabsf(x);
302  y = fabsf(y);
303  if(y > x) {
304  t = x;
305  x = y;
306  y = t;
307  }
308 
309  /* If the angles are too close to cardinal points, then fudge something */
310 
311  if (x > 0.0 && y > 0.0) {
312  tanao2 = 0.5*y/x;
313  tanp2a = x/y;
314  cosa = x/sqrt(x*x + y*y);
315  } else {
316  tanao2 = 0.00005;
317  tanp2a = 10000.0;
318  cosa = 1.0;
319  }
320 
321  /* only outer radius - compute linear intersections top and bot of pixel */
322 
323  x_a = x - tanao2 + (r_out - r)/cosa;
324  if(x_a < x+0.5) {
325 
326  /* intersects */
327 
328  x_b = x + tanao2 + (r_out - r)/cosa;
329 
330  /* three cases to consider */
331 
332  if(x_a < x-0.5)
333  frac = 0.5*MAX(0.0,x_b-(x-0.5))*MAX(0.0,x_b-(x-0.5))*tanp2a;
334  else {
335  if(x_b > x+0.5)
336  frac = 1.0 - 0.5*(x+0.5-x_a)*(x+0.5-x_a)*tanp2a;
337  else
338  frac = 0.5-(x-x_a)+0.5*(x_b-x_a);
339  }
340  } else /* missed entirely */
341  frac = 1.0;
342 
343  return(frac);
344 }
345 
346 /*
347 
348 $Log: imcore_phopt.c,v $
349 Revision 1.3 2015/08/12 11:16:55 jim
350 Modified procedure names to protect namespace
351 
352 Revision 1.2 2015/08/07 13:06:54 jim
353 Fixed copyright to ESO
354 
355 Revision 1.1.1.1 2015/06/12 10:44:32 jim
356 Initial import
357 
358 Revision 1.3 2015/01/09 11:41:29 jim
359 Added average confidence calculation
360 
361 Revision 1.2 2014/04/09 09:09:51 jim
362 Detabbed
363 
364 Revision 1.1.1.1 2013/08/27 12:07:48 jim
365 Imported
366 
367 
368 */
void imcore_phopt(ap_t *ap, float parm[IMNUM][NPAR], int nbit, int naper, float apertures[], float cflux[], float badpix[], int nrcore, float avconf[])
Do multiple profile fitting.
Definition: imcore_phopt.c:91