DETMON Pipeline Reference Manual  1.2.4
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: detmon-1_2_4 $
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_opt_default_mr(cpl_parameterlist * parlist,
1519  const char *recipe_name,
1520  const char *pipeline_name)
1521 {
1522  detmon_lg_fill_parlist_opt_default(parlist,
1523  recipe_name,
1524  pipeline_name);
1525 
1526 
1527  char * group_name = cpl_sprintf("%s.%s", pipeline_name, recipe_name);
1528  char * par_name = cpl_sprintf("%s.%s", group_name, "regions-file");
1529  cpl_parameter * p = cpl_parameter_new_value(par_name, CPL_TYPE_STRING,
1530  "File containing regions, "
1531  "four comma separated points "
1532  "per line",
1533  group_name, "");
1534  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "regions-file");
1535  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
1536  cpl_parameterlist_append(parlist, p);
1537  cpl_free(par_name);
1538  cpl_free(group_name);
1539 
1540  group_name = cpl_sprintf("%s.%s", pipeline_name, recipe_name);
1541  par_name = cpl_sprintf("%s.%s", group_name, "regions");
1542  p = cpl_parameter_new_value(par_name, CPL_TYPE_STRING,
1543  "Colon separated list of regions, four "
1544  "points each, comma separated: "
1545  "llx,lly,urx,ury:llx,...",
1546  group_name, "");
1547  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "regions");
1548  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
1549  cpl_parameterlist_append(parlist, p);
1550  cpl_free(par_name);
1551  cpl_free(group_name);
1552 
1553  return cpl_error_get_code();
1554 }
1555 
1556 
1557 /*---------------------------------------------------------------------------*/
1611 /*---------------------------------------------------------------------------*/
1612 cpl_error_code
1613 detmon_lg_fill_parlist(cpl_parameterlist * parlist,
1614  const char *recipe_name, const char *pipeline_name,
1615  const char *method,
1616  int order,
1617  double kappa,
1618  int niter,
1619  int llx,
1620  int lly,
1621  int urx,
1622  int ury,
1623  int ref_level,
1624  const char *intermediate,
1625  const char *autocorr,
1626  const char *collapse,
1627  const char *rescale,
1628  const char *pix2pix,
1629  const char *bpmbin,
1630  int filter,
1631  int m,
1632  int n,
1633  double tolerance,
1634  const char *pafgen,
1635  const char * pafname,
1636  int llx1,
1637  int lly1,
1638  int urx1,
1639  int ury1,
1640  int llx2,
1641  int lly2,
1642  int urx2,
1643  int ury2,
1644  int llx3,
1645  int lly3,
1646  int urx3,
1647  int ury3,
1648  int llx4,
1649  int lly4,
1650  int urx4,
1651  int ury4,
1652  int llx5, int lly5, int urx5, int ury5, int exts,
1653  cpl_boolean opt_nir)
1654 {
1655  const cpl_error_code error =
1656  detmon_fill_parlist(parlist, recipe_name, pipeline_name, 25,
1657  "method",
1658  "Method to be used when computing GAIN. Methods appliable: <PTC | MED>. By default PTC method will be applied.",
1659  "CPL_TYPE_STRING", method,
1660 
1661  "order",
1662  "Polynomial order for the fit (Linearity)",
1663  "CPL_TYPE_INT", order,
1664  "kappa",
1665  "Kappa value for the kappa-sigma clipping (Gain)",
1666  "CPL_TYPE_DOUBLE", kappa,
1667  "niter",
1668  "Number of iterations to compute rms (Gain)",
1669  "CPL_TYPE_INT", niter,
1670  "llx",
1671  "x coordinate of the lower-left "
1672  "point of the region of interest. If not modified, default value will be 1.",
1673  "CPL_TYPE_INT", llx,
1674  "lly",
1675  "y coordinate of the lower-left "
1676  "point of the region of interest. If not modified, default value will be 1.",
1677  "CPL_TYPE_INT", lly,
1678  "urx",
1679  "x coordinate of the upper-right "
1680  "point of the region of interest. If not modified, default value will be X dimension of the input image.",
1681  "CPL_TYPE_INT", urx,
1682  "ury",
1683  "y coordinate of the upper-right "
1684  "point of the region of interest. If not modified, default value will be Y dimension of the input image.",
1685  "CPL_TYPE_INT", ury,
1686  "ref_level",
1687  "User reference level",
1688  "CPL_TYPE_INT", ref_level,
1689  "intermediate",
1690  "De-/Activate intermediate products",
1691  "CPL_TYPE_BOOL", intermediate,
1692 
1693  "autocorr",
1694  "De-/Activate the autocorr option",
1695  "CPL_TYPE_BOOL", autocorr,
1696 
1697  "collapse",
1698  "De-/Activate the collapse option",
1699  "CPL_TYPE_BOOL", collapse,
1700  "rescale",
1701  "De-/Activate the image rescale option",
1702  "CPL_TYPE_BOOL", rescale,
1703  "pix2pix",
1704  "De-/Activate the computation with pixel to pixel accuracy",
1705  "CPL_TYPE_BOOL", pix2pix,
1706  "bpmbin",
1707  "De-/Activate the binary bpm option",
1708  "CPL_TYPE_BOOL", bpmbin,
1709  "m",
1710  "Maximum x-shift for the autocorr",
1711  "CPL_TYPE_INT", m,
1712  "filter",
1713  "Upper limit of Median flux to be filtered",
1714  "CPL_TYPE_INT", filter,
1715  "n",
1716  "Maximum y-shift for the autocorr",
1717  "CPL_TYPE_INT", n,
1718  "tolerance",
1719  "Tolerance for pair discrimination",
1720  "CPL_TYPE_DOUBLE", tolerance,
1721 
1722  "pafgen",
1723  "Generate PAF file",
1724  "CPL_TYPE_BOOL", pafgen,
1725  "pafname",
1726  "Specific name for PAF file",
1727  "CPL_TYPE_STRING", pafname,
1728 
1729 
1730  "exts",
1731  "Activate the multi-exts option. Choose -1 to process all extensions. Choose an extension number"
1732  " to process the appropriate extension.",
1733  "CPL_TYPE_INT", exts,
1734 
1735  "fpn_method",
1736  "Method for computing Fixed Pattern Noise (SMOOTH or HISTOGRAM)",
1737  "CPL_TYPE_STRING", "HISTOGRAM",
1738 
1739  "fpn_smooth",
1740  "template size in pixels for smoothing during FPN computation (only for SMOOTH method)",
1741  "CPL_TYPE_INT", 13,
1742 
1743  "saturation_limit",
1744  "all frames with mean saturation above the limit would not be used in calculation",
1745  "CPL_TYPE_DOUBLE", 65535.0
1746  );
1747  detmon_fill_parlist(parlist, recipe_name, pipeline_name, 1,
1748  "coeffs_cube_split",
1749  "if TRUE, the recipe writes as many "
1750  "COEFFS_CUBE_Pi (i=0..order) as the value of "
1751  "the order parameter in a separate file",
1752  "CPL_TYPE_BOOL", "CPL_FALSE");
1753  /* OPT specific parameters */
1754  if(opt_nir == FALSE) {
1755  const cpl_error_code erroropt =
1756  detmon_fill_parlist(parlist, recipe_name, pipeline_name, 20,
1757  "llx1",
1758  "x coord of the lower-left point of the first "
1759  "field used for contamination measurement. If not modified, default value will be 1.",
1760  "CPL_TYPE_INT", llx1,
1761  "lly1",
1762  "y coord of the lower-left point of the first "
1763  "field used for contamination measurement. If not modified, default value will be 1.",
1764  "CPL_TYPE_INT", lly1,
1765  "urx1",
1766  "x coord of the upper-right point of the first "
1767  "field used for contamination measurement. If not modified, default value will be X dimension of the input image.",
1768  "CPL_TYPE_INT", urx1,
1769  "ury1",
1770  "y coord of the upper-right point of the first "
1771  "field used for contamination measurement. If not modified, default value will be Y dimension of the input image.",
1772  "CPL_TYPE_INT", ury1,
1773  "llx2",
1774  "x coord of the lower-left point of the second "
1775  "field used for contamination measurement. If not modified, default value will be 1.",
1776  "CPL_TYPE_INT", llx2,
1777  "lly2",
1778  "y coord of the lower-left point of the second "
1779  "field used for contamination measurement. If not modified, default value will be 1.",
1780  "CPL_TYPE_INT", lly2,
1781  "urx2",
1782  "x coord of the upper-right point of the second "
1783  "field used for contamination measurement. If not modified, default value will be half of the X dimension of the input image.",
1784  "CPL_TYPE_INT", urx2,
1785  "ury2",
1786  "y coord of the upper-right point of the second "
1787  "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
1788  "CPL_TYPE_INT", ury2,
1789  "llx3",
1790  "x coord of the lower-left point of the third "
1791  "field used for contamination measurement. If not modified, default value will be 1.",
1792  "CPL_TYPE_INT", llx3,
1793  "lly3",
1794  "y coord of the lower-left point of the third "
1795  "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
1796  "CPL_TYPE_INT", lly3,
1797  "urx3",
1798  "x coord of the upper-right point of the third "
1799  "field used for contamination measurement. If not modified, default value will be half of X dimension of the image.",
1800  "CPL_TYPE_INT", urx3,
1801  "ury3",
1802  "y coord of the upper-right point of the third "
1803  "field used for contamination measurement. If not modified, default value will be Y dimension of the image.",
1804  "CPL_TYPE_INT", ury3,
1805  "llx4",
1806  "x coord of the lower-left point of the fourth "
1807  "field used for contamination measurement. If not modified, default value will be half of X dimension of the image.",
1808  "CPL_TYPE_INT", llx4,
1809  "lly4",
1810  "y coord of the lower-left point of the fourth "
1811  "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
1812  "CPL_TYPE_INT", lly4,
1813  "urx4",
1814  "x coord of the upper-right point of the fourth "
1815  "field used for contamination measurement. If not modified, default value will be X dimension of the image.",
1816  "CPL_TYPE_INT", urx4,
1817  "ury4",
1818  "y coord of the upper-right point of the fourth "
1819  "field used for contamination measurement. If not modified, default value will be Y dimension of the input image.",
1820  "CPL_TYPE_INT", ury4,
1821  "llx5",
1822  "x coord of the lower-left point of the fifth "
1823  "field used for contamination measurement. If not modified, default value will be half of the X dimension of the input image.",
1824  "CPL_TYPE_INT", llx5,
1825  "lly5",
1826  "y coord of the lower-left point of the fifth "
1827  "field used for contamination measurement. If not modified, default value will be 1.",
1828  "CPL_TYPE_INT", lly5,
1829  "urx5",
1830  "x coord of the upper-right point of the fifth "
1831  "field used for contamination measurement. If not modified, default value will be X dimension of the image.",
1832  "CPL_TYPE_INT", urx5,
1833 
1834  "ury5",
1835  "y coord of the upper-right point of the fifth "
1836  "field used for contamination measurement. If not modified, default value will be half of Y dimension of the input image.",
1837  "CPL_TYPE_INT", ury5);
1838  cpl_ensure_code(!erroropt, erroropt);
1839  }
1840 
1841  cpl_ensure_code(!error, error);
1842 
1843  return cpl_error_get_code();
1844 }
1845 
1846 /*---------------------------------------------------------------------------*/
1855 /*---------------------------------------------------------------------------*/
1856 static cpl_error_code
1857 detmon_lg_retrieve_parlist(const char * pipeline_name,
1858  const char * recipe_name,
1859  const cpl_parameterlist * parlist,
1860  cpl_boolean opt_nir)
1861 {
1862 
1863  char * par_name;
1864  cpl_parameter * par;
1865 
1866  /* --method */
1867  par_name = cpl_sprintf("%s.%s.method", pipeline_name, recipe_name);
1868  assert(par_name != NULL);
1869  par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
1870  detmon_lg_config.method = cpl_parameter_get_string(par);
1871  cpl_free(par_name);
1872 
1873  /* --order */
1874  detmon_lg_config.order =
1875  detmon_retrieve_par_int("order", pipeline_name, recipe_name,
1876  parlist);
1877 
1878  /* --kappa */
1879  detmon_lg_config.kappa =
1880  detmon_retrieve_par_double("kappa", pipeline_name, recipe_name,
1881  parlist);
1882 
1883  /* --niter */
1884  detmon_lg_config.niter =
1885  detmon_retrieve_par_int("niter", pipeline_name, recipe_name,
1886  parlist);
1887 
1888  /* --llx */
1889  detmon_lg_config.llx =
1890  detmon_retrieve_par_int("llx", pipeline_name, recipe_name,
1891  parlist);
1892 
1893  /* --lly */
1894  detmon_lg_config.lly =
1895  detmon_retrieve_par_int("lly", pipeline_name, recipe_name,
1896  parlist);
1897 
1898  /* --urx */
1899  detmon_lg_config.urx =
1900  detmon_retrieve_par_int("urx", pipeline_name, recipe_name,
1901  parlist);
1902 
1903  /* --ury */
1904  detmon_lg_config.ury =
1905  detmon_retrieve_par_int("ury", pipeline_name, recipe_name,
1906  parlist);
1907 
1908  /* --ref_level */
1909  detmon_lg_config.ref_level =
1910  detmon_retrieve_par_int("ref_level", pipeline_name, recipe_name,
1911  parlist);
1912 
1913  /* --intermediate */
1914  par_name =
1915  cpl_sprintf("%s.%s.intermediate", pipeline_name, recipe_name);
1916  assert(par_name != NULL);
1917  par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
1918  detmon_lg_config.intermediate = cpl_parameter_get_bool(par);
1919  cpl_free(par_name);
1920 
1921  /* --autocorr */
1922  par_name = cpl_sprintf("%s.%s.autocorr", pipeline_name, recipe_name);
1923  assert(par_name != NULL);
1924  par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
1925  detmon_lg_config.autocorr = cpl_parameter_get_bool(par);
1926  cpl_free(par_name);
1927 
1928  /* --coeffs_cube_split */
1929  par_name = cpl_sprintf("%s.%s.coeffs_cube_split", pipeline_name, recipe_name);
1930  assert(par_name != NULL);
1931  par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
1932  detmon_lg_config.split_coeffs = cpl_parameter_get_bool(par);
1933  cpl_free(par_name);
1934 
1935  /* --collapse */
1936  par_name = cpl_sprintf("%s.%s.collapse", pipeline_name, recipe_name);
1937  assert(par_name != NULL);
1938  par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
1939  detmon_lg_config.collapse = cpl_parameter_get_bool(par);
1940  cpl_free(par_name);
1941 
1942  /* --rescale */
1943  par_name = cpl_sprintf("%s.%s.rescale", pipeline_name, recipe_name);
1944  assert(par_name != NULL);
1945  par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
1946  detmon_lg_config.rescale = cpl_parameter_get_bool(par);
1947  cpl_free(par_name);
1948 
1949  /* --pix2pix */
1950  par_name = cpl_sprintf("%s.%s.pix2pix", pipeline_name, recipe_name);
1951  assert(par_name != NULL);
1952  par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
1953  detmon_lg_config.pix2pix = cpl_parameter_get_bool(par);
1954  cpl_free(par_name);
1955 
1956  /* --bpmbin */
1957  par_name = cpl_sprintf("%s.%s.bpmbin", pipeline_name, recipe_name);
1958  assert(par_name != NULL);
1959  par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
1960  detmon_lg_config.bpmbin = cpl_parameter_get_bool(par);
1961  cpl_free(par_name);
1962 
1963  /* --filter */
1964  detmon_lg_config.filter =
1965  detmon_retrieve_par_int("filter", pipeline_name,
1966  recipe_name, parlist);
1967 
1968  /* --m */
1969  detmon_lg_config.m =
1970  detmon_retrieve_par_int("m", pipeline_name, recipe_name, parlist);
1971 
1972  /* --n */
1973  detmon_lg_config.n =
1974  detmon_retrieve_par_int("n", pipeline_name, recipe_name, parlist);
1975 
1976  /* --tolerance */
1977  par_name = cpl_sprintf("%s.%s.tolerance", pipeline_name, recipe_name);
1978  assert(par_name != NULL);
1979  par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
1980  detmon_lg_config.tolerance = cpl_parameter_get_double(par);
1981  cpl_free(par_name);
1982 
1983 
1984  /* --pafgen */
1985  par_name = cpl_sprintf("%s.%s.pafgen", pipeline_name, recipe_name);
1986  assert(par_name != NULL);
1987  par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
1988  detmon_lg_config.pafgen = cpl_parameter_get_bool(par);
1989  cpl_free(par_name);
1990 
1991  /* --pafname */
1992  par_name = cpl_sprintf("%s.%s.pafname", pipeline_name, recipe_name);
1993  assert(par_name != NULL);
1994  par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
1995  detmon_lg_config.pafname = cpl_parameter_get_string(par);
1996  cpl_free(par_name);
1997 
1998  if(opt_nir == OPT) {
1999  /* --llx1 */
2000  detmon_lg_config.llx1 =
2001  detmon_retrieve_par_int("llx1", pipeline_name, recipe_name,
2002  parlist);
2003 
2004  /* --lly1 */
2005  detmon_lg_config.lly1 =
2006  detmon_retrieve_par_int("lly1", pipeline_name, recipe_name,
2007  parlist);
2008 
2009  /* --urx1 */
2010  detmon_lg_config.urx1 =
2011  detmon_retrieve_par_int("urx1", pipeline_name, recipe_name,
2012  parlist);
2013 
2014  /* --ury1 */
2015  detmon_lg_config.ury1 =
2016  detmon_retrieve_par_int("ury1", pipeline_name, recipe_name,
2017  parlist);
2018 
2019  /* --llx2 */
2020  detmon_lg_config.llx2 =
2021  detmon_retrieve_par_int("llx2", pipeline_name, recipe_name,
2022  parlist);
2023 
2024  /* --lly2 */
2025  detmon_lg_config.lly2 =
2026  detmon_retrieve_par_int("lly2", pipeline_name, recipe_name,
2027  parlist);
2028 
2029  /* --urx2 */
2030  detmon_lg_config.urx2 =
2031  detmon_retrieve_par_int("urx2", pipeline_name, recipe_name,
2032  parlist);
2033 
2034  /* --ury2 */
2035  detmon_lg_config.ury2 =
2036  detmon_retrieve_par_int("ury2", pipeline_name, recipe_name,
2037  parlist);
2038 
2039  /* --llx3 */
2040  detmon_lg_config.llx3 =
2041  detmon_retrieve_par_int("llx3", pipeline_name, recipe_name,
2042  parlist);
2043 
2044  /* --lly3 */
2045  detmon_lg_config.lly3 =
2046  detmon_retrieve_par_int("lly3", pipeline_name, recipe_name,
2047  parlist);
2048 
2049  /* --urx3 */
2050  detmon_lg_config.urx3 =
2051  detmon_retrieve_par_int("urx3", pipeline_name, recipe_name,
2052  parlist);
2053 
2054  /* --ury3 */
2055  detmon_lg_config.ury3 =
2056  detmon_retrieve_par_int("ury3", pipeline_name, recipe_name,
2057  parlist);
2058 
2059  /* --llx4 */
2060  detmon_lg_config.llx4 =
2061  detmon_retrieve_par_int("llx4", pipeline_name, recipe_name,
2062  parlist);
2063 
2064  /* --lly4 */
2065  detmon_lg_config.lly4 =
2066  detmon_retrieve_par_int("lly4", pipeline_name, recipe_name,
2067  parlist);
2068 
2069  /* --urx4 */
2070  detmon_lg_config.urx4 =
2071  detmon_retrieve_par_int("urx4", pipeline_name, recipe_name,
2072  parlist);
2073 
2074  /* --ury4 */
2075  detmon_lg_config.ury4 =
2076  detmon_retrieve_par_int("ury4", pipeline_name, recipe_name,
2077  parlist);
2078 
2079  /* --llx5 */
2080  detmon_lg_config.llx5 =
2081  detmon_retrieve_par_int("llx5", pipeline_name, recipe_name,
2082  parlist);
2083 
2084  /* --lly5 */
2085  detmon_lg_config.lly5 =
2086  detmon_retrieve_par_int("lly5", pipeline_name, recipe_name,
2087  parlist);
2088 
2089  /* --urx5 */
2090  detmon_lg_config.urx5 =
2091  detmon_retrieve_par_int("urx5", pipeline_name, recipe_name,
2092  parlist);
2093 
2094  /* --ury5 */
2095  detmon_lg_config.ury5 =
2096  detmon_retrieve_par_int("ury5", pipeline_name, recipe_name,
2097  parlist);
2098  }
2099 
2100  /* --exts */
2101  detmon_lg_config.exts =
2102  detmon_retrieve_par_int("exts", pipeline_name, recipe_name,
2103  parlist);
2104  /* --fpn_method */
2105  {
2106  detmon_lg_config.fpn_method = FPN_HISTOGRAM;
2107  par_name =
2108  cpl_sprintf("%s.%s.fpn_method", pipeline_name, recipe_name);
2109  assert(par_name != NULL);
2110  par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
2111  if (par)
2112  {
2113  const char * str_method = cpl_parameter_get_string(par);
2114  if (strcmp(str_method, "SMOOTH") == 0)
2115  {
2116  detmon_lg_config.fpn_method = FPN_SMOOTH;
2117  }
2118  else if (strcmp(str_method, "HISTOGRAM") == 0)
2119  {
2120  detmon_lg_config.fpn_method = FPN_HISTOGRAM;
2121  }
2122  }
2123  cpl_free(par_name);
2124  }
2125  /* --fpn_smooth */
2126  detmon_lg_config.fpn_smooth =
2127  detmon_retrieve_par_int("fpn_smooth", pipeline_name, recipe_name,
2128  parlist);
2129  /* --saturation_limit*/
2130  {
2131  detmon_lg_config.saturation_limit = 65535;
2132  par_name =
2133  cpl_sprintf("%s.%s.saturation_limit", pipeline_name, recipe_name);
2134  assert(par_name != NULL);
2135  par = cpl_parameterlist_find((cpl_parameterlist *) parlist, par_name);
2136  if (par)
2137  {
2138  detmon_lg_config.saturation_limit = cpl_parameter_get_double(par);
2139  }
2140  cpl_free(par_name);
2141  }
2142  if(cpl_error_get_code())
2143  {
2144  cpl_msg_error(cpl_func, "Failed to retrieve the input parameters");
2145  cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
2146  }
2147 
2148 
2149  return cpl_error_get_code();
2150 }
2151 
2152 /*---------------------------------------------------------------------------*/
2158 /*---------------------------------------------------------------------------*/
2159 static cpl_error_code
2160 detmon_lg_check_defaults(const cpl_image * reference)
2161 {
2162  const int nx = cpl_image_get_size_x(reference);
2163  const int ny = cpl_image_get_size_y(reference);
2164 
2165  detmon_lg_config.nx = nx;
2166  detmon_lg_config.ny = ny;
2167 
2168  detmon_lg_config.wholechip = CPL_FALSE;
2169 
2170  if(detmon_lg_config.llx == -1)
2171  detmon_lg_config.llx = 1;
2172  if(detmon_lg_config.lly == -1)
2173  detmon_lg_config.lly = 1;
2174  if(detmon_lg_config.urx == -1)
2175  detmon_lg_config.urx = nx;
2176  if(detmon_lg_config.ury == -1)
2177  detmon_lg_config.ury = ny;
2178 
2179  if (detmon_lg_config.llx == 1 &&
2180  detmon_lg_config.lly == 1 &&
2181  detmon_lg_config.urx == nx &&
2182  detmon_lg_config.ury == ny)
2183  detmon_lg_config.wholechip = CPL_TRUE;
2184 
2185  if(detmon_lg_config.llx1 == -1)
2186  detmon_lg_config.llx1 = 1;
2187  if(detmon_lg_config.lly1 == -1)
2188  detmon_lg_config.lly1 = 1;
2189  if(detmon_lg_config.urx1 == -1)
2190  detmon_lg_config.urx1 = nx;
2191  if(detmon_lg_config.ury1 == -1)
2192  detmon_lg_config.ury1 = ny;
2193 
2194  if(detmon_lg_config.llx2 == -1)
2195  detmon_lg_config.llx2 = 1;
2196  if(detmon_lg_config.lly2 == -1)
2197  detmon_lg_config.lly2 = 1;
2198  if(detmon_lg_config.urx2 == -1)
2199  detmon_lg_config.urx2 = nx / 2;
2200  if(detmon_lg_config.ury2 == -1)
2201  detmon_lg_config.ury2 = ny / 2;
2202 
2203  if(detmon_lg_config.llx3 == -1)
2204  detmon_lg_config.llx3 = 1;
2205  if(detmon_lg_config.lly3 == -1)
2206  detmon_lg_config.lly3 = ny / 2;
2207  if(detmon_lg_config.urx3 == -1)
2208  detmon_lg_config.urx3 = nx / 2;
2209  if(detmon_lg_config.ury3 == -1)
2210  detmon_lg_config.ury3 = ny;
2211 
2212  if(detmon_lg_config.llx4 == -1)
2213  detmon_lg_config.llx4 = nx / 2;
2214  if(detmon_lg_config.lly4 == -1)
2215  detmon_lg_config.lly4 = ny / 2;
2216  if(detmon_lg_config.urx4 == -1)
2217  detmon_lg_config.urx4 = nx;
2218  if(detmon_lg_config.ury4 == -1)
2219  detmon_lg_config.ury4 = ny;
2220 
2221  if(detmon_lg_config.llx5 == -1)
2222  detmon_lg_config.llx5 = nx / 2;
2223  if(detmon_lg_config.lly5 == -1)
2224  detmon_lg_config.lly5 = 1;
2225  if(detmon_lg_config.urx5 == -1)
2226  detmon_lg_config.urx5 = nx;
2227  if(detmon_lg_config.ury5 == -1)
2228  detmon_lg_config.ury5 = ny / 2;
2229 
2230  if(detmon_lg_config.intermediate == TRUE) {
2231  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.");
2232  detmon_lg_config.autocorr = TRUE;
2233  }
2234 
2235 
2236  detmon_lg_config.lamp_stability = 0.0;
2237 
2238  detmon_lg_config.lamp_ok = FALSE;
2239 
2240  detmon_lg_config.cr = 0.0;
2241 
2242  return cpl_error_get_code();
2243 }
2244 
2245 /*---------------------------------------------------------------------------*/
2256 /*---------------------------------------------------------------------------*/
2257 static cpl_error_code
2258 detmon_lg_split_onoff(const cpl_frameset * cur_fset,
2259  cpl_frameset * cur_fset_on,
2260  cpl_frameset * cur_fset_off,
2261  const char *tag_on,
2262  const char *tag_off)
2263 {
2264  int nframes;
2265  int i;
2266 
2267  cpl_frame * cur_frame_dup = NULL;
2268 
2269 #if 0
2270  const cpl_frame * first;
2271  const cpl_frame * second;
2272  const char * first_tag;
2273  const char * second_tag;
2274  skip_if((first = cpl_frameset_get_first_const(cur_fset)) == NULL);
2275  skip_if((second = cpl_frameset_get_next_const (cur_fset)) == NULL);
2276 
2277  skip_if((first_tag = cpl_frame_get_tag(first)) == NULL);
2278  skip_if((second_tag = cpl_frame_get_tag(second)) == NULL);
2279  if (opt_nir == OPT &&
2280  ((!strcmp(first_tag, tag_on ) && !strcmp(second_tag, tag_off)) ||
2281  (!strcmp(first_tag, tag_off) && !strcmp(second_tag, tag_on )))) {
2282  detmon_lg_config.lamp_ok = TRUE;
2283  }
2284 #endif
2285 
2286  nframes = cpl_frameset_get_size(cur_fset);
2287  for(i = detmon_lg_config.lamp_ok ? 2 : 0; i < nframes; i++) {
2288  const cpl_frame * cur_frame =
2289  cpl_frameset_get_position_const(cur_fset, i);
2290  char * tag;
2291 
2292  /* Duplication is required for insertion to a different frameset */
2293  cur_frame_dup = cpl_frame_duplicate(cur_frame);
2294  tag = (char *) cpl_frame_get_tag(cur_frame_dup);
2295 
2296  /* Insertion in the corresponding sub-frameset */
2297  if(!strcmp(tag, tag_on)) {
2298  skip_if(cpl_frameset_insert(cur_fset_on, cur_frame_dup));
2299  } else if(!strcmp(tag, tag_off)) {
2300  skip_if(cpl_frameset_insert(cur_fset_off, cur_frame_dup));
2301  } else {
2302  cpl_frame_delete(cur_frame_dup);
2303  cur_frame_dup = NULL;
2304  }
2305  }
2306  cur_frame_dup = NULL;
2307 
2308  end_skip;
2309 
2310  cpl_frame_delete(cur_frame_dup);
2311 
2312  return cpl_error_get_code();
2313 }
2314 
2315 /*--------------------------------------------------------------------------*/
2337 /*--------------------------------------------------------------------------*/
2338 
2339 static cpl_error_code
2340 detmon_lg_reduce(const cpl_frameset * set_on,
2341  const cpl_frameset * set_off,
2342  int* index_on, int* index_off,
2343  double* exptime_on, double* exptime_off,
2344  int *next_index_on, int* next_index_off,
2345  cpl_imagelist ** coeffs_ptr,
2346  cpl_table * gain_table,
2347  cpl_table * linear_table,
2348  cpl_image ** bpm_ptr,
2349  cpl_imagelist * autocorr_images,
2350  cpl_imagelist * diff_flats,
2351  cpl_propertylist * gaint_qclist,
2352  cpl_propertylist * lint_qclist,
2353  cpl_propertylist * linc_qclist,
2354  cpl_propertylist * bpm_qclist,
2355  int (* load_fset) (const cpl_frameset *,
2356  cpl_type,
2357  cpl_imagelist *),
2358  const cpl_boolean opt_nir,
2359  int whichext)
2360 {
2361  cpl_errorstate prestate = cpl_errorstate_get();
2362  const double D_INVALID_VALUE = -999;
2363  int i;
2364  cpl_imagelist * linearity_inputs = NULL;
2365  cpl_imagelist * opt_offs = NULL;
2366  int nsets;
2367  cpl_propertylist * reflist = NULL;
2368  int dit_nskip = 0;
2369  int rows_affected = 1;
2370  int last_best = 0;
2371  /* Test entries */
2372  cpl_ensure(set_on != NULL, CPL_ERROR_NULL_INPUT, CPL_ERROR_NULL_INPUT);
2373  cpl_ensure(set_off != NULL, CPL_ERROR_NULL_INPUT, CPL_ERROR_NULL_INPUT);
2374 
2375  nsets = cpl_frameset_get_size(set_on) / 2;
2376 
2377  detmon_lg_config.load_fset = load_fset;
2378  if(detmon_lg_config.collapse) {
2379  /*
2380  * When the 'collapse' option is used, there are no OFF pairs. We
2381  * construct a pair with the 2 first raw OFF frames, which will be
2382  * passed for each DIT value, to maintain the same API in the function
2383  * detmon_gain_table_fill_row().
2384  */
2385  const cpl_frame *first = cpl_frameset_get_first_const(set_off);
2386  cpl_frame *dup_first = cpl_frame_duplicate(first);
2387 
2388  const cpl_frame *second = cpl_frameset_get_next_const(set_off);
2389  cpl_frame *dup_second = cpl_frame_duplicate(second);
2390 
2391  cpl_frameset *raw_offs = cpl_frameset_new();
2392 
2393  skip_if(cpl_frameset_insert(raw_offs, dup_first));
2394  skip_if(cpl_frameset_insert(raw_offs, dup_second));
2395 
2396  opt_offs = cpl_imagelist_load_frameset(raw_offs, CPL_TYPE_FLOAT,
2397  0, whichext);
2398 
2399  cpl_frameset_delete(raw_offs);
2400  if (opt_offs == NULL) {
2401  cpl_errorstate_set(prestate);
2402  return CPL_ERROR_CONTINUE;
2403  }
2404  }
2405 
2406  skip_if(detmon_lg_reduce_init(gain_table,
2407  linear_table,
2408  &linearity_inputs,
2409  opt_nir));
2410 /*
2411  if (!strcmp(detmon_lg_config.method, "PTC"))
2412  {
2413  cpl_msg_warning(cpl_func, "PTC method incompatible with lamp stability"
2414  "computation");
2415  }
2416 */
2417  /* do always lamp stability check */
2418  if(detmon_lg_lamp_stab(set_on, set_off,
2419  opt_nir, whichext)) {
2420  cpl_errorstate_set(prestate);
2421  }
2422 
2423  if(!detmon_lg_config.collapse)
2424  {
2425  }
2426  /* Unselect all rows, to select only invalid ones */
2427  skip_if(cpl_table_unselect_all(linear_table));
2428  skip_if(cpl_table_unselect_all(gain_table));
2429 
2430  /* Loop on every DIT value */
2431 
2432  for(i = 0; i < nsets ; i++)
2433  {
2434  skip_if(detmon_lg_reduce_dit(set_on,
2435  index_on, exptime_on,
2436  i,
2437  &dit_nskip,
2438  set_off,
2439  index_off, exptime_off,
2440  next_index_on, next_index_off,
2441  linear_table,
2442  gain_table, linearity_inputs,
2443  lint_qclist, opt_nir,
2444  autocorr_images, diff_flats,
2445  opt_offs, whichext,
2446  &rows_affected));
2447  if (rows_affected == 0)
2448  {
2449  cpl_msg_warning(cpl_func, "The rest frames would not be taken "
2450  "into calculation, check the messages above");
2451  cpl_table_select_row(linear_table, i);
2452  cpl_table_select_row(gain_table, i);
2453  }
2454  else
2455  {
2456  last_best = i;
2457  }
2458  }
2459  skip_if(detmon_add_adl_column(linear_table, opt_nir));
2460 
2461  /*
2462  * Removal of rows corresponding to frames above --filter threshold.
2463  * See calls to cpl_table_select_row() in detmon_lg_reduce_dit().
2464  */
2465  skip_if(cpl_table_erase_selected(gain_table));
2466  skip_if(cpl_table_erase_selected(linear_table));
2467 
2468  reflist = cpl_propertylist_new();
2469  skip_if(cpl_propertylist_append_bool(reflist, "ADU", FALSE));
2470  skip_if(cpl_table_sort(gain_table, reflist));
2471  /*
2472  * --Final reduction--
2473  * The following call to detmon_lg_reduce_all() makes the
2474  * computations which are over all posible DIT values.
2475  */
2476  skip_if(detmon_lg_reduce_all(linear_table,
2477  gaint_qclist, lint_qclist, linc_qclist,
2478  bpm_qclist, coeffs_ptr, bpm_ptr,
2479  linearity_inputs,
2480  gain_table, whichext, opt_nir));
2481  {
2482  /*FPN Computation*/
2483  double gain = cpl_propertylist_get_double(gaint_qclist, DETMON_QC_GAIN);
2484  // cpl_propertylist_append_int(gaint_qclist, "NNNEXT", whichext);
2485  // cpl_msg_warning(cpl_func, "---------- ext %i" , whichext);
2486  cpl_error_code cplerr = cpl_error_get_code();
2487  if (cplerr != CPL_ERROR_NONE || (gain == 0.0))
2488  {
2489  cpl_msg_warning(cpl_func, "Cannot read gain from QC parameters - "
2490  "FPN will not be computed");
2491  cpl_error_reset();
2492  }
2493  else
2494  {
2495  detmon_fpn_compute(set_on, index_on, last_best, lint_qclist,
2496  detmon_lg_config.llx,
2497  detmon_lg_config.lly,
2498  detmon_lg_config.urx,
2499  detmon_lg_config.ury,
2500  gain,
2501  whichext,
2502  detmon_lg_config.fpn_method,
2503  detmon_lg_config.fpn_smooth);
2504  }
2505  }
2506  /* change NaN in the gain table to the invalid value D_INVALID_VALUE*/
2507 
2508  detmon_table_fill_invalid(gain_table, D_INVALID_VALUE);
2509  end_skip;
2510  cpl_imagelist_delete(linearity_inputs);
2511  cpl_imagelist_delete(opt_offs);
2512  cpl_propertylist_delete(reflist);
2513 
2514  return cpl_error_get_code();
2515 }
2516 
2517 static cpl_error_code detmon_table_fill_invalid(cpl_table* ptable, double code)
2518 {
2519  int ncols = cpl_table_get_ncol(ptable);
2520  cpl_array* pnames = cpl_table_get_column_names(ptable);
2521  int nrows = cpl_table_get_nrow(ptable);
2522  int i = 0;
2523  for (i=0; i < ncols; i++)
2524  {
2525  int j = 0;
2526  for (j = 0; j< nrows; j++)
2527  {
2528  const char* colname = cpl_array_get_data_string_const(pnames)[i];
2529  int isnull;
2530  cpl_type type = cpl_table_get_column_type(ptable, colname);
2531  cpl_table_get(ptable, colname, j, &isnull);
2532  if(isnull == 1)
2533  {
2534  if (type == CPL_TYPE_DOUBLE)
2535  {
2536  cpl_table_set(ptable,colname,j, code);
2537  }
2538  else if (type == CPL_TYPE_FLOAT)
2539  {
2540  cpl_table_set_float(ptable,colname,j, (float)code);
2541  }
2542  }
2543  }
2544  }
2545  cpl_array_delete(pnames);
2546  return cpl_error_get_code();
2547 }
2548 
2549 static cpl_error_code
2550 detmon_fpn_compute(const cpl_frameset *set_on,
2551  int * index_on,
2552  int last_best,
2553  cpl_propertylist *lint_qclist,
2554  int llx,
2555  int lly,
2556  int urx,
2557  int ury,
2558  double gain,
2559  int whichext,
2560  FPN_METHOD fpn_method,
2561  int smooth_size)
2562 {
2563  double fpn = 0;
2564  const cpl_image* im1 = 0;
2565  int range[4];
2566  cpl_imagelist* ons = 0;
2567  cpl_frameset * pair_on = 0;
2568  int nsets_extracted = cpl_frameset_get_size(set_on);
2569  cpl_size * selection = NULL;
2570  double mse = 0;
2571  range[0] = llx;
2572  range[1] = lly;
2573  range[2] = urx;
2574  range[3] = ury;
2575 
2576  /* Retrieve 2 ON frames with the highest DIT -
2577  * the last best 2 values in the index*/
2578  selection = cpl_malloc(sizeof(cpl_size) * nsets_extracted);
2579  memset(&selection[0], 0, sizeof(cpl_size) * nsets_extracted);
2580 
2581  selection[index_on[last_best*2 + 0] ] = 1;
2582  selection[index_on[last_best*2 + 1] ] = 1;
2583  pair_on = cpl_frameset_extract(set_on, selection, 1);
2584  ons = detmon_lg_config.load_fset_wrp(pair_on, CPL_TYPE_FLOAT, whichext);
2585 
2586  skip_if(ons == NULL);
2587  skip_if((im1 = cpl_imagelist_get_const(ons, 0)) == NULL);
2588 
2589  fpn = irplib_fpn_lg(im1, range, gain, fpn_method, smooth_size, &mse);
2590  skip_if(cpl_propertylist_append_double(lint_qclist, DETMON_QC_FPN,
2591  fpn));
2592  skip_if(cpl_propertylist_append_double(lint_qclist, "ESO QC GAIN ERR",
2593  mse));
2594 
2595  end_skip;
2596  cpl_frameset_delete(pair_on);
2597  cpl_imagelist_delete(ons);
2598  cpl_free(selection);
2599  return cpl_error_get_code();
2600 }
2601 
2602 /*--------------------------------------------------------------------------*/
2610 /*--------------------------------------------------------------------------*/
2611 static cpl_error_code
2612 detmon_lg_lamp_stab(const cpl_frameset * lamps,
2613  const cpl_frameset * darks,
2614  cpl_boolean opt_nir,
2615  int whichext)
2616 {
2617 
2618  /*
2619  * NOTE:
2620  * Most of this code is copied (and modified) from
2621  * isaac_img_detlin_load(), in isaac_img_detlin.c v.1.25
2622  */
2623 
2624  int nb_lamps;
2625  int nb_darks;
2626 
2627  cpl_vector * selection = NULL;
2628  cpl_propertylist * plist;
2629  double dit_lamp, dit_dark;
2630  int dit_stab;
2631  cpl_imagelist * lamps_data = NULL;
2632  cpl_imagelist * darks_data = NULL;
2633  double * stab_levels = NULL;
2634  int i, j;
2635  double * ditvals = NULL;
2636  int last_stab = 0; /* Avoid false uninit warning */
2637 
2638  /* Check that there are as many lamp as darks */
2639  cpl_ensure_code((nb_lamps = cpl_frameset_get_size(lamps)) >= 3,
2640  CPL_ERROR_ILLEGAL_INPUT);
2641 /*
2642  cpl_ensure_code(cpl_frameset_get_size(darks) == nb_lamps,
2643  CPL_ERROR_ILLEGAL_INPUT);
2644 */
2645  /* Check out that they have consistent integration times */
2646  cpl_msg_info(__func__, "Checking DIT consistency");
2647  selection = cpl_vector_new(nb_lamps);
2648  ditvals = cpl_malloc(nb_lamps * sizeof(double));
2649  dit_stab = 0;
2650  for (i = 0; i < nb_lamps; i++) {
2651  const cpl_frame * c_lamp;
2652  const cpl_frame * c_dark;
2653  /* Check if ok */
2654  skip_if (cpl_error_get_code());
2655 
2656  /* DIT from LAMP */
2657  c_lamp = cpl_frameset_get_position_const(lamps, i);
2658  plist = cpl_propertylist_load(cpl_frame_get_filename(c_lamp), 0);
2659  if(opt_nir)
2660  dit_lamp = (double)irplib_pfits_get_dit(plist);
2661  else
2662  dit_lamp = (double)irplib_pfits_get_dit_opt(plist);
2663  cpl_propertylist_delete(plist);
2664  skip_if (cpl_error_get_code());
2665 
2666  /* DIT from DARK */
2667  c_dark = cpl_frameset_get_position_const(darks, i);
2668  plist = cpl_propertylist_load(cpl_frame_get_filename(c_dark), 0);
2669  if(opt_nir)
2670  dit_dark = (double)irplib_pfits_get_dit(plist);
2671  else
2672  dit_dark = (double)irplib_pfits_get_dit_opt(plist);
2673  cpl_propertylist_delete(plist);
2674  skip_if (cpl_error_get_code());
2675 
2676  /* Check consistency */
2677  if (fabs(dit_dark-dit_lamp) > 1e-3) {
2678  cpl_msg_error(__func__, "DIT not consistent between LAMP and DARK, skip lamp stability computation");
2679  /* FIXME: Should an error code be set here? */
2680 
2681  skip_if(1);
2682  }
2683  ditvals[i] = dit_lamp;
2684  /* Set selection */
2685  if (i==0) {
2686  cpl_vector_set(selection, i, -1.0);
2687  dit_stab ++;
2688  last_stab = 0;
2689  } else {
2690  /*
2691  * The second condition is to make sure that frames taken into
2692  * account for lamp stability are not consecutive.
2693  */
2694  if (fabs(dit_lamp - ditvals[0]) < 1e-5 && i - last_stab > 3) {
2695  cpl_vector_set(selection, i, -1.0);
2696  dit_stab ++;
2697  last_stab = i;
2698  } else {
2699  cpl_vector_set(selection, i, 1.0);
2700  }
2701  }
2702  }
2703 
2704  /* Check if there are enough DITs for stability check */
2705  if (dit_stab < 2) {
2706  cpl_msg_info(__func__, "Not enough frames for stability check");
2707  } else {
2708 
2709  /* Load the data and compute lamp-dark */
2710  cpl_msg_info(__func__, "Compute the differences lamp - dark");
2711 
2712 
2713  lamps_data = detmon_load_frameset_window(lamps, CPL_TYPE_FLOAT, 0,
2714  whichext,
2715  detmon_lg_config.llx,
2716  detmon_lg_config.lly,
2717  detmon_lg_config.urx,
2718  detmon_lg_config.ury,
2719  -1, -1);
2720 
2721  darks_data = detmon_load_frameset_window(lamps, CPL_TYPE_FLOAT, 0,
2722  whichext,
2723  detmon_lg_config.llx,
2724  detmon_lg_config.lly,
2725  detmon_lg_config.urx,
2726  detmon_lg_config.ury,
2727  -1, -1);
2728 
2729  nb_darks=cpl_imagelist_get_size(darks_data);
2730  if(nb_darks==nb_lamps) {
2731  skip_if(cpl_imagelist_subtract(lamps_data,darks_data));
2732  } else {
2733  cpl_image* master_dark=cpl_imagelist_collapse_median_create(darks_data);
2734  cpl_imagelist_subtract_image(lamps_data,master_dark);
2735  cpl_image_delete(master_dark);
2736  }
2737  /* Check the lamp stability */
2738  cpl_msg_info(__func__, "Check the lamp stability");
2739  stab_levels = cpl_malloc(dit_stab * sizeof(double));
2740  j = 0;
2741  for (i=0; i<nb_lamps; i++) {
2742  if (cpl_vector_get(selection, i) < 0) {
2743  stab_levels[j] =
2744  cpl_image_get_mean(cpl_imagelist_get(lamps_data, i));
2745  j++;
2746  }
2747  }
2748 
2749  /* Compute the lamp stability */
2750  for (i=1; i<dit_stab; i++) {
2751  if ((fabs(stab_levels[i]-stab_levels[0]) / stab_levels[0]) >
2752  detmon_lg_config.lamp_stability)
2753  detmon_lg_config.lamp_stability =
2754  fabs(stab_levels[i]-stab_levels[0]) / stab_levels[0];
2755  }
2756 
2757 
2758  /* Check the lamp stability */
2759  if (detmon_lg_config.lamp_stability > 0.01) {
2760  cpl_msg_warning(__func__,
2761  "Lamp stability level %g difference too high - proceed anyway",detmon_lg_config.lamp_stability);
2762  }
2763  }
2764  end_skip;
2765 
2766 
2767  cpl_free(ditvals);
2768  cpl_vector_delete(selection);
2769  cpl_imagelist_delete(lamps_data);
2770  cpl_imagelist_delete(darks_data);
2771  cpl_free(stab_levels);
2772 
2773  return cpl_error_get_code();
2774 }
2775 
2776 /*--------------------------------------------------------------------------*/
2799 /*--------------------------------------------------------------------------*/
2800 static cpl_error_code
2801 detmon_lg_reduce_dit(const cpl_frameset * set_on,
2802  int* index_on, double* exptime_on,
2803  const int dit_nb,
2804  int * dit_nskip,
2805  const cpl_frameset * set_off,
2806  int * index_off, double* exptime_off,
2807  int* next_on, int* next_off,
2808  cpl_table * linear_table,
2809  cpl_table * gain_table,
2810  cpl_imagelist * linearity_inputs,
2811  cpl_propertylist * qclist,
2812  cpl_boolean opt_nir,
2813  cpl_imagelist * autocorr_images,
2814  cpl_imagelist * diff_flats,
2815  cpl_imagelist * opt_offs,
2816  int whichext,
2817  int* rows_affected)
2818 {
2819  cpl_frameset * pair_on = NULL;
2820  cpl_frameset * pair_off = NULL;
2821  cpl_imagelist * ons = NULL;
2822  cpl_imagelist * offs = NULL;
2823  cpl_boolean follow = CPL_TRUE;
2824  unsigned mode = detmon_lg_config.autocorr ? IRPLIB_GAIN_WITH_AUTOCORR : 0;
2825  double c_dit;
2826  int c_ndit;
2827 
2828  double current_dit = 0;
2829 
2830  const char * filename;
2831 
2832  cpl_propertylist * plist = NULL;
2833  cpl_propertylist* pDETlist = NULL;
2834 
2835  mode = detmon_lg_config.collapse ?
2836  mode | IRPLIB_GAIN_COLLAPSE | IRPLIB_LIN_COLLAPSE:
2837  mode | IRPLIB_GAIN_NO_COLLAPSE | IRPLIB_LIN_NO_COLLAPSE;
2838  mode = detmon_lg_config.pix2pix ?
2839  mode | IRPLIB_LIN_PIX2PIX : mode;
2840  mode = opt_nir ?
2841  mode | IRPLIB_GAIN_NIR | IRPLIB_LIN_NIR :
2842  mode | IRPLIB_GAIN_OPT | IRPLIB_LIN_OPT ;
2843 
2844 
2845  /* ON pair extraction */
2846  skip_if(detmon_pair_extract_next(set_on, index_on, next_on, exptime_on, &pair_on, detmon_lg_config.tolerance));
2847  current_dit = exptime_on[*next_on - 1];
2848 
2849  /* Load the ON images */
2850  ons = detmon_lg_config.load_fset_wrp(pair_on, CPL_TYPE_FLOAT, whichext);
2851  skip_if(ons == NULL);
2852  cpl_msg_debug(cpl_func, " Loaded ON images: %" CPL_SIZE_FORMAT
2853  ", exptime[%f]",cpl_imagelist_get_size(ons), current_dit );
2854  if(cpl_imagelist_get_size(ons) != 2)
2855  {
2856  cpl_msg_error(cpl_func, "cannot take ON pair, number of images[%"
2857  CPL_SIZE_FORMAT "]", cpl_imagelist_get_size(ons));
2858  skip_if(TRUE);
2859  }
2860  if(detmon_lg_config.filter > 0)
2861  {
2862  double med1 =
2863  cpl_image_get_median_window(cpl_imagelist_get(ons, 0),
2864  detmon_lg_config.llx,
2865  detmon_lg_config.lly,
2866  detmon_lg_config.urx,
2867  detmon_lg_config.ury);
2868  double med2 =
2869  cpl_image_get_median_window(cpl_imagelist_get(ons, 1),
2870  detmon_lg_config.llx,
2871  detmon_lg_config.lly,
2872  detmon_lg_config.urx,
2873  detmon_lg_config.ury);
2874  if ( med1 > (double)detmon_lg_config.filter ||
2875  med2 > (double)detmon_lg_config.filter)
2876  {
2877  follow = CPL_FALSE;
2878  cpl_table_select_row(gain_table, dit_nb);
2879  cpl_table_select_row(linear_table, dit_nb);
2880  (*dit_nskip)++;
2881  cpl_msg_warning(cpl_func, "Frames of EXPTIME nb %d "
2882  "will not be taken into account for computation "
2883  "as they are above --filter threshold", dit_nb);
2884  }
2885  }
2886 
2887  if (follow || detmon_lg_config.filter < 0)
2888  {
2889 
2890  /*
2891  * If the --collapse option is not activated by the user, the OFF
2892  * sub-frameset is also supposed to be organized into pairs and,
2893  * therefore, processed as the ON sub-frameset.
2894  */
2895  if(!detmon_lg_config.collapse)
2896  {
2897  if (!strcmp(detmon_lg_config.method, "MED") ||
2898  cpl_frameset_get_size(set_on) == cpl_frameset_get_size(set_off))
2899  {
2900  skip_if(detmon_pair_extract_next(set_off, index_off, next_off, exptime_off, &pair_off, detmon_lg_config.tolerance));
2901  }
2902  else
2903  {
2904  skip_if(detmon_single_extract_next(set_off, index_off, next_off, exptime_off, &pair_off));
2905  }
2906  /* Load the OFF images */
2907  cpl_msg_debug(cpl_func, " Load the OFF images, ext[%d], exptime[%f]", whichext, exptime_off[*next_off - 1]);
2908  offs = detmon_lg_config.load_fset_wrp(pair_off, CPL_TYPE_FLOAT, whichext);
2909 
2910  skip_if(offs == NULL);
2911  skip_if(cpl_error_get_code());
2912  }
2913  else {
2914  offs = (cpl_imagelist *) opt_offs;
2915  }
2916 
2917  /* Rescaling */
2918  if(detmon_lg_config.rescale)
2919  {
2920  skip_if(detmon_lg_rescale(ons));
2921  if (!detmon_lg_config.collapse &&
2922  !strcmp(detmon_lg_config.method, "MED"))
2923  skip_if(detmon_lg_rescale(offs));
2924  }
2925  /* DIT or EXPTIME value extraction */
2926 
2927  filename =
2928  cpl_frame_get_filename(cpl_frameset_get_first_const(pair_on));
2929  skip_if ((plist = cpl_propertylist_load(filename, 0)) == NULL);
2930  /* Add columns to the tables DETi WINi UITi*/
2931  if (plist)
2932  {
2933  pDETlist = cpl_propertylist_new();
2934  cpl_propertylist_copy_property_regexp(pDETlist, plist, "DET[0-9]* WIN[0-9]* UIT[0-9]*",0);
2935  if (dit_nb == 0)
2936  {
2937  irplib_table_create_column(gain_table, pDETlist);
2938  irplib_table_create_column(linear_table, pDETlist);
2939  }
2940  }
2941  if(opt_nir == NIR) {
2942  c_dit = irplib_pfits_get_dit(plist);
2943  c_ndit = irplib_pfits_get_ndit(plist);
2944  } else {
2945  c_dit = irplib_pfits_get_exptime(plist);
2946  c_ndit=1;
2947  }
2948 
2949  /*
2950  * --GAIN part for each DIT value--
2951  * The following call to detmon_gain_table_fill_row() fills
2952  * in the row nb i
2953  * of the GAIN table (output) and of the FIT table (by-product to be
2954  * used later for the polynomial computation of the GAIN)
2955  */
2956 
2957  cpl_msg_info(cpl_func, "Computing GAIN for EXPTIME value nb %d",
2958  dit_nb + 1);
2959 
2960  /* In case PTC is applied, this is allowed */
2961  if(cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE && dit_nb == 0)
2962  {
2963  cpl_table_erase_column(gain_table, "MEAN_OFF1");
2964  cpl_table_erase_column(gain_table, "MEAN_OFF2");
2965  cpl_table_erase_column(gain_table, "SIG_OFF_DIF");
2966  cpl_table_erase_column(gain_table, "GAIN");
2967  cpl_table_erase_column(gain_table, "GAIN_CORR");
2968  cpl_table_new_column(gain_table, "MEAN_OFF", CPL_TYPE_DOUBLE);
2969  }
2970 
2971  skip_if(detmon_gain_table_fill_row(gain_table,
2972  c_dit,c_ndit,
2973  autocorr_images,
2974  diff_flats, ons, offs,
2975  detmon_lg_config.kappa,
2976  detmon_lg_config.niter,
2977  detmon_lg_config.llx,
2978  detmon_lg_config.lly,
2979  detmon_lg_config.urx,
2980  detmon_lg_config.ury,
2981  detmon_lg_config.m,
2982  detmon_lg_config.n,
2983  detmon_lg_config.saturation_limit,
2984  dit_nb, mode, rows_affected));
2985 
2986 
2987  if (*rows_affected)
2988  {
2989  /* fill DETi WINi OPTi columns - see DFS06921*/
2990  skip_if(irplib_fill_table_DETWINUIT(gain_table, pDETlist, dit_nb));
2991  /* Linearity reduction */
2992  cpl_msg_info(cpl_func, "Linearity reduction for nb %d",
2993  dit_nb + 1);
2994  skip_if(detmon_lin_table_fill_row(linear_table, c_dit,
2995  linearity_inputs, ons, offs,
2996  detmon_lg_config.llx,
2997  detmon_lg_config.lly,
2998  detmon_lg_config.urx,
2999  detmon_lg_config.ury,
3000  dit_nb, *dit_nskip, mode));
3001  /* fill DETi WINi OPTi columns - see DFS06921*/
3002  skip_if(irplib_fill_table_DETWINUIT(linear_table, pDETlist, dit_nb));
3003  }
3004 
3005 
3006  /* as we know only at this point if a frame is
3007  saturated or not, and we would like to compute the
3008  contamination only on the last non saturated frame,
3009  we need de facto to compute saturation on any non saturated
3010  frame, by overwriting the QC parameter. In the end it will
3011  remain only the last value corresponding to a non saturated
3012  frame */
3013 
3014  if(opt_nir == OPT &&
3015  *rows_affected != 0 ) {
3016  detmon_opt_contamination(ons, offs, mode, qclist);
3017  }
3018 
3019  }
3020 
3021  end_skip;
3022 
3023  cpl_frameset_delete(pair_on);
3024  cpl_imagelist_delete(ons);
3025 
3026  if(!detmon_lg_config.collapse ) {
3027  cpl_imagelist_delete(offs);
3028  }
3029 
3030  if(!detmon_lg_config.collapse) {
3031  cpl_frameset_delete(pair_off);
3032  }
3033 
3034  cpl_propertylist_delete(plist);
3035  cpl_propertylist_delete(pDETlist);
3036  return cpl_error_get_code();
3037 }
3038 
3039 /*---------------------------------------------------------------------------*/
3045 /*---------------------------------------------------------------------------*/
3046 static cpl_error_code
3047 detmon_add_adl_column(cpl_table * table,
3048  cpl_boolean opt_nir)
3049 {
3050  cpl_error_code error;
3051  double mean_med_dit;
3052  double *dits;
3053 
3054  cpl_ensure_code(table != NULL, CPL_ERROR_NULL_INPUT);
3055 
3056  mean_med_dit = cpl_table_get_column_mean(table, "MED_DIT");
3057  if (opt_nir == OPT)
3058  dits = cpl_table_get_data_double(table, "EXPTIME");
3059  else
3060  dits = cpl_table_get_data_double(table, "DIT");
3061 
3062  error = cpl_table_copy_data_double(table, "ADL", dits);
3063  cpl_ensure_code(!error, error);
3064  error = cpl_table_multiply_scalar(table, "ADL", mean_med_dit);
3065  cpl_ensure_code(!error, error);
3066 
3067  return cpl_error_get_code();
3068 }
3069 
3070 /*---------------------------------------------------------------------------*/
3078 /*---------------------------------------------------------------------------*/
3079 static cpl_error_code
3080 detmon_lg_reduce_init(cpl_table * gain_table,
3081  cpl_table * linear_table,
3082  cpl_imagelist ** linearity_inputs,
3083  const cpl_boolean opt_nir)
3084 {
3085  skip_if(detmon_gain_table_create(gain_table, opt_nir));
3086  skip_if(detmon_lin_table_create(linear_table, opt_nir));
3087 
3088  if(detmon_lg_config.pix2pix) {
3089  *linearity_inputs = cpl_imagelist_new();
3090  skip_if(*linearity_inputs == NULL);
3091  }
3092 
3093  end_skip;
3094 
3095  return cpl_error_get_code();
3096 }
3097 
3098 /*--------------------------------------------------------------------------*/
3104 /*--------------------------------------------------------------------------*/
3105 static double
3106 irplib_pfits_get_dit(const cpl_propertylist * plist)
3107 {
3108  return irplib_pfits_get_prop_double(plist, "ESO DET DIT");
3109 }
3110 
3111 /*--------------------------------------------------------------------------*/
3117 /*--------------------------------------------------------------------------*/
3118 static double
3119 irplib_pfits_get_dit_opt(const cpl_propertylist * plist)
3120 {
3121  return irplib_pfits_get_prop_double(plist, "ESO DET WIN1 UIT1");
3122 }
3123 
3124 
3125 /*---------------------------------------------------------------------------*/
3130 static cpl_propertylist*
3131 detmon_load_pro_keys(const char* NAME_O)
3132 {
3133  cpl_propertylist* pro_keys=NULL;
3134  pro_keys=cpl_propertylist_load_regexp(NAME_O,0,"^(ESO PRO)",0);
3135  return pro_keys;
3136 }
3137 
3138 
3139 static double irplib_pfits_get_prop_double(const cpl_propertylist * plist,
3140  const char* prop_name)
3141 {
3142  double dit;
3143  dit = cpl_propertylist_get_double(plist, prop_name);
3144  if(cpl_error_get_code() != CPL_ERROR_NONE)
3145  {
3146  cpl_msg_error(cpl_func, "Cannot read property '%s', err[%s]",
3147  prop_name, cpl_error_get_where());
3148  }
3149  return dit;
3150 }
3151 
3152 /*---------------------------------------------------------------------------*/
3184 /*---------------------------------------------------------------------------*/
3185 static cpl_error_code
3186 detmon_gain_table_fill_row(cpl_table * gain_table,
3187  double c_dit,int c_ndit,
3188  cpl_imagelist * autocorr_images,
3189  cpl_imagelist * diff_flats,
3190  const cpl_imagelist * ons,
3191  const cpl_imagelist * offs,
3192  double kappa, int nclip,
3193  int llx, int lly, int urx, int ury,
3194  int m, int n,
3195  double saturation_limit,
3196  const int pos, unsigned mode, int* rows_affected)
3197 {
3198  const cpl_image *image;
3199  cpl_image *on_dif = NULL;
3200  double std = 0;
3201  double avg_on1, avg_on2;
3202  double avg_off1, avg_off2;
3203  double double_adu, autocorr, gain, gain_corr;
3204  double sigma;
3205 
3206  cpl_table_set(gain_table, "FLAG", pos, 1);
3207  if (mode & IRPLIB_GAIN_NIR)
3208  {
3209  cpl_table_set(gain_table, "DIT", pos, c_dit);
3210  cpl_table_set(gain_table, "NDIT", pos, c_ndit);
3211  } else if (mode & IRPLIB_GAIN_OPT)
3212  {
3213  cpl_table_set(gain_table, "EXPTIME", pos, c_dit);
3214  } else
3215  {
3216  cpl_msg_error(cpl_func, "Mandatory mode (OPT or NIR) not provided");
3217  skip_if(1);
3218  }
3219  if(*rows_affected == 0)
3220  {
3221  cpl_msg_info(cpl_func, "skip the frame #%d", pos + 1);
3222  cpl_table_set(gain_table, "FLAG", pos, 0);
3223  if(mode & IRPLIB_GAIN_WITH_AUTOCORR)
3224  {
3225  autocorr = -1;
3226  if (diff_flats)
3227  {
3228  detmon_lg_add_empty_image(diff_flats, pos);
3229  }
3230  if (autocorr_images)
3231  {
3232  detmon_lg_add_empty_image(autocorr_images, pos);
3233  }
3234  }
3235  return cpl_error_get_code();
3236  }
3237  skip_if((image = cpl_imagelist_get_const(ons, 0)) == NULL);
3238  skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
3239  nclip, 1e-5, &avg_on1, &std));
3240  skip_if((image = cpl_imagelist_get_const(ons, 1)) == NULL);
3241  skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
3242  nclip, 1e-5, &avg_on2, &std));
3243 
3244  if ((avg_on1 > saturation_limit) || (avg_on2 > saturation_limit))
3245  {
3246  cpl_msg_warning(cpl_func, "Average saturation is above the limit, "
3247  "the frames would not be taken into calculation");
3248  cpl_msg_warning(cpl_func, "saturation levels [%f ; %f], limit [%f]",
3249  avg_on1, avg_on2, saturation_limit);
3250  cpl_msg_info(cpl_func, "skip the frame #%d", pos + 1);
3251  cpl_table_set(gain_table, "FLAG", pos, 0);
3252  if(mode & IRPLIB_GAIN_WITH_AUTOCORR)
3253  {
3254  autocorr = -1;
3255  if (diff_flats)
3256  {
3257  detmon_lg_add_empty_image(diff_flats, pos);
3258  }
3259  if (autocorr_images)
3260  {
3261  detmon_lg_add_empty_image(autocorr_images, pos);
3262  }
3263  }
3264  *rows_affected = 0;
3265  }
3266  else
3267  {
3268  double sig_off_dif;
3269  *rows_affected = 1;
3270  skip_if(cpl_table_set_double(gain_table, "MEAN_ON1", pos, avg_on1));
3271  skip_if(cpl_table_set_double(gain_table, "MEAN_ON2", pos, avg_on2));
3272 
3273  on_dif =
3274  detmon_subtract_create_window(cpl_imagelist_get_const(ons, 0),
3275  cpl_imagelist_get_const(ons, 1),
3276  llx, lly, urx, ury);
3277  skip_if(on_dif == NULL);
3278 
3279  if(mode & IRPLIB_GAIN_WITH_AUTOCORR)
3280  {
3281  if (diff_flats)
3282  {
3283  cpl_image * diff = cpl_image_duplicate(on_dif);
3284  skip_if(cpl_imagelist_set(diff_flats, diff, pos));
3285  }
3286  if (autocorr_images)
3287  {
3288  cpl_image * corr = NULL;
3289  autocorr = detmon_autocorr_factor(on_dif, &corr, m, n);
3290  if(corr)
3291  {
3292  skip_if(cpl_imagelist_set(autocorr_images, corr, pos));
3293  }
3294  else
3295  {
3296  detmon_lg_add_empty_image(autocorr_images, pos);
3297  }
3298  } else
3299  {
3300  autocorr = detmon_autocorr_factor(on_dif, NULL, m, n);
3301  }
3302  autocorr = isnan(autocorr) ? 1.0 : autocorr;
3303  } else
3304  {
3305  autocorr = 1.0;
3306  }
3307 
3308  if (cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE)
3309  {
3310 
3311  skip_if(irplib_ksigma_clip(cpl_imagelist_get_const(offs, 0),
3312  llx, lly, urx, ury, kappa, nclip,
3313  1e-5, &avg_off1, &std));
3314  skip_if(cpl_table_set_double(gain_table, "MEAN_OFF", pos, avg_off1));
3315 
3316  } else if (mode & IRPLIB_GAIN_NO_COLLAPSE ||
3317  ( pos == 0 && mode & IRPLIB_GAIN_COLLAPSE )) {
3318  cpl_image * off_dif = NULL;
3319  double avg_off_dif;
3320  skip_if(irplib_ksigma_clip(cpl_imagelist_get_const(offs, 0),
3321  llx, lly, urx, ury, kappa, nclip,
3322  1e-5, &avg_off1, &std));
3323  skip_if(cpl_table_set_double(gain_table, "MEAN_OFF1", pos, avg_off1));
3324  skip_if(irplib_ksigma_clip(cpl_imagelist_get_const(offs, 1),
3325  llx, lly, urx, ury, kappa, nclip,
3326  1e-5, &avg_off2, &std));
3327  skip_if(cpl_table_set_double(gain_table, "MEAN_OFF2", pos, avg_off2));
3328  off_dif =
3329  detmon_subtract_create_window(cpl_imagelist_get_const(offs, 0),
3330  cpl_imagelist_get_const(offs, 1),
3331  llx, lly, urx, ury);
3332  skip_if(off_dif == NULL);
3333  irplib_ksigma_clip(off_dif, 1, 1,
3334  cpl_image_get_size_x(off_dif),
3335  cpl_image_get_size_y(off_dif),
3336  kappa, nclip,
3337  1e-5, &avg_off_dif, &sig_off_dif);
3338  cpl_image_delete(off_dif);
3339  skip_if(cpl_table_set_double(gain_table, "SIG_OFF_DIF",
3340  pos, sig_off_dif));
3341  } else if (pos > 0 && mode & IRPLIB_GAIN_COLLAPSE)
3342  {
3343  int status;
3344  avg_off1 = cpl_table_get_double(gain_table, "MEAN_OFF1", 0, &status);
3345  skip_if(cpl_table_set_double(gain_table, "MEAN_OFF1", pos, avg_off1));
3346  avg_off2 = cpl_table_get_double(gain_table, "MEAN_OFF2", 0, &status);
3347  skip_if(cpl_table_set_double(gain_table, "MEAN_OFF2", pos, avg_off2));
3348  sig_off_dif = cpl_table_get_double(gain_table, "SIG_OFF_DIF",
3349  0, &status);
3350  skip_if(cpl_table_set_double(gain_table, "SIG_OFF_DIF",
3351  pos, sig_off_dif));
3352  }
3353 
3354  {
3355  double avg_on_dif, sig_on_dif;
3356  irplib_ksigma_clip(on_dif, 1, 1,
3357  cpl_image_get_size_x(on_dif),
3358  cpl_image_get_size_y(on_dif), kappa,
3359  nclip, 1e-5, &avg_on_dif, &sig_on_dif);
3360  skip_if(cpl_table_set_double(gain_table, "SIG_ON_DIF", pos, sig_on_dif));
3361 
3362  if (cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE)
3363  {
3364  double_adu = (avg_on1 + avg_on2) - 2 * avg_off1;
3365  }
3366  else
3367  {
3368  double_adu = (avg_on1 + avg_on2) - (avg_off1 + avg_off2);
3369 
3370  sigma = (sig_on_dif * sig_on_dif) - (sig_off_dif * sig_off_dif);
3371 
3372  /* sigma_corr = autocorr * sigma; */
3373 
3374  gain = double_adu / (c_ndit * sigma);
3375 
3376  gain_corr = gain / (autocorr);
3377 
3378  skip_if(cpl_table_set_double(gain_table, "GAIN", pos, gain));
3379  skip_if(cpl_table_set_double(gain_table, "GAIN_CORR", pos, gain_corr));
3380  }
3381  /* cpl_msg_info(cpl_func,"gain=%g gain_corr=%g autocorr=%g",gain,gain_corr,autocorr); */
3382  skip_if(cpl_table_set_double(gain_table, "AUTOCORR", pos, autocorr));
3383  skip_if(cpl_table_set_double(gain_table, "ADU", pos, double_adu / 2));
3384 
3385  /* FIXME: Remove the following 3 columns after testing period */
3386  skip_if(cpl_table_set_double(gain_table, "Y_FIT",
3387  pos,
3388  c_ndit* sig_on_dif * sig_on_dif));
3389  skip_if(cpl_table_set_double(gain_table, "Y_FIT_CORR",
3390  pos,
3391  c_ndit * sig_on_dif * sig_on_dif));
3392  skip_if(cpl_table_set_double(gain_table, "X_FIT", pos, double_adu));
3393  skip_if(cpl_table_set_double(gain_table, "X_FIT_CORR",
3394  pos, double_adu / autocorr));
3395  }
3396  }
3397  end_skip;
3398 
3399  cpl_image_delete(on_dif);
3400 
3401  return cpl_error_get_code();
3402 }
3403 
3404 /*--------------------------------------------------------------------------*/
3411 /*--------------------------------------------------------------------------*/
3412 
3413 static cpl_image *
3414 detmon_bpixs(const cpl_imagelist * coeffs,
3415  cpl_boolean bpmbin,
3416  const double kappa,
3417  int *nbpixs)
3418 {
3419  int size;
3420  int i;
3421  const cpl_image *first= cpl_imagelist_get_const(coeffs, 0);
3422  cpl_stats *stats;
3423  double cur_mean;
3424  double cur_stdev;
3425  double lo_cut;
3426  double hi_cut;
3427  cpl_mask *cur_mask;
3428  cpl_mask *mask = cpl_mask_new(cpl_image_get_size_x(first),
3429  cpl_image_get_size_y(first));
3430  cpl_image *cur_image = NULL;
3431  cpl_image *bpm = NULL; /* Avoid false uninit warning */
3432  double p;
3433 
3434  size = cpl_imagelist_get_size(coeffs);
3435 
3436  if(!bpmbin) {
3437  bpm = cpl_image_new(cpl_image_get_size_x(first),
3438  cpl_image_get_size_y(first),
3439  CPL_TYPE_INT);
3440  }
3441 
3442 
3443  for(i = 0; i < size; i++) {
3444  const cpl_image * cur_coeff = cpl_imagelist_get_const(coeffs, i);
3445 
3446  stats = cpl_stats_new_from_image(cur_coeff,
3447  CPL_STATS_MEAN | CPL_STATS_STDEV);
3448  cur_mean = cpl_stats_get_mean(stats);
3449  cur_stdev = cpl_stats_get_stdev(stats);
3450 
3451  lo_cut = cur_mean - kappa * cur_stdev;
3452  hi_cut = cur_mean + kappa * cur_stdev;
3453 
3454  cur_mask = cpl_mask_threshold_image_create(cur_coeff, lo_cut, hi_cut);
3455  cpl_mask_not(cur_mask);
3456 
3457  if(!bpmbin) {
3458  cur_image = cpl_image_new_from_mask(cur_mask);
3459  p = pow(2, i);
3460  cpl_image_power(cur_image, p);
3461  cpl_image_add(bpm, cur_image);
3462  cpl_image_delete(cur_image);
3463  }
3464 
3465  cpl_mask_or(mask, cur_mask);
3466 
3467  cpl_mask_delete(cur_mask);
3468  cpl_stats_delete(stats);
3469  }
3470 
3471  if(bpmbin) {
3472  bpm = cpl_image_new_from_mask(mask);
3473  }
3474 
3475  *nbpixs += cpl_mask_count(mask);
3476 
3477  cpl_mask_delete(mask);
3478 
3479  return bpm;
3480 }
3481 
3482 
3483 /*--------------------------------------------------------------------------*/
3490 /*--------------------------------------------------------------------------*/
3491 /* Not used so we temporary comment it out
3492 static cpl_image *
3493 detmon_bpixs2(cpl_vector* x,const cpl_imagelist* y,
3494  const cpl_imagelist * coeffs,cpl_table* gain_table,
3495  const int order, const double kappa,cpl_boolean bpmbin,
3496  int *nbpixs)
3497 {
3498 
3499 
3500  int size_x=0;
3501  int size_y=0;
3502  int size_c=0;
3503 
3504 
3505  int i=0;
3506  int j=0;
3507  cpl_size k=0;
3508  int z=0;
3509  int pix=0;
3510  int sx=0;
3511  int sy=0;
3512 
3513  double* px=NULL;
3514  const float* pdata=NULL;
3515  const float* pcoeffs=NULL;
3516  double pfit=0.;
3517  double* pgain=NULL;
3518  cpl_binary* pmask=NULL;
3519  double gain=0;
3520  const cpl_image* img_data=NULL;
3521 
3522  const cpl_image* img_coeffs=NULL;
3523  cpl_image* bpm=NULL;
3524  cpl_mask* mask=NULL;
3525 
3526  cpl_polynomial* pol=NULL;
3527 
3528  size_x = cpl_vector_get_size(x);
3529  size_y = cpl_imagelist_get_size(y);
3530  size_c = cpl_imagelist_get_size(coeffs);
3531  img_data = cpl_imagelist_get_const(coeffs, 0);
3532  sx = cpl_image_get_size_x(img_data);
3533  sy = cpl_image_get_size_y(img_data);
3534  mask = cpl_mask_new(sx,sy);
3535 
3536  cpl_ensure(size_x == size_y, CPL_ERROR_NULL_INPUT, NULL);
3537 
3538  cpl_ensure(size_c == (order+1), CPL_ERROR_NULL_INPUT, NULL);
3539 
3540  px = cpl_vector_get_data(x);
3541  pmask=cpl_mask_get_data(mask);
3542  pgain=cpl_table_get_data_double(gain_table,"GAIN");
3543  pol=cpl_polynomial_new(1);
3544  for (z = 0; z < size_x; z++) {
3545 
3546  img_data = cpl_imagelist_get_const(y, z);
3547  pdata = cpl_image_get_data_float_const(img_data);
3548  gain=pgain[z];
3549 
3550  for (j = 0; j < sy; j++) {
3551 
3552  for (i = 0; i < sx; i++) {
3553 
3554  pix = j * sx + i;
3555 
3556  for (k = size_c-1; k >= 0; k--) {
3557 
3558  img_coeffs = cpl_imagelist_get_const(coeffs, k);
3559  pcoeffs = cpl_image_get_data_float_const(img_coeffs);
3560  cpl_polynomial_set_coeff(pol, &k, pcoeffs[pix]);
3561 
3562  }
3563 
3564  pfit = cpl_polynomial_eval_1d(pol,px[z],NULL);
3565  if (pdata[pix] > 0) {
3566  if (fabs(pdata[pix] - pfit) > kappa * sqrt(gain*pdata[pix])) {
3567  pmask[pix] = CPL_BINARY_1;
3568  } // check if point to be flagged
3569  } // check if pos intensity
3570  } // i loop
3571  } // j loop
3572 
3573  //cpl_image_delete(img_data);
3574 
3575  } // z loop
3576  cpl_polynomial_delete(pol);
3577  if (bpmbin) {
3578  bpm = cpl_image_new_from_mask(mask);
3579  }
3580 
3581  *nbpixs += cpl_mask_count(mask);
3582 
3583  cpl_mask_delete(mask);
3584 
3585  return bpm;
3586 }
3587 
3588 */
3589 /*---------------------------------------------------------------------------*/
3601 /*---------------------------------------------------------------------------*/
3602 
3603 static double
3604 detmon_autocorr_factor(const cpl_image * image,
3605  cpl_image ** autocorr_image, int m, int n)
3606 {
3607  cpl_image * mycorr_image = NULL;
3608  double autocorr = 0;
3609  cpl_error_code err = CPL_ERROR_NONE;
3610 
3611  mycorr_image = detmon_image_correlate(image, image, m, n);
3612  err=cpl_error_get_code();
3613  if (err == CPL_ERROR_UNSUPPORTED_MODE)
3614  {
3615  cpl_msg_warning(cpl_func, "FFTW is not supported by CPL, autocorrelation "
3616  "would be computed using internal implementation");
3617  cpl_error_reset();
3618  if (mycorr_image)
3619  cpl_image_delete(mycorr_image);
3620  mycorr_image = detmon_autocorrelate(image, m, n);
3621  }
3622  if(mycorr_image == NULL) {
3623  return -1;
3624  }
3625 
3626  cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), -1);
3627 
3628  autocorr = cpl_image_get_flux(mycorr_image);
3629 
3630  if (autocorr_image) *autocorr_image = mycorr_image;
3631  else cpl_image_delete(mycorr_image);
3632 
3633  return autocorr;
3634 }
3635 
3636 static cpl_propertylist*
3637 detmon_lg_extract_qclist_4plane(cpl_propertylist* linc_qclist,const int ip)
3638 {
3639 
3640  cpl_propertylist* sub_set=NULL;
3641  char* qc_key=NULL;
3642 
3643  sub_set=cpl_propertylist_new();
3644  qc_key=cpl_sprintf("QC LIN COEF%d",ip);
3645  cpl_propertylist_copy_property_regexp(sub_set,linc_qclist,qc_key,0);
3646 
3647  cpl_free(qc_key);
3648  return sub_set;
3649 
3650 }
3651 
3652 
3662 static cpl_error_code
3663 detmon_lg_extract_extention_header(cpl_frameset* frameset,
3664  cpl_propertylist* gaint_qclist,
3665  cpl_propertylist* lint_qclist,
3666  cpl_propertylist* linc_qclist,
3667  cpl_propertylist* bpm_qclist,
3668  int whichext)
3669 {
3670 
3671  cpl_propertylist * xplist = NULL;
3672 
3673  const char * filename =
3674  cpl_frame_get_filename(cpl_frameset_get_first(frameset));
3675 
3676  xplist = cpl_propertylist_load_regexp(filename, whichext,
3677  "ESO DET|EXTNAME", 0);
3678  if (detmon_lg_config.exts >= 0)
3679  {
3680  /* for one extension, copy only extname keyword (if any) - DFS09856 */
3681  cpl_property* propExtname = NULL;
3682  propExtname = cpl_propertylist_get_property(xplist, "EXTNAME");
3683  cpl_error_reset();
3684  if (NULL != propExtname)
3685  {
3686  propExtname = cpl_property_duplicate(propExtname);
3687  }
3688  cpl_propertylist_delete(xplist);
3689  xplist = NULL;
3690  if (NULL != propExtname)
3691  {
3692  xplist = cpl_propertylist_new();
3693  cpl_propertylist_append_property(xplist, propExtname);
3694  cpl_property_delete(propExtname);
3695  }
3696  }
3697  if (NULL != xplist)
3698  {
3699  cpl_propertylist_append(gaint_qclist, xplist);
3700  cpl_propertylist_append(lint_qclist, xplist);
3701  cpl_propertylist_append(linc_qclist, xplist);
3702  cpl_propertylist_append(bpm_qclist, xplist);
3703  cpl_propertylist_delete(xplist);
3704  }
3705 
3706  return cpl_error_get_code();
3707 }
3708 
3709 
3710 
3711 
3712 
3713 /*---------------------------------------------------------------------------*/
3722 /*---------------------------------------------------------------------------*/
3723 static cpl_error_code
3724 detmon_lg_save_table_with_pro_keys(cpl_table* table,
3725  const char* name_o,
3726  cpl_propertylist* xheader,
3727  unsigned CPL_IO_MODE)
3728 {
3729 
3730  cpl_propertylist* pro_keys=NULL;
3731 
3732  pro_keys=detmon_load_pro_keys(name_o);
3733  cpl_propertylist_append(xheader,pro_keys);
3734 
3735  if(CPL_IO_MODE==CPL_IO_DEFAULT) {
3736  cpl_propertylist * pri_head=cpl_propertylist_load(name_o,0);
3737  cpl_table_save(table, pri_head,xheader,name_o,
3738  CPL_IO_DEFAULT);
3739  cpl_propertylist_delete(pri_head);
3740 
3741  } else {
3742  cpl_table_save(table,NULL,xheader,name_o,
3743  CPL_IO_EXTEND);
3744  }
3745  cpl_propertylist_delete(pro_keys);
3746 
3747  return cpl_error_get_code();
3748 }
3749 
3750 /*---------------------------------------------------------------------------*/
3758 /*---------------------------------------------------------------------------*/
3759 static cpl_error_code
3760 detmon_lg_save_image_with_pro_keys(cpl_image* image,
3761  const char* name_o,
3762  cpl_propertylist* xheader)
3763 {
3764 
3765  cpl_propertylist* pro_keys=NULL;
3766  pro_keys=detmon_load_pro_keys(name_o);
3767  cpl_propertylist_append(xheader,pro_keys);
3768 
3769  cpl_image_save(image,name_o, CPL_BPP_IEEE_FLOAT,
3770  xheader,CPL_IO_EXTEND);
3771  cpl_propertylist_delete(pro_keys);
3772 
3773 
3774  return cpl_error_get_code();
3775 }
3776 
3777 /*---------------------------------------------------------------------------*/
3785 /*---------------------------------------------------------------------------*/
3786 static cpl_error_code
3787 detmon_lg_save_imagelist_with_pro_keys(cpl_imagelist* imagelist,
3788  const char* name_o,
3789  cpl_propertylist* xheader)
3790 {
3791 
3792  cpl_propertylist* pro_keys=NULL;
3793  pro_keys=detmon_load_pro_keys(name_o);
3794  cpl_propertylist_append(xheader,pro_keys);
3795 
3796  cpl_imagelist_save(imagelist,name_o, CPL_BPP_IEEE_FLOAT,
3797  xheader,CPL_IO_EXTEND);
3798 
3799  cpl_propertylist_delete(pro_keys);
3800 
3801 
3802  return cpl_error_get_code();
3803 }
3804 
3805 /*---------------------------------------------------------------------------*/
3822 static cpl_error_code
3823 detmon_lg_save_plane(const cpl_parameterlist * parlist,
3824  cpl_frameset* frameset,
3825  const cpl_frameset * usedframes,
3826  int whichext,
3827  const char* recipe_name,
3828  cpl_propertylist* mypro_coeffscube,
3829  cpl_propertylist* linc_plane_qclist,
3830  const char* package,
3831  const char* NAME_O,
3832  cpl_image* plane)
3833 {
3834  if(detmon_lg_config.exts == 0) {
3835  cpl_propertylist* plist=NULL;
3836  cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
3837  NULL, NULL,
3838  CPL_BPP_IEEE_FLOAT, recipe_name,
3839  mypro_coeffscube, NULL,
3840  package, NAME_O);
3841  plist=cpl_propertylist_load(NAME_O,0);
3842  cpl_image_save(plane,NAME_O, CPL_BPP_IEEE_FLOAT,
3843  plist,CPL_IO_DEFAULT);
3844  cpl_propertylist_delete(plist);
3845 
3846  } else if(detmon_lg_config.exts > 0) {
3847  cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
3848  NULL, NULL,
3849  CPL_BPP_IEEE_FLOAT, recipe_name,
3850  mypro_coeffscube, NULL,
3851  package, NAME_O);
3852 
3853  detmon_lg_save_image_with_pro_keys(plane,NAME_O,linc_plane_qclist);
3854  } else {
3855  if(whichext == 1)
3856  {
3857  cpl_dfs_save_image(frameset, NULL, parlist,
3858  usedframes,NULL, NULL,
3859  CPL_BPP_IEEE_FLOAT, recipe_name,
3860  mypro_coeffscube, NULL,
3861  package, NAME_O);
3862  detmon_lg_save_image_with_pro_keys(plane,NAME_O,linc_plane_qclist);
3863  } else {
3864 
3865  detmon_lg_save_image_with_pro_keys(plane,NAME_O,linc_plane_qclist);
3866 
3867  }
3868 
3869  }
3870 
3871  return cpl_error_get_code();
3872 }
3873 
3874 
3875 
3876 /*---------------------------------------------------------------------------*/
3894 static cpl_error_code
3895 detmon_lg_save_cube(const cpl_parameterlist * parlist,
3896  cpl_frameset* frameset,
3897  const cpl_frameset * usedframes,
3898  int whichext,
3899  const char* recipe_name,
3900  cpl_propertylist* mypro_coeffscube,
3901  cpl_propertylist* linc_qclist,
3902  const char* package,
3903  const char* NAME_O,
3904  cpl_imagelist* coeffs)
3905 {
3906 
3907  if(detmon_lg_config.exts == 0) {
3908  cpl_propertylist_append(mypro_coeffscube, linc_qclist);
3909  detmon_lg_dfs_save_imagelist
3910  (frameset, parlist, usedframes, coeffs,
3911  recipe_name, mypro_coeffscube, package,
3912  NAME_O);
3913  } else if(detmon_lg_config.exts > 0) {
3914  cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
3915  NULL, NULL,
3916  CPL_BPP_IEEE_FLOAT, recipe_name,
3917  mypro_coeffscube, NULL,
3918  package, NAME_O);
3919 
3920  detmon_lg_save_imagelist_with_pro_keys(coeffs,NAME_O,linc_qclist);
3921 
3922  } else {
3923  if(whichext == 1) {
3924  cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
3925  NULL, NULL,
3926  CPL_BPP_IEEE_FLOAT, recipe_name,
3927  mypro_coeffscube, NULL,
3928  package, NAME_O);
3929  if (coeffs)
3930  detmon_lg_save_imagelist_with_pro_keys(coeffs,NAME_O,linc_qclist);
3931  else
3932  cpl_propertylist_save(linc_qclist, NAME_O, CPL_IO_EXTEND);
3933  } else {
3934  if (coeffs)
3935  detmon_lg_save_imagelist_with_pro_keys(coeffs,NAME_O,linc_qclist);
3936  else
3937  cpl_propertylist_save(linc_qclist, NAME_O, CPL_IO_EXTEND);
3938  }
3939  }
3940 
3941  return cpl_error_get_code();
3942 }
3943 
3944 static char*
3945 detmon_lg_set_paf_name_and_header(cpl_frame* ref_frame,
3946  int flag_sets,int which_set,
3947  int whichext,
3948  const char* paf_suf,
3949  cpl_propertylist** plist)
3950 {
3951  char * paf_name=NULL;
3952 
3953  if(detmon_lg_config.exts >= 0)
3954  {
3955  *plist =cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
3956  detmon_lg_config.exts);
3957 
3958  if(!flag_sets)
3959  {
3960  paf_name=cpl_sprintf("%s_%s.paf", detmon_lg_config.pafname,paf_suf);
3961  }
3962  else
3963  {
3964  paf_name=cpl_sprintf("%s_%s_set%02d.paf",
3965  detmon_lg_config.pafname, paf_suf,which_set);
3966  }
3967  }
3968  else
3969  {
3970  *plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
3971  whichext);
3972 
3973 
3974  if(!flag_sets)
3975  {
3976  paf_name=cpl_sprintf("%s_%s_ext%02d.paf",
3977  detmon_lg_config.pafname, paf_suf,whichext);
3978  }
3979  else
3980  {
3981  paf_name=cpl_sprintf("%s_%s_set%02d_ext%02d.paf",
3982  detmon_lg_config.pafname,paf_suf,
3983  which_set, whichext);
3984  }
3985  }
3986 
3987  return paf_name;
3988 }
3989 
3990 
3991 static char*
3992 detmon_lg_set_paf_name_and_header_ext(cpl_frame* ref_frame,
3993  int flag_sets,int which_set,
3994  int whichext,
3995  const char* paf_suf,
3996  cpl_propertylist** plist)
3997 {
3998  char* paf_name=NULL;
3999 
4000  if(detmon_lg_config.exts >= 0)
4001  {
4002  *plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4003  detmon_lg_config.exts);
4004 
4005  if(!flag_sets)
4006  {
4007  paf_name=cpl_sprintf("%s_%s.paf", detmon_lg_config.pafname,paf_suf);
4008  } else
4009  {
4010  paf_name=cpl_sprintf("%s_%s_set%02d.paf",
4011  detmon_lg_config.pafname, paf_suf,which_set);
4012  }
4013  } else
4014  {
4015  *plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4016  whichext);
4017  if(!flag_sets)
4018  {
4019  paf_name=cpl_sprintf("%s_%s_ext%02d.paf",
4020  detmon_lg_config.pafname, paf_suf,whichext);
4021  } else
4022  {
4023  paf_name=cpl_sprintf("%s_%s_set%02d_ext%02d.paf",
4024  detmon_lg_config.pafname,paf_suf,
4025  which_set, whichext);
4026  }
4027  }
4028  return paf_name;
4029 
4030 }
4031 
4032 static cpl_error_code
4033 detmon_lg_save_paf_product(cpl_frame* ref_frame,int flag_sets,
4034  int which_set,int whichext,
4035  const char* pafregexp,
4036  const char* procatg,
4037  const char* pipeline_name,
4038  const char* recipe_name,
4039  const char* paf_suf,
4040  cpl_propertylist* qclist,
4041  const int ext)
4042 
4043 {
4044  /* Set the file name for the linearity table PAF */
4045  char* paf_name=NULL;
4046  cpl_propertylist* plist=NULL;
4047  cpl_propertylist* paflist = NULL;
4048  cpl_propertylist* mainplist=NULL;
4049 
4050  mainplist =cpl_propertylist_load(cpl_frame_get_filename(ref_frame),0);
4051  if(ext==0) {
4052  paf_name=detmon_lg_set_paf_name_and_header(ref_frame,flag_sets,
4053  which_set,whichext,
4054  paf_suf,&plist);
4055  } else {
4056  paf_name=detmon_lg_set_paf_name_and_header_ext(ref_frame,flag_sets,
4057  which_set,whichext,
4058  paf_suf,&plist);
4059  }
4060 
4061 
4062  paflist = cpl_propertylist_new();
4063  cpl_propertylist_append_string(paflist, CPL_DFS_PRO_CATG,procatg);
4064 
4065  /* Get the keywords for the paf file */
4066  cpl_propertylist_copy_property_regexp(paflist, plist,pafregexp, 0);
4067  cpl_propertylist_copy_property_regexp(paflist, mainplist,pafregexp, 0);
4068  cpl_propertylist_append(paflist,qclist);
4069 
4070  /* Save the PAF */
4071  cpl_dfs_save_paf(pipeline_name, recipe_name,paflist,paf_name);
4072 
4073  /* free memory */
4074  cpl_propertylist_delete(mainplist);
4075  cpl_propertylist_delete(paflist);
4076  cpl_propertylist_delete(plist);
4077  cpl_free(paf_name);
4078 
4079  return cpl_error_get_code();
4080 
4081 }
4082 
4083 
4084 
4085 /*---------------------------------------------------------------------------*/
4116 static cpl_error_code
4117 detmon_lg_save(const cpl_parameterlist * parlist,
4118  cpl_frameset * frameset,
4119  const char *recipe_name,
4120  const char *pipeline_name,
4121  const char *pafregexp,
4122  const cpl_propertylist * pro_lintbl,
4123  const cpl_propertylist * pro_gaintbl,
4124  const cpl_propertylist * pro_coeffscube,
4125  const cpl_propertylist * pro_bpm,
4126  const cpl_propertylist * pro_corr,
4127  const cpl_propertylist * pro_diff,
4128  const char *package,
4129  cpl_imagelist * coeffs,
4130  cpl_table * gain_table,
4131  cpl_table * linear_table,
4132  cpl_image * bpms,
4133  cpl_imagelist * autocorr_images,
4134  cpl_imagelist * diff_flats,
4135  cpl_propertylist * gaint_qclist,
4136  cpl_propertylist * lint_qclist,
4137  cpl_propertylist * linc_qclist,
4138  cpl_propertylist * bpm_qclist,
4139  const int flag_sets,
4140  const int which_set,
4141  const cpl_frameset * usedframes,
4142  int whichext)
4143 {
4144 
4145  cpl_frame *ref_frame;
4146  cpl_propertylist *plist = NULL;
4147  cpl_propertylist *mainplist = NULL;
4148  char* NAME_O=NULL;
4149  char* PREF_O=NULL;
4150  int nb_images;
4151  int i;
4152 
4153  cpl_propertylist * xplist = NULL;
4154 
4155  cpl_propertylist* linc_plane_qclist=NULL;
4156  cpl_image* plane=NULL;
4157  int ip=0;
4158  char* pcatg_plane=NULL;
4159 
4160  cpl_propertylist * mypro_lintbl =
4161  cpl_propertylist_duplicate(pro_lintbl);
4162  cpl_propertylist * mypro_gaintbl =
4163  cpl_propertylist_duplicate(pro_gaintbl);
4164  cpl_propertylist * mypro_coeffscube =
4165  cpl_propertylist_duplicate(pro_coeffscube);
4166  cpl_propertylist * mypro_bpm =
4167  cpl_propertylist_duplicate(pro_bpm);
4168  cpl_propertylist * mypro_corr =
4169  cpl_propertylist_duplicate(pro_corr);
4170  cpl_propertylist * mypro_diff =
4171  cpl_propertylist_duplicate(pro_diff);
4172 
4173  const char * procatg_lintbl =
4174  cpl_propertylist_get_string(mypro_lintbl, CPL_DFS_PRO_CATG);
4175 
4176  const char * procatg_gaintbl =
4177  cpl_propertylist_get_string(mypro_gaintbl, CPL_DFS_PRO_CATG);
4178 
4179  const char * procatg_coeffscube =
4180  cpl_propertylist_get_string(mypro_coeffscube, CPL_DFS_PRO_CATG);
4181  const char * procatg_bpm =
4182  cpl_propertylist_get_string(mypro_bpm, CPL_DFS_PRO_CATG);
4183 
4184 
4185  /* Extract extension headers if multi-extension */
4186  detmon_lg_extract_extention_header(frameset,gaint_qclist,lint_qclist,
4187  linc_qclist,bpm_qclist,whichext);
4188 
4189  /* This is only used later for PAF and temporarily for COEFFS_CUBE
4190  (see if defined)*/
4191  /* Get FITS header from reference file */
4192  ref_frame = cpl_frameset_get_first(frameset);
4193 
4194  skip_if((mainplist =
4195  cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4196  0)) == NULL);
4197 
4198  /*******************************/
4199  /* Write the LINEARITY TABLE */
4200  /*******************************/
4201  cpl_msg_info(cpl_func,"Write the LINEARITY TABLE");
4202  /* Set the file name for the table */
4203  if(!flag_sets) {
4204  NAME_O=cpl_sprintf("%s_linearity_table.fits", recipe_name);
4205  } else {
4206  NAME_O=cpl_sprintf("%s_linearity_table_set%02d.fits", recipe_name,
4207  which_set);
4208  }
4209 
4210  if (detmon_lg_config.exts >= 0) {
4211  /* Save the table */
4212  cpl_propertylist_append(mypro_lintbl, lint_qclist);
4213  skip_if(cpl_dfs_save_table(frameset, NULL,parlist, usedframes, NULL,
4214  linear_table,NULL, recipe_name,
4215  mypro_lintbl, NULL, package, NAME_O));
4216 
4217  detmon_lg_save_table_with_pro_keys(linear_table,NAME_O,
4218  lint_qclist,CPL_IO_DEFAULT);
4219 
4220  } else {
4221  if(whichext == 1) {
4222  /* Save the 1. extension table */
4223  skip_if(cpl_dfs_save_table(frameset,NULL, parlist, usedframes, NULL,
4224  linear_table,lint_qclist, recipe_name,
4225  mypro_lintbl,NULL, package, NAME_O));
4226  detmon_lg_save_table_with_pro_keys(linear_table,NAME_O,
4227  lint_qclist,CPL_IO_DEFAULT);
4228 
4229 
4230 
4231 
4232  } else {
4233 
4234  detmon_lg_save_table_with_pro_keys(linear_table,NAME_O,
4235  lint_qclist,CPL_IO_EXTEND);
4236  }
4237  }
4238  irplib_free(&NAME_O);
4239  /**************************/
4240  /* Write the GAIN TABLE */
4241  /**************************/
4242  cpl_msg_info(cpl_func,"Write the GAIN TABLE");
4243  /* Set the file name for the table */
4244  if(!flag_sets) {
4245  NAME_O=cpl_sprintf("%s_gain_table.fits", recipe_name);
4246  } else {
4247  NAME_O=cpl_sprintf("%s_gain_table_set%02d.fits", recipe_name,
4248  which_set);
4249  }
4250 
4251  if (detmon_lg_config.exts >= 0)
4252  {
4253  /* Save the table */
4254 
4255  cpl_propertylist_append(mypro_gaintbl, gaint_qclist);
4256  skip_if(cpl_dfs_save_table(frameset, NULL, parlist, usedframes, NULL,
4257  gain_table,NULL, recipe_name, mypro_gaintbl,
4258  NULL, package, NAME_O));
4259  detmon_lg_save_table_with_pro_keys(gain_table,NAME_O,
4260  gaint_qclist,CPL_IO_DEFAULT);
4261 
4262  }
4263  else
4264  {
4265  if(whichext == 1)
4266  {
4267  /* Save the 1. extension table */
4268  skip_if(cpl_dfs_save_table(frameset, NULL, parlist, usedframes, NULL, gain_table,
4269  gaint_qclist, recipe_name, mypro_gaintbl,
4270  NULL, package, NAME_O));
4271  detmon_lg_save_table_with_pro_keys(gain_table,NAME_O,
4272  gaint_qclist,CPL_IO_DEFAULT);
4273 
4274  }
4275  else
4276  {
4277 
4278  detmon_lg_save_table_with_pro_keys(gain_table,NAME_O,
4279  gaint_qclist,CPL_IO_EXTEND);
4280  }
4281  }
4282 
4283  if(detmon_lg_config.pix2pix)
4284  {
4285 
4286  /***************************/
4287  /* Write the COEFFS FITS */
4288  /***************************/
4289  cpl_msg_info(cpl_func,"Write the COEFFS FITS");
4290  irplib_free(&NAME_O);
4291  if(!flag_sets)
4292  {
4293  PREF_O=cpl_sprintf("%s_coeffs_cube", recipe_name);
4294  } else
4295  {
4296  PREF_O=cpl_sprintf("%s_coeffs_cube_set%02d",
4297  recipe_name, which_set);
4298  }
4299  if (detmon_lg_config.split_coeffs == 0) {
4300  NAME_O=cpl_sprintf("%s.fits", PREF_O);
4301  }
4302 
4303 
4304  /* Save the imagelist */
4305  if(detmon_lg_config.split_coeffs != 0){
4306 
4307 
4308  nb_images = cpl_imagelist_get_size(coeffs);
4309  for(ip=0;ip<nb_images;ip++) {
4310  NAME_O=cpl_sprintf("%s_P%d.fits", PREF_O,ip);
4311  pcatg_plane=cpl_sprintf("COEFFS_CUBE_P%d",ip);
4312  cpl_propertylist_delete(mypro_coeffscube);
4313  mypro_coeffscube=cpl_propertylist_duplicate(pro_coeffscube);
4314  cpl_propertylist_set_string(mypro_coeffscube,CPL_DFS_PRO_CATG,
4315  pcatg_plane);
4316  linc_plane_qclist=detmon_lg_extract_qclist_4plane(linc_qclist,ip);
4317  cpl_propertylist_append(mypro_coeffscube, linc_plane_qclist);
4318  plane=cpl_imagelist_get(coeffs,ip);
4319  detmon_lg_save_plane(parlist,frameset,usedframes,whichext,
4320  recipe_name,mypro_coeffscube,
4321  linc_plane_qclist,package,NAME_O,plane);
4322 
4323  if(NULL!=linc_plane_qclist) {
4324  cpl_propertylist_delete(linc_plane_qclist);
4325  }
4326  irplib_free(&NAME_O);
4327 
4328  } /* end for loop over cube planes */
4329  } else {
4330 
4331  detmon_lg_save_cube(parlist,frameset,usedframes,whichext,
4332  recipe_name,mypro_coeffscube,
4333  linc_qclist,package,NAME_O,coeffs);
4334  }
4335 
4336  /*******************************/
4337  /* Write the BAD PIXEL MAP */
4338  /*******************************/
4339  cpl_msg_info(cpl_func,"Write the BAD PIXEL MAP");
4340  irplib_free(&NAME_O);
4341  /* Set the file name for the bpm */
4342  if(!flag_sets)
4343  {
4344  NAME_O=cpl_sprintf("%s_bpm.fits", recipe_name);
4345  } else
4346  {
4347  NAME_O=cpl_sprintf("%s_bpm_set%02d.fits", recipe_name, which_set);
4348  }
4349 
4350 
4351  /* Save the image */
4352  if(detmon_lg_config.exts == 0) {
4353  cpl_propertylist_append(mypro_bpm, bpm_qclist);
4354  cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL, bpms,
4355  CPL_BPP_IEEE_FLOAT, recipe_name,
4356  mypro_bpm, NULL, package,
4357  NAME_O);
4358  }
4359  else if(detmon_lg_config.exts > 0)
4360  {
4361  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,NULL, NULL,
4362  CPL_BPP_IEEE_FLOAT, recipe_name,
4363  mypro_bpm, NULL, package,
4364  NAME_O));
4365  detmon_lg_save_image_with_pro_keys(bpms,NAME_O,bpm_qclist);
4366 
4367  } else
4368  {
4369  if (whichext == 1)
4370  {
4371  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,NULL, NULL,
4372  CPL_BPP_IEEE_FLOAT, recipe_name,
4373  mypro_bpm, NULL, package,
4374  NAME_O));
4375  detmon_lg_save_image_with_pro_keys(bpms,NAME_O,bpm_qclist);
4376  } else
4377  {
4378  detmon_lg_save_image_with_pro_keys(bpms,NAME_O,bpm_qclist);
4379  }
4380  }
4381  } /* End of if(pix2pix) */
4382 
4383  if(detmon_lg_config.intermediate)
4384  {
4385  /******************************/
4386  /* Write the AUTOCORRS FITS */
4387  /******************************/
4388  cpl_msg_info(cpl_func,"Write the AUTOCORRS FITS");
4389  nb_images = cpl_imagelist_get_size(autocorr_images);
4390  cpl_ensure_code(nb_images > 0, CPL_ERROR_DATA_NOT_FOUND);
4391  for(i = 0; i < nb_images; i++)
4392  {
4393  cpl_propertylist* pplist = cpl_propertylist_duplicate(mypro_corr);
4394  int inull = 0;
4395  cpl_array* pnames = cpl_table_get_column_names(linear_table);
4396  double ddit = 0;
4397  if(i < cpl_table_get_nrow(linear_table))
4398  {
4399  ddit = cpl_table_get_double(linear_table,
4400  cpl_array_get_data_string_const(pnames)[0], i, &inull);
4401  }
4402  cpl_array_delete(pnames);
4403  /*cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);*/
4404  /* Set the file name for each image */
4405  irplib_free(&NAME_O);
4406  if(!flag_sets)
4407  {
4408  NAME_O=cpl_sprintf("%s_autocorr_%d.fits", recipe_name, i);
4409  assert(NAME_O != NULL);
4410  } else
4411  {
4412  NAME_O=cpl_sprintf("%s_autocorr_%02d_set%02d.fits",
4413  recipe_name, i, which_set);
4414  assert(NAME_O != NULL);
4415  }
4416  /* Save the image */
4417  if(detmon_lg_config.exts > 0)
4418  {
4419  cpl_propertylist* pextlist = cpl_propertylist_new();
4420  cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4421  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4422  NULL,NULL,CPL_BPP_IEEE_FLOAT,
4423  recipe_name, pplist, NULL,
4424  package, NAME_O));
4425 
4426  detmon_lg_save_image_with_pro_keys(
4427  cpl_imagelist_get(autocorr_images, i),NAME_O,pextlist);
4428 
4429  cpl_propertylist_delete(pextlist);
4430  } else
4431  if(detmon_lg_config.exts == 0)
4432  {
4433  cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);
4434  cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL,
4435  cpl_imagelist_get(autocorr_images, i),
4436  CPL_BPP_IEEE_FLOAT,
4437  recipe_name, pplist, NULL, package,
4438  NAME_O);
4439 
4440  }
4441  else
4442  {
4443  cpl_propertylist* pextlist = cpl_propertylist_new();
4444  cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4445  if(whichext == 1)
4446  {
4447  skip_if(cpl_dfs_save_image(frameset, NULL, parlist,
4448  usedframes, NULL,NULL,
4449  CPL_BPP_IEEE_FLOAT, recipe_name,
4450  pplist, NULL,
4451  package, NAME_O));
4452 
4453  detmon_lg_save_image_with_pro_keys(
4454  cpl_imagelist_get(autocorr_images, i),NAME_O,pextlist);
4455 
4456  } else
4457  {
4458 
4459  detmon_lg_save_image_with_pro_keys(
4460  cpl_imagelist_get(autocorr_images, i),NAME_O,pextlist);
4461  }
4462  cpl_propertylist_delete(pextlist);
4463  }
4464  cpl_propertylist_delete (pplist);
4465  }
4466  irplib_free(&NAME_O);
4467 
4468 
4469  /*
4470  cpl_msg_info(cpl_func, "-----before Write the DIFFS FITS %d", __LINE__);
4471  */
4472  /***************************/
4473  /* Write the DIFFS FITS */
4474  /***************************/
4475  cpl_msg_info(cpl_func,"Write the DIFFS FITS");
4476 
4477  for(i = 0; i < nb_images; i++)
4478  {
4479  cpl_propertylist* pplist = cpl_propertylist_duplicate(mypro_diff);
4480  int inull = 0;
4481  cpl_array* pnames = cpl_table_get_column_names(linear_table);
4482  double ddit = 0;
4483  if(i < cpl_table_get_nrow(linear_table))
4484  {
4485  ddit = cpl_table_get_double(linear_table,
4486  cpl_array_get_data_string_const(pnames)[0], i, &inull);
4487  }
4488  cpl_array_delete(pnames);
4489  /*cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);*/
4490  /* Set the file name for each image */
4491  if(!flag_sets)
4492  {
4493  NAME_O=cpl_sprintf("%s_diff_flat_%d.fits", recipe_name, i);
4494  } else
4495  {
4496  NAME_O=cpl_sprintf("%s_diff_flat_%d_set%02d.fits",
4497  recipe_name, i, which_set);
4498  }
4499  /* Save the image */
4500  if(detmon_lg_config.exts > 0)
4501  {
4502  cpl_propertylist* pextlist = cpl_propertylist_new();
4503  cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4504  cpl_propertylist_append_double(mypro_diff, "ESO DET DIT", ddit);
4505  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4506  NULL,NULL,CPL_BPP_IEEE_FLOAT,
4507  recipe_name,
4508  mypro_diff, NULL,package, NAME_O));
4509 
4510  detmon_lg_save_image_with_pro_keys(
4511  cpl_imagelist_get(diff_flats, i),NAME_O,pextlist);
4512 
4513  cpl_propertylist_delete(pextlist);
4514  }
4515  else if(detmon_lg_config.exts == 0)
4516  {
4517  cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);
4518  cpl_dfs_save_image
4519  (frameset, NULL, parlist, usedframes, NULL,
4520  cpl_imagelist_get(diff_flats, i), CPL_BPP_IEEE_FLOAT,
4521  recipe_name, pplist, NULL, package,
4522  NAME_O);
4523 
4524  } else
4525  {
4526  cpl_propertylist* pextlist = cpl_propertylist_new();
4527  cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4528  if(whichext == 1)
4529  {
4530  cpl_propertylist_append_double(mypro_diff,"ESO DET DIT",ddit);
4531  // cpl_propertylist_erase(mypro_diff, "ESO DET DIT");
4532  skip_if(cpl_dfs_save_image(frameset, NULL, parlist,
4533  usedframes, NULL,NULL,
4534  CPL_BPP_IEEE_FLOAT, recipe_name,
4535  mypro_diff, NULL,package, NAME_O));
4536 
4537  detmon_lg_save_image_with_pro_keys(
4538  cpl_imagelist_get(diff_flats, i),NAME_O,pextlist);
4539 
4540  } else
4541  {
4542 
4543  detmon_lg_save_image_with_pro_keys(
4544  cpl_imagelist_get(diff_flats, i),NAME_O,pextlist);
4545 
4546  }
4547  cpl_propertylist_delete(pextlist);
4548  }
4549  cpl_propertylist_delete(pplist);
4550  irplib_free(&NAME_O);
4551  }
4552  } /* End of if(intermediate) */
4553 
4554 
4555  /*******************************/
4556  /* Write the PAF file(s) */
4557  /*******************************/
4558  cpl_msg_info(cpl_func,"Write the PAF file(s)");
4559 
4560  if(detmon_lg_config.pafgen) {
4561 
4562  detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,whichext,
4563  pafregexp,procatg_gaintbl,
4564  pipeline_name,recipe_name,
4565  "qc01",gaint_qclist,0);
4566 
4567  detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,whichext,
4568  pafregexp,procatg_lintbl,
4569  pipeline_name,recipe_name,
4570  "qc02",lint_qclist,0);
4571 
4572  if(detmon_lg_config.pix2pix)
4573  {
4574 
4575  detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,
4576  whichext,pafregexp,
4577  procatg_coeffscube,
4578  pipeline_name,recipe_name,
4579  "qc03",linc_qclist,1);
4580 
4581  detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,
4582  whichext,pafregexp,procatg_bpm,
4583  pipeline_name,recipe_name,
4584  "qc04",bpm_qclist,1);
4585  }
4586  }
4587 
4588  end_skip;
4589  cpl_msg_info(cpl_func,"exit");
4590 
4591  cpl_propertylist_delete(xplist);
4592  if(plist!=NULL) {
4593  cpl_propertylist_delete(plist);
4594  plist=NULL;
4595  }
4596 
4597  irplib_free(&NAME_O);
4598  cpl_free(PREF_O);
4599  cpl_free(pcatg_plane);
4600  cpl_propertylist_delete(mainplist);
4601  cpl_propertylist_delete(mypro_lintbl);
4602  cpl_propertylist_delete(mypro_gaintbl);
4603  cpl_propertylist_delete(mypro_coeffscube);
4604  cpl_propertylist_delete(mypro_bpm);
4605  cpl_propertylist_delete(mypro_corr);
4606  cpl_propertylist_delete(mypro_diff);
4607 
4608  return cpl_error_get_code();
4609 }
4610 
4611 
4612 /*---------------------------------------------------------------------------*/
4620 /*---------------------------------------------------------------------------*/
4621 static cpl_error_code
4622 detmon_opt_contamination(const cpl_imagelist * ons,
4623  const cpl_imagelist * offs,
4624  unsigned mode,
4625  cpl_propertylist * qclist)
4626 {
4627  struct rect {
4628  size_t llx;
4629  size_t lly;
4630  size_t urx;
4631  size_t ury;
4632  };
4633  struct rect rects[5] = {
4634  (struct rect){ detmon_lg_config.llx1,
4635  detmon_lg_config.lly1,
4636  detmon_lg_config.urx1,
4637  detmon_lg_config.ury1},
4638  (struct rect){ detmon_lg_config.llx2,
4639  detmon_lg_config.lly2,
4640  detmon_lg_config.urx2,
4641  detmon_lg_config.ury2},
4642  (struct rect){ detmon_lg_config.llx3,
4643  detmon_lg_config.lly3,
4644  detmon_lg_config.urx3,
4645  detmon_lg_config.ury3},
4646  (struct rect){ detmon_lg_config.llx4,
4647  detmon_lg_config.lly4,
4648  detmon_lg_config.urx4,
4649  detmon_lg_config.ury4},
4650  (struct rect){ detmon_lg_config.llx5,
4651  detmon_lg_config.lly5,
4652  detmon_lg_config.urx5,
4653  detmon_lg_config.ury5},
4654  };
4655 
4656  for (size_t i = 0; i < 5; i++) {
4657  cpl_image * dif_avg;
4658  const cpl_image * off2;
4659  double median;
4660  char kname[300];
4661  if (cpl_imagelist_get_size(offs) == 1 || mode & IRPLIB_LIN_COLLAPSE)
4662  off2 = cpl_imagelist_get_const(offs, 0);
4663  else
4664  off2 = cpl_imagelist_get_const(offs, 1);
4665 
4666  dif_avg = detmon_subtracted_avg(cpl_imagelist_get_const(ons, 0),
4667  cpl_imagelist_get_const(offs, 0),
4668  cpl_imagelist_get_const(ons, 1),
4669  off2,
4670  rects[i].llx,
4671  rects[i].lly,
4672  rects[i].urx,
4673  rects[i].ury);
4674 
4675  median = cpl_image_get_median(dif_avg);
4676  cpl_image_delete(dif_avg);
4677 
4678  skip_if(0);
4679  sprintf(kname, "%s%d", DETMON_QC_CONTAM, i + 1);
4680 
4681  if(cpl_propertylist_has(qclist,kname)){
4682  skip_if(cpl_propertylist_update_double(qclist,kname,median));
4683  } else {
4684  skip_if(cpl_propertylist_append_double(qclist,kname,median));
4685  skip_if(cpl_propertylist_set_comment(qclist,kname,DETMON_QC_CONTAM_C));
4686  }
4687  }
4688 
4689  end_skip;
4690 
4691  return cpl_error_get_code();
4692 }
4693 
4694 /*---------------------------------------------------------------------------*/
4701 /*---------------------------------------------------------------------------*/
4702 /*
4703 static cpl_error_code
4704 detmon_opt_lampcr(cpl_frameset * cur_fset, int ext)
4705 {
4706  cpl_image * on = NULL;
4707  cpl_image * off = NULL;
4708  cpl_frame * first_off = NULL;
4709  cpl_frame * first_on = NULL;
4710  cpl_propertylist * plist = NULL;
4711  double dit;
4712 
4713  cpl_ensure_code(cur_fset != NULL, CPL_ERROR_NULL_INPUT);
4714 
4715  skip_if((first_off = cpl_frameset_get_first(cur_fset)) == NULL);
4716  skip_if((first_on = cpl_frameset_get_next (cur_fset)) == NULL);
4717 
4718  on = cpl_image_load(cpl_frame_get_filename(first_on),
4719  CPL_TYPE_FLOAT, 0, ext);
4720  off = cpl_image_load(cpl_frame_get_filename(first_off),
4721  CPL_TYPE_FLOAT, 0, ext);
4722  skip_if(cpl_image_subtract(on, off));
4723 
4724  plist = cpl_propertylist_load(cpl_frame_get_filename(first_on), 0);
4725  skip_if(plist == NULL);
4726 
4727  dit = irplib_pfits_get_dit_opt(plist);
4728 
4729  detmon_lg_config.cr = cpl_image_get_mean(on) / dit;
4730 
4731  end_skip;
4732 
4733  cpl_image_delete(on);
4734  cpl_image_delete(off);
4735  cpl_propertylist_delete(plist);
4736 
4737  return cpl_error_get_code();
4738 }
4739 */
4740 /*---------------------------------------------------------------------------*/
4748 /*---------------------------------------------------------------------------*/
4749 int
4750 detmon_lg_dfs_set_groups(cpl_frameset * set,
4751  const char *tag_on, const char *tag_off)
4752 {
4753  cpl_frame *cur_frame;
4754  const char *tag;
4755  int nframes;
4756  int i;
4757 
4758  /* Check entries */
4759  if(set == NULL)
4760  return -1;
4761 
4762  /* Initialize */
4763  nframes = cpl_frameset_get_size(set);
4764 
4765  /* Loop on frames */
4766  for(i = 0; i < nframes; i++) {
4767  cur_frame = cpl_frameset_get_position(set, i);
4768  tag = cpl_frame_get_tag(cur_frame);
4769 
4770  /* RAW frames */
4771  if(!strcmp(tag, tag_on) || !strcmp(tag, tag_off))
4772  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_RAW);
4773  /* CALIB frames */
4774 
4775  /* else if (!strcmp(tag, IIINSTRUMENT_CALIB_FLAT))
4776  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_CALIB);
4777  */
4778  }
4779  return 0;
4780 }
4781 
4782 
4783 /*---------------------------------------------------------------------------*/
4791 /*---------------------------------------------------------------------------*/
4792 static cpl_error_code
4793 detmon_lg_fits_coeffs_and_bpm2chip(cpl_imagelist ** coeffs_ptr,
4794  cpl_image **bpms_ptr)
4795 {
4796  cpl_image* dummy_bpm=NULL;
4797  cpl_image * dummy_coeff=NULL;
4798  cpl_imagelist * dummy_coeffs=NULL;
4799  int * db_p=NULL;
4800  int * rb_p =NULL;
4801  float ** dcs_p;
4802  float ** rcs_p;
4803  int dlength=0;
4804  int rlength=0;
4805  int shift_idx=0;
4806  int i=0;
4807  int k=0;
4808  int j=0;
4809 
4810  dummy_bpm = cpl_image_new(detmon_lg_config.nx,
4811  detmon_lg_config.ny,
4812  CPL_TYPE_INT);
4813  dummy_coeffs = cpl_imagelist_new();
4814 
4815  db_p = cpl_image_get_data_int(dummy_bpm);
4816  rb_p = cpl_image_get_data_int(*bpms_ptr);;
4817  dcs_p = cpl_malloc(sizeof(float *) * (detmon_lg_config.order + 1));
4818  rcs_p = cpl_malloc(sizeof(float *) * (detmon_lg_config.order + 1));
4819  dlength = detmon_lg_config.nx;
4820  rlength = detmon_lg_config.urx - detmon_lg_config.llx + 1;
4821  for (i = 0; i <= detmon_lg_config.order; i++)
4822  {
4823  dummy_coeff = cpl_image_new(detmon_lg_config.nx,
4824  detmon_lg_config.ny,
4825  CPL_TYPE_FLOAT);
4826 
4827  cpl_imagelist_set(dummy_coeffs, dummy_coeff, i);
4828  dcs_p[i] = cpl_image_get_data_float(dummy_coeff);
4829  rcs_p[i] = cpl_image_get_data_float(cpl_imagelist_get(*coeffs_ptr, i));
4830  }
4831  /*copy the coefficients from temporary image to the dummy_bpm*/
4832  for (i = detmon_lg_config.lly - 1; i < detmon_lg_config.ury; i++)
4833  {
4834  for (j = detmon_lg_config.llx - 1; j < detmon_lg_config.urx; j++)
4835  {
4836  shift_idx=(i - detmon_lg_config.lly + 1) * rlength +
4837  j - detmon_lg_config.llx + 1;
4838  *(db_p + i * dlength + j) = *(rb_p + shift_idx);
4839  for (k = 0; k <= detmon_lg_config.order; k++)
4840  {
4841  *(dcs_p[k] + i * dlength + j) =
4842  *(rcs_p[k] + (i - detmon_lg_config.lly + 1) * rlength +
4843  j - detmon_lg_config.llx + 1);
4844  }
4845  }
4846  }
4847  cpl_imagelist_delete(*coeffs_ptr);
4848  cpl_image_delete(*bpms_ptr);
4849  *coeffs_ptr = dummy_coeffs;
4850  *bpms_ptr = dummy_bpm;
4851  cpl_free(dcs_p);
4852  cpl_free(rcs_p);
4853 
4854  return cpl_error_get_code();
4855 }
4856 
4857 /* Not used so we temporaryly comment it out
4858 static cpl_error_code
4859 detmon_lg_qclog_lin_coeff(cpl_imagelist* coeffs_ptr, const int order, cpl_propertylist* linc_qclist)
4860 {
4861  cpl_image* image=NULL;
4862  int i=0;
4863  double coeff=0;
4864  double * pcoeffs = cpl_malloc(sizeof(double)*(order + 1));
4865  char* name_o1=NULL;
4866  char* name_o2=NULL;
4867 
4868  for(i = 0; i <= order; i++)
4869  {
4870  image = cpl_imagelist_get(coeffs_ptr, i);
4871  coeff = cpl_image_get_median(image);
4872  pcoeffs[i] = coeff;
4873  name_o1 = cpl_sprintf("ESO QC LIN COEF%d", i);
4874  name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", i);
4875  assert(name_o1 != NULL);
4876  assert(name_o2 != NULL);
4877  cpl_propertylist_append_double(linc_qclist, name_o1, coeff);
4878  cpl_propertylist_set_comment(linc_qclist,name_o1,DETMON_QC_LIN_COEF_C);
4879  cpl_free(name_o1);
4880  name_o1= NULL;
4881  cpl_propertylist_append_double(linc_qclist, name_o2,cpl_image_get_stdev(image));
4882  cpl_propertylist_set_comment(linc_qclist,name_o2,DETMON_QC_LIN_COEF_ERR_C);
4883  cpl_free(name_o2);
4884  name_o2= NULL;
4885  }
4886  cpl_free(pcoeffs);
4887 
4888  return cpl_error_get_code();
4889 }
4890 */
4891 
4892 /*---------------------------------------------------------------------------*/
4906 /*---------------------------------------------------------------------------*/
4907 static cpl_error_code
4908 detmon_lg_reduce_all(const cpl_table * linear_table,
4909  cpl_propertylist * gaint_qclist,
4910  cpl_propertylist * lint_qclist,
4911  cpl_propertylist * linc_qclist,
4912  cpl_propertylist * bpm_qclist,
4913  cpl_imagelist ** coeffs_ptr,
4914  cpl_image ** bpms_ptr,
4915  const cpl_imagelist * linearity_inputs,
4916  const cpl_table * gain_table,
4917  int which_ext, cpl_boolean opt_nir)
4918 {
4919 
4920  int nbpixs = 0;
4921  const int nsets = cpl_table_get_nrow(linear_table);
4922  double autocorr;
4923  cpl_polynomial *poly_linfit = NULL;
4924  cpl_image *fiterror = NULL;
4925  char * name_o1 = NULL;
4926  char * name_o2 = NULL;
4927  double * pcoeffs = NULL;
4928  unsigned mode = detmon_lg_config.autocorr ? IRPLIB_GAIN_WITH_AUTOCORR : 0;
4929  double min_val=0;
4930  double max_val=0;
4931  cpl_vector *x =NULL;
4932  const cpl_vector *y =NULL;
4933 
4934 
4935  const cpl_image * first = NULL;
4936  int sizex = 0;
4937  int sizey = 0;
4938 
4939  int vsize = 0;
4940  cpl_size deg=0;
4941  /* FIXME: This should go before the x and y vectors.
4942  Checking for all the inputs */
4943  cpl_ensure_code(gaint_qclist != NULL, CPL_ERROR_NULL_INPUT);
4944  cpl_ensure_code(lint_qclist != NULL, CPL_ERROR_NULL_INPUT);
4945  cpl_ensure_code(linc_qclist != NULL, CPL_ERROR_NULL_INPUT);
4946  cpl_ensure_code(bpm_qclist != NULL, CPL_ERROR_NULL_INPUT);
4947 
4948  pcoeffs = cpl_malloc(sizeof(double)*(detmon_lg_config.order + 1));
4949 
4950  skip_if(cpl_propertylist_append_string(gaint_qclist, DETMON_QC_METHOD,
4951  detmon_lg_config.method));
4952  skip_if(cpl_propertylist_set_comment(gaint_qclist, DETMON_QC_METHOD,
4953  DETMON_QC_METHOD_C));
4954 
4955 
4956  if (!strcmp(detmon_lg_config.method, "PTC")) {
4957  /* Computation of GAIN via polynomial fit */
4958  if (detmon_lg_config.exts >= 0) {
4959  cpl_msg_info(cpl_func,
4960  "Polynomial fitting for the GAIN (constant term method)");
4961  } else {
4962  cpl_msg_info(cpl_func,
4963  "Polynomial fitting for the GAIN (constant term method)"
4964  " for extension nb %d", which_ext);
4965  }
4966  skip_if(detmon_lg_qc_ptc(gain_table, gaint_qclist, mode, nsets));
4967  } else {
4968  skip_if(detmon_lg_qc_med(gain_table, gaint_qclist, nsets));
4969  }
4970 
4971  /*^FIXME: This shouldn't be written when no applied */
4972  /* Lamp flux */
4973  if(detmon_lg_config.lamp_ok) {
4974  skip_if(cpl_propertylist_append_double(lint_qclist, DETMON_QC_LAMP_FLUX,
4975  detmon_lg_config.cr));
4976  skip_if(cpl_propertylist_set_comment(lint_qclist, DETMON_QC_LAMP_FLUX,
4977  DETMON_QC_LAMP_FLUX_C));
4978  }
4979 
4980  /*^FIXME: This shouldn't be written when no applied */
4981  if(detmon_lg_config.autocorr == TRUE) {
4982  autocorr = cpl_table_get_column_median(gain_table, "AUTOCORR");
4983  skip_if(cpl_propertylist_append_double(gaint_qclist, DETMON_QC_AUTOCORR,
4984  autocorr));
4985  skip_if(cpl_propertylist_set_comment(gaint_qclist, DETMON_QC_AUTOCORR,
4986  DETMON_QC_AUTOCORR_C));
4987  }
4988  if (detmon_lg_config.exts >= 0) {
4989  cpl_msg_info(cpl_func, "Polynomial fitting pix-to-pix");
4990  } else {
4991  cpl_msg_info(cpl_func, "Polynomial fitting pix-to-pix"
4992  " for extension nb %d", which_ext);
4993  }
4994 
4995  if(!detmon_lg_config.pix2pix) {
4996  double mse = 0;
4997  /* Computation of LINEARITY via polynomial fit */
4998  y = cpl_vector_wrap(nsets,
4999  (double *)cpl_table_get_data_double_const(linear_table,
5000  "MED"));
5001 
5002  if (opt_nir == NIR) {
5003  x = cpl_vector_wrap(nsets,
5004  (double *)cpl_table_get_data_double_const(linear_table,
5005  "DIT"));
5006  } else {
5007  x = cpl_vector_wrap(nsets,
5008  (double *)cpl_table_get_data_double_const(linear_table,
5009  "EXPTIME"));
5010  }
5011 
5012  if(x == NULL || y == NULL) {
5013  cpl_vector_unwrap((cpl_vector *)x);
5014  cpl_vector_unwrap((cpl_vector *)y);
5015  /*
5016  * As x and y are const vectors, if they would be defined at the
5017  * beginning of the function (required for skip_if - end_skip
5018  * scheme), they couldn't be initialised to NULL (required too).
5019  * Therefore, they are considered apart from the scheme.
5020  */
5021  skip_if(1);
5022  }
5023 
5024  cpl_msg_info(cpl_func, "Polynomial fitting for the LINEARITY");
5025  poly_linfit = irplib_polynomial_fit_1d_create(x, y,
5026  detmon_lg_config.order,
5027  &mse);
5028 
5029  if(detmon_lg_config.order == cpl_vector_get_size(x) - 1) {
5030  cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
5031  mse = 0;
5032  }
5033 
5034  if(poly_linfit == NULL) {
5035  cpl_vector_unwrap((cpl_vector *)x);
5036  cpl_vector_unwrap((cpl_vector *)y);
5037  /* See comment in previous error checking if() statement */
5038  skip_if(1);
5039  }
5040 
5041 
5042  min_val=cpl_vector_get_min(y);
5043  max_val=cpl_vector_get_max(y);
5044 
5045  cpl_vector_unwrap((cpl_vector *)x);
5046  cpl_vector_unwrap((cpl_vector *)y);
5047 
5048  for(deg = 0; deg <= detmon_lg_config.order; deg++) {
5049  const double coeff =
5050  cpl_polynomial_get_coeff(poly_linfit, &deg);
5051  char *name_o =
5052  cpl_sprintf("ESO QC LIN COEF%" CPL_SIZE_FORMAT "", deg);
5053  assert(name_o != NULL);
5054  skip_if(cpl_propertylist_append_double(lint_qclist, name_o, coeff));
5055  skip_if(cpl_propertylist_set_comment(lint_qclist,name_o,
5056  DETMON_QC_LIN_COEF_C));
5057 
5058  cpl_free(name_o);
5059  pcoeffs[deg] = coeff;
5060  }
5061  skip_if(cpl_propertylist_append_double(lint_qclist,DETMON_QC_ERRFIT, mse));
5062  skip_if(cpl_propertylist_set_comment(lint_qclist,DETMON_QC_ERRFIT,
5063  DETMON_QC_ERRFIT_MSE_C));
5064 
5065 
5066  } else {
5067  /* pix2pix == TRUE */
5068  y = cpl_vector_wrap(nsets,
5069  (double *)cpl_table_get_data_double_const(linear_table,
5070  "MED"));
5071 
5072  if (opt_nir == NIR)
5073  {
5074  x = cpl_vector_wrap(nsets,
5075  (double *)cpl_table_get_data_double_const(linear_table,
5076  "DIT"));
5077  } else {
5078  x = cpl_vector_wrap(nsets,
5079  (double *)cpl_table_get_data_double_const(linear_table,
5080  "EXPTIME"));
5081 
5082  }
5083 
5084  first = cpl_imagelist_get_const(linearity_inputs, 0);
5085  sizex = cpl_image_get_size_x(first);
5086  sizey = cpl_image_get_size_y(first);
5087  vsize = cpl_vector_get_size(x);
5088  fiterror = cpl_image_new(sizex, sizey, CPL_TYPE_FLOAT);
5089  *coeffs_ptr =
5090  cpl_fit_imagelist_polynomial(x, linearity_inputs, 0,
5091  detmon_lg_config.order, FALSE,
5092  CPL_TYPE_FLOAT, fiterror);
5093  min_val=cpl_vector_get_min(y);
5094  max_val=cpl_vector_get_max(y);
5095  cpl_vector_unwrap((cpl_vector*)x);
5096  cpl_vector_unwrap((cpl_vector*)y);
5097 
5098  irplib_ensure(*coeffs_ptr != NULL, CPL_ERROR_UNSPECIFIED,
5099  "Failed polynomial fit");
5100  //detmon_lg_qclog_lin_coeff(*coeffs_ptr, detmon_lg_config.order,linc_qclist);
5101 
5102  for(deg = 0; deg <= detmon_lg_config.order; deg++)
5103  {
5104  cpl_image *image = cpl_imagelist_get(*coeffs_ptr, deg);
5105  const double coeff = cpl_image_get_median(image);
5106  pcoeffs[deg] = coeff;
5107  name_o1 = cpl_sprintf("ESO QC LIN COEF%d", (int)deg);
5108  name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", (int)deg);
5109  assert(name_o1 != NULL);
5110  assert(name_o2 != NULL);
5111  skip_if(cpl_propertylist_append_double(linc_qclist, name_o1, coeff));
5112  skip_if(cpl_propertylist_set_comment(linc_qclist,name_o1,
5113  DETMON_QC_LIN_COEF_C));
5114  cpl_free(name_o1);
5115  name_o1= NULL;
5116  skip_if(cpl_propertylist_append_double(linc_qclist, name_o2,
5117  cpl_image_get_stdev(image)));
5118  skip_if(cpl_propertylist_set_comment(linc_qclist,name_o2,
5119  DETMON_QC_LIN_COEF_ERR_C));
5120  cpl_free(name_o2);
5121  name_o2= NULL;
5122  }
5123 
5124 
5125  if(detmon_lg_config.order == vsize - 1)
5126  {
5127  cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
5128  skip_if(cpl_propertylist_append_double(linc_qclist,DETMON_QC_ERRFIT,
5129  0.0));
5130  skip_if(cpl_propertylist_set_comment(linc_qclist,DETMON_QC_ERRFIT,
5131  DETMON_QC_ERRFIT_C));
5132  } else
5133  {
5134  skip_if(cpl_propertylist_append_double(linc_qclist,DETMON_QC_ERRFIT,
5135  cpl_image_get_median(fiterror)));
5136  skip_if(cpl_propertylist_set_comment(linc_qclist,DETMON_QC_ERRFIT,
5137  DETMON_QC_ERRFIT_C));
5138  }
5139  } /* end case pix2pix == TRUE */
5140 
5141  skip_if(cpl_propertylist_append_double(lint_qclist,DETMON_QC_COUNTS_MIN,
5142  min_val));
5143  skip_if(cpl_propertylist_set_comment(lint_qclist,DETMON_QC_COUNTS_MIN,
5144  DETMON_QC_COUNTS_MIN_C));
5145  skip_if(cpl_propertylist_append_double(lint_qclist,DETMON_QC_COUNTS_MAX,
5146  max_val));
5147  skip_if(cpl_propertylist_set_comment(lint_qclist,DETMON_QC_COUNTS_MAX,
5148  DETMON_QC_COUNTS_MAX_C));
5149  skip_if(detmon_lg_lineff(pcoeffs,lint_qclist,detmon_lg_config.ref_level,
5150  detmon_lg_config.order));
5151  /* Detection of bad pixels */
5152  if (detmon_lg_config.exts >= 0)
5153  {
5154  cpl_msg_info(cpl_func, "Bad pixel detection");
5155  } else
5156  {
5157  cpl_msg_info(cpl_func, "Bad pixel detection"
5158  " for extension nb %d", which_ext);
5159  }
5160  if(detmon_lg_config.pix2pix)
5161  {
5162 
5163  *bpms_ptr = detmon_bpixs(*coeffs_ptr, detmon_lg_config.bpmbin,
5164  detmon_lg_config.kappa, &nbpixs);
5165 
5166  /*
5167  *bpms_ptr = detmon_bpixs2(x,linearity_inputs,*coeffs_ptr,gain_table,
5168  detmon_lg_config.order,detmon_lg_config.bpmbin,detmon_lg_config.kappa,&nbpixs);
5169  */
5170  /*
5171  cpl_vector_unwrap((cpl_vector*)x);
5172  cpl_vector_unwrap((cpl_vector*)y);
5173  */
5174  skip_if(*bpms_ptr == NULL);
5175  /* we still have to unwrapp x & y that we kept for bpixs2 function */
5176  }
5177 
5178 
5179  skip_if(cpl_propertylist_append_int(bpm_qclist, DETMON_QC_NUM_BPM, nbpixs));
5180  skip_if(cpl_propertylist_set_comment(bpm_qclist, DETMON_QC_NUM_BPM,
5181  DETMON_QC_NUM_BPM_C));
5182  if(detmon_lg_config.lamp_stability != 0.0)
5183  {
5184  skip_if(cpl_propertylist_append_double(lint_qclist, DETMON_QC_LAMP_STAB,
5185  detmon_lg_config.lamp_stability));
5186  skip_if(cpl_propertylist_set_comment(lint_qclist, DETMON_QC_LAMP_STAB,
5187  DETMON_QC_LAMP_STAB_C));
5188  }
5189  /* Fit COEFFS_CUBE and BPM outputs to whole-chip size images (DFS05711) */
5190  if (!detmon_lg_config.wholechip && detmon_lg_config.pix2pix)
5191  {
5192  detmon_lg_fits_coeffs_and_bpm2chip(coeffs_ptr,bpms_ptr);
5193  }
5194  end_skip;
5195 
5196  cpl_free(pcoeffs);
5197  cpl_free(name_o1);
5198  cpl_free(name_o2);
5199  cpl_image_delete(fiterror);
5200  cpl_polynomial_delete(poly_linfit);
5201 
5202 
5203 
5204  return cpl_error_get_code();
5205 }
5206 
5207 /*---------------------------------------------------------------------------*/
5215 /*---------------------------------------------------------------------------*/
5216 static cpl_error_code
5217 detmon_lg_lineff(double * pcoeffs,
5218  cpl_propertylist * qclist,
5219  int ref_level,
5220  int order)
5221 {
5222  double lineff = 0;
5223  double root = 0;
5224  double residual, slope;
5225  int i;
5226  cpl_size deg=0;
5227  cpl_polynomial * poly = cpl_polynomial_new(1);
5228 
5229 
5230  /*
5231  * Construction of the polynomial F_m(F_r) from F_m(t),
5232  * using F_r = a_1 * t.
5233  */
5234  /*
5235  for (deg = 0; deg <= order; deg++) {
5236  cpl_msg_info(cpl_func,"coef[%d]=%g",deg,pcoeffs[deg]);
5237  }
5238  */
5239 
5240 
5241  pcoeffs[0] -= ref_level;
5242 
5243  for (i = 2; i <= order; i++)
5244  {
5245  int j;
5246  for(j = 0; j < i; j++)
5247  {
5248  pcoeffs[i] /= pcoeffs[1];
5249  }
5250  }
5251 
5252  pcoeffs[1] = 1;
5253 
5254  for (deg = 0; deg <= order; deg++) {
5255  /*cpl_msg_info(cpl_func,"coef[%d]=%g",deg,pcoeffs[deg]);*/
5256  skip_if(cpl_polynomial_set_coeff(poly, &deg, pcoeffs[deg]));
5257  }
5258 
5259  /*
5260  * Verification of validity of first guess (0).
5261  * The root to be found will be in the same interval of monotony
5262  * of the first guess; therefore, slope must be greater than 0.
5263  * Slope > 0 and poly(root) = 0 force also residual to be negative.
5264  */
5265  residual = cpl_polynomial_eval_1d(poly, 0.0, &slope);
5266 
5267  if (slope <= 0.0 && residual >= 0.0) {
5268  cpl_msg_warning(cpl_func, "Reference level (--ref_level) outside"
5269  " linearity range of the detector. Cannot compute"
5270  " linearity efficiency (QC.LINEFF).");
5271  lineff = -1;
5272  }
5273  else
5274  {
5275  cpl_error_code err = cpl_polynomial_solve_1d(poly, 0.0, &root, 1);
5276  /*
5277  cpl_msg_info(cpl_func,"root=%g ref_level=%d lin_eff=%d",
5278  root,ref_level,ref_level);
5279  */
5280  if (err == CPL_ERROR_NONE)
5281  {
5282 
5283  lineff = (root - ref_level) / ref_level;
5284  }
5285  else
5286  {
5287  cpl_error_reset();
5288  cpl_msg_warning(cpl_func,
5289  "Cannot compute linearity efficiency (QC.LINEFF)"
5290  "for the current combination "
5291  " of (--ref-level equal %d) and (--order equal %d) parameters. Try "
5292  "to decrease (--ref-level) value.", ref_level, order);
5293  }
5294  }
5295  cpl_msg_warning(cpl_func, "DETMON_QC_LIN_EFF=%f",lineff );
5296  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LIN_EFF,
5297  lineff));
5298  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LIN_EFF,
5299  DETMON_QC_LIN_EFF_C));
5300 
5301  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LIN_EFF_FLUX,
5302  ref_level));
5303  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LIN_EFF_FLUX,
5304  DETMON_QC_LIN_EFF_FLUX_C));
5305 
5306  end_skip;
5307 
5308  cpl_polynomial_delete(poly);
5309 
5310  return cpl_error_get_code();
5311 }
5312 
5313 /*---------------------------------------------------------------------------*/
5320 /*---------------------------------------------------------------------------*/
5321 static cpl_error_code
5322 detmon_lg_qc_ptc(const cpl_table * gain_table,
5323  cpl_propertylist * qclist, unsigned mode, int rows_in_gain)
5324 {
5325  double mse = 0;
5326  cpl_polynomial *poly_fit = NULL;
5327  cpl_polynomial *poly_fit2 = NULL;
5328  cpl_size i;
5329  const int nsets = rows_in_gain;
5330 
5331  cpl_vector *x = NULL;
5332  cpl_vector *y = NULL;
5333 
5334  cpl_errorstate prestate;
5335  double coef = 0;
5336  cpl_ensure_code(gain_table != NULL, CPL_ERROR_NULL_INPUT);
5337  cpl_ensure_code(qclist != NULL, CPL_ERROR_NULL_INPUT);
5338 
5339  x = cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT"));
5340 
5341  y = cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
5342 
5343  skip_if(x == NULL || y == NULL);
5344  if (0 == detmon_lg_check_before_gain(x, y))
5345  {
5346  if (x)
5347  {
5348  cpl_vector_unwrap(x);
5349  }
5350  if (y)
5351  {
5352  cpl_vector_unwrap(y);
5353  }
5354  return CPL_ERROR_NONE;
5355  }
5356  /*it is not really a MSE, but chi square of the fit, see cpl_vector_fill_polynomial_fit_residual for details*/
5357  poly_fit = irplib_polynomial_fit_1d_create_chiq(x, y, 1, &mse);
5358  skip_if(poly_fit == NULL);
5359 
5360  /* Write the QC params corresponding to the fitting of the GAIN */
5361  i = 1;
5362  prestate = cpl_errorstate_get();
5363  coef = cpl_polynomial_get_coeff(poly_fit, &i);
5364  skip_if (!cpl_errorstate_is_equal(prestate) || coef==0);
5365  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD, coef));
5366  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD,
5367  DETMON_QC_CONAD_C));
5368  if (coef != 0)
5369  {
5370  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN,
5371  1 / coef));
5372  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN,
5373  DETMON_QC_GAIN_C));
5374  }
5375  /* MSE is removed - see DFS07358 for details
5376  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_MSE, mse));
5377  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_MSE,
5378  DETMON_QC_GAIN_MSE_C));
5379  */
5380  i = 0;
5381  /* QC.RON computation is disabled, see DFS05852 for details*/
5382 
5383  /* * skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_RON,
5384  cpl_polynomial_get_coeff(poly_fit, &i)));
5385  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_RON,
5386  DETMON_QC_RON_C));
5387  */
5388  if(mode & IRPLIB_GAIN_WITH_AUTOCORR){
5389  const cpl_vector *x2 =
5390  cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT_CORR"));
5391  const cpl_vector *y2 =
5392  cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
5393 
5394  if(x2 == NULL || y2 == NULL) {
5395  cpl_vector_unwrap((cpl_vector *)x2);
5396  cpl_vector_unwrap((cpl_vector *)y2);
5397  /*
5398  * As x and y are const vectors, if they would be defined at the
5399  * beginning of the function (required for skip_if - end_skip
5400  * scheme), they couldn't be initialised to NULL (required too).
5401  * Therefore, they are considered apart from the scheme.
5402  */
5403  skip_if(1);
5404  }
5405 
5406  /* Revise mse, maybe used afterwards */
5407  poly_fit2 = irplib_polynomial_fit_1d_create(x2, y2, 1, &mse);
5408  if(poly_fit2 == NULL) {
5409  cpl_vector_unwrap((cpl_vector *)x2);
5410  cpl_vector_unwrap((cpl_vector *)y2);
5411 
5412  cpl_msg_error(cpl_func, "Error during polynomial fit, err[%s]", cpl_error_get_where());
5413  /* See comment in previous error checking if() statement */
5414  skip_if(1);
5415  }
5416  skip_if(cpl_error_get_code() != CPL_ERROR_NONE);
5417  cpl_vector_unwrap((cpl_vector *)x2);
5418  cpl_vector_unwrap((cpl_vector *)y2);
5419  skip_if(cpl_error_get_code() != CPL_ERROR_NONE);
5420  /* Write the QC params corresponding to the fitting of the GAIN */
5421  i = 1;
5422  prestate = cpl_errorstate_get();
5423  coef = cpl_polynomial_get_coeff(poly_fit2, &i);
5424  skip_if(cpl_error_get_code() != CPL_ERROR_NONE);
5425  skip_if (!cpl_errorstate_is_equal(prestate) || coef == 0);
5426 
5427  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD_CORR,
5428  coef));
5429  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD_CORR,
5430  DETMON_QC_CONAD_CORR_C));
5431 
5432  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_CORR,
5433  1 / coef));
5434  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_CORR,
5435  DETMON_QC_GAIN_CORR_C));
5436  }
5437 
5438  end_skip;
5439 
5440  /*cleanup*/
5441  cpl_vector_unwrap(x);
5442  cpl_vector_unwrap(y);
5443  cpl_polynomial_delete(poly_fit);
5444  cpl_polynomial_delete(poly_fit2);
5445 
5446  return cpl_error_get_code();
5447 }
5448 
5455 static int detmon_lg_check_before_gain(const cpl_vector* x, const cpl_vector* y)
5456 {
5457  const double TOLERANCE = 1e-37;/*MINDOUBLE is not everywhere defined (Mac);*/
5458  double xmin = cpl_vector_get_min(x);
5459  double xmax = cpl_vector_get_max(x);
5460  double ymin = cpl_vector_get_min(y);
5461  double ymax = cpl_vector_get_max(y);
5462  double ystdev = cpl_vector_get_stdev(y);
5463  double xstdev = cpl_vector_get_stdev(x);
5464  int retval = 1;
5465  if (fabs(xmax-xmin) < TOLERANCE &&
5466  fabs(ymax - ymin) < TOLERANCE &&
5467  xstdev < TOLERANCE &&
5468  ystdev < TOLERANCE)
5469  {
5470  cpl_msg_warning(cpl_func, "An empty frame has been detected, linearity, coeffs, gain, FPN values will not be computed.");
5471  retval = 0;
5472  }
5473  return retval;
5474 }
5475 /*---------------------------------------------------------------------------*/
5484 /*---------------------------------------------------------------------------*/
5485 static cpl_error_code
5486 detmon_lg_qc_med(const cpl_table * gain_table,
5487  cpl_propertylist * qclist, int rows_in_gain)
5488 {
5489 
5490  double gain=0;
5491  cpl_vector *x = NULL;
5492  cpl_vector *y = NULL;
5493  int check_result = 0;
5494 
5495  if (rows_in_gain) {/* silence unused var */};
5496 
5497  x = cpl_vector_wrap(rows_in_gain, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT"));
5498  y = cpl_vector_wrap(rows_in_gain, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
5499  check_result = detmon_lg_check_before_gain(x, y);
5500  if (x)
5501  {
5502  cpl_vector_unwrap(x);
5503  }
5504  if (y)
5505  {
5506  cpl_vector_unwrap(y);
5507  }
5508  if (0 == check_result)
5509  {
5510  return CPL_ERROR_NONE;
5511  }
5512 
5513  gain=cpl_table_get_column_median(gain_table, "GAIN");
5514 
5515  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN,gain));
5516 
5517  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN,
5518  DETMON_QC_GAIN_C));
5519 
5520  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_MSE,
5521  cpl_table_get_column_stdev
5522  (gain_table, "GAIN")));
5523  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_MSE,
5524  DETMON_QC_GAIN_MSE_C));
5525 
5526  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD,1./gain));
5527  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD,
5528  DETMON_QC_CONAD_C));
5529 
5530 
5531  gain=cpl_table_get_column_median(gain_table, "GAIN_CORR");
5532 
5533  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_CORR,
5534  gain));
5535  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_CORR,
5536  DETMON_QC_GAIN_CORR_C));
5537 
5538 
5539  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD_CORR,1./gain));
5540  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD_CORR,
5541  DETMON_QC_CONAD_CORR_C));
5542 
5543 
5544  end_skip;
5545 
5546  return cpl_error_get_code();
5547 }
5548 
5549 
5550 /*---------------------------------------------------------------------------*/
5559 /*---------------------------------------------------------------------------*/
5560 static cpl_error_code
5561 detmon_lg_rescale(cpl_imagelist * to_rescale)
5562 {
5563  double med1 =
5564  cpl_image_get_median_window(cpl_imagelist_get(to_rescale, 0),
5565  detmon_lg_config.llx,
5566  detmon_lg_config.lly,
5567  detmon_lg_config.urx,
5568  detmon_lg_config.ury);
5569  double med2 =
5570  cpl_image_get_median_window(cpl_imagelist_get(to_rescale, 1),
5571  detmon_lg_config.llx,
5572  detmon_lg_config.lly,
5573  detmon_lg_config.urx,
5574  detmon_lg_config.ury);
5575 
5576  skip_if(0);
5577 
5578  if(fabs(med1 / med2 - 1) > 0.001) {
5579  if(med1 > med2)
5580  skip_if(cpl_image_divide_scalar(cpl_imagelist_get(to_rescale, 0),
5581  med1 / med2));
5582  else
5583  skip_if(cpl_image_divide_scalar(cpl_imagelist_get(to_rescale, 1),
5584  med2 / med1));
5585  }
5586 
5587  end_skip;
5588 
5589  return cpl_error_get_code();
5590 }
5591 
5592 static cpl_error_code
5593 detmon_pair_extract_next(const cpl_frameset * set,
5594  int* iindex,
5595  int* next_element,
5596  double* dit_array,
5597  cpl_frameset ** pair,
5598  double tolerance) /* detmon_lg_config.tolerance */
5599 {
5600  double dit = -100;
5601  double dit_next = -100;
5602  cpl_size* selection;
5603  int nsets_extracted = 0;
5604  cpl_ensure_code(set != NULL, CPL_ERROR_NULL_INPUT);
5605  cpl_ensure_code(dit_array != NULL, CPL_ERROR_NULL_INPUT);
5606  cpl_ensure_code(iindex != NULL, CPL_ERROR_NULL_INPUT);
5607  cpl_ensure_code(pair != NULL, CPL_ERROR_NULL_INPUT);
5608 
5609  nsets_extracted = cpl_frameset_get_size(set);
5610  selection = cpl_malloc(sizeof(cpl_size) * nsets_extracted);
5611  memset(&selection[0], 0, sizeof(cpl_size) * nsets_extracted);
5612 
5613 
5614  dit = dit_array[*next_element ];
5615  /* cpl_msg_info(cpl_func, "%d: dit %f",*next_element, dit ); */
5616  if (*next_element < nsets_extracted - 1)
5617  {
5618  dit_next = dit_array[*next_element + 1 ];
5619  /* cpl_msg_info(cpl_func, "%d: dit %f",*next_element + 1, dit_next ); */
5620  }
5621  /* one element would be returned always */
5622  selection[iindex[*next_element] ] = 1;
5623  if (fabs(dit - dit_next) < tolerance)
5624  {
5625  /* return a second element of the pair */
5626  selection[iindex[*next_element + 1] ] = 1;
5627  (*next_element)++;
5628  }
5629  else
5630  {
5631  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);
5632  }
5633  (*next_element)++;
5634  /* prepare frameset */
5635  cpl_frameset_delete(*pair);
5636  *pair = cpl_frameset_extract(set, selection, 1);
5637 
5638 
5639  cpl_free(selection);
5640  return cpl_error_get_code();
5641 }
5642 
5643 static cpl_error_code
5644 detmon_single_extract_next(const cpl_frameset * set,
5645  int* iindex,
5646  int* next_element,
5647  double* dit_array,
5648  cpl_frameset ** pair)
5649 {
5650  cpl_size* selection;
5651  int nsets_extracted = 0;
5652  cpl_ensure_code(set != NULL, CPL_ERROR_NULL_INPUT);
5653  cpl_ensure_code(dit_array != NULL, CPL_ERROR_NULL_INPUT);
5654  cpl_ensure_code(iindex != NULL, CPL_ERROR_NULL_INPUT);
5655  cpl_ensure_code(pair != NULL, CPL_ERROR_NULL_INPUT);
5656 
5657  nsets_extracted = cpl_frameset_get_size(set);
5658  selection = cpl_malloc(sizeof(cpl_size) * nsets_extracted);
5659  memset(&selection[0], 0, sizeof(cpl_size) * nsets_extracted);
5660 
5661  /* only one element would be returned */
5662  selection[iindex[*next_element] ] = 1;
5663  (*next_element)++;
5664  /* prepare frameset */
5665  cpl_frameset_delete(*pair);
5666  *pair = cpl_frameset_extract(set, selection, 1);
5667 
5668  cpl_free(selection);
5669  return cpl_error_get_code();
5670 }
5671 
5672 
5673 /*---------------------------------------------------------------------------*/
5762 /*---------------------------------------------------------------------------*/
5763 
5764 cpl_table *
5765 detmon_gain(const cpl_imagelist * imlist_on,
5766  const cpl_imagelist * imlist_off,
5767  const cpl_vector * exptimes,
5768  const cpl_vector * ndit,
5769  double tolerance,
5770  int llx,
5771  int lly,
5772  int urx,
5773  int ury,
5774  double kappa,
5775  int nclip,
5776  int xshift,
5777  int yshift,
5778  cpl_propertylist * qclist,
5779  unsigned mode,
5780  cpl_imagelist ** diff_imlist,
5781  cpl_imagelist ** autocorr_imlist)
5782 {
5783  cpl_table * gain_table = NULL;
5784  cpl_imagelist * difflist = NULL;
5785  cpl_imagelist * autocorrlist = NULL;
5786  cpl_imagelist * c_onlist = NULL;
5787  cpl_imagelist * c_offlist = NULL;
5788  cpl_vector * diffdits = NULL;
5789  cpl_vector * diffndits = NULL;
5790  int rows_in_gain = 0;
5791  int ndiffdits, ndits;
5792  int i, j;
5793  cpl_boolean opt_nir = mode & IRPLIB_GAIN_OPT ? OPT : NIR;
5794  const char * method = mode & IRPLIB_GAIN_PTC ? "PTC" : "MED";
5795 
5796  cpl_ensure(imlist_on != NULL, CPL_ERROR_NULL_INPUT, NULL);
5797  cpl_ensure(imlist_off != NULL, CPL_ERROR_NULL_INPUT, NULL);
5798  cpl_ensure(exptimes != NULL, CPL_ERROR_NULL_INPUT, NULL);
5799  cpl_ensure(qclist != NULL, CPL_ERROR_NULL_INPUT, NULL);
5800 
5801  /* Create table with columns */
5802  gain_table = cpl_table_new(cpl_vector_get_size(exptimes) / 2);
5803  skip_if(detmon_gain_table_create(gain_table, opt_nir));
5804 
5805 
5806  /* Search for different EXPTIME values */
5807  skip_if(detmon_lg_find_dits_ndits(exptimes, ndit,tolerance,&diffdits,
5808  &diffndits));
5809  ndiffdits = cpl_vector_get_size(diffdits);
5810 
5811  ndits = cpl_vector_get_size(exptimes);
5812 
5813  /* AUTOCORR processing requires both. They will become outputs later. */
5814  if (mode & IRPLIB_GAIN_WITH_AUTOCORR && (diff_imlist || autocorr_imlist)) {
5815  difflist = cpl_imagelist_new();
5816  autocorrlist = cpl_imagelist_new();
5817  }
5818 
5819  if (mode & IRPLIB_GAIN_COLLAPSE) {
5820  if (mode & IRPLIB_GAIN_WITH_RESCALE) {
5821  c_offlist = cpl_imagelist_duplicate(imlist_off);
5822  skip_if(detmon_lg_rescale(c_offlist));
5823  } else {
5824  c_offlist = (cpl_imagelist *) imlist_off;
5825  }
5826  }
5827 
5828  /* Loop over the different DITs found in EXPTIMEs */
5829  for (i = 0; i < ndiffdits; i++) {
5830  int c_nons;
5831  int c_noffs = 0; /* False (uninit) warning */
5832 
5833  double c_dit = 0;
5834  int c_ndit = 1;
5835 
5836  c_dit=cpl_vector_get(diffdits, i);
5837 
5838  if(opt_nir) {
5839  c_ndit=(int)cpl_vector_get(diffndits, i);
5840  }
5841 
5842  c_onlist = cpl_imagelist_new();
5843  c_nons = 0;
5844 
5845  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
5846  c_offlist = cpl_imagelist_new();
5847  c_noffs = 0;
5848  }
5849 
5850  /* Extraction of images of EXPTIME i */
5851  for(j = 0; j < ndits; j++) {
5852  if (fabs(c_dit - cpl_vector_get(exptimes, j)) <= tolerance) {
5853  /*
5854  * First we get the corresponding image from the ON imlist.
5855  * The option IRPLIB_GAIN_WITH_RESCALE requires to modify
5856  * the input pixel buffer; therefore we must duplicate it.
5857  * On the other hand, if this option is not required, there
5858  * is no need for that duplication. We must only care that
5859  * c_onlist must not be deleted but only unset.
5860  */
5861  cpl_image * im_on;
5862  if (mode & IRPLIB_GAIN_WITH_RESCALE) {
5863  const cpl_image * im =
5864  cpl_imagelist_get_const(imlist_on, j);
5865  im_on = cpl_image_duplicate(im);
5866  } else {
5867  im_on = (cpl_image *)cpl_imagelist_get_const(imlist_on, j);
5868  }
5869  skip_if(cpl_imagelist_set(c_onlist, im_on, c_nons));
5870  c_nons++;
5871 
5872  /*
5873  * Same explanation as above but for OFF imlist.
5874  * Only necessary when IRPLIB_GAIN_NO_COLLAPSE required.
5875  */
5876  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
5877  cpl_image * im_off;
5878  if (mode & IRPLIB_GAIN_WITH_RESCALE) {
5879  const cpl_image * im =
5880  cpl_imagelist_get_const(imlist_off, j);
5881  im_off = cpl_image_duplicate(im);
5882  } else {
5883  im_off =
5884  (cpl_image *) cpl_imagelist_get_const(imlist_off, j);
5885  }
5886  skip_if(cpl_imagelist_set(c_offlist, im_off, c_noffs));
5887  c_noffs++;
5888  }
5889  }
5890  }
5891 
5892  /* If NO_COLLAPSE, must be the same number of images! */
5893  if (mode & IRPLIB_GAIN_NO_COLLAPSE)
5894  skip_if (c_nons != c_noffs);
5895 
5896  /* There must be pairs! */
5897  skip_if (c_nons == 0 || c_nons % 2 != 0);
5898 
5899  /* Rescaling */
5900  if(mode & IRPLIB_GAIN_WITH_RESCALE) {
5901  skip_if(detmon_lg_rescale(c_onlist));
5902  if (mode & IRPLIB_GAIN_NO_COLLAPSE)
5903  skip_if(detmon_lg_rescale(c_offlist));
5904  }
5905 
5906  /* The following loop is necessary for the case of multiple pairs
5907  of same EXPTIME values */
5908  while(c_nons > 0) {
5909  int rows_affected = 1;
5910  skip_if(detmon_gain_table_fill_row(gain_table,
5911  c_dit,c_ndit,
5912  autocorrlist,
5913  difflist, c_onlist,
5914  c_offlist, kappa, nclip,
5915  llx, lly, urx, ury,
5916  xshift, yshift,1E10, i,
5917  mode, &rows_affected));
5918  if (rows_affected)
5919  {
5920  rows_in_gain++;
5921  }
5922  if (mode & IRPLIB_GAIN_WITH_RESCALE) {
5923  cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
5924  cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
5925  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
5926  cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
5927  cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
5928  }
5929  } else {
5930  cpl_imagelist_unset(c_onlist, 0);
5931  skip_if(0);
5932  cpl_imagelist_unset(c_onlist, 0);
5933  skip_if(0);
5934  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
5935  cpl_imagelist_unset(c_offlist, 0);
5936  skip_if(0);
5937  cpl_imagelist_unset(c_offlist, 0);
5938  skip_if(0);
5939  }
5940  }
5941  skip_if(0);
5942  c_nons -= 2;
5943  }
5944 
5945  cpl_imagelist_delete(c_onlist);
5946  if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
5947  cpl_imagelist_delete(c_offlist);
5948  }
5949  }
5950 
5951  skip_if(cpl_propertylist_append_string(qclist, DETMON_QC_METHOD, method));
5952  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_METHOD,
5953  DETMON_QC_METHOD_C));
5954 
5955  /* Computation of GAIN via polynomial fit */
5956  if (mode & IRPLIB_GAIN_PTC) {
5957  skip_if(detmon_lg_qc_ptc(gain_table, qclist, mode, rows_in_gain));
5958  } else {
5959  skip_if(detmon_lg_qc_med(gain_table, qclist, rows_in_gain));
5960  }
5961 
5962  if(mode & IRPLIB_GAIN_WITH_AUTOCORR) {
5963  double autocorr = cpl_table_get_column_median(gain_table, "AUTOCORR");
5964  skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_AUTOCORR,
5965  autocorr));
5966  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_AUTOCORR,
5967  DETMON_QC_AUTOCORR_C));
5968  }
5969 
5970  if (diff_imlist != NULL) *diff_imlist = difflist;
5971  if (autocorr_imlist != NULL) *autocorr_imlist = autocorrlist;
5972 
5973  end_skip;
5974 
5975  cpl_vector_delete(diffdits);
5976  cpl_vector_delete(diffndits);
5977 
5978  return gain_table;
5979 }
5980 
5981 static cpl_error_code
5982 detmon_gain_table_create(cpl_table * gain_table,
5983  const cpl_boolean opt_nir)
5984 {
5985  if (opt_nir == NIR) {
5986  skip_if(cpl_table_new_column(gain_table, "DIT", CPL_TYPE_DOUBLE));
5987  skip_if(cpl_table_new_column(gain_table, "NDIT", CPL_TYPE_INT));
5988  } else { /* OPT */
5989  skip_if(cpl_table_new_column(gain_table, "EXPTIME", CPL_TYPE_DOUBLE));
5990  }
5991  skip_if(cpl_table_new_column(gain_table, "MEAN_ON1", CPL_TYPE_DOUBLE));
5992  skip_if(cpl_table_new_column(gain_table, "MEAN_ON2", CPL_TYPE_DOUBLE));
5993  skip_if(cpl_table_new_column(gain_table, "MEAN_OFF1", CPL_TYPE_DOUBLE));
5994  skip_if(cpl_table_new_column(gain_table, "MEAN_OFF2", CPL_TYPE_DOUBLE));
5995  skip_if(cpl_table_new_column(gain_table, "SIG_ON_DIF", CPL_TYPE_DOUBLE));
5996  skip_if(cpl_table_new_column(gain_table, "SIG_OFF_DIF", CPL_TYPE_DOUBLE));
5997  skip_if(cpl_table_new_column(gain_table, "GAIN", CPL_TYPE_DOUBLE));
5998  skip_if(cpl_table_new_column(gain_table, "AUTOCORR", CPL_TYPE_DOUBLE));
5999  skip_if(cpl_table_new_column(gain_table, "GAIN_CORR", CPL_TYPE_DOUBLE));
6000  skip_if(cpl_table_new_column(gain_table, "ADU", CPL_TYPE_DOUBLE));
6001  skip_if(cpl_table_new_column(gain_table, "X_FIT", CPL_TYPE_DOUBLE));
6002  skip_if(cpl_table_new_column(gain_table, "X_FIT_CORR", CPL_TYPE_DOUBLE));
6003  skip_if(cpl_table_new_column(gain_table, "Y_FIT", CPL_TYPE_DOUBLE));
6004  skip_if(cpl_table_new_column(gain_table, "Y_FIT_CORR", CPL_TYPE_DOUBLE));
6005  skip_if(cpl_table_new_column(gain_table, "FLAG", CPL_TYPE_INT));
6006 
6007  end_skip;
6008 
6009  return cpl_error_get_code();
6010 }
6011 
6012 static cpl_error_code
6013 detmon_lin_table_create(cpl_table * lin_table,
6014  const cpl_boolean opt_nir)
6015 {
6016  if (opt_nir == NIR) {
6017  skip_if(cpl_table_new_column(lin_table, "DIT", CPL_TYPE_DOUBLE));
6018  } else { /* OPT */
6019  skip_if(cpl_table_new_column(lin_table, "EXPTIME", CPL_TYPE_DOUBLE));
6020  }
6021  skip_if(cpl_table_new_column(lin_table, "MED", CPL_TYPE_DOUBLE));
6022  skip_if(cpl_table_new_column(lin_table, "MEAN", CPL_TYPE_DOUBLE));
6023  skip_if(cpl_table_new_column(lin_table, "MED_DIT", CPL_TYPE_DOUBLE));
6024  skip_if(cpl_table_new_column(lin_table, "MEAN_DIT", CPL_TYPE_DOUBLE));
6025  skip_if(cpl_table_new_column(lin_table, "ADL", CPL_TYPE_DOUBLE));
6026  end_skip;
6027 
6028  return cpl_error_get_code();
6029 }
6030 
6031 static cpl_vector *
6032 detmon_lg_find_dits(const cpl_vector * exptimes,
6033  double tolerance)
6034 {
6035  cpl_vector * dits = cpl_vector_new(cpl_vector_get_size(exptimes) / 2);
6036  int ndits = 0;
6037 
6038  int i, j;
6039 
6040  /* First different EXPTIME */
6041  cpl_vector_set(dits, 0, cpl_vector_get(exptimes, 0));
6042  ndits = 1;
6043 
6044  /* Search for all different EXPTIMEs */
6045  for(i = 1; i < cpl_vector_get_size(exptimes); i++) {
6046  int ndiffs = 0;
6047  for (j = 0; j < ndits; j++) {
6048  if (fabs(cpl_vector_get(exptimes, i) -
6049  cpl_vector_get(dits, j)) > tolerance)
6050  ndiffs++;
6051  }
6052  if(ndiffs == ndits) {
6053  cpl_vector_set(dits, ndits, cpl_vector_get(exptimes, i));
6054  ndits++;
6055  }
6056  }
6057 
6058  cpl_vector_set_size(dits, ndits);
6059 
6060  return dits;
6061 }
6062 
6063 
6064 
6065 
6066 static cpl_error_code
6067 detmon_lg_find_dits_ndits(const cpl_vector * exptimes,
6068  const cpl_vector * vec_ndits,
6069  double tolerance,
6070  cpl_vector** diff_dits,
6071  cpl_vector** diff_ndits)
6072 {
6073  int ndits = 0;
6074 
6075  int i, j;
6076  int size=0;
6077 
6078 
6079  * diff_dits = cpl_vector_new(cpl_vector_get_size(exptimes) / 2);
6080  * diff_ndits = cpl_vector_new(cpl_vector_get_size(*diff_dits));
6081 
6082  /* First different EXPTIME */
6083  cpl_vector_set(*diff_dits, 0, cpl_vector_get(exptimes, 0));
6084  cpl_vector_set(*diff_ndits, 0, cpl_vector_get(vec_ndits, 0));
6085 
6086  ndits = 1;
6087  size=cpl_vector_get_size(exptimes);
6088  /* Search for all different EXPTIMEs */
6089  for(i = 1; i < size; i++) {
6090  int ndiffs = 0;
6091  for (j = 0; j < ndits; j++) {
6092  if (fabs(cpl_vector_get(exptimes, i) -
6093  cpl_vector_get(*diff_dits,j)) > tolerance)
6094  ndiffs++;
6095  }
6096  if(ndiffs == ndits) {
6097  cpl_vector_set(*diff_dits, ndits, cpl_vector_get(exptimes, i));
6098  cpl_vector_set(*diff_ndits, ndits, cpl_vector_get(vec_ndits, i));
6099  ndits++;
6100  }
6101  }
6102 
6103  cpl_vector_set_size(*diff_dits, ndits);
6104  cpl_vector_set_size(*diff_ndits, ndits);
6105 
6106 
6107  return cpl_error_get_code();
6108 }
6109 
6110 
6111 /*---------------------------------------------------------------------------*/
6192 /*---------------------------------------------------------------------------*/
6193 
6194 cpl_table *
6195 detmon_lin(const cpl_imagelist * imlist_on,
6196  const cpl_imagelist * imlist_off,
6197  const cpl_vector * exptimes,
6198  double tolerance,
6199  int llx,
6200  int lly,
6201  int urx,
6202  int ury,
6203  int order,
6204  int ref_level,
6205  double kappa,
6206  cpl_boolean bpmbin,
6207  cpl_propertylist * qclist,
6208  unsigned mode,
6209  cpl_imagelist ** coeffs_cube,
6210  cpl_image ** bpm)
6211 {
6212  cpl_table * lin_table = NULL;
6213  cpl_imagelist * c_onlist = NULL;
6214  cpl_imagelist * c_offlist = NULL;
6215  cpl_vector * diffdits = NULL;
6216  cpl_imagelist * lin_inputs = NULL;
6217  cpl_polynomial * poly_linfit = NULL;
6218  cpl_image * fiterror = NULL;
6219  cpl_vector * vcoeffs = NULL;
6220  double * pcoeffs = NULL;
6221  int ndiffdits, ndits;
6222  int i, j;
6223  cpl_boolean opt_nir = mode & IRPLIB_LIN_OPT ? OPT : NIR;
6224  const cpl_vector *x = NULL;
6225  const cpl_vector *y = NULL;
6226 
6227  const cpl_image * first = NULL;
6228  int sizex = 0;
6229  int sizey = 0;
6230 
6231  cpl_size deg;
6232  double vsize = 0;
6233 
6234 
6235  cpl_ensure(imlist_on != NULL, CPL_ERROR_NULL_INPUT, NULL);
6236  cpl_ensure(imlist_off != NULL, CPL_ERROR_NULL_INPUT, NULL);
6237  cpl_ensure(exptimes != NULL, CPL_ERROR_NULL_INPUT, NULL);
6238  cpl_ensure(qclist != NULL, CPL_ERROR_NULL_INPUT, NULL);
6239  cpl_ensure(order > 0 , CPL_ERROR_ILLEGAL_INPUT, NULL);
6240 
6241  vcoeffs = cpl_vector_new(order + 1);
6242  pcoeffs = cpl_vector_get_data(vcoeffs);
6243 
6244  /* This mode requires optional outputs */
6245  if (mode & IRPLIB_LIN_PIX2PIX) {
6246  cpl_ensure(coeffs_cube != NULL, CPL_ERROR_NULL_INPUT, NULL);
6247  cpl_ensure(bpm != NULL, CPL_ERROR_NULL_INPUT, NULL);
6248  lin_inputs = cpl_imagelist_new();
6249  }
6250 
6251  /* Create table with columns */
6252  lin_table = cpl_table_new(cpl_vector_get_size(exptimes) / 2);
6253  skip_if(detmon_lin_table_create(lin_table, opt_nir));
6254 
6255  /* Search for different EXPTIME values */
6256  /* Search for different EXPTIME values */
6257  diffdits = detmon_lg_find_dits(exptimes, tolerance);
6258  ndiffdits = cpl_vector_get_size(diffdits);
6259 
6260  ndits = cpl_vector_get_size(exptimes);
6261 
6262 
6263 
6264 
6265 
6266 
6267  /* TO BE IMPLEMENTED SIMILARLY TO UPPER LEVEL FUNCTION (search for nskip)
6268  if(filter > 0) {
6269  double med1 =
6270  cpl_image_get_median_window(cpl_imagelist_get(imlist_on, 0),
6271  llx,lly,urx,ury);
6272  double med2 =
6273  cpl_image_get_median_window(cpl_imagelist_get(imlist_on, 1),
6274  llx,lly,urx,ury);
6275  if ( med1 > (double)filter ||
6276  med2 > (double)filter) {
6277  follow = CPL_FALSE;
6278  cpl_table_select_row(lin_table, dit_nb);
6279  dit_nskip++;
6280  cpl_msg_warning(cpl_func, "Frames of EXPTIME nb %d "
6281  "will not be taken into account for computation "
6282  "as they are above --filter threshold", dit_nb);
6283  }
6284  }
6285  */
6286 
6287 
6288 
6289 
6290  if (mode & IRPLIB_LIN_COLLAPSE) {
6291  /*
6292  * The master bias is required only for
6293  * linearity computation in the OPT domain
6294  */
6295  cpl_image * collapse = cpl_imagelist_collapse_create(imlist_off);
6296  skip_if(collapse == NULL);
6297 
6298  c_offlist = cpl_imagelist_new();
6299  skip_if(cpl_imagelist_set(c_offlist, collapse, 0));
6300  }
6301 
6302  /* Loop over the different DITs found in EXPTIMEs */
6303  for (i = 0; i < ndiffdits; i++) {
6304  int c_nons;
6305  int c_noffs = 0; /* False (uninit) warning */
6306 
6307  double c_dit = cpl_vector_get(diffdits, i);
6308 
6309  c_onlist = cpl_imagelist_new();
6310  c_nons = 0;
6311 
6312  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6313  c_offlist = cpl_imagelist_new();
6314  c_noffs = 0;
6315  }
6316 
6317  for(j = 0; j < ndits; j++) {
6318  if (fabs(c_dit - cpl_vector_get(exptimes, j)) <= tolerance) {
6319  /*
6320  * First we get the corresponding image from the ON imlist.
6321  * The option IRPLIB_GAIN_WITH_RESCALE requires to modify
6322  * the input pixel buffer; therefore we must duplicate it.
6323  * On the other hand, if this option is not required, there
6324  * is no need for that duplication. We must only care that
6325  * c_onlist must not be deleted but only unset.
6326  */
6327  cpl_image * im_on;
6328  if (mode & IRPLIB_LIN_WITH_RESCALE) {
6329  const cpl_image * im =
6330  cpl_imagelist_get_const(imlist_on, j);
6331  im_on = cpl_image_duplicate(im);
6332  } else {
6333  im_on = (cpl_image *)cpl_imagelist_get_const(imlist_on, j);
6334  }
6335  skip_if(cpl_imagelist_set(c_onlist, im_on, c_nons));
6336  c_nons++;
6337 
6338  /*
6339  * Same explanation as above but for OFF imlist.
6340  * Only necessary when IRPLIB_GAIN_NO_COLLAPSE required.
6341  */
6342  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6343  cpl_image * im_off;
6344  if (mode & IRPLIB_LIN_WITH_RESCALE) {
6345  const cpl_image * im =
6346  cpl_imagelist_get_const(imlist_off, j);
6347  im_off = cpl_image_duplicate(im);
6348  } else {
6349  im_off =
6350  (cpl_image *) cpl_imagelist_get_const(imlist_off, j);
6351  }
6352  skip_if(cpl_imagelist_set(c_offlist, im_off, c_noffs));
6353  c_noffs++;
6354  }
6355  }
6356  }
6357 
6358  /* If NO_COLLAPSE, must be the same number of images! */
6359  if (mode & IRPLIB_LIN_NO_COLLAPSE)
6360  skip_if (c_nons != c_noffs);
6361 
6362  /* There must be pairs! */
6363  skip_if (c_nons == 0 || c_nons % 2 != 0);
6364 
6365  /* Rescaling */
6366  if(mode & IRPLIB_LIN_WITH_RESCALE) {
6367  skip_if(detmon_lg_rescale(c_onlist));
6368  if (mode & IRPLIB_LIN_NO_COLLAPSE)
6369  skip_if(detmon_lg_rescale(c_offlist));
6370  }
6371 
6372  /* The following loop is necessary for the case of multiple pairs
6373  of same EXPTIME values */
6374  while(c_nons > 0) {
6375 
6376  skip_if(detmon_lin_table_fill_row(lin_table, c_dit,
6377  lin_inputs,
6378  c_onlist, c_offlist,
6379  llx, lly, urx, ury,
6380  i, 0, mode));
6381 
6382  if (mode & IRPLIB_LIN_WITH_RESCALE) {
6383  cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
6384  cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
6385  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6386  cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
6387  cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
6388  }
6389  } else {
6390  cpl_imagelist_unset(c_onlist, 0);
6391  skip_if(0);
6392  cpl_imagelist_unset(c_onlist, 0);
6393  skip_if(0);
6394  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6395  cpl_imagelist_unset(c_offlist, 0);
6396  skip_if(0);
6397  cpl_imagelist_unset(c_offlist, 0);
6398  skip_if(0);
6399  }
6400  }
6401  skip_if(0);
6402  c_nons -= 2;
6403  }
6404 
6405  cpl_imagelist_delete(c_onlist);
6406  if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6407  cpl_imagelist_delete(c_offlist);
6408  }
6409  }
6410 
6411  skip_if(detmon_add_adl_column(lin_table, opt_nir));
6412 
6413  if(!(mode & IRPLIB_LIN_PIX2PIX)) {
6414  double mse = 0;
6415  /* Computation of LINEARITY via polynomial fit */
6416  y = cpl_vector_wrap(cpl_table_get_nrow(lin_table),
6417  (double *)cpl_table_get_data_double_const(lin_table,
6418  "MED"));
6419  if (opt_nir == NIR) {
6420  x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
6421  (double *)cpl_table_get_data_double_const(lin_table, "DIT"));
6422  } else {
6423  x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
6424  (double *)cpl_table_get_data_double_const(lin_table, "EXPTIME"));
6425  }
6426  if(x == NULL || y == NULL) {
6427  cpl_vector_unwrap((cpl_vector *)x);
6428  cpl_vector_unwrap((cpl_vector *)y);
6429  /*
6430  * As x and y are const vectors, if they would be defined at the
6431  * beginning of the function (required for skip_if - end_skip
6432  * scheme), they couldn't be initialised to NULL (required too).
6433  * Therefore, they are considered apart from the scheme.
6434  */
6435  skip_if(1);
6436  }
6437 
6438  cpl_msg_info(cpl_func, "Polynomial fitting for the LINEARITY");
6439  poly_linfit = irplib_polynomial_fit_1d_create_chiq(x, y, order, &mse);
6440 
6441  if(order == cpl_vector_get_size(x) - 1) {
6442  cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
6443  mse = 0;
6444  }
6445 
6446  if(poly_linfit == NULL) {
6447  cpl_vector_unwrap((cpl_vector *)x);
6448  cpl_vector_unwrap((cpl_vector *)y);
6449  /* See comment in previous error checking if() statement */
6450  skip_if(1);
6451  }
6452 
6453  cpl_vector_unwrap((cpl_vector *)x);
6454  cpl_vector_unwrap((cpl_vector *)y);
6455 
6456  for(deg = 0; deg <= order; deg++) {
6457  const double coeff =
6458  cpl_polynomial_get_coeff(poly_linfit, &deg);
6459  char *name_o =
6460  cpl_sprintf("ESO QC LIN COEF%" CPL_SIZE_FORMAT "", deg);
6461  assert(name_o != NULL);
6462  skip_if(cpl_propertylist_append_double(qclist, name_o, coeff));
6463  skip_if(cpl_propertylist_set_comment(qclist,name_o,
6464  DETMON_QC_LIN_COEF_C));
6465  cpl_free(name_o);
6466  pcoeffs[deg] = coeff;
6467  }
6468  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT, mse));
6469  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
6470  DETMON_QC_ERRFIT_MSE_C));
6471 
6472 
6473  } else {
6474  if (opt_nir == NIR) {
6475  x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
6476  (double *)cpl_table_get_data_double_const(lin_table,
6477  "DIT"));
6478  } else {
6479  x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
6480  (double *)cpl_table_get_data_double_const(lin_table,
6481  "EXPTIME"));
6482  }
6483 
6484 
6485  first = cpl_imagelist_get_const(lin_inputs, 0);
6486  sizex = cpl_image_get_size_x(first);
6487  sizey = cpl_image_get_size_y(first);
6488 
6489  vsize = cpl_vector_get_size(x);
6490 
6491  fiterror = cpl_image_new(sizex, sizey, CPL_TYPE_FLOAT);
6492 
6493  *coeffs_cube =
6494  cpl_fit_imagelist_polynomial(x, lin_inputs, 0,
6495  order, FALSE, CPL_TYPE_FLOAT,
6496  fiterror);
6497 
6498  cpl_vector_unwrap((cpl_vector*)x);
6499  irplib_ensure(*coeffs_cube != NULL, CPL_ERROR_UNSPECIFIED,
6500  "Failed polynomial fit");
6501 
6502  for(i = 0; i <= order; i++) {
6503  cpl_image *image = cpl_imagelist_get(*coeffs_cube, i);
6504  const double coeff = cpl_image_get_median(image);
6505  char * name_o1 = cpl_sprintf("ESO QC LIN COEF%d", i);
6506  char * name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", i);
6507  pcoeffs[i] = coeff;
6508  assert(name_o1 != NULL);
6509  assert(name_o2 != NULL);
6510  skip_if(cpl_propertylist_append_double(qclist, name_o1, coeff));
6511  skip_if(cpl_propertylist_set_comment(qclist,name_o1,
6512  DETMON_QC_LIN_COEF_C));
6513  cpl_free(name_o1);
6514  name_o1= NULL;
6515  skip_if(cpl_propertylist_append_double(qclist, name_o2,
6516  cpl_image_get_stdev(image)));
6517  skip_if(cpl_propertylist_set_comment(qclist,name_o2,
6518  DETMON_QC_LIN_COEF_ERR_C));
6519  cpl_free(name_o2);
6520  name_o2= NULL;
6521  }
6522 
6523  if(order == vsize - 1) {
6524  cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
6525  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT,
6526  0.0));
6527  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
6528  DETMON_QC_ERRFIT_C));
6529 
6530 
6531  } else {
6532  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT,
6533  cpl_image_get_median(fiterror)));
6534  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
6535  DETMON_QC_ERRFIT_C));
6536 
6537  }
6538  }
6539 
6540  skip_if(detmon_lg_lineff(pcoeffs, qclist, ref_level, order));
6541 
6542  if(mode & IRPLIB_LIN_PIX2PIX) {
6543  int nbpixs;
6544  *bpm = detmon_bpixs(*coeffs_cube, bpmbin, kappa, &nbpixs);
6545  skip_if(*bpm == NULL);
6546  skip_if(cpl_propertylist_append_int(qclist, DETMON_QC_NUM_BPM,
6547  nbpixs));
6548  skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_NUM_BPM,
6549  DETMON_QC_NUM_BPM_C));
6550  }
6551 
6552  end_skip;
6553 
6554  cpl_vector_delete(diffdits);
6555  cpl_polynomial_delete(poly_linfit);
6556  cpl_imagelist_delete(lin_inputs);
6557  cpl_vector_delete(vcoeffs);
6558  cpl_image_delete(fiterror);
6559 
6560  return lin_table;
6561 
6562 }
6563 
6564 /*--------------------------------------------------------------------------*/
6588 /*--------------------------------------------------------------------------*/
6589 static cpl_error_code
6590 detmon_lin_table_fill_row(cpl_table * lin_table, double c_dit,
6591  cpl_imagelist * linearity_inputs,
6592  const cpl_imagelist * ons,
6593  const cpl_imagelist * offs,
6594  int llx,
6595  int lly,
6596  int urx,
6597  int ury,
6598  const int pos,
6599  const int nskip,
6600  unsigned mode)
6601 {
6602  cpl_image * extracted=NULL;
6603 
6604  cpl_ensure_code(lin_table != NULL, CPL_ERROR_NULL_INPUT);
6605  cpl_ensure_code(ons != NULL, CPL_ERROR_NULL_INPUT);
6606  cpl_ensure_code(offs != NULL, CPL_ERROR_NULL_INPUT);
6607 
6608  if (mode & IRPLIB_LIN_PIX2PIX) {
6609  cpl_msg_debug(cpl_func,"checking linearity inputs");
6610  cpl_ensure_code(linearity_inputs != NULL, CPL_ERROR_NULL_INPUT);
6611  }
6612 
6613 
6614  if (mode & IRPLIB_LIN_NIR) {
6615  cpl_table_set(lin_table, "DIT", pos, c_dit);
6616  } else if (mode & IRPLIB_LIN_OPT) { /*OPT */
6617  cpl_table_set(lin_table, "EXPTIME", pos, c_dit);
6618  } else {
6619  cpl_msg_error(cpl_func, "Mandatory mode not given");
6620  }
6621 
6622  {
6623  const cpl_image * off2;
6624  if (cpl_imagelist_get_size(offs) == 1 || mode & IRPLIB_LIN_COLLAPSE)
6625  off2 = cpl_imagelist_get_const(offs, 0);
6626  else
6627  off2 = cpl_imagelist_get_const(offs, 1);
6628 
6629  extracted = detmon_subtracted_avg(cpl_imagelist_get_const(ons, 0),
6630  cpl_imagelist_get_const(offs, 0),
6631  cpl_imagelist_get_const(ons, 1),
6632  off2,
6633  llx, lly, urx, ury);
6634  cpl_ensure_code(extracted != NULL, cpl_error_get_code());
6635  }
6636 
6637  {
6638  double median = cpl_image_get_median(extracted);
6639  double mean= cpl_image_get_mean(extracted);
6640  cpl_table_set(lin_table, "MED", pos, median);
6641  cpl_table_set(lin_table, "MEAN", pos, mean);
6642 
6643  cpl_table_set(lin_table, "MED_DIT", pos, median / c_dit);
6644  cpl_table_set(lin_table, "MEAN_DIT", pos, mean / c_dit);
6645  }
6646 
6647  /* Insert to the imagelist used to fit the polynomial */
6648  if(mode & IRPLIB_LIN_PIX2PIX) {
6649  cpl_error_code error = cpl_imagelist_set(linearity_inputs, extracted,
6650  pos-nskip);
6651  cpl_ensure_code(!error, error);
6652  } else {
6653  cpl_image_delete(extracted);
6654  }
6655 
6656  return cpl_error_get_code();
6657 }
6658 
6659 static double irplib_calculate_total_noise_smooth(const cpl_image* pimage,
6660  int pattern_x, int pattern_y)
6661 {
6662  cpl_image * p_tmp_image = 0;
6663  cpl_image * psmooth_image = 0;
6664  double ret_noise;
6665  cpl_mask * mask = cpl_mask_new(pattern_x, pattern_y);
6666  cpl_mask_not(mask);
6667  p_tmp_image = cpl_image_duplicate(pimage);
6668  cpl_image_filter_mask(p_tmp_image,pimage, mask,CPL_FILTER_MEDIAN ,CPL_BORDER_FILTER);
6669  cpl_image_divide_scalar(p_tmp_image, cpl_image_get_median(pimage));
6670  psmooth_image = cpl_image_divide_create(pimage,p_tmp_image);
6671  ret_noise = irplib_calculate_total_noise(psmooth_image);
6672  cpl_mask_delete(mask);
6673  cpl_image_delete(psmooth_image);
6674  cpl_image_delete(p_tmp_image);
6675  return ret_noise;
6676 }
6677 
6678 static double irplib_calculate_total_noise(const cpl_image* pimage)
6679 {
6680  double total_noise = -1;
6681  unsigned long max_bin_size = 1E5;
6682  const double hstart = cpl_image_get_min(pimage);
6683  const double hrange = cpl_image_get_max(pimage) - hstart;
6684  const unsigned long nbins = max_bin_size;
6685  cpl_error_code err = CPL_ERROR_NONE;
6686  /* apply histogram method */
6687  irplib_hist * phist = 0;
6688  phist = irplib_hist_new();
6689  /* 2 extra-bins for possible out-of-range values */
6690 
6691  irplib_hist_init(phist, nbins, hstart, hrange);
6692  err = irplib_hist_fill(phist, pimage);
6693  if (err == CPL_ERROR_NONE)
6694  {
6695  unsigned int i = 0;
6696  double x0 = 0;
6697  double area = 0;
6698  double offset = 0;
6699 
6700  /* prepare vector */
6701  unsigned long n_bins = irplib_hist_get_nbins(phist);
6702  double start = irplib_hist_get_start(phist);
6703  double bin_size = irplib_hist_get_bin_size(phist);
6704  cpl_vector* pdata_vector = cpl_vector_new(n_bins);
6705  cpl_vector* ppos_vector = cpl_vector_new(n_bins);
6706  cpl_table* ptable = cpl_table_new(n_bins);
6707  cpl_table_new_column(ptable, "bin", CPL_TYPE_DOUBLE);
6708  cpl_table_new_column(ptable, "value", CPL_TYPE_DOUBLE);
6709  for(i = 0; i < n_bins; i++)
6710  {
6711  unsigned int value = irplib_hist_get_value(phist, i);
6712  double dvalue = (double)(value);
6713  cpl_vector_set(pdata_vector, i, dvalue);
6714  cpl_vector_set(ppos_vector, i, start + i * bin_size);
6715 
6716  cpl_table_set(ptable, "bin", i, start + i * bin_size);
6717  cpl_table_set(ptable, "value", i, dvalue);
6718  }
6719  err = cpl_vector_fit_gaussian(ppos_vector, NULL, pdata_vector, NULL, CPL_FIT_ALL, &x0, &total_noise, &area, &offset, NULL, NULL, NULL );
6720  if (err == CPL_ERROR_NONE)
6721  {
6722  cpl_msg_info(cpl_func, "FPN Calculation: histogram x0[%f] total_noise[%f] area[%f] offset[%f]", x0, total_noise, area, offset);
6723  }
6724  else
6725  {
6726  cpl_msg_warning(cpl_func, "FPN could not be computed due failed Gaussian Fit, err msg [%s]", cpl_error_get_message());
6727  cpl_error_reset();
6728  }
6729  cpl_table_delete(ptable);
6730  cpl_vector_delete(ppos_vector);
6731  cpl_vector_delete(pdata_vector);
6732  }
6733  else
6734  {
6735  cpl_msg_warning(cpl_func, "FPN could not be computed due failed histogram computation, err msg [%s]", cpl_error_get_message());
6736  cpl_error_reset();
6737  }
6738  irplib_hist_delete(phist);
6739 
6740  return total_noise;
6741 }
6742 
6743 static double irplib_compute_err(double gain, double ron, double FA)
6744 {
6745  double int_gain = (gain * gain - 1) / 12;
6746  if (int_gain < 0)
6747  {
6748  int_gain = 0;
6749  }
6750  return sqrt(ron * ron + FA / gain + int_gain);
6751 }
6752 
6753 static double irplib_fpn_lg(const cpl_image* f1, int* range, double gain ,
6754  FPN_METHOD fpn_method, int smooth_size, double* mse)
6755 {
6756  cpl_image* im_diff = 0;
6757  const cpl_image* im_f1 = f1;
6758  cpl_image* im_inrange1 = 0;
6759  double FA = 0;
6760  double s_tot = 0; /* absolute total noise */
6761  double s_fpn = 0; /* fixed pattern noise */
6762  double sr_fpn = 0; /* relative structural noise */
6763  /*che cinput*/
6764  if (gain<=0) {
6765  /* put dummy values Negative to indicate a problem occurred
6766  (FPN should be always positive) */
6767  cpl_msg_warning(cpl_func,"gain[%f]<0", gain);
6768  cpl_msg_warning(cpl_func,"We set dummy values for FPN");
6769  s_fpn=-999.;
6770  sr_fpn=-999;
6771  return sr_fpn;
6772  }
6773  if (range)
6774  {
6775  im_inrange1 = cpl_image_extract(f1, range[0], range[1], range[2], range[3]);
6776  im_f1 = im_inrange1;
6777  }
6778  FA = cpl_image_get_median(im_f1);
6779 
6780  /* apply histogram method */
6781  /* Is this irplib function giving the right result?? */
6782  switch (fpn_method)
6783  {
6784  case FPN_SMOOTH:
6785  cpl_msg_info(cpl_func,"SMOOTH method is used for FPN, pattern size[%d x %d] pixels",smooth_size,smooth_size );
6786  s_tot = irplib_calculate_total_noise_smooth(im_f1,smooth_size,smooth_size);
6787  break;
6788  case FPN_HISTOGRAM:
6789  cpl_msg_info(cpl_func,"HISTOGRAM method is used for FPN");
6790  s_tot = irplib_calculate_total_noise(im_f1);
6791  break;
6792  default:
6793  s_tot = -1;
6794  sr_fpn = -1;
6795  cpl_msg_warning(cpl_func,"fpn_method is not defined");
6796  break;
6797  }
6798  if (s_tot > 0)
6799  {
6800  if (FA<0)
6801  {
6802  /* put dummy values Negative to indicate a problem occurred
6803  (FPN should be always positive) */
6804  cpl_msg_warning(cpl_func,"Median flux on sum of flats<0");
6805  cpl_msg_warning(cpl_func,"We set dummy values for FPN");
6806  s_fpn=-999.;
6807  sr_fpn=-999;
6808  }
6809 
6810  if ((s_tot * s_tot - FA / gain) > 0)
6811  {
6812  s_fpn = sqrt(s_tot * s_tot - FA / gain);
6813  sr_fpn = s_fpn / FA;
6814  *mse = (irplib_compute_err(gain, 0, FA)) * gain / FA;
6815  } else {
6816  /* put dummy values Negative to indicate a problem occurred
6817  (FPN should be always positive) */
6818  cpl_msg_warning(cpl_func,"s_tot * s_tot < FA / gain");
6819  cpl_msg_warning(cpl_func,"We set dummy values for FPN");
6820  s_fpn=-999.;
6821  sr_fpn=-999;
6822  *mse = -1;
6823  }
6824  /*
6825  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);
6826  */
6827  }
6828  cpl_image_delete(im_diff);
6829  if (range)
6830  {
6831  cpl_image_delete(im_inrange1);
6832  }
6833  return sr_fpn;
6834 }
6835 
6836 
6837 static cpl_imagelist * irplib_load_fset_wrp(const cpl_frameset * pframeset,
6838  cpl_type type , int whichext)
6839 {
6840  /* FIXME: load image into window size from beginning to
6841  * save all the extracts */
6842  return detmon_load_frameset_window(pframeset, type, 0, whichext,
6843  detmon_lg_config.llx,
6844  detmon_lg_config.lly,
6845  detmon_lg_config.urx,
6846  detmon_lg_config.ury,
6847  detmon_lg_config.nx,
6848  detmon_lg_config.ny);
6849 }
6850 
6851 static cpl_imagelist * irplib_load_fset_wrp_ext(const cpl_frameset * pframeset,
6852  cpl_type type , int whichext)
6853 {
6854  int i = whichext; /* fake code to avoid compiler warning */
6855  cpl_imagelist* offs = cpl_imagelist_new();
6856  detmon_lg_config.load_fset(pframeset, type, offs);
6857  i++;
6858  return offs;
6859 }
6860 
6861 static cpl_error_code irplib_table_create_column(cpl_table* ptable,
6862  cpl_propertylist* plist)
6863 {
6864  if (ptable && plist)
6865  {
6866  int size = cpl_propertylist_get_size(plist);
6867  int i = 0;
6868  for (i = 0; i < size; i++)
6869  {
6870  cpl_property* pprop = cpl_propertylist_get(plist,i);
6871  if (pprop)
6872  {
6873  const char* pname = cpl_property_get_name(pprop);
6874  if (pname)
6875  {
6876  cpl_table_new_column(ptable, pname, cpl_property_get_type(pprop));
6877  if (cpl_error_get_code() != CPL_ERROR_NONE)
6878  {
6879  cpl_msg_warning(cpl_func, "cannot create new column[%s], err[%s]", pname, cpl_error_get_message());
6880  break; /* leave the cycle */
6881  }
6882  }
6883  }
6884  }
6885  }
6886  return cpl_error_get_code();
6887 }
6888 
6889 static cpl_error_code irplib_fill_table_DETWINUIT(cpl_table* ptable,
6890  cpl_propertylist* plist, int row)
6891 {
6892  cpl_error_code err = CPL_ERROR_NONE;
6893  if (ptable && plist)
6894  {
6895  int size = cpl_propertylist_get_size(plist);
6896  int i = 0;
6897  for (i = 0; i < size; i++)
6898  {
6899  cpl_property* pprop = cpl_propertylist_get(plist,i);
6900  if (pprop)
6901  {
6902  const char* pname = cpl_property_get_name(pprop);
6903  double value = cpl_property_get_double(pprop);
6904  if (pname)
6905  {
6906  cpl_table_set_double(ptable, pname, row, value);
6907  if (cpl_error_get_code() != CPL_ERROR_NONE)
6908  {
6909  cpl_msg_warning(cpl_func, "cannot write value to the table, column[%s] value[%f], err[%s]", pname, value, cpl_error_get_message());
6910  cpl_error_reset();
6911  break; /* leave the cycle */
6912  }
6913  }
6914  }
6915  }
6916  }
6917  return err;
6918 }
6919 
6920 cpl_error_code detmon_check_order(const double *exptime, int sz,
6921  double tolerance, int order)
6922 {
6923  int nsets = 0;
6924  int i = 0;
6925  /* 1. Determine number of groups */
6926  /* cpl_msg_warning(cpl_func, "detmon_check_order sz[%i]", sz);*/
6927  do
6928  {
6929  /* cpl_msg_warning(cpl_func, "detmon_check_order i[%i] exptime[%g]", i, exptime[i]); */
6930  nsets++;
6931  do
6932  {
6933  i++;
6934  if(i == sz - 1)
6935  {
6936  break;
6937  }
6938  } while(fabs(exptime[i-1] - exptime[i]) < tolerance);
6939  } while(i < sz - 1);
6940  /* the very last adjustment for the last group */
6941  if (!fabs(exptime[i-1] - exptime[i]) < tolerance) nsets++;
6942  if(nsets <= order)
6943  {
6944  cpl_error_set_message(cpl_func,CPL_ERROR_INCOMPATIBLE_INPUT,
6945  "Not enough frames for the polynomial"
6946  " fitting. nsets = %d <= %d order",
6947  nsets,order);
6948  }
6949  return cpl_error_get_code();
6950 }
6951 
6952 static cpl_error_code
6953 detmon_lg_dfs_save_imagelist(
6954  cpl_frameset * frameset,
6955  const cpl_parameterlist * parlist,
6956  const cpl_frameset *usedframes,
6957  const cpl_imagelist *coeffs,
6958  const char *recipe_name,
6959  const cpl_propertylist *mypro_coeffscube,
6960  const char * package,
6961  const char * name_o)
6962 {
6963  return(cpl_dfs_save_imagelist
6964  (frameset, NULL, parlist, usedframes, NULL,coeffs, CPL_BPP_IEEE_FLOAT,
6965  recipe_name, mypro_coeffscube, NULL, package,
6966  name_o));
6967 }
6968 
6969 static void detmon_lg_add_empty_image(cpl_imagelist* imlist, int pos)
6970 {
6971  const cpl_image* first = cpl_imagelist_get(imlist, 0);
6972  if (first)
6973  {
6974  int x = cpl_image_get_size_x(first);
6975  int y = cpl_image_get_size_y(first);
6976  cpl_type type = cpl_image_get_type(first);
6977  cpl_image * blank = cpl_image_new(x, y, type);
6978  cpl_imagelist_set(imlist, blank, pos);
6979  }
6980 }
6981 
6982 
6983 cpl_error_code
6984 detmon_lg_set_tag(cpl_frameset* set, const char** tag_on, const char** tag_off)
6985 {
6986  int ntag_old=0;
6987  int ntag_new=0;
6988 
6989  ntag_old=cpl_frameset_count_tags(set,DETMON_LG_ON_RAW_OLD);
6990  ntag_new=cpl_frameset_count_tags(set,DETMON_LG_ON_RAW_NEW);
6991  if(ntag_old) {
6992  *tag_on=DETMON_LG_ON_RAW_OLD;
6993  *tag_off=DETMON_LG_OFF_RAW_OLD;
6994  } else if (ntag_new) {
6995  *tag_on=DETMON_LG_ON_RAW_NEW;
6996  *tag_off=DETMON_LG_OFF_RAW_NEW;
6997  } else {
6998  cpl_msg_error(cpl_func,"Provide %s and %s (or %s and %s) input frames",
6999  DETMON_LG_ON_RAW_NEW,DETMON_LG_OFF_RAW_NEW,
7000  DETMON_LG_ON_RAW_OLD,DETMON_LG_OFF_RAW_OLD);
7001  }
7002 
7003 
7004  return cpl_error_get_code();
7005 }