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