IIINSTRUMENT Pipeline Reference Manual  1.3.10
detmon/detmon_darkron.c
1 /* $Id: detmon.c,v 1.11 2013-07-19 12:00:24 jtaylor Exp $
2  *
3  * This file is part of the irplib package
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: jtaylor $
23  * $Date: 2013-07-19 12:00:24 $
24  * $Revision: 1.11 $
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 "detmon_darkron.h"
37 
38 #include "detmon_ronbias.h"
39 #include "detmon.h"
40 
41 #include "irplib_ksigma_clip.h"
42 #include "irplib_hist.h"
43 #include "irplib_utils.h"
44 
45 #include <math.h>
46 #include <string.h>
47 #include <assert.h>
48 #include <float.h>
49 
51 /*--------------------------------------------------------------------------*/
52 
53 /*
54  * @defgroup detmon Detector monitoring functions
55  */
56 
57 /*--------------------------------------------------------------------------*/
58 
59 /*---------------------------------------------------------------------------
60  Defines
61  ---------------------------------------------------------------------------*/
62 
63 /* Computes the square of an euclidean distance bet. 2 points */
64 #define pdist(x1,y1,x2,y2) (((x1-x2)*(x1-x2))+((y1-y2)*(y1-y2)))
65 
66 #define cpl_drand() ((double)rand()/(double)RAND_MAX)
67 
68 enum pixeltypes
69 {
70  HOT = 0,
71  DEAD = 1,
72  NOISY = 2
73 };
74 
75 enum stackingtypes
76 {
77  MINMAX = 0,
78  MEAN = 1,
79  MEDIAN = 2,
80  KSIGMA = 3
81 };
82 
83 enum readouts
84 {
85  HORIZONTAL = 1,
86  VERTICAL = 2
87 };
88 
89 
90 
91 static struct
92 {
93  const char * ron_method;
94  const char * dsnu_method;
95  int exts;
96  int nb_extensions;
97  cpl_boolean opt_nir;
98 } detmon_dark_config;
99 
100 #define NIR TRUE
101 #define OPT FALSE
102 
103 /*---------------------------------------------------------------------------
104  Private function prototypes
105  ---------------------------------------------------------------------------*/
106 
107 /* The following function is duplicated from cpl_det */
108 int
109 detmon_dark_dfs_set_groups(cpl_frameset *,
110  const char *);
111 
112 cpl_error_code
113 detmon_dark_dsnu(cpl_frameset *,
114  cpl_imagelist *,
115  cpl_table *,
116  cpl_image *,
117  int pos);
118 
119 
120 static cpl_error_code
121 detmon_dark_save(const cpl_parameterlist *,
122  cpl_frameset *,
123  const char *,
124  const char *,
125  const char *,
126  const char *,
127  const char *,
128  const char *,
129  cpl_imagelist **,
130  cpl_table **,
131  cpl_imagelist **,
132  cpl_propertylist **,
133  const int,
134  const int,
135  const cpl_frameset *);
136 
137 
138 
139 static cpl_error_code
140 detmon_retrieve_dark_params(const char *,
141  const char *,
142  const cpl_parameterlist *);
143 
144 cpl_error_code
145 detmon_dark_qc(cpl_propertylist *,
146  cpl_image *);
147 
148 
149 
150 /* RONBIAS FILLING PARLIST */
151 
152 
153 /*---------------------------------------------------------------------------*/
154 
155 /*
156  * @brief Fill input parameters with default values
157  * @param parlist parameters list
158  * @param recipe_name recipe name
159  * @param pipeline_name pipeline name
160 
161  * @return CPL_ERROR_NONE on success.
162  */
163 
164 /*---------------------------------------------------------------------------*/
165 
166  cpl_error_code
167 detmon_darkron_fill_parlist_default(cpl_parameterlist * parlist,
168  const char *recipe_name,
169  const char *pipeline_name)
170 {
171  const cpl_error_code error =
172  detmon_ronbias_fill_parlist(parlist, recipe_name, pipeline_name,
173  "ALL", /* --method */
174  "NORM",/* --pmethod */
175  1, /* --preoverscan_degree */
176  -1, /* --random_nsamples */
177  -1, /* --random_sizex */
178  -1, /* --random_sizey */
179  0, /* --criteria */
180  -1, /* --ref_llx */
181  -1, /* --ref_lly */
182  -1, /* --ref_urx */
183  -1, /* --ref_ury */
184  "MEAN",/* --stacking_method */
185  3, /* --stacking_ks_low */
186  3, /* --stacking_ks_high */
187  5, /* --stacking_ks_iter */
188  0, /* --master_shift_x */
189  0, /* --master_shift_y */
190  -1, /* --ron_llx */
191  -1, /* --ron_lly */
192  -1, /* --ron_urx */
193  -1, /* --ron_ury */
194  0, /* --exts */
195  NIR);
196  cpl_ensure_code(!error, error);
197 
198  return cpl_error_get_code();
199 }
200 
201 
202 /*--------------------------------------------------------------------------*/
203 
204 /*
205  * @brief Comparison function to identify different settings
206  * @param frame1 First frame
207  * @param frame2 Second frame
208  * @return 0 if different, 1 if equal, -1 in error case
209  */
210 
211 /*--------------------------------------------------------------------------*/
212 
213 int
214 detmon_compare_dits(const cpl_frame * frame1, const cpl_frame * frame2)
215 {
216  int comparison;
217  cpl_propertylist *plist1;
218  cpl_propertylist *plist2;
219  double dval1, dval2;
220 
221  /* Test entries */
222  if(frame1 == NULL || frame2 == NULL)
223  return -1;
224 
225  /* Get property lists */
226  if((plist1 = cpl_propertylist_load(cpl_frame_get_filename(frame1),
227  0)) == NULL) {
228  cpl_msg_error(cpl_func, "getting header from reference frame");
229  return -1;
230  }
231  if((plist2 = cpl_propertylist_load(cpl_frame_get_filename(frame2),
232  0)) == NULL) {
233  cpl_msg_error(cpl_func, "getting header from reference frame");
234  cpl_propertylist_delete(plist1);
235  return -1;
236  }
237 
238  /* Test status */
239  if(cpl_error_get_code()) {
240  cpl_propertylist_delete(plist1);
241  cpl_propertylist_delete(plist2);
242  return -1;
243  }
244 
245  /* Compare exposure time */
246  comparison = 1;
247  dval1 = irplib_pfits_get_exptime(plist1);
248  dval2 = irplib_pfits_get_exptime(plist2);
249  if(cpl_error_get_code()) {
250  cpl_msg_error(cpl_func, "cannot get exposure time");
251  cpl_propertylist_delete(plist1);
252  cpl_propertylist_delete(plist2);
253  return -1;
254  }
255  if(fabs(dval1 - dval2) > 1e-3)
256  comparison = 0;
257 
258  /* Free and return */
259  cpl_propertylist_delete(plist1);
260  cpl_propertylist_delete(plist2);
261  return comparison;
262 }
263 
264 /* End of duplicated code */
265 
266 
267 /*---------------------------------------------------------------------------*/
268 /*
269  * @brief dark recipe
270  * @param frameset input frameset
271  * @param parlist input parameter list
272  * @param tag input recipe frame tag
273  * @param recipe_name input recipe name
274  * @param pipeline_name input pipeline name
275  * @param procatg_master input procatg of master product
276  * @param procatg_dsnu input procatg dsnu product
277  * @param procatg_tbl input procatg table
278  * @param package input package name
279  * @param compare function to make comparisons
280  * @return CPL_ERROR_NONE on success.
281  */
282 /*---------------------------------------------------------------------------*/
283 
284 
285 cpl_error_code
286 detmon_dark(cpl_frameset * frameset,
287  const cpl_parameterlist * parlist,
288  const char * tag,
289  const char * recipe_name,
290  const char * pipeline_name,
291  const char * procatg_master,
292  const char * procatg_dsnu,
293  const char * procatg_tbl,
294  const char * package,
295  int (*compare)(const cpl_frame *,
296  const cpl_frame *))
297 {
298  cpl_size nsets;
299  cpl_size *selection = NULL;
300  int i;
301  cpl_error_code error;
302 
303  if(detmon_dark_dfs_set_groups(frameset, tag)) {
304  cpl_msg_error(cpl_func, "Cannot identify RAW and CALIB frames");
305  }
306 
307  /*
308  * This function reads all inputs parameters from parlist
309  * and stores them in a global variable detmon_ronbias_config.
310  * Similar to detmon_lg_retrieve_parlist(). See detmon.c
311  */
312  error = detmon_retrieve_dark_params(pipeline_name,
313  recipe_name, parlist);
314  cpl_ensure_code(!error, error);
315 
316  /* Labelise all input frames */
317  if(compare == NULL)
318  nsets = 1;
319  else {
320  cpl_msg_info(cpl_func, "Identify the different settings");
321  selection = cpl_frameset_labelise(frameset, compare, &nsets);
322  if(selection == NULL)
323  cpl_msg_error(cpl_func, "Cannot labelise input frames");
324  }
325 
326  detmon_dark_config.nb_extensions = 1;
327  if(detmon_dark_config.exts < 0) {
328  const cpl_frame *cur_frame =
329  cpl_frameset_get_position_const(frameset, 0);
330  /* Get the nb of extensions */
331  detmon_dark_config.nb_extensions =
332  cpl_frame_get_nextensions(cur_frame);
333  }
334 
335  /* Extract settings and reduce each of them */
336  for(i = 0; i < nsets; i++) {
337  cpl_size *select_dits = NULL;
338  cpl_frameset *cur_fset =
339  nsets == 1 ? cpl_frameset_duplicate(frameset) :
340  cpl_frameset_extract(frameset, selection, i);
341 
342  cpl_size ndits = 0;
343  int j, k;
344  cpl_table ** dsnu_table = NULL;
345  cpl_imagelist ** dsnu = NULL;
346 
347  cpl_propertylist ** qclist =
348  (cpl_propertylist **)
349  cpl_malloc(detmon_dark_config.nb_extensions *
350  sizeof(cpl_propertylist *));
351 
352 
353  cpl_imagelist ** masters =
354  (cpl_imagelist **)
355  cpl_malloc(detmon_dark_config.nb_extensions *
356  sizeof(cpl_imagelist *));
357 
358  /* Initialise memory for products */
359  if(detmon_dark_config.opt_nir == OPT) {
360  dsnu_table =
361  (cpl_table **) cpl_malloc(detmon_dark_config.nb_extensions *
362  sizeof(cpl_table *));
363  dsnu =
364  (cpl_imagelist **)
365  cpl_malloc(detmon_dark_config.nb_extensions *
366  sizeof(cpl_imagelist *));
367  }
368 
369  select_dits = cpl_frameset_labelise(cur_fset,
370  detmon_compare_dits,
371  &ndits);
372 
373  if(detmon_dark_config.exts >= 0) {
374  *masters = cpl_imagelist_new();
375  if(detmon_dark_config.opt_nir == OPT) {
376  *dsnu = cpl_imagelist_new();
377  *dsnu_table = cpl_table_new(ndits);
378  }
379  *qclist = cpl_propertylist_new();
380  cpl_table_new_column(*dsnu_table, "DIT", CPL_TYPE_DOUBLE);
381  cpl_table_new_column(*dsnu_table, "STDEV", CPL_TYPE_DOUBLE);
382  } else {
383  for ( j = 0; j < detmon_dark_config.nb_extensions; j ++) {
384  masters[j] = cpl_imagelist_new();
385  if(detmon_dark_config.opt_nir == OPT) {
386  dsnu[j] = cpl_imagelist_new();
387  dsnu_table[j] = cpl_table_new(ndits);
388  }
389  qclist[j] = cpl_propertylist_new();
390  cpl_table_new_column(dsnu_table[j], "DIT", CPL_TYPE_DOUBLE);
391  cpl_table_new_column(dsnu_table[j], "STDEV", CPL_TYPE_DOUBLE);
392  }
393  }
394 
395  for(j = 0; j < ndits; j++) {
396  cpl_frameset * cur_fdit = cpl_frameset_extract(cur_fset,
397  select_dits, j);
398  cpl_imagelist ** raws =
399  (cpl_imagelist **)
400  cpl_malloc(detmon_dark_config.nb_extensions *
401  sizeof(cpl_imagelist *));
402 
403  if(detmon_dark_config.exts >= 0) {
404  cpl_image * collapsed;
405  *raws =
406  cpl_imagelist_load_frameset(cur_fdit, CPL_TYPE_FLOAT, 1,
407  detmon_dark_config.exts);
408  collapsed = cpl_imagelist_collapse_create(*raws);
409  cpl_imagelist_set(*masters, collapsed, j);
410  if(detmon_dark_config.opt_nir == OPT) {
411  detmon_dark_dsnu(cur_fdit, *dsnu, *dsnu_table,
412  collapsed, j);
413  }
414  detmon_dark_qc(*qclist, collapsed);
415  } else {
416  cpl_imagelist *raws_all_exts =
417  cpl_imagelist_load_frameset(cur_fdit, CPL_TYPE_FLOAT, 1,
418  -1);
419  for(k = 0; k < detmon_dark_config.nb_extensions; k++) {
420  int nframes = cpl_frameset_get_size(cur_fdit);
421  int h;
422  cpl_image * collapsed;
423  for(h = 0; h < nframes; h++) {
424  cpl_image *image =
425  cpl_imagelist_unset(raws_all_exts,
426  (detmon_dark_config.
427  nb_extensions - 1 - k) * h);
428  cpl_imagelist_set(raws[k], image, h);
429  }
430  collapsed = cpl_imagelist_collapse_create(raws[k]);
431  cpl_imagelist_set(masters[k],collapsed, j);
432  if(detmon_dark_config.opt_nir == OPT) {
433  detmon_dark_dsnu(cur_fdit, dsnu[k],
434  dsnu_table[j], collapsed, j);
435  }
436  detmon_dark_qc(qclist[k], collapsed);
437  }
438  }
439 
440  cpl_frameset_delete(cur_fdit);
441  for(k = 0; k < detmon_dark_config.nb_extensions; k++) {
442  cpl_imagelist_delete(raws[k]);
443  }
444  cpl_free(raws);
445  } /* end of loop (for) around different DIT values */
446 
447  cpl_frameset_delete(cur_fset);
448 
449  detmon_dark_save(parlist, frameset, recipe_name, pipeline_name,
450  procatg_master, procatg_tbl, procatg_dsnu,
451  package, masters, dsnu_table, dsnu, qclist,
452  0, 0, frameset);
453 
454  if(detmon_dark_config.opt_nir == OPT) {
455  for(j = 0; j < detmon_dark_config.nb_extensions; j++) {
456  cpl_table_delete(dsnu_table[j]);
457  cpl_imagelist_delete(dsnu[j]);
458  }
459  cpl_free(dsnu_table);
460  cpl_free(dsnu);
461  }
462 
463  for(j = 0; j < detmon_dark_config.nb_extensions; j++) {
464  cpl_propertylist_delete(qclist[j]);
465  cpl_imagelist_delete(masters[j]);
466  }
467  cpl_free(qclist);
468  cpl_free(masters);
469  cpl_free(select_dits);
470 
471  } /* end of loop (for) around different setting */
472 
473  cpl_free(selection);
474 
475  return cpl_error_get_code();
476 }
477 
478 
479 /*---------------------------------------------------------------------------*/
480 
481 /*
482  * @brief Classifies input frames
483  * @param set Input frameset
484  * @param tag Input frame tag
485 
486  * @return 0 on success, else -1
487  */
488 
489 /*---------------------------------------------------------------------------*/
490 int
491 detmon_dark_dfs_set_groups(cpl_frameset * set, const char *tag)
492 {
493 
494 
495 
496  /* Check entries */
497  if(set == NULL)
498  return -1;
499 
500  /* Initialize */
501  int nframes = cpl_frameset_get_size(set);
502 
503  /* Loop on frames */
504  for(int i = 0; i < nframes; i++) {
505  cpl_frame* cur_frame = cpl_frameset_get_position(set, i);
506  const char* cur_tag = cpl_frame_get_tag(cur_frame);
507 
508  /* RAW frames */
509  if(!strcmp(cur_tag, tag))
510  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_RAW);
511  /* CALIB frames */
512 
513  /* else if (!strcmp(tag, IIINSTRUMENT_CALIB_FLAT))
514  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_CALIB) ;
515  */
516  }
517  return 0;
518 }
519 
520 /*---------------------------------------------------------------------------*/
521 
522 /*
523  * @brief Retrieve input parameters
524  * @param pipeline_name Input pipeline name
525  * @param recipe_name Input recipe name
526  * @param parlist Input parameter list
527  * @return CPL_ERROR_NONE on success.
528  */
529 
530 /*---------------------------------------------------------------------------*/
531 static cpl_error_code
532 detmon_retrieve_dark_params(const char *pipeline_name,
533  const char *recipe_name,
534  const cpl_parameterlist * parlist)
535 {
536  char *par_name;
537  const cpl_parameter *par;
538 
539  /* --ron.method */
540  par_name = cpl_sprintf("%s.%s.ron.method", pipeline_name, recipe_name);
541  assert(par_name != NULL);
542  par = cpl_parameterlist_find_const(parlist, par_name);
543  detmon_dark_config.ron_method = cpl_parameter_get_string(par);
544  cpl_free(par_name);
545 
546  /* --dsnu.method */
547  par_name = cpl_sprintf("%s.%s.dsnu.method", pipeline_name, recipe_name);
548  assert(par_name != NULL);
549  par = cpl_parameterlist_find_const(parlist, par_name);
550  detmon_dark_config.dsnu_method = cpl_parameter_get_string(par);
551  cpl_free(par_name);
552 
553  /* --opt_nir */
554  par_name = cpl_sprintf("%s.%s.opt_nir", pipeline_name, recipe_name);
555  assert(par_name != NULL);
556  par = cpl_parameterlist_find_const(parlist, par_name);
557  detmon_dark_config.opt_nir = cpl_parameter_get_bool(par);
558  cpl_free(par_name);
559 
560  /* --exts */
561  detmon_dark_config.exts =
562  detmon_retrieve_par_int("exts", pipeline_name, recipe_name,
563  parlist);
564 
565  if(cpl_error_get_code()) {
566  cpl_msg_error(cpl_func, "Failed to retrieve the input parameters");
567  cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
568  }
569 
570 
571  return CPL_ERROR_NONE;
572 }
573 
574 
575 /*---------------------------------------------------------------------------*/
576 /*
577  * @brief Fill dark param structure with default values
578  * @param parlist input parameter list
579  * @param recipe_name recipe name
580  * @param pipeline_name pipeline name
581  * @param ron_method method to compute RON
582  * @param dsnu_metthod method to compute DSNU
583  * @param opt_nir opt/nir swich parameter
584  * @param exts extensions
585  *
586  * @return CPL_ERROR_NONE on success.
587  */
588 /*---------------------------------------------------------------------------*/
589  cpl_error_code
590 detmon_fill_dark_params(cpl_parameterlist * parlist,
591  const char *recipe_name,
592  const char *pipeline_name,
593  const char * ron_method,
594  const char * dsnu_method,
595  const char * opt_nir,
596  int exts)
597 {
598  detmon_fill_parlist(parlist, recipe_name, pipeline_name, 4,
599 
600  "ron.method",
601  "Method used to compute RON. Currently no "
602  "change is possible, RMS computed",
603  "CPL_TYPE_STRING", ron_method,
604 
605  "dsnu.method",
606  "Method used to compute DSNU map. Currently no "
607  "change is possible. Method used STDEV",
608  "CPL_TYPE_STRING", dsnu_method,
609 
610  "opt_nir",
611  "Boolean, OPT (FALSE) or NIR(TRUE)",
612  "CPL_TYPE_BOOL", opt_nir,
613 
614  "exts",
615  "Activate the multi-exts option. Default 0"
616  "(primary unit), -1 (all exts)",
617  "CPL_TYPE_INT", exts);
618 
619  return cpl_error_get_code();
620 }
621 
622 /*---------------------------------------------------------------------------*/
623 /*
624  * @brief Fill dark param structure with default values
625  * @param parlist input parameter list
626  * @param recipe_name recipe name
627  * @param pipeline_name pipeline name
628  *
629  * @return CPL_ERROR_NONE on success.
630  */
631 /*---------------------------------------------------------------------------*/
632 int
633 detmon_fill_dark_params_default(cpl_parameterlist * parlist,
634  const char *recipe_name,
635  const char *pipeline_name)
636 {
637  detmon_fill_dark_params(parlist, recipe_name, pipeline_name,
638  "SIMPLE", /* --ron.method */
639  "STDEV", /* --dsnu.method */
640  "CPL_FALSE", /* OPT*/
641  0); /* --exts */
642  return cpl_error_get_code();
643 }
644 
645 /*---------------------------------------------------------------------------*/
646 
647 /*
648  * @brief Computes DSNU
649  * @param cur_fdit Input frameset
650  * @param dsnu Input imagelist
651  * @param dsnu_table input dsnu table
652  * @param collapsed input collapsed image
653  * @param pos frame position in table
654  * @return CPL_ERROR_NONE on success.
655  */
656 
657 /*---------------------------------------------------------------------------*/
658 cpl_error_code
659 detmon_dark_dsnu(cpl_frameset * cur_fdit,
660  cpl_imagelist * dsnu,
661  cpl_table * dsnu_table,
662  cpl_image * collapsed,
663  int pos)
664 {
665  cpl_frame * first = cpl_frameset_get_position(cur_fdit, 0);
666  cpl_propertylist * plist =
667  cpl_propertylist_load(cpl_frame_get_filename(first), 0);
668  double dit = irplib_pfits_get_exptime(plist);
669  double mean = cpl_image_get_mean(collapsed);
670 
671  cpl_image * dsnu_map =
672  cpl_image_subtract_scalar_create(collapsed, mean);
673  double stdev;
674  cpl_image_divide_scalar(dsnu_map, mean);
675  stdev = cpl_image_get_stdev(dsnu_map);
676 
677  cpl_imagelist_set(dsnu, dsnu_map, pos);
678 
679  cpl_table_set(dsnu_table, "DIT", pos, dit);
680  cpl_table_set(dsnu_table, "STDEV", pos, stdev);
681 
682  cpl_propertylist_delete(plist);
683 
684  return cpl_error_get_code();
685 
686 }
687 
688 /*---------------------------------------------------------------------------*/
689 
690 /*
691  * @brief Save dark recipe products
692  * @param parlist input parameter list
693  * @param frameset input frameset
694  * @param recipe_name input recipe name
695  * @param pipeline_name input pipeline name
696  * @param procatg_master input procatg of master product
697  * @param procatg_tbl input procatg table
698  * @param procatg_dsnu input procatg dsnu product
699  * @param package input package name
700  * @param masters list of masters products
701  * @param dsnu_table dsnu table product
702  * @param dsnu list of dsnu images products
703  * @param qclist qc parameters
704  * @param flag_sets switch
705  * @param which_set specifier
706  * @param usedframes used frames
707  * @return CPL_ERROR_NONE on success.
708  */
709 
710 /*---------------------------------------------------------------------------*/
711 static cpl_error_code
712 detmon_dark_save(const cpl_parameterlist * parlist,
713  cpl_frameset * frameset,
714  const char *recipe_name,
715  const char *pipeline_name,
716  const char *procatg_master,
717  const char *procatg_tbl,
718  const char *procatg_dsnu,
719  const char *package,
720  cpl_imagelist ** masters,
721  cpl_table ** dsnu_table,
722  cpl_imagelist ** dsnu,
723  cpl_propertylist ** qclist,
724  const int flag_sets,
725  const int which_set,
726  const cpl_frameset * usedframes)
727 {
728 
729  cpl_frame *ref_frame;
730  cpl_propertylist *plist;
731  char *name_o = NULL; /* Avoid (false) uninit warning */
732  int i, j;
733  cpl_propertylist *paflist;
734  cpl_error_code error;
735  int nb_images;
736 
737  /***************************/
738  /* Write the MASTER FITS */
739  /***************************/
740 
741  nb_images = cpl_imagelist_get_size(masters[0]);
742  cpl_ensure_code(nb_images > 0, CPL_ERROR_DATA_NOT_FOUND);
743 
744 
745  for(i = 0; i < nb_images; i++) {
746  /* Set the file name for each image */
747  if(!flag_sets) {
748  name_o =
749  cpl_sprintf("%s_master_dit_%d.fits", recipe_name, i+1);
750  assert(name_o != NULL);
751  } else {
752  name_o =
753  cpl_sprintf("%s_master_dit_%d_set%02d.fits",
754  recipe_name, i, which_set);
755  assert(name_o != NULL);
756  }
757 
758 
759  /* Save the image */
760  if(detmon_dark_config.exts >= 0) {
761  cpl_propertylist * pro_master = cpl_propertylist_new();
762 
763  cpl_propertylist_append_string(pro_master,
764  CPL_DFS_PRO_CATG, procatg_master);
765 
766  cpl_propertylist_append(pro_master, qclist[0]);
767 
768  if(cpl_dfs_save_image
769  (frameset, NULL, parlist, usedframes, NULL,
770  cpl_imagelist_get(*masters, i), CPL_BPP_IEEE_FLOAT,
771  recipe_name, pro_master, NULL, package,
772  name_o)) {
773  cpl_msg_error(cpl_func, "Cannot save the product: %s",
774  name_o);
775  cpl_free(name_o);
776  cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
777 
778  }
779 
780  cpl_propertylist_delete(pro_master);
781  } else {
782  cpl_propertylist * pro_master = cpl_propertylist_new();
783 
784  cpl_propertylist_append_string(pro_master,
785  CPL_DFS_PRO_CATG, procatg_master);
786 
787  cpl_propertylist_append(pro_master, qclist[0]);
788 
789  if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL,
790  NULL, CPL_BPP_IEEE_FLOAT, recipe_name,
791  pro_master, NULL,
792  package, name_o)) {
793  cpl_msg_error(cpl_func, "Cannot save the product: %s",
794  name_o);
795  cpl_free(name_o);
796  cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
797  }
798 
799  cpl_propertylist_delete(pro_master);
800  for(j = 0; j < detmon_dark_config.nb_extensions; j++) {
801  error =
802  cpl_image_save(cpl_imagelist_get(masters[j], i),
803  name_o, CPL_BPP_IEEE_FLOAT, qclist[j],
804  CPL_IO_EXTEND);
805  cpl_ensure_code(!error, error);
806  }
807  }
808  cpl_free(name_o);
809  }
810 
811  if (detmon_dark_config.opt_nir == OPT) {
812  cpl_propertylist * pro_tbl = cpl_propertylist_new();
813 
814  cpl_propertylist_append_string(pro_tbl,
815  CPL_DFS_PRO_CATG, procatg_tbl);
816 
817  cpl_propertylist_append(pro_tbl, qclist[0]);
818  /*******************************/
819  /* Write the LINEARITY TABLE */
820  /*******************************/
821 
822  /* Set the file name for the table */
823  if(!flag_sets) {
824  name_o = cpl_sprintf("%s_dsnu_table.fits", recipe_name);
825  assert(name_o != NULL);
826  } else {
827  name_o =
828  cpl_sprintf("%s_dsnu_table_set%02d.fits", recipe_name,
829  which_set);
830  assert(name_o != NULL);
831  }
832  /* Save the table */
833  if(cpl_dfs_save_table(frameset, NULL, parlist, usedframes, NULL,
834  dsnu_table[0], NULL, recipe_name, pro_tbl, NULL,
835  package, name_o)) {
836  cpl_msg_error(cpl_func, "Cannot save the product: %s", name_o);
837  cpl_free(name_o);
838  cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
839  }
840 
841  cpl_propertylist_delete(pro_tbl);
842 
843  if(detmon_dark_config.exts < 0) {
844 
845  for(i = 1; i < detmon_dark_config.nb_extensions; i++) {
846  error =
847  cpl_table_save(dsnu_table[i], NULL, qclist[i], name_o,
848  CPL_IO_EXTEND);
849  cpl_ensure_code(!error, error);
850  }
851  }
852 
853  /* Free */
854  cpl_free(name_o);
855 
856  /***************************/
857  /* Write the DSNU_MAP FITS */
858  /***************************/
859 
860  for(i = 0; i < nb_images; i++) {
861  /* Set the file name for each image */
862  if(!flag_sets) {
863  name_o =
864  cpl_sprintf("%s_dsnu_map_dit_%d.fits", recipe_name, i+1);
865  assert(name_o != NULL);
866  } else {
867  name_o =
868  cpl_sprintf("%s_dsnu_map_dit_%d_set%02d.fits",
869  recipe_name, i, which_set);
870  assert(name_o != NULL);
871  }
872 
873 
874  /* Save the image */
875  if(detmon_dark_config.exts >= 0) {
876  cpl_propertylist * pro_dsnu = cpl_propertylist_new();
877 
878  cpl_propertylist_append_string(pro_dsnu,
879  CPL_DFS_PRO_CATG, procatg_dsnu);
880 
881  cpl_propertylist_append(pro_dsnu, qclist[0]);
882 
883  if(cpl_dfs_save_image
884  (frameset, NULL, parlist, usedframes, NULL,
885  cpl_imagelist_get(*dsnu, i), CPL_BPP_IEEE_FLOAT,
886  recipe_name, pro_dsnu, NULL, package,
887  name_o)) {
888  cpl_msg_error(cpl_func, "Cannot save the product: %s",
889  name_o);
890  cpl_free(name_o);
891  cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
892 
893  }
894 
895  cpl_propertylist_delete(pro_dsnu);
896  } else {
897  cpl_propertylist * pro_dsnu = cpl_propertylist_new();
898 
899  cpl_propertylist_append_string(pro_dsnu,
900  CPL_DFS_PRO_CATG, procatg_dsnu);
901 
902  cpl_propertylist_append(pro_dsnu, qclist[0]);
903 
904  if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
905  NULL, NULL,
906  CPL_BPP_IEEE_FLOAT, recipe_name,
907  pro_dsnu, NULL,
908  package, name_o)) {
909  cpl_msg_error(cpl_func, "Cannot save the product: %s",
910  name_o);
911  cpl_free(name_o);
912  cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
913  }
914 
915  cpl_propertylist_delete(pro_dsnu);
916  for(j = 0; j < detmon_dark_config.nb_extensions; j++) {
917  error =
918  cpl_image_save(cpl_imagelist_get(dsnu[j], i),
919  name_o, CPL_BPP_IEEE_FLOAT, qclist[j],
920  CPL_IO_EXTEND);
921  cpl_ensure_code(!error, error);
922  }
923  }
924  cpl_free(name_o);
925  }
926 
927 
928 
929  } /* End of if(OPT) */
930 
931  /*******************************/
932  /* Write the PAF file(s) */
933  /*******************************/
934 
935  /* Get FITS header from reference file */
936  ref_frame = cpl_frameset_get_position(frameset, 0);
937  if((plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
938  0)) == NULL) {
939  cpl_msg_error(cpl_func, "getting header from reference frame");
940  cpl_ensure_code(0, cpl_error_get_code());
941  }
942 
943  /* Get the keywords for the paf file */
944  paflist = cpl_propertylist_new();
945  cpl_propertylist_copy_property_regexp(paflist, plist,
946  "^(ARCFILE|MJD-OBS|ESO TPL ID|"
947  "DATE-OBS|ESO DET DIT|ESO DET NDIT|"
948  "ESO DET NCORRS|"
949  "ESO DET MODE NAME)$", 0);
950 
951  for(i = 0; i < detmon_dark_config.nb_extensions; i++) {
952  cpl_propertylist * c_paflist = cpl_propertylist_duplicate(paflist);
953  error = cpl_propertylist_append(c_paflist, qclist[i]);
954  cpl_ensure_code(!error, error);
955 
956  /* Set the file name for the bpm */
957  if(detmon_dark_config.exts >= 0) {
958  if(!flag_sets) {
959  name_o = cpl_sprintf("%s.paf", recipe_name);
960  assert(name_o != NULL);
961  } else {
962  name_o = cpl_sprintf("%s_set%02d.paf", recipe_name, which_set);
963  assert(name_o != NULL);
964  }
965  } else {
966  if(!flag_sets) {
967  name_o = cpl_sprintf("%s_ext%02d.paf", recipe_name, i+1);
968  assert(name_o != NULL);
969  } else {
970  name_o = cpl_sprintf("%s_set%02d_ext%02d.paf", recipe_name, which_set, i+1);
971  assert(name_o != NULL);
972  }
973  }
974  /* Save the PAF */
975  if(cpl_dfs_save_paf(pipeline_name, recipe_name, c_paflist, name_o)) {
976  cpl_msg_error(cpl_func, "Cannot save the product: %s", name_o);
977  cpl_free(name_o);
978  cpl_propertylist_delete(paflist);
979  cpl_propertylist_delete(plist);
980  cpl_free(name_o);
981  cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
982  }
983  cpl_propertylist_delete(c_paflist);
984  cpl_free(name_o);
985  }
986 
987  cpl_propertylist_delete(plist);
988  cpl_propertylist_delete(paflist);
989 
990  return cpl_error_get_code();
991 }
992 /*---------------------------------------------------------------------------*/
999 /*---------------------------------------------------------------------------*/
1000 cpl_error_code
1001 detmon_dark_qc(cpl_propertylist * qclist,
1002  cpl_image * collapsed)
1003 {
1004  double mean = cpl_image_get_mean(collapsed);
1005  double stdev = cpl_image_get_stdev(collapsed);
1006 
1007 
1008  cpl_propertylist_append_double(qclist,DETMON_QC_DARK, mean);
1009  cpl_propertylist_set_comment(qclist,DETMON_QC_DARK,
1010  DETMON_QC_DARK_C);
1011 
1012  cpl_propertylist_append_double(qclist,DETMON_QC_DARK_STDEV, stdev);
1013  cpl_propertylist_set_comment(qclist,DETMON_QC_DARK_STDEV,
1014  DETMON_QC_DARK_STDEV_C);
1015  detmon_print_rec_status();
1016 
1017  return cpl_error_get_code();
1018 }
1019 
1020