IIINSTRUMENT Pipeline Reference Manual 4.6.1
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
65static cpl_imagelist * visir_img_ff_reduce(const irplib_framelist *);
66
67static cpl_error_code visir_img_ff_qc(cpl_propertylist *,
68 cpl_propertylist *,
69 const irplib_framelist *);
70
71static 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
78VISIR_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
101const unsigned visir_img_ff_border = VISIR_IMG_FF_BORDER;
102
103enum _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
112typedef enum _visir_ff_mode_ visir_ff_mode;
113
114static 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/*----------------------------------------------------------------------------*/
146static 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/*----------------------------------------------------------------------------*/
264static 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/*----------------------------------------------------------------------------*/
384static 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
390 = irplib_framelist_get_propertylist_const(rawframes, 0);
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/*----------------------------------------------------------------------------*/
443static 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}
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
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:234
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_parameterlist_get_double(const cpl_parameterlist *self, const char *recipe, visir_parameter bitmask)
Retrieve the value of a VISIR parameter of type double.
double visir_pfits_get_dit(const cpl_propertylist *self)
The DIT.
Definition: visir_pfits.c:325