VISIR Pipeline Reference Manual  4.1.7
visir_img_ff.c
1 /* $Id: visir_img_ff.c,v 1.94 2010-03-09 12:52:18 llundin Exp $
2  *
3  * This file is part of the VISIR Pipeline
4  * Copyright (C) 2002,2003 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., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: llundin $
23  * $Date: 2010-03-09 12:52:18 $
24  * $Revision: 1.94 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 /*-----------------------------------------------------------------------------
33  Includes
34  -----------------------------------------------------------------------------*/
35 
36 #include <string.h>
37 
38 #include "visir_recipe.h"
39 #include "irplib_flat.h"
40 
41 /*-----------------------------------------------------------------------------
42  Defines
43  -----------------------------------------------------------------------------*/
44 
45 #define PAFCOPY "^(DATE-OBS|ARCFILE|ESO TPL ID|ESO DET DIT|MJD-OBS)$"
46 #define PAF_IMG "^(ESO INS FILT1 NAME|ESO INS PFOV)$"
47 #define PAF_SPC "^(ESO INS FILT2 NAME|ESO INS RESOL|ESO INS SLIT1 WID" \
48  "|ESO INS GRAT1 WLEN|ESO INS GRAT1 NAME)$"
49 
50 #ifndef VISIR_IMG_FF_BORDER
51 #define VISIR_IMG_FF_BORDER 64
52 #endif
53 
54 /* Different powers of two */
55 #define visir_ff_mode_default (1<<0)
56 #define visir_ff_mode_spc (1<<1)
57 #define visir_ff_mode_tech (1<<2)
58 
59 #define RECIPE_STRING "visir_img_ff"
60 
61 /*-----------------------------------------------------------------------------
62  Private Functions prototypes
63  -----------------------------------------------------------------------------*/
64 
65 static cpl_imagelist * visir_img_ff_reduce(const irplib_framelist *);
66 
67 static cpl_error_code visir_img_ff_qc(cpl_propertylist *,
68  cpl_propertylist *,
69  const irplib_framelist *);
70 
71 static cpl_error_code visir_img_ff_save(cpl_frameset *,
72  const cpl_parameterlist *,
73  const cpl_propertylist *,
74  const cpl_propertylist *,
75  const cpl_imagelist *,
76  const cpl_image *);
77 
78 VISIR_RECIPE_DEFINE(visir_img_ff, VISIR_PARAM_LOWLIM | VISIR_PARAM_HIGHLIM,
79  "Flat field recipe",
80  "This recipe computes the flatfield.\n"
81  "The files listed in the Set Of Frames (sof-file) must be "
82  "tagged either\n"
83  "VISIR-flatfield-raw-file.fits " VISIR_IMG_FF_RAW " or\n"
84  "VISIR-flatfield-raw-file.fits " VISIR_IMG_TECH_FF_RAW
85  " or\n"
86  "VISIR-flatfield-raw-file.fits " VISIR_SPC_FF_RAW " or\n"
87  "VISIR-flatfield-raw-file.fits " VISIR_SPC_TECH_FF_RAW "\n"
88  "\n"
89  "The corresponding primary product will have a FITS card\n"
90  "'HIERARCH ESO PRO CATG' with a value of\n"
91  VISIR_IMG_FF_PROCATG " or\n"
92  VISIR_IMG_TECH_FF_PROCATG " or\n"
93  VISIR_SPC_FF_PROCATG " or\n"
94  VISIR_SPC_TECH_FF_PROCATG
95  "\n");
96 
97 /*-----------------------------------------------------------------------------
98  Static variables
99  -----------------------------------------------------------------------------*/
100 
101 const unsigned visir_img_ff_border = VISIR_IMG_FF_BORDER;
102 
103 enum _visir_ff_mode_ {
104  visir_ff_none = 0,
105  visir_ff_img = visir_ff_mode_default,
106  visir_ff_spc = visir_ff_mode_default | visir_ff_mode_spc,
107  visir_ff_img_tech = visir_ff_mode_default | visir_ff_mode_tech,
108  visir_ff_spc_tech = visir_ff_mode_default | visir_ff_mode_tech
109  | visir_ff_mode_spc
110 };
111 
112 typedef enum _visir_ff_mode_ visir_ff_mode;
113 
114 static struct {
115  /* Inputs */
116  visir_ff_mode img_mode;
117  double bpm_lo_thresh;
118  double bpm_hi_thresh;
119  /* Outputs */
120  const char * procatg_ff;
121  const char * procatg_bpm;
122  int bpm_nb_bad;
123  cpl_boolean is_lamp;
124  double fp_noise; /* The Fixed Pattern Noise */
125  double lamp_flux; /* The Lamp Flux (intended for a pair of
126  lamp-on/lamp-off images) */
127 } visir_img_ff_config;
128 
129 /*----------------------------------------------------------------------------*/
133 /*----------------------------------------------------------------------------*/
134 
135 /*-----------------------------------------------------------------------------
136  Functions code
137  -----------------------------------------------------------------------------*/
138 /*----------------------------------------------------------------------------*/
145 /*----------------------------------------------------------------------------*/
146 static int visir_img_ff(cpl_frameset * framelist,
147  const cpl_parameterlist * parlist)
148 {
149  irplib_framelist * allframes = NULL;
150  irplib_framelist * rawframes = NULL;
151  cpl_propertylist * qclist = cpl_propertylist_new();
152  cpl_propertylist * paflist = cpl_propertylist_new();
153  cpl_imagelist * flat = NULL;
154  cpl_image * bpm_int = NULL;
155  cpl_mask * bpm = NULL;
156 
157 
158  /* Retrieve input parameters */
159  visir_img_ff_config.bpm_lo_thresh =
160  visir_parameterlist_get_double(parlist, RECIPE_STRING, VISIR_PARAM_LOWLIM);
161  visir_img_ff_config.bpm_hi_thresh =
162  visir_parameterlist_get_double(parlist, RECIPE_STRING, VISIR_PARAM_HIGHLIM);
163 
164  skip_if (0);
165 
166  /* Identify the RAW and CALIB frames in the input frameset */
167  skip_if (visir_dfs_set_groups(framelist));
168 
169  /* Objects observation */
170  allframes = irplib_framelist_cast(framelist);
171  skip_if(allframes == NULL);
172  rawframes = irplib_framelist_extract_regexp(allframes, "^(" VISIR_IMG_FF_RAW
173  "|" VISIR_IMG_TECH_FF_RAW
174  "|" VISIR_SPC_TECH_FF_RAW
175  "|" VISIR_SPC_FF_RAW ")$",
176  CPL_FALSE);
177  skip_if (rawframes == NULL);
178  irplib_framelist_empty(allframes);
179 
180  skip_if(irplib_framelist_load_propertylist_all(rawframes, 0,
181  visir_property_regexp,
182  CPL_FALSE));
183 
184  skip_if(visir_dfs_check_framelist_tag(rawframes));
185 
186  /* Verify uniqueness of frame type and determine PRO.CATG */
187  visir_img_ff_config.img_mode = visir_ff_none;
188  if (cpl_frameset_find(framelist, VISIR_IMG_FF_RAW)) {
189  visir_img_ff_config.img_mode = visir_ff_img;
190  visir_img_ff_config.procatg_ff = VISIR_IMG_FF_PROCATG;
191  visir_img_ff_config.procatg_bpm = VISIR_IMG_FF_BPM_PROCATG;
192  }
193  if (cpl_frameset_find(framelist, VISIR_SPC_FF_RAW)) {
194  skip_if (visir_img_ff_config.img_mode);
195  visir_img_ff_config.img_mode = visir_ff_spc;
196  visir_img_ff_config.procatg_ff = VISIR_SPC_FF_PROCATG;
197  visir_img_ff_config.procatg_bpm = VISIR_SPC_FF_BPM_PROCATG;
198  }
199  if (cpl_frameset_find(framelist, VISIR_IMG_TECH_FF_RAW)) {
200  skip_if (visir_img_ff_config.img_mode);
201  visir_img_ff_config.img_mode = visir_ff_img_tech;
202  visir_img_ff_config.procatg_ff = VISIR_IMG_TECH_FF_PROCATG;
203  visir_img_ff_config.procatg_bpm = VISIR_IMG_TECH_FF_BPM_PROCATG;
204  }
205  if (cpl_frameset_find(framelist, VISIR_SPC_TECH_FF_RAW)) {
206  skip_if (visir_img_ff_config.img_mode);
207  visir_img_ff_config.img_mode = visir_ff_spc_tech;
208  visir_img_ff_config.procatg_ff = VISIR_SPC_TECH_FF_PROCATG;
209  visir_img_ff_config.procatg_bpm = VISIR_SPC_TECH_FF_BPM_PROCATG;
210  }
211 
212  /* Compute the flatfield */
213  cpl_msg_info(cpl_func, "Compute the flatfield");
214  if ((flat = visir_img_ff_reduce(rawframes)) == NULL) {
215  cpl_msg_error(cpl_func, "Could not compute the flatfield image");
216  skip_if(1);
217  }
218 
219  /* Compute the bad pixels map */
220  cpl_msg_info(cpl_func, "Compute the bad pixels map");
221  bpm = cpl_mask_threshold_image_create(cpl_imagelist_get(flat, 0),
222  visir_img_ff_config.bpm_lo_thresh,
223  visir_img_ff_config.bpm_hi_thresh);
224  if (bpm == NULL) {
225  cpl_msg_error(cpl_func, "Could not compute the bad pixel map");
226  skip_if(1);
227  }
228  skip_if (cpl_mask_not(bpm));
229  visir_img_ff_config.bpm_nb_bad = cpl_mask_count(bpm);
230  bpm_int = cpl_image_new_from_mask(bpm);
231 
232  /* The values <bpm_lo_thresh and >bpm_hi_thresh are set to 1 */
233  skip_if (cpl_image_threshold(cpl_imagelist_get(flat, 0),
234  visir_img_ff_config.bpm_lo_thresh,
235  visir_img_ff_config.bpm_hi_thresh,
236  1.0, 1.0));
237 
238  skip_if (visir_img_ff_qc(qclist, paflist, rawframes));
239  irplib_framelist_empty(rawframes);
240 
241  skip_if (visir_img_ff_save(framelist, parlist, qclist, paflist, flat,
242  bpm_int));
243 
244  end_skip;
245 
246  cpl_propertylist_delete(paflist);
247  cpl_propertylist_delete(qclist);
248  irplib_framelist_delete(allframes);
249  irplib_framelist_delete(rawframes);
250  cpl_imagelist_delete(flat);
251  cpl_mask_delete(bpm);
252  cpl_image_delete(bpm_int);
253 
254  return cpl_error_get_code();
255 }
256 
257 /*----------------------------------------------------------------------------*/
263 /*----------------------------------------------------------------------------*/
264 static cpl_imagelist * visir_img_ff_reduce(const irplib_framelist * rawframes)
265 {
266  cpl_imagelist * iset = NULL;
267  cpl_imagelist * fitted = NULL;
268  cpl_image * diff = NULL;
269  cpl_image * prev = NULL;
270  cpl_image * image = NULL;
271  const cpl_propertylist * plist;
272  const char * sval;
273 
274 
275  bug_if (0);
276  bug_if (rawframes == NULL);
277 
278  plist = irplib_framelist_get_propertylist_const(rawframes, 0);
279  bug_if(plist == NULL);
280 
281  /* FIXME: Need a separate DO_CATG for lamp flats */
282  sval = irplib_pfits_get_dpr_type(plist);
283  skip_if (sval == NULL);
284  visir_img_ff_config.is_lamp
285  = strstr(sval, "SKY") == NULL ? CPL_TRUE : CPL_FALSE;
286 
287  /* Load the image set */
288  iset = irplib_imagelist_load_framelist(rawframes, CPL_TYPE_FLOAT, 0, 0);
289  skip_if (iset == NULL);
290 
291  /* Apply the Fit and compute the gain, intercept map and error */
292  fitted = irplib_flat_fit_set(iset, 1);
293 
294  skip_if (fitted == NULL);
295 
296  if (visir_img_ff_config.is_lamp) {
297  /* Copied from naco_img_lampflat.c */
298  double std_diff[3];
299  double upright_x, upright_y;
300  int i;
301 
302  upright_x = cpl_image_get_size_x(cpl_imagelist_get(iset, 0));
303  upright_y = cpl_image_get_size_y(cpl_imagelist_get(iset, 0));
304  upright_x -= visir_img_ff_border;
305  upright_y -= visir_img_ff_border;
306  skip_if(upright_x <= visir_img_ff_border);
307  skip_if(upright_y <= visir_img_ff_border);
308 
309  for (i=0; i < 4 && i < cpl_imagelist_get_size(iset); i++) {
310 
311  double noise;
312 
313 
314  cpl_image_delete(prev);
315  prev = image;
316  image = cpl_image_extract(cpl_imagelist_get(iset, i),
317  visir_img_ff_border,
318  visir_img_ff_border,
319  upright_x,
320  upright_y);
321  bug_if (image == NULL);
322 
323  if (i == 0) continue;
324 
325  diff = cpl_image_subtract_create(prev, image);
326  bug_if (diff == NULL);
327 
328  bug_if(cpl_flux_get_noise_window(diff, NULL, -1, -1,
329  &noise, NULL));
330 
331  std_diff[i-1] = noise * noise;
332 
333  cpl_msg_debug(cpl_func, "SQ-Noise(%d): %g", i, std_diff[i-1]);
334 
335  if (i == 1) {
336  const double median = cpl_image_get_median(diff);
337  const double ditval = visir_pfits_get_dit(plist);
338 
339  skip_if (0);
340  skip_if (ditval <= 0.0);
341 
342  visir_img_ff_config.lamp_flux = median / ditval;
343  cpl_msg_info(cpl_func, "Lamp Flux: %g",
344  visir_img_ff_config.lamp_flux);
345  }
346 
347  cpl_image_delete(diff);
348  diff = NULL;
349 
350  }
351 
352  if (i == 4) {
353 
354  /* Deduce FPNOISE */
355  const double square = std_diff[0] - std_diff[1] - std_diff[2];
356  visir_img_ff_config.fp_noise = square > 0.0 ? sqrt(square) : 0.0;
357 
358  cpl_msg_info(cpl_func, "Noise: %g",
359  visir_img_ff_config.fp_noise);
360 
361  }
362  }
363 
364  end_skip;
365 
366  cpl_image_delete(diff);
367  cpl_image_delete(image);
368  cpl_image_delete(prev);
369  cpl_imagelist_delete(iset);
370 
371  return fitted;
372 }
373 
374 
375 /*----------------------------------------------------------------------------*/
383 /*----------------------------------------------------------------------------*/
384 static cpl_error_code visir_img_ff_qc(cpl_propertylist * qclist,
385  cpl_propertylist * paflist,
386  const irplib_framelist * rawframes)
387 {
388 
389  const cpl_propertylist * reflist
391 
392  bug_if (0);
393 
394  /* QC.CAPA */
395  skip_if (visir_qc_append_capa(qclist, rawframes));
396 
397  /* QC.NBBADPIX */
398  bug_if(cpl_propertylist_append_int(qclist, "ESO QC NBBADPIX",
399  visir_img_ff_config.bpm_nb_bad));
400 
401  if (visir_img_ff_config.is_lamp) {
402  bug_if(cpl_propertylist_append_double(qclist, "ESO QC FPNOISE",
403  visir_img_ff_config.fp_noise));
404  bug_if(cpl_propertylist_append_double(qclist, "ESO QC LAMPFLUX",
405  visir_img_ff_config.lamp_flux));
406  }
407 
408  bug_if (cpl_propertylist_append(paflist, qclist));
409 
410  bug_if (cpl_propertylist_copy_property_regexp(paflist, reflist,
411  (visir_img_ff_config.img_mode & visir_ff_mode_spc)
412  ? PAFCOPY "|" PAF_SPC : PAFCOPY "|" PAF_IMG, 0));
413 
414  /* PRO.CATG */
415  bug_if (cpl_propertylist_append_string(paflist, CPL_DFS_PRO_CATG,
416  visir_img_ff_config.procatg_ff));
417 
418  bug_if (cpl_propertylist_copy_property_regexp(qclist, reflist,
419  "^(" VISIR_PFITS_FF_COPY
420  ")$", 0));
421 
422  bug_if (irplib_pfits_set_airmass(qclist, rawframes));
423 
424  end_skip;
425 
426  return cpl_error_get_code();
427 
428 }
429 
430 
431 /*----------------------------------------------------------------------------*/
442 /*----------------------------------------------------------------------------*/
443 static cpl_error_code visir_img_ff_save(cpl_frameset * set,
444  const cpl_parameterlist * parlist,
445  const cpl_propertylist * qclist,
446  const cpl_propertylist * paflist,
447  const cpl_imagelist * flat,
448  const cpl_image * bpm)
449 {
450  /* SAVE THE FLAT IMAGE */
451  skip_if (irplib_dfs_save_image(set, parlist, set,
452  cpl_imagelist_get_const(flat, 0),
453  CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
454  visir_img_ff_config.procatg_ff, qclist, NULL,
455  visir_pipe_id, RECIPE_STRING CPL_DFS_FITS));
456 
457  /* SAVE THE BPM IMAGE */
458  skip_if (irplib_dfs_save_image(set, parlist, set, bpm, CPL_BPP_32_SIGNED,
459  RECIPE_STRING, visir_img_ff_config.procatg_bpm,
460  qclist, NULL, visir_pipe_id,
461  RECIPE_STRING "_bpm" CPL_DFS_FITS));
462 
463 #ifdef VISIR_SAVE_PAF
464  skip_if (cpl_dfs_save_paf("VISIR", RECIPE_STRING, paflist,
465  RECIPE_STRING CPL_DFS_PAF));
466 #else
467  bug_if(paflist == NULL);
468 #endif
469 
470  end_skip;
471 
472  return cpl_error_get_code();
473 
474 }
double visir_parameterlist_get_double(const cpl_parameterlist *self, const char *recipe, visir_parameter bitmask)
Retrieve the value of a VISIR parameter of type double.
cpl_imagelist * irplib_imagelist_load_framelist(const irplib_framelist *self, cpl_type pixeltype, int planenum, int extnum)
Load an imagelist from a framelist.
cpl_error_code visir_dfs_check_framelist_tag(const irplib_framelist *self)
Check the tags in a frameset (group raw only)
Definition: visir_dfs.c:218
cpl_imagelist * irplib_flat_fit_set(cpl_imagelist *raw, int mode)
Compute a flat-field out of a set of exposures.
Definition: irplib_flat.c:87
const char * irplib_pfits_get_dpr_type(const cpl_propertylist *self)
The data type.
Definition: irplib_pfits.c:103
cpl_error_code irplib_pfits_set_airmass(cpl_propertylist *self, const irplib_framelist *rawframes)
Update/Set the AIRMASS property.
Definition: irplib_pfits.c:338
irplib_framelist * irplib_framelist_extract_regexp(const irplib_framelist *self, const char *regexp, cpl_boolean invert)
Extract the frames with the given tag from a framelist.
const cpl_propertylist * irplib_framelist_get_propertylist_const(const irplib_framelist *self, int pos)
Get the propertylist of the specified frame in the framelist.
void irplib_framelist_empty(irplib_framelist *self)
Erase all frames from a framelist.
cpl_error_code irplib_dfs_save_image(cpl_frameset *allframes, const cpl_parameterlist *parlist, const cpl_frameset *usedframes, const cpl_image *image, cpl_type_bpp bpp, const char *recipe, const char *procat, const cpl_propertylist *applist, const char *remregexp, const char *pipe_id, const char *filename)
Save an image as a DFS-compliant pipeline product.
Definition: irplib_utils.c:192
cpl_error_code irplib_framelist_load_propertylist_all(irplib_framelist *self, int ind, const char *regexp, cpl_boolean invert)
Load the propertylists of all frames in the framelist.
int visir_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
Definition: visir_dfs.c:72
double visir_pfits_get_dit(const cpl_propertylist *self)
The DIT.
Definition: visir_pfits.c:309
void irplib_framelist_delete(irplib_framelist *self)
Deallocate an irplib_framelist with its frames and properties.
irplib_framelist * irplib_framelist_cast(const cpl_frameset *frameset)
Create an irplib_framelist from a cpl_framelist.