DETMON Pipeline Reference Manual  1.2.10
detmon_lg.c
1 /* $Id: detmon_lg.c,v 1.31 2013-08-07 09:32:37 jtaylor Exp $
2  *
3  * This file is part of the irplib package
4  * Copyright (C) 2002, 2003 European Southern Observatory
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
19  */
20 
21 
22 /*
23  * $Author: jtaylor $
24  * $Date: 2013-08-07 09:32:37 $
25  * $Revision: 1.31 $
26  * $Name: not supported by cvs2svn $
27  *
28  */
29 
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33 
34 /*---------------------------------------------------------------------------
35  Includes
36  ---------------------------------------------------------------------------*/
37 
38 #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  if ( med1 > (double)detmon_lg_config.filter ||
2999  med2 > (double)detmon_lg_config.filter)
3000  {
3001  follow = CPL_FALSE;
3002  cpl_table_select_row(gain_table, dit_nb);
3003  cpl_table_select_row(linear_table, dit_nb);
3004  (*dit_nskip)++;
3005  cpl_msg_warning(cpl_func, "Frames of EXPTIME nb %d "
3006  "will not be taken into account for computation "
3007  "as they are above --filter threshold", dit_nb);
3008  }
3009  }
3010 
3011  if (follow || detmon_lg_config.filter < 0)
3012  {
3013 
3014  /*
3015  * If the --collapse option is not activated by the user, the OFF
3016  * sub-frameset is also supposed to be organized into pairs and,
3017  * therefore, processed as the ON sub-frameset.
3018  */
3019  if(!detmon_lg_config.collapse)
3020  {
3021  /* TODO: We removed this check as with NACO data, that has an odd
3022  * number of input OFF frames it would stop with error
3023  * despite the recipe would reduce the data properly.
3024  * On the other side, on some data without such a check one may get
3025  * failures on another place.
3026  * we need to document such cases and understand how to better deal
3027  * in a robust way the case of odd input off frames
3028  *
3029  if (cpl_frameset_get_size(set_off) % 2 != 0) {
3030  cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
3031  "If collapse is FALSE the OFF frameset"
3032  " must be organized in pairs.");
3033  skip_if(1);
3034  }
3035  */
3036  if (!strcmp(detmon_lg_config.method, "MED") ||
3037  cpl_frameset_get_size(set_on) == cpl_frameset_get_size(set_off))
3038  {
3039  skip_if(detmon_pair_extract_next(set_off, index_off, next_off, exptime_off, &pair_off, detmon_lg_config.tolerance));
3040  }
3041  else
3042  {
3043  skip_if(detmon_single_extract_next(set_off, index_off, next_off, exptime_off, &pair_off));
3044  }
3045  /* Load the OFF images */
3046  cpl_msg_debug(cpl_func, " Load the OFF images, ext[%d], exptime[%f]", whichext, exptime_off[*next_off - 1]);
3047  offs = detmon_lg_config.load_fset_wrp(pair_off, CPL_TYPE_FLOAT, whichext);
3048 
3049  skip_if(offs == NULL);
3050  skip_if(cpl_error_get_code());
3051  }
3052  else {
3053  offs = (cpl_imagelist *) opt_offs;
3054  }
3055 
3056  /* Rescaling */
3057  if(detmon_lg_config.rescale)
3058  {
3059  skip_if(detmon_lg_rescale(ons));
3060  if (!detmon_lg_config.collapse &&
3061  !strcmp(detmon_lg_config.method, "MED"))
3062  skip_if(detmon_lg_rescale(offs));
3063  }
3064  /* DIT or EXPTIME value extraction */
3065 
3066  filename =
3067  cpl_frame_get_filename(cpl_frameset_get_first_const(pair_on));
3068  skip_if ((plist = cpl_propertylist_load(filename, 0)) == NULL);
3069  /* Add columns to the tables DETi WINi UITi*/
3070  if (plist)
3071  {
3072  pDETlist = cpl_propertylist_new();
3073  cpl_propertylist_copy_property_regexp(pDETlist, plist, "DET[0-9]* WIN[0-9]* UIT[0-9]*",0);
3074  if (dit_nb == 0)
3075  {
3076  irplib_table_create_column(gain_table, pDETlist);
3077  irplib_table_create_column(linear_table, pDETlist);
3078  }
3079  }
3080  if(opt_nir == NIR) {
3081  c_dit = irplib_pfits_get_dit(plist);
3082  c_ndit = irplib_pfits_get_ndit(plist);
3083  } else {
3084  c_dit = irplib_pfits_get_exptime(plist);
3085  c_ndit=1;
3086  }
3087 
3088  /*
3089  * --GAIN part for each DIT value--
3090  * The following call to detmon_gain_table_fill_row() fills
3091  * in the row nb i
3092  * of the GAIN table (output) and of the FIT table (by-product to be
3093  * used later for the polynomial computation of the GAIN)
3094  */
3095 
3096  cpl_msg_info(cpl_func, "Computing GAIN for EXPTIME value nb %d",
3097  dit_nb + 1);
3098 
3099  /* In case PTC is applied, this is allowed */
3100  if(cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE && dit_nb == 0)
3101  {
3102  cpl_table_erase_column(gain_table, "MEAN_OFF1");
3103  cpl_table_erase_column(gain_table, "MEAN_OFF2");
3104  cpl_table_erase_column(gain_table, "SIG_OFF_DIF");
3105  cpl_table_erase_column(gain_table, "GAIN");
3106  cpl_table_erase_column(gain_table, "GAIN_CORR");
3107  cpl_table_new_column(gain_table, "MEAN_OFF", CPL_TYPE_DOUBLE);
3108  }
3109 
3110 
3111  skip_if(detmon_gain_table_fill_row(gain_table,
3112  c_dit,c_ndit,
3113  autocorr_images,
3114  diff_flats, ons, offs,
3115  detmon_lg_config.kappa,
3116  detmon_lg_config.niter,
3117  detmon_lg_config.llx,
3118  detmon_lg_config.lly,
3119  detmon_lg_config.urx,
3120  detmon_lg_config.ury,
3121  detmon_lg_config.m,
3122  detmon_lg_config.n,
3123  detmon_lg_config.saturation_limit,
3124  detmon_lg_config.gain_threshold,
3125  dit_nb, mode, rows_gain_affected));
3126 
3127 
3128  skip_if(detmon_check_saturation_on_pair(autocorr_images,
3129  diff_flats,ons,offs,
3130  detmon_lg_config.kappa,
3131  detmon_lg_config.niter,
3132  detmon_lg_config.llx,
3133  detmon_lg_config.lly,
3134  detmon_lg_config.urx,
3135  detmon_lg_config.ury,
3136  detmon_lg_config.saturation_limit,
3137  dit_nb, mode, rows_linear_affected));
3138 
3139 
3140  if (*rows_gain_affected)
3141  {
3142  /* fill DETi WINi OPTi columns - see DFS06921*/
3143  skip_if(irplib_fill_table_DETWINUIT(gain_table, pDETlist, dit_nb));
3144  /* Linearity reduction */
3145  cpl_msg_info(cpl_func, "Linearity reduction for nb %d",
3146  dit_nb + 1);
3147  }
3148  if (*rows_linear_affected) {
3149  skip_if(detmon_lin_table_fill_row(linear_table, c_dit,
3150  linearity_inputs, ons, offs,
3151  detmon_lg_config.llx,
3152  detmon_lg_config.lly,
3153  detmon_lg_config.urx,
3154  detmon_lg_config.ury,
3155  dit_nb, *dit_nskip, mode));
3156  /* fill DETi WINi OPTi columns - see DFS06921*/
3157  skip_if(irplib_fill_table_DETWINUIT(linear_table, pDETlist, dit_nb));
3158  }
3159 
3160 
3161  /* as we know only at this point if a frame is
3162  saturated or not, and we would like to compute the
3163  contamination only on the last non saturated frame,
3164  we need de facto to compute saturation on any non saturated
3165  frame, by overwriting the QC parameter. In the end it will
3166  remain only the last value corresponding to a non saturated
3167  frame */
3168 
3169  if(opt_nir == OPT &&
3170  *rows_linear_affected != 0 ) {
3171  detmon_opt_contamination(ons, offs, mode, qclist);
3172  }
3173 
3174  }
3175 
3176  end_skip;
3177 
3178  cpl_frameset_delete(pair_on);
3179  cpl_imagelist_delete(ons);
3180 
3181  if(!detmon_lg_config.collapse ) {
3182  cpl_imagelist_delete(offs);
3183  }
3184 
3185  if(!detmon_lg_config.collapse) {
3186  cpl_frameset_delete(pair_off);
3187  }
3188 
3189  cpl_propertylist_delete(plist);
3190  cpl_propertylist_delete(pDETlist);
3191  return cpl_error_get_code();
3192 }
3193 
3194 /*---------------------------------------------------------------------------*/
3200 /*---------------------------------------------------------------------------*/
3201 static cpl_error_code
3202 detmon_add_adl_column(cpl_table * table,
3203  cpl_boolean opt_nir)
3204 {
3205  cpl_error_code error;
3206  double mean_med_dit;
3207  double *dits;
3208 
3209  cpl_ensure_code(table != NULL, CPL_ERROR_NULL_INPUT);
3210 
3211  mean_med_dit = cpl_table_get_column_mean(table, "MED_DIT");
3212  if (opt_nir == OPT)
3213  dits = cpl_table_get_data_double(table, "EXPTIME");
3214  else
3215  dits = cpl_table_get_data_double(table, "DIT");
3216 
3217  error = cpl_table_copy_data_double(table, "ADL", dits);
3218  cpl_ensure_code(!error, error);
3219  error = cpl_table_multiply_scalar(table, "ADL", mean_med_dit);
3220  cpl_ensure_code(!error, error);
3221 
3222  return cpl_error_get_code();
3223 }
3224 
3225 /*---------------------------------------------------------------------------*/
3233 /*---------------------------------------------------------------------------*/
3234 static cpl_error_code
3235 detmon_lg_reduce_init(cpl_table * gain_table,
3236  cpl_table * linear_table,
3237  cpl_imagelist ** linearity_inputs,
3238  const cpl_boolean opt_nir)
3239 {
3240  skip_if(detmon_gain_table_create(gain_table, opt_nir));
3241  skip_if(detmon_lin_table_create(linear_table, opt_nir));
3242 
3243  if(detmon_lg_config.pix2pix) {
3244  *linearity_inputs = cpl_imagelist_new();
3245  skip_if(*linearity_inputs == NULL);
3246  }
3247 
3248  end_skip;
3249 
3250  return cpl_error_get_code();
3251 }
3252 
3253 /*--------------------------------------------------------------------------*/
3259 /*--------------------------------------------------------------------------*/
3260 static double
3261 irplib_pfits_get_dit(const cpl_propertylist * plist)
3262 {
3263  return irplib_pfits_get_prop_double(plist, "ESO DET DIT");
3264 }
3265 
3266 /*--------------------------------------------------------------------------*/
3272 /*--------------------------------------------------------------------------*/
3273 static double
3274 irplib_pfits_get_dit_opt(const cpl_propertylist * plist)
3275 {
3276  return irplib_pfits_get_prop_double(plist, "ESO DET WIN1 UIT1");
3277 }
3278 
3279 
3280 /*---------------------------------------------------------------------------*/
3285 static cpl_propertylist*
3286 detmon_load_pro_keys(const char* NAME_O)
3287 {
3288  cpl_propertylist* pro_keys=NULL;
3289  pro_keys=cpl_propertylist_load_regexp(NAME_O,0,"^(ESO PRO)",0);
3290  return pro_keys;
3291 }
3292 
3293 
3294 static double irplib_pfits_get_prop_double(const cpl_propertylist * plist,
3295  const char* prop_name)
3296 {
3297  double dit;
3298  dit = cpl_propertylist_get_double(plist, prop_name);
3299  if(cpl_error_get_code() != CPL_ERROR_NONE)
3300  {
3301  cpl_msg_error(cpl_func, "Cannot read property '%s', err[%s]",
3302  prop_name, cpl_error_get_where());
3303  }
3304  return dit;
3305 }
3306 
3307 static cpl_error_code
3308 detmon_gain_compute_qc(double kappa, int nclip, const int pos,
3309  const cpl_imagelist* offs, unsigned mode,
3310  double double_adu, double avg_on1, double avg_on2,
3311  double avg_off1, double avg_off2, double sigma,
3312  double sig_off_dif, double gain, int c_ndit,
3313  double gain_corr, double autocorr, cpl_image* on_dif,
3314  cpl_table* gain_table)
3315 {
3316 
3317  /* here detmon actually computes gain QC parameter */
3318  double avg_on_dif, sig_on_dif;
3319  irplib_ksigma_clip(on_dif, 1, 1, cpl_image_get_size_x(on_dif),
3320  cpl_image_get_size_y(on_dif), kappa, nclip, 1e-5,
3321  &avg_on_dif, &sig_on_dif);
3322  skip_if(
3323  cpl_table_set_double(gain_table, "SIG_ON_DIF", pos,
3324  sig_on_dif));
3325  if (cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE) {
3326  double_adu = (avg_on1 + avg_on2) - 2 * avg_off1;
3327  }
3328  else {
3329  double_adu = (avg_on1 + avg_on2) - (avg_off1 + avg_off2);
3330 
3331  sigma = (sig_on_dif * sig_on_dif) - (sig_off_dif * sig_off_dif);
3332 
3333  /* sigma_corr = autocorr * sigma; */
3334 
3335  gain = double_adu / (c_ndit * sigma);
3336 
3337  gain_corr = gain / (autocorr);
3338 
3339  skip_if(cpl_table_set_double(gain_table, "GAIN", pos, gain));
3340  skip_if(
3341  cpl_table_set_double(gain_table, "GAIN_CORR", pos,
3342  gain_corr));
3343  }
3344  /* cpl_msg_info(cpl_func,"gain=%g gain_corr=%g autocorr=%g",gain,gain_corr,autocorr); */
3345  skip_if(cpl_table_set_double(gain_table, "AUTOCORR", pos, autocorr));
3346  skip_if(cpl_table_set_double(gain_table, "ADU", pos, double_adu / 2));
3347  /* FIXME: Remove the following 3 columns after testing period */
3348  skip_if(
3349  cpl_table_set_double(gain_table, "Y_FIT", pos,
3350  c_ndit * sig_on_dif * sig_on_dif));
3351  skip_if(
3352  cpl_table_set_double(gain_table, "Y_FIT_CORR", pos,
3353  c_ndit * sig_on_dif * sig_on_dif));
3354  skip_if(cpl_table_set_double(gain_table, "X_FIT", pos, double_adu));
3355  skip_if(
3356  cpl_table_set_double(gain_table, "X_FIT_CORR", pos,
3357  double_adu / autocorr));
3358 
3359  end_skip;
3360 
3361  return cpl_error_get_code();
3362 }
3363 
3364 double
3365 detmon_gain_prepare_autocorr(unsigned mode, const int pos, double autocorr,
3366  int m, int n, cpl_imagelist* diff_flats,
3367  cpl_image* on_dif, cpl_imagelist* autocorr_images)
3368 {
3369  if (mode & IRPLIB_GAIN_WITH_AUTOCORR) {
3370  if (diff_flats) {
3371  cpl_image * diff = cpl_image_duplicate(on_dif);
3372  skip_if(cpl_imagelist_set(diff_flats, diff, pos));
3373  }
3374  if (autocorr_images) {
3375  cpl_image * corr = NULL;
3376  autocorr = detmon_autocorr_factor(on_dif, &corr, m, n);
3377  if (corr) {
3378  skip_if(cpl_imagelist_set(autocorr_images, corr, pos));
3379  }
3380  else {
3381  detmon_lg_add_empty_image(autocorr_images, pos);
3382  }
3383  }
3384  else {
3385  autocorr = detmon_autocorr_factor(on_dif, NULL, m, n);
3386  }
3387  autocorr = isnan(autocorr) ? 1.0 : autocorr;
3388  }
3389  else {
3390  autocorr = 1.0;
3391  }
3392  end_skip;
3393 
3394  return autocorr;
3395 }
3396 
3397 double
3398 detmon_gain_prepare_table(const cpl_imagelist* offs, unsigned mode, int llx,
3399  int lly, int urx, int ury, double kappa, int nclip,
3400  double avg_off1, double std, const int pos,
3401  cpl_table* gain_table, double* avg_off2,
3402  double* sig_off_dif)
3403 {
3404  /* prepare gain table to compute gain QC param */
3405  /* TODO: AMO sees that the condition (mode & IRPLIB_GAIN_NO_COLLAPSE)
3406  * is repeated in 2 if entries==> probably one should rewrite the if
3407  * construct
3408  */
3409  if (cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE) {
3410 
3411  skip_if(
3412  irplib_ksigma_clip(cpl_imagelist_get_const(offs, 0),
3413  llx, lly, urx, ury, kappa, nclip, 1e-5,
3414  &avg_off1, &std));
3415  skip_if(cpl_table_set_double(gain_table, "MEAN_OFF", pos, avg_off1));
3416 
3417  }
3418  else if ((mode & IRPLIB_GAIN_NO_COLLAPSE)
3419  || (pos == 0 && mode & IRPLIB_GAIN_COLLAPSE)) {
3420  cpl_image * off_dif = NULL;
3421  double avg_off_dif;
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_OFF1", pos, avg_off1));
3427  skip_if(
3428  irplib_ksigma_clip(cpl_imagelist_get_const(offs, 1),
3429  llx, lly, urx, ury, kappa, nclip, 1e-5,
3430  avg_off2, &std));
3431  skip_if(cpl_table_set_double(gain_table, "MEAN_OFF2", pos, *avg_off2));
3432  off_dif = detmon_subtract_create_window(
3433  cpl_imagelist_get_const(offs, 0),
3434  cpl_imagelist_get_const(offs, 1), llx, lly, urx, ury);
3435  skip_if(off_dif == NULL);
3436  irplib_ksigma_clip(off_dif, 1, 1, cpl_image_get_size_x(off_dif),
3437  cpl_image_get_size_y(off_dif), kappa, nclip, 1e-5,
3438  &avg_off_dif, sig_off_dif);
3439  cpl_image_delete(off_dif);
3440  skip_if(
3441  cpl_table_set_double(gain_table, "SIG_OFF_DIF", pos,
3442  *sig_off_dif));
3443  }
3444  else if (pos > 0 && (mode & IRPLIB_GAIN_COLLAPSE)) {
3445 
3446  int status;
3447  avg_off1 = cpl_table_get_double(gain_table, "MEAN_OFF1", 0, &status);
3448  skip_if(cpl_table_set_double(gain_table, "MEAN_OFF1", pos, avg_off1));
3449  *avg_off2 = cpl_table_get_double(gain_table, "MEAN_OFF2", 0, &status);
3450  skip_if(cpl_table_set_double(gain_table, "MEAN_OFF2", pos, *avg_off2));
3451  *sig_off_dif = cpl_table_get_double(gain_table, "SIG_OFF_DIF", 0,
3452  &status);
3453  skip_if(
3454  cpl_table_set_double(gain_table, "SIG_OFF_DIF", pos,
3455  *sig_off_dif));
3456  }
3457 
3458  end_skip;
3459 
3460  return avg_off1;
3461 }
3462 
3463 /*---------------------------------------------------------------------------*/
3498 /*---------------------------------------------------------------------------*/
3499 static cpl_error_code
3500 detmon_gain_table_fill_row(cpl_table * gain_table,
3501  double c_dit,int c_ndit,
3502  cpl_imagelist * autocorr_images,
3503  cpl_imagelist * diff_flats,
3504  const cpl_imagelist * ons,
3505  const cpl_imagelist * offs,
3506  double kappa, int nclip,
3507  int llx, int lly, int urx, int ury,
3508  int m, int n,
3509  double saturation_limit,
3510  double gain_threshold,
3511  const int pos, unsigned mode, int* rows_gain_affected)
3512 {
3513  const cpl_image *image;
3514  cpl_image *on_dif = NULL;
3515  double std = 0;
3516  double avg_on1, avg_on2;
3517  double avg_off1, avg_off2;
3518  double double_adu, autocorr, gain, gain_corr;
3519  double sigma;
3520 
3521  cpl_table_set(gain_table, "FLAG", pos, 1);
3522  if (mode & IRPLIB_GAIN_NIR)
3523  {
3524  cpl_table_set(gain_table, "DIT", pos, c_dit);
3525  cpl_table_set(gain_table, "NDIT", pos, c_ndit);
3526  } else if (mode & IRPLIB_GAIN_OPT)
3527  {
3528  cpl_table_set(gain_table, "EXPTIME", pos, c_dit);
3529  } else
3530  {
3531  cpl_msg_error(cpl_func, "Mandatory mode (OPT or NIR) not provided");
3532  skip_if(1);
3533  }
3534  if(*rows_gain_affected == 0)
3535  {
3536  cpl_msg_info(cpl_func, "skip the frame #%d", pos + 1);
3537  cpl_table_set(gain_table, "FLAG", pos, 0);
3538  if(mode & IRPLIB_GAIN_WITH_AUTOCORR)
3539  {
3540  autocorr = -1;
3541  if (diff_flats)
3542  {
3543  detmon_lg_add_empty_image(diff_flats, pos);
3544  }
3545  if (autocorr_images)
3546  {
3547  detmon_lg_add_empty_image(autocorr_images, pos);
3548  }
3549  }
3550  return cpl_error_get_code();
3551  }
3552  skip_if((image = cpl_imagelist_get_const(ons, 0)) == NULL);
3553  skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
3554  nclip, 1e-5, &avg_on1, &std));
3555  skip_if((image = cpl_imagelist_get_const(ons, 1)) == NULL);
3556  skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
3557  nclip, 1e-5, &avg_on2, &std));
3558 
3559  if (
3560  (avg_on1 > gain_threshold) ||
3561  (avg_on2 > gain_threshold)
3562  )
3563  {
3564  /* If frames has intensity above threshold write out warning and adjust
3565  * imagelists
3566  */
3567  if ( (avg_on1 > gain_threshold) || (avg_on2 > gain_threshold) )
3568  {
3569  cpl_msg_warning(cpl_func, "Average level is above the limit set by the gain_theshold parameter, "
3570  "the frames would not be taken into calculation");
3571 
3572  cpl_msg_warning(cpl_func, "Average levels [%f ; %f], limit [%f]",
3573  avg_on1, avg_on2, gain_threshold);
3574  }
3575 
3576  cpl_msg_info(cpl_func, "skip the frame #%d", pos + 1);
3577  cpl_table_set(gain_table, "FLAG", pos, 0);
3578  if(mode & IRPLIB_GAIN_WITH_AUTOCORR)
3579  {
3580  autocorr = -1;
3581  if (diff_flats)
3582  {
3583  detmon_lg_add_empty_image(diff_flats, pos);
3584  }
3585  if (autocorr_images)
3586  {
3587  detmon_lg_add_empty_image(autocorr_images, pos);
3588  }
3589  }
3590  *rows_gain_affected = 0;
3591  }
3592  else
3593  {
3594  /* we can compute gain: first computes relevant quantities to cover all
3595  * cases, then compute QC parameter.
3596  */
3597  double sig_off_dif;
3598  *rows_gain_affected = 1;
3599  skip_if(cpl_table_set_double(gain_table, "MEAN_ON1", pos, avg_on1));
3600  skip_if(cpl_table_set_double(gain_table, "MEAN_ON2", pos, avg_on2));
3601 
3602  on_dif =
3603  detmon_subtract_create_window(cpl_imagelist_get_const(ons, 0),
3604  cpl_imagelist_get_const(ons, 1),
3605  llx, lly, urx, ury);
3606  skip_if(on_dif == NULL);
3607 
3608  autocorr = detmon_gain_prepare_autocorr(mode, pos, autocorr, m, n,
3609  diff_flats, on_dif, autocorr_images);
3610 
3611  avg_off1 = detmon_gain_prepare_table(offs, mode, llx, lly, urx, ury,
3612  kappa, nclip, avg_off1, std, pos, gain_table, &avg_off2,
3613  &sig_off_dif);
3614 
3615  detmon_gain_compute_qc(kappa, nclip, pos, offs, mode, double_adu,
3616  avg_on1, avg_on2, avg_off1, avg_off2, sigma,
3617  sig_off_dif, gain, c_ndit, gain_corr, autocorr, on_dif,
3618  gain_table);
3619  }
3620  end_skip;
3621 
3622  cpl_image_delete(on_dif);
3623 
3624  return cpl_error_get_code();
3625 }
3626 
3627 
3628 
3629 /*---------------------------------------------------------------------------*/
3651 /*---------------------------------------------------------------------------*/
3652 static cpl_error_code
3653 detmon_check_saturation_on_pair(cpl_imagelist * autocorr_images,
3654  cpl_imagelist * diff_flats,
3655  const cpl_imagelist * ons,
3656  const cpl_imagelist * offs,
3657  double kappa, int nclip,
3658  int llx, int lly, int urx, int ury,
3659  double saturation_limit,
3660  const int pos, unsigned mode, int* rows_linear_affected)
3661 {
3662  const cpl_image *image;
3663  double std = 0;
3664  double avg_on1, avg_on2;
3665  double sigma;
3666 
3667 
3668  if(*rows_linear_affected == 0)
3669  {
3670  cpl_msg_info(cpl_func, "For linearity skip the frame #%d", pos + 1);
3671  if(mode & IRPLIB_GAIN_WITH_AUTOCORR)
3672  {
3673  if (diff_flats)
3674  {
3675  detmon_lg_add_empty_image(diff_flats, pos);
3676  }
3677  if (autocorr_images)
3678  {
3679  detmon_lg_add_empty_image(autocorr_images, pos);
3680  }
3681  }
3682  return cpl_error_get_code();
3683  }
3684  skip_if((image = cpl_imagelist_get_const(ons, 0)) == NULL);
3685  skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
3686  nclip, 1e-5, &avg_on1, &std));
3687  skip_if((image = cpl_imagelist_get_const(ons, 1)) == NULL);
3688  skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
3689  nclip, 1e-5, &avg_on2, &std));
3690 
3691  if (
3692  (avg_on1 > saturation_limit) ||
3693  (avg_on2 > saturation_limit)
3694  )
3695  {
3696  /* If frames has intensity above threshold write out warning and adjust
3697  * imagelists
3698  */
3699  if ( (avg_on1 > saturation_limit) || (avg_on2 > saturation_limit) )
3700  {
3701  cpl_msg_warning(cpl_func, "Average level is above the limit set by the saturation_limit parameter, "
3702  "the frames would not be taken into calculation");
3703 
3704  cpl_msg_warning(cpl_func, "Average levels [%f ; %f], limit [%f]",
3705  avg_on1, avg_on2, saturation_limit);
3706  }
3707 
3708  cpl_msg_info(cpl_func, "skip the frame #%d", pos + 1);
3709  *rows_linear_affected = 0;
3710  } else{
3711 
3712  }
3713 
3714  end_skip;
3715 
3716  return cpl_error_get_code();
3717 }
3718 
3719 
3720 
3721 
3722 /*--------------------------------------------------------------------------*/
3729 /*--------------------------------------------------------------------------*/
3730 
3731 static cpl_image *
3732 detmon_bpixs(const cpl_imagelist * coeffs,
3733  cpl_boolean bpmbin,
3734  const double kappa,
3735  int *nbpixs)
3736 {
3737  int size;
3738  int i;
3739  const cpl_image *first= cpl_imagelist_get_const(coeffs, 0);
3740  cpl_stats *stats;
3741  double cur_mean;
3742  double cur_stdev;
3743  double lo_cut;
3744  double hi_cut;
3745  cpl_mask *cur_mask;
3746  cpl_mask *mask = cpl_mask_new(cpl_image_get_size_x(first),
3747  cpl_image_get_size_y(first));
3748  cpl_image *cur_image = NULL;
3749  cpl_image *bpm = NULL; /* Avoid false uninit warning */
3750  double p;
3751 
3752  size = cpl_imagelist_get_size(coeffs);
3753 
3754  if(!bpmbin) {
3755  bpm = cpl_image_new(cpl_image_get_size_x(first),
3756  cpl_image_get_size_y(first),
3757  CPL_TYPE_INT);
3758  }
3759 
3760 
3761  for(i = 0; i < size; i++) {
3762  const cpl_image * cur_coeff = cpl_imagelist_get_const(coeffs, i);
3763 
3764  stats = cpl_stats_new_from_image(cur_coeff,
3765  CPL_STATS_MEAN | CPL_STATS_STDEV);
3766  cur_mean = cpl_stats_get_mean(stats);
3767  cur_stdev = cpl_stats_get_stdev(stats);
3768 
3769  lo_cut = cur_mean - kappa * cur_stdev;
3770  hi_cut = cur_mean + kappa * cur_stdev;
3771 
3772  cur_mask = cpl_mask_threshold_image_create(cur_coeff, lo_cut, hi_cut);
3773  cpl_mask_not(cur_mask);
3774 
3775  if(!bpmbin) {
3776  cur_image = cpl_image_new_from_mask(cur_mask);
3777  p = pow(2, i);
3778  cpl_image_power(cur_image, p);
3779  cpl_image_add(bpm, cur_image);
3780  cpl_image_delete(cur_image);
3781  }
3782 
3783  cpl_mask_or(mask, cur_mask);
3784 
3785  cpl_mask_delete(cur_mask);
3786  cpl_stats_delete(stats);
3787  }
3788 
3789  if(bpmbin) {
3790  bpm = cpl_image_new_from_mask(mask);
3791  }
3792 
3793  *nbpixs += cpl_mask_count(mask);
3794 
3795  cpl_mask_delete(mask);
3796 
3797  return bpm;
3798 }
3799 
3800 
3801 /*--------------------------------------------------------------------------*/
3808 /*--------------------------------------------------------------------------*/
3809 /* Not used so we temporary comment it out
3810 static cpl_image *
3811 detmon_bpixs2(cpl_vector* x,const cpl_imagelist* y,
3812  const cpl_imagelist * coeffs,cpl_table* gain_table,
3813  const int order, const double kappa,cpl_boolean bpmbin,
3814  int *nbpixs)
3815 {
3816 
3817 
3818  int size_x=0;
3819  int size_y=0;
3820  int size_c=0;
3821 
3822 
3823  int i=0;
3824  int j=0;
3825  cpl_size k=0;
3826  int z=0;
3827  int pix=0;
3828  int sx=0;
3829  int sy=0;
3830 
3831  double* px=NULL;
3832  const float* pdata=NULL;
3833  const float* pcoeffs=NULL;
3834  double pfit=0.;
3835  double* pgain=NULL;
3836  cpl_binary* pmask=NULL;
3837  double gain=0;
3838  const cpl_image* img_data=NULL;
3839 
3840  const cpl_image* img_coeffs=NULL;
3841  cpl_image* bpm=NULL;
3842  cpl_mask* mask=NULL;
3843 
3844  cpl_polynomial* pol=NULL;
3845 
3846  size_x = cpl_vector_get_size(x);
3847  size_y = cpl_imagelist_get_size(y);
3848  size_c = cpl_imagelist_get_size(coeffs);
3849  img_data = cpl_imagelist_get_const(coeffs, 0);
3850  sx = cpl_image_get_size_x(img_data);
3851  sy = cpl_image_get_size_y(img_data);
3852  mask = cpl_mask_new(sx,sy);
3853 
3854  cpl_ensure(size_x == size_y, CPL_ERROR_NULL_INPUT, NULL);
3855 
3856  cpl_ensure(size_c == (order+1), CPL_ERROR_NULL_INPUT, NULL);
3857 
3858  px = cpl_vector_get_data(x);
3859  pmask=cpl_mask_get_data(mask);
3860  pgain=cpl_table_get_data_double(gain_table,"GAIN");
3861  pol=cpl_polynomial_new(1);
3862  for (z = 0; z < size_x; z++) {
3863 
3864  img_data = cpl_imagelist_get_const(y, z);
3865  pdata = cpl_image_get_data_float_const(img_data);
3866  gain=pgain[z];
3867 
3868  for (j = 0; j < sy; j++) {
3869 
3870  for (i = 0; i < sx; i++) {
3871 
3872  pix = j * sx + i;
3873 
3874  for (k = size_c-1; k >= 0; k--) {
3875 
3876  img_coeffs = cpl_imagelist_get_const(coeffs, k);
3877  pcoeffs = cpl_image_get_data_float_const(img_coeffs);
3878  cpl_polynomial_set_coeff(pol, &k, pcoeffs[pix]);
3879 
3880  }
3881 
3882  pfit = cpl_polynomial_eval_1d(pol,px[z],NULL);
3883  if (pdata[pix] > 0) {
3884  if (fabs(pdata[pix] - pfit) > kappa * sqrt(gain*pdata[pix])) {
3885  pmask[pix] = CPL_BINARY_1;
3886  } // check if point to be flagged
3887  } // check if pos intensity
3888  } // i loop
3889  } // j loop
3890 
3891  //cpl_image_delete(img_data);
3892 
3893  } // z loop
3894  cpl_polynomial_delete(pol);
3895  if (bpmbin) {
3896  bpm = cpl_image_new_from_mask(mask);
3897  }
3898 
3899  *nbpixs += cpl_mask_count(mask);
3900 
3901  cpl_mask_delete(mask);
3902 
3903  return bpm;
3904 }
3905 
3906 */
3907 /*---------------------------------------------------------------------------*/
3919 /*---------------------------------------------------------------------------*/
3920 
3921 static double
3922 detmon_autocorr_factor(const cpl_image * image,
3923  cpl_image ** autocorr_image, int m, int n)
3924 {
3925  cpl_image * mycorr_image = NULL;
3926  double autocorr = 0;
3927  cpl_error_code err = CPL_ERROR_NONE;
3928 
3929  mycorr_image = detmon_image_correlate(image, image, m, n);
3930  err=cpl_error_get_code();
3931  if (err == CPL_ERROR_UNSUPPORTED_MODE)
3932  {
3933  cpl_msg_warning(cpl_func, "FFTW is not supported by CPL, autocorrelation "
3934  "would be computed using internal implementation");
3935  cpl_error_reset();
3936  if (mycorr_image)
3937  cpl_image_delete(mycorr_image);
3938  mycorr_image = detmon_autocorrelate(image, m, n);
3939  }
3940  if(mycorr_image == NULL) {
3941  return -1;
3942  }
3943 
3944  cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), -1);
3945 
3946  autocorr = cpl_image_get_flux(mycorr_image);
3947 
3948  if (autocorr_image) *autocorr_image = mycorr_image;
3949  else cpl_image_delete(mycorr_image);
3950 
3951  return autocorr;
3952 }
3953 
3954 static cpl_propertylist*
3955 detmon_lg_extract_qclist_4plane(cpl_propertylist* linc_qclist,const int ip)
3956 {
3957 
3958  cpl_propertylist* sub_set=NULL;
3959  char* qc_key=NULL;
3960 
3961  sub_set=cpl_propertylist_new();
3962  qc_key=cpl_sprintf("QC LIN COEF%d",ip);
3963  cpl_propertylist_copy_property_regexp(sub_set,linc_qclist,qc_key,0);
3964 
3965  cpl_free(qc_key);
3966  return sub_set;
3967 
3968 }
3969 
3970 
3980 static cpl_error_code
3981 detmon_lg_extract_extention_header(cpl_frameset* frameset,
3982  cpl_propertylist* gaint_qclist,
3983  cpl_propertylist* lint_qclist,
3984  cpl_propertylist* linc_qclist,
3985  cpl_propertylist* bpm_qclist,
3986  int whichext)
3987 {
3988 
3989  cpl_propertylist * xplist = NULL;
3990 
3991  const char * filename =
3992  cpl_frame_get_filename(cpl_frameset_get_first(frameset));
3993 
3994  xplist = cpl_propertylist_load_regexp(filename, whichext,
3995  "ESO DET|EXTNAME", 0);
3996  if (detmon_lg_config.exts >= 0)
3997  {
3998  /* for one extension, copy only extname keyword (if any) - DFS09856 */
3999  cpl_property* propExtname = NULL;
4000  propExtname = cpl_propertylist_get_property(xplist, "EXTNAME");
4001  cpl_error_reset();
4002  if (NULL != propExtname)
4003  {
4004  propExtname = cpl_property_duplicate(propExtname);
4005  }
4006  cpl_propertylist_delete(xplist);
4007  xplist = NULL;
4008  if (NULL != propExtname)
4009  {
4010  xplist = cpl_propertylist_new();
4011  cpl_propertylist_append_property(xplist, propExtname);
4012  cpl_property_delete(propExtname);
4013  }
4014  }
4015  if (NULL != xplist)
4016  {
4017  cpl_propertylist_append(gaint_qclist, xplist);
4018  cpl_propertylist_append(lint_qclist, xplist);
4019  cpl_propertylist_append(linc_qclist, xplist);
4020  cpl_propertylist_append(bpm_qclist, xplist);
4021  cpl_propertylist_delete(xplist);
4022  }
4023 
4024  return cpl_error_get_code();
4025 }
4026 
4027 
4028 
4029 
4030 
4031 /*---------------------------------------------------------------------------*/
4040 /*---------------------------------------------------------------------------*/
4041 static cpl_error_code
4042 detmon_lg_save_table_with_pro_keys(cpl_table* table,
4043  const char* name_o,
4044  cpl_propertylist* xheader,
4045  unsigned CPL_IO_MODE)
4046 {
4047 
4048  cpl_propertylist* pro_keys=NULL;
4049 
4050  pro_keys=detmon_load_pro_keys(name_o);
4051  cpl_propertylist_append(xheader,pro_keys);
4052 
4053  if(CPL_IO_MODE==CPL_IO_DEFAULT) {
4054  cpl_propertylist * pri_head=cpl_propertylist_load(name_o,0);
4055  cpl_table_save(table, pri_head,xheader,name_o,
4056  CPL_IO_DEFAULT);
4057  cpl_propertylist_delete(pri_head);
4058 
4059  } else {
4060  cpl_table_save(table,NULL,xheader,name_o,
4061  CPL_IO_EXTEND);
4062  }
4063  cpl_propertylist_delete(pro_keys);
4064 
4065  return cpl_error_get_code();
4066 }
4067 
4068 /*---------------------------------------------------------------------------*/
4076 /*---------------------------------------------------------------------------*/
4077 static cpl_error_code
4078 detmon_lg_save_image_with_pro_keys(cpl_image* image,
4079  const char* name_o,
4080  cpl_propertylist* xheader)
4081 {
4082 
4083  cpl_propertylist* pro_keys=NULL;
4084  pro_keys=detmon_load_pro_keys(name_o);
4085  cpl_propertylist_append(xheader,pro_keys);
4086 
4087  cpl_image_save(image,name_o, CPL_BPP_IEEE_FLOAT,
4088  xheader,CPL_IO_EXTEND);
4089  cpl_propertylist_delete(pro_keys);
4090 
4091 
4092  return cpl_error_get_code();
4093 }
4094 
4095 /*---------------------------------------------------------------------------*/
4103 /*---------------------------------------------------------------------------*/
4104 static cpl_error_code
4105 detmon_lg_save_imagelist_with_pro_keys(cpl_imagelist* imagelist,
4106  const char* name_o,
4107  cpl_propertylist* xheader)
4108 {
4109 
4110  cpl_propertylist* pro_keys=NULL;
4111  pro_keys=detmon_load_pro_keys(name_o);
4112  cpl_propertylist_append(xheader,pro_keys);
4113 
4114  cpl_imagelist_save(imagelist,name_o, CPL_BPP_IEEE_FLOAT,
4115  xheader,CPL_IO_EXTEND);
4116 
4117  cpl_propertylist_delete(pro_keys);
4118 
4119 
4120  return cpl_error_get_code();
4121 }
4122 
4123 /*---------------------------------------------------------------------------*/
4140 static cpl_error_code
4141 detmon_lg_save_plane(const cpl_parameterlist * parlist,
4142  cpl_frameset* frameset,
4143  const cpl_frameset * usedframes,
4144  int whichext,
4145  const char* recipe_name,
4146  cpl_propertylist* mypro_coeffscube,
4147  cpl_propertylist* linc_plane_qclist,
4148  const char* package,
4149  const char* NAME_O,
4150  cpl_image* plane)
4151 {
4152  if(detmon_lg_config.exts == 0) {
4153  cpl_propertylist* plist=NULL;
4154  cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4155  NULL, NULL,
4156  CPL_BPP_IEEE_FLOAT, recipe_name,
4157  mypro_coeffscube, NULL,
4158  package, NAME_O);
4159  plist=cpl_propertylist_load(NAME_O,0);
4160  cpl_image_save(plane,NAME_O, CPL_BPP_IEEE_FLOAT,
4161  plist,CPL_IO_DEFAULT);
4162  cpl_propertylist_delete(plist);
4163 
4164  } else if(detmon_lg_config.exts > 0) {
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 
4171  detmon_lg_save_image_with_pro_keys(plane,NAME_O,linc_plane_qclist);
4172  } else {
4173  if(whichext == 1)
4174  {
4175  cpl_dfs_save_image(frameset, NULL, parlist,
4176  usedframes,NULL, NULL,
4177  CPL_BPP_IEEE_FLOAT, recipe_name,
4178  mypro_coeffscube, NULL,
4179  package, NAME_O);
4180  detmon_lg_save_image_with_pro_keys(plane,NAME_O,linc_plane_qclist);
4181  } else {
4182 
4183  detmon_lg_save_image_with_pro_keys(plane,NAME_O,linc_plane_qclist);
4184 
4185  }
4186 
4187  }
4188 
4189  return cpl_error_get_code();
4190 }
4191 
4192 
4193 
4194 /*---------------------------------------------------------------------------*/
4212 static cpl_error_code
4213 detmon_lg_save_cube(const cpl_parameterlist * parlist,
4214  cpl_frameset* frameset,
4215  const cpl_frameset * usedframes,
4216  int whichext,
4217  const char* recipe_name,
4218  cpl_propertylist* mypro_coeffscube,
4219  cpl_propertylist* linc_qclist,
4220  const char* package,
4221  const char* NAME_O,
4222  cpl_imagelist* coeffs)
4223 {
4224 
4225  if(detmon_lg_config.exts == 0) {
4226  cpl_propertylist_append(mypro_coeffscube, linc_qclist);
4227  detmon_lg_dfs_save_imagelist
4228  (frameset, parlist, usedframes, coeffs,
4229  recipe_name, mypro_coeffscube, package,
4230  NAME_O);
4231  } else if(detmon_lg_config.exts > 0) {
4232  cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4233  NULL, NULL,
4234  CPL_BPP_IEEE_FLOAT, recipe_name,
4235  mypro_coeffscube, NULL,
4236  package, NAME_O);
4237 
4238  detmon_lg_save_imagelist_with_pro_keys(coeffs,NAME_O,linc_qclist);
4239 
4240  } else {
4241  if(whichext == 1) {
4242  cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4243  NULL, NULL,
4244  CPL_BPP_IEEE_FLOAT, recipe_name,
4245  mypro_coeffscube, NULL,
4246  package, NAME_O);
4247  if (coeffs)
4248  detmon_lg_save_imagelist_with_pro_keys(coeffs,NAME_O,linc_qclist);
4249  else
4250  cpl_propertylist_save(linc_qclist, NAME_O, CPL_IO_EXTEND);
4251  } else {
4252  if (coeffs)
4253  detmon_lg_save_imagelist_with_pro_keys(coeffs,NAME_O,linc_qclist);
4254  else
4255  cpl_propertylist_save(linc_qclist, NAME_O, CPL_IO_EXTEND);
4256  }
4257  }
4258 
4259  return cpl_error_get_code();
4260 }
4261 
4262 static char*
4263 detmon_lg_set_paf_name_and_header(cpl_frame* ref_frame,
4264  int flag_sets,int which_set,
4265  int whichext,
4266  const char* paf_suf,
4267  cpl_propertylist** plist)
4268 {
4269  char * paf_name=NULL;
4270 
4271  if(detmon_lg_config.exts >= 0)
4272  {
4273  *plist =cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4274  detmon_lg_config.exts);
4275 
4276  if(!flag_sets)
4277  {
4278  paf_name=cpl_sprintf("%s_%s.paf", detmon_lg_config.pafname,paf_suf);
4279  }
4280  else
4281  {
4282  paf_name=cpl_sprintf("%s_%s_set%02d.paf",
4283  detmon_lg_config.pafname, paf_suf,which_set);
4284  }
4285  }
4286  else
4287  {
4288  *plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4289  whichext);
4290 
4291 
4292  if(!flag_sets)
4293  {
4294  paf_name=cpl_sprintf("%s_%s_ext%02d.paf",
4295  detmon_lg_config.pafname, paf_suf,whichext);
4296  }
4297  else
4298  {
4299  paf_name=cpl_sprintf("%s_%s_set%02d_ext%02d.paf",
4300  detmon_lg_config.pafname,paf_suf,
4301  which_set, whichext);
4302  }
4303  }
4304 
4305  return paf_name;
4306 }
4307 
4308 
4309 static char*
4310 detmon_lg_set_paf_name_and_header_ext(cpl_frame* ref_frame,
4311  int flag_sets,int which_set,
4312  int whichext,
4313  const char* paf_suf,
4314  cpl_propertylist** plist)
4315 {
4316  char* paf_name=NULL;
4317 
4318  if(detmon_lg_config.exts >= 0)
4319  {
4320  *plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4321  detmon_lg_config.exts);
4322 
4323  if(!flag_sets)
4324  {
4325  paf_name=cpl_sprintf("%s_%s.paf", detmon_lg_config.pafname,paf_suf);
4326  } else
4327  {
4328  paf_name=cpl_sprintf("%s_%s_set%02d.paf",
4329  detmon_lg_config.pafname, paf_suf,which_set);
4330  }
4331  } else
4332  {
4333  *plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4334  whichext);
4335  if(!flag_sets)
4336  {
4337  paf_name=cpl_sprintf("%s_%s_ext%02d.paf",
4338  detmon_lg_config.pafname, paf_suf,whichext);
4339  } else
4340  {
4341  paf_name=cpl_sprintf("%s_%s_set%02d_ext%02d.paf",
4342  detmon_lg_config.pafname,paf_suf,
4343  which_set, whichext);
4344  }
4345  }
4346  return paf_name;
4347 
4348 }
4349 
4350 static cpl_error_code
4351 detmon_lg_save_paf_product(cpl_frame* ref_frame,int flag_sets,
4352  int which_set,int whichext,
4353  const char* pafregexp,
4354  const char* procatg,
4355  const char* pipeline_name,
4356  const char* recipe_name,
4357  const char* paf_suf,
4358  cpl_propertylist* qclist,
4359  const int ext)
4360 
4361 {
4362  /* Set the file name for the linearity table PAF */
4363  char* paf_name=NULL;
4364  cpl_propertylist* plist=NULL;
4365  cpl_propertylist* paflist = NULL;
4366  cpl_propertylist* mainplist=NULL;
4367 
4368  mainplist =cpl_propertylist_load(cpl_frame_get_filename(ref_frame),0);
4369  if(ext==0) {
4370  paf_name=detmon_lg_set_paf_name_and_header(ref_frame,flag_sets,
4371  which_set,whichext,
4372  paf_suf,&plist);
4373  } else {
4374  paf_name=detmon_lg_set_paf_name_and_header_ext(ref_frame,flag_sets,
4375  which_set,whichext,
4376  paf_suf,&plist);
4377  }
4378 
4379 
4380  paflist = cpl_propertylist_new();
4381  cpl_propertylist_append_string(paflist, CPL_DFS_PRO_CATG,procatg);
4382 
4383  /* Get the keywords for the paf file */
4384  cpl_propertylist_copy_property_regexp(paflist, plist,pafregexp, 0);
4385  cpl_propertylist_copy_property_regexp(paflist, mainplist,pafregexp, 0);
4386  cpl_propertylist_append(paflist,qclist);
4387 
4388  /* Save the PAF */
4389  cpl_dfs_save_paf(pipeline_name, recipe_name,paflist,paf_name);
4390 
4391  /* free memory */
4392  cpl_propertylist_delete(mainplist);
4393  cpl_propertylist_delete(paflist);
4394  cpl_propertylist_delete(plist);
4395  cpl_free(paf_name);
4396 
4397  return cpl_error_get_code();
4398 
4399 }
4400 
4401 
4402 
4403 /*---------------------------------------------------------------------------*/
4434 static cpl_error_code
4435 detmon_lg_save(const cpl_parameterlist * parlist,
4436  cpl_frameset * frameset,
4437  const char *recipe_name,
4438  const char *pipeline_name,
4439  const char *pafregexp,
4440  const cpl_propertylist * pro_lintbl,
4441  const cpl_propertylist * pro_gaintbl,
4442  const cpl_propertylist * pro_coeffscube,
4443  const cpl_propertylist * pro_bpm,
4444  const cpl_propertylist * pro_corr,
4445  const cpl_propertylist * pro_diff,
4446  const char *package,
4447  cpl_imagelist * coeffs,
4448  cpl_table * gain_table,
4449  cpl_table * linear_table,
4450  cpl_image * bpms,
4451  cpl_imagelist * autocorr_images,
4452  cpl_imagelist * diff_flats,
4453  cpl_propertylist * gaint_qclist,
4454  cpl_propertylist * lint_qclist,
4455  cpl_propertylist * linc_qclist,
4456  cpl_propertylist * bpm_qclist,
4457  const int flag_sets,
4458  const int which_set,
4459  const cpl_frameset * usedframes,
4460  int whichext)
4461 {
4462 
4463  cpl_frame *ref_frame;
4464  cpl_propertylist *plist = NULL;
4465  cpl_propertylist *mainplist = NULL;
4466  char* NAME_O=NULL;
4467  char* PREF_O=NULL;
4468  int nb_images;
4469  int i;
4470 
4471  cpl_propertylist * xplist = NULL;
4472 
4473  cpl_propertylist* linc_plane_qclist=NULL;
4474  cpl_image* plane=NULL;
4475  int ip=0;
4476  char* pcatg_plane=NULL;
4477 
4478  cpl_propertylist * mypro_lintbl =
4479  cpl_propertylist_duplicate(pro_lintbl);
4480  cpl_propertylist * mypro_gaintbl =
4481  cpl_propertylist_duplicate(pro_gaintbl);
4482  cpl_propertylist * mypro_coeffscube =
4483  cpl_propertylist_duplicate(pro_coeffscube);
4484  cpl_propertylist * mypro_bpm =
4485  cpl_propertylist_duplicate(pro_bpm);
4486  cpl_propertylist * mypro_corr =
4487  cpl_propertylist_duplicate(pro_corr);
4488  cpl_propertylist * mypro_diff =
4489  cpl_propertylist_duplicate(pro_diff);
4490 
4491  const char * procatg_lintbl =
4492  cpl_propertylist_get_string(mypro_lintbl, CPL_DFS_PRO_CATG);
4493 
4494  const char * procatg_gaintbl =
4495  cpl_propertylist_get_string(mypro_gaintbl, CPL_DFS_PRO_CATG);
4496 
4497  const char * procatg_coeffscube =
4498  cpl_propertylist_get_string(mypro_coeffscube, CPL_DFS_PRO_CATG);
4499  const char * procatg_bpm =
4500  cpl_propertylist_get_string(mypro_bpm, CPL_DFS_PRO_CATG);
4501 
4502 
4503  /* Extract extension headers if multi-extension */
4504  detmon_lg_extract_extention_header(frameset,gaint_qclist,lint_qclist,
4505  linc_qclist,bpm_qclist,whichext);
4506 
4507  /* This is only used later for PAF and temporarily for COEFFS_CUBE
4508  (see if defined)*/
4509  /* Get FITS header from reference file */
4510  ref_frame = cpl_frameset_get_first(frameset);
4511 
4512  skip_if((mainplist =
4513  cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4514  0)) == NULL);
4515 
4516  /*******************************/
4517  /* Write the LINEARITY TABLE */
4518  /*******************************/
4519  cpl_msg_info(cpl_func,"Write the LINEARITY TABLE");
4520  /* Set the file name for the table */
4521  if(!flag_sets) {
4522  NAME_O=cpl_sprintf("%s_linearity_table.fits", recipe_name);
4523  } else {
4524  NAME_O=cpl_sprintf("%s_linearity_table_set%02d.fits", recipe_name,
4525  which_set);
4526  }
4527 
4528  if (detmon_lg_config.exts >= 0) {
4529  /* Save the table */
4530  cpl_propertylist_append(mypro_lintbl, lint_qclist);
4531  skip_if(cpl_dfs_save_table(frameset, NULL,parlist, usedframes, NULL,
4532  linear_table,NULL, recipe_name,
4533  mypro_lintbl, NULL, package, NAME_O));
4534 
4535  detmon_lg_save_table_with_pro_keys(linear_table,NAME_O,
4536  lint_qclist,CPL_IO_DEFAULT);
4537 
4538  } else {
4539  if(whichext == 1) {
4540  /* Save the 1. extension table */
4541  skip_if(cpl_dfs_save_table(frameset,NULL, parlist, usedframes, NULL,
4542  linear_table,lint_qclist, recipe_name,
4543  mypro_lintbl,NULL, package, NAME_O));
4544  detmon_lg_save_table_with_pro_keys(linear_table,NAME_O,
4545  lint_qclist,CPL_IO_DEFAULT);
4546 
4547 
4548 
4549 
4550  } else {
4551 
4552  detmon_lg_save_table_with_pro_keys(linear_table,NAME_O,
4553  lint_qclist,CPL_IO_EXTEND);
4554  }
4555  }
4556  irplib_free(&NAME_O);
4557  /**************************/
4558  /* Write the GAIN TABLE */
4559  /**************************/
4560  cpl_msg_info(cpl_func,"Write the GAIN TABLE");
4561  /* Set the file name for the table */
4562  if(!flag_sets) {
4563  NAME_O=cpl_sprintf("%s_gain_table.fits", recipe_name);
4564  } else {
4565  NAME_O=cpl_sprintf("%s_gain_table_set%02d.fits", recipe_name,
4566  which_set);
4567  }
4568 
4569  if (detmon_lg_config.exts >= 0)
4570  {
4571  /* Save the table */
4572 
4573  cpl_propertylist_append(mypro_gaintbl, gaint_qclist);
4574  skip_if(cpl_dfs_save_table(frameset, NULL, parlist, usedframes, NULL,
4575  gain_table,NULL, recipe_name, mypro_gaintbl,
4576  NULL, package, NAME_O));
4577  detmon_lg_save_table_with_pro_keys(gain_table,NAME_O,
4578  gaint_qclist,CPL_IO_DEFAULT);
4579 
4580  }
4581  else
4582  {
4583  if(whichext == 1)
4584  {
4585  /* Save the 1. extension table */
4586  skip_if(cpl_dfs_save_table(frameset, NULL, parlist, usedframes, NULL, gain_table,
4587  gaint_qclist, recipe_name, mypro_gaintbl,
4588  NULL, package, NAME_O));
4589  detmon_lg_save_table_with_pro_keys(gain_table,NAME_O,
4590  gaint_qclist,CPL_IO_DEFAULT);
4591 
4592  }
4593  else
4594  {
4595 
4596  detmon_lg_save_table_with_pro_keys(gain_table,NAME_O,
4597  gaint_qclist,CPL_IO_EXTEND);
4598  }
4599  }
4600 
4601  if(detmon_lg_config.pix2pix)
4602  {
4603 
4604  /***************************/
4605  /* Write the COEFFS FITS */
4606  /***************************/
4607  cpl_msg_info(cpl_func,"Write the COEFFS FITS");
4608  irplib_free(&NAME_O);
4609  if(!flag_sets)
4610  {
4611  PREF_O=cpl_sprintf("%s_coeffs_cube", recipe_name);
4612  } else
4613  {
4614  PREF_O=cpl_sprintf("%s_coeffs_cube_set%02d",
4615  recipe_name, which_set);
4616  }
4617  if (detmon_lg_config.split_coeffs == 0) {
4618  NAME_O=cpl_sprintf("%s.fits", PREF_O);
4619  }
4620 
4621 
4622  /* Save the imagelist */
4623  if(detmon_lg_config.split_coeffs != 0){
4624 
4625 
4626  nb_images = cpl_imagelist_get_size(coeffs);
4627  for(ip=0;ip<nb_images;ip++) {
4628  NAME_O=cpl_sprintf("%s_P%d.fits", PREF_O,ip);
4629  pcatg_plane=cpl_sprintf("COEFFS_CUBE_P%d",ip);
4630  cpl_propertylist_delete(mypro_coeffscube);
4631  mypro_coeffscube=cpl_propertylist_duplicate(pro_coeffscube);
4632  cpl_propertylist_set_string(mypro_coeffscube,CPL_DFS_PRO_CATG,
4633  pcatg_plane);
4634  linc_plane_qclist=detmon_lg_extract_qclist_4plane(linc_qclist,ip);
4635  cpl_propertylist_append(mypro_coeffscube, linc_plane_qclist);
4636  plane=cpl_imagelist_get(coeffs,ip);
4637  detmon_lg_save_plane(parlist,frameset,usedframes,whichext,
4638  recipe_name,mypro_coeffscube,
4639  linc_plane_qclist,package,NAME_O,plane);
4640 
4641  if(NULL!=linc_plane_qclist) {
4642  cpl_propertylist_delete(linc_plane_qclist);
4643  }
4644  irplib_free(&NAME_O);
4645 
4646  } /* end for loop over cube planes */
4647  } else {
4648 
4649  detmon_lg_save_cube(parlist,frameset,usedframes,whichext,
4650  recipe_name,mypro_coeffscube,
4651  linc_qclist,package,NAME_O,coeffs);
4652  }
4653 
4654  /*******************************/
4655  /* Write the BAD PIXEL MAP */
4656  /*******************************/
4657  cpl_msg_info(cpl_func,"Write the BAD PIXEL MAP");
4658  irplib_free(&NAME_O);
4659  /* Set the file name for the bpm */
4660  if(!flag_sets)
4661  {
4662  NAME_O=cpl_sprintf("%s_bpm.fits", recipe_name);
4663  } else
4664  {
4665  NAME_O=cpl_sprintf("%s_bpm_set%02d.fits", recipe_name, which_set);
4666  }
4667 
4668 
4669  /* Save the image */
4670  if(detmon_lg_config.exts == 0) {
4671  cpl_propertylist_append(mypro_bpm, bpm_qclist);
4672  cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL, bpms,
4673  CPL_BPP_IEEE_FLOAT, recipe_name,
4674  mypro_bpm, NULL, package,
4675  NAME_O);
4676  }
4677  else if(detmon_lg_config.exts > 0)
4678  {
4679  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,NULL, NULL,
4680  CPL_BPP_IEEE_FLOAT, recipe_name,
4681  mypro_bpm, NULL, package,
4682  NAME_O));
4683  detmon_lg_save_image_with_pro_keys(bpms,NAME_O,bpm_qclist);
4684 
4685  } else
4686  {
4687  if (whichext == 1)
4688  {
4689  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,NULL, NULL,
4690  CPL_BPP_IEEE_FLOAT, recipe_name,
4691  mypro_bpm, NULL, package,
4692  NAME_O));
4693  detmon_lg_save_image_with_pro_keys(bpms,NAME_O,bpm_qclist);
4694  } else
4695  {
4696  detmon_lg_save_image_with_pro_keys(bpms,NAME_O,bpm_qclist);
4697  }
4698  }
4699  } /* End of if(pix2pix) */
4700 
4701  if(detmon_lg_config.intermediate)
4702  {
4703  /******************************/
4704  /* Write the AUTOCORRS FITS */
4705  /******************************/
4706  cpl_msg_info(cpl_func,"Write the AUTOCORRS FITS");
4707  nb_images = cpl_imagelist_get_size(autocorr_images);
4708  cpl_ensure_code(nb_images > 0, CPL_ERROR_DATA_NOT_FOUND);
4709  for(i = 0; i < nb_images; i++)
4710  {
4711  cpl_propertylist* pplist = cpl_propertylist_duplicate(mypro_corr);
4712  int inull = 0;
4713  cpl_array* pnames = cpl_table_get_column_names(linear_table);
4714  double ddit = 0;
4715  if(i < cpl_table_get_nrow(linear_table))
4716  {
4717  ddit = cpl_table_get_double(linear_table,
4718  cpl_array_get_data_string_const(pnames)[0], i, &inull);
4719  }
4720  cpl_array_delete(pnames);
4721  /*cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);*/
4722  /* Set the file name for each image */
4723  irplib_free(&NAME_O);
4724  if(!flag_sets)
4725  {
4726  NAME_O=cpl_sprintf("%s_autocorr_%d.fits", recipe_name, i);
4727  assert(NAME_O != NULL);
4728  } else
4729  {
4730  NAME_O=cpl_sprintf("%s_autocorr_%02d_set%02d.fits",
4731  recipe_name, i, which_set);
4732  assert(NAME_O != NULL);
4733  }
4734  /* Save the image */
4735  if(detmon_lg_config.exts > 0)
4736  {
4737  cpl_propertylist* pextlist = cpl_propertylist_new();
4738  cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4739  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4740  NULL,NULL,CPL_BPP_IEEE_FLOAT,
4741  recipe_name, pplist, NULL,
4742  package, NAME_O));
4743 
4744  detmon_lg_save_image_with_pro_keys(
4745  cpl_imagelist_get(autocorr_images, i),NAME_O,pextlist);
4746 
4747  cpl_propertylist_delete(pextlist);
4748  } else
4749  if(detmon_lg_config.exts == 0)
4750  {
4751  cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);
4752  cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL,
4753  cpl_imagelist_get(autocorr_images, i),
4754  CPL_BPP_IEEE_FLOAT,
4755  recipe_name, pplist, NULL, package,
4756  NAME_O);
4757 
4758  }
4759  else
4760  {
4761  cpl_propertylist* pextlist = cpl_propertylist_new();
4762  cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4763  if(whichext == 1)
4764  {
4765  skip_if(cpl_dfs_save_image(frameset, NULL, parlist,
4766  usedframes, NULL,NULL,
4767  CPL_BPP_IEEE_FLOAT, recipe_name,
4768  pplist, NULL,
4769  package, NAME_O));
4770 
4771  detmon_lg_save_image_with_pro_keys(
4772  cpl_imagelist_get(autocorr_images, i),NAME_O,pextlist);
4773 
4774  } else
4775  {
4776 
4777  detmon_lg_save_image_with_pro_keys(
4778  cpl_imagelist_get(autocorr_images, i),NAME_O,pextlist);
4779  }
4780  cpl_propertylist_delete(pextlist);
4781  }
4782  cpl_propertylist_delete (pplist);
4783  }
4784  irplib_free(&NAME_O);
4785 
4786 
4787  /*
4788  cpl_msg_info(cpl_func, "-----before Write the DIFFS FITS %d", __LINE__);
4789  */
4790  /***************************/
4791  /* Write the DIFFS FITS */
4792  /***************************/
4793  cpl_msg_info(cpl_func,"Write the DIFFS FITS");
4794 
4795  for(i = 0; i < nb_images; i++)
4796  {
4797  cpl_propertylist* pplist = cpl_propertylist_duplicate(mypro_diff);
4798  int inull = 0;
4799  cpl_array* pnames = cpl_table_get_column_names(linear_table);
4800  double ddit = 0;
4801  if(i < cpl_table_get_nrow(linear_table))
4802  {
4803  ddit = cpl_table_get_double(linear_table,
4804  cpl_array_get_data_string_const(pnames)[0], i, &inull);
4805  }
4806  cpl_array_delete(pnames);
4807  /*cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);*/
4808  /* Set the file name for each image */
4809  if(!flag_sets)
4810  {
4811  NAME_O=cpl_sprintf("%s_diff_flat_%d.fits", recipe_name, i);
4812  } else
4813  {
4814  NAME_O=cpl_sprintf("%s_diff_flat_%d_set%02d.fits",
4815  recipe_name, i, which_set);
4816  }
4817  /* Save the image */
4818  if(detmon_lg_config.exts > 0)
4819  {
4820  cpl_propertylist* pextlist = cpl_propertylist_new();
4821  cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4822  cpl_propertylist_append_double(mypro_diff, "ESO DET DIT", ddit);
4823  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4824  NULL,NULL,CPL_BPP_IEEE_FLOAT,
4825  recipe_name,
4826  mypro_diff, NULL,package, NAME_O));
4827 
4828  detmon_lg_save_image_with_pro_keys(
4829  cpl_imagelist_get(diff_flats, i),NAME_O,pextlist);
4830 
4831  cpl_propertylist_delete(pextlist);
4832  }
4833  else if(detmon_lg_config.exts == 0)
4834  {
4835  cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);
4836  cpl_dfs_save_image
4837  (frameset, NULL, parlist, usedframes, NULL,
4838  cpl_imagelist_get(diff_flats, i), CPL_BPP_IEEE_FLOAT,
4839  recipe_name, pplist, NULL, package,
4840  NAME_O);
4841 
4842  } else
4843  {
4844  cpl_propertylist* pextlist = cpl_propertylist_new();
4845  cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4846  if(whichext == 1)
4847  {
4848  cpl_propertylist_append_double(mypro_diff,"ESO DET DIT",ddit);
4849  // cpl_propertylist_erase(mypro_diff, "ESO DET DIT");
4850  skip_if(cpl_dfs_save_image(frameset, NULL, parlist,
4851  usedframes, NULL,NULL,
4852  CPL_BPP_IEEE_FLOAT, recipe_name,
4853  mypro_diff, NULL,package, NAME_O));
4854 
4855  detmon_lg_save_image_with_pro_keys(
4856  cpl_imagelist_get(diff_flats, i),NAME_O,pextlist);
4857 
4858  } else
4859  {
4860 
4861  detmon_lg_save_image_with_pro_keys(
4862  cpl_imagelist_get(diff_flats, i),NAME_O,pextlist);
4863 
4864  }
4865  cpl_propertylist_delete(pextlist);
4866  }
4867  cpl_propertylist_delete(pplist);
4868  irplib_free(&NAME_O);
4869  }
4870  } /* End of if(intermediate) */
4871 
4872 
4873  /*******************************/
4874  /* Write the PAF file(s) */
4875  /*******************************/
4876  cpl_msg_info(cpl_func,"Write the PAF file(s)");
4877 
4878  if(detmon_lg_config.pafgen) {
4879 
4880  detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,whichext,
4881  pafregexp,procatg_gaintbl,
4882  pipeline_name,recipe_name,
4883  "qc01",gaint_qclist,0);
4884 
4885  detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,whichext,
4886  pafregexp,procatg_lintbl,
4887  pipeline_name,recipe_name,
4888  "qc02",lint_qclist,0);
4889 
4890  if(detmon_lg_config.pix2pix)
4891  {
4892 
4893  detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,
4894  whichext,pafregexp,
4895  procatg_coeffscube,
4896  pipeline_name,recipe_name,
4897  "qc03",linc_qclist,1);
4898 
4899  detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,
4900  whichext,pafregexp,procatg_bpm,
4901  pipeline_name,recipe_name,
4902  "qc04",bpm_qclist,1);
4903  }
4904  }
4905 
4906  end_skip;
4907  cpl_msg_info(cpl_func,"exit");
4908 
4909  cpl_propertylist_delete(xplist);
4910  if(plist!=NULL) {
4911  cpl_propertylist_delete(plist);
4912  plist=NULL;
4913  }
4914 
4915  irplib_free(&NAME_O);
4916  cpl_free(PREF_O);
4917  cpl_free(pcatg_plane);
4918  cpl_propertylist_delete(mainplist);
4919  cpl_propertylist_delete(mypro_lintbl);
4920  cpl_propertylist_delete(mypro_gaintbl);
4921  cpl_propertylist_delete(mypro_coeffscube);
4922  cpl_propertylist_delete(mypro_bpm);
4923  cpl_propertylist_delete(mypro_corr);
4924  cpl_propertylist_delete(mypro_diff);
4925 
4926  return cpl_error_get_code();
4927 }
4928 
4929 
4930 /*---------------------------------------------------------------------------*/
4938 /*---------------------------------------------------------------------------*/
4939 static cpl_error_code
4940 detmon_opt_contamination(const cpl_imagelist * ons,
4941  const cpl_imagelist * offs,
4942  unsigned mode,
4943  cpl_propertylist * qclist)
4944 {
4945  struct rect {
4946  size_t llx;
4947  size_t lly;
4948  size_t urx;
4949  size_t ury;
4950  };
4951  struct rect rects[5] = {
4952  (struct rect){ detmon_lg_config.llx1,
4953  detmon_lg_config.lly1,
4954  detmon_lg_config.urx1,
4955  detmon_lg_config.ury1},
4956  (struct rect){ detmon_lg_config.llx2,
4957  detmon_lg_config.lly2,
4958  detmon_lg_config.urx2,
4959  detmon_lg_config.ury2},
4960  (struct rect){ detmon_lg_config.llx3,
4961  detmon_lg_config.lly3,
4962  detmon_lg_config.urx3,
4963  detmon_lg_config.ury3},
4964  (struct rect){ detmon_lg_config.llx4,
4965  detmon_lg_config.lly4,
4966  detmon_lg_config.urx4,
4967  detmon_lg_config.ury4},
4968  (struct rect){ detmon_lg_config.llx5,
4969  detmon_lg_config.lly5,
4970  detmon_lg_config.urx5,
4971  detmon_lg_config.ury5},
4972  };
4973 
4974  for (size_t i = 0; i < 5; i++) {
4975  cpl_image * dif_avg;
4976  const cpl_image * off2;
4977  double median;
4978  char kname[300];
4979  if (cpl_imagelist_get_size(offs) == 1 || mode & IRPLIB_LIN_COLLAPSE)
4980  off2 = cpl_imagelist_get_const(offs, 0);
4981  else
4982  off2 = cpl_imagelist_get_const(offs, 1);
4983 
4984  dif_avg = detmon_subtracted_avg(cpl_imagelist_get_const(ons, 0),
4985  cpl_imagelist_get_const(offs, 0),
4986  cpl_imagelist_get_const(ons, 1),
4987  off2,
4988  rects[i].llx,
4989  rects[i].lly,
4990  rects[i].urx,
4991  rects[i].ury);
4992 
4993  median = cpl_image_get_median(dif_avg);
4994  cpl_image_delete(dif_avg);
4995 
4996  skip_if(0);
4997  sprintf(kname, "%s%d", DETMON_QC_CONTAM, i + 1);
4998 
4999  if(cpl_propertylist_has(qclist,kname)){
5000  skip_if(cpl_propertylist_update_double(qclist,kname,median));
5001  } else {
5002  skip_if(cpl_propertylist_append_double(qclist,kname,median));
5003  skip_if(cpl_propertylist_set_comment(qclist,kname,DETMON_QC_CONTAM_C));
5004  }
5005  }
5006 
5007  end_skip;
5008 
5009  return cpl_error_get_code();
5010 }
5011 
5012 /*---------------------------------------------------------------------------*/
5019 /*---------------------------------------------------------------------------*/
5020 /*
5021 static cpl_error_code
5022 detmon_opt_lampcr(cpl_frameset * cur_fset, int ext)
5023 {
5024  cpl_image * on = NULL;
5025  cpl_image * off = NULL;
5026  cpl_frame * first_off = NULL;
5027  cpl_frame * first_on = NULL;
5028  cpl_propertylist * plist = NULL;
5029  double dit;
5030 
5031  cpl_ensure_code(cur_fset != NULL, CPL_ERROR_NULL_INPUT);
5032 
5033  skip_if((first_off = cpl_frameset_get_first(cur_fset)) == NULL);
5034  skip_if((first_on = cpl_frameset_get_next (cur_fset)) == NULL);
5035 
5036  on = cpl_image_load(cpl_frame_get_filename(first_on),
5037  CPL_TYPE_FLOAT, 0, ext);
5038  off = cpl_image_load(cpl_frame_get_filename(first_off),
5039  CPL_TYPE_FLOAT, 0, ext);
5040  skip_if(cpl_image_subtract(on, off));
5041 
5042  plist = cpl_propertylist_load(cpl_frame_get_filename(first_on), 0);
5043  skip_if(plist == NULL);
5044 
5045  dit = irplib_pfits_get_dit_opt(plist);
5046 
5047  detmon_lg_config.cr = cpl_image_get_mean(on) / dit;
5048 
5049  end_skip;
5050 
5051  cpl_image_delete(on);
5052  cpl_image_delete(off);
5053  cpl_propertylist_delete(plist);
5054 
5055  return cpl_error_get_code();
5056 }
5057 */
5058 /*---------------------------------------------------------------------------*/
5066 /*---------------------------------------------------------------------------*/
5067 int
5068 detmon_lg_dfs_set_groups(cpl_frameset * set,
5069  const char *tag_on, const char *tag_off)
5070 {
5071  cpl_frame *cur_frame;
5072  const char *tag;
5073  int nframes;
5074  int i;
5075 
5076  /* Check entries */
5077  if(set == NULL)
5078  return -1;
5079 
5080  /* Initialize */
5081  nframes = cpl_frameset_get_size(set);
5082 
5083  /* Loop on frames */
5084  for(i = 0; i < nframes; i++) {
5085  cur_frame = cpl_frameset_get_position(set, i);
5086  tag = cpl_frame_get_tag(cur_frame);
5087 
5088  /* RAW frames */
5089  if(!strcmp(tag, tag_on) || !strcmp(tag, tag_off))
5090  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_RAW);
5091  /* CALIB frames */
5092 
5093  /* else if (!strcmp(tag, IIINSTRUMENT_CALIB_FLAT))
5094  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_CALIB);
5095  */
5096  }
5097  return 0;
5098 }
5099 
5100 
5101 /*---------------------------------------------------------------------------*/
5109 /*---------------------------------------------------------------------------*/
5110 static cpl_error_code
5111 detmon_lg_fits_coeffs_and_bpm2chip(cpl_imagelist ** coeffs_ptr,
5112  cpl_image **bpms_ptr)
5113 {
5114  cpl_image* dummy_bpm=NULL;
5115  cpl_image * dummy_coeff=NULL;
5116  cpl_imagelist * dummy_coeffs=NULL;
5117  int * db_p=NULL;
5118  int * rb_p =NULL;
5119  float ** dcs_p;
5120  float ** rcs_p;
5121  int dlength=0;
5122  int rlength=0;
5123  int shift_idx=0;
5124  int i=0;
5125  int k=0;
5126  int j=0;
5127 
5128  dummy_bpm = cpl_image_new(detmon_lg_config.nx,
5129  detmon_lg_config.ny,
5130  CPL_TYPE_INT);
5131  dummy_coeffs = cpl_imagelist_new();
5132 
5133  db_p = cpl_image_get_data_int(dummy_bpm);
5134  rb_p = cpl_image_get_data_int(*bpms_ptr);;
5135  dcs_p = cpl_malloc(sizeof(float *) * (detmon_lg_config.order + 1));
5136  rcs_p = cpl_malloc(sizeof(float *) * (detmon_lg_config.order + 1));
5137  dlength = detmon_lg_config.nx;
5138  rlength = detmon_lg_config.urx - detmon_lg_config.llx + 1;
5139  for (i = 0; i <= detmon_lg_config.order; i++)
5140  {
5141  dummy_coeff = cpl_image_new(detmon_lg_config.nx,
5142  detmon_lg_config.ny,
5143  CPL_TYPE_FLOAT);
5144 
5145  cpl_imagelist_set(dummy_coeffs, dummy_coeff, i);
5146  dcs_p[i] = cpl_image_get_data_float(dummy_coeff);
5147  rcs_p[i] = cpl_image_get_data_float(cpl_imagelist_get(*coeffs_ptr, i));
5148  }
5149  /*copy the coefficients from temporary image to the dummy_bpm*/
5150  for (i = detmon_lg_config.lly - 1; i < detmon_lg_config.ury; i++)
5151  {
5152  for (j = detmon_lg_config.llx - 1; j < detmon_lg_config.urx; j++)
5153  {
5154  shift_idx=(i - detmon_lg_config.lly + 1) * rlength +
5155  j - detmon_lg_config.llx + 1;
5156  *(db_p + i * dlength + j) = *(rb_p + shift_idx);
5157  for (k = 0; k <= detmon_lg_config.order; k++)
5158  {
5159  *(dcs_p[k] + i * dlength + j) =
5160  *(rcs_p[k] + (i - detmon_lg_config.lly + 1) * rlength +
5161  j - detmon_lg_config.llx + 1);
5162  }
5163  }
5164  }
5165  cpl_imagelist_delete(*coeffs_ptr);
5166  cpl_image_delete(*bpms_ptr);
5167  *coeffs_ptr = dummy_coeffs;
5168  *bpms_ptr = dummy_bpm;
5169  cpl_free(dcs_p);
5170  cpl_free(rcs_p);
5171 
5172  return cpl_error_get_code();
5173 }
5174 
5175 /* Not used so we temporaryly comment it out
5176 static cpl_error_code
5177 detmon_lg_qclog_lin_coeff(cpl_imagelist* coeffs_ptr, const int order, cpl_propertylist* linc_qclist)
5178 {
5179  cpl_image* image=NULL;
5180  int i=0;
5181  double coeff=0;
5182  double * pcoeffs = cpl_malloc(sizeof(double)*(order + 1));
5183  char* name_o1=NULL;
5184  char* name_o2=NULL;
5185 
5186  for(i = 0; i <= order; i++)
5187  {
5188  image = cpl_imagelist_get(coeffs_ptr, i);
5189  coeff = cpl_image_get_median(image);
5190  pcoeffs[i] = coeff;
5191  name_o1 = cpl_sprintf("ESO QC LIN COEF%d", i);
5192  name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", i);
5193  assert(name_o1 != NULL);
5194  assert(name_o2 != NULL);
5195  cpl_propertylist_append_double(linc_qclist, name_o1, coeff);
5196  cpl_propertylist_set_comment(linc_qclist,name_o1,DETMON_QC_LIN_COEF_C);
5197  cpl_free(name_o1);
5198  name_o1= NULL;
5199  cpl_propertylist_append_double(linc_qclist, name_o2,cpl_image_get_stdev(image));
5200  cpl_propertylist_set_comment(linc_qclist,name_o2,DETMON_QC_LIN_COEF_ERR_C);
5201  cpl_free(name_o2);
5202  name_o2= NULL;
5203  }
5204  cpl_free(pcoeffs);
5205 
5206  return cpl_error_get_code();
5207 }
5208 */
5209 /*----------------------------------------------------------------------------*/
5230 /*----------------------------------------------------------------------------*/
5231 cpl_error_code
5232 detmon_detector_shotnoise_model(const cpl_image* ima_data, const double gain,
5233  const double ron, cpl_image ** ima_errs)
5234 {
5235  cpl_ensure_code(ima_data, CPL_ERROR_NULL_INPUT);
5236  cpl_ensure_code(ima_errs, CPL_ERROR_NULL_INPUT);
5237  cpl_ensure_code(gain > 0., CPL_ERROR_ILLEGAL_INPUT);
5238  cpl_ensure_code(ron > 0., CPL_ERROR_ILLEGAL_INPUT);
5239 
5240  *ima_errs = cpl_image_duplicate(ima_data);
5241  /* set negative values (= zero measurable electrons) to read out noise */
5242  cpl_image_threshold(*ima_errs, 0., INFINITY, ron, ron);
5243 
5244  /* err_ADU = sqrt(counts/gain + ron * ron)*/
5245 
5246  cpl_image_divide_scalar(*ima_errs, gain);
5247  cpl_image_add_scalar(*ima_errs, ron * ron);
5248  cpl_image_power(*ima_errs, 0.5);
5249 
5250  return cpl_error_get_code();
5251 }
5252 
5253 int
5254 detmon_compute_badpixmap(cpl_boolean opt_nir, const int nsets,
5255  const cpl_table* linear_table,
5256  const cpl_imagelist* linearity_inputs, int nbpixs,
5257  cpl_vector* x, cpl_propertylist* gaint_qclist,
5258  cpl_image** bpms_ptr)
5259 {
5260  /* Here determines the bad pixel map
5261  * HDRL based version
5262  * AMO: this if is repeated: the following code should be up up
5263  */
5264  if (opt_nir == NIR) {
5265  x = cpl_vector_wrap(nsets,
5266  (double *) cpl_table_get_data_double_const(linear_table,
5267  "DIT"));
5268  }
5269  else {
5270  x = cpl_vector_wrap(nsets,
5271  (double *) cpl_table_get_data_double_const(linear_table,
5272  "EXPTIME"));
5273 
5274  }
5275  int sz = cpl_imagelist_get_size(linearity_inputs);
5276  int sx = cpl_image_get_size_x(cpl_imagelist_get(linearity_inputs, 0));
5277  int sy = cpl_image_get_size_y(cpl_imagelist_get(linearity_inputs, 0));
5278  double kappa = detmon_lg_config.kappa;
5279  int niter = detmon_lg_config.niter;
5280  int llx = detmon_lg_config.llx;
5281  int urx = detmon_lg_config.urx;
5282  int lly = detmon_lg_config.lly;
5283  int ury = detmon_lg_config.ury;
5284  hdrl_parameter* p;
5285  double median;
5286  cpl_image *ima, *err;
5287  // fit-chi-rel method
5288  // errors to be used with fit_chi_rel method
5289  cpl_imagelist* errors = cpl_imagelist_new();
5290  /*
5291  // case1: error proportional to sqrt(EXPTIME)
5292  for(int i=0;i<sz;i++) {
5293  err=cpl_image_new(sx,sy,CPL_TYPE_DOUBLE);
5294  cpl_image_add_scalar(err,1.);
5295  cpl_imagelist_set(errors,err,i);
5296  }
5297  */
5298  /*
5299  // case2:shot noise model to be used with fit_chi_rel method
5300  double gain=1.;
5301  double ron=1.;
5302  for(int i=0;i<sz;i++) {
5303  ima=cpl_imagelist_get(linearity_inputs,i);
5304  hdrldemo_detector_shotnoise_model(ima, gain, ron, &err);
5305  cpl_imagelist_set(errors,err,i);
5306  }
5307  */
5308  // case3: error obtained using mad error approximation
5309  double dmad;
5310  //cpl_msg_info(cpl_func,"sz=%d",sz);
5311  cpl_imagelist* linearity_scaled = cpl_imagelist_new();
5312  double gain = 0;
5313  gain = cpl_propertylist_get_double(gaint_qclist, DETMON_QC_GAIN);
5314  //cpl_msg_info(cpl_func,"ok1 gain=%g",gain);
5315  /* on simulations gain ,may be < 0: make sure it is > 0 */
5316  //cpl_msg_info(cpl_func,"ok1 gain=%g",gain);
5317  gain = (gain < 0) ? 1 : gain;
5318  double gain_eff = 2 * gain;
5319  //gain_eff=1;
5320  double ron = 1;
5321  double avg = 0;
5322  double rms = 0;
5323  int k = 0;
5324  char dname[80];
5325  char ename[80];
5326  char fname[80];
5327  skip_if(rms);
5328  //cpl_msg_info(cpl_func,"sz=%d",sz);
5329  //cpl_msg_info(cpl_func,"llx=%d lly=%d urx=%d ury=%d",llx,lly,urx,ury);
5330  for (int i = 0; i < sz; i++) {
5331  ima = cpl_imagelist_get(linearity_inputs, i);
5332  /*
5333  cpl_msg_info(cpl_func,"sx=%d sy=%d",
5334  cpl_image_get_size_x(ima),cpl_image_get_size_y(ima));
5335  */
5336  //cpl_msg_info(cpl_func,"max_x=%d max_y=%d",urx-llx+1,ury-lly+1);
5337  //median=cpl_image_get_median_window(ima,1,1,urx-llx+1,ury-lly+1);
5338  skip_if(
5339  irplib_ksigma_clip(ima, 1, 1, urx - llx + 1,
5340  ury - lly + 1, kappa, niter, 1e-5, &avg,
5341  &rms));
5342 
5343  //cpl_msg_info(cpl_func,"avg=%g median=%g",avg,median);
5344  //cpl_msg_info(cpl_func,"thresh=%g", detmon_lg_config.saturation_limit);
5345  if (avg < detmon_lg_config.saturation_limit) {
5346 
5347  //cpl_msg_info(cpl_func,">>>>i=%d", i);
5348  /*
5349  err=cpl_image_duplicate(ima);
5350  cpl_image_multiply_scalar(err, gain);
5351  cpl_image_power(err,0.5);
5352  */
5353  cpl_image_get_mad(ima, &dmad);
5354  err = cpl_image_duplicate(ima);
5355  cpl_image_multiply_scalar(err, 0);
5356  cpl_image_add_scalar(err, dmad * CPL_MATH_STD_MAD);
5357 
5358  //detmon_detector_shotnoise_model(ima, gain_eff,ron, &err);
5359  /*
5360  cpl_msg_info(cpl_func,"err sx=%d",cpl_image_get_size_x(err));
5361  cpl_msg_info(cpl_func,"err sy=%d",cpl_image_get_size_y(err));
5362  cpl_msg_info(cpl_func,"ima sx=%d",cpl_image_get_size_x(ima));
5363  cpl_msg_info(cpl_func,"ima sy=%d",cpl_image_get_size_y(ima));
5364  cpl_msg_info(cpl_func,"sy=%d",cpl_image_get_size_y(err));
5365  */
5366  cpl_imagelist_set(errors, err, i);
5367  /*
5368  sprintf(dname,"data_%d.fits",i);
5369  sprintf(ename,"errs_%d.fits",i);
5370  cpl_image_save(err, ename, CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
5371  cpl_image_save(ima, dname, CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
5372  */
5373  skip_if(
5374  cpl_imagelist_set(linearity_scaled,
5375  cpl_image_duplicate(ima), i));
5376  }
5377  }
5378  hdrl_imagelist* hil = hdrl_imagelist_create(linearity_scaled, errors);
5379  /*
5380  cpl_imagelist_save(linearity_scaled,"lin_data.fits", CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
5381  cpl_imagelist_save(errors,"lin_errs.fits", CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
5382  */
5383  cpl_imagelist_delete(errors);
5384  /* P-val method */
5385  double pval = 0.001;
5386  p = hdrl_bpm_fit_parameter_create_pval(1, pval);
5387  /*
5388  p = hdrl_bpm_fit_parameter_create_rel_coef(1, 1., 1.);
5389  hdrl_parameter_delete(p);
5390  */
5391  /* chi-rel method
5392  int ord=detmon_lg_config.order;
5393  p = hdrl_bpm_fit_parameter_create_rel_chi(1, kappa, kappa);
5394  */
5395  hdrl_bpm_fit_compute(p, hil, x, bpms_ptr);
5396  //cpl_vector_dump(x,stdout);
5397  /*
5398  // bpm-3D method
5399  cpl_imagelist* linearity_scaled=cpl_imagelist_new();
5400 
5401  for(int i=0;i<sz;i++) {
5402  ima=cpl_imagelist_get(linearity_inputs,i);
5403  median=cpl_image_get_median(ima);
5404  if(median < detmon_lg_config.saturation_limit) {
5405  cpl_image_divide_scalar(ima,median);
5406  cpl_imagelist_set(linearity_scaled,cpl_image_duplicate(ima),i);
5407  }
5408  }
5409  hdrl_imagelist* hil= hdrl_imagelist_create(linearity_scaled,NULL);
5410 
5411 
5412  // bpm-3D method
5413  hdrl_bpm_3d_method method = HDRL_BPM_3D_THRESHOLD_RELATIVE ;
5414  p=hdrl_bpm_3d_parameter_create(kappa, kappa, method) ;
5415  cpl_imagelist * out_imlist = hdrl_bpm_3d_compute(hil, p);
5416  *bpms_ptr = cpl_imagelist_collapse_create(out_imlist);
5417  cpl_msg_info(cpl_func,"BP map value: min=%g max=%g",
5418  cpl_image_get_min(*bpms_ptr),cpl_image_get_max(*bpms_ptr));
5419  */
5420  nbpixs = cpl_image_get_flux(*bpms_ptr);
5421  /* clean-up memory */
5422  hdrl_imagelist_delete(hil);
5423  cpl_imagelist_delete(linearity_scaled);
5424  cpl_vector_unwrap((cpl_vector*) x);
5425  hdrl_parameter_delete(p);
5426  // 3D method only
5427  //cpl_imagelist_delete(out_imlist);
5428  /* ORIGINAL BP MAP COMPUTATION
5429  *bpms_ptr = detmon_bpixs(*coeffs_ptr, detmon_lg_config.bpmbin,
5430  detmon_lg_config.kappa, &nbpixs);
5431  */
5432  /*
5433  *bpms_ptr = detmon_bpixs2(x,linearity_inputs,*coeffs_ptr,gain_table,
5434  detmon_lg_config.order,detmon_lg_config.bpmbin,detmon_lg_config.kappa,&nbpixs);
5435  */
5436  /*
5437  cpl_vector_unwrap((cpl_vector*)x);
5438  cpl_vector_unwrap((cpl_vector*)y);
5439  */
5440  //cpl_msg_info(cpl_func,"nbpixs=%d",nbpixs);
5441  skip_if(*bpms_ptr == NULL);
5442 
5443  end_skip;
5444  return nbpixs;
5445 }
5446 
5447 /*---------------------------------------------------------------------------*/
5461 /*---------------------------------------------------------------------------*/
5462 static cpl_error_code
5463 detmon_lg_reduce_all(const cpl_table * linear_table,
5464  cpl_propertylist * gaint_qclist,
5465  cpl_propertylist * lint_qclist,
5466  cpl_propertylist * linc_qclist,
5467  cpl_propertylist * bpm_qclist,
5468  cpl_imagelist ** coeffs_ptr,
5469  cpl_image ** bpms_ptr,
5470  const cpl_imagelist * linearity_inputs,
5471  const cpl_table * gain_table,
5472  int which_ext, cpl_boolean opt_nir)
5473 {
5474 
5475  int nbpixs = 0;
5476  const int linear_nsets = cpl_table_get_nrow(linear_table);
5477  const int gain_nsets = cpl_table_get_nrow(gain_table);
5478  double autocorr;
5479  cpl_polynomial *poly_linfit = NULL;
5480  cpl_image *fiterror = NULL;
5481  char * name_o1 = NULL;
5482  char * name_o2 = NULL;
5483  double * pcoeffs = NULL;
5484  unsigned mode = detmon_lg_config.autocorr ? IRPLIB_GAIN_WITH_AUTOCORR : 0;
5485  double min_val=0;
5486  double max_val=0;
5487  cpl_vector *x =NULL;
5488  const cpl_vector *y =NULL;
5489 
5490 
5491  const cpl_image * first = NULL;
5492  int sizex = 0;
5493  int sizey = 0;
5494 
5495  int vsize = 0;
5496  cpl_size deg=0;
5497  /* FIXME: This should go before the x and y vectors.
5498  Checking for all the inputs */
5499  cpl_ensure_code(gaint_qclist != NULL, CPL_ERROR_NULL_INPUT);
5500  cpl_ensure_code(lint_qclist != NULL, CPL_ERROR_NULL_INPUT);
5501  cpl_ensure_code(linc_qclist != NULL, CPL_ERROR_NULL_INPUT);
5502  cpl_ensure_code(bpm_qclist != NULL, CPL_ERROR_NULL_INPUT);
5503 
5504  pcoeffs = cpl_malloc(sizeof(double)*(detmon_lg_config.order + 1));
5505 
5506  skip_if(cpl_propertylist_append_string(gaint_qclist, DETMON_QC_METHOD,
5507  detmon_lg_config.method));
5508  skip_if(cpl_propertylist_set_comment(gaint_qclist, DETMON_QC_METHOD,
5509  DETMON_QC_METHOD_C));
5510 
5511 
5512  if (!strcmp(detmon_lg_config.method, "PTC")) {
5513  /* Computation of GAIN via polynomial fit */
5514  if (detmon_lg_config.exts >= 0) {
5515  cpl_msg_info(cpl_func,
5516  "Polynomial fitting for the GAIN (constant term method)");
5517  } else {
5518  cpl_msg_info(cpl_func,
5519  "Polynomial fitting for the GAIN (constant term method)"
5520  " for extension nb %d", which_ext);
5521  }
5522  skip_if(detmon_lg_qc_ptc(gain_table, gaint_qclist, mode, gain_nsets));
5523  } else {
5524  skip_if(detmon_lg_qc_med(gain_table, gaint_qclist, gain_nsets));
5525  }
5526 
5527  /*^FIXME: This shouldn't be written when no applied */
5528  /* Lamp flux */
5529  if(detmon_lg_config.lamp_ok) {
5530  skip_if(cpl_propertylist_append_double(lint_qclist, DETMON_QC_LAMP_FLUX,
5531  detmon_lg_config.cr));
5532  skip_if(cpl_propertylist_set_comment(lint_qclist, DETMON_QC_LAMP_FLUX,
5533  DETMON_QC_LAMP_FLUX_C));
5534  }
5535 
5536  /*^FIXME: This shouldn't be written when no applied */
5537  if(detmon_lg_config.autocorr == TRUE) {
5538  autocorr = cpl_table_get_column_median(gain_table, "AUTOCORR");
5539  skip_if(cpl_propertylist_append_double(gaint_qclist, DETMON_QC_AUTOCORR,
5540  autocorr));
5541  skip_if(cpl_propertylist_set_comment(gaint_qclist, DETMON_QC_AUTOCORR,
5542  DETMON_QC_AUTOCORR_C));
5543  }
5544  if (detmon_lg_config.exts >= 0) {
5545  cpl_msg_info(cpl_func, "Polynomial fitting pix-to-pix");
5546  } else {
5547  cpl_msg_info(cpl_func, "Polynomial fitting pix-to-pix"
5548  " for extension nb %d", which_ext);
5549  }
5550 
5551  if(!detmon_lg_config.pix2pix) {
5552  const int order=detmon_lg_config.order;
5553 
5554 
5555 
5556 
5557 
5558  double mse = 0;
5559  /* Computation of LINEARITY via polynomial fit */
5560  y = cpl_vector_wrap(linear_nsets,
5561  (double *)cpl_table_get_data_double_const(linear_table,
5562  "MED"));
5563 
5564  if (opt_nir == NIR) {
5565  x = cpl_vector_wrap(linear_nsets,
5566  (double *)cpl_table_get_data_double_const(linear_table,
5567  "DIT"));
5568  } else {
5569  x = cpl_vector_wrap(linear_nsets,
5570  (double *)cpl_table_get_data_double_const(linear_table,
5571  "EXPTIME"));
5572  }
5573 
5574  if(x == NULL || y == NULL) {
5575  cpl_vector_unwrap((cpl_vector *)x);
5576  cpl_vector_unwrap((cpl_vector *)y);
5577  /*
5578  * As x and y are const vectors, if they would be defined at the
5579  * beginning of the function (required for skip_if - end_skip
5580  * scheme), they couldn't be initialised to NULL (required too).
5581  * Therefore, they are considered apart from the scheme.
5582  */
5583  skip_if(1);
5584  }
5585 
5586  cpl_msg_info(cpl_func, "Polynomial fitting for the LINEARITY");
5587  poly_linfit = irplib_polynomial_fit_1d_create(x, y,order,&mse);
5588 
5589  if(order == cpl_vector_get_size(x) - 1) {
5590  cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
5591  mse = 0;
5592  }
5593 
5594  if(poly_linfit == NULL) {
5595  cpl_vector_unwrap((cpl_vector *)x);
5596  cpl_vector_unwrap((cpl_vector *)y);
5597  /* See comment in previous error checking if() statement */
5598  skip_if(1);
5599  }
5600 
5601 
5602  min_val=cpl_vector_get_min(y);
5603  max_val=cpl_vector_get_max(y);
5604 
5605  cpl_vector_unwrap((cpl_vector *)x);
5606  cpl_vector_unwrap((cpl_vector *)y);
5607 
5608  for(deg = 0; deg <= order; deg++) {
5609  const double coeff =
5610  cpl_polynomial_get_coeff(poly_linfit, &deg);
5611  char *name_o =
5612  cpl_sprintf("ESO QC LIN COEF%" CPL_SIZE_FORMAT "", deg);
5613  assert(name_o != NULL);
5614  skip_if(cpl_propertylist_append_double(lint_qclist, name_o, coeff));
5615  skip_if(cpl_propertylist_set_comment(lint_qclist,name_o,
5616  DETMON_QC_LIN_COEF_C));
5617 
5618  cpl_free(name_o);
5619  pcoeffs[deg] = coeff;
5620  }
5621  skip_if(cpl_propertylist_append_double(lint_qclist,DETMON_QC_ERRFIT, mse));
5622  skip_if(cpl_propertylist_set_comment(lint_qclist,DETMON_QC_ERRFIT,
5623  DETMON_QC_ERRFIT_MSE_C));
5624 
5625 
5626  } else {
5627  const int order=detmon_lg_config.order;
5628  /* pix2pix == TRUE */
5629  y = cpl_vector_wrap(linear_nsets,
5630  (double *)cpl_table_get_data_double_const(linear_table,
5631  "MED"));
5632 
5633  if (opt_nir == NIR)
5634  {
5635  x = cpl_vector_wrap(linear_nsets,
5636  (double *)cpl_table_get_data_double_const(linear_table,
5637  "DIT"));
5638  } else {
5639  x = cpl_vector_wrap(linear_nsets,
5640  (double *)cpl_table_get_data_double_const(linear_table,
5641  "EXPTIME"));
5642 
5643  }
5644 
5645  first = cpl_imagelist_get_const(linearity_inputs, 0);
5646  sizex = cpl_image_get_size_x(first);
5647  sizey = cpl_image_get_size_y(first);
5648  vsize = cpl_vector_get_size(x);
5649  fiterror = cpl_image_new(sizex, sizey, CPL_TYPE_FLOAT);
5650  *coeffs_ptr =
5651  cpl_fit_imagelist_polynomial(x, linearity_inputs, 0,order, FALSE,
5652  CPL_TYPE_FLOAT, fiterror);
5653  min_val=cpl_vector_get_min(y);
5654  max_val=cpl_vector_get_max(y);
5655  cpl_vector_unwrap((cpl_vector*)x);
5656  cpl_vector_unwrap((cpl_vector*)y);
5657 
5658  irplib_ensure(*coeffs_ptr != NULL, CPL_ERROR_UNSPECIFIED,
5659  "Failed polynomial fit");
5660  //detmon_lg_qclog_lin_coeff(*coeffs_ptr, order,linc_qclist);
5661 
5662  for(deg = 0; deg <= order; deg++)
5663  {
5664  cpl_image *image = cpl_imagelist_get(*coeffs_ptr, deg);
5665  const double coeff = cpl_image_get_median(image);
5666  pcoeffs[deg] = coeff;
5667  name_o1 = cpl_sprintf("ESO QC LIN COEF%d", (int)deg);
5668  name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", (int)deg);
5669  assert(name_o1 != NULL);
5670  assert(name_o2 != NULL);
5671  skip_if(cpl_propertylist_append_double(linc_qclist, name_o1, coeff));
5672  skip_if(cpl_propertylist_set_comment(linc_qclist,name_o1,
5673  DETMON_QC_LIN_COEF_C));
5674  cpl_free(name_o1);
5675  name_o1= NULL;
5676  skip_if(cpl_propertylist_append_double(linc_qclist, name_o2,
5677  cpl_image_get_stdev(image)));
5678  skip_if(cpl_propertylist_set_comment(linc_qclist,name_o2,
5679  DETMON_QC_LIN_COEF_ERR_C));
5680  cpl_free(name_o2);
5681  name_o2= NULL;
5682  }
5683 
5684 
5685  if(order == vsize - 1)
5686  {
5687  cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
5688  skip_if(cpl_propertylist_append_double(linc_qclist,DETMON_QC_ERRFIT,
5689  0.0));
5690  skip_if(cpl_propertylist_set_comment(linc_qclist,DETMON_QC_ERRFIT,
5691  DETMON_QC_ERRFIT_C));
5692  } else
5693  {
5694  skip_if(cpl_propertylist_append_double(linc_qclist,DETMON_QC_ERRFIT,
5695  cpl_image_get_median(fiterror)));
5696  skip_if(cpl_propertylist_set_comment(linc_qclist,DETMON_QC_ERRFIT,
5697  DETMON_QC_ERRFIT_C));
5698  }
5699  } /* end case pix2pix == TRUE */
5700 
5701  skip_if(cpl_propertylist_append_double(lint_qclist,DETMON_QC_COUNTS_MIN,
5702  min_val));
5703  skip_if(cpl_propertylist_set_comment(lint_qclist,DETMON_QC_COUNTS_MIN,
5704  DETMON_QC_COUNTS_MIN_C));
5705  skip_if(cpl_propertylist_append_double(lint_qclist,DETMON_QC_COUNTS_MAX,
5706  max_val));
5707  skip_if(cpl_propertylist_set_comment(lint_qclist,DETMON_QC_COUNTS_MAX,
5708  DETMON_QC_COUNTS_MAX_C));
5709  skip_if(detmon_lg_lineff(pcoeffs,lint_qclist,detmon_lg_config.ref_level,
5710  detmon_lg_config.order));
5711  /* Detection of bad pixels */
5712  if (detmon_lg_config.exts >= 0)
5713  {
5714  cpl_msg_info(cpl_func, "Bad pixel detection");
5715  } else
5716  {
5717  cpl_msg_info(cpl_func, "Bad pixel detection"
5718  " for extension nb %d", which_ext);
5719  }
5720  if(detmon_lg_config.pix2pix)
5721  {
5722 
5723  /* Determines bad pixel map */
5724  nbpixs = detmon_compute_badpixmap(opt_nir, linear_nsets, linear_table,
5725  linearity_inputs, nbpixs, x,gaint_qclist, bpms_ptr);
5726  /* we still have to unwrapp x & y that we kept for bpixs2 function */
5727  }
5728 
5729 
5730  skip_if(cpl_propertylist_append_int(bpm_qclist, DETMON_QC_NUM_BPM, nbpixs));
5731  skip_if(cpl_propertylist_set_comment(bpm_qclist, DETMON_QC_NUM_BPM,
5732  DETMON_QC_NUM_BPM_C));
5733  cpl_msg_info(cpl_func,"stability=%g",detmon_lg_config.lamp_stability);
5734  if(detmon_lg_config.lamp_stability != 0.0)
5735  {
5736  skip_if(cpl_propertylist_append_double(lint_qclist, DETMON_QC_LAMP_STAB,
5737  detmon_lg_config.lamp_stability));
5738  skip_if(cpl_propertylist_set_comment(lint_qclist, DETMON_QC_LAMP_STAB,
5739  DETMON_QC_LAMP_STAB_C));
5740  }
5741  /* Fit COEFFS_CUBE and BPM outputs to whole-chip size images (DFS05711) */
5742  if (!detmon_lg_config.wholechip && detmon_lg_config.pix2pix)
5743  {
5744  detmon_lg_fits_coeffs_and_bpm2chip(coeffs_ptr,bpms_ptr);
5745  }
5746  end_skip;
5747 
5748  cpl_free(pcoeffs);
5749  cpl_free(name_o1);
5750  cpl_free(name_o2);
5751  cpl_image_delete(fiterror);
5752  cpl_polynomial_delete(poly_linfit);
5753 
5754 
5755 
5756  return cpl_error_get_code();
5757 }
5758 
5759 /*---------------------------------------------------------------------------*/
5767 /*---------------------------------------------------------------------------*/
5768 static cpl_error_code
5769 detmon_lg_lineff(double * pcoeffs,
5770  cpl_propertylist * qclist,
5771  int ref_level,
5772  int order)
5773 {
5774  double lineff = 0;
5775  double root = 0;
5776  double residual, slope;
5777  int i;
5778  cpl_size deg=0;
5779  cpl_polynomial * poly = cpl_polynomial_new(1);
5780 
5781 
5782  /*
5783  * Construction of the polynomial F_m(F_r) from F_m(t),
5784  * using F_r = a_1 * t.
5785  */
5786  /*
5787  for (deg = 0; deg <= order; deg++) {
5788  cpl_msg_info(cpl_func,"coef[%d]=%g",deg,pcoeffs[deg]);
5789  }
5790  */
5791 
5792 
5793  pcoeffs[0] -= ref_level;
5794 
5795  for (i = 2; i <= order; i++)
5796  {
5797  int j;
5798  for(j = 0; j < i; j++)
5799  {
5800  pcoeffs[i] /= pcoeffs[1];
5801  }
5802  }
5803 
5804  pcoeffs[1] = 1;
5805 
5806  for (deg = 0; deg <= order; deg++) {
5807  /*cpl_msg_info(cpl_func,"coef[%d]=%g",deg,pcoeffs[deg]);*/
5808  skip_if(cpl_polynomial_set_coeff(poly, &deg, pcoeffs[deg]));
5809  }
5810 
5811  /*
5812  * Verification of validity of first guess (0).
5813  * The root to be found will be in the same interval of monotony
5814  * of the first guess; therefore, slope must be greater than 0.
5815  * Slope > 0 and poly(root) = 0 force also residual to be negative.
5816  */
5817  residual = cpl_polynomial_eval_1d(poly, 0.0, &slope);
5818 
5819  if (slope <= 0.0 && residual >= 0.0) {
5820  cpl_msg_warning(cpl_func, "Reference level (--ref_level) outside"
5821  " linearity range of the detector. Cannot compute"
5822  " linearity efficiency (QC.LINEFF).");
5823  lineff = -1;
5824  }
5825  else
5826  {
5827  cpl_error_code err = cpl_polynomial_solve_1d(poly, 0.0, &root, 1);
5828  /*
5829  cpl_msg_info(cpl_func,"root=%g ref_level=%d lin_eff=%d",
5830  root,ref_level,ref_level);
5831  */
5832  if (err == CPL_ERROR_NONE)
5833  {
5834 
5835  lineff = (root - ref_level) / ref_level;
5836  }
5837  else
5838  {
5839  cpl_error_reset();
5840  cpl_msg_warning(cpl_func,
5841  "Cannot compute linearity efficiency (QC.LINEFF)"
5842  "for the current combination "
5843  " of (--ref-level equal %d) and (--order equal %d) parameters. Try "
5844  "to decrease (--ref-level) value.", ref_level, order);
5845  }
5846  }
5847  cpl_msg_warning(cpl_func, "DETMON_QC_LIN_EFF=%f",lineff );
5848  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LIN_EFF,
5849  lineff));
5850  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LIN_EFF,
5851  DETMON_QC_LIN_EFF_C));
5852 
5853  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LIN_EFF_FLUX,
5854  ref_level));
5855  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LIN_EFF_FLUX,
5856  DETMON_QC_LIN_EFF_FLUX_C));
5857 
5858  end_skip;
5859 
5860  cpl_polynomial_delete(poly);
5861 
5862  return cpl_error_get_code();
5863 }
5864 
5865 /*---------------------------------------------------------------------------*/
5872 /*---------------------------------------------------------------------------*/
5873 static cpl_error_code
5874 detmon_lg_qc_ptc(const cpl_table * gain_table,
5875  cpl_propertylist * qclist, unsigned mode, int rows_in_gain)
5876 {
5877  double mse = 0;
5878  cpl_polynomial *poly_fit = NULL;
5879  cpl_polynomial *poly_fit2 = NULL;
5880  cpl_size i;
5881  const int nsets = rows_in_gain;
5882 
5883  cpl_vector *x = NULL;
5884  cpl_vector *y = NULL;
5885 
5886  cpl_errorstate prestate;
5887  double coef = 0;
5888  cpl_ensure_code(gain_table != NULL, CPL_ERROR_NULL_INPUT);
5889  cpl_ensure_code(qclist != NULL, CPL_ERROR_NULL_INPUT);
5890 
5891  x = cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT"));
5892 
5893  y = cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
5894 
5895  skip_if(x == NULL || y == NULL);
5896  if (0 == detmon_lg_check_before_gain(x, y))
5897  {
5898  if (x)
5899  {
5900  cpl_vector_unwrap(x);
5901  }
5902  if (y)
5903  {
5904  cpl_vector_unwrap(y);
5905  }
5906  return CPL_ERROR_NONE;
5907  }
5908  /*it is not really a MSE, but chi square of the fit, see cpl_vector_fill_polynomial_fit_residual for details*/
5909  poly_fit = irplib_polynomial_fit_1d_create_chiq(x, y, 1, &mse);
5910  skip_if(poly_fit == NULL);
5911 
5912  /* Write the QC params corresponding to the fitting of the GAIN */
5913  i = 1;
5914  prestate = cpl_errorstate_get();
5915  coef = cpl_polynomial_get_coeff(poly_fit, &i);
5916  skip_if (!cpl_errorstate_is_equal(prestate) || coef==0);
5917  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD, coef));
5918  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD,
5919  DETMON_QC_CONAD_C));
5920  if (coef != 0)
5921  {
5922  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN,
5923  1 / coef));
5924  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN,
5925  DETMON_QC_GAIN_C));
5926  }
5927  /* MSE is removed - see DFS07358 for details
5928  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_MSE, mse));
5929  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_MSE,
5930  DETMON_QC_GAIN_MSE_C));
5931  */
5932  i = 0;
5933  /* QC.RON computation is disabled, see DFS05852 for details*/
5934 
5935  /* * skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_RON,
5936  cpl_polynomial_get_coeff(poly_fit, &i)));
5937  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_RON,
5938  DETMON_QC_RON_C));
5939  */
5940  if(mode & IRPLIB_GAIN_WITH_AUTOCORR){
5941  const cpl_vector *x2 =
5942  cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT_CORR"));
5943  const cpl_vector *y2 =
5944  cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
5945 
5946  if(x2 == NULL || y2 == NULL) {
5947  cpl_vector_unwrap((cpl_vector *)x2);
5948  cpl_vector_unwrap((cpl_vector *)y2);
5949  /*
5950  * As x and y are const vectors, if they would be defined at the
5951  * beginning of the function (required for skip_if - end_skip
5952  * scheme), they couldn't be initialised to NULL (required too).
5953  * Therefore, they are considered apart from the scheme.
5954  */
5955  skip_if(1);
5956  }
5957 
5958  /* Revise mse, maybe used afterwards */
5959  poly_fit2 = irplib_polynomial_fit_1d_create(x2, y2, 1, &mse);
5960  if(poly_fit2 == NULL) {
5961  cpl_vector_unwrap((cpl_vector *)x2);
5962  cpl_vector_unwrap((cpl_vector *)y2);
5963 
5964  cpl_msg_error(cpl_func, "Error during polynomial fit, err[%s]", cpl_error_get_where());
5965  /* See comment in previous error checking if() statement */
5966  skip_if(1);
5967  }
5968  skip_if(cpl_error_get_code() != CPL_ERROR_NONE);
5969  cpl_vector_unwrap((cpl_vector *)x2);
5970  cpl_vector_unwrap((cpl_vector *)y2);
5971  skip_if(cpl_error_get_code() != CPL_ERROR_NONE);
5972  /* Write the QC params corresponding to the fitting of the GAIN */
5973  i = 1;
5974  prestate = cpl_errorstate_get();
5975  coef = cpl_polynomial_get_coeff(poly_fit2, &i);
5976  skip_if(cpl_error_get_code() != CPL_ERROR_NONE);
5977  skip_if (!cpl_errorstate_is_equal(prestate) || coef == 0);
5978 
5979  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD_CORR,
5980  coef));
5981  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD_CORR,
5982  DETMON_QC_CONAD_CORR_C));
5983 
5984  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_CORR,
5985  1 / coef));
5986  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_CORR,
5987  DETMON_QC_GAIN_CORR_C));
5988  }
5989 
5990  end_skip;
5991 
5992  /*cleanup*/
5993  cpl_vector_unwrap(x);
5994  cpl_vector_unwrap(y);
5995  cpl_polynomial_delete(poly_fit);
5996  cpl_polynomial_delete(poly_fit2);
5997 
5998  return cpl_error_get_code();
5999 }
6000 
6007 static int detmon_lg_check_before_gain(const cpl_vector* x, const cpl_vector* y)
6008 {
6009  const double TOLERANCE = 1e-37;/*MINDOUBLE is not everywhere defined (Mac);*/
6010  double xmin = cpl_vector_get_min(x);
6011  double xmax = cpl_vector_get_max(x);
6012  double ymin = cpl_vector_get_min(y);
6013  double ymax = cpl_vector_get_max(y);
6014  double ystdev = cpl_vector_get_stdev(y);
6015  double xstdev = cpl_vector_get_stdev(x);
6016  int retval = 1;
6017  if (fabs(xmax-xmin) < TOLERANCE &&
6018  fabs(ymax - ymin) < TOLERANCE &&
6019  xstdev < TOLERANCE &&
6020  ystdev < TOLERANCE)
6021  {
6022  cpl_msg_warning(cpl_func, "An empty frame has been detected, linearity, coeffs, gain, FPN values will not be computed.");
6023  retval = 0;
6024  }
6025  return retval;
6026 }
6027 /*---------------------------------------------------------------------------*/
6036 /*---------------------------------------------------------------------------*/
6037 static cpl_error_code
6038 detmon_lg_qc_med(const cpl_table * gain_table,
6039  cpl_propertylist * qclist, int rows_in_gain)
6040 {
6041 
6042  double gain=0;
6043  cpl_vector *x = NULL;
6044  cpl_vector *y = NULL;
6045  int check_result = 0;
6046 
6047  if (rows_in_gain) {/* silence unused var */};
6048 
6049  x = cpl_vector_wrap(rows_in_gain, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT"));
6050  y = cpl_vector_wrap(rows_in_gain, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
6051  check_result = detmon_lg_check_before_gain(x, y);
6052  if (x)
6053  {
6054  cpl_vector_unwrap(x);
6055  }
6056  if (y)
6057  {
6058  cpl_vector_unwrap(y);
6059  }
6060  if (0 == check_result)
6061  {
6062  return CPL_ERROR_NONE;
6063  }
6064 
6065  gain=cpl_table_get_column_median(gain_table, "GAIN");
6066 
6067  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN,gain));
6068 
6069  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN,
6070  DETMON_QC_GAIN_C));
6071 
6072  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_MSE,
6073  cpl_table_get_column_stdev
6074  (gain_table, "GAIN")));
6075  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_MSE,
6076  DETMON_QC_GAIN_MSE_C));
6077 
6078  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD,1./gain));
6079  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD,
6080  DETMON_QC_CONAD_C));
6081 
6082 
6083  gain=cpl_table_get_column_median(gain_table, "GAIN_CORR");
6084 
6085  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_CORR,
6086  gain));
6087  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_CORR,
6088  DETMON_QC_GAIN_CORR_C));
6089 
6090 
6091  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD_CORR,1./gain));
6092  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD_CORR,
6093  DETMON_QC_CONAD_CORR_C));
6094 
6095 
6096  end_skip;
6097 
6098  return cpl_error_get_code();
6099 }
6100 
6101 
6102 /*---------------------------------------------------------------------------*/
6111 /*---------------------------------------------------------------------------*/
6112 static cpl_error_code
6113 detmon_lg_rescale(cpl_imagelist * to_rescale)
6114 {
6115  double med1 =
6116  cpl_image_get_median_window(cpl_imagelist_get(to_rescale, 0),
6117  detmon_lg_config.llx,
6118  detmon_lg_config.lly,
6119  detmon_lg_config.urx,
6120  detmon_lg_config.ury);
6121  double med2 =
6122  cpl_image_get_median_window(cpl_imagelist_get(to_rescale, 1),
6123  detmon_lg_config.llx,
6124  detmon_lg_config.lly,
6125  detmon_lg_config.urx,
6126  detmon_lg_config.ury);
6127 
6128  skip_if(0);
6129 
6130  if(fabs(med1 / med2 - 1) > 0.001) {
6131  if(med1 > med2)
6132  skip_if(cpl_image_divide_scalar(cpl_imagelist_get(to_rescale, 0),
6133  med1 / med2));
6134  else
6135  skip_if(cpl_image_divide_scalar(cpl_imagelist_get(to_rescale, 1),
6136  med2 / med1));
6137  }
6138 
6139  end_skip;
6140 
6141  return cpl_error_get_code();
6142 }
6143 
6144 static cpl_error_code
6145 detmon_pair_extract_next(const cpl_frameset * set,
6146  int* iindex,
6147  int* next_element,
6148  double* dit_array,
6149  cpl_frameset ** pair,
6150  double tolerance) /* detmon_lg_config.tolerance */
6151 {
6152  double dit = -100;
6153  double dit_next = -100;
6154  cpl_size* selection;
6155  int nsets_extracted = 0;
6156  cpl_ensure_code(set != NULL, CPL_ERROR_NULL_INPUT);
6157  cpl_ensure_code(dit_array != NULL, CPL_ERROR_NULL_INPUT);
6158  cpl_ensure_code(iindex != NULL, CPL_ERROR_NULL_INPUT);
6159  cpl_ensure_code(pair != NULL, CPL_ERROR_NULL_INPUT);
6160 
6161  nsets_extracted = cpl_frameset_get_size(set);
6162  selection = cpl_malloc(sizeof(cpl_size) * nsets_extracted);
6163  memset(&selection[0], 0, sizeof(cpl_size) * nsets_extracted);
6164 
6165 
6166  dit = dit_array[*next_element ];
6167  /* cpl_msg_info(cpl_func, "%d: dit %f",*next_element, dit ); */
6168  if (*next_element < nsets_extracted - 1)
6169  {
6170  dit_next = dit_array[*next_element + 1 ];
6171  /* cpl_msg_info(cpl_func, "%d: dit %f",*next_element + 1, dit_next ); */
6172  }
6173  /* one element would be returned always */
6174  selection[iindex[*next_element] ] = 1;
6175  if (fabs(dit - dit_next) < tolerance)
6176  {
6177  /* return a second element of the pair */
6178  selection[iindex[*next_element + 1] ] = 1;
6179  (*next_element)++;
6180  }
6181  else
6182  {
6183  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);
6184  }
6185  (*next_element)++;
6186  /* prepare frameset */
6187  cpl_frameset_delete(*pair);
6188  *pair = cpl_frameset_extract(set, selection, 1);
6189 
6190 
6191  cpl_free(selection);
6192  return cpl_error_get_code();
6193 }
6194 
6195 static cpl_error_code
6196 detmon_single_extract_next(const cpl_frameset * set,
6197  int* iindex,
6198  int* next_element,
6199  double* dit_array,
6200  cpl_frameset ** pair)
6201 {
6202  cpl_size* selection;
6203  int nsets_extracted = 0;
6204  cpl_ensure_code(set != NULL, CPL_ERROR_NULL_INPUT);
6205  cpl_ensure_code(dit_array != NULL, CPL_ERROR_NULL_INPUT);
6206  cpl_ensure_code(iindex != NULL, CPL_ERROR_NULL_INPUT);
6207  cpl_ensure_code(pair != NULL, CPL_ERROR_NULL_INPUT);
6208 
6209  nsets_extracted = cpl_frameset_get_size(set);
6210  selection = cpl_malloc(sizeof(cpl_size) * nsets_extracted);
6211  memset(&selection[0], 0, sizeof(cpl_size) * nsets_extracted);
6212 
6213  /* only one element would be returned */
6214  selection[iindex[*next_element] ] = 1;
6215  (*next_element)++;
6216  /* prepare frameset */
6217  cpl_frameset_delete(*pair);
6218  *pair = cpl_frameset_extract(set, selection, 1);
6219 
6220  cpl_free(selection);
6221  return cpl_error_get_code();
6222 }
6223 
6224 
6225 /*---------------------------------------------------------------------------*/
6316 /*---------------------------------------------------------------------------*/
6317 
6318 cpl_table *
6319 detmon_gain(const cpl_imagelist * imlist_on,
6320  const cpl_imagelist * imlist_off,
6321  const cpl_vector * exptimes,
6322  const cpl_vector * ndit,
6323  double tolerance,
6324  int llx,
6325  int lly,
6326  int urx,
6327  int ury,
6328  double kappa,
6329  int nclip,
6330  int xshift,
6331  int yshift,
6332  cpl_propertylist * qclist,
6333  unsigned mode,
6334  cpl_imagelist ** diff_imlist,
6335  cpl_imagelist ** autocorr_imlist)
6336 {
6337  cpl_table * gain_table = NULL;
6338  cpl_imagelist * difflist = NULL;
6339  cpl_imagelist * autocorrlist = NULL;
6340  cpl_imagelist * c_onlist = NULL;
6341  cpl_imagelist * c_offlist = NULL;
6342  cpl_vector * diffdits = NULL;
6343  cpl_vector * diffndits = NULL;
6344  int rows_in_gain = 0;
6345  int ndiffdits, ndits;
6346  int i, j;
6347  cpl_boolean opt_nir = mode & IRPLIB_GAIN_OPT ? OPT : NIR;
6348  const char * method = mode & IRPLIB_GAIN_PTC ? "PTC" : "MED";
6349 
6350  cpl_ensure(imlist_on != NULL, CPL_ERROR_NULL_INPUT, NULL);
6351  cpl_ensure(imlist_off != NULL, CPL_ERROR_NULL_INPUT, NULL);
6352  cpl_ensure(exptimes != NULL, CPL_ERROR_NULL_INPUT, NULL);
6353  cpl_ensure(qclist != NULL, CPL_ERROR_NULL_INPUT, NULL);
6354 
6355  /* Create table with columns */
6356  gain_table = cpl_table_new(cpl_vector_get_size(exptimes) / 2);
6357  skip_if(detmon_gain_table_create(gain_table, opt_nir));
6358 
6359 
6360  /* Search for different EXPTIME values */
6361  skip_if(detmon_lg_find_dits_ndits(exptimes, ndit,tolerance,&diffdits,
6362  &diffndits));
6363  ndiffdits = cpl_vector_get_size(diffdits);
6364 
6365  ndits = cpl_vector_get_size(exptimes);
6366 
6367  /* AUTOCORR processing requires both. They will become outputs later. */
6368  if (mode & IRPLIB_GAIN_WITH_AUTOCORR && (diff_imlist || autocorr_imlist)) {
6369  difflist = cpl_imagelist_new();
6370  autocorrlist = cpl_imagelist_new();
6371  }
6372 
6373  if (mode & IRPLIB_GAIN_COLLAPSE) {
6374  if (mode & IRPLIB_GAIN_WITH_RESCALE) {
6375  c_offlist = cpl_imagelist_duplicate(imlist_off);
6376  skip_if(detmon_lg_rescale(c_offlist));
6377  } else {
6378  c_offlist = (cpl_imagelist *) imlist_off;
6379  }
6380  }
6381 
6382  /* Loop over the different DITs found in EXPTIMEs */
6383  for (i = 0; i < ndiffdits; i++) {
6384  int c_nons;
6385  int c_noffs = 0; /* False (uninit) warning */
6386 
6387  double c_dit = 0;
6388  int c_ndit = 1;
6389 
6390  c_dit=cpl_vector_get(diffdits, i);
6391 
6392  if(opt_nir) {
6393  c_ndit=(int)cpl_vector_get(diffndits, i);
6394  }
6395 
6396  c_onlist = cpl_imagelist_new();
6397  c_nons = 0;
6398 
6399  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
6400  c_offlist = cpl_imagelist_new();
6401  c_noffs = 0;
6402  }
6403 
6404  /* Extraction of images of EXPTIME i */
6405  for(j = 0; j < ndits; j++) {
6406  if (fabs(c_dit - cpl_vector_get(exptimes, j)) <= tolerance) {
6407  /*
6408  * First we get the corresponding image from the ON imlist.
6409  * The option IRPLIB_GAIN_WITH_RESCALE requires to modify
6410  * the input pixel buffer; therefore we must duplicate it.
6411  * On the other hand, if this option is not required, there
6412  * is no need for that duplication. We must only care that
6413  * c_onlist must not be deleted but only unset.
6414  */
6415  cpl_image * im_on;
6416  if (mode & IRPLIB_GAIN_WITH_RESCALE) {
6417  const cpl_image * im =
6418  cpl_imagelist_get_const(imlist_on, j);
6419  im_on = cpl_image_duplicate(im);
6420  } else {
6421  im_on = (cpl_image *)cpl_imagelist_get_const(imlist_on, j);
6422  }
6423  skip_if(cpl_imagelist_set(c_onlist, im_on, c_nons));
6424  c_nons++;
6425 
6426  /*
6427  * Same explanation as above but for OFF imlist.
6428  * Only necessary when IRPLIB_GAIN_NO_COLLAPSE required.
6429  */
6430  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
6431  cpl_image * im_off;
6432  if (mode & IRPLIB_GAIN_WITH_RESCALE) {
6433  const cpl_image * im =
6434  cpl_imagelist_get_const(imlist_off, j);
6435  im_off = cpl_image_duplicate(im);
6436  } else {
6437  im_off =
6438  (cpl_image *) cpl_imagelist_get_const(imlist_off, j);
6439  }
6440  skip_if(cpl_imagelist_set(c_offlist, im_off, c_noffs));
6441  c_noffs++;
6442  }
6443  }
6444  }
6445 
6446  /* If NO_COLLAPSE, must be the same number of images! */
6447  if (mode & IRPLIB_GAIN_NO_COLLAPSE)
6448  skip_if (c_nons != c_noffs);
6449 
6450  /* There must be pairs! */
6451  skip_if (c_nons == 0 || c_nons % 2 != 0);
6452 
6453  /* Rescaling */
6454  if(mode & IRPLIB_GAIN_WITH_RESCALE) {
6455  skip_if(detmon_lg_rescale(c_onlist));
6456  if (mode & IRPLIB_GAIN_NO_COLLAPSE)
6457  skip_if(detmon_lg_rescale(c_offlist));
6458  }
6459 
6460  /* The following loop is necessary for the case of multiple pairs
6461  of same EXPTIME values */
6462  while(c_nons > 0) {
6463  int rows_affected = 1;
6464  skip_if(detmon_gain_table_fill_row(gain_table,
6465  c_dit,c_ndit,
6466  autocorrlist,
6467  difflist, c_onlist,
6468  c_offlist, kappa, nclip,
6469  llx, lly, urx, ury,
6470  xshift, yshift,1E10, 1E10, i,
6471  mode, &rows_affected));
6472  if (rows_affected)
6473  {
6474  rows_in_gain++;
6475  }
6476  if (mode & IRPLIB_GAIN_WITH_RESCALE) {
6477  cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
6478  cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
6479  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
6480  cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
6481  cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
6482  }
6483  } else {
6484  cpl_imagelist_unset(c_onlist, 0);
6485  skip_if(0);
6486  cpl_imagelist_unset(c_onlist, 0);
6487  skip_if(0);
6488  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
6489  cpl_imagelist_unset(c_offlist, 0);
6490  skip_if(0);
6491  cpl_imagelist_unset(c_offlist, 0);
6492  skip_if(0);
6493  }
6494  }
6495  skip_if(0);
6496  c_nons -= 2;
6497  }
6498 
6499  cpl_imagelist_delete(c_onlist);
6500  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
6501  cpl_imagelist_delete(c_offlist);
6502  }
6503  }
6504 
6505  skip_if(cpl_propertylist_append_string(qclist, DETMON_QC_METHOD, method));
6506  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_METHOD,
6507  DETMON_QC_METHOD_C));
6508 
6509  /* Computation of GAIN via polynomial fit */
6510  if (mode & IRPLIB_GAIN_PTC) {
6511  skip_if(detmon_lg_qc_ptc(gain_table, qclist, mode, rows_in_gain));
6512  } else {
6513  skip_if(detmon_lg_qc_med(gain_table, qclist, rows_in_gain));
6514  }
6515 
6516  if(mode & IRPLIB_GAIN_WITH_AUTOCORR) {
6517  double autocorr = cpl_table_get_column_median(gain_table, "AUTOCORR");
6518  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_AUTOCORR,
6519  autocorr));
6520  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_AUTOCORR,
6521  DETMON_QC_AUTOCORR_C));
6522  }
6523 
6524  if (diff_imlist != NULL) *diff_imlist = difflist;
6525  if (autocorr_imlist != NULL) *autocorr_imlist = autocorrlist;
6526 
6527  end_skip;
6528 
6529  cpl_vector_delete(diffdits);
6530  cpl_vector_delete(diffndits);
6531 
6532  return gain_table;
6533 }
6534 
6535 static cpl_error_code
6536 detmon_gain_table_create(cpl_table * gain_table,
6537  const cpl_boolean opt_nir)
6538 {
6539  if (opt_nir == NIR) {
6540  skip_if(cpl_table_new_column(gain_table, "DIT", CPL_TYPE_DOUBLE));
6541  skip_if(cpl_table_new_column(gain_table, "NDIT", CPL_TYPE_INT));
6542  } else { /* OPT */
6543  skip_if(cpl_table_new_column(gain_table, "EXPTIME", CPL_TYPE_DOUBLE));
6544  }
6545  skip_if(cpl_table_new_column(gain_table, "MEAN_ON1", CPL_TYPE_DOUBLE));
6546  skip_if(cpl_table_new_column(gain_table, "MEAN_ON2", CPL_TYPE_DOUBLE));
6547  skip_if(cpl_table_new_column(gain_table, "MEAN_OFF1", CPL_TYPE_DOUBLE));
6548  skip_if(cpl_table_new_column(gain_table, "MEAN_OFF2", CPL_TYPE_DOUBLE));
6549  skip_if(cpl_table_new_column(gain_table, "SIG_ON_DIF", CPL_TYPE_DOUBLE));
6550  skip_if(cpl_table_new_column(gain_table, "SIG_OFF_DIF", CPL_TYPE_DOUBLE));
6551  skip_if(cpl_table_new_column(gain_table, "GAIN", CPL_TYPE_DOUBLE));
6552  skip_if(cpl_table_new_column(gain_table, "AUTOCORR", CPL_TYPE_DOUBLE));
6553  skip_if(cpl_table_new_column(gain_table, "GAIN_CORR", CPL_TYPE_DOUBLE));
6554  skip_if(cpl_table_new_column(gain_table, "ADU", CPL_TYPE_DOUBLE));
6555  skip_if(cpl_table_new_column(gain_table, "X_FIT", CPL_TYPE_DOUBLE));
6556  skip_if(cpl_table_new_column(gain_table, "X_FIT_CORR", CPL_TYPE_DOUBLE));
6557  skip_if(cpl_table_new_column(gain_table, "Y_FIT", CPL_TYPE_DOUBLE));
6558  skip_if(cpl_table_new_column(gain_table, "Y_FIT_CORR", CPL_TYPE_DOUBLE));
6559  skip_if(cpl_table_new_column(gain_table, "FLAG", CPL_TYPE_INT));
6560 
6561  end_skip;
6562 
6563  return cpl_error_get_code();
6564 }
6565 
6566 static cpl_error_code
6567 detmon_lin_table_create(cpl_table * lin_table,
6568  const cpl_boolean opt_nir)
6569 {
6570  if (opt_nir == NIR) {
6571  skip_if(cpl_table_new_column(lin_table, "DIT", CPL_TYPE_DOUBLE));
6572  } else { /* OPT */
6573  skip_if(cpl_table_new_column(lin_table, "EXPTIME", CPL_TYPE_DOUBLE));
6574  }
6575  skip_if(cpl_table_new_column(lin_table, "MED", CPL_TYPE_DOUBLE));
6576  skip_if(cpl_table_new_column(lin_table, "MEAN", CPL_TYPE_DOUBLE));
6577  skip_if(cpl_table_new_column(lin_table, "MED_DIT", CPL_TYPE_DOUBLE));
6578  skip_if(cpl_table_new_column(lin_table, "MEAN_DIT", CPL_TYPE_DOUBLE));
6579  skip_if(cpl_table_new_column(lin_table, "ADL", CPL_TYPE_DOUBLE));
6580  end_skip;
6581 
6582  return cpl_error_get_code();
6583 }
6584 
6585 static cpl_vector *
6586 detmon_lg_find_dits(const cpl_vector * exptimes,
6587  double tolerance)
6588 {
6589  cpl_vector * dits = cpl_vector_new(cpl_vector_get_size(exptimes) / 2);
6590  int ndits = 0;
6591 
6592  int i, j;
6593 
6594  /* First different EXPTIME */
6595  cpl_vector_set(dits, 0, cpl_vector_get(exptimes, 0));
6596  ndits = 1;
6597 
6598  /* Search for all different EXPTIMEs */
6599  for(i = 1; i < cpl_vector_get_size(exptimes); i++) {
6600  int ndiffs = 0;
6601  for (j = 0; j < ndits; j++) {
6602  if (fabs(cpl_vector_get(exptimes, i) -
6603  cpl_vector_get(dits, j)) > tolerance)
6604  ndiffs++;
6605  }
6606  if(ndiffs == ndits) {
6607  cpl_vector_set(dits, ndits, cpl_vector_get(exptimes, i));
6608  ndits++;
6609  }
6610  }
6611 
6612  cpl_vector_set_size(dits, ndits);
6613 
6614  return dits;
6615 }
6616 
6617 
6618 
6619 
6620 static cpl_error_code
6621 detmon_lg_find_dits_ndits(const cpl_vector * exptimes,
6622  const cpl_vector * vec_ndits,
6623  double tolerance,
6624  cpl_vector** diff_dits,
6625  cpl_vector** diff_ndits)
6626 {
6627  int ndits = 0;
6628 
6629  int i, j;
6630  int size=0;
6631 
6632 
6633  * diff_dits = cpl_vector_new(cpl_vector_get_size(exptimes) / 2);
6634  * diff_ndits = cpl_vector_new(cpl_vector_get_size(*diff_dits));
6635 
6636  /* First different EXPTIME */
6637  cpl_vector_set(*diff_dits, 0, cpl_vector_get(exptimes, 0));
6638  cpl_vector_set(*diff_ndits, 0, cpl_vector_get(vec_ndits, 0));
6639 
6640  ndits = 1;
6641  size=cpl_vector_get_size(exptimes);
6642  /* Search for all different EXPTIMEs */
6643  for(i = 1; i < size; i++) {
6644  int ndiffs = 0;
6645  for (j = 0; j < ndits; j++) {
6646  if (fabs(cpl_vector_get(exptimes, i) -
6647  cpl_vector_get(*diff_dits,j)) > tolerance)
6648  ndiffs++;
6649  }
6650  if(ndiffs == ndits) {
6651  cpl_vector_set(*diff_dits, ndits, cpl_vector_get(exptimes, i));
6652  cpl_vector_set(*diff_ndits, ndits, cpl_vector_get(vec_ndits, i));
6653  ndits++;
6654  }
6655  }
6656 
6657  cpl_vector_set_size(*diff_dits, ndits);
6658  cpl_vector_set_size(*diff_ndits, ndits);
6659 
6660 
6661  return cpl_error_get_code();
6662 }
6663 
6664 
6665 /*---------------------------------------------------------------------------*/
6748 /*---------------------------------------------------------------------------*/
6749 
6750 cpl_table *
6751 detmon_lin(const cpl_imagelist * imlist_on,
6752  const cpl_imagelist * imlist_off,
6753  const cpl_vector * exptimes,
6754  double tolerance,
6755  int llx,
6756  int lly,
6757  int urx,
6758  int ury,
6759  int order,
6760  int ref_level,
6761  double kappa,
6762  cpl_boolean bpmbin,
6763  cpl_propertylist * qclist,
6764  unsigned mode,
6765  cpl_imagelist ** coeffs_cube,
6766  cpl_image ** bpm)
6767 {
6768  cpl_table * lin_table = NULL;
6769  cpl_imagelist * c_onlist = NULL;
6770  cpl_imagelist * c_offlist = NULL;
6771  cpl_vector * diffdits = NULL;
6772  cpl_imagelist * lin_inputs = NULL;
6773  cpl_polynomial * poly_linfit = NULL;
6774  cpl_image * fiterror = NULL;
6775  cpl_vector * vcoeffs = NULL;
6776  double * pcoeffs = NULL;
6777  int ndiffdits, ndits;
6778  int i, j;
6779  cpl_boolean opt_nir = mode & IRPLIB_LIN_OPT ? OPT : NIR;
6780  const cpl_vector *x = NULL;
6781  const cpl_vector *y = NULL;
6782 
6783  const cpl_image * first = NULL;
6784  int sizex = 0;
6785  int sizey = 0;
6786 
6787  cpl_size deg;
6788  double vsize = 0;
6789 
6790 
6791  cpl_ensure(imlist_on != NULL, CPL_ERROR_NULL_INPUT, NULL);
6792  cpl_ensure(imlist_off != NULL, CPL_ERROR_NULL_INPUT, NULL);
6793  cpl_ensure(exptimes != NULL, CPL_ERROR_NULL_INPUT, NULL);
6794  cpl_ensure(qclist != NULL, CPL_ERROR_NULL_INPUT, NULL);
6795  cpl_ensure(order > 0 , CPL_ERROR_ILLEGAL_INPUT, NULL);
6796 
6797  vcoeffs = cpl_vector_new(order + 1);
6798  pcoeffs = cpl_vector_get_data(vcoeffs);
6799 
6800  /* This mode requires optional outputs */
6801  if (mode & IRPLIB_LIN_PIX2PIX) {
6802  cpl_ensure(coeffs_cube != NULL, CPL_ERROR_NULL_INPUT, NULL);
6803  cpl_ensure(bpm != NULL, CPL_ERROR_NULL_INPUT, NULL);
6804  lin_inputs = cpl_imagelist_new();
6805  }
6806 
6807  /* Create table with columns */
6808  lin_table = cpl_table_new(cpl_vector_get_size(exptimes) / 2);
6809  skip_if(detmon_lin_table_create(lin_table, opt_nir));
6810 
6811  /* Search for different EXPTIME values */
6812  /* Search for different EXPTIME values */
6813  diffdits = detmon_lg_find_dits(exptimes, tolerance);
6814  ndiffdits = cpl_vector_get_size(diffdits);
6815 
6816  ndits = cpl_vector_get_size(exptimes);
6817 
6818 
6819 
6820 
6821 
6822 
6823  /* TO BE IMPLEMENTED SIMILARLY TO UPPER LEVEL FUNCTION (search for nskip)
6824  if(filter > 0) {
6825  double med1 =
6826  cpl_image_get_median_window(cpl_imagelist_get(imlist_on, 0),
6827  llx,lly,urx,ury);
6828  double med2 =
6829  cpl_image_get_median_window(cpl_imagelist_get(imlist_on, 1),
6830  llx,lly,urx,ury);
6831  if ( med1 > (double)filter ||
6832  med2 > (double)filter) {
6833  follow = CPL_FALSE;
6834  cpl_table_select_row(lin_table, dit_nb);
6835  dit_nskip++;
6836  cpl_msg_warning(cpl_func, "Frames of EXPTIME nb %d "
6837  "will not be taken into account for computation "
6838  "as they are above --filter threshold", dit_nb);
6839  }
6840  }
6841  */
6842 
6843 
6844 
6845 
6846  if (mode & IRPLIB_LIN_COLLAPSE) {
6847  /*
6848  * The master bias is required only for
6849  * linearity computation in the OPT domain
6850  */
6851  cpl_image * collapse = cpl_imagelist_collapse_create(imlist_off);
6852  skip_if(collapse == NULL);
6853 
6854  c_offlist = cpl_imagelist_new();
6855  skip_if(cpl_imagelist_set(c_offlist, collapse, 0));
6856  }
6857 
6858  /* Loop over the different DITs found in EXPTIMEs */
6859  for (i = 0; i < ndiffdits; i++) {
6860  int c_nons;
6861  int c_noffs = 0; /* False (uninit) warning */
6862 
6863  double c_dit = cpl_vector_get(diffdits, i);
6864 
6865  c_onlist = cpl_imagelist_new();
6866  c_nons = 0;
6867 
6868  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6869  c_offlist = cpl_imagelist_new();
6870  c_noffs = 0;
6871  }
6872 
6873  for(j = 0; j < ndits; j++) {
6874  if (fabs(c_dit - cpl_vector_get(exptimes, j)) <= tolerance) {
6875  /*
6876  * First we get the corresponding image from the ON imlist.
6877  * The option IRPLIB_GAIN_WITH_RESCALE requires to modify
6878  * the input pixel buffer; therefore we must duplicate it.
6879  * On the other hand, if this option is not required, there
6880  * is no need for that duplication. We must only care that
6881  * c_onlist must not be deleted but only unset.
6882  */
6883  cpl_image * im_on;
6884  if (mode & IRPLIB_LIN_WITH_RESCALE) {
6885  const cpl_image * im =
6886  cpl_imagelist_get_const(imlist_on, j);
6887  im_on = cpl_image_duplicate(im);
6888  } else {
6889  im_on = (cpl_image *)cpl_imagelist_get_const(imlist_on, j);
6890  }
6891  skip_if(cpl_imagelist_set(c_onlist, im_on, c_nons));
6892  c_nons++;
6893 
6894  /*
6895  * Same explanation as above but for OFF imlist.
6896  * Only necessary when IRPLIB_GAIN_NO_COLLAPSE required.
6897  */
6898  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6899  cpl_image * im_off;
6900  if (mode & IRPLIB_LIN_WITH_RESCALE) {
6901  const cpl_image * im =
6902  cpl_imagelist_get_const(imlist_off, j);
6903  im_off = cpl_image_duplicate(im);
6904  } else {
6905  im_off =
6906  (cpl_image *) cpl_imagelist_get_const(imlist_off, j);
6907  }
6908  skip_if(cpl_imagelist_set(c_offlist, im_off, c_noffs));
6909  c_noffs++;
6910  }
6911  }
6912  }
6913 
6914  /* If NO_COLLAPSE, must be the same number of images! */
6915  if (mode & IRPLIB_LIN_NO_COLLAPSE)
6916  skip_if (c_nons != c_noffs);
6917 
6918  /* There must be pairs! */
6919  skip_if (c_nons == 0 || c_nons % 2 != 0);
6920 
6921  /* Rescaling */
6922  if(mode & IRPLIB_LIN_WITH_RESCALE) {
6923  skip_if(detmon_lg_rescale(c_onlist));
6924  if (mode & IRPLIB_LIN_NO_COLLAPSE)
6925  skip_if(detmon_lg_rescale(c_offlist));
6926  }
6927 
6928  /* The following loop is necessary for the case of multiple pairs
6929  of same EXPTIME values */
6930  while(c_nons > 0) {
6931 
6932  skip_if(detmon_lin_table_fill_row(lin_table, c_dit,
6933  lin_inputs,
6934  c_onlist, c_offlist,
6935  llx, lly, urx, ury,
6936  i, 0, mode));
6937 
6938  if (mode & IRPLIB_LIN_WITH_RESCALE) {
6939  cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
6940  cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
6941  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6942  cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
6943  cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
6944  }
6945  } else {
6946  cpl_imagelist_unset(c_onlist, 0);
6947  skip_if(0);
6948  cpl_imagelist_unset(c_onlist, 0);
6949  skip_if(0);
6950  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6951  cpl_imagelist_unset(c_offlist, 0);
6952  skip_if(0);
6953  cpl_imagelist_unset(c_offlist, 0);
6954  skip_if(0);
6955  }
6956  }
6957  skip_if(0);
6958  c_nons -= 2;
6959  }
6960 
6961  cpl_imagelist_delete(c_onlist);
6962  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6963  cpl_imagelist_delete(c_offlist);
6964  }
6965  }
6966 
6967  skip_if(detmon_add_adl_column(lin_table, opt_nir));
6968 
6969  if(!(mode & IRPLIB_LIN_PIX2PIX)) {
6970  double mse = 0;
6971  /* Computation of LINEARITY via polynomial fit */
6972  y = cpl_vector_wrap(cpl_table_get_nrow(lin_table),
6973  (double *)cpl_table_get_data_double_const(lin_table,
6974  "MED"));
6975  if (opt_nir == NIR) {
6976  x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
6977  (double *)cpl_table_get_data_double_const(lin_table, "DIT"));
6978  } else {
6979  x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
6980  (double *)cpl_table_get_data_double_const(lin_table, "EXPTIME"));
6981  }
6982  if(x == NULL || y == NULL) {
6983  cpl_vector_unwrap((cpl_vector *)x);
6984  cpl_vector_unwrap((cpl_vector *)y);
6985  /*
6986  * As x and y are const vectors, if they would be defined at the
6987  * beginning of the function (required for skip_if - end_skip
6988  * scheme), they couldn't be initialised to NULL (required too).
6989  * Therefore, they are considered apart from the scheme.
6990  */
6991  skip_if(1);
6992  }
6993 
6994  cpl_msg_info(cpl_func, "Polynomial fitting for the LINEARITY");
6995  poly_linfit = irplib_polynomial_fit_1d_create_chiq(x, y, order, &mse);
6996 
6997  if(order == cpl_vector_get_size(x) - 1) {
6998  cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
6999  mse = 0;
7000  }
7001 
7002  if(poly_linfit == NULL) {
7003  cpl_vector_unwrap((cpl_vector *)x);
7004  cpl_vector_unwrap((cpl_vector *)y);
7005  /* See comment in previous error checking if() statement */
7006  skip_if(1);
7007  }
7008 
7009  cpl_vector_unwrap((cpl_vector *)x);
7010  cpl_vector_unwrap((cpl_vector *)y);
7011 
7012  for(deg = 0; deg <= order; deg++) {
7013  const double coeff =
7014  cpl_polynomial_get_coeff(poly_linfit, &deg);
7015  char *name_o =
7016  cpl_sprintf("ESO QC LIN COEF%" CPL_SIZE_FORMAT "", deg);
7017  assert(name_o != NULL);
7018  skip_if(cpl_propertylist_append_double(qclist, name_o, coeff));
7019  skip_if(cpl_propertylist_set_comment(qclist,name_o,
7020  DETMON_QC_LIN_COEF_C));
7021  cpl_free(name_o);
7022  pcoeffs[deg] = coeff;
7023  }
7024  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT, mse));
7025  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
7026  DETMON_QC_ERRFIT_MSE_C));
7027 
7028 
7029  } else {
7030  if (opt_nir == NIR) {
7031  x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
7032  (double *)cpl_table_get_data_double_const(lin_table,
7033  "DIT"));
7034  } else {
7035  x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
7036  (double *)cpl_table_get_data_double_const(lin_table,
7037  "EXPTIME"));
7038  }
7039 
7040 
7041  first = cpl_imagelist_get_const(lin_inputs, 0);
7042  sizex = cpl_image_get_size_x(first);
7043  sizey = cpl_image_get_size_y(first);
7044 
7045  vsize = cpl_vector_get_size(x);
7046 
7047  fiterror = cpl_image_new(sizex, sizey, CPL_TYPE_FLOAT);
7048 
7049  *coeffs_cube =
7050  cpl_fit_imagelist_polynomial(x, lin_inputs, 0,
7051  order, FALSE, CPL_TYPE_FLOAT,
7052  fiterror);
7053 
7054  cpl_vector_unwrap((cpl_vector*)x);
7055  irplib_ensure(*coeffs_cube != NULL, CPL_ERROR_UNSPECIFIED,
7056  "Failed polynomial fit");
7057 
7058  for(i = 0; i <= order; i++) {
7059  cpl_image *image = cpl_imagelist_get(*coeffs_cube, i);
7060  const double coeff = cpl_image_get_median(image);
7061  char * name_o1 = cpl_sprintf("ESO QC LIN COEF%d", i);
7062  char * name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", i);
7063  pcoeffs[i] = coeff;
7064  assert(name_o1 != NULL);
7065  assert(name_o2 != NULL);
7066  skip_if(cpl_propertylist_append_double(qclist, name_o1, coeff));
7067  skip_if(cpl_propertylist_set_comment(qclist,name_o1,
7068  DETMON_QC_LIN_COEF_C));
7069  cpl_free(name_o1);
7070  name_o1= NULL;
7071  skip_if(cpl_propertylist_append_double(qclist, name_o2,
7072  cpl_image_get_stdev(image)));
7073  skip_if(cpl_propertylist_set_comment(qclist,name_o2,
7074  DETMON_QC_LIN_COEF_ERR_C));
7075  cpl_free(name_o2);
7076  name_o2= NULL;
7077  }
7078 
7079  if(order == vsize - 1) {
7080  cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
7081  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT,
7082  0.0));
7083  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
7084  DETMON_QC_ERRFIT_C));
7085 
7086 
7087  } else {
7088  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT,
7089  cpl_image_get_median(fiterror)));
7090  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
7091  DETMON_QC_ERRFIT_C));
7092 
7093  }
7094  }
7095 
7096  skip_if(detmon_lg_lineff(pcoeffs, qclist, ref_level, order));
7097 
7098  if(mode & IRPLIB_LIN_PIX2PIX) {
7099  int nbpixs;
7100  *bpm = detmon_bpixs(*coeffs_cube, bpmbin, kappa, &nbpixs);
7101  skip_if(*bpm == NULL);
7102  skip_if(cpl_propertylist_append_int(qclist, DETMON_QC_NUM_BPM,
7103  nbpixs));
7104  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_NUM_BPM,
7105  DETMON_QC_NUM_BPM_C));
7106  }
7107 
7108  end_skip;
7109 
7110  cpl_vector_delete(diffdits);
7111  cpl_polynomial_delete(poly_linfit);
7112  cpl_imagelist_delete(lin_inputs);
7113  cpl_vector_delete(vcoeffs);
7114  cpl_image_delete(fiterror);
7115 
7116  return lin_table;
7117 
7118 }
7119 
7120 /*--------------------------------------------------------------------------*/
7144 /*--------------------------------------------------------------------------*/
7145 static cpl_error_code
7146 detmon_lin_table_fill_row(cpl_table * lin_table, double c_dit,
7147  cpl_imagelist * linearity_inputs,
7148  const cpl_imagelist * ons,
7149  const cpl_imagelist * offs,
7150  int llx,
7151  int lly,
7152  int urx,
7153  int ury,
7154  const int pos,
7155  const int nskip,
7156  unsigned mode)
7157 {
7158  cpl_image * extracted=NULL;
7159 
7160  cpl_ensure_code(lin_table != NULL, CPL_ERROR_NULL_INPUT);
7161  cpl_ensure_code(ons != NULL, CPL_ERROR_NULL_INPUT);
7162  cpl_ensure_code(offs != NULL, CPL_ERROR_NULL_INPUT);
7163 
7164  if (mode & IRPLIB_LIN_PIX2PIX) {
7165  cpl_msg_debug(cpl_func,"checking linearity inputs");
7166  cpl_ensure_code(linearity_inputs != NULL, CPL_ERROR_NULL_INPUT);
7167  }
7168 
7169 
7170  if (mode & IRPLIB_LIN_NIR) {
7171  cpl_table_set(lin_table, "DIT", pos, c_dit);
7172  } else if (mode & IRPLIB_LIN_OPT) { /*OPT */
7173  cpl_table_set(lin_table, "EXPTIME", pos, c_dit);
7174  } else {
7175  cpl_msg_error(cpl_func, "Mandatory mode not given");
7176  }
7177 
7178  {
7179  const cpl_image * off2;
7180  if (cpl_imagelist_get_size(offs) == 1 || mode & IRPLIB_LIN_COLLAPSE)
7181  off2 = cpl_imagelist_get_const(offs, 0);
7182  else
7183  off2 = cpl_imagelist_get_const(offs, 1);
7184 
7185  extracted = detmon_subtracted_avg(cpl_imagelist_get_const(ons, 0),
7186  cpl_imagelist_get_const(offs, 0),
7187  cpl_imagelist_get_const(ons, 1),
7188  off2,
7189  llx, lly, urx, ury);
7190  cpl_ensure_code(extracted != NULL, cpl_error_get_code());
7191  }
7192 
7193  {
7194  double median = cpl_image_get_median(extracted);
7195  double mean= cpl_image_get_mean(extracted);
7196  cpl_table_set(lin_table, "MED", pos, median);
7197  cpl_table_set(lin_table, "MEAN", pos, mean);
7198 
7199  cpl_table_set(lin_table, "MED_DIT", pos, median / c_dit);
7200  cpl_table_set(lin_table, "MEAN_DIT", pos, mean / c_dit);
7201  }
7202 
7203  /* Insert to the imagelist used to fit the polynomial */
7204  if(mode & IRPLIB_LIN_PIX2PIX) {
7205  cpl_error_code error = cpl_imagelist_set(linearity_inputs, extracted,
7206  pos-nskip);
7207  cpl_ensure_code(!error, error);
7208  } else {
7209  cpl_image_delete(extracted);
7210  }
7211 
7212  return cpl_error_get_code();
7213 }
7214 
7215 static double irplib_calculate_total_noise_smooth(const cpl_image* pimage,
7216  int pattern_x, int pattern_y)
7217 {
7218  cpl_image * p_tmp_image = 0;
7219  cpl_image * psmooth_image = 0;
7220  double ret_noise;
7221  cpl_mask * mask = cpl_mask_new(pattern_x, pattern_y);
7222  cpl_mask_not(mask);
7223  p_tmp_image = cpl_image_duplicate(pimage);
7224  cpl_image_filter_mask(p_tmp_image,pimage, mask,CPL_FILTER_MEDIAN ,CPL_BORDER_FILTER);
7225  cpl_image_divide_scalar(p_tmp_image, cpl_image_get_median(pimage));
7226  psmooth_image = cpl_image_divide_create(pimage,p_tmp_image);
7227  ret_noise = irplib_calculate_total_noise(psmooth_image);
7228  cpl_mask_delete(mask);
7229  cpl_image_delete(psmooth_image);
7230  cpl_image_delete(p_tmp_image);
7231  return ret_noise;
7232 }
7233 
7234 static double irplib_calculate_total_noise(const cpl_image* pimage)
7235 {
7236  double total_noise = -1;
7237  unsigned long max_bin_size = 1E5;
7238  const double hstart = cpl_image_get_min(pimage);
7239  const double hrange = cpl_image_get_max(pimage) - hstart;
7240  const unsigned long nbins = max_bin_size;
7241  cpl_error_code err = CPL_ERROR_NONE;
7242  /* apply histogram method */
7243  irplib_hist * phist = 0;
7244  phist = irplib_hist_new();
7245  /* 2 extra-bins for possible out-of-range values */
7246 
7247  irplib_hist_init(phist, nbins, hstart, hrange);
7248  err = irplib_hist_fill(phist, pimage);
7249  if (err == CPL_ERROR_NONE)
7250  {
7251  unsigned int i = 0;
7252  double x0 = 0;
7253  double area = 0;
7254  double offset = 0;
7255 
7256  /* prepare vector */
7257  unsigned long n_bins = irplib_hist_get_nbins(phist);
7258  double start = irplib_hist_get_start(phist);
7259  double bin_size = irplib_hist_get_bin_size(phist);
7260  cpl_vector* pdata_vector = cpl_vector_new(n_bins);
7261  cpl_vector* ppos_vector = cpl_vector_new(n_bins);
7262  cpl_table* ptable = cpl_table_new(n_bins);
7263  cpl_table_new_column(ptable, "bin", CPL_TYPE_DOUBLE);
7264  cpl_table_new_column(ptable, "value", CPL_TYPE_DOUBLE);
7265  for(i = 0; i < n_bins; i++)
7266  {
7267  unsigned int value = irplib_hist_get_value(phist, i);
7268  double dvalue = (double)(value);
7269  cpl_vector_set(pdata_vector, i, dvalue);
7270  cpl_vector_set(ppos_vector, i, start + i * bin_size);
7271 
7272  cpl_table_set(ptable, "bin", i, start + i * bin_size);
7273  cpl_table_set(ptable, "value", i, dvalue);
7274  }
7275  err = cpl_vector_fit_gaussian(ppos_vector, NULL, pdata_vector, NULL, CPL_FIT_ALL, &x0, &total_noise, &area, &offset, NULL, NULL, NULL );
7276  if (err == CPL_ERROR_NONE)
7277  {
7278  cpl_msg_info(cpl_func, "FPN Calculation: histogram x0[%f] total_noise[%f] area[%f] offset[%f]", x0, total_noise, area, offset);
7279  }
7280  else
7281  {
7282  cpl_msg_warning(cpl_func, "FPN could not be computed due failed Gaussian Fit, err msg [%s]", cpl_error_get_message());
7283  cpl_error_reset();
7284  }
7285  cpl_table_delete(ptable);
7286  cpl_vector_delete(ppos_vector);
7287  cpl_vector_delete(pdata_vector);
7288  }
7289  else
7290  {
7291  cpl_msg_warning(cpl_func, "FPN could not be computed due failed histogram computation, err msg [%s]", cpl_error_get_message());
7292  cpl_error_reset();
7293  }
7294  irplib_hist_delete(phist);
7295 
7296  return total_noise;
7297 }
7298 
7299 static double irplib_compute_err(double gain, double ron, double FA)
7300 {
7301  double int_gain = (gain * gain - 1) / 12;
7302  if (int_gain < 0)
7303  {
7304  int_gain = 0;
7305  }
7306  return sqrt(ron * ron + FA / gain + int_gain);
7307 }
7308 
7309 static double irplib_fpn_lg(const cpl_image* f1, int* range, double gain ,
7310  FPN_METHOD fpn_method, int smooth_size, double* mse)
7311 {
7312  cpl_image* im_diff = 0;
7313  const cpl_image* im_f1 = f1;
7314  cpl_image* im_inrange1 = 0;
7315  double FA = 0;
7316  double s_tot = 0; /* absolute total noise */
7317  double s_fpn = 0; /* fixed pattern noise */
7318  double sr_fpn = 0; /* relative structural noise */
7319  /*che cinput*/
7320  if (gain<=0) {
7321  /* put dummy values Negative to indicate a problem occurred
7322  (FPN should be always positive) */
7323  cpl_msg_warning(cpl_func,"gain[%f]<0", gain);
7324  cpl_msg_warning(cpl_func,"We set dummy values for FPN");
7325  s_fpn=-999.;
7326  sr_fpn=-999;
7327  return sr_fpn;
7328  }
7329  if (range)
7330  {
7331  im_inrange1 = cpl_image_extract(f1, range[0], range[1], range[2], range[3]);
7332  im_f1 = im_inrange1;
7333  }
7334  FA = cpl_image_get_median(im_f1);
7335 
7336  /* apply histogram method */
7337  /* Is this irplib function giving the right result?? */
7338  switch (fpn_method)
7339  {
7340  case FPN_SMOOTH:
7341  cpl_msg_info(cpl_func,"SMOOTH method is used for FPN, pattern size[%d x %d] pixels",smooth_size,smooth_size );
7342  s_tot = irplib_calculate_total_noise_smooth(im_f1,smooth_size,smooth_size);
7343  break;
7344  case FPN_HISTOGRAM:
7345  cpl_msg_info(cpl_func,"HISTOGRAM method is used for FPN");
7346  s_tot = irplib_calculate_total_noise(im_f1);
7347  break;
7348  default:
7349  s_tot = -1;
7350  sr_fpn = -1;
7351  cpl_msg_warning(cpl_func,"fpn_method is not defined");
7352  break;
7353  }
7354  if (s_tot > 0)
7355  {
7356  if (FA<0)
7357  {
7358  /* put dummy values Negative to indicate a problem occurred
7359  (FPN should be always positive) */
7360  cpl_msg_warning(cpl_func,"Median flux on sum of flats<0");
7361  cpl_msg_warning(cpl_func,"We set dummy values for FPN");
7362  s_fpn=-999.;
7363  sr_fpn=-999;
7364  }
7365 
7366  if ((s_tot * s_tot - FA / gain) > 0)
7367  {
7368  s_fpn = sqrt(s_tot * s_tot - FA / gain);
7369  sr_fpn = s_fpn / FA;
7370  *mse = (irplib_compute_err(gain, 0, FA)) * gain / FA;
7371  } else {
7372  /* put dummy values Negative to indicate a problem occurred
7373  (FPN should be always positive) */
7374  cpl_msg_warning(cpl_func,"s_tot * s_tot < FA / gain");
7375  cpl_msg_warning(cpl_func,"We set dummy values for FPN");
7376  s_fpn=-999.;
7377  sr_fpn=-999;
7378  *mse = -1;
7379  }
7380  /*
7381  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);
7382  */
7383  }
7384  cpl_image_delete(im_diff);
7385  if (range)
7386  {
7387  cpl_image_delete(im_inrange1);
7388  }
7389  return sr_fpn;
7390 }
7391 
7392 
7393 static cpl_imagelist * irplib_load_fset_wrp(const cpl_frameset * pframeset,
7394  cpl_type type , int whichext)
7395 {
7396  /* FIXME: load image into window size from beginning to
7397  * save all the extracts */
7398  return detmon_load_frameset_window(pframeset, type, 0, whichext,
7399  detmon_lg_config.llx,
7400  detmon_lg_config.lly,
7401  detmon_lg_config.urx,
7402  detmon_lg_config.ury,
7403  detmon_lg_config.nx,
7404  detmon_lg_config.ny);
7405 }
7406 
7407 static cpl_imagelist * irplib_load_fset_wrp_ext(const cpl_frameset * pframeset,
7408  cpl_type type , int whichext)
7409 {
7410  int i = whichext; /* fake code to avoid compiler warning */
7411  cpl_imagelist* offs = cpl_imagelist_new();
7412  detmon_lg_config.load_fset(pframeset, type, offs);
7413  i++;
7414  return offs;
7415 }
7416 
7417 static cpl_error_code irplib_table_create_column(cpl_table* ptable,
7418  cpl_propertylist* plist)
7419 {
7420  if (ptable && plist)
7421  {
7422  int size = cpl_propertylist_get_size(plist);
7423  int i = 0;
7424  for (i = 0; i < size; i++)
7425  {
7426  cpl_property* pprop = cpl_propertylist_get(plist,i);
7427  if (pprop)
7428  {
7429  const char* pname = cpl_property_get_name(pprop);
7430  if (pname)
7431  {
7432  cpl_table_new_column(ptable, pname, cpl_property_get_type(pprop));
7433  if (cpl_error_get_code() != CPL_ERROR_NONE)
7434  {
7435  cpl_msg_warning(cpl_func, "cannot create new column[%s], err[%s]", pname, cpl_error_get_message());
7436  break; /* leave the cycle */
7437  }
7438  }
7439  }
7440  }
7441  }
7442  return cpl_error_get_code();
7443 }
7444 
7445 static cpl_error_code irplib_fill_table_DETWINUIT(cpl_table* ptable,
7446  cpl_propertylist* plist, int row)
7447 {
7448  cpl_error_code err = CPL_ERROR_NONE;
7449  if (ptable && plist)
7450  {
7451  int size = cpl_propertylist_get_size(plist);
7452  int i = 0;
7453  for (i = 0; i < size; i++)
7454  {
7455  cpl_property* pprop = cpl_propertylist_get(plist,i);
7456  if (pprop)
7457  {
7458  const char* pname = cpl_property_get_name(pprop);
7459  double value = cpl_property_get_double(pprop);
7460  if (pname)
7461  {
7462  cpl_table_set_double(ptable, pname, row, value);
7463  if (cpl_error_get_code() != CPL_ERROR_NONE)
7464  {
7465  cpl_msg_warning(cpl_func, "cannot write value to the table, column[%s] value[%f], err[%s]", pname, value, cpl_error_get_message());
7466  cpl_error_reset();
7467  break; /* leave the cycle */
7468  }
7469  }
7470  }
7471  }
7472  }
7473  return err;
7474 }
7475 
7476 cpl_error_code detmon_check_order(const double *exptime, int sz,
7477  double tolerance, int order)
7478 {
7479  int nsets = 0;
7480  int i = 0;
7481  /* 1. Determine number of groups */
7482  /* cpl_msg_warning(cpl_func, "detmon_check_order sz[%i]", sz);*/
7483  do
7484  {
7485  /* cpl_msg_warning(cpl_func, "detmon_check_order i[%i] exptime[%g]", i, exptime[i]); */
7486  nsets++;
7487  do
7488  {
7489  i++;
7490  if(i == sz - 1)
7491  {
7492  break;
7493  }
7494  } while(fabs(exptime[i-1] - exptime[i]) < tolerance);
7495  } while(i < sz - 1);
7496  /* the very last adjustment for the last group */
7497  if (!fabs(exptime[i-1] - exptime[i]) < tolerance) nsets++;
7498  if(nsets <= order)
7499  {
7500  cpl_error_set_message(cpl_func,CPL_ERROR_INCOMPATIBLE_INPUT,
7501  "Not enough frames for the polynomial"
7502  " fitting. nsets = %d <= %d order",
7503  nsets,order);
7504  }
7505  return cpl_error_get_code();
7506 }
7507 
7508 static cpl_error_code
7509 detmon_lg_dfs_save_imagelist(
7510  cpl_frameset * frameset,
7511  const cpl_parameterlist * parlist,
7512  const cpl_frameset *usedframes,
7513  const cpl_imagelist *coeffs,
7514  const char *recipe_name,
7515  const cpl_propertylist *mypro_coeffscube,
7516  const char * package,
7517  const char * name_o)
7518 {
7519  return(cpl_dfs_save_imagelist
7520  (frameset, NULL, parlist, usedframes, NULL,coeffs, CPL_BPP_IEEE_FLOAT,
7521  recipe_name, mypro_coeffscube, NULL, package,
7522  name_o));
7523 }
7524 
7525 static void detmon_lg_add_empty_image(cpl_imagelist* imlist, int pos)
7526 {
7527  const cpl_image* first = cpl_imagelist_get(imlist, 0);
7528  if (first)
7529  {
7530  int x = cpl_image_get_size_x(first);
7531  int y = cpl_image_get_size_y(first);
7532  cpl_type type = cpl_image_get_type(first);
7533  cpl_image * blank = cpl_image_new(x, y, type);
7534  cpl_imagelist_set(imlist, blank, pos);
7535  }
7536 }
7537 
7538 
7539 cpl_error_code
7540 detmon_lg_set_tag(cpl_frameset* set, const char** tag_on, const char** tag_off)
7541 {
7542  int ntag_old=0;
7543  int ntag_new=0;
7544 
7545  ntag_old=cpl_frameset_count_tags(set,DETMON_LG_ON_RAW_OLD);
7546  ntag_new=cpl_frameset_count_tags(set,DETMON_LG_ON_RAW_NEW);
7547  if(ntag_old) {
7548  *tag_on=DETMON_LG_ON_RAW_OLD;
7549  *tag_off=DETMON_LG_OFF_RAW_OLD;
7550  } else if (ntag_new) {
7551  *tag_on=DETMON_LG_ON_RAW_NEW;
7552  *tag_off=DETMON_LG_OFF_RAW_NEW;
7553  } else {
7554  cpl_msg_error(cpl_func,"Provide %s and %s (or %s and %s) input frames",
7555  DETMON_LG_ON_RAW_NEW,DETMON_LG_OFF_RAW_NEW,
7556  DETMON_LG_ON_RAW_OLD,DETMON_LG_OFF_RAW_OLD);
7557  }
7558 
7559 
7560  return cpl_error_get_code();
7561 }