IIINSTRUMENT Pipeline Reference Manual  1.3.11a
detmon_lg.c
1 /* $Id: detmon_lg.c,v 1.31 2013-08-07 09:32:37 jtaylor Exp $
2  *
3  * This file is part of the irplib package
4  * Copyright (C) 2002, 2003 European Southern Observatory
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
19  */
20 
21 
22 /*
23  * $Author: jtaylor $
24  * $Date: 2013-08-07 09:32:37 $
25  * $Revision: 1.31 $
26  * $Name: not supported by cvs2svn $
27  *
28  */
29 
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33 
34 /*---------------------------------------------------------------------------
35  Includes
36  ---------------------------------------------------------------------------*/
37 
38 /* Must include first to ensure declaration of complex CPL functions */
39 #include <complex.h>
40 
41 #include "detmon_lg.h"
42 
43 #include "detmon.h"
44 #include "detmon_utils.h"
45 #include "detmon_lg_impl.h"
46 
47 #include "irplib_ksigma_clip.h"
48 #include "irplib_utils.h"
49 #include "irplib_hist.h"
50 
51 #include "hdrl.h"
52 
53 #include <math.h>
54 #include <string.h>
55 #include <assert.h>
56 
58 /*
59  * @defgroup irplib_detmon Detector monitoring functions
60  */
61 
62 /*--------------------------------------------------------------------------*/
63 
64 /*---------------------------------------------------------------------------
65  Defines
66  ---------------------------------------------------------------------------*/
67 /*method for calculating Fixed Pattern Noise (FPN)*/
68 enum _FPN_METHOD
69 {
70  FPN_UNKNOWN,
71  FPN_HISTOGRAM, /*default*/
72  FPN_SMOOTH,
73 };
74 typedef enum _FPN_METHOD FPN_METHOD;
75 static struct
76 {
77  const char * method;
78  /* Inputs */
79  int order;
80  double kappa;
81  int niter;
82  int threshold_min;
83  int threshold_max;
84  int llx;
85  int lly;
86  int urx;
87  int ury;
88  int ref_level;
89  int threshold;
90  int m;
91  int n;
92  int llx1;
93  int lly1;
94  int urx1;
95  int ury1;
96  int llx2;
97  int lly2;
98  int urx2;
99  int ury2;
100  int llx3;
101  int lly3;
102  int urx3;
103  int ury3;
104  int llx4;
105  int lly4;
106  int urx4;
107  int ury4;
108  int llx5;
109  int lly5;
110  int urx5;
111  int ury5;
112  int nx;
113  int ny;
114  cpl_boolean wholechip;
115  cpl_boolean autocorr;
116  cpl_boolean intermediate;
117  cpl_boolean collapse;
118  cpl_boolean rescale;
119  cpl_boolean pix2pix;
120  cpl_boolean bpmbin;
121  int filter;
122  double tolerance;
123  cpl_boolean pafgen;
124  const char * pafname;
125  /* Outputs */
126  double cr;
127  int exts;
128  int nb_extensions;
129  double lamp_stability;
130  cpl_boolean lamp_ok;
131  /* by kmirny */
132  int (* load_fset) (const cpl_frameset *, cpl_type, cpl_imagelist *);
133  cpl_imagelist * (* load_fset_wrp) (const cpl_frameset *, cpl_type, int);
134  FPN_METHOD fpn_method;
135  int fpn_smooth;
136  double saturation_limit;
137  double gain_threshold;
138  cpl_boolean split_coeffs;
139 } detmon_lg_config;
140 
141 /* static const char* COL_NAME_DET1_WIN1_UIT1 = "DET1_WIN1_UIT1"; */
142 /*---------------------------------------------------------------------------
143  Private function prototypes
144  ---------------------------------------------------------------------------*/
145 /* Functions for the Linearity/Gain recipe, detmon_lg() */
146 
147 /* Parameters */
148 static cpl_error_code
149 detmon_lg_retrieve_parlist(const char *,
150  const char *, const cpl_parameterlist *,
151  cpl_boolean);
152 
153 
154 static cpl_error_code
155 detmon_lg_split_onoff(const cpl_frameset *,
156  cpl_frameset *,
157  cpl_frameset *,
158  const char *, const char * /*, cpl_boolean*/);
159 
160 static cpl_error_code
161 detmon_lg_reduce(const cpl_frameset *,
162  const cpl_frameset *,
163  int* index_on, int* index_off,
164  double* exptime_on, double* exptime_off,
165  int *next_index_on, int* next_index_off,
166  cpl_imagelist **,
167  cpl_table *,
168  cpl_table *,
169  cpl_image **,
170  cpl_imagelist *,
171  cpl_imagelist *,
172  cpl_propertylist *,
173  cpl_propertylist *,
174  cpl_propertylist *,
175  cpl_propertylist *,
176  int (* load_fset) (const cpl_frameset *,
177  cpl_type,
178  cpl_imagelist *),
179  const cpl_boolean, int);
180 
181 
182 
183 
184 static cpl_error_code
185 detmon_lin_table_fill_row(cpl_table *, double,
186  cpl_imagelist *,
187  const cpl_imagelist *,
188  const cpl_imagelist *,
189  int, int, int, int,
190  const int,
191  const int,
192  unsigned);
193 
194 static cpl_error_code
195 detmon_gain_table_fill_row(cpl_table * gain_table,
196  double c_dit,int c_ndit,
197  cpl_imagelist * autocorr_images,
198  cpl_imagelist * diff_flats,
199  const cpl_imagelist * ons,
200  const cpl_imagelist * offs,
201  double kappa, int nclip,
202  int llx, int lly, int urx, int ury,
203  int m, int n,
204  double gain_threshold,
205  int pos, unsigned mode, int* rows_affected);
206 
207 
208 static cpl_error_code
209 detmon_check_saturation_on_pair(cpl_imagelist * autocorr_images,
210  cpl_imagelist * diff_flats,
211  const cpl_imagelist * ons,
212  double kappa, int nclip,
213  int llx, int lly, int urx, int ury,
214  double saturation_limit,
215  const int pos, unsigned mode,
216  int* rows_linear_affected);
217 
218 static cpl_error_code
219 detmon_lg_save(const cpl_parameterlist *,
220  cpl_frameset *,
221  const char *,
222  const char *,
223  const char *,
224  const cpl_propertylist *,
225  const cpl_propertylist *,
226  const cpl_propertylist *,
227  const cpl_propertylist *,
228  const cpl_propertylist *,
229  const cpl_propertylist *,
230  const char *,
231  cpl_imagelist *,
232  cpl_table *,
233  cpl_table *,
234  cpl_image *,
235  cpl_imagelist *,
236  cpl_imagelist *,
237  cpl_propertylist *,
238  cpl_propertylist *,
239  cpl_propertylist *,
240  cpl_propertylist *,
241  const int, const int, const cpl_frameset *,
242  int);
243 
244 static cpl_error_code
245 detmon_lg_qc_ptc(const cpl_table *,
246  cpl_propertylist *, unsigned, int);
247 
248 static cpl_error_code
249 detmon_lg_qc_med(const cpl_table *,
250  cpl_propertylist *, int);
251 
252 
253 static double
254 detmon_pfits_get_dit(const cpl_propertylist *);
255 
256 static double
257 detmon_pfits_get_dit_opt(const cpl_propertylist *);
258 static double
259 irplib_pfits_get_prop_double(const cpl_propertylist * plist,
260  const char* prop_name);
261 
262 static cpl_image * detmon_bpixs(const cpl_imagelist *,
263  cpl_boolean, const double, int *);
264 
265 static double
266 detmon_autocorr_factor(const cpl_image *,
267  cpl_image **, int, int);
268 
269 
270 
271 static cpl_error_code
272 detmon_opt_contamination(const cpl_imagelist *,
273  const cpl_imagelist *,
274  unsigned mode, cpl_propertylist *);
275 
276 #if 0
277 detmon_opt_lampcr(cpl_frameset *, int);
278 #endif
279 
280 int
281 detmon_lg_dfs_set_groups(cpl_frameset *, const char *, const char *);
282 
283 static cpl_error_code
284 detmon_lg_reduce_all(const cpl_table *,
285  cpl_propertylist *,
286  cpl_propertylist *,
287  cpl_propertylist *,
288  cpl_propertylist *,
289  cpl_imagelist **,
290  cpl_image **,
291  const cpl_imagelist *,
292  const cpl_table *, int, cpl_boolean);
293 
294 static cpl_error_code
295 detmon_lg_check_defaults(const cpl_image *);
296 
297 static cpl_error_code
298 detmon_lg_rescale(cpl_imagelist *);
299 
300 static cpl_error_code
301 detmon_lg_reduce_init(cpl_table *,
302  cpl_table *,
303  cpl_imagelist **,
304  const cpl_boolean);
305 
306 
307 static cpl_error_code
308 detmon_add_adl_column(cpl_table *, cpl_boolean);
309 
310 static cpl_error_code
311 detmon_lg_lamp_stab(const cpl_frameset *,
312  const cpl_frameset *,
313  cpl_boolean, int);
314 
315 
316 static cpl_error_code
317 detmon_lg_reduce_dit(const cpl_frameset * set_on,
318  int* index_on, double* exptime_on,
319  const int dit_nb,
320  int * dit_nskip,
321  const cpl_frameset * set_off,
322  int * index_off, double* exptime_off,
323  int* next_on, int* next_off,
324  cpl_table * linear_table,
325  cpl_table * gain_table,
326  cpl_imagelist * linearity_inputs,
327  cpl_propertylist * qclist,
328  cpl_boolean opt_nir,
329  cpl_imagelist * autocorr_images,
330  cpl_imagelist * diff_flats,
331  cpl_imagelist * opt_offs,
332  int whichext,
333  int * rows_linear_affected,
334  int * rows_gain_affected);
335 
336 static cpl_error_code
337 detmon_lg_core(cpl_frameset * cur_fset_on,
338  cpl_frameset * cur_fset_off,
339  int * index_on,
340  int * index_off,
341  double * exptime_on,
342  double * exptime_off,
343  int whichext,
344  int whichset,
345  const char * recipe_name,
346  const char * pipeline_name,
347  const char * pafregexp,
348  const cpl_propertylist * pro_lintbl,
349  const cpl_propertylist * pro_gaintbl,
350  const cpl_propertylist * pro_coeffscube,
351  const cpl_propertylist * pro_bpm,
352  const cpl_propertylist * pro_corr,
353  const cpl_propertylist * pro_diff,
354  const char * package,
355  int (* load_fset) (const cpl_frameset *,
356  cpl_type,
357  cpl_imagelist *),
358  int nsets, cpl_boolean opt_nir,
359  cpl_frameset * frameset, const cpl_parameterlist * parlist,
360  cpl_frameset * cur_fset);
361 
362 static cpl_error_code
363 detmon_lg_lineff(double *, cpl_propertylist *, int, int);
364 
365 /*
366  static int
367  detmon_lg_compare_pairs(const cpl_frame *,
368  const cpl_frame *);
369  */
370 static cpl_error_code
371 detmon_gain_table_create(cpl_table *,
372  const cpl_boolean);
373 
374 
375 static cpl_error_code
376 detmon_lin_table_create(cpl_table *,
377  const cpl_boolean);
378 
379 static cpl_vector *
380 detmon_lg_find_dits(const cpl_vector *,
381  double );
382 
383 static cpl_error_code
384 detmon_lg_find_dits_ndits(const cpl_vector * exptimes,
385  const cpl_vector * vec_ndits,
386  double tolerance,
387  cpl_vector** diff_dits,
388  cpl_vector** diff_ndits);
389 
390 static cpl_error_code
391 detmon_fpn_compute(const cpl_frameset *set_on,
392  int * index_on,
393  int last_linear_best,
394  cpl_propertylist *lint_qclist,
395  int llx,
396  int lly,
397  int urx,
398  int ury,
399  double gain,
400  int whichext,
401  FPN_METHOD fpn_method,
402  int smooth_size);
403 static double irplib_fpn_lg(const cpl_image* f1, int* range, double gain,
404  FPN_METHOD fpn_method, int, double* mse);
405 static double irplib_calculate_total_noise(const cpl_image* pimage);
406 
407 static cpl_imagelist* irplib_load_fset_wrp(const cpl_frameset *,
408  cpl_type, int whichext);
409 static cpl_imagelist * irplib_load_fset_wrp_ext(const cpl_frameset *,
410  cpl_type, int);
411 
412 static cpl_error_code irplib_table_create_column(cpl_table* ptable,
413  cpl_propertylist* plist);
414 static cpl_error_code irplib_fill_table_DETWINUIT(cpl_table* ptable,
415  cpl_propertylist* plist,
416  int row);
417 
418 static cpl_error_code
419 detmon_pair_extract_next(const cpl_frameset * set,
420  int* index,
421  int* next_element,
422  double* dit_array,
423  /* int * with_equal_dit,
424  int onoff, */
425  cpl_frameset ** pair,
426  double tolerance);
427 static cpl_error_code
428 detmon_single_extract_next(const cpl_frameset * set,
429  int* index,
430  int* next_element,
431  double* dit_array,
432  cpl_frameset ** pair);
433 
434 /*
435  static int frame_get_ndit(const cpl_frame * pframe);
436  static cpl_error_code
437  irplib_frameset_get_ndit(const cpl_frameset * self, int* ndit);
438  */
439 static cpl_error_code detmon_table_fill_invalid(cpl_table* ptable, double code);
440 static void detmon_lg_add_empty_image(cpl_imagelist* imlist, int pos);
441 static int detmon_lg_check_before_gain(const cpl_vector* x, const cpl_vector* y);
442 /*---------------------------------------------------------------------------*/
449 /*---------------------------------------------------------------------------*/
450 static int irplib_pfits_get_ndit(const cpl_propertylist * plist)
451 {
452  return cpl_propertylist_get_int(plist,"ESO DET NDIT");
453 }
454 
455 
456 /*
457 static int frame_get_ndit(const cpl_frame * pframe)
458 {
459  cpl_propertylist *plist = 0;
460  int ival = 0;
461 
462  plist = cpl_propertylist_load(cpl_frame_get_filename(pframe),0);
463  if(plist)
464  {
465  ival = cpl_propertylist_get_int(plist, "NDIT");
466  }
467 
468  cpl_propertylist_delete(plist);
469  return ival;
470 }
471 */
472 
473 /*
474 static cpl_error_code
475 irplib_frameset_get_ndit(const cpl_frameset * self, int* ndit)
476 {
477  int sz = 0;
478  int i = 0;
479  const cpl_frame* tmp_frame = 0;
480  cpl_error_code error = CPL_ERROR_NONE;
481  sz = cpl_frameset_get_size(self);
482 
483  tmp_frame = cpl_frameset_get_position_const(self, 0);
484  while(tmp_frame)
485  {
486  ndit[i] = frame_get_ndit(tmp_frame);
487  i++
488  tmp_frame = cpl_frameset_get_position_const(self, i);
489  }
490 
491  return error;
492 }
493 */
494 
495 #ifdef DETMON_USE_DETECTOR_SHOTNOISE_MODEL
496 /*----------------------------------------------------------------------------*/
517 /*----------------------------------------------------------------------------*/
518 static cpl_error_code
519 hdrldemo_detector_shotnoise_model(const cpl_image* ima_data, const double gain,
520  const double ron, cpl_image ** ima_errs)
521 {
522  cpl_ensure_code(ima_data, CPL_ERROR_NULL_INPUT);
523  cpl_ensure_code(ima_errs, CPL_ERROR_NULL_INPUT);
524  cpl_ensure_code(gain > 0., CPL_ERROR_ILLEGAL_INPUT);
525  cpl_ensure_code(ron > 0., CPL_ERROR_ILLEGAL_INPUT);
526 
527  *ima_errs = cpl_image_duplicate(ima_data);
528  /* set negative values (= zero measurable electrons) to read out noise */
529  cpl_image_threshold(*ima_errs, 0., INFINITY, ron, ron);
530 
531  /* err_ADU = sqrt(counts/gain + ron * ron)*/
532 
533  cpl_image_divide_scalar(*ima_errs, gain);
534  cpl_image_add_scalar(*ima_errs, ron * ron);
535  cpl_image_power(*ima_errs, 0.5);
536 
537  return cpl_error_get_code();
538 }
539 #endif
540 
541 static cpl_error_code
542 detmon_lg_reduce_set(int i, cpl_frameset * frameset,
543  int nsets,
544  const char * tag_on,
545  const char * tag_off,
546  const char * recipe_name,
547  const char * pipeline_name,
548  const char * pafregexp,
549  const cpl_propertylist * pro_lintbl,
550  const cpl_propertylist * pro_gaintbl,
551  const cpl_propertylist * pro_coeffscube,
552  const cpl_propertylist * pro_bpm,
553  const cpl_propertylist * pro_corr,
554  const cpl_propertylist * pro_diff,
555  const char * package,
556  int (* load_fset)
557  (const cpl_frameset *, cpl_type, cpl_imagelist *),
558  const cpl_boolean opt_nir,
559  const cpl_parameterlist * parlist,
560  cpl_size* selection
561  );
562 static double irplib_compute_err(double gain, double ron, double photon_noise);
563 /* wrapper function for different cpl versions*/
564 static cpl_error_code
565 detmon_lg_dfs_save_imagelist(cpl_frameset * frameset,
566  const cpl_parameterlist * parlist,
567  const cpl_frameset *usedframes,
568  const cpl_imagelist *coeffs,
569  const char *recipe_name,
570  const cpl_propertylist *mypro_coeffscube,
571  const char * package,
572  const char * name_o);
573 
574 /*--------------------------------------------------------------------------*/
575 static void irplib_free(char** pointer){
576 
577  if(pointer && *pointer) {
578  cpl_free(*pointer);
579  *pointer=NULL;
580  }
581 }
582 
583 static cpl_error_code
584 detmon_lg_reduce_set(int i, cpl_frameset * frameset, int nsets,
585  const char * tag_on,
586  const char * tag_off,
587  const char * recipe_name,
588  const char * pipeline_name,
589  const char * pafregexp,
590  const cpl_propertylist * pro_lintbl,
591  const cpl_propertylist * pro_gaintbl,
592  const cpl_propertylist * pro_coeffscube,
593  const cpl_propertylist * pro_bpm,
594  const cpl_propertylist * pro_corr,
595  const cpl_propertylist * pro_diff,
596  const char * package,
597  int (* load_fset)
598  (const cpl_frameset *, cpl_type, cpl_imagelist *),
599  const cpl_boolean opt_nir,
600  const cpl_parameterlist * parlist,
601  cpl_size* selection
602  )
603 {
604  int j;
605  int nexts = detmon_lg_config.nb_extensions;
606 
607  double* exptime_on = 0;
608  double* exptime_off = 0;
609  int* index_on = 0;
610  int* index_off = 0;
611  cpl_frameset * cur_fset = NULL;
612  cpl_frameset* cur_fset_on = 0;
613  cpl_frameset* cur_fset_off = 0;
614 
615  /* Reduce data set nb i */
616  cur_fset =
617  (nsets == 1) ? /* would be better (selection == 0) ? */
618  cpl_frameset_duplicate(frameset) : cpl_frameset_extract(frameset, selection, i);
619 
620 
621  skip_if(cur_fset == NULL);
622 
623  /* Split input frameset into 2 sub-framesets for ON and OFF frames */
624  cur_fset_on = cpl_frameset_new();
625  cur_fset_off = cpl_frameset_new();
626  cpl_msg_info(cpl_func, "Splitting into ON and OFF sub-framesets");
627  skip_if (detmon_lg_split_onoff(cur_fset,
628  cur_fset_on, cur_fset_off,
629  tag_on, tag_off /*, opt_nir*/));
630  if (cpl_frameset_get_size(cur_fset_on) == 0)
631  {
632  cpl_msg_error(cpl_func, "No lamp frames in input");
633  skip_if(1);
634  }
635 
636  if (cpl_frameset_get_size(cur_fset_off) == 0)
637  {
638  cpl_msg_error(cpl_func, "No dark / bias frames in input");
639  skip_if(1);
640  }
641  cpl_msg_info(cpl_func, "found on-frames[%" CPL_SIZE_FORMAT "] off-frames[%" CPL_SIZE_FORMAT "]",cpl_frameset_get_size(cur_fset_on), cpl_frameset_get_size(cur_fset_off));
642  /* Labelise each sub-frameset according to DIT values */
643  /* selection_on = cpl_frameset_labelise(cur_fset_on,
644  detmon_lg_compare_pairs,
645  &nsets_on);
646 
647  skip_if (selection_on == NULL);
648  */
649  exptime_on = cpl_malloc(sizeof(double)*cpl_frameset_get_size(cur_fset_on));
650  exptime_off = cpl_malloc(sizeof(double)*cpl_frameset_get_size(cur_fset_off));
651 
652  index_on = cpl_malloc(sizeof(int)*cpl_frameset_get_size(cur_fset_on));
653  index_off = cpl_malloc(sizeof(int)*cpl_frameset_get_size(cur_fset_off));
654  irplib_frameset_sort(cur_fset_on, index_on, exptime_on);
655  irplib_frameset_sort(cur_fset_off, index_off, exptime_off);
656  /* for (j = 0; j < cpl_frameset_get_size(cur_fset_on); j++)
657  {
658  cpl_msg_info(cpl_func, "%d: \t %d \t %f", j , index_on[j], exptime_on[j]);
659  }
660  */
661  /* TODO Check that each ON frame pair has a corresponding OFF frame*/
662 
663  /* Test if they have equal nb of labels */
664  /* if (!detmon_lg_config.collapse) {
665  skip_if(nsets_on != nsets_off);
666  }
667  */
668  skip_if(detmon_check_order(exptime_on, cpl_frameset_get_size(cur_fset_on), detmon_lg_config.tolerance, detmon_lg_config.order));
669 
670  if(detmon_lg_config.exts >= 0)
671  {
672  /*
673  * In the optical domain, the first 2 frames
674  * are used apart from the pairs.
675  */
676 
677 #if 0
678  if (detmon_lg_config.lamp_ok) {
679  skip_if(detmon_opt_lampcr(cur_fset, 0));
680  }
681 #endif
682  skip_if(detmon_lg_core(cur_fset_on, cur_fset_off,
683  index_on,
684  index_off,
685  exptime_on,
686  exptime_off,
687  detmon_lg_config.exts,
688  i,
689  recipe_name, pipeline_name, pafregexp,
690  pro_lintbl, pro_gaintbl, pro_coeffscube, pro_bpm, pro_corr, pro_diff,
691  package, load_fset, nsets, opt_nir, frameset, parlist, cur_fset));
692  } else {
693  for(j = 1; j <= nexts; j++) {
694  /*
695  * In the optical domain, the first 2 frames
696  * are used apart from the pairs.
697  */
698 
699 #if 0
700  if (detmon_lg_config.lamp_ok) {
701  skip_if(detmon_opt_lampcr(cur_fset, j));
702  }
703 #endif
704 
705  skip_if(detmon_lg_core(cur_fset_on, cur_fset_off,
706  index_on,
707  index_off,
708  exptime_on,
709  exptime_off,
710  j, i, recipe_name,
711  pipeline_name, pafregexp,
712  pro_lintbl, pro_gaintbl,
713  pro_coeffscube,
714  pro_bpm, pro_corr, pro_diff,
715  package, load_fset, nsets, opt_nir,
716  frameset, parlist, cur_fset));
717  }
718  }
719  end_skip;
720 
721  // PIPE-10123
722  // NOTE - we test against recipe name, rather than is_nir, because we
723  // don't want the _mr recipes to include these calculations
724  char* par_name = NULL ;
725  if (strcmp(recipe_name, "detmon_opt_lg") == 0 ||
726  strcmp(recipe_name, "detmon_ir_lg") == 0) {
727  cpl_msg_info(cpl_func, "This is where I want to write the 'super' QC kw");
728  cpl_msg_info(cpl_func, "Writing super QC kw for recipe %s", recipe_name);
729  // Compute values & write back
730 // if (cpl_error_get_code() != CPL_ERROR_NONE) {
731 // cpl_msg_error(__func__, "Error found in detmon_lg_reduce_set!");
732 // cpl_msg_error(__func__, "At: before computing for gain and lin global");
733 // cpl_msg_error(__func__, "In %s, L%u", cpl_error_get_file(),
734 // cpl_error_get_line());
735 // cpl_msg_error(__func__, "%s", cpl_error_get_message());
736 // getchar();
737 // }
738  detmon_lg_qc_params_global_gain(recipe_name, nsets);
739  detmon_lg_qc_params_global_lin(recipe_name, nsets);
740  // cpl_parameterlist_dump(parlist, stdout);
741  par_name = cpl_sprintf("detmon.%s.pix2pix", recipe_name);
742  cpl_parameter* pix2pix = cpl_parameterlist_find(
743  parlist,
744  par_name);
745  if (pix2pix != NULL && cpl_parameter_get_bool(pix2pix)) {
746 // if (cpl_error_get_code() != CPL_ERROR_NONE) {
747 // cpl_msg_error(__func__, "Error found in detmon_lg_reduce_set!");
748 // cpl_msg_error(__func__, "At: before computing for bpm and coeffs global");
749 // cpl_msg_error(__func__, "In %s, L%u", cpl_error_get_file(),
750 // cpl_error_get_line());
751 // cpl_msg_error(__func__, "%s", cpl_error_get_message());
752 // getchar();
753 // }
754  detmon_lg_qc_params_global_bpm(recipe_name, nsets);
755  detmon_lg_qc_params_global_coeffs(recipe_name, nsets);
756  }
757  }
758  cpl_free(par_name);
759 
760  cpl_frameset_delete(cur_fset);
761  cpl_frameset_delete(cur_fset_on);
762  cpl_frameset_delete(cur_fset_off);
763  cpl_free(index_on);
764  cpl_free(index_off);
765  cpl_free(exptime_on);
766  cpl_free(exptime_off);
767  return cpl_error_get_code();
768 }
769 
770 /*
771  * @brief Reduce linearity and gain in the IR domain
772  * @param parlist List of required parameters
773  * @param frameset Input frameset
774  * @param tag_on Tag to identify the ON frames
775  * @param tag_off Tag to identify the OFF frames
776  * @param recipe_name Name of the recipe calling this function
777  * @param pipeline_name Name of the pipeline calling this function
778  * @param procatg_lintbl PRO.CATG keyword for the Linearity Table
779  * @param procatg_gaintbl PRO.CATG keyword for the Gain Table
780  * @param procatg_coeffscube PRO.CATG keyword for the
781  * Linearity Coefficients' Images
782  * @param procatg_bpm PRO.CATG required for the Bad Pixel Map
783  * @param procatg_corr PRO.CATG required for the Autocorrelation Images
784  * (Intermediate product - only created if required)
785  * @param procatg_diff PRO.CATG required for the Difference Images
786  * (Intermediate Product - only created if required)
787  * @param package PACKAGE (incl. VERSION) required
788  * for the DFS keywords
789  * @param compare Compare function used to classified frameset into
790  * different settings, if any.
791  * @param load_fset Loading function for preprocessing of input
792  frames with special data format (needed for
793  AMBER and MIDI processing)
794 
795  * @param opt_nir Boolean parameter to activate/deactivate
796  * OPT-only / IR-only parts of the recipe
797  * @return 0 on success, -1 on fail.
798  * @note: The parlist contains the following parameters:
799  *
800  * @par1 kappa Kappa value used for the kappa-sigma clipping
801  * rejection of bad pixels when computing sigma for
802  * gain calculation
803  * @par2 niter Number of iterations for the kappa-sigma clipping
804  * @par3 threshold_min Minimum threshold of the k-sigma (Not applied)
805  * @par4 threshold_max Maximum threshold of the k-sigma (Not applied)
806  * @par5 llx Region of Interest (Default to the whole area)
807  * @par6 lly Region of Interest (Default to the whole area)
808  * @par7 urx Region of Interest (Default to the whole area)
809  * @par8 ury Region of Interest (Default to the whole area)
810  * @par9 ref_level Reference Level (Not applied)
811  * @par10 threshold Threshold (Not applied)
812  * @par11 intermediate Boolean to activate the production of
813  * Intermediate Products
814  * @par12 autocorr Boolean to activate autocorr method
815  * @par13 collapse Boolean to activate collapse of OFF frames
816  * @par14 rescale Boolean to activate pair rescaling
817  * @par15 m X-Shift of the autocorrelation
818  * @par16 n Y-Shift of the autocorrelation
819  * @par17 llx1 Region of Interest 1 (Only OPT)
820  * @par18 lly1 Region of Interest 1 (Only OPT)
821  * @par19 urx1 Region of Interest 1 (Only OPT)
822  * @par20 ury1 Region of Interest 1 (Only OPT)
823  * @par21 llx2 Region of Interest 2 (Only OPT)
824  * @par22 lly2 Region of Interest 2 (Only OPT)
825  * @par23 urx2 Region of Interest 2 (Only OPT)
826  * @par24 ury2 Region of Interest 2 (Only OPT)
827  * @par25 llx3 Region of Interest 3 (Only OPT)
828  * @par26 lly3 Region of Interest 3 (Only OPT)
829  * @par27 urx3 Region of Interest 3 (Only OPT)
830  * @par28 ury3 Region of Interest 3 (Only OPT)
831  * @par29 llx4 Region of Interest 4 (Only OPT)
832  * @par30 lly4 Region of Interest 4 (Only OPT)
833  * @par31 urx4 Region of Interest 4 (Only OPT)
834  * @par32 ury4 Region of Interest 4 (Only OPT)
835  * @par33 llx5 Region of Interest 5 (Only OPT)
836  * @par34 lly5 Region of Interest 5 (Only OPT)
837  * @par35 urx5 Region of Interest 5 (Only OPT)
838  * @par36 ury5 Region of Interest 5 (Only OPT)
839  * @par37 exts Integer to select extension
840  */
841 
842 /*--------------------------------------------------------------------------*/
843 
844 cpl_error_code
845 detmon_lg(cpl_frameset * frameset,
846  const cpl_parameterlist * parlist,
847  const char * tag_on,
848  const char * tag_off,
849  const char * recipe_name,
850  const char * pipeline_name,
851  const char * pafregexp,
852  const cpl_propertylist * pro_lintbl,
853  const cpl_propertylist * pro_gaintbl,
854  const cpl_propertylist * pro_coeffscube,
855  const cpl_propertylist * pro_bpm,
856  const cpl_propertylist * pro_corr,
857  const cpl_propertylist * pro_diff,
858  const char * package,
859  int (* compare) (const cpl_frame *,
860  const cpl_frame *),
861  int (* load_fset) (const cpl_frameset *,
862  cpl_type,
863  cpl_imagelist *),
864  const cpl_boolean opt_nir)
865 {
866  cpl_errorstate cleanstate = cpl_errorstate_get();
867  cpl_size nsets;
868  cpl_size * selection = NULL;
869  cpl_frame * first = NULL;
870  cpl_image * reference = NULL;
871 
872  /*
873  * Variables used only inside the for() statement.
874  * However, there are declared here to ease
875  * memory management in error case.
876  */
877  cpl_frameset * cur_fset = NULL;
878  cpl_frameset * cur_fset_on = NULL;
879  cpl_frameset * cur_fset_off = NULL;
880 
881  /* Test entries */
882  cpl_ensure_code(frameset != NULL, CPL_ERROR_NULL_INPUT);
883  cpl_ensure_code(parlist != NULL, CPL_ERROR_NULL_INPUT);
884  cpl_ensure_code(tag_on != NULL, CPL_ERROR_NULL_INPUT);
885  cpl_ensure_code(tag_off != NULL, CPL_ERROR_NULL_INPUT);
886  cpl_ensure_code(recipe_name != NULL, CPL_ERROR_NULL_INPUT);
887  cpl_ensure_code(pipeline_name != NULL, CPL_ERROR_NULL_INPUT);
888  cpl_ensure_code(pro_lintbl != NULL, CPL_ERROR_NULL_INPUT);
889  cpl_ensure_code(pro_gaintbl != NULL, CPL_ERROR_NULL_INPUT);
890  cpl_ensure_code(pro_coeffscube != NULL, CPL_ERROR_NULL_INPUT);
891  cpl_ensure_code(pro_bpm != NULL, CPL_ERROR_NULL_INPUT);
892  cpl_ensure_code(pro_corr != NULL, CPL_ERROR_NULL_INPUT);
893  cpl_ensure_code(pro_diff != NULL, CPL_ERROR_NULL_INPUT);
894  cpl_ensure_code(package != NULL, CPL_ERROR_NULL_INPUT);
895 
896  cpl_msg_info(cpl_func,"frameset size [%" CPL_SIZE_FORMAT "]", cpl_frameset_get_size(frameset));
897 
898 
899  skip_if (detmon_lg_dfs_set_groups(frameset, tag_on, tag_off));
900 
901  /*
902  * First check of input consistency in NIR case:
903  * There must be a pair ON and a pair OFF for each DIT.
904  */
905 
906  skip_if (detmon_lg_retrieve_parlist(pipeline_name, recipe_name,
907  parlist, opt_nir));
908 
909  /*
910  * Retrieve first image to check some parameters' values and
911  * set default values which refer to the image.
912  */
913 
914  first = cpl_frameset_get_position(frameset, 0);
915  irplib_ensure (first != NULL, CPL_ERROR_ILLEGAL_INPUT, "Empty data set! Provide %s and %s input frames",tag_on,tag_off);
916 
917  detmon_lg_config.load_fset = load_fset;
918  detmon_lg_config.load_fset_wrp = load_fset ? irplib_load_fset_wrp_ext : irplib_load_fset_wrp;
919 
920 
921  detmon_lg_config.nb_extensions = 1;
922  if (detmon_lg_config.exts < 0) {
923  int i = 1;
924  detmon_lg_config.nb_extensions = cpl_frame_get_nextensions(first);
925  while (reference == NULL && i <= detmon_lg_config.nb_extensions) {
926  reference = cpl_image_load(cpl_frame_get_filename(first),
927  CPL_TYPE_FLOAT, 0, i);
928  if (reference == NULL) {
929  cpl_msg_warning(cpl_func, "Extension %d empty, skipping", i);
930  cpl_errorstate_set(cleanstate);
931  }
932  i++;
933  }
934  cpl_errorstate_set(cleanstate);
935  irplib_ensure (reference != NULL, CPL_ERROR_ILLEGAL_INPUT,
936  "No data found in any extension");
937  cpl_msg_info(cpl_func, "Using extension %d as reference", i - 1);
938  } else {
939  if (load_fset != NULL) {
940  cpl_frameset * new = cpl_frameset_new();
941  cpl_imagelist * p = cpl_imagelist_new();
942  cpl_frameset_insert(new, cpl_frame_duplicate(first));
943  (*load_fset)(new, CPL_TYPE_FLOAT, p);
944  reference = cpl_image_duplicate(cpl_imagelist_get(p, 0));
945  cpl_imagelist_delete(p);
946  cpl_frameset_delete(new);
947  } else {
948  cpl_msg_info(cpl_func,"name=%s",cpl_frame_get_filename(first));
949  reference = cpl_image_load(cpl_frame_get_filename(first),
950  CPL_TYPE_FLOAT, 0, detmon_lg_config.exts);
951  }
952  cpl_errorstate_set(cleanstate);
953  irplib_ensure (reference != NULL, CPL_ERROR_ILLEGAL_INPUT,
954  "No data found in requested extension %d",
955  detmon_lg_config.exts);
956  }
957  skip_if (reference == NULL);
958 
959  skip_if (detmon_lg_check_defaults(reference));
960 
961  /* Labelise all input frames */
962 
963  /*
964  * After each setting iteration, frameset will be modified (product
965  * frames will have been added), so it is better to duplicate it, keep
966  * it in its original state for the labelise-extract scheme.
967  */
968  if (compare == NULL) {
969  nsets = 1;
970  } else {
971  cpl_msg_info(cpl_func, "Identifying different settings");
972  selection = cpl_frameset_labelise(frameset, compare, &nsets);
973  skip_if (selection == NULL);
974  }
975 
976  /* Extract settings and reduce each of them */
977  for(int i = 0; i < nsets; i++)
978  {
979  int fr_size = cpl_frameset_get_size(frameset);
980  int fr_size_new = 0;
981  cpl_msg_info(cpl_func, "Reduce data set nb %d out of %" CPL_SIZE_FORMAT "",
982  i + 1, nsets);
983  skip_if(detmon_lg_reduce_set(i, frameset, nsets, tag_on, tag_off,
984  recipe_name,
985  pipeline_name,
986  pafregexp,
987  pro_lintbl,
988  pro_gaintbl,
989  pro_coeffscube,
990  pro_bpm,
991  pro_corr,
992  pro_diff,
993  package,
994  load_fset,
995  opt_nir,
996  parlist,
997  selection));
998  fr_size_new = cpl_frameset_get_size(frameset);
999  /* the size of the frameset could be changed during the detmon_lg_reduce_set call
1000  * so the size of the selection array should be adjusted with some fake values,
1001  * to avoid reading of the not allocated memory
1002  * see DFS08110 for the error description
1003  * */
1004  if (fr_size_new > fr_size)
1005  {
1006  selection = cpl_realloc(selection, fr_size_new * sizeof(selection[0]));
1007  memset(selection + fr_size, -1, (fr_size_new - fr_size) * sizeof(selection[0]));
1008  }
1009  }
1010 
1011  end_skip;
1012 
1013  cpl_frameset_delete(cur_fset);
1014  cpl_frameset_delete(cur_fset_on);
1015  cpl_frameset_delete(cur_fset_off);
1016  cpl_free(selection);
1017  cpl_image_delete(reference);
1018 
1019  return cpl_error_get_code();
1020 }
1021 
1022 /*---------------------------------------------------------------------------*/
1053 /*---------------------------------------------------------------------------*/
1054 
1055 static cpl_error_code
1056 detmon_lg_core(cpl_frameset * cur_fset_on,
1057  cpl_frameset * cur_fset_off,
1058  int * index_on,
1059  int * index_off,
1060  double * exptime_on,
1061  double * exptime_off,
1062  int whichext,
1063  int whichset,
1064  const char * recipe_name,
1065  const char * pipeline_name,
1066  const char * pafregexp,
1067  const cpl_propertylist * pro_lintbl,
1068  const cpl_propertylist * pro_gaintbl,
1069  const cpl_propertylist * pro_coeffscube,
1070  const cpl_propertylist * pro_bpm,
1071  const cpl_propertylist * pro_corr,
1072  const cpl_propertylist * pro_diff,
1073  const char * package,
1074  int (* load_fset) (const cpl_frameset *,
1075  cpl_type,
1076  cpl_imagelist *),
1077  int nsets, cpl_boolean opt_nir,
1078  cpl_frameset * frameset, const cpl_parameterlist * parlist,
1079  cpl_frameset * cur_fset)
1080 {
1081  cpl_table * gain_table = cpl_table_new(
1082  cpl_frameset_get_size(cur_fset_on) / 2);
1083  cpl_table * linear_table = cpl_table_new(
1084  cpl_frameset_get_size(cur_fset_on) / 2);
1085  cpl_imagelist * coeffs = NULL;
1086  cpl_image * bpm = NULL;
1087  cpl_imagelist * autocorr_images = NULL;
1088  cpl_imagelist * diff_flats = NULL;
1089  cpl_propertylist * gaint_qclist = NULL;
1090  cpl_propertylist * lint_qclist = NULL;
1091  cpl_propertylist * linc_qclist = NULL;
1092  cpl_propertylist * bpm_qclist = NULL;
1093 
1094  int next_index_on = 0;
1095  int next_index_off = 0;
1096 
1097  /* Reduce extension nb i */
1098  cpl_msg_info(cpl_func, "Reduce extension nb %d ", whichext);
1099 
1100  /* FIXME: All other memory objects in use should be
1101  initialised here (except coeffs which can not be) */
1102  if (detmon_lg_config.intermediate) {
1103  autocorr_images = cpl_imagelist_new();
1104  diff_flats = cpl_imagelist_new();
1105  }
1106 
1107  gaint_qclist = cpl_propertylist_new();
1108  lint_qclist = cpl_propertylist_new();
1109  linc_qclist = cpl_propertylist_new();
1110  bpm_qclist = cpl_propertylist_new();
1111 
1112  /* Reduction done here */
1113  cpl_msg_info(cpl_func, "Starting data reduction");
1114  if (detmon_lg_reduce(cur_fset_on, cur_fset_off,
1115  index_on, index_off, exptime_on, exptime_off,
1116  &next_index_on, &next_index_off,
1117  &coeffs, gain_table,
1118  linear_table, &bpm, autocorr_images,
1119  diff_flats, gaint_qclist, lint_qclist,
1120  linc_qclist, bpm_qclist, load_fset,
1121  opt_nir, whichext) == CPL_ERROR_CONTINUE) {
1122  cpl_msg_info(cpl_func, "Empty extension %d", whichext);
1123  }
1124 
1125  // PIPE-10123 insert QC parameter write here
1126  // NOTE - we test against recipe name, rather than is_nir, because we
1127  // don't want the _mr recipes to include these calculations
1128  if (strcmp(recipe_name, "detmon_opt_lg") == 0 ||
1129  strcmp(recipe_name, "detmon_ir_lg") == 0) {
1130  detmon_lg_qc_params(
1131  linear_table, lint_qclist,
1132  gain_table, gaint_qclist,
1133  coeffs, linc_qclist,
1134  bpm, bpm_qclist,
1135  recipe_name
1136  );
1137  }
1138 
1139  /* Save the products for each setting */
1140  cpl_msg_info(cpl_func, "Saving the products");
1141  if (nsets == 1) {
1142  skip_if(
1143  detmon_lg_save(parlist, frameset, recipe_name,
1144  pipeline_name, pafregexp,
1145  pro_lintbl, pro_gaintbl,
1146  pro_coeffscube, pro_bpm,
1147  pro_corr, pro_diff, package,
1148  coeffs, gain_table, linear_table,
1149  bpm, autocorr_images, diff_flats,
1150  gaint_qclist, lint_qclist, linc_qclist,
1151  bpm_qclist,
1152  0, 0,
1153  cur_fset, whichext));
1154  } else {
1155  skip_if(
1156  detmon_lg_save(parlist, frameset, recipe_name,
1157  pipeline_name, pafregexp,
1158  pro_lintbl, pro_gaintbl,
1159  pro_coeffscube, pro_bpm,
1160  pro_corr, pro_diff, package,
1161  coeffs, gain_table, linear_table,
1162  bpm, autocorr_images, diff_flats,
1163  gaint_qclist, lint_qclist, linc_qclist,
1164  bpm_qclist,
1165  1, whichset+ 1,
1166  cur_fset, whichext));
1167  }
1168 
1169  end_skip;
1170 
1171  /* Free for each extension */
1172 
1173  cpl_table_delete(gain_table);
1174  cpl_table_delete(linear_table);
1175  cpl_imagelist_delete(coeffs);
1176  cpl_propertylist_delete(gaint_qclist);
1177  cpl_propertylist_delete(lint_qclist);
1178  cpl_propertylist_delete(linc_qclist);
1179  if(bpm_qclist != NULL) cpl_propertylist_delete(bpm_qclist);
1180  cpl_image_delete(bpm);
1181  cpl_imagelist_delete(autocorr_images);
1182  cpl_imagelist_delete(diff_flats);
1183 
1184  return cpl_error_get_code();
1185 }
1186 
1187 
1188 /*--------------------------------------------------------------------------*/
1189 
1190 /*
1191  * @brief Correlate two images with a given range of shifts
1192  * @param image1 Input image
1193  * @param image2 Input image
1194  * @param m Shift to apply on the x-axis
1195  * @param n Shift to apply on the y-axis
1196  * @return An image of size 2m+1 by 2n+1. Each pixel value
1197  * corresponds to the correlation of shift the position
1198  * of the pixel. Pixel in the centre (m+1, n+1),
1199  * corresponds to shift (0,0). Pixels to the left and
1200  * down correspond to negative shifts.
1201  *
1202  * @note At this moment, this function only accepts images to
1203  * have both the same size.
1204  */
1205 
1206 /*--------------------------------------------------------------------------*/
1207 
1208 cpl_image *
1209 detmon_image_correlate(const cpl_image * image1,
1210  const cpl_image * image2,
1211  const int m, const int n)
1212 {
1213  cpl_image *image1_padded = NULL;
1214  cpl_image *image2_padded = NULL;
1215  int nx, ny;
1216  int nx2, ny2;
1217 
1218  cpl_image *corr_image_window = NULL;
1219 
1220  cpl_image* image_ri1 = NULL;
1221  cpl_image* image_ri2 = NULL;
1222  cpl_error_code err = CPL_ERROR_NONE;
1223 
1224  /* Test the entries */
1225  cpl_ensure(image1 != NULL, CPL_ERROR_NULL_INPUT, NULL);
1226  cpl_ensure(image2 != NULL, CPL_ERROR_NULL_INPUT, NULL);
1227 
1228  cpl_ensure(m > 0, CPL_ERROR_NULL_INPUT, NULL);
1229  cpl_ensure(n > 0, CPL_ERROR_NULL_INPUT, NULL);
1230 
1231  nx = cpl_image_get_size_x(image1);
1232  ny = cpl_image_get_size_y(image1);
1233 
1234  nx2 = cpl_image_get_size_x(image2);
1235  ny2 = cpl_image_get_size_y(image2);
1236 
1237  /* At this moment, the images must be of the same size */
1238  cpl_ensure(nx == nx2 && ny == ny2, CPL_ERROR_ILLEGAL_INPUT, NULL);
1239 
1240  /* Pad the images with zeroes to avoid periodical effects of DFT */
1241  image1_padded = cpl_image_new(nx + 2 * m, ny + 2 * n, CPL_TYPE_FLOAT);
1242  cpl_image_copy(image1_padded, image1, m + 1, n + 1);
1243 
1244  image2_padded = cpl_image_new(nx + 2 * m, ny + 2 * n, CPL_TYPE_FLOAT);
1245  cpl_image_copy(image2_padded, image2, m + 1, n + 1);
1246 
1247  /*New dimensions of the padded images */
1248  nx = nx + 2 * m;
1249  ny = ny + 2 * n;
1250 
1251  image_ri1 = cpl_image_new(nx, ny, CPL_TYPE_FLOAT_COMPLEX);
1252  image_ri2 = cpl_image_new(nx, ny , CPL_TYPE_FLOAT_COMPLEX);
1253  /* Actually perform the FFT */
1254  cpl_fft_image(image_ri1, image1_padded, CPL_FFT_FORWARD);
1255  cpl_fft_image(image_ri2, image2_padded, CPL_FFT_FORWARD);
1256  err = cpl_error_get_code();
1257  cpl_image_delete(image1_padded);
1258  image1_padded = NULL;
1259  cpl_image_delete(image2_padded);
1260  image2_padded = NULL;
1261  if (err == CPL_ERROR_NONE)
1262  {
1263  /* Cleanup resources */
1264  cpl_image * corr_image = NULL;
1265  cpl_image * reorganised= NULL;
1266  cpl_image * image_ri_inv = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
1267  cpl_image * image_in_inv = cpl_image_new(nx, ny,
1268  CPL_TYPE_FLOAT_COMPLEX);
1269  int i,j;
1270 
1271  for (i = 1; i <= nx; i++)
1272  {
1273  for (j = 1; j <= ny; j++)
1274  {
1275  int rej = 0;
1276  double complex value1, value2, value;
1277  value1 = cpl_image_get_complex(image_ri1, i, j, &rej);
1278  value2 = cpl_image_get_complex(image_ri2, i, j, &rej);;
1279  value = conj(value1) * value2;
1280  cpl_image_set_complex(image_in_inv, i, j, value);
1281  }
1282  }
1283  cpl_image_delete(image_ri1);
1284  image_ri1 = NULL;
1285  cpl_image_delete(image_ri2);
1286  image_ri2 = NULL;
1287 
1288  err = cpl_error_get_code();
1289  if (err == CPL_ERROR_NONE)
1290  {
1291 
1292  /* Actually perform the FFT */
1293  cpl_fft_image(image_ri_inv, image_in_inv,CPL_FFT_BACKWARD);
1294  cpl_image_delete(image_in_inv);
1295 
1296  /* Get the module of the inversed signal */
1297  corr_image = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
1298  for (i = 1; i <= nx; i++)
1299  {
1300  for (j = 1; j <= ny; j++)
1301  {
1302  int rej = 0;
1303  double value =0;
1304  value = cpl_image_get(image_ri_inv, i, j, &rej);
1305  cpl_image_set(corr_image, i, j, value);
1306  }
1307  }
1308  cpl_image_delete(image_ri_inv);
1309  err = cpl_error_get_code();
1310  if (err == CPL_ERROR_NONE)
1311  {
1312  /* Reorganise the pixels to the output */
1313  cpl_image * image =
1314  cpl_image_extract(corr_image, nx / 2 + 1, 1, nx, ny);
1315  reorganised = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
1316 
1317  cpl_image_copy(reorganised, image, 1, 1);
1318  cpl_image_delete(image);
1319  image = cpl_image_extract(corr_image, 1, 1, nx / 2, ny);
1320  cpl_image_copy(reorganised, image, nx / 2 + 1, 1);
1321  cpl_image_delete(image);
1322 
1323  cpl_image_delete(corr_image);
1324 
1325  corr_image = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
1326  image = cpl_image_extract(reorganised, 1, ny / 2 + 1, nx, ny);
1327  cpl_image_copy(corr_image, image, 1, 1);
1328  cpl_image_delete(image);
1329 
1330  image = cpl_image_extract(reorganised, 1, 1, nx, ny / 2);
1331  cpl_image_copy(corr_image, image, 1, ny / 2 + 1);
1332  cpl_image_delete(image);
1333  /* Extract a window with the desired shifts */
1334  corr_image_window = cpl_image_extract(corr_image,
1335  nx / 2 + 1 - m,
1336  ny / 2 + 1 - n,
1337  nx / 2 + 1 + m, ny / 2 + 1 + n);
1338  }
1339  /* Free and return */
1340 
1341  }
1342  cpl_image_delete(reorganised);
1343  cpl_image_delete(corr_image);
1344 
1345  if(cpl_image_divide_scalar(corr_image_window,
1346  cpl_image_get_max(corr_image_window))) {
1347  cpl_image_delete(corr_image_window);
1348  return NULL;
1349  }
1350  }
1351  cpl_image_delete (image_ri1);
1352  cpl_image_delete (image_ri2);
1353  cpl_image_delete (image1_padded);
1354  cpl_image_delete (image2_padded);
1355  return corr_image_window;
1356 }
1357 
1358 
1359 
1360 /*--------------------------------------------------------------------------*/
1361 
1362 /*
1363  * @brief Autocorrelate an image with a given range of shifts, using
1364  * cpl_image_fft()
1365  * @param input2 Input image
1366  * @param m Shift to apply on the x-axis
1367  * @param n Shift to apply on the y-axis
1368  * @return An image of size 2m+1 by 2n+1. Each pixel value
1369  * corresponds to the correlation of shift the position
1370  * of the pixel. Pixel in the centre (m+1, n+1),
1371  * corresponds to shift (0,0). Pixels to the left and
1372  * down correspond to negative shifts.
1373  */
1374 
1375 /*--------------------------------------------------------------------------*/
1376 
1377 cpl_image *
1378 detmon_autocorrelate(const cpl_image * input2, const int m,
1379  const int n)
1380 {
1381  cpl_image *im_re = NULL;
1382  cpl_image *im_im = NULL;
1383  int nx, ny;
1384  cpl_image *ifft_re = NULL;
1385  cpl_image *ifft_im = NULL;
1386  cpl_image *autocorr = NULL;
1387  cpl_image *autocorr_norm_double = NULL;
1388  cpl_image *autocorr_norm = NULL;
1389  cpl_image *reorganised = NULL;
1390  cpl_image *image = NULL;
1391  int p;
1392  cpl_error_code error;
1393  cpl_image *input;
1394 
1395  cpl_ensure(input2 != NULL, CPL_ERROR_NULL_INPUT, NULL);
1396 
1397  cpl_ensure(m > 0, CPL_ERROR_NULL_INPUT, NULL);
1398  cpl_ensure(n > 0, CPL_ERROR_NULL_INPUT, NULL);
1399 
1400  nx = cpl_image_get_size_x(input2) + 2 * m;
1401  ny = cpl_image_get_size_y(input2) + 2 * n;
1402 
1403  p = 128;
1404  while(nx > p || ny > p) {
1405  p *= 2;
1406  }
1407 
1408  input = cpl_image_cast(input2, CPL_TYPE_DOUBLE);
1409 
1410  im_re = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
1411  error = cpl_image_copy(im_re, input, 1, 1);
1412  cpl_image_delete(input);
1413 
1414  cpl_ensure(!error, error, NULL);
1415 
1416  im_im = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
1417 
1418  error = cpl_image_fft(im_re, im_im, CPL_FFT_DEFAULT);
1419  cpl_ensure(!error, error, NULL);
1420 
1421  ifft_re = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
1422  error = cpl_image_power(im_re, 2);
1423  cpl_ensure(!error, error, NULL);
1424 
1425  error = cpl_image_add(ifft_re, im_re);
1426  cpl_ensure(!error, error, NULL);
1427 
1428  cpl_image_delete(im_re);
1429 
1430  error = cpl_image_power(im_im, 2);
1431  cpl_ensure(!error, error, NULL);
1432 
1433  error = cpl_image_add(ifft_re, im_im);
1434  cpl_ensure(!error, error, NULL);
1435 
1436  cpl_image_delete(im_im);
1437 
1438  ifft_im = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
1439 
1440  error = cpl_image_fft(ifft_re, ifft_im, CPL_FFT_INVERSE);
1441  cpl_ensure(!error, error, NULL);
1442 
1443  autocorr = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
1444 
1445  error = cpl_image_power(ifft_re, 2);
1446  cpl_ensure(!error, error, NULL);
1447 
1448  error = cpl_image_add(autocorr, ifft_re);
1449  cpl_ensure(!error, error, NULL);
1450 
1451  cpl_image_delete(ifft_re);
1452 
1453  error = cpl_image_power(ifft_im, 2);
1454  cpl_ensure(!error, error, NULL);
1455 
1456  error = cpl_image_add(autocorr, ifft_im);
1457  cpl_ensure(!error, error, NULL);
1458 
1459  cpl_image_delete(ifft_im);
1460 
1461  /* Reorganise the pixels to the output */
1462  reorganised = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
1463 
1464  image = cpl_image_extract(autocorr, p / 2 + 1, 1, p, p);
1465  cpl_image_copy(reorganised, image, 1, 1);
1466  cpl_image_delete(image);
1467 
1468  image = cpl_image_extract(autocorr, 1, 1, p / 2, p);
1469  cpl_image_copy(reorganised, image, p / 2 + 1, 1);
1470  cpl_image_delete(image);
1471 
1472  cpl_image_delete(autocorr);
1473 
1474  autocorr = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
1475 
1476  image = cpl_image_extract(reorganised, 1, p / 2 + 1, p, p);
1477  cpl_image_copy(autocorr, image, 1, 1);
1478  cpl_image_delete(image);
1479 
1480  image = cpl_image_extract(reorganised, 1, 1, p, p / 2);
1481  cpl_image_copy(autocorr, image, 1, p / 2 + 1);
1482  cpl_image_delete(image);
1483 
1484  cpl_image_delete(reorganised);
1485 
1486  autocorr_norm_double =
1487  cpl_image_extract(autocorr, p / 2 + 1 - m, p / 2 + 1 - n,
1488  p / 2 + 1 + m, p / 2 + 1 + n);
1489 
1490  cpl_image_delete(autocorr);
1491 
1492  if(cpl_image_divide_scalar(autocorr_norm_double,
1493  cpl_image_get_max(autocorr_norm_double))) {
1494  cpl_image_delete(autocorr_norm_double);
1495  cpl_ensure(0, cpl_error_get_code(), NULL);
1496  }
1497 
1498 
1499  autocorr_norm = cpl_image_cast(autocorr_norm_double, CPL_TYPE_FLOAT);
1500  cpl_image_delete(autocorr_norm_double);
1501 
1502  return autocorr_norm;
1503 }
1504 
1505 /*---------------------------------------------------------------------------*/
1516 /*---------------------------------------------------------------------------*/
1517 cpl_error_code
1518 detmon_lg_fill_parlist_nir_default(cpl_parameterlist * parlist,
1519  const char *recipe_name,
1520  const char *pipeline_name)
1521 {
1522  const cpl_error_code error =
1523  detmon_lg_fill_parlist(parlist, recipe_name, pipeline_name,
1524  "PTC", /* --method */
1525  3, /* --order */
1526  3., /* --kappa */
1527  5, /* --niter */
1528  -1, /* --llx */
1529  -1, /* --lly */
1530  -1, /* --urx */
1531  -1, /* --ury */
1532  10000, /* --ref_level */
1533  "CPL_FALSE", /* --intermediate */
1534  "CPL_FALSE", /* --autocorr */
1535  "CPL_FALSE", /* --collapse */
1536  "CPL_TRUE", /* --rescale */
1537  "CPL_TRUE",/* --pix2pix */
1538  "CPL_FALSE", /* --bpmbin */
1539  -1, /* --filter */
1540  26, /* --m */
1541  26, /* --n */
1542  1e-3, /* --tolerance */
1543  "CPL_FALSE", /* --pafgen */
1544  recipe_name, /* --pafname */
1545  -1, /* --llx1 */
1546  -1, /* --lly1 */
1547  -1, /* --urx1 */
1548  -1, /* --ury1 */
1549  -1, /* --llx2 */
1550  -1, /* --lly2 */
1551  -1, /* --urx2 */
1552  -1, /* --ury2 */
1553  -1, /* --llx3 */
1554  -1, /* --lly3 */
1555  -1, /* --urx3 */
1556  -1, /* --ury3 */
1557  -1, /* --llx4 */
1558  -1, /* --lly4 */
1559  -1, /* --urx4 */
1560  -1, /* --ury4 */
1561  -1, /* --llx5 */
1562  -1, /* --lly5 */
1563  -1, /* --urx5 */
1564  -1, /* --ury5 */
1565  0, /* --exts */
1566  NIR); /* This is to specify OPT params */
1567 
1568 
1569  cpl_ensure_code(!error, error);
1570 
1571  return cpl_error_get_code();
1572 }
1573 
1574 /*---------------------------------------------------------------------------*/
1585 /*---------------------------------------------------------------------------*/
1586 cpl_error_code
1587 detmon_lg_fill_parlist_opt_default(cpl_parameterlist * parlist,
1588  const char *recipe_name,
1589  const char *pipeline_name)
1590 {
1591  const cpl_error_code error =
1592  detmon_lg_fill_parlist(parlist, recipe_name, pipeline_name,
1593  "PTC", /* --method */
1594  3, /* --order */
1595  3., /* --kappa */
1596  5, /* --niter */
1597  -1, /* --llx */
1598  -1, /* --lly */
1599  -1, /* --urx */
1600  -1, /* --ury */
1601  10000, /* --ref_level */
1602  "CPL_FALSE", /* --intermediate */
1603  "CPL_FALSE", /* --autocorr */
1604  "CPL_TRUE", /* --collapse */
1605  "CPL_TRUE", /* --rescale */
1606  "CPL_FALSE", /* --pix2pix */
1607  "CPL_FALSE", /* --bpmbin */
1608  -1, /* --filter */
1609  26, /* --m */
1610  26, /* --n */
1611  1e-3, /* --tolerance */
1612  "CPL_FALSE", /* --pafgen */
1613  recipe_name, /* --pafname */
1614  -1, /* --llx1 */
1615  -1, /* --lly1 */
1616  -1, /* --urx1 */
1617  -1, /* --ury1 */
1618  -1, /* --llx2 */
1619  -1, /* --lly2 */
1620  -1, /* --urx2 */
1621  -1, /* --ury2 */
1622  -1, /* --llx3 */
1623  -1, /* --lly3 */
1624  -1, /* --urx3 */
1625  -1, /* --ury3 */
1626  -1, /* --llx4 */
1627  -1, /* --lly4 */
1628  -1, /* --urx4 */
1629  -1, /* --ury4 */
1630  -1, /* --llx5 */
1631  -1, /* --lly5 */
1632  -1, /* --urx5 */
1633  -1, /* --ury5 */
1634  0, /* --exts */
1635  OPT); /* This is to specify OPT params */
1636 
1637  cpl_ensure_code(!error, error);
1638 
1639  return cpl_error_get_code();
1640 }
1641 
1642 static cpl_error_code
1643 detmon_lg_fill_parlist_default_mr(cpl_parameterlist * parlist,
1644  const char *recipe_name,
1645  const char *pipeline_name)
1646 {
1647  char * group_name = cpl_sprintf("%s.%s", pipeline_name, recipe_name);
1648  char * par_name = cpl_sprintf("%s.%s", group_name, "regions-file");
1649  cpl_parameter * p = cpl_parameter_new_value(par_name, CPL_TYPE_STRING,
1650  "File containing regions, "
1651  "four comma separated points "
1652  "per line",
1653  group_name, "");
1654  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "regions-file");
1655  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
1656  cpl_parameterlist_append(parlist, p);
1657  cpl_free(par_name);
1658  cpl_free(group_name);
1659 
1660  group_name = cpl_sprintf("%s.%s", pipeline_name, recipe_name);
1661  par_name = cpl_sprintf("%s.%s", group_name, "regions");
1662  p = cpl_parameter_new_value(par_name, CPL_TYPE_STRING,
1663  "Colon separated list of regions, four "
1664  "points each, comma separated: "
1665  "llx,lly,urx,ury:llx,...",
1666  group_name, "");
1667  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "regions");
1668  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
1669  cpl_parameterlist_append(parlist, p);
1670  cpl_free(par_name);
1671  cpl_free(group_name);
1672 
1673  return cpl_error_get_code();
1674 }
1675 
1676 cpl_error_code
1677 detmon_lg_fill_parlist_opt_default_mr(cpl_parameterlist * parlist,
1678  const char *recipe_name,
1679  const char *pipeline_name)
1680 {
1681  detmon_lg_fill_parlist_opt_default(parlist, recipe_name, pipeline_name);
1682  detmon_lg_fill_parlist_default_mr(parlist, recipe_name, pipeline_name);
1683  return cpl_error_get_code();
1684 }
1685 
1686 cpl_error_code
1687 detmon_lg_fill_parlist_nir_default_mr(cpl_parameterlist * parlist,
1688  const char *recipe_name,
1689  const char *pipeline_name)
1690 {
1691  detmon_lg_fill_parlist_nir_default(parlist, recipe_name, pipeline_name);
1692  detmon_lg_fill_parlist_default_mr(parlist, recipe_name, pipeline_name);
1693 
1694  return cpl_error_get_code();
1695 }
1696 
1697 
1698 /*---------------------------------------------------------------------------*/
1752 /*---------------------------------------------------------------------------*/
1753 cpl_error_code
1754 detmon_lg_fill_parlist(cpl_parameterlist * parlist,
1755  const char *recipe_name, const char *pipeline_name,
1756  const char *method,
1757  int order,
1758  double kappa,
1759  int niter,
1760  int llx,
1761  int lly,
1762  int urx,
1763  int ury,
1764  int ref_level,
1765  const char *intermediate,
1766  const char *autocorr,
1767  const char *collapse,
1768  const char *rescale,
1769  const char *pix2pix,
1770  const char *bpmbin,
1771  int filter,
1772  int m,
1773  int n,
1774  double tolerance,
1775  const char *pafgen,
1776  const char * pafname,
1777  int llx1,
1778  int lly1,
1779  int urx1,
1780  int ury1,
1781  int llx2,
1782  int lly2,
1783  int urx2,
1784  int ury2,
1785  int llx3,
1786  int lly3,
1787  int urx3,
1788  int ury3,
1789  int llx4,
1790  int lly4,
1791  int urx4,
1792  int ury4,
1793  int llx5, int lly5, int urx5, int ury5, int exts,
1794  cpl_boolean opt_nir)
1795 {
1796  const cpl_error_code error =
1797  detmon_fill_parlist(parlist, recipe_name, pipeline_name, 26,
1798  "method",
1799  "Method to be used when computing GAIN. Methods appliable: <PTC | MED>. By default PTC method will be applied.",
1800  "CPL_TYPE_STRING", method,
1801 
1802  "order",
1803  "Polynomial order for the fit (Linearity)",
1804  "CPL_TYPE_INT", order,
1805  "kappa",
1806  "Kappa value for the kappa-sigma clipping (Gain)",
1807  "CPL_TYPE_DOUBLE", kappa,
1808  "niter",
1809  "Number of iterations to compute rms (Gain)",
1810  "CPL_TYPE_INT", niter,
1811  "llx",
1812  "x coordinate of the lower-left "
1813  "point of the region of interest. If not modified, default value will be 1.",
1814  "CPL_TYPE_INT", llx,
1815  "lly",
1816  "y coordinate of the lower-left "
1817  "point of the region of interest. If not modified, default value will be 1.",
1818  "CPL_TYPE_INT", lly,
1819  "urx",
1820  "x coordinate of the upper-right "
1821  "point of the region of interest. If not modified, default value will be X dimension of the input image.",
1822  "CPL_TYPE_INT", urx,
1823  "ury",
1824  "y coordinate of the upper-right "
1825  "point of the region of interest. If not modified, default value will be Y dimension of the input image.",
1826  "CPL_TYPE_INT", ury,
1827  "ref_level",
1828  "User reference level",
1829  "CPL_TYPE_INT", ref_level,
1830  "intermediate",
1831  "De-/Activate intermediate products",
1832  "CPL_TYPE_BOOL", intermediate,
1833 
1834  "autocorr",
1835  "De-/Activate the autocorr option",
1836  "CPL_TYPE_BOOL", autocorr,
1837 
1838  "collapse",
1839  "De-/Activate the collapse option",
1840  "CPL_TYPE_BOOL", collapse,
1841  "rescale",
1842  "De-/Activate the image rescale option",
1843  "CPL_TYPE_BOOL", rescale,
1844  "pix2pix",
1845  "De-/Activate the computation with pixel to pixel accuracy",
1846  "CPL_TYPE_BOOL", pix2pix,
1847  "bpmbin",
1848  "De-/Activate the binary bpm option",
1849  "CPL_TYPE_BOOL", bpmbin,
1850  "m",
1851  "Maximum x-shift for the autocorr",
1852  "CPL_TYPE_INT", m,
1853  "filter",
1854  "Upper limit of Median flux to be filtered",
1855  "CPL_TYPE_INT", filter,
1856  "n",
1857  "Maximum y-shift for the autocorr",
1858  "CPL_TYPE_INT", n,
1859  "tolerance",
1860  "Tolerance for pair discrimination",
1861  "CPL_TYPE_DOUBLE", tolerance,
1862 
1863  "pafgen",
1864  "Generate PAF file",
1865  "CPL_TYPE_BOOL", pafgen,
1866  "pafname",
1867  "Specific name for PAF file",
1868  "CPL_TYPE_STRING", pafname,
1869 
1870 
1871  "exts",
1872  "Activate the multi-exts option. Choose -1 to process all extensions. Choose an extension number"
1873  " to process the appropriate extension.",
1874  "CPL_TYPE_INT", exts,
1875 
1876  "fpn_method",
1877  "Method for computing Fixed Pattern Noise (SMOOTH or HISTOGRAM)",
1878  "CPL_TYPE_STRING", "HISTOGRAM",
1879 
1880  "fpn_smooth",
1881  "template size in pixels for smoothing during FPN computation (only for SMOOTH method)",
1882  "CPL_TYPE_INT", 13,
1883 
1884  "saturation_limit",
1885  "all frames with mean saturation above the limit would not be used in linearity calculation",
1886  "CPL_TYPE_DOUBLE", 65535.0,
1887 
1888  "gain_threshold",
1889  "all frames with mean flux above the threshold would not be used in gain calculation",
1890  "CPL_TYPE_DOUBLE", 65535.0
1891 
1892  );
1893  detmon_fill_parlist(parlist, recipe_name, pipeline_name, 1,
1894  "coeffs_cube_split",
1895  "if TRUE, the recipe writes as many "
1896  "COEFFS_CUBE_Pi (i=0..order) as the value of "
1897  "the order parameter in a separate file",
1898  "CPL_TYPE_BOOL", "CPL_FALSE");
1899  /* OPT specific parameters */
1900  if(opt_nir == FALSE) {
1901  const cpl_error_code erroropt =
1902  detmon_fill_parlist(parlist, recipe_name, pipeline_name, 20,
1903  "llx1",
1904  "x coord of the lower-left point of the first "
1905  "field used for contamination measurement. If not modified, default value will be 1.",
1906  "CPL_TYPE_INT", llx1,
1907  "lly1",
1908  "y coord of the lower-left point of the first "
1909  "field used for contamination measurement. If not modified, default value will be 1.",
1910  "CPL_TYPE_INT", lly1,
1911  "urx1",
1912  "x coord of the upper-right point of the first "
1913  "field used for contamination measurement. If not modified, default value will be X dimension of the input image.",
1914  "CPL_TYPE_INT", urx1,
1915  "ury1",
1916  "y coord of the upper-right point of the first "
1917  "field used for contamination measurement. If not modified, default value will be Y dimension of the input image.",
1918  "CPL_TYPE_INT", ury1,
1919  "llx2",
1920  "x coord of the lower-left point of the second "
1921  "field used for contamination measurement. If not modified, default value will be 1.",
1922  "CPL_TYPE_INT", llx2,
1923  "lly2",
1924  "y coord of the lower-left point of the second "
1925  "field used for contamination measurement. If not modified, default value will be 1.",
1926  "CPL_TYPE_INT", lly2,
1927  "urx2",
1928  "x coord of the upper-right point of the second "
1929  "field used for contamination measurement. If not modified, default value will be half of the X dimension of the input image.",
1930  "CPL_TYPE_INT", urx2,
1931  "ury2",
1932  "y coord of the upper-right point of the second "
1933  "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
1934  "CPL_TYPE_INT", ury2,
1935  "llx3",
1936  "x coord of the lower-left point of the third "
1937  "field used for contamination measurement. If not modified, default value will be 1.",
1938  "CPL_TYPE_INT", llx3,
1939  "lly3",
1940  "y coord of the lower-left point of the third "
1941  "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
1942  "CPL_TYPE_INT", lly3,
1943  "urx3",
1944  "x coord of the upper-right point of the third "
1945  "field used for contamination measurement. If not modified, default value will be half of X dimension of the image.",
1946  "CPL_TYPE_INT", urx3,
1947  "ury3",
1948  "y coord of the upper-right point of the third "
1949  "field used for contamination measurement. If not modified, default value will be Y dimension of the image.",
1950  "CPL_TYPE_INT", ury3,
1951  "llx4",
1952  "x coord of the lower-left point of the fourth "
1953  "field used for contamination measurement. If not modified, default value will be half of X dimension of the image.",
1954  "CPL_TYPE_INT", llx4,
1955  "lly4",
1956  "y coord of the lower-left point of the fourth "
1957  "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
1958  "CPL_TYPE_INT", lly4,
1959  "urx4",
1960  "x coord of the upper-right point of the fourth "
1961  "field used for contamination measurement. If not modified, default value will be X dimension of the image.",
1962  "CPL_TYPE_INT", urx4,
1963  "ury4",
1964  "y coord of the upper-right point of the fourth "
1965  "field used for contamination measurement. If not modified, default value will be Y dimension of the input image.",
1966  "CPL_TYPE_INT", ury4,
1967  "llx5",
1968  "x coord of the lower-left point of the fifth "
1969  "field used for contamination measurement. If not modified, default value will be half of the X dimension of the input image.",
1970  "CPL_TYPE_INT", llx5,
1971  "lly5",
1972  "y coord of the lower-left point of the fifth "
1973  "field used for contamination measurement. If not modified, default value will be 1.",
1974  "CPL_TYPE_INT", lly5,
1975  "urx5",
1976  "x coord of the upper-right point of the fifth "
1977  "field used for contamination measurement. If not modified, default value will be X dimension of the image.",
1978  "CPL_TYPE_INT", urx5,
1979 
1980  "ury5",
1981  "y coord of the upper-right point of the fifth "
1982  "field used for contamination measurement. If not modified, default value will be half of Y dimension of the input image.",
1983  "CPL_TYPE_INT", ury5);
1984 
1985 
1986  cpl_ensure_code(!erroropt, erroropt);
1987  }
1988 
1989  cpl_ensure_code(!error, error);
1990 
1991  return cpl_error_get_code();
1992 }
1993 
1994 /*---------------------------------------------------------------------------*/
2003 /*---------------------------------------------------------------------------*/
2004 static cpl_error_code
2005 detmon_lg_retrieve_parlist(const char * pipeline_name,
2006  const char * recipe_name,
2007  const cpl_parameterlist * parlist,
2008  cpl_boolean opt_nir)
2009 {
2010 
2011  char * par_name;
2012  const cpl_parameter * par;
2013 
2014  /* --method */
2015  par_name = cpl_sprintf("%s.%s.method", pipeline_name, recipe_name);
2016  assert(par_name != NULL);
2017  par = cpl_parameterlist_find_const(parlist, par_name);
2018  detmon_lg_config.method = cpl_parameter_get_string(par);
2019  cpl_free(par_name);
2020 
2021  /* --order */
2022  detmon_lg_config.order =
2023  detmon_retrieve_par_int("order", pipeline_name, recipe_name,
2024  parlist);
2025 
2026  /* --kappa */
2027  detmon_lg_config.kappa =
2028  detmon_retrieve_par_double("kappa", pipeline_name, recipe_name,
2029  parlist);
2030 
2031  /* --niter */
2032  detmon_lg_config.niter =
2033  detmon_retrieve_par_int("niter", pipeline_name, recipe_name,
2034  parlist);
2035 
2036  /* --llx */
2037  detmon_lg_config.llx =
2038  detmon_retrieve_par_int("llx", pipeline_name, recipe_name,
2039  parlist);
2040 
2041  /* --lly */
2042  detmon_lg_config.lly =
2043  detmon_retrieve_par_int("lly", pipeline_name, recipe_name,
2044  parlist);
2045 
2046  /* --urx */
2047  detmon_lg_config.urx =
2048  detmon_retrieve_par_int("urx", pipeline_name, recipe_name,
2049  parlist);
2050 
2051  /* --ury */
2052  detmon_lg_config.ury =
2053  detmon_retrieve_par_int("ury", pipeline_name, recipe_name,
2054  parlist);
2055 
2056  /* --ref_level */
2057  detmon_lg_config.ref_level =
2058  detmon_retrieve_par_int("ref_level", pipeline_name, recipe_name,
2059  parlist);
2060 
2061  /* --intermediate */
2062  par_name =
2063  cpl_sprintf("%s.%s.intermediate", pipeline_name, recipe_name);
2064  assert(par_name != NULL);
2065  par = cpl_parameterlist_find_const(parlist, par_name);
2066  detmon_lg_config.intermediate = cpl_parameter_get_bool(par);
2067  cpl_free(par_name);
2068 
2069  /* --autocorr */
2070  par_name = cpl_sprintf("%s.%s.autocorr", pipeline_name, recipe_name);
2071  assert(par_name != NULL);
2072  par = cpl_parameterlist_find_const(parlist, par_name);
2073  detmon_lg_config.autocorr = cpl_parameter_get_bool(par);
2074  cpl_free(par_name);
2075 
2076  /* --coeffs_cube_split */
2077  par_name = cpl_sprintf("%s.%s.coeffs_cube_split", pipeline_name, recipe_name);
2078  assert(par_name != NULL);
2079  par = cpl_parameterlist_find_const(parlist, par_name);
2080  detmon_lg_config.split_coeffs = cpl_parameter_get_bool(par);
2081  cpl_free(par_name);
2082 
2083  /* --collapse */
2084  par_name = cpl_sprintf("%s.%s.collapse", pipeline_name, recipe_name);
2085  assert(par_name != NULL);
2086  par = cpl_parameterlist_find_const(parlist, par_name);
2087  detmon_lg_config.collapse = cpl_parameter_get_bool(par);
2088  cpl_free(par_name);
2089 
2090  /* --rescale */
2091  par_name = cpl_sprintf("%s.%s.rescale", pipeline_name, recipe_name);
2092  assert(par_name != NULL);
2093  par = cpl_parameterlist_find_const(parlist, par_name);
2094  detmon_lg_config.rescale = cpl_parameter_get_bool(par);
2095  cpl_free(par_name);
2096 
2097  /* --pix2pix */
2098  par_name = cpl_sprintf("%s.%s.pix2pix", pipeline_name, recipe_name);
2099  assert(par_name != NULL);
2100  par = cpl_parameterlist_find_const(parlist, par_name);
2101  detmon_lg_config.pix2pix = cpl_parameter_get_bool(par);
2102  cpl_free(par_name);
2103 
2104  /* --bpmbin */
2105  par_name = cpl_sprintf("%s.%s.bpmbin", pipeline_name, recipe_name);
2106  assert(par_name != NULL);
2107  par = cpl_parameterlist_find_const(parlist, par_name);
2108  detmon_lg_config.bpmbin = cpl_parameter_get_bool(par);
2109  cpl_free(par_name);
2110 
2111  /* --filter */
2112  detmon_lg_config.filter =
2113  detmon_retrieve_par_int("filter", pipeline_name,
2114  recipe_name, parlist);
2115 
2116  /* --m */
2117  detmon_lg_config.m =
2118  detmon_retrieve_par_int("m", pipeline_name, recipe_name, parlist);
2119 
2120  /* --n */
2121  detmon_lg_config.n =
2122  detmon_retrieve_par_int("n", pipeline_name, recipe_name, parlist);
2123 
2124  /* --tolerance */
2125  par_name = cpl_sprintf("%s.%s.tolerance", pipeline_name, recipe_name);
2126  assert(par_name != NULL);
2127  par = cpl_parameterlist_find_const(parlist, par_name);
2128  detmon_lg_config.tolerance = cpl_parameter_get_double(par);
2129  cpl_free(par_name);
2130 
2131 
2132  /* --pafgen */
2133  par_name = cpl_sprintf("%s.%s.pafgen", pipeline_name, recipe_name);
2134  assert(par_name != NULL);
2135  par = cpl_parameterlist_find_const(parlist, par_name);
2136  detmon_lg_config.pafgen = cpl_parameter_get_bool(par);
2137  cpl_free(par_name);
2138 
2139  /* --pafname */
2140  par_name = cpl_sprintf("%s.%s.pafname", pipeline_name, recipe_name);
2141  assert(par_name != NULL);
2142  par = cpl_parameterlist_find_const(parlist, par_name);
2143  detmon_lg_config.pafname = cpl_parameter_get_string(par);
2144  cpl_free(par_name);
2145 
2146  if(opt_nir == OPT) {
2147  /* --llx1 */
2148  detmon_lg_config.llx1 =
2149  detmon_retrieve_par_int("llx1", pipeline_name, recipe_name,
2150  parlist);
2151 
2152  /* --lly1 */
2153  detmon_lg_config.lly1 =
2154  detmon_retrieve_par_int("lly1", pipeline_name, recipe_name,
2155  parlist);
2156 
2157  /* --urx1 */
2158  detmon_lg_config.urx1 =
2159  detmon_retrieve_par_int("urx1", pipeline_name, recipe_name,
2160  parlist);
2161 
2162  /* --ury1 */
2163  detmon_lg_config.ury1 =
2164  detmon_retrieve_par_int("ury1", pipeline_name, recipe_name,
2165  parlist);
2166 
2167  /* --llx2 */
2168  detmon_lg_config.llx2 =
2169  detmon_retrieve_par_int("llx2", pipeline_name, recipe_name,
2170  parlist);
2171 
2172  /* --lly2 */
2173  detmon_lg_config.lly2 =
2174  detmon_retrieve_par_int("lly2", pipeline_name, recipe_name,
2175  parlist);
2176 
2177  /* --urx2 */
2178  detmon_lg_config.urx2 =
2179  detmon_retrieve_par_int("urx2", pipeline_name, recipe_name,
2180  parlist);
2181 
2182  /* --ury2 */
2183  detmon_lg_config.ury2 =
2184  detmon_retrieve_par_int("ury2", pipeline_name, recipe_name,
2185  parlist);
2186 
2187  /* --llx3 */
2188  detmon_lg_config.llx3 =
2189  detmon_retrieve_par_int("llx3", pipeline_name, recipe_name,
2190  parlist);
2191 
2192  /* --lly3 */
2193  detmon_lg_config.lly3 =
2194  detmon_retrieve_par_int("lly3", pipeline_name, recipe_name,
2195  parlist);
2196 
2197  /* --urx3 */
2198  detmon_lg_config.urx3 =
2199  detmon_retrieve_par_int("urx3", pipeline_name, recipe_name,
2200  parlist);
2201 
2202  /* --ury3 */
2203  detmon_lg_config.ury3 =
2204  detmon_retrieve_par_int("ury3", pipeline_name, recipe_name,
2205  parlist);
2206 
2207  /* --llx4 */
2208  detmon_lg_config.llx4 =
2209  detmon_retrieve_par_int("llx4", pipeline_name, recipe_name,
2210  parlist);
2211 
2212  /* --lly4 */
2213  detmon_lg_config.lly4 =
2214  detmon_retrieve_par_int("lly4", pipeline_name, recipe_name,
2215  parlist);
2216 
2217  /* --urx4 */
2218  detmon_lg_config.urx4 =
2219  detmon_retrieve_par_int("urx4", pipeline_name, recipe_name,
2220  parlist);
2221 
2222  /* --ury4 */
2223  detmon_lg_config.ury4 =
2224  detmon_retrieve_par_int("ury4", pipeline_name, recipe_name,
2225  parlist);
2226 
2227  /* --llx5 */
2228  detmon_lg_config.llx5 =
2229  detmon_retrieve_par_int("llx5", pipeline_name, recipe_name,
2230  parlist);
2231 
2232  /* --lly5 */
2233  detmon_lg_config.lly5 =
2234  detmon_retrieve_par_int("lly5", pipeline_name, recipe_name,
2235  parlist);
2236 
2237  /* --urx5 */
2238  detmon_lg_config.urx5 =
2239  detmon_retrieve_par_int("urx5", pipeline_name, recipe_name,
2240  parlist);
2241 
2242  /* --ury5 */
2243  detmon_lg_config.ury5 =
2244  detmon_retrieve_par_int("ury5", pipeline_name, recipe_name,
2245  parlist);
2246  }
2247 
2248  /* --exts */
2249  detmon_lg_config.exts =
2250  detmon_retrieve_par_int("exts", pipeline_name, recipe_name,
2251  parlist);
2252  /* --fpn_method */
2253  {
2254  detmon_lg_config.fpn_method = FPN_HISTOGRAM;
2255  par_name =
2256  cpl_sprintf("%s.%s.fpn_method", pipeline_name, recipe_name);
2257  assert(par_name != NULL);
2258  par = cpl_parameterlist_find_const(parlist, par_name);
2259  if (par)
2260  {
2261  const char * str_method = cpl_parameter_get_string(par);
2262  if (strcmp(str_method, "SMOOTH") == 0)
2263  {
2264  detmon_lg_config.fpn_method = FPN_SMOOTH;
2265  }
2266  else if (strcmp(str_method, "HISTOGRAM") == 0)
2267  {
2268  detmon_lg_config.fpn_method = FPN_HISTOGRAM;
2269  }
2270  }
2271  cpl_free(par_name);
2272  }
2273  /* --fpn_smooth */
2274  detmon_lg_config.fpn_smooth =
2275  detmon_retrieve_par_int("fpn_smooth", pipeline_name, recipe_name,
2276  parlist);
2277  /* --saturation_limit*/
2278  {
2279  detmon_lg_config.saturation_limit = 65535;
2280  par_name =
2281  cpl_sprintf("%s.%s.saturation_limit", pipeline_name, recipe_name);
2282  assert(par_name != NULL);
2283  par = cpl_parameterlist_find_const(parlist, par_name);
2284  if (par)
2285  {
2286  detmon_lg_config.saturation_limit = cpl_parameter_get_double(par);
2287  }
2288  cpl_free(par_name);
2289  }
2290 
2291  /* --gain_threshold*/
2292  {
2293  detmon_lg_config.gain_threshold = 0;
2294  par_name =
2295  cpl_sprintf("%s.%s.gain_threshold", pipeline_name, recipe_name);
2296  assert(par_name != NULL);
2297  par = cpl_parameterlist_find_const(parlist, par_name);
2298  if (par)
2299  {
2300  detmon_lg_config.gain_threshold = cpl_parameter_get_double(par);
2301  }
2302  cpl_free(par_name);
2303  }
2304 
2305  if(cpl_error_get_code())
2306  {
2307  cpl_msg_error(cpl_func, "Failed to retrieve the input parameters");
2308  cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
2309  }
2310 
2311 
2312  return cpl_error_get_code();
2313 }
2314 
2315 /*---------------------------------------------------------------------------*/
2321 /*---------------------------------------------------------------------------*/
2322 static cpl_error_code
2323 detmon_lg_check_defaults(const cpl_image * reference)
2324 {
2325  const int nx = cpl_image_get_size_x(reference);
2326  const int ny = cpl_image_get_size_y(reference);
2327 
2328  detmon_lg_config.nx = nx;
2329  detmon_lg_config.ny = ny;
2330 
2331  detmon_lg_config.wholechip = CPL_FALSE;
2332 
2333  if(detmon_lg_config.llx == -1)
2334  detmon_lg_config.llx = 1;
2335  if(detmon_lg_config.lly == -1)
2336  detmon_lg_config.lly = 1;
2337  if(detmon_lg_config.urx == -1)
2338  detmon_lg_config.urx = nx;
2339  if(detmon_lg_config.ury == -1)
2340  detmon_lg_config.ury = ny;
2341 
2342  if (detmon_lg_config.llx == 1 &&
2343  detmon_lg_config.lly == 1 &&
2344  detmon_lg_config.urx == nx &&
2345  detmon_lg_config.ury == ny)
2346  detmon_lg_config.wholechip = CPL_TRUE;
2347 
2348  if(detmon_lg_config.llx1 == -1)
2349  detmon_lg_config.llx1 = 1;
2350  if(detmon_lg_config.lly1 == -1)
2351  detmon_lg_config.lly1 = 1;
2352  if(detmon_lg_config.urx1 == -1)
2353  detmon_lg_config.urx1 = nx;
2354  if(detmon_lg_config.ury1 == -1)
2355  detmon_lg_config.ury1 = ny;
2356 
2357  if(detmon_lg_config.llx2 == -1)
2358  detmon_lg_config.llx2 = 1;
2359  if(detmon_lg_config.lly2 == -1)
2360  detmon_lg_config.lly2 = 1;
2361  if(detmon_lg_config.urx2 == -1)
2362  detmon_lg_config.urx2 = nx / 2;
2363  if(detmon_lg_config.ury2 == -1)
2364  detmon_lg_config.ury2 = ny / 2;
2365 
2366  if(detmon_lg_config.llx3 == -1)
2367  detmon_lg_config.llx3 = 1;
2368  if(detmon_lg_config.lly3 == -1)
2369  detmon_lg_config.lly3 = ny / 2;
2370  if(detmon_lg_config.urx3 == -1)
2371  detmon_lg_config.urx3 = nx / 2;
2372  if(detmon_lg_config.ury3 == -1)
2373  detmon_lg_config.ury3 = ny;
2374 
2375  if(detmon_lg_config.llx4 == -1)
2376  detmon_lg_config.llx4 = nx / 2;
2377  if(detmon_lg_config.lly4 == -1)
2378  detmon_lg_config.lly4 = ny / 2;
2379  if(detmon_lg_config.urx4 == -1)
2380  detmon_lg_config.urx4 = nx;
2381  if(detmon_lg_config.ury4 == -1)
2382  detmon_lg_config.ury4 = ny;
2383 
2384  if(detmon_lg_config.llx5 == -1)
2385  detmon_lg_config.llx5 = nx / 2;
2386  if(detmon_lg_config.lly5 == -1)
2387  detmon_lg_config.lly5 = 1;
2388  if(detmon_lg_config.urx5 == -1)
2389  detmon_lg_config.urx5 = nx;
2390  if(detmon_lg_config.ury5 == -1)
2391  detmon_lg_config.ury5 = ny / 2;
2392 
2393  if(detmon_lg_config.intermediate == TRUE) {
2394  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.");
2395  detmon_lg_config.autocorr = TRUE;
2396  }
2397 
2398 
2399  detmon_lg_config.lamp_stability = 0.0;
2400 
2401  detmon_lg_config.lamp_ok = FALSE;
2402 
2403  detmon_lg_config.cr = 0.0;
2404 
2405  return cpl_error_get_code();
2406 }
2407 
2408 /*---------------------------------------------------------------------------*/
2419 /*---------------------------------------------------------------------------*/
2420 static cpl_error_code
2421 detmon_lg_split_onoff(const cpl_frameset * cur_fset,
2422  cpl_frameset * cur_fset_on,
2423  cpl_frameset * cur_fset_off,
2424  const char *tag_on,
2425  const char *tag_off)
2426 {
2427  int nframes;
2428  int i;
2429 
2430  cpl_frame * cur_frame_dup = NULL;
2431 
2432 #if 0
2433  const cpl_frame * first;
2434  const cpl_frame * second;
2435  const char * first_tag;
2436  const char * second_tag;
2437  skip_if((first = cpl_frameset_get_position_const(cur_fset, 0)) == NULL);
2438  skip_if((second = cpl_frameset_get_position_const(cur_fset, 1)) == NULL);
2439 
2440  skip_if((first_tag = cpl_frame_get_tag(first)) == NULL);
2441  skip_if((second_tag = cpl_frame_get_tag(second)) == NULL);
2442  if (opt_nir == OPT &&
2443  ((!strcmp(first_tag, tag_on ) && !strcmp(second_tag, tag_off)) ||
2444  (!strcmp(first_tag, tag_off) && !strcmp(second_tag, tag_on )))) {
2445  detmon_lg_config.lamp_ok = TRUE;
2446  }
2447 #endif
2448 
2449  nframes = cpl_frameset_get_size(cur_fset);
2450  for(i = detmon_lg_config.lamp_ok ? 2 : 0; i < nframes; i++) {
2451  const cpl_frame * cur_frame =
2452  cpl_frameset_get_position_const(cur_fset, i);
2453  char * tag;
2454 
2455  /* Duplication is required for insertion to a different frameset */
2456  cur_frame_dup = cpl_frame_duplicate(cur_frame);
2457  tag = (char *) cpl_frame_get_tag(cur_frame_dup);
2458 
2459  /* Insertion in the corresponding sub-frameset */
2460  if(!strcmp(tag, tag_on)) {
2461  skip_if(cpl_frameset_insert(cur_fset_on, cur_frame_dup));
2462  } else if(!strcmp(tag, tag_off)) {
2463  skip_if(cpl_frameset_insert(cur_fset_off, cur_frame_dup));
2464  } else {
2465  cpl_frame_delete(cur_frame_dup);
2466  cur_frame_dup = NULL;
2467  }
2468  }
2469  cur_frame_dup = NULL;
2470 
2471  end_skip;
2472 
2473  cpl_frame_delete(cur_frame_dup);
2474 
2475  return cpl_error_get_code();
2476 }
2477 
2478 /*--------------------------------------------------------------------------*/
2500 /*--------------------------------------------------------------------------*/
2501 
2502 static cpl_error_code
2503 detmon_lg_reduce(const cpl_frameset * set_on,
2504  const cpl_frameset * set_off,
2505  int* index_on, int* index_off,
2506  double* exptime_on, double* exptime_off,
2507  int *next_index_on, int* next_index_off,
2508  cpl_imagelist ** coeffs_ptr,
2509  cpl_table * gain_table,
2510  cpl_table * linear_table,
2511  cpl_image ** bpm_ptr,
2512  cpl_imagelist * autocorr_images,
2513  cpl_imagelist * diff_flats,
2514  cpl_propertylist * gaint_qclist,
2515  cpl_propertylist * lint_qclist,
2516  cpl_propertylist * linc_qclist,
2517  cpl_propertylist * bpm_qclist,
2518  int (* load_fset) (const cpl_frameset *,
2519  cpl_type,
2520  cpl_imagelist *),
2521  const cpl_boolean opt_nir,
2522  int whichext)
2523 {
2524  cpl_errorstate prestate = cpl_errorstate_get();
2525  const double D_INVALID_VALUE = -999;
2526  int i;
2527  cpl_imagelist * linearity_inputs = NULL;
2528  cpl_imagelist * opt_offs = NULL;
2529  int nsets;
2530  cpl_propertylist * reflist = NULL;
2531  int dit_nskip = 0;
2532  int rows_linear_affected = 1;
2533  int rows_gain_affected = 1;
2534  int last_linear_best = 0;
2535  /* Test entries */
2536  cpl_ensure(set_on != NULL, CPL_ERROR_NULL_INPUT, CPL_ERROR_NULL_INPUT);
2537  cpl_ensure(set_off != NULL, CPL_ERROR_NULL_INPUT, CPL_ERROR_NULL_INPUT);
2538 
2539  nsets = cpl_frameset_get_size(set_on) / 2;
2540 
2541  detmon_lg_config.load_fset = load_fset;
2542  if(detmon_lg_config.collapse) {
2543  /*
2544  * When the 'collapse' option is used, there are no OFF pairs. We
2545  * construct a pair with the 2 first raw OFF frames, which will be
2546  * passed for each DIT value, to maintain the same API in the function
2547  * detmon_gain_table_fill_row().
2548  */
2549  const cpl_frame *first = cpl_frameset_get_position_const(set_off, 0);
2550  cpl_frame *dup_first = cpl_frame_duplicate(first);
2551 
2552  const cpl_frame *second = cpl_frameset_get_position_const(set_off, 1);
2553  cpl_frame *dup_second = cpl_frame_duplicate(second);
2554 
2555  cpl_frameset *raw_offs = cpl_frameset_new();
2556 
2557  skip_if(cpl_frameset_insert(raw_offs, dup_first));
2558  skip_if(cpl_frameset_insert(raw_offs, dup_second));
2559 
2560  opt_offs = cpl_imagelist_load_frameset(raw_offs, CPL_TYPE_FLOAT,
2561  0, whichext);
2562 
2563  cpl_frameset_delete(raw_offs);
2564  if (opt_offs == NULL) {
2565  cpl_errorstate_set(prestate);
2566  return CPL_ERROR_CONTINUE;
2567  }
2568  }
2569 
2570  skip_if(detmon_lg_reduce_init(gain_table,
2571  linear_table,
2572  &linearity_inputs,
2573  opt_nir));
2574 /*
2575  if (!strcmp(detmon_lg_config.method, "PTC"))
2576  {
2577  cpl_msg_warning(cpl_func, "PTC method incompatible with lamp stability"
2578  "computation");
2579  }
2580 */
2581  /* do always lamp stability check */
2582  if(detmon_lg_lamp_stab(set_on, set_off,
2583  opt_nir, whichext)) {
2584  cpl_errorstate_set(prestate);
2585  }
2586 
2587  if(!detmon_lg_config.collapse)
2588  {
2589  }
2590  /* Unselect all rows, to select only invalid ones */
2591  skip_if(cpl_table_unselect_all(linear_table));
2592  skip_if(cpl_table_unselect_all(gain_table));
2593 
2594  /* Loop on every DIT value */
2595 
2596  for(i = 0; i < nsets ; i++)
2597  {
2598  skip_if(detmon_lg_reduce_dit(set_on,
2599  index_on, exptime_on,
2600  i,
2601  &dit_nskip,
2602  set_off,
2603  index_off, exptime_off,
2604  next_index_on, next_index_off,
2605  linear_table,
2606  gain_table, linearity_inputs,
2607  lint_qclist, opt_nir,
2608  autocorr_images, diff_flats,
2609  opt_offs, whichext,
2610  &rows_linear_affected,&rows_gain_affected));
2611  /* TODO: the following if could be done directly inside the
2612  * function detmon_lg_reduce_dit
2613  */
2614  if (rows_linear_affected == 0)
2615  {
2616  cpl_msg_warning(cpl_func, "The rest frames would not be taken "
2617  "into linear calculation, check the messages above");
2618  cpl_table_select_row(linear_table, i);
2619  }
2620  else
2621  {
2622  last_linear_best = i;
2623  }
2624 
2625  if (rows_gain_affected == 0)
2626  {
2627  cpl_msg_warning(cpl_func, "The rest frames would not be taken "
2628  "into gain calculation, check the messages above");
2629  cpl_table_select_row(gain_table, i);
2630  }
2631 
2632 
2633 
2634  }
2635 
2636  skip_if(detmon_add_adl_column(linear_table, opt_nir));
2637 
2638  /*
2639  * Removal of rows corresponding to frames above --filter threshold.
2640  * See calls to cpl_table_select_row() in detmon_lg_reduce_dit().
2641  */
2642  skip_if(cpl_table_erase_selected(gain_table));
2643  skip_if(cpl_table_erase_selected(linear_table));
2644 
2645 
2646  reflist = cpl_propertylist_new();
2647  skip_if(cpl_propertylist_append_bool(reflist, "ADU", FALSE));
2648  skip_if(cpl_table_sort(gain_table, reflist));
2649  /*
2650  * --Final reduction--
2651  * The following call to detmon_lg_reduce_all() makes the
2652  * computations which are over all posible DIT values.
2653  */
2654  skip_if(detmon_lg_reduce_all(linear_table,
2655  gaint_qclist, lint_qclist, linc_qclist,
2656  bpm_qclist, coeffs_ptr, bpm_ptr,
2657  linearity_inputs,
2658  gain_table, whichext, opt_nir));
2659  {
2660  /*FPN Computation*/
2661  double gain = cpl_propertylist_get_double(gaint_qclist, DETMON_QC_GAIN);
2662  // cpl_propertylist_append_int(gaint_qclist, "NNNEXT", whichext);
2663  // cpl_msg_warning(cpl_func, "---------- ext %i" , whichext);
2664  cpl_error_code cplerr = cpl_error_get_code();
2665  if (cplerr != CPL_ERROR_NONE || (gain == 0.0))
2666  {
2667  cpl_msg_warning(cpl_func, "Cannot read gain from QC parameters - "
2668  "FPN will not be computed");
2669  cpl_error_reset();
2670  }
2671  else
2672  {
2673  detmon_fpn_compute(set_on, index_on, last_linear_best, lint_qclist,
2674  detmon_lg_config.llx,
2675  detmon_lg_config.lly,
2676  detmon_lg_config.urx,
2677  detmon_lg_config.ury,
2678  gain,
2679  whichext,
2680  detmon_lg_config.fpn_method,
2681  detmon_lg_config.fpn_smooth);
2682  }
2683  }
2684  /* change NaN in the gain table to the invalid value D_INVALID_VALUE*/
2685 
2686  detmon_table_fill_invalid(gain_table, D_INVALID_VALUE);
2687  end_skip;
2688  cpl_imagelist_delete(linearity_inputs);
2689  cpl_imagelist_delete(opt_offs);
2690  cpl_propertylist_delete(reflist);
2691 
2692  return cpl_error_get_code();
2693 }
2694 
2695 static cpl_error_code detmon_table_fill_invalid(cpl_table* ptable, double code)
2696 {
2697  int ncols = cpl_table_get_ncol(ptable);
2698  cpl_array* pnames = cpl_table_get_column_names(ptable);
2699  int nrows = cpl_table_get_nrow(ptable);
2700  int i = 0;
2701  for (i=0; i < ncols; i++)
2702  {
2703  int j = 0;
2704  for (j = 0; j< nrows; j++)
2705  {
2706  const char* colname = cpl_array_get_data_string_const(pnames)[i];
2707  int isnull;
2708  cpl_type type = cpl_table_get_column_type(ptable, colname);
2709  cpl_table_get(ptable, colname, j, &isnull);
2710  if(isnull == 1)
2711  {
2712  if (type == CPL_TYPE_DOUBLE)
2713  {
2714  cpl_table_set(ptable,colname,j, code);
2715  }
2716  else if (type == CPL_TYPE_FLOAT)
2717  {
2718  cpl_table_set_float(ptable,colname,j, (float)code);
2719  }
2720  }
2721  }
2722  }
2723  cpl_array_delete(pnames);
2724  return cpl_error_get_code();
2725 }
2726 
2727 static cpl_error_code
2728 detmon_fpn_compute(const cpl_frameset *set_on,
2729  int * index_on,
2730  int last_linear_best,
2731  cpl_propertylist *lint_qclist,
2732  int llx,
2733  int lly,
2734  int urx,
2735  int ury,
2736  double gain,
2737  int whichext,
2738  FPN_METHOD fpn_method,
2739  int smooth_size)
2740 {
2741  double fpn = 0;
2742  const cpl_image* im1 = 0;
2743  int range[4];
2744  cpl_imagelist* ons = 0;
2745  cpl_frameset * pair_on = 0;
2746  int nsets_extracted = cpl_frameset_get_size(set_on);
2747  cpl_size * selection = NULL;
2748  double mse = 0;
2749  range[0] = llx;
2750  range[1] = lly;
2751  range[2] = urx;
2752  range[3] = ury;
2753 
2754  /* Retrieve 2 ON frames with the highest DIT -
2755  * the last best 2 values in the index*/
2756  selection = cpl_malloc(sizeof(cpl_size) * nsets_extracted);
2757  memset(&selection[0], 0, sizeof(cpl_size) * nsets_extracted);
2758 
2759  selection[index_on[last_linear_best*2 + 0] ] = 1;
2760  selection[index_on[last_linear_best*2 + 1] ] = 1;
2761  pair_on = cpl_frameset_extract(set_on, selection, 1);
2762  ons = detmon_lg_config.load_fset_wrp(pair_on, CPL_TYPE_FLOAT, whichext);
2763 
2764  skip_if(ons == NULL);
2765  skip_if((im1 = cpl_imagelist_get_const(ons, 0)) == NULL);
2766 
2767  fpn = irplib_fpn_lg(im1, range, gain, fpn_method, smooth_size, &mse);
2768  skip_if(cpl_propertylist_append_double(lint_qclist, DETMON_QC_FPN,
2769  fpn));
2770  skip_if(cpl_propertylist_append_double(lint_qclist, "ESO QC GAIN ERR",
2771  mse));
2772 
2773  end_skip;
2774  cpl_frameset_delete(pair_on);
2775  cpl_imagelist_delete(ons);
2776  cpl_free(selection);
2777  return cpl_error_get_code();
2778 }
2779 
2780 /*--------------------------------------------------------------------------*/
2788 /*--------------------------------------------------------------------------*/
2789 static cpl_error_code
2790 detmon_lg_lamp_stab(const cpl_frameset * lamps,
2791  const cpl_frameset * darks,
2792  cpl_boolean opt_nir,
2793  int whichext)
2794 {
2795 
2796  /*
2797  * NOTE:
2798  * Most of this code is copied (and modified) from
2799  * isaac_img_detlin_load(), in isaac_img_detlin.c v.1.25
2800  */
2801 
2802  int nb_lamps;
2803  int nb_darks;
2804 
2805  cpl_vector * selection = NULL;
2806  cpl_propertylist * plist;
2807  double dit_lamp, dit_dark;
2808  int dit_stab;
2809  cpl_imagelist * lamps_data = NULL;
2810  cpl_imagelist * darks_data = NULL;
2811  double * stab_levels = NULL;
2812  int i, j;
2813  double * ditvals = NULL;
2814  int last_stab = 0; /* Avoid false uninit warning */
2815 
2816  /* Check that there are as many lamp as darks */
2817  cpl_ensure_code((nb_lamps = cpl_frameset_get_size(lamps)) >= 3,
2818  CPL_ERROR_ILLEGAL_INPUT);
2819 /*
2820  cpl_ensure_code(cpl_frameset_get_size(darks) == nb_lamps,
2821  CPL_ERROR_ILLEGAL_INPUT);
2822 */
2823  /* Check out that they have consistent integration times */
2824  cpl_msg_info(__func__, "Checking DIT consistency");
2825  selection = cpl_vector_new(nb_lamps);
2826  ditvals = cpl_malloc(nb_lamps * sizeof(double));
2827  dit_stab = 0;
2828  for (i = 0; i < nb_lamps; i++) {
2829  const cpl_frame * c_lamp;
2830  const cpl_frame * c_dark;
2831  /* Check if ok */
2832  skip_if (cpl_error_get_code());
2833 
2834  /* DIT from LAMP */
2835  c_lamp = cpl_frameset_get_position_const(lamps, i);
2836  plist = cpl_propertylist_load(cpl_frame_get_filename(c_lamp), 0);
2837  if(opt_nir)
2838  dit_lamp = (double)detmon_pfits_get_dit(plist);
2839  else
2840  dit_lamp = (double)detmon_pfits_get_dit_opt(plist);
2841  cpl_propertylist_delete(plist);
2842  skip_if (cpl_error_get_code());
2843 
2844  /* DIT from DARK */
2845  c_dark = cpl_frameset_get_position_const(darks, i);
2846  plist = cpl_propertylist_load(cpl_frame_get_filename(c_dark), 0);
2847  if(opt_nir)
2848  dit_dark = (double)detmon_pfits_get_dit(plist);
2849  else
2850  dit_dark = (double)detmon_pfits_get_dit_opt(plist);
2851  cpl_propertylist_delete(plist);
2852  skip_if (cpl_error_get_code());
2853 
2854  /* Check consistency */
2855  if (fabs(dit_dark-dit_lamp) > 1e-3) {
2856  cpl_msg_error(__func__, "DIT not consistent between LAMP and DARK, skip lamp stability computation");
2857  /* FIXME: Should an error code be set here? */
2858 
2859  skip_if(1);
2860  }
2861  ditvals[i] = dit_lamp;
2862  /* Set selection */
2863  if (i==0) {
2864  cpl_vector_set(selection, i, -1.0);
2865  dit_stab ++;
2866  last_stab = 0;
2867  } else {
2868  /*
2869  * The second condition is to make sure that frames taken into
2870  * account for lamp stability are not consecutive.
2871  */
2872  if (fabs(dit_lamp - ditvals[0]) < 1e-5 && i - last_stab > 3) {
2873  cpl_vector_set(selection, i, -1.0);
2874  dit_stab ++;
2875  last_stab = i;
2876  } else {
2877  cpl_vector_set(selection, i, 1.0);
2878  }
2879  }
2880  }
2881 
2882  /* Check if there are enough DITs for stability check */
2883  if (dit_stab < 2) {
2884  cpl_msg_info(__func__, "Not enough frames for stability check");
2885  } else {
2886 
2887  /* Load the data and compute lamp-dark */
2888  cpl_msg_info(__func__, "Compute the differences lamp - dark");
2889 
2890 
2891  lamps_data = detmon_load_frameset_window(lamps, CPL_TYPE_FLOAT, 0,
2892  whichext,
2893  detmon_lg_config.llx,
2894  detmon_lg_config.lly,
2895  detmon_lg_config.urx,
2896  detmon_lg_config.ury,
2897  -1, -1);
2898 
2899  darks_data = detmon_load_frameset_window(lamps, CPL_TYPE_FLOAT, 0,
2900  whichext,
2901  detmon_lg_config.llx,
2902  detmon_lg_config.lly,
2903  detmon_lg_config.urx,
2904  detmon_lg_config.ury,
2905  -1, -1);
2906 
2907  nb_darks=cpl_imagelist_get_size(darks_data);
2908  if(nb_darks==nb_lamps) {
2909  skip_if(cpl_imagelist_subtract(lamps_data,darks_data));
2910  } else {
2911  cpl_image* master_dark=cpl_imagelist_collapse_median_create(darks_data);
2912  cpl_imagelist_subtract_image(lamps_data,master_dark);
2913  cpl_image_delete(master_dark);
2914  }
2915  /* Check the lamp stability */
2916  cpl_msg_info(__func__, "Check the lamp stability");
2917  stab_levels = cpl_malloc(dit_stab * sizeof(double));
2918  j = 0;
2919  for (i=0; i<nb_lamps; i++) {
2920  if (cpl_vector_get(selection, i) < 0) {
2921  stab_levels[j] =
2922  cpl_image_get_mean(cpl_imagelist_get(lamps_data, i));
2923  j++;
2924  }
2925  }
2926 
2927  /* Compute the lamp stability */
2928  for (i=1; i<dit_stab; i++) {
2929  if ((fabs(stab_levels[i]-stab_levels[0]) / stab_levels[0]) >
2930  detmon_lg_config.lamp_stability)
2931  detmon_lg_config.lamp_stability =
2932  fabs(stab_levels[i]-stab_levels[0]) / stab_levels[0];
2933  }
2934 
2935 
2936  /* Check the lamp stability */
2937  if (detmon_lg_config.lamp_stability > 0.01) {
2938  cpl_msg_warning(__func__,
2939  "Lamp stability level %g difference too high - proceed anyway",detmon_lg_config.lamp_stability);
2940  }
2941  }
2942  end_skip;
2943 
2944 
2945  cpl_free(ditvals);
2946  cpl_vector_delete(selection);
2947  cpl_imagelist_delete(lamps_data);
2948  cpl_imagelist_delete(darks_data);
2949  cpl_free(stab_levels);
2950 
2951  return cpl_error_get_code();
2952 }
2953 
2954 /*--------------------------------------------------------------------------*/
2977 /*--------------------------------------------------------------------------*/
2978 static cpl_error_code
2979 detmon_lg_reduce_dit(const cpl_frameset * set_on,
2980  int* index_on, double* exptime_on,
2981  const int dit_nb,
2982  int * dit_nskip,
2983  const cpl_frameset * set_off,
2984  int * index_off, double* exptime_off,
2985  int* next_on, int* next_off,
2986  cpl_table * linear_table,
2987  cpl_table * gain_table,
2988  cpl_imagelist * linearity_inputs,
2989  cpl_propertylist * qclist,
2990  cpl_boolean opt_nir,
2991  cpl_imagelist * autocorr_images,
2992  cpl_imagelist * diff_flats,
2993  cpl_imagelist * opt_offs,
2994  int whichext,
2995  int* rows_linear_affected,
2996  int* rows_gain_affected)
2997 {
2998  cpl_frameset * pair_on = NULL;
2999  cpl_frameset * pair_off = NULL;
3000  cpl_imagelist * ons = NULL;
3001  cpl_imagelist * offs = NULL;
3002  cpl_boolean follow = CPL_TRUE;
3003  unsigned mode = detmon_lg_config.autocorr ? IRPLIB_GAIN_WITH_AUTOCORR : 0;
3004  double c_dit;
3005  int c_ndit;
3006 
3007  double current_dit = 0;
3008 
3009  const char * filename;
3010 
3011  cpl_propertylist * plist = NULL;
3012  cpl_propertylist* pDETlist = NULL;
3013 
3014  mode = detmon_lg_config.collapse ?
3015  mode | IRPLIB_GAIN_COLLAPSE | IRPLIB_LIN_COLLAPSE:
3016  mode | IRPLIB_GAIN_NO_COLLAPSE | IRPLIB_LIN_NO_COLLAPSE;
3017  mode = detmon_lg_config.pix2pix ?
3018  mode | IRPLIB_LIN_PIX2PIX : mode;
3019  mode = opt_nir ?
3020  mode | IRPLIB_GAIN_NIR | IRPLIB_LIN_NIR :
3021  mode | IRPLIB_GAIN_OPT | IRPLIB_LIN_OPT ;
3022 
3023 
3024  /* ON pair extraction */
3025  skip_if(detmon_pair_extract_next(set_on, index_on, next_on, exptime_on, &pair_on, detmon_lg_config.tolerance));
3026  current_dit = exptime_on[*next_on - 1];
3027 
3028  /* Load the ON images */
3029  ons = detmon_lg_config.load_fset_wrp(pair_on, CPL_TYPE_FLOAT, whichext);
3030  skip_if(ons == NULL);
3031  cpl_msg_debug(cpl_func, " Loaded ON images: %" CPL_SIZE_FORMAT
3032  ", exptime[%f]",cpl_imagelist_get_size(ons), current_dit );
3033  if(cpl_imagelist_get_size(ons) != 2)
3034  {
3035  cpl_msg_error(cpl_func, "cannot take ON pair, number of images[%"
3036  CPL_SIZE_FORMAT "]", cpl_imagelist_get_size(ons));
3037  skip_if(TRUE);
3038  }
3039  if(detmon_lg_config.filter > 0)
3040  {
3041  double med1 =
3042  cpl_image_get_median_window(cpl_imagelist_get(ons, 0),
3043  detmon_lg_config.llx,
3044  detmon_lg_config.lly,
3045  detmon_lg_config.urx,
3046  detmon_lg_config.ury);
3047  double med2 =
3048  cpl_image_get_median_window(cpl_imagelist_get(ons, 1),
3049  detmon_lg_config.llx,
3050  detmon_lg_config.lly,
3051  detmon_lg_config.urx,
3052  detmon_lg_config.ury);
3053 
3054 
3055 
3056  if ( med1 > (double)detmon_lg_config.filter ||
3057  med2 > (double)detmon_lg_config.filter)
3058  {
3059  follow = CPL_FALSE;
3060  cpl_table_select_row(gain_table, dit_nb);
3061  cpl_table_select_row(linear_table, dit_nb);
3062  (*dit_nskip)++;
3063  cpl_msg_warning(cpl_func, "Frames of EXPTIME nb %d "
3064  "will not be taken into account for computation "
3065  "as the median of the on frames computed on the "
3066  "user defined region [%d,%d,%d,%d] are above "
3067  "--filter threshold (%d)",
3068  dit_nb,
3069  detmon_lg_config.llx,
3070  detmon_lg_config.lly,
3071  detmon_lg_config.urx,
3072  detmon_lg_config.ury,
3073  detmon_lg_config.filter);
3074  }
3075  }
3076 
3077  if (follow || detmon_lg_config.filter < 0)
3078  {
3079 
3080  /*
3081  * If the --collapse option is not activated by the user, the OFF
3082  * sub-frameset is also supposed to be organized into pairs and,
3083  * therefore, processed as the ON sub-frameset.
3084  */
3085  if(!detmon_lg_config.collapse)
3086  {
3087  /* TODO: We removed this check as with NACO data, that has an odd
3088  * number of input OFF frames it would stop with error
3089  * despite the recipe would reduce the data properly.
3090  * On the other side, on some data without such a check one may get
3091  * failures on another place.
3092  * we need to document such cases and understand how to better deal
3093  * in a robust way the case of odd input off frames
3094  *
3095  if (cpl_frameset_get_size(set_off) % 2 != 0) {
3096  cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
3097  "If collapse is FALSE the OFF frameset"
3098  " must be organized in pairs.");
3099  skip_if(1);
3100  }
3101  */
3102  if (!strcmp(detmon_lg_config.method, "MED") ||
3103  cpl_frameset_get_size(set_on) == cpl_frameset_get_size(set_off))
3104  {
3105  skip_if(detmon_pair_extract_next(set_off, index_off, next_off, exptime_off, &pair_off, detmon_lg_config.tolerance));
3106  }
3107  else
3108  {
3109  skip_if(detmon_single_extract_next(set_off, index_off, next_off, exptime_off, &pair_off));
3110  }
3111  /* Load the OFF images */
3112  cpl_msg_debug(cpl_func, " Load the OFF images, ext[%d], exptime[%f]", whichext, exptime_off[*next_off - 1]);
3113  offs = detmon_lg_config.load_fset_wrp(pair_off, CPL_TYPE_FLOAT, whichext);
3114 
3115  skip_if(offs == NULL);
3116  skip_if(cpl_error_get_code());
3117  }
3118  else {
3119  offs = (cpl_imagelist *) opt_offs;
3120  }
3121 
3122  /* Rescaling */
3123  if(detmon_lg_config.rescale)
3124  {
3125  skip_if(detmon_lg_rescale(ons));
3126  if (!detmon_lg_config.collapse &&
3127  !strcmp(detmon_lg_config.method, "MED"))
3128  skip_if(detmon_lg_rescale(offs));
3129  }
3130  /* DIT or EXPTIME value extraction */
3131 
3132  filename =
3133  cpl_frame_get_filename(cpl_frameset_get_position_const(pair_on, 0));
3134  skip_if ((plist = cpl_propertylist_load(filename, 0)) == NULL);
3135  /* Add columns to the tables DETi WINi UITi*/
3136  if (plist)
3137  {
3138  pDETlist = cpl_propertylist_new();
3139  cpl_propertylist_copy_property_regexp(pDETlist, plist, "DET[0-9]* WIN[0-9]* UIT[0-9]*",0);
3140  if (dit_nb == 0)
3141  {
3142  irplib_table_create_column(gain_table, pDETlist);
3143  irplib_table_create_column(linear_table, pDETlist);
3144  }
3145  }
3146  if(opt_nir == NIR) {
3147  c_dit = detmon_pfits_get_dit(plist);
3148  c_ndit = irplib_pfits_get_ndit(plist);
3149  } else {
3150  c_dit = irplib_pfits_get_exptime(plist);
3151  c_ndit=1;
3152  }
3153 
3154  /*
3155  * --GAIN part for each DIT value--
3156  * The following call to detmon_gain_table_fill_row() fills
3157  * in the row nb i
3158  * of the GAIN table (output) and of the FIT table (by-product to be
3159  * used later for the polynomial computation of the GAIN)
3160  */
3161 
3162  cpl_msg_info(cpl_func, "Computing GAIN for EXPTIME value nb %d",
3163  dit_nb + 1);
3164 
3165  /* In case PTC is applied, this is allowed */
3166  if(cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE && dit_nb == 0)
3167  {
3168  cpl_table_erase_column(gain_table, "MEAN_OFF1");
3169  cpl_table_erase_column(gain_table, "MEAN_OFF2");
3170  cpl_table_erase_column(gain_table, "SIG_OFF_DIF");
3171  cpl_table_erase_column(gain_table, "GAIN");
3172  cpl_table_erase_column(gain_table, "GAIN_CORR");
3173  cpl_table_new_column(gain_table, "MEAN_OFF", CPL_TYPE_DOUBLE);
3174  }
3175 
3176 
3177  skip_if(detmon_gain_table_fill_row(gain_table,
3178  c_dit,c_ndit,
3179  autocorr_images,
3180  diff_flats, ons, offs,
3181  detmon_lg_config.kappa,
3182  detmon_lg_config.niter,
3183  detmon_lg_config.llx,
3184  detmon_lg_config.lly,
3185  detmon_lg_config.urx,
3186  detmon_lg_config.ury,
3187  detmon_lg_config.m,
3188  detmon_lg_config.n,
3189  detmon_lg_config.gain_threshold,
3190  dit_nb, mode, rows_gain_affected));
3191 
3192 
3193  skip_if(detmon_check_saturation_on_pair(autocorr_images,
3194  diff_flats,ons,
3195  detmon_lg_config.kappa,
3196  detmon_lg_config.niter,
3197  detmon_lg_config.llx,
3198  detmon_lg_config.lly,
3199  detmon_lg_config.urx,
3200  detmon_lg_config.ury,
3201  detmon_lg_config.saturation_limit,
3202  dit_nb, mode, rows_linear_affected));
3203 
3204 
3205  if (*rows_gain_affected)
3206  {
3207  /* fill DETi WINi OPTi columns - see DFS06921*/
3208  skip_if(irplib_fill_table_DETWINUIT(gain_table, pDETlist, dit_nb));
3209  /* Linearity reduction */
3210  cpl_msg_info(cpl_func, "Linearity reduction for nb %d",
3211  dit_nb + 1);
3212  }
3213  if (*rows_linear_affected) {
3214  skip_if(detmon_lin_table_fill_row(linear_table, c_dit,
3215  linearity_inputs, ons, offs,
3216  detmon_lg_config.llx,
3217  detmon_lg_config.lly,
3218  detmon_lg_config.urx,
3219  detmon_lg_config.ury,
3220  dit_nb, *dit_nskip, mode));
3221  /* fill DETi WINi OPTi columns - see DFS06921*/
3222  skip_if(irplib_fill_table_DETWINUIT(linear_table, pDETlist, dit_nb));
3223  }
3224 
3225 
3226  /* as we know only at this point if a frame is
3227  saturated or not, and we would like to compute the
3228  contamination only on the last non saturated frame,
3229  we need de facto to compute saturation on any non saturated
3230  frame, by overwriting the QC parameter. In the end it will
3231  remain only the last value corresponding to a non saturated
3232  frame */
3233 
3234  if(opt_nir == OPT &&
3235  *rows_linear_affected != 0 ) {
3236  detmon_opt_contamination(ons, offs, mode, qclist);
3237  }
3238 
3239  }
3240 
3241  end_skip;
3242 
3243  cpl_frameset_delete(pair_on);
3244  cpl_imagelist_delete(ons);
3245 
3246  if(!detmon_lg_config.collapse ) {
3247  cpl_imagelist_delete(offs);
3248  }
3249 
3250  if(!detmon_lg_config.collapse) {
3251  cpl_frameset_delete(pair_off);
3252  }
3253 
3254  cpl_propertylist_delete(plist);
3255  cpl_propertylist_delete(pDETlist);
3256  return cpl_error_get_code();
3257 }
3258 
3259 /*---------------------------------------------------------------------------*/
3265 /*---------------------------------------------------------------------------*/
3266 static cpl_error_code
3267 detmon_add_adl_column(cpl_table * table,
3268  cpl_boolean opt_nir)
3269 {
3270  cpl_error_code error;
3271  double mean_med_dit;
3272  double *dits;
3273 
3274  cpl_ensure_code(table != NULL, CPL_ERROR_NULL_INPUT);
3275 
3276  mean_med_dit = cpl_table_get_column_mean(table, "MED_DIT");
3277  if (opt_nir == OPT)
3278  dits = cpl_table_get_data_double(table, "EXPTIME");
3279  else
3280  dits = cpl_table_get_data_double(table, "DIT");
3281 
3282  error = cpl_table_copy_data_double(table, "ADL", dits);
3283  cpl_ensure_code(!error, error);
3284  error = cpl_table_multiply_scalar(table, "ADL", mean_med_dit);
3285  cpl_ensure_code(!error, error);
3286 
3287  return cpl_error_get_code();
3288 }
3289 
3290 /*---------------------------------------------------------------------------*/
3298 /*---------------------------------------------------------------------------*/
3299 static cpl_error_code
3300 detmon_lg_reduce_init(cpl_table * gain_table,
3301  cpl_table * linear_table,
3302  cpl_imagelist ** linearity_inputs,
3303  const cpl_boolean opt_nir)
3304 {
3305  skip_if(detmon_gain_table_create(gain_table, opt_nir));
3306  skip_if(detmon_lin_table_create(linear_table, opt_nir));
3307 
3308  if(detmon_lg_config.pix2pix) {
3309  *linearity_inputs = cpl_imagelist_new();
3310  skip_if(*linearity_inputs == NULL);
3311  }
3312 
3313  end_skip;
3314 
3315  return cpl_error_get_code();
3316 }
3317 
3318 /*--------------------------------------------------------------------------*/
3324 /*--------------------------------------------------------------------------*/
3325 static double
3326 detmon_pfits_get_dit(const cpl_propertylist * plist)
3327 {
3328  if (cpl_propertylist_has(plist, "ESO DET DIT")) {
3329  /* FIERA Detector Controller */
3330  return irplib_pfits_get_prop_double(plist, "ESO DET DIT");
3331  } else {
3332  /* New Generation Detector Controller */
3333  return irplib_pfits_get_prop_double(plist, "ESO DET SEQ1 DIT");
3334  }
3335  (void)cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND, "FITS key "
3336  "ESO DET DIT or ESO DET DIT not found");
3337  return 0.0;
3338 }
3339 
3340 /*--------------------------------------------------------------------------*/
3346 /*--------------------------------------------------------------------------*/
3347 static double
3348 detmon_pfits_get_dit_opt(const cpl_propertylist * plist)
3349 {
3350  if (cpl_propertylist_has(plist, "ESO DET WIN1 UIT1")) {
3351  /* FIERA Detector Controller */
3352  return irplib_pfits_get_prop_double(plist, "ESO DET WIN1 UIT1");
3353  } else if (cpl_propertylist_has(plist, "ESO DET UIT1")) {
3354  /* New Generation Detector Controller */
3355  return irplib_pfits_get_prop_double(plist, "ESO DET WIN1 UIT1");
3356  }
3357 
3358  (void)cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND, "FITS key "
3359  "ESO DET WIN1 UIT1 or ESO DET UIT1 not found");
3360  return 0.0;
3361 }
3362 
3363 
3364 /*---------------------------------------------------------------------------*/
3369 static cpl_propertylist*
3370 detmon_load_pro_keys(const char* NAME_O)
3371 {
3372  cpl_propertylist* pro_keys=NULL;
3373  pro_keys=cpl_propertylist_load_regexp(NAME_O,0,"^(ESO PRO)",0);
3374  return pro_keys;
3375 }
3376 
3377 
3378 static double irplib_pfits_get_prop_double(const cpl_propertylist * plist,
3379  const char* prop_name)
3380 {
3381  double dit;
3382  dit = cpl_propertylist_get_double(plist, prop_name);
3383  if(cpl_error_get_code() != CPL_ERROR_NONE)
3384  {
3385  cpl_msg_error(cpl_func, "Cannot read property '%s', err[%s]",
3386  prop_name, cpl_error_get_where());
3387  }
3388  return dit;
3389 }
3390 
3391 static cpl_error_code
3392 detmon_gain_compute_qc(double kappa, int nclip, const int pos,
3393  const cpl_imagelist* offs, unsigned mode,
3394  double avg_on1, double avg_on2,
3395  double avg_off1, double avg_off2,
3396  double sig_off_dif, int c_ndit,
3397  double autocorr, cpl_image* on_dif,
3398  cpl_table* gain_table)
3399 {
3400 
3401  /* here detmon actually computes gain QC parameter */
3402  double double_adu;
3403  double avg_on_dif, sig_on_dif;
3404  irplib_ksigma_clip(on_dif, 1, 1, cpl_image_get_size_x(on_dif),
3405  cpl_image_get_size_y(on_dif), kappa, nclip, 1e-5,
3406  &avg_on_dif, &sig_on_dif);
3407  skip_if(
3408  cpl_table_set_double(gain_table, "SIG_ON_DIF", pos,
3409  sig_on_dif));
3410  if (cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE) {
3411  double_adu = (avg_on1 + avg_on2) - 2 * avg_off1;
3412  }
3413  else {
3414  double_adu = (avg_on1 + avg_on2) - (avg_off1 + avg_off2);
3415 
3416  const double sigma
3417  = (sig_on_dif * sig_on_dif) - (sig_off_dif * sig_off_dif);
3418 
3419  /* sigma_corr = autocorr * sigma; */
3420 
3421  const double gain = double_adu / (c_ndit * sigma);
3422 
3423  const double gain_corr = gain / (autocorr);
3424 
3425  skip_if(cpl_table_set_double(gain_table, "GAIN", pos, gain));
3426  skip_if(
3427  cpl_table_set_double(gain_table, "GAIN_CORR", pos,
3428  gain_corr));
3429  }
3430  /* cpl_msg_info(cpl_func,"gain=%g gain_corr=%g autocorr=%g",gain,gain_corr,autocorr); */
3431  skip_if(cpl_table_set_double(gain_table, "AUTOCORR", pos, autocorr));
3432  skip_if(cpl_table_set_double(gain_table, "ADU", pos, double_adu / 2));
3433  /* FIXME: Remove the following 3 columns after testing period */
3434  skip_if(
3435  cpl_table_set_double(gain_table, "Y_FIT", pos,
3436  c_ndit * sig_on_dif * sig_on_dif));
3437  skip_if(
3438  cpl_table_set_double(gain_table, "Y_FIT_CORR", pos,
3439  c_ndit * sig_on_dif * sig_on_dif));
3440  skip_if(cpl_table_set_double(gain_table, "X_FIT", pos, double_adu));
3441  skip_if(
3442  cpl_table_set_double(gain_table, "X_FIT_CORR", pos,
3443  double_adu / autocorr));
3444 
3445  end_skip;
3446 
3447  return cpl_error_get_code();
3448 }
3449 
3450 static double
3451 detmon_gain_prepare_autocorr(unsigned mode, const int pos,
3452  int m, int n, cpl_imagelist* diff_flats,
3453  cpl_image* on_dif, cpl_imagelist* autocorr_images)
3454 {
3455  double autocorr = 1.0;
3456 
3457  if (mode & IRPLIB_GAIN_WITH_AUTOCORR) {
3458  if (diff_flats) {
3459  cpl_image * diff = cpl_image_duplicate(on_dif);
3460  skip_if(cpl_imagelist_set(diff_flats, diff, pos));
3461  }
3462  if (autocorr_images) {
3463  cpl_image * corr = NULL;
3464  autocorr = detmon_autocorr_factor(on_dif, &corr, m, n);
3465  if (corr) {
3466  skip_if(cpl_imagelist_set(autocorr_images, corr, pos));
3467  }
3468  else {
3469  detmon_lg_add_empty_image(autocorr_images, pos);
3470  }
3471  }
3472  else {
3473  autocorr = detmon_autocorr_factor(on_dif, NULL, m, n);
3474  }
3475  autocorr = isnan(autocorr) ? 1.0 : autocorr;
3476  }
3477  end_skip;
3478 
3479  return autocorr;
3480 }
3481 
3482 static double
3483 detmon_gain_prepare_table(const cpl_imagelist* offs, unsigned mode, int llx,
3484  int lly, int urx, int ury, double kappa, int nclip,
3485  double std, const int pos,
3486  cpl_table* gain_table, double* avg_off2,
3487  double* sig_off_dif)
3488 {
3489  double avg_off1 = 0.0;
3490 
3491  /* prepare gain table to compute gain QC param */
3492  /* TODO: AMO sees that the condition (mode & IRPLIB_GAIN_NO_COLLAPSE)
3493  * is repeated in 2 if entries==> probably one should rewrite the if
3494  * construct
3495  */
3496  if (cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE) {
3497 
3498  skip_if(
3499  irplib_ksigma_clip(cpl_imagelist_get_const(offs, 0),
3500  llx, lly, urx, ury, kappa, nclip, 1e-5,
3501  &avg_off1, &std));
3502  skip_if(cpl_table_set_double(gain_table, "MEAN_OFF", pos, avg_off1));
3503 
3504  }
3505  else if ((mode & IRPLIB_GAIN_NO_COLLAPSE)
3506  || (pos == 0 && mode & IRPLIB_GAIN_COLLAPSE)) {
3507  cpl_image * off_dif = NULL;
3508  double avg_off_dif;
3509  skip_if(
3510  irplib_ksigma_clip(cpl_imagelist_get_const(offs, 0),
3511  llx, lly, urx, ury, kappa, nclip, 1e-5,
3512  &avg_off1, &std));
3513  skip_if(cpl_table_set_double(gain_table, "MEAN_OFF1", pos, avg_off1));
3514  skip_if(
3515  irplib_ksigma_clip(cpl_imagelist_get_const(offs, 1),
3516  llx, lly, urx, ury, kappa, nclip, 1e-5,
3517  avg_off2, &std));
3518  skip_if(cpl_table_set_double(gain_table, "MEAN_OFF2", pos, *avg_off2));
3519  off_dif = detmon_subtract_create_window(
3520  cpl_imagelist_get_const(offs, 0),
3521  cpl_imagelist_get_const(offs, 1), llx, lly, urx, ury);
3522  skip_if(off_dif == NULL);
3523  irplib_ksigma_clip(off_dif, 1, 1, cpl_image_get_size_x(off_dif),
3524  cpl_image_get_size_y(off_dif), kappa, nclip, 1e-5,
3525  &avg_off_dif, sig_off_dif);
3526  cpl_image_delete(off_dif);
3527  skip_if(
3528  cpl_table_set_double(gain_table, "SIG_OFF_DIF", pos,
3529  *sig_off_dif));
3530  }
3531  else if (pos > 0 && (mode & IRPLIB_GAIN_COLLAPSE)) {
3532 
3533  int status;
3534  avg_off1 = cpl_table_get_double(gain_table, "MEAN_OFF1", 0, &status);
3535  skip_if(cpl_table_set_double(gain_table, "MEAN_OFF1", pos, avg_off1));
3536  *avg_off2 = cpl_table_get_double(gain_table, "MEAN_OFF2", 0, &status);
3537  skip_if(cpl_table_set_double(gain_table, "MEAN_OFF2", pos, *avg_off2));
3538  *sig_off_dif = cpl_table_get_double(gain_table, "SIG_OFF_DIF", 0,
3539  &status);
3540  skip_if(
3541  cpl_table_set_double(gain_table, "SIG_OFF_DIF", pos,
3542  *sig_off_dif));
3543  }
3544 
3545  end_skip;
3546 
3547  return avg_off1;
3548 }
3549 
3550 /*---------------------------------------------------------------------------*/
3585 /*---------------------------------------------------------------------------*/
3586 static cpl_error_code
3587 detmon_gain_table_fill_row(cpl_table * gain_table,
3588  double c_dit,int c_ndit,
3589  cpl_imagelist * autocorr_images,
3590  cpl_imagelist * diff_flats,
3591  const cpl_imagelist * ons,
3592  const cpl_imagelist * offs,
3593  double kappa, int nclip,
3594  int llx, int lly, int urx, int ury,
3595  int m, int n,
3596  double gain_threshold,
3597  int pos, unsigned mode, int* rows_gain_affected)
3598 {
3599  const cpl_image *image;
3600  cpl_image *on_dif = NULL;
3601  double std = 0;
3602  double avg_on1, avg_on2;
3603  double avg_off1, avg_off2;
3604  double autocorr;
3605 
3606  cpl_table_set(gain_table, "FLAG", pos, 1);
3607  if (mode & IRPLIB_GAIN_NIR)
3608  {
3609  cpl_table_set(gain_table, "DIT", pos, c_dit);
3610  cpl_table_set(gain_table, "NDIT", pos, c_ndit);
3611  } else if (mode & IRPLIB_GAIN_OPT)
3612  {
3613  cpl_table_set(gain_table, "EXPTIME", pos, c_dit);
3614  } else
3615  {
3616  cpl_msg_error(cpl_func, "Mandatory mode (OPT or NIR) not provided");
3617  skip_if(1);
3618  }
3619  if(*rows_gain_affected == 0)
3620  {
3621  cpl_msg_info(cpl_func, "skip the frame #%d", pos + 1);
3622  cpl_table_set(gain_table, "FLAG", pos, 0);
3623  if(mode & IRPLIB_GAIN_WITH_AUTOCORR)
3624  {
3625  autocorr = -1;
3626  if (diff_flats)
3627  {
3628  detmon_lg_add_empty_image(diff_flats, pos);
3629  }
3630  if (autocorr_images)
3631  {
3632  detmon_lg_add_empty_image(autocorr_images, pos);
3633  }
3634  }
3635  return cpl_error_get_code();
3636  }
3637  skip_if((image = cpl_imagelist_get_const(ons, 0)) == NULL);
3638  skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
3639  nclip, 1e-5, &avg_on1, &std));
3640  skip_if((image = cpl_imagelist_get_const(ons, 1)) == NULL);
3641  skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
3642  nclip, 1e-5, &avg_on2, &std));
3643 
3644  if (
3645  (avg_on1 > gain_threshold) ||
3646  (avg_on2 > gain_threshold)
3647  )
3648  {
3649  /* If frames has intensity above threshold write out warning and adjust
3650  * imagelists
3651  */
3652  if ( (avg_on1 > gain_threshold) || (avg_on2 > gain_threshold) )
3653  {
3654  cpl_msg_warning(cpl_func, "Average level is above the limit set by the gain_theshold parameter, "
3655  "the frames would not be taken into calculation");
3656 
3657  cpl_msg_warning(cpl_func, "Average levels [%f ; %f], limit [%f]",
3658  avg_on1, avg_on2, gain_threshold);
3659  }
3660 
3661  cpl_msg_info(cpl_func, "skip the frame #%d", pos + 1);
3662  cpl_table_set(gain_table, "FLAG", pos, 0);
3663  if(mode & IRPLIB_GAIN_WITH_AUTOCORR)
3664  {
3665  autocorr = -1;
3666  if (diff_flats)
3667  {
3668  detmon_lg_add_empty_image(diff_flats, pos);
3669  }
3670  if (autocorr_images)
3671  {
3672  detmon_lg_add_empty_image(autocorr_images, pos);
3673  }
3674  }
3675  *rows_gain_affected = 0;
3676  }
3677  else
3678  {
3679  /* we can compute gain: first computes relevant quantities to cover all
3680  * cases, then compute QC parameter.
3681  */
3682  double sig_off_dif;
3683  *rows_gain_affected = 1;
3684  skip_if(cpl_table_set_double(gain_table, "MEAN_ON1", pos, avg_on1));
3685  skip_if(cpl_table_set_double(gain_table, "MEAN_ON2", pos, avg_on2));
3686 
3687  on_dif =
3688  detmon_subtract_create_window(cpl_imagelist_get_const(ons, 0),
3689  cpl_imagelist_get_const(ons, 1),
3690  llx, lly, urx, ury);
3691  skip_if(on_dif == NULL);
3692 
3693  autocorr = detmon_gain_prepare_autocorr(mode, pos, m, n,
3694  diff_flats, on_dif, autocorr_images);
3695 
3696  avg_off1 = detmon_gain_prepare_table(offs, mode, llx, lly, urx, ury,
3697  kappa, nclip, std, pos, gain_table, &avg_off2,
3698  &sig_off_dif);
3699 
3700  detmon_gain_compute_qc(kappa, nclip, pos, offs, mode,
3701  avg_on1, avg_on2, avg_off1, avg_off2,
3702  sig_off_dif, c_ndit, autocorr, on_dif,
3703  gain_table);
3704  }
3705  end_skip;
3706 
3707  cpl_image_delete(on_dif);
3708 
3709  return cpl_error_get_code();
3710 }
3711 
3712 
3713 
3714 /*---------------------------------------------------------------------------*/
3735 /*---------------------------------------------------------------------------*/
3736 static cpl_error_code
3737 detmon_check_saturation_on_pair(cpl_imagelist * autocorr_images,
3738  cpl_imagelist * diff_flats,
3739  const cpl_imagelist * ons,
3740  double kappa, int nclip,
3741  int llx, int lly, int urx, int ury,
3742  double saturation_limit,
3743  const int pos, unsigned mode, int* rows_linear_affected)
3744 {
3745  const cpl_image *image;
3746  double std = 0;
3747  double avg_on1, avg_on2;
3748 
3749 
3750  if(*rows_linear_affected == 0)
3751  {
3752  cpl_msg_info(cpl_func, "For linearity skip the frame #%d", pos + 1);
3753  if(mode & IRPLIB_GAIN_WITH_AUTOCORR)
3754  {
3755  if (diff_flats)
3756  {
3757  detmon_lg_add_empty_image(diff_flats, pos);
3758  }
3759  if (autocorr_images)
3760  {
3761  detmon_lg_add_empty_image(autocorr_images, pos);
3762  }
3763  }
3764  return cpl_error_get_code();
3765  }
3766  skip_if((image = cpl_imagelist_get_const(ons, 0)) == NULL);
3767  skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
3768  nclip, 1e-5, &avg_on1, &std));
3769  skip_if((image = cpl_imagelist_get_const(ons, 1)) == NULL);
3770  skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
3771  nclip, 1e-5, &avg_on2, &std));
3772 
3773  if (
3774  (avg_on1 > saturation_limit) ||
3775  (avg_on2 > saturation_limit)
3776  )
3777  {
3778  /* If frames has intensity above threshold write out warning and adjust
3779  * imagelists
3780  */
3781  if ( (avg_on1 > saturation_limit) || (avg_on2 > saturation_limit) )
3782  {
3783  cpl_msg_warning(cpl_func, "Average level is above the limit set by the saturation_limit parameter, "
3784  "the frames would not be taken into calculation");
3785 
3786  cpl_msg_warning(cpl_func, "Average levels [%f ; %f], limit [%f]",
3787  avg_on1, avg_on2, saturation_limit);
3788  }
3789 
3790  cpl_msg_info(cpl_func, "skip the frame #%d", pos + 1);
3791  *rows_linear_affected = 0;
3792  } else{
3793 
3794  }
3795 
3796  end_skip;
3797 
3798  return cpl_error_get_code();
3799 }
3800 
3801 
3802 
3803 
3804 /*--------------------------------------------------------------------------*/
3811 /*--------------------------------------------------------------------------*/
3812 
3813 static cpl_image *
3814 detmon_bpixs(const cpl_imagelist * coeffs,
3815  cpl_boolean bpmbin,
3816  const double kappa,
3817  int *nbpixs)
3818 {
3819 
3820 
3821  const cpl_image *first= cpl_imagelist_get_const(coeffs, 0);
3822 
3823 
3824 
3825 
3826 
3827 
3828  cpl_mask *mask = cpl_mask_new(cpl_image_get_size_x(first),
3829  cpl_image_get_size_y(first));
3830 
3831  cpl_image *bpm = NULL; /* Avoid false uninit warning */
3832 
3833 
3834  int size = cpl_imagelist_get_size(coeffs);
3835 
3836  if(!bpmbin) {
3837  bpm = cpl_image_new(cpl_image_get_size_x(first),
3838  cpl_image_get_size_y(first),
3839  CPL_TYPE_INT);
3840  }
3841 
3842 
3843  for(int i = 0; i < size; i++) {
3844  const cpl_image * cur_coeff = cpl_imagelist_get_const(coeffs, i);
3845 
3846  cpl_stats* stats = cpl_stats_new_from_image(cur_coeff,
3847  CPL_STATS_MEAN | CPL_STATS_STDEV);
3848  double cur_mean = cpl_stats_get_mean(stats);
3849  double cur_stdev = cpl_stats_get_stdev(stats);
3850 
3851  double lo_cut = cur_mean - kappa * cur_stdev;
3852  double hi_cut = cur_mean + kappa * cur_stdev;
3853 
3854  cpl_mask* cur_mask = cpl_mask_threshold_image_create(cur_coeff, lo_cut, hi_cut);
3855  cpl_mask_not(cur_mask);
3856 
3857  if(!bpmbin) {
3858  cpl_image* cur_image = cpl_image_new_from_mask(cur_mask);
3859  double p = pow(2, i);
3860  cpl_image_power(cur_image, p);
3861  cpl_image_add(bpm, cur_image);
3862  cpl_image_delete(cur_image);
3863  }
3864 
3865  cpl_mask_or(mask, cur_mask);
3866 
3867  cpl_mask_delete(cur_mask);
3868  cpl_stats_delete(stats);
3869  }
3870 
3871  if(bpmbin) {
3872  bpm = cpl_image_new_from_mask(mask);
3873  }
3874 
3875  *nbpixs = cpl_mask_count(mask);
3876 
3877  cpl_mask_delete(mask);
3878 
3879  return bpm;
3880 }
3881 
3882 
3883 /*--------------------------------------------------------------------------*/
3890 /*--------------------------------------------------------------------------*/
3891 /* Not used so we temporary comment it out
3892 static cpl_image *
3893 detmon_bpixs2(cpl_vector* x,const cpl_imagelist* y,
3894  const cpl_imagelist * coeffs,cpl_table* gain_table,
3895  const int order, const double kappa,cpl_boolean bpmbin,
3896  int *nbpixs)
3897 {
3898 
3899 
3900  int size_x=0;
3901  int size_y=0;
3902  int size_c=0;
3903 
3904 
3905  int i=0;
3906  int j=0;
3907  cpl_size k=0;
3908  int z=0;
3909  int pix=0;
3910  int sx=0;
3911  int sy=0;
3912 
3913  double* px=NULL;
3914  const float* pdata=NULL;
3915  const float* pcoeffs=NULL;
3916  double pfit=0.;
3917  double* pgain=NULL;
3918  cpl_binary* pmask=NULL;
3919  double gain=0;
3920  const cpl_image* img_data=NULL;
3921 
3922  const cpl_image* img_coeffs=NULL;
3923  cpl_image* bpm=NULL;
3924  cpl_mask* mask=NULL;
3925 
3926  cpl_polynomial* pol=NULL;
3927 
3928  size_x = cpl_vector_get_size(x);
3929  size_y = cpl_imagelist_get_size(y);
3930  size_c = cpl_imagelist_get_size(coeffs);
3931  img_data = cpl_imagelist_get_const(coeffs, 0);
3932  sx = cpl_image_get_size_x(img_data);
3933  sy = cpl_image_get_size_y(img_data);
3934  mask = cpl_mask_new(sx,sy);
3935 
3936  cpl_ensure(size_x == size_y, CPL_ERROR_NULL_INPUT, NULL);
3937 
3938  cpl_ensure(size_c == (order+1), CPL_ERROR_NULL_INPUT, NULL);
3939 
3940  px = cpl_vector_get_data(x);
3941  pmask=cpl_mask_get_data(mask);
3942  pgain=cpl_table_get_data_double(gain_table,"GAIN");
3943  pol=cpl_polynomial_new(1);
3944  for (z = 0; z < size_x; z++) {
3945 
3946  img_data = cpl_imagelist_get_const(y, z);
3947  pdata = cpl_image_get_data_float_const(img_data);
3948  gain=pgain[z];
3949 
3950  for (j = 0; j < sy; j++) {
3951 
3952  for (i = 0; i < sx; i++) {
3953 
3954  pix = j * sx + i;
3955 
3956  for (k = size_c-1; k >= 0; k--) {
3957 
3958  img_coeffs = cpl_imagelist_get_const(coeffs, k);
3959  pcoeffs = cpl_image_get_data_float_const(img_coeffs);
3960  cpl_polynomial_set_coeff(pol, &k, pcoeffs[pix]);
3961 
3962  }
3963 
3964  pfit = cpl_polynomial_eval_1d(pol,px[z],NULL);
3965  if (pdata[pix] > 0) {
3966  if (fabs(pdata[pix] - pfit) > kappa * sqrt(gain*pdata[pix])) {
3967  pmask[pix] = CPL_BINARY_1;
3968  } // check if point to be flagged
3969  } // check if pos intensity
3970  } // i loop
3971  } // j loop
3972 
3973  //cpl_image_delete(img_data);
3974 
3975  } // z loop
3976  cpl_polynomial_delete(pol);
3977  if (bpmbin) {
3978  bpm = cpl_image_new_from_mask(mask);
3979  }
3980 
3981  *nbpixs += cpl_mask_count(mask);
3982 
3983  cpl_mask_delete(mask);
3984 
3985  return bpm;
3986 }
3987 
3988 */
3989 /*---------------------------------------------------------------------------*/
4001 /*---------------------------------------------------------------------------*/
4002 
4003 static double
4004 detmon_autocorr_factor(const cpl_image * image,
4005  cpl_image ** autocorr_image, int m, int n)
4006 {
4007  cpl_image * mycorr_image = NULL;
4008  double autocorr = 0;
4009 
4010 
4011  mycorr_image = detmon_image_correlate(image, image, m, n);
4012 
4013  if (cpl_error_get_code() == CPL_ERROR_UNSUPPORTED_MODE)
4014  {
4015  cpl_msg_warning(cpl_func, "FFTW is not supported by CPL, autocorrelation "
4016  "would be computed using internal implementation");
4017  cpl_error_reset();
4018  if (mycorr_image)
4019  cpl_image_delete(mycorr_image);
4020  mycorr_image = detmon_autocorrelate(image, m, n);
4021  }
4022  if(mycorr_image == NULL) {
4023  return -1;
4024  }
4025 
4026  cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), -1);
4027 
4028  autocorr = cpl_image_get_flux(mycorr_image);
4029 
4030  if (autocorr_image) *autocorr_image = mycorr_image;
4031  else cpl_image_delete(mycorr_image);
4032 
4033  return autocorr;
4034 }
4035 
4036 static cpl_propertylist*
4037 detmon_lg_extract_qclist_4plane(cpl_propertylist* linc_qclist,const int ip)
4038 {
4039 
4040  cpl_propertylist* sub_set=NULL;
4041  char* qc_key=NULL;
4042 
4043  sub_set=cpl_propertylist_new();
4044  qc_key=cpl_sprintf("QC LIN COEF%d",ip);
4045  cpl_propertylist_copy_property_regexp(sub_set,linc_qclist,qc_key,0);
4046 
4047  cpl_free(qc_key);
4048  return sub_set;
4049 
4050 }
4051 
4052 
4062 static cpl_error_code
4063 detmon_lg_extract_extention_header(cpl_frameset* frameset,
4064  cpl_propertylist* gaint_qclist,
4065  cpl_propertylist* lint_qclist,
4066  cpl_propertylist* linc_qclist,
4067  cpl_propertylist* bpm_qclist,
4068  int whichext)
4069 {
4070 
4071  cpl_propertylist * xplist = NULL;
4072 
4073  const char * filename =
4074  cpl_frame_get_filename(cpl_frameset_get_position(frameset, 0));
4075 
4076  xplist = cpl_propertylist_load_regexp(filename, whichext,
4077  "ESO DET|EXTNAME", 0);
4078  if (detmon_lg_config.exts >= 0)
4079  {
4080  /* for one extension, copy only extname keyword (if any) - DFS09856 */
4081  cpl_property* propExtname = NULL;
4082  propExtname = cpl_propertylist_get_property(xplist, "EXTNAME");
4083  cpl_error_reset();
4084  if (NULL != propExtname)
4085  {
4086  propExtname = cpl_property_duplicate(propExtname);
4087  }
4088  cpl_propertylist_delete(xplist);
4089  xplist = NULL;
4090  if (NULL != propExtname)
4091  {
4092  xplist = cpl_propertylist_new();
4093  cpl_propertylist_append_property(xplist, propExtname);
4094  cpl_property_delete(propExtname);
4095  }
4096  }
4097  if (NULL != xplist)
4098  {
4099  cpl_propertylist_append(gaint_qclist, xplist);
4100  cpl_propertylist_append(lint_qclist, xplist);
4101  cpl_propertylist_append(linc_qclist, xplist);
4102  cpl_propertylist_append(bpm_qclist, xplist);
4103  cpl_propertylist_delete(xplist);
4104  }
4105 
4106  return cpl_error_get_code();
4107 }
4108 
4109 
4110 
4111 
4112 
4113 /*---------------------------------------------------------------------------*/
4122 /*---------------------------------------------------------------------------*/
4123 static cpl_error_code
4124 detmon_lg_save_table_with_pro_keys(cpl_table* table,
4125  const char* name_o,
4126  cpl_propertylist* xheader,
4127  unsigned CPL_IO_MODE)
4128 {
4129 
4130  cpl_propertylist* pro_keys=NULL;
4131 
4132  pro_keys=detmon_load_pro_keys(name_o);
4133  cpl_propertylist_append(xheader,pro_keys);
4134 
4135  if(CPL_IO_MODE==CPL_IO_DEFAULT) {
4136  cpl_propertylist * pri_head=cpl_propertylist_load(name_o,0);
4137  cpl_table_save(table, pri_head,xheader,name_o,
4138  CPL_IO_DEFAULT);
4139  cpl_propertylist_delete(pri_head);
4140 
4141  } else {
4142  cpl_table_save(table,NULL,xheader,name_o,
4143  CPL_IO_EXTEND);
4144  }
4145  cpl_propertylist_delete(pro_keys);
4146 
4147  return cpl_error_get_code();
4148 }
4149 
4150 /*---------------------------------------------------------------------------*/
4158 /*---------------------------------------------------------------------------*/
4159 static cpl_error_code
4160 detmon_lg_save_image_with_pro_keys(cpl_image* image,
4161  const char* name_o,
4162  cpl_propertylist* xheader)
4163 {
4164 
4165  cpl_propertylist* pro_keys=NULL;
4166  pro_keys=detmon_load_pro_keys(name_o);
4167  cpl_propertylist_append(xheader,pro_keys);
4168 
4169  cpl_image_save(image,name_o, CPL_BPP_IEEE_FLOAT,
4170  xheader,CPL_IO_EXTEND);
4171  cpl_propertylist_delete(pro_keys);
4172 
4173 
4174  return cpl_error_get_code();
4175 }
4176 
4177 /*---------------------------------------------------------------------------*/
4185 /*---------------------------------------------------------------------------*/
4186 static cpl_error_code
4187 detmon_lg_save_imagelist_with_pro_keys(cpl_imagelist* imagelist,
4188  const char* name_o,
4189  cpl_propertylist* xheader)
4190 {
4191 
4192  cpl_propertylist* pro_keys=NULL;
4193  pro_keys=detmon_load_pro_keys(name_o);
4194  cpl_propertylist_append(xheader,pro_keys);
4195 
4196  cpl_imagelist_save(imagelist,name_o, CPL_BPP_IEEE_FLOAT,
4197  xheader,CPL_IO_EXTEND);
4198 
4199  cpl_propertylist_delete(pro_keys);
4200 
4201 
4202  return cpl_error_get_code();
4203 }
4204 
4205 /*---------------------------------------------------------------------------*/
4222 static cpl_error_code
4223 detmon_lg_save_plane(const cpl_parameterlist * parlist,
4224  cpl_frameset* frameset,
4225  const cpl_frameset * usedframes,
4226  int whichext,
4227  const char* recipe_name,
4228  cpl_propertylist* mypro_coeffscube,
4229  cpl_propertylist* linc_plane_qclist,
4230  const char* package,
4231  const char* NAME_O,
4232  cpl_image* plane)
4233 {
4234  if(detmon_lg_config.exts == 0) {
4235  cpl_propertylist* plist=NULL;
4236  cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4237  NULL, NULL,
4238  CPL_BPP_IEEE_FLOAT, recipe_name,
4239  mypro_coeffscube, NULL,
4240  package, NAME_O);
4241  plist=cpl_propertylist_load(NAME_O,0);
4242  cpl_image_save(plane,NAME_O, CPL_BPP_IEEE_FLOAT,
4243  plist,CPL_IO_DEFAULT);
4244  cpl_propertylist_delete(plist);
4245 
4246  } else if(detmon_lg_config.exts > 0) {
4247  cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4248  NULL, NULL,
4249  CPL_BPP_IEEE_FLOAT, recipe_name,
4250  mypro_coeffscube, NULL,
4251  package, NAME_O);
4252 
4253  detmon_lg_save_image_with_pro_keys(plane,NAME_O,linc_plane_qclist);
4254  } else {
4255  if(whichext == 1)
4256  {
4257  cpl_dfs_save_image(frameset, NULL, parlist,
4258  usedframes,NULL, NULL,
4259  CPL_BPP_IEEE_FLOAT, recipe_name,
4260  mypro_coeffscube, NULL,
4261  package, NAME_O);
4262  detmon_lg_save_image_with_pro_keys(plane,NAME_O,linc_plane_qclist);
4263  } else {
4264 
4265  detmon_lg_save_image_with_pro_keys(plane,NAME_O,linc_plane_qclist);
4266 
4267  }
4268 
4269  }
4270 
4271  return cpl_error_get_code();
4272 }
4273 
4274 
4275 
4276 /*---------------------------------------------------------------------------*/
4294 static cpl_error_code
4295 detmon_lg_save_cube(const cpl_parameterlist * parlist,
4296  cpl_frameset* frameset,
4297  const cpl_frameset * usedframes,
4298  int whichext,
4299  const char* recipe_name,
4300  cpl_propertylist* mypro_coeffscube,
4301  cpl_propertylist* linc_qclist,
4302  const char* package,
4303  const char* NAME_O,
4304  cpl_imagelist* coeffs)
4305 {
4306 
4307  if(detmon_lg_config.exts == 0) {
4308  cpl_propertylist_append(mypro_coeffscube, linc_qclist);
4309  detmon_lg_dfs_save_imagelist
4310  (frameset, parlist, usedframes, coeffs,
4311  recipe_name, mypro_coeffscube, package,
4312  NAME_O);
4313  } else if(detmon_lg_config.exts > 0) {
4314  cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4315  NULL, NULL,
4316  CPL_BPP_IEEE_FLOAT, recipe_name,
4317  mypro_coeffscube, NULL,
4318  package, NAME_O);
4319 
4320  detmon_lg_save_imagelist_with_pro_keys(coeffs,NAME_O,linc_qclist);
4321 
4322  } else {
4323  if(whichext == 1) {
4324  cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4325  NULL, NULL,
4326  CPL_BPP_IEEE_FLOAT, recipe_name,
4327  mypro_coeffscube, NULL,
4328  package, NAME_O);
4329  if (coeffs)
4330  detmon_lg_save_imagelist_with_pro_keys(coeffs,NAME_O,linc_qclist);
4331  else
4332  cpl_propertylist_save(linc_qclist, NAME_O, CPL_IO_EXTEND);
4333  } else {
4334  if (coeffs)
4335  detmon_lg_save_imagelist_with_pro_keys(coeffs,NAME_O,linc_qclist);
4336  else
4337  cpl_propertylist_save(linc_qclist, NAME_O, CPL_IO_EXTEND);
4338  }
4339  }
4340 
4341  return cpl_error_get_code();
4342 }
4343 
4344 static char*
4345 detmon_lg_set_paf_name_and_header(cpl_frame* ref_frame,
4346  int flag_sets,int which_set,
4347  int whichext,
4348  const char* paf_suf,
4349  cpl_propertylist** plist)
4350 {
4351  char * paf_name=NULL;
4352 
4353  if(detmon_lg_config.exts >= 0)
4354  {
4355  *plist =cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4356  detmon_lg_config.exts);
4357 
4358  if(!flag_sets)
4359  {
4360  paf_name=cpl_sprintf("%s_%s.paf", detmon_lg_config.pafname,paf_suf);
4361  }
4362  else
4363  {
4364  paf_name=cpl_sprintf("%s_%s_set%02d.paf",
4365  detmon_lg_config.pafname, paf_suf,which_set);
4366  }
4367  }
4368  else
4369  {
4370  *plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4371  whichext);
4372 
4373 
4374  if(!flag_sets)
4375  {
4376  paf_name=cpl_sprintf("%s_%s_ext%02d.paf",
4377  detmon_lg_config.pafname, paf_suf,whichext);
4378  }
4379  else
4380  {
4381  paf_name=cpl_sprintf("%s_%s_set%02d_ext%02d.paf",
4382  detmon_lg_config.pafname,paf_suf,
4383  which_set, whichext);
4384  }
4385  }
4386 
4387  return paf_name;
4388 }
4389 
4390 
4391 static char*
4392 detmon_lg_set_paf_name_and_header_ext(cpl_frame* ref_frame,
4393  int flag_sets,int which_set,
4394  int whichext,
4395  const char* paf_suf,
4396  cpl_propertylist** plist)
4397 {
4398  char* paf_name=NULL;
4399 
4400  if(detmon_lg_config.exts >= 0)
4401  {
4402  *plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4403  detmon_lg_config.exts);
4404 
4405  if(!flag_sets)
4406  {
4407  paf_name=cpl_sprintf("%s_%s.paf", detmon_lg_config.pafname,paf_suf);
4408  } else
4409  {
4410  paf_name=cpl_sprintf("%s_%s_set%02d.paf",
4411  detmon_lg_config.pafname, paf_suf,which_set);
4412  }
4413  } else
4414  {
4415  *plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4416  whichext);
4417  if(!flag_sets)
4418  {
4419  paf_name=cpl_sprintf("%s_%s_ext%02d.paf",
4420  detmon_lg_config.pafname, paf_suf,whichext);
4421  } else
4422  {
4423  paf_name=cpl_sprintf("%s_%s_set%02d_ext%02d.paf",
4424  detmon_lg_config.pafname,paf_suf,
4425  which_set, whichext);
4426  }
4427  }
4428  return paf_name;
4429 
4430 }
4431 
4432 static cpl_error_code
4433 detmon_lg_save_paf_product(cpl_frame* ref_frame,int flag_sets,
4434  int which_set,int whichext,
4435  const char* pafregexp,
4436  const char* procatg,
4437  const char* pipeline_name,
4438  const char* recipe_name,
4439  const char* paf_suf,
4440  cpl_propertylist* qclist,
4441  const int ext)
4442 
4443 {
4444  /* Set the file name for the linearity table PAF */
4445  char* paf_name=NULL;
4446  cpl_propertylist* plist=NULL;
4447  cpl_propertylist* paflist = NULL;
4448  cpl_propertylist* mainplist=NULL;
4449 
4450  mainplist =cpl_propertylist_load(cpl_frame_get_filename(ref_frame),0);
4451  if(ext==0) {
4452  paf_name=detmon_lg_set_paf_name_and_header(ref_frame,flag_sets,
4453  which_set,whichext,
4454  paf_suf,&plist);
4455  } else {
4456  paf_name=detmon_lg_set_paf_name_and_header_ext(ref_frame,flag_sets,
4457  which_set,whichext,
4458  paf_suf,&plist);
4459  }
4460 
4461 
4462  paflist = cpl_propertylist_new();
4463  cpl_propertylist_append_string(paflist, CPL_DFS_PRO_CATG,procatg);
4464 
4465  /* Get the keywords for the paf file */
4466  cpl_propertylist_copy_property_regexp(paflist, plist,pafregexp, 0);
4467  cpl_propertylist_copy_property_regexp(paflist, mainplist,pafregexp, 0);
4468  cpl_propertylist_append(paflist,qclist);
4469 
4470  /* Save the PAF */
4471  cpl_dfs_save_paf(pipeline_name, recipe_name,paflist,paf_name);
4472 
4473  /* free memory */
4474  cpl_propertylist_delete(mainplist);
4475  cpl_propertylist_delete(paflist);
4476  cpl_propertylist_delete(plist);
4477  cpl_free(paf_name);
4478 
4479  return cpl_error_get_code();
4480 
4481 }
4482 
4483 
4484 // FIXME - Update this docstring to match current arguments
4485 /*---------------------------------------------------------------------------*/
4516 static cpl_error_code
4517 detmon_lg_save(const cpl_parameterlist * parlist,
4518  cpl_frameset * frameset,
4519  const char *recipe_name,
4520  const char *pipeline_name,
4521  const char *pafregexp,
4522  const cpl_propertylist * pro_lintbl,
4523  const cpl_propertylist * pro_gaintbl,
4524  const cpl_propertylist * pro_coeffscube,
4525  const cpl_propertylist * pro_bpm,
4526  const cpl_propertylist * pro_corr,
4527  const cpl_propertylist * pro_diff,
4528  const char *package,
4529  cpl_imagelist * coeffs,
4530  cpl_table * gain_table,
4531  cpl_table * linear_table,
4532  cpl_image * bpms,
4533  cpl_imagelist * autocorr_images,
4534  cpl_imagelist * diff_flats,
4535  cpl_propertylist * gaint_qclist,
4536  cpl_propertylist * lint_qclist,
4537  cpl_propertylist * linc_qclist,
4538  cpl_propertylist * bpm_qclist,
4539  const int flag_sets,
4540  const int which_set,
4541  const cpl_frameset * usedframes,
4542  int whichext)
4543 {
4544 
4545  cpl_frame *ref_frame;
4546  cpl_propertylist *plist = NULL;
4547  cpl_propertylist *mainplist = NULL;
4548  char* NAME_O=NULL;
4549  char* PREF_O=NULL;
4550  int nb_images;
4551  int i;
4552 
4553  cpl_propertylist * xplist = NULL;
4554 
4555  cpl_propertylist* linc_plane_qclist=NULL;
4556  cpl_image* plane=NULL;
4557  int ip=0;
4558  char* pcatg_plane=NULL;
4559 
4560  cpl_propertylist * mypro_lintbl =
4561  cpl_propertylist_duplicate(pro_lintbl);
4562  cpl_propertylist * mypro_gaintbl =
4563  cpl_propertylist_duplicate(pro_gaintbl);
4564  cpl_propertylist * mypro_coeffscube =
4565  cpl_propertylist_duplicate(pro_coeffscube);
4566  cpl_propertylist * mypro_bpm =
4567  cpl_propertylist_duplicate(pro_bpm);
4568  cpl_propertylist * mypro_corr =
4569  cpl_propertylist_duplicate(pro_corr);
4570  cpl_propertylist * mypro_diff =
4571  cpl_propertylist_duplicate(pro_diff);
4572 
4573  const char * procatg_lintbl =
4574  cpl_propertylist_get_string(mypro_lintbl, CPL_DFS_PRO_CATG);
4575 
4576  const char * procatg_gaintbl =
4577  cpl_propertylist_get_string(mypro_gaintbl, CPL_DFS_PRO_CATG);
4578 
4579  const char * procatg_coeffscube =
4580  cpl_propertylist_get_string(mypro_coeffscube, CPL_DFS_PRO_CATG);
4581  const char * procatg_bpm =
4582  cpl_propertylist_get_string(mypro_bpm, CPL_DFS_PRO_CATG);
4583 
4584 
4585  /* Extract extension headers if multi-extension */
4586  detmon_lg_extract_extention_header(frameset,gaint_qclist,lint_qclist,
4587  linc_qclist,bpm_qclist,whichext);
4588 
4589  /* This is only used later for PAF and temporarily for COEFFS_CUBE
4590  (see if defined)*/
4591  /* Get FITS header from reference file */
4592  ref_frame = cpl_frameset_get_position(frameset, 0);
4593 
4594  skip_if((mainplist =
4595  cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4596  0)) == NULL);
4597 
4598  /*******************************/
4599  /* Write the LINEARITY TABLE */
4600  /*******************************/
4601  cpl_msg_info(cpl_func,"Write the LINEARITY TABLE");
4602  /* Set the file name for the table */
4603  if(!flag_sets) {
4604  NAME_O=cpl_sprintf("%s_linearity_table.fits", recipe_name);
4605  } else {
4606  NAME_O=cpl_sprintf("%s_linearity_table_set%02d.fits", recipe_name,
4607  which_set);
4608  }
4609 
4610  if (detmon_lg_config.exts >= 0) {
4611  /* Save the table */
4612  cpl_propertylist_append(mypro_lintbl, lint_qclist);
4613  skip_if(cpl_dfs_save_table(frameset, NULL,parlist, usedframes, NULL,
4614  linear_table,NULL, recipe_name,
4615  mypro_lintbl, NULL, package, NAME_O));
4616 
4617  detmon_lg_save_table_with_pro_keys(linear_table,NAME_O,
4618  lint_qclist,CPL_IO_DEFAULT);
4619 
4620  } else {
4621  if(whichext == 1) {
4622  /* Save the 1. extension table */
4623  skip_if(cpl_dfs_save_table(frameset,NULL, parlist, usedframes, NULL,
4624  linear_table,lint_qclist, recipe_name,
4625  mypro_lintbl,NULL, package, NAME_O));
4626  detmon_lg_save_table_with_pro_keys(linear_table,NAME_O,
4627  lint_qclist,CPL_IO_DEFAULT);
4628 
4629 
4630 
4631 
4632  } else {
4633 
4634  detmon_lg_save_table_with_pro_keys(linear_table,NAME_O,
4635  lint_qclist,CPL_IO_EXTEND);
4636  }
4637  }
4638  irplib_free(&NAME_O);
4639  /**************************/
4640  /* Write the GAIN TABLE */
4641  /**************************/
4642  cpl_msg_info(cpl_func,"Write the GAIN TABLE");
4643  /* Set the file name for the table */
4644  if(!flag_sets) {
4645  NAME_O=cpl_sprintf("%s_gain_table.fits", recipe_name);
4646  } else {
4647  NAME_O=cpl_sprintf("%s_gain_table_set%02d.fits", recipe_name,
4648  which_set);
4649  }
4650 
4651  if (detmon_lg_config.exts >= 0)
4652  {
4653  /* Save the table */
4654 
4655  cpl_propertylist_append(mypro_gaintbl, gaint_qclist);
4656  skip_if(cpl_dfs_save_table(frameset, NULL, parlist, usedframes, NULL,
4657  gain_table,NULL, recipe_name, mypro_gaintbl,
4658  NULL, package, NAME_O));
4659  detmon_lg_save_table_with_pro_keys(gain_table,NAME_O,
4660  gaint_qclist,CPL_IO_DEFAULT);
4661 
4662  }
4663  else
4664  {
4665  if(whichext == 1)
4666  {
4667  /* Save the 1. extension table */
4668  skip_if(cpl_dfs_save_table(frameset, NULL, parlist, usedframes, NULL, gain_table,
4669  gaint_qclist, recipe_name, mypro_gaintbl,
4670  NULL, package, NAME_O));
4671  detmon_lg_save_table_with_pro_keys(gain_table,NAME_O,
4672  gaint_qclist,CPL_IO_DEFAULT);
4673 
4674  }
4675  else
4676  {
4677 
4678  detmon_lg_save_table_with_pro_keys(gain_table,NAME_O,
4679  gaint_qclist,CPL_IO_EXTEND);
4680  }
4681  }
4682 
4683  if(detmon_lg_config.pix2pix)
4684  {
4685 
4686  /***************************/
4687  /* Write the COEFFS FITS */
4688  /***************************/
4689  cpl_msg_info(cpl_func,"Write the COEFFS FITS");
4690  irplib_free(&NAME_O);
4691  if(!flag_sets)
4692  {
4693  PREF_O=cpl_sprintf("%s_coeffs_cube", recipe_name);
4694  } else
4695  {
4696  PREF_O=cpl_sprintf("%s_coeffs_cube_set%02d",
4697  recipe_name, which_set);
4698  }
4699  if (detmon_lg_config.split_coeffs == 0) {
4700  NAME_O=cpl_sprintf("%s.fits", PREF_O);
4701  }
4702 
4703 
4704  /* Save the imagelist */
4705  if(detmon_lg_config.split_coeffs != 0){
4706 
4707 
4708  nb_images = cpl_imagelist_get_size(coeffs);
4709  for(ip=0;ip<nb_images;ip++) {
4710  NAME_O=cpl_sprintf("%s_P%d.fits", PREF_O,ip);
4711  pcatg_plane=cpl_sprintf("COEFFS_CUBE_P%d",ip);
4712  cpl_propertylist_delete(mypro_coeffscube);
4713  mypro_coeffscube=cpl_propertylist_duplicate(pro_coeffscube);
4714  cpl_propertylist_set_string(mypro_coeffscube,CPL_DFS_PRO_CATG,
4715  pcatg_plane);
4716  linc_plane_qclist=detmon_lg_extract_qclist_4plane(linc_qclist,ip);
4717  cpl_propertylist_append(mypro_coeffscube, linc_plane_qclist);
4718  plane=cpl_imagelist_get(coeffs,ip);
4719  detmon_lg_save_plane(parlist,frameset,usedframes,whichext,
4720  recipe_name,mypro_coeffscube,
4721  linc_plane_qclist,package,NAME_O,plane);
4722 
4723  if(NULL!=linc_plane_qclist) {
4724  cpl_propertylist_delete(linc_plane_qclist);
4725  }
4726  irplib_free(&NAME_O);
4727 
4728  } /* end for loop over cube planes */
4729  } else {
4730 
4731  detmon_lg_save_cube(parlist,frameset,usedframes,whichext,
4732  recipe_name,mypro_coeffscube,
4733  linc_qclist,package,NAME_O,coeffs);
4734  }
4735 
4736  /*******************************/
4737  /* Write the BAD PIXEL MAP */
4738  /*******************************/
4739  cpl_msg_info(cpl_func,"Write the BAD PIXEL MAP");
4740  irplib_free(&NAME_O);
4741  /* Set the file name for the bpm */
4742  if(!flag_sets)
4743  {
4744  NAME_O=cpl_sprintf("%s_bpm.fits", recipe_name);
4745  } else
4746  {
4747  NAME_O=cpl_sprintf("%s_bpm_set%02d.fits", recipe_name, which_set);
4748  }
4749 
4750 
4751  /* Save the image */
4752  if(detmon_lg_config.exts == 0) {
4753  cpl_propertylist_append(mypro_bpm, bpm_qclist);
4754  cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL, bpms,
4755  CPL_BPP_IEEE_FLOAT, recipe_name,
4756  mypro_bpm, NULL, package,
4757  NAME_O);
4758  }
4759  else if(detmon_lg_config.exts > 0)
4760  {
4761  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,NULL, NULL,
4762  CPL_BPP_IEEE_FLOAT, recipe_name,
4763  mypro_bpm, NULL, package,
4764  NAME_O));
4765  detmon_lg_save_image_with_pro_keys(bpms,NAME_O,bpm_qclist);
4766 
4767  } else
4768  {
4769  if (whichext == 1)
4770  {
4771  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,NULL, NULL,
4772  CPL_BPP_IEEE_FLOAT, recipe_name,
4773  mypro_bpm, NULL, package,
4774  NAME_O));
4775  detmon_lg_save_image_with_pro_keys(bpms,NAME_O,bpm_qclist);
4776  } else
4777  {
4778  detmon_lg_save_image_with_pro_keys(bpms,NAME_O,bpm_qclist);
4779  }
4780  }
4781  } /* End of if(pix2pix) */
4782 
4783  if(detmon_lg_config.intermediate)
4784  {
4785  /******************************/
4786  /* Write the AUTOCORRS FITS */
4787  /******************************/
4788  cpl_msg_info(cpl_func,"Write the AUTOCORRS FITS");
4789  nb_images = cpl_imagelist_get_size(autocorr_images);
4790  cpl_ensure_code(nb_images > 0, CPL_ERROR_DATA_NOT_FOUND);
4791  for(i = 0; i < nb_images; i++)
4792  {
4793  cpl_propertylist* pplist = cpl_propertylist_duplicate(mypro_corr);
4794  int inull = 0;
4795  cpl_array* pnames = cpl_table_get_column_names(linear_table);
4796  double ddit = 0;
4797  if(i < cpl_table_get_nrow(linear_table))
4798  {
4799  ddit = cpl_table_get_double(linear_table,
4800  cpl_array_get_data_string_const(pnames)[0], i, &inull);
4801  }
4802  cpl_array_delete(pnames);
4803  /*cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);*/
4804  /* Set the file name for each image */
4805  irplib_free(&NAME_O);
4806  if(!flag_sets)
4807  {
4808  NAME_O=cpl_sprintf("%s_autocorr_%d.fits", recipe_name, i);
4809  assert(NAME_O != NULL);
4810  } else
4811  {
4812  NAME_O=cpl_sprintf("%s_autocorr_%02d_set%02d.fits",
4813  recipe_name, i, which_set);
4814  assert(NAME_O != NULL);
4815  }
4816  /* Save the image */
4817  if(detmon_lg_config.exts > 0)
4818  {
4819  cpl_propertylist* pextlist = cpl_propertylist_new();
4820  cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4821  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4822  NULL,NULL,CPL_BPP_IEEE_FLOAT,
4823  recipe_name, pplist, NULL,
4824  package, NAME_O));
4825 
4826  detmon_lg_save_image_with_pro_keys(
4827  cpl_imagelist_get(autocorr_images, i),NAME_O,pextlist);
4828 
4829  cpl_propertylist_delete(pextlist);
4830  } else
4831  if(detmon_lg_config.exts == 0)
4832  {
4833  cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);
4834  cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL,
4835  cpl_imagelist_get(autocorr_images, i),
4836  CPL_BPP_IEEE_FLOAT,
4837  recipe_name, pplist, NULL, package,
4838  NAME_O);
4839 
4840  }
4841  else
4842  {
4843  cpl_propertylist* pextlist = cpl_propertylist_new();
4844  cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4845  if(whichext == 1)
4846  {
4847  skip_if(cpl_dfs_save_image(frameset, NULL, parlist,
4848  usedframes, NULL,NULL,
4849  CPL_BPP_IEEE_FLOAT, recipe_name,
4850  pplist, NULL,
4851  package, NAME_O));
4852 
4853  detmon_lg_save_image_with_pro_keys(
4854  cpl_imagelist_get(autocorr_images, i),NAME_O,pextlist);
4855 
4856  } else
4857  {
4858 
4859  detmon_lg_save_image_with_pro_keys(
4860  cpl_imagelist_get(autocorr_images, i),NAME_O,pextlist);
4861  }
4862  cpl_propertylist_delete(pextlist);
4863  }
4864  cpl_propertylist_delete (pplist);
4865  }
4866  irplib_free(&NAME_O);
4867 
4868 
4869  /*
4870  cpl_msg_info(cpl_func, "-----before Write the DIFFS FITS %d", __LINE__);
4871  */
4872  /***************************/
4873  /* Write the DIFFS FITS */
4874  /***************************/
4875  cpl_msg_info(cpl_func,"Write the DIFFS FITS");
4876 
4877  for(i = 0; i < nb_images; i++)
4878  {
4879  cpl_propertylist* pplist = cpl_propertylist_duplicate(mypro_diff);
4880  int inull = 0;
4881  cpl_array* pnames = cpl_table_get_column_names(linear_table);
4882  double ddit = 0;
4883  if(i < cpl_table_get_nrow(linear_table))
4884  {
4885  ddit = cpl_table_get_double(linear_table,
4886  cpl_array_get_data_string_const(pnames)[0], i, &inull);
4887  }
4888  cpl_array_delete(pnames);
4889  /*cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);*/
4890  /* Set the file name for each image */
4891  if(!flag_sets)
4892  {
4893  NAME_O=cpl_sprintf("%s_diff_flat_%d.fits", recipe_name, i);
4894  } else
4895  {
4896  NAME_O=cpl_sprintf("%s_diff_flat_%d_set%02d.fits",
4897  recipe_name, i, which_set);
4898  }
4899  /* Save the image */
4900  if(detmon_lg_config.exts > 0)
4901  {
4902  cpl_propertylist* pextlist = cpl_propertylist_new();
4903  cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4904  cpl_propertylist_append_double(mypro_diff, "ESO DET DIT", ddit);
4905  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4906  NULL,NULL,CPL_BPP_IEEE_FLOAT,
4907  recipe_name,
4908  mypro_diff, NULL,package, NAME_O));
4909 
4910  detmon_lg_save_image_with_pro_keys(
4911  cpl_imagelist_get(diff_flats, i),NAME_O,pextlist);
4912 
4913  cpl_propertylist_delete(pextlist);
4914  }
4915  else if(detmon_lg_config.exts == 0)
4916  {
4917  cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);
4918  cpl_dfs_save_image
4919  (frameset, NULL, parlist, usedframes, NULL,
4920  cpl_imagelist_get(diff_flats, i), CPL_BPP_IEEE_FLOAT,
4921  recipe_name, pplist, NULL, package,
4922  NAME_O);
4923 
4924  } else
4925  {
4926  cpl_propertylist* pextlist = cpl_propertylist_new();
4927  cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4928  if(whichext == 1)
4929  {
4930  cpl_propertylist_append_double(mypro_diff,"ESO DET DIT",ddit);
4931  // cpl_propertylist_erase(mypro_diff, "ESO DET DIT");
4932  skip_if(cpl_dfs_save_image(frameset, NULL, parlist,
4933  usedframes, NULL,NULL,
4934  CPL_BPP_IEEE_FLOAT, recipe_name,
4935  mypro_diff, NULL,package, NAME_O));
4936 
4937  detmon_lg_save_image_with_pro_keys(
4938  cpl_imagelist_get(diff_flats, i),NAME_O,pextlist);
4939 
4940  } else
4941  {
4942 
4943  detmon_lg_save_image_with_pro_keys(
4944  cpl_imagelist_get(diff_flats, i),NAME_O,pextlist);
4945 
4946  }
4947  cpl_propertylist_delete(pextlist);
4948  }
4949  cpl_propertylist_delete(pplist);
4950  irplib_free(&NAME_O);
4951  }
4952  } /* End of if(intermediate) */
4953 
4954 
4955  /*******************************/
4956  /* Write the PAF file(s) */
4957  /*******************************/
4958  cpl_msg_info(cpl_func,"Write the PAF file(s)");
4959 
4960  if(detmon_lg_config.pafgen) {
4961 
4962  detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,whichext,
4963  pafregexp,procatg_gaintbl,
4964  pipeline_name,recipe_name,
4965  "qc01",gaint_qclist,0);
4966 
4967  detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,whichext,
4968  pafregexp,procatg_lintbl,
4969  pipeline_name,recipe_name,
4970  "qc02",lint_qclist,0);
4971 
4972  if(detmon_lg_config.pix2pix)
4973  {
4974 
4975  detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,
4976  whichext,pafregexp,
4977  procatg_coeffscube,
4978  pipeline_name,recipe_name,
4979  "qc03",linc_qclist,1);
4980 
4981  detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,
4982  whichext,pafregexp,procatg_bpm,
4983  pipeline_name,recipe_name,
4984  "qc04",bpm_qclist,1);
4985  }
4986  }
4987 
4988  end_skip;
4989  cpl_msg_info(cpl_func,"exit");
4990 
4991  cpl_propertylist_delete(xplist);
4992  if(plist!=NULL) {
4993  cpl_propertylist_delete(plist);
4994  plist=NULL;
4995  }
4996 
4997  irplib_free(&NAME_O);
4998  cpl_free(PREF_O);
4999  cpl_free(pcatg_plane);
5000  cpl_propertylist_delete(mainplist);
5001  cpl_propertylist_delete(mypro_lintbl);
5002  cpl_propertylist_delete(mypro_gaintbl);
5003  cpl_propertylist_delete(mypro_coeffscube);
5004  cpl_propertylist_delete(mypro_bpm);
5005  cpl_propertylist_delete(mypro_corr);
5006  cpl_propertylist_delete(mypro_diff);
5007 
5008  return cpl_error_get_code();
5009 }
5010 
5011 
5012 /*---------------------------------------------------------------------------*/
5020 /*---------------------------------------------------------------------------*/
5021 static cpl_error_code
5022 detmon_opt_contamination(const cpl_imagelist * ons,
5023  const cpl_imagelist * offs,
5024  unsigned mode,
5025  cpl_propertylist * qclist)
5026 {
5027  struct rect {
5028  size_t llx;
5029  size_t lly;
5030  size_t urx;
5031  size_t ury;
5032  };
5033  struct rect rects[5] = {
5034  (struct rect){ detmon_lg_config.llx1,
5035  detmon_lg_config.lly1,
5036  detmon_lg_config.urx1,
5037  detmon_lg_config.ury1},
5038  (struct rect){ detmon_lg_config.llx2,
5039  detmon_lg_config.lly2,
5040  detmon_lg_config.urx2,
5041  detmon_lg_config.ury2},
5042  (struct rect){ detmon_lg_config.llx3,
5043  detmon_lg_config.lly3,
5044  detmon_lg_config.urx3,
5045  detmon_lg_config.ury3},
5046  (struct rect){ detmon_lg_config.llx4,
5047  detmon_lg_config.lly4,
5048  detmon_lg_config.urx4,
5049  detmon_lg_config.ury4},
5050  (struct rect){ detmon_lg_config.llx5,
5051  detmon_lg_config.lly5,
5052  detmon_lg_config.urx5,
5053  detmon_lg_config.ury5},
5054  };
5055 
5056  for (size_t i = 0; i < 5; i++) {
5057  cpl_image * dif_avg;
5058  const cpl_image * off2;
5059  double median;
5060  char kname[300];
5061  if (cpl_imagelist_get_size(offs) == 1 || mode & IRPLIB_LIN_COLLAPSE)
5062  off2 = cpl_imagelist_get_const(offs, 0);
5063  else
5064  off2 = cpl_imagelist_get_const(offs, 1);
5065 
5066  dif_avg = detmon_subtracted_avg(cpl_imagelist_get_const(ons, 0),
5067  cpl_imagelist_get_const(offs, 0),
5068  cpl_imagelist_get_const(ons, 1),
5069  off2,
5070  rects[i].llx,
5071  rects[i].lly,
5072  rects[i].urx,
5073  rects[i].ury);
5074 
5075  median = cpl_image_get_median(dif_avg);
5076  cpl_image_delete(dif_avg);
5077 
5078  skip_if(0);
5079  sprintf(kname, DETMON_QC_CONTAM "%zd", i + 1);
5080 
5081  if(cpl_propertylist_has(qclist,kname)){
5082  skip_if(cpl_propertylist_update_double(qclist,kname,median));
5083  } else {
5084  skip_if(cpl_propertylist_append_double(qclist,kname,median));
5085  skip_if(cpl_propertylist_set_comment(qclist,kname,DETMON_QC_CONTAM_C));
5086  }
5087  }
5088 
5089  end_skip;
5090 
5091  return cpl_error_get_code();
5092 }
5093 
5094 /*---------------------------------------------------------------------------*/
5101 /*---------------------------------------------------------------------------*/
5102 /*
5103 static cpl_error_code
5104 detmon_opt_lampcr(cpl_frameset * cur_fset, int ext)
5105 {
5106  cpl_image * on = NULL;
5107  cpl_image * off = NULL;
5108  cpl_frame * first_off = NULL;
5109  cpl_frame * first_on = NULL;
5110  cpl_propertylist * plist = NULL;
5111  double dit;
5112 
5113  cpl_ensure_code(cur_fset != NULL, CPL_ERROR_NULL_INPUT);
5114 
5115  skip_if((first_off = cpl_frameset_get_position(cur_fset, 0)) == NULL);
5116  skip_if((first_on = cpl_frameset_get_position(cur_fset, 1)) == NULL);
5117 
5118  on = cpl_image_load(cpl_frame_get_filename(first_on),
5119  CPL_TYPE_FLOAT, 0, ext);
5120  off = cpl_image_load(cpl_frame_get_filename(first_off),
5121  CPL_TYPE_FLOAT, 0, ext);
5122  skip_if(cpl_image_subtract(on, off));
5123 
5124  plist = cpl_propertylist_load(cpl_frame_get_filename(first_on), 0);
5125  skip_if(plist == NULL);
5126 
5127  dit = detmon_pfits_get_dit_opt(plist);
5128 
5129  detmon_lg_config.cr = cpl_image_get_mean(on) / dit;
5130 
5131  end_skip;
5132 
5133  cpl_image_delete(on);
5134  cpl_image_delete(off);
5135  cpl_propertylist_delete(plist);
5136 
5137  return cpl_error_get_code();
5138 }
5139 */
5140 /*---------------------------------------------------------------------------*/
5148 /*---------------------------------------------------------------------------*/
5149 int
5150 detmon_lg_dfs_set_groups(cpl_frameset * set,
5151  const char *tag_on, const char *tag_off)
5152 {
5153 
5154 
5155 
5156 
5157 
5158  /* Check entries */
5159  if(set == NULL)
5160  return -1;
5161 
5162  /* Initialize */
5163  int nframes = cpl_frameset_get_size(set);
5164 
5165  /* Loop on frames */
5166  for(int i = 0; i < nframes; i++) {
5167  cpl_frame* cur_frame = cpl_frameset_get_position(set, i);
5168  const char* tag = cpl_frame_get_tag(cur_frame);
5169 
5170  /* RAW frames */
5171  if(!strcmp(tag, tag_on) || !strcmp(tag, tag_off))
5172  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_RAW);
5173  /* CALIB frames */
5174 
5175  /* else if (!strcmp(tag, IIINSTRUMENT_CALIB_FLAT))
5176  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_CALIB);
5177  */
5178  }
5179  return 0;
5180 }
5181 
5182 
5183 /*---------------------------------------------------------------------------*/
5191 /*---------------------------------------------------------------------------*/
5192 static cpl_error_code
5193 detmon_lg_fits_coeffs_and_bpm2chip(cpl_imagelist ** coeffs_ptr,
5194  cpl_image **bpms_ptr)
5195 {
5196 
5197 
5198 
5199 
5200 
5201 
5202 
5203 
5204 
5205  int shift_idx=0;
5206 
5207 
5208 
5209 
5210  cpl_image* dummy_bpm = cpl_image_new(detmon_lg_config.nx,
5211  detmon_lg_config.ny,
5212  CPL_TYPE_INT);
5213  cpl_imagelist* dummy_coeffs = cpl_imagelist_new();
5214 
5215  int* db_p = cpl_image_get_data_int(dummy_bpm);
5216  int* rb_p = cpl_image_get_data_int(*bpms_ptr);;
5217  float** dcs_p = cpl_malloc(sizeof(float *) * (detmon_lg_config.order + 1));
5218  float** rcs_p = cpl_malloc(sizeof(float *) * (detmon_lg_config.order + 1));
5219  int dlength = detmon_lg_config.nx;
5220 
5221  int rlength = detmon_lg_config.urx - detmon_lg_config.llx + 1;
5222  for (int i = 0; i <= detmon_lg_config.order; i++)
5223  {
5224  cpl_image* dummy_coeff = cpl_image_new(detmon_lg_config.nx,
5225  detmon_lg_config.ny,
5226  CPL_TYPE_FLOAT);
5227 
5228  cpl_imagelist_set(dummy_coeffs, dummy_coeff, i);
5229  dcs_p[i] = cpl_image_get_data_float(dummy_coeff);
5230  rcs_p[i] = cpl_image_get_data_float(cpl_imagelist_get(*coeffs_ptr, i));
5231  }
5232  /*copy the coefficients from temporary image to the dummy_bpm*/
5233  for (int i = detmon_lg_config.lly - 1; i < detmon_lg_config.ury; i++)
5234  {
5235  for (int j = detmon_lg_config.llx - 1; j < detmon_lg_config.urx; j++)
5236  {
5237  shift_idx=(i - detmon_lg_config.lly + 1) * rlength +
5238  j - detmon_lg_config.llx + 1;
5239  *(db_p + i * dlength + j) = *(rb_p + shift_idx);
5240  for (int k = 0; k <= detmon_lg_config.order; k++)
5241  {
5242  *(dcs_p[k] + i * dlength + j) =
5243  *(rcs_p[k] + (i - detmon_lg_config.lly + 1) * rlength +
5244  j - detmon_lg_config.llx + 1);
5245  }
5246  }
5247  }
5248  cpl_imagelist_delete(*coeffs_ptr);
5249  cpl_image_delete(*bpms_ptr);
5250  *coeffs_ptr = dummy_coeffs;
5251  *bpms_ptr = dummy_bpm;
5252  cpl_free(dcs_p);
5253  cpl_free(rcs_p);
5254 
5255  return cpl_error_get_code();
5256 }
5257 
5258 /* Not used so we temporaryly comment it out
5259 static cpl_error_code
5260 detmon_lg_qclog_lin_coeff(cpl_imagelist* coeffs_ptr, const int order, cpl_propertylist* linc_qclist)
5261 {
5262  cpl_image* image=NULL;
5263  int i=0;
5264  double coeff=0;
5265  double * pcoeffs = cpl_malloc(sizeof(double)*(order + 1));
5266  char* name_o1=NULL;
5267  char* name_o2=NULL;
5268 
5269  for(i = 0; i <= order; i++)
5270  {
5271  image = cpl_imagelist_get(coeffs_ptr, i);
5272  coeff = cpl_image_get_median(image);
5273  pcoeffs[i] = coeff;
5274  name_o1 = cpl_sprintf("ESO QC LIN COEF%d", i);
5275  name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", i);
5276  assert(name_o1 != NULL);
5277  assert(name_o2 != NULL);
5278  cpl_propertylist_append_double(linc_qclist, name_o1, coeff);
5279  cpl_propertylist_set_comment(linc_qclist,name_o1,DETMON_QC_LIN_COEF_C);
5280  cpl_free(name_o1);
5281  name_o1= NULL;
5282  cpl_propertylist_append_double(linc_qclist, name_o2,cpl_image_get_stdev(image));
5283  cpl_propertylist_set_comment(linc_qclist,name_o2,DETMON_QC_LIN_COEF_ERR_C);
5284  cpl_free(name_o2);
5285  name_o2= NULL;
5286  }
5287  cpl_free(pcoeffs);
5288 
5289  return cpl_error_get_code();
5290 }
5291 */
5292 #ifdef DETMON_USE_DETECTOR_SHOTNOISE_MODEL
5293 /*----------------------------------------------------------------------------*/
5314 /*----------------------------------------------------------------------------*/
5315 static cpl_error_code
5316 detmon_detector_shotnoise_model(const cpl_image* ima_data, const double gain,
5317  const double ron, cpl_image ** ima_errs)
5318 {
5319  cpl_ensure_code(ima_data, CPL_ERROR_NULL_INPUT);
5320  cpl_ensure_code(ima_errs, CPL_ERROR_NULL_INPUT);
5321  cpl_ensure_code(gain > 0., CPL_ERROR_ILLEGAL_INPUT);
5322  cpl_ensure_code(ron > 0., CPL_ERROR_ILLEGAL_INPUT);
5323 
5324  *ima_errs = cpl_image_duplicate(ima_data);
5325  /* set negative values (= zero measurable electrons) to read out noise */
5326  cpl_image_threshold(*ima_errs, 0., INFINITY, ron, ron);
5327 
5328  /* err_ADU = sqrt(counts/gain + ron * ron)*/
5329 
5330  cpl_image_divide_scalar(*ima_errs, gain);
5331  cpl_image_add_scalar(*ima_errs, ron * ron);
5332  cpl_image_power(*ima_errs, 0.5);
5333 
5334  return cpl_error_get_code();
5335 }
5336 #endif
5337 
5338 static int
5339 detmon_compute_badpixmap(cpl_boolean opt_nir, const int nsets,
5340  const cpl_table* linear_table,
5341  const cpl_imagelist* linearity_inputs, int nbpixs,
5342  cpl_vector* x, cpl_propertylist* gaint_qclist,
5343  cpl_image** bpms_ptr)
5344 {
5345  /* Here determines the bad pixel map
5346  * HDRL based version
5347  * AMO: this if is repeated: the following code should be up up
5348  */
5349  if (opt_nir == NIR) {
5350  x = cpl_vector_wrap(nsets,
5351  (double *) cpl_table_get_data_double_const(linear_table,
5352  "DIT"));
5353  }
5354  else {
5355  x = cpl_vector_wrap(nsets,
5356  (double *) cpl_table_get_data_double_const(linear_table,
5357  "EXPTIME"));
5358 
5359  }
5360  int sz = cpl_imagelist_get_size(linearity_inputs);
5361  double kappa = detmon_lg_config.kappa;
5362  int niter = detmon_lg_config.niter;
5363  int llx = detmon_lg_config.llx;
5364  int urx = detmon_lg_config.urx;
5365  int lly = detmon_lg_config.lly;
5366  int ury = detmon_lg_config.ury;
5367  hdrl_parameter* p;
5368  const cpl_image *ima;
5369  cpl_image *err;
5370  // fit-chi-rel method
5371  // errors to be used with fit_chi_rel method
5372  cpl_imagelist* errors = cpl_imagelist_new();
5373  /*
5374  // case1: error proportional to sqrt(EXPTIME)
5375  for(int i=0;i<sz;i++) {
5376  err=cpl_image_new(sx,sy,CPL_TYPE_DOUBLE);
5377  cpl_image_add_scalar(err,1.);
5378  cpl_imagelist_set(errors,err,i);
5379  }
5380  */
5381  /*
5382  // case2:shot noise model to be used with fit_chi_rel method
5383  double gain=1.;
5384  double ron=1.;
5385  for(int i=0;i<sz;i++) {
5386  ima=cpl_imagelist_get(linearity_inputs,i);
5387  hdrldemo_detector_shotnoise_model(ima, gain, ron, &err);
5388  cpl_imagelist_set(errors,err,i);
5389  }
5390  */
5391  // case3: error obtained using mad error approximation
5392  double dmad;
5393  //cpl_msg_info(cpl_func,"sz=%d",sz);
5394  cpl_imagelist* linearity_scaled = cpl_imagelist_new();
5395  double gain = 0;
5396  gain = cpl_propertylist_get_double(gaint_qclist, DETMON_QC_GAIN);
5397  //cpl_msg_info(cpl_func,"ok1 gain=%g",gain);
5398  /* on simulations gain ,may be < 0: make sure it is > 0 */
5399  //cpl_msg_info(cpl_func,"ok1 gain=%g",gain);
5400  gain = (gain < 0) ? 1 : gain;
5401  double avg = 0;
5402  double rms = 0;
5403  skip_if(rms);
5404  //cpl_msg_info(cpl_func,"sz=%d",sz);
5405  //cpl_msg_info(cpl_func,"llx=%d lly=%d urx=%d ury=%d",llx,lly,urx,ury);
5406  for (int i = 0; i < sz; i++) {
5407  ima = cpl_imagelist_get_const(linearity_inputs, i);
5408  /*
5409  cpl_msg_info(cpl_func,"sx=%d sy=%d",
5410  cpl_image_get_size_x(ima),cpl_image_get_size_y(ima));
5411  */
5412  //cpl_msg_info(cpl_func,"max_x=%d max_y=%d",urx-llx+1,ury-lly+1);
5413  //median=cpl_image_get_median_window(ima,1,1,urx-llx+1,ury-lly+1);
5414  skip_if(
5415  irplib_ksigma_clip(ima, 1, 1, urx - llx + 1,
5416  ury - lly + 1, kappa, niter, 1e-5, &avg,
5417  &rms));
5418 
5419  //cpl_msg_info(cpl_func,"avg=%g median=%g",avg,median);
5420  //cpl_msg_info(cpl_func,"thresh=%g", detmon_lg_config.saturation_limit);
5421  if (avg < detmon_lg_config.saturation_limit) {
5422 
5423  //cpl_msg_info(cpl_func,">>>>i=%d", i);
5424  /*
5425  err=cpl_image_duplicate(ima);
5426  cpl_image_multiply_scalar(err, gain);
5427  cpl_image_power(err,0.5);
5428  */
5429  cpl_image_get_mad(ima, &dmad);
5430  err = cpl_image_duplicate(ima);
5431  cpl_image_multiply_scalar(err, 0);
5432  cpl_image_add_scalar(err, dmad * CPL_MATH_STD_MAD);
5433 
5434  //detmon_detector_shotnoise_model(ima, gain_eff,ron, &err);
5435  /*
5436  cpl_msg_info(cpl_func,"err sx=%d",cpl_image_get_size_x(err));
5437  cpl_msg_info(cpl_func,"err sy=%d",cpl_image_get_size_y(err));
5438  cpl_msg_info(cpl_func,"ima sx=%d",cpl_image_get_size_x(ima));
5439  cpl_msg_info(cpl_func,"ima sy=%d",cpl_image_get_size_y(ima));
5440  cpl_msg_info(cpl_func,"sy=%d",cpl_image_get_size_y(err));
5441  */
5442  cpl_imagelist_set(errors, err, i);
5443  /*
5444  sprintf(dname,"data_%d.fits",i);
5445  sprintf(ename,"errs_%d.fits",i);
5446  cpl_image_save(err, ename, CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
5447  cpl_image_save(ima, dname, CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
5448  */
5449  skip_if(
5450  cpl_imagelist_set(linearity_scaled,
5451  cpl_image_duplicate(ima), i));
5452  }
5453  }
5454  hdrl_imagelist* hil = hdrl_imagelist_create(linearity_scaled, errors);
5455  /*
5456  cpl_imagelist_save(linearity_scaled,"lin_data.fits", CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
5457  cpl_imagelist_save(errors,"lin_errs.fits", CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
5458  */
5459  cpl_imagelist_delete(errors);
5460  /* P-val method */
5461  double pval = 0.001;
5462  p = hdrl_bpm_fit_parameter_create_pval(1, pval);
5463  /*
5464  p = hdrl_bpm_fit_parameter_create_rel_coef(1, 1., 1.);
5465  hdrl_parameter_delete(p);
5466  */
5467  /* chi-rel method
5468  int ord=detmon_lg_config.order;
5469  p = hdrl_bpm_fit_parameter_create_rel_chi(1, kappa, kappa);
5470  */
5471  hdrl_bpm_fit_compute(p, hil, x, bpms_ptr);
5472  //cpl_vector_dump(x,stdout);
5473  /*
5474  // bpm-3D method
5475  cpl_imagelist* linearity_scaled=cpl_imagelist_new();
5476 
5477  for(int i=0;i<sz;i++) {
5478  ima=cpl_imagelist_get(linearity_inputs,i);
5479  median=cpl_image_get_median(ima);
5480  if(median < detmon_lg_config.saturation_limit) {
5481  cpl_image_divide_scalar(ima,median);
5482  cpl_imagelist_set(linearity_scaled,cpl_image_duplicate(ima),i);
5483  }
5484  }
5485  hdrl_imagelist* hil= hdrl_imagelist_create(linearity_scaled,NULL);
5486 
5487 
5488  // bpm-3D method
5489  hdrl_bpm_3d_method method = HDRL_BPM_3D_THRESHOLD_RELATIVE ;
5490  p=hdrl_bpm_3d_parameter_create(kappa, kappa, method) ;
5491  cpl_imagelist * out_imlist = hdrl_bpm_3d_compute(hil, p);
5492  *bpms_ptr = cpl_imagelist_collapse_create(out_imlist);
5493  cpl_msg_info(cpl_func,"BP map value: min=%g max=%g",
5494  cpl_image_get_min(*bpms_ptr),cpl_image_get_max(*bpms_ptr));
5495  */
5496  nbpixs = cpl_image_get_flux(*bpms_ptr);
5497  /* clean-up memory */
5498  hdrl_imagelist_delete(hil);
5499  cpl_imagelist_delete(linearity_scaled);
5500  cpl_vector_unwrap((cpl_vector*) x);
5501  hdrl_parameter_delete(p);
5502  // 3D method only
5503  //cpl_imagelist_delete(out_imlist);
5504  /* ORIGINAL BP MAP COMPUTATION
5505  *bpms_ptr = detmon_bpixs(*coeffs_ptr, detmon_lg_config.bpmbin,
5506  detmon_lg_config.kappa, &nbpixs);
5507  */
5508  /*
5509  *bpms_ptr = detmon_bpixs2(x,linearity_inputs,*coeffs_ptr,gain_table,
5510  detmon_lg_config.order,detmon_lg_config.bpmbin,detmon_lg_config.kappa,&nbpixs);
5511  */
5512  /*
5513  cpl_vector_unwrap((cpl_vector*)x);
5514  cpl_vector_unwrap((cpl_vector*)y);
5515  */
5516  //cpl_msg_info(cpl_func,"nbpixs=%d",nbpixs);
5517  skip_if(*bpms_ptr == NULL);
5518 
5519  end_skip;
5520  return nbpixs;
5521 }
5522 
5523 /*---------------------------------------------------------------------------*/
5537 /*---------------------------------------------------------------------------*/
5538 static cpl_error_code
5539 detmon_lg_reduce_all(const cpl_table * linear_table,
5540  cpl_propertylist * gaint_qclist,
5541  cpl_propertylist * lint_qclist,
5542  cpl_propertylist * linc_qclist,
5543  cpl_propertylist * bpm_qclist,
5544  cpl_imagelist ** coeffs_ptr,
5545  cpl_image ** bpms_ptr,
5546  const cpl_imagelist * linearity_inputs,
5547  const cpl_table * gain_table,
5548  int which_ext, cpl_boolean opt_nir)
5549 {
5550 
5551  int nbpixs = 0;
5552  const int linear_nsets = cpl_table_get_nrow(linear_table);
5553  const int gain_nsets = cpl_table_get_nrow(gain_table);
5554  double autocorr;
5555  cpl_polynomial *poly_linfit = NULL;
5556  cpl_image *fiterror = NULL;
5557  char * name_o1 = NULL;
5558  char * name_o2 = NULL;
5559  double * pcoeffs = NULL;
5560  unsigned mode = detmon_lg_config.autocorr ? IRPLIB_GAIN_WITH_AUTOCORR : 0;
5561  double min_val=0;
5562  double max_val=0;
5563  cpl_vector *x =NULL;
5564  const cpl_vector *y =NULL;
5565 
5566 
5567  const cpl_image * first = NULL;
5568  int sizex = 0;
5569  int sizey = 0;
5570 
5571  int vsize = 0;
5572  cpl_size deg=0;
5573  /* FIXME: This should go before the x and y vectors.
5574  Checking for all the inputs */
5575  cpl_ensure_code(gaint_qclist != NULL, CPL_ERROR_NULL_INPUT);
5576  cpl_ensure_code(lint_qclist != NULL, CPL_ERROR_NULL_INPUT);
5577  cpl_ensure_code(linc_qclist != NULL, CPL_ERROR_NULL_INPUT);
5578  cpl_ensure_code(bpm_qclist != NULL, CPL_ERROR_NULL_INPUT);
5579 
5580  pcoeffs = cpl_malloc(sizeof(double)*(detmon_lg_config.order + 1));
5581 
5582  skip_if(cpl_propertylist_append_string(gaint_qclist, DETMON_QC_METHOD,
5583  detmon_lg_config.method));
5584  skip_if(cpl_propertylist_set_comment(gaint_qclist, DETMON_QC_METHOD,
5585  DETMON_QC_METHOD_C));
5586 
5587 
5588  if (!strcmp(detmon_lg_config.method, "PTC")) {
5589  /* Computation of GAIN via polynomial fit */
5590  if (detmon_lg_config.exts >= 0) {
5591  cpl_msg_info(cpl_func,
5592  "Polynomial fitting for the GAIN (constant term method)");
5593  } else {
5594  cpl_msg_info(cpl_func,
5595  "Polynomial fitting for the GAIN (constant term method)"
5596  " for extension nb %d", which_ext);
5597  }
5598  skip_if(detmon_lg_qc_ptc(gain_table, gaint_qclist, mode, gain_nsets));
5599  } else {
5600  skip_if(detmon_lg_qc_med(gain_table, gaint_qclist, gain_nsets));
5601  }
5602 
5603  /*^FIXME: This shouldn't be written when no applied */
5604  /* Lamp flux */
5605  if(detmon_lg_config.lamp_ok) {
5606  skip_if(cpl_propertylist_append_double(lint_qclist, DETMON_QC_LAMP_FLUX,
5607  detmon_lg_config.cr));
5608  skip_if(cpl_propertylist_set_comment(lint_qclist, DETMON_QC_LAMP_FLUX,
5609  DETMON_QC_LAMP_FLUX_C));
5610  }
5611 
5612  /*^FIXME: This shouldn't be written when no applied */
5613  if(detmon_lg_config.autocorr == TRUE) {
5614  autocorr = cpl_table_get_column_median(gain_table, "AUTOCORR");
5615  skip_if(cpl_propertylist_append_double(gaint_qclist, DETMON_QC_AUTOCORR,
5616  autocorr));
5617  skip_if(cpl_propertylist_set_comment(gaint_qclist, DETMON_QC_AUTOCORR,
5618  DETMON_QC_AUTOCORR_C));
5619  }
5620  if (detmon_lg_config.exts >= 0) {
5621  cpl_msg_info(cpl_func, "Polynomial fitting pix-to-pix");
5622  } else {
5623  cpl_msg_info(cpl_func, "Polynomial fitting pix-to-pix"
5624  " for extension nb %d", which_ext);
5625  }
5626 
5627  if(!detmon_lg_config.pix2pix) {
5628  const int order=detmon_lg_config.order;
5629 
5630 
5631 
5632 
5633 
5634  double mse = 0;
5635  /* Computation of LINEARITY via polynomial fit */
5636  y = cpl_vector_wrap(linear_nsets,
5637  (double *)cpl_table_get_data_double_const(linear_table,
5638  "MED"));
5639 
5640  if (opt_nir == NIR) {
5641  x = cpl_vector_wrap(linear_nsets,
5642  (double *)cpl_table_get_data_double_const(linear_table,
5643  "DIT"));
5644  } else {
5645  x = cpl_vector_wrap(linear_nsets,
5646  (double *)cpl_table_get_data_double_const(linear_table,
5647  "EXPTIME"));
5648  }
5649 
5650  if(x == NULL || y == NULL) {
5651  cpl_vector_unwrap((cpl_vector *)x);
5652  cpl_vector_unwrap((cpl_vector *)y);
5653  /*
5654  * As x and y are const vectors, if they would be defined at the
5655  * beginning of the function (required for skip_if - end_skip
5656  * scheme), they couldn't be initialised to NULL (required too).
5657  * Therefore, they are considered apart from the scheme.
5658  */
5659  skip_if(1);
5660  }
5661 
5662  cpl_msg_info(cpl_func, "Polynomial fitting for the LINEARITY");
5663  poly_linfit = irplib_polynomial_fit_1d_create(x, y,order,&mse);
5664 
5665  if(order == cpl_vector_get_size(x) - 1) {
5666  cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
5667  mse = 0;
5668  }
5669 
5670  if(poly_linfit == NULL) {
5671  cpl_vector_unwrap((cpl_vector *)x);
5672  cpl_vector_unwrap((cpl_vector *)y);
5673  /* See comment in previous error checking if() statement */
5674  skip_if(1);
5675  }
5676 
5677 
5678  min_val=cpl_vector_get_min(y);
5679  max_val=cpl_vector_get_max(y);
5680 
5681  cpl_vector_unwrap((cpl_vector *)x);
5682  cpl_vector_unwrap((cpl_vector *)y);
5683 
5684  for(deg = 0; deg <= order; deg++) {
5685  const double coeff =
5686  cpl_polynomial_get_coeff(poly_linfit, &deg);
5687  // FIXME Should not be hardcoded
5688  char *name_o =
5689  cpl_sprintf("ESO QC LIN COEF%" CPL_SIZE_FORMAT "", deg);
5690  assert(name_o != NULL);
5691  skip_if(cpl_propertylist_append_double(lint_qclist, name_o, coeff));
5692  skip_if(cpl_propertylist_set_comment(lint_qclist,name_o,
5693  DETMON_QC_LIN_COEF_C));
5694 
5695  cpl_free(name_o);
5696  pcoeffs[deg] = coeff;
5697  }
5698  skip_if(cpl_propertylist_append_double(lint_qclist,DETMON_QC_ERRFIT, mse));
5699  skip_if(cpl_propertylist_set_comment(lint_qclist,DETMON_QC_ERRFIT,
5700  DETMON_QC_ERRFIT_MSE_C));
5701 
5702 
5703  } else {
5704  const int order=detmon_lg_config.order;
5705  /* pix2pix == TRUE */
5706  y = cpl_vector_wrap(linear_nsets,
5707  (double *)cpl_table_get_data_double_const(linear_table,
5708  "MED"));
5709 
5710  if (opt_nir == NIR)
5711  {
5712  x = cpl_vector_wrap(linear_nsets,
5713  (double *)cpl_table_get_data_double_const(linear_table,
5714  "DIT"));
5715  } else {
5716  x = cpl_vector_wrap(linear_nsets,
5717  (double *)cpl_table_get_data_double_const(linear_table,
5718  "EXPTIME"));
5719 
5720  }
5721 
5722  first = cpl_imagelist_get_const(linearity_inputs, 0);
5723  sizex = cpl_image_get_size_x(first);
5724  sizey = cpl_image_get_size_y(first);
5725  vsize = cpl_vector_get_size(x);
5726  fiterror = cpl_image_new(sizex, sizey, CPL_TYPE_FLOAT);
5727  *coeffs_ptr =
5728  cpl_fit_imagelist_polynomial(x, linearity_inputs, 0,order, FALSE,
5729  CPL_TYPE_FLOAT, fiterror);
5730  min_val=cpl_vector_get_min(y);
5731  max_val=cpl_vector_get_max(y);
5732  cpl_vector_unwrap((cpl_vector*)x);
5733  cpl_vector_unwrap((cpl_vector*)y);
5734 
5735  irplib_ensure(*coeffs_ptr != NULL, CPL_ERROR_UNSPECIFIED,
5736  "Failed polynomial fit");
5737  //detmon_lg_qclog_lin_coeff(*coeffs_ptr, order,linc_qclist);
5738 
5739  for(deg = 0; deg <= order; deg++)
5740  {
5741  cpl_image *image = cpl_imagelist_get(*coeffs_ptr, deg);
5742  const double coeff = cpl_image_get_median(image);
5743  pcoeffs[deg] = coeff;
5744  // FIXME Should not be hardcoded
5745  name_o1 = cpl_sprintf("ESO QC LIN COEF%d", (int)deg);
5746  name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", (int)deg);
5747  assert(name_o1 != NULL);
5748  assert(name_o2 != NULL);
5749  skip_if(cpl_propertylist_append_double(linc_qclist, name_o1, coeff));
5750  skip_if(cpl_propertylist_set_comment(linc_qclist,name_o1,
5751  DETMON_QC_LIN_COEF_C));
5752  cpl_free(name_o1);
5753  name_o1= NULL;
5754  skip_if(cpl_propertylist_append_double(linc_qclist, name_o2,
5755  cpl_image_get_stdev(image)));
5756  skip_if(cpl_propertylist_set_comment(linc_qclist,name_o2,
5757  DETMON_QC_LIN_COEF_ERR_C));
5758  cpl_free(name_o2);
5759  name_o2= NULL;
5760  }
5761 
5762 
5763  if(order == vsize - 1)
5764  {
5765  cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
5766  skip_if(cpl_propertylist_append_double(linc_qclist,DETMON_QC_ERRFIT,
5767  0.0));
5768  skip_if(cpl_propertylist_set_comment(linc_qclist,DETMON_QC_ERRFIT,
5769  DETMON_QC_ERRFIT_C));
5770  } else
5771  {
5772  skip_if(cpl_propertylist_append_double(linc_qclist,DETMON_QC_ERRFIT,
5773  cpl_image_get_median(fiterror)));
5774  skip_if(cpl_propertylist_set_comment(linc_qclist,DETMON_QC_ERRFIT,
5775  DETMON_QC_ERRFIT_C));
5776  }
5777  } /* end case pix2pix == TRUE */
5778 
5779  skip_if(cpl_propertylist_append_double(lint_qclist,DETMON_QC_COUNTS_MIN,
5780  min_val));
5781  skip_if(cpl_propertylist_set_comment(lint_qclist,DETMON_QC_COUNTS_MIN,
5782  DETMON_QC_COUNTS_MIN_C));
5783  skip_if(cpl_propertylist_append_double(lint_qclist,DETMON_QC_COUNTS_MAX,
5784  max_val));
5785  skip_if(cpl_propertylist_set_comment(lint_qclist,DETMON_QC_COUNTS_MAX,
5786  DETMON_QC_COUNTS_MAX_C));
5787  skip_if(detmon_lg_lineff(pcoeffs,lint_qclist,detmon_lg_config.ref_level,
5788  detmon_lg_config.order));
5789  /* Detection of bad pixels */
5790  if (detmon_lg_config.exts >= 0)
5791  {
5792  cpl_msg_info(cpl_func, "Bad pixel detection");
5793  } else
5794  {
5795  cpl_msg_info(cpl_func, "Bad pixel detection"
5796  " for extension nb %d", which_ext);
5797  }
5798  if(detmon_lg_config.pix2pix)
5799  {
5800 
5801  /* Determines bad pixel map */
5802  nbpixs = detmon_compute_badpixmap(opt_nir, linear_nsets, linear_table,
5803  linearity_inputs, nbpixs, x,gaint_qclist, bpms_ptr);
5804  /* we still have to unwrapp x & y that we kept for bpixs2 function */
5805  }
5806 
5807 
5808  skip_if(cpl_propertylist_append_int(bpm_qclist, DETMON_QC_NUM_BPM, nbpixs));
5809  skip_if(cpl_propertylist_set_comment(bpm_qclist, DETMON_QC_NUM_BPM,
5810  DETMON_QC_NUM_BPM_C));
5811  cpl_msg_info(cpl_func,"stability=%g",detmon_lg_config.lamp_stability);
5812  if(detmon_lg_config.lamp_stability != 0.0)
5813  {
5814  skip_if(cpl_propertylist_append_double(lint_qclist, DETMON_QC_LAMP_STAB,
5815  detmon_lg_config.lamp_stability));
5816  skip_if(cpl_propertylist_set_comment(lint_qclist, DETMON_QC_LAMP_STAB,
5817  DETMON_QC_LAMP_STAB_C));
5818  }
5819  /* Fit COEFFS_CUBE and BPM outputs to whole-chip size images (DFS05711) */
5820  if (!detmon_lg_config.wholechip && detmon_lg_config.pix2pix)
5821  {
5822  detmon_lg_fits_coeffs_and_bpm2chip(coeffs_ptr,bpms_ptr);
5823  }
5824  end_skip;
5825 
5826  cpl_free(pcoeffs);
5827  cpl_free(name_o1);
5828  cpl_free(name_o2);
5829  cpl_image_delete(fiterror);
5830  cpl_polynomial_delete(poly_linfit);
5831 
5832 
5833 
5834  return cpl_error_get_code();
5835 }
5836 
5837 /*---------------------------------------------------------------------------*/
5845 /*---------------------------------------------------------------------------*/
5846 static cpl_error_code
5847 detmon_lg_lineff(double * pcoeffs,
5848  cpl_propertylist * qclist,
5849  int ref_level,
5850  int order)
5851 {
5852  double lineff = 0;
5853  double root = 0;
5854  double residual, slope;
5855  int i;
5856  cpl_size deg=0;
5857  cpl_polynomial * poly = cpl_polynomial_new(1);
5858 
5859 
5860  /*
5861  * Construction of the polynomial F_m(F_r) from F_m(t),
5862  * using F_r = a_1 * t.
5863  */
5864  /*
5865  for (deg = 0; deg <= order; deg++) {
5866  cpl_msg_info(cpl_func,"coef[%d]=%g",deg,pcoeffs[deg]);
5867  }
5868  */
5869 
5870 
5871  pcoeffs[0] -= ref_level;
5872 
5873  for (i = 2; i <= order; i++)
5874  {
5875  int j;
5876  for(j = 0; j < i; j++)
5877  {
5878  pcoeffs[i] /= pcoeffs[1];
5879  }
5880  }
5881 
5882  pcoeffs[1] = 1;
5883 
5884  for (deg = 0; deg <= order; deg++) {
5885  /*cpl_msg_info(cpl_func,"coef[%d]=%g",deg,pcoeffs[deg]);*/
5886  skip_if(cpl_polynomial_set_coeff(poly, &deg, pcoeffs[deg]));
5887  }
5888 
5889  /*
5890  * Verification of validity of first guess (0).
5891  * The root to be found will be in the same interval of monotony
5892  * of the first guess; therefore, slope must be greater than 0.
5893  * Slope > 0 and poly(root) = 0 force also residual to be negative.
5894  */
5895  residual = cpl_polynomial_eval_1d(poly, 0.0, &slope);
5896 
5897  if (slope <= 0.0 && residual >= 0.0) {
5898  cpl_msg_warning(cpl_func, "Reference level (--ref_level) outside"
5899  " linearity range of the detector. Cannot compute"
5900  " linearity efficiency (QC.LINEFF).");
5901  lineff = -1;
5902  }
5903  else
5904  {
5905  cpl_error_code err = cpl_polynomial_solve_1d(poly, 0.0, &root, 1);
5906  /*
5907  cpl_msg_info(cpl_func,"root=%g ref_level=%d lin_eff=%d",
5908  root,ref_level,ref_level);
5909  */
5910  if (err == CPL_ERROR_NONE)
5911  {
5912 
5913  lineff = (root - ref_level) / ref_level;
5914  }
5915  else
5916  {
5917  cpl_error_reset();
5918  cpl_msg_warning(cpl_func,
5919  "Cannot compute linearity efficiency (QC.LINEFF)"
5920  "for the current combination "
5921  " of (--ref-level equal %d) and (--order equal %d) parameters. Try "
5922  "to decrease (--ref-level) value.", ref_level, order);
5923  }
5924  }
5925  cpl_msg_warning(cpl_func, "DETMON_QC_LIN_EFF=%f",lineff );
5926  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LIN_EFF,
5927  lineff));
5928  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LIN_EFF,
5929  DETMON_QC_LIN_EFF_C));
5930 
5931  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LIN_EFF_FLUX,
5932  ref_level));
5933  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LIN_EFF_FLUX,
5934  DETMON_QC_LIN_EFF_FLUX_C));
5935 
5936  end_skip;
5937 
5938  cpl_polynomial_delete(poly);
5939 
5940  return cpl_error_get_code();
5941 }
5942 
5943 /*---------------------------------------------------------------------------*/
5950 /*---------------------------------------------------------------------------*/
5951 static cpl_error_code
5952 detmon_lg_qc_ptc(const cpl_table * gain_table,
5953  cpl_propertylist * qclist, unsigned mode, int rows_in_gain)
5954 {
5955  double mse = 0;
5956  cpl_polynomial *poly_fit = NULL;
5957  cpl_polynomial *poly_fit2 = NULL;
5958  cpl_size i;
5959  const int nsets = rows_in_gain;
5960 
5961  cpl_vector *x = NULL;
5962  cpl_vector *y = NULL;
5963 
5964  cpl_errorstate prestate;
5965  double coef = 0;
5966  cpl_ensure_code(gain_table != NULL, CPL_ERROR_NULL_INPUT);
5967  cpl_ensure_code(qclist != NULL, CPL_ERROR_NULL_INPUT);
5968 
5969  x = cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT"));
5970 
5971  y = cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
5972 
5973  skip_if(x == NULL || y == NULL);
5974  if (0 == detmon_lg_check_before_gain(x, y))
5975  {
5976  if (x)
5977  {
5978  cpl_vector_unwrap(x);
5979  }
5980  if (y)
5981  {
5982  cpl_vector_unwrap(y);
5983  }
5984  return CPL_ERROR_NONE;
5985  }
5986  /*it is not really a MSE, but chi square of the fit, see cpl_vector_fill_polynomial_fit_residual for details*/
5987  poly_fit = irplib_polynomial_fit_1d_create_chiq(x, y, 1, &mse);
5988  skip_if(poly_fit == NULL);
5989 
5990  /* Write the QC params corresponding to the fitting of the GAIN */
5991  i = 1;
5992  prestate = cpl_errorstate_get();
5993  coef = cpl_polynomial_get_coeff(poly_fit, &i);
5994  skip_if (!cpl_errorstate_is_equal(prestate) || coef==0);
5995  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD, coef));
5996  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD,
5997  DETMON_QC_CONAD_C));
5998  if (coef != 0)
5999  {
6000  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN,
6001  1 / coef));
6002  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN,
6003  DETMON_QC_GAIN_C));
6004  }
6005  /* MSE is removed - see DFS07358 for details
6006  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_MSE, mse));
6007  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_MSE,
6008  DETMON_QC_GAIN_MSE_C));
6009  */
6010  i = 0;
6011  /* QC.RON computation is disabled, see DFS05852 for details*/
6012 
6013  /* * skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_RON,
6014  cpl_polynomial_get_coeff(poly_fit, &i)));
6015  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_RON,
6016  DETMON_QC_RON_C));
6017  */
6018  if(mode & IRPLIB_GAIN_WITH_AUTOCORR){
6019  const cpl_vector *x2 =
6020  cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT_CORR"));
6021  const cpl_vector *y2 =
6022  cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
6023 
6024  if(x2 == NULL || y2 == NULL) {
6025  cpl_vector_unwrap((cpl_vector *)x2);
6026  cpl_vector_unwrap((cpl_vector *)y2);
6027  /*
6028  * As x and y are const vectors, if they would be defined at the
6029  * beginning of the function (required for skip_if - end_skip
6030  * scheme), they couldn't be initialised to NULL (required too).
6031  * Therefore, they are considered apart from the scheme.
6032  */
6033  skip_if(1);
6034  }
6035 
6036  /* Revise mse, maybe used afterwards */
6037  poly_fit2 = irplib_polynomial_fit_1d_create(x2, y2, 1, &mse);
6038  if(poly_fit2 == NULL) {
6039  cpl_vector_unwrap((cpl_vector *)x2);
6040  cpl_vector_unwrap((cpl_vector *)y2);
6041 
6042  cpl_msg_error(cpl_func, "Error during polynomial fit, err[%s]", cpl_error_get_where());
6043  /* See comment in previous error checking if() statement */
6044  skip_if(1);
6045  }
6046  skip_if(cpl_error_get_code() != CPL_ERROR_NONE);
6047  cpl_vector_unwrap((cpl_vector *)x2);
6048  cpl_vector_unwrap((cpl_vector *)y2);
6049  skip_if(cpl_error_get_code() != CPL_ERROR_NONE);
6050  /* Write the QC params corresponding to the fitting of the GAIN */
6051  i = 1;
6052  prestate = cpl_errorstate_get();
6053  coef = cpl_polynomial_get_coeff(poly_fit2, &i);
6054  skip_if(cpl_error_get_code() != CPL_ERROR_NONE);
6055  skip_if (!cpl_errorstate_is_equal(prestate) || coef == 0);
6056 
6057  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD_CORR,
6058  coef));
6059  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD_CORR,
6060  DETMON_QC_CONAD_CORR_C));
6061 
6062  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_CORR,
6063  1 / coef));
6064  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_CORR,
6065  DETMON_QC_GAIN_CORR_C));
6066  }
6067 
6068  end_skip;
6069 
6070  /*cleanup*/
6071  cpl_vector_unwrap(x);
6072  cpl_vector_unwrap(y);
6073  cpl_polynomial_delete(poly_fit);
6074  cpl_polynomial_delete(poly_fit2);
6075 
6076  return cpl_error_get_code();
6077 }
6078 
6085 static int detmon_lg_check_before_gain(const cpl_vector* x, const cpl_vector* y)
6086 {
6087  const double TOLERANCE = 1e-37;/*MINDOUBLE is not everywhere defined (Mac);*/
6088  double xmin = cpl_vector_get_min(x);
6089  double xmax = cpl_vector_get_max(x);
6090  double ymin = cpl_vector_get_min(y);
6091  double ymax = cpl_vector_get_max(y);
6092  double ystdev = cpl_vector_get_stdev(y);
6093  double xstdev = cpl_vector_get_stdev(x);
6094  int retval = 1;
6095  if (fabs(xmax-xmin) < TOLERANCE &&
6096  fabs(ymax - ymin) < TOLERANCE &&
6097  xstdev < TOLERANCE &&
6098  ystdev < TOLERANCE)
6099  {
6100  cpl_msg_warning(cpl_func, "An empty frame has been detected, linearity, coeffs, gain, FPN values will not be computed.");
6101  retval = 0;
6102  }
6103  return retval;
6104 }
6105 /*---------------------------------------------------------------------------*/
6114 /*---------------------------------------------------------------------------*/
6115 static cpl_error_code
6116 detmon_lg_qc_med(const cpl_table * gain_table,
6117  cpl_propertylist * qclist, int rows_in_gain)
6118 {
6119 
6120  double gain=0;
6121  cpl_vector *x = NULL;
6122  cpl_vector *y = NULL;
6123  int check_result = 0;
6124 
6125  if (rows_in_gain) {/* silence unused var */};
6126 
6127  x = cpl_vector_wrap(rows_in_gain, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT"));
6128  y = cpl_vector_wrap(rows_in_gain, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
6129  check_result = detmon_lg_check_before_gain(x, y);
6130  if (x)
6131  {
6132  cpl_vector_unwrap(x);
6133  }
6134  if (y)
6135  {
6136  cpl_vector_unwrap(y);
6137  }
6138  if (0 == check_result)
6139  {
6140  return CPL_ERROR_NONE;
6141  }
6142 
6143  gain=cpl_table_get_column_median(gain_table, "GAIN");
6144 
6145  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN,gain));
6146 
6147  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN,
6148  DETMON_QC_GAIN_C));
6149 
6150  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_MSE,
6151  cpl_table_get_column_stdev
6152  (gain_table, "GAIN")));
6153  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_MSE,
6154  DETMON_QC_GAIN_MSE_C));
6155 
6156  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD,1./gain));
6157  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD,
6158  DETMON_QC_CONAD_C));
6159 
6160 
6161  gain=cpl_table_get_column_median(gain_table, "GAIN_CORR");
6162 
6163  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_CORR,
6164  gain));
6165  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_CORR,
6166  DETMON_QC_GAIN_CORR_C));
6167 
6168 
6169  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD_CORR,1./gain));
6170  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD_CORR,
6171  DETMON_QC_CONAD_CORR_C));
6172 
6173 
6174  end_skip;
6175 
6176  return cpl_error_get_code();
6177 }
6178 
6179 
6180 /*---------------------------------------------------------------------------*/
6189 /*---------------------------------------------------------------------------*/
6190 static cpl_error_code
6191 detmon_lg_rescale(cpl_imagelist * to_rescale)
6192 {
6193  double med1 =
6194  cpl_image_get_median_window(cpl_imagelist_get(to_rescale, 0),
6195  detmon_lg_config.llx,
6196  detmon_lg_config.lly,
6197  detmon_lg_config.urx,
6198  detmon_lg_config.ury);
6199  double med2 =
6200  cpl_image_get_median_window(cpl_imagelist_get(to_rescale, 1),
6201  detmon_lg_config.llx,
6202  detmon_lg_config.lly,
6203  detmon_lg_config.urx,
6204  detmon_lg_config.ury);
6205 
6206  skip_if(0);
6207 
6208  if(fabs(med1 / med2 - 1) > 0.001) {
6209  if(med1 > med2)
6210  skip_if(cpl_image_divide_scalar(cpl_imagelist_get(to_rescale, 0),
6211  med1 / med2));
6212  else
6213  skip_if(cpl_image_divide_scalar(cpl_imagelist_get(to_rescale, 1),
6214  med2 / med1));
6215  }
6216 
6217  end_skip;
6218 
6219  return cpl_error_get_code();
6220 }
6221 
6222 static cpl_error_code
6223 detmon_pair_extract_next(const cpl_frameset * set,
6224  int* iindex,
6225  int* next_element,
6226  double* dit_array,
6227  cpl_frameset ** pair,
6228  double tolerance) /* detmon_lg_config.tolerance */
6229 {
6230  double dit = -100;
6231  double dit_next = -100;
6232  cpl_size* selection;
6233  int nsets_extracted = 0;
6234  cpl_ensure_code(set != NULL, CPL_ERROR_NULL_INPUT);
6235  cpl_ensure_code(dit_array != NULL, CPL_ERROR_NULL_INPUT);
6236  cpl_ensure_code(iindex != NULL, CPL_ERROR_NULL_INPUT);
6237  cpl_ensure_code(pair != NULL, CPL_ERROR_NULL_INPUT);
6238 
6239  nsets_extracted = cpl_frameset_get_size(set);
6240  selection = cpl_malloc(sizeof(cpl_size) * nsets_extracted);
6241  memset(&selection[0], 0, sizeof(cpl_size) * nsets_extracted);
6242 
6243 
6244  dit = dit_array[*next_element ];
6245  /* cpl_msg_info(cpl_func, "%d: dit %f",*next_element, dit ); */
6246  if (*next_element < nsets_extracted - 1)
6247  {
6248  dit_next = dit_array[*next_element + 1 ];
6249  /* cpl_msg_info(cpl_func, "%d: dit %f",*next_element + 1, dit_next ); */
6250  }
6251  /* one element would be returned always */
6252  selection[iindex[*next_element] ] = 1;
6253  if (fabs(dit - dit_next) < tolerance)
6254  {
6255  /* return a second element of the pair */
6256  selection[iindex[*next_element + 1] ] = 1;
6257  (*next_element)++;
6258  }
6259  else
6260  {
6261  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);
6262  }
6263  (*next_element)++;
6264  /* prepare frameset */
6265  cpl_frameset_delete(*pair);
6266  *pair = cpl_frameset_extract(set, selection, 1);
6267 
6268 
6269  cpl_free(selection);
6270  return cpl_error_get_code();
6271 }
6272 
6273 static cpl_error_code
6274 detmon_single_extract_next(const cpl_frameset * set,
6275  int* iindex,
6276  int* next_element,
6277  double* dit_array,
6278  cpl_frameset ** pair)
6279 {
6280  cpl_size* selection;
6281  int nsets_extracted = 0;
6282  cpl_ensure_code(set != NULL, CPL_ERROR_NULL_INPUT);
6283  cpl_ensure_code(dit_array != NULL, CPL_ERROR_NULL_INPUT);
6284  cpl_ensure_code(iindex != NULL, CPL_ERROR_NULL_INPUT);
6285  cpl_ensure_code(pair != NULL, CPL_ERROR_NULL_INPUT);
6286 
6287  nsets_extracted = cpl_frameset_get_size(set);
6288  selection = cpl_malloc(sizeof(cpl_size) * nsets_extracted);
6289  memset(&selection[0], 0, sizeof(cpl_size) * nsets_extracted);
6290 
6291  /* only one element would be returned */
6292  selection[iindex[*next_element] ] = 1;
6293  (*next_element)++;
6294  /* prepare frameset */
6295  cpl_frameset_delete(*pair);
6296  *pair = cpl_frameset_extract(set, selection, 1);
6297 
6298  cpl_free(selection);
6299  return cpl_error_get_code();
6300 }
6301 
6302 
6303 /*---------------------------------------------------------------------------*/
6394 /*---------------------------------------------------------------------------*/
6395 
6396 cpl_table *
6397 detmon_gain(const cpl_imagelist * imlist_on,
6398  const cpl_imagelist * imlist_off,
6399  const cpl_vector * exptimes,
6400  const cpl_vector * ndit,
6401  double tolerance,
6402  int llx,
6403  int lly,
6404  int urx,
6405  int ury,
6406  double kappa,
6407  int nclip,
6408  int xshift,
6409  int yshift,
6410  cpl_propertylist * qclist,
6411  unsigned mode,
6412  cpl_imagelist ** diff_imlist,
6413  cpl_imagelist ** autocorr_imlist)
6414 {
6415  cpl_table * gain_table = NULL;
6416  cpl_imagelist * difflist = NULL;
6417  cpl_imagelist * autocorrlist = NULL;
6418  cpl_imagelist * c_onlist = NULL;
6419  cpl_imagelist * c_offlist = NULL;
6420  cpl_vector * diffdits = NULL;
6421  cpl_vector * diffndits = NULL;
6422  int rows_in_gain = 0;
6423  int ndiffdits, ndits;
6424  int i, j;
6425  cpl_boolean opt_nir = mode & IRPLIB_GAIN_OPT ? OPT : NIR;
6426  const char * method = mode & IRPLIB_GAIN_PTC ? "PTC" : "MED";
6427 
6428  cpl_ensure(imlist_on != NULL, CPL_ERROR_NULL_INPUT, NULL);
6429  cpl_ensure(imlist_off != NULL, CPL_ERROR_NULL_INPUT, NULL);
6430  cpl_ensure(exptimes != NULL, CPL_ERROR_NULL_INPUT, NULL);
6431  cpl_ensure(qclist != NULL, CPL_ERROR_NULL_INPUT, NULL);
6432 
6433  /* Create table with columns */
6434  gain_table = cpl_table_new(cpl_vector_get_size(exptimes) / 2);
6435  skip_if(detmon_gain_table_create(gain_table, opt_nir));
6436 
6437 
6438  /* Search for different EXPTIME values */
6439  skip_if(detmon_lg_find_dits_ndits(exptimes, ndit,tolerance,&diffdits,
6440  &diffndits));
6441  ndiffdits = cpl_vector_get_size(diffdits);
6442 
6443  ndits = cpl_vector_get_size(exptimes);
6444 
6445  /* AUTOCORR processing requires both. They will become outputs later. */
6446  if (mode & IRPLIB_GAIN_WITH_AUTOCORR && (diff_imlist || autocorr_imlist)) {
6447  difflist = cpl_imagelist_new();
6448  autocorrlist = cpl_imagelist_new();
6449  }
6450 
6451  if (mode & IRPLIB_GAIN_COLLAPSE) {
6452  if (mode & IRPLIB_GAIN_WITH_RESCALE) {
6453  c_offlist = cpl_imagelist_duplicate(imlist_off);
6454  skip_if(detmon_lg_rescale(c_offlist));
6455  } else {
6456  c_offlist = (cpl_imagelist *) imlist_off;
6457  }
6458  }
6459 
6460  /* Loop over the different DITs found in EXPTIMEs */
6461  for (i = 0; i < ndiffdits; i++) {
6462  int c_nons;
6463  int c_noffs = 0; /* False (uninit) warning */
6464 
6465  double c_dit = 0;
6466  int c_ndit = 1;
6467 
6468  c_dit=cpl_vector_get(diffdits, i);
6469 
6470  if(opt_nir) {
6471  c_ndit=(int)cpl_vector_get(diffndits, i);
6472  }
6473 
6474  c_onlist = cpl_imagelist_new();
6475  c_nons = 0;
6476 
6477  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
6478  c_offlist = cpl_imagelist_new();
6479  c_noffs = 0;
6480  }
6481 
6482  /* Extraction of images of EXPTIME i */
6483  for(j = 0; j < ndits; j++) {
6484  if (fabs(c_dit - cpl_vector_get(exptimes, j)) <= tolerance) {
6485  /*
6486  * First we get the corresponding image from the ON imlist.
6487  * The option IRPLIB_GAIN_WITH_RESCALE requires to modify
6488  * the input pixel buffer; therefore we must duplicate it.
6489  * On the other hand, if this option is not required, there
6490  * is no need for that duplication. We must only care that
6491  * c_onlist must not be deleted but only unset.
6492  */
6493  cpl_image * im_on;
6494  if (mode & IRPLIB_GAIN_WITH_RESCALE) {
6495  const cpl_image * im =
6496  cpl_imagelist_get_const(imlist_on, j);
6497  im_on = cpl_image_duplicate(im);
6498  } else {
6499  im_on = (cpl_image *)cpl_imagelist_get_const(imlist_on, j);
6500  }
6501  skip_if(cpl_imagelist_set(c_onlist, im_on, c_nons));
6502  c_nons++;
6503 
6504  /*
6505  * Same explanation as above but for OFF imlist.
6506  * Only necessary when IRPLIB_GAIN_NO_COLLAPSE required.
6507  */
6508  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
6509  cpl_image * im_off;
6510  if (mode & IRPLIB_GAIN_WITH_RESCALE) {
6511  const cpl_image * im =
6512  cpl_imagelist_get_const(imlist_off, j);
6513  im_off = cpl_image_duplicate(im);
6514  } else {
6515  im_off =
6516  (cpl_image *) cpl_imagelist_get_const(imlist_off, j);
6517  }
6518  skip_if(cpl_imagelist_set(c_offlist, im_off, c_noffs));
6519  c_noffs++;
6520  }
6521  }
6522  }
6523 
6524  /* If NO_COLLAPSE, must be the same number of images! */
6525  if (mode & IRPLIB_GAIN_NO_COLLAPSE)
6526  skip_if (c_nons != c_noffs);
6527 
6528  /* There must be pairs! */
6529  skip_if (c_nons == 0 || c_nons % 2 != 0);
6530 
6531  /* Rescaling */
6532  if(mode & IRPLIB_GAIN_WITH_RESCALE) {
6533  skip_if(detmon_lg_rescale(c_onlist));
6534  if (mode & IRPLIB_GAIN_NO_COLLAPSE)
6535  skip_if(detmon_lg_rescale(c_offlist));
6536  }
6537 
6538  /* The following loop is necessary for the case of multiple pairs
6539  of same EXPTIME values */
6540  while(c_nons > 0) {
6541  int rows_affected = 1;
6542  skip_if(detmon_gain_table_fill_row(gain_table,
6543  c_dit,c_ndit,
6544  autocorrlist,
6545  difflist, c_onlist,
6546  c_offlist, kappa, nclip,
6547  llx, lly, urx, ury,
6548  xshift, yshift, 1E10, i,
6549  mode, &rows_affected));
6550  if (rows_affected)
6551  {
6552  rows_in_gain++;
6553  }
6554  if (mode & IRPLIB_GAIN_WITH_RESCALE) {
6555  cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
6556  cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
6557  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
6558  cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
6559  cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
6560  }
6561  } else {
6562  cpl_imagelist_unset(c_onlist, 0);
6563  skip_if(0);
6564  cpl_imagelist_unset(c_onlist, 0);
6565  skip_if(0);
6566  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
6567  cpl_imagelist_unset(c_offlist, 0);
6568  skip_if(0);
6569  cpl_imagelist_unset(c_offlist, 0);
6570  skip_if(0);
6571  }
6572  }
6573  skip_if(0);
6574  c_nons -= 2;
6575  }
6576 
6577  cpl_imagelist_delete(c_onlist);
6578  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
6579  cpl_imagelist_delete(c_offlist);
6580  }
6581  }
6582 
6583  skip_if(cpl_propertylist_append_string(qclist, DETMON_QC_METHOD, method));
6584  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_METHOD,
6585  DETMON_QC_METHOD_C));
6586 
6587  /* Computation of GAIN via polynomial fit */
6588  if (mode & IRPLIB_GAIN_PTC) {
6589  skip_if(detmon_lg_qc_ptc(gain_table, qclist, mode, rows_in_gain));
6590  } else {
6591  skip_if(detmon_lg_qc_med(gain_table, qclist, rows_in_gain));
6592  }
6593 
6594  if(mode & IRPLIB_GAIN_WITH_AUTOCORR) {
6595  double autocorr = cpl_table_get_column_median(gain_table, "AUTOCORR");
6596  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_AUTOCORR,
6597  autocorr));
6598  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_AUTOCORR,
6599  DETMON_QC_AUTOCORR_C));
6600  }
6601 
6602  if (diff_imlist != NULL) *diff_imlist = difflist;
6603  if (autocorr_imlist != NULL) *autocorr_imlist = autocorrlist;
6604 
6605  end_skip;
6606 
6607  cpl_vector_delete(diffdits);
6608  cpl_vector_delete(diffndits);
6609 
6610  return gain_table;
6611 }
6612 
6613 static cpl_error_code
6614 detmon_gain_table_create(cpl_table * gain_table,
6615  const cpl_boolean opt_nir)
6616 {
6617  if (opt_nir == NIR) {
6618  skip_if(cpl_table_new_column(gain_table, "DIT", CPL_TYPE_DOUBLE));
6619  skip_if(cpl_table_new_column(gain_table, "NDIT", CPL_TYPE_INT));
6620  } else { /* OPT */
6621  skip_if(cpl_table_new_column(gain_table, "EXPTIME", CPL_TYPE_DOUBLE));
6622  }
6623  skip_if(cpl_table_new_column(gain_table, "MEAN_ON1", CPL_TYPE_DOUBLE));
6624  skip_if(cpl_table_new_column(gain_table, "MEAN_ON2", CPL_TYPE_DOUBLE));
6625  skip_if(cpl_table_new_column(gain_table, "MEAN_OFF1", CPL_TYPE_DOUBLE));
6626  skip_if(cpl_table_new_column(gain_table, "MEAN_OFF2", CPL_TYPE_DOUBLE));
6627  skip_if(cpl_table_new_column(gain_table, "SIG_ON_DIF", CPL_TYPE_DOUBLE));
6628  skip_if(cpl_table_new_column(gain_table, "SIG_OFF_DIF", CPL_TYPE_DOUBLE));
6629  skip_if(cpl_table_new_column(gain_table, "GAIN", CPL_TYPE_DOUBLE));
6630  skip_if(cpl_table_new_column(gain_table, "AUTOCORR", CPL_TYPE_DOUBLE));
6631  skip_if(cpl_table_new_column(gain_table, "GAIN_CORR", CPL_TYPE_DOUBLE));
6632  skip_if(cpl_table_new_column(gain_table, "ADU", CPL_TYPE_DOUBLE));
6633  skip_if(cpl_table_new_column(gain_table, "X_FIT", CPL_TYPE_DOUBLE));
6634  skip_if(cpl_table_new_column(gain_table, "X_FIT_CORR", CPL_TYPE_DOUBLE));
6635  skip_if(cpl_table_new_column(gain_table, "Y_FIT", CPL_TYPE_DOUBLE));
6636  skip_if(cpl_table_new_column(gain_table, "Y_FIT_CORR", CPL_TYPE_DOUBLE));
6637  skip_if(cpl_table_new_column(gain_table, "FLAG", CPL_TYPE_INT));
6638 
6639  end_skip;
6640 
6641  return cpl_error_get_code();
6642 }
6643 
6644 static cpl_error_code
6645 detmon_lin_table_create(cpl_table * lin_table,
6646  const cpl_boolean opt_nir)
6647 {
6648  if (opt_nir == NIR) {
6649  skip_if(cpl_table_new_column(lin_table, "DIT", CPL_TYPE_DOUBLE));
6650  } else { /* OPT */
6651  skip_if(cpl_table_new_column(lin_table, "EXPTIME", CPL_TYPE_DOUBLE));
6652  }
6653  skip_if(cpl_table_new_column(lin_table, "MED", CPL_TYPE_DOUBLE));
6654  skip_if(cpl_table_new_column(lin_table, "MEAN", CPL_TYPE_DOUBLE));
6655  skip_if(cpl_table_new_column(lin_table, "MED_DIT", CPL_TYPE_DOUBLE));
6656  skip_if(cpl_table_new_column(lin_table, "MEAN_DIT", CPL_TYPE_DOUBLE));
6657  skip_if(cpl_table_new_column(lin_table, "ADL", CPL_TYPE_DOUBLE));
6658  end_skip;
6659 
6660  return cpl_error_get_code();
6661 }
6662 
6663 static cpl_vector *
6664 detmon_lg_find_dits(const cpl_vector * exptimes,
6665  double tolerance)
6666 {
6667  cpl_vector * dits = cpl_vector_new(cpl_vector_get_size(exptimes) / 2);
6668  int ndits = 0;
6669 
6670  int i, j;
6671 
6672  /* First different EXPTIME */
6673  cpl_vector_set(dits, 0, cpl_vector_get(exptimes, 0));
6674  ndits = 1;
6675 
6676  /* Search for all different EXPTIMEs */
6677  for(i = 1; i < cpl_vector_get_size(exptimes); i++) {
6678  int ndiffs = 0;
6679  for (j = 0; j < ndits; j++) {
6680  if (fabs(cpl_vector_get(exptimes, i) -
6681  cpl_vector_get(dits, j)) > tolerance)
6682  ndiffs++;
6683  }
6684  if(ndiffs == ndits) {
6685  cpl_vector_set(dits, ndits, cpl_vector_get(exptimes, i));
6686  ndits++;
6687  }
6688  }
6689 
6690  cpl_vector_set_size(dits, ndits);
6691 
6692  return dits;
6693 }
6694 
6695 
6696 
6697 
6698 static cpl_error_code
6699 detmon_lg_find_dits_ndits(const cpl_vector * exptimes,
6700  const cpl_vector * vec_ndits,
6701  double tolerance,
6702  cpl_vector** diff_dits,
6703  cpl_vector** diff_ndits)
6704 {
6705  int ndits = 0;
6706 
6707  int i, j;
6708  int size=0;
6709 
6710 
6711  * diff_dits = cpl_vector_new(cpl_vector_get_size(exptimes) / 2);
6712  * diff_ndits = cpl_vector_new(cpl_vector_get_size(*diff_dits));
6713 
6714  /* First different EXPTIME */
6715  cpl_vector_set(*diff_dits, 0, cpl_vector_get(exptimes, 0));
6716  cpl_vector_set(*diff_ndits, 0, cpl_vector_get(vec_ndits, 0));
6717 
6718  ndits = 1;
6719  size=cpl_vector_get_size(exptimes);
6720  /* Search for all different EXPTIMEs */
6721  for(i = 1; i < size; i++) {
6722  int ndiffs = 0;
6723  for (j = 0; j < ndits; j++) {
6724  if (fabs(cpl_vector_get(exptimes, i) -
6725  cpl_vector_get(*diff_dits,j)) > tolerance)
6726  ndiffs++;
6727  }
6728  if(ndiffs == ndits) {
6729  cpl_vector_set(*diff_dits, ndits, cpl_vector_get(exptimes, i));
6730  cpl_vector_set(*diff_ndits, ndits, cpl_vector_get(vec_ndits, i));
6731  ndits++;
6732  }
6733  }
6734 
6735  cpl_vector_set_size(*diff_dits, ndits);
6736  cpl_vector_set_size(*diff_ndits, ndits);
6737 
6738 
6739  return cpl_error_get_code();
6740 }
6741 
6742 
6743 /*---------------------------------------------------------------------------*/
6826 /*---------------------------------------------------------------------------*/
6827 
6828 cpl_table *
6829 detmon_lin(const cpl_imagelist * imlist_on,
6830  const cpl_imagelist * imlist_off,
6831  const cpl_vector * exptimes,
6832  double tolerance,
6833  int llx,
6834  int lly,
6835  int urx,
6836  int ury,
6837  int order,
6838  int ref_level,
6839  double kappa,
6840  cpl_boolean bpmbin,
6841  cpl_propertylist * qclist,
6842  unsigned mode,
6843  cpl_imagelist ** coeffs_cube,
6844  cpl_image ** bpm)
6845 {
6846  cpl_table * lin_table = NULL;
6847  cpl_imagelist * c_onlist = NULL;
6848  cpl_imagelist * c_offlist = NULL;
6849  cpl_vector * diffdits = NULL;
6850  cpl_imagelist * lin_inputs = NULL;
6851  cpl_polynomial * poly_linfit = NULL;
6852  cpl_image * fiterror = NULL;
6853  cpl_vector * vcoeffs = NULL;
6854  double * pcoeffs = NULL;
6855  int ndiffdits, ndits;
6856  int i, j;
6857  cpl_boolean opt_nir = mode & IRPLIB_LIN_OPT ? OPT : NIR;
6858  const cpl_vector *x = NULL;
6859  const cpl_vector *y = NULL;
6860 
6861  const cpl_image * first = NULL;
6862  int sizex = 0;
6863  int sizey = 0;
6864 
6865  cpl_size deg;
6866  double vsize = 0;
6867 
6868 
6869  cpl_ensure(imlist_on != NULL, CPL_ERROR_NULL_INPUT, NULL);
6870  cpl_ensure(imlist_off != NULL, CPL_ERROR_NULL_INPUT, NULL);
6871  cpl_ensure(exptimes != NULL, CPL_ERROR_NULL_INPUT, NULL);
6872  cpl_ensure(qclist != NULL, CPL_ERROR_NULL_INPUT, NULL);
6873  cpl_ensure(order > 0 , CPL_ERROR_ILLEGAL_INPUT, NULL);
6874 
6875  vcoeffs = cpl_vector_new(order + 1);
6876  pcoeffs = cpl_vector_get_data(vcoeffs);
6877 
6878  /* This mode requires optional outputs */
6879  if (mode & IRPLIB_LIN_PIX2PIX) {
6880  cpl_ensure(coeffs_cube != NULL, CPL_ERROR_NULL_INPUT, NULL);
6881  cpl_ensure(bpm != NULL, CPL_ERROR_NULL_INPUT, NULL);
6882  lin_inputs = cpl_imagelist_new();
6883  }
6884 
6885  /* Create table with columns */
6886  lin_table = cpl_table_new(cpl_vector_get_size(exptimes) / 2);
6887  skip_if(detmon_lin_table_create(lin_table, opt_nir));
6888 
6889  /* Search for different EXPTIME values */
6890  /* Search for different EXPTIME values */
6891  diffdits = detmon_lg_find_dits(exptimes, tolerance);
6892  ndiffdits = cpl_vector_get_size(diffdits);
6893 
6894  ndits = cpl_vector_get_size(exptimes);
6895 
6896 
6897 
6898 
6899 
6900 
6901  /* TO BE IMPLEMENTED SIMILARLY TO UPPER LEVEL FUNCTION (search for nskip)
6902  if(filter > 0) {
6903  double med1 =
6904  cpl_image_get_median_window(cpl_imagelist_get(imlist_on, 0),
6905  llx,lly,urx,ury);
6906  double med2 =
6907  cpl_image_get_median_window(cpl_imagelist_get(imlist_on, 1),
6908  llx,lly,urx,ury);
6909  if ( med1 > (double)filter ||
6910  med2 > (double)filter) {
6911  follow = CPL_FALSE;
6912  cpl_table_select_row(lin_table, dit_nb);
6913  dit_nskip++;
6914  cpl_msg_warning(cpl_func, "Frames of EXPTIME nb %d "
6915  "will not be taken into account for computation "
6916  "as they are above --filter threshold", dit_nb);
6917  }
6918  }
6919  */
6920 
6921 
6922 
6923 
6924  if (mode & IRPLIB_LIN_COLLAPSE) {
6925  /*
6926  * The master bias is required only for
6927  * linearity computation in the OPT domain
6928  */
6929  cpl_image * collapse = cpl_imagelist_collapse_create(imlist_off);
6930  skip_if(collapse == NULL);
6931 
6932  c_offlist = cpl_imagelist_new();
6933  skip_if(cpl_imagelist_set(c_offlist, collapse, 0));
6934  }
6935 
6936  /* Loop over the different DITs found in EXPTIMEs */
6937  for (i = 0; i < ndiffdits; i++) {
6938  int c_nons;
6939  int c_noffs = 0; /* False (uninit) warning */
6940 
6941  double c_dit = cpl_vector_get(diffdits, i);
6942 
6943  c_onlist = cpl_imagelist_new();
6944  c_nons = 0;
6945 
6946  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6947  c_offlist = cpl_imagelist_new();
6948  c_noffs = 0;
6949  }
6950 
6951  for(j = 0; j < ndits; j++) {
6952  if (fabs(c_dit - cpl_vector_get(exptimes, j)) <= tolerance) {
6953  /*
6954  * First we get the corresponding image from the ON imlist.
6955  * The option IRPLIB_GAIN_WITH_RESCALE requires to modify
6956  * the input pixel buffer; therefore we must duplicate it.
6957  * On the other hand, if this option is not required, there
6958  * is no need for that duplication. We must only care that
6959  * c_onlist must not be deleted but only unset.
6960  */
6961  cpl_image * im_on;
6962  if (mode & IRPLIB_LIN_WITH_RESCALE) {
6963  const cpl_image * im =
6964  cpl_imagelist_get_const(imlist_on, j);
6965  im_on = cpl_image_duplicate(im);
6966  } else {
6967  im_on = (cpl_image *)cpl_imagelist_get_const(imlist_on, j);
6968  }
6969  skip_if(cpl_imagelist_set(c_onlist, im_on, c_nons));
6970  c_nons++;
6971 
6972  /*
6973  * Same explanation as above but for OFF imlist.
6974  * Only necessary when IRPLIB_GAIN_NO_COLLAPSE required.
6975  */
6976  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6977  cpl_image * im_off;
6978  if (mode & IRPLIB_LIN_WITH_RESCALE) {
6979  const cpl_image * im =
6980  cpl_imagelist_get_const(imlist_off, j);
6981  im_off = cpl_image_duplicate(im);
6982  } else {
6983  im_off =
6984  (cpl_image *) cpl_imagelist_get_const(imlist_off, j);
6985  }
6986  skip_if(cpl_imagelist_set(c_offlist, im_off, c_noffs));
6987  c_noffs++;
6988  }
6989  }
6990  }
6991 
6992  /* If NO_COLLAPSE, must be the same number of images! */
6993  if (mode & IRPLIB_LIN_NO_COLLAPSE)
6994  skip_if (c_nons != c_noffs);
6995 
6996  /* There must be pairs! */
6997  skip_if (c_nons == 0 || c_nons % 2 != 0);
6998 
6999  /* Rescaling */
7000  if(mode & IRPLIB_LIN_WITH_RESCALE) {
7001  skip_if(detmon_lg_rescale(c_onlist));
7002  if (mode & IRPLIB_LIN_NO_COLLAPSE)
7003  skip_if(detmon_lg_rescale(c_offlist));
7004  }
7005 
7006  /* The following loop is necessary for the case of multiple pairs
7007  of same EXPTIME values */
7008  while(c_nons > 0) {
7009 
7010  skip_if(detmon_lin_table_fill_row(lin_table, c_dit,
7011  lin_inputs,
7012  c_onlist, c_offlist,
7013  llx, lly, urx, ury,
7014  i, 0, mode));
7015 
7016  if (mode & IRPLIB_LIN_WITH_RESCALE) {
7017  cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
7018  cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
7019  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
7020  cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
7021  cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
7022  }
7023  } else {
7024  cpl_imagelist_unset(c_onlist, 0);
7025  skip_if(0);
7026  cpl_imagelist_unset(c_onlist, 0);
7027  skip_if(0);
7028  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
7029  cpl_imagelist_unset(c_offlist, 0);
7030  skip_if(0);
7031  cpl_imagelist_unset(c_offlist, 0);
7032  skip_if(0);
7033  }
7034  }
7035  skip_if(0);
7036  c_nons -= 2;
7037  }
7038 
7039  cpl_imagelist_delete(c_onlist);
7040  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
7041  cpl_imagelist_delete(c_offlist);
7042  }
7043  }
7044 
7045  skip_if(detmon_add_adl_column(lin_table, opt_nir));
7046 
7047  if(!(mode & IRPLIB_LIN_PIX2PIX)) {
7048  double mse = 0;
7049  /* Computation of LINEARITY via polynomial fit */
7050  y = cpl_vector_wrap(cpl_table_get_nrow(lin_table),
7051  (double *)cpl_table_get_data_double_const(lin_table,
7052  "MED"));
7053  if (opt_nir == NIR) {
7054  x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
7055  (double *)cpl_table_get_data_double_const(lin_table, "DIT"));
7056  } else {
7057  x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
7058  (double *)cpl_table_get_data_double_const(lin_table, "EXPTIME"));
7059  }
7060  if(x == NULL || y == NULL) {
7061  cpl_vector_unwrap((cpl_vector *)x);
7062  cpl_vector_unwrap((cpl_vector *)y);
7063  /*
7064  * As x and y are const vectors, if they would be defined at the
7065  * beginning of the function (required for skip_if - end_skip
7066  * scheme), they couldn't be initialised to NULL (required too).
7067  * Therefore, they are considered apart from the scheme.
7068  */
7069  skip_if(1);
7070  }
7071 
7072  cpl_msg_info(cpl_func, "Polynomial fitting for the LINEARITY");
7073  poly_linfit = irplib_polynomial_fit_1d_create_chiq(x, y, order, &mse);
7074 
7075  if(order == cpl_vector_get_size(x) - 1) {
7076  cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
7077  mse = 0;
7078  }
7079 
7080  if(poly_linfit == NULL) {
7081  cpl_vector_unwrap((cpl_vector *)x);
7082  cpl_vector_unwrap((cpl_vector *)y);
7083  /* See comment in previous error checking if() statement */
7084  skip_if(1);
7085  }
7086 
7087  cpl_vector_unwrap((cpl_vector *)x);
7088  cpl_vector_unwrap((cpl_vector *)y);
7089 
7090  for(deg = 0; deg <= order; deg++) {
7091  const double coeff =
7092  cpl_polynomial_get_coeff(poly_linfit, &deg);
7093  char *name_o =
7094  cpl_sprintf("ESO QC LIN COEF%" CPL_SIZE_FORMAT "", deg);
7095  assert(name_o != NULL);
7096  skip_if(cpl_propertylist_append_double(qclist, name_o, coeff));
7097  skip_if(cpl_propertylist_set_comment(qclist,name_o,
7098  DETMON_QC_LIN_COEF_C));
7099  cpl_free(name_o);
7100  pcoeffs[deg] = coeff;
7101  }
7102  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT, mse));
7103  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
7104  DETMON_QC_ERRFIT_MSE_C));
7105 
7106 
7107  } else {
7108  if (opt_nir == NIR) {
7109  x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
7110  (double *)cpl_table_get_data_double_const(lin_table,
7111  "DIT"));
7112  } else {
7113  x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
7114  (double *)cpl_table_get_data_double_const(lin_table,
7115  "EXPTIME"));
7116  }
7117 
7118 
7119  first = cpl_imagelist_get_const(lin_inputs, 0);
7120  sizex = cpl_image_get_size_x(first);
7121  sizey = cpl_image_get_size_y(first);
7122 
7123  vsize = cpl_vector_get_size(x);
7124 
7125  fiterror = cpl_image_new(sizex, sizey, CPL_TYPE_FLOAT);
7126 
7127  *coeffs_cube =
7128  cpl_fit_imagelist_polynomial(x, lin_inputs, 0,
7129  order, FALSE, CPL_TYPE_FLOAT,
7130  fiterror);
7131 
7132  cpl_vector_unwrap((cpl_vector*)x);
7133  irplib_ensure(*coeffs_cube != NULL, CPL_ERROR_UNSPECIFIED,
7134  "Failed polynomial fit");
7135 
7136  for(i = 0; i <= order; i++) {
7137  cpl_image *image = cpl_imagelist_get(*coeffs_cube, i);
7138  const double coeff = cpl_image_get_median(image);
7139  char * name_o1 = cpl_sprintf("ESO QC LIN COEF%d", i);
7140  char * name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", i);
7141  pcoeffs[i] = coeff;
7142  assert(name_o1 != NULL);
7143  assert(name_o2 != NULL);
7144  skip_if(cpl_propertylist_append_double(qclist, name_o1, coeff));
7145  skip_if(cpl_propertylist_set_comment(qclist,name_o1,
7146  DETMON_QC_LIN_COEF_C));
7147  cpl_free(name_o1);
7148  name_o1= NULL;
7149  skip_if(cpl_propertylist_append_double(qclist, name_o2,
7150  cpl_image_get_stdev(image)));
7151  skip_if(cpl_propertylist_set_comment(qclist,name_o2,
7152  DETMON_QC_LIN_COEF_ERR_C));
7153  cpl_free(name_o2);
7154  name_o2= NULL;
7155  }
7156 
7157  if(order == vsize - 1) {
7158  cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
7159  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT,
7160  0.0));
7161  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
7162  DETMON_QC_ERRFIT_C));
7163 
7164 
7165  } else {
7166  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT,
7167  cpl_image_get_median(fiterror)));
7168  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
7169  DETMON_QC_ERRFIT_C));
7170 
7171  }
7172  }
7173 
7174  skip_if(detmon_lg_lineff(pcoeffs, qclist, ref_level, order));
7175 
7176  if(mode & IRPLIB_LIN_PIX2PIX) {
7177  int nbpixs;
7178  *bpm = detmon_bpixs(*coeffs_cube, bpmbin, kappa, &nbpixs);
7179  skip_if(*bpm == NULL);
7180  skip_if(cpl_propertylist_append_int(qclist, DETMON_QC_NUM_BPM,
7181  nbpixs));
7182  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_NUM_BPM,
7183  DETMON_QC_NUM_BPM_C));
7184  }
7185 
7186  end_skip;
7187 
7188  cpl_vector_delete(diffdits);
7189  cpl_polynomial_delete(poly_linfit);
7190  cpl_imagelist_delete(lin_inputs);
7191  cpl_vector_delete(vcoeffs);
7192  cpl_image_delete(fiterror);
7193 
7194  return lin_table;
7195 
7196 }
7197 
7198 /*--------------------------------------------------------------------------*/
7221 /*--------------------------------------------------------------------------*/
7222 static cpl_error_code
7223 detmon_lin_table_fill_row(cpl_table * lin_table, double c_dit,
7224  cpl_imagelist * linearity_inputs,
7225  const cpl_imagelist * ons,
7226  const cpl_imagelist * offs,
7227  int llx,
7228  int lly,
7229  int urx,
7230  int ury,
7231  const int pos,
7232  const int nskip,
7233  unsigned mode)
7234 {
7235  cpl_image * extracted=NULL;
7236 
7237  cpl_ensure_code(lin_table != NULL, CPL_ERROR_NULL_INPUT);
7238  cpl_ensure_code(ons != NULL, CPL_ERROR_NULL_INPUT);
7239  cpl_ensure_code(offs != NULL, CPL_ERROR_NULL_INPUT);
7240 
7241  if (mode & IRPLIB_LIN_PIX2PIX) {
7242  cpl_msg_debug(cpl_func,"checking linearity inputs");
7243  cpl_ensure_code(linearity_inputs != NULL, CPL_ERROR_NULL_INPUT);
7244  }
7245 
7246 
7247  if (mode & IRPLIB_LIN_NIR) {
7248  cpl_table_set(lin_table, "DIT", pos, c_dit);
7249  } else if (mode & IRPLIB_LIN_OPT) { /*OPT */
7250  cpl_table_set(lin_table, "EXPTIME", pos, c_dit);
7251  } else {
7252  cpl_msg_error(cpl_func, "Mandatory mode not given");
7253  }
7254 
7255  {
7256  const cpl_image * off2;
7257  if (cpl_imagelist_get_size(offs) == 1 || mode & IRPLIB_LIN_COLLAPSE)
7258  off2 = cpl_imagelist_get_const(offs, 0);
7259  else
7260  off2 = cpl_imagelist_get_const(offs, 1);
7261 
7262  extracted = detmon_subtracted_avg(cpl_imagelist_get_const(ons, 0),
7263  cpl_imagelist_get_const(offs, 0),
7264  cpl_imagelist_get_const(ons, 1),
7265  off2,
7266  llx, lly, urx, ury);
7267  cpl_ensure_code(extracted != NULL, cpl_error_get_code());
7268  }
7269 
7270  {
7271  double median = cpl_image_get_median(extracted);
7272  double mean= cpl_image_get_mean(extracted);
7273  cpl_table_set(lin_table, "MED", pos, median);
7274  cpl_table_set(lin_table, "MEAN", pos, mean);
7275 
7276  cpl_table_set(lin_table, "MED_DIT", pos, median / c_dit);
7277  cpl_table_set(lin_table, "MEAN_DIT", pos, mean / c_dit);
7278  }
7279 
7280  /* Insert to the imagelist used to fit the polynomial */
7281  if(mode & IRPLIB_LIN_PIX2PIX) {
7282  cpl_error_code error = cpl_imagelist_set(linearity_inputs, extracted,
7283  pos-nskip);
7284  cpl_ensure_code(!error, error);
7285  } else {
7286  cpl_image_delete(extracted);
7287  }
7288 
7289  return cpl_error_get_code();
7290 }
7291 
7292 static double irplib_calculate_total_noise_smooth(const cpl_image* pimage,
7293  int pattern_x, int pattern_y)
7294 {
7295  cpl_image * p_tmp_image = 0;
7296  cpl_image * psmooth_image = 0;
7297  double ret_noise;
7298  cpl_mask * mask = cpl_mask_new(pattern_x, pattern_y);
7299  cpl_mask_not(mask);
7300  p_tmp_image = cpl_image_duplicate(pimage);
7301  cpl_image_filter_mask(p_tmp_image,pimage, mask,CPL_FILTER_MEDIAN ,CPL_BORDER_FILTER);
7302  cpl_image_divide_scalar(p_tmp_image, cpl_image_get_median(pimage));
7303  psmooth_image = cpl_image_divide_create(pimage,p_tmp_image);
7304  ret_noise = irplib_calculate_total_noise(psmooth_image);
7305  cpl_mask_delete(mask);
7306  cpl_image_delete(psmooth_image);
7307  cpl_image_delete(p_tmp_image);
7308  return ret_noise;
7309 }
7310 
7311 static double irplib_calculate_total_noise(const cpl_image* pimage)
7312 {
7313  double total_noise = -1;
7314  unsigned long max_bin_size = 1E5;
7315  const double hstart = cpl_image_get_min(pimage);
7316  const double hrange = cpl_image_get_max(pimage) - hstart;
7317  const unsigned long nbins = max_bin_size;
7318  cpl_error_code err;
7319  /* apply histogram method */
7320  irplib_hist * phist = 0;
7321  phist = irplib_hist_new();
7322  /* 2 extra-bins for possible out-of-range values */
7323 
7324  irplib_hist_init(phist, nbins, hstart, hrange);
7325  err = irplib_hist_fill(phist, pimage);
7326  if (err == CPL_ERROR_NONE)
7327  {
7328  unsigned int i = 0;
7329  double x0 = 0;
7330  double area = 0;
7331  double offset = 0;
7332 
7333  /* prepare vector */
7334  unsigned long n_bins = irplib_hist_get_nbins(phist);
7335  double start = irplib_hist_get_start(phist);
7336  double bin_size = irplib_hist_get_bin_size(phist);
7337  cpl_vector* pdata_vector = cpl_vector_new(n_bins);
7338  cpl_vector* ppos_vector = cpl_vector_new(n_bins);
7339  cpl_table* ptable = cpl_table_new(n_bins);
7340  cpl_table_new_column(ptable, "bin", CPL_TYPE_DOUBLE);
7341  cpl_table_new_column(ptable, "value", CPL_TYPE_DOUBLE);
7342  for(i = 0; i < n_bins; i++)
7343  {
7344  unsigned int value = irplib_hist_get_value(phist, i);
7345  double dvalue = (double)(value);
7346  cpl_vector_set(pdata_vector, i, dvalue);
7347  cpl_vector_set(ppos_vector, i, start + i * bin_size);
7348 
7349  cpl_table_set(ptable, "bin", i, start + i * bin_size);
7350  cpl_table_set(ptable, "value", i, dvalue);
7351  }
7352  err = cpl_vector_fit_gaussian(ppos_vector, NULL, pdata_vector, NULL, CPL_FIT_ALL, &x0, &total_noise, &area, &offset, NULL, NULL, NULL );
7353  if (err == CPL_ERROR_NONE)
7354  {
7355  cpl_msg_info(cpl_func, "FPN Calculation: histogram x0[%f] total_noise[%f] area[%f] offset[%f]", x0, total_noise, area, offset);
7356  }
7357  else
7358  {
7359  cpl_msg_warning(cpl_func, "FPN could not be computed due failed Gaussian Fit, err msg [%s]", cpl_error_get_message());
7360  cpl_error_reset();
7361  }
7362  cpl_table_delete(ptable);
7363  cpl_vector_delete(ppos_vector);
7364  cpl_vector_delete(pdata_vector);
7365  }
7366  else
7367  {
7368  cpl_msg_warning(cpl_func, "FPN could not be computed due failed histogram computation, err msg [%s]", cpl_error_get_message());
7369  cpl_error_reset();
7370  }
7371  irplib_hist_delete(phist);
7372 
7373  return total_noise;
7374 }
7375 
7376 static double irplib_compute_err(double gain, double ron, double FA)
7377 {
7378  double int_gain = (gain * gain - 1) / 12;
7379  if (int_gain < 0)
7380  {
7381  int_gain = 0;
7382  }
7383  return sqrt(ron * ron + FA / gain + int_gain);
7384 }
7385 
7386 static double irplib_fpn_lg(const cpl_image* f1, int* range, double gain ,
7387  FPN_METHOD fpn_method, int smooth_size, double* mse)
7388 {
7389  cpl_image* im_diff = 0;
7390  const cpl_image* im_f1 = f1;
7391  cpl_image* im_inrange1 = 0;
7392  double FA = 0;
7393  double s_tot = 0; /* absolute total noise */
7394  double s_fpn = 0; /* fixed pattern noise */
7395  double sr_fpn = 0; /* relative structural noise */
7396  /*che cinput*/
7397  if (gain<=0) {
7398  /* put dummy values Negative to indicate a problem occurred
7399  (FPN should be always positive) */
7400  cpl_msg_warning(cpl_func,"gain[%f]<0", gain);
7401  cpl_msg_warning(cpl_func,"We set dummy values for FPN");
7402  s_fpn=-999.;
7403  sr_fpn=-999;
7404  return sr_fpn;
7405  }
7406  if (range)
7407  {
7408  im_inrange1 = cpl_image_extract(f1, range[0], range[1], range[2], range[3]);
7409  im_f1 = im_inrange1;
7410  }
7411  FA = cpl_image_get_median(im_f1);
7412 
7413  /* apply histogram method */
7414  /* Is this irplib function giving the right result?? */
7415  switch (fpn_method)
7416  {
7417  case FPN_SMOOTH:
7418  cpl_msg_info(cpl_func,"SMOOTH method is used for FPN, pattern size[%d x %d] pixels",smooth_size,smooth_size );
7419  s_tot = irplib_calculate_total_noise_smooth(im_f1,smooth_size,smooth_size);
7420  break;
7421  case FPN_HISTOGRAM:
7422  cpl_msg_info(cpl_func,"HISTOGRAM method is used for FPN");
7423  s_tot = irplib_calculate_total_noise(im_f1);
7424  break;
7425  default:
7426  s_tot = -1;
7427  sr_fpn = -1;
7428  cpl_msg_warning(cpl_func,"fpn_method is not defined");
7429  break;
7430  }
7431  if (s_tot > 0)
7432  {
7433  if (FA<0)
7434  {
7435  /* put dummy values Negative to indicate a problem occurred
7436  (FPN should be always positive) */
7437  cpl_msg_warning(cpl_func,"Median flux on sum of flats<0");
7438  cpl_msg_warning(cpl_func,"We set dummy values for FPN");
7439  s_fpn=-999.;
7440  sr_fpn=-999;
7441  }
7442 
7443  if ((s_tot * s_tot - FA / gain) > 0)
7444  {
7445  s_fpn = sqrt(s_tot * s_tot - FA / gain);
7446  sr_fpn = s_fpn / FA;
7447  *mse = (irplib_compute_err(gain, 0, FA)) * gain / FA;
7448  } else {
7449  /* put dummy values Negative to indicate a problem occurred
7450  (FPN should be always positive) */
7451  cpl_msg_warning(cpl_func,"s_tot * s_tot < FA / gain");
7452  cpl_msg_warning(cpl_func,"We set dummy values for FPN");
7453  //s_fpn=-999.; /* in this case s_fpn value would be never used */
7454  sr_fpn=-999;
7455  *mse = -1;
7456  }
7457  /*
7458  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);
7459  */
7460  }
7461  cpl_image_delete(im_diff);
7462  if (range)
7463  {
7464  cpl_image_delete(im_inrange1);
7465  }
7466  return sr_fpn;
7467 }
7468 
7469 
7470 static cpl_imagelist * irplib_load_fset_wrp(const cpl_frameset * pframeset,
7471  cpl_type type , int whichext)
7472 {
7473  /* FIXME: load image into window size from beginning to
7474  * save all the extracts */
7475  return detmon_load_frameset_window(pframeset, type, 0, whichext,
7476  detmon_lg_config.llx,
7477  detmon_lg_config.lly,
7478  detmon_lg_config.urx,
7479  detmon_lg_config.ury,
7480  detmon_lg_config.nx,
7481  detmon_lg_config.ny);
7482 }
7483 
7484 static cpl_imagelist * irplib_load_fset_wrp_ext(const cpl_frameset * pframeset,
7485  cpl_type type , int whichext)
7486 {
7487  int i = whichext; /* fake code to avoid compiler warning */
7488  cpl_imagelist* offs = cpl_imagelist_new();
7489  detmon_lg_config.load_fset(pframeset, type, offs);
7490  i++;
7491  return offs;
7492 }
7493 
7494 static cpl_error_code irplib_table_create_column(cpl_table* ptable,
7495  cpl_propertylist* plist)
7496 {
7497  if (ptable && plist)
7498  {
7499  int size = cpl_propertylist_get_size(plist);
7500  int i = 0;
7501  for (i = 0; i < size; i++)
7502  {
7503  cpl_property* pprop = cpl_propertylist_get(plist,i);
7504  if (pprop)
7505  {
7506  const char* pname = cpl_property_get_name(pprop);
7507  if (pname)
7508  {
7509  cpl_table_new_column(ptable, pname, cpl_property_get_type(pprop));
7510  if (cpl_error_get_code() != CPL_ERROR_NONE)
7511  {
7512  cpl_msg_warning(cpl_func, "cannot create new column[%s], err[%s]", pname, cpl_error_get_message());
7513  break; /* leave the cycle */
7514  }
7515  }
7516  }
7517  }
7518  }
7519  return cpl_error_get_code();
7520 }
7521 
7522 static cpl_error_code irplib_fill_table_DETWINUIT(cpl_table* ptable,
7523  cpl_propertylist* plist, int row)
7524 {
7525  cpl_error_code err = CPL_ERROR_NONE;
7526  if (ptable && plist)
7527  {
7528  int size = cpl_propertylist_get_size(plist);
7529  int i = 0;
7530  for (i = 0; i < size; i++)
7531  {
7532  cpl_property* pprop = cpl_propertylist_get(plist,i);
7533  if (pprop)
7534  {
7535  const char* pname = cpl_property_get_name(pprop);
7536  double value = cpl_property_get_double(pprop);
7537  if (pname)
7538  {
7539  cpl_table_set_double(ptable, pname, row, value);
7540  if (cpl_error_get_code() != CPL_ERROR_NONE)
7541  {
7542  cpl_msg_warning(cpl_func, "cannot write value to the table, column[%s] value[%f], err[%s]", pname, value, cpl_error_get_message());
7543  cpl_error_reset();
7544  break; /* leave the cycle */
7545  }
7546  }
7547  }
7548  }
7549  }
7550  return err;
7551 }
7552 
7553 cpl_error_code detmon_check_order(const double *exptime, int sz,
7554  double tolerance, int order)
7555 {
7556  int nsets = 0;
7557  int i = 0;
7558  /* 1. Determine number of groups */
7559  /* cpl_msg_warning(cpl_func, "detmon_check_order sz[%i]", sz);*/
7560  do
7561  {
7562  /* cpl_msg_warning(cpl_func, "detmon_check_order i[%i] exptime[%g]", i, exptime[i]); */
7563  nsets++;
7564  do
7565  {
7566  i++;
7567  if(i == sz - 1)
7568  {
7569  break;
7570  }
7571  } while(fabs(exptime[i-1] - exptime[i]) < tolerance);
7572  } while(i < sz - 1);
7573  /* the very last adjustment for the last group */
7574  if ( !( fabs(exptime[i-1] - exptime[i]) < tolerance ) ) nsets++;
7575  if(nsets <= order)
7576  {
7577  cpl_error_set_message(cpl_func,CPL_ERROR_INCOMPATIBLE_INPUT,
7578  "Not enough frames for the polynomial"
7579  " fitting. nsets = %d <= %d order",
7580  nsets,order);
7581  }
7582  return cpl_error_get_code();
7583 }
7584 
7585 static cpl_error_code
7586 detmon_lg_dfs_save_imagelist(
7587  cpl_frameset * frameset,
7588  const cpl_parameterlist * parlist,
7589  const cpl_frameset *usedframes,
7590  const cpl_imagelist *coeffs,
7591  const char *recipe_name,
7592  const cpl_propertylist *mypro_coeffscube,
7593  const char * package,
7594  const char * name_o)
7595 {
7596  return(cpl_dfs_save_imagelist
7597  (frameset, NULL, parlist, usedframes, NULL,coeffs, CPL_BPP_IEEE_FLOAT,
7598  recipe_name, mypro_coeffscube, NULL, package,
7599  name_o));
7600 }
7601 
7602 static void detmon_lg_add_empty_image(cpl_imagelist* imlist, int pos)
7603 {
7604  const cpl_image* first = cpl_imagelist_get(imlist, 0);
7605  if (first)
7606  {
7607  int x = cpl_image_get_size_x(first);
7608  int y = cpl_image_get_size_y(first);
7609  cpl_type type = cpl_image_get_type(first);
7610  cpl_image * blank = cpl_image_new(x, y, type);
7611  cpl_imagelist_set(imlist, blank, pos);
7612  }
7613 }
7614 
7615 
7616 static cpl_error_code
7617 detmon_lg_set_keyword_from_base_double(cpl_propertylist* pl,
7618  char* keyword_base,
7619  char* keyword_ext,
7620  char* comment_base,
7621  char* comment_ext,
7622  double value) {
7623  char* hkw = cpl_sprintf("%s %s", keyword_base, keyword_ext);
7624  char* hcm = cpl_sprintf("%s %s", comment_base, comment_ext);
7625 
7626  cpl_propertylist_append_double(pl, hkw, value);
7627  cpl_propertylist_set_comment(pl, hkw, hcm);
7628 
7629  cpl_free(hkw);
7630  cpl_free(hcm);
7631 
7632  return cpl_error_get_code();
7633 }
7634 
7635 static cpl_error_code
7636 detmon_lg_set_keyword_from_insert_double(cpl_propertylist* pl,
7637  char* keyword_base,
7638  char* keyword_ins,
7639  char* comment_base,
7640  char* comment_ins,
7641  double value) {
7642  char* hkw = cpl_sprintf(keyword_base, keyword_ins);
7643  char* hcm = cpl_sprintf(comment_base, comment_ins);
7644 
7645  cpl_propertylist_append_double(pl, hkw, value);
7646  cpl_propertylist_set_comment(pl, hkw, hcm);
7647 
7648  cpl_free(hkw);
7649  cpl_free(hcm);
7650 
7651  return cpl_error_get_code();
7652 }
7653 
7654 cpl_error_code
7655 detmon_lg_set_tag(cpl_frameset* set, const char** tag_on, const char** tag_off)
7656 {
7657  int ntag_old=0;
7658  int ntag_new=0;
7659 
7660  ntag_old=cpl_frameset_count_tags(set,DETMON_LG_ON_RAW_OLD);
7661  ntag_new=cpl_frameset_count_tags(set,DETMON_LG_ON_RAW_NEW);
7662  if(ntag_old) {
7663  *tag_on=DETMON_LG_ON_RAW_OLD;
7664  *tag_off=DETMON_LG_OFF_RAW_OLD;
7665  } else if (ntag_new) {
7666  *tag_on=DETMON_LG_ON_RAW_NEW;
7667  *tag_off=DETMON_LG_OFF_RAW_NEW;
7668  } else {
7669  cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
7670  "Provide %s and %s (or %s and %s) input frames",
7671  DETMON_LG_ON_RAW_NEW,DETMON_LG_OFF_RAW_NEW,
7672  DETMON_LG_ON_RAW_OLD,DETMON_LG_OFF_RAW_OLD);
7673  }
7674 
7675 
7676  return cpl_error_get_code();
7677 }
7678 
7679 cpl_error_code
7680 detmon_lg_qc_params(cpl_table* linear_table, cpl_propertylist* lint_qclist,
7681  cpl_table* gain_table, cpl_propertylist* gaint_qclist,
7682  cpl_imagelist* coeffs, cpl_propertylist* linc_qclist,
7683  cpl_image* bpm, cpl_propertylist* bpm_qclist,
7684  const char * recipe_name) {
7685 
7686  char* qc_contam = NULL ;
7687  char* qc_contam_ref = cpl_sprintf("%s%01d", DETMON_QC_CONTAM, 5);
7688 
7689  cpl_msg_info(cpl_func, "This is where I'll write the QC parameters");
7690 
7691  if (linear_table != NULL && lint_qclist != NULL) {
7692  // QC.CONTAM<i>.NORM
7693  if (cpl_propertylist_has(
7694  lint_qclist, qc_contam_ref)) {
7695  for (int i=1; i<5; ++i) {
7696  qc_contam = cpl_sprintf("%s%01d", DETMON_QC_CONTAM, i);
7697  if (cpl_propertylist_has(lint_qclist, qc_contam_ref) &&
7698  cpl_propertylist_has(lint_qclist, qc_contam)) {
7699  cpl_propertylist_append_double(
7700  lint_qclist, cpl_sprintf(DETMON_QC_CONTAMi_NORM, i),
7701  cpl_propertylist_get_double(lint_qclist, qc_contam) /
7702  cpl_propertylist_get_double(lint_qclist, qc_contam_ref));
7703  cpl_propertylist_set_comment(
7704  lint_qclist, cpl_sprintf(DETMON_QC_CONTAMi_NORM, i),
7705  cpl_sprintf(DETMON_QC_CONTAMi_NORM_C, i)
7706  );
7707  }
7708  }
7709  }
7710  }
7711 
7712  cpl_free(qc_contam);
7713  cpl_free(qc_contam_ref);
7714  return cpl_error_get_code();
7715 }
7716 
7717 cpl_error_code
7718 detmon_lg_qc_params_global_gain(const char * recipe_name, int nsets) {
7719  cpl_msg_info(cpl_func, "Going to update gain table for recipe %s, nsets=%d",
7720  recipe_name, nsets);
7721 
7722  char * fn ;
7723  cpl_error_code err ;
7724  if (nsets == 1) {
7725  fn = cpl_sprintf("%s_gain_table.fits", recipe_name) ;
7726  cpl_msg_info(cpl_func, "Will be modifying %s", fn) ;
7727  err = detmon_lg_qc_params_global_gain_update(fn, recipe_name);
7728  cpl_free(fn);
7729  } else {
7730  int j;
7731  for (j=0; j<nsets; ++j) {
7732  fn = cpl_sprintf("%s_gain_table_set%02d.fits", recipe_name, j);
7733  cpl_msg_info(cpl_func, "Will be modifying %s", fn);
7734  err = detmon_lg_qc_params_global_gain_update(fn, recipe_name);
7735  cpl_free(fn);
7736  }
7737  }
7738 
7739  return err;
7740 }
7741 
7742 
7743 cpl_error_code
7744 detmon_lg_qc_params_global_gain_update(const char * fn,
7745  const char * recipe_name) {
7746  cpl_msg_info(cpl_func, "Now updating %s", fn);
7747 
7748  cpl_propertylist* phu = cpl_propertylist_load(fn, 0);
7749  cpl_propertylist** ehus = NULL;
7750  cpl_table** gain_tables = NULL;
7751  cpl_array* gains = NULL;
7752  cpl_array* conads = NULL ;
7753  cpl_frame* fr = cpl_frame_new();
7754 
7755  // Count the number of extensions in this file
7756  cpl_frame_set_filename(fr, fn);
7757  int nexts = cpl_frame_get_nextensions(fr);
7758  cpl_msg_info(cpl_func, "Detected %d nexts", nexts);
7759  if (nexts < 1) {
7760  cpl_msg_warning(cpl_func, "No extensions in %s, so no QC "
7761  "keywords to write", fn);
7762  cpl_msg_warning(cpl_func, "Triggering goto cleanup");
7763  // FIXME Identify correct error(s) to check against
7764  if (1) {
7765  cpl_error_reset();
7766  // Reset the error caused when trying to get nexts
7767  }
7768  goto cleanup;
7769  }
7770  ehus = (cpl_propertylist**)cpl_malloc(nexts * sizeof(cpl_propertylist*));
7771  gain_tables = (cpl_table**)cpl_malloc(nexts * sizeof(cpl_table*));
7772 
7773  // Load up
7774  int j;
7775  for (j=1; j <= nexts; j++) {
7776  cpl_msg_info(cpl_func, "Loading EHU %d", j);
7777  ehus[j-1] = cpl_propertylist_load(fn, j);
7778  gain_tables[j-1] = cpl_table_load(fn, j, 1);
7779 // cpl_propertylist_dump(ehus[j-1], stdout);
7780  }
7781 
7782  // Compute values
7783  cpl_msg_info(cpl_func, "Populating data arrays");
7784  gains = cpl_array_new(nexts, CPL_TYPE_DOUBLE);
7785  conads = cpl_array_new(nexts, CPL_TYPE_DOUBLE);
7786  for (j=1; j <= nexts; j++) {
7787  cpl_msg_info(cpl_func, " %d", j);
7788  if (cpl_propertylist_has(ehus[j-1], DETMON_QC_GAIN)) {
7789  cpl_array_set(gains, j-1,
7790  cpl_propertylist_get_double(ehus[j-1],
7791  DETMON_QC_GAIN));
7792  }
7793  if (cpl_propertylist_has(ehus[j-1], DETMON_QC_CONAD)) {
7794  cpl_array_set(conads, j-1,
7795  cpl_propertylist_get_double(ehus[j-1],
7796  DETMON_QC_CONAD));
7797  }
7798  }
7799  cpl_msg_info(cpl_func, "...populating complete!");
7800  // QC GAIN AVG
7801  cpl_propertylist_append_double(phu, DETMON_QC_GAIN_AVG,
7802  cpl_array_get_mean(gains));
7803  cpl_propertylist_set_comment(phu, DETMON_QC_GAIN_AVG,
7804  DETMON_QC_GAIN_AVG_C);
7805  // QC GAIN RMS
7806  cpl_propertylist_append_double(phu, DETMON_QC_GAIN_RMS,
7807  cpl_array_get_stdev(gains));
7808  cpl_propertylist_set_comment(phu, DETMON_QC_GAIN_RMS,
7809  DETMON_QC_GAIN_RMS_C);
7810 
7811  // The remaining kw are for detmon_opt_lg and detmon_ir_lg only
7812  if (strcmp(recipe_name, "detmon_opt_lg_mr") != 0) {
7813 
7814  // QC CONAD AVG
7815  cpl_propertylist_append_double(phu, DETMON_QC_CONAD_AVG,
7816  cpl_array_get_mean(conads));
7817  cpl_propertylist_set_comment(phu, DETMON_QC_CONAD_AVG,
7818  DETMON_QC_CONAD_AVG_C);
7819  // QC CONAD RMS
7820  cpl_propertylist_append_double(phu, DETMON_QC_CONAD_RMS,
7821  cpl_array_get_stdev(conads));
7822  cpl_propertylist_set_comment(phu, DETMON_QC_CONAD_RMS,
7823  DETMON_QC_CONAD_RMS_C);
7824  // cpl_propertylist_dump(phu, stdout);
7825  // getchar();
7826  }
7827  cpl_msg_info(cpl_func, "Calculations complete!");
7828 
7829  // Write out
7830  cpl_propertylist_save(phu, fn, CPL_IO_CREATE);
7831  for (j=1; j<=nexts; ++j) {
7832  cpl_table_save(gain_tables[j-1], NULL,
7833  ehus[j-1], fn, CPL_IO_EXTEND);
7834  cpl_propertylist_delete(ehus[j-1]);
7835  cpl_table_delete(gain_tables[j-1]);
7836  }
7837 
7838 
7839  // Cleanup
7840  cleanup:
7841 
7842 // if (cpl_error_get_code() != CPL_ERROR_NONE) {
7843 // cpl_msg_error(__func__, "Error found in detmon_lg_qc_params_global_lin_update!");
7844 // cpl_msg_error(__func__, "In %s, L%u", cpl_error_get_file(),
7845 // cpl_error_get_line());
7846 // cpl_msg_error(__func__, "%s", cpl_error_get_message());
7847 // getchar();
7848 // }
7849 
7850  cpl_msg_info(cpl_func, "Cleaning up...");
7851  cpl_propertylist_delete(phu);
7852 // cpl_msg_info(cpl_func, " PHU gone");
7853  cpl_free(ehus);
7854 // cpl_msg_info(cpl_func, " ehus gone");
7855  cpl_free(gain_tables);
7856 // cpl_msg_info(cpl_func, " gain_tables gone");
7857  cpl_frame_delete(fr);
7858 // cpl_msg_info(cpl_func, " fr gone");
7859 // if (conads != NULL) {
7860  cpl_array_delete(conads);
7861 // cpl_msg_info(cpl_func, " conads gone");
7862 // }
7863 // if (gains != NULL) {
7864  cpl_array_delete(gains);
7865 // cpl_msg_info(cpl_func, " gains gone");
7866 // }
7867  cpl_msg_info(cpl_func, "...done!");
7868 
7869  return cpl_error_get_code();
7870 }
7871 
7872 
7873 cpl_error_code
7874 detmon_lg_qc_params_global_lin(const char * recipe_name, int nsets) {
7875  cpl_msg_info(cpl_func, "Going to update linearity table for "
7876  "recipe %s, nsets=%d",
7877  recipe_name, nsets);
7878 
7879  char * fn ;
7880  if (nsets == 1) {
7881  fn = cpl_sprintf("%s_linearity_table.fits", recipe_name) ;
7882  cpl_msg_info(cpl_func, "Will be modifying %s", fn, recipe_name) ;
7883  detmon_lg_qc_params_global_lin_update(fn, recipe_name);
7884  cpl_free(fn);
7885  } else {
7886  int j;
7887  for (j=0; j<nsets; ++j) {
7888  fn = cpl_sprintf("%s_linearity_table_set%02d.fits", recipe_name, j);
7889  cpl_msg_info(cpl_func, "Will be modifying %s", fn);
7890  detmon_lg_qc_params_global_lin_update(fn, recipe_name);
7891  cpl_free(fn);
7892  }
7893  }
7894 
7895  return cpl_error_get_code();
7896 }
7897 
7898 
7899 cpl_error_code
7900 detmon_lg_qc_params_global_lin_update(const char * fn,
7901  const char * recipe_name) {
7902  cpl_msg_info(cpl_func, "Now updating %s", fn);
7903 
7904  cpl_propertylist* phu = cpl_propertylist_load(fn, 0);
7905  cpl_propertylist** ehus = NULL;
7906  cpl_table** lin_tables = NULL;
7907  cpl_array* gain_err = NULL;
7908  cpl_array* counts_min = NULL;
7909  cpl_array* counts_max = NULL;
7910  cpl_array* lin_eff = NULL;
7911  cpl_array* lin_eff_flux = NULL;
7912  int j, contam;
7913  cpl_array** contams = (cpl_array**)cpl_malloc(5 * sizeof(cpl_array*));
7914  for (contam=0; contam < 5; ++contam) {
7915  contams[contam] = NULL;
7916  }
7917  cpl_frame* fr = cpl_frame_new();
7918  char * coeff_kw = NULL ;
7919  char * coeff_comm = NULL ;
7920 
7921 // if (cpl_error_get_code() != CPL_ERROR_NONE) {
7922 // cpl_msg_error(__func__, "Error found in detmon_lg_qc_params_global_lin_update!");
7923 // cpl_msg_error(__func__, "In %s, L%u", cpl_error_get_file(),
7924 // cpl_error_get_line());
7925 // cpl_msg_error(__func__, "%s", cpl_error_get_message());
7926 // getchar();
7927 // }
7928 
7929  // Count the number of extensions in this file
7930  cpl_frame_set_filename(fr, fn);
7931  int nexts = cpl_frame_get_nextensions(fr);
7932  if (nexts < 1) {
7933  cpl_msg_warning(cpl_func, "No extensions in %s, so no QC "
7934  "keywords to write", fn);
7935  // FIXME Identify correct error(s) to check against
7936  if (1) {
7937  cpl_error_reset();
7938  // Reset the error caused when trying to get nexts
7939  }
7940  goto cleanup;
7941  }
7942  cpl_msg_info(cpl_func, "Detected %d nexts", nexts);
7943  ehus = (cpl_propertylist**)cpl_malloc(nexts * sizeof(cpl_propertylist*));
7944  lin_tables = (cpl_table**)cpl_malloc(nexts * sizeof(cpl_table*));
7945 
7946 // if (cpl_error_get_code() != CPL_ERROR_NONE) {
7947 // cpl_msg_error(__func__, "Error found in detmon_lg_qc_params_global_lin_update!");
7948 // cpl_msg_error(__func__, "In %s, L%u", cpl_error_get_file(),
7949 // cpl_error_get_line());
7950 // cpl_msg_error(__func__, "%s", cpl_error_get_message());
7951 // getchar();
7952 // }
7953 
7954  // Load up
7955  gain_err = cpl_array_new(nexts, CPL_TYPE_DOUBLE);
7956  counts_min = cpl_array_new(nexts, CPL_TYPE_DOUBLE);
7957  counts_max = cpl_array_new(nexts, CPL_TYPE_DOUBLE);
7958  lin_eff = cpl_array_new(nexts, CPL_TYPE_DOUBLE);
7959  lin_eff_flux = cpl_array_new(nexts, CPL_TYPE_DOUBLE);
7960  for (contam=0; contam < 5; ++contam) {
7961  contams[contam] = cpl_array_new(nexts, CPL_TYPE_DOUBLE);
7962  }
7963  for (j=1; j <= nexts; ++j) {
7964  cpl_msg_info(cpl_func, "Loading EHU %d", j);
7965  ehus[j-1] = cpl_propertylist_load(fn, j);
7966  lin_tables[j-1] = cpl_table_load(fn, j, 1);
7967 
7968  cpl_msg_info(cpl_func, "Doing non-CONTAM values");
7969 
7970  if (cpl_propertylist_has(ehus[j-1], "ESO QC GAIN ERR")) {
7971  cpl_array_set_double(gain_err, j-1,
7972  cpl_propertylist_get_double(
7973  ehus[j-1], "ESO QC GAIN ERR"));
7974  }
7975  if (cpl_propertylist_has(ehus[j-1], DETMON_QC_COUNTS_MIN)) {
7976  cpl_array_set_double(counts_min, j-1,
7977  cpl_propertylist_get_double(
7978  ehus[j-1], DETMON_QC_COUNTS_MIN));
7979  }
7980  if (cpl_propertylist_has(ehus[j-1], DETMON_QC_COUNTS_MAX)) {
7981  cpl_array_set_double(counts_max, j-1,
7982  cpl_propertylist_get_double(
7983  ehus[j-1], DETMON_QC_COUNTS_MAX));
7984  }
7985  if (cpl_propertylist_has(ehus[j-1], DETMON_QC_LIN_EFF)) {
7986  cpl_array_set_double(lin_eff, j-1,
7987  cpl_propertylist_get_double(
7988  ehus[j-1], DETMON_QC_LIN_EFF));
7989  }
7990  if (cpl_propertylist_has(ehus[j-1], DETMON_QC_LIN_EFF_FLUX)) {
7991  cpl_array_set_double(lin_eff_flux, j-1,
7992  cpl_propertylist_get_double(
7993  ehus[j-1], DETMON_QC_LIN_EFF_FLUX));
7994  }
7995 
7996  cpl_msg_info(cpl_func, "Looping through contam values...");
7997  if (strcmp(recipe_name, "detmon_opt_lg") == 0) {
7998  for (contam=0; contam<5 ; ++contam) {
7999  // FIXME use variable for keyword name
8000  coeff_kw = cpl_sprintf(DETMON_QC_CONTAM "%zd",
8001  contam+1);
8002  if (cpl_propertylist_has(ehus[j-1],
8003  coeff_kw)) {
8004  cpl_array_set_double(contams[contam], j-1,
8005  cpl_propertylist_get_double(
8006  ehus[j-1],
8007  coeff_kw));
8008  }
8009  cpl_free(coeff_kw);
8010  }
8011  }
8012 // if (cpl_error_get_code() != CPL_ERROR_NONE) {
8013 // cpl_msg_error(__func__, "Error found in detmon_lg_qc_params_global_lin_update!");
8014 // cpl_msg_error(__func__, "In %s, L%u", cpl_error_get_file(),
8015 // cpl_error_get_line());
8016 // cpl_msg_error(__func__, "%s", cpl_error_get_message());
8017 // getchar();
8018 // }
8019  }
8020 
8021  // Compute values
8022  cpl_msg_info(cpl_func, "Computing & setting global values...");
8023  // QC GAIN ERR AVG
8024  cpl_propertylist_append_double(phu, DETMON_QC_GAIN_ERR_AVG,
8025  cpl_array_get_mean(gain_err));
8026  cpl_propertylist_set_comment(phu, DETMON_QC_GAIN_ERR_AVG,
8027  DETMON_QC_GAIN_ERR_AVG_C);
8028  // QC GAIN ERR RMS
8029  cpl_propertylist_append_double(phu, DETMON_QC_GAIN_ERR_RMS,
8030  cpl_array_get_stdev(gain_err));
8031  cpl_propertylist_set_comment(phu, DETMON_QC_GAIN_ERR_RMS,
8032  DETMON_QC_GAIN_ERR_RMS_C);
8033  // QC COUNTS MIN AVG
8034  cpl_propertylist_append_double(phu, DETMON_QC_COUNTS_MIN_AVG,
8035  cpl_array_get_mean(counts_min));
8036  cpl_propertylist_set_comment(phu, DETMON_QC_COUNTS_MIN_AVG,
8037  DETMON_QC_COUNTS_MIN_AVG_C);
8038  // QC COUNTS MIN RMS
8039  cpl_propertylist_append_double(phu, DETMON_QC_COUNTS_MIN_RMS,
8040  cpl_array_get_stdev(counts_min));
8041  cpl_propertylist_set_comment(phu, DETMON_QC_COUNTS_MIN_RMS,
8042  DETMON_QC_COUNTS_MIN_RMS_C);
8043  // QC COUNTS MAX AVG
8044  cpl_propertylist_append_double(phu, DETMON_QC_COUNTS_MAX_AVG,
8045  cpl_array_get_mean(counts_max));
8046  cpl_propertylist_set_comment(phu, DETMON_QC_COUNTS_MAX_AVG,
8047  DETMON_QC_COUNTS_MAX_AVG_C);
8048  // QC COUNTS MAX RMS
8049  cpl_propertylist_append_double(phu, DETMON_QC_COUNTS_MAX_RMS,
8050  cpl_array_get_stdev(counts_max));
8051  cpl_propertylist_set_comment(phu, DETMON_QC_COUNTS_MAX_RMS,
8052  DETMON_QC_COUNTS_MAX_RMS_C);
8053  // QC LIN EFF AVG
8054  cpl_propertylist_append_double(phu, DETMON_QC_LIN_EFF_AVG,
8055  cpl_array_get_mean(lin_eff));
8056  cpl_propertylist_set_comment(phu, DETMON_QC_LIN_EFF_AVG,
8057  DETMON_QC_LIN_EFF_AVG_C);
8058  // QC LIN EFF RMS
8059  cpl_propertylist_append_double(phu, DETMON_QC_LIN_EFF_RMS,
8060  cpl_array_get_stdev(lin_eff));
8061  cpl_propertylist_set_comment(phu, DETMON_QC_LIN_EFF_RMS,
8062  DETMON_QC_LIN_EFF_RMS_C);
8063  if (strcmp(recipe_name, "detmon_opt_lg") == 0) {
8064  cpl_msg_info(cpl_func, " Computing additional detmon_opt_lg values...");
8065  // QC LIN EFF FLUX AVG
8066  cpl_propertylist_append_double(phu, DETMON_QC_LIN_EFF_FLUX_AVG,
8067  cpl_array_get_mean(lin_eff_flux));
8068  cpl_propertylist_set_comment(phu, DETMON_QC_LIN_EFF_FLUX_AVG,
8069  DETMON_QC_LIN_EFF_FLUX_AVG_C);
8070  // QC LIN EFF FLUX RMS
8071  cpl_propertylist_append_double(phu, DETMON_QC_LIN_EFF_FLUX_RMS,
8072  cpl_array_get_stdev(lin_eff_flux));
8073  cpl_propertylist_set_comment(phu, DETMON_QC_LIN_EFF_FLUX_RMS,
8074  DETMON_QC_LIN_EFF_FLUX_RMS_C);
8075 
8076  // QC CONTAMi AVG & RMS
8077  for (contam=0 ; contam < 5; ++contam) {
8078  // FIXME re-jig with variable for keyword name
8079  coeff_kw = cpl_sprintf(DETMON_QC_CONTAMi_AVG,
8080  contam+1);
8081  coeff_comm = cpl_sprintf(DETMON_QC_CONTAMi_AVG_C,
8082  contam+1);
8083  cpl_propertylist_append_double(phu,
8084  coeff_kw,
8085  cpl_array_get_mean(contams[contam]));
8086  cpl_propertylist_set_comment(phu,
8087  coeff_kw,
8088  coeff_comm);
8089  cpl_free(coeff_kw);
8090  cpl_free(coeff_comm);
8091 
8092  coeff_kw = cpl_sprintf(DETMON_QC_CONTAMi_RMS,
8093  contam+1);
8094  coeff_comm = cpl_sprintf(DETMON_QC_CONTAMi_RMS_C,
8095  contam+1);
8096  cpl_propertylist_append_double(phu,
8097  coeff_kw,
8098  cpl_array_get_stdev(
8099  contams[contam]));
8100  cpl_propertylist_set_comment(phu,
8101  coeff_kw,
8102  coeff_comm);
8103  cpl_free(coeff_kw);
8104  cpl_free(coeff_comm);
8105 
8106  }
8107  }
8108 
8109 // if (cpl_error_get_code() != CPL_ERROR_NONE) {
8110 // cpl_msg_error(__func__, "Error found in detmon_lg_qc_params_global_lin_update!");
8111 // cpl_msg_error(__func__, "In %s, L%u", cpl_error_get_file(),
8112 // cpl_error_get_line());
8113 // cpl_msg_error(__func__, "%s", cpl_error_get_message());
8114 // getchar();
8115 // }
8116 
8117  // Write out
8118  cpl_propertylist_save(phu, fn, CPL_IO_CREATE);
8119  for (j=1; j<=nexts; ++j) {
8120  cpl_table_save(lin_tables[j-1], NULL,
8121  ehus[j-1], fn, CPL_IO_EXTEND);
8122  cpl_propertylist_delete(ehus[j-1]);
8123  cpl_table_delete(lin_tables[j-1]);
8124  }
8125 
8126  // Cleanup
8127  cleanup:
8128 
8129 // if (cpl_error_get_code() != CPL_ERROR_NONE) {
8130 // cpl_msg_error(__func__, "Error found in detmon_lg_qc_params_global_lin_update!");
8131 // cpl_msg_error(__func__, "In %s, L%u", cpl_error_get_file(),
8132 // cpl_error_get_line());
8133 // cpl_msg_error(__func__, "%s", cpl_error_get_message());
8134 // getchar();
8135 // }
8136 
8137  cpl_msg_info(cpl_func, "Going into cleanup...");
8138  for (contam=0 ; contam<5 ; ++contam) {
8139  cpl_array_delete(contams[contam]);
8140 // cpl_msg_info(cpl_func, " contams array %d gone", contam);
8141  }
8142 // cpl_msg_info(cpl_func, " contams arrays gone");
8143  cpl_free(ehus);
8144  cpl_propertylist_delete(phu);
8145 // cpl_msg_info(cpl_func, " ehus gone");
8146  cpl_free(lin_tables);
8147 // cpl_msg_info(cpl_func, " lin_tables gone");
8148  cpl_free(contams);
8149 // cpl_msg_info(cpl_func, " contams gone");
8150  cpl_array_delete(gain_err);
8151 // cpl_msg_info(cpl_func, " gain_err gone");
8152  cpl_array_delete(counts_min);
8153 // cpl_msg_info(cpl_func, " counts_min gone");
8154  cpl_array_delete(counts_max);
8155 // cpl_msg_info(cpl_func, " counts_max gone");
8156  cpl_array_delete(lin_eff);
8157 // cpl_msg_info(cpl_func, " lin_eff gone");
8158  cpl_array_delete(lin_eff_flux);
8159 // cpl_msg_info(cpl_func, " lin_eff_flux gone");
8160  cpl_frame_delete(fr);
8161 // cpl_msg_info(cpl_func, " fr gone");
8162  cpl_msg_info(cpl_func, "...done!");
8163 
8164  return cpl_error_get_code();
8165 }
8166 
8167 cpl_error_code
8168 detmon_lg_qc_params_global_bpm(const char * recipe_name, int nsets) {
8169  cpl_msg_info(cpl_func, "Going to update BPM image for "
8170  "recipe %s, nsets=%d",
8171  recipe_name, nsets);
8172 
8173  char * fn ;
8174  cpl_error_code err;
8175  if (nsets == 1) {
8176  fn = cpl_sprintf("%s_bpm.fits", recipe_name) ;
8177  cpl_msg_info(cpl_func, "Will be modifying %s", fn) ;
8178  err = detmon_lg_qc_params_global_bpm_update(fn, recipe_name);
8179  cpl_free(fn);
8180  } else {
8181  int j;
8182  for (j=0; j<nsets; ++j) {
8183  fn = cpl_sprintf("%s_bpm_set%02d.fits", recipe_name, j);
8184  cpl_msg_info(cpl_func, "Will be modifying %s", fn);
8185  err = detmon_lg_qc_params_global_bpm_update(fn, recipe_name);
8186  cpl_free(fn);
8187  }
8188  }
8189 
8190  return err;
8191 }
8192 
8193 cpl_error_code
8194 detmon_lg_qc_params_global_bpm_update(const char * fn,
8195  const char * recipe_name) {
8196  cpl_msg_info(cpl_func, "Now updating %s", fn);
8197 
8198  cpl_propertylist* phu = cpl_propertylist_load(fn, 0);
8199  cpl_propertylist** ehus = NULL ;
8200  cpl_image** bpm_imgs = NULL ;
8201  cpl_array* num_bpm = NULL;
8202  cpl_frame* fr = cpl_frame_new();
8203 
8204  // Both recipes use this function the same way,
8205  // so no need to test recipe name
8206 
8207  // No-op for the MR recipes
8208  if ((strcmp(recipe_name, "detmon_opt_lg_mr") == 0 ) ||
8209  (strcmp(recipe_name, "detmon_ir_lg_mr")) == 0) {
8210  goto cleanup ;
8211  }
8212 
8213  // Count the number of extensions in this file
8214  cpl_frame_set_filename(fr, fn);
8215  int nexts = cpl_frame_get_nextensions(fr);
8216  if (nexts < 1) {
8217  cpl_msg_warning(cpl_func, "No extensions in %s, so no QC "
8218  "keywords to write", fn);
8219  // FIXME Identify correct error(s) to check against
8220  if (1) {
8221  cpl_error_reset();
8222  // Reset the error caused when trying to get nexts
8223  }
8224  goto cleanup;
8225  }
8226  cpl_msg_info(cpl_func, "Detected %d nexts", nexts);
8227  ehus = (cpl_propertylist**)cpl_malloc(nexts * sizeof(cpl_propertylist*));
8228  bpm_imgs = (cpl_image**)cpl_malloc(nexts * sizeof(cpl_image*));
8229 
8230  // Load up
8231  int j ;
8232  num_bpm = cpl_array_new(nexts, CPL_TYPE_INT);
8233 
8234  for (j=1; j<=nexts; ++j) {
8235  cpl_msg_info(cpl_func, "Loading ext %d", j);
8236  ehus[j-1] = cpl_propertylist_load(fn, j);
8237  bpm_imgs[j-1] = cpl_image_load(fn, CPL_BPP_IEEE_FLOAT, 0, j);
8238  if (cpl_propertylist_has(ehus[j-1], DETMON_QC_NUM_BPM)) {
8239  cpl_array_set_int(num_bpm, j-1,
8240  cpl_propertylist_get_int(ehus[j-1],
8241  DETMON_QC_NUM_BPM));
8242  }
8243  }
8244 
8245  // Compute values
8246  // QC NUM BPM AVG
8247  cpl_propertylist_append_double(phu, DETMON_QC_NUM_BPM_AVG,
8248  cpl_array_get_mean(num_bpm));
8249  cpl_propertylist_set_comment(phu, DETMON_QC_NUM_BPM_AVG,
8250  DETMON_QC_NUM_BPM_AVG_C);
8251 
8252  // Write out
8253  cpl_propertylist_save(phu, fn, CPL_IO_CREATE);
8254  for (j=1; j<=nexts; ++j) {
8255  cpl_image_save(bpm_imgs[j-1], fn, CPL_BPP_IEEE_FLOAT, ehus[j-1],
8256  CPL_IO_EXTEND);
8257  cpl_propertylist_delete(ehus[j-1]);
8258  cpl_image_delete(bpm_imgs[j-1]);
8259  }
8260 
8261  // Cleanup
8262  cleanup:
8263 
8264 // if (cpl_error_get_code() != CPL_ERROR_NONE) {
8265 // cpl_msg_error(__func__, "Error found in detmon_lg_qc_params_global_bpm_update!");
8266 // cpl_msg_error(__func__, "In %s, L%u", cpl_error_get_file(),
8267 // cpl_error_get_line());
8268 // cpl_msg_error(__func__, "%s", cpl_error_get_message());
8269 // getchar();
8270 // }
8271 
8272  cpl_msg_info(cpl_func, "Doing cleanup");
8273  cpl_free(ehus);
8274  cpl_propertylist_delete(phu);
8275 // cpl_msg_info(cpl_func, " ehus gone");
8276  cpl_free(bpm_imgs);
8277 // cpl_msg_info(cpl_func, " bpm_imgs gone");
8278  cpl_array_delete(num_bpm);
8279 // cpl_msg_info(cpl_func, " num_bpm gone");
8280  cpl_frame_delete(fr);
8281 // cpl_msg_info(cpl_func, " fr gone");
8282  cpl_msg_info(cpl_func, "...done!");
8283 
8284  return cpl_error_get_code();
8285 }
8286 
8287 
8288 cpl_error_code
8289 detmon_lg_qc_params_global_coeffs(const char * recipe_name, int nsets) {
8290  cpl_msg_info(cpl_func, "Going to update coeffs image for "
8291  "recipe %s, nsets=%d",
8292  recipe_name, nsets);
8293 
8294  cpl_error_code err = CPL_ERROR_NONE;
8295  char * fn ;
8296  if (nsets == 1) {
8297  fn = cpl_sprintf("%s_coeffs_cube.fits", recipe_name);
8298  cpl_msg_info(cpl_func, "Will be modifying %s", fn) ;
8299  err = detmon_lg_qc_params_global_coeffs_update(fn, recipe_name);
8300  cpl_free(fn);
8301  } else {
8302  int j;
8303  for (j=0; j<nsets; ++j) {
8304  fn = cpl_sprintf("%s_coeffs_cube_set%02d.fits",
8305  recipe_name, j);
8306  cpl_msg_info(cpl_func, "Will be modifying %s", fn);
8307  err = detmon_lg_qc_params_global_coeffs_update(fn, recipe_name);
8308  cpl_free(fn);
8309  }
8310  }
8311 
8312  return err;
8313 }
8314 
8315 cpl_error_code
8316 detmon_lg_qc_params_global_coeffs_update(const char * fn,
8317  const char * recipe_name) {
8318  cpl_msg_info(cpl_func, "Now updating %s", fn);
8319 
8320  cpl_propertylist* phu = cpl_propertylist_load(fn, 0);
8321  cpl_propertylist** ehus = NULL;
8322  cpl_imagelist** coeff_cubes = NULL;
8323  cpl_frame* fr = NULL;
8324  cpl_array* lin_coeff = NULL;
8325  cpl_array* lin_coeff_err = NULL;
8326  cpl_array* errfit = NULL;
8327  char* coeff_kw = NULL ;
8328  char* coeff_kw_err = NULL ;
8329  char* coeff_str = NULL ;
8330 
8331  // Count the number of extensions in this file
8332  fr = cpl_frame_new();
8333  cpl_frame_set_filename(fr, fn);
8334  int nexts = cpl_frame_get_nextensions(fr);
8335  if (nexts < 1) {
8336  cpl_msg_warning(cpl_func, "No extensions in %s, so no QC "
8337  "keywords to write", fn);
8338  // FIXME Identify correct error(s) to check against
8339  if (1) {
8340  cpl_error_reset();
8341  // Reset the error caused when trying to get nexts
8342  }
8343  goto cleanup;
8344  }
8345  // No-op for the MR recipes
8346  if ((strcmp(recipe_name, "detmon_opt_lg_mr") == 0 ) ||
8347  (strcmp(recipe_name, "detmon_ir_lg_mr")) == 0) {
8348  cpl_msg_info(cpl_func, "Skipping %s for recipe %s",
8349  cpl_func, recipe_name);
8350 // getchar();
8351  goto cleanup ;
8352  }
8353  cpl_msg_info(cpl_func, "Detected %d nexts", nexts);
8354  ehus = (cpl_propertylist**)cpl_malloc(nexts * sizeof(cpl_propertylist*));
8355  coeff_cubes = (cpl_imagelist**)cpl_malloc(nexts * sizeof(cpl_imagelist*));
8356  cpl_msg_info(cpl_func, "Malloc'd data structures for eventual re-write");
8357 
8358  // Load up (headers only)
8359  int j, coeff, coeff_max ;
8360 
8361  for (j=1; j<=nexts; ++j) {
8362  ehus[j-1] = cpl_propertylist_load(fn, j);
8363  }
8364  cpl_msg_info(__func__, "Loaded extension headers");
8365 
8366  // Compute
8367  cpl_msg_info(__func__, "Creating lin_coeff and errfit arrays...");
8368  lin_coeff = cpl_array_new(nexts, CPL_TYPE_DOUBLE);
8369  lin_coeff_err = cpl_array_new(nexts, CPL_TYPE_DOUBLE);
8370  errfit = cpl_array_new(nexts, CPL_TYPE_DOUBLE);
8371  cpl_msg_info(__func__, "...done!");
8372 
8373  if (strcmp(recipe_name, "detmon_ir_lg") == 0) {
8374  coeff_max = 0 ;
8375 
8376  cpl_msg_info(cpl_func, "Populating errfit arrays");
8377  for (j=1; j<=nexts; ++j) {
8378  if (cpl_propertylist_has(ehus[j-1], DETMON_QC_ERRFIT)) {
8379  cpl_array_set_double(
8380  errfit, j-1,
8381  cpl_propertylist_get_double(ehus[j-1],
8382  DETMON_QC_ERRFIT));
8383  }
8384  }
8385 
8386  cpl_msg_info(cpl_func, "Setting keywords with new funcs");
8387  detmon_lg_set_keyword_from_base_double(phu,
8388  DETMON_QC_ERRFIT, "AVG",
8389  DETMON_QC_ERRFIT,
8390  "AVG over exts.",
8391  cpl_array_get_mean(errfit));
8392 
8393  detmon_lg_set_keyword_from_base_double(phu,
8394  DETMON_QC_ERRFIT, "RMS",
8395  DETMON_QC_ERRFIT,
8396  "RMS over exts.",
8397  cpl_array_get_stdev(errfit));
8398 
8399  } else {
8400  coeff_max = 4 ;
8401  }
8402 
8403 // if (cpl_error_get_code() != CPL_ERROR_NONE) {
8404 // cpl_msg_error(__func__, "Error found in detmon_lg_qc_params_global_lin_update!");
8405 // cpl_msg_error(__func__, "At: before entering the coeff loop");
8406 // cpl_msg_error(__func__, "In %s, L%u", cpl_error_get_file(),
8407 // cpl_error_get_line());
8408 // cpl_msg_error(__func__, "%s", cpl_error_get_message());
8409 // getchar();
8410 // }
8411 
8412  for (coeff = 0 ; coeff < coeff_max + 1 ; ++coeff) {
8413  cpl_msg_info(cpl_func, "Forming coeff keyword %d", coeff);
8414  coeff_kw = cpl_sprintf("ESO QC LIN COEF%d", coeff);
8415  coeff_kw_err = cpl_sprintf("ESO QC LIN COEF%d ERR",
8416  coeff);
8417  coeff_str = cpl_sprintf("%d", coeff);
8418  // Re-fill the input arrays from the headers
8419 
8420  cpl_msg_info(cpl_func, "Reading in the coeff values");
8421  for (j=1; j<=nexts; ++j) {
8422  // FIXME Should not be hardcoded
8423  if (cpl_propertylist_has(ehus[j-1],
8424  coeff_kw)) {
8425  cpl_array_set_double(
8426  lin_coeff,
8427  j-1,
8428  cpl_propertylist_get_double(
8429  ehus[j-1],
8430  coeff_kw
8431  ));
8432  cpl_msg_info(cpl_func, "Added value %f to lin_coeff in pos %d",
8433  cpl_propertylist_get_double(
8434  ehus[j-1],
8435  coeff_kw
8436  ), j-1);
8437  }
8438  if (cpl_propertylist_has(ehus[j-1],
8439  coeff_kw_err)) {
8440  cpl_array_set_double(
8441  lin_coeff_err, j-1,
8442  cpl_propertylist_get_double(
8443  ehus[j-1],
8444  coeff_kw_err));
8445  }
8446 
8447  cpl_msg_info(__func__, "Insertions complete! (%d)", coeff);
8448 
8449 // if (cpl_error_get_code() != CPL_ERROR_NONE) {
8450 // cpl_msg_error(__func__, "Error found in detmon_lg_qc_params_global_lin_update!");
8451 // cpl_msg_error(__func__, "At: After insertions, before writing back");
8452 // cpl_msg_error(__func__, "In %s, L%u", cpl_error_get_file(),
8453 // cpl_error_get_line());
8454 // cpl_msg_error(__func__, "%s", cpl_error_get_message());
8455 // getchar();
8456 // }
8457  }
8458 
8459  // Write back the relevant header kws
8460  cpl_msg_info(cpl_func, "Writing back header keywords for %d", coeff);
8461  // ESO QC COEFF<i> AVG
8462  if (cpl_array_count_invalid(lin_coeff) < (cpl_size)nexts) {
8463  detmon_lg_set_keyword_from_insert_double(
8464  phu,
8465  DETMON_QC_LIN_COEFF_AVG, coeff_str,
8466  DETMON_QC_LIN_COEFF_AVG_C, coeff_str,
8467  cpl_array_get_mean(lin_coeff)
8468  );
8469 
8470  // ESO QC COEFF<i> RMS
8471  detmon_lg_set_keyword_from_insert_double(
8472  phu,
8473  DETMON_QC_LIN_COEFF_RMS, coeff_str,
8474  DETMON_QC_LIN_COEFF_RMS_C, coeff_str,
8475  cpl_array_get_stdev(lin_coeff)
8476  );
8477  }
8478 
8479  if (cpl_array_count_invalid(lin_coeff_err) < (cpl_size)nexts) {
8480  // ESO QC COEFF<i> ERR AVG
8481  detmon_lg_set_keyword_from_insert_double(
8482  phu,
8483  DETMON_QC_LIN_COEFF_ERR_AVG, coeff_str,
8484  DETMON_QC_LIN_COEFF_ERR_AVG_C, coeff_str,
8485  cpl_array_get_mean(lin_coeff_err)
8486  );
8487 
8488  // ESO QC COEFF<i> ERR RMS
8489  detmon_lg_set_keyword_from_insert_double(
8490  phu,
8491  DETMON_QC_LIN_COEFF_ERR_RMS, coeff_str,
8492  DETMON_QC_LIN_COEFF_ERR_RMS_C, coeff_str,
8493  cpl_array_get_stdev(lin_coeff)
8494  );
8495  }
8496 
8497  cpl_msg_info(__func__, "Data write complete! (%d)", coeff);
8498 
8499 // if (cpl_error_get_code() != CPL_ERROR_NONE) {
8500 // cpl_msg_error(__func__, "Error found in detmon_lg_qc_params_global_lin_update!");
8501 // cpl_msg_error(__func__, "At: the end of the coeff loop calculations");
8502 // cpl_msg_error(__func__, "In %s, L%u, called by %s", cpl_error_get_file(),
8503 // cpl_error_get_line(), cpl_error_get_function());
8504 // cpl_msg_error(__func__, "lin_coeff is:");
8505 // cpl_array_dump_structure(lin_coeff, stdout);
8506 // cpl_msg_error(__func__, "%s", cpl_error_get_message());
8507 // getchar();
8508 // }
8509 
8510  // Blank the input arrays
8511  cpl_array_fill_window_invalid(lin_coeff, 0, nexts);
8512  cpl_array_fill_window_invalid(lin_coeff_err, 0, nexts);
8513  cpl_msg_info(__func__, "Arrays reset! (%d)", coeff);
8514 
8515 // if (cpl_error_get_code() != CPL_ERROR_NONE) {
8516 // cpl_msg_error(__func__, "Error found in detmon_lg_qc_params_global_lin_update!");
8517 // cpl_msg_error(__func__, "At: the end of the coeff loop input array reset");
8518 // cpl_msg_error(__func__, "In %s, L%u, called by %s", cpl_error_get_file(),
8519 // cpl_error_get_line(), cpl_error_get_function());
8520 // cpl_msg_error(__func__, "%s", cpl_error_get_message());
8521 // getchar();
8522 // }
8523 
8524  cpl_msg_info(cpl_func, "Purging the coeff keywords");
8525  cpl_free(coeff_kw);
8526  cpl_free(coeff_kw_err);
8527  cpl_free(coeff_str);
8528  coeff_kw = NULL ;
8529  coeff_kw_err = NULL ;
8530  coeff_str = NULL ;
8531 
8532 // if (cpl_error_get_code() != CPL_ERROR_NONE) {
8533 // cpl_msg_error(__func__, "Error found in detmon_lg_qc_params_global_lin_update!");
8534 // cpl_msg_error(__func__, "At: the end of the coeff loop mem management");
8535 // cpl_msg_error(__func__, "In %s, L%u, called by %s", cpl_error_get_file(),
8536 // cpl_error_get_line(), cpl_error_get_function());
8537 // cpl_msg_error(__func__, "lin_coeff is:");
8538 // cpl_array_dump_structure(lin_coeff, stdout);
8539 // cpl_msg_error(__func__, "%s", cpl_error_get_message());
8540 // getchar();
8541 // }
8542  }
8543 
8544 // if (cpl_error_get_code() != CPL_ERROR_NONE) {
8545 // cpl_msg_error(__func__, "Error found in detmon_lg_qc_params_global_lin_update!");
8546 // cpl_msg_error(__func__, "At: after the coeff loop call");
8547 // cpl_msg_error(__func__, "In %s, L%u, called by %s", cpl_error_get_file(),
8548 // cpl_error_get_line(), cpl_error_get_function());
8549 // cpl_msg_error(__func__, "%s", cpl_error_get_message());
8550 // getchar();
8551 // }
8552 
8553 
8554  // Write out
8555  // Load up data (wait til here to save on memory)
8556  for (j=1; j<=nexts; ++j) {
8557  coeff_cubes[j-1] = cpl_imagelist_load(fn, CPL_BPP_IEEE_FLOAT, j);
8558  }
8559  cpl_propertylist_save(phu, fn, CPL_IO_CREATE);
8560  for (j=1; j<=nexts; ++j) {
8561  cpl_imagelist_save(coeff_cubes[j-1], fn, CPL_BPP_IEEE_FLOAT, ehus[j-1],
8562  CPL_IO_EXTEND);
8563 // Memory improvement - remove them here
8564  cpl_propertylist_delete(ehus[j-1]);
8565  cpl_imagelist_delete(coeff_cubes[j-1]);
8566  }
8567  cpl_msg_info(__func__, "Removed all file data in memory");
8568 
8569  cleanup:
8570 // if (cpl_error_get_code() != CPL_ERROR_NONE) {
8571 // cpl_msg_error(__func__, "Error found in detmon_lg_qc_params_global_lin_update!");
8572 // cpl_msg_error(__func__, "At the start of the cleanup marker");
8573 // cpl_msg_error(__func__, "In %s, L%u called by %s", cpl_error_get_file(),
8574 // cpl_error_get_line(), cpl_error_get_function());
8575 // cpl_msg_error(__func__, "%s", cpl_error_get_message());
8576 // getchar();
8577 // }
8578 
8579  // Cleanup
8580  cpl_msg_info(cpl_func, "Doing cleanup...");
8581  cpl_free(ehus);
8582 // cpl_msg_info(cpl_func, " ehus gone");
8583  cpl_propertylist_delete(phu);
8584 // cpl_msg_info(cpl_func, " phus gone");
8585  cpl_free(coeff_cubes);
8586 // cpl_msg_info(cpl_func, " coeff_cubes gone");
8587  cpl_frame_delete(fr);
8588 // cpl_msg_info(cpl_func, " fr gone");
8589  cpl_array_delete(lin_coeff);
8590 // cpl_msg_info(cpl_func, " lin_coeff gone");
8591  cpl_array_delete(lin_coeff_err);
8592 // cpl_msg_info(cpl_func, " lin_coeff_err gone");
8593  cpl_array_delete(errfit);
8594 // cpl_msg_info(cpl_func, " errfit gone");
8595  cpl_msg_info(cpl_func, "...done!");
8596  return cpl_error_get_code();
8597 }
8598 
8599 cpl_error_code
8600 detmon_lg_qc_set_kw_from_table_column(cpl_table* table,
8601  const char * column,
8602  const char * op,
8603  cpl_propertylist* header,
8604  const char * kw,
8605  const char * kw_comment) {
8606  double value ;
8607  if (strcmp(op, "mean") == 0) {
8608  value = cpl_table_get_column_mean(table, column);
8609  } else if (strcmp(op, "stdev") == 0) {
8610  value = cpl_table_get_column_stdev(table, column);
8611  } else {
8612  cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
8613  return cpl_error_get_code();
8614  }
8615 
8616  cpl_propertylist_append_double(header, kw, value);
8617  if (kw_comment != NULL) {
8618  cpl_propertylist_set_comment(header, kw, kw_comment);
8619  }
8620  return cpl_error_get_code();
8621 }
8622