IIINSTRUMENT Pipeline Reference Manual 4.4.13
naco_spc_lampflat.c
1/* $Id: naco_spc_lampflat.c,v 1.21 2011-12-22 11:21:03 llundin Exp $
2 *
3 * This file is part of the NACO 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: 2011-12-22 11:21:03 $
24 * $Revision: 1.21 $
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 "naco_recipe.h"
37
38#include "naco_spc.h"
39
40/*-----------------------------------------------------------------------------
41 Recipe defines
42 -----------------------------------------------------------------------------*/
43
44#define RECIPE_STRING "naco_spc_lampflat"
45
46#ifndef NACO_SPC_MEDIAN_XSIZE
47#define NACO_SPC_MEDIAN_XSIZE 200
48#endif
49
50#ifndef NACO_SPC_MEDIAN_YSIZE
51#define NACO_SPC_MEDIAN_YSIZE NACO_SPC_MEDIAN_XSIZE
52#endif
53
54/*-----------------------------------------------------------------------------
55 Private Functions prototypes
56 -----------------------------------------------------------------------------*/
57
58static cpl_image * naco_spc_lampflat_reduce(cpl_propertylist *,
59 const irplib_framelist *,
60 const cpl_parameterlist *);
61
62static cpl_error_code naco_spc_lampflat_qc(cpl_propertylist *,
63 cpl_propertylist *,
64 const irplib_framelist *);
65
66static cpl_error_code naco_spc_lampflat_save(cpl_frameset *,
67 const cpl_parameterlist *,
68 const cpl_propertylist *,
69 const cpl_propertylist *,
70 const cpl_image *,
71 int, const irplib_framelist *);
72
73NACO_RECIPE_DEFINE(naco_spc_lampflat,
74 NACO_PARAM_REJBORD | NACO_PARAM_HOT_LIM | NACO_PARAM_COLD_LIM,
75 "Spectrocopic flat recipe using a lamp",
76 RECIPE_STRING " -- NACO spectrocopy flat-field creation from "
77 "lamp images.\n"
78 "The files listed in the Set Of Frames (sof-file) "
79 "must be tagged:\n"
80 "NACO-raw-file.fits " NACO_SPC_LAMPFLAT_RAW "\n"
81 "\n"
82 NACO_SPC_MAN_MODESPLIT "\n\n"
83 "Furthermore, the input set of frames must have values of "
84 "the FITS key "
85 NACO_PFITS_INT_LAMP2 " that of zero for off-frames and "
86 "non-zero for on-frames.\n");
87
88
89/*----------------------------------------------------------------------------*/
93/*----------------------------------------------------------------------------*/
94
95/*-----------------------------------------------------------------------------
96 Functions code
97 -----------------------------------------------------------------------------*/
98
99/*----------------------------------------------------------------------------*/
106/*----------------------------------------------------------------------------*/
107static int naco_spc_lampflat(cpl_frameset * framelist,
108 const cpl_parameterlist * parlist)
109{
110 cpl_errorstate cleanstate = cpl_errorstate_get();
111 irplib_framelist * allframes = NULL;
112 irplib_framelist * rawframes = NULL;
113 irplib_framelist * f_one = NULL;
114 const char ** taglist = NULL;
115 cpl_image * lamp_flat = NULL;
116 cpl_propertylist * qclist = cpl_propertylist_new();
117 cpl_propertylist * paflist = cpl_propertylist_new();
118 int nb_good = 0;
119 int nsets;
120 int i;
121
122
123 /* Identify the RAW and CALIB frames in the input frameset */
124 skip_if (naco_dfs_set_groups(framelist));
125
126 allframes = irplib_framelist_cast(framelist);
127 skip_if(allframes == NULL);
128
129 rawframes = irplib_framelist_extract(allframes, NACO_SPC_LAMPFLAT_RAW);
130 skip_if(rawframes == NULL);
131 irplib_framelist_empty(allframes);
132
133 skip_if(irplib_framelist_load_propertylist_all(rawframes, 0, "^("
134 NACO_PFITS_REGEXP_SPCFLAT "|"
135 NACO_PFITS_REGEXP_SPCFLAT_PAF
136 ")$", CPL_FALSE));
137
138 taglist = naco_framelist_set_tag(rawframes, naco_spc_make_tag, &nsets);
139 skip_if(taglist == NULL);
140
141 cpl_msg_info(cpl_func, "Identified %d setting(s) in %d frames",
142 nsets, irplib_framelist_get_size(rawframes));
143
144 /* Extract settings and reduce each of them */
145 for (i=0 ; i < nsets ; i++) {
146
147 /* Reduce data set nb i */
148 cpl_msg_info(cpl_func, "Reducing data set %d of %d", i+1, nsets);
149
150 /* Reduce data set nb i */
151 f_one = irplib_framelist_extract(rawframes, taglist[i]);
152
153 /* Reset the tag */
154 skip_if(irplib_framelist_set_tag_all(f_one, NACO_SPC_LAMPFLAT_RAW));
155
156 cpl_msg_info(cpl_func, "Reducing frame set %d of %d (size=%d) with "
157 "setting: %s", i+1, nsets,
158 irplib_framelist_get_size(f_one), taglist[i]);
159
160 skip_if (f_one == NULL);
161
162 lamp_flat = naco_spc_lampflat_reduce(qclist, f_one, parlist);
163
164 /* Save the products */
165 if (lamp_flat == NULL) {
166 if (nsets > 1)
167 irplib_error_recover(cleanstate, "Could not compute the flat for "
168 "this setting");
169 } else {
170 skip_if(naco_spc_lampflat_qc(qclist, paflist, f_one));
171 /* PRO.CATG */
172 bug_if (cpl_propertylist_append_string(paflist, CPL_DFS_PRO_CATG,
173 NACO_CALIB_SPCFLAT));
174 skip_if(naco_spc_lampflat_save(framelist, parlist, qclist, paflist,
175 lamp_flat, i+1, f_one));
176 cpl_image_delete(lamp_flat);
177 lamp_flat = NULL;
178 nb_good++;
179 }
180 cpl_propertylist_empty(qclist);
181 cpl_propertylist_empty(paflist);
182 irplib_framelist_delete(f_one);
183 f_one = NULL;
184 }
185
186 irplib_ensure(nb_good > 0, CPL_ERROR_DATA_NOT_FOUND,
187 "None of the %d sets could be reduced", nsets);
188
189 end_skip;
190
191 cpl_free(taglist);
192 cpl_image_delete(lamp_flat);
193 irplib_framelist_delete(f_one);
194 irplib_framelist_delete(allframes);
195 irplib_framelist_delete(rawframes);
196 cpl_propertylist_delete(qclist);
197 cpl_propertylist_delete(paflist);
198
199 return cpl_error_get_code();
200}
201
202/*----------------------------------------------------------------------------*/
210/*----------------------------------------------------------------------------*/
211static cpl_image * naco_spc_lampflat_reduce(cpl_propertylist * qclist,
212 const irplib_framelist * framelist,
213 const cpl_parameterlist * parlist)
214{
215 cpl_image * self = NULL;
216 cpl_imagelist * difflist = cpl_imagelist_new();
217 cpl_mask * bpm = NULL;
218 cpl_vector * medians = NULL;
219 const double hot_thresh
220 = naco_parameterlist_get_double(parlist, RECIPE_STRING,
221 NACO_PARAM_HOT_LIM);
222 const double cold_thresh = 1.0 /
223 naco_parameterlist_get_double(parlist, RECIPE_STRING,
224 NACO_PARAM_COLD_LIM);
225 const char * rej_bord
226 = naco_parameterlist_get_string(parlist, RECIPE_STRING,
227 NACO_PARAM_REJBORD);
228 cpl_propertylist * lampkeys = cpl_propertylist_new();
229 int rej_left, rej_right, rej_bottom, rej_top;
230 int nflat, nbad;
231 int ndiff, idiff;
232
233
234 skip_if (0);
235 bug_if (qclist == NULL);
236 bug_if (framelist == NULL);
237 bug_if (parlist == NULL);
238
239 skip_if(cold_thresh <= 0.0);
240 skip_if(cold_thresh >= 1.0);
241 skip_if(hot_thresh <= 1.0);
242
243 skip_if_ne(sscanf(rej_bord, "%d %d %d %d",
244 &rej_left, &rej_right, &rej_bottom, &rej_top), 4,
245 "number(s) in string parameter (%s): \"%s\"",
246 CPL_XSTRINGIFY(NACO_PARAM_REJBORD), rej_bord);
247
248 /* On-frames have lamp2 on and lamp1 off */
249 bug_if(cpl_propertylist_append_int(lampkeys, NACO_PFITS_INT_LAMP2, 1));
250 bug_if(cpl_propertylist_append_int(lampkeys, NACO_PFITS_BOOL_LAMP1, 0));
251
252 skip_if(naco_imagelist_load_diff(difflist, framelist, lampkeys));
253
254 ndiff = cpl_imagelist_get_size(difflist);
255
256 medians = cpl_vector_new(ndiff);
257
258 bug_if(0);
259
260 for (idiff = 0, nflat = 0; idiff < ndiff; idiff++) {
261 cpl_image * diff = cpl_imagelist_get(difflist, nflat);
262 const int nx = cpl_image_get_size_x(diff);
263 const int ny = cpl_image_get_size_y(diff);
264
265 double median;
266 const double mean
267 = cpl_image_get_mean_window(diff,
268 rej_left, nx - rej_right,
269 rej_bottom, ny - rej_top);
270
271 skip_if(0);
272
273 if (mean <= 0.0) {
274 cpl_msg_warning(cpl_func, "Ignoring difference image %d with an "
275 "invalid mean: %g", 1+idiff, mean);
276 cpl_image_delete(cpl_imagelist_unset(difflist, nflat));
277 continue;
278 }
279
280 /* Get the median of the central region */
281 median = cpl_image_get_median_window(diff,
282 (nx-NACO_SPC_MEDIAN_XSIZE)/2,
283 (ny-NACO_SPC_MEDIAN_YSIZE)/2,
284 (nx+NACO_SPC_MEDIAN_XSIZE)/2,
285 (ny+NACO_SPC_MEDIAN_YSIZE)/2);
286 skip_if(0);
287
288 /* Normalize the difference image */
289 bug_if(cpl_image_divide_scalar(diff, mean));
290
291 /* Find non-hot/cold pixels */
292 bpm = cpl_mask_threshold_image_create(diff, cold_thresh, hot_thresh);
293 bug_if(bpm == NULL);
294
295 if (cpl_mask_is_empty(bpm)) {
296 cpl_msg_warning(cpl_func, "Ignoring difference image %d with no "
297 "good pixels", 1+idiff);
298 cpl_mask_delete(bpm);
299 bpm = NULL;
300 cpl_image_delete(cpl_imagelist_unset(difflist, nflat));
301 continue;
302 }
303
304 bug_if(cpl_mask_not(bpm));
305
306 cpl_msg_info(cpl_func, "Difference image %d has %d bad pixels", 1+idiff,
307 (int)cpl_mask_count(bpm));
308
309 /* Reject hot and cold pixels */
310 bug_if(cpl_mask_or(cpl_image_get_bpm(diff), bpm));
311
312 cpl_mask_delete(bpm);
313 bpm = NULL;
314
315 bug_if (cpl_vector_set(medians, nflat, median));
316
317 nflat++;
318 }
319
320 bug_if(nflat != cpl_imagelist_get_size(difflist));
321
322 error_if(nflat == 0, CPL_ERROR_DATA_NOT_FOUND,
323 "The %d difference images are all invalid", ndiff);
324
325 self = cpl_imagelist_collapse_create(difflist);
326 bug_if(0);
327
328 nbad = cpl_image_count_rejected(self);
329 bug_if(0);
330
331 if (nbad > 0) {
332 cpl_msg_info(cpl_func, "Setting %d bad pixels in master flat to 1.0",
333 nbad);
334 bug_if(cpl_image_fill_rejected(self, 1.0));
335 }
336
337 bug_if(cpl_vector_set_size(medians, nflat));
338
339 bug_if(cpl_propertylist_append_double(qclist, "ESO QC SPECFLAT NCOUNTS",
340 cpl_vector_get_mean(medians)));
341 bug_if(cpl_propertylist_append_double(qclist, "ESO QC SPECFLAT STDEV",
342 cpl_vector_get_stdev(medians)));
343
344 end_skip;
345
346 if (cpl_error_get_code()) {
347 cpl_image_delete(self);
348 self = NULL;
349 }
350
351 cpl_propertylist_delete(lampkeys);
352 cpl_imagelist_delete(difflist);
353 cpl_mask_delete(bpm);
354 cpl_vector_delete(medians);
355
356 return self;
357}
358
359
360/*----------------------------------------------------------------------------*/
368/*----------------------------------------------------------------------------*/
369static cpl_error_code naco_spc_lampflat_qc(cpl_propertylist * qclist,
370 cpl_propertylist * paflist,
371 const irplib_framelist * rawframes)
372{
373
374 const cpl_propertylist * reflist
375 = irplib_framelist_get_propertylist_const(rawframes, 0);
376 const char pafcopy[] = "^(" NACO_PFITS_REGEXP_SPCFLAT_PAF ")$";
377
378
379 bug_if (0);
380
381
382 /* THE PAF FILE FOR QC PARAMETERS */
383 skip_if (cpl_propertylist_copy_property_regexp(paflist, reflist, pafcopy,
384 0));
385 skip_if (cpl_propertylist_append(paflist, qclist));
386
387 bug_if (cpl_propertylist_copy_property_regexp(qclist, reflist, "^("
388 IRPLIB_PFITS_REGEXP_RECAL_LAMP
389 ")$", 0));
390
391 end_skip;
392
393 return cpl_error_get_code();
394}
395
396/*----------------------------------------------------------------------------*/
408/*----------------------------------------------------------------------------*/
409static cpl_error_code naco_spc_lampflat_save(cpl_frameset * set_tot,
410 const cpl_parameterlist * parlist,
411 const cpl_propertylist * qclist,
412 const cpl_propertylist * paflist,
413 const cpl_image * flat,
414 int set_nb,
415 const irplib_framelist * rawframes)
416{
417 cpl_frameset * proframes = irplib_frameset_cast(rawframes);
418 char * filename = NULL;
419
420
421
422 /* This will catch rawframes == NULL */
423 bug_if (0);
424
425 /* SAVE THE COMBINED IMAGE */
426 filename = cpl_sprintf(RECIPE_STRING "_set%02d" CPL_DFS_FITS, set_nb);
427 skip_if (irplib_dfs_save_image(set_tot, parlist, proframes, flat,
428 CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
429 NACO_CALIB_SPCFLAT, qclist, NULL,
430 naco_pipe_id, filename));
431
432#ifdef NACO_SAVE_PAF
433 cpl_free(filename);
434 filename = cpl_sprintf(RECIPE_STRING "_set%02d" CPL_DFS_PAF, set_nb);
435 skip_if (cpl_dfs_save_paf("NACO", RECIPE_STRING, paflist, filename));
436#else
437 bug_if(paflist == NULL);
438#endif
439
440 end_skip;
441
442 cpl_free(filename);
443 cpl_frameset_delete(proframes);
444
445 return cpl_error_get_code();
446
447}
int naco_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
Definition: naco_dfs.c:62
double naco_parameterlist_get_double(const cpl_parameterlist *self, const char *recipe, naco_parameter bitmask)
Retrieve the value of a NACO parameter of type double.
const char * naco_parameterlist_get_string(const cpl_parameterlist *self, const char *recipe, naco_parameter bitmask)
Retrieve the value of a NACO string parameter.
char * naco_spc_make_tag(const cpl_frame *self, const cpl_propertylist *plist, int dummy)
Create a string suitable for frame comparison in spectroscopy.
Definition: naco_spc.c:407
cpl_error_code naco_imagelist_load_diff(cpl_imagelist *self, const irplib_framelist *onofflist, const cpl_propertylist *onoffkeys)
Fill the list of difference images from on/off frames.
Definition: naco_spc.c:482
const char ** naco_framelist_set_tag(irplib_framelist *self, char *(*pftag)(const cpl_frame *, const cpl_propertylist *, int), int *pntags)
Retag a framelist according to the given tagging function.
Definition: naco_utils.c:176