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