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