HAWKI Pipeline Reference Manual  1.8.12
hawki_cal_dark.c
1 /* $Id: hawki_cal_dark.c,v 1.21 2011/02/16 16:33:21 cgarcia Exp $
2  *
3  * This file is part of the HAWKI 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: cgarcia $
23  * $Date: 2011/02/16 16:33:21 $
24  * $Revision: 1.21 $
25  * $Name: hawki-1_8_12 $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 /*-----------------------------------------------------------------------------
33  Includes
34  -----------------------------------------------------------------------------*/
35 
36 #include <math.h>
37 #include <cpl.h>
38 
39 #include "irplib_utils.h"
40 
41 #include "hawki_utils.h"
42 #include "hawki_image_stats.h"
43 #include "hawki_pfits.h"
44 #include "hawki_dfs.h"
45 #include "hawki_load.h"
46 #include "hawki_save.h"
47 #include "hawki_variance.h"
48 
49 /*-----------------------------------------------------------------------------
50  Functions prototypes
51  -----------------------------------------------------------------------------*/
52 
53 static int hawki_cal_dark_create(cpl_plugin *) ;
54 static int hawki_cal_dark_exec(cpl_plugin *) ;
55 static int hawki_cal_dark_destroy(cpl_plugin *) ;
56 static int hawki_cal_dark(cpl_parameterlist *, cpl_frameset *) ;
57 
58 void hawki_cal_dark_initialise_qc(void);
59 static int hawki_cal_dark_retrieve_input_param
60 (cpl_parameterlist * parlist);
61 static double hawki_cal_dark_ron(const cpl_image *, const cpl_image *, int) ;
62 static int hawki_cal_dark_save
63 (const cpl_imagelist * dark,
64  const cpl_imagelist * master_dark_err,
65  const cpl_imagelist * bpmdark,
66  cpl_table ** raw_dark_stats,
67  const cpl_vector ** rons,
68  const cpl_frameset * used_frames,
69  cpl_parameterlist * parlist,
70  cpl_frameset * set);
71 
72 /*-----------------------------------------------------------------------------
73  Static variables
74  -----------------------------------------------------------------------------*/
75 
76 static struct {
77  /* Inputs */
78  int hsize ;
79  int nsamples ;
80  double sigma ;
81  int llx ;
82  int lly ;
83  int urx ;
84  int ury ;
85  double gain;
86  double ron;
87  int error_tracking;
88 } hawki_cal_dark_config ;
89 
90 static struct {
91  /* Outputs */
92  int nb_badpix[HAWKI_NB_DETECTORS] ;
93  double master_dark_mean[HAWKI_NB_DETECTORS] ;
94  double master_dark_med[HAWKI_NB_DETECTORS] ;
95  double master_dark_stdev[HAWKI_NB_DETECTORS] ;
96  double master_dark_error_mean[HAWKI_NB_DETECTORS] ;
97  double master_dark_error_med[HAWKI_NB_DETECTORS] ;
98  double master_dark_error_stdev[HAWKI_NB_DETECTORS] ;
99  double vc_mean[HAWKI_NB_DETECTORS][HAWKI_NB_VC] ;
100  double vc_med[HAWKI_NB_DETECTORS][HAWKI_NB_VC] ;
101  double vc_stdev[HAWKI_NB_DETECTORS][HAWKI_NB_VC] ;
102  double dit;
103  int ndit;
104  int ndsamples;
105 } hawki_cal_dark_outputs;
106 
107 static char hawki_cal_dark_description[] =
108 "hawki_cal_dark -- Dark recipe\n"
109 "The files listed in the Set Of Frames (sof-file) must be tagged:\n"
110 "raw-file.fits "HAWKI_CAL_DARK_RAW" or\n"
111 "raw-file.fits "HAWKI_TEC_FLAT_RAW".\n"
112 "The recipe creates as an output:\n"
113 "hawki_cal_dark.fits ("HAWKI_CALPRO_DARK"): The master dark\n"
114 "hawki_cal_dark_bpmdark.fits("HAWKI_CALPRO_BPM_HOT"): The bad pixel mask associated to the dark\n"
115 "hawki_cal_dark_stats.fits("HAWKI_CALPRO_DARK_STATS"): Statistics of the raw darks\n"
116 "Optionally it also creates:\n"
117 "hawki_cal_dark_err.fits("HAWKI_CALPRO_DARK_ERR"): The error in the master dark\n"
118 "Return code:\n"
119 "esorex exits with an error code of 0 if the recipe completes successfully\n"
120 "or 1 otherwise";
121 
122 /*-----------------------------------------------------------------------------
123  Functions code
124  -----------------------------------------------------------------------------*/
125 
126 /*----------------------------------------------------------------------------*/
135 /*----------------------------------------------------------------------------*/
136 int cpl_plugin_get_info(cpl_pluginlist * list)
137 {
138  cpl_recipe * recipe = cpl_calloc(1, sizeof *recipe ) ;
139  cpl_plugin * plugin = &recipe->interface ;
140 
141  cpl_plugin_init(plugin,
142  CPL_PLUGIN_API,
143  HAWKI_BINARY_VERSION,
144  CPL_PLUGIN_TYPE_RECIPE,
145  "hawki_cal_dark",
146  "Dark recipe",
147  hawki_cal_dark_description,
148  "Cesar Enrique Garcia Dabo",
149  PACKAGE_BUGREPORT,
151  hawki_cal_dark_create,
152  hawki_cal_dark_exec,
153  hawki_cal_dark_destroy) ;
154 
155  cpl_pluginlist_append(list, plugin) ;
156 
157  return 0;
158 }
159 
160 /*----------------------------------------------------------------------------*/
168 /*----------------------------------------------------------------------------*/
169 static int hawki_cal_dark_create(cpl_plugin * plugin)
170 {
171  cpl_recipe * recipe ;
172  cpl_parameter * p ;
173 
174  /* Check that the plugin is part of a valid recipe */
175  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
176  recipe = (cpl_recipe *)plugin ;
177  else return -1 ;
178 
179  /* Create the parameters list in the cpl_recipe object */
180  recipe->parameters = cpl_parameterlist_new() ;
181 
182  /* Fill the parameters list */
183  /* --sigma */
184  p = cpl_parameter_new_value("hawki.hawki_cal_dark.sigma",
185  CPL_TYPE_DOUBLE, "sigma for hot bad pixels detection",
186  "hawki.hawki_cal_dark", 10.0) ;
187  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sigma") ;
188  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
189  cpl_parameterlist_append(recipe->parameters, p) ;
190  /* --nsamples */
191  p = cpl_parameter_new_value("hawki.hawki_cal_dark.nsamples",
192  CPL_TYPE_INT, "number of samples for RON computation",
193  "hawki.hawki_cal_dark", 100) ;
194  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "nsamples") ;
195  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
196  cpl_parameterlist_append(recipe->parameters, p) ;
197  /* --hsize */
198  p = cpl_parameter_new_value("hawki.hawki_cal_dark.hsize",
199  CPL_TYPE_INT, "half size of the window for RON computation",
200  "hawki.hawki_cal_dark", 6) ;
201  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "hsize") ;
202  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
203  cpl_parameterlist_append(recipe->parameters, p) ;
204  /* --zone */
205  p = cpl_parameter_new_value("hawki.hawki_cal_dark.zone",
206  CPL_TYPE_STRING,
207  "Stats zone",
208  "hawki.hawki_cal_dark",
209  "512,512,1536,1536") ;
210  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "zone") ;
211  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
212  cpl_parameterlist_append(recipe->parameters, p) ;
213  /* --gain */
214  p = cpl_parameter_new_value("hawki.hawki_cal_dark.gain",
215  CPL_TYPE_DOUBLE,
216  "Detector nominal gain (e-/ADU)",
217  "hawki.hawki_cal_dark",
218  -1.);
219  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "gain") ;
220  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
221  cpl_parameterlist_append(recipe->parameters, p) ;
222  /* --ron */
223  p = cpl_parameter_new_value("hawki.hawki_cal_dark.ron",
224  CPL_TYPE_DOUBLE,
225  "Detector nominal RON for a single readout (ADU)",
226  "hawki.hawki_cal_dark",
227  -1.);
228  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ron") ;
229  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV) ;
230  cpl_parameterlist_append(recipe->parameters, p) ;
231 
232  /* Return */
233  return 0;
234 }
235 
236 /*----------------------------------------------------------------------------*/
242 /*----------------------------------------------------------------------------*/
243 static int hawki_cal_dark_exec(cpl_plugin * plugin)
244 {
245  cpl_recipe * recipe ;
246 
247  /* Get the recipe out of the plugin */
248  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
249  recipe = (cpl_recipe *)plugin ;
250  else return -1 ;
251 
252  /* Issue a banner */
254 
255  return hawki_cal_dark(recipe->parameters, recipe->frames) ;
256 }
257 
258 /*----------------------------------------------------------------------------*/
264 /*----------------------------------------------------------------------------*/
265 static int hawki_cal_dark_destroy(cpl_plugin * plugin)
266 {
267  cpl_recipe * recipe ;
268 
269  /* Get the recipe out of the plugin */
270  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
271  recipe = (cpl_recipe *)plugin ;
272  else return -1 ;
273 
274  cpl_parameterlist_delete(recipe->parameters) ;
275  return 0 ;
276 }
277 
278 /*----------------------------------------------------------------------------*/
285 /*----------------------------------------------------------------------------*/
286 static int hawki_cal_dark(
287  cpl_parameterlist * parlist,
288  cpl_frameset * frameset)
289 {
290  cpl_frameset * rawframes ;
291  cpl_frame * ref_frame ;
292  cpl_propertylist * plist ;
293  cpl_imagelist * darks_raw ;
294  cpl_imagelist * master_dark;
295  cpl_imagelist * master_dark_err;
296  cpl_imagelist * bpmdark;
297  cpl_image * bpm ;
298  cpl_image * ima_curr ;
299  cpl_image * ima_next ;
300  cpl_image * ima_accu ;
301  cpl_image * ima_accu_err = NULL;
302  int nframes ;
303  cpl_vector * rons[HAWKI_NB_DETECTORS] ;
304  cpl_table ** raw_dark_stats;
305  double ron ;
306  int vc_urx, vc_ury, vc_llx, vc_lly ;
307  int j, k ;
308  int idet;
309  cpl_errorstate error_prevstate;
310 
311  /* Initialise */
312  rawframes = NULL ;
313  ima_accu = NULL ;
314  ima_next = NULL ;
315  master_dark_err = NULL;
316  hawki_cal_dark_initialise_qc();
317 
318  /* Retrieve input parameters */
319  if(hawki_cal_dark_retrieve_input_param(parlist))
320  {
321  cpl_msg_error(__func__, "Wrong parameters");
322  return -1;
323  }
324 
325  /* Identify the RAW and CALIB frames in the input frameset */
326  if (hawki_dfs_set_groups(frameset)) {
327  cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
328  return -1 ;
329  }
330 
331  /* Retrieve raw frames */
332  rawframes = hawki_extract_frameset(frameset, HAWKI_CAL_DARK_RAW) ;
333 
334  /* Test if raw frames have been found */
335  if (rawframes == NULL) {
336  cpl_msg_error(__func__, "No raw frame in input (%s)",HAWKI_CAL_DARK_RAW);
337  return -1 ;
338  }
339 
340  /* At least 3 frames */
341  if (cpl_frameset_get_size(rawframes) < 3) {
342  cpl_msg_error(__func__, "Not enough input frames");
343  cpl_frameset_delete(rawframes) ;
344  return -1 ;
345  }
346 
347  /* Get DIT / NDIT from the header */
348  error_prevstate = cpl_errorstate_get();
349  ref_frame = cpl_frameset_get_frame(rawframes, 0) ;
350  if ((plist=cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
351  0)) == NULL) {
352  cpl_msg_error(__func__, "Cannot get header from frame");
353  cpl_msg_indent_less() ;
354  cpl_frameset_delete(rawframes) ;
355  return -1 ;
356  }
357  hawki_cal_dark_outputs.dit = hawki_pfits_get_dit(plist) ;
358  hawki_cal_dark_outputs.ndit = hawki_pfits_get_ndit(plist) ;
359  hawki_cal_dark_outputs.ndsamples = hawki_pfits_get_ndsamples(plist);
360  cpl_propertylist_delete(plist) ;
361  if(!cpl_errorstate_is_equal(error_prevstate))
362  {
363  cpl_msg_error(__func__, "Cannot get the DIT/NDIT/NDSAMPLES from the header") ;
364  cpl_msg_indent_less() ;
365  cpl_frameset_delete(rawframes) ;
366  return -1 ;
367  }
368  cpl_msg_info(__func__, "DIT value: %g sec.", hawki_cal_dark_outputs.dit);
369  cpl_msg_info(__func__, "NDIT value: %d", hawki_cal_dark_outputs.ndit);
370  cpl_msg_info(__func__, "NDSAMPLES value: %d", hawki_cal_dark_outputs.ndsamples);
371 
372  /* Check that DIT/NDIT and NDSAMPLES are the same for all the frames */
376  {
377  cpl_msg_error(__func__, "Not all input darks have the same "
378  "DIT/NDIT/NDSAMPLES values");
379  cpl_msg_indent_less() ;
380  return -1 ;
381  }
382 
383  /* Number of frames */
384  nframes = cpl_frameset_get_size(rawframes) ;
385 
386  /* Create the statistics table */
387  raw_dark_stats = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_table *));
388  for( idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
389  {
390  raw_dark_stats[idet] = cpl_table_new(nframes);
391  }
392  hawki_image_stats_initialize(raw_dark_stats);
393 
394  /* Loop on the detectors */
395  master_dark = cpl_imagelist_new();
396  if(hawki_cal_dark_config.error_tracking)
397  master_dark_err = cpl_imagelist_new();
398  bpmdark = cpl_imagelist_new();
399  cpl_msg_info(__func__, "Dark computation");
400  cpl_msg_indent_more() ;
401  for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++) {
402  cpl_msg_info(__func__, "Handle chip number %d", idet+1) ;
403 
404  /* Create the rons vectors */
405  rons[idet] = cpl_vector_new(nframes) ;
406 
407  /* Load the input data */
408  darks_raw = hawki_load_detector(rawframes, idet+1, CPL_TYPE_FLOAT) ;
409 
410  /* Loop on the frames */
411  for (j=0 ; j<nframes ; j++) {
412  /* Load the current and next images */
413  if (j==nframes-1) {
414  ima_curr = cpl_imagelist_get(darks_raw, j) ;
415  ima_next = cpl_imagelist_get(darks_raw, 0) ;
416  } else {
417  ima_curr = cpl_imagelist_get(darks_raw, j) ;
418  ima_next = cpl_imagelist_get(darks_raw, j+1) ;
419  }
420 
421  /* Compute the dark stats and store in table */
423  (raw_dark_stats,
424  ima_curr,
425  hawki_cal_dark_config.llx,
426  hawki_cal_dark_config.lly,
427  hawki_cal_dark_config.urx,
428  hawki_cal_dark_config.ury,
429  idet,
430  j) != 0)
431  {
432  cpl_msg_error(__func__, "Cannot compute statistics") ;
433  cpl_msg_indent_less() ;
434  cpl_frameset_delete(rawframes) ;
435  cpl_imagelist_delete(master_dark);
436  if(hawki_cal_dark_config.error_tracking)
437  cpl_imagelist_delete(master_dark_err);
438  cpl_imagelist_delete(darks_raw);
439  cpl_imagelist_delete(bpmdark) ;
440  for (k=0 ; k<=idet ; k++)
441  cpl_vector_delete(rons[k]) ;
442  for( idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
443  cpl_table_delete(raw_dark_stats[idet]);
444  cpl_free(raw_dark_stats);
445  return -1 ;
446  }
447 
448  /* Compute the RON */
449  ron = hawki_cal_dark_ron(ima_curr, ima_next, hawki_cal_dark_outputs.ndit) ;
450  cpl_vector_set(rons[idet], j, ron);
451  }
452 
453  /* Collapse */
454  if (nframes > 2)
455  {
456  ima_accu = cpl_imagelist_collapse_minmax_create(darks_raw, 0, 1) ;
457  if(hawki_cal_dark_config.error_tracking)
458  {
459  cpl_imagelist * variances;
460  cpl_image * accu_var;
461  cpl_msg_info(__func__, "Computing the uncertainty in dark");
463  (darks_raw, hawki_cal_dark_config.gain,
464  hawki_cal_dark_config.ron, hawki_cal_dark_outputs.ndit,
465  hawki_cal_dark_outputs.ndsamples);
466  /* The variances are collapsed, like the dark_raw. Given that
467  * the variances are a monotically increasing function with
468  * respect to the dark_raw, the minmax algorithm will select
469  * the same values as for the dark_raw
470  * The nframes - 1 is because only one frame is being rejected*/
471  accu_var = cpl_imagelist_collapse_minmax_create(variances,0,1);
472  cpl_image_divide_scalar(accu_var, nframes - 1);
473  ima_accu_err = cpl_image_duplicate(accu_var);
474  cpl_image_power(ima_accu_err, 0.5);
475  cpl_imagelist_delete(variances);
476  cpl_image_delete(accu_var);
477  }
478 
479  } else {
480  ima_accu = cpl_imagelist_collapse_create(darks_raw) ;
481  if(hawki_cal_dark_config.error_tracking)
482  {
483  cpl_imagelist * variances;
484  cpl_image * accu_var;
485  cpl_msg_info(__func__, "Computing the uncertainty in dark");
487  (darks_raw, hawki_cal_dark_config.gain,
488  hawki_cal_dark_config.ron, hawki_cal_dark_outputs.ndit,
489  hawki_cal_dark_outputs.ndsamples);
490  accu_var = cpl_imagelist_collapse_create(variances);
491  cpl_image_divide_scalar(accu_var, nframes);
492  ima_accu_err = cpl_image_duplicate(accu_var);
493  cpl_image_power(ima_accu_err, 0.5);
494  cpl_imagelist_delete(variances);
495  cpl_image_delete(accu_var);
496  }
497  }
498  if (ima_accu == NULL) {
499  cpl_msg_error(__func__, "Cannot compute the average") ;
500  cpl_frameset_delete(rawframes) ;
501  cpl_imagelist_delete(bpmdark) ;
502  cpl_imagelist_delete(master_dark) ;
503  if(ima_accu_err != NULL)
504  cpl_image_delete(ima_accu_err);
505  cpl_imagelist_delete(darks_raw);
506  for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
507  cpl_vector_delete(rons[idet]) ;
508  for( idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
509  cpl_table_delete(raw_dark_stats[idet]);
510  cpl_free(raw_dark_stats);
511  return -1 ;
512  }
513  cpl_imagelist_delete(darks_raw) ;
514 
515  /* Put the result in the list */
516  cpl_imagelist_set(master_dark, ima_accu, idet) ;
517  if(hawki_cal_dark_config.error_tracking)
518  cpl_imagelist_set(master_dark_err, ima_accu_err, idet) ;
519 
520  /* Compute the dark_med and stdev */
521  hawki_cal_dark_outputs.master_dark_med[idet]=
522  cpl_image_get_median(ima_accu) / hawki_cal_dark_outputs.dit;
523  hawki_cal_dark_outputs.master_dark_mean[idet] =
524  cpl_image_get_mean(ima_accu) / hawki_cal_dark_outputs.dit;
525  hawki_cal_dark_outputs.master_dark_stdev[idet] =
526  cpl_image_get_stdev(ima_accu) / hawki_cal_dark_outputs.dit;
527  if(hawki_cal_dark_config.error_tracking)
528  {
529  hawki_cal_dark_outputs.master_dark_error_med[idet]=
530  cpl_image_get_median(ima_accu_err) / hawki_cal_dark_outputs.dit;
531  hawki_cal_dark_outputs.master_dark_error_mean[idet] =
532  cpl_image_get_mean(ima_accu_err) / hawki_cal_dark_outputs.dit;
533  hawki_cal_dark_outputs.master_dark_error_stdev[idet] =
534  cpl_image_get_stdev(ima_accu_err) / hawki_cal_dark_outputs.dit;
535  }
536 
537  /* Compute the Video Channels stats */
538  vc_lly = 973 ;
539  vc_ury = 1036 ;
540  for (j=0 ; j<HAWKI_NB_VC ; j++) {
541  vc_llx = j*(2048/HAWKI_NB_VC) + 1 ;
542  vc_urx = (j+1)*(2048/HAWKI_NB_VC) ;
543 
544  hawki_cal_dark_outputs.vc_mean[idet][j] =
545  cpl_image_get_mean_window(ima_accu, vc_llx, vc_lly,
546  vc_urx, vc_ury) ;
547 
548  hawki_cal_dark_outputs.vc_med[idet][j] =
549  cpl_image_get_median_window(ima_accu, vc_llx, vc_lly,
550  vc_urx, vc_ury) ;
551 
552  hawki_cal_dark_outputs.vc_stdev[idet][j] =
553  cpl_image_get_stdev_window(ima_accu, vc_llx, vc_lly,
554  vc_urx, vc_ury) ;
555  }
556 
557  /* Compute the HOT pixels map */
558  cpl_msg_info(__func__, "Compute the BPM from the dark") ;
559  cpl_msg_indent_more() ;
560  if ((bpm=hawki_compute_darkbpm(ima_accu,
561  hawki_cal_dark_config.sigma)) == NULL) {
562  cpl_msg_error(__func__, "Cannot compute the hot pixels") ;
563  cpl_msg_indent_less() ;
564  cpl_frameset_delete(rawframes) ;
565  cpl_imagelist_delete(bpmdark) ;
566  cpl_imagelist_delete(master_dark);
567  if(hawki_cal_dark_config.error_tracking)
568  cpl_imagelist_delete(master_dark_err);
569  for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
570  cpl_vector_delete(rons[idet]) ;
571  for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
572  cpl_table_delete(raw_dark_stats[idet]);
573  cpl_free(raw_dark_stats);
574  return -1 ;
575  }
576  cpl_imagelist_set(bpmdark, bpm, idet) ;
577  hawki_cal_dark_outputs.nb_badpix[idet]=(int)cpl_image_get_flux(bpm);
578  cpl_msg_indent_less() ;
579  }
580  cpl_msg_indent_less() ;
581 
582  /* Divide by DIT */
583  cpl_msg_info(__func__, "Division by DIT") ;
584  cpl_imagelist_divide_scalar(master_dark, hawki_cal_dark_outputs.dit);
585  if(hawki_cal_dark_config.error_tracking)
586  cpl_imagelist_divide_scalar(master_dark_err, hawki_cal_dark_outputs.dit);
587 
588  /* Save the product */
589  cpl_msg_info(__func__, "Save the products") ;
590  cpl_msg_indent_more() ;
591  if (hawki_cal_dark_save(master_dark, master_dark_err,
592  bpmdark, raw_dark_stats,
593  (const cpl_vector **)rons,
594  rawframes,
595  parlist, frameset))
596  cpl_msg_warning(__func__,"Some data could not be saved. "
597  "Check permisions or disk space");
598 
599  /* Free */
600  cpl_frameset_delete(rawframes) ;
601  for (idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
602  cpl_vector_delete(rons[idet]) ;
603  cpl_imagelist_delete(master_dark) ;
604  if(hawki_cal_dark_config.error_tracking)
605  cpl_imagelist_delete(master_dark_err);
606  cpl_imagelist_delete(bpmdark) ;
607  cpl_msg_indent_less() ;
608  for( idet=0 ; idet<HAWKI_NB_DETECTORS ; idet++)
609  cpl_table_delete(raw_dark_stats[idet]);
610  cpl_free(raw_dark_stats);
611 
612  /* Return */
613  if (cpl_error_get_code())
614  {
615  cpl_msg_error(__func__,
616  "HAWK-I pipeline could not recover from previous errors");
617  return -1 ;
618  }
619  else return 0 ;
620 }
621 
622 /*----------------------------------------------------------------------------*/
630 /*----------------------------------------------------------------------------*/
631 static double hawki_cal_dark_ron(
632  const cpl_image * ima1,
633  const cpl_image * ima2,
634  int ndit)
635 {
636  cpl_image * ima ;
637  double norm ;
638  double ron ;
639 
640  /* Test entries */
641  if (ima1 == NULL) return -1.0 ;
642  if (ima2 == NULL) return -1.0 ;
643  if (ndit < 1) return -1.0 ;
644 
645  /* Compute norm */
646  norm = 0.5 * ndit ;
647  norm = sqrt(norm) ;
648 
649  /* Subtraction */
650  if ((ima = cpl_image_subtract_create(ima2, ima1)) == NULL) return -1.0 ;
651 
652  /* RON measurement */
653  cpl_flux_get_noise_window(ima, NULL, hawki_cal_dark_config.hsize,
654  hawki_cal_dark_config.nsamples, &ron, NULL) ;
655  cpl_image_delete(ima) ;
656  return norm*ron ;
657 }
658 
659 /*----------------------------------------------------------------------------*/
669 /*----------------------------------------------------------------------------*/
670 static int hawki_cal_dark_save
671 (const cpl_imagelist * master_dark,
672  const cpl_imagelist * master_dark_err,
673  const cpl_imagelist * bpmdark,
674  cpl_table ** raw_dark_stats,
675  const cpl_vector ** rons,
676  const cpl_frameset * used_frames,
677  cpl_parameterlist * parlist,
678  cpl_frameset * set)
679 {
680  cpl_propertylist ** qclists ;
681  const cpl_frame * ref_frame ;
682  char sval[32] ;
683  cpl_propertylist * inputlist ;
684  int ext_nb ;
685  const char * recipe_name = "hawki_cal_dark" ;
686  int i, j ;
687  cpl_errorstate error_prevstate = cpl_errorstate_get();
688 
689 
690  /* Get the reference frame */
691  ref_frame = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW) ;
692 
693  /* Create the QC lists */
694  qclists = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_propertylist*)) ;
695  for (i=0 ; i<HAWKI_NB_DETECTORS ; i++) {
696  qclists[i] = cpl_propertylist_new();
697  cpl_propertylist_append_int(qclists[i], "ESO QC DARK NBADPIX",
698  hawki_cal_dark_outputs.nb_badpix[i]);
699  cpl_propertylist_append_double(qclists[i], "ESO QC DARK MEAN",
700  hawki_cal_dark_outputs.master_dark_mean[i]);
701  cpl_propertylist_append_double(qclists[i], "ESO QC DARK MED",
702  hawki_cal_dark_outputs.master_dark_med[i]);
703  cpl_propertylist_append_double(qclists[i], "ESO QC DARK STDEV",
704  hawki_cal_dark_outputs.master_dark_stdev[i]);
705  cpl_propertylist_append_double(qclists[i], "ESO QC DARK NONORM MEAN",
706  hawki_cal_dark_outputs.master_dark_mean[i] * hawki_cal_dark_outputs.dit);
707  cpl_propertylist_append_double(qclists[i], "ESO QC DARK NONORM MED",
708  hawki_cal_dark_outputs.master_dark_med[i] * hawki_cal_dark_outputs.dit);
709  cpl_propertylist_append_double(qclists[i], "ESO QC DARK NONORM STDEV",
710  hawki_cal_dark_outputs.master_dark_stdev[i] * hawki_cal_dark_outputs.dit);
711  if(hawki_cal_dark_config.error_tracking)
712  {
713  cpl_propertylist_append_double(qclists[i], "ESO QC DARK ERR MEAN",
714  hawki_cal_dark_outputs.master_dark_error_mean[i]);
715  cpl_propertylist_append_double(qclists[i], "ESO QC DARK ERR MED",
716  hawki_cal_dark_outputs.master_dark_error_med[i]);
717  cpl_propertylist_append_double(qclists[i], "ESO QC DARK ERR STDEV",
718  hawki_cal_dark_outputs.master_dark_error_stdev[i]);
719  cpl_propertylist_append_double(qclists[i], "ESO QC DARK ERR NONORM MEAN",
720  hawki_cal_dark_outputs.master_dark_error_mean[i] * hawki_cal_dark_outputs.dit);
721  cpl_propertylist_append_double(qclists[i], "ESO QC DARK ERR NONORM MED",
722  hawki_cal_dark_outputs.master_dark_error_med[i] * hawki_cal_dark_outputs.dit);
723  cpl_propertylist_append_double(qclists[i], "ESO QC DARK ERR NONORM STDEV",
724  hawki_cal_dark_outputs.master_dark_error_stdev[i] * hawki_cal_dark_outputs.dit);
725  }
726  for (j=0 ; j<HAWKI_NB_VC ; j++) {
727  sprintf(sval, "ESO QC DARK VC%d MEAN", j+1) ;
728  cpl_propertylist_append_double(qclists[i], sval,
729  hawki_cal_dark_outputs.vc_mean[i][j]) ;
730  sprintf(sval, "ESO QC DARK VC%d MED", j+1) ;
731  cpl_propertylist_append_double(qclists[i], sval,
732  hawki_cal_dark_outputs.vc_med[i][j]) ;
733  sprintf(sval, "ESO QC DARK VC%d STDEV", j+1) ;
734  cpl_propertylist_append_double(qclists[i], sval,
735  hawki_cal_dark_outputs.vc_stdev[i][j]) ;
736  }
737  for (j=0 ; j<cpl_vector_get_size(rons[i]) ; j++) {
738  sprintf(sval, "ESO QC RON%d", j+1) ;
739  cpl_propertylist_append_double(qclists[i], sval,
740  cpl_vector_get(rons[i], j)) ;
741  }
742  cpl_propertylist_append_double(qclists[i], "ESO QC RON MEAN",
743  cpl_vector_get_mean(rons[i])) ;
744  cpl_propertylist_append_double(qclists[i], "ESO QC RON MED",
745  cpl_vector_get_median_const(rons[i])) ;
746  cpl_propertylist_append_double(qclists[i], "ESO QC RON STDEV",
747  cpl_vector_get_stdev(rons[i])) ;
748  cpl_propertylist_append_double(qclists[i], "ESO QC DATANCOM",
749  cpl_frameset_get_size(set)) ;
750 
751  /* Propagate some keywords from input raw frame extensions */
752  ext_nb=hawki_get_ext_from_detector(cpl_frame_get_filename(ref_frame), i+1);
753  inputlist = cpl_propertylist_load_regexp(
754  cpl_frame_get_filename(ref_frame), ext_nb,
755  HAWKI_HEADER_EXT_FORWARD, 0) ;
756  cpl_propertylist_append(qclists[i], inputlist) ;
757  cpl_propertylist_delete(inputlist) ;
758  }
759  /* Statistics of the raw images in the QC */
760  hawki_image_stats_stats(raw_dark_stats, qclists);
761 
762  /* Write the dark image */
764  parlist,
765  used_frames,
766  master_dark,
767  recipe_name,
768  HAWKI_CALPRO_DARK,
769  HAWKI_PROTYPE_DARK,
770  NULL,
771  (const cpl_propertylist**)qclists,
772  "hawki_cal_dark.fits") ;
773 
774  /* Write the dark image error */
775  if(master_dark_err != NULL)
776  {
778  parlist,
779  used_frames,
780  master_dark_err,
781  recipe_name,
782  HAWKI_CALPRO_DARK_ERR,
783  HAWKI_PROTYPE_DARK_ERR,
784  NULL,
785  NULL,
786  "hawki_cal_dark_err.fits") ;
787  }
788 
789  /* Write the bpmdark pixels image */
791  parlist,
792  used_frames,
793  bpmdark,
794  recipe_name,
795  HAWKI_CALPRO_BPM_HOT,
796  HAWKI_PROTYPE_BPM,
797  NULL,
798  NULL,
799  "hawki_cal_dark_bpmdark.fits") ;
800 
801 
802  /* Write the table with the statistics */
803  hawki_tables_save(set,
804  parlist,
805  used_frames,
806  (const cpl_table **)raw_dark_stats,
807  recipe_name,
808  HAWKI_CALPRO_DARK_STATS,
809  HAWKI_PROTYPE_DARK_STATS,
810  NULL,
811  NULL,
812  "hawki_cal_dark_stats.fits") ;
813 
814  /* Free and return */
815  for (i=0 ; i<HAWKI_NB_DETECTORS ; i++) {
816  cpl_propertylist_delete(qclists[i]) ;
817  }
818  cpl_free(qclists) ;
819  if(!cpl_errorstate_is_equal(error_prevstate))
820  {
821  cpl_errorstate_set(CPL_ERROR_NONE);
822  return -1;
823  }
824  return 0;
825 }
826 
827 static int hawki_cal_dark_retrieve_input_param
828 (cpl_parameterlist * parlist)
829 {
830  cpl_parameter * par ;
831  const char * sval ;
832  cpl_errorstate error_prevstate = cpl_errorstate_get();
833 
834  /* Retrieve input parameters */
835  par = cpl_parameterlist_find(parlist, "hawki.hawki_cal_dark.sigma") ;
836  hawki_cal_dark_config.sigma = cpl_parameter_get_double(par) ;
837  par = cpl_parameterlist_find(parlist, "hawki.hawki_cal_dark.hsize") ;
838  hawki_cal_dark_config.hsize = cpl_parameter_get_int(par) ;
839  par = cpl_parameterlist_find(parlist, "hawki.hawki_cal_dark.nsamples") ;
840  hawki_cal_dark_config.nsamples = cpl_parameter_get_int(par) ;
841  par = cpl_parameterlist_find(parlist, "hawki.hawki_cal_dark.zone") ;
842  sval = cpl_parameter_get_string(par) ;
843  if (sscanf(sval, "%d,%d,%d,%d",
844  &hawki_cal_dark_config.llx,
845  &hawki_cal_dark_config.lly,
846  &hawki_cal_dark_config.urx,
847  &hawki_cal_dark_config.ury)!=4) {
848  return -1 ;
849  }
850  par = cpl_parameterlist_find(parlist, "hawki.hawki_cal_dark.gain") ;
851  hawki_cal_dark_config.gain = cpl_parameter_get_double(par);
852  par = cpl_parameterlist_find(parlist, "hawki.hawki_cal_dark.ron") ;
853  hawki_cal_dark_config.ron = cpl_parameter_get_double(par);
854  hawki_cal_dark_config.error_tracking = 0;
855  if(hawki_cal_dark_config.gain > 0 && hawki_cal_dark_config.ron > 0)
856  hawki_cal_dark_config.error_tracking = 1;
857 
858  if(!cpl_errorstate_is_equal(error_prevstate))
859  return -1;
860 
861  return 0;
862 }
863 
864 void hawki_cal_dark_initialise_qc(void)
865 {
866  int idet;
867  int j;
868 
869  for(idet=0; idet<HAWKI_NB_DETECTORS; idet++)
870  {
871  hawki_cal_dark_outputs.nb_badpix[idet] = -1 ;
872  hawki_cal_dark_outputs.master_dark_mean[idet] = -1.0 ;
873  hawki_cal_dark_outputs.master_dark_med[idet] = -1.0 ;
874  hawki_cal_dark_outputs.master_dark_stdev[idet] = -1.0 ;
875  hawki_cal_dark_outputs.master_dark_error_mean[idet] = -1.0 ;
876  hawki_cal_dark_outputs.master_dark_error_med[idet] = -1.0 ;
877  hawki_cal_dark_outputs.master_dark_error_stdev[idet] = -1.0 ;
878  for (j=0 ; j<HAWKI_NB_VC ; j++)
879  {
880  hawki_cal_dark_outputs.vc_mean[idet][j] = -1.0 ;
881  hawki_cal_dark_outputs.vc_med[idet][j] = -1.0 ;
882  hawki_cal_dark_outputs.vc_stdev[idet][j] = -1.0 ;
883  }
884  }
885 }