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