VIRCAM Pipeline 2.3.15
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
51static int casu_defringe_1(casu_fits **infiles, int nimages, casu_fits *fringe,
52 casu_mask *mask, int nbsize, float *scaleout,
53 int *status);
54
55static void kernel_init(int *nkernel, float **skernel);
56static float *convolve(float *data, int nx, int ny, int nkernel,
57 float *skernel);
58
61/*---------------------------------------------------------------------------*/
113/*---------------------------------------------------------------------------*/
114
115extern 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
220static 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
417static 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
461static 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 $
493Revision 1.4 2015/11/18 20:05:17 jim
494Removed spurious character that snuck in somehow...
495
496Revision 1.3 2015/09/11 09:27:53 jim
497Fixed some problems with the docs
498
499Revision 1.2 2015/08/07 13:06:54 jim
500Fixed copyright to ESO
501
502Revision 1.1.1.1 2015/06/12 10:44:32 jim
503Initial import
504
505Revision 1.2 2015/04/30 12:08:24 jim
506nothing
507
508Revision 1.1 2015/04/08 14:57:19 jim
509Initial 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