VIRCAM Pipeline  2.3.12
casu_defringe.c
1 /* $Id: casu_defringe.c,v 1.4 2015/11/18 20:05:17 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/11/18 20:05:17 $
24  * $Revision: 1.4 $
25  * $Name: $
26  */
27 
28 /* Includes */
29 
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33 
34 #include <math.h>
35 #include <cpl.h>
36 #include "casu_mods.h"
37 #include "catalogue/casu_utils.h"
38 #include "catalogue/casu_fits.h"
39 #include "casu_stats.h"
40 #include "casu_mask.h"
41 
42 #define NTERMAX 15
43 #define ITERMAX 7
44 #define OGAP 0.01
45 #define GAPMIN 0.25
46 #define CLIPLEV 4.0
47 
48 #define KFWHM 3.0
49 #define NFWHM 2
50 
51 static int casu_defringe_1(casu_fits **infiles, int nimages, casu_fits *fringe,
52  casu_mask *mask, int nbsize, float *scaleout,
53  int *status);
54 
55 static void kernel_init(int *nkernel, float **skernel);
56 static float *convolve(float *data, int nx, int ny, int nkernel,
57  float *skernel);
58 
61 /*---------------------------------------------------------------------------*/
113 /*---------------------------------------------------------------------------*/
114 
115 extern int casu_defringe(casu_fits **infiles, int nimages, casu_fits **fringes,
116  int nfringes, casu_mask *mask, int nbsize,
117  int *status) {
118  float *sig_before,*scale,*idata,med,mad,ratio;
119  unsigned char *bpm;
120  int i,j,npts;
121  char pname1[64],comment1[64],pname2[64],comment2[64];
122  cpl_propertylist *ehu;
123 
124  /* Inherited status */
125 
126  if (*status != CASU_OK)
127  return(*status);
128 
129  /* Get some workspace to use for working out the background sigmas */
130 
131  sig_before = cpl_malloc(nimages*sizeof(float));
132  scale = cpl_malloc(nimages*sizeof(float));
133 
134  /* Now work out the background sigma of each image */
135 
136  bpm = casu_mask_get_data(mask);
137  npts = (int)cpl_image_get_size_x(casu_fits_get_image(infiles[0]))*
138  (int)cpl_image_get_size_y(casu_fits_get_image(infiles[0]));
139  for (i = 0; i < nimages; i++) {
140  idata = cpl_image_get_data_float(casu_fits_get_image(infiles[i]));
141  casu_medmad(idata,bpm,(long)npts,&med,&mad);
142  sig_before[i] = 1.48*mad;
143  }
144 
145  /* Now do the defringing */
146 
147  for (i = 0; i < nfringes; i++) {
148  (void)casu_defringe_1(infiles,nimages,fringes[i],mask,nbsize,scale,
149  status);
150 
151  /* Create scale factor and fringe name information for headers */
152 
153  (void)sprintf(pname1,"ESO DRS FRINGE%d",i+1);
154  (void)sprintf(comment1,"Fringe frame # %d",i+1);
155  (void)sprintf(pname2,"ESO DRS FRNGSC%d",i+1);
156  (void)sprintf(comment2,"Fringe scale # %d",i+1);
157 
158  /* Now loop for each image and write these to the headers */
159 
160  for (j = 0; j < nimages; j++) {
161  ehu = casu_fits_get_ehu(infiles[j]);
162  cpl_propertylist_update_string(ehu,pname1,
163  casu_fits_get_fullname(fringes[i]));
164  cpl_propertylist_set_comment(ehu,pname1,comment1);
165  cpl_propertylist_update_float(ehu,pname2,scale[i]);
166  cpl_propertylist_set_comment(ehu,pname2,comment2);
167  }
168  }
169 
170  /* Now work out the final background sigma and add the ratio of the
171  before to after to the QC header of each image */
172 
173  for (i = 0; i < nimages; i++) {
174  ehu = casu_fits_get_ehu(infiles[i]);
175  idata = cpl_image_get_data_float(casu_fits_get_image(infiles[i]));
176  casu_medmad(idata,bpm,(long)npts,&med,&mad);
177  ratio = sig_before[i]/(1.48*mad);
178  cpl_propertylist_update_float(ehu,"ESO QC FRINGE_RATIO",ratio);
179  cpl_propertylist_set_comment(ehu,"ESO QC FRINGE_RATIO",
180  "Ratio RMS before to after defringing");
181  }
182  freespace(sig_before);
183  freespace(scale);
184  GOOD_STATUS
185 }
186 
187 /*---------------------------------------------------------------------------*/
218 /*---------------------------------------------------------------------------*/
219 
220 static int casu_defringe_1(casu_fits **infiles, int nimages, casu_fits *fringe,
221  casu_mask *mask, int nbsize, float *scaleout,
222  int *status) {
223  float frmed,immed,*frdata,*frorig,*wptr,*imdata,*data,scaleth,scalemin;
224  float scaleprev,spreadmin,spreadfbest,gap,offset,clipmax,clip,spreadf;
225  float scalefound,scale,scalelist[3],diff,spreadlist[3],a,b,c;
226  float *frback,*imback,*skernel,*frdatasm,*datasm;
227  long npts,ntot;
228  int i,iter,nter,k,j,nx,ny,nkernel;
229  casu_fits *im;
230  unsigned char *bpm;
231  cpl_binary *bpmcpl;
232 
233  /* Inherited status */
234 
235  if (*status != CASU_OK)
236  return(*status);
237 
238  /* Get BPM */
239 
240  nx = cpl_image_get_size_x(casu_fits_get_image(fringe));
241  ny = cpl_image_get_size_y(casu_fits_get_image(fringe));
242  npts = (long)(nx*ny);
243  bpm = casu_mask_get_data(mask);
244  bpmcpl = cpl_malloc(npts*sizeof(cpl_binary));
245  for (i = 0; i < npts; i++)
246  bpmcpl[i] = bpm[i];
247 
248  /* Prepare the fringe frame by creating a background map */
249 
250  frorig = cpl_image_get_data(casu_fits_get_image(fringe));
251  (void)casu_backmap(frorig,bpmcpl,nx,ny,nbsize,&frmed,&frback,status);
252 
253  /* Create a fringe frame image that is background corrected and normalised
254  to zero median */
255 
256  frdata = cpl_malloc(npts*sizeof(float));
257  for (i = 0; i < npts; i++)
258  frdata[i] = frorig[i] - frback[i];
259 
260  /* Convolve the normalised fringe frame to remove any low-level noise
261  patterns */
262 
263  kernel_init(&nkernel,&skernel);
264  frdatasm = convolve(frdata,nx,ny,nkernel,skernel);
265 
266  /* Get some workspace */
267 
268  wptr = cpl_malloc(npts*sizeof(float));
269 
270  /* Now loop for each of the input images */
271 
272  for (i = 0; i < nimages; i++) {
273  im = infiles[i];
274 
275  /* Create a background map and correct for it */
276 
277  imdata = cpl_image_get_data_float(casu_fits_get_image(im));
278  (void)casu_backmap(imdata,bpmcpl,nx,ny,nbsize,&immed,&imback,status);
279  data = cpl_malloc(npts*sizeof(float));
280  for (j = 0; j < npts; j++)
281  data[j] = imdata[j] - imback[j];
282 
283  /* Now smooth the image data */
284 
285  datasm = convolve(data,nx,ny,nkernel,skernel);
286 
287  /* The overall medians are used as a first guess of the scaling
288  between the two images */
289 
290  scaleth = immed/frmed;
291 
292  /* Set up some values for tracking the goodness of fit */
293 
294  scalemin = 0.0;
295  scaleprev = 1.0e6;
296  spreadmin = 1.0e3;
297  spreadfbest = 1.0e6;
298  iter = 0;
299  nter = 0;
300  gap = scaleth;
301  offset = 0.5;
302  clipmax = 1.0e3;
303 
304  /* Begin the iteration loop */
305 
306  while (nter < NTERMAX && iter < ITERMAX && (fabs(offset)*gap > OGAP ||
307  gap > GAPMIN)) {
308  iter++;
309  nter++;
310 
311  /* Clip levels */
312 
313  clip = min(clipmax,CLIPLEV*1.48*spreadmin);
314 
315  /* Speed up convergence if sitting on top of a solution.
316  Slow it down if outside range */
317 
318  if (fabs(scalemin - scaleprev) < 0.5*gap)
319  iter += 1;
320  scaleprev = scalemin;
321  if (fabs(offset) > 0.9)
322  iter -= 1;
323  gap = scaleth*pow(2.0,(double)(1-iter));
324 
325  /* Initialise a few things */
326 
327  spreadf = 1.0e6;
328  scalefound = 2.0;
329 
330  /* Do three calculations -- just below, at and just above
331  the current best guess scale factor */
332 
333  for (k = 0; k < 3; k++) {
334  scale = scalemin + gap*(float)(k-1);
335  scalelist[k] = scale;
336  ntot = 0;
337 
338  /* Do a scaled subtraction of the fringe from the data */
339 
340  for (j = 0; j < npts; j++) {
341  if (bpm[j] == 0) {
342  diff = fabs(datasm[j] - scale*frdatasm[j]);
343  if (diff < clip)
344  wptr[ntot++] = diff;
345  }
346  }
347 
348  /* Find the MAD */
349 
350  spreadlist[k] = casu_med(wptr,NULL,ntot);
351  if (spreadlist[k] < spreadf) {
352  spreadf = spreadlist[k];
353  scalefound = scale;
354  }
355  }
356 
357  /* Right, how have we done on this iteration? If the spread
358  has started to increase then this is the last iteration */
359 
360  if (spreadf > spreadfbest) {
361  nter = NTERMAX + 1;
362 
363  /* Otherwise interpolate to find the best solution */
364 
365  } else {
366  a = spreadlist[1];
367  b = 0.5*(spreadlist[2] - spreadlist[0]);
368  c = 0.5*(spreadlist[2] + spreadlist[0] - 2.0*spreadlist[1]);
369  offset = max(min((-0.5*b/c),1.0),-1.0);
370  spreadmin = a + b*offset + c*offset*offset;
371  scalemin = scalelist[1] + offset*gap;
372 
373  /* Make sure we're not going for a maximum instead of
374  a minimum */
375 
376  if (spreadmin > spreadf) {
377  spreadmin = spreadf;
378  scalemin = scalefound;
379  }
380  }
381 
382  /* Define the best spread found so far */
383 
384  spreadfbest = min(spreadfbest,spreadf);
385 
386  } /* End of iteration loop */
387 
388  /* Trap for no refinement */
389 
390  if (iter == 0)
391  scalemin = scaleth;
392 
393  /* Subtract the fringe frame now with the defined scale factor */
394 
395  for (j = 0; j < npts; j++)
396  imdata[j] -= scalemin*(frorig[j] - frmed);
397  scaleout[i] = scalemin;
398 
399  /* Tidy */
400 
401  freespace(data);
402  freespace(datasm);
403  freespace(imback);
404  }
405 
406  /* Do a bit more tidying */
407 
408  freespace(frdata);
409  freespace(frdatasm);
410  freespace(frback);
411  freespace(wptr);
412  freespace(bpmcpl);
413  freespace(skernel);
414  GOOD_STATUS
415 }
416 
417 static void kernel_init(int *nkernel, float **skernel) {
418  int nk2,n,i,j;
419  double gsigsq,di,dj;
420  float renorm;
421 
422  /* Set the kernel size and get some memory */
423 
424  *nkernel = (int)(KFWHM*NFWHM + 0.5);
425  if (! (*nkernel & 1))
426  (*nkernel)++;
427  *skernel = cpl_malloc((*nkernel)*(*nkernel)*sizeof(float));
428  nk2 = *nkernel/2;
429 
430  /* Set the normalisation constants */
431 
432  gsigsq = 1.0/(2.0*pow((double)KFWHM/2.35,2.0));
433  renorm = 0.0;
434 
435  /* Now work out the weights */
436 
437  n = -1;
438  for (i = -nk2; i <= nk2; i++) {
439  di = (double)i;
440  di *= gsigsq*di;
441  for (j = -nk2; j <= nk2; j++) {
442  dj = (double)j;
443  dj *= gsigsq*dj;
444  n++;
445  (*skernel)[n] = (float)exp(-(di+dj));
446  renorm += (*skernel)[n];
447  }
448  }
449 
450  /* Now normalise the weights */
451 
452  n = -1;
453  for (i = -nk2; i <= nk2; i++) {
454  for (j = -nk2; j <= nk2; j++) {
455  n++;
456  (*skernel)[n] /= renorm;
457  }
458  }
459 }
460 
461 static float *convolve(float *data, int nx, int ny, int nkernel,
462  float *skernel) {
463  float *work,*d;
464  int nk2,ix,iy,jx,jy,n;
465 
466  /* Get some space for the smoothed image */
467 
468  work = cpl_calloc(nx*ny,sizeof(float));
469  nk2 = nkernel/2;
470 
471  /* Do the convolution */
472 
473  for (iy = nk2; iy < ny-nk2; iy++) {
474  for (ix = nk2; ix < nx-nk2; ix++) {
475  n = -1;
476  for (jy = iy-nk2; jy <= iy+nk2; jy++) {
477  d = data +jy*nx;
478  for (jx = ix-nk2; jx <= ix+nk2; jx++) {
479  n++;
480  work[iy*nx+ix] += skernel[n]*d[jx];
481  }
482  }
483  }
484  }
485  return(work);
486 }
487 
490 /*
491 
492 $Log: casu_defringe.c,v $
493 Revision 1.4 2015/11/18 20:05:17 jim
494 Removed spurious character that snuck in somehow...
495 
496 Revision 1.3 2015/09/11 09:27:53 jim
497 Fixed some problems with the docs
498 
499 Revision 1.2 2015/08/07 13:06:54 jim
500 Fixed copyright to ESO
501 
502 Revision 1.1.1.1 2015/06/12 10:44:32 jim
503 Initial import
504 
505 Revision 1.2 2015/04/30 12:08:24 jim
506 nothing
507 
508 Revision 1.1 2015/04/08 14:57:19 jim
509 Initial entry
510 
511 
512 */
cpl_image * casu_fits_get_image(casu_fits *p)
Definition: casu_fits.c:436
char * casu_fits_get_fullname(casu_fits *p)
Definition: casu_fits.c:680
cpl_propertylist * casu_fits_get_ehu(casu_fits *p)
Definition: casu_fits.c:576
unsigned char * casu_mask_get_data(casu_mask *m)
Definition: casu_mask.c:544
int casu_backmap(float *map, cpl_binary *bpm, int nx, int ny, int nbsize, float *avback, float **skymap, int *status)
Model background of an image.
Definition: casu_backmap.c:108
int casu_defringe(casu_fits **infiles, int nimages, casu_fits **fringes, int nfringes, casu_mask *mask, int nbsize, int *status)
Correct input data to remove fringes.
void casu_medmad(float *data, unsigned char *bpm, long np, float *med, float *mad)
Definition: casu_stats.c:347
float casu_med(float *data, unsigned char *bpm, long npts)
Definition: casu_stats.c:89