NACO Pipeline Reference Manual  4.4.0
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 
58 static cpl_image * naco_spc_lampflat_reduce(cpl_propertylist *,
59  const irplib_framelist *,
60  const cpl_parameterlist *);
61 
62 static cpl_error_code naco_spc_lampflat_qc(cpl_propertylist *,
63  cpl_propertylist *,
64  const irplib_framelist *);
65 
66 static 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 
73 NACO_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 /*----------------------------------------------------------------------------*/
107 static 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);
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);
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 /*----------------------------------------------------------------------------*/
211 static 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 (sscanf(rej_bord, "%d %d %d %d",
244  &rej_left, &rej_right, &rej_bottom, &rej_top) != 4);
245 
246  /* On-frames have lamp2 on and lamp1 off */
247  bug_if(cpl_propertylist_append_int(lampkeys, NACO_PFITS_INT_LAMP2, 1));
248  bug_if(cpl_propertylist_append_int(lampkeys, NACO_PFITS_BOOL_LAMP1, 0));
249 
250  skip_if(naco_imagelist_load_diff(difflist, framelist, lampkeys));
251 
252  ndiff = cpl_imagelist_get_size(difflist);
253 
254  medians = cpl_vector_new(ndiff);
255 
256  bug_if(0);
257 
258  for (idiff = 0, nflat = 0; idiff < ndiff; idiff++) {
259  cpl_image * diff = cpl_imagelist_get(difflist, nflat);
260  const int nx = cpl_image_get_size_x(diff);
261  const int ny = cpl_image_get_size_y(diff);
262 
263  double median;
264  const double mean
265  = cpl_image_get_mean_window(diff,
266  rej_left, nx - rej_right,
267  rej_bottom, ny - rej_top);
268 
269  skip_if(0);
270 
271  if (mean <= 0.0) {
272  cpl_msg_warning(cpl_func, "Ignoring difference image %d with an "
273  "invalid mean: %g", 1+idiff, mean);
274  cpl_image_delete(cpl_imagelist_unset(difflist, nflat));
275  continue;
276  }
277 
278  /* Get the median of the central region */
279  median = cpl_image_get_median_window(diff,
280  (nx-NACO_SPC_MEDIAN_XSIZE)/2,
281  (ny-NACO_SPC_MEDIAN_YSIZE)/2,
282  (nx+NACO_SPC_MEDIAN_XSIZE)/2,
283  (ny+NACO_SPC_MEDIAN_YSIZE)/2);
284  skip_if(0);
285 
286  /* Normalize the difference image */
287  bug_if(cpl_image_divide_scalar(diff, mean));
288 
289  /* Find non-hot/cold pixels */
290  bpm = cpl_mask_threshold_image_create(diff, cold_thresh, hot_thresh);
291  bug_if(bpm == NULL);
292 
293  if (cpl_mask_is_empty(bpm)) {
294  cpl_msg_warning(cpl_func, "Ignoring difference image %d with no "
295  "good pixels", 1+idiff);
296  cpl_mask_delete(bpm);
297  bpm = NULL;
298  cpl_image_delete(cpl_imagelist_unset(difflist, nflat));
299  continue;
300  }
301 
302  bug_if(cpl_mask_not(bpm));
303 
304  cpl_msg_info(cpl_func, "Difference image %d has %d bad pixels", 1+idiff,
305  (int)cpl_mask_count(bpm));
306 
307  /* Reject hot and cold pixels */
308  bug_if(cpl_mask_or(cpl_image_get_bpm(diff), bpm));
309 
310  cpl_mask_delete(bpm);
311  bpm = NULL;
312 
313  bug_if (cpl_vector_set(medians, nflat, median));
314 
315  nflat++;
316  }
317 
318  bug_if(nflat != cpl_imagelist_get_size(difflist));
319 
320  error_if(nflat == 0, CPL_ERROR_DATA_NOT_FOUND,
321  "The %d difference images are all invalid", ndiff);
322 
323  self = cpl_imagelist_collapse_create(difflist);
324  bug_if(0);
325 
326  nbad = cpl_image_count_rejected(self);
327  bug_if(0);
328 
329  if (nbad > 0) {
330  cpl_msg_info(cpl_func, "Setting %d bad pixels in master flat to 1.0",
331  nbad);
332  bug_if(cpl_image_fill_rejected(self, 1.0));
333  }
334 
335  bug_if(cpl_vector_set_size(medians, nflat));
336 
337  bug_if(cpl_propertylist_append_double(qclist, "ESO QC SPECFLAT NCOUNTS",
338  cpl_vector_get_mean(medians)));
339  bug_if(cpl_propertylist_append_double(qclist, "ESO QC SPECFLAT STDEV",
340  cpl_vector_get_stdev(medians)));
341 
342  end_skip;
343 
344  if (cpl_error_get_code()) {
345  cpl_image_delete(self);
346  self = NULL;
347  }
348 
349  cpl_propertylist_delete(lampkeys);
350  cpl_imagelist_delete(difflist);
351  cpl_mask_delete(bpm);
352  cpl_vector_delete(medians);
353 
354  return self;
355 }
356 
357 
358 /*----------------------------------------------------------------------------*/
366 /*----------------------------------------------------------------------------*/
367 static cpl_error_code naco_spc_lampflat_qc(cpl_propertylist * qclist,
368  cpl_propertylist * paflist,
369  const irplib_framelist * rawframes)
370 {
371 
372  const cpl_propertylist * reflist
374  const char pafcopy[] = "^(" NACO_PFITS_REGEXP_SPCFLAT_PAF ")$";
375 
376 
377  bug_if (0);
378 
379 
380  /* THE PAF FILE FOR QC PARAMETERS */
381  skip_if (cpl_propertylist_copy_property_regexp(paflist, reflist, pafcopy,
382  0));
383  skip_if (cpl_propertylist_append(paflist, qclist));
384 
385  bug_if (cpl_propertylist_copy_property_regexp(qclist, reflist, "^("
386  IRPLIB_PFITS_REGEXP_RECAL_LAMP
387  ")$", 0));
388 
389  end_skip;
390 
391  return cpl_error_get_code();
392 }
393 
394 /*----------------------------------------------------------------------------*/
406 /*----------------------------------------------------------------------------*/
407 static cpl_error_code naco_spc_lampflat_save(cpl_frameset * set_tot,
408  const cpl_parameterlist * parlist,
409  const cpl_propertylist * qclist,
410  const cpl_propertylist * paflist,
411  const cpl_image * flat,
412  int set_nb,
413  const irplib_framelist * rawframes)
414 {
415  cpl_frameset * proframes = irplib_frameset_cast(rawframes);
416  char * filename = NULL;
417 
418 
419 
420  /* This will catch rawframes == NULL */
421  bug_if (0);
422 
423  /* SAVE THE COMBINED IMAGE */
424  filename = cpl_sprintf(RECIPE_STRING "_set%02d" CPL_DFS_FITS, set_nb);
425  skip_if (irplib_dfs_save_image(set_tot, parlist, proframes, flat,
426  CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
427  NACO_CALIB_SPCFLAT, qclist, NULL,
428  naco_pipe_id, filename));
429 
430 #ifdef NACO_SAVE_PAF
431  cpl_free(filename);
432  filename = cpl_sprintf(RECIPE_STRING "_set%02d" CPL_DFS_PAF, set_nb);
433  skip_if (cpl_dfs_save_paf("NACO", RECIPE_STRING, paflist, filename));
434 #else
435  bug_if(paflist == NULL);
436 #endif
437 
438  end_skip;
439 
440  cpl_free(filename);
441  cpl_frameset_delete(proframes);
442 
443  return cpl_error_get_code();
444 
445 }
cpl_frameset * irplib_frameset_cast(const irplib_framelist *self)
Create a CPL frameset from an irplib_framelist.
cpl_error_code irplib_framelist_set_tag_all(irplib_framelist *self, const char *tag)
Set the tag of all frames in the list.
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
int naco_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
Definition: naco_dfs.c:62
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:208
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.
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.
irplib_framelist * irplib_framelist_extract(const irplib_framelist *self, const char *tag)
Extract the frames with the given tag from a framelist.
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
void irplib_framelist_delete(irplib_framelist *self)
Deallocate an irplib_framelist with its frames and properties.
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
irplib_framelist * irplib_framelist_cast(const cpl_frameset *frameset)
Create an irplib_framelist from a cpl_framelist.
const char * naco_parameterlist_get_string(const cpl_parameterlist *self, const char *recipe, naco_parameter bitmask)
Retrieve the value of a NACO string parameter.
int irplib_framelist_get_size(const irplib_framelist *self)
Get the size of a framelist.