DETMON Pipeline Reference Manual  1.2.7
detmon.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 
45 #include "detmon.h"
46 
47 #include "irplib_ksigma_clip.h"
48 #include "irplib_hist.h"
49 #include "irplib_utils.h"
50 
51 
52 /* Computes the square of an euclidean distance bet. 2 points */
53 #define pdist(x1,y1,x2,y2) (((x1-x2)*(x1-x2))+((y1-y2)*(y1-y2)))
54 
55 #define cpl_drand() ((double)rand()/(double)RAND_MAX)
56 
57 /*--------------------------------------------------------------------------*/
58 
59 /*
60  * @defgroup detmon Detector monitoring functions
61  */
62 
63 /*--------------------------------------------------------------------------*/
64 
65 /*---------------------------------------------------------------------------
66  Defines
67  ---------------------------------------------------------------------------*/
68 
69 
70 #define HIST_FACT 2.354820045
71 
72 enum pixeltypes
73 {
74  HOT = 0,
75  DEAD = 1,
76  NOISY = 2
77 };
78 
79 enum stackingtypes
80 {
81  MINMAX = 0,
82  MEAN = 1,
83  MEDIAN = 2,
84  KSIGMA = 3
85 };
86 
87 enum readouts
88 {
89  HORIZONTAL = 1,
90  VERTICAL = 2
91 };
92 
93 
94 static struct
95 {
96  /* Inputs */
97  const char *method;
98  const char *pmethod;
99  irplib_ronbias_method method_bitmask;
100  int prescan_llx;
101  int prescan_lly;
102  int prescan_urx;
103  int prescan_ury;
104  int overscan_llx;
105  int overscan_lly;
106  int overscan_urx;
107  int overscan_ury;
108  cpl_size preoverscan_degree;
109  int random_nsamples;
110  int random_sizex;
111  int random_sizey;
112  int criteria;
113  int ref_llx;
114  int ref_lly;
115  int ref_urx;
116  int ref_ury;
117  const char *stacking_method;
118  int stacking_ks_low;
119  int stacking_ks_high;
120  int stacking_ks_iter;
121  int master_shift_x;
122  int master_shift_y;
123  int ron_llx;
124  int ron_lly;
125  int ron_urx;
126  int ron_ury;
127  int exts;
128  int nb_extensions;
129 } detmon_ronbias_config;
130 
131 static struct
132 {
133  int mode;
134  cpl_boolean direction;
135  double speed;
136  int llx;
137  int lly;
138  int urx;
139  int ury;
140  int kappa;
141  int exts;
142  int nb_extensions;
143 } detmon_pernoise_config;
144 
145 static struct
146 {
147  const char * ron_method;
148  const char * dsnu_method;
149  int exts;
150  int nb_extensions;
151  cpl_boolean opt_nir;
152 } detmon_dark_config;
153 
154 #define NIR TRUE
155 #define OPT FALSE
156 
157 /*---------------------------------------------------------------------------
158  Private function prototypes
159  ---------------------------------------------------------------------------*/
160 
161 /* Functions for RON/Bias recipe, detmon_ronbias() */
162 
163 static cpl_error_code
164 detmon_ronbias_retrieve_parlist(const char *,
165  const char *,
166  const cpl_parameterlist *,
167  cpl_boolean);
168 
169 static cpl_error_code
170 detmon_ronbias_random(const cpl_imagelist *,
171  const cpl_image *, cpl_propertylist *);
172 
173 static cpl_error_code
174 detmon_ronbias_histo(const cpl_imagelist *,
175  const cpl_image *, cpl_propertylist *);
176 
177 static cpl_error_code
178 detmon_ronbias_preoverscan(const cpl_imagelist *, /*const cpl_image *,*/
179  cpl_propertylist *, cpl_image **);
180 
181 static cpl_error_code
182 detmon_ronbias_region(const cpl_imagelist *,
183  const cpl_image *, cpl_propertylist *);
184 
185 static cpl_image *
186 detmon_ronbias_master(const cpl_imagelist *,
187  cpl_mask **, cpl_mask **, cpl_mask **,
188  cpl_propertylist *);
189 
190 static cpl_error_code
191 detmon_ronbias_save(const cpl_parameterlist *,
192  cpl_frameset *,
193  const char *,
194  const char *,
195  const char *,
196  const cpl_propertylist *,
197  const cpl_propertylist *,
198  const cpl_propertylist *,
199  const cpl_propertylist *,
200  const cpl_propertylist *,
201  const cpl_propertylist *,
202  const cpl_propertylist *,
203  const char *,
204  const cpl_image *,
205  const cpl_image *,
206  const cpl_mask *,
207  const cpl_mask *,
208  const cpl_mask *,
209  cpl_propertylist *,
210  const int,
211  const int,
212  cpl_frameset *,
213  int);
214 
215 int
216 detmon_ronbias_dfs_set_groups(cpl_frameset *, const char *);
217 
218 
219 static cpl_error_code
220 detmon_ronbias_dutycycl(const cpl_frameset *, cpl_propertylist *);
221 
222 cpl_error_code
223 detmon_rm_bpixs(cpl_image **,
224  const double,
225  int ,
226  int );
227 
228 /* The following 2 functions are duplicated from cpl_det */
229 
230 
231 
232 static cpl_bivector *
233 irplib_bivector_gen_rect_poisson(const int *r,
234  const int np,
235  const int homog);
236 
237 /* End of duplicated code */
238 
239 
240 cpl_error_code
241 detmon_ronbias_check_defaults(const cpl_frameset *, const int whichext);
242 
243 
244 /* Functions for Periodic Noise Characterisation, detmon_pernoise() */
245 
246 int
247 detmon_pernoise_dfs_set_groups(cpl_frameset *,
248  const char *);
249 
250 static cpl_error_code
251 detmon_pernoise_retrieve_parlist(const char *,
252  const char *,
253  const cpl_parameterlist *);
254 
255 static cpl_error_code
256 detmon_pernoise_qc(cpl_propertylist *,
257  cpl_table *,
258  int);
259 
260 static cpl_error_code
261 detmon_pernoise_save(const cpl_parameterlist *,
262  cpl_frameset *,
263  const char *,
264  const char *,
265  const char *,
266  const char *,
267  cpl_table **,
268  cpl_propertylist **,
269  const int,
270  const int,
271  const cpl_frameset *);
272 
273 cpl_error_code
274 detmon_pernoise_rm_bg(cpl_image *,
275  int,
276  int);
277 
278 int
279 detmon_dark_dfs_set_groups(cpl_frameset *,
280  const char *);
281 
282 cpl_error_code
283 detmon_dark_dsnu(cpl_frameset *,
284  cpl_imagelist *,
285  cpl_table *,
286  cpl_image *,
287  int pos);
288 
289 
290 static cpl_error_code
291 detmon_dark_save(const cpl_parameterlist *,
292  cpl_frameset *,
293  const char *,
294  const char *,
295  const char *,
296  const char *,
297  const char *,
298  const char *,
299  cpl_imagelist **,
300  cpl_table **,
301  cpl_imagelist **,
302  cpl_propertylist **,
303  const int,
304  const int,
305  const cpl_frameset *);
306 
307 
308 
309 static cpl_error_code
310 detmon_retrieve_dark_params(const char *,
311  const char *,
312  const cpl_parameterlist *);
313 
314 cpl_error_code
315 detmon_dark_qc(cpl_propertylist *,
316  cpl_image *);
317 
318 
319 
320 /* RONBIAS FILLING PARLIST */
321 
322 
323 
324 /*---------------------------------------------------------------------------*/
325 
326 /*
327  * @brief Fill input parameters with default values
328  * @param parlist parameters list
329  * @param recipe_name recipe name
330  * @param pipeline_name pipeline name
331 
332  * @return CPL_ERROR_NONE on success.
333  */
334 
335 /*---------------------------------------------------------------------------*/
336 
337 cpl_error_code
338 detmon_ronbias_fill_parlist_default(cpl_parameterlist * parlist,
339  const char *recipe_name,
340  const char *pipeline_name)
341 {
342  const cpl_error_code error =
343  detmon_ronbias_fill_parlist(parlist, recipe_name, pipeline_name,
344  "ALL", /* --method */
345  "NORM",/* --pmethod */
346  1, /* --preoverscan_degree */
347  -1, /* --random_nsamples */
348  -1, /* --random_sizex */
349  -1, /* --random_sizey */
350  0, /* --criteria */
351  -1, /* --ref_llx */
352  -1, /* --ref_lly */
353  -1, /* --ref_urx */
354  -1, /* --ref_ury */
355  "MEAN",/* --stacking_method */
356  3, /* --stacking_ks_low */
357  3, /* --stacking_ks_high */
358  5, /* --stacking_ks_iter */
359  0, /* --master_shift_x */
360  0, /* --master_shift_y */
361  -1, /* --ron_llx */
362  -1, /* --ron_lly */
363  -1, /* --ron_urx */
364  -1, /* --ron_ury */
365  0, /* --exts */
366  OPT);
367  cpl_ensure_code(!error, error);
368 
369  return cpl_error_get_code();
370 }
371 
372 
373 
374 /*---------------------------------------------------------------------------*/
375 
376 /*
377  * @brief Fill input parameters with default values
378  * @param parlist parameters list
379  * @param recipe_name recipe name
380  * @param pipeline_name pipeline name
381 
382  * @return CPL_ERROR_NONE on success.
383  */
384 
385 /*---------------------------------------------------------------------------*/
386 
387  cpl_error_code
388 detmon_darkron_fill_parlist_default(cpl_parameterlist * parlist,
389  const char *recipe_name,
390  const char *pipeline_name)
391 {
392  const cpl_error_code error =
393  detmon_ronbias_fill_parlist(parlist, recipe_name, pipeline_name,
394  "ALL", /* --method */
395  "NORM",/* --pmethod */
396  1, /* --preoverscan_degree */
397  -1, /* --random_nsamples */
398  -1, /* --random_sizex */
399  -1, /* --random_sizey */
400  0, /* --criteria */
401  -1, /* --ref_llx */
402  -1, /* --ref_lly */
403  -1, /* --ref_urx */
404  -1, /* --ref_ury */
405  "MEAN",/* --stacking_method */
406  3, /* --stacking_ks_low */
407  3, /* --stacking_ks_high */
408  5, /* --stacking_ks_iter */
409  0, /* --master_shift_x */
410  0, /* --master_shift_y */
411  -1, /* --ron_llx */
412  -1, /* --ron_lly */
413  -1, /* --ron_urx */
414  -1, /* --ron_ury */
415  0, /* --exts */
416  NIR);
417  cpl_ensure_code(!error, error);
418 
419  return cpl_error_get_code();
420 }
421 
422 
423 
424 /*---------------------------------------------------------------------------*/
425 
426 /*
427  * @brief Fill input parameters with default values
428  * @param parlist parameters list
429  * @param recipe_name recipe name
430  * @param pipeline_name pipeline name
431  * @param method adopted method
432  * @param pmethod adopted pre-method
433  * @param preoverscan_degree degree used ti fit pre-overscan regions
434  * @param random_nsamples number of samples used for random computation
435  * @param random_sizex x size of rectangle area for random computation
436  * @param random_sizey x size of rectangle area for random computation
437  * @param criteria
438  * @param ref_llx reference region lower left x
439  * @param ref_lly reference region lower left y
440  * @param ref_urx reference region upper right x
441  * @param ref_ury reference region upper right y
442  * @param stacking_method frame stacking method
443  * @param stacking_ks_low kappa value to kappa sigma low intensity pixels
444  * @param stacking_ks_high kappa value to kappa sigma high intensity pixels
445  * @param stacking_ks_iter kappa value to kappa sigma number of iterations
446  * @param master_shift_x x shift value applied to master
447  * @param master_shift_y y shift value applied to master
448  * @param ron_llx reference region lower left x to compute RON
449  * @param ron_lly reference region lower left y to compute RON
450  * @param ron_urx reference region upper right x to compute RON
451  * @param ron_ury reference region upper right y to compute RON
452  * @param exts image extension to be reduced
453  * @param opt_nir switch to specify if in input are OPT or NIR data
454 
455  * @return CPL_ERROR_NONE on success.
456  */
457 
458 /*---------------------------------------------------------------------------*/
459 
460 cpl_error_code
461 detmon_ronbias_fill_parlist(cpl_parameterlist * parlist,
462  const char *recipe_name,
463  const char *pipeline_name,
464  const char * method,
465  const char * pmethod,
466  const int preoverscan_degree,
467  const int random_nsamples,
468  const int random_sizex,
469  const int random_sizey,
470  const int criteria,
471  const int ref_llx,
472  const int ref_lly,
473  const int ref_urx,
474  const int ref_ury,
475  const char * stacking_method,
476  const int stacking_ks_low,
477  const int stacking_ks_high,
478  const int stacking_ks_iter,
479  const int master_shift_x,
480  const int master_shift_y,
481  const int ron_llx,
482  const int ron_lly,
483  const int ron_urx,
484  const int ron_ury,
485  const int exts,
486  cpl_boolean opt_nir)
487 {
488 
489  const char * meth_desc_opt =
490  "Method to be used when computing bias. Methods appliable: "
491  "<RANDOM | HISTO | PREOVERSCAN | REGION | ALL>. By default ALL "
492  "methods are applied. More than a method can be chosen; in that "
493  "case selected methods must be separated by a single space and put "
494  "together between inverted commas (ex. --method=\"HISTO REGION\")."
495  "\n RANDOM: Bias is computed as the mean value on a given number "
496  "(--random.nsamples) of boxes (dimensions --random.sizex and "
497  "--random.sizey) randomly taken accross the detector.\n HISTO: "
498  "An histogram of the pixels of the image is built.\n PREOVERSCAN: "
499  "Mean, median and RMS values computed and designated areas. \n "
500  "REGION: Mean, median and RMS values on reference region.";
501 
502  const char * meth_desc_nir =
503  "Method to be used when computing bias. Methods appliable: "
504  "<RANDOM | HISTO | REGION | ALL>. By default ALL "
505  "methods are applied. More than a method can be chosen; in that "
506  "case selected methods must be separated by a single space and put "
507  "together between inverted commas (ex. --method=\"HISTO REGION\")."
508  "\n RANDOM: Bias is computed as the mean value on a given number "
509  "(--random.nsamples) of boxes (dimensions --random.sizex and "
510  "--random.sizey) randomly taken accross the detector.\n HISTO: "
511  "An histogram of the pixels of the image is built.\n "
512  "REGION: Mean, median and RMS values on reference region.";
513 
514  const char * method_desc = opt_nir == OPT ? meth_desc_opt : meth_desc_nir;
515 
516  const cpl_error_code error =
517  detmon_fill_parlist(parlist, recipe_name, pipeline_name, 22,
518  "method",
519  method_desc,
520  "CPL_TYPE_STRING", method,
521 
522  "pmethod",
523  "Pre-method for RANDOM, HISTO and REGION."
524  "Difference raw frames or not",
525  "CPL_TYPE_STRING", pmethod,
526 
527  "preoverscan.degree",
528  "Degree used for pre-overscan method",
529  "CPL_TYPE_INT", preoverscan_degree,
530 
531  "random.nsamples",
532  "Number of samples",
533  "CPL_TYPE_INT", random_nsamples,
534 
535  "random.sizex",
536  "X size of the boxes",
537  "CPL_TYPE_INT", random_sizex,
538 
539  "random.sizey",
540  "Y size of the boxes",
541  "CPL_TYPE_INT", random_sizey,
542 
543  "criteria",
544  "Criteria",
545  "CPL_TYPE_INT", criteria,
546 
547  "ref.llx",
548  "x coordinate of the lower-left point "
549  "of the reference region of the frame",
550  "CPL_TYPE_INT", ref_llx,
551 
552  "ref.lly",
553  "y coordinate of the lower-left point "
554  "of the reference region of the frame",
555  "CPL_TYPE_INT", ref_lly,
556 
557  "ref.urx",
558  "x coordinate of the upper-right point "
559  "of the reference region of the frame",
560  "CPL_TYPE_INT", ref_urx,
561 
562  "ref.ury",
563  "y coordinate of the upper-right point "
564  "of the reference region of the frame",
565  "CPL_TYPE_INT", ref_ury,
566 
567  "stacking.method",
568  "Method to be used when stacking the master. Posible values < MINMAX | MEAN | MEDIAN | KSIGMA >",
569  "CPL_TYPE_STRING", stacking_method,
570 
571  "stacking.ks.low",
572  "Low threshold for kappa-sigma clipping",
573  "CPL_TYPE_INT", stacking_ks_low,
574 
575  "stacking.ks.high",
576  "High threshold for kappa-sigma clipping",
577  "CPL_TYPE_INT", stacking_ks_high,
578 
579  "stacking.ks.iter",
580  "Nb of iterations for kappa-sigma clipping",
581  "CPL_TYPE_INT", stacking_ks_iter,
582 
583  "master.shift.x",
584  "Master shift X",
585  "CPL_TYPE_INT", master_shift_x,
586 
587  "master.shift.y",
588  "Master shift Y",
589  "CPL_TYPE_INT", master_shift_y,
590 
591  "ron.llx",
592  "x coordinate of the lower-left point "
593  "of the RON frame",
594  "CPL_TYPE_INT", ron_llx,
595 
596  "ron.lly",
597  "y coordinate of the lower-left point "
598  "of the RON frame",
599  "CPL_TYPE_INT", ron_lly,
600 
601  "ron.urx",
602  "x coordinate of the upper-right point "
603  "of the RON frame",
604  "CPL_TYPE_INT", ron_urx,
605 
606  "ron.ury",
607  "y coordinate of the upper-right point "
608  "of the RON frame", "CPL_TYPE_INT", ron_ury,
609 
610  "exts",
611  "Activate the multi-exts option",
612  "CPL_TYPE_INT", exts);
613 
614 
615  cpl_ensure_code(!error, error);
616 
617  return cpl_error_get_code();
618 }
619 
620 
621 
622 
623 /*---------------------------------------------------------------------------*/
624 
625 /*
626  * @brief Fill input parameters values
627  * @param parlist parameters list
628  * @param recipe_name recipe name
629  * @param pipeline_name pipeline name
630  * @param npars number of parameters
631 
632  * @return CPL_ERROR_NONE on success.
633  */
634 
635 /*---------------------------------------------------------------------------*/
636 cpl_error_code
637 detmon_fill_parlist(cpl_parameterlist * parlist,
638  const char *recipe_name,
639  const char *pipeline_name,
640  int npars, ...)
641 {
642 
643  va_list ap;
644 
645  char *group_name;
646 
647  int pars_counter = 0;
648 
649  group_name = cpl_sprintf("%s.%s", pipeline_name, recipe_name);
650  assert(group_name != NULL);
651 
652 #define insert_par(PARNAME, PARDESC, PARVALUE, PARTYPE) \
653  do { \
654  char * par_name = cpl_sprintf("%s.%s", group_name, PARNAME); \
655  cpl_parameter * p; \
656  assert(par_name != NULL); \
657  p = cpl_parameter_new_value(par_name, PARTYPE, \
658  PARDESC, group_name, PARVALUE); \
659  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, PARNAME); \
660  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); \
661  cpl_parameterlist_append(parlist, p); \
662  cpl_free(par_name); \
663  } while(0);
664 
665 
666  va_start(ap, npars);
667 
668  while(pars_counter < npars) {
669  char *name = va_arg(ap, char *);
670  char *desc = va_arg(ap, char *);
671  char *type = va_arg(ap, char *);
672 
673  if(!strcmp(type, "CPL_TYPE_INT")) {
674  int v1 = va_arg(ap, int);
675 
676  insert_par(name, desc, v1, CPL_TYPE_INT);
677  } else if(!strcmp(type, "CPL_TYPE_BOOL")) {
678  char *v2 = va_arg(ap, char *);
679 
680  if(!strcmp(v2, "CPL_FALSE"))
681  insert_par(name, desc, CPL_FALSE, CPL_TYPE_BOOL);
682  if(!strcmp(v2, "CPL_TRUE"))
683  insert_par(name, desc, CPL_TRUE, CPL_TYPE_BOOL);
684  } else if(!strcmp(type, "CPL_TYPE_STRING")) {
685  char *v2 = va_arg(ap, char *);
686 
687  insert_par(name, desc, v2, CPL_TYPE_STRING);
688  } else if(!strcmp(type, "CPL_TYPE_DOUBLE")) {
689  double v3 = va_arg(ap, double);
690  insert_par(name, desc, v3, CPL_TYPE_DOUBLE);
691  }
692 
693  pars_counter++;
694  }
695 
696  va_end(ap);
697 
698  cpl_free(group_name);
699 
700 #undef insert_par
701  return 0;
702 }
703 
704 /*---------------------------------------------------------------------------*/
705 
706 /*
707  * @brief Retrieve input parameters
708  * @param pipeline_name Input image
709  * @param recipe_name Input image
710  * @param parlist Shift to apply on the x-axis
711  * @return CPL_ERROR_NONE on success.
712  */
713 
714 /*---------------------------------------------------------------------------*/
715 int
716 detmon_retrieve_par_int(const char *parn,
717  const char *pipeline_name,
718  const char *recipe_name,
719  const cpl_parameterlist * parlist)
720 {
721  char *par_name;
722  cpl_parameter *par;
723  int value;
724 
725  par_name = cpl_sprintf("%s.%s.%s", pipeline_name, recipe_name, parn);
726  assert(par_name != NULL);
727  par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
728  value = cpl_parameter_get_int(par);
729  cpl_free(par_name);
730 
731  return value;
732 }
733 
734 /*---------------------------------------------------------------------------*/
735 
736 /*
737  * @brief Retrieve input parameters
738  * @param pipeline_name Input image
739  * @param recipe_name Input image
740  * @param parlist Shift to apply on the x-axis
741  * @return CPL_ERROR_NONE on success.
742  */
743 
744 /*---------------------------------------------------------------------------*/
745 double
746 detmon_retrieve_par_double(const char *parn,
747  const char *pipeline_name,
748  const char *recipe_name,
749  const cpl_parameterlist * parlist)
750 {
751  char *par_name;
752  cpl_parameter *par;
753  double value;
754 
755  par_name = cpl_sprintf("%s.%s.%s", pipeline_name, recipe_name, parn);
756  assert(par_name != NULL);
757  par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
758  value = cpl_parameter_get_double(par);
759  cpl_free(par_name);
760 
761  return value;
762 }
763 
764 /*--------------------------------------------------------------------------*/
765 
766 /*
767  * @brief Comparison function to identify different settings
768  * @param frame1 First frame
769  * @param frame2 Second frame
770  * @return 0 if different, 1 if equal, -1 in error case
771  */
772 
773 /*--------------------------------------------------------------------------*/
774 
775 int
776 detmon_compare_dits(const cpl_frame * frame1, const cpl_frame * frame2)
777 {
778  int comparison;
779  cpl_propertylist *plist1;
780  cpl_propertylist *plist2;
781  double dval1, dval2;
782 
783  /* Test entries */
784  if(frame1 == NULL || frame2 == NULL)
785  return -1;
786 
787  /* Get property lists */
788  if((plist1 = cpl_propertylist_load(cpl_frame_get_filename(frame1),
789  0)) == NULL) {
790  cpl_msg_error(cpl_func, "getting header from reference frame");
791  return -1;
792  }
793  if((plist2 = cpl_propertylist_load(cpl_frame_get_filename(frame2),
794  0)) == NULL) {
795  cpl_msg_error(cpl_func, "getting header from reference frame");
796  cpl_propertylist_delete(plist1);
797  return -1;
798  }
799 
800  /* Test status */
801  if(cpl_error_get_code()) {
802  cpl_propertylist_delete(plist1);
803  cpl_propertylist_delete(plist2);
804  return -1;
805  }
806 
807  /* Compare exposure time */
808  comparison = 1;
809  dval1 = irplib_pfits_get_exptime(plist1);
810  dval2 = irplib_pfits_get_exptime(plist2);
811  if(cpl_error_get_code()) {
812  cpl_msg_error(cpl_func, "cannot get exposure time");
813  cpl_propertylist_delete(plist1);
814  cpl_propertylist_delete(plist2);
815  return -1;
816  }
817  if(fabs(dval1 - dval2) > 1e-3)
818  comparison = 0;
819 
820  /* Free and return */
821  cpl_propertylist_delete(plist1);
822  cpl_propertylist_delete(plist2);
823  return comparison;
824 }
825 
826 /*---------------------------------------------------------------------------*/
827 
828 /*
829  * @brief Retrieve exposure time
830  * @param plist parameter list
831  * @return "EXPTIME" keyword value.
832  */
833 
834 /*---------------------------------------------------------------------------*/
835 
836 double
837 irplib_pfits_get_exptime(const cpl_propertylist * plist)
838 {
839  double exptime;
840 
841  exptime = cpl_propertylist_get_double(plist, "EXPTIME");
842 
843  return exptime;
844 }
845 
846 /*---------------------------------------------------------------------------*/
847 
848 /*
849  * @brief Retrieve input parameters
850  * @param pipeline_name Input image
851  * @param recipe_name Input image
852  * @param parlist Shift to apply on the x-axis
853  * @param opt_nir switch to specify if in input are OPT or NIR data
854  * @return CPL_ERROR_NONE on success.
855  */
856 
857 /*---------------------------------------------------------------------------*/
858 static cpl_error_code
859 detmon_ronbias_retrieve_parlist(const char *pipeline_name,
860  const char *recipe_name,
861  const cpl_parameterlist * parlist,
862  cpl_boolean opt_nir)
863 {
864  char *par_name;
865  cpl_parameter *par;
866 
867  char m1[20] = "";
868  char m2[20] = "";
869  char m3[20] = "";
870 
871  /* --method */
872  par_name = cpl_sprintf("%s.%s.method", pipeline_name, recipe_name);
873  assert(par_name != NULL);
874  par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
875  detmon_ronbias_config.method = cpl_parameter_get_string(par);
876  cpl_free(par_name);
877 
878  detmon_ronbias_config.method_bitmask = 0;
879 
880  sscanf(detmon_ronbias_config.method, "%s %s %s", m1, m2, m3);
881 
882  if(!strcmp(m1, "RANDOM") || !strcmp(m2, "RANDOM")
883  || !strcmp(m3, "RANDOM"))
884  detmon_ronbias_config.method_bitmask += RANDOM;
885 
886  if(!strcmp(m1, "HISTO") || !strcmp(m2, "HISTO") || !strcmp(m3, "HISTO"))
887  detmon_ronbias_config.method_bitmask += HISTO;
888 
889  if(!strcmp(m1, "PREOVERSCAN") || !strcmp(m2, "PREOVERSCAN")
890  || !strcmp(m3, "PREOVERSCAN")) {
891  if (opt_nir == NIR) {
892  /* Just in case some advance user reads himself in the code and
893  tries to trick the interface providing an option no contained
894  in the man-page */
895  cpl_msg_warning(cpl_func, "PREOVERSCAN is not appliable for NIR");
896  } else {
897  detmon_ronbias_config.method_bitmask += PREOVERSCAN;
898  }
899  }
900  if(!strcmp(m1, "REGION") || !strcmp(m2, "REGION")
901  || !strcmp(m3, "REGION"))
902  detmon_ronbias_config.method_bitmask += REGION;
903 
904  if(!strcmp(m1, "ALL")) {
905  if (opt_nir == OPT) {
906  detmon_ronbias_config.method_bitmask =
907  RANDOM | HISTO | PREOVERSCAN | REGION;
908  } else {
909  detmon_ronbias_config.method_bitmask =
910  RANDOM | HISTO | REGION;
911  }
912  }
913 
914  /* --pmethod */
915  par_name = cpl_sprintf("%s.%s.pmethod", pipeline_name, recipe_name);
916  assert(par_name != NULL);
917  par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
918  detmon_ronbias_config.pmethod = cpl_parameter_get_string(par);
919  cpl_free(par_name);
920 
921  /* --preoverscan.degree */
922  detmon_ronbias_config.preoverscan_degree =
923  detmon_retrieve_par_int("preoverscan.degree", pipeline_name,
924  recipe_name, parlist);
925 
926  /* --nsamples */
927  detmon_ronbias_config.random_nsamples =
928  detmon_retrieve_par_int("random.nsamples", pipeline_name,
929  recipe_name, parlist);
930 
931  /* --sizex */
932  detmon_ronbias_config.random_sizex =
933  detmon_retrieve_par_int("random.sizex", pipeline_name,
934  recipe_name, parlist);
935 
936  /* --sizey */
937  detmon_ronbias_config.random_sizey =
938  detmon_retrieve_par_int("random.sizey", pipeline_name,
939  recipe_name, parlist);
940 
941  /* --criteria */
942  detmon_ronbias_config.criteria =
943  detmon_retrieve_par_int("criteria", pipeline_name, recipe_name,
944  parlist);
945 
946  /* --ref.llx */
947  detmon_ronbias_config.ref_llx =
948  detmon_retrieve_par_int("ref.llx", pipeline_name, recipe_name,
949  parlist);
950  /* --ref.lly */
951  detmon_ronbias_config.ref_lly =
952  detmon_retrieve_par_int("ref.lly", pipeline_name, recipe_name,
953  parlist);
954  /* --ref.urx */
955  detmon_ronbias_config.ref_urx =
956  detmon_retrieve_par_int("ref.urx", pipeline_name, recipe_name,
957  parlist);
958  /* --ref.ury */
959  detmon_ronbias_config.ref_ury =
960  detmon_retrieve_par_int("ref.ury", pipeline_name, recipe_name,
961  parlist);
962 
963  /* --stacking.method */
964  par_name =
965  cpl_sprintf("%s.%s.stacking.method", pipeline_name, recipe_name);
966  assert(par_name != NULL);
967  par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
968  detmon_ronbias_config.stacking_method = cpl_parameter_get_string(par);
969  cpl_free(par_name);
970 
971  /* --stacking.ks.low */
972  detmon_ronbias_config.stacking_ks_low =
973  detmon_retrieve_par_int("stacking.ks.low", pipeline_name,
974  recipe_name, parlist);
975  /* --stacking.ks.high */
976  detmon_ronbias_config.stacking_ks_high =
977  detmon_retrieve_par_int("stacking.ks.high", pipeline_name,
978  recipe_name, parlist);
979  /* --stacking.ks.iter */
980  detmon_ronbias_config.stacking_ks_iter =
981  detmon_retrieve_par_int("stacking.ks.iter", pipeline_name,
982  recipe_name, parlist);
983  /* --master.shift.x */
984  detmon_ronbias_config.master_shift_x =
985  detmon_retrieve_par_int("master.shift.x", pipeline_name,
986  recipe_name, parlist);
987  /* --master.shift.y */
988  detmon_ronbias_config.master_shift_y =
989  detmon_retrieve_par_int("master.shift.y", pipeline_name,
990  recipe_name, parlist);
991  /* --ron.llx */
992  detmon_ronbias_config.ron_llx =
993  detmon_retrieve_par_int("ron.llx", pipeline_name, recipe_name,
994  parlist);
995  /* --ron.lly */
996  detmon_ronbias_config.ron_lly =
997  detmon_retrieve_par_int("ron.lly", pipeline_name, recipe_name,
998  parlist);
999  /* --ron.urx */
1000  detmon_ronbias_config.ron_urx =
1001  detmon_retrieve_par_int("ron.urx", pipeline_name, recipe_name,
1002  parlist);
1003  /* --ron.ury */
1004  detmon_ronbias_config.ron_ury =
1005  detmon_retrieve_par_int("ron.ury", pipeline_name, recipe_name,
1006  parlist);
1007  /* --exts */
1008  detmon_ronbias_config.exts =
1009  detmon_retrieve_par_int("exts", pipeline_name, recipe_name,
1010  parlist);
1011 
1012  if(cpl_error_get_code()) {
1013  cpl_msg_error(cpl_func, "Failed to retrieve the input parameters");
1014  cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
1015  }
1016 
1017 
1018  return CPL_ERROR_NONE;
1019 }
1020 
1021 /*---------------------------------------------------------------------------*/
1022 
1023 /*
1024  * @brief Check parameter defauls
1025  * @param set Input set of frames
1026  * @param whichext extension to be reduced
1027  * @return CPL_ERROR_NONE on success.
1028  */
1029 
1030 /*---------------------------------------------------------------------------*/
1031 cpl_error_code
1032 detmon_ronbias_check_defaults(const cpl_frameset * set,
1033  const int whichext)
1034 {
1035  const cpl_frame * fr = cpl_frameset_get_first_const(set);
1036 
1037  cpl_propertylist * plist =
1038  cpl_propertylist_load(cpl_frame_get_filename(fr), whichext);
1039 
1040  const int naxis1 = cpl_propertylist_get_int(plist, "NAXIS1");
1041  const int naxis2 = cpl_propertylist_get_int(plist, "NAXIS2");
1042 
1043  if(detmon_ronbias_config.method_bitmask & PREOVERSCAN)
1044  {
1045  const int nx = cpl_propertylist_get_int(plist, "ESO DET OUT1 NX");
1046  const int ny = cpl_propertylist_get_int(plist, "ESO DET OUT1 NY");
1047 
1048  int prscsize;
1049  int ovscsize;
1050 
1051  if (naxis1 != nx)
1052  {
1053  prscsize =
1054  cpl_propertylist_get_int(plist, "ESO DET OUT1 PRSCX");
1055  ovscsize =
1056  cpl_propertylist_get_int(plist, "ESO DET OUT1 OVSCX");
1057 
1058  cpl_error_ensure(cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(), goto cleanup,"error");
1059 
1060  detmon_ronbias_config.prescan_llx = 1;
1061  detmon_ronbias_config.prescan_lly = 1;
1062  detmon_ronbias_config.prescan_urx = prscsize;
1063  detmon_ronbias_config.prescan_ury = naxis2;
1064  detmon_ronbias_config.overscan_llx = naxis1 - ovscsize;
1065  detmon_ronbias_config.overscan_lly = 1;
1066  detmon_ronbias_config.overscan_urx = naxis1;
1067  detmon_ronbias_config.overscan_ury = naxis2;
1068  } else if (naxis2 != ny)
1069  {
1070  prscsize =
1071  cpl_propertylist_get_int(plist, "ESO DET OUT1 PRSCY");
1072  ovscsize =
1073  cpl_propertylist_get_int(plist, "ESO DET OUT1 OVSCY");
1074  cpl_error_ensure(cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(), goto cleanup,"error");
1075 
1076  detmon_ronbias_config.prescan_llx = 1;
1077  detmon_ronbias_config.prescan_lly = 1;
1078  detmon_ronbias_config.prescan_urx = naxis1;
1079  detmon_ronbias_config.prescan_ury = prscsize;
1080  detmon_ronbias_config.overscan_llx = 1;
1081  detmon_ronbias_config.overscan_lly = naxis2 - ovscsize;
1082  detmon_ronbias_config.overscan_urx = naxis1;
1083  detmon_ronbias_config.overscan_ury = naxis2;
1084  } else
1085  {
1086  cpl_msg_error(cpl_func,
1087  "No PREOVERSCAN areas found");
1088  cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
1089  goto cleanup;
1090  }
1091  }
1092 
1093  if(detmon_ronbias_config.ref_llx == -1)
1094  detmon_ronbias_config.ref_llx = naxis1 / 8;
1095  if(detmon_ronbias_config.ref_lly == -1)
1096  detmon_ronbias_config.ref_lly = naxis2 / 8;
1097  if(detmon_ronbias_config.ref_urx == -1)
1098  detmon_ronbias_config.ref_urx = naxis1 * 7 / 8;
1099  if(detmon_ronbias_config.ref_ury == -1)
1100  detmon_ronbias_config.ref_ury = naxis2 * 7 / 8;
1101 
1102  if(detmon_ronbias_config.ron_llx == -1)
1103  detmon_ronbias_config.ron_llx = 1;
1104  if(detmon_ronbias_config.ron_lly == -1)
1105  detmon_ronbias_config.ron_lly = 1;
1106  if(detmon_ronbias_config.ron_urx == -1)
1107  detmon_ronbias_config.ron_urx = naxis1;
1108  if(detmon_ronbias_config.ron_ury == -1)
1109  detmon_ronbias_config.ron_ury = naxis2;
1110 
1111 cleanup:
1112  cpl_propertylist_delete(plist);
1113  return cpl_error_get_code();
1114 }
1115 
1116 
1117 /*---------------------------------------------------------------------------*/
1118 
1119 /*
1120  * @brief Retrieve input parameters
1121  * @param pipeline_name Input image
1122  * @param recipe_name Input image
1123  * @param parlist Shift to apply on the x-axis
1124  * @return CPL_ERROR_NONE on success.
1125  */
1126 
1127 /*---------------------------------------------------------------------------*/
1128 cpl_error_code
1129 detmon_ronbias(cpl_frameset * frameset,
1130  const cpl_parameterlist * parlist,
1131  const char *tag,
1132  const char *recipe_name,
1133  const char *pipeline_name,
1134  const char *pafregexp,
1135  const cpl_propertylist * pro_master,
1136  const cpl_propertylist * pro_xstr, /* Unsupported*/
1137  const cpl_propertylist * pro_ystr, /* Unsupported*/
1138  const cpl_propertylist * pro_synth,
1139  const cpl_propertylist * pro_bpmhot,
1140  const cpl_propertylist * pro_bpmcold,
1141  const cpl_propertylist * pro_bpmdev,
1142  const char *package,
1143  int (*compare) (const cpl_frame *, const cpl_frame *),
1144  cpl_boolean opt_nir)
1145 {
1146 
1147  cpl_size nsets;
1148  int i;
1149 
1150  cpl_size * selection = NULL;
1151  cpl_frameset * cur_fset = NULL;
1152  cpl_propertylist * qclist = NULL;
1153  cpl_image * synthetic = NULL;
1154  cpl_image * masterbias = NULL;
1155  cpl_imagelist * rawbiases = NULL;
1156  cpl_mask * bpmhot = NULL;
1157  cpl_mask * bpmcold = NULL;
1158  cpl_mask * bpmdev = NULL;
1159 
1160  /* Test entries */
1161  cpl_ensure_code(frameset != NULL, CPL_ERROR_NULL_INPUT);
1162  cpl_ensure_code(parlist != NULL, CPL_ERROR_NULL_INPUT);
1163  cpl_ensure_code(tag != NULL, CPL_ERROR_NULL_INPUT);
1164  cpl_ensure_code(recipe_name != NULL, CPL_ERROR_NULL_INPUT);
1165  cpl_ensure_code(pipeline_name != NULL, CPL_ERROR_NULL_INPUT);
1166  cpl_ensure_code(pro_master != NULL, CPL_ERROR_NULL_INPUT);
1167  cpl_ensure_code(pro_bpmhot != NULL, CPL_ERROR_NULL_INPUT);
1168  cpl_ensure_code(pro_bpmcold != NULL, CPL_ERROR_NULL_INPUT);
1169  cpl_ensure_code(pro_bpmdev != NULL, CPL_ERROR_NULL_INPUT);
1170  cpl_ensure_code(package != NULL, CPL_ERROR_NULL_INPUT);
1171 
1172  if(detmon_ronbias_dfs_set_groups(frameset, tag)) {
1173  cpl_msg_error(cpl_func, "Cannot identify RAW and CALIB frames");
1174  }
1175 
1176  /*
1177  * First of all test the entries.
1178  * See if the selected method(s) is/are appliable.
1179  * See if necessary parameters for those selected have been provided.
1180  */
1181 
1182  /* clreturn_if(detmon_ronbias_test_entries());
1183  */
1184  /*
1185  * This function reads all inputs parameters from parlist
1186  * and stores them in a global variable detmon_ronbias_config.
1187  * Similar to detmon_lg_retrieve_parlist(). See detmon.c
1188  */
1189  detmon_ronbias_retrieve_parlist(pipeline_name,
1190  recipe_name, parlist, opt_nir);
1191 
1192  /* Extra input check for PREOVERSCAN */
1193  if(detmon_ronbias_config.method_bitmask & PREOVERSCAN)
1194  cpl_ensure_code(pro_synth != NULL, CPL_ERROR_NULL_INPUT);
1195 
1196 
1197  /* Labelise all input frames */
1198  if(compare == NULL)
1199  nsets = 1;
1200  else {
1201  cpl_msg_info(cpl_func, "Identify the different settings");
1202  selection = cpl_frameset_labelise(frameset, compare, &nsets);
1203  if(selection == NULL)
1204  cpl_msg_error(cpl_func, "Cannot labelise input frames");
1205  }
1206 
1207  /* Extract settings and reduce each of them */
1208  for(i = 0; i < nsets; i++) {
1209  int j;
1210  int first_ext = 0;
1211  int last_ext = 1;
1212 
1213  detmon_ronbias_config.nb_extensions = 1;
1214 
1215  /* Reduce data set nb i */
1216  cpl_msg_info(cpl_func, "Reduce data set nb %d out of %" CPL_SIZE_FORMAT "",
1217  i + 1, nsets);
1218 
1219  cur_fset = nsets == 1 ?
1220  cpl_frameset_duplicate(frameset) :
1221  cpl_frameset_extract(frameset, selection, i);
1222  skip_if(cur_fset == NULL);
1223 
1224  if(detmon_ronbias_config.exts > 0) {
1225  first_ext = detmon_ronbias_config.exts;
1226  last_ext = first_ext + 1;
1227  } else if(detmon_ronbias_config.exts < 0) {
1228  const cpl_frame *cur_frame =
1229  cpl_frameset_get_first_const(cur_fset);
1230  /* Get the nb of extensions */
1231  detmon_ronbias_config.nb_extensions =
1232  cpl_frame_get_nextensions(cur_frame);
1233  first_ext = 1;
1234  last_ext = detmon_ronbias_config.nb_extensions + 1;
1235  }
1236 
1237  if (last_ext - first_ext > 1) {
1238  skip_if(detmon_ronbias_save(parlist, frameset,
1239  recipe_name,
1240  pipeline_name, pafregexp,
1241  pro_master, pro_xstr,
1242  pro_ystr, pro_synth,
1243  pro_bpmhot,
1244  pro_bpmcold, pro_bpmdev,
1245  package, NULL, NULL, NULL,
1246  NULL, NULL, NULL,
1247  0, 0, cur_fset, 0));
1248  }
1249 
1250  for(j = first_ext; j < last_ext; j++) {
1251  int whichext;
1252 
1253  qclist = cpl_propertylist_new();
1254 
1255  rawbiases
1256  = cpl_imagelist_load_frameset(cur_fset,
1257  CPL_TYPE_FLOAT, 1, j);
1258  skip_if(rawbiases == NULL);
1259 
1260  skip_if(detmon_ronbias_check_defaults(cur_fset, j));
1261 
1262  skip_if(detmon_ronbias_dutycycl(cur_fset, qclist));
1263 
1264  masterbias = detmon_ronbias_master(rawbiases,
1265  &bpmhot, &bpmcold,
1266  &bpmdev, qclist);
1267  skip_if(masterbias == NULL);
1268 
1269  /*
1270  * Following, a function corresponding each of the
1271  * possible methods is to be found.
1272  */
1273 
1274  if(detmon_ronbias_config.method_bitmask & RANDOM) {
1275  skip_if(detmon_ronbias_random(rawbiases, masterbias,
1276  qclist));
1277  }
1278 
1279  if(detmon_ronbias_config.method_bitmask & HISTO) {
1280  skip_if(detmon_ronbias_histo(rawbiases, masterbias,
1281  qclist));
1282  }
1283 
1284  if(detmon_ronbias_config.method_bitmask & PREOVERSCAN) {
1285  skip_if(detmon_ronbias_preoverscan(rawbiases,
1286  /*masterbias,*/
1287  qclist, &synthetic));
1288  }
1289 
1290  if(detmon_ronbias_config.method_bitmask & REGION) {
1291  skip_if(detmon_ronbias_region(rawbiases, masterbias,
1292  qclist));
1293  }
1294 
1295  /*
1296  * This function takes the QC list where all the results of the
1297  * methods applied are stored, and compares them.
1298  * No action defined yet if comparison reveals important differences.
1299  */
1300 #if 0
1301  detmon_ronbias_check(qclist);
1302 #endif
1303 
1304  /* Definition of the extension of the output where to save
1305  the products. If input are multiextension but only
1306  computation on a single extension is required, it is 0 */
1307  whichext = first_ext > 1 ? 0 : j;
1308 
1309  skip_if(detmon_ronbias_save(parlist, frameset,
1310  recipe_name,
1311  pipeline_name, pafregexp,
1312  pro_master, pro_xstr,
1313  pro_ystr, pro_synth,
1314  pro_bpmhot,
1315  pro_bpmcold, pro_bpmdev,
1316  package, masterbias, synthetic,
1317  bpmhot, bpmcold, bpmdev,
1318  qclist, 0, 0, cur_fset,
1319  whichext));
1320 
1321  cpl_image_delete(synthetic);
1322  cpl_image_delete(masterbias);
1323  cpl_mask_delete(bpmhot);
1324  cpl_mask_delete(bpmcold);
1325  cpl_mask_delete(bpmdev);
1326  cpl_imagelist_delete(rawbiases);
1327  cpl_propertylist_delete(qclist);
1328 
1329  qclist = NULL;
1330  rawbiases = NULL;
1331  masterbias = NULL;
1332  bpmhot = NULL;
1333  bpmcold = NULL;
1334  bpmdev = NULL;
1335  synthetic = NULL;
1336  } /* for each extension */
1337 
1338  cpl_frameset_delete(cur_fset);
1339  cur_fset = NULL;
1340 
1341  } /* for each setting */
1342 
1343  end_skip;
1344 
1345  cpl_free(selection);
1346 
1347  cpl_frameset_delete(cur_fset);
1348 
1349  cpl_image_delete(synthetic);
1350  cpl_image_delete(masterbias);
1351  cpl_mask_delete(bpmhot);
1352  cpl_mask_delete(bpmcold);
1353  cpl_mask_delete(bpmdev);
1354  cpl_imagelist_delete(rawbiases);
1355  cpl_propertylist_delete(qclist);
1356 
1357  return cpl_error_get_code();
1358 }
1359 
1360 /*---------------------------------------------------------------------------*/
1361 
1362 /*
1363  * @brief Retrieve input parameters
1364  * @param pipeline_name Input image
1365  * @param recipe_name Input image
1366  * @param parlist Shift to apply on the x-axis
1367  * @return CPL_ERROR_NONE on success.
1368  */
1369 
1370 /*---------------------------------------------------------------------------*/
1371 static cpl_error_code
1372 detmon_ronbias_random(const cpl_imagelist * rawbiases,
1373  const cpl_image * masterbias,
1374  cpl_propertylist * qclist)
1375 {
1376  int nraws = cpl_imagelist_get_size(rawbiases);
1377  int i;
1378  double bias = DBL_MAX; /* Avoid (false) uninit warning */
1379  double bias_error;
1380 
1381  double ron_error;
1382  double *ron =
1383  (double *) cpl_malloc(sizeof(double) * nraws);
1384 
1385  cpl_vector *v;
1386  double stdev = 0;
1387  cpl_error_code error = CPL_ERROR_NONE;
1388 
1389  /* As we are applying to diff frames instead of raw frames,
1390  there is one less to compute on */
1391  if(!strcmp(detmon_ronbias_config.pmethod, "DIF"))
1392  {
1393  nraws--;
1394  /* As we are applying to diff frames instead of raw frames,
1395  there is one less to compute on */
1396  for(i = 0; i < nraws; i++)
1397  {
1398  const cpl_image *c1_raw =
1399  cpl_imagelist_get_const(rawbiases, i);
1400  const cpl_image *c2_raw =
1401  cpl_imagelist_get_const(rawbiases, i + 1);
1402  /*FIXME: See if const modifier is necessary */
1403  const cpl_image *c_raw = cpl_image_subtract_create(c1_raw,
1404  c2_raw);
1405  error = cpl_flux_get_noise_window(c_raw, NULL,
1406  detmon_ronbias_config.random_sizex / 2,
1407  detmon_ronbias_config.random_nsamples,
1408  ron + i, &ron_error);
1409  cpl_image_delete((cpl_image*)c_raw);
1410  if (error != CPL_ERROR_NONE)
1411  {
1412  break;
1413  }
1414  }
1415  } else
1416  {
1417  for(i = 0; i < nraws; i++)
1418  {
1419  const cpl_image *c_raw = cpl_imagelist_get_const(rawbiases, i);
1420  skip_if(cpl_flux_get_noise_window(c_raw, NULL,
1421  detmon_ronbias_config.random_sizex / 2,
1422  detmon_ronbias_config.random_nsamples,
1423  ron + i, &ron_error));
1424  }
1425  }
1426 
1427  /*FIXME: Calls to noise_window could be out from if() and
1428  coded only once */
1429  if (error == CPL_ERROR_NONE)
1430  {
1431  irplib_flux_get_bias_window(masterbias, NULL,
1432  detmon_ronbias_config.random_sizex / 2,
1433  detmon_ronbias_config.random_nsamples,
1434  &bias, &bias_error);
1435 
1436  v = cpl_vector_wrap(nraws, ron);
1437  stdev = cpl_vector_get_median_const(v);
1438  cpl_vector_unwrap(v);
1439 
1440 
1441  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_RANDOM_VAL, bias));
1442  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_RANDOM_VAL,
1443  DETMON_QC_BIAS_RANDOM_VAL_C));
1444 
1445  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_RANDOM_RON, stdev));
1446  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_RANDOM_RON,
1447  DETMON_QC_BIAS_RANDOM_RON_C));
1448  }
1449 
1450  irplib_flux_get_bias_window(masterbias, NULL,
1451  detmon_ronbias_config.random_sizex / 2,
1452  detmon_ronbias_config.random_nsamples,
1453  &bias, &bias_error);
1454 
1455  v = cpl_vector_wrap(nraws, ron);
1456  if (v)
1457  {
1458  stdev = cpl_vector_get_median_const(v);
1459  cpl_vector_unwrap(v);
1460  }
1461 
1462  error = cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_RANDOM_VAL, bias);
1463  error = cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_RANDOM_VAL,
1464  DETMON_QC_BIAS_RANDOM_VAL_C);
1465 
1466 
1467  error = cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_RANDOM_RON, stdev);
1468  error = cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_RANDOM_RON,
1469  DETMON_QC_BIAS_RANDOM_RON_C);
1470 
1471  end_skip;
1472  if (ron)
1473  cpl_free(ron);
1474  return cpl_error_get_code();
1475 }
1476 
1477 static cpl_error_code
1478 detmon_ronbias_histo(const cpl_imagelist * rawbiases,
1479  const cpl_image * masterbias,
1480  cpl_propertylist * qclist)
1481 {
1482  int nraws = cpl_imagelist_get_size(rawbiases);
1483  int i;
1484 
1485  double mbias = DBL_MAX;
1486  double mfwhm = DBL_MAX;
1487  double mmax = DBL_MAX;
1488 
1489  cpl_vector * fwhms;
1490  cpl_vector * maxs;
1491 
1492  double mean_fwhm = DBL_MAX;
1493 
1494  if(!strcmp(detmon_ronbias_config.pmethod, "DIF")) nraws--;
1495 
1496  fwhms = cpl_vector_new(nraws);
1497  maxs = cpl_vector_new(nraws);
1498 
1499  for(i = 0; i < nraws; i++) {
1500  /*FIXME: See if it is necessary to have const */
1501  const cpl_image * c_raw;
1502  double bias = DBL_MAX;
1503  double fwhm = DBL_MAX;
1504  double max = DBL_MAX;
1505 
1506  if(strcmp(detmon_ronbias_config.pmethod, "DIF")) {
1507  c_raw = cpl_imagelist_get_const(rawbiases, i);
1508  } else {
1509  const cpl_image *c1_raw = cpl_imagelist_get_const(rawbiases, i);
1510  const cpl_image * c2_raw = cpl_imagelist_get_const(rawbiases, i+1);
1511  c_raw = cpl_image_subtract_create(c1_raw, c2_raw);
1512  }
1513 
1514  skip_if(detmon_ronbias_histo_reduce(c_raw, &bias, &fwhm, &max));
1515 
1516  skip_if(bias == DBL_MAX || fwhm == DBL_MAX || max == DBL_MAX);
1517 
1518  if(!strcmp(detmon_ronbias_config.pmethod, "DIF"))
1519  cpl_image_delete((cpl_image *)c_raw);
1520 
1521  skip_if(cpl_vector_set(maxs, i, max));
1522  skip_if(cpl_vector_set(fwhms, i, fwhm));
1523 
1524  /* FIXME: Add properly a hist-saving in debug-mode */
1525  }
1526 
1527  skip_if(cpl_vector_divide_scalar(fwhms, HIST_FACT));
1528 
1529  detmon_ronbias_histo_reduce(masterbias, &mbias, &mfwhm, &mmax);
1530 
1531  skip_if(mbias == DBL_MAX || mfwhm == DBL_MAX || mmax == DBL_MAX);
1532 
1533  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_HISTO_VAL,
1534  mbias));
1535  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_HISTO_VAL,
1536  DETMON_QC_BIAS_HISTO_VAL_C));
1537  mean_fwhm = cpl_vector_get_mean(fwhms);
1538 
1539  skip_if(mean_fwhm == DBL_MAX);
1540  skip_if(cpl_error_get_code());
1541 
1542  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_HISTO_RON,
1543  mean_fwhm));
1544  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_HISTO_RON,
1545  DETMON_QC_BIAS_HISTO_RON_C));
1546 
1547  end_skip;
1548 
1549  cpl_vector_delete(fwhms);
1550  cpl_vector_delete(maxs);
1551 
1552  return cpl_error_get_code();
1553 }
1554 
1555 cpl_error_code
1556 detmon_ronbias_histo_reduce(const cpl_image * c_raw,
1557  double * bias,
1558  double * fwhm,
1559  double * max)
1560 {
1561  unsigned long uj;
1562  irplib_hist *hist;
1563  unsigned long maxwhere = 0;
1564 
1565  cpl_image * dupi;
1566  unsigned long x1a = 1;
1567  unsigned long x2a = 1;
1568 
1569  double x1 = 0;
1570  double x2 = 0;
1571 
1572  double maxwhere_interp;
1573  double max_interp;
1574  double a, b, c;
1575  cpl_matrix * coeffs =cpl_matrix_new(3, 3);
1576  cpl_matrix * rhs =cpl_matrix_new(3, 1);
1577  int p, q;
1578  cpl_matrix * result = NULL;
1579 
1580  dupi = cpl_image_duplicate(c_raw);
1581 
1582  /* FIXME: Still to decide if it is necessary to remove bad pixels
1583  in advance or not*/
1584 
1585  hist = irplib_hist_new();
1586  irplib_hist_fill(hist, dupi);
1587 
1588  cpl_image_delete(dupi);
1589 
1590  irplib_hist_get_max(hist, &maxwhere);
1591 
1592  for( p = 0; p< 3; p++){
1593  unsigned long bi = irplib_hist_get_value(hist, maxwhere-1+p);
1594  cpl_matrix_set(rhs, p, 0, bi);
1595  for( q= 0; q< 3; q++) {
1596  cpl_matrix_set(coeffs, p,q,pow((maxwhere-1+p),q));
1597  }
1598  }
1599 
1600  result = cpl_matrix_solve(coeffs, rhs);
1601 
1602  a = cpl_matrix_get(result, 2, 0);
1603  b = cpl_matrix_get(result, 1, 0);
1604  c = cpl_matrix_get(result, 0, 0);
1605 
1606  maxwhere_interp = -0.5 * b / (2 * a);
1607  max_interp = -1 * b * b / (4 * a) + c;
1608 
1609  cpl_matrix_delete(coeffs);
1610  cpl_matrix_delete(rhs);
1611  cpl_matrix_delete(result);
1612 
1613  /* Look for the points of half-maximum */
1614  for(uj = 0; uj < maxwhere; uj++) {
1615  if(irplib_hist_get_value(hist, uj) <= max_interp / 2 &&
1616  irplib_hist_get_value(hist, uj + 1) > max_interp / 2) {
1617  x1a = uj;
1618  }
1619  }
1620  for(uj = maxwhere; uj < irplib_hist_get_nbins(hist)-1; uj++) {
1621  if(irplib_hist_get_value(hist, uj) >= max_interp / 2 &&
1622  irplib_hist_get_value(hist, uj + 1) < max_interp / 2) {
1623  x2a = uj;
1624  }
1625  }
1626 
1627  x1 = (max_interp / 2 - irplib_hist_get_value(hist, x1a)) /
1628  (irplib_hist_get_value(hist, x1a + 1) -
1629  irplib_hist_get_value(hist, x1a)) + x1a;
1630  x2 = (max_interp / 2 - irplib_hist_get_value(hist, x2a)) /
1631  (irplib_hist_get_value(hist, x2a + 1) -
1632  irplib_hist_get_value(hist, x2a)) + x2a;
1633 
1634  *fwhm = (x2 - x1) * irplib_hist_get_bin_size(hist);
1635 
1636  *max = max_interp;
1637 
1638  *bias = maxwhere_interp * irplib_hist_get_bin_size(hist) +
1639  irplib_hist_get_start(hist);
1640 
1641  irplib_hist_delete(hist);
1642 
1643  return cpl_error_get_code();
1644 }
1645 /*---------------------------------------------------------------------------*/
1646 
1647 /*
1648  * @brief Retrieve input parameters
1649  * @param pipeline_name Input image
1650  * @param recipe_name Input image
1651  * @param parlist Shift to apply on the x-axis
1652  * @return CPL_ERROR_NONE on success.
1653  */
1654 
1655 /*---------------------------------------------------------------------------*/
1656  static cpl_error_code
1657 detmon_ronbias_preoverscan(const cpl_imagelist * rawbiases,
1658  cpl_propertylist * qclist,
1659  cpl_image ** synthetic)
1660 {
1661  int i;
1662  int nx, ny;
1663  int nraws;
1664 
1665  cpl_vector *meanspre;
1666  cpl_vector *medspre;
1667  cpl_vector *rmsspre;
1668  cpl_vector *meansover;
1669  cpl_vector *medsover;
1670  cpl_vector *rmssover;
1671 
1672  cpl_error_code error;
1673 
1674  nraws = cpl_imagelist_get_size(rawbiases);
1675  cpl_ensure_code(nraws != -1, CPL_ERROR_ILLEGAL_INPUT);
1676 
1677  nx = cpl_image_get_size_x(cpl_imagelist_get_const(rawbiases, 0));
1678  ny = cpl_image_get_size_y(cpl_imagelist_get_const(rawbiases, 0));
1679  cpl_ensure_code(nx != -1 && ny != -1, CPL_ERROR_ILLEGAL_INPUT);
1680 
1681  if(nx < detmon_ronbias_config.prescan_urx ||
1682  nx < detmon_ronbias_config.overscan_urx ||
1683  ny < detmon_ronbias_config.prescan_ury ||
1684  ny < detmon_ronbias_config.overscan_ury) {
1685  cpl_msg_warning(cpl_func, "PREOVERSCAN method not applied. Given "
1686  "limits of prescan and overscan area "
1687  "exceed image size. Please check and rerun.");
1688  return CPL_ERROR_NONE;
1689  }
1690 
1691  meanspre = cpl_vector_new(nraws);
1692  medspre = cpl_vector_new(nraws);
1693  rmsspre = cpl_vector_new(nraws);
1694  meansover = cpl_vector_new(nraws);
1695  medsover = cpl_vector_new(nraws);
1696  rmssover = cpl_vector_new(nraws);
1697 
1698  for(i = 0; i < nraws; i++) {
1699  double mean = 0;
1700  double stdev = 0;
1701 
1702  cpl_image *prescan = NULL;
1703  cpl_image *overscan = NULL;
1704 
1705  const cpl_image *c_raw = cpl_imagelist_get_const(rawbiases, i);
1706 
1707  cpl_ensure_code(c_raw != NULL, CPL_ERROR_ILLEGAL_INPUT);
1708 
1709  prescan =
1710  cpl_image_extract(c_raw,
1711  detmon_ronbias_config.prescan_llx,
1712  detmon_ronbias_config.prescan_lly,
1713  detmon_ronbias_config.prescan_urx,
1714  detmon_ronbias_config.prescan_ury);
1715  cpl_ensure_code(prescan != NULL, CPL_ERROR_ILLEGAL_INPUT);
1716  overscan =
1717  cpl_image_extract(c_raw,
1718  detmon_ronbias_config.overscan_llx,
1719  detmon_ronbias_config.overscan_lly,
1720  detmon_ronbias_config.overscan_urx,
1721  detmon_ronbias_config.overscan_ury);
1722  cpl_ensure_code(overscan != NULL, CPL_ERROR_ILLEGAL_INPUT);
1723 
1724  if(i == 0) {
1725  *synthetic = detmon_build_synthetic(prescan, overscan);
1726  cpl_msg_info(cpl_func, "Creating SYNTHETIC frame");
1727  if(*synthetic == NULL) {
1728  cpl_msg_error(cpl_func, "Error creating SYNTHETIC frame");
1729  return CPL_ERROR_UNSPECIFIED;
1730  }
1731  }
1732 
1733  error = irplib_ksigma_clip(c_raw,
1734  detmon_ronbias_config.
1735  prescan_llx,
1736  detmon_ronbias_config.
1737  prescan_lly,
1738  detmon_ronbias_config.
1739  prescan_urx,
1740  detmon_ronbias_config.
1741  prescan_ury,
1742  (double) detmon_ronbias_config.
1743  stacking_ks_low,
1744  detmon_ronbias_config.
1745  stacking_ks_iter, 1e-5,
1746  &mean, &stdev);
1747  cpl_ensure_code(!error, error);
1748 
1749  cpl_ensure_code(mean != 0 && stdev != 0, CPL_ERROR_UNSPECIFIED);
1750 
1751  error = cpl_vector_set(medspre, i, cpl_image_get_median(prescan));
1752  cpl_ensure_code(!error, error);
1753 
1754  error = cpl_vector_set(meanspre, i, mean);
1755  cpl_ensure_code(!error, error);
1756  error = cpl_vector_set(rmsspre, i, stdev);
1757  cpl_ensure_code(!error, error);
1758  error = irplib_ksigma_clip(c_raw,
1759  detmon_ronbias_config.
1760  overscan_llx,
1761  detmon_ronbias_config.
1762  overscan_lly,
1763  detmon_ronbias_config.
1764  overscan_urx,
1765  detmon_ronbias_config.
1766  overscan_ury,
1767  (double) detmon_ronbias_config.
1768  stacking_ks_low,
1769  detmon_ronbias_config.
1770  stacking_ks_iter, 1e-5,
1771  &mean, &stdev);
1772  cpl_ensure_code(!error, error);
1773 
1774  cpl_ensure_code(mean != 0 && stdev != 0, CPL_ERROR_UNSPECIFIED);
1775 
1776  error = cpl_vector_set(medsover, i, cpl_image_get_median(overscan));
1777  cpl_ensure_code(!error, error);
1778 
1779  error = cpl_vector_set(meansover, i, mean);
1780  cpl_ensure_code(!error, error);
1781  error = cpl_vector_set(rmssover, i, stdev);
1782  cpl_ensure_code(!error, error);
1783 
1784  cpl_image_delete(prescan);
1785  cpl_image_delete(overscan);
1786  }
1787 
1788  error = cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_PRESCAN_MEAN,
1789  cpl_vector_get_mean(meanspre));
1790 
1791  error = cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_PRESCAN_MEAN,
1792  DETMON_QC_BIAS_PRESCAN_MEAN_C);
1793 
1794  cpl_ensure_code(!error, error);
1795  error = cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_PRESCAN_MED,
1796  cpl_vector_get_mean(medspre));
1797  error = cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_PRESCAN_MED,
1798  DETMON_QC_BIAS_PRESCAN_MED_C);
1799 
1800  cpl_ensure_code(!error, error);
1801  error = cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_PRESCAN_RON,
1802  cpl_vector_get_mean(rmsspre));
1803 
1804  error = cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_PRESCAN_RON,
1805  DETMON_QC_BIAS_PRESCAN_RON_C);
1806  cpl_ensure_code(!error, error);
1807 
1808  error =
1809  cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_OVERSCAN_MEAN,
1810  cpl_vector_get_mean(meansover));
1811  error = cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_OVERSCAN_MEAN,
1812  DETMON_QC_BIAS_OVERSCAN_MEAN_C);
1813  cpl_ensure_code(!error, error);
1814  error = cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_OVERSCAN_MED,
1815  cpl_vector_get_mean(medsover));
1816  error = cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_OVERSCAN_MED,
1817  DETMON_QC_BIAS_OVERSCAN_MED_C);
1818  cpl_ensure_code(!error, error);
1819  error = cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_OVERSCAN_RON,
1820  cpl_vector_get_mean(rmssover));
1821  error = cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_OVERSCAN_RON,
1822  DETMON_QC_BIAS_OVERSCAN_RON_C);
1823  cpl_ensure_code(!error, error);
1824 
1825  /* The following seems not to be necessary.
1826  Pending of revision to be removed */
1827  /*
1828  error =
1829  cpl_propertylist_append_double(qclist,
1830  "ESO QC BIAS PRESCAN MEAN STDEV",
1831  cpl_vector_get_stdev(meanspre));
1832  cpl_ensure_code(!error, error);
1833  error =
1834  cpl_propertylist_append_double(qclist,
1835  "ESO QC BIAS PRESCAN MED STDEV",
1836  cpl_vector_get_stdev(medspre));
1837  cpl_ensure_code(!error, error);
1838  error =
1839  cpl_propertylist_append_double(qclist,
1840  "ESO QC BIAS PRESCAN RMS STDEV",
1841  cpl_vector_get_stdev(rmsspre));
1842  cpl_ensure_code(!error, error);
1843 
1844  error =
1845  cpl_propertylist_append_double(qclist,
1846  "ESO QC BIAS OVERSCAN MEAN STDEV",
1847  cpl_vector_get_stdev(meansover));
1848  cpl_ensure_code(!error, error);
1849  error =
1850  cpl_propertylist_append_double(qclist,
1851  "ESO QC BIAS OVERSCAN MED STDEV",
1852  cpl_vector_get_stdev(medsover));
1853  cpl_ensure_code(!error, error);
1854  error =
1855  cpl_propertylist_append_double(qclist,
1856  "ESO QC BIAS OVERSCAN RMS STDEV",
1857  cpl_vector_get_stdev(rmssover));
1858  cpl_ensure_code(!error, error);
1859  */
1860 
1861  cpl_vector_delete(meanspre);
1862  cpl_vector_delete(medspre);
1863  cpl_vector_delete(rmsspre);
1864  cpl_vector_delete(meansover);
1865  cpl_vector_delete(medsover);
1866  cpl_vector_delete(rmssover);
1867 
1868  return CPL_ERROR_NONE;
1869 }
1870 
1871 /*---------------------------------------------------------------------------*/
1872 
1873 /*
1874  * @brief Retrieve input parameters
1875  * @param pipeline_name Input image
1876  * @param recipe_name Input image
1877  * @param parlist Shift to apply on the x-axis
1878  * @return CPL_ERROR_NONE on success.
1879  */
1880 
1881 /*---------------------------------------------------------------------------*/
1882 static cpl_error_code
1883 detmon_ronbias_region(const cpl_imagelist * rawbiases,
1884  const cpl_image * masterbias,
1885  cpl_propertylist * qclist)
1886 {
1887 
1888  int nraws = cpl_imagelist_get_size(rawbiases);
1889  int i;
1890 
1891  int nx =
1892  cpl_image_get_size_x(cpl_imagelist_get_const(rawbiases, 0));
1893  int ny =
1894  cpl_image_get_size_y(cpl_imagelist_get_const(rawbiases, 0));
1895 
1896  cpl_vector *rmssreg;
1897  cpl_error_code error;
1898 
1899  const cpl_image * c_raw;
1900  double median, mbias, mstdev;
1901 
1902  if(!strcmp(detmon_ronbias_config.pmethod, "DIF")) nraws--;
1903 
1904  rmssreg = cpl_vector_new(nraws);
1905 
1906  if(nx < detmon_ronbias_config.ref_urx ||
1907  ny < detmon_ronbias_config.ref_ury) {
1908  cpl_msg_warning(cpl_func, "REGION method not applied. Given "
1909  "limits of prescan and overscan area "
1910  "exceed image size. Please check and rerun.");
1911  return CPL_ERROR_NONE;
1912  }
1913 
1914  for(i = 0; i < nraws; i++) {
1915  double mean = 0;
1916  double stdev = 0;
1917  if(strcmp(detmon_ronbias_config.pmethod, "DIF")) {
1918  c_raw = cpl_imagelist_get_const(rawbiases, i);
1919  } else {
1920  const cpl_image *c1_raw = cpl_imagelist_get_const(rawbiases, i);
1921  const cpl_image * c2_raw = cpl_imagelist_get_const(rawbiases, i+1);
1922  c_raw = cpl_image_subtract_create(c1_raw, c2_raw);
1923  }
1924  error = irplib_ksigma_clip(c_raw,
1925  detmon_ronbias_config.ref_llx,
1926  detmon_ronbias_config.ref_lly,
1927  detmon_ronbias_config.ref_urx,
1928  detmon_ronbias_config.ref_ury,
1929  (double) detmon_ronbias_config.
1930  stacking_ks_low,
1931  detmon_ronbias_config.
1932  stacking_ks_iter, 1e-5,
1933  &mean, &stdev);
1934  cpl_ensure_code(!error, error);
1935  /* cpl_vector_set(rmssreg, i, cpl_image_get_stdev_window(c_raw,
1936  detmon_ronbias_config.ref_llx,
1937  detmon_ronbias_config.ref_lly,
1938  detmon_ronbias_config.ref_urx,
1939  detmon_ronbias_config.ref_ury));
1940  */
1941  error = cpl_vector_set(rmssreg, i, stdev);
1942  cpl_ensure_code(!error, error);
1943  if(!strcmp(detmon_ronbias_config.pmethod, "DIF")) cpl_image_delete((cpl_image *)c_raw);
1944  }
1945 
1946  median = cpl_image_get_median_window(masterbias,
1947  detmon_ronbias_config.ref_llx,
1948  detmon_ronbias_config.ref_lly,
1949  detmon_ronbias_config.ref_urx,
1950  detmon_ronbias_config.ref_ury);
1951  error = irplib_ksigma_clip(masterbias,
1952  detmon_ronbias_config.ref_llx,
1953  detmon_ronbias_config.ref_lly,
1954  detmon_ronbias_config.ref_urx,
1955  detmon_ronbias_config.ref_ury,
1956  (double) detmon_ronbias_config.
1957  stacking_ks_low,
1958  detmon_ronbias_config.
1959  stacking_ks_iter, 1e-5,
1960  &mbias, &mstdev);
1961 
1962  error = cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_REGION_MED,
1963  median);
1964  error = cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_REGION_MED,
1965  DETMON_QC_BIAS_REGION_MED_C);
1966  cpl_ensure_code(!error, error);
1967 
1968  error = cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_REGION_VAL,
1969  mbias);
1970  error = cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_REGION_VAL,
1971  DETMON_QC_BIAS_REGION_VAL_C);
1972  cpl_ensure_code(!error, error);
1973  error = cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_REGION_RON,
1974  cpl_vector_get_mean(rmssreg));
1975  error = cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_REGION_RON,
1976  DETMON_QC_BIAS_REGION_RON_C);
1977  cpl_ensure_code(!error, error);
1978  /*
1979  error =
1980  cpl_propertylist_append_double(qclist, "ESO QC BIAS REGION RMS STDEV",
1981  cpl_vector_get_stdev(rmssreg));
1982  cpl_ensure_code(!error, error);
1983  */
1984  cpl_vector_delete(rmssreg);
1985 
1986  return cpl_error_get_code();
1987 }
1988 
1989 /*---------------------------------------------------------------------------*/
1990 
1991 /*
1992  * @brief Retrieve input parameters
1993  * @param pipeline_name Input image
1994  * @param recipe_name Input image
1995  * @param parlist Shift to apply on the x-axis
1996  * @return CPL_ERROR_NONE on success.
1997  */
1998 
1999 /*---------------------------------------------------------------------------*/
2000 static cpl_image *
2001 detmon_ronbias_master(const cpl_imagelist * rawbiases,
2002  cpl_mask ** bpmhot, cpl_mask ** bpmcold,
2003  cpl_mask ** bpmdev, cpl_propertylist * qclist)
2004 {
2005  double mean = 0;
2006  double stdev = 0;
2007  cpl_image *masterbias = NULL;
2008  double dark_med, stdev_med,lower, upper;
2009  int hotpix_nb, coldpix_nb, devpix_nb;
2010  cpl_image * stdev_im = NULL;
2011 
2012  if(!strcmp(detmon_ronbias_config.stacking_method, "MEAN"))
2013  masterbias = cpl_imagelist_collapse_create(rawbiases);
2014  if(!strcmp(detmon_ronbias_config.stacking_method, "MINMAX"))
2015  masterbias =
2016  cpl_imagelist_collapse_minmax_create(rawbiases, 0, 10000);
2017  if(!strcmp(detmon_ronbias_config.stacking_method, "KSIGMA"))
2018  masterbias =
2019  cpl_imagelist_collapse_sigclip_create(rawbiases, 3.0, 3.0, 0.9,
2020  CPL_COLLAPSE_MEAN, NULL);
2021  if(!strcmp(detmon_ronbias_config.stacking_method, "MEDIAN"))
2022  masterbias = cpl_imagelist_collapse_median_create(rawbiases);
2023 
2024  skip_if(masterbias == NULL);
2025 
2026  skip_if(irplib_ksigma_clip(masterbias, 1, 1,
2027  cpl_image_get_size_x(masterbias),
2028  cpl_image_get_size_y(masterbias),
2029  (double) detmon_ronbias_config.
2030  stacking_ks_low,
2031  detmon_ronbias_config.
2032  stacking_ks_iter, 1e-5,
2033  &mean, &stdev));
2034 
2035  if(irplib_isnan(mean))
2036  cpl_msg_error(cpl_func, "We have an error in mean");
2037  if(irplib_isnan(stdev))
2038  cpl_msg_error(cpl_func, "We have an error in stdev");
2039 
2040  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_MASTER_MEAN,
2041  mean));
2042  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_MASTER_MEAN,
2043  DETMON_QC_MASTER_MEAN_C));
2044 
2045  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_MASTER_RMS,
2046  stdev));
2047  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_MASTER_RMS,
2048  DETMON_QC_MASTER_RMS_C));
2049 
2050  /* Compute median-rms of the central part of the dark */
2051  dark_med = cpl_image_get_median(masterbias);
2052 
2053  lower = dark_med - stdev * detmon_ronbias_config.stacking_ks_low;
2054  upper = dark_med + stdev * detmon_ronbias_config.stacking_ks_high;
2055 
2056  /* Create the hot pixel map */
2057  cpl_mask_delete(*bpmhot);
2058  irplib_check(*bpmhot = cpl_mask_threshold_image_create(masterbias,
2059  upper, DBL_MAX),
2060  "Cannot compute the hot pixel map");
2061  hotpix_nb = cpl_mask_count(*bpmhot);
2062  skip_if (0);
2063 
2064  /* Create the cold pixel map */
2065  cpl_mask_delete(*bpmcold);
2066  irplib_check(*bpmcold = cpl_mask_threshold_image_create(masterbias,
2067  -FLT_MAX, lower),
2068  "Cannot compute the cold pixel map");
2069  coldpix_nb = cpl_mask_count(*bpmcold);
2070  skip_if (0);
2071 
2072  /* Create the deviant pixel map */
2073  stdev_im = irplib_imagelist_collapse_stdev_create(rawbiases);
2074  stdev_med = cpl_image_get_median(stdev_im);
2075 
2076  skip_if(irplib_ksigma_clip(stdev_im, 1, 1,
2077  cpl_image_get_size_x(stdev_im),
2078  cpl_image_get_size_y(stdev_im),
2079  (double) detmon_ronbias_config.
2080  stacking_ks_low,
2081  detmon_ronbias_config.
2082  stacking_ks_iter, 1e-5,
2083  &mean, &stdev));
2084 
2085  lower = stdev_med - stdev * detmon_ronbias_config.stacking_ks_low;
2086  upper = stdev_med + stdev * detmon_ronbias_config.stacking_ks_high;
2087 
2088  cpl_mask_delete(*bpmdev);
2089  irplib_check(*bpmdev = cpl_mask_threshold_image_create(stdev_im,
2090  lower, upper),
2091  "Cannot compute the cold pixel map");
2092  cpl_mask_not(*bpmdev);
2093  devpix_nb = cpl_mask_count(*bpmdev);
2094  skip_if (0);
2095 
2096 
2097  skip_if(cpl_propertylist_append_int(qclist,DETMON_QC_NBCOLDPIX,coldpix_nb));
2098  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_NBCOLDPIX,
2099  DETMON_QC_NBCOLDPIX_C));
2100 
2101  skip_if(cpl_propertylist_append_int(qclist,DETMON_QC_NBHOTPIX, hotpix_nb));
2102  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_NBHOTPIX,
2103  DETMON_QC_NBHOTPIX_C));
2104 
2105  skip_if(cpl_propertylist_append_int(qclist,DETMON_QC_NBDEVPIX, devpix_nb));
2106  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_NBDEVPIX,
2107  DETMON_QC_NBDEVPIX_C));
2108 
2109  end_skip;
2110 
2111  cpl_image_delete(stdev_im);
2112 
2113  if (cpl_error_get_code()) {
2114  cpl_image_delete(masterbias);
2115  masterbias = NULL;
2116  }
2117 
2118  return masterbias;
2119 }
2120 
2121 /*---------------------------------------------------------------------------*/
2122 
2123 /*
2124  * @brief Retrieve input parameters
2125  * @param pipeline_name Input image
2126  * @param recipe_name Input image
2127  * @param parlist Shift to apply on the x-axis
2128  * @return CPL_ERROR_NONE on success.
2129  */
2130 
2131 /*---------------------------------------------------------------------------*/
2132 static cpl_error_code
2133 detmon_ronbias_save(const cpl_parameterlist * parlist,
2134  cpl_frameset * frameset,
2135  const char *recipe_name,
2136  const char *pipeline_name,
2137  const char *pafregexp,
2138  const cpl_propertylist * pro_master,
2139  const cpl_propertylist * pro_xstr, /* Unsupported*/
2140  const cpl_propertylist * pro_ystr, /* Unsupported*/
2141  const cpl_propertylist * pro_synth,
2142  const cpl_propertylist * pro_bpmhot,
2143  const cpl_propertylist * pro_bpmcold,
2144  const cpl_propertylist * pro_bpmdev,
2145  const char *package,
2146  const cpl_image * masterbias,
2147  const cpl_image * synthetic,
2148  const cpl_mask * bpmhot,
2149  const cpl_mask * bpmcold,
2150  const cpl_mask * bpmdev,
2151  cpl_propertylist * qclist,
2152  const int flag_sets,
2153  const int which_set,
2154  cpl_frameset * usedframes,
2155  int whichext)
2156 {
2157 
2158  cpl_frame *ref_frame;
2159  cpl_propertylist *plist = NULL;
2160  char *name_o = NULL; /* Avoid (false) uninit warning */
2161 
2162  cpl_propertylist * paflist = NULL;
2163  cpl_propertylist * mainplist = NULL;
2164  cpl_propertylist * xplist = NULL;
2165  cpl_image * image = NULL;
2166 
2167  cpl_propertylist * mypro_master =
2168  cpl_propertylist_duplicate(pro_master);
2169 
2170  cpl_propertylist * mypro_synth = NULL;
2171  cpl_propertylist * mypro_bpmhot =
2172  cpl_propertylist_duplicate(pro_bpmhot);
2173  cpl_propertylist * mypro_bpmcold =
2174  cpl_propertylist_duplicate(pro_bpmcold);
2175  cpl_propertylist * mypro_bpmdev =
2176  cpl_propertylist_duplicate(pro_bpmdev);
2177 
2178  cpl_ensure_code(parlist != NULL, CPL_ERROR_NULL_INPUT);
2179  cpl_ensure_code(frameset != NULL, CPL_ERROR_NULL_INPUT);
2180  cpl_ensure_code(pafregexp != NULL, CPL_ERROR_NULL_INPUT);
2181  cpl_ensure_code(package != NULL, CPL_ERROR_NULL_INPUT);
2182  cpl_ensure_code(recipe_name != NULL, CPL_ERROR_NULL_INPUT);
2183  cpl_ensure_code(pipeline_name != NULL, CPL_ERROR_NULL_INPUT);
2184  cpl_ensure_code(usedframes != NULL, CPL_ERROR_NULL_INPUT);
2185 
2186  if (pro_synth)
2187  mypro_synth = cpl_propertylist_duplicate(pro_synth);
2188 
2189  /* Extra check while XSTR and YSTR are not supported */
2190  cpl_ensure_code(pro_xstr == NULL && pro_ystr == NULL,
2191  CPL_ERROR_UNSUPPORTED_MODE);
2192 
2193  /* Extract extension headers if multi-extension */
2194  if (detmon_ronbias_config.exts < 0) {
2195  const char * filename =
2196  cpl_frame_get_filename(cpl_frameset_get_first(frameset));
2197 
2198 
2199  xplist = cpl_propertylist_load_regexp(filename, whichext,
2200  "ESO DET", 0);
2201  skip_if(cpl_propertylist_append(xplist, qclist));
2202  }
2203 
2204  cpl_msg_info(cpl_func,"dealing with extention %d",whichext);
2205 
2206  /* This is only used later for PAF */
2207  /* Get FITS header from reference file */
2208  ref_frame = cpl_frameset_get_first(frameset);
2209  skip_if(ref_frame == NULL);
2210 
2211  skip_if((mainplist =
2212  cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
2213  0)) == NULL);
2214 
2215  /**************************/
2216  /* Write the MASTERBIAS */
2217  /**************************/
2218 
2219  /* Set the file name for the table */
2220  if(!flag_sets) {
2221  name_o = cpl_sprintf("%s_masterbias.fits", recipe_name);
2222  assert(name_o != NULL);
2223  } else {
2224  name_o =
2225  cpl_sprintf("%s_masterbias_set%02d.fits", recipe_name,
2226  which_set);
2227  assert(name_o != NULL);
2228  }
2229  /* Save the MASTERBIAS image */
2230  if (whichext == 0) {
2231  cpl_propertylist_append(mypro_master, qclist);
2232 
2233  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL,
2234  masterbias, CPL_BPP_IEEE_FLOAT, recipe_name,
2235  mypro_master, NULL, package, name_o));
2236  } else
2237  skip_if(cpl_image_save(masterbias,
2238  name_o, CPL_BPP_IEEE_FLOAT, xplist,
2239  CPL_IO_EXTEND));
2240 
2241  /* Free */
2242  cpl_free(name_o);
2243  name_o = NULL;
2244 
2245  /*****************************/
2246  /* Write the HOT PIXEL MAP */
2247  /*****************************/
2248 
2249  /* Set the file name for the table */
2250  if(!flag_sets) {
2251  name_o = cpl_sprintf("%s_hotpixmap.fits", recipe_name);
2252  assert(name_o != NULL);
2253  } else {
2254  name_o =
2255  cpl_sprintf("%s_hotpixmap_set%02d.fits", recipe_name,
2256  which_set);
2257  assert(name_o != NULL);
2258  }
2259  /* Save the HOTBPM image */
2260  skip_if(0);
2261  image = cpl_image_new_from_mask(bpmhot);
2262  cpl_error_reset();
2263 
2264  if (whichext == 0) {
2265  cpl_propertylist_append(mypro_bpmhot, qclist);
2266 
2267  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL,
2268  image, CPL_BPP_IEEE_FLOAT, recipe_name,
2269  mypro_bpmhot, NULL, package, name_o));
2270  } else
2271  skip_if(cpl_image_save(image,
2272  name_o, CPL_BPP_IEEE_FLOAT, xplist,
2273  CPL_IO_EXTEND));
2274 
2275  /* Free */
2276  cpl_free(name_o);
2277  cpl_image_delete(image);
2278  image = NULL;
2279  name_o = NULL;
2280 
2281  /*****************************/
2282  /* Write the COLD PIXEL MAP */
2283  /*****************************/
2284 
2285  /* Set the file name for the table */
2286  if(!flag_sets) {
2287  name_o = cpl_sprintf("%s_coldpixmap.fits", recipe_name);
2288  assert(name_o != NULL);
2289  } else {
2290  name_o =
2291  cpl_sprintf("%s_coldpixmap_set%02d.fits", recipe_name,
2292  which_set);
2293  assert(name_o != NULL);
2294  }
2295  /* Save the COLDBPM image */
2296  skip_if(0);
2297  image = cpl_image_new_from_mask(bpmcold);
2298  cpl_error_reset();
2299 
2300  if (whichext == 0) {
2301  cpl_propertylist_append(mypro_bpmcold, qclist);
2302 
2303  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL,
2304  image, CPL_BPP_IEEE_FLOAT, recipe_name,
2305  mypro_bpmcold, NULL, package, name_o));
2306  } else
2307  skip_if(cpl_image_save(image,
2308  name_o, CPL_BPP_IEEE_FLOAT, xplist,
2309  CPL_IO_EXTEND));
2310 
2311  /* Free */
2312  cpl_free(name_o);
2313  cpl_image_delete(image);
2314  image = NULL;
2315  name_o = NULL;
2316 
2317  /*****************************/
2318  /* Write the DEV PIXEL MAP */
2319  /*****************************/
2320 
2321  /* Set the file name for the table */
2322  if(!flag_sets) {
2323  name_o = cpl_sprintf("%s_devpixmap.fits", recipe_name);
2324  assert(name_o != NULL);
2325  } else {
2326  name_o =
2327  cpl_sprintf("%s_devpixmap_set%02d.fits", recipe_name,
2328  which_set);
2329  assert(name_o != NULL);
2330  }
2331  /* Save the DEVBPM image */
2332  skip_if(0);
2333  image = cpl_image_new_from_mask(bpmdev);
2334  cpl_error_reset();
2335 
2336  if (whichext == 0) {
2337  cpl_propertylist_append(mypro_bpmdev, qclist);
2338 
2339  skip_if(cpl_dfs_save_image(frameset, NULL,parlist, usedframes, NULL,
2340  image, CPL_BPP_IEEE_FLOAT, recipe_name,
2341  mypro_bpmdev, NULL, package, name_o));
2342  } else
2343  skip_if(cpl_image_save(image,
2344  name_o, CPL_BPP_IEEE_FLOAT, xplist,
2345  CPL_IO_EXTEND));
2346 
2347  /* Free */
2348  cpl_free(name_o);
2349  cpl_image_delete(image);
2350  image = NULL;
2351  name_o = NULL;
2352 
2353  /*******************************/
2354  /* Write the SYNTHETIC */
2355  /*******************************/
2356  if(detmon_ronbias_config.method_bitmask & PREOVERSCAN) {
2357  /* Set the file name for the table */
2358  if(!flag_sets) {
2359  name_o = cpl_sprintf("%s_synthetic.fits", recipe_name);
2360  assert(name_o != NULL);
2361  } else {
2362  name_o =
2363  cpl_sprintf("%s_synthetic_set%02d.fits", recipe_name,
2364  which_set);
2365  assert(name_o != NULL);
2366  }
2367 
2368  if (whichext == 0) {
2369  /* Save the SYNTHETIC image */
2370  cpl_propertylist_append(mypro_synth, qclist);
2371 
2372  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
2373  NULL,synthetic, CPL_BPP_IEEE_DOUBLE,
2374  recipe_name, mypro_synth, NULL,
2375  package, name_o));
2376  } else
2377  skip_if(cpl_image_save(synthetic, name_o, CPL_BPP_IEEE_FLOAT,
2378  xplist, CPL_IO_EXTEND));
2379 
2380  /* Free */
2381  cpl_free(name_o);
2382  name_o = NULL;
2383  }
2384 
2385  /*******************************/
2386  /* Write the PAF file */
2387  /*******************************/
2388  if (qclist) {
2389  paflist = cpl_propertylist_new();
2390 
2391  /* Set the file name for the PAF */
2392  if(detmon_ronbias_config.exts >= 0) {
2393  skip_if((plist =
2394  cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
2395  detmon_ronbias_config.exts)) == NULL);
2396 
2397  if(!flag_sets) {
2398  name_o = cpl_sprintf("%s.paf", recipe_name);
2399  assert(name_o != NULL);
2400  } else {
2401  name_o = cpl_sprintf("%s_set%02d.paf",
2402  recipe_name, which_set);
2403  assert(name_o != NULL);
2404  }
2405  } else {
2406  skip_if((plist =
2407  cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
2408  whichext)) == NULL);
2409 
2410 
2411  if(!flag_sets) {
2412  name_o = cpl_sprintf("%s_ext%02d.paf",
2413  recipe_name, whichext);
2414  assert(name_o != NULL);
2415  } else {
2416  name_o = cpl_sprintf("%s_set%02d_ext%02d.paf",
2417  recipe_name,
2418  which_set, whichext);
2419  assert(name_o != NULL);
2420  }
2421  }
2422 
2423  /* Get the keywords for the paf file */
2424  skip_if(cpl_propertylist_copy_property_regexp(paflist, plist,
2425  pafregexp, 0));
2426  skip_if(cpl_propertylist_copy_property_regexp(paflist, mainplist,
2427  pafregexp, 0));
2428 
2429  skip_if(cpl_propertylist_append(paflist, qclist));
2430 
2431  /* Save the PAF */
2432  skip_if(cpl_dfs_save_paf(pipeline_name, recipe_name, paflist, name_o));
2433 
2434  }
2435 
2436  end_skip;
2437 
2438  cpl_propertylist_delete(plist);
2439  cpl_propertylist_delete(paflist);
2440  cpl_propertylist_delete(mainplist);
2441  cpl_propertylist_delete(xplist);
2442  cpl_free(name_o);
2443  cpl_image_delete(image);
2444 
2445  cpl_propertylist_delete(mypro_master);
2446  cpl_propertylist_delete(mypro_synth);
2447  cpl_propertylist_delete(mypro_bpmhot);
2448  cpl_propertylist_delete(mypro_bpmcold);
2449  cpl_propertylist_delete(mypro_bpmdev);
2450 
2451  return cpl_error_get_code();
2452 }
2453 
2454 cpl_propertylist *
2455 detmon_fill_prolist(const char * procatg,
2456  const char * protype,
2457  const char * protech,
2458  cpl_boolean proscience)
2459 {
2460  cpl_propertylist * prolist = cpl_propertylist_new();
2461 
2462  cpl_propertylist_append_string(prolist, CPL_DFS_PRO_CATG, procatg);
2463  cpl_propertylist_append_bool(prolist, CPL_DFS_PRO_SCIENCE, proscience);
2464  if (protype)
2465  cpl_propertylist_append_string(prolist, CPL_DFS_PRO_TYPE, protype);
2466  if (protech)
2467  cpl_propertylist_append_string(prolist, CPL_DFS_PRO_TECH, protech);
2468 
2469  return prolist;
2470 }
2471 
2472 /*---------------------------------------------------------------------------*/
2473 
2474 /*
2475  * @brief Retrieve input parameters
2476  * @param pipeline_name Input image
2477  * @param recipe_name Input image
2478  * @param parlist Shift to apply on the x-axis
2479  * @return CPL_ERROR_NONE on success.
2480  */
2481 
2482 /*---------------------------------------------------------------------------*/
2483 int
2484 detmon_ronbias_dfs_set_groups(cpl_frameset * set, const char *tag)
2485 {
2486  cpl_frame *cur_frame;
2487  const char *cur_tag;
2488  int nframes;
2489  int i;
2490 
2491  /* Check entries */
2492  if(set == NULL)
2493  return -1;
2494 
2495  /* Initialize */
2496  nframes = cpl_frameset_get_size(set);
2497 
2498  /* Loop on frames */
2499  for(i = 0; i < nframes; i++) {
2500  cur_frame = cpl_frameset_get_frame(set, i);
2501  cur_tag = cpl_frame_get_tag(cur_frame);
2502 
2503  /* RAW frames */
2504  if(!strcmp(cur_tag, tag))
2505  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_RAW);
2506  /* CALIB frames */
2507 
2508  /* else if (!strcmp(tag, IIINSTRUMENT_CALIB_FLAT))
2509  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_CALIB) ;
2510  */
2511  }
2512  return 0;
2513 }
2514 
2515 /*---------------------------------------------------------------------------*/
2516 
2517 /*
2518  * @brief Retrieve input parameters
2519  * @param pipeline_name Input image
2520  * @param recipe_name Input image
2521  * @param parlist Shift to apply on the x-axis
2522  * @return CPL_ERROR_NONE on success.
2523  */
2524 
2525 /*---------------------------------------------------------------------------*/
2526 cpl_image *
2527 detmon_build_synthetic(cpl_image * prescan, cpl_image * overscan)
2528 {
2529  cpl_size j;
2530 
2531  int distance = detmon_ronbias_config.overscan_urx -
2532  detmon_ronbias_config.prescan_llx + 1;
2533 
2534  double * mean_x = (double *) cpl_malloc(sizeof(double) * distance);
2535 
2536  double * xvalues = (double *) cpl_malloc(sizeof(double) * distance);
2537 
2538  cpl_vector *x = NULL;
2539  cpl_vector *y = NULL;
2540 
2541  cpl_polynomial *poly = NULL;
2542  cpl_polynomial *poly2 = NULL;
2543 
2544  cpl_matrix * samppos;
2545 
2546  cpl_size pows[2] = { 0, 0 };
2547 
2548  cpl_image * synthetic = NULL;
2549 
2550  double initial = 0;
2551 
2552  /* Initialize */
2553  for(j = 0; j < distance; j++) {
2554  *(mean_x + j) = 0;
2555  *(xvalues + j) = j;
2556  }
2557 
2558  for(j = 0; j < cpl_image_get_size_x(prescan); j++) {
2559  *(mean_x + j) =
2560  cpl_image_get_mean_window(prescan, j + 1, 1, j + 1,
2561  cpl_image_get_size_y(prescan));
2562  }
2563 
2564  for(j = 0; j < cpl_image_get_size_x(overscan); j++) {
2565  *(mean_x + distance - cpl_image_get_size_x(overscan) + j) =
2566  cpl_image_get_mean_window(overscan, j + 1, 1, j + 1,
2567  cpl_image_get_size_y(overscan));
2568  }
2569 
2570  x = cpl_vector_wrap(distance, xvalues);
2571  y = cpl_vector_wrap(distance, mean_x);
2572 
2573  poly = cpl_polynomial_new(1);
2574  samppos =
2575  cpl_matrix_wrap(1, cpl_vector_get_size(x), cpl_vector_get_data(x));
2576 
2577  cpl_polynomial_fit(poly, samppos, NULL, y, NULL,
2578  CPL_FALSE, NULL, &detmon_ronbias_config.preoverscan_degree);
2579 
2580  cpl_matrix_unwrap(samppos);
2581 
2582  cpl_vector_unwrap(x);
2583  cpl_vector_unwrap(y);
2584 
2585  initial = *mean_x;
2586 
2587  cpl_free(xvalues);
2588  cpl_free(mean_x);
2589 
2590  poly2 = cpl_polynomial_new(2);
2591 
2592  j = 0;
2593  cpl_polynomial_set_coeff(poly2, pows, cpl_polynomial_get_coeff(poly, &j));
2594 
2595  pows[0] = 1;
2596  j = 1;
2597  cpl_polynomial_set_coeff(poly2, pows, cpl_polynomial_get_coeff(poly, &j));
2598 
2599  cpl_polynomial_delete(poly);
2600 
2601  synthetic =
2602  cpl_image_new(distance, cpl_image_get_size_y(prescan),
2603  CPL_TYPE_DOUBLE);
2604 
2605  if(cpl_image_fill_polynomial(synthetic, poly2, initial, 1, 1, 1)) {
2606  cpl_msg_error(cpl_func, "Error creating the synthetic frame");
2607  cpl_polynomial_delete(poly2);
2608  return NULL;
2609  }
2610 
2611  cpl_polynomial_delete(poly2);
2612 
2613  return synthetic;
2614 }
2615 
2616 /*---------------------------------------------------------------------------*/
2617 
2618 /*
2619  * @brief Retrieve input parameters
2620  * @param pipeline_name Input image
2621  * @param recipe_name Input image
2622  * @param parlist Shift to apply on the x-axis
2623  * @return CPL_ERROR_NONE on success.
2624  */
2625 
2626 /*---------------------------------------------------------------------------*/
2627 static cpl_error_code
2628 detmon_ronbias_dutycycl(const cpl_frameset * frameset,
2629  cpl_propertylist * qclist)
2630 {
2631  const cpl_frame *first = 0;
2632  cpl_propertylist *plistfirst = 0;
2633  double tfirst;
2634  int nraws;
2635  const cpl_frame *last = 0;
2636  cpl_propertylist *plistlast = 0;
2637  double tlast;
2638  double dutycycl;
2639  cpl_error_code error;
2640 
2641  first = cpl_frameset_get_first_const(frameset);
2642  plistfirst = cpl_propertylist_load(cpl_frame_get_filename(first), 0);
2643  tfirst = cpl_propertylist_get_double(plistfirst, "MJD-OBS");
2644  nraws = cpl_frameset_get_size(frameset);
2645  last = cpl_frameset_get_frame_const(frameset, nraws - 1);
2646  plistlast = cpl_propertylist_load(cpl_frame_get_filename(last), 0);
2647  tlast = cpl_propertylist_get_double(plistlast, "MJD-OBS");
2648  dutycycl = (tlast - tfirst) / (nraws - 1);
2649 
2650  error = cpl_error_get_code();
2651  if (error != CPL_ERROR_NONE)
2652  {
2653  goto cleanup;
2654  }
2655  cpl_propertylist_append_double(qclist,DETMON_QC_DUTYCYCL, dutycycl);
2656  error = cpl_propertylist_set_comment(qclist,DETMON_QC_DUTYCYCL,
2657  DETMON_QC_DUTYCYCL_C);
2658 
2659 cleanup:
2660 
2661  cpl_propertylist_delete(plistfirst);
2662  cpl_propertylist_delete(plistlast);
2663 
2664  return error;
2665 }
2666 
2667 
2668 /*--------------------------------------------------------------------------*/
2669 
2670 /*
2671  * @brief Reduce periodic noise
2672  * @param image Input image
2673  * @param freq Readout frequency, given in Kpixel/s.
2674  *
2675  * @return 1-d image, representing the distribution of noise. NULL if failed.
2676  */
2677 
2678 /*--------------------------------------------------------------------------*/
2679 
2680 
2681 #define HORIZONTAL TRUE
2682 
2683 cpl_table *
2684 detmon_pernoise_reduce(cpl_image * image)
2685 {
2686  int nsamples, nffts;
2687  int i, j;
2688 
2689  int status;
2690  float * hanning = 0;
2691  float * power = 0;
2692  cpl_image * power_im = 0;
2693  cpl_image * output = 0;
2694  cpl_image * pos_spec = 0;
2695  cpl_table * table = 0;
2696  cpl_image* fourier_im = 0;
2697  double freq;
2698  cpl_error_code error = CPL_ERROR_NONE;
2699  cpl_image * sub_image = 0;
2700  int nffts_old;
2701 
2702 
2703  if(detmon_pernoise_config.direction == HORIZONTAL) {
2704  error = cpl_image_flip(image, 1);
2705  cpl_ensure(!error, error, NULL);
2706  }
2707 
2708  nsamples = cpl_image_get_size_x(image);
2709  nffts = cpl_image_get_size_y(image);
2710 
2711 
2712  /* Rewrite the previous lines with a better style (: ...) */
2713 
2714  /*
2715  * 1. preprocessing task:
2716  * Estimate the background fitting the image to a
2717  * 2-D polynomial and substract it from the image.
2718  */
2719 
2720  error = detmon_pernoise_rm_bg(image, nsamples, nffts);
2721  cpl_ensure(!error, error, NULL);
2722 
2723  sub_image = cpl_image_extract(image, nsamples/8 + 1, nffts/8+1,
2724  nsamples*7/8, nffts*7/8);
2725  nffts_old = nffts;
2726  nsamples = cpl_image_get_size_x(sub_image);
2727  nffts = cpl_image_get_size_y(sub_image);
2728 
2729  /*
2730  * 2. preprocessing task:
2731  * Remove the effect of hot and dark pixels, replacing their values by
2732  * the average value of the neighbouring pixels.
2733  */
2734 
2735  /*
2736  * 3. preprocessing task:
2737  * Apply a Hanning vector
2738  */
2739 
2740  hanning = cpl_malloc(sizeof(float) * nsamples);
2741 
2742  for(i = 0; i < nsamples; i++) {
2743  *(hanning + i) = 0.5 - 0.5 * cos(2 * CPL_MATH_PI * (float) i / nsamples);
2744  for(j = 0; j < nffts; j++) {
2745  double value =
2746  cpl_image_get(sub_image, i + 1, j + 1, &status);
2747  error = cpl_image_set(sub_image, i + 1, j + 1, (*(hanning + i)) * value);
2748  }
2749  }
2750 
2751  cpl_free(hanning);
2752  if (error != CPL_ERROR_NONE)
2753  {
2754  goto cleanup;
2755  }
2756 
2757  power = (float *) cpl_calloc(sizeof(float), nsamples * nffts);
2758 
2759 
2760  fourier_im = cpl_image_new(nsamples,nffts, CPL_TYPE_FLOAT_COMPLEX);
2761  error = cpl_fft_image(fourier_im, sub_image, CPL_FFT_FORWARD);
2762 
2763  for(i = 1; i <= nffts; i++) {
2764  for(j = 1; j <= nsamples; j++) {
2765  int rej = 0;
2766  double complex cvalue = cpl_image_get_complex(fourier_im,j, i, &rej );
2767  double value = cabs(cvalue);
2768  /*
2769  *(power + j + i * nsamples) = *((float complex *)fourier + j + i * nsamples) *
2770  conjf(*((float complex *)fourier +j + i * nsamples));
2771  */
2772  cpl_image_set(power_im, j, i, value);
2773  }
2774  /* Is it necessary to divide here by 2 * pi? */
2775  }
2776  cpl_image_delete(fourier_im);
2777 
2778  output = cpl_image_collapse_create(power_im, 0);
2779  pos_spec = cpl_image_extract(output, 1, 1, nsamples/2, 1);
2780 
2781  cpl_image_delete(power_im);
2782  cpl_free(power);
2783 
2784  cpl_image_delete(output);
2785 
2786  table = cpl_table_new(nsamples/2);
2787  cpl_table_new_column(table, "FREQ", CPL_TYPE_DOUBLE);
2788  cpl_table_new_column(table, "POW", CPL_TYPE_DOUBLE);
2789 
2790  freq = detmon_pernoise_config.speed*1000/nffts_old;
2791 
2792  for(i = 0; i < nsamples/2; i++) {
2793  error = cpl_table_set(table, "FREQ", i, freq/(nsamples/2)*i);
2794  error = cpl_table_set(table, "POW", i, cpl_image_get(pos_spec, i+1, 1, &status));
2795  }
2796 
2797  for(i= 0; i < 5; i++) {
2798  error = cpl_table_set(table, "POW", i, 0.0);
2799  }
2800 
2801 
2802 cleanup:
2803  cpl_image_delete(pos_spec);
2804 
2805  cpl_image_delete(sub_image);
2806  if (error != CPL_ERROR_NONE)
2807  {
2808  cpl_table_delete(table);
2809  table = 0;
2810  }
2811  return table;
2812 }
2813 #undef HORIZONTAL
2814 
2815 
2816 
2817 /*---------------------------------------------------------------------------*/
2818 
2819 /*
2820  * @brief Retrieve input parameters
2821  * @param pipeline_name Input image
2822  * @param recipe_name Input image
2823  * @param parlist Shift to apply on the x-axis
2824  * @return CPL_ERROR_NONE on success.
2825  */
2826 
2827 /*---------------------------------------------------------------------------*/
2828 
2829 
2830 cpl_error_code
2831 detmon_rm_bpixs(cpl_image ** image,
2832  const double kappa, int nffts, int nsamples)
2833 {
2834  int i, j;
2835 
2836  float *data = cpl_image_get_data_float(*image);
2837  int k = 0;
2838  for(i = 0; i < nffts; i++) {
2839  for(j = 0; j < nsamples; j++) {
2840  float neighbours = 0;
2841  int nneighs = 0;
2842  float average = 0;
2843 
2844  /*
2845  * Look for the way to optimize this:
2846  * Some of the points added to neighbours coincide
2847  * in one iteration and the following
2848  */
2849  if(i > 0) {
2850  neighbours += *(data + (i - 1) * nsamples + j);
2851  nneighs++;
2852  }
2853  if(i < nffts - 1) {
2854  neighbours += *(data + (i + 1) * nsamples + j);
2855  nneighs++;
2856  }
2857  if(j > 0) {
2858  neighbours += *(data + i * nsamples + (j - 1));
2859  nneighs++;
2860  }
2861  if(j < nsamples - 1) {
2862  neighbours += *(data + i * nsamples + (j + 1));
2863  nneighs++;
2864  }
2865  average = neighbours / nneighs;
2866  if(average > 0) {
2867  if(*(data + i * nsamples + j) < average * (-1 * kappa) ||
2868  *(data + i * nsamples + j) > average * (kappa)) {
2869  k++;
2870  *(data + i * nsamples + j) = average;
2871  }
2872  }
2873  if(average < 0) {
2874  if(*(data + i * nsamples + j) > average * (-1 * kappa) ||
2875  *(data + i * nsamples + j) < average * (kappa)) {
2876  k++;
2877  *(data + i * nsamples + j) = average;
2878  }
2879  }
2880 
2881  }
2882  }
2883 
2884 
2885  return cpl_error_get_code();
2886 
2887 }
2888 
2889 /* Start duplicated code */
2890 
2891 #define RECT_RON_HS 4
2892 #define RECT_RON_SAMPLES 100
2893 
2894 /*---------------------------------------------------------------------------*/
2895 
2896 /*
2897  * @brief Retrieve input parameters
2898  * @param pipeline_name Input image
2899  * @param recipe_name Input image
2900  * @param parlist Shift to apply on the x-axis
2901  * @return CPL_ERROR_NONE on success.
2902  */
2903 
2904 /*---------------------------------------------------------------------------*/
2905 cpl_error_code
2906 irplib_flux_get_bias_window(const cpl_image * diff,
2907  const int *zone_def,
2908  int ron_hsize,
2909  int ron_nsamp, double *bias, double *error)
2910 {
2911  const int hsize = ron_hsize < 0 ? RECT_RON_HS : ron_hsize;
2912  const int nsamples =
2913  ron_nsamp < 0 ? RECT_RON_SAMPLES : ron_nsamp;
2914  cpl_bivector *sample_reg;
2915  cpl_vector *rms_list;
2916  int rect[4];
2917  int zone[4];
2918  double *px;
2919  double *py;
2920  double *pr;
2921  int i;
2922 
2923  /* Test entries */
2924  cpl_ensure_code(diff && bias, CPL_ERROR_NULL_INPUT);
2925 
2926  /* Generate nsamples window centers in the image */
2927  if(zone_def != NULL) {
2928  rect[0] = zone_def[0] + hsize + 1; /* xmin */
2929  rect[1] = zone_def[1] - hsize - 1; /* xmax */
2930  rect[2] = zone_def[2] + hsize + 1; /* ymin */
2931  rect[3] = zone_def[3] - hsize - 1; /* ymax */
2932  } else {
2933  rect[0] = hsize + 1; /* xmin */
2934  rect[1] = cpl_image_get_size_x(diff) - hsize - 1; /* xmax */
2935  rect[2] = hsize + 1; /* ymin */
2936  rect[3] = cpl_image_get_size_y(diff) - hsize - 1; /* ymax */
2937  }
2938 
2939  cpl_ensure_code(rect[0] < rect[1] && rect[2] < rect[3],
2940  CPL_ERROR_ILLEGAL_INPUT);
2941 
2942  /* Generate n+1 regions, because the first region is always at (0,0) */
2943  /* and it would bias the measurement. */
2944  sample_reg =
2945  irplib_bivector_gen_rect_poisson(rect, nsamples + 1, nsamples + 1);
2946  cpl_ensure(sample_reg != NULL, CPL_ERROR_ILLEGAL_INPUT,
2947  CPL_ERROR_ILLEGAL_INPUT);
2948 
2949  px = cpl_bivector_get_x_data(sample_reg);
2950  py = cpl_bivector_get_y_data(sample_reg);
2951 
2952  /* Now, for each window center, extract a vignette and compute the */
2953  /* signal RMS in it. Store this rms into a table. */
2954  rms_list = cpl_vector_new(nsamples);
2955  cpl_ensure(rms_list != NULL, CPL_ERROR_NULL_INPUT, CPL_ERROR_NULL_INPUT);
2956  pr = cpl_vector_get_data(rms_list);
2957 
2958  for(i = 0; i < nsamples; i++) {
2959  zone[0] = (int) px[i + 1] - hsize;
2960  zone[1] = (int) px[i + 1] + hsize;
2961  zone[2] = (int) py[i + 1] - hsize;
2962  zone[3] = (int) py[i + 1] + hsize;
2963  pr[i] = cpl_image_get_mean_window(diff,
2964  zone[0], zone[2], zone[1], zone[3]);
2965  }
2966  cpl_bivector_delete(sample_reg);
2967 
2968  /* The error is the rms of the rms */
2969  if(error != NULL)
2970  *error = cpl_vector_get_stdev(rms_list);
2971 
2972  /* The final computed RMS is the median of all values. */
2973  /* This call will modify the rms_list */
2974  *bias = cpl_vector_get_median(rms_list);
2975 
2976  cpl_vector_delete(rms_list);
2977 
2978  return CPL_ERROR_NONE;
2979 }
2980 
2981 #undef RECT_RON_HS
2982 #undef RECT_RON_SAMPLES
2983 
2984 /*---------------------------------------------------------------------------*/
2985 
2986 /*
2987  * @brief Retrieve input parameters
2988  * @param pipeline_name Input image
2989  * @param recipe_name Input image
2990  * @param parlist Shift to apply on the x-axis
2991  * @return CPL_ERROR_NONE on success.
2992  */
2993 
2994 /*---------------------------------------------------------------------------*/
2995 static cpl_bivector *
2996 irplib_bivector_gen_rect_poisson(const int *r, const int np, const int homog)
2997 {
2998  double min_dist;
2999  int i;
3000  int gnp;
3001  cpl_bivector *list;
3002  double cand_x, cand_y;
3003  int ok;
3004  int start_ndx;
3005  int xmin, xmax, ymin, ymax;
3006 
3007  /* Corrected Homogeneity factor */
3008  const int homogc = 0 < homog && homog < np ? homog : np;
3009  double *px;
3010  double *py;
3011 
3012  /* error handling: test arguments are correct */
3013  cpl_ensure(r, CPL_ERROR_NULL_INPUT, NULL);
3014  cpl_ensure(np > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
3015 
3016  list = cpl_bivector_new(np);
3017  cpl_ensure(list, CPL_ERROR_NULL_INPUT, NULL);
3018  px = cpl_bivector_get_x_data(list);
3019  py = cpl_bivector_get_y_data(list);
3020 
3021  xmin = r[0];
3022  xmax = r[1];
3023  ymin = r[2];
3024  ymax = r[3];
3025 
3026  min_dist =
3027  CPL_MATH_SQRT1_2 * ((xmax - xmin) * (ymax - ymin) / (double) (homogc + 1));
3028  gnp = 1;
3029  px[0] = 0;
3030  py[0] = 0;
3031 
3032  /* First: generate <homog> points */
3033  while(gnp < homogc) {
3034  /* Pick a random point within requested range */
3035  cand_x = cpl_drand() * (xmax - xmin) + xmin;
3036  cand_y = cpl_drand() * (ymax - ymin) + ymin;
3037 
3038  /* Check the candidate obeys the minimal Poisson distance */
3039  ok = 1;
3040  for(i = 0; i < gnp; i++) {
3041  if(pdist(cand_x, cand_y, px[i], py[i]) < min_dist) {
3042  /* does not check Poisson law: reject point */
3043  ok = 0;
3044  break;
3045  }
3046  }
3047  if(ok) {
3048  /* obeys Poisson law: register the point as valid */
3049  px[gnp] = cand_x;
3050  py[gnp] = cand_y;
3051  gnp++;
3052  }
3053  }
3054 
3055  /* Iterative process: */
3056  /* Pick points out of Poisson distance of the last <homogc-1> points. */
3057  start_ndx = 0;
3058  while(gnp < np) {
3059  /* Pick a random point within requested range */
3060  cand_x = cpl_drand() * (xmax - xmin) + xmin;
3061  cand_y = cpl_drand() * (ymax - ymin) + ymin;
3062 
3063  /* Check the candidate obeys the minimal Poisson distance */
3064  ok = 1;
3065  for(i = 0; i < homogc; i++) {
3066  if(pdist(cand_x,
3067  cand_y,
3068  px[start_ndx + i], py[start_ndx + i]) < min_dist) {
3069  /* does not check Poisson law: reject point */
3070  ok = 0;
3071  break;
3072  }
3073  }
3074  if(ok) {
3075  /* obeys Poisson law: register the point as valid */
3076  px[gnp] = cand_x;
3077  py[gnp] = cand_y;
3078  gnp++;
3079  }
3080  }
3081 
3082  /* Iterative process: */
3083  /* Pick points out of Poisson distance of the last <homogc-1> points. */
3084  start_ndx = 0;
3085  while(gnp < np) {
3086  /* Pick a random point within requested range */
3087  cand_x = cpl_drand() * (xmax - xmin) + xmin;
3088  cand_y = cpl_drand() * (ymax - ymin) + ymin;
3089 
3090  /* Check the candidate obeys the minimal Poisson distance */
3091  ok = 1;
3092  for(i = 0; i < homogc; i++) {
3093  if(pdist(cand_x,
3094  cand_y,
3095  px[start_ndx + i], py[start_ndx + i]) < min_dist) {
3096  /* does not check Poisson law: reject point */
3097  ok = 0;
3098  break;
3099  }
3100  }
3101  if(ok) {
3102  /* obeys Poisson law: register the point as valid */
3103  px[gnp] = cand_x;
3104  py[gnp] = cand_y;
3105  gnp++;
3106  start_ndx++;
3107  }
3108  }
3109  return list;
3110 }
3111 
3112 /* End of duplicated code */
3113 
3114 /*---------------------------------------------------------------------------*/
3115 
3116 /*
3117  * @brief Retrieve input parameters
3118  * @param pipeline_name Input image
3119  * @param recipe_name Input image
3120  * @param parlist Shift to apply on the x-axis
3121  * @return CPL_ERROR_NONE on success.
3122  */
3123 
3124 /*---------------------------------------------------------------------------*/
3125 cpl_error_code
3126 detmon_pernoise(cpl_frameset * frameset,
3127  const cpl_parameterlist * parlist,
3128  const char * tag,
3129  const char * recipe_name,
3130  const char * pipeline_name,
3131  const char * procatg_tbl,
3132  const char * package,
3133  int (*compare)(const cpl_frame *,
3134  const cpl_frame *))
3135 {
3136  cpl_size nsets;
3137  cpl_size *selection = NULL;
3138  int i;
3139  cpl_error_code error;
3140 
3141  if(detmon_pernoise_dfs_set_groups(frameset, tag)) {
3142  cpl_msg_error(cpl_func, "Cannot identify RAW and CALIB frames");
3143  }
3144 
3145  /*
3146  * This function reads all inputs parameters from parlist
3147  * and stores them in a global variable detmon_ronbias_config.
3148  * Similar to detmon_lg_retrieve_parlist(). See detmon.c
3149  */
3150  error = detmon_pernoise_retrieve_parlist(pipeline_name,
3151  recipe_name, parlist);
3152  cpl_ensure_code(!error, error);
3153 
3154  /* Labelise all input frames */
3155  if(compare == NULL)
3156  nsets = 1;
3157  else {
3158  cpl_msg_info(cpl_func, "Identify the different settings");
3159  selection = cpl_frameset_labelise(frameset, compare, &nsets);
3160  if(selection == NULL)
3161  cpl_msg_error(cpl_func, "Cannot labelise input frames");
3162  }
3163 
3164  detmon_pernoise_config.nb_extensions = 1;
3165  if(detmon_pernoise_config.exts < 0) {
3166  const cpl_frame *cur_frame =
3167  cpl_frameset_get_first_const(frameset);
3168  /* Get the nb of extensions */
3169  detmon_pernoise_config.nb_extensions =
3170  cpl_frame_get_nextensions(cur_frame);
3171  }
3172 
3173  /* Extract settings and reduce each of them */
3174  for(i = 0; i < nsets; i++)
3175  {
3176  int j;
3177  cpl_table ** freq_table;
3178  cpl_propertylist ** qclist =
3179  (cpl_propertylist **)
3180  cpl_malloc(detmon_pernoise_config.nb_extensions *
3181  sizeof(cpl_propertylist *));
3182 
3183  cpl_imagelist ** raws = (cpl_imagelist **) cpl_malloc(detmon_pernoise_config.nb_extensions * sizeof(cpl_imagelist *));
3184  cpl_image ** input = (cpl_image **) cpl_malloc(detmon_pernoise_config.nb_extensions * sizeof(cpl_image *));
3185 
3186  /* Initialise memory for products */
3187  if(detmon_pernoise_config.mode == 1)
3188  {
3189  freq_table =
3190  (cpl_table **) cpl_malloc(detmon_pernoise_config.nb_extensions *
3191  4 * sizeof(cpl_table *));
3192  } else
3193  {
3194  freq_table =
3195  (cpl_table **) cpl_malloc(detmon_pernoise_config.nb_extensions *
3196  sizeof(cpl_table *));
3197  }
3198 
3199  if(detmon_pernoise_config.exts >= 0)
3200  {
3201  *raws =
3202  cpl_imagelist_load_frameset(frameset, CPL_TYPE_FLOAT, 1,
3203  detmon_pernoise_config.exts);
3204  *input = cpl_image_subtract_create(cpl_imagelist_get(*raws,0),
3205  cpl_imagelist_get(*raws,1));
3206  } else
3207  {
3208  cpl_imagelist *raws_all_exts =
3209  cpl_imagelist_load_frameset(frameset, CPL_TYPE_FLOAT, 1,
3210  -1);
3211  for(j = 0; j < detmon_pernoise_config.nb_extensions; j++)
3212  {
3213  int nframes = cpl_frameset_get_size(frameset);
3214  int k;
3215  for(k = 0; k < nframes; k++)
3216  {
3217  cpl_image *image =
3218  cpl_imagelist_unset(raws_all_exts,
3219  (detmon_pernoise_config.
3220  nb_extensions - 1 - j) * k);
3221  cpl_imagelist_set(raws[j], image, k);
3222  }
3223  input[j] =
3224  cpl_image_subtract_create(cpl_imagelist_get(raws[j],0),
3225  cpl_imagelist_get(raws[j],1));
3226  }
3227  }
3228 
3229  for(j = 0; j < detmon_pernoise_config.nb_extensions; j++) {
3230  cpl_msg_info(cpl_func, "Starting reduction");
3231  qclist[j] = cpl_propertylist_new();
3232  if(detmon_pernoise_config.mode == 1)
3233  {
3234  int nx = cpl_image_get_size_x(input[j]);
3235  int ny = cpl_image_get_size_y(input[j]);
3236  int k = 0;
3237  cpl_image* quad[4];
3238 
3239  quad[0] = cpl_image_extract(input[j], 1, 1, nx/2, ny/2);
3240  quad[1] = cpl_image_extract(input[j], 1, ny/2+1, nx/2, ny);
3241  quad[2] = cpl_image_extract(input[j], nx/2+1, 1, nx, ny/2);
3242  quad[3] = cpl_image_extract(input[j], nx/2+1, ny/2+1, nx, ny);
3243 
3244  for (k = 0; k < 4; k++)
3245  {
3246  freq_table[j * 4 + k] = detmon_pernoise_reduce(quad[k]);
3247  }
3248  for(k = 0; k < 4; k++)
3249  {
3250  error = detmon_pernoise_qc(qclist[j], freq_table[j + k], k+1);
3251  if (error != CPL_ERROR_NONE)
3252  break;
3253  }
3254  for (k = 0; k < 4; k++)
3255  {
3256  cpl_image_delete(quad[k]);
3257  }
3258  } else
3259  {
3260  freq_table[j] = detmon_pernoise_reduce(input[j]);
3261  if(freq_table[j] != NULL)
3262  {
3263  error = detmon_pernoise_qc(qclist[j], freq_table[j], 0);
3264  }
3265  }
3266  if (error != CPL_ERROR_NONE)
3267  {
3268  break;
3269  }
3270  }
3271  if (error == CPL_ERROR_NONE)
3272  {
3273  error = detmon_pernoise_save(parlist, frameset, recipe_name,
3274  pipeline_name, procatg_tbl,
3275  package, freq_table, qclist, 0,
3276  0, frameset);
3277  }
3278 
3279  for(j = 0; j < detmon_pernoise_config.nb_extensions; j++)
3280  {
3281  cpl_propertylist_delete(qclist[j]);
3282  cpl_imagelist_delete(raws[j]);
3283  cpl_image_delete(input[j]);
3284  }
3285  cpl_free(qclist);
3286  cpl_free(raws);
3287  cpl_free(input);
3288  if(detmon_pernoise_config.mode == 1)
3289  {
3290  for(j= 0; j < detmon_pernoise_config.nb_extensions * 4; j++) {
3291  cpl_table_delete(freq_table[j]);
3292  }
3293  } else {
3294  for(j= 0; j < detmon_pernoise_config.nb_extensions; j++) {
3295  cpl_table_delete(freq_table[j]);
3296  }
3297  }
3298  cpl_free(freq_table);
3299  if (error != CPL_ERROR_NONE)
3300  {
3301  break;
3302  }
3303  }
3304 
3305  return cpl_error_get_code();
3306 }
3307 
3308 /*---------------------------------------------------------------------------*/
3309 
3310 /*
3311  * @brief Retrieve input parameters
3312  * @param pipeline_name Input image
3313  * @param recipe_name Input image
3314  * @param parlist Shift to apply on the x-axis
3315  * @return CPL_ERROR_NONE on success.
3316  */
3317 
3318 /*---------------------------------------------------------------------------*/
3319 int
3320 detmon_pernoise_dfs_set_groups(cpl_frameset * set, const char *tag)
3321 {
3322  cpl_frame *cur_frame;
3323  const char *cur_tag;
3324  int nframes;
3325  int i;
3326 
3327  /* Check entries */
3328  if(set == NULL)
3329  return -1;
3330 
3331  /* Initialize */
3332  nframes = cpl_frameset_get_size(set);
3333 
3334  /* Loop on frames */
3335  for(i = 0; i < nframes; i++) {
3336  cur_frame = cpl_frameset_get_frame(set, i);
3337  cur_tag = cpl_frame_get_tag(cur_frame);
3338 
3339  /* RAW frames */
3340  if(!strcmp(cur_tag, tag))
3341  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_RAW);
3342  /* CALIB frames */
3343 
3344  /* else if (!strcmp(tag, IIINSTRUMENT_CALIB_FLAT))
3345  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_CALIB) ;
3346  */
3347  }
3348  return 0;
3349 }
3350 
3351 /*---------------------------------------------------------------------------*/
3352 
3353 /*
3354  * @brief Retrieve input parameters
3355  * @param pipeline_name Input image
3356  * @param recipe_name Input image
3357  * @param parlist Shift to apply on the x-axis
3358  * @return CPL_ERROR_NONE on success.
3359  */
3360 
3361 /*---------------------------------------------------------------------------*/
3362  cpl_error_code
3363 detmon_fill_pernoise_params(cpl_parameterlist * parlist,
3364  const char *recipe_name,
3365  const char *pipeline_name,
3366  int mode,
3367  const char * direction,
3368  double speed,
3369  int llx,
3370  int lly,
3371  int urx,
3372  int ury,
3373  double kappa,
3374  int exts)
3375 {
3376  detmon_fill_parlist(parlist, recipe_name, pipeline_name, 9,
3377 
3378  "mode",
3379  "Mode",
3380  "CPL_TYPE_INT", mode,
3381 
3382  "direction",
3383  "Readout direction",
3384  "CPL_TYPE_BOOL", direction,
3385 
3386  "speed",
3387  "Readout speed",
3388  "CPL_TYPE_DOUBLE", speed,
3389 
3390  "llx",
3391  "(yet unsupported) x coordinate of the lower-left "
3392  "point of the region of interest. If not modified, default value will be 1.",
3393  "CPL_TYPE_INT", llx,
3394  "lly",
3395  "(yet unsupported) y coordinate of the lower-left "
3396  "point of the region of interest. If not modified, default value will be 1.",
3397  "CPL_TYPE_INT", lly,
3398  "urx",
3399  "(yet unsupported) x coordinate of the upper-right "
3400  "point of the region of interest. If not modified, default value will be X dimension of the input image.",
3401  "CPL_TYPE_INT", urx,
3402  "ury",
3403  "(yet unsupported) y coordinate of the upper-right "
3404  "point of the region of interest. If not modified, default value will be Y dimension of the input image.",
3405  "CPL_TYPE_INT", ury,
3406 
3407  "kappa",
3408  "Kappa used for determining threshold of bad (hot, cold) pixels",
3409  "CPL_TYPE_DOUBLE", kappa,
3410 
3411  "exts",
3412  "Activate the multi-exts option",
3413  "CPL_TYPE_INT", exts);
3414 
3415  return 0;
3416 }
3417 
3418 /*---------------------------------------------------------------------------*/
3419 
3420 /*
3421  * @brief Retrieve input parameters
3422  * @param pipeline_name Input image
3423  * @param recipe_name Input image
3424  * @param parlist Shift to apply on the x-axis
3425  * @return CPL_ERROR_NONE on success.
3426  */
3427 
3428 /*---------------------------------------------------------------------------*/
3429 int
3430 detmon_fill_pernoise_params_default(cpl_parameterlist * parlist,
3431  const char *recipe_name,
3432  const char *pipeline_name)
3433 {
3434  detmon_fill_pernoise_params(parlist, recipe_name, pipeline_name,
3435  1, /* --mode */
3436  "CPL_TRUE", /* --direction */
3437  84.5, /* --speed */
3438  -1, /* --llx */
3439  -1, /* --lly */
3440  -1, /* --urx */
3441  -1, /* --ury */
3442  100, /* --kappa */
3443  0); /* --exts */
3444 
3445  return 0;
3446 
3447 }
3448 
3449 
3450 static cpl_error_code
3451 detmon_pernoise_retrieve_parlist(const char *pipeline_name,
3452  const char *recipe_name,
3453  const cpl_parameterlist * parlist)
3454 {
3455  char *par_name;
3456  cpl_parameter *par;
3457 
3458  /* --mode */
3459  detmon_pernoise_config.mode =
3460  detmon_retrieve_par_int("mode", pipeline_name, recipe_name,
3461  parlist);
3462 
3463  /* --direction */
3464  par_name = cpl_sprintf("%s.%s.direction", pipeline_name, recipe_name);
3465  assert(par_name != NULL);
3466  par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
3467  detmon_pernoise_config.direction = cpl_parameter_get_bool(par);
3468  cpl_free(par_name);
3469 
3470  /* --speed */
3471  par_name = cpl_sprintf("%s.%s.speed", pipeline_name, recipe_name);
3472  assert(par_name != NULL);
3473  par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
3474  detmon_pernoise_config.speed = cpl_parameter_get_double(par);
3475  cpl_free(par_name);
3476 
3477  /* --llx */
3478  detmon_pernoise_config.llx =
3479  detmon_retrieve_par_int("llx", pipeline_name, recipe_name,
3480  parlist);
3481 
3482  /* --lly */
3483  detmon_pernoise_config.lly =
3484  detmon_retrieve_par_int("lly", pipeline_name, recipe_name,
3485  parlist);
3486  /* --urx */
3487  detmon_pernoise_config.urx =
3488  detmon_retrieve_par_int("urx", pipeline_name, recipe_name,
3489  parlist);
3490  /* --ury */
3491  detmon_pernoise_config.ury =
3492  detmon_retrieve_par_int("ury", pipeline_name, recipe_name,
3493  parlist);
3494  /* --kappa */
3495  detmon_pernoise_config.kappa =
3496  detmon_retrieve_par_double("kappa", pipeline_name, recipe_name,
3497  parlist);
3498 
3499  /* --exts */
3500  detmon_pernoise_config.exts =
3501  detmon_retrieve_par_int("exts", pipeline_name, recipe_name,
3502  parlist);
3503 
3504  if(cpl_error_get_code()) {
3505  cpl_msg_error(cpl_func, "Failed to retrieve the input parameters");
3506  cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
3507  }
3508 
3509  return cpl_error_get_code();
3510 }
3511 
3512 /*---------------------------------------------------------------------------*/
3513 
3514 /*
3515  * @brief Retrieve input parameters
3516  * @param pipeline_name Input image
3517  * @param recipe_name Input image
3518  * @param parlist Shift to apply on the x-axis
3519  * @return CPL_ERROR_NONE on success.
3520  */
3521 
3522 /*---------------------------------------------------------------------------*/
3523 static cpl_error_code
3524 detmon_pernoise_save(const cpl_parameterlist * parlist,
3525  cpl_frameset * frameset,
3526  const char *recipe_name,
3527  const char *pipeline_name,
3528  const char *procatg_tbl,
3529  const char *package,
3530  cpl_table ** freq_table,
3531  cpl_propertylist ** qclist,
3532  const int flag_sets,
3533  const int which_set,
3534  const cpl_frameset * usedframes)
3535 {
3536 
3537  cpl_frame *ref_frame;
3538  cpl_propertylist *plist;
3539  char *name_o = NULL; /* Avoid (false) uninit warning */
3540  int i, j;
3541  cpl_propertylist *paflist;
3542  cpl_error_code error;
3543 
3544  cpl_propertylist * pro_tbl = cpl_propertylist_new();
3545 
3546  cpl_propertylist_append_string(pro_tbl,
3547  CPL_DFS_PRO_CATG, procatg_tbl);
3548 
3549  cpl_propertylist_append(pro_tbl, qclist[0]);
3550 
3551  /*******************************/
3552  /* Write the FREQ TABLE */
3553 
3554  /*******************************/
3555 
3556  if(detmon_pernoise_config.mode != 1) {
3557  /* Set the file name for the table */
3558  if(!flag_sets) {
3559  name_o = cpl_sprintf("%s_freq_table.fits", recipe_name);
3560  assert(name_o != NULL);
3561  } else {
3562  name_o =
3563  cpl_sprintf("%s_freq_table_set%02d.fits", recipe_name,
3564  which_set);
3565  assert(name_o != NULL);
3566  }
3567 
3568  /* Save the table */
3569  if(cpl_dfs_save_table(frameset, NULL, parlist, usedframes, NULL, freq_table[0],
3570  NULL, recipe_name, pro_tbl, NULL,
3571  package, name_o)) {
3572  cpl_msg_error(cpl_func, "Cannot save the product: %s", name_o);
3573  cpl_free(name_o);
3574  cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
3575  }
3576 
3577  if(detmon_pernoise_config.exts < 0) {
3578 
3579  for(i = 1; i < detmon_pernoise_config.nb_extensions; i++) {
3580  error =
3581  cpl_table_save(freq_table[i], NULL, qclist[i], name_o,
3582  CPL_IO_EXTEND);
3583  cpl_ensure_code(!error, error);
3584  }
3585  }
3586 
3587  /* Free */
3588  cpl_free(name_o);
3589 
3590  } else {
3591  for (j = 1; j <= 4; j++) {
3592  /* Set the file name for the table */
3593  if(!flag_sets) {
3594  name_o = cpl_sprintf("%s_freq_table_quad%02d.fits",
3595  recipe_name, j);
3596  assert(name_o != NULL);
3597  } else {
3598  name_o =
3599  cpl_sprintf("%s_freq_table_quad%02d_set%02d.fits",
3600  recipe_name, j, which_set);
3601  assert(name_o != NULL);
3602  }
3603 
3604  /* Save the table */
3605  if(cpl_dfs_save_table(frameset, NULL, parlist, usedframes, NULL,
3606  freq_table[j - 1],
3607  NULL, recipe_name, pro_tbl, NULL,
3608  package, name_o)) {
3609  cpl_msg_error(cpl_func, "Cannot save the product: %s", name_o);
3610  cpl_free(name_o);
3611  cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
3612  }
3613 
3614  if(detmon_pernoise_config.exts < 0) {
3615  for(i = 1; i < detmon_pernoise_config.nb_extensions; i++) {
3616  error = cpl_table_save(freq_table[(j-1) + 4 * i],
3617  NULL, qclist[i], name_o,
3618  CPL_IO_EXTEND);
3619  cpl_ensure_code(!error, error);
3620  }
3621  }
3622 
3623  /* Free */
3624  cpl_free(name_o);
3625  }
3626 
3627  }
3628  /*******************************/
3629  /* Write the PAF file(s) */
3630  /*******************************/
3631 
3632  /* Get FITS header from reference file */
3633  ref_frame = cpl_frameset_get_first(frameset);
3634  if((plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
3635  0)) == NULL) {
3636  cpl_msg_error(cpl_func, "getting header from reference frame");
3637  cpl_ensure_code(0, cpl_error_get_code());
3638  }
3639 
3640  /* Get the keywords for the paf file */
3641  paflist = cpl_propertylist_new();
3642  cpl_propertylist_copy_property_regexp(paflist, plist,
3643  "^(ARCFILE|MJD-OBS|ESO TPL ID|"
3644  "DATE-OBS|ESO DET DIT|ESO DET NDIT|"
3645  "ESO DET NCORRS|"
3646  "ESO DET MODE NAME)$", 0);
3647 
3648  for(i = 0; i < detmon_pernoise_config.nb_extensions; i++) {
3649  cpl_propertylist * c_paflist = cpl_propertylist_duplicate(paflist);
3650  error = cpl_propertylist_append(c_paflist, qclist[i]);
3651  cpl_ensure_code(!error, error);
3652 
3653  /* Set the file name for the bpm */
3654  if(detmon_pernoise_config.exts >= 0) {
3655  if(!flag_sets) {
3656  name_o = cpl_sprintf("%s.paf", recipe_name);
3657  assert(name_o != NULL);
3658  } else {
3659  name_o = cpl_sprintf("%s_set%02d.paf", recipe_name, which_set);
3660  assert(name_o != NULL);
3661  }
3662  } else {
3663  if(!flag_sets) {
3664  name_o = cpl_sprintf("%s_ext%02d.paf", recipe_name, i+1);
3665  assert(name_o != NULL);
3666  } else {
3667  name_o = cpl_sprintf("%s_set%02d_ext%02d.paf", recipe_name, which_set, i+1);
3668  assert(name_o != NULL);
3669  }
3670  }
3671  /* Save the PAF */
3672  if(cpl_dfs_save_paf(pipeline_name, recipe_name, c_paflist, name_o)) {
3673  cpl_msg_error(cpl_func, "Cannot save the product: %s", name_o);
3674  cpl_free(name_o);
3675  cpl_propertylist_delete(paflist);
3676  cpl_propertylist_delete(plist);
3677  cpl_free(name_o);
3678  cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
3679  }
3680  cpl_propertylist_delete(c_paflist);
3681  cpl_free(name_o);
3682  }
3683 
3684  cpl_propertylist_delete(plist);
3685  cpl_propertylist_delete(paflist);
3686  cpl_propertylist_delete(pro_tbl);
3687  return cpl_error_get_code();
3688 }
3689 
3690 static cpl_error_code
3691 detmon_pernoise_qc(cpl_propertylist * qclist,
3692  cpl_table * table,
3693  int iquad)
3694 {
3695  cpl_error_code error;
3696  char * propname;
3697 
3698  double freqs[3] = {0, 0, 0};
3699  double pows[3] = {0, 0, 0};
3700 
3701  /* error = cpl_propertylist_append_bool(reflist, "POW", TRUE);
3702  cpl_ensure_code(!error, error);
3703 
3704  error = cpl_table_sort(table, reflist);
3705  cpl_ensure_code(!error, error);
3706  */
3707 
3708  int nrows = cpl_table_get_nrow(table);
3709  int i;
3710 
3711  double * all_freqs = cpl_table_get_data_double(table, "FREQ");
3712  double * all_pows = cpl_table_get_data_double(table, "POW");
3713 
3714  for ( i= 1; i< nrows-1; i++){
3715  if (all_pows[i] > pows[0]) {
3716  if(all_pows[i-1] < all_pows[i] && all_pows[i] > all_pows[i+1]){
3717  pows[2]=pows[1];
3718  pows[1]=pows[0];
3719  pows[0]=all_pows[i];
3720 
3721  freqs[2]=freqs[1];
3722  freqs[1]=freqs[0];
3723  freqs[0]=all_freqs[i];
3724  }
3725  } else if (all_pows[i] > pows[1]) {
3726  if(all_pows[i-1] < all_pows[i] && all_pows[i] > all_pows[i+1]){
3727  pows[2]=pows[1];
3728  pows[1]=all_pows[i];
3729 
3730  freqs[2]=freqs[1];
3731  freqs[1]=all_freqs[i];
3732  }
3733 
3734  } else if(all_pows[i] > pows[2]) {
3735  if(all_pows[i-1] < all_pows[i] && all_pows[i] > all_pows[i+1]){
3736  pows[2]=all_pows[i];
3737 
3738  freqs[2]=all_freqs[i];
3739  }
3740 
3741  }
3742  }
3743 
3744  if (detmon_pernoise_config.mode == 1) {
3745  propname = cpl_sprintf("ESO QC FREQ1 %d", iquad);
3746  assert(propname != NULL);
3747  } else {
3748  propname = cpl_sprintf("ESO QC FREQ1");
3749  }
3750 
3751  error = cpl_propertylist_append_double(qclist, propname, freqs[0]);
3752  error = cpl_propertylist_set_comment(qclist,propname,DETMON_QC_FREQ_C);
3753  cpl_ensure_code(!error, error);
3754 
3755  cpl_free(propname);
3756 
3757  if (detmon_pernoise_config.mode == 1) {
3758  propname = cpl_sprintf("ESO QC FREQ2 %d", iquad);
3759  assert(propname != NULL);
3760  } else {
3761  propname = cpl_sprintf("ESO QC FREQ2");
3762  }
3763 
3764  error = cpl_propertylist_append_double(qclist, propname, freqs[1]);
3765  error = cpl_propertylist_set_comment(qclist,propname,DETMON_QC_FREQ_C);
3766  cpl_ensure_code(!error, error);
3767 
3768  cpl_free(propname);
3769 
3770  if (detmon_pernoise_config.mode == 1) {
3771  propname = cpl_sprintf("ESO QC FREQ3 %d", iquad);
3772  assert(propname != NULL);
3773  } else {
3774  propname = cpl_sprintf("ESO QC FREQ3");
3775  }
3776 
3777  error = cpl_propertylist_append_double(qclist, propname, freqs[2]);
3778  error = cpl_propertylist_set_comment(qclist,propname,DETMON_QC_FREQ_C);
3779  cpl_ensure_code(!error, error);
3780 
3781  cpl_free(propname);
3782 
3783  if (detmon_pernoise_config.mode == 1) {
3784  propname = cpl_sprintf("ESO QC POW1 %d", iquad);
3785  assert(propname != NULL);
3786  } else {
3787  propname = cpl_sprintf("ESO QC POW1");
3788  }
3789 
3790  error = cpl_propertylist_append_double(qclist, propname, pows[0]);
3791  error = cpl_propertylist_set_comment(qclist,propname,DETMON_QC_POW_C);
3792  cpl_ensure_code(!error, error);
3793 
3794  cpl_free(propname);
3795 
3796  if (detmon_pernoise_config.mode == 1) {
3797  propname = cpl_sprintf("ESO QC POW2 %d", iquad);
3798  assert(propname != NULL);
3799  } else {
3800  propname = cpl_sprintf("ESO QC POW2");
3801  }
3802 
3803  error = cpl_propertylist_append_double(qclist, propname, pows[1]);
3804  error = cpl_propertylist_set_comment(qclist,propname,DETMON_QC_POW_C);
3805  cpl_ensure_code(!error, error);
3806 
3807  cpl_free(propname);
3808 
3809  if (detmon_pernoise_config.mode == 1) {
3810  propname = cpl_sprintf("ESO QC POW3 %d", iquad);
3811  assert(propname != NULL);
3812  } else {
3813  propname = cpl_sprintf("ESO QC POW3");
3814  }
3815 
3816  error = cpl_propertylist_append_double(qclist, propname, pows[2]);
3817  error = cpl_propertylist_set_comment(qclist,propname,DETMON_QC_POW_C);
3818  cpl_ensure_code(!error, error);
3819 
3820 
3821  cpl_free(propname);
3822 
3823  return cpl_error_get_code();
3824 }
3825 
3826 /*---------------------------------------------------------------------------*/
3827 
3828 /*
3829  * @brief Retrieve input parameters
3830  * @param pipeline_name Input image
3831  * @param recipe_name Input image
3832  * @param parlist Shift to apply on the x-axis
3833  * @return CPL_ERROR_NONE on success.
3834  */
3835 
3836 /*---------------------------------------------------------------------------*/
3837 cpl_error_code
3838 detmon_pernoise_rm_bg(cpl_image * image, int nsamples, int nffts)
3839 {
3840  cpl_vector *values = cpl_vector_new(nsamples * nffts);
3841 
3842  int rejected;
3843  int i, j;
3844  cpl_vector *xy_pos = cpl_vector_new(nsamples * nffts * 2);
3845  cpl_polynomial * poly_2d = 0;
3846  cpl_image * poly_ima = 0;
3847  cpl_size degree = 3;
3848  cpl_error_code error = CPL_ERROR_NONE;
3849  cpl_matrix * samppos = 0;
3850 
3851  for(i = 1; i <= nffts; i++) {
3852  for(j = 1; j <= nsamples; j++) {
3853  cpl_vector_set(xy_pos, (i - 1) * nsamples + (j - 1), j);
3854  cpl_vector_set(xy_pos, (i - 1) * nsamples + (j - 1) + nsamples * nffts, i);
3855  cpl_vector_set(values, (i - 1) * nsamples + (j - 1),
3856  cpl_image_get(image, j, i, &rejected));
3857  error = cpl_error_get_code();
3858  if (error != CPL_ERROR_NONE)
3859  {
3860  break;
3861  }
3862  }
3863  if (error != CPL_ERROR_NONE)
3864  {
3865  break;
3866  }
3867  }
3868  if (error != CPL_ERROR_NONE)
3869  {
3870  goto cleanup;
3871  }
3872 
3873  poly_2d = cpl_polynomial_new(2);
3874  samppos =
3875  cpl_matrix_wrap(2, nsamples * nffts, cpl_vector_get_data(xy_pos));
3876 
3877  cpl_polynomial_fit(poly_2d, samppos, NULL, values, NULL,
3878  CPL_FALSE, NULL, &degree);
3879 
3880  cpl_matrix_unwrap(samppos);
3881 
3882  poly_ima = cpl_image_new(nsamples, nffts, CPL_TYPE_FLOAT);
3883 
3884  cpl_image_fill_polynomial(poly_ima, poly_2d, 1, 1, 1, 1);
3885 
3886  cpl_image_subtract(image, poly_ima);
3887 
3888 cleanup:
3889  cpl_polynomial_delete(poly_2d);
3890  cpl_image_delete(poly_ima);
3891  cpl_vector_delete(xy_pos);
3892  cpl_vector_delete(values);
3893 
3894  return cpl_error_get_code();
3895 }
3896 
3897 /*---------------------------------------------------------------------------*/
3898 
3899 /*
3900  * @brief Retrieve input parameters
3901  * @param pipeline_name Input image
3902  * @param recipe_name Input image
3903  * @param parlist Shift to apply on the x-axis
3904  * @return CPL_ERROR_NONE on success.
3905  */
3906 
3907 /*---------------------------------------------------------------------------*/
3908 cpl_error_code
3909 detmon_dark(cpl_frameset * frameset,
3910  const cpl_parameterlist * parlist,
3911  const char * tag,
3912  const char * recipe_name,
3913  const char * pipeline_name,
3914  const char * procatg_master,
3915  const char * procatg_dsnu,
3916  const char * procatg_tbl,
3917  const char * package,
3918  int (*compare)(const cpl_frame *,
3919  const cpl_frame *))
3920 {
3921  cpl_size nsets;
3922  cpl_size *selection = NULL;
3923  int i;
3924  cpl_error_code error;
3925 
3926  if(detmon_dark_dfs_set_groups(frameset, tag)) {
3927  cpl_msg_error(cpl_func, "Cannot identify RAW and CALIB frames");
3928  }
3929 
3930  /*
3931  * This function reads all inputs parameters from parlist
3932  * and stores them in a global variable detmon_ronbias_config.
3933  * Similar to detmon_lg_retrieve_parlist(). See detmon.c
3934  */
3935  error = detmon_retrieve_dark_params(pipeline_name,
3936  recipe_name, parlist);
3937  cpl_ensure_code(!error, error);
3938 
3939  /* Labelise all input frames */
3940  if(compare == NULL)
3941  nsets = 1;
3942  else {
3943  cpl_msg_info(cpl_func, "Identify the different settings");
3944  selection = cpl_frameset_labelise(frameset, compare, &nsets);
3945  if(selection == NULL)
3946  cpl_msg_error(cpl_func, "Cannot labelise input frames");
3947  }
3948 
3949  detmon_dark_config.nb_extensions = 1;
3950  if(detmon_dark_config.exts < 0) {
3951  const cpl_frame *cur_frame =
3952  cpl_frameset_get_first_const(frameset);
3953  /* Get the nb of extensions */
3954  detmon_dark_config.nb_extensions =
3955  cpl_frame_get_nextensions(cur_frame);
3956  }
3957 
3958  /* Extract settings and reduce each of them */
3959  for(i = 0; i < nsets; i++) {
3960  cpl_size *select_dits = NULL;
3961  cpl_frameset *cur_fset =
3962  nsets == 1 ? cpl_frameset_duplicate(frameset) :
3963  cpl_frameset_extract(frameset, selection, i);
3964 
3965  cpl_size ndits = 0;
3966  int j, k;
3967  cpl_table ** dsnu_table = NULL;
3968  cpl_imagelist ** dsnu = NULL;
3969 
3970  cpl_propertylist ** qclist =
3971  (cpl_propertylist **)
3972  cpl_malloc(detmon_dark_config.nb_extensions *
3973  sizeof(cpl_propertylist *));
3974 
3975 
3976  cpl_imagelist ** masters =
3977  (cpl_imagelist **)
3978  cpl_malloc(detmon_dark_config.nb_extensions *
3979  sizeof(cpl_imagelist *));
3980 
3981  /* Initialise memory for products */
3982  if(detmon_dark_config.opt_nir == OPT) {
3983  dsnu_table =
3984  (cpl_table **) cpl_malloc(detmon_dark_config.nb_extensions *
3985  sizeof(cpl_table *));
3986  dsnu =
3987  (cpl_imagelist **)
3988  cpl_malloc(detmon_dark_config.nb_extensions *
3989  sizeof(cpl_imagelist *));
3990  }
3991 
3992  select_dits = cpl_frameset_labelise(cur_fset,
3993  detmon_compare_dits,
3994  &ndits);
3995 
3996  if(detmon_dark_config.exts >= 0) {
3997  *masters = cpl_imagelist_new();
3998  if(detmon_dark_config.opt_nir == OPT) {
3999  *dsnu = cpl_imagelist_new();
4000  *dsnu_table = cpl_table_new(ndits);
4001  }
4002  *qclist = cpl_propertylist_new();
4003  cpl_table_new_column(*dsnu_table, "DIT", CPL_TYPE_DOUBLE);
4004  cpl_table_new_column(*dsnu_table, "STDEV", CPL_TYPE_DOUBLE);
4005  } else {
4006  for ( j = 0; j < detmon_dark_config.nb_extensions; j ++) {
4007  masters[j] = cpl_imagelist_new();
4008  if(detmon_dark_config.opt_nir == OPT) {
4009  dsnu[j] = cpl_imagelist_new();
4010  dsnu_table[j] = cpl_table_new(ndits);
4011  }
4012  qclist[j] = cpl_propertylist_new();
4013  cpl_table_new_column(dsnu_table[j], "DIT", CPL_TYPE_DOUBLE);
4014  cpl_table_new_column(dsnu_table[j], "STDEV", CPL_TYPE_DOUBLE);
4015  }
4016  }
4017 
4018  for(j = 0; j < ndits; j++) {
4019  cpl_frameset * cur_fdit = cpl_frameset_extract(cur_fset,
4020  select_dits, j);
4021  cpl_imagelist ** raws =
4022  (cpl_imagelist **)
4023  cpl_malloc(detmon_dark_config.nb_extensions *
4024  sizeof(cpl_imagelist *));
4025 
4026  if(detmon_dark_config.exts >= 0) {
4027  cpl_image * collapsed;
4028  *raws =
4029  cpl_imagelist_load_frameset(cur_fdit, CPL_TYPE_FLOAT, 1,
4030  detmon_dark_config.exts);
4031  collapsed = cpl_imagelist_collapse_create(*raws);
4032  cpl_imagelist_set(*masters, collapsed, j);
4033  if(detmon_dark_config.opt_nir == OPT) {
4034  detmon_dark_dsnu(cur_fdit, *dsnu, *dsnu_table,
4035  collapsed, j);
4036  }
4037  detmon_dark_qc(*qclist, collapsed);
4038  } else {
4039  cpl_imagelist *raws_all_exts =
4040  cpl_imagelist_load_frameset(cur_fdit, CPL_TYPE_FLOAT, 1,
4041  -1);
4042  for(k = 0; k < detmon_dark_config.nb_extensions; k++) {
4043  int nframes = cpl_frameset_get_size(cur_fdit);
4044  int h;
4045  cpl_image * collapsed;
4046  for(h = 0; h < nframes; h++) {
4047  cpl_image *image =
4048  cpl_imagelist_unset(raws_all_exts,
4049  (detmon_dark_config.
4050  nb_extensions - 1 - k) * h);
4051  cpl_imagelist_set(raws[k], image, h);
4052  }
4053  collapsed = cpl_imagelist_collapse_create(raws[k]);
4054  cpl_imagelist_set(masters[k],collapsed, j);
4055  if(detmon_dark_config.opt_nir == OPT) {
4056  detmon_dark_dsnu(cur_fdit, dsnu[k],
4057  dsnu_table[j], collapsed, j);
4058  }
4059  detmon_dark_qc(qclist[k], collapsed);
4060  }
4061  }
4062 
4063  cpl_frameset_delete(cur_fdit);
4064  for(k = 0; k < detmon_dark_config.nb_extensions; k++) {
4065  cpl_imagelist_delete(raws[k]);
4066  }
4067  cpl_free(raws);
4068  } /* end of loop (for) around different DIT values */
4069 
4070  cpl_frameset_delete(cur_fset);
4071 
4072  detmon_dark_save(parlist, frameset, recipe_name, pipeline_name,
4073  procatg_master, procatg_tbl, procatg_dsnu,
4074  package, masters, dsnu_table, dsnu, qclist,
4075  0, 0, frameset);
4076 
4077  if(detmon_dark_config.opt_nir == OPT) {
4078  for(j = 0; j < detmon_dark_config.nb_extensions; j++) {
4079  cpl_table_delete(dsnu_table[j]);
4080  cpl_imagelist_delete(dsnu[j]);
4081  }
4082  cpl_free(dsnu_table);
4083  cpl_free(dsnu);
4084  }
4085 
4086  for(j = 0; j < detmon_dark_config.nb_extensions; j++) {
4087  cpl_propertylist_delete(qclist[j]);
4088  cpl_imagelist_delete(masters[j]);
4089  }
4090  cpl_free(qclist);
4091  cpl_free(masters);
4092  cpl_free(select_dits);
4093 
4094  } /* end of loop (for) around different setting */
4095 
4096  cpl_free(selection);
4097 
4098  return cpl_error_get_code();
4099 }
4100 
4101 
4102 /*---------------------------------------------------------------------------*/
4103 
4104 /*
4105  * @brief Retrieve input parameters
4106  * @param pipeline_name Input image
4107  * @param recipe_name Input image
4108  * @param parlist Shift to apply on the x-axis
4109  * @return CPL_ERROR_NONE on success.
4110  */
4111 
4112 /*---------------------------------------------------------------------------*/
4113 int
4114 detmon_dark_dfs_set_groups(cpl_frameset * set, const char *tag)
4115 {
4116  cpl_frame *cur_frame;
4117  const char *cur_tag;
4118  int nframes;
4119  int i;
4120 
4121  /* Check entries */
4122  if(set == NULL)
4123  return -1;
4124 
4125  /* Initialize */
4126  nframes = cpl_frameset_get_size(set);
4127 
4128  /* Loop on frames */
4129  for(i = 0; i < nframes; i++) {
4130  cur_frame = cpl_frameset_get_frame(set, i);
4131  cur_tag = cpl_frame_get_tag(cur_frame);
4132 
4133  /* RAW frames */
4134  if(!strcmp(cur_tag, tag))
4135  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_RAW);
4136  /* CALIB frames */
4137 
4138  /* else if (!strcmp(tag, IIINSTRUMENT_CALIB_FLAT))
4139  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_CALIB) ;
4140  */
4141  }
4142  return 0;
4143 }
4144 
4145 /*---------------------------------------------------------------------------*/
4146 
4147 /*
4148  * @brief Retrieve input parameters
4149  * @param pipeline_name Input image
4150  * @param recipe_name Input image
4151  * @param parlist Shift to apply on the x-axis
4152  * @return CPL_ERROR_NONE on success.
4153  */
4154 
4155 /*---------------------------------------------------------------------------*/
4156 static cpl_error_code
4157 detmon_retrieve_dark_params(const char *pipeline_name,
4158  const char *recipe_name,
4159  const cpl_parameterlist * parlist)
4160 {
4161  char *par_name;
4162  cpl_parameter *par;
4163 
4164  /* --ron.method */
4165  par_name = cpl_sprintf("%s.%s.ron.method", pipeline_name, recipe_name);
4166  assert(par_name != NULL);
4167  par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
4168  detmon_dark_config.ron_method = cpl_parameter_get_string(par);
4169  cpl_free(par_name);
4170 
4171  /* --dsnu.method */
4172  par_name = cpl_sprintf("%s.%s.dsnu.method", pipeline_name, recipe_name);
4173  assert(par_name != NULL);
4174  par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
4175  detmon_dark_config.dsnu_method = cpl_parameter_get_string(par);
4176  cpl_free(par_name);
4177 
4178  /* --opt_nir */
4179  par_name = cpl_sprintf("%s.%s.opt_nir", pipeline_name, recipe_name);
4180  assert(par_name != NULL);
4181  par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
4182  detmon_dark_config.opt_nir = cpl_parameter_get_bool(par);
4183  cpl_free(par_name);
4184 
4185  /* --exts */
4186  detmon_dark_config.exts =
4187  detmon_retrieve_par_int("exts", pipeline_name, recipe_name,
4188  parlist);
4189 
4190  if(cpl_error_get_code()) {
4191  cpl_msg_error(cpl_func, "Failed to retrieve the input parameters");
4192  cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
4193  }
4194 
4195 
4196  return CPL_ERROR_NONE;
4197 }
4198 
4199 
4200 /*---------------------------------------------------------------------------*/
4201 
4202 /*
4203  * @brief Retrieve input parameters
4204  * @param pipeline_name Input image
4205  * @param recipe_name Input image
4206  * @param parlist Shift to apply on the x-axis
4207  * @return CPL_ERROR_NONE on success.
4208  */
4209 
4210 /*---------------------------------------------------------------------------*/
4211  cpl_error_code
4212 detmon_fill_dark_params(cpl_parameterlist * parlist,
4213  const char *recipe_name,
4214  const char *pipeline_name,
4215  const char * ron_method,
4216  const char * dsnu_method,
4217  const char * opt_nir,
4218  int exts)
4219 {
4220  detmon_fill_parlist(parlist, recipe_name, pipeline_name, 4,
4221 
4222  "ron.method",
4223  "Method used to compute RON. Currently no "
4224  "change is possible, RMS computed",
4225  "CPL_TYPE_STRING", ron_method,
4226 
4227  "dsnu.method",
4228  "Method used to compute DSNU map. Currently no "
4229  "change is possible. Method used STDEV",
4230  "CPL_TYPE_STRING", dsnu_method,
4231 
4232  "opt_nir",
4233  "Boolean, OPT (FALSE) or NIR(TRUE)",
4234  "CPL_TYPE_BOOL", opt_nir,
4235 
4236  "exts",
4237  "Activate the multi-exts option. Default 0"
4238  "(primary unit), -1 (all exts)",
4239  "CPL_TYPE_INT", exts);
4240 
4241  return cpl_error_get_code();
4242 }
4243 
4244 /*---------------------------------------------------------------------------*/
4245 
4246 /*
4247  * @brief Retrieve input parameters
4248  * @param pipeline_name Input image
4249  * @param recipe_name Input image
4250  * @param parlist Shift to apply on the x-axis
4251  * @return CPL_ERROR_NONE on success.
4252  */
4253 
4254 /*---------------------------------------------------------------------------*/
4255 int
4256 detmon_fill_dark_params_default(cpl_parameterlist * parlist,
4257  const char *recipe_name,
4258  const char *pipeline_name)
4259 {
4260  detmon_fill_dark_params(parlist, recipe_name, pipeline_name,
4261  "SIMPLE", /* --ron.method */
4262  "STDEV", /* --dsnu.method */
4263  "CPL_FALSE", /* OPT*/
4264  0); /* --exts */
4265  return cpl_error_get_code();
4266 }
4267 
4268 /*---------------------------------------------------------------------------*/
4269 
4270 /*
4271  * @brief Retrieve input parameters
4272  * @param pipeline_name Input image
4273  * @param recipe_name Input image
4274  * @param parlist Shift to apply on the x-axis
4275  * @return CPL_ERROR_NONE on success.
4276  */
4277 
4278 /*---------------------------------------------------------------------------*/
4279 cpl_error_code
4280 detmon_dark_dsnu(cpl_frameset * cur_fdit,
4281  cpl_imagelist * dsnu,
4282  cpl_table * dsnu_table,
4283  cpl_image * collapsed,
4284  int pos)
4285 {
4286  cpl_frame * first = cpl_frameset_get_first(cur_fdit);
4287  cpl_propertylist * plist =
4288  cpl_propertylist_load(cpl_frame_get_filename(first), 0);
4289  double dit = irplib_pfits_get_exptime(plist);
4290  double mean = cpl_image_get_mean(collapsed);
4291 
4292  cpl_image * dsnu_map =
4293  cpl_image_subtract_scalar_create(collapsed, mean);
4294  double stdev;
4295  cpl_image_divide_scalar(dsnu_map, mean);
4296  stdev = cpl_image_get_stdev(dsnu_map);
4297 
4298  cpl_imagelist_set(dsnu, dsnu_map, pos);
4299 
4300  cpl_table_set(dsnu_table, "DIT", pos, dit);
4301  cpl_table_set(dsnu_table, "STDEV", pos, stdev);
4302 
4303  cpl_propertylist_delete(plist);
4304 
4305  return cpl_error_get_code();
4306 
4307 }
4308 
4309 /*---------------------------------------------------------------------------*/
4310 
4311 /*
4312  * @brief Retrieve input parameters
4313  * @param pipeline_name Input image
4314  * @param recipe_name Input image
4315  * @param parlist Shift to apply on the x-axis
4316  * @return CPL_ERROR_NONE on success.
4317  */
4318 
4319 /*---------------------------------------------------------------------------*/
4320 static cpl_error_code
4321 detmon_dark_save(const cpl_parameterlist * parlist,
4322  cpl_frameset * frameset,
4323  const char *recipe_name,
4324  const char *pipeline_name,
4325  const char *procatg_master,
4326  const char *procatg_tbl,
4327  const char *procatg_dsnu,
4328  const char *package,
4329  cpl_imagelist ** masters,
4330  cpl_table ** dsnu_table,
4331  cpl_imagelist ** dsnu,
4332  cpl_propertylist ** qclist,
4333  const int flag_sets,
4334  const int which_set,
4335  const cpl_frameset * usedframes)
4336 {
4337 
4338  cpl_frame *ref_frame;
4339  cpl_propertylist *plist;
4340  char *name_o = NULL; /* Avoid (false) uninit warning */
4341  int i, j;
4342  cpl_propertylist *paflist;
4343  cpl_error_code error;
4344  int nb_images;
4345 
4346  /***************************/
4347  /* Write the MASTER FITS */
4348  /***************************/
4349 
4350  nb_images = cpl_imagelist_get_size(masters[0]);
4351  cpl_ensure_code(nb_images > 0, CPL_ERROR_DATA_NOT_FOUND);
4352 
4353 
4354  for(i = 0; i < nb_images; i++) {
4355  /* Set the file name for each image */
4356  if(!flag_sets) {
4357  name_o =
4358  cpl_sprintf("%s_master_dit_%d.fits", recipe_name, i+1);
4359  assert(name_o != NULL);
4360  } else {
4361  name_o =
4362  cpl_sprintf("%s_master_dit_%d_set%02d.fits",
4363  recipe_name, i, which_set);
4364  assert(name_o != NULL);
4365  }
4366 
4367 
4368  /* Save the image */
4369  if(detmon_dark_config.exts >= 0) {
4370  cpl_propertylist * pro_master = cpl_propertylist_new();
4371 
4372  cpl_propertylist_append_string(pro_master,
4373  CPL_DFS_PRO_CATG, procatg_master);
4374 
4375  cpl_propertylist_append(pro_master, qclist[0]);
4376 
4377  if(cpl_dfs_save_image
4378  (frameset, NULL, parlist, usedframes, NULL,
4379  cpl_imagelist_get(*masters, i), CPL_BPP_IEEE_FLOAT,
4380  recipe_name, pro_master, NULL, package,
4381  name_o)) {
4382  cpl_msg_error(cpl_func, "Cannot save the product: %s",
4383  name_o);
4384  cpl_free(name_o);
4385  cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
4386 
4387  }
4388 
4389  cpl_propertylist_delete(pro_master);
4390  } else {
4391  cpl_propertylist * pro_master = cpl_propertylist_new();
4392 
4393  cpl_propertylist_append_string(pro_master,
4394  CPL_DFS_PRO_CATG, procatg_master);
4395 
4396  cpl_propertylist_append(pro_master, qclist[0]);
4397 
4398  if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL,
4399  NULL, CPL_BPP_IEEE_FLOAT, recipe_name,
4400  pro_master, NULL,
4401  package, name_o)) {
4402  cpl_msg_error(cpl_func, "Cannot save the product: %s",
4403  name_o);
4404  cpl_free(name_o);
4405  cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
4406  }
4407 
4408  cpl_propertylist_delete(pro_master);
4409  for(j = 0; j < detmon_dark_config.nb_extensions; j++) {
4410  error =
4411  cpl_image_save(cpl_imagelist_get(masters[j], i),
4412  name_o, CPL_BPP_IEEE_FLOAT, qclist[j],
4413  CPL_IO_EXTEND);
4414  cpl_ensure_code(!error, error);
4415  }
4416  }
4417  cpl_free(name_o);
4418  }
4419 
4420  if (detmon_dark_config.opt_nir == OPT) {
4421  cpl_propertylist * pro_tbl = cpl_propertylist_new();
4422 
4423  cpl_propertylist_append_string(pro_tbl,
4424  CPL_DFS_PRO_CATG, procatg_tbl);
4425 
4426  cpl_propertylist_append(pro_tbl, qclist[0]);
4427  /*******************************/
4428  /* Write the LINEARITY TABLE */
4429  /*******************************/
4430 
4431  /* Set the file name for the table */
4432  if(!flag_sets) {
4433  name_o = cpl_sprintf("%s_dsnu_table.fits", recipe_name);
4434  assert(name_o != NULL);
4435  } else {
4436  name_o =
4437  cpl_sprintf("%s_dsnu_table_set%02d.fits", recipe_name,
4438  which_set);
4439  assert(name_o != NULL);
4440  }
4441  /* Save the table */
4442  if(cpl_dfs_save_table(frameset, NULL, parlist, usedframes, NULL,
4443  dsnu_table[0], NULL, recipe_name, pro_tbl, NULL,
4444  package, name_o)) {
4445  cpl_msg_error(cpl_func, "Cannot save the product: %s", name_o);
4446  cpl_free(name_o);
4447  cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
4448  }
4449 
4450  cpl_propertylist_delete(pro_tbl);
4451 
4452  if(detmon_dark_config.exts < 0) {
4453 
4454  for(i = 1; i < detmon_dark_config.nb_extensions; i++) {
4455  error =
4456  cpl_table_save(dsnu_table[i], NULL, qclist[i], name_o,
4457  CPL_IO_EXTEND);
4458  cpl_ensure_code(!error, error);
4459  }
4460  }
4461 
4462  /* Free */
4463  cpl_free(name_o);
4464 
4465  /***************************/
4466  /* Write the DSNU_MAP FITS */
4467  /***************************/
4468 
4469  for(i = 0; i < nb_images; i++) {
4470  /* Set the file name for each image */
4471  if(!flag_sets) {
4472  name_o =
4473  cpl_sprintf("%s_dsnu_map_dit_%d.fits", recipe_name, i+1);
4474  assert(name_o != NULL);
4475  } else {
4476  name_o =
4477  cpl_sprintf("%s_dsnu_map_dit_%d_set%02d.fits",
4478  recipe_name, i, which_set);
4479  assert(name_o != NULL);
4480  }
4481 
4482 
4483  /* Save the image */
4484  if(detmon_dark_config.exts >= 0) {
4485  cpl_propertylist * pro_dsnu = cpl_propertylist_new();
4486 
4487  cpl_propertylist_append_string(pro_dsnu,
4488  CPL_DFS_PRO_CATG, procatg_dsnu);
4489 
4490  cpl_propertylist_append(pro_dsnu, qclist[0]);
4491 
4492  if(cpl_dfs_save_image
4493  (frameset, NULL, parlist, usedframes, NULL,
4494  cpl_imagelist_get(*dsnu, i), CPL_BPP_IEEE_FLOAT,
4495  recipe_name, pro_dsnu, NULL, package,
4496  name_o)) {
4497  cpl_msg_error(cpl_func, "Cannot save the product: %s",
4498  name_o);
4499  cpl_free(name_o);
4500  cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
4501 
4502  }
4503 
4504  cpl_propertylist_delete(pro_dsnu);
4505  } else {
4506  cpl_propertylist * pro_dsnu = cpl_propertylist_new();
4507 
4508  cpl_propertylist_append_string(pro_dsnu,
4509  CPL_DFS_PRO_CATG, procatg_dsnu);
4510 
4511  cpl_propertylist_append(pro_dsnu, qclist[0]);
4512 
4513  if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4514  NULL, NULL,
4515  CPL_BPP_IEEE_FLOAT, recipe_name,
4516  pro_dsnu, NULL,
4517  package, name_o)) {
4518  cpl_msg_error(cpl_func, "Cannot save the product: %s",
4519  name_o);
4520  cpl_free(name_o);
4521  cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
4522  }
4523 
4524  cpl_propertylist_delete(pro_dsnu);
4525  for(j = 0; j < detmon_dark_config.nb_extensions; j++) {
4526  error =
4527  cpl_image_save(cpl_imagelist_get(dsnu[j], i),
4528  name_o, CPL_BPP_IEEE_FLOAT, qclist[j],
4529  CPL_IO_EXTEND);
4530  cpl_ensure_code(!error, error);
4531  }
4532  }
4533  cpl_free(name_o);
4534  }
4535 
4536 
4537 
4538  } /* End of if(OPT) */
4539 
4540  /*******************************/
4541  /* Write the PAF file(s) */
4542  /*******************************/
4543 
4544  /* Get FITS header from reference file */
4545  ref_frame = cpl_frameset_get_first(frameset);
4546  if((plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4547  0)) == NULL) {
4548  cpl_msg_error(cpl_func, "getting header from reference frame");
4549  cpl_ensure_code(0, cpl_error_get_code());
4550  }
4551 
4552  /* Get the keywords for the paf file */
4553  paflist = cpl_propertylist_new();
4554  cpl_propertylist_copy_property_regexp(paflist, plist,
4555  "^(ARCFILE|MJD-OBS|ESO TPL ID|"
4556  "DATE-OBS|ESO DET DIT|ESO DET NDIT|"
4557  "ESO DET NCORRS|"
4558  "ESO DET MODE NAME)$", 0);
4559 
4560  for(i = 0; i < detmon_dark_config.nb_extensions; i++) {
4561  cpl_propertylist * c_paflist = cpl_propertylist_duplicate(paflist);
4562  error = cpl_propertylist_append(c_paflist, qclist[i]);
4563  cpl_ensure_code(!error, error);
4564 
4565  /* Set the file name for the bpm */
4566  if(detmon_dark_config.exts >= 0) {
4567  if(!flag_sets) {
4568  name_o = cpl_sprintf("%s.paf", recipe_name);
4569  assert(name_o != NULL);
4570  } else {
4571  name_o = cpl_sprintf("%s_set%02d.paf", recipe_name, which_set);
4572  assert(name_o != NULL);
4573  }
4574  } else {
4575  if(!flag_sets) {
4576  name_o = cpl_sprintf("%s_ext%02d.paf", recipe_name, i+1);
4577  assert(name_o != NULL);
4578  } else {
4579  name_o = cpl_sprintf("%s_set%02d_ext%02d.paf", recipe_name, which_set, i+1);
4580  assert(name_o != NULL);
4581  }
4582  }
4583  /* Save the PAF */
4584  if(cpl_dfs_save_paf(pipeline_name, recipe_name, c_paflist, name_o)) {
4585  cpl_msg_error(cpl_func, "Cannot save the product: %s", name_o);
4586  cpl_free(name_o);
4587  cpl_propertylist_delete(paflist);
4588  cpl_propertylist_delete(plist);
4589  cpl_free(name_o);
4590  cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
4591  }
4592  cpl_propertylist_delete(c_paflist);
4593  cpl_free(name_o);
4594  }
4595 
4596  cpl_propertylist_delete(plist);
4597  cpl_propertylist_delete(paflist);
4598 
4599  return cpl_error_get_code();
4600 }
4601 
4602 cpl_error_code
4603 detmon_dark_qc(cpl_propertylist * qclist,
4604  cpl_image * collapsed)
4605 {
4606  double mean = cpl_image_get_mean(collapsed);
4607  double stdev = cpl_image_get_stdev(collapsed);
4608 
4609  cpl_error_code error;
4610 
4611  error = cpl_propertylist_append_double(qclist,DETMON_QC_DARK, mean);
4612  error = cpl_propertylist_set_comment(qclist,DETMON_QC_DARK,
4613  DETMON_QC_DARK_C);
4614  cpl_ensure_code(!error, error);
4615 
4616  error = cpl_propertylist_append_double(qclist,DETMON_QC_DARK_STDEV, stdev);
4617  error = cpl_propertylist_set_comment(qclist,DETMON_QC_DARK_STDEV,
4618  DETMON_QC_DARK_STDEV_C);
4619  cpl_ensure_code(!error, error);
4620 
4621  return cpl_error_get_code();
4622 }
4623 
4624 
4625 /*---------------------------------------------------------------------------*/
4642 /*---------------------------------------------------------------------------*/
4643 cpl_image *
4644 irplib_imagelist_collapse_stdev_create(const cpl_imagelist * imlist)
4645 {
4646  cpl_image * mean;
4647  cpl_image * delta;
4648  cpl_image * sq_delta;
4649  cpl_image * stdev;
4650 
4651  int i;
4652 
4653  /* Check inputs */
4654  cpl_ensure(imlist != NULL, CPL_ERROR_NULL_INPUT, NULL);
4655  cpl_ensure(cpl_imagelist_is_uniform(imlist) == 0, CPL_ERROR_ILLEGAL_INPUT,
4656  NULL);
4657 
4658  /* Create mean image with its first iterative value = first image */
4659  mean = cpl_image_duplicate(cpl_imagelist_get_const(imlist, 0));
4660  cpl_image_fill_rejected(mean, 0.0);
4661  cpl_image_accept_all(mean);
4662 
4663  stdev = cpl_image_new(cpl_image_get_size_x(mean),
4664  cpl_image_get_size_y(mean),
4665  CPL_TYPE_FLOAT);
4666 
4667  for (i = 1; i < cpl_imagelist_get_size(imlist); i++) {
4668  delta = cpl_image_subtract_create(cpl_imagelist_get_const(imlist, i),
4669  mean);
4670  cpl_image_fill_rejected(delta, 0.0);
4671  cpl_image_accept_all(delta);
4672 
4673  sq_delta = cpl_image_multiply_create(delta, delta);
4674 
4675  cpl_image_multiply_scalar(sq_delta, ((double) i / (double)(i+1)));
4676  cpl_image_add(stdev, sq_delta);
4677 
4678  cpl_image_divide_scalar(delta, i + 1);
4679  cpl_image_add(mean, delta);
4680 
4681  cpl_image_delete(delta);
4682  cpl_image_delete(sq_delta);
4683  }
4684 
4685  cpl_image_divide_scalar(stdev, cpl_imagelist_get_size(imlist) - 1);
4686  cpl_image_power(stdev, 0.5);
4687 
4688  cpl_image_delete(mean);
4689 
4690  return stdev;
4691 }