DETMON Pipeline Reference Manual  1.2.7
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  /* TODO: We removed this check as with NACO data, that has an odd
2913  * number of input OFF frames it would stop with error
2914  * despite the recipe would reduce the data properly.
2915  * On the other side, on some data without such a check one may get
2916  * failures on another place.
2917  * we need to document such cases and understand how to better deal
2918  * in a robust way the case of odd input off frames
2919  *
2920  if (cpl_frameset_get_size(set_off) % 2 != 0) {
2921  cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
2922  "If collapse is FALSE the OFF frameset"
2923  " must be organized in pairs.");
2924  skip_if(1);
2925  }
2926  */
2927  if (!strcmp(detmon_lg_config.method, "MED") ||
2928  cpl_frameset_get_size(set_on) == cpl_frameset_get_size(set_off))
2929  {
2930  skip_if(detmon_pair_extract_next(set_off, index_off, next_off, exptime_off, &pair_off, detmon_lg_config.tolerance));
2931  }
2932  else
2933  {
2934  skip_if(detmon_single_extract_next(set_off, index_off, next_off, exptime_off, &pair_off));
2935  }
2936  /* Load the OFF images */
2937  cpl_msg_debug(cpl_func, " Load the OFF images, ext[%d], exptime[%f]", whichext, exptime_off[*next_off - 1]);
2938  offs = detmon_lg_config.load_fset_wrp(pair_off, CPL_TYPE_FLOAT, whichext);
2939 
2940  skip_if(offs == NULL);
2941  skip_if(cpl_error_get_code());
2942  }
2943  else {
2944  offs = (cpl_imagelist *) opt_offs;
2945  }
2946 
2947  /* Rescaling */
2948  if(detmon_lg_config.rescale)
2949  {
2950  skip_if(detmon_lg_rescale(ons));
2951  if (!detmon_lg_config.collapse &&
2952  !strcmp(detmon_lg_config.method, "MED"))
2953  skip_if(detmon_lg_rescale(offs));
2954  }
2955  /* DIT or EXPTIME value extraction */
2956 
2957  filename =
2958  cpl_frame_get_filename(cpl_frameset_get_first_const(pair_on));
2959  skip_if ((plist = cpl_propertylist_load(filename, 0)) == NULL);
2960  /* Add columns to the tables DETi WINi UITi*/
2961  if (plist)
2962  {
2963  pDETlist = cpl_propertylist_new();
2964  cpl_propertylist_copy_property_regexp(pDETlist, plist, "DET[0-9]* WIN[0-9]* UIT[0-9]*",0);
2965  if (dit_nb == 0)
2966  {
2967  irplib_table_create_column(gain_table, pDETlist);
2968  irplib_table_create_column(linear_table, pDETlist);
2969  }
2970  }
2971  if(opt_nir == NIR) {
2972  c_dit = irplib_pfits_get_dit(plist);
2973  c_ndit = irplib_pfits_get_ndit(plist);
2974  } else {
2975  c_dit = irplib_pfits_get_exptime(plist);
2976  c_ndit=1;
2977  }
2978 
2979  /*
2980  * --GAIN part for each DIT value--
2981  * The following call to detmon_gain_table_fill_row() fills
2982  * in the row nb i
2983  * of the GAIN table (output) and of the FIT table (by-product to be
2984  * used later for the polynomial computation of the GAIN)
2985  */
2986 
2987  cpl_msg_info(cpl_func, "Computing GAIN for EXPTIME value nb %d",
2988  dit_nb + 1);
2989 
2990  /* In case PTC is applied, this is allowed */
2991  if(cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE && dit_nb == 0)
2992  {
2993  cpl_table_erase_column(gain_table, "MEAN_OFF1");
2994  cpl_table_erase_column(gain_table, "MEAN_OFF2");
2995  cpl_table_erase_column(gain_table, "SIG_OFF_DIF");
2996  cpl_table_erase_column(gain_table, "GAIN");
2997  cpl_table_erase_column(gain_table, "GAIN_CORR");
2998  cpl_table_new_column(gain_table, "MEAN_OFF", CPL_TYPE_DOUBLE);
2999  }
3000 
3001  skip_if(detmon_gain_table_fill_row(gain_table,
3002  c_dit,c_ndit,
3003  autocorr_images,
3004  diff_flats, ons, offs,
3005  detmon_lg_config.kappa,
3006  detmon_lg_config.niter,
3007  detmon_lg_config.llx,
3008  detmon_lg_config.lly,
3009  detmon_lg_config.urx,
3010  detmon_lg_config.ury,
3011  detmon_lg_config.m,
3012  detmon_lg_config.n,
3013  detmon_lg_config.saturation_limit,
3014  dit_nb, mode, rows_affected));
3015 
3016 
3017  if (*rows_affected)
3018  {
3019  /* fill DETi WINi OPTi columns - see DFS06921*/
3020  skip_if(irplib_fill_table_DETWINUIT(gain_table, pDETlist, dit_nb));
3021  /* Linearity reduction */
3022  cpl_msg_info(cpl_func, "Linearity reduction for nb %d",
3023  dit_nb + 1);
3024  skip_if(detmon_lin_table_fill_row(linear_table, c_dit,
3025  linearity_inputs, ons, offs,
3026  detmon_lg_config.llx,
3027  detmon_lg_config.lly,
3028  detmon_lg_config.urx,
3029  detmon_lg_config.ury,
3030  dit_nb, *dit_nskip, mode));
3031  /* fill DETi WINi OPTi columns - see DFS06921*/
3032  skip_if(irplib_fill_table_DETWINUIT(linear_table, pDETlist, dit_nb));
3033  }
3034 
3035 
3036  /* as we know only at this point if a frame is
3037  saturated or not, and we would like to compute the
3038  contamination only on the last non saturated frame,
3039  we need de facto to compute saturation on any non saturated
3040  frame, by overwriting the QC parameter. In the end it will
3041  remain only the last value corresponding to a non saturated
3042  frame */
3043 
3044  if(opt_nir == OPT &&
3045  *rows_affected != 0 ) {
3046  detmon_opt_contamination(ons, offs, mode, qclist);
3047  }
3048 
3049  }
3050 
3051  end_skip;
3052 
3053  cpl_frameset_delete(pair_on);
3054  cpl_imagelist_delete(ons);
3055 
3056  if(!detmon_lg_config.collapse ) {
3057  cpl_imagelist_delete(offs);
3058  }
3059 
3060  if(!detmon_lg_config.collapse) {
3061  cpl_frameset_delete(pair_off);
3062  }
3063 
3064  cpl_propertylist_delete(plist);
3065  cpl_propertylist_delete(pDETlist);
3066  return cpl_error_get_code();
3067 }
3068 
3069 /*---------------------------------------------------------------------------*/
3075 /*---------------------------------------------------------------------------*/
3076 static cpl_error_code
3077 detmon_add_adl_column(cpl_table * table,
3078  cpl_boolean opt_nir)
3079 {
3080  cpl_error_code error;
3081  double mean_med_dit;
3082  double *dits;
3083 
3084  cpl_ensure_code(table != NULL, CPL_ERROR_NULL_INPUT);
3085 
3086  mean_med_dit = cpl_table_get_column_mean(table, "MED_DIT");
3087  if (opt_nir == OPT)
3088  dits = cpl_table_get_data_double(table, "EXPTIME");
3089  else
3090  dits = cpl_table_get_data_double(table, "DIT");
3091 
3092  error = cpl_table_copy_data_double(table, "ADL", dits);
3093  cpl_ensure_code(!error, error);
3094  error = cpl_table_multiply_scalar(table, "ADL", mean_med_dit);
3095  cpl_ensure_code(!error, error);
3096 
3097  return cpl_error_get_code();
3098 }
3099 
3100 /*---------------------------------------------------------------------------*/
3108 /*---------------------------------------------------------------------------*/
3109 static cpl_error_code
3110 detmon_lg_reduce_init(cpl_table * gain_table,
3111  cpl_table * linear_table,
3112  cpl_imagelist ** linearity_inputs,
3113  const cpl_boolean opt_nir)
3114 {
3115  skip_if(detmon_gain_table_create(gain_table, opt_nir));
3116  skip_if(detmon_lin_table_create(linear_table, opt_nir));
3117 
3118  if(detmon_lg_config.pix2pix) {
3119  *linearity_inputs = cpl_imagelist_new();
3120  skip_if(*linearity_inputs == NULL);
3121  }
3122 
3123  end_skip;
3124 
3125  return cpl_error_get_code();
3126 }
3127 
3128 /*--------------------------------------------------------------------------*/
3134 /*--------------------------------------------------------------------------*/
3135 static double
3136 irplib_pfits_get_dit(const cpl_propertylist * plist)
3137 {
3138  return irplib_pfits_get_prop_double(plist, "ESO DET DIT");
3139 }
3140 
3141 /*--------------------------------------------------------------------------*/
3147 /*--------------------------------------------------------------------------*/
3148 static double
3149 irplib_pfits_get_dit_opt(const cpl_propertylist * plist)
3150 {
3151  return irplib_pfits_get_prop_double(plist, "ESO DET WIN1 UIT1");
3152 }
3153 
3154 
3155 /*---------------------------------------------------------------------------*/
3160 static cpl_propertylist*
3161 detmon_load_pro_keys(const char* NAME_O)
3162 {
3163  cpl_propertylist* pro_keys=NULL;
3164  pro_keys=cpl_propertylist_load_regexp(NAME_O,0,"^(ESO PRO)",0);
3165  return pro_keys;
3166 }
3167 
3168 
3169 static double irplib_pfits_get_prop_double(const cpl_propertylist * plist,
3170  const char* prop_name)
3171 {
3172  double dit;
3173  dit = cpl_propertylist_get_double(plist, prop_name);
3174  if(cpl_error_get_code() != CPL_ERROR_NONE)
3175  {
3176  cpl_msg_error(cpl_func, "Cannot read property '%s', err[%s]",
3177  prop_name, cpl_error_get_where());
3178  }
3179  return dit;
3180 }
3181 
3182 /*---------------------------------------------------------------------------*/
3214 /*---------------------------------------------------------------------------*/
3215 static cpl_error_code
3216 detmon_gain_table_fill_row(cpl_table * gain_table,
3217  double c_dit,int c_ndit,
3218  cpl_imagelist * autocorr_images,
3219  cpl_imagelist * diff_flats,
3220  const cpl_imagelist * ons,
3221  const cpl_imagelist * offs,
3222  double kappa, int nclip,
3223  int llx, int lly, int urx, int ury,
3224  int m, int n,
3225  double saturation_limit,
3226  const int pos, unsigned mode, int* rows_affected)
3227 {
3228  const cpl_image *image;
3229  cpl_image *on_dif = NULL;
3230  double std = 0;
3231  double avg_on1, avg_on2;
3232  double avg_off1, avg_off2;
3233  double double_adu, autocorr, gain, gain_corr;
3234  double sigma;
3235 
3236  cpl_table_set(gain_table, "FLAG", pos, 1);
3237  if (mode & IRPLIB_GAIN_NIR)
3238  {
3239  cpl_table_set(gain_table, "DIT", pos, c_dit);
3240  cpl_table_set(gain_table, "NDIT", pos, c_ndit);
3241  } else if (mode & IRPLIB_GAIN_OPT)
3242  {
3243  cpl_table_set(gain_table, "EXPTIME", pos, c_dit);
3244  } else
3245  {
3246  cpl_msg_error(cpl_func, "Mandatory mode (OPT or NIR) not provided");
3247  skip_if(1);
3248  }
3249  if(*rows_affected == 0)
3250  {
3251  cpl_msg_info(cpl_func, "skip the frame #%d", pos + 1);
3252  cpl_table_set(gain_table, "FLAG", pos, 0);
3253  if(mode & IRPLIB_GAIN_WITH_AUTOCORR)
3254  {
3255  autocorr = -1;
3256  if (diff_flats)
3257  {
3258  detmon_lg_add_empty_image(diff_flats, pos);
3259  }
3260  if (autocorr_images)
3261  {
3262  detmon_lg_add_empty_image(autocorr_images, pos);
3263  }
3264  }
3265  return cpl_error_get_code();
3266  }
3267  skip_if((image = cpl_imagelist_get_const(ons, 0)) == NULL);
3268  skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
3269  nclip, 1e-5, &avg_on1, &std));
3270  skip_if((image = cpl_imagelist_get_const(ons, 1)) == NULL);
3271  skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
3272  nclip, 1e-5, &avg_on2, &std));
3273 
3274  if ((avg_on1 > saturation_limit) || (avg_on2 > saturation_limit))
3275  {
3276  cpl_msg_warning(cpl_func, "Average saturation is above the limit, "
3277  "the frames would not be taken into calculation");
3278  cpl_msg_warning(cpl_func, "saturation levels [%f ; %f], limit [%f]",
3279  avg_on1, avg_on2, saturation_limit);
3280  cpl_msg_info(cpl_func, "skip the frame #%d", pos + 1);
3281  cpl_table_set(gain_table, "FLAG", pos, 0);
3282  if(mode & IRPLIB_GAIN_WITH_AUTOCORR)
3283  {
3284  autocorr = -1;
3285  if (diff_flats)
3286  {
3287  detmon_lg_add_empty_image(diff_flats, pos);
3288  }
3289  if (autocorr_images)
3290  {
3291  detmon_lg_add_empty_image(autocorr_images, pos);
3292  }
3293  }
3294  *rows_affected = 0;
3295  }
3296  else
3297  {
3298  double sig_off_dif;
3299  *rows_affected = 1;
3300  skip_if(cpl_table_set_double(gain_table, "MEAN_ON1", pos, avg_on1));
3301  skip_if(cpl_table_set_double(gain_table, "MEAN_ON2", pos, avg_on2));
3302 
3303  on_dif =
3304  detmon_subtract_create_window(cpl_imagelist_get_const(ons, 0),
3305  cpl_imagelist_get_const(ons, 1),
3306  llx, lly, urx, ury);
3307  skip_if(on_dif == NULL);
3308 
3309  if(mode & IRPLIB_GAIN_WITH_AUTOCORR)
3310  {
3311  if (diff_flats)
3312  {
3313  cpl_image * diff = cpl_image_duplicate(on_dif);
3314  skip_if(cpl_imagelist_set(diff_flats, diff, pos));
3315  }
3316  if (autocorr_images)
3317  {
3318  cpl_image * corr = NULL;
3319  autocorr = detmon_autocorr_factor(on_dif, &corr, m, n);
3320  if(corr)
3321  {
3322  skip_if(cpl_imagelist_set(autocorr_images, corr, pos));
3323  }
3324  else
3325  {
3326  detmon_lg_add_empty_image(autocorr_images, pos);
3327  }
3328  } else
3329  {
3330  autocorr = detmon_autocorr_factor(on_dif, NULL, m, n);
3331  }
3332  autocorr = isnan(autocorr) ? 1.0 : autocorr;
3333  } else
3334  {
3335  autocorr = 1.0;
3336  }
3337 
3338  if (cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE)
3339  {
3340 
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_OFF", pos, avg_off1));
3345 
3346  } else if (mode & IRPLIB_GAIN_NO_COLLAPSE ||
3347  ( pos == 0 && mode & IRPLIB_GAIN_COLLAPSE )) {
3348  cpl_image * off_dif = NULL;
3349  double avg_off_dif;
3350  skip_if(irplib_ksigma_clip(cpl_imagelist_get_const(offs, 0),
3351  llx, lly, urx, ury, kappa, nclip,
3352  1e-5, &avg_off1, &std));
3353  skip_if(cpl_table_set_double(gain_table, "MEAN_OFF1", pos, avg_off1));
3354  skip_if(irplib_ksigma_clip(cpl_imagelist_get_const(offs, 1),
3355  llx, lly, urx, ury, kappa, nclip,
3356  1e-5, &avg_off2, &std));
3357  skip_if(cpl_table_set_double(gain_table, "MEAN_OFF2", pos, avg_off2));
3358  off_dif =
3359  detmon_subtract_create_window(cpl_imagelist_get_const(offs, 0),
3360  cpl_imagelist_get_const(offs, 1),
3361  llx, lly, urx, ury);
3362  skip_if(off_dif == NULL);
3363  irplib_ksigma_clip(off_dif, 1, 1,
3364  cpl_image_get_size_x(off_dif),
3365  cpl_image_get_size_y(off_dif),
3366  kappa, nclip,
3367  1e-5, &avg_off_dif, &sig_off_dif);
3368  cpl_image_delete(off_dif);
3369  skip_if(cpl_table_set_double(gain_table, "SIG_OFF_DIF",
3370  pos, sig_off_dif));
3371  } else if (pos > 0 && mode & IRPLIB_GAIN_COLLAPSE)
3372  {
3373  int status;
3374  avg_off1 = cpl_table_get_double(gain_table, "MEAN_OFF1", 0, &status);
3375  skip_if(cpl_table_set_double(gain_table, "MEAN_OFF1", pos, avg_off1));
3376  avg_off2 = cpl_table_get_double(gain_table, "MEAN_OFF2", 0, &status);
3377  skip_if(cpl_table_set_double(gain_table, "MEAN_OFF2", pos, avg_off2));
3378  sig_off_dif = cpl_table_get_double(gain_table, "SIG_OFF_DIF",
3379  0, &status);
3380  skip_if(cpl_table_set_double(gain_table, "SIG_OFF_DIF",
3381  pos, sig_off_dif));
3382  }
3383 
3384  {
3385  double avg_on_dif, sig_on_dif;
3386  irplib_ksigma_clip(on_dif, 1, 1,
3387  cpl_image_get_size_x(on_dif),
3388  cpl_image_get_size_y(on_dif), kappa,
3389  nclip, 1e-5, &avg_on_dif, &sig_on_dif);
3390  skip_if(cpl_table_set_double(gain_table, "SIG_ON_DIF", pos, sig_on_dif));
3391 
3392  if (cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE)
3393  {
3394  double_adu = (avg_on1 + avg_on2) - 2 * avg_off1;
3395  }
3396  else
3397  {
3398  double_adu = (avg_on1 + avg_on2) - (avg_off1 + avg_off2);
3399 
3400  sigma = (sig_on_dif * sig_on_dif) - (sig_off_dif * sig_off_dif);
3401 
3402  /* sigma_corr = autocorr * sigma; */
3403 
3404  gain = double_adu / (c_ndit * sigma);
3405 
3406  gain_corr = gain / (autocorr);
3407 
3408  skip_if(cpl_table_set_double(gain_table, "GAIN", pos, gain));
3409  skip_if(cpl_table_set_double(gain_table, "GAIN_CORR", pos, gain_corr));
3410  }
3411  /* cpl_msg_info(cpl_func,"gain=%g gain_corr=%g autocorr=%g",gain,gain_corr,autocorr); */
3412  skip_if(cpl_table_set_double(gain_table, "AUTOCORR", pos, autocorr));
3413  skip_if(cpl_table_set_double(gain_table, "ADU", pos, double_adu / 2));
3414 
3415  /* FIXME: Remove the following 3 columns after testing period */
3416  skip_if(cpl_table_set_double(gain_table, "Y_FIT",
3417  pos,
3418  c_ndit* sig_on_dif * sig_on_dif));
3419  skip_if(cpl_table_set_double(gain_table, "Y_FIT_CORR",
3420  pos,
3421  c_ndit * sig_on_dif * sig_on_dif));
3422  skip_if(cpl_table_set_double(gain_table, "X_FIT", pos, double_adu));
3423  skip_if(cpl_table_set_double(gain_table, "X_FIT_CORR",
3424  pos, double_adu / autocorr));
3425  }
3426  }
3427  end_skip;
3428 
3429  cpl_image_delete(on_dif);
3430 
3431  return cpl_error_get_code();
3432 }
3433 
3434 /*--------------------------------------------------------------------------*/
3441 /*--------------------------------------------------------------------------*/
3442 
3443 static cpl_image *
3444 detmon_bpixs(const cpl_imagelist * coeffs,
3445  cpl_boolean bpmbin,
3446  const double kappa,
3447  int *nbpixs)
3448 {
3449  int size;
3450  int i;
3451  const cpl_image *first= cpl_imagelist_get_const(coeffs, 0);
3452  cpl_stats *stats;
3453  double cur_mean;
3454  double cur_stdev;
3455  double lo_cut;
3456  double hi_cut;
3457  cpl_mask *cur_mask;
3458  cpl_mask *mask = cpl_mask_new(cpl_image_get_size_x(first),
3459  cpl_image_get_size_y(first));
3460  cpl_image *cur_image = NULL;
3461  cpl_image *bpm = NULL; /* Avoid false uninit warning */
3462  double p;
3463 
3464  size = cpl_imagelist_get_size(coeffs);
3465 
3466  if(!bpmbin) {
3467  bpm = cpl_image_new(cpl_image_get_size_x(first),
3468  cpl_image_get_size_y(first),
3469  CPL_TYPE_INT);
3470  }
3471 
3472 
3473  for(i = 0; i < size; i++) {
3474  const cpl_image * cur_coeff = cpl_imagelist_get_const(coeffs, i);
3475 
3476  stats = cpl_stats_new_from_image(cur_coeff,
3477  CPL_STATS_MEAN | CPL_STATS_STDEV);
3478  cur_mean = cpl_stats_get_mean(stats);
3479  cur_stdev = cpl_stats_get_stdev(stats);
3480 
3481  lo_cut = cur_mean - kappa * cur_stdev;
3482  hi_cut = cur_mean + kappa * cur_stdev;
3483 
3484  cur_mask = cpl_mask_threshold_image_create(cur_coeff, lo_cut, hi_cut);
3485  cpl_mask_not(cur_mask);
3486 
3487  if(!bpmbin) {
3488  cur_image = cpl_image_new_from_mask(cur_mask);
3489  p = pow(2, i);
3490  cpl_image_power(cur_image, p);
3491  cpl_image_add(bpm, cur_image);
3492  cpl_image_delete(cur_image);
3493  }
3494 
3495  cpl_mask_or(mask, cur_mask);
3496 
3497  cpl_mask_delete(cur_mask);
3498  cpl_stats_delete(stats);
3499  }
3500 
3501  if(bpmbin) {
3502  bpm = cpl_image_new_from_mask(mask);
3503  }
3504 
3505  *nbpixs += cpl_mask_count(mask);
3506 
3507  cpl_mask_delete(mask);
3508 
3509  return bpm;
3510 }
3511 
3512 
3513 /*--------------------------------------------------------------------------*/
3520 /*--------------------------------------------------------------------------*/
3521 /* Not used so we temporary comment it out
3522 static cpl_image *
3523 detmon_bpixs2(cpl_vector* x,const cpl_imagelist* y,
3524  const cpl_imagelist * coeffs,cpl_table* gain_table,
3525  const int order, const double kappa,cpl_boolean bpmbin,
3526  int *nbpixs)
3527 {
3528 
3529 
3530  int size_x=0;
3531  int size_y=0;
3532  int size_c=0;
3533 
3534 
3535  int i=0;
3536  int j=0;
3537  cpl_size k=0;
3538  int z=0;
3539  int pix=0;
3540  int sx=0;
3541  int sy=0;
3542 
3543  double* px=NULL;
3544  const float* pdata=NULL;
3545  const float* pcoeffs=NULL;
3546  double pfit=0.;
3547  double* pgain=NULL;
3548  cpl_binary* pmask=NULL;
3549  double gain=0;
3550  const cpl_image* img_data=NULL;
3551 
3552  const cpl_image* img_coeffs=NULL;
3553  cpl_image* bpm=NULL;
3554  cpl_mask* mask=NULL;
3555 
3556  cpl_polynomial* pol=NULL;
3557 
3558  size_x = cpl_vector_get_size(x);
3559  size_y = cpl_imagelist_get_size(y);
3560  size_c = cpl_imagelist_get_size(coeffs);
3561  img_data = cpl_imagelist_get_const(coeffs, 0);
3562  sx = cpl_image_get_size_x(img_data);
3563  sy = cpl_image_get_size_y(img_data);
3564  mask = cpl_mask_new(sx,sy);
3565 
3566  cpl_ensure(size_x == size_y, CPL_ERROR_NULL_INPUT, NULL);
3567 
3568  cpl_ensure(size_c == (order+1), CPL_ERROR_NULL_INPUT, NULL);
3569 
3570  px = cpl_vector_get_data(x);
3571  pmask=cpl_mask_get_data(mask);
3572  pgain=cpl_table_get_data_double(gain_table,"GAIN");
3573  pol=cpl_polynomial_new(1);
3574  for (z = 0; z < size_x; z++) {
3575 
3576  img_data = cpl_imagelist_get_const(y, z);
3577  pdata = cpl_image_get_data_float_const(img_data);
3578  gain=pgain[z];
3579 
3580  for (j = 0; j < sy; j++) {
3581 
3582  for (i = 0; i < sx; i++) {
3583 
3584  pix = j * sx + i;
3585 
3586  for (k = size_c-1; k >= 0; k--) {
3587 
3588  img_coeffs = cpl_imagelist_get_const(coeffs, k);
3589  pcoeffs = cpl_image_get_data_float_const(img_coeffs);
3590  cpl_polynomial_set_coeff(pol, &k, pcoeffs[pix]);
3591 
3592  }
3593 
3594  pfit = cpl_polynomial_eval_1d(pol,px[z],NULL);
3595  if (pdata[pix] > 0) {
3596  if (fabs(pdata[pix] - pfit) > kappa * sqrt(gain*pdata[pix])) {
3597  pmask[pix] = CPL_BINARY_1;
3598  } // check if point to be flagged
3599  } // check if pos intensity
3600  } // i loop
3601  } // j loop
3602 
3603  //cpl_image_delete(img_data);
3604 
3605  } // z loop
3606  cpl_polynomial_delete(pol);
3607  if (bpmbin) {
3608  bpm = cpl_image_new_from_mask(mask);
3609  }
3610 
3611  *nbpixs += cpl_mask_count(mask);
3612 
3613  cpl_mask_delete(mask);
3614 
3615  return bpm;
3616 }
3617 
3618 */
3619 /*---------------------------------------------------------------------------*/
3631 /*---------------------------------------------------------------------------*/
3632 
3633 static double
3634 detmon_autocorr_factor(const cpl_image * image,
3635  cpl_image ** autocorr_image, int m, int n)
3636 {
3637  cpl_image * mycorr_image = NULL;
3638  double autocorr = 0;
3639  cpl_error_code err = CPL_ERROR_NONE;
3640 
3641  mycorr_image = detmon_image_correlate(image, image, m, n);
3642  err=cpl_error_get_code();
3643  if (err == CPL_ERROR_UNSUPPORTED_MODE)
3644  {
3645  cpl_msg_warning(cpl_func, "FFTW is not supported by CPL, autocorrelation "
3646  "would be computed using internal implementation");
3647  cpl_error_reset();
3648  if (mycorr_image)
3649  cpl_image_delete(mycorr_image);
3650  mycorr_image = detmon_autocorrelate(image, m, n);
3651  }
3652  if(mycorr_image == NULL) {
3653  return -1;
3654  }
3655 
3656  cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), -1);
3657 
3658  autocorr = cpl_image_get_flux(mycorr_image);
3659 
3660  if (autocorr_image) *autocorr_image = mycorr_image;
3661  else cpl_image_delete(mycorr_image);
3662 
3663  return autocorr;
3664 }
3665 
3666 static cpl_propertylist*
3667 detmon_lg_extract_qclist_4plane(cpl_propertylist* linc_qclist,const int ip)
3668 {
3669 
3670  cpl_propertylist* sub_set=NULL;
3671  char* qc_key=NULL;
3672 
3673  sub_set=cpl_propertylist_new();
3674  qc_key=cpl_sprintf("QC LIN COEF%d",ip);
3675  cpl_propertylist_copy_property_regexp(sub_set,linc_qclist,qc_key,0);
3676 
3677  cpl_free(qc_key);
3678  return sub_set;
3679 
3680 }
3681 
3682 
3692 static cpl_error_code
3693 detmon_lg_extract_extention_header(cpl_frameset* frameset,
3694  cpl_propertylist* gaint_qclist,
3695  cpl_propertylist* lint_qclist,
3696  cpl_propertylist* linc_qclist,
3697  cpl_propertylist* bpm_qclist,
3698  int whichext)
3699 {
3700 
3701  cpl_propertylist * xplist = NULL;
3702 
3703  const char * filename =
3704  cpl_frame_get_filename(cpl_frameset_get_first(frameset));
3705 
3706  xplist = cpl_propertylist_load_regexp(filename, whichext,
3707  "ESO DET|EXTNAME", 0);
3708  if (detmon_lg_config.exts >= 0)
3709  {
3710  /* for one extension, copy only extname keyword (if any) - DFS09856 */
3711  cpl_property* propExtname = NULL;
3712  propExtname = cpl_propertylist_get_property(xplist, "EXTNAME");
3713  cpl_error_reset();
3714  if (NULL != propExtname)
3715  {
3716  propExtname = cpl_property_duplicate(propExtname);
3717  }
3718  cpl_propertylist_delete(xplist);
3719  xplist = NULL;
3720  if (NULL != propExtname)
3721  {
3722  xplist = cpl_propertylist_new();
3723  cpl_propertylist_append_property(xplist, propExtname);
3724  cpl_property_delete(propExtname);
3725  }
3726  }
3727  if (NULL != xplist)
3728  {
3729  cpl_propertylist_append(gaint_qclist, xplist);
3730  cpl_propertylist_append(lint_qclist, xplist);
3731  cpl_propertylist_append(linc_qclist, xplist);
3732  cpl_propertylist_append(bpm_qclist, xplist);
3733  cpl_propertylist_delete(xplist);
3734  }
3735 
3736  return cpl_error_get_code();
3737 }
3738 
3739 
3740 
3741 
3742 
3743 /*---------------------------------------------------------------------------*/
3752 /*---------------------------------------------------------------------------*/
3753 static cpl_error_code
3754 detmon_lg_save_table_with_pro_keys(cpl_table* table,
3755  const char* name_o,
3756  cpl_propertylist* xheader,
3757  unsigned CPL_IO_MODE)
3758 {
3759 
3760  cpl_propertylist* pro_keys=NULL;
3761 
3762  pro_keys=detmon_load_pro_keys(name_o);
3763  cpl_propertylist_append(xheader,pro_keys);
3764 
3765  if(CPL_IO_MODE==CPL_IO_DEFAULT) {
3766  cpl_propertylist * pri_head=cpl_propertylist_load(name_o,0);
3767  cpl_table_save(table, pri_head,xheader,name_o,
3768  CPL_IO_DEFAULT);
3769  cpl_propertylist_delete(pri_head);
3770 
3771  } else {
3772  cpl_table_save(table,NULL,xheader,name_o,
3773  CPL_IO_EXTEND);
3774  }
3775  cpl_propertylist_delete(pro_keys);
3776 
3777  return cpl_error_get_code();
3778 }
3779 
3780 /*---------------------------------------------------------------------------*/
3788 /*---------------------------------------------------------------------------*/
3789 static cpl_error_code
3790 detmon_lg_save_image_with_pro_keys(cpl_image* image,
3791  const char* name_o,
3792  cpl_propertylist* xheader)
3793 {
3794 
3795  cpl_propertylist* pro_keys=NULL;
3796  pro_keys=detmon_load_pro_keys(name_o);
3797  cpl_propertylist_append(xheader,pro_keys);
3798 
3799  cpl_image_save(image,name_o, CPL_BPP_IEEE_FLOAT,
3800  xheader,CPL_IO_EXTEND);
3801  cpl_propertylist_delete(pro_keys);
3802 
3803 
3804  return cpl_error_get_code();
3805 }
3806 
3807 /*---------------------------------------------------------------------------*/
3815 /*---------------------------------------------------------------------------*/
3816 static cpl_error_code
3817 detmon_lg_save_imagelist_with_pro_keys(cpl_imagelist* imagelist,
3818  const char* name_o,
3819  cpl_propertylist* xheader)
3820 {
3821 
3822  cpl_propertylist* pro_keys=NULL;
3823  pro_keys=detmon_load_pro_keys(name_o);
3824  cpl_propertylist_append(xheader,pro_keys);
3825 
3826  cpl_imagelist_save(imagelist,name_o, CPL_BPP_IEEE_FLOAT,
3827  xheader,CPL_IO_EXTEND);
3828 
3829  cpl_propertylist_delete(pro_keys);
3830 
3831 
3832  return cpl_error_get_code();
3833 }
3834 
3835 /*---------------------------------------------------------------------------*/
3852 static cpl_error_code
3853 detmon_lg_save_plane(const cpl_parameterlist * parlist,
3854  cpl_frameset* frameset,
3855  const cpl_frameset * usedframes,
3856  int whichext,
3857  const char* recipe_name,
3858  cpl_propertylist* mypro_coeffscube,
3859  cpl_propertylist* linc_plane_qclist,
3860  const char* package,
3861  const char* NAME_O,
3862  cpl_image* plane)
3863 {
3864  if(detmon_lg_config.exts == 0) {
3865  cpl_propertylist* plist=NULL;
3866  cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
3867  NULL, NULL,
3868  CPL_BPP_IEEE_FLOAT, recipe_name,
3869  mypro_coeffscube, NULL,
3870  package, NAME_O);
3871  plist=cpl_propertylist_load(NAME_O,0);
3872  cpl_image_save(plane,NAME_O, CPL_BPP_IEEE_FLOAT,
3873  plist,CPL_IO_DEFAULT);
3874  cpl_propertylist_delete(plist);
3875 
3876  } else if(detmon_lg_config.exts > 0) {
3877  cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
3878  NULL, NULL,
3879  CPL_BPP_IEEE_FLOAT, recipe_name,
3880  mypro_coeffscube, NULL,
3881  package, NAME_O);
3882 
3883  detmon_lg_save_image_with_pro_keys(plane,NAME_O,linc_plane_qclist);
3884  } else {
3885  if(whichext == 1)
3886  {
3887  cpl_dfs_save_image(frameset, NULL, parlist,
3888  usedframes,NULL, NULL,
3889  CPL_BPP_IEEE_FLOAT, recipe_name,
3890  mypro_coeffscube, NULL,
3891  package, NAME_O);
3892  detmon_lg_save_image_with_pro_keys(plane,NAME_O,linc_plane_qclist);
3893  } else {
3894 
3895  detmon_lg_save_image_with_pro_keys(plane,NAME_O,linc_plane_qclist);
3896 
3897  }
3898 
3899  }
3900 
3901  return cpl_error_get_code();
3902 }
3903 
3904 
3905 
3906 /*---------------------------------------------------------------------------*/
3924 static cpl_error_code
3925 detmon_lg_save_cube(const cpl_parameterlist * parlist,
3926  cpl_frameset* frameset,
3927  const cpl_frameset * usedframes,
3928  int whichext,
3929  const char* recipe_name,
3930  cpl_propertylist* mypro_coeffscube,
3931  cpl_propertylist* linc_qclist,
3932  const char* package,
3933  const char* NAME_O,
3934  cpl_imagelist* coeffs)
3935 {
3936 
3937  if(detmon_lg_config.exts == 0) {
3938  cpl_propertylist_append(mypro_coeffscube, linc_qclist);
3939  detmon_lg_dfs_save_imagelist
3940  (frameset, parlist, usedframes, coeffs,
3941  recipe_name, mypro_coeffscube, package,
3942  NAME_O);
3943  } else if(detmon_lg_config.exts > 0) {
3944  cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
3945  NULL, NULL,
3946  CPL_BPP_IEEE_FLOAT, recipe_name,
3947  mypro_coeffscube, NULL,
3948  package, NAME_O);
3949 
3950  detmon_lg_save_imagelist_with_pro_keys(coeffs,NAME_O,linc_qclist);
3951 
3952  } else {
3953  if(whichext == 1) {
3954  cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
3955  NULL, NULL,
3956  CPL_BPP_IEEE_FLOAT, recipe_name,
3957  mypro_coeffscube, NULL,
3958  package, NAME_O);
3959  if (coeffs)
3960  detmon_lg_save_imagelist_with_pro_keys(coeffs,NAME_O,linc_qclist);
3961  else
3962  cpl_propertylist_save(linc_qclist, NAME_O, CPL_IO_EXTEND);
3963  } else {
3964  if (coeffs)
3965  detmon_lg_save_imagelist_with_pro_keys(coeffs,NAME_O,linc_qclist);
3966  else
3967  cpl_propertylist_save(linc_qclist, NAME_O, CPL_IO_EXTEND);
3968  }
3969  }
3970 
3971  return cpl_error_get_code();
3972 }
3973 
3974 static char*
3975 detmon_lg_set_paf_name_and_header(cpl_frame* ref_frame,
3976  int flag_sets,int which_set,
3977  int whichext,
3978  const char* paf_suf,
3979  cpl_propertylist** plist)
3980 {
3981  char * paf_name=NULL;
3982 
3983  if(detmon_lg_config.exts >= 0)
3984  {
3985  *plist =cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
3986  detmon_lg_config.exts);
3987 
3988  if(!flag_sets)
3989  {
3990  paf_name=cpl_sprintf("%s_%s.paf", detmon_lg_config.pafname,paf_suf);
3991  }
3992  else
3993  {
3994  paf_name=cpl_sprintf("%s_%s_set%02d.paf",
3995  detmon_lg_config.pafname, paf_suf,which_set);
3996  }
3997  }
3998  else
3999  {
4000  *plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4001  whichext);
4002 
4003 
4004  if(!flag_sets)
4005  {
4006  paf_name=cpl_sprintf("%s_%s_ext%02d.paf",
4007  detmon_lg_config.pafname, paf_suf,whichext);
4008  }
4009  else
4010  {
4011  paf_name=cpl_sprintf("%s_%s_set%02d_ext%02d.paf",
4012  detmon_lg_config.pafname,paf_suf,
4013  which_set, whichext);
4014  }
4015  }
4016 
4017  return paf_name;
4018 }
4019 
4020 
4021 static char*
4022 detmon_lg_set_paf_name_and_header_ext(cpl_frame* ref_frame,
4023  int flag_sets,int which_set,
4024  int whichext,
4025  const char* paf_suf,
4026  cpl_propertylist** plist)
4027 {
4028  char* paf_name=NULL;
4029 
4030  if(detmon_lg_config.exts >= 0)
4031  {
4032  *plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4033  detmon_lg_config.exts);
4034 
4035  if(!flag_sets)
4036  {
4037  paf_name=cpl_sprintf("%s_%s.paf", detmon_lg_config.pafname,paf_suf);
4038  } else
4039  {
4040  paf_name=cpl_sprintf("%s_%s_set%02d.paf",
4041  detmon_lg_config.pafname, paf_suf,which_set);
4042  }
4043  } else
4044  {
4045  *plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4046  whichext);
4047  if(!flag_sets)
4048  {
4049  paf_name=cpl_sprintf("%s_%s_ext%02d.paf",
4050  detmon_lg_config.pafname, paf_suf,whichext);
4051  } else
4052  {
4053  paf_name=cpl_sprintf("%s_%s_set%02d_ext%02d.paf",
4054  detmon_lg_config.pafname,paf_suf,
4055  which_set, whichext);
4056  }
4057  }
4058  return paf_name;
4059 
4060 }
4061 
4062 static cpl_error_code
4063 detmon_lg_save_paf_product(cpl_frame* ref_frame,int flag_sets,
4064  int which_set,int whichext,
4065  const char* pafregexp,
4066  const char* procatg,
4067  const char* pipeline_name,
4068  const char* recipe_name,
4069  const char* paf_suf,
4070  cpl_propertylist* qclist,
4071  const int ext)
4072 
4073 {
4074  /* Set the file name for the linearity table PAF */
4075  char* paf_name=NULL;
4076  cpl_propertylist* plist=NULL;
4077  cpl_propertylist* paflist = NULL;
4078  cpl_propertylist* mainplist=NULL;
4079 
4080  mainplist =cpl_propertylist_load(cpl_frame_get_filename(ref_frame),0);
4081  if(ext==0) {
4082  paf_name=detmon_lg_set_paf_name_and_header(ref_frame,flag_sets,
4083  which_set,whichext,
4084  paf_suf,&plist);
4085  } else {
4086  paf_name=detmon_lg_set_paf_name_and_header_ext(ref_frame,flag_sets,
4087  which_set,whichext,
4088  paf_suf,&plist);
4089  }
4090 
4091 
4092  paflist = cpl_propertylist_new();
4093  cpl_propertylist_append_string(paflist, CPL_DFS_PRO_CATG,procatg);
4094 
4095  /* Get the keywords for the paf file */
4096  cpl_propertylist_copy_property_regexp(paflist, plist,pafregexp, 0);
4097  cpl_propertylist_copy_property_regexp(paflist, mainplist,pafregexp, 0);
4098  cpl_propertylist_append(paflist,qclist);
4099 
4100  /* Save the PAF */
4101  cpl_dfs_save_paf(pipeline_name, recipe_name,paflist,paf_name);
4102 
4103  /* free memory */
4104  cpl_propertylist_delete(mainplist);
4105  cpl_propertylist_delete(paflist);
4106  cpl_propertylist_delete(plist);
4107  cpl_free(paf_name);
4108 
4109  return cpl_error_get_code();
4110 
4111 }
4112 
4113 
4114 
4115 /*---------------------------------------------------------------------------*/
4146 static cpl_error_code
4147 detmon_lg_save(const cpl_parameterlist * parlist,
4148  cpl_frameset * frameset,
4149  const char *recipe_name,
4150  const char *pipeline_name,
4151  const char *pafregexp,
4152  const cpl_propertylist * pro_lintbl,
4153  const cpl_propertylist * pro_gaintbl,
4154  const cpl_propertylist * pro_coeffscube,
4155  const cpl_propertylist * pro_bpm,
4156  const cpl_propertylist * pro_corr,
4157  const cpl_propertylist * pro_diff,
4158  const char *package,
4159  cpl_imagelist * coeffs,
4160  cpl_table * gain_table,
4161  cpl_table * linear_table,
4162  cpl_image * bpms,
4163  cpl_imagelist * autocorr_images,
4164  cpl_imagelist * diff_flats,
4165  cpl_propertylist * gaint_qclist,
4166  cpl_propertylist * lint_qclist,
4167  cpl_propertylist * linc_qclist,
4168  cpl_propertylist * bpm_qclist,
4169  const int flag_sets,
4170  const int which_set,
4171  const cpl_frameset * usedframes,
4172  int whichext)
4173 {
4174 
4175  cpl_frame *ref_frame;
4176  cpl_propertylist *plist = NULL;
4177  cpl_propertylist *mainplist = NULL;
4178  char* NAME_O=NULL;
4179  char* PREF_O=NULL;
4180  int nb_images;
4181  int i;
4182 
4183  cpl_propertylist * xplist = NULL;
4184 
4185  cpl_propertylist* linc_plane_qclist=NULL;
4186  cpl_image* plane=NULL;
4187  int ip=0;
4188  char* pcatg_plane=NULL;
4189 
4190  cpl_propertylist * mypro_lintbl =
4191  cpl_propertylist_duplicate(pro_lintbl);
4192  cpl_propertylist * mypro_gaintbl =
4193  cpl_propertylist_duplicate(pro_gaintbl);
4194  cpl_propertylist * mypro_coeffscube =
4195  cpl_propertylist_duplicate(pro_coeffscube);
4196  cpl_propertylist * mypro_bpm =
4197  cpl_propertylist_duplicate(pro_bpm);
4198  cpl_propertylist * mypro_corr =
4199  cpl_propertylist_duplicate(pro_corr);
4200  cpl_propertylist * mypro_diff =
4201  cpl_propertylist_duplicate(pro_diff);
4202 
4203  const char * procatg_lintbl =
4204  cpl_propertylist_get_string(mypro_lintbl, CPL_DFS_PRO_CATG);
4205 
4206  const char * procatg_gaintbl =
4207  cpl_propertylist_get_string(mypro_gaintbl, CPL_DFS_PRO_CATG);
4208 
4209  const char * procatg_coeffscube =
4210  cpl_propertylist_get_string(mypro_coeffscube, CPL_DFS_PRO_CATG);
4211  const char * procatg_bpm =
4212  cpl_propertylist_get_string(mypro_bpm, CPL_DFS_PRO_CATG);
4213 
4214 
4215  /* Extract extension headers if multi-extension */
4216  detmon_lg_extract_extention_header(frameset,gaint_qclist,lint_qclist,
4217  linc_qclist,bpm_qclist,whichext);
4218 
4219  /* This is only used later for PAF and temporarily for COEFFS_CUBE
4220  (see if defined)*/
4221  /* Get FITS header from reference file */
4222  ref_frame = cpl_frameset_get_first(frameset);
4223 
4224  skip_if((mainplist =
4225  cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4226  0)) == NULL);
4227 
4228  /*******************************/
4229  /* Write the LINEARITY TABLE */
4230  /*******************************/
4231  cpl_msg_info(cpl_func,"Write the LINEARITY TABLE");
4232  /* Set the file name for the table */
4233  if(!flag_sets) {
4234  NAME_O=cpl_sprintf("%s_linearity_table.fits", recipe_name);
4235  } else {
4236  NAME_O=cpl_sprintf("%s_linearity_table_set%02d.fits", recipe_name,
4237  which_set);
4238  }
4239 
4240  if (detmon_lg_config.exts >= 0) {
4241  /* Save the table */
4242  cpl_propertylist_append(mypro_lintbl, lint_qclist);
4243  skip_if(cpl_dfs_save_table(frameset, NULL,parlist, usedframes, NULL,
4244  linear_table,NULL, recipe_name,
4245  mypro_lintbl, NULL, package, NAME_O));
4246 
4247  detmon_lg_save_table_with_pro_keys(linear_table,NAME_O,
4248  lint_qclist,CPL_IO_DEFAULT);
4249 
4250  } else {
4251  if(whichext == 1) {
4252  /* Save the 1. extension table */
4253  skip_if(cpl_dfs_save_table(frameset,NULL, parlist, usedframes, NULL,
4254  linear_table,lint_qclist, recipe_name,
4255  mypro_lintbl,NULL, package, NAME_O));
4256  detmon_lg_save_table_with_pro_keys(linear_table,NAME_O,
4257  lint_qclist,CPL_IO_DEFAULT);
4258 
4259 
4260 
4261 
4262  } else {
4263 
4264  detmon_lg_save_table_with_pro_keys(linear_table,NAME_O,
4265  lint_qclist,CPL_IO_EXTEND);
4266  }
4267  }
4268  irplib_free(&NAME_O);
4269  /**************************/
4270  /* Write the GAIN TABLE */
4271  /**************************/
4272  cpl_msg_info(cpl_func,"Write the GAIN TABLE");
4273  /* Set the file name for the table */
4274  if(!flag_sets) {
4275  NAME_O=cpl_sprintf("%s_gain_table.fits", recipe_name);
4276  } else {
4277  NAME_O=cpl_sprintf("%s_gain_table_set%02d.fits", recipe_name,
4278  which_set);
4279  }
4280 
4281  if (detmon_lg_config.exts >= 0)
4282  {
4283  /* Save the table */
4284 
4285  cpl_propertylist_append(mypro_gaintbl, gaint_qclist);
4286  skip_if(cpl_dfs_save_table(frameset, NULL, parlist, usedframes, NULL,
4287  gain_table,NULL, recipe_name, mypro_gaintbl,
4288  NULL, package, NAME_O));
4289  detmon_lg_save_table_with_pro_keys(gain_table,NAME_O,
4290  gaint_qclist,CPL_IO_DEFAULT);
4291 
4292  }
4293  else
4294  {
4295  if(whichext == 1)
4296  {
4297  /* Save the 1. extension table */
4298  skip_if(cpl_dfs_save_table(frameset, NULL, parlist, usedframes, NULL, gain_table,
4299  gaint_qclist, recipe_name, mypro_gaintbl,
4300  NULL, package, NAME_O));
4301  detmon_lg_save_table_with_pro_keys(gain_table,NAME_O,
4302  gaint_qclist,CPL_IO_DEFAULT);
4303 
4304  }
4305  else
4306  {
4307 
4308  detmon_lg_save_table_with_pro_keys(gain_table,NAME_O,
4309  gaint_qclist,CPL_IO_EXTEND);
4310  }
4311  }
4312 
4313  if(detmon_lg_config.pix2pix)
4314  {
4315 
4316  /***************************/
4317  /* Write the COEFFS FITS */
4318  /***************************/
4319  cpl_msg_info(cpl_func,"Write the COEFFS FITS");
4320  irplib_free(&NAME_O);
4321  if(!flag_sets)
4322  {
4323  PREF_O=cpl_sprintf("%s_coeffs_cube", recipe_name);
4324  } else
4325  {
4326  PREF_O=cpl_sprintf("%s_coeffs_cube_set%02d",
4327  recipe_name, which_set);
4328  }
4329  if (detmon_lg_config.split_coeffs == 0) {
4330  NAME_O=cpl_sprintf("%s.fits", PREF_O);
4331  }
4332 
4333 
4334  /* Save the imagelist */
4335  if(detmon_lg_config.split_coeffs != 0){
4336 
4337 
4338  nb_images = cpl_imagelist_get_size(coeffs);
4339  for(ip=0;ip<nb_images;ip++) {
4340  NAME_O=cpl_sprintf("%s_P%d.fits", PREF_O,ip);
4341  pcatg_plane=cpl_sprintf("COEFFS_CUBE_P%d",ip);
4342  cpl_propertylist_delete(mypro_coeffscube);
4343  mypro_coeffscube=cpl_propertylist_duplicate(pro_coeffscube);
4344  cpl_propertylist_set_string(mypro_coeffscube,CPL_DFS_PRO_CATG,
4345  pcatg_plane);
4346  linc_plane_qclist=detmon_lg_extract_qclist_4plane(linc_qclist,ip);
4347  cpl_propertylist_append(mypro_coeffscube, linc_plane_qclist);
4348  plane=cpl_imagelist_get(coeffs,ip);
4349  detmon_lg_save_plane(parlist,frameset,usedframes,whichext,
4350  recipe_name,mypro_coeffscube,
4351  linc_plane_qclist,package,NAME_O,plane);
4352 
4353  if(NULL!=linc_plane_qclist) {
4354  cpl_propertylist_delete(linc_plane_qclist);
4355  }
4356  irplib_free(&NAME_O);
4357 
4358  } /* end for loop over cube planes */
4359  } else {
4360 
4361  detmon_lg_save_cube(parlist,frameset,usedframes,whichext,
4362  recipe_name,mypro_coeffscube,
4363  linc_qclist,package,NAME_O,coeffs);
4364  }
4365 
4366  /*******************************/
4367  /* Write the BAD PIXEL MAP */
4368  /*******************************/
4369  cpl_msg_info(cpl_func,"Write the BAD PIXEL MAP");
4370  irplib_free(&NAME_O);
4371  /* Set the file name for the bpm */
4372  if(!flag_sets)
4373  {
4374  NAME_O=cpl_sprintf("%s_bpm.fits", recipe_name);
4375  } else
4376  {
4377  NAME_O=cpl_sprintf("%s_bpm_set%02d.fits", recipe_name, which_set);
4378  }
4379 
4380 
4381  /* Save the image */
4382  if(detmon_lg_config.exts == 0) {
4383  cpl_propertylist_append(mypro_bpm, bpm_qclist);
4384  cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL, bpms,
4385  CPL_BPP_IEEE_FLOAT, recipe_name,
4386  mypro_bpm, NULL, package,
4387  NAME_O);
4388  }
4389  else if(detmon_lg_config.exts > 0)
4390  {
4391  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,NULL, NULL,
4392  CPL_BPP_IEEE_FLOAT, recipe_name,
4393  mypro_bpm, NULL, package,
4394  NAME_O));
4395  detmon_lg_save_image_with_pro_keys(bpms,NAME_O,bpm_qclist);
4396 
4397  } else
4398  {
4399  if (whichext == 1)
4400  {
4401  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,NULL, NULL,
4402  CPL_BPP_IEEE_FLOAT, recipe_name,
4403  mypro_bpm, NULL, package,
4404  NAME_O));
4405  detmon_lg_save_image_with_pro_keys(bpms,NAME_O,bpm_qclist);
4406  } else
4407  {
4408  detmon_lg_save_image_with_pro_keys(bpms,NAME_O,bpm_qclist);
4409  }
4410  }
4411  } /* End of if(pix2pix) */
4412 
4413  if(detmon_lg_config.intermediate)
4414  {
4415  /******************************/
4416  /* Write the AUTOCORRS FITS */
4417  /******************************/
4418  cpl_msg_info(cpl_func,"Write the AUTOCORRS FITS");
4419  nb_images = cpl_imagelist_get_size(autocorr_images);
4420  cpl_ensure_code(nb_images > 0, CPL_ERROR_DATA_NOT_FOUND);
4421  for(i = 0; i < nb_images; i++)
4422  {
4423  cpl_propertylist* pplist = cpl_propertylist_duplicate(mypro_corr);
4424  int inull = 0;
4425  cpl_array* pnames = cpl_table_get_column_names(linear_table);
4426  double ddit = 0;
4427  if(i < cpl_table_get_nrow(linear_table))
4428  {
4429  ddit = cpl_table_get_double(linear_table,
4430  cpl_array_get_data_string_const(pnames)[0], i, &inull);
4431  }
4432  cpl_array_delete(pnames);
4433  /*cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);*/
4434  /* Set the file name for each image */
4435  irplib_free(&NAME_O);
4436  if(!flag_sets)
4437  {
4438  NAME_O=cpl_sprintf("%s_autocorr_%d.fits", recipe_name, i);
4439  assert(NAME_O != NULL);
4440  } else
4441  {
4442  NAME_O=cpl_sprintf("%s_autocorr_%02d_set%02d.fits",
4443  recipe_name, i, which_set);
4444  assert(NAME_O != NULL);
4445  }
4446  /* Save the image */
4447  if(detmon_lg_config.exts > 0)
4448  {
4449  cpl_propertylist* pextlist = cpl_propertylist_new();
4450  cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4451  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4452  NULL,NULL,CPL_BPP_IEEE_FLOAT,
4453  recipe_name, pplist, NULL,
4454  package, NAME_O));
4455 
4456  detmon_lg_save_image_with_pro_keys(
4457  cpl_imagelist_get(autocorr_images, i),NAME_O,pextlist);
4458 
4459  cpl_propertylist_delete(pextlist);
4460  } else
4461  if(detmon_lg_config.exts == 0)
4462  {
4463  cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);
4464  cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL,
4465  cpl_imagelist_get(autocorr_images, i),
4466  CPL_BPP_IEEE_FLOAT,
4467  recipe_name, pplist, NULL, package,
4468  NAME_O);
4469 
4470  }
4471  else
4472  {
4473  cpl_propertylist* pextlist = cpl_propertylist_new();
4474  cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4475  if(whichext == 1)
4476  {
4477  skip_if(cpl_dfs_save_image(frameset, NULL, parlist,
4478  usedframes, NULL,NULL,
4479  CPL_BPP_IEEE_FLOAT, recipe_name,
4480  pplist, NULL,
4481  package, NAME_O));
4482 
4483  detmon_lg_save_image_with_pro_keys(
4484  cpl_imagelist_get(autocorr_images, i),NAME_O,pextlist);
4485 
4486  } else
4487  {
4488 
4489  detmon_lg_save_image_with_pro_keys(
4490  cpl_imagelist_get(autocorr_images, i),NAME_O,pextlist);
4491  }
4492  cpl_propertylist_delete(pextlist);
4493  }
4494  cpl_propertylist_delete (pplist);
4495  }
4496  irplib_free(&NAME_O);
4497 
4498 
4499  /*
4500  cpl_msg_info(cpl_func, "-----before Write the DIFFS FITS %d", __LINE__);
4501  */
4502  /***************************/
4503  /* Write the DIFFS FITS */
4504  /***************************/
4505  cpl_msg_info(cpl_func,"Write the DIFFS FITS");
4506 
4507  for(i = 0; i < nb_images; i++)
4508  {
4509  cpl_propertylist* pplist = cpl_propertylist_duplicate(mypro_diff);
4510  int inull = 0;
4511  cpl_array* pnames = cpl_table_get_column_names(linear_table);
4512  double ddit = 0;
4513  if(i < cpl_table_get_nrow(linear_table))
4514  {
4515  ddit = cpl_table_get_double(linear_table,
4516  cpl_array_get_data_string_const(pnames)[0], i, &inull);
4517  }
4518  cpl_array_delete(pnames);
4519  /*cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);*/
4520  /* Set the file name for each image */
4521  if(!flag_sets)
4522  {
4523  NAME_O=cpl_sprintf("%s_diff_flat_%d.fits", recipe_name, i);
4524  } else
4525  {
4526  NAME_O=cpl_sprintf("%s_diff_flat_%d_set%02d.fits",
4527  recipe_name, i, which_set);
4528  }
4529  /* Save the image */
4530  if(detmon_lg_config.exts > 0)
4531  {
4532  cpl_propertylist* pextlist = cpl_propertylist_new();
4533  cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4534  cpl_propertylist_append_double(mypro_diff, "ESO DET DIT", ddit);
4535  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4536  NULL,NULL,CPL_BPP_IEEE_FLOAT,
4537  recipe_name,
4538  mypro_diff, NULL,package, NAME_O));
4539 
4540  detmon_lg_save_image_with_pro_keys(
4541  cpl_imagelist_get(diff_flats, i),NAME_O,pextlist);
4542 
4543  cpl_propertylist_delete(pextlist);
4544  }
4545  else if(detmon_lg_config.exts == 0)
4546  {
4547  cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);
4548  cpl_dfs_save_image
4549  (frameset, NULL, parlist, usedframes, NULL,
4550  cpl_imagelist_get(diff_flats, i), CPL_BPP_IEEE_FLOAT,
4551  recipe_name, pplist, NULL, package,
4552  NAME_O);
4553 
4554  } else
4555  {
4556  cpl_propertylist* pextlist = cpl_propertylist_new();
4557  cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4558  if(whichext == 1)
4559  {
4560  cpl_propertylist_append_double(mypro_diff,"ESO DET DIT",ddit);
4561  // cpl_propertylist_erase(mypro_diff, "ESO DET DIT");
4562  skip_if(cpl_dfs_save_image(frameset, NULL, parlist,
4563  usedframes, NULL,NULL,
4564  CPL_BPP_IEEE_FLOAT, recipe_name,
4565  mypro_diff, NULL,package, NAME_O));
4566 
4567  detmon_lg_save_image_with_pro_keys(
4568  cpl_imagelist_get(diff_flats, i),NAME_O,pextlist);
4569 
4570  } else
4571  {
4572 
4573  detmon_lg_save_image_with_pro_keys(
4574  cpl_imagelist_get(diff_flats, i),NAME_O,pextlist);
4575 
4576  }
4577  cpl_propertylist_delete(pextlist);
4578  }
4579  cpl_propertylist_delete(pplist);
4580  irplib_free(&NAME_O);
4581  }
4582  } /* End of if(intermediate) */
4583 
4584 
4585  /*******************************/
4586  /* Write the PAF file(s) */
4587  /*******************************/
4588  cpl_msg_info(cpl_func,"Write the PAF file(s)");
4589 
4590  if(detmon_lg_config.pafgen) {
4591 
4592  detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,whichext,
4593  pafregexp,procatg_gaintbl,
4594  pipeline_name,recipe_name,
4595  "qc01",gaint_qclist,0);
4596 
4597  detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,whichext,
4598  pafregexp,procatg_lintbl,
4599  pipeline_name,recipe_name,
4600  "qc02",lint_qclist,0);
4601 
4602  if(detmon_lg_config.pix2pix)
4603  {
4604 
4605  detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,
4606  whichext,pafregexp,
4607  procatg_coeffscube,
4608  pipeline_name,recipe_name,
4609  "qc03",linc_qclist,1);
4610 
4611  detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,
4612  whichext,pafregexp,procatg_bpm,
4613  pipeline_name,recipe_name,
4614  "qc04",bpm_qclist,1);
4615  }
4616  }
4617 
4618  end_skip;
4619  cpl_msg_info(cpl_func,"exit");
4620 
4621  cpl_propertylist_delete(xplist);
4622  if(plist!=NULL) {
4623  cpl_propertylist_delete(plist);
4624  plist=NULL;
4625  }
4626 
4627  irplib_free(&NAME_O);
4628  cpl_free(PREF_O);
4629  cpl_free(pcatg_plane);
4630  cpl_propertylist_delete(mainplist);
4631  cpl_propertylist_delete(mypro_lintbl);
4632  cpl_propertylist_delete(mypro_gaintbl);
4633  cpl_propertylist_delete(mypro_coeffscube);
4634  cpl_propertylist_delete(mypro_bpm);
4635  cpl_propertylist_delete(mypro_corr);
4636  cpl_propertylist_delete(mypro_diff);
4637 
4638  return cpl_error_get_code();
4639 }
4640 
4641 
4642 /*---------------------------------------------------------------------------*/
4650 /*---------------------------------------------------------------------------*/
4651 static cpl_error_code
4652 detmon_opt_contamination(const cpl_imagelist * ons,
4653  const cpl_imagelist * offs,
4654  unsigned mode,
4655  cpl_propertylist * qclist)
4656 {
4657  struct rect {
4658  size_t llx;
4659  size_t lly;
4660  size_t urx;
4661  size_t ury;
4662  };
4663  struct rect rects[5] = {
4664  (struct rect){ detmon_lg_config.llx1,
4665  detmon_lg_config.lly1,
4666  detmon_lg_config.urx1,
4667  detmon_lg_config.ury1},
4668  (struct rect){ detmon_lg_config.llx2,
4669  detmon_lg_config.lly2,
4670  detmon_lg_config.urx2,
4671  detmon_lg_config.ury2},
4672  (struct rect){ detmon_lg_config.llx3,
4673  detmon_lg_config.lly3,
4674  detmon_lg_config.urx3,
4675  detmon_lg_config.ury3},
4676  (struct rect){ detmon_lg_config.llx4,
4677  detmon_lg_config.lly4,
4678  detmon_lg_config.urx4,
4679  detmon_lg_config.ury4},
4680  (struct rect){ detmon_lg_config.llx5,
4681  detmon_lg_config.lly5,
4682  detmon_lg_config.urx5,
4683  detmon_lg_config.ury5},
4684  };
4685 
4686  for (size_t i = 0; i < 5; i++) {
4687  cpl_image * dif_avg;
4688  const cpl_image * off2;
4689  double median;
4690  char kname[300];
4691  if (cpl_imagelist_get_size(offs) == 1 || mode & IRPLIB_LIN_COLLAPSE)
4692  off2 = cpl_imagelist_get_const(offs, 0);
4693  else
4694  off2 = cpl_imagelist_get_const(offs, 1);
4695 
4696  dif_avg = detmon_subtracted_avg(cpl_imagelist_get_const(ons, 0),
4697  cpl_imagelist_get_const(offs, 0),
4698  cpl_imagelist_get_const(ons, 1),
4699  off2,
4700  rects[i].llx,
4701  rects[i].lly,
4702  rects[i].urx,
4703  rects[i].ury);
4704 
4705  median = cpl_image_get_median(dif_avg);
4706  cpl_image_delete(dif_avg);
4707 
4708  skip_if(0);
4709  sprintf(kname, "%s%d", DETMON_QC_CONTAM, i + 1);
4710 
4711  if(cpl_propertylist_has(qclist,kname)){
4712  skip_if(cpl_propertylist_update_double(qclist,kname,median));
4713  } else {
4714  skip_if(cpl_propertylist_append_double(qclist,kname,median));
4715  skip_if(cpl_propertylist_set_comment(qclist,kname,DETMON_QC_CONTAM_C));
4716  }
4717  }
4718 
4719  end_skip;
4720 
4721  return cpl_error_get_code();
4722 }
4723 
4724 /*---------------------------------------------------------------------------*/
4731 /*---------------------------------------------------------------------------*/
4732 /*
4733 static cpl_error_code
4734 detmon_opt_lampcr(cpl_frameset * cur_fset, int ext)
4735 {
4736  cpl_image * on = NULL;
4737  cpl_image * off = NULL;
4738  cpl_frame * first_off = NULL;
4739  cpl_frame * first_on = NULL;
4740  cpl_propertylist * plist = NULL;
4741  double dit;
4742 
4743  cpl_ensure_code(cur_fset != NULL, CPL_ERROR_NULL_INPUT);
4744 
4745  skip_if((first_off = cpl_frameset_get_first(cur_fset)) == NULL);
4746  skip_if((first_on = cpl_frameset_get_next (cur_fset)) == NULL);
4747 
4748  on = cpl_image_load(cpl_frame_get_filename(first_on),
4749  CPL_TYPE_FLOAT, 0, ext);
4750  off = cpl_image_load(cpl_frame_get_filename(first_off),
4751  CPL_TYPE_FLOAT, 0, ext);
4752  skip_if(cpl_image_subtract(on, off));
4753 
4754  plist = cpl_propertylist_load(cpl_frame_get_filename(first_on), 0);
4755  skip_if(plist == NULL);
4756 
4757  dit = irplib_pfits_get_dit_opt(plist);
4758 
4759  detmon_lg_config.cr = cpl_image_get_mean(on) / dit;
4760 
4761  end_skip;
4762 
4763  cpl_image_delete(on);
4764  cpl_image_delete(off);
4765  cpl_propertylist_delete(plist);
4766 
4767  return cpl_error_get_code();
4768 }
4769 */
4770 /*---------------------------------------------------------------------------*/
4778 /*---------------------------------------------------------------------------*/
4779 int
4780 detmon_lg_dfs_set_groups(cpl_frameset * set,
4781  const char *tag_on, const char *tag_off)
4782 {
4783  cpl_frame *cur_frame;
4784  const char *tag;
4785  int nframes;
4786  int i;
4787 
4788  /* Check entries */
4789  if(set == NULL)
4790  return -1;
4791 
4792  /* Initialize */
4793  nframes = cpl_frameset_get_size(set);
4794 
4795  /* Loop on frames */
4796  for(i = 0; i < nframes; i++) {
4797  cur_frame = cpl_frameset_get_position(set, i);
4798  tag = cpl_frame_get_tag(cur_frame);
4799 
4800  /* RAW frames */
4801  if(!strcmp(tag, tag_on) || !strcmp(tag, tag_off))
4802  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_RAW);
4803  /* CALIB frames */
4804 
4805  /* else if (!strcmp(tag, IIINSTRUMENT_CALIB_FLAT))
4806  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_CALIB);
4807  */
4808  }
4809  return 0;
4810 }
4811 
4812 
4813 /*---------------------------------------------------------------------------*/
4821 /*---------------------------------------------------------------------------*/
4822 static cpl_error_code
4823 detmon_lg_fits_coeffs_and_bpm2chip(cpl_imagelist ** coeffs_ptr,
4824  cpl_image **bpms_ptr)
4825 {
4826  cpl_image* dummy_bpm=NULL;
4827  cpl_image * dummy_coeff=NULL;
4828  cpl_imagelist * dummy_coeffs=NULL;
4829  int * db_p=NULL;
4830  int * rb_p =NULL;
4831  float ** dcs_p;
4832  float ** rcs_p;
4833  int dlength=0;
4834  int rlength=0;
4835  int shift_idx=0;
4836  int i=0;
4837  int k=0;
4838  int j=0;
4839 
4840  dummy_bpm = cpl_image_new(detmon_lg_config.nx,
4841  detmon_lg_config.ny,
4842  CPL_TYPE_INT);
4843  dummy_coeffs = cpl_imagelist_new();
4844 
4845  db_p = cpl_image_get_data_int(dummy_bpm);
4846  rb_p = cpl_image_get_data_int(*bpms_ptr);;
4847  dcs_p = cpl_malloc(sizeof(float *) * (detmon_lg_config.order + 1));
4848  rcs_p = cpl_malloc(sizeof(float *) * (detmon_lg_config.order + 1));
4849  dlength = detmon_lg_config.nx;
4850  rlength = detmon_lg_config.urx - detmon_lg_config.llx + 1;
4851  for (i = 0; i <= detmon_lg_config.order; i++)
4852  {
4853  dummy_coeff = cpl_image_new(detmon_lg_config.nx,
4854  detmon_lg_config.ny,
4855  CPL_TYPE_FLOAT);
4856 
4857  cpl_imagelist_set(dummy_coeffs, dummy_coeff, i);
4858  dcs_p[i] = cpl_image_get_data_float(dummy_coeff);
4859  rcs_p[i] = cpl_image_get_data_float(cpl_imagelist_get(*coeffs_ptr, i));
4860  }
4861  /*copy the coefficients from temporary image to the dummy_bpm*/
4862  for (i = detmon_lg_config.lly - 1; i < detmon_lg_config.ury; i++)
4863  {
4864  for (j = detmon_lg_config.llx - 1; j < detmon_lg_config.urx; j++)
4865  {
4866  shift_idx=(i - detmon_lg_config.lly + 1) * rlength +
4867  j - detmon_lg_config.llx + 1;
4868  *(db_p + i * dlength + j) = *(rb_p + shift_idx);
4869  for (k = 0; k <= detmon_lg_config.order; k++)
4870  {
4871  *(dcs_p[k] + i * dlength + j) =
4872  *(rcs_p[k] + (i - detmon_lg_config.lly + 1) * rlength +
4873  j - detmon_lg_config.llx + 1);
4874  }
4875  }
4876  }
4877  cpl_imagelist_delete(*coeffs_ptr);
4878  cpl_image_delete(*bpms_ptr);
4879  *coeffs_ptr = dummy_coeffs;
4880  *bpms_ptr = dummy_bpm;
4881  cpl_free(dcs_p);
4882  cpl_free(rcs_p);
4883 
4884  return cpl_error_get_code();
4885 }
4886 
4887 /* Not used so we temporaryly comment it out
4888 static cpl_error_code
4889 detmon_lg_qclog_lin_coeff(cpl_imagelist* coeffs_ptr, const int order, cpl_propertylist* linc_qclist)
4890 {
4891  cpl_image* image=NULL;
4892  int i=0;
4893  double coeff=0;
4894  double * pcoeffs = cpl_malloc(sizeof(double)*(order + 1));
4895  char* name_o1=NULL;
4896  char* name_o2=NULL;
4897 
4898  for(i = 0; i <= order; i++)
4899  {
4900  image = cpl_imagelist_get(coeffs_ptr, i);
4901  coeff = cpl_image_get_median(image);
4902  pcoeffs[i] = coeff;
4903  name_o1 = cpl_sprintf("ESO QC LIN COEF%d", i);
4904  name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", i);
4905  assert(name_o1 != NULL);
4906  assert(name_o2 != NULL);
4907  cpl_propertylist_append_double(linc_qclist, name_o1, coeff);
4908  cpl_propertylist_set_comment(linc_qclist,name_o1,DETMON_QC_LIN_COEF_C);
4909  cpl_free(name_o1);
4910  name_o1= NULL;
4911  cpl_propertylist_append_double(linc_qclist, name_o2,cpl_image_get_stdev(image));
4912  cpl_propertylist_set_comment(linc_qclist,name_o2,DETMON_QC_LIN_COEF_ERR_C);
4913  cpl_free(name_o2);
4914  name_o2= NULL;
4915  }
4916  cpl_free(pcoeffs);
4917 
4918  return cpl_error_get_code();
4919 }
4920 */
4921 
4922 /*---------------------------------------------------------------------------*/
4936 /*---------------------------------------------------------------------------*/
4937 static cpl_error_code
4938 detmon_lg_reduce_all(const cpl_table * linear_table,
4939  cpl_propertylist * gaint_qclist,
4940  cpl_propertylist * lint_qclist,
4941  cpl_propertylist * linc_qclist,
4942  cpl_propertylist * bpm_qclist,
4943  cpl_imagelist ** coeffs_ptr,
4944  cpl_image ** bpms_ptr,
4945  const cpl_imagelist * linearity_inputs,
4946  const cpl_table * gain_table,
4947  int which_ext, cpl_boolean opt_nir)
4948 {
4949 
4950  int nbpixs = 0;
4951  const int nsets = cpl_table_get_nrow(linear_table);
4952  double autocorr;
4953  cpl_polynomial *poly_linfit = NULL;
4954  cpl_image *fiterror = NULL;
4955  char * name_o1 = NULL;
4956  char * name_o2 = NULL;
4957  double * pcoeffs = NULL;
4958  unsigned mode = detmon_lg_config.autocorr ? IRPLIB_GAIN_WITH_AUTOCORR : 0;
4959  double min_val=0;
4960  double max_val=0;
4961  cpl_vector *x =NULL;
4962  const cpl_vector *y =NULL;
4963 
4964 
4965  const cpl_image * first = NULL;
4966  int sizex = 0;
4967  int sizey = 0;
4968 
4969  int vsize = 0;
4970  cpl_size deg=0;
4971  /* FIXME: This should go before the x and y vectors.
4972  Checking for all the inputs */
4973  cpl_ensure_code(gaint_qclist != NULL, CPL_ERROR_NULL_INPUT);
4974  cpl_ensure_code(lint_qclist != NULL, CPL_ERROR_NULL_INPUT);
4975  cpl_ensure_code(linc_qclist != NULL, CPL_ERROR_NULL_INPUT);
4976  cpl_ensure_code(bpm_qclist != NULL, CPL_ERROR_NULL_INPUT);
4977 
4978  pcoeffs = cpl_malloc(sizeof(double)*(detmon_lg_config.order + 1));
4979 
4980  skip_if(cpl_propertylist_append_string(gaint_qclist, DETMON_QC_METHOD,
4981  detmon_lg_config.method));
4982  skip_if(cpl_propertylist_set_comment(gaint_qclist, DETMON_QC_METHOD,
4983  DETMON_QC_METHOD_C));
4984 
4985 
4986  if (!strcmp(detmon_lg_config.method, "PTC")) {
4987  /* Computation of GAIN via polynomial fit */
4988  if (detmon_lg_config.exts >= 0) {
4989  cpl_msg_info(cpl_func,
4990  "Polynomial fitting for the GAIN (constant term method)");
4991  } else {
4992  cpl_msg_info(cpl_func,
4993  "Polynomial fitting for the GAIN (constant term method)"
4994  " for extension nb %d", which_ext);
4995  }
4996  skip_if(detmon_lg_qc_ptc(gain_table, gaint_qclist, mode, nsets));
4997  } else {
4998  skip_if(detmon_lg_qc_med(gain_table, gaint_qclist, nsets));
4999  }
5000 
5001  /*^FIXME: This shouldn't be written when no applied */
5002  /* Lamp flux */
5003  if(detmon_lg_config.lamp_ok) {
5004  skip_if(cpl_propertylist_append_double(lint_qclist, DETMON_QC_LAMP_FLUX,
5005  detmon_lg_config.cr));
5006  skip_if(cpl_propertylist_set_comment(lint_qclist, DETMON_QC_LAMP_FLUX,
5007  DETMON_QC_LAMP_FLUX_C));
5008  }
5009 
5010  /*^FIXME: This shouldn't be written when no applied */
5011  if(detmon_lg_config.autocorr == TRUE) {
5012  autocorr = cpl_table_get_column_median(gain_table, "AUTOCORR");
5013  skip_if(cpl_propertylist_append_double(gaint_qclist, DETMON_QC_AUTOCORR,
5014  autocorr));
5015  skip_if(cpl_propertylist_set_comment(gaint_qclist, DETMON_QC_AUTOCORR,
5016  DETMON_QC_AUTOCORR_C));
5017  }
5018  if (detmon_lg_config.exts >= 0) {
5019  cpl_msg_info(cpl_func, "Polynomial fitting pix-to-pix");
5020  } else {
5021  cpl_msg_info(cpl_func, "Polynomial fitting pix-to-pix"
5022  " for extension nb %d", which_ext);
5023  }
5024 
5025  if(!detmon_lg_config.pix2pix) {
5026  double mse = 0;
5027  /* Computation of LINEARITY via polynomial fit */
5028  y = cpl_vector_wrap(nsets,
5029  (double *)cpl_table_get_data_double_const(linear_table,
5030  "MED"));
5031 
5032  if (opt_nir == NIR) {
5033  x = cpl_vector_wrap(nsets,
5034  (double *)cpl_table_get_data_double_const(linear_table,
5035  "DIT"));
5036  } else {
5037  x = cpl_vector_wrap(nsets,
5038  (double *)cpl_table_get_data_double_const(linear_table,
5039  "EXPTIME"));
5040  }
5041 
5042  if(x == NULL || y == NULL) {
5043  cpl_vector_unwrap((cpl_vector *)x);
5044  cpl_vector_unwrap((cpl_vector *)y);
5045  /*
5046  * As x and y are const vectors, if they would be defined at the
5047  * beginning of the function (required for skip_if - end_skip
5048  * scheme), they couldn't be initialised to NULL (required too).
5049  * Therefore, they are considered apart from the scheme.
5050  */
5051  skip_if(1);
5052  }
5053 
5054  cpl_msg_info(cpl_func, "Polynomial fitting for the LINEARITY");
5055  poly_linfit = irplib_polynomial_fit_1d_create(x, y,
5056  detmon_lg_config.order,
5057  &mse);
5058 
5059  if(detmon_lg_config.order == cpl_vector_get_size(x) - 1) {
5060  cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
5061  mse = 0;
5062  }
5063 
5064  if(poly_linfit == NULL) {
5065  cpl_vector_unwrap((cpl_vector *)x);
5066  cpl_vector_unwrap((cpl_vector *)y);
5067  /* See comment in previous error checking if() statement */
5068  skip_if(1);
5069  }
5070 
5071 
5072  min_val=cpl_vector_get_min(y);
5073  max_val=cpl_vector_get_max(y);
5074 
5075  cpl_vector_unwrap((cpl_vector *)x);
5076  cpl_vector_unwrap((cpl_vector *)y);
5077 
5078  for(deg = 0; deg <= detmon_lg_config.order; deg++) {
5079  const double coeff =
5080  cpl_polynomial_get_coeff(poly_linfit, &deg);
5081  char *name_o =
5082  cpl_sprintf("ESO QC LIN COEF%" CPL_SIZE_FORMAT "", deg);
5083  assert(name_o != NULL);
5084  skip_if(cpl_propertylist_append_double(lint_qclist, name_o, coeff));
5085  skip_if(cpl_propertylist_set_comment(lint_qclist,name_o,
5086  DETMON_QC_LIN_COEF_C));
5087 
5088  cpl_free(name_o);
5089  pcoeffs[deg] = coeff;
5090  }
5091  skip_if(cpl_propertylist_append_double(lint_qclist,DETMON_QC_ERRFIT, mse));
5092  skip_if(cpl_propertylist_set_comment(lint_qclist,DETMON_QC_ERRFIT,
5093  DETMON_QC_ERRFIT_MSE_C));
5094 
5095 
5096  } else {
5097  /* pix2pix == TRUE */
5098  y = cpl_vector_wrap(nsets,
5099  (double *)cpl_table_get_data_double_const(linear_table,
5100  "MED"));
5101 
5102  if (opt_nir == NIR)
5103  {
5104  x = cpl_vector_wrap(nsets,
5105  (double *)cpl_table_get_data_double_const(linear_table,
5106  "DIT"));
5107  } else {
5108  x = cpl_vector_wrap(nsets,
5109  (double *)cpl_table_get_data_double_const(linear_table,
5110  "EXPTIME"));
5111 
5112  }
5113 
5114  first = cpl_imagelist_get_const(linearity_inputs, 0);
5115  sizex = cpl_image_get_size_x(first);
5116  sizey = cpl_image_get_size_y(first);
5117  vsize = cpl_vector_get_size(x);
5118  fiterror = cpl_image_new(sizex, sizey, CPL_TYPE_FLOAT);
5119  *coeffs_ptr =
5120  cpl_fit_imagelist_polynomial(x, linearity_inputs, 0,
5121  detmon_lg_config.order, FALSE,
5122  CPL_TYPE_FLOAT, fiterror);
5123  min_val=cpl_vector_get_min(y);
5124  max_val=cpl_vector_get_max(y);
5125  cpl_vector_unwrap((cpl_vector*)x);
5126  cpl_vector_unwrap((cpl_vector*)y);
5127 
5128  irplib_ensure(*coeffs_ptr != NULL, CPL_ERROR_UNSPECIFIED,
5129  "Failed polynomial fit");
5130  //detmon_lg_qclog_lin_coeff(*coeffs_ptr, detmon_lg_config.order,linc_qclist);
5131 
5132  for(deg = 0; deg <= detmon_lg_config.order; deg++)
5133  {
5134  cpl_image *image = cpl_imagelist_get(*coeffs_ptr, deg);
5135  const double coeff = cpl_image_get_median(image);
5136  pcoeffs[deg] = coeff;
5137  name_o1 = cpl_sprintf("ESO QC LIN COEF%d", (int)deg);
5138  name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", (int)deg);
5139  assert(name_o1 != NULL);
5140  assert(name_o2 != NULL);
5141  skip_if(cpl_propertylist_append_double(linc_qclist, name_o1, coeff));
5142  skip_if(cpl_propertylist_set_comment(linc_qclist,name_o1,
5143  DETMON_QC_LIN_COEF_C));
5144  cpl_free(name_o1);
5145  name_o1= NULL;
5146  skip_if(cpl_propertylist_append_double(linc_qclist, name_o2,
5147  cpl_image_get_stdev(image)));
5148  skip_if(cpl_propertylist_set_comment(linc_qclist,name_o2,
5149  DETMON_QC_LIN_COEF_ERR_C));
5150  cpl_free(name_o2);
5151  name_o2= NULL;
5152  }
5153 
5154 
5155  if(detmon_lg_config.order == vsize - 1)
5156  {
5157  cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
5158  skip_if(cpl_propertylist_append_double(linc_qclist,DETMON_QC_ERRFIT,
5159  0.0));
5160  skip_if(cpl_propertylist_set_comment(linc_qclist,DETMON_QC_ERRFIT,
5161  DETMON_QC_ERRFIT_C));
5162  } else
5163  {
5164  skip_if(cpl_propertylist_append_double(linc_qclist,DETMON_QC_ERRFIT,
5165  cpl_image_get_median(fiterror)));
5166  skip_if(cpl_propertylist_set_comment(linc_qclist,DETMON_QC_ERRFIT,
5167  DETMON_QC_ERRFIT_C));
5168  }
5169  } /* end case pix2pix == TRUE */
5170 
5171  skip_if(cpl_propertylist_append_double(lint_qclist,DETMON_QC_COUNTS_MIN,
5172  min_val));
5173  skip_if(cpl_propertylist_set_comment(lint_qclist,DETMON_QC_COUNTS_MIN,
5174  DETMON_QC_COUNTS_MIN_C));
5175  skip_if(cpl_propertylist_append_double(lint_qclist,DETMON_QC_COUNTS_MAX,
5176  max_val));
5177  skip_if(cpl_propertylist_set_comment(lint_qclist,DETMON_QC_COUNTS_MAX,
5178  DETMON_QC_COUNTS_MAX_C));
5179  skip_if(detmon_lg_lineff(pcoeffs,lint_qclist,detmon_lg_config.ref_level,
5180  detmon_lg_config.order));
5181  /* Detection of bad pixels */
5182  if (detmon_lg_config.exts >= 0)
5183  {
5184  cpl_msg_info(cpl_func, "Bad pixel detection");
5185  } else
5186  {
5187  cpl_msg_info(cpl_func, "Bad pixel detection"
5188  " for extension nb %d", which_ext);
5189  }
5190  if(detmon_lg_config.pix2pix)
5191  {
5192 
5193  *bpms_ptr = detmon_bpixs(*coeffs_ptr, detmon_lg_config.bpmbin,
5194  detmon_lg_config.kappa, &nbpixs);
5195 
5196  /*
5197  *bpms_ptr = detmon_bpixs2(x,linearity_inputs,*coeffs_ptr,gain_table,
5198  detmon_lg_config.order,detmon_lg_config.bpmbin,detmon_lg_config.kappa,&nbpixs);
5199  */
5200  /*
5201  cpl_vector_unwrap((cpl_vector*)x);
5202  cpl_vector_unwrap((cpl_vector*)y);
5203  */
5204  skip_if(*bpms_ptr == NULL);
5205  /* we still have to unwrapp x & y that we kept for bpixs2 function */
5206  }
5207 
5208 
5209  skip_if(cpl_propertylist_append_int(bpm_qclist, DETMON_QC_NUM_BPM, nbpixs));
5210  skip_if(cpl_propertylist_set_comment(bpm_qclist, DETMON_QC_NUM_BPM,
5211  DETMON_QC_NUM_BPM_C));
5212  if(detmon_lg_config.lamp_stability != 0.0)
5213  {
5214  skip_if(cpl_propertylist_append_double(lint_qclist, DETMON_QC_LAMP_STAB,
5215  detmon_lg_config.lamp_stability));
5216  skip_if(cpl_propertylist_set_comment(lint_qclist, DETMON_QC_LAMP_STAB,
5217  DETMON_QC_LAMP_STAB_C));
5218  }
5219  /* Fit COEFFS_CUBE and BPM outputs to whole-chip size images (DFS05711) */
5220  if (!detmon_lg_config.wholechip && detmon_lg_config.pix2pix)
5221  {
5222  detmon_lg_fits_coeffs_and_bpm2chip(coeffs_ptr,bpms_ptr);
5223  }
5224  end_skip;
5225 
5226  cpl_free(pcoeffs);
5227  cpl_free(name_o1);
5228  cpl_free(name_o2);
5229  cpl_image_delete(fiterror);
5230  cpl_polynomial_delete(poly_linfit);
5231 
5232 
5233 
5234  return cpl_error_get_code();
5235 }
5236 
5237 /*---------------------------------------------------------------------------*/
5245 /*---------------------------------------------------------------------------*/
5246 static cpl_error_code
5247 detmon_lg_lineff(double * pcoeffs,
5248  cpl_propertylist * qclist,
5249  int ref_level,
5250  int order)
5251 {
5252  double lineff = 0;
5253  double root = 0;
5254  double residual, slope;
5255  int i;
5256  cpl_size deg=0;
5257  cpl_polynomial * poly = cpl_polynomial_new(1);
5258 
5259 
5260  /*
5261  * Construction of the polynomial F_m(F_r) from F_m(t),
5262  * using F_r = a_1 * t.
5263  */
5264  /*
5265  for (deg = 0; deg <= order; deg++) {
5266  cpl_msg_info(cpl_func,"coef[%d]=%g",deg,pcoeffs[deg]);
5267  }
5268  */
5269 
5270 
5271  pcoeffs[0] -= ref_level;
5272 
5273  for (i = 2; i <= order; i++)
5274  {
5275  int j;
5276  for(j = 0; j < i; j++)
5277  {
5278  pcoeffs[i] /= pcoeffs[1];
5279  }
5280  }
5281 
5282  pcoeffs[1] = 1;
5283 
5284  for (deg = 0; deg <= order; deg++) {
5285  /*cpl_msg_info(cpl_func,"coef[%d]=%g",deg,pcoeffs[deg]);*/
5286  skip_if(cpl_polynomial_set_coeff(poly, &deg, pcoeffs[deg]));
5287  }
5288 
5289  /*
5290  * Verification of validity of first guess (0).
5291  * The root to be found will be in the same interval of monotony
5292  * of the first guess; therefore, slope must be greater than 0.
5293  * Slope > 0 and poly(root) = 0 force also residual to be negative.
5294  */
5295  residual = cpl_polynomial_eval_1d(poly, 0.0, &slope);
5296 
5297  if (slope <= 0.0 && residual >= 0.0) {
5298  cpl_msg_warning(cpl_func, "Reference level (--ref_level) outside"
5299  " linearity range of the detector. Cannot compute"
5300  " linearity efficiency (QC.LINEFF).");
5301  lineff = -1;
5302  }
5303  else
5304  {
5305  cpl_error_code err = cpl_polynomial_solve_1d(poly, 0.0, &root, 1);
5306  /*
5307  cpl_msg_info(cpl_func,"root=%g ref_level=%d lin_eff=%d",
5308  root,ref_level,ref_level);
5309  */
5310  if (err == CPL_ERROR_NONE)
5311  {
5312 
5313  lineff = (root - ref_level) / ref_level;
5314  }
5315  else
5316  {
5317  cpl_error_reset();
5318  cpl_msg_warning(cpl_func,
5319  "Cannot compute linearity efficiency (QC.LINEFF)"
5320  "for the current combination "
5321  " of (--ref-level equal %d) and (--order equal %d) parameters. Try "
5322  "to decrease (--ref-level) value.", ref_level, order);
5323  }
5324  }
5325  cpl_msg_warning(cpl_func, "DETMON_QC_LIN_EFF=%f",lineff );
5326  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LIN_EFF,
5327  lineff));
5328  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LIN_EFF,
5329  DETMON_QC_LIN_EFF_C));
5330 
5331  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LIN_EFF_FLUX,
5332  ref_level));
5333  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LIN_EFF_FLUX,
5334  DETMON_QC_LIN_EFF_FLUX_C));
5335 
5336  end_skip;
5337 
5338  cpl_polynomial_delete(poly);
5339 
5340  return cpl_error_get_code();
5341 }
5342 
5343 /*---------------------------------------------------------------------------*/
5350 /*---------------------------------------------------------------------------*/
5351 static cpl_error_code
5352 detmon_lg_qc_ptc(const cpl_table * gain_table,
5353  cpl_propertylist * qclist, unsigned mode, int rows_in_gain)
5354 {
5355  double mse = 0;
5356  cpl_polynomial *poly_fit = NULL;
5357  cpl_polynomial *poly_fit2 = NULL;
5358  cpl_size i;
5359  const int nsets = rows_in_gain;
5360 
5361  cpl_vector *x = NULL;
5362  cpl_vector *y = NULL;
5363 
5364  cpl_errorstate prestate;
5365  double coef = 0;
5366  cpl_ensure_code(gain_table != NULL, CPL_ERROR_NULL_INPUT);
5367  cpl_ensure_code(qclist != NULL, CPL_ERROR_NULL_INPUT);
5368 
5369  x = cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT"));
5370 
5371  y = cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
5372 
5373  skip_if(x == NULL || y == NULL);
5374  if (0 == detmon_lg_check_before_gain(x, y))
5375  {
5376  if (x)
5377  {
5378  cpl_vector_unwrap(x);
5379  }
5380  if (y)
5381  {
5382  cpl_vector_unwrap(y);
5383  }
5384  return CPL_ERROR_NONE;
5385  }
5386  /*it is not really a MSE, but chi square of the fit, see cpl_vector_fill_polynomial_fit_residual for details*/
5387  poly_fit = irplib_polynomial_fit_1d_create_chiq(x, y, 1, &mse);
5388  skip_if(poly_fit == NULL);
5389 
5390  /* Write the QC params corresponding to the fitting of the GAIN */
5391  i = 1;
5392  prestate = cpl_errorstate_get();
5393  coef = cpl_polynomial_get_coeff(poly_fit, &i);
5394  skip_if (!cpl_errorstate_is_equal(prestate) || coef==0);
5395  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD, coef));
5396  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD,
5397  DETMON_QC_CONAD_C));
5398  if (coef != 0)
5399  {
5400  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN,
5401  1 / coef));
5402  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN,
5403  DETMON_QC_GAIN_C));
5404  }
5405  /* MSE is removed - see DFS07358 for details
5406  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_MSE, mse));
5407  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_MSE,
5408  DETMON_QC_GAIN_MSE_C));
5409  */
5410  i = 0;
5411  /* QC.RON computation is disabled, see DFS05852 for details*/
5412 
5413  /* * skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_RON,
5414  cpl_polynomial_get_coeff(poly_fit, &i)));
5415  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_RON,
5416  DETMON_QC_RON_C));
5417  */
5418  if(mode & IRPLIB_GAIN_WITH_AUTOCORR){
5419  const cpl_vector *x2 =
5420  cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT_CORR"));
5421  const cpl_vector *y2 =
5422  cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
5423 
5424  if(x2 == NULL || y2 == NULL) {
5425  cpl_vector_unwrap((cpl_vector *)x2);
5426  cpl_vector_unwrap((cpl_vector *)y2);
5427  /*
5428  * As x and y are const vectors, if they would be defined at the
5429  * beginning of the function (required for skip_if - end_skip
5430  * scheme), they couldn't be initialised to NULL (required too).
5431  * Therefore, they are considered apart from the scheme.
5432  */
5433  skip_if(1);
5434  }
5435 
5436  /* Revise mse, maybe used afterwards */
5437  poly_fit2 = irplib_polynomial_fit_1d_create(x2, y2, 1, &mse);
5438  if(poly_fit2 == NULL) {
5439  cpl_vector_unwrap((cpl_vector *)x2);
5440  cpl_vector_unwrap((cpl_vector *)y2);
5441 
5442  cpl_msg_error(cpl_func, "Error during polynomial fit, err[%s]", cpl_error_get_where());
5443  /* See comment in previous error checking if() statement */
5444  skip_if(1);
5445  }
5446  skip_if(cpl_error_get_code() != CPL_ERROR_NONE);
5447  cpl_vector_unwrap((cpl_vector *)x2);
5448  cpl_vector_unwrap((cpl_vector *)y2);
5449  skip_if(cpl_error_get_code() != CPL_ERROR_NONE);
5450  /* Write the QC params corresponding to the fitting of the GAIN */
5451  i = 1;
5452  prestate = cpl_errorstate_get();
5453  coef = cpl_polynomial_get_coeff(poly_fit2, &i);
5454  skip_if(cpl_error_get_code() != CPL_ERROR_NONE);
5455  skip_if (!cpl_errorstate_is_equal(prestate) || coef == 0);
5456 
5457  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD_CORR,
5458  coef));
5459  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD_CORR,
5460  DETMON_QC_CONAD_CORR_C));
5461 
5462  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_CORR,
5463  1 / coef));
5464  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_CORR,
5465  DETMON_QC_GAIN_CORR_C));
5466  }
5467 
5468  end_skip;
5469 
5470  /*cleanup*/
5471  cpl_vector_unwrap(x);
5472  cpl_vector_unwrap(y);
5473  cpl_polynomial_delete(poly_fit);
5474  cpl_polynomial_delete(poly_fit2);
5475 
5476  return cpl_error_get_code();
5477 }
5478 
5485 static int detmon_lg_check_before_gain(const cpl_vector* x, const cpl_vector* y)
5486 {
5487  const double TOLERANCE = 1e-37;/*MINDOUBLE is not everywhere defined (Mac);*/
5488  double xmin = cpl_vector_get_min(x);
5489  double xmax = cpl_vector_get_max(x);
5490  double ymin = cpl_vector_get_min(y);
5491  double ymax = cpl_vector_get_max(y);
5492  double ystdev = cpl_vector_get_stdev(y);
5493  double xstdev = cpl_vector_get_stdev(x);
5494  int retval = 1;
5495  if (fabs(xmax-xmin) < TOLERANCE &&
5496  fabs(ymax - ymin) < TOLERANCE &&
5497  xstdev < TOLERANCE &&
5498  ystdev < TOLERANCE)
5499  {
5500  cpl_msg_warning(cpl_func, "An empty frame has been detected, linearity, coeffs, gain, FPN values will not be computed.");
5501  retval = 0;
5502  }
5503  return retval;
5504 }
5505 /*---------------------------------------------------------------------------*/
5514 /*---------------------------------------------------------------------------*/
5515 static cpl_error_code
5516 detmon_lg_qc_med(const cpl_table * gain_table,
5517  cpl_propertylist * qclist, int rows_in_gain)
5518 {
5519 
5520  double gain=0;
5521  cpl_vector *x = NULL;
5522  cpl_vector *y = NULL;
5523  int check_result = 0;
5524 
5525  if (rows_in_gain) {/* silence unused var */};
5526 
5527  x = cpl_vector_wrap(rows_in_gain, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT"));
5528  y = cpl_vector_wrap(rows_in_gain, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
5529  check_result = detmon_lg_check_before_gain(x, y);
5530  if (x)
5531  {
5532  cpl_vector_unwrap(x);
5533  }
5534  if (y)
5535  {
5536  cpl_vector_unwrap(y);
5537  }
5538  if (0 == check_result)
5539  {
5540  return CPL_ERROR_NONE;
5541  }
5542 
5543  gain=cpl_table_get_column_median(gain_table, "GAIN");
5544 
5545  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN,gain));
5546 
5547  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN,
5548  DETMON_QC_GAIN_C));
5549 
5550  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_MSE,
5551  cpl_table_get_column_stdev
5552  (gain_table, "GAIN")));
5553  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_MSE,
5554  DETMON_QC_GAIN_MSE_C));
5555 
5556  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD,1./gain));
5557  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD,
5558  DETMON_QC_CONAD_C));
5559 
5560 
5561  gain=cpl_table_get_column_median(gain_table, "GAIN_CORR");
5562 
5563  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_CORR,
5564  gain));
5565  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_CORR,
5566  DETMON_QC_GAIN_CORR_C));
5567 
5568 
5569  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD_CORR,1./gain));
5570  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD_CORR,
5571  DETMON_QC_CONAD_CORR_C));
5572 
5573 
5574  end_skip;
5575 
5576  return cpl_error_get_code();
5577 }
5578 
5579 
5580 /*---------------------------------------------------------------------------*/
5589 /*---------------------------------------------------------------------------*/
5590 static cpl_error_code
5591 detmon_lg_rescale(cpl_imagelist * to_rescale)
5592 {
5593  double med1 =
5594  cpl_image_get_median_window(cpl_imagelist_get(to_rescale, 0),
5595  detmon_lg_config.llx,
5596  detmon_lg_config.lly,
5597  detmon_lg_config.urx,
5598  detmon_lg_config.ury);
5599  double med2 =
5600  cpl_image_get_median_window(cpl_imagelist_get(to_rescale, 1),
5601  detmon_lg_config.llx,
5602  detmon_lg_config.lly,
5603  detmon_lg_config.urx,
5604  detmon_lg_config.ury);
5605 
5606  skip_if(0);
5607 
5608  if(fabs(med1 / med2 - 1) > 0.001) {
5609  if(med1 > med2)
5610  skip_if(cpl_image_divide_scalar(cpl_imagelist_get(to_rescale, 0),
5611  med1 / med2));
5612  else
5613  skip_if(cpl_image_divide_scalar(cpl_imagelist_get(to_rescale, 1),
5614  med2 / med1));
5615  }
5616 
5617  end_skip;
5618 
5619  return cpl_error_get_code();
5620 }
5621 
5622 static cpl_error_code
5623 detmon_pair_extract_next(const cpl_frameset * set,
5624  int* iindex,
5625  int* next_element,
5626  double* dit_array,
5627  cpl_frameset ** pair,
5628  double tolerance) /* detmon_lg_config.tolerance */
5629 {
5630  double dit = -100;
5631  double dit_next = -100;
5632  cpl_size* selection;
5633  int nsets_extracted = 0;
5634  cpl_ensure_code(set != NULL, CPL_ERROR_NULL_INPUT);
5635  cpl_ensure_code(dit_array != NULL, CPL_ERROR_NULL_INPUT);
5636  cpl_ensure_code(iindex != NULL, CPL_ERROR_NULL_INPUT);
5637  cpl_ensure_code(pair != NULL, CPL_ERROR_NULL_INPUT);
5638 
5639  nsets_extracted = cpl_frameset_get_size(set);
5640  selection = cpl_malloc(sizeof(cpl_size) * nsets_extracted);
5641  memset(&selection[0], 0, sizeof(cpl_size) * nsets_extracted);
5642 
5643 
5644  dit = dit_array[*next_element ];
5645  /* cpl_msg_info(cpl_func, "%d: dit %f",*next_element, dit ); */
5646  if (*next_element < nsets_extracted - 1)
5647  {
5648  dit_next = dit_array[*next_element + 1 ];
5649  /* cpl_msg_info(cpl_func, "%d: dit %f",*next_element + 1, dit_next ); */
5650  }
5651  /* one element would be returned always */
5652  selection[iindex[*next_element] ] = 1;
5653  if (fabs(dit - dit_next) < tolerance)
5654  {
5655  /* return a second element of the pair */
5656  selection[iindex[*next_element + 1] ] = 1;
5657  (*next_element)++;
5658  }
5659  else
5660  {
5661  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);
5662  }
5663  (*next_element)++;
5664  /* prepare frameset */
5665  cpl_frameset_delete(*pair);
5666  *pair = cpl_frameset_extract(set, selection, 1);
5667 
5668 
5669  cpl_free(selection);
5670  return cpl_error_get_code();
5671 }
5672 
5673 static cpl_error_code
5674 detmon_single_extract_next(const cpl_frameset * set,
5675  int* iindex,
5676  int* next_element,
5677  double* dit_array,
5678  cpl_frameset ** pair)
5679 {
5680  cpl_size* selection;
5681  int nsets_extracted = 0;
5682  cpl_ensure_code(set != NULL, CPL_ERROR_NULL_INPUT);
5683  cpl_ensure_code(dit_array != NULL, CPL_ERROR_NULL_INPUT);
5684  cpl_ensure_code(iindex != NULL, CPL_ERROR_NULL_INPUT);
5685  cpl_ensure_code(pair != NULL, CPL_ERROR_NULL_INPUT);
5686 
5687  nsets_extracted = cpl_frameset_get_size(set);
5688  selection = cpl_malloc(sizeof(cpl_size) * nsets_extracted);
5689  memset(&selection[0], 0, sizeof(cpl_size) * nsets_extracted);
5690 
5691  /* only one element would be returned */
5692  selection[iindex[*next_element] ] = 1;
5693  (*next_element)++;
5694  /* prepare frameset */
5695  cpl_frameset_delete(*pair);
5696  *pair = cpl_frameset_extract(set, selection, 1);
5697 
5698  cpl_free(selection);
5699  return cpl_error_get_code();
5700 }
5701 
5702 
5703 /*---------------------------------------------------------------------------*/
5792 /*---------------------------------------------------------------------------*/
5793 
5794 cpl_table *
5795 detmon_gain(const cpl_imagelist * imlist_on,
5796  const cpl_imagelist * imlist_off,
5797  const cpl_vector * exptimes,
5798  const cpl_vector * ndit,
5799  double tolerance,
5800  int llx,
5801  int lly,
5802  int urx,
5803  int ury,
5804  double kappa,
5805  int nclip,
5806  int xshift,
5807  int yshift,
5808  cpl_propertylist * qclist,
5809  unsigned mode,
5810  cpl_imagelist ** diff_imlist,
5811  cpl_imagelist ** autocorr_imlist)
5812 {
5813  cpl_table * gain_table = NULL;
5814  cpl_imagelist * difflist = NULL;
5815  cpl_imagelist * autocorrlist = NULL;
5816  cpl_imagelist * c_onlist = NULL;
5817  cpl_imagelist * c_offlist = NULL;
5818  cpl_vector * diffdits = NULL;
5819  cpl_vector * diffndits = NULL;
5820  int rows_in_gain = 0;
5821  int ndiffdits, ndits;
5822  int i, j;
5823  cpl_boolean opt_nir = mode & IRPLIB_GAIN_OPT ? OPT : NIR;
5824  const char * method = mode & IRPLIB_GAIN_PTC ? "PTC" : "MED";
5825 
5826  cpl_ensure(imlist_on != NULL, CPL_ERROR_NULL_INPUT, NULL);
5827  cpl_ensure(imlist_off != NULL, CPL_ERROR_NULL_INPUT, NULL);
5828  cpl_ensure(exptimes != NULL, CPL_ERROR_NULL_INPUT, NULL);
5829  cpl_ensure(qclist != NULL, CPL_ERROR_NULL_INPUT, NULL);
5830 
5831  /* Create table with columns */
5832  gain_table = cpl_table_new(cpl_vector_get_size(exptimes) / 2);
5833  skip_if(detmon_gain_table_create(gain_table, opt_nir));
5834 
5835 
5836  /* Search for different EXPTIME values */
5837  skip_if(detmon_lg_find_dits_ndits(exptimes, ndit,tolerance,&diffdits,
5838  &diffndits));
5839  ndiffdits = cpl_vector_get_size(diffdits);
5840 
5841  ndits = cpl_vector_get_size(exptimes);
5842 
5843  /* AUTOCORR processing requires both. They will become outputs later. */
5844  if (mode & IRPLIB_GAIN_WITH_AUTOCORR && (diff_imlist || autocorr_imlist)) {
5845  difflist = cpl_imagelist_new();
5846  autocorrlist = cpl_imagelist_new();
5847  }
5848 
5849  if (mode & IRPLIB_GAIN_COLLAPSE) {
5850  if (mode & IRPLIB_GAIN_WITH_RESCALE) {
5851  c_offlist = cpl_imagelist_duplicate(imlist_off);
5852  skip_if(detmon_lg_rescale(c_offlist));
5853  } else {
5854  c_offlist = (cpl_imagelist *) imlist_off;
5855  }
5856  }
5857 
5858  /* Loop over the different DITs found in EXPTIMEs */
5859  for (i = 0; i < ndiffdits; i++) {
5860  int c_nons;
5861  int c_noffs = 0; /* False (uninit) warning */
5862 
5863  double c_dit = 0;
5864  int c_ndit = 1;
5865 
5866  c_dit=cpl_vector_get(diffdits, i);
5867 
5868  if(opt_nir) {
5869  c_ndit=(int)cpl_vector_get(diffndits, i);
5870  }
5871 
5872  c_onlist = cpl_imagelist_new();
5873  c_nons = 0;
5874 
5875  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
5876  c_offlist = cpl_imagelist_new();
5877  c_noffs = 0;
5878  }
5879 
5880  /* Extraction of images of EXPTIME i */
5881  for(j = 0; j < ndits; j++) {
5882  if (fabs(c_dit - cpl_vector_get(exptimes, j)) <= tolerance) {
5883  /*
5884  * First we get the corresponding image from the ON imlist.
5885  * The option IRPLIB_GAIN_WITH_RESCALE requires to modify
5886  * the input pixel buffer; therefore we must duplicate it.
5887  * On the other hand, if this option is not required, there
5888  * is no need for that duplication. We must only care that
5889  * c_onlist must not be deleted but only unset.
5890  */
5891  cpl_image * im_on;
5892  if (mode & IRPLIB_GAIN_WITH_RESCALE) {
5893  const cpl_image * im =
5894  cpl_imagelist_get_const(imlist_on, j);
5895  im_on = cpl_image_duplicate(im);
5896  } else {
5897  im_on = (cpl_image *)cpl_imagelist_get_const(imlist_on, j);
5898  }
5899  skip_if(cpl_imagelist_set(c_onlist, im_on, c_nons));
5900  c_nons++;
5901 
5902  /*
5903  * Same explanation as above but for OFF imlist.
5904  * Only necessary when IRPLIB_GAIN_NO_COLLAPSE required.
5905  */
5906  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
5907  cpl_image * im_off;
5908  if (mode & IRPLIB_GAIN_WITH_RESCALE) {
5909  const cpl_image * im =
5910  cpl_imagelist_get_const(imlist_off, j);
5911  im_off = cpl_image_duplicate(im);
5912  } else {
5913  im_off =
5914  (cpl_image *) cpl_imagelist_get_const(imlist_off, j);
5915  }
5916  skip_if(cpl_imagelist_set(c_offlist, im_off, c_noffs));
5917  c_noffs++;
5918  }
5919  }
5920  }
5921 
5922  /* If NO_COLLAPSE, must be the same number of images! */
5923  if (mode & IRPLIB_GAIN_NO_COLLAPSE)
5924  skip_if (c_nons != c_noffs);
5925 
5926  /* There must be pairs! */
5927  skip_if (c_nons == 0 || c_nons % 2 != 0);
5928 
5929  /* Rescaling */
5930  if(mode & IRPLIB_GAIN_WITH_RESCALE) {
5931  skip_if(detmon_lg_rescale(c_onlist));
5932  if (mode & IRPLIB_GAIN_NO_COLLAPSE)
5933  skip_if(detmon_lg_rescale(c_offlist));
5934  }
5935 
5936  /* The following loop is necessary for the case of multiple pairs
5937  of same EXPTIME values */
5938  while(c_nons > 0) {
5939  int rows_affected = 1;
5940  skip_if(detmon_gain_table_fill_row(gain_table,
5941  c_dit,c_ndit,
5942  autocorrlist,
5943  difflist, c_onlist,
5944  c_offlist, kappa, nclip,
5945  llx, lly, urx, ury,
5946  xshift, yshift,1E10, i,
5947  mode, &rows_affected));
5948  if (rows_affected)
5949  {
5950  rows_in_gain++;
5951  }
5952  if (mode & IRPLIB_GAIN_WITH_RESCALE) {
5953  cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
5954  cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
5955  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
5956  cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
5957  cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
5958  }
5959  } else {
5960  cpl_imagelist_unset(c_onlist, 0);
5961  skip_if(0);
5962  cpl_imagelist_unset(c_onlist, 0);
5963  skip_if(0);
5964  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
5965  cpl_imagelist_unset(c_offlist, 0);
5966  skip_if(0);
5967  cpl_imagelist_unset(c_offlist, 0);
5968  skip_if(0);
5969  }
5970  }
5971  skip_if(0);
5972  c_nons -= 2;
5973  }
5974 
5975  cpl_imagelist_delete(c_onlist);
5976  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
5977  cpl_imagelist_delete(c_offlist);
5978  }
5979  }
5980 
5981  skip_if(cpl_propertylist_append_string(qclist, DETMON_QC_METHOD, method));
5982  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_METHOD,
5983  DETMON_QC_METHOD_C));
5984 
5985  /* Computation of GAIN via polynomial fit */
5986  if (mode & IRPLIB_GAIN_PTC) {
5987  skip_if(detmon_lg_qc_ptc(gain_table, qclist, mode, rows_in_gain));
5988  } else {
5989  skip_if(detmon_lg_qc_med(gain_table, qclist, rows_in_gain));
5990  }
5991 
5992  if(mode & IRPLIB_GAIN_WITH_AUTOCORR) {
5993  double autocorr = cpl_table_get_column_median(gain_table, "AUTOCORR");
5994  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_AUTOCORR,
5995  autocorr));
5996  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_AUTOCORR,
5997  DETMON_QC_AUTOCORR_C));
5998  }
5999 
6000  if (diff_imlist != NULL) *diff_imlist = difflist;
6001  if (autocorr_imlist != NULL) *autocorr_imlist = autocorrlist;
6002 
6003  end_skip;
6004 
6005  cpl_vector_delete(diffdits);
6006  cpl_vector_delete(diffndits);
6007 
6008  return gain_table;
6009 }
6010 
6011 static cpl_error_code
6012 detmon_gain_table_create(cpl_table * gain_table,
6013  const cpl_boolean opt_nir)
6014 {
6015  if (opt_nir == NIR) {
6016  skip_if(cpl_table_new_column(gain_table, "DIT", CPL_TYPE_DOUBLE));
6017  skip_if(cpl_table_new_column(gain_table, "NDIT", CPL_TYPE_INT));
6018  } else { /* OPT */
6019  skip_if(cpl_table_new_column(gain_table, "EXPTIME", CPL_TYPE_DOUBLE));
6020  }
6021  skip_if(cpl_table_new_column(gain_table, "MEAN_ON1", CPL_TYPE_DOUBLE));
6022  skip_if(cpl_table_new_column(gain_table, "MEAN_ON2", CPL_TYPE_DOUBLE));
6023  skip_if(cpl_table_new_column(gain_table, "MEAN_OFF1", CPL_TYPE_DOUBLE));
6024  skip_if(cpl_table_new_column(gain_table, "MEAN_OFF2", CPL_TYPE_DOUBLE));
6025  skip_if(cpl_table_new_column(gain_table, "SIG_ON_DIF", CPL_TYPE_DOUBLE));
6026  skip_if(cpl_table_new_column(gain_table, "SIG_OFF_DIF", CPL_TYPE_DOUBLE));
6027  skip_if(cpl_table_new_column(gain_table, "GAIN", CPL_TYPE_DOUBLE));
6028  skip_if(cpl_table_new_column(gain_table, "AUTOCORR", CPL_TYPE_DOUBLE));
6029  skip_if(cpl_table_new_column(gain_table, "GAIN_CORR", CPL_TYPE_DOUBLE));
6030  skip_if(cpl_table_new_column(gain_table, "ADU", CPL_TYPE_DOUBLE));
6031  skip_if(cpl_table_new_column(gain_table, "X_FIT", CPL_TYPE_DOUBLE));
6032  skip_if(cpl_table_new_column(gain_table, "X_FIT_CORR", CPL_TYPE_DOUBLE));
6033  skip_if(cpl_table_new_column(gain_table, "Y_FIT", CPL_TYPE_DOUBLE));
6034  skip_if(cpl_table_new_column(gain_table, "Y_FIT_CORR", CPL_TYPE_DOUBLE));
6035  skip_if(cpl_table_new_column(gain_table, "FLAG", CPL_TYPE_INT));
6036 
6037  end_skip;
6038 
6039  return cpl_error_get_code();
6040 }
6041 
6042 static cpl_error_code
6043 detmon_lin_table_create(cpl_table * lin_table,
6044  const cpl_boolean opt_nir)
6045 {
6046  if (opt_nir == NIR) {
6047  skip_if(cpl_table_new_column(lin_table, "DIT", CPL_TYPE_DOUBLE));
6048  } else { /* OPT */
6049  skip_if(cpl_table_new_column(lin_table, "EXPTIME", CPL_TYPE_DOUBLE));
6050  }
6051  skip_if(cpl_table_new_column(lin_table, "MED", CPL_TYPE_DOUBLE));
6052  skip_if(cpl_table_new_column(lin_table, "MEAN", CPL_TYPE_DOUBLE));
6053  skip_if(cpl_table_new_column(lin_table, "MED_DIT", CPL_TYPE_DOUBLE));
6054  skip_if(cpl_table_new_column(lin_table, "MEAN_DIT", CPL_TYPE_DOUBLE));
6055  skip_if(cpl_table_new_column(lin_table, "ADL", CPL_TYPE_DOUBLE));
6056  end_skip;
6057 
6058  return cpl_error_get_code();
6059 }
6060 
6061 static cpl_vector *
6062 detmon_lg_find_dits(const cpl_vector * exptimes,
6063  double tolerance)
6064 {
6065  cpl_vector * dits = cpl_vector_new(cpl_vector_get_size(exptimes) / 2);
6066  int ndits = 0;
6067 
6068  int i, j;
6069 
6070  /* First different EXPTIME */
6071  cpl_vector_set(dits, 0, cpl_vector_get(exptimes, 0));
6072  ndits = 1;
6073 
6074  /* Search for all different EXPTIMEs */
6075  for(i = 1; i < cpl_vector_get_size(exptimes); i++) {
6076  int ndiffs = 0;
6077  for (j = 0; j < ndits; j++) {
6078  if (fabs(cpl_vector_get(exptimes, i) -
6079  cpl_vector_get(dits, j)) > tolerance)
6080  ndiffs++;
6081  }
6082  if(ndiffs == ndits) {
6083  cpl_vector_set(dits, ndits, cpl_vector_get(exptimes, i));
6084  ndits++;
6085  }
6086  }
6087 
6088  cpl_vector_set_size(dits, ndits);
6089 
6090  return dits;
6091 }
6092 
6093 
6094 
6095 
6096 static cpl_error_code
6097 detmon_lg_find_dits_ndits(const cpl_vector * exptimes,
6098  const cpl_vector * vec_ndits,
6099  double tolerance,
6100  cpl_vector** diff_dits,
6101  cpl_vector** diff_ndits)
6102 {
6103  int ndits = 0;
6104 
6105  int i, j;
6106  int size=0;
6107 
6108 
6109  * diff_dits = cpl_vector_new(cpl_vector_get_size(exptimes) / 2);
6110  * diff_ndits = cpl_vector_new(cpl_vector_get_size(*diff_dits));
6111 
6112  /* First different EXPTIME */
6113  cpl_vector_set(*diff_dits, 0, cpl_vector_get(exptimes, 0));
6114  cpl_vector_set(*diff_ndits, 0, cpl_vector_get(vec_ndits, 0));
6115 
6116  ndits = 1;
6117  size=cpl_vector_get_size(exptimes);
6118  /* Search for all different EXPTIMEs */
6119  for(i = 1; i < size; i++) {
6120  int ndiffs = 0;
6121  for (j = 0; j < ndits; j++) {
6122  if (fabs(cpl_vector_get(exptimes, i) -
6123  cpl_vector_get(*diff_dits,j)) > tolerance)
6124  ndiffs++;
6125  }
6126  if(ndiffs == ndits) {
6127  cpl_vector_set(*diff_dits, ndits, cpl_vector_get(exptimes, i));
6128  cpl_vector_set(*diff_ndits, ndits, cpl_vector_get(vec_ndits, i));
6129  ndits++;
6130  }
6131  }
6132 
6133  cpl_vector_set_size(*diff_dits, ndits);
6134  cpl_vector_set_size(*diff_ndits, ndits);
6135 
6136 
6137  return cpl_error_get_code();
6138 }
6139 
6140 
6141 /*---------------------------------------------------------------------------*/
6222 /*---------------------------------------------------------------------------*/
6223 
6224 cpl_table *
6225 detmon_lin(const cpl_imagelist * imlist_on,
6226  const cpl_imagelist * imlist_off,
6227  const cpl_vector * exptimes,
6228  double tolerance,
6229  int llx,
6230  int lly,
6231  int urx,
6232  int ury,
6233  int order,
6234  int ref_level,
6235  double kappa,
6236  cpl_boolean bpmbin,
6237  cpl_propertylist * qclist,
6238  unsigned mode,
6239  cpl_imagelist ** coeffs_cube,
6240  cpl_image ** bpm)
6241 {
6242  cpl_table * lin_table = NULL;
6243  cpl_imagelist * c_onlist = NULL;
6244  cpl_imagelist * c_offlist = NULL;
6245  cpl_vector * diffdits = NULL;
6246  cpl_imagelist * lin_inputs = NULL;
6247  cpl_polynomial * poly_linfit = NULL;
6248  cpl_image * fiterror = NULL;
6249  cpl_vector * vcoeffs = NULL;
6250  double * pcoeffs = NULL;
6251  int ndiffdits, ndits;
6252  int i, j;
6253  cpl_boolean opt_nir = mode & IRPLIB_LIN_OPT ? OPT : NIR;
6254  const cpl_vector *x = NULL;
6255  const cpl_vector *y = NULL;
6256 
6257  const cpl_image * first = NULL;
6258  int sizex = 0;
6259  int sizey = 0;
6260 
6261  cpl_size deg;
6262  double vsize = 0;
6263 
6264 
6265  cpl_ensure(imlist_on != NULL, CPL_ERROR_NULL_INPUT, NULL);
6266  cpl_ensure(imlist_off != NULL, CPL_ERROR_NULL_INPUT, NULL);
6267  cpl_ensure(exptimes != NULL, CPL_ERROR_NULL_INPUT, NULL);
6268  cpl_ensure(qclist != NULL, CPL_ERROR_NULL_INPUT, NULL);
6269  cpl_ensure(order > 0 , CPL_ERROR_ILLEGAL_INPUT, NULL);
6270 
6271  vcoeffs = cpl_vector_new(order + 1);
6272  pcoeffs = cpl_vector_get_data(vcoeffs);
6273 
6274  /* This mode requires optional outputs */
6275  if (mode & IRPLIB_LIN_PIX2PIX) {
6276  cpl_ensure(coeffs_cube != NULL, CPL_ERROR_NULL_INPUT, NULL);
6277  cpl_ensure(bpm != NULL, CPL_ERROR_NULL_INPUT, NULL);
6278  lin_inputs = cpl_imagelist_new();
6279  }
6280 
6281  /* Create table with columns */
6282  lin_table = cpl_table_new(cpl_vector_get_size(exptimes) / 2);
6283  skip_if(detmon_lin_table_create(lin_table, opt_nir));
6284 
6285  /* Search for different EXPTIME values */
6286  /* Search for different EXPTIME values */
6287  diffdits = detmon_lg_find_dits(exptimes, tolerance);
6288  ndiffdits = cpl_vector_get_size(diffdits);
6289 
6290  ndits = cpl_vector_get_size(exptimes);
6291 
6292 
6293 
6294 
6295 
6296 
6297  /* TO BE IMPLEMENTED SIMILARLY TO UPPER LEVEL FUNCTION (search for nskip)
6298  if(filter > 0) {
6299  double med1 =
6300  cpl_image_get_median_window(cpl_imagelist_get(imlist_on, 0),
6301  llx,lly,urx,ury);
6302  double med2 =
6303  cpl_image_get_median_window(cpl_imagelist_get(imlist_on, 1),
6304  llx,lly,urx,ury);
6305  if ( med1 > (double)filter ||
6306  med2 > (double)filter) {
6307  follow = CPL_FALSE;
6308  cpl_table_select_row(lin_table, dit_nb);
6309  dit_nskip++;
6310  cpl_msg_warning(cpl_func, "Frames of EXPTIME nb %d "
6311  "will not be taken into account for computation "
6312  "as they are above --filter threshold", dit_nb);
6313  }
6314  }
6315  */
6316 
6317 
6318 
6319 
6320  if (mode & IRPLIB_LIN_COLLAPSE) {
6321  /*
6322  * The master bias is required only for
6323  * linearity computation in the OPT domain
6324  */
6325  cpl_image * collapse = cpl_imagelist_collapse_create(imlist_off);
6326  skip_if(collapse == NULL);
6327 
6328  c_offlist = cpl_imagelist_new();
6329  skip_if(cpl_imagelist_set(c_offlist, collapse, 0));
6330  }
6331 
6332  /* Loop over the different DITs found in EXPTIMEs */
6333  for (i = 0; i < ndiffdits; i++) {
6334  int c_nons;
6335  int c_noffs = 0; /* False (uninit) warning */
6336 
6337  double c_dit = cpl_vector_get(diffdits, i);
6338 
6339  c_onlist = cpl_imagelist_new();
6340  c_nons = 0;
6341 
6342  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6343  c_offlist = cpl_imagelist_new();
6344  c_noffs = 0;
6345  }
6346 
6347  for(j = 0; j < ndits; j++) {
6348  if (fabs(c_dit - cpl_vector_get(exptimes, j)) <= tolerance) {
6349  /*
6350  * First we get the corresponding image from the ON imlist.
6351  * The option IRPLIB_GAIN_WITH_RESCALE requires to modify
6352  * the input pixel buffer; therefore we must duplicate it.
6353  * On the other hand, if this option is not required, there
6354  * is no need for that duplication. We must only care that
6355  * c_onlist must not be deleted but only unset.
6356  */
6357  cpl_image * im_on;
6358  if (mode & IRPLIB_LIN_WITH_RESCALE) {
6359  const cpl_image * im =
6360  cpl_imagelist_get_const(imlist_on, j);
6361  im_on = cpl_image_duplicate(im);
6362  } else {
6363  im_on = (cpl_image *)cpl_imagelist_get_const(imlist_on, j);
6364  }
6365  skip_if(cpl_imagelist_set(c_onlist, im_on, c_nons));
6366  c_nons++;
6367 
6368  /*
6369  * Same explanation as above but for OFF imlist.
6370  * Only necessary when IRPLIB_GAIN_NO_COLLAPSE required.
6371  */
6372  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6373  cpl_image * im_off;
6374  if (mode & IRPLIB_LIN_WITH_RESCALE) {
6375  const cpl_image * im =
6376  cpl_imagelist_get_const(imlist_off, j);
6377  im_off = cpl_image_duplicate(im);
6378  } else {
6379  im_off =
6380  (cpl_image *) cpl_imagelist_get_const(imlist_off, j);
6381  }
6382  skip_if(cpl_imagelist_set(c_offlist, im_off, c_noffs));
6383  c_noffs++;
6384  }
6385  }
6386  }
6387 
6388  /* If NO_COLLAPSE, must be the same number of images! */
6389  if (mode & IRPLIB_LIN_NO_COLLAPSE)
6390  skip_if (c_nons != c_noffs);
6391 
6392  /* There must be pairs! */
6393  skip_if (c_nons == 0 || c_nons % 2 != 0);
6394 
6395  /* Rescaling */
6396  if(mode & IRPLIB_LIN_WITH_RESCALE) {
6397  skip_if(detmon_lg_rescale(c_onlist));
6398  if (mode & IRPLIB_LIN_NO_COLLAPSE)
6399  skip_if(detmon_lg_rescale(c_offlist));
6400  }
6401 
6402  /* The following loop is necessary for the case of multiple pairs
6403  of same EXPTIME values */
6404  while(c_nons > 0) {
6405 
6406  skip_if(detmon_lin_table_fill_row(lin_table, c_dit,
6407  lin_inputs,
6408  c_onlist, c_offlist,
6409  llx, lly, urx, ury,
6410  i, 0, mode));
6411 
6412  if (mode & IRPLIB_LIN_WITH_RESCALE) {
6413  cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
6414  cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
6415  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6416  cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
6417  cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
6418  }
6419  } else {
6420  cpl_imagelist_unset(c_onlist, 0);
6421  skip_if(0);
6422  cpl_imagelist_unset(c_onlist, 0);
6423  skip_if(0);
6424  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6425  cpl_imagelist_unset(c_offlist, 0);
6426  skip_if(0);
6427  cpl_imagelist_unset(c_offlist, 0);
6428  skip_if(0);
6429  }
6430  }
6431  skip_if(0);
6432  c_nons -= 2;
6433  }
6434 
6435  cpl_imagelist_delete(c_onlist);
6436  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6437  cpl_imagelist_delete(c_offlist);
6438  }
6439  }
6440 
6441  skip_if(detmon_add_adl_column(lin_table, opt_nir));
6442 
6443  if(!(mode & IRPLIB_LIN_PIX2PIX)) {
6444  double mse = 0;
6445  /* Computation of LINEARITY via polynomial fit */
6446  y = cpl_vector_wrap(cpl_table_get_nrow(lin_table),
6447  (double *)cpl_table_get_data_double_const(lin_table,
6448  "MED"));
6449  if (opt_nir == NIR) {
6450  x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
6451  (double *)cpl_table_get_data_double_const(lin_table, "DIT"));
6452  } else {
6453  x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
6454  (double *)cpl_table_get_data_double_const(lin_table, "EXPTIME"));
6455  }
6456  if(x == NULL || y == NULL) {
6457  cpl_vector_unwrap((cpl_vector *)x);
6458  cpl_vector_unwrap((cpl_vector *)y);
6459  /*
6460  * As x and y are const vectors, if they would be defined at the
6461  * beginning of the function (required for skip_if - end_skip
6462  * scheme), they couldn't be initialised to NULL (required too).
6463  * Therefore, they are considered apart from the scheme.
6464  */
6465  skip_if(1);
6466  }
6467 
6468  cpl_msg_info(cpl_func, "Polynomial fitting for the LINEARITY");
6469  poly_linfit = irplib_polynomial_fit_1d_create_chiq(x, y, order, &mse);
6470 
6471  if(order == cpl_vector_get_size(x) - 1) {
6472  cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
6473  mse = 0;
6474  }
6475 
6476  if(poly_linfit == NULL) {
6477  cpl_vector_unwrap((cpl_vector *)x);
6478  cpl_vector_unwrap((cpl_vector *)y);
6479  /* See comment in previous error checking if() statement */
6480  skip_if(1);
6481  }
6482 
6483  cpl_vector_unwrap((cpl_vector *)x);
6484  cpl_vector_unwrap((cpl_vector *)y);
6485 
6486  for(deg = 0; deg <= order; deg++) {
6487  const double coeff =
6488  cpl_polynomial_get_coeff(poly_linfit, &deg);
6489  char *name_o =
6490  cpl_sprintf("ESO QC LIN COEF%" CPL_SIZE_FORMAT "", deg);
6491  assert(name_o != NULL);
6492  skip_if(cpl_propertylist_append_double(qclist, name_o, coeff));
6493  skip_if(cpl_propertylist_set_comment(qclist,name_o,
6494  DETMON_QC_LIN_COEF_C));
6495  cpl_free(name_o);
6496  pcoeffs[deg] = coeff;
6497  }
6498  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT, mse));
6499  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
6500  DETMON_QC_ERRFIT_MSE_C));
6501 
6502 
6503  } else {
6504  if (opt_nir == NIR) {
6505  x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
6506  (double *)cpl_table_get_data_double_const(lin_table,
6507  "DIT"));
6508  } else {
6509  x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
6510  (double *)cpl_table_get_data_double_const(lin_table,
6511  "EXPTIME"));
6512  }
6513 
6514 
6515  first = cpl_imagelist_get_const(lin_inputs, 0);
6516  sizex = cpl_image_get_size_x(first);
6517  sizey = cpl_image_get_size_y(first);
6518 
6519  vsize = cpl_vector_get_size(x);
6520 
6521  fiterror = cpl_image_new(sizex, sizey, CPL_TYPE_FLOAT);
6522 
6523  *coeffs_cube =
6524  cpl_fit_imagelist_polynomial(x, lin_inputs, 0,
6525  order, FALSE, CPL_TYPE_FLOAT,
6526  fiterror);
6527 
6528  cpl_vector_unwrap((cpl_vector*)x);
6529  irplib_ensure(*coeffs_cube != NULL, CPL_ERROR_UNSPECIFIED,
6530  "Failed polynomial fit");
6531 
6532  for(i = 0; i <= order; i++) {
6533  cpl_image *image = cpl_imagelist_get(*coeffs_cube, i);
6534  const double coeff = cpl_image_get_median(image);
6535  char * name_o1 = cpl_sprintf("ESO QC LIN COEF%d", i);
6536  char * name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", i);
6537  pcoeffs[i] = coeff;
6538  assert(name_o1 != NULL);
6539  assert(name_o2 != NULL);
6540  skip_if(cpl_propertylist_append_double(qclist, name_o1, coeff));
6541  skip_if(cpl_propertylist_set_comment(qclist,name_o1,
6542  DETMON_QC_LIN_COEF_C));
6543  cpl_free(name_o1);
6544  name_o1= NULL;
6545  skip_if(cpl_propertylist_append_double(qclist, name_o2,
6546  cpl_image_get_stdev(image)));
6547  skip_if(cpl_propertylist_set_comment(qclist,name_o2,
6548  DETMON_QC_LIN_COEF_ERR_C));
6549  cpl_free(name_o2);
6550  name_o2= NULL;
6551  }
6552 
6553  if(order == vsize - 1) {
6554  cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
6555  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT,
6556  0.0));
6557  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
6558  DETMON_QC_ERRFIT_C));
6559 
6560 
6561  } else {
6562  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT,
6563  cpl_image_get_median(fiterror)));
6564  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
6565  DETMON_QC_ERRFIT_C));
6566 
6567  }
6568  }
6569 
6570  skip_if(detmon_lg_lineff(pcoeffs, qclist, ref_level, order));
6571 
6572  if(mode & IRPLIB_LIN_PIX2PIX) {
6573  int nbpixs;
6574  *bpm = detmon_bpixs(*coeffs_cube, bpmbin, kappa, &nbpixs);
6575  skip_if(*bpm == NULL);
6576  skip_if(cpl_propertylist_append_int(qclist, DETMON_QC_NUM_BPM,
6577  nbpixs));
6578  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_NUM_BPM,
6579  DETMON_QC_NUM_BPM_C));
6580  }
6581 
6582  end_skip;
6583 
6584  cpl_vector_delete(diffdits);
6585  cpl_polynomial_delete(poly_linfit);
6586  cpl_imagelist_delete(lin_inputs);
6587  cpl_vector_delete(vcoeffs);
6588  cpl_image_delete(fiterror);
6589 
6590  return lin_table;
6591 
6592 }
6593 
6594 /*--------------------------------------------------------------------------*/
6618 /*--------------------------------------------------------------------------*/
6619 static cpl_error_code
6620 detmon_lin_table_fill_row(cpl_table * lin_table, double c_dit,
6621  cpl_imagelist * linearity_inputs,
6622  const cpl_imagelist * ons,
6623  const cpl_imagelist * offs,
6624  int llx,
6625  int lly,
6626  int urx,
6627  int ury,
6628  const int pos,
6629  const int nskip,
6630  unsigned mode)
6631 {
6632  cpl_image * extracted=NULL;
6633 
6634  cpl_ensure_code(lin_table != NULL, CPL_ERROR_NULL_INPUT);
6635  cpl_ensure_code(ons != NULL, CPL_ERROR_NULL_INPUT);
6636  cpl_ensure_code(offs != NULL, CPL_ERROR_NULL_INPUT);
6637 
6638  if (mode & IRPLIB_LIN_PIX2PIX) {
6639  cpl_msg_debug(cpl_func,"checking linearity inputs");
6640  cpl_ensure_code(linearity_inputs != NULL, CPL_ERROR_NULL_INPUT);
6641  }
6642 
6643 
6644  if (mode & IRPLIB_LIN_NIR) {
6645  cpl_table_set(lin_table, "DIT", pos, c_dit);
6646  } else if (mode & IRPLIB_LIN_OPT) { /*OPT */
6647  cpl_table_set(lin_table, "EXPTIME", pos, c_dit);
6648  } else {
6649  cpl_msg_error(cpl_func, "Mandatory mode not given");
6650  }
6651 
6652  {
6653  const cpl_image * off2;
6654  if (cpl_imagelist_get_size(offs) == 1 || mode & IRPLIB_LIN_COLLAPSE)
6655  off2 = cpl_imagelist_get_const(offs, 0);
6656  else
6657  off2 = cpl_imagelist_get_const(offs, 1);
6658 
6659  extracted = detmon_subtracted_avg(cpl_imagelist_get_const(ons, 0),
6660  cpl_imagelist_get_const(offs, 0),
6661  cpl_imagelist_get_const(ons, 1),
6662  off2,
6663  llx, lly, urx, ury);
6664  cpl_ensure_code(extracted != NULL, cpl_error_get_code());
6665  }
6666 
6667  {
6668  double median = cpl_image_get_median(extracted);
6669  double mean= cpl_image_get_mean(extracted);
6670  cpl_table_set(lin_table, "MED", pos, median);
6671  cpl_table_set(lin_table, "MEAN", pos, mean);
6672 
6673  cpl_table_set(lin_table, "MED_DIT", pos, median / c_dit);
6674  cpl_table_set(lin_table, "MEAN_DIT", pos, mean / c_dit);
6675  }
6676 
6677  /* Insert to the imagelist used to fit the polynomial */
6678  if(mode & IRPLIB_LIN_PIX2PIX) {
6679  cpl_error_code error = cpl_imagelist_set(linearity_inputs, extracted,
6680  pos-nskip);
6681  cpl_ensure_code(!error, error);
6682  } else {
6683  cpl_image_delete(extracted);
6684  }
6685 
6686  return cpl_error_get_code();
6687 }
6688 
6689 static double irplib_calculate_total_noise_smooth(const cpl_image* pimage,
6690  int pattern_x, int pattern_y)
6691 {
6692  cpl_image * p_tmp_image = 0;
6693  cpl_image * psmooth_image = 0;
6694  double ret_noise;
6695  cpl_mask * mask = cpl_mask_new(pattern_x, pattern_y);
6696  cpl_mask_not(mask);
6697  p_tmp_image = cpl_image_duplicate(pimage);
6698  cpl_image_filter_mask(p_tmp_image,pimage, mask,CPL_FILTER_MEDIAN ,CPL_BORDER_FILTER);
6699  cpl_image_divide_scalar(p_tmp_image, cpl_image_get_median(pimage));
6700  psmooth_image = cpl_image_divide_create(pimage,p_tmp_image);
6701  ret_noise = irplib_calculate_total_noise(psmooth_image);
6702  cpl_mask_delete(mask);
6703  cpl_image_delete(psmooth_image);
6704  cpl_image_delete(p_tmp_image);
6705  return ret_noise;
6706 }
6707 
6708 static double irplib_calculate_total_noise(const cpl_image* pimage)
6709 {
6710  double total_noise = -1;
6711  unsigned long max_bin_size = 1E5;
6712  const double hstart = cpl_image_get_min(pimage);
6713  const double hrange = cpl_image_get_max(pimage) - hstart;
6714  const unsigned long nbins = max_bin_size;
6715  cpl_error_code err = CPL_ERROR_NONE;
6716  /* apply histogram method */
6717  irplib_hist * phist = 0;
6718  phist = irplib_hist_new();
6719  /* 2 extra-bins for possible out-of-range values */
6720 
6721  irplib_hist_init(phist, nbins, hstart, hrange);
6722  err = irplib_hist_fill(phist, pimage);
6723  if (err == CPL_ERROR_NONE)
6724  {
6725  unsigned int i = 0;
6726  double x0 = 0;
6727  double area = 0;
6728  double offset = 0;
6729 
6730  /* prepare vector */
6731  unsigned long n_bins = irplib_hist_get_nbins(phist);
6732  double start = irplib_hist_get_start(phist);
6733  double bin_size = irplib_hist_get_bin_size(phist);
6734  cpl_vector* pdata_vector = cpl_vector_new(n_bins);
6735  cpl_vector* ppos_vector = cpl_vector_new(n_bins);
6736  cpl_table* ptable = cpl_table_new(n_bins);
6737  cpl_table_new_column(ptable, "bin", CPL_TYPE_DOUBLE);
6738  cpl_table_new_column(ptable, "value", CPL_TYPE_DOUBLE);
6739  for(i = 0; i < n_bins; i++)
6740  {
6741  unsigned int value = irplib_hist_get_value(phist, i);
6742  double dvalue = (double)(value);
6743  cpl_vector_set(pdata_vector, i, dvalue);
6744  cpl_vector_set(ppos_vector, i, start + i * bin_size);
6745 
6746  cpl_table_set(ptable, "bin", i, start + i * bin_size);
6747  cpl_table_set(ptable, "value", i, dvalue);
6748  }
6749  err = cpl_vector_fit_gaussian(ppos_vector, NULL, pdata_vector, NULL, CPL_FIT_ALL, &x0, &total_noise, &area, &offset, NULL, NULL, NULL );
6750  if (err == CPL_ERROR_NONE)
6751  {
6752  cpl_msg_info(cpl_func, "FPN Calculation: histogram x0[%f] total_noise[%f] area[%f] offset[%f]", x0, total_noise, area, offset);
6753  }
6754  else
6755  {
6756  cpl_msg_warning(cpl_func, "FPN could not be computed due failed Gaussian Fit, err msg [%s]", cpl_error_get_message());
6757  cpl_error_reset();
6758  }
6759  cpl_table_delete(ptable);
6760  cpl_vector_delete(ppos_vector);
6761  cpl_vector_delete(pdata_vector);
6762  }
6763  else
6764  {
6765  cpl_msg_warning(cpl_func, "FPN could not be computed due failed histogram computation, err msg [%s]", cpl_error_get_message());
6766  cpl_error_reset();
6767  }
6768  irplib_hist_delete(phist);
6769 
6770  return total_noise;
6771 }
6772 
6773 static double irplib_compute_err(double gain, double ron, double FA)
6774 {
6775  double int_gain = (gain * gain - 1) / 12;
6776  if (int_gain < 0)
6777  {
6778  int_gain = 0;
6779  }
6780  return sqrt(ron * ron + FA / gain + int_gain);
6781 }
6782 
6783 static double irplib_fpn_lg(const cpl_image* f1, int* range, double gain ,
6784  FPN_METHOD fpn_method, int smooth_size, double* mse)
6785 {
6786  cpl_image* im_diff = 0;
6787  const cpl_image* im_f1 = f1;
6788  cpl_image* im_inrange1 = 0;
6789  double FA = 0;
6790  double s_tot = 0; /* absolute total noise */
6791  double s_fpn = 0; /* fixed pattern noise */
6792  double sr_fpn = 0; /* relative structural noise */
6793  /*che cinput*/
6794  if (gain<=0) {
6795  /* put dummy values Negative to indicate a problem occurred
6796  (FPN should be always positive) */
6797  cpl_msg_warning(cpl_func,"gain[%f]<0", gain);
6798  cpl_msg_warning(cpl_func,"We set dummy values for FPN");
6799  s_fpn=-999.;
6800  sr_fpn=-999;
6801  return sr_fpn;
6802  }
6803  if (range)
6804  {
6805  im_inrange1 = cpl_image_extract(f1, range[0], range[1], range[2], range[3]);
6806  im_f1 = im_inrange1;
6807  }
6808  FA = cpl_image_get_median(im_f1);
6809 
6810  /* apply histogram method */
6811  /* Is this irplib function giving the right result?? */
6812  switch (fpn_method)
6813  {
6814  case FPN_SMOOTH:
6815  cpl_msg_info(cpl_func,"SMOOTH method is used for FPN, pattern size[%d x %d] pixels",smooth_size,smooth_size );
6816  s_tot = irplib_calculate_total_noise_smooth(im_f1,smooth_size,smooth_size);
6817  break;
6818  case FPN_HISTOGRAM:
6819  cpl_msg_info(cpl_func,"HISTOGRAM method is used for FPN");
6820  s_tot = irplib_calculate_total_noise(im_f1);
6821  break;
6822  default:
6823  s_tot = -1;
6824  sr_fpn = -1;
6825  cpl_msg_warning(cpl_func,"fpn_method is not defined");
6826  break;
6827  }
6828  if (s_tot > 0)
6829  {
6830  if (FA<0)
6831  {
6832  /* put dummy values Negative to indicate a problem occurred
6833  (FPN should be always positive) */
6834  cpl_msg_warning(cpl_func,"Median flux on sum of flats<0");
6835  cpl_msg_warning(cpl_func,"We set dummy values for FPN");
6836  s_fpn=-999.;
6837  sr_fpn=-999;
6838  }
6839 
6840  if ((s_tot * s_tot - FA / gain) > 0)
6841  {
6842  s_fpn = sqrt(s_tot * s_tot - FA / gain);
6843  sr_fpn = s_fpn / FA;
6844  *mse = (irplib_compute_err(gain, 0, FA)) * gain / FA;
6845  } else {
6846  /* put dummy values Negative to indicate a problem occurred
6847  (FPN should be always positive) */
6848  cpl_msg_warning(cpl_func,"s_tot * s_tot < FA / gain");
6849  cpl_msg_warning(cpl_func,"We set dummy values for FPN");
6850  s_fpn=-999.;
6851  sr_fpn=-999;
6852  *mse = -1;
6853  }
6854  /*
6855  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);
6856  */
6857  }
6858  cpl_image_delete(im_diff);
6859  if (range)
6860  {
6861  cpl_image_delete(im_inrange1);
6862  }
6863  return sr_fpn;
6864 }
6865 
6866 
6867 static cpl_imagelist * irplib_load_fset_wrp(const cpl_frameset * pframeset,
6868  cpl_type type , int whichext)
6869 {
6870  /* FIXME: load image into window size from beginning to
6871  * save all the extracts */
6872  return detmon_load_frameset_window(pframeset, type, 0, whichext,
6873  detmon_lg_config.llx,
6874  detmon_lg_config.lly,
6875  detmon_lg_config.urx,
6876  detmon_lg_config.ury,
6877  detmon_lg_config.nx,
6878  detmon_lg_config.ny);
6879 }
6880 
6881 static cpl_imagelist * irplib_load_fset_wrp_ext(const cpl_frameset * pframeset,
6882  cpl_type type , int whichext)
6883 {
6884  int i = whichext; /* fake code to avoid compiler warning */
6885  cpl_imagelist* offs = cpl_imagelist_new();
6886  detmon_lg_config.load_fset(pframeset, type, offs);
6887  i++;
6888  return offs;
6889 }
6890 
6891 static cpl_error_code irplib_table_create_column(cpl_table* ptable,
6892  cpl_propertylist* plist)
6893 {
6894  if (ptable && plist)
6895  {
6896  int size = cpl_propertylist_get_size(plist);
6897  int i = 0;
6898  for (i = 0; i < size; i++)
6899  {
6900  cpl_property* pprop = cpl_propertylist_get(plist,i);
6901  if (pprop)
6902  {
6903  const char* pname = cpl_property_get_name(pprop);
6904  if (pname)
6905  {
6906  cpl_table_new_column(ptable, pname, cpl_property_get_type(pprop));
6907  if (cpl_error_get_code() != CPL_ERROR_NONE)
6908  {
6909  cpl_msg_warning(cpl_func, "cannot create new column[%s], err[%s]", pname, cpl_error_get_message());
6910  break; /* leave the cycle */
6911  }
6912  }
6913  }
6914  }
6915  }
6916  return cpl_error_get_code();
6917 }
6918 
6919 static cpl_error_code irplib_fill_table_DETWINUIT(cpl_table* ptable,
6920  cpl_propertylist* plist, int row)
6921 {
6922  cpl_error_code err = CPL_ERROR_NONE;
6923  if (ptable && plist)
6924  {
6925  int size = cpl_propertylist_get_size(plist);
6926  int i = 0;
6927  for (i = 0; i < size; i++)
6928  {
6929  cpl_property* pprop = cpl_propertylist_get(plist,i);
6930  if (pprop)
6931  {
6932  const char* pname = cpl_property_get_name(pprop);
6933  double value = cpl_property_get_double(pprop);
6934  if (pname)
6935  {
6936  cpl_table_set_double(ptable, pname, row, value);
6937  if (cpl_error_get_code() != CPL_ERROR_NONE)
6938  {
6939  cpl_msg_warning(cpl_func, "cannot write value to the table, column[%s] value[%f], err[%s]", pname, value, cpl_error_get_message());
6940  cpl_error_reset();
6941  break; /* leave the cycle */
6942  }
6943  }
6944  }
6945  }
6946  }
6947  return err;
6948 }
6949 
6950 cpl_error_code detmon_check_order(const double *exptime, int sz,
6951  double tolerance, int order)
6952 {
6953  int nsets = 0;
6954  int i = 0;
6955  /* 1. Determine number of groups */
6956  /* cpl_msg_warning(cpl_func, "detmon_check_order sz[%i]", sz);*/
6957  do
6958  {
6959  /* cpl_msg_warning(cpl_func, "detmon_check_order i[%i] exptime[%g]", i, exptime[i]); */
6960  nsets++;
6961  do
6962  {
6963  i++;
6964  if(i == sz - 1)
6965  {
6966  break;
6967  }
6968  } while(fabs(exptime[i-1] - exptime[i]) < tolerance);
6969  } while(i < sz - 1);
6970  /* the very last adjustment for the last group */
6971  if (!fabs(exptime[i-1] - exptime[i]) < tolerance) nsets++;
6972  if(nsets <= order)
6973  {
6974  cpl_error_set_message(cpl_func,CPL_ERROR_INCOMPATIBLE_INPUT,
6975  "Not enough frames for the polynomial"
6976  " fitting. nsets = %d <= %d order",
6977  nsets,order);
6978  }
6979  return cpl_error_get_code();
6980 }
6981 
6982 static cpl_error_code
6983 detmon_lg_dfs_save_imagelist(
6984  cpl_frameset * frameset,
6985  const cpl_parameterlist * parlist,
6986  const cpl_frameset *usedframes,
6987  const cpl_imagelist *coeffs,
6988  const char *recipe_name,
6989  const cpl_propertylist *mypro_coeffscube,
6990  const char * package,
6991  const char * name_o)
6992 {
6993  return(cpl_dfs_save_imagelist
6994  (frameset, NULL, parlist, usedframes, NULL,coeffs, CPL_BPP_IEEE_FLOAT,
6995  recipe_name, mypro_coeffscube, NULL, package,
6996  name_o));
6997 }
6998 
6999 static void detmon_lg_add_empty_image(cpl_imagelist* imlist, int pos)
7000 {
7001  const cpl_image* first = cpl_imagelist_get(imlist, 0);
7002  if (first)
7003  {
7004  int x = cpl_image_get_size_x(first);
7005  int y = cpl_image_get_size_y(first);
7006  cpl_type type = cpl_image_get_type(first);
7007  cpl_image * blank = cpl_image_new(x, y, type);
7008  cpl_imagelist_set(imlist, blank, pos);
7009  }
7010 }
7011 
7012 
7013 cpl_error_code
7014 detmon_lg_set_tag(cpl_frameset* set, const char** tag_on, const char** tag_off)
7015 {
7016  int ntag_old=0;
7017  int ntag_new=0;
7018 
7019  ntag_old=cpl_frameset_count_tags(set,DETMON_LG_ON_RAW_OLD);
7020  ntag_new=cpl_frameset_count_tags(set,DETMON_LG_ON_RAW_NEW);
7021  if(ntag_old) {
7022  *tag_on=DETMON_LG_ON_RAW_OLD;
7023  *tag_off=DETMON_LG_OFF_RAW_OLD;
7024  } else if (ntag_new) {
7025  *tag_on=DETMON_LG_ON_RAW_NEW;
7026  *tag_off=DETMON_LG_OFF_RAW_NEW;
7027  } else {
7028  cpl_msg_error(cpl_func,"Provide %s and %s (or %s and %s) input frames",
7029  DETMON_LG_ON_RAW_NEW,DETMON_LG_OFF_RAW_NEW,
7030  DETMON_LG_ON_RAW_OLD,DETMON_LG_OFF_RAW_OLD);
7031  }
7032 
7033 
7034  return cpl_error_get_code();
7035 }