UVES Pipeline Reference Manual  5.4.6
uves_flatfield.c
1 /* *
2  * This file is part of the ESO UVES Pipeline *
3  * Copyright (C) 2004,2005 European Southern Observatory *
4  * *
5  * This library is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the Free Software *
17  * Foundation, 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA *
18  * */
19 
20 /*
21  * $Author: amodigli $
22  * $Date: 2012-03-02 17:01:40 $
23  * $Revision: 1.36 $
24  * $Name: not supported by cvs2svn $
25  * $Log: not supported by cvs2svn $
26  * Revision 1.35 2011/12/08 13:57:49 amodigli
27  * Fox warnings with CPL6
28  *
29  * Revision 1.34 2010/09/29 09:39:07 amodigli
30  * fixed compiler warnings
31  *
32  * Revision 1.33 2010/09/27 07:58:36 amodigli
33  * fixed mem leak in case a new mask is allocated
34  *
35  * Revision 1.32 2010/09/27 06:33:33 amodigli
36  * fixed mem leaks
37  *
38  * Revision 1.31 2010/09/24 09:32:03 amodigli
39  * put back QFITS dependency to fix problem spot by NRI on FIBER mode (with MIDAS calibs) data
40  *
41  * Revision 1.29 2009/07/07 14:26:12 amodigli
42  * Fixed a problem dealing with images missing a bpm
43  *
44  * Revision 1.28 2008/09/29 06:56:10 amodigli
45  * add #include <string.h>
46  *
47  * Revision 1.27 2007/08/21 13:08:26 jmlarsen
48  * Removed irplib_access module, largely deprecated by CPL-4
49  *
50  * Revision 1.26 2007/06/06 08:17:33 amodigli
51  * replace tab with 4 spaces
52  *
53  * Revision 1.25 2007/05/24 13:07:46 jmlarsen
54  * Fail if the provided flat-field has unreasonable (zero, nan or inf) mean value
55  *
56  * Revision 1.24 2007/05/22 11:36:37 jmlarsen
57  * Removed MIDAS flag for good
58  *
59  * Revision 1.23 2006/11/15 15:02:14 jmlarsen
60  * Implemented const safe workarounds for CPL functions
61  *
62  * Revision 1.21 2006/11/15 14:04:08 jmlarsen
63  * Removed non-const version of parameterlist_get_first/last/next which is already
64  * in CPL, added const-safe wrapper, unwrapper and deallocator functions
65  *
66  * Revision 1.20 2006/11/13 14:23:55 jmlarsen
67  * Removed workarounds for CPL const bugs
68  *
69  * Revision 1.19 2006/11/06 15:19:41 jmlarsen
70  * Removed unused include directives
71  *
72  * Revision 1.18 2006/08/17 13:56:53 jmlarsen
73  * Reduced max line length
74  *
75  * Revision 1.17 2006/08/17 09:16:40 jmlarsen
76  * Removed CPL2 code
77  *
78  * Revision 1.16 2006/08/10 10:49:57 jmlarsen
79  * Removed workaround for cpl_image_get_bpm
80  *
81  * Revision 1.15 2006/06/16 08:23:31 jmlarsen
82  * Changed 0 -> false
83  *
84  * Revision 1.14 2006/04/24 09:20:12 jmlarsen
85  * Always use the MIDAS normalization
86  *
87  * Revision 1.13 2006/03/24 14:16:43 jmlarsen
88  * Changed order of for loops for efficiency
89  *
90  * Revision 1.12 2006/03/03 13:54:11 jmlarsen
91  * Changed syntax of check macro
92  *
93  * Revision 1.11 2006/02/21 14:26:54 jmlarsen
94  * Minor changes
95  *
96  * Revision 1.10 2006/02/03 07:46:30 jmlarsen
97  * Moved recipe implementations to ./uves directory
98  *
99  * Revision 1.9 2006/01/31 08:24:16 jmlarsen
100  * Wrapper for cpl_image_get_bpm
101  *
102  * Revision 1.8 2006/01/25 16:13:20 jmlarsen
103  * Changed interface of gauss.fitting routine
104  *
105  * Revision 1.7 2005/12/19 16:17:56 jmlarsen
106  * Replaced bool -> int
107  *
108  * Revision 1.6 2005/12/16 14:22:23 jmlarsen
109  * Removed midas test data; Added sof files
110  *
111  * Revision 1.5 2005/12/02 10:41:49 jmlarsen
112  * Minor update
113  *
114  * Revision 1.4 2005/11/28 08:18:12 jmlarsen
115  * Replaced cpl_mask_get_bpm -> cpl_image_get_bpm
116  *
117  * Revision 1.3 2005/11/25 09:27:00 jmlarsen
118  * Switched off time component
119  *
120  * Revision 1.2 2005/11/24 11:54:46 jmlarsen
121  * Added support for CPL 3 interface
122  *
123  * Revision 1.1 2005/11/11 13:18:54 jmlarsen
124  * Reorganized code, renamed source files
125  *
126  */
127 
128 #ifdef HAVE_CONFIG_H
129 # include <config.h>
130 #endif
131 
132 /*----------------------------------------------------------------------------*/
139 /*----------------------------------------------------------------------------*/
142 /*-----------------------------------------------------------------------------
143  Includes
144  -----------------------------------------------------------------------------*/
145 #include <string.h>
146 #include <uves_flatfield.h>
147 #include <uves_utils.h>
148 #include <uves_utils_wrappers.h>
149 #include <uves_error.h>
150 
151 #include <cpl.h>
152 
153 /*-----------------------------------------------------------------------------
154  Functions prototypes
155  -----------------------------------------------------------------------------*/
156 
157 /*-----------------------------------------------------------------------------
158  Implementation
159  -----------------------------------------------------------------------------*/
160 
161 
162 /*----------------------------------------------------------------------------*/
183 /*----------------------------------------------------------------------------*/
184 cpl_error_code
185 uves_flatfielding(cpl_image *image, cpl_image *noise,
186  const cpl_image *master_flat, const cpl_image *mflat_noise)
187 {
188  double *image_data = NULL; /* We have to get direct pointers because of the slow */
189  cpl_mask *image_mask = NULL; /* bad pix handling in cpl_image_get() CPLv2-3 */
190  cpl_binary *image_bad = NULL;
191 
192  double *noise_data = NULL;
193  cpl_mask *noise_mask = NULL;
194  cpl_binary *noise_bad = NULL;
195 
196  const double *mf_data = NULL;
197  const cpl_mask *mf_mask = NULL;
198  const cpl_binary *mf_bad = NULL;
199 
200  const double *mfnoise_data = NULL;
201  const cpl_mask *mfnoise_mask = NULL;
202  cpl_mask *mfnoise_mask_own = NULL;
203  cpl_mask *mf_mask_own = NULL;
204  const cpl_binary *mfnoise_bad = NULL;
205 
206 
207  double ff_mean;
208  int nx, ny;
209  int x, y;
210 
211  passure( image != NULL, " ");
212  passure( master_flat != NULL, " ");
213  passure( noise == NULL || mflat_noise != NULL, " ");
214 
215  passure( cpl_image_get_type(image) == CPL_TYPE_DOUBLE,
216  "Image must be double");
217  passure( noise == NULL || cpl_image_get_type(noise) == CPL_TYPE_DOUBLE,
218  "Image must be double");
219  passure( cpl_image_get_type(master_flat) == CPL_TYPE_DOUBLE,
220  "Image must be double");
221  passure( mflat_noise == NULL || cpl_image_get_type(mflat_noise) == CPL_TYPE_DOUBLE,
222  "Image must be double");
223 
224  nx = cpl_image_get_size_x(image);
225  ny = cpl_image_get_size_y(image);
226 
227  assure( nx == cpl_image_get_size_x(master_flat),
228  CPL_ERROR_INCOMPATIBLE_INPUT,
229  "Input image and master flat field image have different widths: "
230  "%d and %" CPL_SIZE_FORMAT " (pixels)",
231  nx, cpl_image_get_size_x(master_flat));
232 
233  assure( ny == cpl_image_get_size_y(master_flat),
234  CPL_ERROR_INCOMPATIBLE_INPUT,
235  "Input image and master flat field image have different heights: "
236  "%d and %" CPL_SIZE_FORMAT " (pixels)",
237  ny, cpl_image_get_size_y(master_flat));
238 
239  /* Get all pointers */
240  check_nomsg(image_data = cpl_image_get_data(image));
241  check_nomsg(image_mask = cpl_image_get_bpm(image));
242  check_nomsg(image_bad = cpl_mask_get_data(image_mask));
243 
244  check_nomsg(mf_data = cpl_image_get_data_const(master_flat));
245  check_nomsg(mf_mask = cpl_image_get_bpm_const(master_flat));
246  if(mf_mask==NULL) {
247  mf_mask_own = cpl_mask_new(nx,ny);
248  mf_mask = mf_mask_own ;
249  }
250  check_nomsg(mf_bad = cpl_mask_get_data_const(mf_mask));
251 
252  if (noise != NULL)
253  {
254  check_nomsg(noise_data = cpl_image_get_data(noise));
255  check_nomsg(noise_mask = cpl_image_get_bpm(noise));
256  check_nomsg(noise_bad = cpl_mask_get_data(noise_mask));
257 
258  check_nomsg(mfnoise_data = cpl_image_get_data_const(mflat_noise));
259  check_nomsg(mfnoise_mask = cpl_image_get_bpm_const(mflat_noise));
260  if(mfnoise_mask==NULL) {
261  mfnoise_mask_own = cpl_mask_new(nx,ny);
262  mfnoise_mask = mfnoise_mask_own ;
263  }
264  check_nomsg(mfnoise_bad = cpl_mask_get_data_const(mfnoise_mask));
265  }
266 
267  if (false)
268  {
269  /* This would actually be the proper thing to do (take bad
270  pixels into account), but for backwards compatibility
271  with MIDAS, pretend bad pixels have value zero.
272  This is done in order to get the same normalization and
273  be able to use response curves produces by the MIDAS pipeline.
274 
275  (The difference in normalization is usually ~10% or so)
276  */
277  check( ff_mean = cpl_image_get_mean(master_flat),
278  "Could not read average flux of master flat image");
279  }
280  else
281  {
282  /* To get same normalization as MIDAS (which doesn't take bad pixels
283  * into account), calculate 'ff_mean' while assuming that bad pixels
284  * have value zero.
285  */
286  check( ff_mean = cpl_image_get_flux(master_flat) / (nx * ny),
287  "Could not read average flux of master flat image");
288  }
289 
290  assure( ff_mean != 0 && !irplib_isnan(ff_mean) &&
291  !irplib_isinf(ff_mean), CPL_ERROR_ILLEGAL_INPUT,
292  "Flat-field mean value is %g! Please provide a better flat-field",
293  ff_mean );
294 
295  /* Divide by normalized master flat */
296  for (y = 0; y < ny; y++)
297  {
298  for (x = 0; x < nx; x++)
299  {
300  double mf, mf_noise = 0;
301  double flux, flux_noise = 0, flux_corrected = 0;
302  double noise_corrected = 0;
303  cpl_binary pis_rejected;
304  bool is_bad = false;
305 
306  mf = mf_data[x + y*nx];
307  pis_rejected = mf_bad [x + y*nx];
308  is_bad = is_bad || (pis_rejected == CPL_BINARY_1);
309  /* Slow: mf = cpl_image_get(master_flat, x, y, &pis_rejected);
310  is_bad = is_bad || pis_rejected; */
311 
312  if (noise != NULL)
313  {
314  flux_noise = noise_data[x + y*nx];
315  pis_rejected = noise_bad [x + y*nx];
316  is_bad = is_bad || (pis_rejected == CPL_BINARY_1);
317  /* Slow: flux_noise =
318  cpl_image_get(image_noise, x, y, &pis_rejected);
319  is_bad = is_bad || pis_rejected; */
320 
321  mf_noise = mfnoise_data[x + y*nx];
322  pis_rejected = mfnoise_bad [x + y*nx];
323  is_bad = is_bad || (pis_rejected == CPL_BINARY_1);
324  /* Slow: mf_noise =
325  cpl_image_get(mflat_noise, x, y, &pis_rejected);
326  is_bad = is_bad || pis_rejected; */
327  }
328 
329  flux = image_data[x + y*nx];
330  pis_rejected = image_bad [x + y*nx];
331  is_bad = is_bad || (pis_rejected == CPL_BINARY_1);
332  /* Slow: flux = cpl_image_get(image, x, y, &pis_rejected);
333  is_bad = is_bad || pis_rejected; */
334 
335 
336 
337 
338  if (mf > 0)
339  {
340  flux_corrected = (flux / mf) * ff_mean;
341  }
342  else
343  {
344  /* Some mf frames (produced by MIDAS) have have
345  negative flux values because of improper
346  background subtraction */
347  is_bad = true;
348  }
349 
350  if (noise != NULL)
351  {
352  noise_corrected = uves_error_fraction(
353  flux, mf, flux_noise, mf_noise)
354  * ff_mean;
355  }
356 
357  if (is_bad)
358  {
359  image_bad[x + nx*y] = CPL_BINARY_1;
360  /* Slow: cpl_image_reject(image, x, y);*/
361  if (noise != NULL)
362  {
363  noise_bad[x + nx*y] = CPL_BINARY_1;
364  /* Slow: cpl_image_reject(noise, x, y);*/
365  }
366  }
367  else
368  {
369  image_data[x + nx*y] = flux_corrected;
370  /* Slow: cpl_image_set(image, x, y, flux_corrected); */
371  if (noise != NULL)
372  {
373  noise_data[x + nx*y] = noise_corrected;
374  /* Slow: cpl_image_set(noise, x, y, noise_corrected); */
375  }
376  }
377  }
378  }
379 
380  cleanup:
381  if(mf_mask_own) uves_free_mask(&mf_mask_own);
382  if(mfnoise_mask_own) uves_free_mask(&mfnoise_mask_own);
383  return cpl_error_get_code();
384 }
385 
386 /*----------------------------------------------------------------------------*/
396 /*----------------------------------------------------------------------------*/
397 flatfielding_method
398 uves_get_flatfield_method(const cpl_parameterlist *parameters,
399  const char *context, const char *subcontext)
400 {
401  const char *ff = "";
402  flatfielding_method result = 0;
403 
404  check( uves_get_parameter(parameters, context, subcontext, "ffmethod", CPL_TYPE_STRING, &ff),
405  "Could not read parameter");
406 
407  if (strcmp(ff, "pixel" ) == 0) result = FF_PIXEL;
408  else if (strcmp(ff, "extract") == 0) result = FF_EXTRACT;
409  else if (strcmp(ff, "no" ) == 0) result = FF_NO;
410  else
411  {
412  assure(false, CPL_ERROR_ILLEGAL_INPUT, "No such flat-fielding method: '%s'", ff);
413  }
414 
415  cleanup:
416  return result;
417 }
418 
#define check_nomsg(CMD)
Definition: uves_error.h:204
#define passure(BOOL,...)
Definition: uves_error.h:207
flatfielding_method uves_get_flatfield_method(const cpl_parameterlist *parameters, const char *context, const char *subcontext)
Read flat-field method from parameter list.
cpl_error_code uves_flatfielding(cpl_image *image, cpl_image *noise, const cpl_image *master_flat, const cpl_image *mflat_noise)
Divide by flat field.
#define check(CMD,...)
Definition: uves_error.h:198