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