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