IIINSTRUMENT Pipeline Reference Manual  1.3.10
detmon_lg.c
1 /* $Id: detmon_lg.c,v 1.31 2013-08-07 09:32:37 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 /*
23  * $Author: jtaylor $
24  * $Date: 2013-08-07 09:32:37 $
25  * $Revision: 1.31 $
26  * $Name: not supported by cvs2svn $
27  *
28  */
29 
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33 
34 /*---------------------------------------------------------------------------
35  Includes
36  ---------------------------------------------------------------------------*/
37 
38 /* Must include first to ensure declaration of complex CPL functions */
39 #include <complex.h>
40 
41 #include "detmon_lg.h"
42 
43 #include "detmon.h"
44 #include "detmon_utils.h"
45 #include "detmon_lg_impl.h"
46 
47 #include "irplib_ksigma_clip.h"
48 #include "irplib_utils.h"
49 #include "irplib_hist.h"
50 
51 #include "hdrl.h"
52 
53 #include <math.h>
54 #include <string.h>
55 #include <assert.h>
56 
58 /*
59  * @defgroup irplib_detmon Detector monitoring functions
60  */
61 
62 /*--------------------------------------------------------------------------*/
63 
64 /*---------------------------------------------------------------------------
65  Defines
66  ---------------------------------------------------------------------------*/
67 /*method for calculating Fixed Pattern Noise (FPN)*/
68 enum _FPN_METHOD
69 {
70  FPN_UNKNOWN,
71  FPN_HISTOGRAM, /*default*/
72  FPN_SMOOTH,
73 };
74 typedef enum _FPN_METHOD FPN_METHOD;
75 static struct
76 {
77  const char * method;
78  /* Inputs */
79  int order;
80  double kappa;
81  int niter;
82  int threshold_min;
83  int threshold_max;
84  int llx;
85  int lly;
86  int urx;
87  int ury;
88  int ref_level;
89  int threshold;
90  int m;
91  int n;
92  int llx1;
93  int lly1;
94  int urx1;
95  int ury1;
96  int llx2;
97  int lly2;
98  int urx2;
99  int ury2;
100  int llx3;
101  int lly3;
102  int urx3;
103  int ury3;
104  int llx4;
105  int lly4;
106  int urx4;
107  int ury4;
108  int llx5;
109  int lly5;
110  int urx5;
111  int ury5;
112  int nx;
113  int ny;
114  cpl_boolean wholechip;
115  cpl_boolean autocorr;
116  cpl_boolean intermediate;
117  cpl_boolean collapse;
118  cpl_boolean rescale;
119  cpl_boolean pix2pix;
120  cpl_boolean bpmbin;
121  int filter;
122  double tolerance;
123  cpl_boolean pafgen;
124  const char * pafname;
125  /* Outputs */
126  double cr;
127  int exts;
128  int nb_extensions;
129  double lamp_stability;
130  cpl_boolean lamp_ok;
131  /* by kmirny */
132  int (* load_fset) (const cpl_frameset *, cpl_type, cpl_imagelist *);
133  cpl_imagelist * (* load_fset_wrp) (const cpl_frameset *, cpl_type, int);
134  FPN_METHOD fpn_method;
135  int fpn_smooth;
136  double saturation_limit;
137  double gain_threshold;
138  cpl_boolean split_coeffs;
139 } detmon_lg_config;
140 
141 /* static const char* COL_NAME_DET1_WIN1_UIT1 = "DET1_WIN1_UIT1"; */
142 /*---------------------------------------------------------------------------
143  Private function prototypes
144  ---------------------------------------------------------------------------*/
145 /* Functions for the Linearity/Gain recipe, detmon_lg() */
146 
147 /* Parameters */
148 static cpl_error_code
149 detmon_lg_retrieve_parlist(const char *,
150  const char *, const cpl_parameterlist *,
151  cpl_boolean);
152 
153 
154 static cpl_error_code
155 detmon_lg_split_onoff(const cpl_frameset *,
156  cpl_frameset *,
157  cpl_frameset *,
158  const char *, const char * /*, cpl_boolean*/);
159 
160 static cpl_error_code
161 detmon_lg_reduce(const cpl_frameset *,
162  const cpl_frameset *,
163  int* index_on, int* index_off,
164  double* exptime_on, double* exptime_off,
165  int *next_index_on, int* next_index_off,
166  cpl_imagelist **,
167  cpl_table *,
168  cpl_table *,
169  cpl_image **,
170  cpl_imagelist *,
171  cpl_imagelist *,
172  cpl_propertylist *,
173  cpl_propertylist *,
174  cpl_propertylist *,
175  cpl_propertylist *,
176  int (* load_fset) (const cpl_frameset *,
177  cpl_type,
178  cpl_imagelist *),
179  const cpl_boolean, int);
180 
181 
182 
183 
184 static cpl_error_code
185 detmon_lin_table_fill_row(cpl_table *, double,
186  cpl_imagelist *,
187  const cpl_imagelist *,
188  const cpl_imagelist *,
189  int, int, int, int,
190  const int,
191  const int,
192  unsigned);
193 
194 static cpl_error_code
195 detmon_gain_table_fill_row(cpl_table * gain_table,
196  double c_dit,int c_ndit,
197  cpl_imagelist * autocorr_images,
198  cpl_imagelist * diff_flats,
199  const cpl_imagelist * ons,
200  const cpl_imagelist * offs,
201  double kappa, int nclip,
202  int llx, int lly, int urx, int ury,
203  int m, int n,
204  double gain_threshold,
205  int pos, unsigned mode, int* rows_affected);
206 
207 
208 static cpl_error_code
209 detmon_check_saturation_on_pair(cpl_imagelist * autocorr_images,
210  cpl_imagelist * diff_flats,
211  const cpl_imagelist * ons,
212  double kappa, int nclip,
213  int llx, int lly, int urx, int ury,
214  double saturation_limit,
215  const int pos, unsigned mode,
216  int* rows_linear_affected);
217 
218 static cpl_error_code
219 detmon_lg_save(const cpl_parameterlist *,
220  cpl_frameset *,
221  const char *,
222  const char *,
223  const char *,
224  const cpl_propertylist *,
225  const cpl_propertylist *,
226  const cpl_propertylist *,
227  const cpl_propertylist *,
228  const cpl_propertylist *,
229  const cpl_propertylist *,
230  const char *,
231  cpl_imagelist *,
232  cpl_table *,
233  cpl_table *,
234  cpl_image *,
235  cpl_imagelist *,
236  cpl_imagelist *,
237  cpl_propertylist *,
238  cpl_propertylist *,
239  cpl_propertylist *,
240  cpl_propertylist *,
241  const int, const int, const cpl_frameset *,
242  int);
243 
244 static cpl_error_code
245 detmon_lg_qc_ptc(const cpl_table *,
246  cpl_propertylist *, unsigned, int);
247 
248 static cpl_error_code
249 detmon_lg_qc_med(const cpl_table *,
250  cpl_propertylist *, int);
251 
252 
253 static double
254 detmon_pfits_get_dit(const cpl_propertylist *);
255 
256 static double
257 detmon_pfits_get_dit_opt(const cpl_propertylist *);
258 static double
259 irplib_pfits_get_prop_double(const cpl_propertylist * plist,
260  const char* prop_name);
261 
262 static cpl_image * detmon_bpixs(const cpl_imagelist *,
263  cpl_boolean, const double, int *);
264 
265 static double
266 detmon_autocorr_factor(const cpl_image *,
267  cpl_image **, int, int);
268 
269 
270 
271 static cpl_error_code
272 detmon_opt_contamination(const cpl_imagelist *,
273  const cpl_imagelist *,
274  unsigned mode, cpl_propertylist *);
275 
276 #if 0
277 detmon_opt_lampcr(cpl_frameset *, int);
278 #endif
279 
280 int
281 detmon_lg_dfs_set_groups(cpl_frameset *, const char *, const char *);
282 
283 static cpl_error_code
284 detmon_lg_reduce_all(const cpl_table *,
285  cpl_propertylist *,
286  cpl_propertylist *,
287  cpl_propertylist *,
288  cpl_propertylist *,
289  cpl_imagelist **,
290  cpl_image **,
291  const cpl_imagelist *,
292  const cpl_table *, int, cpl_boolean);
293 
294 static cpl_error_code
295 detmon_lg_check_defaults(const cpl_image *);
296 
297 static cpl_error_code
298 detmon_lg_rescale(cpl_imagelist *);
299 
300 static cpl_error_code
301 detmon_lg_reduce_init(cpl_table *,
302  cpl_table *,
303  cpl_imagelist **,
304  const cpl_boolean);
305 
306 
307 static cpl_error_code
308 detmon_add_adl_column(cpl_table *, cpl_boolean);
309 
310 static cpl_error_code
311 detmon_lg_lamp_stab(const cpl_frameset *,
312  const cpl_frameset *,
313  cpl_boolean, int);
314 
315 
316 static cpl_error_code
317 detmon_lg_reduce_dit(const cpl_frameset * set_on,
318  int* index_on, double* exptime_on,
319  const int dit_nb,
320  int * dit_nskip,
321  const cpl_frameset * set_off,
322  int * index_off, double* exptime_off,
323  int* next_on, int* next_off,
324  cpl_table * linear_table,
325  cpl_table * gain_table,
326  cpl_imagelist * linearity_inputs,
327  cpl_propertylist * qclist,
328  cpl_boolean opt_nir,
329  cpl_imagelist * autocorr_images,
330  cpl_imagelist * diff_flats,
331  cpl_imagelist * opt_offs,
332  int whichext,
333  int * rows_linear_affected,
334  int * rows_gain_affected);
335 
336 static cpl_error_code
337 detmon_lg_core(cpl_frameset * cur_fset_on,
338  cpl_frameset * cur_fset_off,
339  int * index_on,
340  int * index_off,
341  double * exptime_on,
342  double * exptime_off,
343  int whichext,
344  int whichset,
345  const char * recipe_name,
346  const char * pipeline_name,
347  const char * pafregexp,
348  const cpl_propertylist * pro_lintbl,
349  const cpl_propertylist * pro_gaintbl,
350  const cpl_propertylist * pro_coeffscube,
351  const cpl_propertylist * pro_bpm,
352  const cpl_propertylist * pro_corr,
353  const cpl_propertylist * pro_diff,
354  const char * package,
355  int (* load_fset) (const cpl_frameset *,
356  cpl_type,
357  cpl_imagelist *),
358  int nsets, cpl_boolean opt_nir,
359  cpl_frameset * frameset, const cpl_parameterlist * parlist,
360  cpl_frameset * cur_fset);
361 
362 static cpl_error_code
363 detmon_lg_lineff(double *, cpl_propertylist *, int, int);
364 
365 /*
366  static int
367  detmon_lg_compare_pairs(const cpl_frame *,
368  const cpl_frame *);
369  */
370 static cpl_error_code
371 detmon_gain_table_create(cpl_table *,
372  const cpl_boolean);
373 
374 
375 static cpl_error_code
376 detmon_lin_table_create(cpl_table *,
377  const cpl_boolean);
378 
379 static cpl_vector *
380 detmon_lg_find_dits(const cpl_vector *,
381  double );
382 
383 static cpl_error_code
384 detmon_lg_find_dits_ndits(const cpl_vector * exptimes,
385  const cpl_vector * vec_ndits,
386  double tolerance,
387  cpl_vector** diff_dits,
388  cpl_vector** diff_ndits);
389 
390 static cpl_error_code
391 detmon_fpn_compute(const cpl_frameset *set_on,
392  int * index_on,
393  int last_linear_best,
394  cpl_propertylist *lint_qclist,
395  int llx,
396  int lly,
397  int urx,
398  int ury,
399  double gain,
400  int whichext,
401  FPN_METHOD fpn_method,
402  int smooth_size);
403 static double irplib_fpn_lg(const cpl_image* f1, int* range, double gain,
404  FPN_METHOD fpn_method, int, double* mse);
405 static double irplib_calculate_total_noise(const cpl_image* pimage);
406 
407 static cpl_imagelist* irplib_load_fset_wrp(const cpl_frameset *,
408  cpl_type, int whichext);
409 static cpl_imagelist * irplib_load_fset_wrp_ext(const cpl_frameset *,
410  cpl_type, int);
411 
412 static cpl_error_code irplib_table_create_column(cpl_table* ptable,
413  cpl_propertylist* plist);
414 static cpl_error_code irplib_fill_table_DETWINUIT(cpl_table* ptable,
415  cpl_propertylist* plist,
416  int row);
417 
418 static cpl_error_code
419 detmon_pair_extract_next(const cpl_frameset * set,
420  int* index,
421  int* next_element,
422  double* dit_array,
423  /* int * with_equal_dit,
424  int onoff, */
425  cpl_frameset ** pair,
426  double tolerance);
427 static cpl_error_code
428 detmon_single_extract_next(const cpl_frameset * set,
429  int* index,
430  int* next_element,
431  double* dit_array,
432  cpl_frameset ** pair);
433 
434 /*
435  static int frame_get_ndit(const cpl_frame * pframe);
436  static cpl_error_code
437  irplib_frameset_get_ndit(const cpl_frameset * self, int* ndit);
438  */
439 static cpl_error_code detmon_table_fill_invalid(cpl_table* ptable, double code);
440 static void detmon_lg_add_empty_image(cpl_imagelist* imlist, int pos);
441 static int detmon_lg_check_before_gain(const cpl_vector* x, const cpl_vector* y);
442 /*---------------------------------------------------------------------------*/
449 /*---------------------------------------------------------------------------*/
450 static int irplib_pfits_get_ndit(const cpl_propertylist * plist)
451 {
452  return cpl_propertylist_get_int(plist,"ESO DET NDIT");
453 }
454 
455 
456 /*
457 static int frame_get_ndit(const cpl_frame * pframe)
458 {
459  cpl_propertylist *plist = 0;
460  int ival = 0;
461 
462  plist = cpl_propertylist_load(cpl_frame_get_filename(pframe),0);
463  if(plist)
464  {
465  ival = cpl_propertylist_get_int(plist, "NDIT");
466  }
467 
468  cpl_propertylist_delete(plist);
469  return ival;
470 }
471 */
472 
473 /*
474 static cpl_error_code
475 irplib_frameset_get_ndit(const cpl_frameset * self, int* ndit)
476 {
477  int sz = 0;
478  int i = 0;
479  const cpl_frame* tmp_frame = 0;
480  cpl_error_code error = CPL_ERROR_NONE;
481  sz = cpl_frameset_get_size(self);
482 
483  tmp_frame = cpl_frameset_get_position_const(self, 0);
484  while(tmp_frame)
485  {
486  ndit[i] = frame_get_ndit(tmp_frame);
487  i++
488  tmp_frame = cpl_frameset_get_position_const(self, i);
489  }
490 
491  return error;
492 }
493 */
494 
495 #ifdef DETMON_USE_DETECTOR_SHOTNOISE_MODEL
496 /*----------------------------------------------------------------------------*/
517 /*----------------------------------------------------------------------------*/
518 static cpl_error_code
519 hdrldemo_detector_shotnoise_model(const cpl_image* ima_data, const double gain,
520  const double ron, cpl_image ** ima_errs)
521 {
522  cpl_ensure_code(ima_data, CPL_ERROR_NULL_INPUT);
523  cpl_ensure_code(ima_errs, CPL_ERROR_NULL_INPUT);
524  cpl_ensure_code(gain > 0., CPL_ERROR_ILLEGAL_INPUT);
525  cpl_ensure_code(ron > 0., CPL_ERROR_ILLEGAL_INPUT);
526 
527  *ima_errs = cpl_image_duplicate(ima_data);
528  /* set negative values (= zero measurable electrons) to read out noise */
529  cpl_image_threshold(*ima_errs, 0., INFINITY, ron, ron);
530 
531  /* err_ADU = sqrt(counts/gain + ron * ron)*/
532 
533  cpl_image_divide_scalar(*ima_errs, gain);
534  cpl_image_add_scalar(*ima_errs, ron * ron);
535  cpl_image_power(*ima_errs, 0.5);
536 
537  return cpl_error_get_code();
538 }
539 #endif
540 
541 static cpl_error_code
542 detmon_lg_reduce_set(int i, cpl_frameset * frameset,
543  int nsets,
544  const char * tag_on,
545  const char * tag_off,
546  const char * recipe_name,
547  const char * pipeline_name,
548  const char * pafregexp,
549  const cpl_propertylist * pro_lintbl,
550  const cpl_propertylist * pro_gaintbl,
551  const cpl_propertylist * pro_coeffscube,
552  const cpl_propertylist * pro_bpm,
553  const cpl_propertylist * pro_corr,
554  const cpl_propertylist * pro_diff,
555  const char * package,
556  int (* load_fset)
557  (const cpl_frameset *, cpl_type, cpl_imagelist *),
558  const cpl_boolean opt_nir,
559  const cpl_parameterlist * parlist,
560  cpl_size* selection
561  );
562 static double irplib_compute_err(double gain, double ron, double photon_noise);
563 /* wrapper function for different cpl versions*/
564 static cpl_error_code
565 detmon_lg_dfs_save_imagelist(cpl_frameset * frameset,
566  const cpl_parameterlist * parlist,
567  const cpl_frameset *usedframes,
568  const cpl_imagelist *coeffs,
569  const char *recipe_name,
570  const cpl_propertylist *mypro_coeffscube,
571  const char * package,
572  const char * name_o);
573 
574 /*--------------------------------------------------------------------------*/
575 static void irplib_free(char** pointer){
576 
577  if(pointer && *pointer) {
578  cpl_free(*pointer);
579  *pointer=NULL;
580  }
581 }
582 
583 static cpl_error_code
584 detmon_lg_reduce_set(int i, cpl_frameset * frameset, int nsets,
585  const char * tag_on,
586  const char * tag_off,
587  const char * recipe_name,
588  const char * pipeline_name,
589  const char * pafregexp,
590  const cpl_propertylist * pro_lintbl,
591  const cpl_propertylist * pro_gaintbl,
592  const cpl_propertylist * pro_coeffscube,
593  const cpl_propertylist * pro_bpm,
594  const cpl_propertylist * pro_corr,
595  const cpl_propertylist * pro_diff,
596  const char * package,
597  int (* load_fset)
598  (const cpl_frameset *, cpl_type, cpl_imagelist *),
599  const cpl_boolean opt_nir,
600  const cpl_parameterlist * parlist,
601  cpl_size* selection
602  )
603 {
604  int j;
605  int nexts = detmon_lg_config.nb_extensions;
606 
607  double* exptime_on = 0;
608  double* exptime_off = 0;
609  int* index_on = 0;
610  int* index_off = 0;
611  cpl_frameset * cur_fset = NULL;
612  cpl_frameset* cur_fset_on = 0;
613  cpl_frameset* cur_fset_off = 0;
614 
615  /* Reduce data set nb i */
616  cur_fset =
617  (nsets == 1) ? /* would be better (selection == 0) ? */
618  cpl_frameset_duplicate(frameset) : cpl_frameset_extract(frameset, selection, i);
619 
620 
621  skip_if(cur_fset == NULL);
622 
623  /* Split input frameset into 2 sub-framesets for ON and OFF frames */
624  cur_fset_on = cpl_frameset_new();
625  cur_fset_off = cpl_frameset_new();
626  cpl_msg_info(cpl_func, "Splitting into ON and OFF sub-framesets");
627  skip_if (detmon_lg_split_onoff(cur_fset,
628  cur_fset_on, cur_fset_off,
629  tag_on, tag_off /*, opt_nir*/));
630  if (cpl_frameset_get_size(cur_fset_on) == 0)
631  {
632  cpl_msg_error(cpl_func, "No lamp frames in input");
633  skip_if(1);
634  }
635 
636  if (cpl_frameset_get_size(cur_fset_off) == 0)
637  {
638  cpl_msg_error(cpl_func, "No dark / bias frames in input");
639  skip_if(1);
640  }
641  cpl_msg_info(cpl_func, "found on-frames[%" CPL_SIZE_FORMAT "] off-frames[%" CPL_SIZE_FORMAT "]",cpl_frameset_get_size(cur_fset_on), cpl_frameset_get_size(cur_fset_off));
642  /* Labelise each sub-frameset according to DIT values */
643  /* selection_on = cpl_frameset_labelise(cur_fset_on,
644  detmon_lg_compare_pairs,
645  &nsets_on);
646 
647  skip_if (selection_on == NULL);
648  */
649  exptime_on = cpl_malloc(sizeof(double)*cpl_frameset_get_size(cur_fset_on));
650  exptime_off = cpl_malloc(sizeof(double)*cpl_frameset_get_size(cur_fset_off));
651 
652  index_on = cpl_malloc(sizeof(int)*cpl_frameset_get_size(cur_fset_on));
653  index_off = cpl_malloc(sizeof(int)*cpl_frameset_get_size(cur_fset_off));
654  irplib_frameset_sort(cur_fset_on, index_on, exptime_on);
655  irplib_frameset_sort(cur_fset_off, index_off, exptime_off);
656  /* for (j = 0; j < cpl_frameset_get_size(cur_fset_on); j++)
657  {
658  cpl_msg_info(cpl_func, "%d: \t %d \t %f", j , index_on[j], exptime_on[j]);
659  }
660  */
661  /* TODO Check that each ON frame pair has a corresponding OFF frame*/
662 
663  /* Test if they have equal nb of labels */
664  /* if (!detmon_lg_config.collapse) {
665  skip_if(nsets_on != nsets_off);
666  }
667  */
668  skip_if(detmon_check_order(exptime_on, cpl_frameset_get_size(cur_fset_on), detmon_lg_config.tolerance, detmon_lg_config.order));
669 
670  if(detmon_lg_config.exts >= 0)
671  {
672  /*
673  * In the optical domain, the first 2 frames
674  * are used apart from the pairs.
675  */
676 
677 #if 0
678  if (detmon_lg_config.lamp_ok) {
679  skip_if(detmon_opt_lampcr(cur_fset, 0));
680  }
681 #endif
682  skip_if(detmon_lg_core(cur_fset_on, cur_fset_off,
683  index_on,
684  index_off,
685  exptime_on,
686  exptime_off,
687  detmon_lg_config.exts,
688  i,
689  recipe_name, pipeline_name, pafregexp,
690  pro_lintbl, pro_gaintbl, pro_coeffscube, pro_bpm, pro_corr, pro_diff,
691  package, load_fset, nsets, opt_nir, frameset, parlist, cur_fset));
692  } else {
693  for(j = 1; j <= nexts; j++) {
694  /*
695  * In the optical domain, the first 2 frames
696  * are used apart from the pairs.
697  */
698 
699 #if 0
700  if (detmon_lg_config.lamp_ok) {
701  skip_if(detmon_opt_lampcr(cur_fset, j));
702  }
703 #endif
704 
705  skip_if(detmon_lg_core(cur_fset_on, cur_fset_off,
706  index_on,
707  index_off,
708  exptime_on,
709  exptime_off,
710  j, i, recipe_name, pipeline_name,pafregexp, pro_lintbl, pro_gaintbl, pro_coeffscube, pro_bpm, pro_corr, pro_diff, package, load_fset, nsets, opt_nir, frameset, parlist, cur_fset));
711  }
712  }
713  end_skip;
714 
715  cpl_frameset_delete(cur_fset);
716  cpl_frameset_delete(cur_fset_on);
717  cpl_frameset_delete(cur_fset_off);
718  cpl_free(index_on);
719  cpl_free(index_off);
720  cpl_free(exptime_on);
721  cpl_free(exptime_off);
722  return cpl_error_get_code();
723 }
724 
725 /*
726  * @brief Reduce linearity and gain in the IR domain
727  * @param parlist List of required parameters
728  * @param frameset Input frameset
729  * @param tag_on Tag to identify the ON frames
730  * @param tag_off Tag to identify the OFF frames
731  * @param recipe_name Name of the recipe calling this function
732  * @param pipeline_name Name of the pipeline calling this function
733  * @param procatg_lintbl PRO.CATG keyword for the Linearity Table
734  * @param procatg_gaintbl PRO.CATG keyword for the Gain Table
735  * @param procatg_coeffscube PRO.CATG keyword for the
736  * Linearity Coefficients' Images
737  * @param procatg_bpm PRO.CATG required for the Bad Pixel Map
738  * @param procatg_corr PRO.CATG required for the Autocorrelation Images
739  * (Intermediate product - only created if required)
740  * @param procatg_diff PRO.CATG required for the Difference Images
741  * (Intermediate Product - only created if required)
742  * @param package PACKAGE (incl. VERSION) required
743  * for the DFS keywords
744  * @param compare Compare function used to classified frameset into
745  * different settings, if any.
746  * @param load_fset Loading function for preprocessing of input
747  frames with special data format (needed for
748  AMBER and MIDI processing)
749 
750  * @param opt_nir Boolean parameter to activate/deactivate
751  * OPT-only / IR-only parts of the recipe
752  * @return 0 on success, -1 on fail.
753  * @note: The parlist contains the following parameters:
754  *
755  * @par1 kappa Kappa value used for the kappa-sigma clipping
756  * rejection of bad pixels when computing sigma for
757  * gain calculation
758  * @par2 niter Number of iterations for the kappa-sigma clipping
759  * @par3 threshold_min Minimum threshold of the k-sigma (Not applied)
760  * @par4 threshold_max Maximum threshold of the k-sigma (Not applied)
761  * @par5 llx Region of Interest (Default to the whole area)
762  * @par6 lly Region of Interest (Default to the whole area)
763  * @par7 urx Region of Interest (Default to the whole area)
764  * @par8 ury Region of Interest (Default to the whole area)
765  * @par9 ref_level Reference Level (Not applied)
766  * @par10 threshold Threshold (Not applied)
767  * @par11 intermediate Boolean to activate the production of
768  * Intermediate Products
769  * @par12 autocorr Boolean to activate autocorr method
770  * @par13 collapse Boolean to activate collapse of OFF frames
771  * @par14 rescale Boolean to activate pair rescaling
772  * @par15 m X-Shift of the autocorrelation
773  * @par16 n Y-Shift of the autocorrelation
774  * @par17 llx1 Region of Interest 1 (Only OPT)
775  * @par18 lly1 Region of Interest 1 (Only OPT)
776  * @par19 urx1 Region of Interest 1 (Only OPT)
777  * @par20 ury1 Region of Interest 1 (Only OPT)
778  * @par21 llx2 Region of Interest 2 (Only OPT)
779  * @par22 lly2 Region of Interest 2 (Only OPT)
780  * @par23 urx2 Region of Interest 2 (Only OPT)
781  * @par24 ury2 Region of Interest 2 (Only OPT)
782  * @par25 llx3 Region of Interest 3 (Only OPT)
783  * @par26 lly3 Region of Interest 3 (Only OPT)
784  * @par27 urx3 Region of Interest 3 (Only OPT)
785  * @par28 ury3 Region of Interest 3 (Only OPT)
786  * @par29 llx4 Region of Interest 4 (Only OPT)
787  * @par30 lly4 Region of Interest 4 (Only OPT)
788  * @par31 urx4 Region of Interest 4 (Only OPT)
789  * @par32 ury4 Region of Interest 4 (Only OPT)
790  * @par33 llx5 Region of Interest 5 (Only OPT)
791  * @par34 lly5 Region of Interest 5 (Only OPT)
792  * @par35 urx5 Region of Interest 5 (Only OPT)
793  * @par36 ury5 Region of Interest 5 (Only OPT)
794  * @par37 exts Integer to select extension
795  */
796 
797 /*--------------------------------------------------------------------------*/
798 
799 cpl_error_code
800 detmon_lg(cpl_frameset * frameset,
801  const cpl_parameterlist * parlist,
802  const char * tag_on,
803  const char * tag_off,
804  const char * recipe_name,
805  const char * pipeline_name,
806  const char * pafregexp,
807  const cpl_propertylist * pro_lintbl,
808  const cpl_propertylist * pro_gaintbl,
809  const cpl_propertylist * pro_coeffscube,
810  const cpl_propertylist * pro_bpm,
811  const cpl_propertylist * pro_corr,
812  const cpl_propertylist * pro_diff,
813  const char * package,
814  int (* compare) (const cpl_frame *,
815  const cpl_frame *),
816  int (* load_fset) (const cpl_frameset *,
817  cpl_type,
818  cpl_imagelist *),
819  const cpl_boolean opt_nir)
820 {
821  cpl_errorstate cleanstate = cpl_errorstate_get();
822  cpl_size nsets;
823  cpl_size * selection = NULL;
824  cpl_frame * first = NULL;
825  cpl_image * reference = NULL;
826 
827  /*
828  * Variables used only inside the for() statement.
829  * However, there are declared here to ease
830  * memory management in error case.
831  */
832  cpl_frameset * cur_fset = NULL;
833  cpl_frameset * cur_fset_on = NULL;
834  cpl_frameset * cur_fset_off = NULL;
835 
836  /* Test entries */
837  cpl_ensure_code(frameset != NULL, CPL_ERROR_NULL_INPUT);
838  cpl_ensure_code(parlist != NULL, CPL_ERROR_NULL_INPUT);
839  cpl_ensure_code(tag_on != NULL, CPL_ERROR_NULL_INPUT);
840  cpl_ensure_code(tag_off != NULL, CPL_ERROR_NULL_INPUT);
841  cpl_ensure_code(recipe_name != NULL, CPL_ERROR_NULL_INPUT);
842  cpl_ensure_code(pipeline_name != NULL, CPL_ERROR_NULL_INPUT);
843  cpl_ensure_code(pro_lintbl != NULL, CPL_ERROR_NULL_INPUT);
844  cpl_ensure_code(pro_gaintbl != NULL, CPL_ERROR_NULL_INPUT);
845  cpl_ensure_code(pro_coeffscube != NULL, CPL_ERROR_NULL_INPUT);
846  cpl_ensure_code(pro_bpm != NULL, CPL_ERROR_NULL_INPUT);
847  cpl_ensure_code(pro_corr != NULL, CPL_ERROR_NULL_INPUT);
848  cpl_ensure_code(pro_diff != NULL, CPL_ERROR_NULL_INPUT);
849  cpl_ensure_code(package != NULL, CPL_ERROR_NULL_INPUT);
850 
851  cpl_msg_info(cpl_func,"frameset size [%" CPL_SIZE_FORMAT "]", cpl_frameset_get_size(frameset));
852 
853 
854  skip_if (detmon_lg_dfs_set_groups(frameset, tag_on, tag_off));
855 
856  /*
857  * First check of input consistency in NIR case:
858  * There must be a pair ON and a pair OFF for each DIT.
859  */
860 
861  skip_if (detmon_lg_retrieve_parlist(pipeline_name, recipe_name,
862  parlist, opt_nir));
863 
864  /*
865  * Retrieve first image to check some parameters' values and
866  * set default values which refer to the image.
867  */
868 
869  first = cpl_frameset_get_position(frameset, 0);
870  irplib_ensure (first != NULL, CPL_ERROR_ILLEGAL_INPUT, "Empty data set! Provide %s and %s input frames",tag_on,tag_off);
871 
872  detmon_lg_config.load_fset = load_fset;
873  detmon_lg_config.load_fset_wrp = load_fset ? irplib_load_fset_wrp_ext : irplib_load_fset_wrp;
874 
875 
876  detmon_lg_config.nb_extensions = 1;
877  if (detmon_lg_config.exts < 0) {
878  int i = 1;
879  detmon_lg_config.nb_extensions = cpl_frame_get_nextensions(first);
880  while (reference == NULL && i <= detmon_lg_config.nb_extensions) {
881  reference = cpl_image_load(cpl_frame_get_filename(first),
882  CPL_TYPE_FLOAT, 0, i);
883  if (reference == NULL) {
884  cpl_msg_warning(cpl_func, "Extension %d empty, skipping", i);
885  cpl_errorstate_set(cleanstate);
886  }
887  i++;
888  }
889  cpl_errorstate_set(cleanstate);
890  irplib_ensure (reference != NULL, CPL_ERROR_ILLEGAL_INPUT,
891  "No data found in any extension");
892  cpl_msg_info(cpl_func, "Using extension %d as reference", i - 1);
893  } else {
894  if (load_fset != NULL) {
895  cpl_frameset * new = cpl_frameset_new();
896  cpl_imagelist * p = cpl_imagelist_new();
897  cpl_frameset_insert(new, cpl_frame_duplicate(first));
898  (*load_fset)(new, CPL_TYPE_FLOAT, p);
899  reference = cpl_image_duplicate(cpl_imagelist_get(p, 0));
900  cpl_imagelist_delete(p);
901  cpl_frameset_delete(new);
902  } else {
903  cpl_msg_info(cpl_func,"name=%s",cpl_frame_get_filename(first));
904  reference = cpl_image_load(cpl_frame_get_filename(first),
905  CPL_TYPE_FLOAT, 0, detmon_lg_config.exts);
906  }
907  cpl_errorstate_set(cleanstate);
908  irplib_ensure (reference != NULL, CPL_ERROR_ILLEGAL_INPUT,
909  "No data found in requested extension %d",
910  detmon_lg_config.exts);
911  }
912  skip_if (reference == NULL);
913 
914  skip_if (detmon_lg_check_defaults(reference));
915 
916  /* Labelise all input frames */
917 
918  /*
919  * After each setting iteration, frameset will be modified (product
920  * frames will have been added), so it is better to duplicate it, keep
921  * it in its original state for the labelise-extract scheme.
922  */
923  if (compare == NULL) {
924  nsets = 1;
925  } else {
926  cpl_msg_info(cpl_func, "Identifying different settings");
927  selection = cpl_frameset_labelise(frameset, compare, &nsets);
928  skip_if (selection == NULL);
929  }
930 
931  /* Extract settings and reduce each of them */
932  for(int i = 0; i < nsets; i++)
933  {
934  int fr_size = cpl_frameset_get_size(frameset);
935  int fr_size_new = 0;
936  cpl_msg_info(cpl_func, "Reduce data set nb %d out of %" CPL_SIZE_FORMAT "",
937  i + 1, nsets);
938  skip_if(detmon_lg_reduce_set(i, frameset, nsets, tag_on, tag_off,
939  recipe_name,
940  pipeline_name,
941  pafregexp,
942  pro_lintbl,
943  pro_gaintbl,
944  pro_coeffscube,
945  pro_bpm,
946  pro_corr,
947  pro_diff,
948  package,
949  load_fset,
950  opt_nir,
951  parlist,
952  selection));
953  fr_size_new = cpl_frameset_get_size(frameset);
954  /* the size of the frameset could be changed during the detmon_lg_reduce_set call
955  * so the size of the selection array should be adjusted with some fake values,
956  * to avoid reading of the not allocated memory
957  * see DFS08110 for the error description
958  * */
959  if (fr_size_new > fr_size)
960  {
961  selection = cpl_realloc(selection, fr_size_new * sizeof(selection[0]));
962  memset(selection + fr_size, -1, (fr_size_new - fr_size) * sizeof(selection[0]));
963  }
964  }
965 
966  end_skip;
967 
968  cpl_frameset_delete(cur_fset);
969  cpl_frameset_delete(cur_fset_on);
970  cpl_frameset_delete(cur_fset_off);
971  cpl_free(selection);
972  cpl_image_delete(reference);
973 
974  return cpl_error_get_code();
975 }
976 
977 /*---------------------------------------------------------------------------*/
1008 /*---------------------------------------------------------------------------*/
1009 
1010 static cpl_error_code
1011 detmon_lg_core(cpl_frameset * cur_fset_on,
1012  cpl_frameset * cur_fset_off,
1013  int * index_on,
1014  int * index_off,
1015  double * exptime_on,
1016  double * exptime_off,
1017  int whichext,
1018  int whichset,
1019  const char * recipe_name,
1020  const char * pipeline_name,
1021  const char * pafregexp,
1022  const cpl_propertylist * pro_lintbl,
1023  const cpl_propertylist * pro_gaintbl,
1024  const cpl_propertylist * pro_coeffscube,
1025  const cpl_propertylist * pro_bpm,
1026  const cpl_propertylist * pro_corr,
1027  const cpl_propertylist * pro_diff,
1028  const char * package,
1029  int (* load_fset) (const cpl_frameset *,
1030  cpl_type,
1031  cpl_imagelist *),
1032  int nsets, cpl_boolean opt_nir,
1033  cpl_frameset * frameset, const cpl_parameterlist * parlist,
1034  cpl_frameset * cur_fset)
1035 {
1036  cpl_table * gain_table = cpl_table_new(
1037  cpl_frameset_get_size(cur_fset_on) / 2);
1038  cpl_table * linear_table = cpl_table_new(
1039  cpl_frameset_get_size(cur_fset_on) / 2);
1040  cpl_imagelist * coeffs = NULL;
1041  cpl_image * bpm = NULL;
1042  cpl_imagelist * autocorr_images = NULL;
1043  cpl_imagelist * diff_flats = NULL;
1044  cpl_propertylist * gaint_qclist = NULL;
1045  cpl_propertylist * lint_qclist = NULL;
1046  cpl_propertylist * linc_qclist = NULL;
1047  cpl_propertylist * bpm_qclist = NULL;
1048 
1049  int next_index_on = 0;
1050  int next_index_off = 0;
1051 
1052  /* Reduce extension nb i */
1053  cpl_msg_info(cpl_func, "Reduce extension nb %d ", whichext);
1054 
1055  /* FIXME: All other memory objects in use should be
1056  initialised here (except coeffs which can not be) */
1057  if (detmon_lg_config.intermediate) {
1058  autocorr_images = cpl_imagelist_new();
1059  diff_flats = cpl_imagelist_new();
1060  }
1061 
1062  gaint_qclist = cpl_propertylist_new();
1063  lint_qclist = cpl_propertylist_new();
1064  linc_qclist = cpl_propertylist_new();
1065  bpm_qclist = cpl_propertylist_new();
1066 
1067  /* Reduction done here */
1068  cpl_msg_info(cpl_func, "Starting data reduction");
1069  if (detmon_lg_reduce(cur_fset_on, cur_fset_off,
1070  index_on, index_off, exptime_on, exptime_off,
1071  &next_index_on, &next_index_off,
1072  &coeffs, gain_table,
1073  linear_table, &bpm, autocorr_images,
1074  diff_flats, gaint_qclist, lint_qclist,
1075  linc_qclist, bpm_qclist, load_fset,
1076  opt_nir, whichext) == CPL_ERROR_CONTINUE) {
1077  cpl_msg_info(cpl_func, "Empty extension %d", whichext);
1078  }
1079 
1080  /* Save the products for each setting */
1081  cpl_msg_info(cpl_func, "Saving the products");
1082  if (nsets == 1) {
1083  skip_if(
1084  detmon_lg_save(parlist, frameset, recipe_name,
1085  pipeline_name, pafregexp,
1086  pro_lintbl, pro_gaintbl,
1087  pro_coeffscube, pro_bpm,
1088  pro_corr, pro_diff, package,
1089  coeffs, gain_table, linear_table,
1090  bpm, autocorr_images, diff_flats,
1091  gaint_qclist, lint_qclist, linc_qclist,
1092  bpm_qclist, 0, 0, cur_fset, whichext));
1093  } else {
1094  skip_if(
1095  detmon_lg_save(parlist, frameset, recipe_name,
1096  pipeline_name, pafregexp,
1097  pro_lintbl, pro_gaintbl,
1098  pro_coeffscube, pro_bpm,
1099  pro_corr, pro_diff, package,
1100  coeffs, gain_table, linear_table,
1101  bpm, autocorr_images, diff_flats,
1102  gaint_qclist, lint_qclist, linc_qclist,
1103  bpm_qclist, 1, whichset+ 1, cur_fset,
1104  whichext));
1105  }
1106 
1107  end_skip;
1108 
1109  /* Free for each extension */
1110 
1111  cpl_table_delete(gain_table);
1112  cpl_table_delete(linear_table);
1113  cpl_imagelist_delete(coeffs);
1114  cpl_propertylist_delete(gaint_qclist);
1115  cpl_propertylist_delete(lint_qclist);
1116  cpl_propertylist_delete(linc_qclist);
1117  if(bpm_qclist != NULL) cpl_propertylist_delete(bpm_qclist);
1118  cpl_image_delete(bpm);
1119  cpl_imagelist_delete(autocorr_images);
1120  cpl_imagelist_delete(diff_flats);
1121 
1122  return cpl_error_get_code();
1123 }
1124 
1125 
1126 /*--------------------------------------------------------------------------*/
1127 
1128 /*
1129  * @brief Correlate two images with a given range of shifts
1130  * @param image1 Input image
1131  * @param image2 Input image
1132  * @param m Shift to apply on the x-axis
1133  * @param n Shift to apply on the y-axis
1134  * @return An image of size 2m+1 by 2n+1. Each pixel value
1135  * corresponds to the correlation of shift the position
1136  * of the pixel. Pixel in the centre (m+1, n+1),
1137  * corresponds to shift (0,0). Pixels to the left and
1138  * down correspond to negative shifts.
1139  *
1140  * @note At this moment, this function only accepts images to
1141  * have both the same size.
1142  */
1143 
1144 /*--------------------------------------------------------------------------*/
1145 
1146 cpl_image *
1147 detmon_image_correlate(const cpl_image * image1,
1148  const cpl_image * image2,
1149  const int m, const int n)
1150 {
1151  cpl_image *image1_padded = NULL;
1152  cpl_image *image2_padded = NULL;
1153  int nx, ny;
1154  int nx2, ny2;
1155 
1156  cpl_image *corr_image_window = NULL;
1157 
1158  cpl_image* image_ri1 = NULL;
1159  cpl_image* image_ri2 = NULL;
1160  cpl_error_code err = CPL_ERROR_NONE;
1161 
1162  /* Test the entries */
1163  cpl_ensure(image1 != NULL, CPL_ERROR_NULL_INPUT, NULL);
1164  cpl_ensure(image2 != NULL, CPL_ERROR_NULL_INPUT, NULL);
1165 
1166  cpl_ensure(m > 0, CPL_ERROR_NULL_INPUT, NULL);
1167  cpl_ensure(n > 0, CPL_ERROR_NULL_INPUT, NULL);
1168 
1169  nx = cpl_image_get_size_x(image1);
1170  ny = cpl_image_get_size_y(image1);
1171 
1172  nx2 = cpl_image_get_size_x(image2);
1173  ny2 = cpl_image_get_size_y(image2);
1174 
1175  /* At this moment, the images must be of the same size */
1176  cpl_ensure(nx == nx2 && ny == ny2, CPL_ERROR_ILLEGAL_INPUT, NULL);
1177 
1178  /* Pad the images with zeroes to avoid periodical effects of DFT */
1179  image1_padded = cpl_image_new(nx + 2 * m, ny + 2 * n, CPL_TYPE_FLOAT);
1180  cpl_image_copy(image1_padded, image1, m + 1, n + 1);
1181 
1182  image2_padded = cpl_image_new(nx + 2 * m, ny + 2 * n, CPL_TYPE_FLOAT);
1183  cpl_image_copy(image2_padded, image2, m + 1, n + 1);
1184 
1185  /*New dimensions of the padded images */
1186  nx = nx + 2 * m;
1187  ny = ny + 2 * n;
1188 
1189  image_ri1 = cpl_image_new(nx, ny, CPL_TYPE_FLOAT_COMPLEX);
1190  image_ri2 = cpl_image_new(nx, ny , CPL_TYPE_FLOAT_COMPLEX);
1191  /* Actually perform the FFT */
1192  cpl_fft_image(image_ri1, image1_padded, CPL_FFT_FORWARD);
1193  cpl_fft_image(image_ri2, image2_padded, CPL_FFT_FORWARD);
1194  err = cpl_error_get_code();
1195  cpl_image_delete(image1_padded);
1196  image1_padded = NULL;
1197  cpl_image_delete(image2_padded);
1198  image2_padded = NULL;
1199  if (err == CPL_ERROR_NONE)
1200  {
1201  /* Cleanup resources */
1202  cpl_image * corr_image = NULL;
1203  cpl_image * reorganised= NULL;
1204  cpl_image * image_ri_inv = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
1205  cpl_image * image_in_inv = cpl_image_new(nx, ny,
1206  CPL_TYPE_FLOAT_COMPLEX);
1207  int i,j;
1208 
1209  for (i = 1; i <= nx; i++)
1210  {
1211  for (j = 1; j <= ny; j++)
1212  {
1213  int rej = 0;
1214  double complex value1, value2, value;
1215  value1 = cpl_image_get_complex(image_ri1, i, j, &rej);
1216  value2 = cpl_image_get_complex(image_ri2, i, j, &rej);;
1217  value = conj(value1) * value2;
1218  cpl_image_set_complex(image_in_inv, i, j, value);
1219  }
1220  }
1221  cpl_image_delete(image_ri1);
1222  image_ri1 = NULL;
1223  cpl_image_delete(image_ri2);
1224  image_ri2 = NULL;
1225 
1226  err = cpl_error_get_code();
1227  if (err == CPL_ERROR_NONE)
1228  {
1229 
1230  /* Actually perform the FFT */
1231  cpl_fft_image(image_ri_inv, image_in_inv,CPL_FFT_BACKWARD);
1232  cpl_image_delete(image_in_inv);
1233 
1234  /* Get the module of the inversed signal */
1235  corr_image = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
1236  for (i = 1; i <= nx; i++)
1237  {
1238  for (j = 1; j <= ny; j++)
1239  {
1240  int rej = 0;
1241  double value =0;
1242  value = cpl_image_get(image_ri_inv, i, j, &rej);
1243  cpl_image_set(corr_image, i, j, value);
1244  }
1245  }
1246  cpl_image_delete(image_ri_inv);
1247  err = cpl_error_get_code();
1248  if (err == CPL_ERROR_NONE)
1249  {
1250  /* Reorganise the pixels to the output */
1251  cpl_image * image =
1252  cpl_image_extract(corr_image, nx / 2 + 1, 1, nx, ny);
1253  reorganised = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
1254 
1255  cpl_image_copy(reorganised, image, 1, 1);
1256  cpl_image_delete(image);
1257  image = cpl_image_extract(corr_image, 1, 1, nx / 2, ny);
1258  cpl_image_copy(reorganised, image, nx / 2 + 1, 1);
1259  cpl_image_delete(image);
1260 
1261  cpl_image_delete(corr_image);
1262 
1263  corr_image = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
1264  image = cpl_image_extract(reorganised, 1, ny / 2 + 1, nx, ny);
1265  cpl_image_copy(corr_image, image, 1, 1);
1266  cpl_image_delete(image);
1267 
1268  image = cpl_image_extract(reorganised, 1, 1, nx, ny / 2);
1269  cpl_image_copy(corr_image, image, 1, ny / 2 + 1);
1270  cpl_image_delete(image);
1271  /* Extract a window with the desired shifts */
1272  corr_image_window = cpl_image_extract(corr_image,
1273  nx / 2 + 1 - m,
1274  ny / 2 + 1 - n,
1275  nx / 2 + 1 + m, ny / 2 + 1 + n);
1276  }
1277  /* Free and return */
1278 
1279  }
1280  cpl_image_delete(reorganised);
1281  cpl_image_delete(corr_image);
1282 
1283  if(cpl_image_divide_scalar(corr_image_window,
1284  cpl_image_get_max(corr_image_window))) {
1285  cpl_image_delete(corr_image_window);
1286  return NULL;
1287  }
1288  }
1289  cpl_image_delete (image_ri1);
1290  cpl_image_delete (image_ri2);
1291  cpl_image_delete (image1_padded);
1292  cpl_image_delete (image2_padded);
1293  return corr_image_window;
1294 }
1295 
1296 
1297 
1298 /*--------------------------------------------------------------------------*/
1299 
1300 /*
1301  * @brief Autocorrelate an image with a given range of shifts, using
1302  * cpl_image_fft()
1303  * @param input2 Input image
1304  * @param m Shift to apply on the x-axis
1305  * @param n Shift to apply on the y-axis
1306  * @return An image of size 2m+1 by 2n+1. Each pixel value
1307  * corresponds to the correlation of shift the position
1308  * of the pixel. Pixel in the centre (m+1, n+1),
1309  * corresponds to shift (0,0). Pixels to the left and
1310  * down correspond to negative shifts.
1311  */
1312 
1313 /*--------------------------------------------------------------------------*/
1314 
1315 cpl_image *
1316 detmon_autocorrelate(const cpl_image * input2, const int m,
1317  const int n)
1318 {
1319  cpl_image *im_re = NULL;
1320  cpl_image *im_im = NULL;
1321  int nx, ny;
1322  cpl_image *ifft_re = NULL;
1323  cpl_image *ifft_im = NULL;
1324  cpl_image *autocorr = NULL;
1325  cpl_image *autocorr_norm_double = NULL;
1326  cpl_image *autocorr_norm = NULL;
1327  cpl_image *reorganised = NULL;
1328  cpl_image *image = NULL;
1329  int p;
1330  cpl_error_code error;
1331  cpl_image *input;
1332 
1333  cpl_ensure(input2 != NULL, CPL_ERROR_NULL_INPUT, NULL);
1334 
1335  cpl_ensure(m > 0, CPL_ERROR_NULL_INPUT, NULL);
1336  cpl_ensure(n > 0, CPL_ERROR_NULL_INPUT, NULL);
1337 
1338  nx = cpl_image_get_size_x(input2) + 2 * m;
1339  ny = cpl_image_get_size_y(input2) + 2 * n;
1340 
1341  p = 128;
1342  while(nx > p || ny > p) {
1343  p *= 2;
1344  }
1345 
1346  input = cpl_image_cast(input2, CPL_TYPE_DOUBLE);
1347 
1348  im_re = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
1349  error = cpl_image_copy(im_re, input, 1, 1);
1350  cpl_image_delete(input);
1351 
1352  cpl_ensure(!error, error, NULL);
1353 
1354  im_im = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
1355 
1356  error = cpl_image_fft(im_re, im_im, CPL_FFT_DEFAULT);
1357  cpl_ensure(!error, error, NULL);
1358 
1359  ifft_re = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
1360  error = cpl_image_power(im_re, 2);
1361  cpl_ensure(!error, error, NULL);
1362 
1363  error = cpl_image_add(ifft_re, im_re);
1364  cpl_ensure(!error, error, NULL);
1365 
1366  cpl_image_delete(im_re);
1367 
1368  error = cpl_image_power(im_im, 2);
1369  cpl_ensure(!error, error, NULL);
1370 
1371  error = cpl_image_add(ifft_re, im_im);
1372  cpl_ensure(!error, error, NULL);
1373 
1374  cpl_image_delete(im_im);
1375 
1376  ifft_im = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
1377 
1378  error = cpl_image_fft(ifft_re, ifft_im, CPL_FFT_INVERSE);
1379  cpl_ensure(!error, error, NULL);
1380 
1381  autocorr = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
1382 
1383  error = cpl_image_power(ifft_re, 2);
1384  cpl_ensure(!error, error, NULL);
1385 
1386  error = cpl_image_add(autocorr, ifft_re);
1387  cpl_ensure(!error, error, NULL);
1388 
1389  cpl_image_delete(ifft_re);
1390 
1391  error = cpl_image_power(ifft_im, 2);
1392  cpl_ensure(!error, error, NULL);
1393 
1394  error = cpl_image_add(autocorr, ifft_im);
1395  cpl_ensure(!error, error, NULL);
1396 
1397  cpl_image_delete(ifft_im);
1398 
1399  /* Reorganise the pixels to the output */
1400  reorganised = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
1401 
1402  image = cpl_image_extract(autocorr, p / 2 + 1, 1, p, p);
1403  cpl_image_copy(reorganised, image, 1, 1);
1404  cpl_image_delete(image);
1405 
1406  image = cpl_image_extract(autocorr, 1, 1, p / 2, p);
1407  cpl_image_copy(reorganised, image, p / 2 + 1, 1);
1408  cpl_image_delete(image);
1409 
1410  cpl_image_delete(autocorr);
1411 
1412  autocorr = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
1413 
1414  image = cpl_image_extract(reorganised, 1, p / 2 + 1, p, p);
1415  cpl_image_copy(autocorr, image, 1, 1);
1416  cpl_image_delete(image);
1417 
1418  image = cpl_image_extract(reorganised, 1, 1, p, p / 2);
1419  cpl_image_copy(autocorr, image, 1, p / 2 + 1);
1420  cpl_image_delete(image);
1421 
1422  cpl_image_delete(reorganised);
1423 
1424  autocorr_norm_double =
1425  cpl_image_extract(autocorr, p / 2 + 1 - m, p / 2 + 1 - n,
1426  p / 2 + 1 + m, p / 2 + 1 + n);
1427 
1428  cpl_image_delete(autocorr);
1429 
1430  if(cpl_image_divide_scalar(autocorr_norm_double,
1431  cpl_image_get_max(autocorr_norm_double))) {
1432  cpl_image_delete(autocorr_norm_double);
1433  cpl_ensure(0, cpl_error_get_code(), NULL);
1434  }
1435 
1436 
1437  autocorr_norm = cpl_image_cast(autocorr_norm_double, CPL_TYPE_FLOAT);
1438  cpl_image_delete(autocorr_norm_double);
1439 
1440  return autocorr_norm;
1441 }
1442 
1443 /*---------------------------------------------------------------------------*/
1454 /*---------------------------------------------------------------------------*/
1455 cpl_error_code
1456 detmon_lg_fill_parlist_nir_default(cpl_parameterlist * parlist,
1457  const char *recipe_name,
1458  const char *pipeline_name)
1459 {
1460  const cpl_error_code error =
1461  detmon_lg_fill_parlist(parlist, recipe_name, pipeline_name,
1462  "PTC", /* --method */
1463  3, /* --order */
1464  3., /* --kappa */
1465  5, /* --niter */
1466  -1, /* --llx */
1467  -1, /* --lly */
1468  -1, /* --urx */
1469  -1, /* --ury */
1470  10000, /* --ref_level */
1471  "CPL_FALSE", /* --intermediate */
1472  "CPL_FALSE", /* --autocorr */
1473  "CPL_FALSE", /* --collapse */
1474  "CPL_TRUE", /* --rescale */
1475  "CPL_TRUE",/* --pix2pix */
1476  "CPL_FALSE", /* --bpmbin */
1477  -1, /* --filter */
1478  26, /* --m */
1479  26, /* --n */
1480  1e-3, /* --tolerance */
1481  "CPL_FALSE", /* --pafgen */
1482  recipe_name, /* --pafname */
1483  -1, /* --llx1 */
1484  -1, /* --lly1 */
1485  -1, /* --urx1 */
1486  -1, /* --ury1 */
1487  -1, /* --llx2 */
1488  -1, /* --lly2 */
1489  -1, /* --urx2 */
1490  -1, /* --ury2 */
1491  -1, /* --llx3 */
1492  -1, /* --lly3 */
1493  -1, /* --urx3 */
1494  -1, /* --ury3 */
1495  -1, /* --llx4 */
1496  -1, /* --lly4 */
1497  -1, /* --urx4 */
1498  -1, /* --ury4 */
1499  -1, /* --llx5 */
1500  -1, /* --lly5 */
1501  -1, /* --urx5 */
1502  -1, /* --ury5 */
1503  0, /* --exts */
1504  NIR); /* This is to specify OPT params */
1505 
1506 
1507  cpl_ensure_code(!error, error);
1508 
1509  return cpl_error_get_code();
1510 }
1511 
1512 /*---------------------------------------------------------------------------*/
1523 /*---------------------------------------------------------------------------*/
1524 cpl_error_code
1525 detmon_lg_fill_parlist_opt_default(cpl_parameterlist * parlist,
1526  const char *recipe_name,
1527  const char *pipeline_name)
1528 {
1529  const cpl_error_code error =
1530  detmon_lg_fill_parlist(parlist, recipe_name, pipeline_name,
1531  "PTC", /* --method */
1532  3, /* --order */
1533  3., /* --kappa */
1534  5, /* --niter */
1535  -1, /* --llx */
1536  -1, /* --lly */
1537  -1, /* --urx */
1538  -1, /* --ury */
1539  10000, /* --ref_level */
1540  "CPL_FALSE", /* --intermediate */
1541  "CPL_FALSE", /* --autocorr */
1542  "CPL_TRUE", /* --collapse */
1543  "CPL_TRUE", /* --rescale */
1544  "CPL_FALSE", /* --pix2pix */
1545  "CPL_FALSE", /* --bpmbin */
1546  -1, /* --filter */
1547  26, /* --m */
1548  26, /* --n */
1549  1e-3, /* --tolerance */
1550  "CPL_FALSE", /* --pafgen */
1551  recipe_name, /* --pafname */
1552  -1, /* --llx1 */
1553  -1, /* --lly1 */
1554  -1, /* --urx1 */
1555  -1, /* --ury1 */
1556  -1, /* --llx2 */
1557  -1, /* --lly2 */
1558  -1, /* --urx2 */
1559  -1, /* --ury2 */
1560  -1, /* --llx3 */
1561  -1, /* --lly3 */
1562  -1, /* --urx3 */
1563  -1, /* --ury3 */
1564  -1, /* --llx4 */
1565  -1, /* --lly4 */
1566  -1, /* --urx4 */
1567  -1, /* --ury4 */
1568  -1, /* --llx5 */
1569  -1, /* --lly5 */
1570  -1, /* --urx5 */
1571  -1, /* --ury5 */
1572  0, /* --exts */
1573  OPT); /* This is to specify OPT params */
1574 
1575  cpl_ensure_code(!error, error);
1576 
1577  return cpl_error_get_code();
1578 }
1579 
1580 static cpl_error_code
1581 detmon_lg_fill_parlist_default_mr(cpl_parameterlist * parlist,
1582  const char *recipe_name,
1583  const char *pipeline_name)
1584 {
1585  char * group_name = cpl_sprintf("%s.%s", pipeline_name, recipe_name);
1586  char * par_name = cpl_sprintf("%s.%s", group_name, "regions-file");
1587  cpl_parameter * p = cpl_parameter_new_value(par_name, CPL_TYPE_STRING,
1588  "File containing regions, "
1589  "four comma separated points "
1590  "per line",
1591  group_name, "");
1592  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "regions-file");
1593  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
1594  cpl_parameterlist_append(parlist, p);
1595  cpl_free(par_name);
1596  cpl_free(group_name);
1597 
1598  group_name = cpl_sprintf("%s.%s", pipeline_name, recipe_name);
1599  par_name = cpl_sprintf("%s.%s", group_name, "regions");
1600  p = cpl_parameter_new_value(par_name, CPL_TYPE_STRING,
1601  "Colon separated list of regions, four "
1602  "points each, comma separated: "
1603  "llx,lly,urx,ury:llx,...",
1604  group_name, "");
1605  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "regions");
1606  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
1607  cpl_parameterlist_append(parlist, p);
1608  cpl_free(par_name);
1609  cpl_free(group_name);
1610 
1611  return cpl_error_get_code();
1612 }
1613 
1614 cpl_error_code
1615 detmon_lg_fill_parlist_opt_default_mr(cpl_parameterlist * parlist,
1616  const char *recipe_name,
1617  const char *pipeline_name)
1618 {
1619  detmon_lg_fill_parlist_opt_default(parlist, recipe_name, pipeline_name);
1620  detmon_lg_fill_parlist_default_mr(parlist, recipe_name, pipeline_name);
1621  return cpl_error_get_code();
1622 }
1623 
1624 cpl_error_code
1625 detmon_lg_fill_parlist_nir_default_mr(cpl_parameterlist * parlist,
1626  const char *recipe_name,
1627  const char *pipeline_name)
1628 {
1629  detmon_lg_fill_parlist_nir_default(parlist, recipe_name, pipeline_name);
1630  detmon_lg_fill_parlist_default_mr(parlist, recipe_name, pipeline_name);
1631 
1632  return cpl_error_get_code();
1633 }
1634 
1635 
1636 /*---------------------------------------------------------------------------*/
1690 /*---------------------------------------------------------------------------*/
1691 cpl_error_code
1692 detmon_lg_fill_parlist(cpl_parameterlist * parlist,
1693  const char *recipe_name, const char *pipeline_name,
1694  const char *method,
1695  int order,
1696  double kappa,
1697  int niter,
1698  int llx,
1699  int lly,
1700  int urx,
1701  int ury,
1702  int ref_level,
1703  const char *intermediate,
1704  const char *autocorr,
1705  const char *collapse,
1706  const char *rescale,
1707  const char *pix2pix,
1708  const char *bpmbin,
1709  int filter,
1710  int m,
1711  int n,
1712  double tolerance,
1713  const char *pafgen,
1714  const char * pafname,
1715  int llx1,
1716  int lly1,
1717  int urx1,
1718  int ury1,
1719  int llx2,
1720  int lly2,
1721  int urx2,
1722  int ury2,
1723  int llx3,
1724  int lly3,
1725  int urx3,
1726  int ury3,
1727  int llx4,
1728  int lly4,
1729  int urx4,
1730  int ury4,
1731  int llx5, int lly5, int urx5, int ury5, int exts,
1732  cpl_boolean opt_nir)
1733 {
1734  const cpl_error_code error =
1735  detmon_fill_parlist(parlist, recipe_name, pipeline_name, 26,
1736  "method",
1737  "Method to be used when computing GAIN. Methods appliable: <PTC | MED>. By default PTC method will be applied.",
1738  "CPL_TYPE_STRING", method,
1739 
1740  "order",
1741  "Polynomial order for the fit (Linearity)",
1742  "CPL_TYPE_INT", order,
1743  "kappa",
1744  "Kappa value for the kappa-sigma clipping (Gain)",
1745  "CPL_TYPE_DOUBLE", kappa,
1746  "niter",
1747  "Number of iterations to compute rms (Gain)",
1748  "CPL_TYPE_INT", niter,
1749  "llx",
1750  "x coordinate of the lower-left "
1751  "point of the region of interest. If not modified, default value will be 1.",
1752  "CPL_TYPE_INT", llx,
1753  "lly",
1754  "y coordinate of the lower-left "
1755  "point of the region of interest. If not modified, default value will be 1.",
1756  "CPL_TYPE_INT", lly,
1757  "urx",
1758  "x coordinate of the upper-right "
1759  "point of the region of interest. If not modified, default value will be X dimension of the input image.",
1760  "CPL_TYPE_INT", urx,
1761  "ury",
1762  "y coordinate of the upper-right "
1763  "point of the region of interest. If not modified, default value will be Y dimension of the input image.",
1764  "CPL_TYPE_INT", ury,
1765  "ref_level",
1766  "User reference level",
1767  "CPL_TYPE_INT", ref_level,
1768  "intermediate",
1769  "De-/Activate intermediate products",
1770  "CPL_TYPE_BOOL", intermediate,
1771 
1772  "autocorr",
1773  "De-/Activate the autocorr option",
1774  "CPL_TYPE_BOOL", autocorr,
1775 
1776  "collapse",
1777  "De-/Activate the collapse option",
1778  "CPL_TYPE_BOOL", collapse,
1779  "rescale",
1780  "De-/Activate the image rescale option",
1781  "CPL_TYPE_BOOL", rescale,
1782  "pix2pix",
1783  "De-/Activate the computation with pixel to pixel accuracy",
1784  "CPL_TYPE_BOOL", pix2pix,
1785  "bpmbin",
1786  "De-/Activate the binary bpm option",
1787  "CPL_TYPE_BOOL", bpmbin,
1788  "m",
1789  "Maximum x-shift for the autocorr",
1790  "CPL_TYPE_INT", m,
1791  "filter",
1792  "Upper limit of Median flux to be filtered",
1793  "CPL_TYPE_INT", filter,
1794  "n",
1795  "Maximum y-shift for the autocorr",
1796  "CPL_TYPE_INT", n,
1797  "tolerance",
1798  "Tolerance for pair discrimination",
1799  "CPL_TYPE_DOUBLE", tolerance,
1800 
1801  "pafgen",
1802  "Generate PAF file",
1803  "CPL_TYPE_BOOL", pafgen,
1804  "pafname",
1805  "Specific name for PAF file",
1806  "CPL_TYPE_STRING", pafname,
1807 
1808 
1809  "exts",
1810  "Activate the multi-exts option. Choose -1 to process all extensions. Choose an extension number"
1811  " to process the appropriate extension.",
1812  "CPL_TYPE_INT", exts,
1813 
1814  "fpn_method",
1815  "Method for computing Fixed Pattern Noise (SMOOTH or HISTOGRAM)",
1816  "CPL_TYPE_STRING", "HISTOGRAM",
1817 
1818  "fpn_smooth",
1819  "template size in pixels for smoothing during FPN computation (only for SMOOTH method)",
1820  "CPL_TYPE_INT", 13,
1821 
1822  "saturation_limit",
1823  "all frames with mean saturation above the limit would not be used in linearity calculation",
1824  "CPL_TYPE_DOUBLE", 65535.0,
1825 
1826  "gain_threshold",
1827  "all frames with mean flux above the threshold would not be used in gain calculation",
1828  "CPL_TYPE_DOUBLE", 65535.0
1829 
1830  );
1831  detmon_fill_parlist(parlist, recipe_name, pipeline_name, 1,
1832  "coeffs_cube_split",
1833  "if TRUE, the recipe writes as many "
1834  "COEFFS_CUBE_Pi (i=0..order) as the value of "
1835  "the order parameter in a separate file",
1836  "CPL_TYPE_BOOL", "CPL_FALSE");
1837  /* OPT specific parameters */
1838  if(opt_nir == FALSE) {
1839  const cpl_error_code erroropt =
1840  detmon_fill_parlist(parlist, recipe_name, pipeline_name, 20,
1841  "llx1",
1842  "x coord of the lower-left point of the first "
1843  "field used for contamination measurement. If not modified, default value will be 1.",
1844  "CPL_TYPE_INT", llx1,
1845  "lly1",
1846  "y coord of the lower-left point of the first "
1847  "field used for contamination measurement. If not modified, default value will be 1.",
1848  "CPL_TYPE_INT", lly1,
1849  "urx1",
1850  "x coord of the upper-right point of the first "
1851  "field used for contamination measurement. If not modified, default value will be X dimension of the input image.",
1852  "CPL_TYPE_INT", urx1,
1853  "ury1",
1854  "y coord of the upper-right point of the first "
1855  "field used for contamination measurement. If not modified, default value will be Y dimension of the input image.",
1856  "CPL_TYPE_INT", ury1,
1857  "llx2",
1858  "x coord of the lower-left point of the second "
1859  "field used for contamination measurement. If not modified, default value will be 1.",
1860  "CPL_TYPE_INT", llx2,
1861  "lly2",
1862  "y coord of the lower-left point of the second "
1863  "field used for contamination measurement. If not modified, default value will be 1.",
1864  "CPL_TYPE_INT", lly2,
1865  "urx2",
1866  "x coord of the upper-right point of the second "
1867  "field used for contamination measurement. If not modified, default value will be half of the X dimension of the input image.",
1868  "CPL_TYPE_INT", urx2,
1869  "ury2",
1870  "y coord of the upper-right point of the second "
1871  "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
1872  "CPL_TYPE_INT", ury2,
1873  "llx3",
1874  "x coord of the lower-left point of the third "
1875  "field used for contamination measurement. If not modified, default value will be 1.",
1876  "CPL_TYPE_INT", llx3,
1877  "lly3",
1878  "y coord of the lower-left point of the third "
1879  "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
1880  "CPL_TYPE_INT", lly3,
1881  "urx3",
1882  "x coord of the upper-right point of the third "
1883  "field used for contamination measurement. If not modified, default value will be half of X dimension of the image.",
1884  "CPL_TYPE_INT", urx3,
1885  "ury3",
1886  "y coord of the upper-right point of the third "
1887  "field used for contamination measurement. If not modified, default value will be Y dimension of the image.",
1888  "CPL_TYPE_INT", ury3,
1889  "llx4",
1890  "x coord of the lower-left point of the fourth "
1891  "field used for contamination measurement. If not modified, default value will be half of X dimension of the image.",
1892  "CPL_TYPE_INT", llx4,
1893  "lly4",
1894  "y coord of the lower-left point of the fourth "
1895  "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
1896  "CPL_TYPE_INT", lly4,
1897  "urx4",
1898  "x coord of the upper-right point of the fourth "
1899  "field used for contamination measurement. If not modified, default value will be X dimension of the image.",
1900  "CPL_TYPE_INT", urx4,
1901  "ury4",
1902  "y coord of the upper-right point of the fourth "
1903  "field used for contamination measurement. If not modified, default value will be Y dimension of the input image.",
1904  "CPL_TYPE_INT", ury4,
1905  "llx5",
1906  "x coord of the lower-left point of the fifth "
1907  "field used for contamination measurement. If not modified, default value will be half of the X dimension of the input image.",
1908  "CPL_TYPE_INT", llx5,
1909  "lly5",
1910  "y coord of the lower-left point of the fifth "
1911  "field used for contamination measurement. If not modified, default value will be 1.",
1912  "CPL_TYPE_INT", lly5,
1913  "urx5",
1914  "x coord of the upper-right point of the fifth "
1915  "field used for contamination measurement. If not modified, default value will be X dimension of the image.",
1916  "CPL_TYPE_INT", urx5,
1917 
1918  "ury5",
1919  "y coord of the upper-right point of the fifth "
1920  "field used for contamination measurement. If not modified, default value will be half of Y dimension of the input image.",
1921  "CPL_TYPE_INT", ury5);
1922 
1923 
1924  cpl_ensure_code(!erroropt, erroropt);
1925  }
1926 
1927  cpl_ensure_code(!error, error);
1928 
1929  return cpl_error_get_code();
1930 }
1931 
1932 /*---------------------------------------------------------------------------*/
1941 /*---------------------------------------------------------------------------*/
1942 static cpl_error_code
1943 detmon_lg_retrieve_parlist(const char * pipeline_name,
1944  const char * recipe_name,
1945  const cpl_parameterlist * parlist,
1946  cpl_boolean opt_nir)
1947 {
1948 
1949  char * par_name;
1950  const cpl_parameter * par;
1951 
1952  /* --method */
1953  par_name = cpl_sprintf("%s.%s.method", pipeline_name, recipe_name);
1954  assert(par_name != NULL);
1955  par = cpl_parameterlist_find_const(parlist, par_name);
1956  detmon_lg_config.method = cpl_parameter_get_string(par);
1957  cpl_free(par_name);
1958 
1959  /* --order */
1960  detmon_lg_config.order =
1961  detmon_retrieve_par_int("order", pipeline_name, recipe_name,
1962  parlist);
1963 
1964  /* --kappa */
1965  detmon_lg_config.kappa =
1966  detmon_retrieve_par_double("kappa", pipeline_name, recipe_name,
1967  parlist);
1968 
1969  /* --niter */
1970  detmon_lg_config.niter =
1971  detmon_retrieve_par_int("niter", pipeline_name, recipe_name,
1972  parlist);
1973 
1974  /* --llx */
1975  detmon_lg_config.llx =
1976  detmon_retrieve_par_int("llx", pipeline_name, recipe_name,
1977  parlist);
1978 
1979  /* --lly */
1980  detmon_lg_config.lly =
1981  detmon_retrieve_par_int("lly", pipeline_name, recipe_name,
1982  parlist);
1983 
1984  /* --urx */
1985  detmon_lg_config.urx =
1986  detmon_retrieve_par_int("urx", pipeline_name, recipe_name,
1987  parlist);
1988 
1989  /* --ury */
1990  detmon_lg_config.ury =
1991  detmon_retrieve_par_int("ury", pipeline_name, recipe_name,
1992  parlist);
1993 
1994  /* --ref_level */
1995  detmon_lg_config.ref_level =
1996  detmon_retrieve_par_int("ref_level", pipeline_name, recipe_name,
1997  parlist);
1998 
1999  /* --intermediate */
2000  par_name =
2001  cpl_sprintf("%s.%s.intermediate", pipeline_name, recipe_name);
2002  assert(par_name != NULL);
2003  par = cpl_parameterlist_find_const(parlist, par_name);
2004  detmon_lg_config.intermediate = cpl_parameter_get_bool(par);
2005  cpl_free(par_name);
2006 
2007  /* --autocorr */
2008  par_name = cpl_sprintf("%s.%s.autocorr", pipeline_name, recipe_name);
2009  assert(par_name != NULL);
2010  par = cpl_parameterlist_find_const(parlist, par_name);
2011  detmon_lg_config.autocorr = cpl_parameter_get_bool(par);
2012  cpl_free(par_name);
2013 
2014  /* --coeffs_cube_split */
2015  par_name = cpl_sprintf("%s.%s.coeffs_cube_split", pipeline_name, recipe_name);
2016  assert(par_name != NULL);
2017  par = cpl_parameterlist_find_const(parlist, par_name);
2018  detmon_lg_config.split_coeffs = cpl_parameter_get_bool(par);
2019  cpl_free(par_name);
2020 
2021  /* --collapse */
2022  par_name = cpl_sprintf("%s.%s.collapse", pipeline_name, recipe_name);
2023  assert(par_name != NULL);
2024  par = cpl_parameterlist_find_const(parlist, par_name);
2025  detmon_lg_config.collapse = cpl_parameter_get_bool(par);
2026  cpl_free(par_name);
2027 
2028  /* --rescale */
2029  par_name = cpl_sprintf("%s.%s.rescale", pipeline_name, recipe_name);
2030  assert(par_name != NULL);
2031  par = cpl_parameterlist_find_const(parlist, par_name);
2032  detmon_lg_config.rescale = cpl_parameter_get_bool(par);
2033  cpl_free(par_name);
2034 
2035  /* --pix2pix */
2036  par_name = cpl_sprintf("%s.%s.pix2pix", pipeline_name, recipe_name);
2037  assert(par_name != NULL);
2038  par = cpl_parameterlist_find_const(parlist, par_name);
2039  detmon_lg_config.pix2pix = cpl_parameter_get_bool(par);
2040  cpl_free(par_name);
2041 
2042  /* --bpmbin */
2043  par_name = cpl_sprintf("%s.%s.bpmbin", pipeline_name, recipe_name);
2044  assert(par_name != NULL);
2045  par = cpl_parameterlist_find_const(parlist, par_name);
2046  detmon_lg_config.bpmbin = cpl_parameter_get_bool(par);
2047  cpl_free(par_name);
2048 
2049  /* --filter */
2050  detmon_lg_config.filter =
2051  detmon_retrieve_par_int("filter", pipeline_name,
2052  recipe_name, parlist);
2053 
2054  /* --m */
2055  detmon_lg_config.m =
2056  detmon_retrieve_par_int("m", pipeline_name, recipe_name, parlist);
2057 
2058  /* --n */
2059  detmon_lg_config.n =
2060  detmon_retrieve_par_int("n", pipeline_name, recipe_name, parlist);
2061 
2062  /* --tolerance */
2063  par_name = cpl_sprintf("%s.%s.tolerance", pipeline_name, recipe_name);
2064  assert(par_name != NULL);
2065  par = cpl_parameterlist_find_const(parlist, par_name);
2066  detmon_lg_config.tolerance = cpl_parameter_get_double(par);
2067  cpl_free(par_name);
2068 
2069 
2070  /* --pafgen */
2071  par_name = cpl_sprintf("%s.%s.pafgen", pipeline_name, recipe_name);
2072  assert(par_name != NULL);
2073  par = cpl_parameterlist_find_const(parlist, par_name);
2074  detmon_lg_config.pafgen = cpl_parameter_get_bool(par);
2075  cpl_free(par_name);
2076 
2077  /* --pafname */
2078  par_name = cpl_sprintf("%s.%s.pafname", pipeline_name, recipe_name);
2079  assert(par_name != NULL);
2080  par = cpl_parameterlist_find_const(parlist, par_name);
2081  detmon_lg_config.pafname = cpl_parameter_get_string(par);
2082  cpl_free(par_name);
2083 
2084  if(opt_nir == OPT) {
2085  /* --llx1 */
2086  detmon_lg_config.llx1 =
2087  detmon_retrieve_par_int("llx1", pipeline_name, recipe_name,
2088  parlist);
2089 
2090  /* --lly1 */
2091  detmon_lg_config.lly1 =
2092  detmon_retrieve_par_int("lly1", pipeline_name, recipe_name,
2093  parlist);
2094 
2095  /* --urx1 */
2096  detmon_lg_config.urx1 =
2097  detmon_retrieve_par_int("urx1", pipeline_name, recipe_name,
2098  parlist);
2099 
2100  /* --ury1 */
2101  detmon_lg_config.ury1 =
2102  detmon_retrieve_par_int("ury1", pipeline_name, recipe_name,
2103  parlist);
2104 
2105  /* --llx2 */
2106  detmon_lg_config.llx2 =
2107  detmon_retrieve_par_int("llx2", pipeline_name, recipe_name,
2108  parlist);
2109 
2110  /* --lly2 */
2111  detmon_lg_config.lly2 =
2112  detmon_retrieve_par_int("lly2", pipeline_name, recipe_name,
2113  parlist);
2114 
2115  /* --urx2 */
2116  detmon_lg_config.urx2 =
2117  detmon_retrieve_par_int("urx2", pipeline_name, recipe_name,
2118  parlist);
2119 
2120  /* --ury2 */
2121  detmon_lg_config.ury2 =
2122  detmon_retrieve_par_int("ury2", pipeline_name, recipe_name,
2123  parlist);
2124 
2125  /* --llx3 */
2126  detmon_lg_config.llx3 =
2127  detmon_retrieve_par_int("llx3", pipeline_name, recipe_name,
2128  parlist);
2129 
2130  /* --lly3 */
2131  detmon_lg_config.lly3 =
2132  detmon_retrieve_par_int("lly3", pipeline_name, recipe_name,
2133  parlist);
2134 
2135  /* --urx3 */
2136  detmon_lg_config.urx3 =
2137  detmon_retrieve_par_int("urx3", pipeline_name, recipe_name,
2138  parlist);
2139 
2140  /* --ury3 */
2141  detmon_lg_config.ury3 =
2142  detmon_retrieve_par_int("ury3", pipeline_name, recipe_name,
2143  parlist);
2144 
2145  /* --llx4 */
2146  detmon_lg_config.llx4 =
2147  detmon_retrieve_par_int("llx4", pipeline_name, recipe_name,
2148  parlist);
2149 
2150  /* --lly4 */
2151  detmon_lg_config.lly4 =
2152  detmon_retrieve_par_int("lly4", pipeline_name, recipe_name,
2153  parlist);
2154 
2155  /* --urx4 */
2156  detmon_lg_config.urx4 =
2157  detmon_retrieve_par_int("urx4", pipeline_name, recipe_name,
2158  parlist);
2159 
2160  /* --ury4 */
2161  detmon_lg_config.ury4 =
2162  detmon_retrieve_par_int("ury4", pipeline_name, recipe_name,
2163  parlist);
2164 
2165  /* --llx5 */
2166  detmon_lg_config.llx5 =
2167  detmon_retrieve_par_int("llx5", pipeline_name, recipe_name,
2168  parlist);
2169 
2170  /* --lly5 */
2171  detmon_lg_config.lly5 =
2172  detmon_retrieve_par_int("lly5", pipeline_name, recipe_name,
2173  parlist);
2174 
2175  /* --urx5 */
2176  detmon_lg_config.urx5 =
2177  detmon_retrieve_par_int("urx5", pipeline_name, recipe_name,
2178  parlist);
2179 
2180  /* --ury5 */
2181  detmon_lg_config.ury5 =
2182  detmon_retrieve_par_int("ury5", pipeline_name, recipe_name,
2183  parlist);
2184  }
2185 
2186  /* --exts */
2187  detmon_lg_config.exts =
2188  detmon_retrieve_par_int("exts", pipeline_name, recipe_name,
2189  parlist);
2190  /* --fpn_method */
2191  {
2192  detmon_lg_config.fpn_method = FPN_HISTOGRAM;
2193  par_name =
2194  cpl_sprintf("%s.%s.fpn_method", pipeline_name, recipe_name);
2195  assert(par_name != NULL);
2196  par = cpl_parameterlist_find_const(parlist, par_name);
2197  if (par)
2198  {
2199  const char * str_method = cpl_parameter_get_string(par);
2200  if (strcmp(str_method, "SMOOTH") == 0)
2201  {
2202  detmon_lg_config.fpn_method = FPN_SMOOTH;
2203  }
2204  else if (strcmp(str_method, "HISTOGRAM") == 0)
2205  {
2206  detmon_lg_config.fpn_method = FPN_HISTOGRAM;
2207  }
2208  }
2209  cpl_free(par_name);
2210  }
2211  /* --fpn_smooth */
2212  detmon_lg_config.fpn_smooth =
2213  detmon_retrieve_par_int("fpn_smooth", pipeline_name, recipe_name,
2214  parlist);
2215  /* --saturation_limit*/
2216  {
2217  detmon_lg_config.saturation_limit = 65535;
2218  par_name =
2219  cpl_sprintf("%s.%s.saturation_limit", pipeline_name, recipe_name);
2220  assert(par_name != NULL);
2221  par = cpl_parameterlist_find_const(parlist, par_name);
2222  if (par)
2223  {
2224  detmon_lg_config.saturation_limit = cpl_parameter_get_double(par);
2225  }
2226  cpl_free(par_name);
2227  }
2228 
2229  /* --gain_threshold*/
2230  {
2231  detmon_lg_config.gain_threshold = 0;
2232  par_name =
2233  cpl_sprintf("%s.%s.gain_threshold", pipeline_name, recipe_name);
2234  assert(par_name != NULL);
2235  par = cpl_parameterlist_find_const(parlist, par_name);
2236  if (par)
2237  {
2238  detmon_lg_config.gain_threshold = cpl_parameter_get_double(par);
2239  }
2240  cpl_free(par_name);
2241  }
2242 
2243  if(cpl_error_get_code())
2244  {
2245  cpl_msg_error(cpl_func, "Failed to retrieve the input parameters");
2246  cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
2247  }
2248 
2249 
2250  return cpl_error_get_code();
2251 }
2252 
2253 /*---------------------------------------------------------------------------*/
2259 /*---------------------------------------------------------------------------*/
2260 static cpl_error_code
2261 detmon_lg_check_defaults(const cpl_image * reference)
2262 {
2263  const int nx = cpl_image_get_size_x(reference);
2264  const int ny = cpl_image_get_size_y(reference);
2265 
2266  detmon_lg_config.nx = nx;
2267  detmon_lg_config.ny = ny;
2268 
2269  detmon_lg_config.wholechip = CPL_FALSE;
2270 
2271  if(detmon_lg_config.llx == -1)
2272  detmon_lg_config.llx = 1;
2273  if(detmon_lg_config.lly == -1)
2274  detmon_lg_config.lly = 1;
2275  if(detmon_lg_config.urx == -1)
2276  detmon_lg_config.urx = nx;
2277  if(detmon_lg_config.ury == -1)
2278  detmon_lg_config.ury = ny;
2279 
2280  if (detmon_lg_config.llx == 1 &&
2281  detmon_lg_config.lly == 1 &&
2282  detmon_lg_config.urx == nx &&
2283  detmon_lg_config.ury == ny)
2284  detmon_lg_config.wholechip = CPL_TRUE;
2285 
2286  if(detmon_lg_config.llx1 == -1)
2287  detmon_lg_config.llx1 = 1;
2288  if(detmon_lg_config.lly1 == -1)
2289  detmon_lg_config.lly1 = 1;
2290  if(detmon_lg_config.urx1 == -1)
2291  detmon_lg_config.urx1 = nx;
2292  if(detmon_lg_config.ury1 == -1)
2293  detmon_lg_config.ury1 = ny;
2294 
2295  if(detmon_lg_config.llx2 == -1)
2296  detmon_lg_config.llx2 = 1;
2297  if(detmon_lg_config.lly2 == -1)
2298  detmon_lg_config.lly2 = 1;
2299  if(detmon_lg_config.urx2 == -1)
2300  detmon_lg_config.urx2 = nx / 2;
2301  if(detmon_lg_config.ury2 == -1)
2302  detmon_lg_config.ury2 = ny / 2;
2303 
2304  if(detmon_lg_config.llx3 == -1)
2305  detmon_lg_config.llx3 = 1;
2306  if(detmon_lg_config.lly3 == -1)
2307  detmon_lg_config.lly3 = ny / 2;
2308  if(detmon_lg_config.urx3 == -1)
2309  detmon_lg_config.urx3 = nx / 2;
2310  if(detmon_lg_config.ury3 == -1)
2311  detmon_lg_config.ury3 = ny;
2312 
2313  if(detmon_lg_config.llx4 == -1)
2314  detmon_lg_config.llx4 = nx / 2;
2315  if(detmon_lg_config.lly4 == -1)
2316  detmon_lg_config.lly4 = ny / 2;
2317  if(detmon_lg_config.urx4 == -1)
2318  detmon_lg_config.urx4 = nx;
2319  if(detmon_lg_config.ury4 == -1)
2320  detmon_lg_config.ury4 = ny;
2321 
2322  if(detmon_lg_config.llx5 == -1)
2323  detmon_lg_config.llx5 = nx / 2;
2324  if(detmon_lg_config.lly5 == -1)
2325  detmon_lg_config.lly5 = 1;
2326  if(detmon_lg_config.urx5 == -1)
2327  detmon_lg_config.urx5 = nx;
2328  if(detmon_lg_config.ury5 == -1)
2329  detmon_lg_config.ury5 = ny / 2;
2330 
2331  if(detmon_lg_config.intermediate == TRUE) {
2332  cpl_msg_warning(cpl_func, "PLEASE NOTE: The --intermediate option saves the difference and correlation images produced during autocorrelation computation. Therefore, --autocorr option has been automatically activated. If you didn't want to run this, please abort and rerun.");
2333  detmon_lg_config.autocorr = TRUE;
2334  }
2335 
2336 
2337  detmon_lg_config.lamp_stability = 0.0;
2338 
2339  detmon_lg_config.lamp_ok = FALSE;
2340 
2341  detmon_lg_config.cr = 0.0;
2342 
2343  return cpl_error_get_code();
2344 }
2345 
2346 /*---------------------------------------------------------------------------*/
2357 /*---------------------------------------------------------------------------*/
2358 static cpl_error_code
2359 detmon_lg_split_onoff(const cpl_frameset * cur_fset,
2360  cpl_frameset * cur_fset_on,
2361  cpl_frameset * cur_fset_off,
2362  const char *tag_on,
2363  const char *tag_off)
2364 {
2365  int nframes;
2366  int i;
2367 
2368  cpl_frame * cur_frame_dup = NULL;
2369 
2370 #if 0
2371  const cpl_frame * first;
2372  const cpl_frame * second;
2373  const char * first_tag;
2374  const char * second_tag;
2375  skip_if((first = cpl_frameset_get_position_const(cur_fset, 0)) == NULL);
2376  skip_if((second = cpl_frameset_get_position_const(cur_fset, 1)) == NULL);
2377 
2378  skip_if((first_tag = cpl_frame_get_tag(first)) == NULL);
2379  skip_if((second_tag = cpl_frame_get_tag(second)) == NULL);
2380  if (opt_nir == OPT &&
2381  ((!strcmp(first_tag, tag_on ) && !strcmp(second_tag, tag_off)) ||
2382  (!strcmp(first_tag, tag_off) && !strcmp(second_tag, tag_on )))) {
2383  detmon_lg_config.lamp_ok = TRUE;
2384  }
2385 #endif
2386 
2387  nframes = cpl_frameset_get_size(cur_fset);
2388  for(i = detmon_lg_config.lamp_ok ? 2 : 0; i < nframes; i++) {
2389  const cpl_frame * cur_frame =
2390  cpl_frameset_get_position_const(cur_fset, i);
2391  char * tag;
2392 
2393  /* Duplication is required for insertion to a different frameset */
2394  cur_frame_dup = cpl_frame_duplicate(cur_frame);
2395  tag = (char *) cpl_frame_get_tag(cur_frame_dup);
2396 
2397  /* Insertion in the corresponding sub-frameset */
2398  if(!strcmp(tag, tag_on)) {
2399  skip_if(cpl_frameset_insert(cur_fset_on, cur_frame_dup));
2400  } else if(!strcmp(tag, tag_off)) {
2401  skip_if(cpl_frameset_insert(cur_fset_off, cur_frame_dup));
2402  } else {
2403  cpl_frame_delete(cur_frame_dup);
2404  cur_frame_dup = NULL;
2405  }
2406  }
2407  cur_frame_dup = NULL;
2408 
2409  end_skip;
2410 
2411  cpl_frame_delete(cur_frame_dup);
2412 
2413  return cpl_error_get_code();
2414 }
2415 
2416 /*--------------------------------------------------------------------------*/
2438 /*--------------------------------------------------------------------------*/
2439 
2440 static cpl_error_code
2441 detmon_lg_reduce(const cpl_frameset * set_on,
2442  const cpl_frameset * set_off,
2443  int* index_on, int* index_off,
2444  double* exptime_on, double* exptime_off,
2445  int *next_index_on, int* next_index_off,
2446  cpl_imagelist ** coeffs_ptr,
2447  cpl_table * gain_table,
2448  cpl_table * linear_table,
2449  cpl_image ** bpm_ptr,
2450  cpl_imagelist * autocorr_images,
2451  cpl_imagelist * diff_flats,
2452  cpl_propertylist * gaint_qclist,
2453  cpl_propertylist * lint_qclist,
2454  cpl_propertylist * linc_qclist,
2455  cpl_propertylist * bpm_qclist,
2456  int (* load_fset) (const cpl_frameset *,
2457  cpl_type,
2458  cpl_imagelist *),
2459  const cpl_boolean opt_nir,
2460  int whichext)
2461 {
2462  cpl_errorstate prestate = cpl_errorstate_get();
2463  const double D_INVALID_VALUE = -999;
2464  int i;
2465  cpl_imagelist * linearity_inputs = NULL;
2466  cpl_imagelist * opt_offs = NULL;
2467  int nsets;
2468  cpl_propertylist * reflist = NULL;
2469  int dit_nskip = 0;
2470  int rows_linear_affected = 1;
2471  int rows_gain_affected = 1;
2472  int last_linear_best = 0;
2473  /* Test entries */
2474  cpl_ensure(set_on != NULL, CPL_ERROR_NULL_INPUT, CPL_ERROR_NULL_INPUT);
2475  cpl_ensure(set_off != NULL, CPL_ERROR_NULL_INPUT, CPL_ERROR_NULL_INPUT);
2476 
2477  nsets = cpl_frameset_get_size(set_on) / 2;
2478 
2479  detmon_lg_config.load_fset = load_fset;
2480  if(detmon_lg_config.collapse) {
2481  /*
2482  * When the 'collapse' option is used, there are no OFF pairs. We
2483  * construct a pair with the 2 first raw OFF frames, which will be
2484  * passed for each DIT value, to maintain the same API in the function
2485  * detmon_gain_table_fill_row().
2486  */
2487  const cpl_frame *first = cpl_frameset_get_position_const(set_off, 0);
2488  cpl_frame *dup_first = cpl_frame_duplicate(first);
2489 
2490  const cpl_frame *second = cpl_frameset_get_position_const(set_off, 1);
2491  cpl_frame *dup_second = cpl_frame_duplicate(second);
2492 
2493  cpl_frameset *raw_offs = cpl_frameset_new();
2494 
2495  skip_if(cpl_frameset_insert(raw_offs, dup_first));
2496  skip_if(cpl_frameset_insert(raw_offs, dup_second));
2497 
2498  opt_offs = cpl_imagelist_load_frameset(raw_offs, CPL_TYPE_FLOAT,
2499  0, whichext);
2500 
2501  cpl_frameset_delete(raw_offs);
2502  if (opt_offs == NULL) {
2503  cpl_errorstate_set(prestate);
2504  return CPL_ERROR_CONTINUE;
2505  }
2506  }
2507 
2508  skip_if(detmon_lg_reduce_init(gain_table,
2509  linear_table,
2510  &linearity_inputs,
2511  opt_nir));
2512 /*
2513  if (!strcmp(detmon_lg_config.method, "PTC"))
2514  {
2515  cpl_msg_warning(cpl_func, "PTC method incompatible with lamp stability"
2516  "computation");
2517  }
2518 */
2519  /* do always lamp stability check */
2520  if(detmon_lg_lamp_stab(set_on, set_off,
2521  opt_nir, whichext)) {
2522  cpl_errorstate_set(prestate);
2523  }
2524 
2525  if(!detmon_lg_config.collapse)
2526  {
2527  }
2528  /* Unselect all rows, to select only invalid ones */
2529  skip_if(cpl_table_unselect_all(linear_table));
2530  skip_if(cpl_table_unselect_all(gain_table));
2531 
2532  /* Loop on every DIT value */
2533 
2534  for(i = 0; i < nsets ; i++)
2535  {
2536  skip_if(detmon_lg_reduce_dit(set_on,
2537  index_on, exptime_on,
2538  i,
2539  &dit_nskip,
2540  set_off,
2541  index_off, exptime_off,
2542  next_index_on, next_index_off,
2543  linear_table,
2544  gain_table, linearity_inputs,
2545  lint_qclist, opt_nir,
2546  autocorr_images, diff_flats,
2547  opt_offs, whichext,
2548  &rows_linear_affected,&rows_gain_affected));
2549  /* TODO: the following if could be done directly inside the
2550  * function detmon_lg_reduce_dit
2551  */
2552  if (rows_linear_affected == 0)
2553  {
2554  cpl_msg_warning(cpl_func, "The rest frames would not be taken "
2555  "into linear calculation, check the messages above");
2556  cpl_table_select_row(linear_table, i);
2557  }
2558  else
2559  {
2560  last_linear_best = i;
2561  }
2562 
2563  if (rows_gain_affected == 0)
2564  {
2565  cpl_msg_warning(cpl_func, "The rest frames would not be taken "
2566  "into gain calculation, check the messages above");
2567  cpl_table_select_row(gain_table, i);
2568  }
2569 
2570 
2571 
2572  }
2573 
2574  skip_if(detmon_add_adl_column(linear_table, opt_nir));
2575 
2576  /*
2577  * Removal of rows corresponding to frames above --filter threshold.
2578  * See calls to cpl_table_select_row() in detmon_lg_reduce_dit().
2579  */
2580  skip_if(cpl_table_erase_selected(gain_table));
2581  skip_if(cpl_table_erase_selected(linear_table));
2582 
2583 
2584  reflist = cpl_propertylist_new();
2585  skip_if(cpl_propertylist_append_bool(reflist, "ADU", FALSE));
2586  skip_if(cpl_table_sort(gain_table, reflist));
2587  /*
2588  * --Final reduction--
2589  * The following call to detmon_lg_reduce_all() makes the
2590  * computations which are over all posible DIT values.
2591  */
2592  skip_if(detmon_lg_reduce_all(linear_table,
2593  gaint_qclist, lint_qclist, linc_qclist,
2594  bpm_qclist, coeffs_ptr, bpm_ptr,
2595  linearity_inputs,
2596  gain_table, whichext, opt_nir));
2597  {
2598  /*FPN Computation*/
2599  double gain = cpl_propertylist_get_double(gaint_qclist, DETMON_QC_GAIN);
2600  // cpl_propertylist_append_int(gaint_qclist, "NNNEXT", whichext);
2601  // cpl_msg_warning(cpl_func, "---------- ext %i" , whichext);
2602  cpl_error_code cplerr = cpl_error_get_code();
2603  if (cplerr != CPL_ERROR_NONE || (gain == 0.0))
2604  {
2605  cpl_msg_warning(cpl_func, "Cannot read gain from QC parameters - "
2606  "FPN will not be computed");
2607  cpl_error_reset();
2608  }
2609  else
2610  {
2611  detmon_fpn_compute(set_on, index_on, last_linear_best, lint_qclist,
2612  detmon_lg_config.llx,
2613  detmon_lg_config.lly,
2614  detmon_lg_config.urx,
2615  detmon_lg_config.ury,
2616  gain,
2617  whichext,
2618  detmon_lg_config.fpn_method,
2619  detmon_lg_config.fpn_smooth);
2620  }
2621  }
2622  /* change NaN in the gain table to the invalid value D_INVALID_VALUE*/
2623 
2624  detmon_table_fill_invalid(gain_table, D_INVALID_VALUE);
2625  end_skip;
2626  cpl_imagelist_delete(linearity_inputs);
2627  cpl_imagelist_delete(opt_offs);
2628  cpl_propertylist_delete(reflist);
2629 
2630  return cpl_error_get_code();
2631 }
2632 
2633 static cpl_error_code detmon_table_fill_invalid(cpl_table* ptable, double code)
2634 {
2635  int ncols = cpl_table_get_ncol(ptable);
2636  cpl_array* pnames = cpl_table_get_column_names(ptable);
2637  int nrows = cpl_table_get_nrow(ptable);
2638  int i = 0;
2639  for (i=0; i < ncols; i++)
2640  {
2641  int j = 0;
2642  for (j = 0; j< nrows; j++)
2643  {
2644  const char* colname = cpl_array_get_data_string_const(pnames)[i];
2645  int isnull;
2646  cpl_type type = cpl_table_get_column_type(ptable, colname);
2647  cpl_table_get(ptable, colname, j, &isnull);
2648  if(isnull == 1)
2649  {
2650  if (type == CPL_TYPE_DOUBLE)
2651  {
2652  cpl_table_set(ptable,colname,j, code);
2653  }
2654  else if (type == CPL_TYPE_FLOAT)
2655  {
2656  cpl_table_set_float(ptable,colname,j, (float)code);
2657  }
2658  }
2659  }
2660  }
2661  cpl_array_delete(pnames);
2662  return cpl_error_get_code();
2663 }
2664 
2665 static cpl_error_code
2666 detmon_fpn_compute(const cpl_frameset *set_on,
2667  int * index_on,
2668  int last_linear_best,
2669  cpl_propertylist *lint_qclist,
2670  int llx,
2671  int lly,
2672  int urx,
2673  int ury,
2674  double gain,
2675  int whichext,
2676  FPN_METHOD fpn_method,
2677  int smooth_size)
2678 {
2679  double fpn = 0;
2680  const cpl_image* im1 = 0;
2681  int range[4];
2682  cpl_imagelist* ons = 0;
2683  cpl_frameset * pair_on = 0;
2684  int nsets_extracted = cpl_frameset_get_size(set_on);
2685  cpl_size * selection = NULL;
2686  double mse = 0;
2687  range[0] = llx;
2688  range[1] = lly;
2689  range[2] = urx;
2690  range[3] = ury;
2691 
2692  /* Retrieve 2 ON frames with the highest DIT -
2693  * the last best 2 values in the index*/
2694  selection = cpl_malloc(sizeof(cpl_size) * nsets_extracted);
2695  memset(&selection[0], 0, sizeof(cpl_size) * nsets_extracted);
2696 
2697  selection[index_on[last_linear_best*2 + 0] ] = 1;
2698  selection[index_on[last_linear_best*2 + 1] ] = 1;
2699  pair_on = cpl_frameset_extract(set_on, selection, 1);
2700  ons = detmon_lg_config.load_fset_wrp(pair_on, CPL_TYPE_FLOAT, whichext);
2701 
2702  skip_if(ons == NULL);
2703  skip_if((im1 = cpl_imagelist_get_const(ons, 0)) == NULL);
2704 
2705  fpn = irplib_fpn_lg(im1, range, gain, fpn_method, smooth_size, &mse);
2706  skip_if(cpl_propertylist_append_double(lint_qclist, DETMON_QC_FPN,
2707  fpn));
2708  skip_if(cpl_propertylist_append_double(lint_qclist, "ESO QC GAIN ERR",
2709  mse));
2710 
2711  end_skip;
2712  cpl_frameset_delete(pair_on);
2713  cpl_imagelist_delete(ons);
2714  cpl_free(selection);
2715  return cpl_error_get_code();
2716 }
2717 
2718 /*--------------------------------------------------------------------------*/
2726 /*--------------------------------------------------------------------------*/
2727 static cpl_error_code
2728 detmon_lg_lamp_stab(const cpl_frameset * lamps,
2729  const cpl_frameset * darks,
2730  cpl_boolean opt_nir,
2731  int whichext)
2732 {
2733 
2734  /*
2735  * NOTE:
2736  * Most of this code is copied (and modified) from
2737  * isaac_img_detlin_load(), in isaac_img_detlin.c v.1.25
2738  */
2739 
2740  int nb_lamps;
2741  int nb_darks;
2742 
2743  cpl_vector * selection = NULL;
2744  cpl_propertylist * plist;
2745  double dit_lamp, dit_dark;
2746  int dit_stab;
2747  cpl_imagelist * lamps_data = NULL;
2748  cpl_imagelist * darks_data = NULL;
2749  double * stab_levels = NULL;
2750  int i, j;
2751  double * ditvals = NULL;
2752  int last_stab = 0; /* Avoid false uninit warning */
2753 
2754  /* Check that there are as many lamp as darks */
2755  cpl_ensure_code((nb_lamps = cpl_frameset_get_size(lamps)) >= 3,
2756  CPL_ERROR_ILLEGAL_INPUT);
2757 /*
2758  cpl_ensure_code(cpl_frameset_get_size(darks) == nb_lamps,
2759  CPL_ERROR_ILLEGAL_INPUT);
2760 */
2761  /* Check out that they have consistent integration times */
2762  cpl_msg_info(__func__, "Checking DIT consistency");
2763  selection = cpl_vector_new(nb_lamps);
2764  ditvals = cpl_malloc(nb_lamps * sizeof(double));
2765  dit_stab = 0;
2766  for (i = 0; i < nb_lamps; i++) {
2767  const cpl_frame * c_lamp;
2768  const cpl_frame * c_dark;
2769  /* Check if ok */
2770  skip_if (cpl_error_get_code());
2771 
2772  /* DIT from LAMP */
2773  c_lamp = cpl_frameset_get_position_const(lamps, i);
2774  plist = cpl_propertylist_load(cpl_frame_get_filename(c_lamp), 0);
2775  if(opt_nir)
2776  dit_lamp = (double)detmon_pfits_get_dit(plist);
2777  else
2778  dit_lamp = (double)detmon_pfits_get_dit_opt(plist);
2779  cpl_propertylist_delete(plist);
2780  skip_if (cpl_error_get_code());
2781 
2782  /* DIT from DARK */
2783  c_dark = cpl_frameset_get_position_const(darks, i);
2784  plist = cpl_propertylist_load(cpl_frame_get_filename(c_dark), 0);
2785  if(opt_nir)
2786  dit_dark = (double)detmon_pfits_get_dit(plist);
2787  else
2788  dit_dark = (double)detmon_pfits_get_dit_opt(plist);
2789  cpl_propertylist_delete(plist);
2790  skip_if (cpl_error_get_code());
2791 
2792  /* Check consistency */
2793  if (fabs(dit_dark-dit_lamp) > 1e-3) {
2794  cpl_msg_error(__func__, "DIT not consistent between LAMP and DARK, skip lamp stability computation");
2795  /* FIXME: Should an error code be set here? */
2796 
2797  skip_if(1);
2798  }
2799  ditvals[i] = dit_lamp;
2800  /* Set selection */
2801  if (i==0) {
2802  cpl_vector_set(selection, i, -1.0);
2803  dit_stab ++;
2804  last_stab = 0;
2805  } else {
2806  /*
2807  * The second condition is to make sure that frames taken into
2808  * account for lamp stability are not consecutive.
2809  */
2810  if (fabs(dit_lamp - ditvals[0]) < 1e-5 && i - last_stab > 3) {
2811  cpl_vector_set(selection, i, -1.0);
2812  dit_stab ++;
2813  last_stab = i;
2814  } else {
2815  cpl_vector_set(selection, i, 1.0);
2816  }
2817  }
2818  }
2819 
2820  /* Check if there are enough DITs for stability check */
2821  if (dit_stab < 2) {
2822  cpl_msg_info(__func__, "Not enough frames for stability check");
2823  } else {
2824 
2825  /* Load the data and compute lamp-dark */
2826  cpl_msg_info(__func__, "Compute the differences lamp - dark");
2827 
2828 
2829  lamps_data = detmon_load_frameset_window(lamps, CPL_TYPE_FLOAT, 0,
2830  whichext,
2831  detmon_lg_config.llx,
2832  detmon_lg_config.lly,
2833  detmon_lg_config.urx,
2834  detmon_lg_config.ury,
2835  -1, -1);
2836 
2837  darks_data = detmon_load_frameset_window(lamps, CPL_TYPE_FLOAT, 0,
2838  whichext,
2839  detmon_lg_config.llx,
2840  detmon_lg_config.lly,
2841  detmon_lg_config.urx,
2842  detmon_lg_config.ury,
2843  -1, -1);
2844 
2845  nb_darks=cpl_imagelist_get_size(darks_data);
2846  if(nb_darks==nb_lamps) {
2847  skip_if(cpl_imagelist_subtract(lamps_data,darks_data));
2848  } else {
2849  cpl_image* master_dark=cpl_imagelist_collapse_median_create(darks_data);
2850  cpl_imagelist_subtract_image(lamps_data,master_dark);
2851  cpl_image_delete(master_dark);
2852  }
2853  /* Check the lamp stability */
2854  cpl_msg_info(__func__, "Check the lamp stability");
2855  stab_levels = cpl_malloc(dit_stab * sizeof(double));
2856  j = 0;
2857  for (i=0; i<nb_lamps; i++) {
2858  if (cpl_vector_get(selection, i) < 0) {
2859  stab_levels[j] =
2860  cpl_image_get_mean(cpl_imagelist_get(lamps_data, i));
2861  j++;
2862  }
2863  }
2864 
2865  /* Compute the lamp stability */
2866  for (i=1; i<dit_stab; i++) {
2867  if ((fabs(stab_levels[i]-stab_levels[0]) / stab_levels[0]) >
2868  detmon_lg_config.lamp_stability)
2869  detmon_lg_config.lamp_stability =
2870  fabs(stab_levels[i]-stab_levels[0]) / stab_levels[0];
2871  }
2872 
2873 
2874  /* Check the lamp stability */
2875  if (detmon_lg_config.lamp_stability > 0.01) {
2876  cpl_msg_warning(__func__,
2877  "Lamp stability level %g difference too high - proceed anyway",detmon_lg_config.lamp_stability);
2878  }
2879  }
2880  end_skip;
2881 
2882 
2883  cpl_free(ditvals);
2884  cpl_vector_delete(selection);
2885  cpl_imagelist_delete(lamps_data);
2886  cpl_imagelist_delete(darks_data);
2887  cpl_free(stab_levels);
2888 
2889  return cpl_error_get_code();
2890 }
2891 
2892 /*--------------------------------------------------------------------------*/
2915 /*--------------------------------------------------------------------------*/
2916 static cpl_error_code
2917 detmon_lg_reduce_dit(const cpl_frameset * set_on,
2918  int* index_on, double* exptime_on,
2919  const int dit_nb,
2920  int * dit_nskip,
2921  const cpl_frameset * set_off,
2922  int * index_off, double* exptime_off,
2923  int* next_on, int* next_off,
2924  cpl_table * linear_table,
2925  cpl_table * gain_table,
2926  cpl_imagelist * linearity_inputs,
2927  cpl_propertylist * qclist,
2928  cpl_boolean opt_nir,
2929  cpl_imagelist * autocorr_images,
2930  cpl_imagelist * diff_flats,
2931  cpl_imagelist * opt_offs,
2932  int whichext,
2933  int* rows_linear_affected,
2934  int* rows_gain_affected)
2935 {
2936  cpl_frameset * pair_on = NULL;
2937  cpl_frameset * pair_off = NULL;
2938  cpl_imagelist * ons = NULL;
2939  cpl_imagelist * offs = NULL;
2940  cpl_boolean follow = CPL_TRUE;
2941  unsigned mode = detmon_lg_config.autocorr ? IRPLIB_GAIN_WITH_AUTOCORR : 0;
2942  double c_dit;
2943  int c_ndit;
2944 
2945  double current_dit = 0;
2946 
2947  const char * filename;
2948 
2949  cpl_propertylist * plist = NULL;
2950  cpl_propertylist* pDETlist = NULL;
2951 
2952  mode = detmon_lg_config.collapse ?
2953  mode | IRPLIB_GAIN_COLLAPSE | IRPLIB_LIN_COLLAPSE:
2954  mode | IRPLIB_GAIN_NO_COLLAPSE | IRPLIB_LIN_NO_COLLAPSE;
2955  mode = detmon_lg_config.pix2pix ?
2956  mode | IRPLIB_LIN_PIX2PIX : mode;
2957  mode = opt_nir ?
2958  mode | IRPLIB_GAIN_NIR | IRPLIB_LIN_NIR :
2959  mode | IRPLIB_GAIN_OPT | IRPLIB_LIN_OPT ;
2960 
2961 
2962  /* ON pair extraction */
2963  skip_if(detmon_pair_extract_next(set_on, index_on, next_on, exptime_on, &pair_on, detmon_lg_config.tolerance));
2964  current_dit = exptime_on[*next_on - 1];
2965 
2966  /* Load the ON images */
2967  ons = detmon_lg_config.load_fset_wrp(pair_on, CPL_TYPE_FLOAT, whichext);
2968  skip_if(ons == NULL);
2969  cpl_msg_debug(cpl_func, " Loaded ON images: %" CPL_SIZE_FORMAT
2970  ", exptime[%f]",cpl_imagelist_get_size(ons), current_dit );
2971  if(cpl_imagelist_get_size(ons) != 2)
2972  {
2973  cpl_msg_error(cpl_func, "cannot take ON pair, number of images[%"
2974  CPL_SIZE_FORMAT "]", cpl_imagelist_get_size(ons));
2975  skip_if(TRUE);
2976  }
2977  if(detmon_lg_config.filter > 0)
2978  {
2979  double med1 =
2980  cpl_image_get_median_window(cpl_imagelist_get(ons, 0),
2981  detmon_lg_config.llx,
2982  detmon_lg_config.lly,
2983  detmon_lg_config.urx,
2984  detmon_lg_config.ury);
2985  double med2 =
2986  cpl_image_get_median_window(cpl_imagelist_get(ons, 1),
2987  detmon_lg_config.llx,
2988  detmon_lg_config.lly,
2989  detmon_lg_config.urx,
2990  detmon_lg_config.ury);
2991 
2992 
2993 
2994  if ( med1 > (double)detmon_lg_config.filter ||
2995  med2 > (double)detmon_lg_config.filter)
2996  {
2997  follow = CPL_FALSE;
2998  cpl_table_select_row(gain_table, dit_nb);
2999  cpl_table_select_row(linear_table, dit_nb);
3000  (*dit_nskip)++;
3001  cpl_msg_warning(cpl_func, "Frames of EXPTIME nb %d "
3002  "will not be taken into account for computation "
3003  "as the median of the on frames computed on the "
3004  "user defined region [%d,%d,%d,%d] are above "
3005  "--filter threshold (%d)",
3006  dit_nb,
3007  detmon_lg_config.llx,
3008  detmon_lg_config.lly,
3009  detmon_lg_config.urx,
3010  detmon_lg_config.ury,
3011  detmon_lg_config.filter);
3012  }
3013  }
3014 
3015  if (follow || detmon_lg_config.filter < 0)
3016  {
3017 
3018  /*
3019  * If the --collapse option is not activated by the user, the OFF
3020  * sub-frameset is also supposed to be organized into pairs and,
3021  * therefore, processed as the ON sub-frameset.
3022  */
3023  if(!detmon_lg_config.collapse)
3024  {
3025  /* TODO: We removed this check as with NACO data, that has an odd
3026  * number of input OFF frames it would stop with error
3027  * despite the recipe would reduce the data properly.
3028  * On the other side, on some data without such a check one may get
3029  * failures on another place.
3030  * we need to document such cases and understand how to better deal
3031  * in a robust way the case of odd input off frames
3032  *
3033  if (cpl_frameset_get_size(set_off) % 2 != 0) {
3034  cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
3035  "If collapse is FALSE the OFF frameset"
3036  " must be organized in pairs.");
3037  skip_if(1);
3038  }
3039  */
3040  if (!strcmp(detmon_lg_config.method, "MED") ||
3041  cpl_frameset_get_size(set_on) == cpl_frameset_get_size(set_off))
3042  {
3043  skip_if(detmon_pair_extract_next(set_off, index_off, next_off, exptime_off, &pair_off, detmon_lg_config.tolerance));
3044  }
3045  else
3046  {
3047  skip_if(detmon_single_extract_next(set_off, index_off, next_off, exptime_off, &pair_off));
3048  }
3049  /* Load the OFF images */
3050  cpl_msg_debug(cpl_func, " Load the OFF images, ext[%d], exptime[%f]", whichext, exptime_off[*next_off - 1]);
3051  offs = detmon_lg_config.load_fset_wrp(pair_off, CPL_TYPE_FLOAT, whichext);
3052 
3053  skip_if(offs == NULL);
3054  skip_if(cpl_error_get_code());
3055  }
3056  else {
3057  offs = (cpl_imagelist *) opt_offs;
3058  }
3059 
3060  /* Rescaling */
3061  if(detmon_lg_config.rescale)
3062  {
3063  skip_if(detmon_lg_rescale(ons));
3064  if (!detmon_lg_config.collapse &&
3065  !strcmp(detmon_lg_config.method, "MED"))
3066  skip_if(detmon_lg_rescale(offs));
3067  }
3068  /* DIT or EXPTIME value extraction */
3069 
3070  filename =
3071  cpl_frame_get_filename(cpl_frameset_get_position_const(pair_on, 0));
3072  skip_if ((plist = cpl_propertylist_load(filename, 0)) == NULL);
3073  /* Add columns to the tables DETi WINi UITi*/
3074  if (plist)
3075  {
3076  pDETlist = cpl_propertylist_new();
3077  cpl_propertylist_copy_property_regexp(pDETlist, plist, "DET[0-9]* WIN[0-9]* UIT[0-9]*",0);
3078  if (dit_nb == 0)
3079  {
3080  irplib_table_create_column(gain_table, pDETlist);
3081  irplib_table_create_column(linear_table, pDETlist);
3082  }
3083  }
3084  if(opt_nir == NIR) {
3085  c_dit = detmon_pfits_get_dit(plist);
3086  c_ndit = irplib_pfits_get_ndit(plist);
3087  } else {
3088  c_dit = irplib_pfits_get_exptime(plist);
3089  c_ndit=1;
3090  }
3091 
3092  /*
3093  * --GAIN part for each DIT value--
3094  * The following call to detmon_gain_table_fill_row() fills
3095  * in the row nb i
3096  * of the GAIN table (output) and of the FIT table (by-product to be
3097  * used later for the polynomial computation of the GAIN)
3098  */
3099 
3100  cpl_msg_info(cpl_func, "Computing GAIN for EXPTIME value nb %d",
3101  dit_nb + 1);
3102 
3103  /* In case PTC is applied, this is allowed */
3104  if(cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE && dit_nb == 0)
3105  {
3106  cpl_table_erase_column(gain_table, "MEAN_OFF1");
3107  cpl_table_erase_column(gain_table, "MEAN_OFF2");
3108  cpl_table_erase_column(gain_table, "SIG_OFF_DIF");
3109  cpl_table_erase_column(gain_table, "GAIN");
3110  cpl_table_erase_column(gain_table, "GAIN_CORR");
3111  cpl_table_new_column(gain_table, "MEAN_OFF", CPL_TYPE_DOUBLE);
3112  }
3113 
3114 
3115  skip_if(detmon_gain_table_fill_row(gain_table,
3116  c_dit,c_ndit,
3117  autocorr_images,
3118  diff_flats, ons, offs,
3119  detmon_lg_config.kappa,
3120  detmon_lg_config.niter,
3121  detmon_lg_config.llx,
3122  detmon_lg_config.lly,
3123  detmon_lg_config.urx,
3124  detmon_lg_config.ury,
3125  detmon_lg_config.m,
3126  detmon_lg_config.n,
3127  detmon_lg_config.gain_threshold,
3128  dit_nb, mode, rows_gain_affected));
3129 
3130 
3131  skip_if(detmon_check_saturation_on_pair(autocorr_images,
3132  diff_flats,ons,
3133  detmon_lg_config.kappa,
3134  detmon_lg_config.niter,
3135  detmon_lg_config.llx,
3136  detmon_lg_config.lly,
3137  detmon_lg_config.urx,
3138  detmon_lg_config.ury,
3139  detmon_lg_config.saturation_limit,
3140  dit_nb, mode, rows_linear_affected));
3141 
3142 
3143  if (*rows_gain_affected)
3144  {
3145  /* fill DETi WINi OPTi columns - see DFS06921*/
3146  skip_if(irplib_fill_table_DETWINUIT(gain_table, pDETlist, dit_nb));
3147  /* Linearity reduction */
3148  cpl_msg_info(cpl_func, "Linearity reduction for nb %d",
3149  dit_nb + 1);
3150  }
3151  if (*rows_linear_affected) {
3152  skip_if(detmon_lin_table_fill_row(linear_table, c_dit,
3153  linearity_inputs, ons, offs,
3154  detmon_lg_config.llx,
3155  detmon_lg_config.lly,
3156  detmon_lg_config.urx,
3157  detmon_lg_config.ury,
3158  dit_nb, *dit_nskip, mode));
3159  /* fill DETi WINi OPTi columns - see DFS06921*/
3160  skip_if(irplib_fill_table_DETWINUIT(linear_table, pDETlist, dit_nb));
3161  }
3162 
3163 
3164  /* as we know only at this point if a frame is
3165  saturated or not, and we would like to compute the
3166  contamination only on the last non saturated frame,
3167  we need de facto to compute saturation on any non saturated
3168  frame, by overwriting the QC parameter. In the end it will
3169  remain only the last value corresponding to a non saturated
3170  frame */
3171 
3172  if(opt_nir == OPT &&
3173  *rows_linear_affected != 0 ) {
3174  detmon_opt_contamination(ons, offs, mode, qclist);
3175  }
3176 
3177  }
3178 
3179  end_skip;
3180 
3181  cpl_frameset_delete(pair_on);
3182  cpl_imagelist_delete(ons);
3183 
3184  if(!detmon_lg_config.collapse ) {
3185  cpl_imagelist_delete(offs);
3186  }
3187 
3188  if(!detmon_lg_config.collapse) {
3189  cpl_frameset_delete(pair_off);
3190  }
3191 
3192  cpl_propertylist_delete(plist);
3193  cpl_propertylist_delete(pDETlist);
3194  return cpl_error_get_code();
3195 }
3196 
3197 /*---------------------------------------------------------------------------*/
3203 /*---------------------------------------------------------------------------*/
3204 static cpl_error_code
3205 detmon_add_adl_column(cpl_table * table,
3206  cpl_boolean opt_nir)
3207 {
3208  cpl_error_code error;
3209  double mean_med_dit;
3210  double *dits;
3211 
3212  cpl_ensure_code(table != NULL, CPL_ERROR_NULL_INPUT);
3213 
3214  mean_med_dit = cpl_table_get_column_mean(table, "MED_DIT");
3215  if (opt_nir == OPT)
3216  dits = cpl_table_get_data_double(table, "EXPTIME");
3217  else
3218  dits = cpl_table_get_data_double(table, "DIT");
3219 
3220  error = cpl_table_copy_data_double(table, "ADL", dits);
3221  cpl_ensure_code(!error, error);
3222  error = cpl_table_multiply_scalar(table, "ADL", mean_med_dit);
3223  cpl_ensure_code(!error, error);
3224 
3225  return cpl_error_get_code();
3226 }
3227 
3228 /*---------------------------------------------------------------------------*/
3236 /*---------------------------------------------------------------------------*/
3237 static cpl_error_code
3238 detmon_lg_reduce_init(cpl_table * gain_table,
3239  cpl_table * linear_table,
3240  cpl_imagelist ** linearity_inputs,
3241  const cpl_boolean opt_nir)
3242 {
3243  skip_if(detmon_gain_table_create(gain_table, opt_nir));
3244  skip_if(detmon_lin_table_create(linear_table, opt_nir));
3245 
3246  if(detmon_lg_config.pix2pix) {
3247  *linearity_inputs = cpl_imagelist_new();
3248  skip_if(*linearity_inputs == NULL);
3249  }
3250 
3251  end_skip;
3252 
3253  return cpl_error_get_code();
3254 }
3255 
3256 /*--------------------------------------------------------------------------*/
3262 /*--------------------------------------------------------------------------*/
3263 static double
3264 detmon_pfits_get_dit(const cpl_propertylist * plist)
3265 {
3266  if (cpl_propertylist_has(plist, "ESO DET DIT")) {
3267  /* FIERA Detector Controller */
3268  return irplib_pfits_get_prop_double(plist, "ESO DET DIT");
3269  } else {
3270  /* New Generation Detector Controller */
3271  return irplib_pfits_get_prop_double(plist, "ESO DET SEQ1 DIT");
3272  }
3273  (void)cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND, "FITS key "
3274  "ESO DET DIT or ESO DET DIT not found");
3275  return 0.0;
3276 }
3277 
3278 /*--------------------------------------------------------------------------*/
3284 /*--------------------------------------------------------------------------*/
3285 static double
3286 detmon_pfits_get_dit_opt(const cpl_propertylist * plist)
3287 {
3288  if (cpl_propertylist_has(plist, "ESO DET WIN1 UIT1")) {
3289  /* FIERA Detector Controller */
3290  return irplib_pfits_get_prop_double(plist, "ESO DET WIN1 UIT1");
3291  } else if (cpl_propertylist_has(plist, "ESO DET UIT1")) {
3292  /* New Generation Detector Controller */
3293  return irplib_pfits_get_prop_double(plist, "ESO DET WIN1 UIT1");
3294  }
3295 
3296  (void)cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND, "FITS key "
3297  "ESO DET WIN1 UIT1 or ESO DET UIT1 not found");
3298  return 0.0;
3299 }
3300 
3301 
3302 /*---------------------------------------------------------------------------*/
3307 static cpl_propertylist*
3308 detmon_load_pro_keys(const char* NAME_O)
3309 {
3310  cpl_propertylist* pro_keys=NULL;
3311  pro_keys=cpl_propertylist_load_regexp(NAME_O,0,"^(ESO PRO)",0);
3312  return pro_keys;
3313 }
3314 
3315 
3316 static double irplib_pfits_get_prop_double(const cpl_propertylist * plist,
3317  const char* prop_name)
3318 {
3319  double dit;
3320  dit = cpl_propertylist_get_double(plist, prop_name);
3321  if(cpl_error_get_code() != CPL_ERROR_NONE)
3322  {
3323  cpl_msg_error(cpl_func, "Cannot read property '%s', err[%s]",
3324  prop_name, cpl_error_get_where());
3325  }
3326  return dit;
3327 }
3328 
3329 static cpl_error_code
3330 detmon_gain_compute_qc(double kappa, int nclip, const int pos,
3331  const cpl_imagelist* offs, unsigned mode,
3332  double avg_on1, double avg_on2,
3333  double avg_off1, double avg_off2,
3334  double sig_off_dif, int c_ndit,
3335  double autocorr, cpl_image* on_dif,
3336  cpl_table* gain_table)
3337 {
3338 
3339  /* here detmon actually computes gain QC parameter */
3340  double double_adu;
3341  double avg_on_dif, sig_on_dif;
3342  irplib_ksigma_clip(on_dif, 1, 1, cpl_image_get_size_x(on_dif),
3343  cpl_image_get_size_y(on_dif), kappa, nclip, 1e-5,
3344  &avg_on_dif, &sig_on_dif);
3345  skip_if(
3346  cpl_table_set_double(gain_table, "SIG_ON_DIF", pos,
3347  sig_on_dif));
3348  if (cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE) {
3349  double_adu = (avg_on1 + avg_on2) - 2 * avg_off1;
3350  }
3351  else {
3352  double_adu = (avg_on1 + avg_on2) - (avg_off1 + avg_off2);
3353 
3354  const double sigma
3355  = (sig_on_dif * sig_on_dif) - (sig_off_dif * sig_off_dif);
3356 
3357  /* sigma_corr = autocorr * sigma; */
3358 
3359  const double gain = double_adu / (c_ndit * sigma);
3360 
3361  const double gain_corr = gain / (autocorr);
3362 
3363  skip_if(cpl_table_set_double(gain_table, "GAIN", pos, gain));
3364  skip_if(
3365  cpl_table_set_double(gain_table, "GAIN_CORR", pos,
3366  gain_corr));
3367  }
3368  /* cpl_msg_info(cpl_func,"gain=%g gain_corr=%g autocorr=%g",gain,gain_corr,autocorr); */
3369  skip_if(cpl_table_set_double(gain_table, "AUTOCORR", pos, autocorr));
3370  skip_if(cpl_table_set_double(gain_table, "ADU", pos, double_adu / 2));
3371  /* FIXME: Remove the following 3 columns after testing period */
3372  skip_if(
3373  cpl_table_set_double(gain_table, "Y_FIT", pos,
3374  c_ndit * sig_on_dif * sig_on_dif));
3375  skip_if(
3376  cpl_table_set_double(gain_table, "Y_FIT_CORR", pos,
3377  c_ndit * sig_on_dif * sig_on_dif));
3378  skip_if(cpl_table_set_double(gain_table, "X_FIT", pos, double_adu));
3379  skip_if(
3380  cpl_table_set_double(gain_table, "X_FIT_CORR", pos,
3381  double_adu / autocorr));
3382 
3383  end_skip;
3384 
3385  return cpl_error_get_code();
3386 }
3387 
3388 static double
3389 detmon_gain_prepare_autocorr(unsigned mode, const int pos,
3390  int m, int n, cpl_imagelist* diff_flats,
3391  cpl_image* on_dif, cpl_imagelist* autocorr_images)
3392 {
3393  double autocorr = 1.0;
3394 
3395  if (mode & IRPLIB_GAIN_WITH_AUTOCORR) {
3396  if (diff_flats) {
3397  cpl_image * diff = cpl_image_duplicate(on_dif);
3398  skip_if(cpl_imagelist_set(diff_flats, diff, pos));
3399  }
3400  if (autocorr_images) {
3401  cpl_image * corr = NULL;
3402  autocorr = detmon_autocorr_factor(on_dif, &corr, m, n);
3403  if (corr) {
3404  skip_if(cpl_imagelist_set(autocorr_images, corr, pos));
3405  }
3406  else {
3407  detmon_lg_add_empty_image(autocorr_images, pos);
3408  }
3409  }
3410  else {
3411  autocorr = detmon_autocorr_factor(on_dif, NULL, m, n);
3412  }
3413  autocorr = isnan(autocorr) ? 1.0 : autocorr;
3414  }
3415  end_skip;
3416 
3417  return autocorr;
3418 }
3419 
3420 static double
3421 detmon_gain_prepare_table(const cpl_imagelist* offs, unsigned mode, int llx,
3422  int lly, int urx, int ury, double kappa, int nclip,
3423  double std, const int pos,
3424  cpl_table* gain_table, double* avg_off2,
3425  double* sig_off_dif)
3426 {
3427  double avg_off1 = 0.0;
3428 
3429  /* prepare gain table to compute gain QC param */
3430  /* TODO: AMO sees that the condition (mode & IRPLIB_GAIN_NO_COLLAPSE)
3431  * is repeated in 2 if entries==> probably one should rewrite the if
3432  * construct
3433  */
3434  if (cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE) {
3435 
3436  skip_if(
3437  irplib_ksigma_clip(cpl_imagelist_get_const(offs, 0),
3438  llx, lly, urx, ury, kappa, nclip, 1e-5,
3439  &avg_off1, &std));
3440  skip_if(cpl_table_set_double(gain_table, "MEAN_OFF", pos, avg_off1));
3441 
3442  }
3443  else if ((mode & IRPLIB_GAIN_NO_COLLAPSE)
3444  || (pos == 0 && mode & IRPLIB_GAIN_COLLAPSE)) {
3445  cpl_image * off_dif = NULL;
3446  double avg_off_dif;
3447  skip_if(
3448  irplib_ksigma_clip(cpl_imagelist_get_const(offs, 0),
3449  llx, lly, urx, ury, kappa, nclip, 1e-5,
3450  &avg_off1, &std));
3451  skip_if(cpl_table_set_double(gain_table, "MEAN_OFF1", pos, avg_off1));
3452  skip_if(
3453  irplib_ksigma_clip(cpl_imagelist_get_const(offs, 1),
3454  llx, lly, urx, ury, kappa, nclip, 1e-5,
3455  avg_off2, &std));
3456  skip_if(cpl_table_set_double(gain_table, "MEAN_OFF2", pos, *avg_off2));
3457  off_dif = detmon_subtract_create_window(
3458  cpl_imagelist_get_const(offs, 0),
3459  cpl_imagelist_get_const(offs, 1), llx, lly, urx, ury);
3460  skip_if(off_dif == NULL);
3461  irplib_ksigma_clip(off_dif, 1, 1, cpl_image_get_size_x(off_dif),
3462  cpl_image_get_size_y(off_dif), kappa, nclip, 1e-5,
3463  &avg_off_dif, sig_off_dif);
3464  cpl_image_delete(off_dif);
3465  skip_if(
3466  cpl_table_set_double(gain_table, "SIG_OFF_DIF", pos,
3467  *sig_off_dif));
3468  }
3469  else if (pos > 0 && (mode & IRPLIB_GAIN_COLLAPSE)) {
3470 
3471  int status;
3472  avg_off1 = cpl_table_get_double(gain_table, "MEAN_OFF1", 0, &status);
3473  skip_if(cpl_table_set_double(gain_table, "MEAN_OFF1", pos, avg_off1));
3474  *avg_off2 = cpl_table_get_double(gain_table, "MEAN_OFF2", 0, &status);
3475  skip_if(cpl_table_set_double(gain_table, "MEAN_OFF2", pos, *avg_off2));
3476  *sig_off_dif = cpl_table_get_double(gain_table, "SIG_OFF_DIF", 0,
3477  &status);
3478  skip_if(
3479  cpl_table_set_double(gain_table, "SIG_OFF_DIF", pos,
3480  *sig_off_dif));
3481  }
3482 
3483  end_skip;
3484 
3485  return avg_off1;
3486 }
3487 
3488 /*---------------------------------------------------------------------------*/
3523 /*---------------------------------------------------------------------------*/
3524 static cpl_error_code
3525 detmon_gain_table_fill_row(cpl_table * gain_table,
3526  double c_dit,int c_ndit,
3527  cpl_imagelist * autocorr_images,
3528  cpl_imagelist * diff_flats,
3529  const cpl_imagelist * ons,
3530  const cpl_imagelist * offs,
3531  double kappa, int nclip,
3532  int llx, int lly, int urx, int ury,
3533  int m, int n,
3534  double gain_threshold,
3535  int pos, unsigned mode, int* rows_gain_affected)
3536 {
3537  const cpl_image *image;
3538  cpl_image *on_dif = NULL;
3539  double std = 0;
3540  double avg_on1, avg_on2;
3541  double avg_off1, avg_off2;
3542  double autocorr;
3543 
3544  cpl_table_set(gain_table, "FLAG", pos, 1);
3545  if (mode & IRPLIB_GAIN_NIR)
3546  {
3547  cpl_table_set(gain_table, "DIT", pos, c_dit);
3548  cpl_table_set(gain_table, "NDIT", pos, c_ndit);
3549  } else if (mode & IRPLIB_GAIN_OPT)
3550  {
3551  cpl_table_set(gain_table, "EXPTIME", pos, c_dit);
3552  } else
3553  {
3554  cpl_msg_error(cpl_func, "Mandatory mode (OPT or NIR) not provided");
3555  skip_if(1);
3556  }
3557  if(*rows_gain_affected == 0)
3558  {
3559  cpl_msg_info(cpl_func, "skip the frame #%d", pos + 1);
3560  cpl_table_set(gain_table, "FLAG", pos, 0);
3561  if(mode & IRPLIB_GAIN_WITH_AUTOCORR)
3562  {
3563  autocorr = -1;
3564  if (diff_flats)
3565  {
3566  detmon_lg_add_empty_image(diff_flats, pos);
3567  }
3568  if (autocorr_images)
3569  {
3570  detmon_lg_add_empty_image(autocorr_images, pos);
3571  }
3572  }
3573  return cpl_error_get_code();
3574  }
3575  skip_if((image = cpl_imagelist_get_const(ons, 0)) == NULL);
3576  skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
3577  nclip, 1e-5, &avg_on1, &std));
3578  skip_if((image = cpl_imagelist_get_const(ons, 1)) == NULL);
3579  skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
3580  nclip, 1e-5, &avg_on2, &std));
3581 
3582  if (
3583  (avg_on1 > gain_threshold) ||
3584  (avg_on2 > gain_threshold)
3585  )
3586  {
3587  /* If frames has intensity above threshold write out warning and adjust
3588  * imagelists
3589  */
3590  if ( (avg_on1 > gain_threshold) || (avg_on2 > gain_threshold) )
3591  {
3592  cpl_msg_warning(cpl_func, "Average level is above the limit set by the gain_theshold parameter, "
3593  "the frames would not be taken into calculation");
3594 
3595  cpl_msg_warning(cpl_func, "Average levels [%f ; %f], limit [%f]",
3596  avg_on1, avg_on2, gain_threshold);
3597  }
3598 
3599  cpl_msg_info(cpl_func, "skip the frame #%d", pos + 1);
3600  cpl_table_set(gain_table, "FLAG", pos, 0);
3601  if(mode & IRPLIB_GAIN_WITH_AUTOCORR)
3602  {
3603  autocorr = -1;
3604  if (diff_flats)
3605  {
3606  detmon_lg_add_empty_image(diff_flats, pos);
3607  }
3608  if (autocorr_images)
3609  {
3610  detmon_lg_add_empty_image(autocorr_images, pos);
3611  }
3612  }
3613  *rows_gain_affected = 0;
3614  }
3615  else
3616  {
3617  /* we can compute gain: first computes relevant quantities to cover all
3618  * cases, then compute QC parameter.
3619  */
3620  double sig_off_dif;
3621  *rows_gain_affected = 1;
3622  skip_if(cpl_table_set_double(gain_table, "MEAN_ON1", pos, avg_on1));
3623  skip_if(cpl_table_set_double(gain_table, "MEAN_ON2", pos, avg_on2));
3624 
3625  on_dif =
3626  detmon_subtract_create_window(cpl_imagelist_get_const(ons, 0),
3627  cpl_imagelist_get_const(ons, 1),
3628  llx, lly, urx, ury);
3629  skip_if(on_dif == NULL);
3630 
3631  autocorr = detmon_gain_prepare_autocorr(mode, pos, m, n,
3632  diff_flats, on_dif, autocorr_images);
3633 
3634  avg_off1 = detmon_gain_prepare_table(offs, mode, llx, lly, urx, ury,
3635  kappa, nclip, std, pos, gain_table, &avg_off2,
3636  &sig_off_dif);
3637 
3638  detmon_gain_compute_qc(kappa, nclip, pos, offs, mode,
3639  avg_on1, avg_on2, avg_off1, avg_off2,
3640  sig_off_dif, c_ndit, autocorr, on_dif,
3641  gain_table);
3642  }
3643  end_skip;
3644 
3645  cpl_image_delete(on_dif);
3646 
3647  return cpl_error_get_code();
3648 }
3649 
3650 
3651 
3652 /*---------------------------------------------------------------------------*/
3673 /*---------------------------------------------------------------------------*/
3674 static cpl_error_code
3675 detmon_check_saturation_on_pair(cpl_imagelist * autocorr_images,
3676  cpl_imagelist * diff_flats,
3677  const cpl_imagelist * ons,
3678  double kappa, int nclip,
3679  int llx, int lly, int urx, int ury,
3680  double saturation_limit,
3681  const int pos, unsigned mode, int* rows_linear_affected)
3682 {
3683  const cpl_image *image;
3684  double std = 0;
3685  double avg_on1, avg_on2;
3686 
3687 
3688  if(*rows_linear_affected == 0)
3689  {
3690  cpl_msg_info(cpl_func, "For linearity skip the frame #%d", pos + 1);
3691  if(mode & IRPLIB_GAIN_WITH_AUTOCORR)
3692  {
3693  if (diff_flats)
3694  {
3695  detmon_lg_add_empty_image(diff_flats, pos);
3696  }
3697  if (autocorr_images)
3698  {
3699  detmon_lg_add_empty_image(autocorr_images, pos);
3700  }
3701  }
3702  return cpl_error_get_code();
3703  }
3704  skip_if((image = cpl_imagelist_get_const(ons, 0)) == NULL);
3705  skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
3706  nclip, 1e-5, &avg_on1, &std));
3707  skip_if((image = cpl_imagelist_get_const(ons, 1)) == NULL);
3708  skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
3709  nclip, 1e-5, &avg_on2, &std));
3710 
3711  if (
3712  (avg_on1 > saturation_limit) ||
3713  (avg_on2 > saturation_limit)
3714  )
3715  {
3716  /* If frames has intensity above threshold write out warning and adjust
3717  * imagelists
3718  */
3719  if ( (avg_on1 > saturation_limit) || (avg_on2 > saturation_limit) )
3720  {
3721  cpl_msg_warning(cpl_func, "Average level is above the limit set by the saturation_limit parameter, "
3722  "the frames would not be taken into calculation");
3723 
3724  cpl_msg_warning(cpl_func, "Average levels [%f ; %f], limit [%f]",
3725  avg_on1, avg_on2, saturation_limit);
3726  }
3727 
3728  cpl_msg_info(cpl_func, "skip the frame #%d", pos + 1);
3729  *rows_linear_affected = 0;
3730  } else{
3731 
3732  }
3733 
3734  end_skip;
3735 
3736  return cpl_error_get_code();
3737 }
3738 
3739 
3740 
3741 
3742 /*--------------------------------------------------------------------------*/
3749 /*--------------------------------------------------------------------------*/
3750 
3751 static cpl_image *
3752 detmon_bpixs(const cpl_imagelist * coeffs,
3753  cpl_boolean bpmbin,
3754  const double kappa,
3755  int *nbpixs)
3756 {
3757 
3758 
3759  const cpl_image *first= cpl_imagelist_get_const(coeffs, 0);
3760 
3761 
3762 
3763 
3764 
3765 
3766  cpl_mask *mask = cpl_mask_new(cpl_image_get_size_x(first),
3767  cpl_image_get_size_y(first));
3768 
3769  cpl_image *bpm = NULL; /* Avoid false uninit warning */
3770 
3771 
3772  int size = cpl_imagelist_get_size(coeffs);
3773 
3774  if(!bpmbin) {
3775  bpm = cpl_image_new(cpl_image_get_size_x(first),
3776  cpl_image_get_size_y(first),
3777  CPL_TYPE_INT);
3778  }
3779 
3780 
3781  for(int i = 0; i < size; i++) {
3782  const cpl_image * cur_coeff = cpl_imagelist_get_const(coeffs, i);
3783 
3784  cpl_stats* stats = cpl_stats_new_from_image(cur_coeff,
3785  CPL_STATS_MEAN | CPL_STATS_STDEV);
3786  double cur_mean = cpl_stats_get_mean(stats);
3787  double cur_stdev = cpl_stats_get_stdev(stats);
3788 
3789  double lo_cut = cur_mean - kappa * cur_stdev;
3790  double hi_cut = cur_mean + kappa * cur_stdev;
3791 
3792  cpl_mask* cur_mask = cpl_mask_threshold_image_create(cur_coeff, lo_cut, hi_cut);
3793  cpl_mask_not(cur_mask);
3794 
3795  if(!bpmbin) {
3796  cpl_image* cur_image = cpl_image_new_from_mask(cur_mask);
3797  double p = pow(2, i);
3798  cpl_image_power(cur_image, p);
3799  cpl_image_add(bpm, cur_image);
3800  cpl_image_delete(cur_image);
3801  }
3802 
3803  cpl_mask_or(mask, cur_mask);
3804 
3805  cpl_mask_delete(cur_mask);
3806  cpl_stats_delete(stats);
3807  }
3808 
3809  if(bpmbin) {
3810  bpm = cpl_image_new_from_mask(mask);
3811  }
3812 
3813  *nbpixs = cpl_mask_count(mask);
3814 
3815  cpl_mask_delete(mask);
3816 
3817  return bpm;
3818 }
3819 
3820 
3821 /*--------------------------------------------------------------------------*/
3828 /*--------------------------------------------------------------------------*/
3829 /* Not used so we temporary comment it out
3830 static cpl_image *
3831 detmon_bpixs2(cpl_vector* x,const cpl_imagelist* y,
3832  const cpl_imagelist * coeffs,cpl_table* gain_table,
3833  const int order, const double kappa,cpl_boolean bpmbin,
3834  int *nbpixs)
3835 {
3836 
3837 
3838  int size_x=0;
3839  int size_y=0;
3840  int size_c=0;
3841 
3842 
3843  int i=0;
3844  int j=0;
3845  cpl_size k=0;
3846  int z=0;
3847  int pix=0;
3848  int sx=0;
3849  int sy=0;
3850 
3851  double* px=NULL;
3852  const float* pdata=NULL;
3853  const float* pcoeffs=NULL;
3854  double pfit=0.;
3855  double* pgain=NULL;
3856  cpl_binary* pmask=NULL;
3857  double gain=0;
3858  const cpl_image* img_data=NULL;
3859 
3860  const cpl_image* img_coeffs=NULL;
3861  cpl_image* bpm=NULL;
3862  cpl_mask* mask=NULL;
3863 
3864  cpl_polynomial* pol=NULL;
3865 
3866  size_x = cpl_vector_get_size(x);
3867  size_y = cpl_imagelist_get_size(y);
3868  size_c = cpl_imagelist_get_size(coeffs);
3869  img_data = cpl_imagelist_get_const(coeffs, 0);
3870  sx = cpl_image_get_size_x(img_data);
3871  sy = cpl_image_get_size_y(img_data);
3872  mask = cpl_mask_new(sx,sy);
3873 
3874  cpl_ensure(size_x == size_y, CPL_ERROR_NULL_INPUT, NULL);
3875 
3876  cpl_ensure(size_c == (order+1), CPL_ERROR_NULL_INPUT, NULL);
3877 
3878  px = cpl_vector_get_data(x);
3879  pmask=cpl_mask_get_data(mask);
3880  pgain=cpl_table_get_data_double(gain_table,"GAIN");
3881  pol=cpl_polynomial_new(1);
3882  for (z = 0; z < size_x; z++) {
3883 
3884  img_data = cpl_imagelist_get_const(y, z);
3885  pdata = cpl_image_get_data_float_const(img_data);
3886  gain=pgain[z];
3887 
3888  for (j = 0; j < sy; j++) {
3889 
3890  for (i = 0; i < sx; i++) {
3891 
3892  pix = j * sx + i;
3893 
3894  for (k = size_c-1; k >= 0; k--) {
3895 
3896  img_coeffs = cpl_imagelist_get_const(coeffs, k);
3897  pcoeffs = cpl_image_get_data_float_const(img_coeffs);
3898  cpl_polynomial_set_coeff(pol, &k, pcoeffs[pix]);
3899 
3900  }
3901 
3902  pfit = cpl_polynomial_eval_1d(pol,px[z],NULL);
3903  if (pdata[pix] > 0) {
3904  if (fabs(pdata[pix] - pfit) > kappa * sqrt(gain*pdata[pix])) {
3905  pmask[pix] = CPL_BINARY_1;
3906  } // check if point to be flagged
3907  } // check if pos intensity
3908  } // i loop
3909  } // j loop
3910 
3911  //cpl_image_delete(img_data);
3912 
3913  } // z loop
3914  cpl_polynomial_delete(pol);
3915  if (bpmbin) {
3916  bpm = cpl_image_new_from_mask(mask);
3917  }
3918 
3919  *nbpixs += cpl_mask_count(mask);
3920 
3921  cpl_mask_delete(mask);
3922 
3923  return bpm;
3924 }
3925 
3926 */
3927 /*---------------------------------------------------------------------------*/
3939 /*---------------------------------------------------------------------------*/
3940 
3941 static double
3942 detmon_autocorr_factor(const cpl_image * image,
3943  cpl_image ** autocorr_image, int m, int n)
3944 {
3945  cpl_image * mycorr_image = NULL;
3946  double autocorr = 0;
3947 
3948 
3949  mycorr_image = detmon_image_correlate(image, image, m, n);
3950 
3951  if (cpl_error_get_code() == CPL_ERROR_UNSUPPORTED_MODE)
3952  {
3953  cpl_msg_warning(cpl_func, "FFTW is not supported by CPL, autocorrelation "
3954  "would be computed using internal implementation");
3955  cpl_error_reset();
3956  if (mycorr_image)
3957  cpl_image_delete(mycorr_image);
3958  mycorr_image = detmon_autocorrelate(image, m, n);
3959  }
3960  if(mycorr_image == NULL) {
3961  return -1;
3962  }
3963 
3964  cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), -1);
3965 
3966  autocorr = cpl_image_get_flux(mycorr_image);
3967 
3968  if (autocorr_image) *autocorr_image = mycorr_image;
3969  else cpl_image_delete(mycorr_image);
3970 
3971  return autocorr;
3972 }
3973 
3974 static cpl_propertylist*
3975 detmon_lg_extract_qclist_4plane(cpl_propertylist* linc_qclist,const int ip)
3976 {
3977 
3978  cpl_propertylist* sub_set=NULL;
3979  char* qc_key=NULL;
3980 
3981  sub_set=cpl_propertylist_new();
3982  qc_key=cpl_sprintf("QC LIN COEF%d",ip);
3983  cpl_propertylist_copy_property_regexp(sub_set,linc_qclist,qc_key,0);
3984 
3985  cpl_free(qc_key);
3986  return sub_set;
3987 
3988 }
3989 
3990 
4000 static cpl_error_code
4001 detmon_lg_extract_extention_header(cpl_frameset* frameset,
4002  cpl_propertylist* gaint_qclist,
4003  cpl_propertylist* lint_qclist,
4004  cpl_propertylist* linc_qclist,
4005  cpl_propertylist* bpm_qclist,
4006  int whichext)
4007 {
4008 
4009  cpl_propertylist * xplist = NULL;
4010 
4011  const char * filename =
4012  cpl_frame_get_filename(cpl_frameset_get_position(frameset, 0));
4013 
4014  xplist = cpl_propertylist_load_regexp(filename, whichext,
4015  "ESO DET|EXTNAME", 0);
4016  if (detmon_lg_config.exts >= 0)
4017  {
4018  /* for one extension, copy only extname keyword (if any) - DFS09856 */
4019  cpl_property* propExtname = NULL;
4020  propExtname = cpl_propertylist_get_property(xplist, "EXTNAME");
4021  cpl_error_reset();
4022  if (NULL != propExtname)
4023  {
4024  propExtname = cpl_property_duplicate(propExtname);
4025  }
4026  cpl_propertylist_delete(xplist);
4027  xplist = NULL;
4028  if (NULL != propExtname)
4029  {
4030  xplist = cpl_propertylist_new();
4031  cpl_propertylist_append_property(xplist, propExtname);
4032  cpl_property_delete(propExtname);
4033  }
4034  }
4035  if (NULL != xplist)
4036  {
4037  cpl_propertylist_append(gaint_qclist, xplist);
4038  cpl_propertylist_append(lint_qclist, xplist);
4039  cpl_propertylist_append(linc_qclist, xplist);
4040  cpl_propertylist_append(bpm_qclist, xplist);
4041  cpl_propertylist_delete(xplist);
4042  }
4043 
4044  return cpl_error_get_code();
4045 }
4046 
4047 
4048 
4049 
4050 
4051 /*---------------------------------------------------------------------------*/
4060 /*---------------------------------------------------------------------------*/
4061 static cpl_error_code
4062 detmon_lg_save_table_with_pro_keys(cpl_table* table,
4063  const char* name_o,
4064  cpl_propertylist* xheader,
4065  unsigned CPL_IO_MODE)
4066 {
4067 
4068  cpl_propertylist* pro_keys=NULL;
4069 
4070  pro_keys=detmon_load_pro_keys(name_o);
4071  cpl_propertylist_append(xheader,pro_keys);
4072 
4073  if(CPL_IO_MODE==CPL_IO_DEFAULT) {
4074  cpl_propertylist * pri_head=cpl_propertylist_load(name_o,0);
4075  cpl_table_save(table, pri_head,xheader,name_o,
4076  CPL_IO_DEFAULT);
4077  cpl_propertylist_delete(pri_head);
4078 
4079  } else {
4080  cpl_table_save(table,NULL,xheader,name_o,
4081  CPL_IO_EXTEND);
4082  }
4083  cpl_propertylist_delete(pro_keys);
4084 
4085  return cpl_error_get_code();
4086 }
4087 
4088 /*---------------------------------------------------------------------------*/
4096 /*---------------------------------------------------------------------------*/
4097 static cpl_error_code
4098 detmon_lg_save_image_with_pro_keys(cpl_image* image,
4099  const char* name_o,
4100  cpl_propertylist* xheader)
4101 {
4102 
4103  cpl_propertylist* pro_keys=NULL;
4104  pro_keys=detmon_load_pro_keys(name_o);
4105  cpl_propertylist_append(xheader,pro_keys);
4106 
4107  cpl_image_save(image,name_o, CPL_BPP_IEEE_FLOAT,
4108  xheader,CPL_IO_EXTEND);
4109  cpl_propertylist_delete(pro_keys);
4110 
4111 
4112  return cpl_error_get_code();
4113 }
4114 
4115 /*---------------------------------------------------------------------------*/
4123 /*---------------------------------------------------------------------------*/
4124 static cpl_error_code
4125 detmon_lg_save_imagelist_with_pro_keys(cpl_imagelist* imagelist,
4126  const char* name_o,
4127  cpl_propertylist* xheader)
4128 {
4129 
4130  cpl_propertylist* pro_keys=NULL;
4131  pro_keys=detmon_load_pro_keys(name_o);
4132  cpl_propertylist_append(xheader,pro_keys);
4133 
4134  cpl_imagelist_save(imagelist,name_o, CPL_BPP_IEEE_FLOAT,
4135  xheader,CPL_IO_EXTEND);
4136 
4137  cpl_propertylist_delete(pro_keys);
4138 
4139 
4140  return cpl_error_get_code();
4141 }
4142 
4143 /*---------------------------------------------------------------------------*/
4160 static cpl_error_code
4161 detmon_lg_save_plane(const cpl_parameterlist * parlist,
4162  cpl_frameset* frameset,
4163  const cpl_frameset * usedframes,
4164  int whichext,
4165  const char* recipe_name,
4166  cpl_propertylist* mypro_coeffscube,
4167  cpl_propertylist* linc_plane_qclist,
4168  const char* package,
4169  const char* NAME_O,
4170  cpl_image* plane)
4171 {
4172  if(detmon_lg_config.exts == 0) {
4173  cpl_propertylist* plist=NULL;
4174  cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4175  NULL, NULL,
4176  CPL_BPP_IEEE_FLOAT, recipe_name,
4177  mypro_coeffscube, NULL,
4178  package, NAME_O);
4179  plist=cpl_propertylist_load(NAME_O,0);
4180  cpl_image_save(plane,NAME_O, CPL_BPP_IEEE_FLOAT,
4181  plist,CPL_IO_DEFAULT);
4182  cpl_propertylist_delete(plist);
4183 
4184  } else if(detmon_lg_config.exts > 0) {
4185  cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4186  NULL, NULL,
4187  CPL_BPP_IEEE_FLOAT, recipe_name,
4188  mypro_coeffscube, NULL,
4189  package, NAME_O);
4190 
4191  detmon_lg_save_image_with_pro_keys(plane,NAME_O,linc_plane_qclist);
4192  } else {
4193  if(whichext == 1)
4194  {
4195  cpl_dfs_save_image(frameset, NULL, parlist,
4196  usedframes,NULL, NULL,
4197  CPL_BPP_IEEE_FLOAT, recipe_name,
4198  mypro_coeffscube, NULL,
4199  package, NAME_O);
4200  detmon_lg_save_image_with_pro_keys(plane,NAME_O,linc_plane_qclist);
4201  } else {
4202 
4203  detmon_lg_save_image_with_pro_keys(plane,NAME_O,linc_plane_qclist);
4204 
4205  }
4206 
4207  }
4208 
4209  return cpl_error_get_code();
4210 }
4211 
4212 
4213 
4214 /*---------------------------------------------------------------------------*/
4232 static cpl_error_code
4233 detmon_lg_save_cube(const cpl_parameterlist * parlist,
4234  cpl_frameset* frameset,
4235  const cpl_frameset * usedframes,
4236  int whichext,
4237  const char* recipe_name,
4238  cpl_propertylist* mypro_coeffscube,
4239  cpl_propertylist* linc_qclist,
4240  const char* package,
4241  const char* NAME_O,
4242  cpl_imagelist* coeffs)
4243 {
4244 
4245  if(detmon_lg_config.exts == 0) {
4246  cpl_propertylist_append(mypro_coeffscube, linc_qclist);
4247  detmon_lg_dfs_save_imagelist
4248  (frameset, parlist, usedframes, coeffs,
4249  recipe_name, mypro_coeffscube, package,
4250  NAME_O);
4251  } else if(detmon_lg_config.exts > 0) {
4252  cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4253  NULL, NULL,
4254  CPL_BPP_IEEE_FLOAT, recipe_name,
4255  mypro_coeffscube, NULL,
4256  package, NAME_O);
4257 
4258  detmon_lg_save_imagelist_with_pro_keys(coeffs,NAME_O,linc_qclist);
4259 
4260  } else {
4261  if(whichext == 1) {
4262  cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4263  NULL, NULL,
4264  CPL_BPP_IEEE_FLOAT, recipe_name,
4265  mypro_coeffscube, NULL,
4266  package, NAME_O);
4267  if (coeffs)
4268  detmon_lg_save_imagelist_with_pro_keys(coeffs,NAME_O,linc_qclist);
4269  else
4270  cpl_propertylist_save(linc_qclist, NAME_O, CPL_IO_EXTEND);
4271  } else {
4272  if (coeffs)
4273  detmon_lg_save_imagelist_with_pro_keys(coeffs,NAME_O,linc_qclist);
4274  else
4275  cpl_propertylist_save(linc_qclist, NAME_O, CPL_IO_EXTEND);
4276  }
4277  }
4278 
4279  return cpl_error_get_code();
4280 }
4281 
4282 static char*
4283 detmon_lg_set_paf_name_and_header(cpl_frame* ref_frame,
4284  int flag_sets,int which_set,
4285  int whichext,
4286  const char* paf_suf,
4287  cpl_propertylist** plist)
4288 {
4289  char * paf_name=NULL;
4290 
4291  if(detmon_lg_config.exts >= 0)
4292  {
4293  *plist =cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4294  detmon_lg_config.exts);
4295 
4296  if(!flag_sets)
4297  {
4298  paf_name=cpl_sprintf("%s_%s.paf", detmon_lg_config.pafname,paf_suf);
4299  }
4300  else
4301  {
4302  paf_name=cpl_sprintf("%s_%s_set%02d.paf",
4303  detmon_lg_config.pafname, paf_suf,which_set);
4304  }
4305  }
4306  else
4307  {
4308  *plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4309  whichext);
4310 
4311 
4312  if(!flag_sets)
4313  {
4314  paf_name=cpl_sprintf("%s_%s_ext%02d.paf",
4315  detmon_lg_config.pafname, paf_suf,whichext);
4316  }
4317  else
4318  {
4319  paf_name=cpl_sprintf("%s_%s_set%02d_ext%02d.paf",
4320  detmon_lg_config.pafname,paf_suf,
4321  which_set, whichext);
4322  }
4323  }
4324 
4325  return paf_name;
4326 }
4327 
4328 
4329 static char*
4330 detmon_lg_set_paf_name_and_header_ext(cpl_frame* ref_frame,
4331  int flag_sets,int which_set,
4332  int whichext,
4333  const char* paf_suf,
4334  cpl_propertylist** plist)
4335 {
4336  char* paf_name=NULL;
4337 
4338  if(detmon_lg_config.exts >= 0)
4339  {
4340  *plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4341  detmon_lg_config.exts);
4342 
4343  if(!flag_sets)
4344  {
4345  paf_name=cpl_sprintf("%s_%s.paf", detmon_lg_config.pafname,paf_suf);
4346  } else
4347  {
4348  paf_name=cpl_sprintf("%s_%s_set%02d.paf",
4349  detmon_lg_config.pafname, paf_suf,which_set);
4350  }
4351  } else
4352  {
4353  *plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4354  whichext);
4355  if(!flag_sets)
4356  {
4357  paf_name=cpl_sprintf("%s_%s_ext%02d.paf",
4358  detmon_lg_config.pafname, paf_suf,whichext);
4359  } else
4360  {
4361  paf_name=cpl_sprintf("%s_%s_set%02d_ext%02d.paf",
4362  detmon_lg_config.pafname,paf_suf,
4363  which_set, whichext);
4364  }
4365  }
4366  return paf_name;
4367 
4368 }
4369 
4370 static cpl_error_code
4371 detmon_lg_save_paf_product(cpl_frame* ref_frame,int flag_sets,
4372  int which_set,int whichext,
4373  const char* pafregexp,
4374  const char* procatg,
4375  const char* pipeline_name,
4376  const char* recipe_name,
4377  const char* paf_suf,
4378  cpl_propertylist* qclist,
4379  const int ext)
4380 
4381 {
4382  /* Set the file name for the linearity table PAF */
4383  char* paf_name=NULL;
4384  cpl_propertylist* plist=NULL;
4385  cpl_propertylist* paflist = NULL;
4386  cpl_propertylist* mainplist=NULL;
4387 
4388  mainplist =cpl_propertylist_load(cpl_frame_get_filename(ref_frame),0);
4389  if(ext==0) {
4390  paf_name=detmon_lg_set_paf_name_and_header(ref_frame,flag_sets,
4391  which_set,whichext,
4392  paf_suf,&plist);
4393  } else {
4394  paf_name=detmon_lg_set_paf_name_and_header_ext(ref_frame,flag_sets,
4395  which_set,whichext,
4396  paf_suf,&plist);
4397  }
4398 
4399 
4400  paflist = cpl_propertylist_new();
4401  cpl_propertylist_append_string(paflist, CPL_DFS_PRO_CATG,procatg);
4402 
4403  /* Get the keywords for the paf file */
4404  cpl_propertylist_copy_property_regexp(paflist, plist,pafregexp, 0);
4405  cpl_propertylist_copy_property_regexp(paflist, mainplist,pafregexp, 0);
4406  cpl_propertylist_append(paflist,qclist);
4407 
4408  /* Save the PAF */
4409  cpl_dfs_save_paf(pipeline_name, recipe_name,paflist,paf_name);
4410 
4411  /* free memory */
4412  cpl_propertylist_delete(mainplist);
4413  cpl_propertylist_delete(paflist);
4414  cpl_propertylist_delete(plist);
4415  cpl_free(paf_name);
4416 
4417  return cpl_error_get_code();
4418 
4419 }
4420 
4421 
4422 
4423 /*---------------------------------------------------------------------------*/
4454 static cpl_error_code
4455 detmon_lg_save(const cpl_parameterlist * parlist,
4456  cpl_frameset * frameset,
4457  const char *recipe_name,
4458  const char *pipeline_name,
4459  const char *pafregexp,
4460  const cpl_propertylist * pro_lintbl,
4461  const cpl_propertylist * pro_gaintbl,
4462  const cpl_propertylist * pro_coeffscube,
4463  const cpl_propertylist * pro_bpm,
4464  const cpl_propertylist * pro_corr,
4465  const cpl_propertylist * pro_diff,
4466  const char *package,
4467  cpl_imagelist * coeffs,
4468  cpl_table * gain_table,
4469  cpl_table * linear_table,
4470  cpl_image * bpms,
4471  cpl_imagelist * autocorr_images,
4472  cpl_imagelist * diff_flats,
4473  cpl_propertylist * gaint_qclist,
4474  cpl_propertylist * lint_qclist,
4475  cpl_propertylist * linc_qclist,
4476  cpl_propertylist * bpm_qclist,
4477  const int flag_sets,
4478  const int which_set,
4479  const cpl_frameset * usedframes,
4480  int whichext)
4481 {
4482 
4483  cpl_frame *ref_frame;
4484  cpl_propertylist *plist = NULL;
4485  cpl_propertylist *mainplist = NULL;
4486  char* NAME_O=NULL;
4487  char* PREF_O=NULL;
4488  int nb_images;
4489  int i;
4490 
4491  cpl_propertylist * xplist = NULL;
4492 
4493  cpl_propertylist* linc_plane_qclist=NULL;
4494  cpl_image* plane=NULL;
4495  int ip=0;
4496  char* pcatg_plane=NULL;
4497 
4498  cpl_propertylist * mypro_lintbl =
4499  cpl_propertylist_duplicate(pro_lintbl);
4500  cpl_propertylist * mypro_gaintbl =
4501  cpl_propertylist_duplicate(pro_gaintbl);
4502  cpl_propertylist * mypro_coeffscube =
4503  cpl_propertylist_duplicate(pro_coeffscube);
4504  cpl_propertylist * mypro_bpm =
4505  cpl_propertylist_duplicate(pro_bpm);
4506  cpl_propertylist * mypro_corr =
4507  cpl_propertylist_duplicate(pro_corr);
4508  cpl_propertylist * mypro_diff =
4509  cpl_propertylist_duplicate(pro_diff);
4510 
4511  const char * procatg_lintbl =
4512  cpl_propertylist_get_string(mypro_lintbl, CPL_DFS_PRO_CATG);
4513 
4514  const char * procatg_gaintbl =
4515  cpl_propertylist_get_string(mypro_gaintbl, CPL_DFS_PRO_CATG);
4516 
4517  const char * procatg_coeffscube =
4518  cpl_propertylist_get_string(mypro_coeffscube, CPL_DFS_PRO_CATG);
4519  const char * procatg_bpm =
4520  cpl_propertylist_get_string(mypro_bpm, CPL_DFS_PRO_CATG);
4521 
4522 
4523  /* Extract extension headers if multi-extension */
4524  detmon_lg_extract_extention_header(frameset,gaint_qclist,lint_qclist,
4525  linc_qclist,bpm_qclist,whichext);
4526 
4527  /* This is only used later for PAF and temporarily for COEFFS_CUBE
4528  (see if defined)*/
4529  /* Get FITS header from reference file */
4530  ref_frame = cpl_frameset_get_position(frameset, 0);
4531 
4532  skip_if((mainplist =
4533  cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4534  0)) == NULL);
4535 
4536  /*******************************/
4537  /* Write the LINEARITY TABLE */
4538  /*******************************/
4539  cpl_msg_info(cpl_func,"Write the LINEARITY TABLE");
4540  /* Set the file name for the table */
4541  if(!flag_sets) {
4542  NAME_O=cpl_sprintf("%s_linearity_table.fits", recipe_name);
4543  } else {
4544  NAME_O=cpl_sprintf("%s_linearity_table_set%02d.fits", recipe_name,
4545  which_set);
4546  }
4547 
4548  if (detmon_lg_config.exts >= 0) {
4549  /* Save the table */
4550  cpl_propertylist_append(mypro_lintbl, lint_qclist);
4551  skip_if(cpl_dfs_save_table(frameset, NULL,parlist, usedframes, NULL,
4552  linear_table,NULL, recipe_name,
4553  mypro_lintbl, NULL, package, NAME_O));
4554 
4555  detmon_lg_save_table_with_pro_keys(linear_table,NAME_O,
4556  lint_qclist,CPL_IO_DEFAULT);
4557 
4558  } else {
4559  if(whichext == 1) {
4560  /* Save the 1. extension table */
4561  skip_if(cpl_dfs_save_table(frameset,NULL, parlist, usedframes, NULL,
4562  linear_table,lint_qclist, recipe_name,
4563  mypro_lintbl,NULL, package, NAME_O));
4564  detmon_lg_save_table_with_pro_keys(linear_table,NAME_O,
4565  lint_qclist,CPL_IO_DEFAULT);
4566 
4567 
4568 
4569 
4570  } else {
4571 
4572  detmon_lg_save_table_with_pro_keys(linear_table,NAME_O,
4573  lint_qclist,CPL_IO_EXTEND);
4574  }
4575  }
4576  irplib_free(&NAME_O);
4577  /**************************/
4578  /* Write the GAIN TABLE */
4579  /**************************/
4580  cpl_msg_info(cpl_func,"Write the GAIN TABLE");
4581  /* Set the file name for the table */
4582  if(!flag_sets) {
4583  NAME_O=cpl_sprintf("%s_gain_table.fits", recipe_name);
4584  } else {
4585  NAME_O=cpl_sprintf("%s_gain_table_set%02d.fits", recipe_name,
4586  which_set);
4587  }
4588 
4589  if (detmon_lg_config.exts >= 0)
4590  {
4591  /* Save the table */
4592 
4593  cpl_propertylist_append(mypro_gaintbl, gaint_qclist);
4594  skip_if(cpl_dfs_save_table(frameset, NULL, parlist, usedframes, NULL,
4595  gain_table,NULL, recipe_name, mypro_gaintbl,
4596  NULL, package, NAME_O));
4597  detmon_lg_save_table_with_pro_keys(gain_table,NAME_O,
4598  gaint_qclist,CPL_IO_DEFAULT);
4599 
4600  }
4601  else
4602  {
4603  if(whichext == 1)
4604  {
4605  /* Save the 1. extension table */
4606  skip_if(cpl_dfs_save_table(frameset, NULL, parlist, usedframes, NULL, gain_table,
4607  gaint_qclist, recipe_name, mypro_gaintbl,
4608  NULL, package, NAME_O));
4609  detmon_lg_save_table_with_pro_keys(gain_table,NAME_O,
4610  gaint_qclist,CPL_IO_DEFAULT);
4611 
4612  }
4613  else
4614  {
4615 
4616  detmon_lg_save_table_with_pro_keys(gain_table,NAME_O,
4617  gaint_qclist,CPL_IO_EXTEND);
4618  }
4619  }
4620 
4621  if(detmon_lg_config.pix2pix)
4622  {
4623 
4624  /***************************/
4625  /* Write the COEFFS FITS */
4626  /***************************/
4627  cpl_msg_info(cpl_func,"Write the COEFFS FITS");
4628  irplib_free(&NAME_O);
4629  if(!flag_sets)
4630  {
4631  PREF_O=cpl_sprintf("%s_coeffs_cube", recipe_name);
4632  } else
4633  {
4634  PREF_O=cpl_sprintf("%s_coeffs_cube_set%02d",
4635  recipe_name, which_set);
4636  }
4637  if (detmon_lg_config.split_coeffs == 0) {
4638  NAME_O=cpl_sprintf("%s.fits", PREF_O);
4639  }
4640 
4641 
4642  /* Save the imagelist */
4643  if(detmon_lg_config.split_coeffs != 0){
4644 
4645 
4646  nb_images = cpl_imagelist_get_size(coeffs);
4647  for(ip=0;ip<nb_images;ip++) {
4648  NAME_O=cpl_sprintf("%s_P%d.fits", PREF_O,ip);
4649  pcatg_plane=cpl_sprintf("COEFFS_CUBE_P%d",ip);
4650  cpl_propertylist_delete(mypro_coeffscube);
4651  mypro_coeffscube=cpl_propertylist_duplicate(pro_coeffscube);
4652  cpl_propertylist_set_string(mypro_coeffscube,CPL_DFS_PRO_CATG,
4653  pcatg_plane);
4654  linc_plane_qclist=detmon_lg_extract_qclist_4plane(linc_qclist,ip);
4655  cpl_propertylist_append(mypro_coeffscube, linc_plane_qclist);
4656  plane=cpl_imagelist_get(coeffs,ip);
4657  detmon_lg_save_plane(parlist,frameset,usedframes,whichext,
4658  recipe_name,mypro_coeffscube,
4659  linc_plane_qclist,package,NAME_O,plane);
4660 
4661  if(NULL!=linc_plane_qclist) {
4662  cpl_propertylist_delete(linc_plane_qclist);
4663  }
4664  irplib_free(&NAME_O);
4665 
4666  } /* end for loop over cube planes */
4667  } else {
4668 
4669  detmon_lg_save_cube(parlist,frameset,usedframes,whichext,
4670  recipe_name,mypro_coeffscube,
4671  linc_qclist,package,NAME_O,coeffs);
4672  }
4673 
4674  /*******************************/
4675  /* Write the BAD PIXEL MAP */
4676  /*******************************/
4677  cpl_msg_info(cpl_func,"Write the BAD PIXEL MAP");
4678  irplib_free(&NAME_O);
4679  /* Set the file name for the bpm */
4680  if(!flag_sets)
4681  {
4682  NAME_O=cpl_sprintf("%s_bpm.fits", recipe_name);
4683  } else
4684  {
4685  NAME_O=cpl_sprintf("%s_bpm_set%02d.fits", recipe_name, which_set);
4686  }
4687 
4688 
4689  /* Save the image */
4690  if(detmon_lg_config.exts == 0) {
4691  cpl_propertylist_append(mypro_bpm, bpm_qclist);
4692  cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL, bpms,
4693  CPL_BPP_IEEE_FLOAT, recipe_name,
4694  mypro_bpm, NULL, package,
4695  NAME_O);
4696  }
4697  else if(detmon_lg_config.exts > 0)
4698  {
4699  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,NULL, NULL,
4700  CPL_BPP_IEEE_FLOAT, recipe_name,
4701  mypro_bpm, NULL, package,
4702  NAME_O));
4703  detmon_lg_save_image_with_pro_keys(bpms,NAME_O,bpm_qclist);
4704 
4705  } else
4706  {
4707  if (whichext == 1)
4708  {
4709  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,NULL, NULL,
4710  CPL_BPP_IEEE_FLOAT, recipe_name,
4711  mypro_bpm, NULL, package,
4712  NAME_O));
4713  detmon_lg_save_image_with_pro_keys(bpms,NAME_O,bpm_qclist);
4714  } else
4715  {
4716  detmon_lg_save_image_with_pro_keys(bpms,NAME_O,bpm_qclist);
4717  }
4718  }
4719  } /* End of if(pix2pix) */
4720 
4721  if(detmon_lg_config.intermediate)
4722  {
4723  /******************************/
4724  /* Write the AUTOCORRS FITS */
4725  /******************************/
4726  cpl_msg_info(cpl_func,"Write the AUTOCORRS FITS");
4727  nb_images = cpl_imagelist_get_size(autocorr_images);
4728  cpl_ensure_code(nb_images > 0, CPL_ERROR_DATA_NOT_FOUND);
4729  for(i = 0; i < nb_images; i++)
4730  {
4731  cpl_propertylist* pplist = cpl_propertylist_duplicate(mypro_corr);
4732  int inull = 0;
4733  cpl_array* pnames = cpl_table_get_column_names(linear_table);
4734  double ddit = 0;
4735  if(i < cpl_table_get_nrow(linear_table))
4736  {
4737  ddit = cpl_table_get_double(linear_table,
4738  cpl_array_get_data_string_const(pnames)[0], i, &inull);
4739  }
4740  cpl_array_delete(pnames);
4741  /*cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);*/
4742  /* Set the file name for each image */
4743  irplib_free(&NAME_O);
4744  if(!flag_sets)
4745  {
4746  NAME_O=cpl_sprintf("%s_autocorr_%d.fits", recipe_name, i);
4747  assert(NAME_O != NULL);
4748  } else
4749  {
4750  NAME_O=cpl_sprintf("%s_autocorr_%02d_set%02d.fits",
4751  recipe_name, i, which_set);
4752  assert(NAME_O != NULL);
4753  }
4754  /* Save the image */
4755  if(detmon_lg_config.exts > 0)
4756  {
4757  cpl_propertylist* pextlist = cpl_propertylist_new();
4758  cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4759  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4760  NULL,NULL,CPL_BPP_IEEE_FLOAT,
4761  recipe_name, pplist, NULL,
4762  package, NAME_O));
4763 
4764  detmon_lg_save_image_with_pro_keys(
4765  cpl_imagelist_get(autocorr_images, i),NAME_O,pextlist);
4766 
4767  cpl_propertylist_delete(pextlist);
4768  } else
4769  if(detmon_lg_config.exts == 0)
4770  {
4771  cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);
4772  cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL,
4773  cpl_imagelist_get(autocorr_images, i),
4774  CPL_BPP_IEEE_FLOAT,
4775  recipe_name, pplist, NULL, package,
4776  NAME_O);
4777 
4778  }
4779  else
4780  {
4781  cpl_propertylist* pextlist = cpl_propertylist_new();
4782  cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4783  if(whichext == 1)
4784  {
4785  skip_if(cpl_dfs_save_image(frameset, NULL, parlist,
4786  usedframes, NULL,NULL,
4787  CPL_BPP_IEEE_FLOAT, recipe_name,
4788  pplist, NULL,
4789  package, NAME_O));
4790 
4791  detmon_lg_save_image_with_pro_keys(
4792  cpl_imagelist_get(autocorr_images, i),NAME_O,pextlist);
4793 
4794  } else
4795  {
4796 
4797  detmon_lg_save_image_with_pro_keys(
4798  cpl_imagelist_get(autocorr_images, i),NAME_O,pextlist);
4799  }
4800  cpl_propertylist_delete(pextlist);
4801  }
4802  cpl_propertylist_delete (pplist);
4803  }
4804  irplib_free(&NAME_O);
4805 
4806 
4807  /*
4808  cpl_msg_info(cpl_func, "-----before Write the DIFFS FITS %d", __LINE__);
4809  */
4810  /***************************/
4811  /* Write the DIFFS FITS */
4812  /***************************/
4813  cpl_msg_info(cpl_func,"Write the DIFFS FITS");
4814 
4815  for(i = 0; i < nb_images; i++)
4816  {
4817  cpl_propertylist* pplist = cpl_propertylist_duplicate(mypro_diff);
4818  int inull = 0;
4819  cpl_array* pnames = cpl_table_get_column_names(linear_table);
4820  double ddit = 0;
4821  if(i < cpl_table_get_nrow(linear_table))
4822  {
4823  ddit = cpl_table_get_double(linear_table,
4824  cpl_array_get_data_string_const(pnames)[0], i, &inull);
4825  }
4826  cpl_array_delete(pnames);
4827  /*cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);*/
4828  /* Set the file name for each image */
4829  if(!flag_sets)
4830  {
4831  NAME_O=cpl_sprintf("%s_diff_flat_%d.fits", recipe_name, i);
4832  } else
4833  {
4834  NAME_O=cpl_sprintf("%s_diff_flat_%d_set%02d.fits",
4835  recipe_name, i, which_set);
4836  }
4837  /* Save the image */
4838  if(detmon_lg_config.exts > 0)
4839  {
4840  cpl_propertylist* pextlist = cpl_propertylist_new();
4841  cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4842  cpl_propertylist_append_double(mypro_diff, "ESO DET DIT", ddit);
4843  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4844  NULL,NULL,CPL_BPP_IEEE_FLOAT,
4845  recipe_name,
4846  mypro_diff, NULL,package, NAME_O));
4847 
4848  detmon_lg_save_image_with_pro_keys(
4849  cpl_imagelist_get(diff_flats, i),NAME_O,pextlist);
4850 
4851  cpl_propertylist_delete(pextlist);
4852  }
4853  else if(detmon_lg_config.exts == 0)
4854  {
4855  cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);
4856  cpl_dfs_save_image
4857  (frameset, NULL, parlist, usedframes, NULL,
4858  cpl_imagelist_get(diff_flats, i), CPL_BPP_IEEE_FLOAT,
4859  recipe_name, pplist, NULL, package,
4860  NAME_O);
4861 
4862  } else
4863  {
4864  cpl_propertylist* pextlist = cpl_propertylist_new();
4865  cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4866  if(whichext == 1)
4867  {
4868  cpl_propertylist_append_double(mypro_diff,"ESO DET DIT",ddit);
4869  // cpl_propertylist_erase(mypro_diff, "ESO DET DIT");
4870  skip_if(cpl_dfs_save_image(frameset, NULL, parlist,
4871  usedframes, NULL,NULL,
4872  CPL_BPP_IEEE_FLOAT, recipe_name,
4873  mypro_diff, NULL,package, NAME_O));
4874 
4875  detmon_lg_save_image_with_pro_keys(
4876  cpl_imagelist_get(diff_flats, i),NAME_O,pextlist);
4877 
4878  } else
4879  {
4880 
4881  detmon_lg_save_image_with_pro_keys(
4882  cpl_imagelist_get(diff_flats, i),NAME_O,pextlist);
4883 
4884  }
4885  cpl_propertylist_delete(pextlist);
4886  }
4887  cpl_propertylist_delete(pplist);
4888  irplib_free(&NAME_O);
4889  }
4890  } /* End of if(intermediate) */
4891 
4892 
4893  /*******************************/
4894  /* Write the PAF file(s) */
4895  /*******************************/
4896  cpl_msg_info(cpl_func,"Write the PAF file(s)");
4897 
4898  if(detmon_lg_config.pafgen) {
4899 
4900  detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,whichext,
4901  pafregexp,procatg_gaintbl,
4902  pipeline_name,recipe_name,
4903  "qc01",gaint_qclist,0);
4904 
4905  detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,whichext,
4906  pafregexp,procatg_lintbl,
4907  pipeline_name,recipe_name,
4908  "qc02",lint_qclist,0);
4909 
4910  if(detmon_lg_config.pix2pix)
4911  {
4912 
4913  detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,
4914  whichext,pafregexp,
4915  procatg_coeffscube,
4916  pipeline_name,recipe_name,
4917  "qc03",linc_qclist,1);
4918 
4919  detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,
4920  whichext,pafregexp,procatg_bpm,
4921  pipeline_name,recipe_name,
4922  "qc04",bpm_qclist,1);
4923  }
4924  }
4925 
4926  end_skip;
4927  cpl_msg_info(cpl_func,"exit");
4928 
4929  cpl_propertylist_delete(xplist);
4930  if(plist!=NULL) {
4931  cpl_propertylist_delete(plist);
4932  plist=NULL;
4933  }
4934 
4935  irplib_free(&NAME_O);
4936  cpl_free(PREF_O);
4937  cpl_free(pcatg_plane);
4938  cpl_propertylist_delete(mainplist);
4939  cpl_propertylist_delete(mypro_lintbl);
4940  cpl_propertylist_delete(mypro_gaintbl);
4941  cpl_propertylist_delete(mypro_coeffscube);
4942  cpl_propertylist_delete(mypro_bpm);
4943  cpl_propertylist_delete(mypro_corr);
4944  cpl_propertylist_delete(mypro_diff);
4945 
4946  return cpl_error_get_code();
4947 }
4948 
4949 
4950 /*---------------------------------------------------------------------------*/
4958 /*---------------------------------------------------------------------------*/
4959 static cpl_error_code
4960 detmon_opt_contamination(const cpl_imagelist * ons,
4961  const cpl_imagelist * offs,
4962  unsigned mode,
4963  cpl_propertylist * qclist)
4964 {
4965  struct rect {
4966  size_t llx;
4967  size_t lly;
4968  size_t urx;
4969  size_t ury;
4970  };
4971  struct rect rects[5] = {
4972  (struct rect){ detmon_lg_config.llx1,
4973  detmon_lg_config.lly1,
4974  detmon_lg_config.urx1,
4975  detmon_lg_config.ury1},
4976  (struct rect){ detmon_lg_config.llx2,
4977  detmon_lg_config.lly2,
4978  detmon_lg_config.urx2,
4979  detmon_lg_config.ury2},
4980  (struct rect){ detmon_lg_config.llx3,
4981  detmon_lg_config.lly3,
4982  detmon_lg_config.urx3,
4983  detmon_lg_config.ury3},
4984  (struct rect){ detmon_lg_config.llx4,
4985  detmon_lg_config.lly4,
4986  detmon_lg_config.urx4,
4987  detmon_lg_config.ury4},
4988  (struct rect){ detmon_lg_config.llx5,
4989  detmon_lg_config.lly5,
4990  detmon_lg_config.urx5,
4991  detmon_lg_config.ury5},
4992  };
4993 
4994  for (size_t i = 0; i < 5; i++) {
4995  cpl_image * dif_avg;
4996  const cpl_image * off2;
4997  double median;
4998  char kname[300];
4999  if (cpl_imagelist_get_size(offs) == 1 || mode & IRPLIB_LIN_COLLAPSE)
5000  off2 = cpl_imagelist_get_const(offs, 0);
5001  else
5002  off2 = cpl_imagelist_get_const(offs, 1);
5003 
5004  dif_avg = detmon_subtracted_avg(cpl_imagelist_get_const(ons, 0),
5005  cpl_imagelist_get_const(offs, 0),
5006  cpl_imagelist_get_const(ons, 1),
5007  off2,
5008  rects[i].llx,
5009  rects[i].lly,
5010  rects[i].urx,
5011  rects[i].ury);
5012 
5013  median = cpl_image_get_median(dif_avg);
5014  cpl_image_delete(dif_avg);
5015 
5016  skip_if(0);
5017  sprintf(kname, DETMON_QC_CONTAM "%zd", i + 1);
5018 
5019  if(cpl_propertylist_has(qclist,kname)){
5020  skip_if(cpl_propertylist_update_double(qclist,kname,median));
5021  } else {
5022  skip_if(cpl_propertylist_append_double(qclist,kname,median));
5023  skip_if(cpl_propertylist_set_comment(qclist,kname,DETMON_QC_CONTAM_C));
5024  }
5025  }
5026 
5027  end_skip;
5028 
5029  return cpl_error_get_code();
5030 }
5031 
5032 /*---------------------------------------------------------------------------*/
5039 /*---------------------------------------------------------------------------*/
5040 /*
5041 static cpl_error_code
5042 detmon_opt_lampcr(cpl_frameset * cur_fset, int ext)
5043 {
5044  cpl_image * on = NULL;
5045  cpl_image * off = NULL;
5046  cpl_frame * first_off = NULL;
5047  cpl_frame * first_on = NULL;
5048  cpl_propertylist * plist = NULL;
5049  double dit;
5050 
5051  cpl_ensure_code(cur_fset != NULL, CPL_ERROR_NULL_INPUT);
5052 
5053  skip_if((first_off = cpl_frameset_get_position(cur_fset, 0)) == NULL);
5054  skip_if((first_on = cpl_frameset_get_position(cur_fset, 1)) == NULL);
5055 
5056  on = cpl_image_load(cpl_frame_get_filename(first_on),
5057  CPL_TYPE_FLOAT, 0, ext);
5058  off = cpl_image_load(cpl_frame_get_filename(first_off),
5059  CPL_TYPE_FLOAT, 0, ext);
5060  skip_if(cpl_image_subtract(on, off));
5061 
5062  plist = cpl_propertylist_load(cpl_frame_get_filename(first_on), 0);
5063  skip_if(plist == NULL);
5064 
5065  dit = detmon_pfits_get_dit_opt(plist);
5066 
5067  detmon_lg_config.cr = cpl_image_get_mean(on) / dit;
5068 
5069  end_skip;
5070 
5071  cpl_image_delete(on);
5072  cpl_image_delete(off);
5073  cpl_propertylist_delete(plist);
5074 
5075  return cpl_error_get_code();
5076 }
5077 */
5078 /*---------------------------------------------------------------------------*/
5086 /*---------------------------------------------------------------------------*/
5087 int
5088 detmon_lg_dfs_set_groups(cpl_frameset * set,
5089  const char *tag_on, const char *tag_off)
5090 {
5091 
5092 
5093 
5094 
5095 
5096  /* Check entries */
5097  if(set == NULL)
5098  return -1;
5099 
5100  /* Initialize */
5101  int nframes = cpl_frameset_get_size(set);
5102 
5103  /* Loop on frames */
5104  for(int i = 0; i < nframes; i++) {
5105  cpl_frame* cur_frame = cpl_frameset_get_position(set, i);
5106  const char* tag = cpl_frame_get_tag(cur_frame);
5107 
5108  /* RAW frames */
5109  if(!strcmp(tag, tag_on) || !strcmp(tag, tag_off))
5110  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_RAW);
5111  /* CALIB frames */
5112 
5113  /* else if (!strcmp(tag, IIINSTRUMENT_CALIB_FLAT))
5114  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_CALIB);
5115  */
5116  }
5117  return 0;
5118 }
5119 
5120 
5121 /*---------------------------------------------------------------------------*/
5129 /*---------------------------------------------------------------------------*/
5130 static cpl_error_code
5131 detmon_lg_fits_coeffs_and_bpm2chip(cpl_imagelist ** coeffs_ptr,
5132  cpl_image **bpms_ptr)
5133 {
5134 
5135 
5136 
5137 
5138 
5139 
5140 
5141 
5142 
5143  int shift_idx=0;
5144 
5145 
5146 
5147 
5148  cpl_image* dummy_bpm = cpl_image_new(detmon_lg_config.nx,
5149  detmon_lg_config.ny,
5150  CPL_TYPE_INT);
5151  cpl_imagelist* dummy_coeffs = cpl_imagelist_new();
5152 
5153  int* db_p = cpl_image_get_data_int(dummy_bpm);
5154  int* rb_p = cpl_image_get_data_int(*bpms_ptr);;
5155  float** dcs_p = cpl_malloc(sizeof(float *) * (detmon_lg_config.order + 1));
5156  float** rcs_p = cpl_malloc(sizeof(float *) * (detmon_lg_config.order + 1));
5157  int dlength = detmon_lg_config.nx;
5158 
5159  int rlength = detmon_lg_config.urx - detmon_lg_config.llx + 1;
5160  for (int i = 0; i <= detmon_lg_config.order; i++)
5161  {
5162  cpl_image* dummy_coeff = cpl_image_new(detmon_lg_config.nx,
5163  detmon_lg_config.ny,
5164  CPL_TYPE_FLOAT);
5165 
5166  cpl_imagelist_set(dummy_coeffs, dummy_coeff, i);
5167  dcs_p[i] = cpl_image_get_data_float(dummy_coeff);
5168  rcs_p[i] = cpl_image_get_data_float(cpl_imagelist_get(*coeffs_ptr, i));
5169  }
5170  /*copy the coefficients from temporary image to the dummy_bpm*/
5171  for (int i = detmon_lg_config.lly - 1; i < detmon_lg_config.ury; i++)
5172  {
5173  for (int j = detmon_lg_config.llx - 1; j < detmon_lg_config.urx; j++)
5174  {
5175  shift_idx=(i - detmon_lg_config.lly + 1) * rlength +
5176  j - detmon_lg_config.llx + 1;
5177  *(db_p + i * dlength + j) = *(rb_p + shift_idx);
5178  for (int k = 0; k <= detmon_lg_config.order; k++)
5179  {
5180  *(dcs_p[k] + i * dlength + j) =
5181  *(rcs_p[k] + (i - detmon_lg_config.lly + 1) * rlength +
5182  j - detmon_lg_config.llx + 1);
5183  }
5184  }
5185  }
5186  cpl_imagelist_delete(*coeffs_ptr);
5187  cpl_image_delete(*bpms_ptr);
5188  *coeffs_ptr = dummy_coeffs;
5189  *bpms_ptr = dummy_bpm;
5190  cpl_free(dcs_p);
5191  cpl_free(rcs_p);
5192 
5193  return cpl_error_get_code();
5194 }
5195 
5196 /* Not used so we temporaryly comment it out
5197 static cpl_error_code
5198 detmon_lg_qclog_lin_coeff(cpl_imagelist* coeffs_ptr, const int order, cpl_propertylist* linc_qclist)
5199 {
5200  cpl_image* image=NULL;
5201  int i=0;
5202  double coeff=0;
5203  double * pcoeffs = cpl_malloc(sizeof(double)*(order + 1));
5204  char* name_o1=NULL;
5205  char* name_o2=NULL;
5206 
5207  for(i = 0; i <= order; i++)
5208  {
5209  image = cpl_imagelist_get(coeffs_ptr, i);
5210  coeff = cpl_image_get_median(image);
5211  pcoeffs[i] = coeff;
5212  name_o1 = cpl_sprintf("ESO QC LIN COEF%d", i);
5213  name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", i);
5214  assert(name_o1 != NULL);
5215  assert(name_o2 != NULL);
5216  cpl_propertylist_append_double(linc_qclist, name_o1, coeff);
5217  cpl_propertylist_set_comment(linc_qclist,name_o1,DETMON_QC_LIN_COEF_C);
5218  cpl_free(name_o1);
5219  name_o1= NULL;
5220  cpl_propertylist_append_double(linc_qclist, name_o2,cpl_image_get_stdev(image));
5221  cpl_propertylist_set_comment(linc_qclist,name_o2,DETMON_QC_LIN_COEF_ERR_C);
5222  cpl_free(name_o2);
5223  name_o2= NULL;
5224  }
5225  cpl_free(pcoeffs);
5226 
5227  return cpl_error_get_code();
5228 }
5229 */
5230 #ifdef DETMON_USE_DETECTOR_SHOTNOISE_MODEL
5231 /*----------------------------------------------------------------------------*/
5252 /*----------------------------------------------------------------------------*/
5253 static cpl_error_code
5254 detmon_detector_shotnoise_model(const cpl_image* ima_data, const double gain,
5255  const double ron, cpl_image ** ima_errs)
5256 {
5257  cpl_ensure_code(ima_data, CPL_ERROR_NULL_INPUT);
5258  cpl_ensure_code(ima_errs, CPL_ERROR_NULL_INPUT);
5259  cpl_ensure_code(gain > 0., CPL_ERROR_ILLEGAL_INPUT);
5260  cpl_ensure_code(ron > 0., CPL_ERROR_ILLEGAL_INPUT);
5261 
5262  *ima_errs = cpl_image_duplicate(ima_data);
5263  /* set negative values (= zero measurable electrons) to read out noise */
5264  cpl_image_threshold(*ima_errs, 0., INFINITY, ron, ron);
5265 
5266  /* err_ADU = sqrt(counts/gain + ron * ron)*/
5267 
5268  cpl_image_divide_scalar(*ima_errs, gain);
5269  cpl_image_add_scalar(*ima_errs, ron * ron);
5270  cpl_image_power(*ima_errs, 0.5);
5271 
5272  return cpl_error_get_code();
5273 }
5274 #endif
5275 
5276 static int
5277 detmon_compute_badpixmap(cpl_boolean opt_nir, const int nsets,
5278  const cpl_table* linear_table,
5279  const cpl_imagelist* linearity_inputs, int nbpixs,
5280  cpl_vector* x, cpl_propertylist* gaint_qclist,
5281  cpl_image** bpms_ptr)
5282 {
5283  /* Here determines the bad pixel map
5284  * HDRL based version
5285  * AMO: this if is repeated: the following code should be up up
5286  */
5287  if (opt_nir == NIR) {
5288  x = cpl_vector_wrap(nsets,
5289  (double *) cpl_table_get_data_double_const(linear_table,
5290  "DIT"));
5291  }
5292  else {
5293  x = cpl_vector_wrap(nsets,
5294  (double *) cpl_table_get_data_double_const(linear_table,
5295  "EXPTIME"));
5296 
5297  }
5298  int sz = cpl_imagelist_get_size(linearity_inputs);
5299  double kappa = detmon_lg_config.kappa;
5300  int niter = detmon_lg_config.niter;
5301  int llx = detmon_lg_config.llx;
5302  int urx = detmon_lg_config.urx;
5303  int lly = detmon_lg_config.lly;
5304  int ury = detmon_lg_config.ury;
5305  hdrl_parameter* p;
5306  const cpl_image *ima;
5307  cpl_image *err;
5308  // fit-chi-rel method
5309  // errors to be used with fit_chi_rel method
5310  cpl_imagelist* errors = cpl_imagelist_new();
5311  /*
5312  // case1: error proportional to sqrt(EXPTIME)
5313  for(int i=0;i<sz;i++) {
5314  err=cpl_image_new(sx,sy,CPL_TYPE_DOUBLE);
5315  cpl_image_add_scalar(err,1.);
5316  cpl_imagelist_set(errors,err,i);
5317  }
5318  */
5319  /*
5320  // case2:shot noise model to be used with fit_chi_rel method
5321  double gain=1.;
5322  double ron=1.;
5323  for(int i=0;i<sz;i++) {
5324  ima=cpl_imagelist_get(linearity_inputs,i);
5325  hdrldemo_detector_shotnoise_model(ima, gain, ron, &err);
5326  cpl_imagelist_set(errors,err,i);
5327  }
5328  */
5329  // case3: error obtained using mad error approximation
5330  double dmad;
5331  //cpl_msg_info(cpl_func,"sz=%d",sz);
5332  cpl_imagelist* linearity_scaled = cpl_imagelist_new();
5333  double gain = 0;
5334  gain = cpl_propertylist_get_double(gaint_qclist, DETMON_QC_GAIN);
5335  //cpl_msg_info(cpl_func,"ok1 gain=%g",gain);
5336  /* on simulations gain ,may be < 0: make sure it is > 0 */
5337  //cpl_msg_info(cpl_func,"ok1 gain=%g",gain);
5338  gain = (gain < 0) ? 1 : gain;
5339  double avg = 0;
5340  double rms = 0;
5341  skip_if(rms);
5342  //cpl_msg_info(cpl_func,"sz=%d",sz);
5343  //cpl_msg_info(cpl_func,"llx=%d lly=%d urx=%d ury=%d",llx,lly,urx,ury);
5344  for (int i = 0; i < sz; i++) {
5345  ima = cpl_imagelist_get_const(linearity_inputs, i);
5346  /*
5347  cpl_msg_info(cpl_func,"sx=%d sy=%d",
5348  cpl_image_get_size_x(ima),cpl_image_get_size_y(ima));
5349  */
5350  //cpl_msg_info(cpl_func,"max_x=%d max_y=%d",urx-llx+1,ury-lly+1);
5351  //median=cpl_image_get_median_window(ima,1,1,urx-llx+1,ury-lly+1);
5352  skip_if(
5353  irplib_ksigma_clip(ima, 1, 1, urx - llx + 1,
5354  ury - lly + 1, kappa, niter, 1e-5, &avg,
5355  &rms));
5356 
5357  //cpl_msg_info(cpl_func,"avg=%g median=%g",avg,median);
5358  //cpl_msg_info(cpl_func,"thresh=%g", detmon_lg_config.saturation_limit);
5359  if (avg < detmon_lg_config.saturation_limit) {
5360 
5361  //cpl_msg_info(cpl_func,">>>>i=%d", i);
5362  /*
5363  err=cpl_image_duplicate(ima);
5364  cpl_image_multiply_scalar(err, gain);
5365  cpl_image_power(err,0.5);
5366  */
5367  cpl_image_get_mad(ima, &dmad);
5368  err = cpl_image_duplicate(ima);
5369  cpl_image_multiply_scalar(err, 0);
5370  cpl_image_add_scalar(err, dmad * CPL_MATH_STD_MAD);
5371 
5372  //detmon_detector_shotnoise_model(ima, gain_eff,ron, &err);
5373  /*
5374  cpl_msg_info(cpl_func,"err sx=%d",cpl_image_get_size_x(err));
5375  cpl_msg_info(cpl_func,"err sy=%d",cpl_image_get_size_y(err));
5376  cpl_msg_info(cpl_func,"ima sx=%d",cpl_image_get_size_x(ima));
5377  cpl_msg_info(cpl_func,"ima sy=%d",cpl_image_get_size_y(ima));
5378  cpl_msg_info(cpl_func,"sy=%d",cpl_image_get_size_y(err));
5379  */
5380  cpl_imagelist_set(errors, err, i);
5381  /*
5382  sprintf(dname,"data_%d.fits",i);
5383  sprintf(ename,"errs_%d.fits",i);
5384  cpl_image_save(err, ename, CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
5385  cpl_image_save(ima, dname, CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
5386  */
5387  skip_if(
5388  cpl_imagelist_set(linearity_scaled,
5389  cpl_image_duplicate(ima), i));
5390  }
5391  }
5392  hdrl_imagelist* hil = hdrl_imagelist_create(linearity_scaled, errors);
5393  /*
5394  cpl_imagelist_save(linearity_scaled,"lin_data.fits", CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
5395  cpl_imagelist_save(errors,"lin_errs.fits", CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
5396  */
5397  cpl_imagelist_delete(errors);
5398  /* P-val method */
5399  double pval = 0.001;
5400  p = hdrl_bpm_fit_parameter_create_pval(1, pval);
5401  /*
5402  p = hdrl_bpm_fit_parameter_create_rel_coef(1, 1., 1.);
5403  hdrl_parameter_delete(p);
5404  */
5405  /* chi-rel method
5406  int ord=detmon_lg_config.order;
5407  p = hdrl_bpm_fit_parameter_create_rel_chi(1, kappa, kappa);
5408  */
5409  hdrl_bpm_fit_compute(p, hil, x, bpms_ptr);
5410  //cpl_vector_dump(x,stdout);
5411  /*
5412  // bpm-3D method
5413  cpl_imagelist* linearity_scaled=cpl_imagelist_new();
5414 
5415  for(int i=0;i<sz;i++) {
5416  ima=cpl_imagelist_get(linearity_inputs,i);
5417  median=cpl_image_get_median(ima);
5418  if(median < detmon_lg_config.saturation_limit) {
5419  cpl_image_divide_scalar(ima,median);
5420  cpl_imagelist_set(linearity_scaled,cpl_image_duplicate(ima),i);
5421  }
5422  }
5423  hdrl_imagelist* hil= hdrl_imagelist_create(linearity_scaled,NULL);
5424 
5425 
5426  // bpm-3D method
5427  hdrl_bpm_3d_method method = HDRL_BPM_3D_THRESHOLD_RELATIVE ;
5428  p=hdrl_bpm_3d_parameter_create(kappa, kappa, method) ;
5429  cpl_imagelist * out_imlist = hdrl_bpm_3d_compute(hil, p);
5430  *bpms_ptr = cpl_imagelist_collapse_create(out_imlist);
5431  cpl_msg_info(cpl_func,"BP map value: min=%g max=%g",
5432  cpl_image_get_min(*bpms_ptr),cpl_image_get_max(*bpms_ptr));
5433  */
5434  nbpixs = cpl_image_get_flux(*bpms_ptr);
5435  /* clean-up memory */
5436  hdrl_imagelist_delete(hil);
5437  cpl_imagelist_delete(linearity_scaled);
5438  cpl_vector_unwrap((cpl_vector*) x);
5439  hdrl_parameter_delete(p);
5440  // 3D method only
5441  //cpl_imagelist_delete(out_imlist);
5442  /* ORIGINAL BP MAP COMPUTATION
5443  *bpms_ptr = detmon_bpixs(*coeffs_ptr, detmon_lg_config.bpmbin,
5444  detmon_lg_config.kappa, &nbpixs);
5445  */
5446  /*
5447  *bpms_ptr = detmon_bpixs2(x,linearity_inputs,*coeffs_ptr,gain_table,
5448  detmon_lg_config.order,detmon_lg_config.bpmbin,detmon_lg_config.kappa,&nbpixs);
5449  */
5450  /*
5451  cpl_vector_unwrap((cpl_vector*)x);
5452  cpl_vector_unwrap((cpl_vector*)y);
5453  */
5454  //cpl_msg_info(cpl_func,"nbpixs=%d",nbpixs);
5455  skip_if(*bpms_ptr == NULL);
5456 
5457  end_skip;
5458  return nbpixs;
5459 }
5460 
5461 /*---------------------------------------------------------------------------*/
5475 /*---------------------------------------------------------------------------*/
5476 static cpl_error_code
5477 detmon_lg_reduce_all(const cpl_table * linear_table,
5478  cpl_propertylist * gaint_qclist,
5479  cpl_propertylist * lint_qclist,
5480  cpl_propertylist * linc_qclist,
5481  cpl_propertylist * bpm_qclist,
5482  cpl_imagelist ** coeffs_ptr,
5483  cpl_image ** bpms_ptr,
5484  const cpl_imagelist * linearity_inputs,
5485  const cpl_table * gain_table,
5486  int which_ext, cpl_boolean opt_nir)
5487 {
5488 
5489  int nbpixs = 0;
5490  const int linear_nsets = cpl_table_get_nrow(linear_table);
5491  const int gain_nsets = cpl_table_get_nrow(gain_table);
5492  double autocorr;
5493  cpl_polynomial *poly_linfit = NULL;
5494  cpl_image *fiterror = NULL;
5495  char * name_o1 = NULL;
5496  char * name_o2 = NULL;
5497  double * pcoeffs = NULL;
5498  unsigned mode = detmon_lg_config.autocorr ? IRPLIB_GAIN_WITH_AUTOCORR : 0;
5499  double min_val=0;
5500  double max_val=0;
5501  cpl_vector *x =NULL;
5502  const cpl_vector *y =NULL;
5503 
5504 
5505  const cpl_image * first = NULL;
5506  int sizex = 0;
5507  int sizey = 0;
5508 
5509  int vsize = 0;
5510  cpl_size deg=0;
5511  /* FIXME: This should go before the x and y vectors.
5512  Checking for all the inputs */
5513  cpl_ensure_code(gaint_qclist != NULL, CPL_ERROR_NULL_INPUT);
5514  cpl_ensure_code(lint_qclist != NULL, CPL_ERROR_NULL_INPUT);
5515  cpl_ensure_code(linc_qclist != NULL, CPL_ERROR_NULL_INPUT);
5516  cpl_ensure_code(bpm_qclist != NULL, CPL_ERROR_NULL_INPUT);
5517 
5518  pcoeffs = cpl_malloc(sizeof(double)*(detmon_lg_config.order + 1));
5519 
5520  skip_if(cpl_propertylist_append_string(gaint_qclist, DETMON_QC_METHOD,
5521  detmon_lg_config.method));
5522  skip_if(cpl_propertylist_set_comment(gaint_qclist, DETMON_QC_METHOD,
5523  DETMON_QC_METHOD_C));
5524 
5525 
5526  if (!strcmp(detmon_lg_config.method, "PTC")) {
5527  /* Computation of GAIN via polynomial fit */
5528  if (detmon_lg_config.exts >= 0) {
5529  cpl_msg_info(cpl_func,
5530  "Polynomial fitting for the GAIN (constant term method)");
5531  } else {
5532  cpl_msg_info(cpl_func,
5533  "Polynomial fitting for the GAIN (constant term method)"
5534  " for extension nb %d", which_ext);
5535  }
5536  skip_if(detmon_lg_qc_ptc(gain_table, gaint_qclist, mode, gain_nsets));
5537  } else {
5538  skip_if(detmon_lg_qc_med(gain_table, gaint_qclist, gain_nsets));
5539  }
5540 
5541  /*^FIXME: This shouldn't be written when no applied */
5542  /* Lamp flux */
5543  if(detmon_lg_config.lamp_ok) {
5544  skip_if(cpl_propertylist_append_double(lint_qclist, DETMON_QC_LAMP_FLUX,
5545  detmon_lg_config.cr));
5546  skip_if(cpl_propertylist_set_comment(lint_qclist, DETMON_QC_LAMP_FLUX,
5547  DETMON_QC_LAMP_FLUX_C));
5548  }
5549 
5550  /*^FIXME: This shouldn't be written when no applied */
5551  if(detmon_lg_config.autocorr == TRUE) {
5552  autocorr = cpl_table_get_column_median(gain_table, "AUTOCORR");
5553  skip_if(cpl_propertylist_append_double(gaint_qclist, DETMON_QC_AUTOCORR,
5554  autocorr));
5555  skip_if(cpl_propertylist_set_comment(gaint_qclist, DETMON_QC_AUTOCORR,
5556  DETMON_QC_AUTOCORR_C));
5557  }
5558  if (detmon_lg_config.exts >= 0) {
5559  cpl_msg_info(cpl_func, "Polynomial fitting pix-to-pix");
5560  } else {
5561  cpl_msg_info(cpl_func, "Polynomial fitting pix-to-pix"
5562  " for extension nb %d", which_ext);
5563  }
5564 
5565  if(!detmon_lg_config.pix2pix) {
5566  const int order=detmon_lg_config.order;
5567 
5568 
5569 
5570 
5571 
5572  double mse = 0;
5573  /* Computation of LINEARITY via polynomial fit */
5574  y = cpl_vector_wrap(linear_nsets,
5575  (double *)cpl_table_get_data_double_const(linear_table,
5576  "MED"));
5577 
5578  if (opt_nir == NIR) {
5579  x = cpl_vector_wrap(linear_nsets,
5580  (double *)cpl_table_get_data_double_const(linear_table,
5581  "DIT"));
5582  } else {
5583  x = cpl_vector_wrap(linear_nsets,
5584  (double *)cpl_table_get_data_double_const(linear_table,
5585  "EXPTIME"));
5586  }
5587 
5588  if(x == NULL || y == NULL) {
5589  cpl_vector_unwrap((cpl_vector *)x);
5590  cpl_vector_unwrap((cpl_vector *)y);
5591  /*
5592  * As x and y are const vectors, if they would be defined at the
5593  * beginning of the function (required for skip_if - end_skip
5594  * scheme), they couldn't be initialised to NULL (required too).
5595  * Therefore, they are considered apart from the scheme.
5596  */
5597  skip_if(1);
5598  }
5599 
5600  cpl_msg_info(cpl_func, "Polynomial fitting for the LINEARITY");
5601  poly_linfit = irplib_polynomial_fit_1d_create(x, y,order,&mse);
5602 
5603  if(order == cpl_vector_get_size(x) - 1) {
5604  cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
5605  mse = 0;
5606  }
5607 
5608  if(poly_linfit == NULL) {
5609  cpl_vector_unwrap((cpl_vector *)x);
5610  cpl_vector_unwrap((cpl_vector *)y);
5611  /* See comment in previous error checking if() statement */
5612  skip_if(1);
5613  }
5614 
5615 
5616  min_val=cpl_vector_get_min(y);
5617  max_val=cpl_vector_get_max(y);
5618 
5619  cpl_vector_unwrap((cpl_vector *)x);
5620  cpl_vector_unwrap((cpl_vector *)y);
5621 
5622  for(deg = 0; deg <= order; deg++) {
5623  const double coeff =
5624  cpl_polynomial_get_coeff(poly_linfit, &deg);
5625  char *name_o =
5626  cpl_sprintf("ESO QC LIN COEF%" CPL_SIZE_FORMAT "", deg);
5627  assert(name_o != NULL);
5628  skip_if(cpl_propertylist_append_double(lint_qclist, name_o, coeff));
5629  skip_if(cpl_propertylist_set_comment(lint_qclist,name_o,
5630  DETMON_QC_LIN_COEF_C));
5631 
5632  cpl_free(name_o);
5633  pcoeffs[deg] = coeff;
5634  }
5635  skip_if(cpl_propertylist_append_double(lint_qclist,DETMON_QC_ERRFIT, mse));
5636  skip_if(cpl_propertylist_set_comment(lint_qclist,DETMON_QC_ERRFIT,
5637  DETMON_QC_ERRFIT_MSE_C));
5638 
5639 
5640  } else {
5641  const int order=detmon_lg_config.order;
5642  /* pix2pix == TRUE */
5643  y = cpl_vector_wrap(linear_nsets,
5644  (double *)cpl_table_get_data_double_const(linear_table,
5645  "MED"));
5646 
5647  if (opt_nir == NIR)
5648  {
5649  x = cpl_vector_wrap(linear_nsets,
5650  (double *)cpl_table_get_data_double_const(linear_table,
5651  "DIT"));
5652  } else {
5653  x = cpl_vector_wrap(linear_nsets,
5654  (double *)cpl_table_get_data_double_const(linear_table,
5655  "EXPTIME"));
5656 
5657  }
5658 
5659  first = cpl_imagelist_get_const(linearity_inputs, 0);
5660  sizex = cpl_image_get_size_x(first);
5661  sizey = cpl_image_get_size_y(first);
5662  vsize = cpl_vector_get_size(x);
5663  fiterror = cpl_image_new(sizex, sizey, CPL_TYPE_FLOAT);
5664  *coeffs_ptr =
5665  cpl_fit_imagelist_polynomial(x, linearity_inputs, 0,order, FALSE,
5666  CPL_TYPE_FLOAT, fiterror);
5667  min_val=cpl_vector_get_min(y);
5668  max_val=cpl_vector_get_max(y);
5669  cpl_vector_unwrap((cpl_vector*)x);
5670  cpl_vector_unwrap((cpl_vector*)y);
5671 
5672  irplib_ensure(*coeffs_ptr != NULL, CPL_ERROR_UNSPECIFIED,
5673  "Failed polynomial fit");
5674  //detmon_lg_qclog_lin_coeff(*coeffs_ptr, order,linc_qclist);
5675 
5676  for(deg = 0; deg <= order; deg++)
5677  {
5678  cpl_image *image = cpl_imagelist_get(*coeffs_ptr, deg);
5679  const double coeff = cpl_image_get_median(image);
5680  pcoeffs[deg] = coeff;
5681  name_o1 = cpl_sprintf("ESO QC LIN COEF%d", (int)deg);
5682  name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", (int)deg);
5683  assert(name_o1 != NULL);
5684  assert(name_o2 != NULL);
5685  skip_if(cpl_propertylist_append_double(linc_qclist, name_o1, coeff));
5686  skip_if(cpl_propertylist_set_comment(linc_qclist,name_o1,
5687  DETMON_QC_LIN_COEF_C));
5688  cpl_free(name_o1);
5689  name_o1= NULL;
5690  skip_if(cpl_propertylist_append_double(linc_qclist, name_o2,
5691  cpl_image_get_stdev(image)));
5692  skip_if(cpl_propertylist_set_comment(linc_qclist,name_o2,
5693  DETMON_QC_LIN_COEF_ERR_C));
5694  cpl_free(name_o2);
5695  name_o2= NULL;
5696  }
5697 
5698 
5699  if(order == vsize - 1)
5700  {
5701  cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
5702  skip_if(cpl_propertylist_append_double(linc_qclist,DETMON_QC_ERRFIT,
5703  0.0));
5704  skip_if(cpl_propertylist_set_comment(linc_qclist,DETMON_QC_ERRFIT,
5705  DETMON_QC_ERRFIT_C));
5706  } else
5707  {
5708  skip_if(cpl_propertylist_append_double(linc_qclist,DETMON_QC_ERRFIT,
5709  cpl_image_get_median(fiterror)));
5710  skip_if(cpl_propertylist_set_comment(linc_qclist,DETMON_QC_ERRFIT,
5711  DETMON_QC_ERRFIT_C));
5712  }
5713  } /* end case pix2pix == TRUE */
5714 
5715  skip_if(cpl_propertylist_append_double(lint_qclist,DETMON_QC_COUNTS_MIN,
5716  min_val));
5717  skip_if(cpl_propertylist_set_comment(lint_qclist,DETMON_QC_COUNTS_MIN,
5718  DETMON_QC_COUNTS_MIN_C));
5719  skip_if(cpl_propertylist_append_double(lint_qclist,DETMON_QC_COUNTS_MAX,
5720  max_val));
5721  skip_if(cpl_propertylist_set_comment(lint_qclist,DETMON_QC_COUNTS_MAX,
5722  DETMON_QC_COUNTS_MAX_C));
5723  skip_if(detmon_lg_lineff(pcoeffs,lint_qclist,detmon_lg_config.ref_level,
5724  detmon_lg_config.order));
5725  /* Detection of bad pixels */
5726  if (detmon_lg_config.exts >= 0)
5727  {
5728  cpl_msg_info(cpl_func, "Bad pixel detection");
5729  } else
5730  {
5731  cpl_msg_info(cpl_func, "Bad pixel detection"
5732  " for extension nb %d", which_ext);
5733  }
5734  if(detmon_lg_config.pix2pix)
5735  {
5736 
5737  /* Determines bad pixel map */
5738  nbpixs = detmon_compute_badpixmap(opt_nir, linear_nsets, linear_table,
5739  linearity_inputs, nbpixs, x,gaint_qclist, bpms_ptr);
5740  /* we still have to unwrapp x & y that we kept for bpixs2 function */
5741  }
5742 
5743 
5744  skip_if(cpl_propertylist_append_int(bpm_qclist, DETMON_QC_NUM_BPM, nbpixs));
5745  skip_if(cpl_propertylist_set_comment(bpm_qclist, DETMON_QC_NUM_BPM,
5746  DETMON_QC_NUM_BPM_C));
5747  cpl_msg_info(cpl_func,"stability=%g",detmon_lg_config.lamp_stability);
5748  if(detmon_lg_config.lamp_stability != 0.0)
5749  {
5750  skip_if(cpl_propertylist_append_double(lint_qclist, DETMON_QC_LAMP_STAB,
5751  detmon_lg_config.lamp_stability));
5752  skip_if(cpl_propertylist_set_comment(lint_qclist, DETMON_QC_LAMP_STAB,
5753  DETMON_QC_LAMP_STAB_C));
5754  }
5755  /* Fit COEFFS_CUBE and BPM outputs to whole-chip size images (DFS05711) */
5756  if (!detmon_lg_config.wholechip && detmon_lg_config.pix2pix)
5757  {
5758  detmon_lg_fits_coeffs_and_bpm2chip(coeffs_ptr,bpms_ptr);
5759  }
5760  end_skip;
5761 
5762  cpl_free(pcoeffs);
5763  cpl_free(name_o1);
5764  cpl_free(name_o2);
5765  cpl_image_delete(fiterror);
5766  cpl_polynomial_delete(poly_linfit);
5767 
5768 
5769 
5770  return cpl_error_get_code();
5771 }
5772 
5773 /*---------------------------------------------------------------------------*/
5781 /*---------------------------------------------------------------------------*/
5782 static cpl_error_code
5783 detmon_lg_lineff(double * pcoeffs,
5784  cpl_propertylist * qclist,
5785  int ref_level,
5786  int order)
5787 {
5788  double lineff = 0;
5789  double root = 0;
5790  double residual, slope;
5791  int i;
5792  cpl_size deg=0;
5793  cpl_polynomial * poly = cpl_polynomial_new(1);
5794 
5795 
5796  /*
5797  * Construction of the polynomial F_m(F_r) from F_m(t),
5798  * using F_r = a_1 * t.
5799  */
5800  /*
5801  for (deg = 0; deg <= order; deg++) {
5802  cpl_msg_info(cpl_func,"coef[%d]=%g",deg,pcoeffs[deg]);
5803  }
5804  */
5805 
5806 
5807  pcoeffs[0] -= ref_level;
5808 
5809  for (i = 2; i <= order; i++)
5810  {
5811  int j;
5812  for(j = 0; j < i; j++)
5813  {
5814  pcoeffs[i] /= pcoeffs[1];
5815  }
5816  }
5817 
5818  pcoeffs[1] = 1;
5819 
5820  for (deg = 0; deg <= order; deg++) {
5821  /*cpl_msg_info(cpl_func,"coef[%d]=%g",deg,pcoeffs[deg]);*/
5822  skip_if(cpl_polynomial_set_coeff(poly, &deg, pcoeffs[deg]));
5823  }
5824 
5825  /*
5826  * Verification of validity of first guess (0).
5827  * The root to be found will be in the same interval of monotony
5828  * of the first guess; therefore, slope must be greater than 0.
5829  * Slope > 0 and poly(root) = 0 force also residual to be negative.
5830  */
5831  residual = cpl_polynomial_eval_1d(poly, 0.0, &slope);
5832 
5833  if (slope <= 0.0 && residual >= 0.0) {
5834  cpl_msg_warning(cpl_func, "Reference level (--ref_level) outside"
5835  " linearity range of the detector. Cannot compute"
5836  " linearity efficiency (QC.LINEFF).");
5837  lineff = -1;
5838  }
5839  else
5840  {
5841  cpl_error_code err = cpl_polynomial_solve_1d(poly, 0.0, &root, 1);
5842  /*
5843  cpl_msg_info(cpl_func,"root=%g ref_level=%d lin_eff=%d",
5844  root,ref_level,ref_level);
5845  */
5846  if (err == CPL_ERROR_NONE)
5847  {
5848 
5849  lineff = (root - ref_level) / ref_level;
5850  }
5851  else
5852  {
5853  cpl_error_reset();
5854  cpl_msg_warning(cpl_func,
5855  "Cannot compute linearity efficiency (QC.LINEFF)"
5856  "for the current combination "
5857  " of (--ref-level equal %d) and (--order equal %d) parameters. Try "
5858  "to decrease (--ref-level) value.", ref_level, order);
5859  }
5860  }
5861  cpl_msg_warning(cpl_func, "DETMON_QC_LIN_EFF=%f",lineff );
5862  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LIN_EFF,
5863  lineff));
5864  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LIN_EFF,
5865  DETMON_QC_LIN_EFF_C));
5866 
5867  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LIN_EFF_FLUX,
5868  ref_level));
5869  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LIN_EFF_FLUX,
5870  DETMON_QC_LIN_EFF_FLUX_C));
5871 
5872  end_skip;
5873 
5874  cpl_polynomial_delete(poly);
5875 
5876  return cpl_error_get_code();
5877 }
5878 
5879 /*---------------------------------------------------------------------------*/
5886 /*---------------------------------------------------------------------------*/
5887 static cpl_error_code
5888 detmon_lg_qc_ptc(const cpl_table * gain_table,
5889  cpl_propertylist * qclist, unsigned mode, int rows_in_gain)
5890 {
5891  double mse = 0;
5892  cpl_polynomial *poly_fit = NULL;
5893  cpl_polynomial *poly_fit2 = NULL;
5894  cpl_size i;
5895  const int nsets = rows_in_gain;
5896 
5897  cpl_vector *x = NULL;
5898  cpl_vector *y = NULL;
5899 
5900  cpl_errorstate prestate;
5901  double coef = 0;
5902  cpl_ensure_code(gain_table != NULL, CPL_ERROR_NULL_INPUT);
5903  cpl_ensure_code(qclist != NULL, CPL_ERROR_NULL_INPUT);
5904 
5905  x = cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT"));
5906 
5907  y = cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
5908 
5909  skip_if(x == NULL || y == NULL);
5910  if (0 == detmon_lg_check_before_gain(x, y))
5911  {
5912  if (x)
5913  {
5914  cpl_vector_unwrap(x);
5915  }
5916  if (y)
5917  {
5918  cpl_vector_unwrap(y);
5919  }
5920  return CPL_ERROR_NONE;
5921  }
5922  /*it is not really a MSE, but chi square of the fit, see cpl_vector_fill_polynomial_fit_residual for details*/
5923  poly_fit = irplib_polynomial_fit_1d_create_chiq(x, y, 1, &mse);
5924  skip_if(poly_fit == NULL);
5925 
5926  /* Write the QC params corresponding to the fitting of the GAIN */
5927  i = 1;
5928  prestate = cpl_errorstate_get();
5929  coef = cpl_polynomial_get_coeff(poly_fit, &i);
5930  skip_if (!cpl_errorstate_is_equal(prestate) || coef==0);
5931  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD, coef));
5932  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD,
5933  DETMON_QC_CONAD_C));
5934  if (coef != 0)
5935  {
5936  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN,
5937  1 / coef));
5938  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN,
5939  DETMON_QC_GAIN_C));
5940  }
5941  /* MSE is removed - see DFS07358 for details
5942  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_MSE, mse));
5943  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_MSE,
5944  DETMON_QC_GAIN_MSE_C));
5945  */
5946  i = 0;
5947  /* QC.RON computation is disabled, see DFS05852 for details*/
5948 
5949  /* * skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_RON,
5950  cpl_polynomial_get_coeff(poly_fit, &i)));
5951  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_RON,
5952  DETMON_QC_RON_C));
5953  */
5954  if(mode & IRPLIB_GAIN_WITH_AUTOCORR){
5955  const cpl_vector *x2 =
5956  cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT_CORR"));
5957  const cpl_vector *y2 =
5958  cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
5959 
5960  if(x2 == NULL || y2 == NULL) {
5961  cpl_vector_unwrap((cpl_vector *)x2);
5962  cpl_vector_unwrap((cpl_vector *)y2);
5963  /*
5964  * As x and y are const vectors, if they would be defined at the
5965  * beginning of the function (required for skip_if - end_skip
5966  * scheme), they couldn't be initialised to NULL (required too).
5967  * Therefore, they are considered apart from the scheme.
5968  */
5969  skip_if(1);
5970  }
5971 
5972  /* Revise mse, maybe used afterwards */
5973  poly_fit2 = irplib_polynomial_fit_1d_create(x2, y2, 1, &mse);
5974  if(poly_fit2 == NULL) {
5975  cpl_vector_unwrap((cpl_vector *)x2);
5976  cpl_vector_unwrap((cpl_vector *)y2);
5977 
5978  cpl_msg_error(cpl_func, "Error during polynomial fit, err[%s]", cpl_error_get_where());
5979  /* See comment in previous error checking if() statement */
5980  skip_if(1);
5981  }
5982  skip_if(cpl_error_get_code() != CPL_ERROR_NONE);
5983  cpl_vector_unwrap((cpl_vector *)x2);
5984  cpl_vector_unwrap((cpl_vector *)y2);
5985  skip_if(cpl_error_get_code() != CPL_ERROR_NONE);
5986  /* Write the QC params corresponding to the fitting of the GAIN */
5987  i = 1;
5988  prestate = cpl_errorstate_get();
5989  coef = cpl_polynomial_get_coeff(poly_fit2, &i);
5990  skip_if(cpl_error_get_code() != CPL_ERROR_NONE);
5991  skip_if (!cpl_errorstate_is_equal(prestate) || coef == 0);
5992 
5993  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD_CORR,
5994  coef));
5995  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD_CORR,
5996  DETMON_QC_CONAD_CORR_C));
5997 
5998  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_CORR,
5999  1 / coef));
6000  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_CORR,
6001  DETMON_QC_GAIN_CORR_C));
6002  }
6003 
6004  end_skip;
6005 
6006  /*cleanup*/
6007  cpl_vector_unwrap(x);
6008  cpl_vector_unwrap(y);
6009  cpl_polynomial_delete(poly_fit);
6010  cpl_polynomial_delete(poly_fit2);
6011 
6012  return cpl_error_get_code();
6013 }
6014 
6021 static int detmon_lg_check_before_gain(const cpl_vector* x, const cpl_vector* y)
6022 {
6023  const double TOLERANCE = 1e-37;/*MINDOUBLE is not everywhere defined (Mac);*/
6024  double xmin = cpl_vector_get_min(x);
6025  double xmax = cpl_vector_get_max(x);
6026  double ymin = cpl_vector_get_min(y);
6027  double ymax = cpl_vector_get_max(y);
6028  double ystdev = cpl_vector_get_stdev(y);
6029  double xstdev = cpl_vector_get_stdev(x);
6030  int retval = 1;
6031  if (fabs(xmax-xmin) < TOLERANCE &&
6032  fabs(ymax - ymin) < TOLERANCE &&
6033  xstdev < TOLERANCE &&
6034  ystdev < TOLERANCE)
6035  {
6036  cpl_msg_warning(cpl_func, "An empty frame has been detected, linearity, coeffs, gain, FPN values will not be computed.");
6037  retval = 0;
6038  }
6039  return retval;
6040 }
6041 /*---------------------------------------------------------------------------*/
6050 /*---------------------------------------------------------------------------*/
6051 static cpl_error_code
6052 detmon_lg_qc_med(const cpl_table * gain_table,
6053  cpl_propertylist * qclist, int rows_in_gain)
6054 {
6055 
6056  double gain=0;
6057  cpl_vector *x = NULL;
6058  cpl_vector *y = NULL;
6059  int check_result = 0;
6060 
6061  if (rows_in_gain) {/* silence unused var */};
6062 
6063  x = cpl_vector_wrap(rows_in_gain, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT"));
6064  y = cpl_vector_wrap(rows_in_gain, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
6065  check_result = detmon_lg_check_before_gain(x, y);
6066  if (x)
6067  {
6068  cpl_vector_unwrap(x);
6069  }
6070  if (y)
6071  {
6072  cpl_vector_unwrap(y);
6073  }
6074  if (0 == check_result)
6075  {
6076  return CPL_ERROR_NONE;
6077  }
6078 
6079  gain=cpl_table_get_column_median(gain_table, "GAIN");
6080 
6081  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN,gain));
6082 
6083  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN,
6084  DETMON_QC_GAIN_C));
6085 
6086  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_MSE,
6087  cpl_table_get_column_stdev
6088  (gain_table, "GAIN")));
6089  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_MSE,
6090  DETMON_QC_GAIN_MSE_C));
6091 
6092  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD,1./gain));
6093  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD,
6094  DETMON_QC_CONAD_C));
6095 
6096 
6097  gain=cpl_table_get_column_median(gain_table, "GAIN_CORR");
6098 
6099  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_CORR,
6100  gain));
6101  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_CORR,
6102  DETMON_QC_GAIN_CORR_C));
6103 
6104 
6105  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD_CORR,1./gain));
6106  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD_CORR,
6107  DETMON_QC_CONAD_CORR_C));
6108 
6109 
6110  end_skip;
6111 
6112  return cpl_error_get_code();
6113 }
6114 
6115 
6116 /*---------------------------------------------------------------------------*/
6125 /*---------------------------------------------------------------------------*/
6126 static cpl_error_code
6127 detmon_lg_rescale(cpl_imagelist * to_rescale)
6128 {
6129  double med1 =
6130  cpl_image_get_median_window(cpl_imagelist_get(to_rescale, 0),
6131  detmon_lg_config.llx,
6132  detmon_lg_config.lly,
6133  detmon_lg_config.urx,
6134  detmon_lg_config.ury);
6135  double med2 =
6136  cpl_image_get_median_window(cpl_imagelist_get(to_rescale, 1),
6137  detmon_lg_config.llx,
6138  detmon_lg_config.lly,
6139  detmon_lg_config.urx,
6140  detmon_lg_config.ury);
6141 
6142  skip_if(0);
6143 
6144  if(fabs(med1 / med2 - 1) > 0.001) {
6145  if(med1 > med2)
6146  skip_if(cpl_image_divide_scalar(cpl_imagelist_get(to_rescale, 0),
6147  med1 / med2));
6148  else
6149  skip_if(cpl_image_divide_scalar(cpl_imagelist_get(to_rescale, 1),
6150  med2 / med1));
6151  }
6152 
6153  end_skip;
6154 
6155  return cpl_error_get_code();
6156 }
6157 
6158 static cpl_error_code
6159 detmon_pair_extract_next(const cpl_frameset * set,
6160  int* iindex,
6161  int* next_element,
6162  double* dit_array,
6163  cpl_frameset ** pair,
6164  double tolerance) /* detmon_lg_config.tolerance */
6165 {
6166  double dit = -100;
6167  double dit_next = -100;
6168  cpl_size* selection;
6169  int nsets_extracted = 0;
6170  cpl_ensure_code(set != NULL, CPL_ERROR_NULL_INPUT);
6171  cpl_ensure_code(dit_array != NULL, CPL_ERROR_NULL_INPUT);
6172  cpl_ensure_code(iindex != NULL, CPL_ERROR_NULL_INPUT);
6173  cpl_ensure_code(pair != NULL, CPL_ERROR_NULL_INPUT);
6174 
6175  nsets_extracted = cpl_frameset_get_size(set);
6176  selection = cpl_malloc(sizeof(cpl_size) * nsets_extracted);
6177  memset(&selection[0], 0, sizeof(cpl_size) * nsets_extracted);
6178 
6179 
6180  dit = dit_array[*next_element ];
6181  /* cpl_msg_info(cpl_func, "%d: dit %f",*next_element, dit ); */
6182  if (*next_element < nsets_extracted - 1)
6183  {
6184  dit_next = dit_array[*next_element + 1 ];
6185  /* cpl_msg_info(cpl_func, "%d: dit %f",*next_element + 1, dit_next ); */
6186  }
6187  /* one element would be returned always */
6188  selection[iindex[*next_element] ] = 1;
6189  if (fabs(dit - dit_next) < tolerance)
6190  {
6191  /* return a second element of the pair */
6192  selection[iindex[*next_element + 1] ] = 1;
6193  (*next_element)++;
6194  }
6195  else
6196  {
6197  cpl_msg_warning(cpl_func, "DIT for the second frame in the pair is above tolerance level - could not be taken, dit1[%f] dit2[%f] next_element: %d . Check input data set and tolerance value", dit, dit_next, *next_element);
6198  }
6199  (*next_element)++;
6200  /* prepare frameset */
6201  cpl_frameset_delete(*pair);
6202  *pair = cpl_frameset_extract(set, selection, 1);
6203 
6204 
6205  cpl_free(selection);
6206  return cpl_error_get_code();
6207 }
6208 
6209 static cpl_error_code
6210 detmon_single_extract_next(const cpl_frameset * set,
6211  int* iindex,
6212  int* next_element,
6213  double* dit_array,
6214  cpl_frameset ** pair)
6215 {
6216  cpl_size* selection;
6217  int nsets_extracted = 0;
6218  cpl_ensure_code(set != NULL, CPL_ERROR_NULL_INPUT);
6219  cpl_ensure_code(dit_array != NULL, CPL_ERROR_NULL_INPUT);
6220  cpl_ensure_code(iindex != NULL, CPL_ERROR_NULL_INPUT);
6221  cpl_ensure_code(pair != NULL, CPL_ERROR_NULL_INPUT);
6222 
6223  nsets_extracted = cpl_frameset_get_size(set);
6224  selection = cpl_malloc(sizeof(cpl_size) * nsets_extracted);
6225  memset(&selection[0], 0, sizeof(cpl_size) * nsets_extracted);
6226 
6227  /* only one element would be returned */
6228  selection[iindex[*next_element] ] = 1;
6229  (*next_element)++;
6230  /* prepare frameset */
6231  cpl_frameset_delete(*pair);
6232  *pair = cpl_frameset_extract(set, selection, 1);
6233 
6234  cpl_free(selection);
6235  return cpl_error_get_code();
6236 }
6237 
6238 
6239 /*---------------------------------------------------------------------------*/
6330 /*---------------------------------------------------------------------------*/
6331 
6332 cpl_table *
6333 detmon_gain(const cpl_imagelist * imlist_on,
6334  const cpl_imagelist * imlist_off,
6335  const cpl_vector * exptimes,
6336  const cpl_vector * ndit,
6337  double tolerance,
6338  int llx,
6339  int lly,
6340  int urx,
6341  int ury,
6342  double kappa,
6343  int nclip,
6344  int xshift,
6345  int yshift,
6346  cpl_propertylist * qclist,
6347  unsigned mode,
6348  cpl_imagelist ** diff_imlist,
6349  cpl_imagelist ** autocorr_imlist)
6350 {
6351  cpl_table * gain_table = NULL;
6352  cpl_imagelist * difflist = NULL;
6353  cpl_imagelist * autocorrlist = NULL;
6354  cpl_imagelist * c_onlist = NULL;
6355  cpl_imagelist * c_offlist = NULL;
6356  cpl_vector * diffdits = NULL;
6357  cpl_vector * diffndits = NULL;
6358  int rows_in_gain = 0;
6359  int ndiffdits, ndits;
6360  int i, j;
6361  cpl_boolean opt_nir = mode & IRPLIB_GAIN_OPT ? OPT : NIR;
6362  const char * method = mode & IRPLIB_GAIN_PTC ? "PTC" : "MED";
6363 
6364  cpl_ensure(imlist_on != NULL, CPL_ERROR_NULL_INPUT, NULL);
6365  cpl_ensure(imlist_off != NULL, CPL_ERROR_NULL_INPUT, NULL);
6366  cpl_ensure(exptimes != NULL, CPL_ERROR_NULL_INPUT, NULL);
6367  cpl_ensure(qclist != NULL, CPL_ERROR_NULL_INPUT, NULL);
6368 
6369  /* Create table with columns */
6370  gain_table = cpl_table_new(cpl_vector_get_size(exptimes) / 2);
6371  skip_if(detmon_gain_table_create(gain_table, opt_nir));
6372 
6373 
6374  /* Search for different EXPTIME values */
6375  skip_if(detmon_lg_find_dits_ndits(exptimes, ndit,tolerance,&diffdits,
6376  &diffndits));
6377  ndiffdits = cpl_vector_get_size(diffdits);
6378 
6379  ndits = cpl_vector_get_size(exptimes);
6380 
6381  /* AUTOCORR processing requires both. They will become outputs later. */
6382  if (mode & IRPLIB_GAIN_WITH_AUTOCORR && (diff_imlist || autocorr_imlist)) {
6383  difflist = cpl_imagelist_new();
6384  autocorrlist = cpl_imagelist_new();
6385  }
6386 
6387  if (mode & IRPLIB_GAIN_COLLAPSE) {
6388  if (mode & IRPLIB_GAIN_WITH_RESCALE) {
6389  c_offlist = cpl_imagelist_duplicate(imlist_off);
6390  skip_if(detmon_lg_rescale(c_offlist));
6391  } else {
6392  c_offlist = (cpl_imagelist *) imlist_off;
6393  }
6394  }
6395 
6396  /* Loop over the different DITs found in EXPTIMEs */
6397  for (i = 0; i < ndiffdits; i++) {
6398  int c_nons;
6399  int c_noffs = 0; /* False (uninit) warning */
6400 
6401  double c_dit = 0;
6402  int c_ndit = 1;
6403 
6404  c_dit=cpl_vector_get(diffdits, i);
6405 
6406  if(opt_nir) {
6407  c_ndit=(int)cpl_vector_get(diffndits, i);
6408  }
6409 
6410  c_onlist = cpl_imagelist_new();
6411  c_nons = 0;
6412 
6413  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
6414  c_offlist = cpl_imagelist_new();
6415  c_noffs = 0;
6416  }
6417 
6418  /* Extraction of images of EXPTIME i */
6419  for(j = 0; j < ndits; j++) {
6420  if (fabs(c_dit - cpl_vector_get(exptimes, j)) <= tolerance) {
6421  /*
6422  * First we get the corresponding image from the ON imlist.
6423  * The option IRPLIB_GAIN_WITH_RESCALE requires to modify
6424  * the input pixel buffer; therefore we must duplicate it.
6425  * On the other hand, if this option is not required, there
6426  * is no need for that duplication. We must only care that
6427  * c_onlist must not be deleted but only unset.
6428  */
6429  cpl_image * im_on;
6430  if (mode & IRPLIB_GAIN_WITH_RESCALE) {
6431  const cpl_image * im =
6432  cpl_imagelist_get_const(imlist_on, j);
6433  im_on = cpl_image_duplicate(im);
6434  } else {
6435  im_on = (cpl_image *)cpl_imagelist_get_const(imlist_on, j);
6436  }
6437  skip_if(cpl_imagelist_set(c_onlist, im_on, c_nons));
6438  c_nons++;
6439 
6440  /*
6441  * Same explanation as above but for OFF imlist.
6442  * Only necessary when IRPLIB_GAIN_NO_COLLAPSE required.
6443  */
6444  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
6445  cpl_image * im_off;
6446  if (mode & IRPLIB_GAIN_WITH_RESCALE) {
6447  const cpl_image * im =
6448  cpl_imagelist_get_const(imlist_off, j);
6449  im_off = cpl_image_duplicate(im);
6450  } else {
6451  im_off =
6452  (cpl_image *) cpl_imagelist_get_const(imlist_off, j);
6453  }
6454  skip_if(cpl_imagelist_set(c_offlist, im_off, c_noffs));
6455  c_noffs++;
6456  }
6457  }
6458  }
6459 
6460  /* If NO_COLLAPSE, must be the same number of images! */
6461  if (mode & IRPLIB_GAIN_NO_COLLAPSE)
6462  skip_if (c_nons != c_noffs);
6463 
6464  /* There must be pairs! */
6465  skip_if (c_nons == 0 || c_nons % 2 != 0);
6466 
6467  /* Rescaling */
6468  if(mode & IRPLIB_GAIN_WITH_RESCALE) {
6469  skip_if(detmon_lg_rescale(c_onlist));
6470  if (mode & IRPLIB_GAIN_NO_COLLAPSE)
6471  skip_if(detmon_lg_rescale(c_offlist));
6472  }
6473 
6474  /* The following loop is necessary for the case of multiple pairs
6475  of same EXPTIME values */
6476  while(c_nons > 0) {
6477  int rows_affected = 1;
6478  skip_if(detmon_gain_table_fill_row(gain_table,
6479  c_dit,c_ndit,
6480  autocorrlist,
6481  difflist, c_onlist,
6482  c_offlist, kappa, nclip,
6483  llx, lly, urx, ury,
6484  xshift, yshift, 1E10, i,
6485  mode, &rows_affected));
6486  if (rows_affected)
6487  {
6488  rows_in_gain++;
6489  }
6490  if (mode & IRPLIB_GAIN_WITH_RESCALE) {
6491  cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
6492  cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
6493  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
6494  cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
6495  cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
6496  }
6497  } else {
6498  cpl_imagelist_unset(c_onlist, 0);
6499  skip_if(0);
6500  cpl_imagelist_unset(c_onlist, 0);
6501  skip_if(0);
6502  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
6503  cpl_imagelist_unset(c_offlist, 0);
6504  skip_if(0);
6505  cpl_imagelist_unset(c_offlist, 0);
6506  skip_if(0);
6507  }
6508  }
6509  skip_if(0);
6510  c_nons -= 2;
6511  }
6512 
6513  cpl_imagelist_delete(c_onlist);
6514  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
6515  cpl_imagelist_delete(c_offlist);
6516  }
6517  }
6518 
6519  skip_if(cpl_propertylist_append_string(qclist, DETMON_QC_METHOD, method));
6520  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_METHOD,
6521  DETMON_QC_METHOD_C));
6522 
6523  /* Computation of GAIN via polynomial fit */
6524  if (mode & IRPLIB_GAIN_PTC) {
6525  skip_if(detmon_lg_qc_ptc(gain_table, qclist, mode, rows_in_gain));
6526  } else {
6527  skip_if(detmon_lg_qc_med(gain_table, qclist, rows_in_gain));
6528  }
6529 
6530  if(mode & IRPLIB_GAIN_WITH_AUTOCORR) {
6531  double autocorr = cpl_table_get_column_median(gain_table, "AUTOCORR");
6532  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_AUTOCORR,
6533  autocorr));
6534  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_AUTOCORR,
6535  DETMON_QC_AUTOCORR_C));
6536  }
6537 
6538  if (diff_imlist != NULL) *diff_imlist = difflist;
6539  if (autocorr_imlist != NULL) *autocorr_imlist = autocorrlist;
6540 
6541  end_skip;
6542 
6543  cpl_vector_delete(diffdits);
6544  cpl_vector_delete(diffndits);
6545 
6546  return gain_table;
6547 }
6548 
6549 static cpl_error_code
6550 detmon_gain_table_create(cpl_table * gain_table,
6551  const cpl_boolean opt_nir)
6552 {
6553  if (opt_nir == NIR) {
6554  skip_if(cpl_table_new_column(gain_table, "DIT", CPL_TYPE_DOUBLE));
6555  skip_if(cpl_table_new_column(gain_table, "NDIT", CPL_TYPE_INT));
6556  } else { /* OPT */
6557  skip_if(cpl_table_new_column(gain_table, "EXPTIME", CPL_TYPE_DOUBLE));
6558  }
6559  skip_if(cpl_table_new_column(gain_table, "MEAN_ON1", CPL_TYPE_DOUBLE));
6560  skip_if(cpl_table_new_column(gain_table, "MEAN_ON2", CPL_TYPE_DOUBLE));
6561  skip_if(cpl_table_new_column(gain_table, "MEAN_OFF1", CPL_TYPE_DOUBLE));
6562  skip_if(cpl_table_new_column(gain_table, "MEAN_OFF2", CPL_TYPE_DOUBLE));
6563  skip_if(cpl_table_new_column(gain_table, "SIG_ON_DIF", CPL_TYPE_DOUBLE));
6564  skip_if(cpl_table_new_column(gain_table, "SIG_OFF_DIF", CPL_TYPE_DOUBLE));
6565  skip_if(cpl_table_new_column(gain_table, "GAIN", CPL_TYPE_DOUBLE));
6566  skip_if(cpl_table_new_column(gain_table, "AUTOCORR", CPL_TYPE_DOUBLE));
6567  skip_if(cpl_table_new_column(gain_table, "GAIN_CORR", CPL_TYPE_DOUBLE));
6568  skip_if(cpl_table_new_column(gain_table, "ADU", CPL_TYPE_DOUBLE));
6569  skip_if(cpl_table_new_column(gain_table, "X_FIT", CPL_TYPE_DOUBLE));
6570  skip_if(cpl_table_new_column(gain_table, "X_FIT_CORR", CPL_TYPE_DOUBLE));
6571  skip_if(cpl_table_new_column(gain_table, "Y_FIT", CPL_TYPE_DOUBLE));
6572  skip_if(cpl_table_new_column(gain_table, "Y_FIT_CORR", CPL_TYPE_DOUBLE));
6573  skip_if(cpl_table_new_column(gain_table, "FLAG", CPL_TYPE_INT));
6574 
6575  end_skip;
6576 
6577  return cpl_error_get_code();
6578 }
6579 
6580 static cpl_error_code
6581 detmon_lin_table_create(cpl_table * lin_table,
6582  const cpl_boolean opt_nir)
6583 {
6584  if (opt_nir == NIR) {
6585  skip_if(cpl_table_new_column(lin_table, "DIT", CPL_TYPE_DOUBLE));
6586  } else { /* OPT */
6587  skip_if(cpl_table_new_column(lin_table, "EXPTIME", CPL_TYPE_DOUBLE));
6588  }
6589  skip_if(cpl_table_new_column(lin_table, "MED", CPL_TYPE_DOUBLE));
6590  skip_if(cpl_table_new_column(lin_table, "MEAN", CPL_TYPE_DOUBLE));
6591  skip_if(cpl_table_new_column(lin_table, "MED_DIT", CPL_TYPE_DOUBLE));
6592  skip_if(cpl_table_new_column(lin_table, "MEAN_DIT", CPL_TYPE_DOUBLE));
6593  skip_if(cpl_table_new_column(lin_table, "ADL", CPL_TYPE_DOUBLE));
6594  end_skip;
6595 
6596  return cpl_error_get_code();
6597 }
6598 
6599 static cpl_vector *
6600 detmon_lg_find_dits(const cpl_vector * exptimes,
6601  double tolerance)
6602 {
6603  cpl_vector * dits = cpl_vector_new(cpl_vector_get_size(exptimes) / 2);
6604  int ndits = 0;
6605 
6606  int i, j;
6607 
6608  /* First different EXPTIME */
6609  cpl_vector_set(dits, 0, cpl_vector_get(exptimes, 0));
6610  ndits = 1;
6611 
6612  /* Search for all different EXPTIMEs */
6613  for(i = 1; i < cpl_vector_get_size(exptimes); i++) {
6614  int ndiffs = 0;
6615  for (j = 0; j < ndits; j++) {
6616  if (fabs(cpl_vector_get(exptimes, i) -
6617  cpl_vector_get(dits, j)) > tolerance)
6618  ndiffs++;
6619  }
6620  if(ndiffs == ndits) {
6621  cpl_vector_set(dits, ndits, cpl_vector_get(exptimes, i));
6622  ndits++;
6623  }
6624  }
6625 
6626  cpl_vector_set_size(dits, ndits);
6627 
6628  return dits;
6629 }
6630 
6631 
6632 
6633 
6634 static cpl_error_code
6635 detmon_lg_find_dits_ndits(const cpl_vector * exptimes,
6636  const cpl_vector * vec_ndits,
6637  double tolerance,
6638  cpl_vector** diff_dits,
6639  cpl_vector** diff_ndits)
6640 {
6641  int ndits = 0;
6642 
6643  int i, j;
6644  int size=0;
6645 
6646 
6647  * diff_dits = cpl_vector_new(cpl_vector_get_size(exptimes) / 2);
6648  * diff_ndits = cpl_vector_new(cpl_vector_get_size(*diff_dits));
6649 
6650  /* First different EXPTIME */
6651  cpl_vector_set(*diff_dits, 0, cpl_vector_get(exptimes, 0));
6652  cpl_vector_set(*diff_ndits, 0, cpl_vector_get(vec_ndits, 0));
6653 
6654  ndits = 1;
6655  size=cpl_vector_get_size(exptimes);
6656  /* Search for all different EXPTIMEs */
6657  for(i = 1; i < size; i++) {
6658  int ndiffs = 0;
6659  for (j = 0; j < ndits; j++) {
6660  if (fabs(cpl_vector_get(exptimes, i) -
6661  cpl_vector_get(*diff_dits,j)) > tolerance)
6662  ndiffs++;
6663  }
6664  if(ndiffs == ndits) {
6665  cpl_vector_set(*diff_dits, ndits, cpl_vector_get(exptimes, i));
6666  cpl_vector_set(*diff_ndits, ndits, cpl_vector_get(vec_ndits, i));
6667  ndits++;
6668  }
6669  }
6670 
6671  cpl_vector_set_size(*diff_dits, ndits);
6672  cpl_vector_set_size(*diff_ndits, ndits);
6673 
6674 
6675  return cpl_error_get_code();
6676 }
6677 
6678 
6679 /*---------------------------------------------------------------------------*/
6762 /*---------------------------------------------------------------------------*/
6763 
6764 cpl_table *
6765 detmon_lin(const cpl_imagelist * imlist_on,
6766  const cpl_imagelist * imlist_off,
6767  const cpl_vector * exptimes,
6768  double tolerance,
6769  int llx,
6770  int lly,
6771  int urx,
6772  int ury,
6773  int order,
6774  int ref_level,
6775  double kappa,
6776  cpl_boolean bpmbin,
6777  cpl_propertylist * qclist,
6778  unsigned mode,
6779  cpl_imagelist ** coeffs_cube,
6780  cpl_image ** bpm)
6781 {
6782  cpl_table * lin_table = NULL;
6783  cpl_imagelist * c_onlist = NULL;
6784  cpl_imagelist * c_offlist = NULL;
6785  cpl_vector * diffdits = NULL;
6786  cpl_imagelist * lin_inputs = NULL;
6787  cpl_polynomial * poly_linfit = NULL;
6788  cpl_image * fiterror = NULL;
6789  cpl_vector * vcoeffs = NULL;
6790  double * pcoeffs = NULL;
6791  int ndiffdits, ndits;
6792  int i, j;
6793  cpl_boolean opt_nir = mode & IRPLIB_LIN_OPT ? OPT : NIR;
6794  const cpl_vector *x = NULL;
6795  const cpl_vector *y = NULL;
6796 
6797  const cpl_image * first = NULL;
6798  int sizex = 0;
6799  int sizey = 0;
6800 
6801  cpl_size deg;
6802  double vsize = 0;
6803 
6804 
6805  cpl_ensure(imlist_on != NULL, CPL_ERROR_NULL_INPUT, NULL);
6806  cpl_ensure(imlist_off != NULL, CPL_ERROR_NULL_INPUT, NULL);
6807  cpl_ensure(exptimes != NULL, CPL_ERROR_NULL_INPUT, NULL);
6808  cpl_ensure(qclist != NULL, CPL_ERROR_NULL_INPUT, NULL);
6809  cpl_ensure(order > 0 , CPL_ERROR_ILLEGAL_INPUT, NULL);
6810 
6811  vcoeffs = cpl_vector_new(order + 1);
6812  pcoeffs = cpl_vector_get_data(vcoeffs);
6813 
6814  /* This mode requires optional outputs */
6815  if (mode & IRPLIB_LIN_PIX2PIX) {
6816  cpl_ensure(coeffs_cube != NULL, CPL_ERROR_NULL_INPUT, NULL);
6817  cpl_ensure(bpm != NULL, CPL_ERROR_NULL_INPUT, NULL);
6818  lin_inputs = cpl_imagelist_new();
6819  }
6820 
6821  /* Create table with columns */
6822  lin_table = cpl_table_new(cpl_vector_get_size(exptimes) / 2);
6823  skip_if(detmon_lin_table_create(lin_table, opt_nir));
6824 
6825  /* Search for different EXPTIME values */
6826  /* Search for different EXPTIME values */
6827  diffdits = detmon_lg_find_dits(exptimes, tolerance);
6828  ndiffdits = cpl_vector_get_size(diffdits);
6829 
6830  ndits = cpl_vector_get_size(exptimes);
6831 
6832 
6833 
6834 
6835 
6836 
6837  /* TO BE IMPLEMENTED SIMILARLY TO UPPER LEVEL FUNCTION (search for nskip)
6838  if(filter > 0) {
6839  double med1 =
6840  cpl_image_get_median_window(cpl_imagelist_get(imlist_on, 0),
6841  llx,lly,urx,ury);
6842  double med2 =
6843  cpl_image_get_median_window(cpl_imagelist_get(imlist_on, 1),
6844  llx,lly,urx,ury);
6845  if ( med1 > (double)filter ||
6846  med2 > (double)filter) {
6847  follow = CPL_FALSE;
6848  cpl_table_select_row(lin_table, dit_nb);
6849  dit_nskip++;
6850  cpl_msg_warning(cpl_func, "Frames of EXPTIME nb %d "
6851  "will not be taken into account for computation "
6852  "as they are above --filter threshold", dit_nb);
6853  }
6854  }
6855  */
6856 
6857 
6858 
6859 
6860  if (mode & IRPLIB_LIN_COLLAPSE) {
6861  /*
6862  * The master bias is required only for
6863  * linearity computation in the OPT domain
6864  */
6865  cpl_image * collapse = cpl_imagelist_collapse_create(imlist_off);
6866  skip_if(collapse == NULL);
6867 
6868  c_offlist = cpl_imagelist_new();
6869  skip_if(cpl_imagelist_set(c_offlist, collapse, 0));
6870  }
6871 
6872  /* Loop over the different DITs found in EXPTIMEs */
6873  for (i = 0; i < ndiffdits; i++) {
6874  int c_nons;
6875  int c_noffs = 0; /* False (uninit) warning */
6876 
6877  double c_dit = cpl_vector_get(diffdits, i);
6878 
6879  c_onlist = cpl_imagelist_new();
6880  c_nons = 0;
6881 
6882  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6883  c_offlist = cpl_imagelist_new();
6884  c_noffs = 0;
6885  }
6886 
6887  for(j = 0; j < ndits; j++) {
6888  if (fabs(c_dit - cpl_vector_get(exptimes, j)) <= tolerance) {
6889  /*
6890  * First we get the corresponding image from the ON imlist.
6891  * The option IRPLIB_GAIN_WITH_RESCALE requires to modify
6892  * the input pixel buffer; therefore we must duplicate it.
6893  * On the other hand, if this option is not required, there
6894  * is no need for that duplication. We must only care that
6895  * c_onlist must not be deleted but only unset.
6896  */
6897  cpl_image * im_on;
6898  if (mode & IRPLIB_LIN_WITH_RESCALE) {
6899  const cpl_image * im =
6900  cpl_imagelist_get_const(imlist_on, j);
6901  im_on = cpl_image_duplicate(im);
6902  } else {
6903  im_on = (cpl_image *)cpl_imagelist_get_const(imlist_on, j);
6904  }
6905  skip_if(cpl_imagelist_set(c_onlist, im_on, c_nons));
6906  c_nons++;
6907 
6908  /*
6909  * Same explanation as above but for OFF imlist.
6910  * Only necessary when IRPLIB_GAIN_NO_COLLAPSE required.
6911  */
6912  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6913  cpl_image * im_off;
6914  if (mode & IRPLIB_LIN_WITH_RESCALE) {
6915  const cpl_image * im =
6916  cpl_imagelist_get_const(imlist_off, j);
6917  im_off = cpl_image_duplicate(im);
6918  } else {
6919  im_off =
6920  (cpl_image *) cpl_imagelist_get_const(imlist_off, j);
6921  }
6922  skip_if(cpl_imagelist_set(c_offlist, im_off, c_noffs));
6923  c_noffs++;
6924  }
6925  }
6926  }
6927 
6928  /* If NO_COLLAPSE, must be the same number of images! */
6929  if (mode & IRPLIB_LIN_NO_COLLAPSE)
6930  skip_if (c_nons != c_noffs);
6931 
6932  /* There must be pairs! */
6933  skip_if (c_nons == 0 || c_nons % 2 != 0);
6934 
6935  /* Rescaling */
6936  if(mode & IRPLIB_LIN_WITH_RESCALE) {
6937  skip_if(detmon_lg_rescale(c_onlist));
6938  if (mode & IRPLIB_LIN_NO_COLLAPSE)
6939  skip_if(detmon_lg_rescale(c_offlist));
6940  }
6941 
6942  /* The following loop is necessary for the case of multiple pairs
6943  of same EXPTIME values */
6944  while(c_nons > 0) {
6945 
6946  skip_if(detmon_lin_table_fill_row(lin_table, c_dit,
6947  lin_inputs,
6948  c_onlist, c_offlist,
6949  llx, lly, urx, ury,
6950  i, 0, mode));
6951 
6952  if (mode & IRPLIB_LIN_WITH_RESCALE) {
6953  cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
6954  cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
6955  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6956  cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
6957  cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
6958  }
6959  } else {
6960  cpl_imagelist_unset(c_onlist, 0);
6961  skip_if(0);
6962  cpl_imagelist_unset(c_onlist, 0);
6963  skip_if(0);
6964  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6965  cpl_imagelist_unset(c_offlist, 0);
6966  skip_if(0);
6967  cpl_imagelist_unset(c_offlist, 0);
6968  skip_if(0);
6969  }
6970  }
6971  skip_if(0);
6972  c_nons -= 2;
6973  }
6974 
6975  cpl_imagelist_delete(c_onlist);
6976  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6977  cpl_imagelist_delete(c_offlist);
6978  }
6979  }
6980 
6981  skip_if(detmon_add_adl_column(lin_table, opt_nir));
6982 
6983  if(!(mode & IRPLIB_LIN_PIX2PIX)) {
6984  double mse = 0;
6985  /* Computation of LINEARITY via polynomial fit */
6986  y = cpl_vector_wrap(cpl_table_get_nrow(lin_table),
6987  (double *)cpl_table_get_data_double_const(lin_table,
6988  "MED"));
6989  if (opt_nir == NIR) {
6990  x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
6991  (double *)cpl_table_get_data_double_const(lin_table, "DIT"));
6992  } else {
6993  x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
6994  (double *)cpl_table_get_data_double_const(lin_table, "EXPTIME"));
6995  }
6996  if(x == NULL || y == NULL) {
6997  cpl_vector_unwrap((cpl_vector *)x);
6998  cpl_vector_unwrap((cpl_vector *)y);
6999  /*
7000  * As x and y are const vectors, if they would be defined at the
7001  * beginning of the function (required for skip_if - end_skip
7002  * scheme), they couldn't be initialised to NULL (required too).
7003  * Therefore, they are considered apart from the scheme.
7004  */
7005  skip_if(1);
7006  }
7007 
7008  cpl_msg_info(cpl_func, "Polynomial fitting for the LINEARITY");
7009  poly_linfit = irplib_polynomial_fit_1d_create_chiq(x, y, order, &mse);
7010 
7011  if(order == cpl_vector_get_size(x) - 1) {
7012  cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
7013  mse = 0;
7014  }
7015 
7016  if(poly_linfit == NULL) {
7017  cpl_vector_unwrap((cpl_vector *)x);
7018  cpl_vector_unwrap((cpl_vector *)y);
7019  /* See comment in previous error checking if() statement */
7020  skip_if(1);
7021  }
7022 
7023  cpl_vector_unwrap((cpl_vector *)x);
7024  cpl_vector_unwrap((cpl_vector *)y);
7025 
7026  for(deg = 0; deg <= order; deg++) {
7027  const double coeff =
7028  cpl_polynomial_get_coeff(poly_linfit, &deg);
7029  char *name_o =
7030  cpl_sprintf("ESO QC LIN COEF%" CPL_SIZE_FORMAT "", deg);
7031  assert(name_o != NULL);
7032  skip_if(cpl_propertylist_append_double(qclist, name_o, coeff));
7033  skip_if(cpl_propertylist_set_comment(qclist,name_o,
7034  DETMON_QC_LIN_COEF_C));
7035  cpl_free(name_o);
7036  pcoeffs[deg] = coeff;
7037  }
7038  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT, mse));
7039  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
7040  DETMON_QC_ERRFIT_MSE_C));
7041 
7042 
7043  } else {
7044  if (opt_nir == NIR) {
7045  x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
7046  (double *)cpl_table_get_data_double_const(lin_table,
7047  "DIT"));
7048  } else {
7049  x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
7050  (double *)cpl_table_get_data_double_const(lin_table,
7051  "EXPTIME"));
7052  }
7053 
7054 
7055  first = cpl_imagelist_get_const(lin_inputs, 0);
7056  sizex = cpl_image_get_size_x(first);
7057  sizey = cpl_image_get_size_y(first);
7058 
7059  vsize = cpl_vector_get_size(x);
7060 
7061  fiterror = cpl_image_new(sizex, sizey, CPL_TYPE_FLOAT);
7062 
7063  *coeffs_cube =
7064  cpl_fit_imagelist_polynomial(x, lin_inputs, 0,
7065  order, FALSE, CPL_TYPE_FLOAT,
7066  fiterror);
7067 
7068  cpl_vector_unwrap((cpl_vector*)x);
7069  irplib_ensure(*coeffs_cube != NULL, CPL_ERROR_UNSPECIFIED,
7070  "Failed polynomial fit");
7071 
7072  for(i = 0; i <= order; i++) {
7073  cpl_image *image = cpl_imagelist_get(*coeffs_cube, i);
7074  const double coeff = cpl_image_get_median(image);
7075  char * name_o1 = cpl_sprintf("ESO QC LIN COEF%d", i);
7076  char * name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", i);
7077  pcoeffs[i] = coeff;
7078  assert(name_o1 != NULL);
7079  assert(name_o2 != NULL);
7080  skip_if(cpl_propertylist_append_double(qclist, name_o1, coeff));
7081  skip_if(cpl_propertylist_set_comment(qclist,name_o1,
7082  DETMON_QC_LIN_COEF_C));
7083  cpl_free(name_o1);
7084  name_o1= NULL;
7085  skip_if(cpl_propertylist_append_double(qclist, name_o2,
7086  cpl_image_get_stdev(image)));
7087  skip_if(cpl_propertylist_set_comment(qclist,name_o2,
7088  DETMON_QC_LIN_COEF_ERR_C));
7089  cpl_free(name_o2);
7090  name_o2= NULL;
7091  }
7092 
7093  if(order == vsize - 1) {
7094  cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
7095  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT,
7096  0.0));
7097  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
7098  DETMON_QC_ERRFIT_C));
7099 
7100 
7101  } else {
7102  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT,
7103  cpl_image_get_median(fiterror)));
7104  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
7105  DETMON_QC_ERRFIT_C));
7106 
7107  }
7108  }
7109 
7110  skip_if(detmon_lg_lineff(pcoeffs, qclist, ref_level, order));
7111 
7112  if(mode & IRPLIB_LIN_PIX2PIX) {
7113  int nbpixs;
7114  *bpm = detmon_bpixs(*coeffs_cube, bpmbin, kappa, &nbpixs);
7115  skip_if(*bpm == NULL);
7116  skip_if(cpl_propertylist_append_int(qclist, DETMON_QC_NUM_BPM,
7117  nbpixs));
7118  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_NUM_BPM,
7119  DETMON_QC_NUM_BPM_C));
7120  }
7121 
7122  end_skip;
7123 
7124  cpl_vector_delete(diffdits);
7125  cpl_polynomial_delete(poly_linfit);
7126  cpl_imagelist_delete(lin_inputs);
7127  cpl_vector_delete(vcoeffs);
7128  cpl_image_delete(fiterror);
7129 
7130  return lin_table;
7131 
7132 }
7133 
7134 /*--------------------------------------------------------------------------*/
7157 /*--------------------------------------------------------------------------*/
7158 static cpl_error_code
7159 detmon_lin_table_fill_row(cpl_table * lin_table, double c_dit,
7160  cpl_imagelist * linearity_inputs,
7161  const cpl_imagelist * ons,
7162  const cpl_imagelist * offs,
7163  int llx,
7164  int lly,
7165  int urx,
7166  int ury,
7167  const int pos,
7168  const int nskip,
7169  unsigned mode)
7170 {
7171  cpl_image * extracted=NULL;
7172 
7173  cpl_ensure_code(lin_table != NULL, CPL_ERROR_NULL_INPUT);
7174  cpl_ensure_code(ons != NULL, CPL_ERROR_NULL_INPUT);
7175  cpl_ensure_code(offs != NULL, CPL_ERROR_NULL_INPUT);
7176 
7177  if (mode & IRPLIB_LIN_PIX2PIX) {
7178  cpl_msg_debug(cpl_func,"checking linearity inputs");
7179  cpl_ensure_code(linearity_inputs != NULL, CPL_ERROR_NULL_INPUT);
7180  }
7181 
7182 
7183  if (mode & IRPLIB_LIN_NIR) {
7184  cpl_table_set(lin_table, "DIT", pos, c_dit);
7185  } else if (mode & IRPLIB_LIN_OPT) { /*OPT */
7186  cpl_table_set(lin_table, "EXPTIME", pos, c_dit);
7187  } else {
7188  cpl_msg_error(cpl_func, "Mandatory mode not given");
7189  }
7190 
7191  {
7192  const cpl_image * off2;
7193  if (cpl_imagelist_get_size(offs) == 1 || mode & IRPLIB_LIN_COLLAPSE)
7194  off2 = cpl_imagelist_get_const(offs, 0);
7195  else
7196  off2 = cpl_imagelist_get_const(offs, 1);
7197 
7198  extracted = detmon_subtracted_avg(cpl_imagelist_get_const(ons, 0),
7199  cpl_imagelist_get_const(offs, 0),
7200  cpl_imagelist_get_const(ons, 1),
7201  off2,
7202  llx, lly, urx, ury);
7203  cpl_ensure_code(extracted != NULL, cpl_error_get_code());
7204  }
7205 
7206  {
7207  double median = cpl_image_get_median(extracted);
7208  double mean= cpl_image_get_mean(extracted);
7209  cpl_table_set(lin_table, "MED", pos, median);
7210  cpl_table_set(lin_table, "MEAN", pos, mean);
7211 
7212  cpl_table_set(lin_table, "MED_DIT", pos, median / c_dit);
7213  cpl_table_set(lin_table, "MEAN_DIT", pos, mean / c_dit);
7214  }
7215 
7216  /* Insert to the imagelist used to fit the polynomial */
7217  if(mode & IRPLIB_LIN_PIX2PIX) {
7218  cpl_error_code error = cpl_imagelist_set(linearity_inputs, extracted,
7219  pos-nskip);
7220  cpl_ensure_code(!error, error);
7221  } else {
7222  cpl_image_delete(extracted);
7223  }
7224 
7225  return cpl_error_get_code();
7226 }
7227 
7228 static double irplib_calculate_total_noise_smooth(const cpl_image* pimage,
7229  int pattern_x, int pattern_y)
7230 {
7231  cpl_image * p_tmp_image = 0;
7232  cpl_image * psmooth_image = 0;
7233  double ret_noise;
7234  cpl_mask * mask = cpl_mask_new(pattern_x, pattern_y);
7235  cpl_mask_not(mask);
7236  p_tmp_image = cpl_image_duplicate(pimage);
7237  cpl_image_filter_mask(p_tmp_image,pimage, mask,CPL_FILTER_MEDIAN ,CPL_BORDER_FILTER);
7238  cpl_image_divide_scalar(p_tmp_image, cpl_image_get_median(pimage));
7239  psmooth_image = cpl_image_divide_create(pimage,p_tmp_image);
7240  ret_noise = irplib_calculate_total_noise(psmooth_image);
7241  cpl_mask_delete(mask);
7242  cpl_image_delete(psmooth_image);
7243  cpl_image_delete(p_tmp_image);
7244  return ret_noise;
7245 }
7246 
7247 static double irplib_calculate_total_noise(const cpl_image* pimage)
7248 {
7249  double total_noise = -1;
7250  unsigned long max_bin_size = 1E5;
7251  const double hstart = cpl_image_get_min(pimage);
7252  const double hrange = cpl_image_get_max(pimage) - hstart;
7253  const unsigned long nbins = max_bin_size;
7254  cpl_error_code err;
7255  /* apply histogram method */
7256  irplib_hist * phist = 0;
7257  phist = irplib_hist_new();
7258  /* 2 extra-bins for possible out-of-range values */
7259 
7260  irplib_hist_init(phist, nbins, hstart, hrange);
7261  err = irplib_hist_fill(phist, pimage);
7262  if (err == CPL_ERROR_NONE)
7263  {
7264  unsigned int i = 0;
7265  double x0 = 0;
7266  double area = 0;
7267  double offset = 0;
7268 
7269  /* prepare vector */
7270  unsigned long n_bins = irplib_hist_get_nbins(phist);
7271  double start = irplib_hist_get_start(phist);
7272  double bin_size = irplib_hist_get_bin_size(phist);
7273  cpl_vector* pdata_vector = cpl_vector_new(n_bins);
7274  cpl_vector* ppos_vector = cpl_vector_new(n_bins);
7275  cpl_table* ptable = cpl_table_new(n_bins);
7276  cpl_table_new_column(ptable, "bin", CPL_TYPE_DOUBLE);
7277  cpl_table_new_column(ptable, "value", CPL_TYPE_DOUBLE);
7278  for(i = 0; i < n_bins; i++)
7279  {
7280  unsigned int value = irplib_hist_get_value(phist, i);
7281  double dvalue = (double)(value);
7282  cpl_vector_set(pdata_vector, i, dvalue);
7283  cpl_vector_set(ppos_vector, i, start + i * bin_size);
7284 
7285  cpl_table_set(ptable, "bin", i, start + i * bin_size);
7286  cpl_table_set(ptable, "value", i, dvalue);
7287  }
7288  err = cpl_vector_fit_gaussian(ppos_vector, NULL, pdata_vector, NULL, CPL_FIT_ALL, &x0, &total_noise, &area, &offset, NULL, NULL, NULL );
7289  if (err == CPL_ERROR_NONE)
7290  {
7291  cpl_msg_info(cpl_func, "FPN Calculation: histogram x0[%f] total_noise[%f] area[%f] offset[%f]", x0, total_noise, area, offset);
7292  }
7293  else
7294  {
7295  cpl_msg_warning(cpl_func, "FPN could not be computed due failed Gaussian Fit, err msg [%s]", cpl_error_get_message());
7296  cpl_error_reset();
7297  }
7298  cpl_table_delete(ptable);
7299  cpl_vector_delete(ppos_vector);
7300  cpl_vector_delete(pdata_vector);
7301  }
7302  else
7303  {
7304  cpl_msg_warning(cpl_func, "FPN could not be computed due failed histogram computation, err msg [%s]", cpl_error_get_message());
7305  cpl_error_reset();
7306  }
7307  irplib_hist_delete(phist);
7308 
7309  return total_noise;
7310 }
7311 
7312 static double irplib_compute_err(double gain, double ron, double FA)
7313 {
7314  double int_gain = (gain * gain - 1) / 12;
7315  if (int_gain < 0)
7316  {
7317  int_gain = 0;
7318  }
7319  return sqrt(ron * ron + FA / gain + int_gain);
7320 }
7321 
7322 static double irplib_fpn_lg(const cpl_image* f1, int* range, double gain ,
7323  FPN_METHOD fpn_method, int smooth_size, double* mse)
7324 {
7325  cpl_image* im_diff = 0;
7326  const cpl_image* im_f1 = f1;
7327  cpl_image* im_inrange1 = 0;
7328  double FA = 0;
7329  double s_tot = 0; /* absolute total noise */
7330  double s_fpn = 0; /* fixed pattern noise */
7331  double sr_fpn = 0; /* relative structural noise */
7332  /*che cinput*/
7333  if (gain<=0) {
7334  /* put dummy values Negative to indicate a problem occurred
7335  (FPN should be always positive) */
7336  cpl_msg_warning(cpl_func,"gain[%f]<0", gain);
7337  cpl_msg_warning(cpl_func,"We set dummy values for FPN");
7338  s_fpn=-999.;
7339  sr_fpn=-999;
7340  return sr_fpn;
7341  }
7342  if (range)
7343  {
7344  im_inrange1 = cpl_image_extract(f1, range[0], range[1], range[2], range[3]);
7345  im_f1 = im_inrange1;
7346  }
7347  FA = cpl_image_get_median(im_f1);
7348 
7349  /* apply histogram method */
7350  /* Is this irplib function giving the right result?? */
7351  switch (fpn_method)
7352  {
7353  case FPN_SMOOTH:
7354  cpl_msg_info(cpl_func,"SMOOTH method is used for FPN, pattern size[%d x %d] pixels",smooth_size,smooth_size );
7355  s_tot = irplib_calculate_total_noise_smooth(im_f1,smooth_size,smooth_size);
7356  break;
7357  case FPN_HISTOGRAM:
7358  cpl_msg_info(cpl_func,"HISTOGRAM method is used for FPN");
7359  s_tot = irplib_calculate_total_noise(im_f1);
7360  break;
7361  default:
7362  s_tot = -1;
7363  sr_fpn = -1;
7364  cpl_msg_warning(cpl_func,"fpn_method is not defined");
7365  break;
7366  }
7367  if (s_tot > 0)
7368  {
7369  if (FA<0)
7370  {
7371  /* put dummy values Negative to indicate a problem occurred
7372  (FPN should be always positive) */
7373  cpl_msg_warning(cpl_func,"Median flux on sum of flats<0");
7374  cpl_msg_warning(cpl_func,"We set dummy values for FPN");
7375  s_fpn=-999.;
7376  sr_fpn=-999;
7377  }
7378 
7379  if ((s_tot * s_tot - FA / gain) > 0)
7380  {
7381  s_fpn = sqrt(s_tot * s_tot - FA / gain);
7382  sr_fpn = s_fpn / FA;
7383  *mse = (irplib_compute_err(gain, 0, FA)) * gain / FA;
7384  } else {
7385  /* put dummy values Negative to indicate a problem occurred
7386  (FPN should be always positive) */
7387  cpl_msg_warning(cpl_func,"s_tot * s_tot < FA / gain");
7388  cpl_msg_warning(cpl_func,"We set dummy values for FPN");
7389  //s_fpn=-999.; /* in this case s_fpn value would be never used */
7390  sr_fpn=-999;
7391  *mse = -1;
7392  }
7393  /*
7394  cpl_msg_debug(cpl_func, "FPN Calculation: FA[%f] s_tot[%f] photon_noise[%f] s_fpn[%f] sr_fpn[%f] mse[%f]", FA, s_tot, photon_noise, s_fpn, sr_fpn, *mse);
7395  */
7396  }
7397  cpl_image_delete(im_diff);
7398  if (range)
7399  {
7400  cpl_image_delete(im_inrange1);
7401  }
7402  return sr_fpn;
7403 }
7404 
7405 
7406 static cpl_imagelist * irplib_load_fset_wrp(const cpl_frameset * pframeset,
7407  cpl_type type , int whichext)
7408 {
7409  /* FIXME: load image into window size from beginning to
7410  * save all the extracts */
7411  return detmon_load_frameset_window(pframeset, type, 0, whichext,
7412  detmon_lg_config.llx,
7413  detmon_lg_config.lly,
7414  detmon_lg_config.urx,
7415  detmon_lg_config.ury,
7416  detmon_lg_config.nx,
7417  detmon_lg_config.ny);
7418 }
7419 
7420 static cpl_imagelist * irplib_load_fset_wrp_ext(const cpl_frameset * pframeset,
7421  cpl_type type , int whichext)
7422 {
7423  int i = whichext; /* fake code to avoid compiler warning */
7424  cpl_imagelist* offs = cpl_imagelist_new();
7425  detmon_lg_config.load_fset(pframeset, type, offs);
7426  i++;
7427  return offs;
7428 }
7429 
7430 static cpl_error_code irplib_table_create_column(cpl_table* ptable,
7431  cpl_propertylist* plist)
7432 {
7433  if (ptable && plist)
7434  {
7435  int size = cpl_propertylist_get_size(plist);
7436  int i = 0;
7437  for (i = 0; i < size; i++)
7438  {
7439  cpl_property* pprop = cpl_propertylist_get(plist,i);
7440  if (pprop)
7441  {
7442  const char* pname = cpl_property_get_name(pprop);
7443  if (pname)
7444  {
7445  cpl_table_new_column(ptable, pname, cpl_property_get_type(pprop));
7446  if (cpl_error_get_code() != CPL_ERROR_NONE)
7447  {
7448  cpl_msg_warning(cpl_func, "cannot create new column[%s], err[%s]", pname, cpl_error_get_message());
7449  break; /* leave the cycle */
7450  }
7451  }
7452  }
7453  }
7454  }
7455  return cpl_error_get_code();
7456 }
7457 
7458 static cpl_error_code irplib_fill_table_DETWINUIT(cpl_table* ptable,
7459  cpl_propertylist* plist, int row)
7460 {
7461  cpl_error_code err = CPL_ERROR_NONE;
7462  if (ptable && plist)
7463  {
7464  int size = cpl_propertylist_get_size(plist);
7465  int i = 0;
7466  for (i = 0; i < size; i++)
7467  {
7468  cpl_property* pprop = cpl_propertylist_get(plist,i);
7469  if (pprop)
7470  {
7471  const char* pname = cpl_property_get_name(pprop);
7472  double value = cpl_property_get_double(pprop);
7473  if (pname)
7474  {
7475  cpl_table_set_double(ptable, pname, row, value);
7476  if (cpl_error_get_code() != CPL_ERROR_NONE)
7477  {
7478  cpl_msg_warning(cpl_func, "cannot write value to the table, column[%s] value[%f], err[%s]", pname, value, cpl_error_get_message());
7479  cpl_error_reset();
7480  break; /* leave the cycle */
7481  }
7482  }
7483  }
7484  }
7485  }
7486  return err;
7487 }
7488 
7489 cpl_error_code detmon_check_order(const double *exptime, int sz,
7490  double tolerance, int order)
7491 {
7492  int nsets = 0;
7493  int i = 0;
7494  /* 1. Determine number of groups */
7495  /* cpl_msg_warning(cpl_func, "detmon_check_order sz[%i]", sz);*/
7496  do
7497  {
7498  /* cpl_msg_warning(cpl_func, "detmon_check_order i[%i] exptime[%g]", i, exptime[i]); */
7499  nsets++;
7500  do
7501  {
7502  i++;
7503  if(i == sz - 1)
7504  {
7505  break;
7506  }
7507  } while(fabs(exptime[i-1] - exptime[i]) < tolerance);
7508  } while(i < sz - 1);
7509  /* the very last adjustment for the last group */
7510  if ( !( fabs(exptime[i-1] - exptime[i]) < tolerance ) ) nsets++;
7511  if(nsets <= order)
7512  {
7513  cpl_error_set_message(cpl_func,CPL_ERROR_INCOMPATIBLE_INPUT,
7514  "Not enough frames for the polynomial"
7515  " fitting. nsets = %d <= %d order",
7516  nsets,order);
7517  }
7518  return cpl_error_get_code();
7519 }
7520 
7521 static cpl_error_code
7522 detmon_lg_dfs_save_imagelist(
7523  cpl_frameset * frameset,
7524  const cpl_parameterlist * parlist,
7525  const cpl_frameset *usedframes,
7526  const cpl_imagelist *coeffs,
7527  const char *recipe_name,
7528  const cpl_propertylist *mypro_coeffscube,
7529  const char * package,
7530  const char * name_o)
7531 {
7532  return(cpl_dfs_save_imagelist
7533  (frameset, NULL, parlist, usedframes, NULL,coeffs, CPL_BPP_IEEE_FLOAT,
7534  recipe_name, mypro_coeffscube, NULL, package,
7535  name_o));
7536 }
7537 
7538 static void detmon_lg_add_empty_image(cpl_imagelist* imlist, int pos)
7539 {
7540  const cpl_image* first = cpl_imagelist_get(imlist, 0);
7541  if (first)
7542  {
7543  int x = cpl_image_get_size_x(first);
7544  int y = cpl_image_get_size_y(first);
7545  cpl_type type = cpl_image_get_type(first);
7546  cpl_image * blank = cpl_image_new(x, y, type);
7547  cpl_imagelist_set(imlist, blank, pos);
7548  }
7549 }
7550 
7551 
7552 cpl_error_code
7553 detmon_lg_set_tag(cpl_frameset* set, const char** tag_on, const char** tag_off)
7554 {
7555  int ntag_old=0;
7556  int ntag_new=0;
7557 
7558  ntag_old=cpl_frameset_count_tags(set,DETMON_LG_ON_RAW_OLD);
7559  ntag_new=cpl_frameset_count_tags(set,DETMON_LG_ON_RAW_NEW);
7560  if(ntag_old) {
7561  *tag_on=DETMON_LG_ON_RAW_OLD;
7562  *tag_off=DETMON_LG_OFF_RAW_OLD;
7563  } else if (ntag_new) {
7564  *tag_on=DETMON_LG_ON_RAW_NEW;
7565  *tag_off=DETMON_LG_OFF_RAW_NEW;
7566  } else {
7567  cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
7568  "Provide %s and %s (or %s and %s) input frames",
7569  DETMON_LG_ON_RAW_NEW,DETMON_LG_OFF_RAW_NEW,
7570  DETMON_LG_ON_RAW_OLD,DETMON_LG_OFF_RAW_OLD);
7571  }
7572 
7573 
7574  return cpl_error_get_code();
7575 }