IIINSTRUMENT Pipeline Reference Manual 1.3.14
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
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
62/*--------------------------------------------------------------------------*/
63
64/*---------------------------------------------------------------------------
65 Defines
66 ---------------------------------------------------------------------------*/
67/*method for calculating Fixed Pattern Noise (FPN)*/
68enum _FPN_METHOD
69{
70 FPN_UNKNOWN,
71 FPN_HISTOGRAM, /*default*/
72 FPN_SMOOTH,
73};
74typedef enum _FPN_METHOD FPN_METHOD;
75static struct
76{
77 const char * method;
78 /* Inputs */
79 int order;
80 double kappa;
81 int niter;
82 int threshold_min;
83 int threshold_max;
84 int llx;
85 int lly;
86 int urx;
87 int ury;
88 int ref_level;
89 int threshold;
90 int m;
91 int n;
92 int llx1;
93 int lly1;
94 int urx1;
95 int ury1;
96 int llx2;
97 int lly2;
98 int urx2;
99 int ury2;
100 int llx3;
101 int lly3;
102 int urx3;
103 int ury3;
104 int llx4;
105 int lly4;
106 int urx4;
107 int ury4;
108 int llx5;
109 int lly5;
110 int urx5;
111 int ury5;
112 int nx;
113 int ny;
114 cpl_boolean wholechip;
115 cpl_boolean autocorr;
116 cpl_boolean intermediate;
117 cpl_boolean collapse;
118 cpl_boolean rescale;
119 cpl_boolean pix2pix;
120 cpl_boolean bpmbin;
121 int filter;
122 double tolerance;
123 cpl_boolean pafgen;
124 const char * pafname;
125 /* Outputs */
126 double cr;
127 int exts;
128 int nb_extensions;
129 double lamp_stability;
130 cpl_boolean lamp_ok;
131 /* by kmirny */
132 int (* load_fset) (const cpl_frameset *, cpl_type, cpl_imagelist *);
133 cpl_imagelist * (* load_fset_wrp) (const cpl_frameset *, cpl_type, int);
134 FPN_METHOD fpn_method;
135 int fpn_smooth;
136 double saturation_limit;
137 double gain_threshold;
138 cpl_boolean split_coeffs;
139} detmon_lg_config;
140
141/* static const char* COL_NAME_DET1_WIN1_UIT1 = "DET1_WIN1_UIT1"; */
142/*---------------------------------------------------------------------------
143 Private function prototypes
144 ---------------------------------------------------------------------------*/
145/* Functions for the Linearity/Gain recipe, detmon_lg() */
146
147/* Parameters */
148static cpl_error_code
149detmon_lg_retrieve_parlist(const char *,
150 const char *, const cpl_parameterlist *,
151 cpl_boolean);
152
153
154static cpl_error_code
155detmon_lg_split_onoff(const cpl_frameset *,
156 cpl_frameset *,
157 cpl_frameset *,
158 const char *, const char * /*, cpl_boolean*/);
159
160static cpl_error_code
161detmon_lg_reduce(const cpl_frameset *,
162 const cpl_frameset *,
163 int* index_on, int* index_off,
164 double* exptime_on, double* exptime_off,
165 int *next_index_on, int* next_index_off,
166 cpl_imagelist **,
167 cpl_table *,
168 cpl_table *,
169 cpl_image **,
170 cpl_imagelist *,
171 cpl_imagelist *,
172 cpl_propertylist *,
173 cpl_propertylist *,
174 cpl_propertylist *,
175 cpl_propertylist *,
176 int (* load_fset) (const cpl_frameset *,
177 cpl_type,
178 cpl_imagelist *),
179 const cpl_boolean, int);
180
181
182
183
184static cpl_error_code
185detmon_lin_table_fill_row(cpl_table *, double,
186 cpl_imagelist *,
187 const cpl_imagelist *,
188 const cpl_imagelist *,
189 int, int, int, int,
190 const int,
191 const int,
192 unsigned);
193
194static cpl_error_code
195detmon_gain_table_fill_row(cpl_table * gain_table,
196 double c_dit,int c_ndit,
197 cpl_imagelist * autocorr_images,
198 cpl_imagelist * diff_flats,
199 const cpl_imagelist * ons,
200 const cpl_imagelist * offs,
201 double kappa, int nclip,
202 int llx, int lly, int urx, int ury,
203 int m, int n,
204 double gain_threshold,
205 int pos, unsigned mode, int* rows_affected);
206
207
208static cpl_error_code
209detmon_check_saturation_on_pair(cpl_imagelist * autocorr_images,
210 cpl_imagelist * diff_flats,
211 const cpl_imagelist * ons,
212 double kappa, int nclip,
213 int llx, int lly, int urx, int ury,
214 double saturation_limit,
215 const int pos, unsigned mode,
216 int* rows_linear_affected);
217
218static cpl_error_code
219detmon_lg_save(const cpl_parameterlist *,
220 cpl_frameset *,
221 const char *,
222 const char *,
223 const char *,
224 const cpl_propertylist *,
225 const cpl_propertylist *,
226 const cpl_propertylist *,
227 const cpl_propertylist *,
228 const cpl_propertylist *,
229 const cpl_propertylist *,
230 const char *,
231 cpl_imagelist *,
232 cpl_table *,
233 cpl_table *,
234 cpl_image *,
235 cpl_imagelist *,
236 cpl_imagelist *,
237 cpl_propertylist *,
238 cpl_propertylist *,
239 cpl_propertylist *,
240 cpl_propertylist *,
241 const int, const int, const cpl_frameset *,
242 int);
243
244static cpl_error_code
245detmon_lg_qc_ptc(const cpl_table *,
246 cpl_propertylist *, unsigned, int);
247
248static cpl_error_code
249detmon_lg_qc_med(const cpl_table *,
250 cpl_propertylist *, int);
251
252
253static double
254detmon_pfits_get_dit(const cpl_propertylist *);
255
256static double
257detmon_pfits_get_dit_opt(const cpl_propertylist *);
258static double
259irplib_pfits_get_prop_double(const cpl_propertylist * plist,
260 const char* prop_name);
261
262static cpl_image * detmon_bpixs(const cpl_imagelist *,
263 cpl_boolean, const double, int *);
264
265static double
266detmon_autocorr_factor(const cpl_image *,
267 cpl_image **, int, int);
268
269
270
271static cpl_error_code
272detmon_opt_contamination(const cpl_imagelist *,
273 const cpl_imagelist *,
274 unsigned mode, cpl_propertylist *);
275
276#if 0
277detmon_opt_lampcr(cpl_frameset *, int);
278#endif
279
280int
281detmon_lg_dfs_set_groups(cpl_frameset *, const char *, const char *);
282
283static cpl_error_code
284detmon_lg_reduce_all(const cpl_table *,
285 cpl_propertylist *,
286 cpl_propertylist *,
287 cpl_propertylist *,
288 cpl_propertylist *,
289 cpl_imagelist **,
290 cpl_image **,
291 const cpl_imagelist *,
292 const cpl_table *, int, cpl_boolean);
293
294static cpl_error_code
295detmon_lg_check_defaults(const cpl_image *);
296
297static cpl_error_code
298detmon_lg_rescale(cpl_imagelist *);
299
300static cpl_error_code
301detmon_lg_reduce_init(cpl_table *,
302 cpl_table *,
303 cpl_imagelist **,
304 const cpl_boolean);
305
306
307static cpl_error_code
308detmon_add_adl_column(cpl_table *, cpl_boolean);
309
310static cpl_error_code
311detmon_lg_lamp_stab(const cpl_frameset *,
312 const cpl_frameset *,
313 cpl_boolean, int);
314
315
316static cpl_error_code
317detmon_lg_reduce_dit(const cpl_frameset * set_on,
318 int* index_on, double* exptime_on,
319 const int dit_nb,
320 int * dit_nskip,
321 const cpl_frameset * set_off,
322 int * index_off, double* exptime_off,
323 int* next_on, int* next_off,
324 cpl_table * linear_table,
325 cpl_table * gain_table,
326 cpl_imagelist * linearity_inputs,
327 cpl_propertylist * qclist,
328 cpl_boolean opt_nir,
329 cpl_imagelist * autocorr_images,
330 cpl_imagelist * diff_flats,
331 cpl_imagelist * opt_offs,
332 int whichext,
333 int * rows_linear_affected,
334 int * rows_gain_affected);
335
336static cpl_error_code
337detmon_lg_core(cpl_frameset * cur_fset_on,
338 cpl_frameset * cur_fset_off,
339 int * index_on,
340 int * index_off,
341 double * exptime_on,
342 double * exptime_off,
343 int whichext,
344 int whichset,
345 const char * recipe_name,
346 const char * pipeline_name,
347 const char * pafregexp,
348 const cpl_propertylist * pro_lintbl,
349 const cpl_propertylist * pro_gaintbl,
350 const cpl_propertylist * pro_coeffscube,
351 const cpl_propertylist * pro_bpm,
352 const cpl_propertylist * pro_corr,
353 const cpl_propertylist * pro_diff,
354 const char * package,
355 int (* load_fset) (const cpl_frameset *,
356 cpl_type,
357 cpl_imagelist *),
358 int nsets, cpl_boolean opt_nir,
359 cpl_frameset * frameset, const cpl_parameterlist * parlist,
360 cpl_frameset * cur_fset);
361
362static cpl_error_code
363detmon_lg_lineff(double *, cpl_propertylist *, int, int);
364
365/*
366 static int
367 detmon_lg_compare_pairs(const cpl_frame *,
368 const cpl_frame *);
369 */
370static cpl_error_code
371detmon_gain_table_create(cpl_table *,
372 const cpl_boolean);
373
374
375static cpl_error_code
376detmon_lin_table_create(cpl_table *,
377 const cpl_boolean);
378
379static cpl_vector *
380detmon_lg_find_dits(const cpl_vector *,
381 double );
382
383static cpl_error_code
384detmon_lg_find_dits_ndits(const cpl_vector * exptimes,
385 const cpl_vector * vec_ndits,
386 double tolerance,
387 cpl_vector** diff_dits,
388 cpl_vector** diff_ndits);
389
390static cpl_error_code
391detmon_fpn_compute(const cpl_frameset *set_on,
392 int * index_on,
393 int last_linear_best,
394 cpl_propertylist *lint_qclist,
395 int llx,
396 int lly,
397 int urx,
398 int ury,
399 double gain,
400 int whichext,
401 FPN_METHOD fpn_method,
402 int smooth_size);
403static double irplib_fpn_lg(const cpl_image* f1, int* range, double gain,
404 FPN_METHOD fpn_method, int, double* mse);
405static double irplib_calculate_total_noise(const cpl_image* pimage);
406
407static cpl_imagelist* irplib_load_fset_wrp(const cpl_frameset *,
408 cpl_type, int whichext);
409static cpl_imagelist * irplib_load_fset_wrp_ext(const cpl_frameset *,
410 cpl_type, int);
411
412static cpl_error_code irplib_table_create_column(cpl_table* ptable,
413 cpl_propertylist* plist);
414static cpl_error_code irplib_fill_table_DETWINUIT(cpl_table* ptable,
415 cpl_propertylist* plist,
416 int row);
417
418static cpl_error_code
419detmon_pair_extract_next(const cpl_frameset * set,
420 int* index,
421 int* next_element,
422 double* dit_array,
423 /* int * with_equal_dit,
424 int onoff, */
425 cpl_frameset ** pair,
426 double tolerance);
427static cpl_error_code
428detmon_single_extract_next(const cpl_frameset * set,
429 int* index,
430 int* next_element,
431 double* dit_array,
432 cpl_frameset ** pair);
433
434/*
435 static int frame_get_ndit(const cpl_frame * pframe);
436 static cpl_error_code
437 irplib_frameset_get_ndit(const cpl_frameset * self, int* ndit);
438 */
439static cpl_error_code detmon_table_fill_invalid(cpl_table* ptable, double code);
440static void detmon_lg_add_empty_image(cpl_imagelist* imlist, int pos);
441static int detmon_lg_check_before_gain(const cpl_vector* x, const cpl_vector* y);
442/*---------------------------------------------------------------------------*/
449/*---------------------------------------------------------------------------*/
450static int irplib_pfits_get_ndit(const cpl_propertylist * plist)
451{
452 return cpl_propertylist_get_int(plist,"ESO DET NDIT");
453}
454
455
456/*
457static int frame_get_ndit(const cpl_frame * pframe)
458{
459 cpl_propertylist *plist = 0;
460 int ival = 0;
461
462 plist = cpl_propertylist_load(cpl_frame_get_filename(pframe),0);
463 if(plist)
464 {
465 ival = cpl_propertylist_get_int(plist, "NDIT");
466 }
467
468 cpl_propertylist_delete(plist);
469 return ival;
470}
471*/
472
473/*
474static cpl_error_code
475irplib_frameset_get_ndit(const cpl_frameset * self, int* ndit)
476{
477 int sz = 0;
478 int i = 0;
479 const cpl_frame* tmp_frame = 0;
480 cpl_error_code error = CPL_ERROR_NONE;
481 sz = cpl_frameset_get_size(self);
482
483 tmp_frame = cpl_frameset_get_position_const(self, 0);
484 while(tmp_frame)
485 {
486 ndit[i] = frame_get_ndit(tmp_frame);
487 i++
488 tmp_frame = cpl_frameset_get_position_const(self, i);
489 }
490
491 return error;
492}
493*/
494
495#ifdef DETMON_USE_DETECTOR_SHOTNOISE_MODEL
496/*----------------------------------------------------------------------------*/
517/*----------------------------------------------------------------------------*/
518static cpl_error_code
519hdrldemo_detector_shotnoise_model(const cpl_image* ima_data, const double gain,
520 const double ron, cpl_image ** ima_errs)
521{
522 cpl_ensure_code(ima_data, CPL_ERROR_NULL_INPUT);
523 cpl_ensure_code(ima_errs, CPL_ERROR_NULL_INPUT);
524 cpl_ensure_code(gain > 0., CPL_ERROR_ILLEGAL_INPUT);
525 cpl_ensure_code(ron > 0., CPL_ERROR_ILLEGAL_INPUT);
526
527 *ima_errs = cpl_image_duplicate(ima_data);
528 /* set negative values (= zero measurable electrons) to read out noise */
529 cpl_image_threshold(*ima_errs, 0., INFINITY, ron, ron);
530
531 /* err_ADU = sqrt(counts/gain + ron * ron)*/
532
533 cpl_image_divide_scalar(*ima_errs, gain);
534 cpl_image_add_scalar(*ima_errs, ron * ron);
535 cpl_image_power(*ima_errs, 0.5);
536
537 return cpl_error_get_code();
538}
539#endif
540
541static cpl_error_code
542detmon_lg_reduce_set(int i, cpl_frameset * frameset,
543 int nsets,
544 const char * tag_on,
545 const char * tag_off,
546 const char * recipe_name,
547 const char * pipeline_name,
548 const char * pafregexp,
549 const cpl_propertylist * pro_lintbl,
550 const cpl_propertylist * pro_gaintbl,
551 const cpl_propertylist * pro_coeffscube,
552 const cpl_propertylist * pro_bpm,
553 const cpl_propertylist * pro_corr,
554 const cpl_propertylist * pro_diff,
555 const char * package,
556 int (* load_fset)
557 (const cpl_frameset *, cpl_type, cpl_imagelist *),
558 const cpl_boolean opt_nir,
559 const cpl_parameterlist * parlist,
560 cpl_size* selection
561 );
562static double irplib_compute_err(double gain, double ron, double photon_noise);
563/* wrapper function for different cpl versions*/
564static cpl_error_code
565detmon_lg_dfs_save_imagelist(cpl_frameset * frameset,
566 const cpl_parameterlist * parlist,
567 const cpl_frameset *usedframes,
568 const cpl_imagelist *coeffs,
569 const char *recipe_name,
570 const cpl_propertylist *mypro_coeffscube,
571 const char * package,
572 const char * name_o);
573
574/*--------------------------------------------------------------------------*/
575static void irplib_free(char** pointer){
576
577 if(pointer && *pointer) {
578 cpl_free(*pointer);
579 *pointer=NULL;
580 }
581}
582
583static cpl_error_code
584detmon_lg_reduce_set(int i, cpl_frameset * frameset, int nsets,
585 const char * tag_on,
586 const char * tag_off,
587 const char * recipe_name,
588 const char * pipeline_name,
589 const char * pafregexp,
590 const cpl_propertylist * pro_lintbl,
591 const cpl_propertylist * pro_gaintbl,
592 const cpl_propertylist * pro_coeffscube,
593 const cpl_propertylist * pro_bpm,
594 const cpl_propertylist * pro_corr,
595 const cpl_propertylist * pro_diff,
596 const char * package,
597 int (* load_fset)
598 (const cpl_frameset *, cpl_type, cpl_imagelist *),
599 const cpl_boolean opt_nir,
600 const cpl_parameterlist * parlist,
601 cpl_size* selection
602 )
603{
604 int j;
605 int nexts = detmon_lg_config.nb_extensions;
606
607 double* exptime_on = 0;
608 double* exptime_off = 0;
609 int* index_on = 0;
610 int* index_off = 0;
611 cpl_frameset * cur_fset = NULL;
612 cpl_frameset* cur_fset_on = 0;
613 cpl_frameset* cur_fset_off = 0;
614
615 /* Reduce data set nb i */
616 cur_fset =
617 (nsets == 1) ? /* would be better (selection == 0) ? */
618 cpl_frameset_duplicate(frameset) : cpl_frameset_extract(frameset, selection, i);
619
620
621 skip_if(cur_fset == NULL);
622
623 /* Split input frameset into 2 sub-framesets for ON and OFF frames */
624 cur_fset_on = cpl_frameset_new();
625 cur_fset_off = cpl_frameset_new();
626 cpl_msg_info(cpl_func, "Splitting into ON and OFF sub-framesets");
627 skip_if (detmon_lg_split_onoff(cur_fset,
628 cur_fset_on, cur_fset_off,
629 tag_on, tag_off /*, opt_nir*/));
630 if (cpl_frameset_get_size(cur_fset_on) == 0)
631 {
632 cpl_msg_error(cpl_func, "No lamp frames in input");
633 skip_if(1);
634 }
635
636 if (cpl_frameset_get_size(cur_fset_off) == 0)
637 {
638 cpl_msg_error(cpl_func, "No dark / bias frames in input");
639 skip_if(1);
640 }
641 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));
642 /* Labelise each sub-frameset according to DIT values */
643 /* selection_on = cpl_frameset_labelise(cur_fset_on,
644 detmon_lg_compare_pairs,
645 &nsets_on);
646
647 skip_if (selection_on == NULL);
648 */
649 exptime_on = cpl_malloc(sizeof(double)*cpl_frameset_get_size(cur_fset_on));
650 exptime_off = cpl_malloc(sizeof(double)*cpl_frameset_get_size(cur_fset_off));
651
652 index_on = cpl_malloc(sizeof(int)*cpl_frameset_get_size(cur_fset_on));
653 index_off = cpl_malloc(sizeof(int)*cpl_frameset_get_size(cur_fset_off));
654 irplib_frameset_sort(cur_fset_on, index_on, exptime_on);
655 irplib_frameset_sort(cur_fset_off, index_off, exptime_off);
656 /* for (j = 0; j < cpl_frameset_get_size(cur_fset_on); j++)
657 {
658 cpl_msg_info(cpl_func, "%d: \t %d \t %f", j , index_on[j], exptime_on[j]);
659 }
660 */
661 /* TODO Check that each ON frame pair has a corresponding OFF frame*/
662
663 /* Test if they have equal nb of labels */
664 /* if (!detmon_lg_config.collapse) {
665 skip_if(nsets_on != nsets_off);
666 }
667 */
668 skip_if(detmon_check_order(exptime_on, cpl_frameset_get_size(cur_fset_on), detmon_lg_config.tolerance, detmon_lg_config.order));
669
670 if(detmon_lg_config.exts >= 0)
671 {
672 /*
673 * In the optical domain, the first 2 frames
674 * are used apart from the pairs.
675 */
676
677#if 0
678 if (detmon_lg_config.lamp_ok) {
679 skip_if(detmon_opt_lampcr(cur_fset, 0));
680 }
681#endif
682 skip_if(detmon_lg_core(cur_fset_on, cur_fset_off,
683 index_on,
684 index_off,
685 exptime_on,
686 exptime_off,
687 detmon_lg_config.exts,
688 i,
689 recipe_name, pipeline_name, pafregexp,
690 pro_lintbl, pro_gaintbl, pro_coeffscube, pro_bpm, pro_corr, pro_diff,
691 package, load_fset, nsets, opt_nir, frameset, parlist, cur_fset));
692 } else {
693 for(j = 1; j <= nexts; j++) {
694 /*
695 * In the optical domain, the first 2 frames
696 * are used apart from the pairs.
697 */
698
699#if 0
700 if (detmon_lg_config.lamp_ok) {
701 skip_if(detmon_opt_lampcr(cur_fset, j));
702 }
703#endif
704
705 skip_if(detmon_lg_core(cur_fset_on, cur_fset_off,
706 index_on,
707 index_off,
708 exptime_on,
709 exptime_off,
710 j, i, recipe_name,
711 pipeline_name, pafregexp,
712 pro_lintbl, pro_gaintbl,
713 pro_coeffscube,
714 pro_bpm, pro_corr, pro_diff,
715 package, load_fset, nsets, opt_nir,
716 frameset, parlist, cur_fset));
717 }
718 }
719 end_skip;
720
721 // PIPE-10123
722 // NOTE - we test against recipe name, rather than is_nir, because we
723 // don't want the _mr recipes to include these calculations
724 char* par_name = NULL ;
725 if (strcmp(recipe_name, "detmon_opt_lg") == 0 ||
726 strcmp(recipe_name, "detmon_ir_lg") == 0) {
727 cpl_msg_debug(cpl_func, "This is where I want to write the 'super' QC kw");
728 cpl_msg_debug(cpl_func, "Writing super QC kw for recipe %s", recipe_name);
729 // Compute values & write back
730 if (cpl_error_get_code() != CPL_ERROR_NONE) {
731 cpl_msg_error(__func__, "Error found in detmon_lg_reduce_set!");
732 cpl_msg_error(__func__, "At: before computing for gain and lin global");
733 cpl_msg_error(__func__, "In %s, L%u", cpl_error_get_file(),
734 cpl_error_get_line());
735 cpl_msg_error(__func__, "%s", cpl_error_get_message());
736 }
737 detmon_lg_qc_params_global_gain(recipe_name, nsets);
738 detmon_lg_qc_params_global_lin(recipe_name, nsets);
739 par_name = cpl_sprintf("detmon.%s.pix2pix", recipe_name);
740 cpl_parameter* pix2pix = cpl_parameterlist_find(
741 parlist,
742 par_name);
743 if (pix2pix != NULL && cpl_parameter_get_bool(pix2pix)) {
744 if (cpl_error_get_code() != CPL_ERROR_NONE) {
745 cpl_msg_error(__func__, "Error found in detmon_lg_reduce_set!");
746 cpl_msg_error(__func__, "At: before computing for bpm and coeffs global");
747 cpl_msg_error(__func__, "In %s, L%u", cpl_error_get_file(),
748 cpl_error_get_line());
749 cpl_msg_error(__func__, "%s", cpl_error_get_message());
750 }
751 detmon_lg_qc_params_global_bpm(recipe_name, nsets);
752 detmon_lg_qc_params_global_coeffs(recipe_name, nsets);
753 }
754 }
755 cpl_free(par_name);
756
757 cpl_frameset_delete(cur_fset);
758 cpl_frameset_delete(cur_fset_on);
759 cpl_frameset_delete(cur_fset_off);
760 cpl_free(index_on);
761 cpl_free(index_off);
762 cpl_free(exptime_on);
763 cpl_free(exptime_off);
764 return cpl_error_get_code();
765}
766
767/*
768 * @brief Reduce linearity and gain in the IR domain
769 * @param parlist List of required parameters
770 * @param frameset Input frameset
771 * @param tag_on Tag to identify the ON frames
772 * @param tag_off Tag to identify the OFF frames
773 * @param recipe_name Name of the recipe calling this function
774 * @param pipeline_name Name of the pipeline calling this function
775 * @param procatg_lintbl PRO.CATG keyword for the Linearity Table
776 * @param procatg_gaintbl PRO.CATG keyword for the Gain Table
777 * @param procatg_coeffscube PRO.CATG keyword for the
778 * Linearity Coefficients' Images
779 * @param procatg_bpm PRO.CATG required for the Bad Pixel Map
780 * @param procatg_corr PRO.CATG required for the Autocorrelation Images
781 * (Intermediate product - only created if required)
782 * @param procatg_diff PRO.CATG required for the Difference Images
783 * (Intermediate Product - only created if required)
784 * @param package PACKAGE (incl. VERSION) required
785 * for the DFS keywords
786 * @param compare Compare function used to classified frameset into
787 * different settings, if any.
788 * @param load_fset Loading function for preprocessing of input
789 frames with special data format (needed for
790 AMBER and MIDI processing)
791
792 * @param opt_nir Boolean parameter to activate/deactivate
793 * OPT-only / IR-only parts of the recipe
794 * @return 0 on success, -1 on fail.
795 * @note: The parlist contains the following parameters:
796 *
797 * @par1 kappa Kappa value used for the kappa-sigma clipping
798 * rejection of bad pixels when computing sigma for
799 * gain calculation
800 * @par2 niter Number of iterations for the kappa-sigma clipping
801 * @par3 threshold_min Minimum threshold of the k-sigma (Not applied)
802 * @par4 threshold_max Maximum threshold of the k-sigma (Not applied)
803 * @par5 llx Region of Interest (Default to the whole area)
804 * @par6 lly Region of Interest (Default to the whole area)
805 * @par7 urx Region of Interest (Default to the whole area)
806 * @par8 ury Region of Interest (Default to the whole area)
807 * @par9 ref_level Reference Level (Not applied)
808 * @par10 threshold Threshold (Not applied)
809 * @par11 intermediate Boolean to activate the production of
810 * Intermediate Products
811 * @par12 autocorr Boolean to activate autocorr method
812 * @par13 collapse Boolean to activate collapse of OFF frames
813 * @par14 rescale Boolean to activate pair rescaling
814 * @par15 m X-Shift of the autocorrelation
815 * @par16 n Y-Shift of the autocorrelation
816 * @par17 llx1 Region of Interest 1 (Only OPT)
817 * @par18 lly1 Region of Interest 1 (Only OPT)
818 * @par19 urx1 Region of Interest 1 (Only OPT)
819 * @par20 ury1 Region of Interest 1 (Only OPT)
820 * @par21 llx2 Region of Interest 2 (Only OPT)
821 * @par22 lly2 Region of Interest 2 (Only OPT)
822 * @par23 urx2 Region of Interest 2 (Only OPT)
823 * @par24 ury2 Region of Interest 2 (Only OPT)
824 * @par25 llx3 Region of Interest 3 (Only OPT)
825 * @par26 lly3 Region of Interest 3 (Only OPT)
826 * @par27 urx3 Region of Interest 3 (Only OPT)
827 * @par28 ury3 Region of Interest 3 (Only OPT)
828 * @par29 llx4 Region of Interest 4 (Only OPT)
829 * @par30 lly4 Region of Interest 4 (Only OPT)
830 * @par31 urx4 Region of Interest 4 (Only OPT)
831 * @par32 ury4 Region of Interest 4 (Only OPT)
832 * @par33 llx5 Region of Interest 5 (Only OPT)
833 * @par34 lly5 Region of Interest 5 (Only OPT)
834 * @par35 urx5 Region of Interest 5 (Only OPT)
835 * @par36 ury5 Region of Interest 5 (Only OPT)
836 * @par37 exts Integer to select extension
837 */
838
839/*--------------------------------------------------------------------------*/
840
841cpl_error_code
842detmon_lg(cpl_frameset * frameset,
843 const cpl_parameterlist * parlist,
844 const char * tag_on,
845 const char * tag_off,
846 const char * recipe_name,
847 const char * pipeline_name,
848 const char * pafregexp,
849 const cpl_propertylist * pro_lintbl,
850 const cpl_propertylist * pro_gaintbl,
851 const cpl_propertylist * pro_coeffscube,
852 const cpl_propertylist * pro_bpm,
853 const cpl_propertylist * pro_corr,
854 const cpl_propertylist * pro_diff,
855 const char * package,
856 int (* compare) (const cpl_frame *,
857 const cpl_frame *),
858 int (* load_fset) (const cpl_frameset *,
859 cpl_type,
860 cpl_imagelist *),
861 const cpl_boolean opt_nir)
862{
863 cpl_errorstate cleanstate = cpl_errorstate_get();
864 cpl_size nsets;
865 cpl_size * selection = NULL;
866 cpl_frame * first = NULL;
867 cpl_image * reference = NULL;
868
869 /*
870 * Variables used only inside the for() statement.
871 * However, there are declared here to ease
872 * memory management in error case.
873 */
874 cpl_frameset * cur_fset = NULL;
875 cpl_frameset * cur_fset_on = NULL;
876 cpl_frameset * cur_fset_off = NULL;
877
878 /* Test entries */
879 cpl_ensure_code(frameset != NULL, CPL_ERROR_NULL_INPUT);
880 cpl_ensure_code(parlist != NULL, CPL_ERROR_NULL_INPUT);
881 cpl_ensure_code(tag_on != NULL, CPL_ERROR_NULL_INPUT);
882 cpl_ensure_code(tag_off != NULL, CPL_ERROR_NULL_INPUT);
883 cpl_ensure_code(recipe_name != NULL, CPL_ERROR_NULL_INPUT);
884 cpl_ensure_code(pipeline_name != NULL, CPL_ERROR_NULL_INPUT);
885 cpl_ensure_code(pro_lintbl != NULL, CPL_ERROR_NULL_INPUT);
886 cpl_ensure_code(pro_gaintbl != NULL, CPL_ERROR_NULL_INPUT);
887 cpl_ensure_code(pro_coeffscube != NULL, CPL_ERROR_NULL_INPUT);
888 cpl_ensure_code(pro_bpm != NULL, CPL_ERROR_NULL_INPUT);
889 cpl_ensure_code(pro_corr != NULL, CPL_ERROR_NULL_INPUT);
890 cpl_ensure_code(pro_diff != NULL, CPL_ERROR_NULL_INPUT);
891 cpl_ensure_code(package != NULL, CPL_ERROR_NULL_INPUT);
892
893 cpl_msg_info(cpl_func,"frameset size [%" CPL_SIZE_FORMAT "]", cpl_frameset_get_size(frameset));
894
895
896 skip_if (detmon_lg_dfs_set_groups(frameset, tag_on, tag_off));
897
898 /*
899 * First check of input consistency in NIR case:
900 * There must be a pair ON and a pair OFF for each DIT.
901 */
902
903 skip_if (detmon_lg_retrieve_parlist(pipeline_name, recipe_name,
904 parlist, opt_nir));
905
906 /*
907 * Retrieve first image to check some parameters' values and
908 * set default values which refer to the image.
909 */
910
911 first = cpl_frameset_get_position(frameset, 0);
912 irplib_ensure (first != NULL, CPL_ERROR_ILLEGAL_INPUT, "Empty data set! Provide %s and %s input frames",tag_on,tag_off);
913
914 detmon_lg_config.load_fset = load_fset;
915 detmon_lg_config.load_fset_wrp = load_fset ? irplib_load_fset_wrp_ext : irplib_load_fset_wrp;
916
917
918 detmon_lg_config.nb_extensions = 1;
919 if (detmon_lg_config.exts < 0) {
920 int i = 1;
921 detmon_lg_config.nb_extensions = cpl_frame_get_nextensions(first);
922 while (reference == NULL && i <= detmon_lg_config.nb_extensions) {
923 reference = cpl_image_load(cpl_frame_get_filename(first),
924 CPL_TYPE_FLOAT, 0, i);
925 if (reference == NULL) {
926 cpl_msg_warning(cpl_func, "Extension %d empty, skipping", i);
927 cpl_errorstate_set(cleanstate);
928 }
929 i++;
930 }
931 cpl_errorstate_set(cleanstate);
932 irplib_ensure (reference != NULL, CPL_ERROR_ILLEGAL_INPUT,
933 "No data found in any extension");
934 cpl_msg_info(cpl_func, "Using extension %d as reference", i - 1);
935 } else {
936 if (load_fset != NULL) {
937 cpl_frameset * new = cpl_frameset_new();
938 cpl_imagelist * p = cpl_imagelist_new();
939 cpl_frameset_insert(new, cpl_frame_duplicate(first));
940 (*load_fset)(new, CPL_TYPE_FLOAT, p);
941 reference = cpl_image_duplicate(cpl_imagelist_get(p, 0));
942 cpl_imagelist_delete(p);
943 cpl_frameset_delete(new);
944 } else {
945 cpl_msg_info(cpl_func,"name=%s",cpl_frame_get_filename(first));
946 reference = cpl_image_load(cpl_frame_get_filename(first),
947 CPL_TYPE_FLOAT, 0, detmon_lg_config.exts);
948 }
949 cpl_errorstate_set(cleanstate);
950 irplib_ensure (reference != NULL, CPL_ERROR_ILLEGAL_INPUT,
951 "No data found in requested extension %d",
952 detmon_lg_config.exts);
953 }
954 skip_if (reference == NULL);
955
956 skip_if (detmon_lg_check_defaults(reference));
957
958 /* Labelise all input frames */
959
960 /*
961 * After each setting iteration, frameset will be modified (product
962 * frames will have been added), so it is better to duplicate it, keep
963 * it in its original state for the labelise-extract scheme.
964 */
965 if (compare == NULL) {
966 nsets = 1;
967 } else {
968 cpl_msg_info(cpl_func, "Identifying different settings");
969 selection = cpl_frameset_labelise(frameset, compare, &nsets);
970 skip_if (selection == NULL);
971 }
972
973 /* Extract settings and reduce each of them */
974 for(int i = 0; i < nsets; i++)
975 {
976 int fr_size = cpl_frameset_get_size(frameset);
977 int fr_size_new = 0;
978 cpl_msg_info(cpl_func, "Reduce data set nb %d out of %" CPL_SIZE_FORMAT "",
979 i + 1, nsets);
980 skip_if(detmon_lg_reduce_set(i, frameset, nsets, tag_on, tag_off,
981 recipe_name,
982 pipeline_name,
983 pafregexp,
984 pro_lintbl,
985 pro_gaintbl,
986 pro_coeffscube,
987 pro_bpm,
988 pro_corr,
989 pro_diff,
990 package,
991 load_fset,
992 opt_nir,
993 parlist,
994 selection));
995 fr_size_new = cpl_frameset_get_size(frameset);
996 /* the size of the frameset could be changed during the detmon_lg_reduce_set call
997 * so the size of the selection array should be adjusted with some fake values,
998 * to avoid reading of the not allocated memory
999 * see DFS08110 for the error description
1000 * */
1001 if (fr_size_new > fr_size)
1002 {
1003 selection = cpl_realloc(selection, fr_size_new * sizeof(selection[0]));
1004 memset(selection + fr_size, -1, (fr_size_new - fr_size) * sizeof(selection[0]));
1005 }
1006 }
1007
1008 end_skip;
1009
1010 cpl_frameset_delete(cur_fset);
1011 cpl_frameset_delete(cur_fset_on);
1012 cpl_frameset_delete(cur_fset_off);
1013 cpl_free(selection);
1014 cpl_image_delete(reference);
1015
1016 return cpl_error_get_code();
1017}
1018
1019/*---------------------------------------------------------------------------*/
1050/*---------------------------------------------------------------------------*/
1051
1052static cpl_error_code
1053detmon_lg_core(cpl_frameset * cur_fset_on,
1054 cpl_frameset * cur_fset_off,
1055 int * index_on,
1056 int * index_off,
1057 double * exptime_on,
1058 double * exptime_off,
1059 int whichext,
1060 int whichset,
1061 const char * recipe_name,
1062 const char * pipeline_name,
1063 const char * pafregexp,
1064 const cpl_propertylist * pro_lintbl,
1065 const cpl_propertylist * pro_gaintbl,
1066 const cpl_propertylist * pro_coeffscube,
1067 const cpl_propertylist * pro_bpm,
1068 const cpl_propertylist * pro_corr,
1069 const cpl_propertylist * pro_diff,
1070 const char * package,
1071 int (* load_fset) (const cpl_frameset *,
1072 cpl_type,
1073 cpl_imagelist *),
1074 int nsets, cpl_boolean opt_nir,
1075 cpl_frameset * frameset, const cpl_parameterlist * parlist,
1076 cpl_frameset * cur_fset)
1077{
1078 cpl_table * gain_table = cpl_table_new(
1079 cpl_frameset_get_size(cur_fset_on) / 2);
1080 cpl_table * linear_table = cpl_table_new(
1081 cpl_frameset_get_size(cur_fset_on) / 2);
1082 cpl_imagelist * coeffs = NULL;
1083 cpl_image * bpm = NULL;
1084 cpl_imagelist * autocorr_images = NULL;
1085 cpl_imagelist * diff_flats = NULL;
1086 cpl_propertylist * gaint_qclist = NULL;
1087 cpl_propertylist * lint_qclist = NULL;
1088 cpl_propertylist * linc_qclist = NULL;
1089 cpl_propertylist * bpm_qclist = NULL;
1090
1091 int next_index_on = 0;
1092 int next_index_off = 0;
1093
1094 /* Reduce extension nb i */
1095 cpl_msg_info(cpl_func, "Reduce extension nb %d ", whichext);
1096
1097 /* FIXME: All other memory objects in use should be
1098 initialised here (except coeffs which can not be) */
1099 if (detmon_lg_config.intermediate) {
1100 autocorr_images = cpl_imagelist_new();
1101 diff_flats = cpl_imagelist_new();
1102 }
1103
1104 gaint_qclist = cpl_propertylist_new();
1105 lint_qclist = cpl_propertylist_new();
1106 linc_qclist = cpl_propertylist_new();
1107 bpm_qclist = cpl_propertylist_new();
1108
1109 /* Reduction done here */
1110 cpl_msg_info(cpl_func, "Starting data reduction");
1111 if (detmon_lg_reduce(cur_fset_on, cur_fset_off,
1112 index_on, index_off, exptime_on, exptime_off,
1113 &next_index_on, &next_index_off,
1114 &coeffs, gain_table,
1115 linear_table, &bpm, autocorr_images,
1116 diff_flats, gaint_qclist, lint_qclist,
1117 linc_qclist, bpm_qclist, load_fset,
1118 opt_nir, whichext) == CPL_ERROR_CONTINUE) {
1119 cpl_msg_info(cpl_func, "Empty extension %d", whichext);
1120 }
1121
1122 // PIPE-10123 insert QC parameter write here
1123 // NOTE - we test against recipe name, rather than is_nir, because we
1124 // don't want the _mr recipes to include these calculations
1125 if (strcmp(recipe_name, "detmon_opt_lg") == 0 ||
1126 strcmp(recipe_name, "detmon_ir_lg") == 0) {
1127 cpl_msg_debug(cpl_func, "Inserting per-extension QC params");
1128 detmon_lg_qc_params(
1129 linear_table, lint_qclist,
1130 gain_table, gaint_qclist,
1131 coeffs, linc_qclist,
1132 bpm, bpm_qclist,
1133 recipe_name
1134 );
1135 }
1136
1137 /* Save the products for each setting */
1138 cpl_msg_info(cpl_func, "Saving the products");
1139 if (nsets == 1) {
1140 skip_if(
1141 detmon_lg_save(parlist, frameset, recipe_name,
1142 pipeline_name, pafregexp,
1143 pro_lintbl, pro_gaintbl,
1144 pro_coeffscube, pro_bpm,
1145 pro_corr, pro_diff, package,
1146 coeffs, gain_table, linear_table,
1147 bpm, autocorr_images, diff_flats,
1148 gaint_qclist, lint_qclist, linc_qclist,
1149 bpm_qclist,
1150 0, 0,
1151 cur_fset, whichext));
1152 } else {
1153 skip_if(
1154 detmon_lg_save(parlist, frameset, recipe_name,
1155 pipeline_name, pafregexp,
1156 pro_lintbl, pro_gaintbl,
1157 pro_coeffscube, pro_bpm,
1158 pro_corr, pro_diff, package,
1159 coeffs, gain_table, linear_table,
1160 bpm, autocorr_images, diff_flats,
1161 gaint_qclist, lint_qclist, linc_qclist,
1162 bpm_qclist,
1163 1, whichset+ 1,
1164 cur_fset, whichext));
1165 }
1166
1167 end_skip;
1168
1169 /* Free for each extension */
1170
1171 cpl_table_delete(gain_table);
1172 cpl_table_delete(linear_table);
1173 cpl_imagelist_delete(coeffs);
1174 cpl_propertylist_delete(gaint_qclist);
1175 cpl_propertylist_delete(lint_qclist);
1176 cpl_propertylist_delete(linc_qclist);
1177 if(bpm_qclist != NULL) cpl_propertylist_delete(bpm_qclist);
1178 cpl_image_delete(bpm);
1179 cpl_imagelist_delete(autocorr_images);
1180 cpl_imagelist_delete(diff_flats);
1181
1182 return cpl_error_get_code();
1183}
1184
1185
1186/*--------------------------------------------------------------------------*/
1187
1188/*
1189 * @brief Correlate two images with a given range of shifts
1190 * @param image1 Input image
1191 * @param image2 Input image
1192 * @param m Shift to apply on the x-axis
1193 * @param n Shift to apply on the y-axis
1194 * @return An image of size 2m+1 by 2n+1. Each pixel value
1195 * corresponds to the correlation of shift the position
1196 * of the pixel. Pixel in the centre (m+1, n+1),
1197 * corresponds to shift (0,0). Pixels to the left and
1198 * down correspond to negative shifts.
1199 *
1200 * @note At this moment, this function only accepts images to
1201 * have both the same size.
1202 */
1203
1204/*--------------------------------------------------------------------------*/
1205
1206cpl_image *
1207detmon_image_correlate(const cpl_image * image1,
1208 const cpl_image * image2,
1209 const int m, const int n)
1210{
1211 cpl_image *image1_padded = NULL;
1212 cpl_image *image2_padded = NULL;
1213 int nx, ny;
1214 int nx2, ny2;
1215
1216 cpl_image *corr_image_window = NULL;
1217
1218 cpl_image* image_ri1 = NULL;
1219 cpl_image* image_ri2 = NULL;
1220 cpl_error_code err = CPL_ERROR_NONE;
1221
1222 /* Test the entries */
1223 cpl_ensure(image1 != NULL, CPL_ERROR_NULL_INPUT, NULL);
1224 cpl_ensure(image2 != NULL, CPL_ERROR_NULL_INPUT, NULL);
1225
1226 cpl_ensure(m > 0, CPL_ERROR_NULL_INPUT, NULL);
1227 cpl_ensure(n > 0, CPL_ERROR_NULL_INPUT, NULL);
1228
1229 nx = cpl_image_get_size_x(image1);
1230 ny = cpl_image_get_size_y(image1);
1231
1232 nx2 = cpl_image_get_size_x(image2);
1233 ny2 = cpl_image_get_size_y(image2);
1234
1235 /* At this moment, the images must be of the same size */
1236 cpl_ensure(nx == nx2 && ny == ny2, CPL_ERROR_ILLEGAL_INPUT, NULL);
1237
1238 /* Pad the images with zeroes to avoid periodical effects of DFT */
1239 image1_padded = cpl_image_new(nx + 2 * m, ny + 2 * n, CPL_TYPE_FLOAT);
1240 cpl_image_copy(image1_padded, image1, m + 1, n + 1);
1241
1242 image2_padded = cpl_image_new(nx + 2 * m, ny + 2 * n, CPL_TYPE_FLOAT);
1243 cpl_image_copy(image2_padded, image2, m + 1, n + 1);
1244
1245 /*New dimensions of the padded images */
1246 nx = nx + 2 * m;
1247 ny = ny + 2 * n;
1248
1249 image_ri1 = cpl_image_new(nx, ny, CPL_TYPE_FLOAT_COMPLEX);
1250 image_ri2 = cpl_image_new(nx, ny , CPL_TYPE_FLOAT_COMPLEX);
1251 /* Actually perform the FFT */
1252 cpl_fft_image(image_ri1, image1_padded, CPL_FFT_FORWARD);
1253 cpl_fft_image(image_ri2, image2_padded, CPL_FFT_FORWARD);
1254 err = cpl_error_get_code();
1255 cpl_image_delete(image1_padded);
1256 image1_padded = NULL;
1257 cpl_image_delete(image2_padded);
1258 image2_padded = NULL;
1259 if (err == CPL_ERROR_NONE)
1260 {
1261 /* Cleanup resources */
1262 cpl_image * corr_image = NULL;
1263 cpl_image * reorganised= NULL;
1264 cpl_image * image_ri_inv = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
1265 cpl_image * image_in_inv = cpl_image_new(nx, ny,
1266 CPL_TYPE_FLOAT_COMPLEX);
1267 int i,j;
1268
1269 for (i = 1; i <= nx; i++)
1270 {
1271 for (j = 1; j <= ny; j++)
1272 {
1273 int rej = 0;
1274 double complex value1, value2, value;
1275 value1 = cpl_image_get_complex(image_ri1, i, j, &rej);
1276 value2 = cpl_image_get_complex(image_ri2, i, j, &rej);;
1277 value = conj(value1) * value2;
1278 cpl_image_set_complex(image_in_inv, i, j, value);
1279 }
1280 }
1281 cpl_image_delete(image_ri1);
1282 image_ri1 = NULL;
1283 cpl_image_delete(image_ri2);
1284 image_ri2 = NULL;
1285
1286 err = cpl_error_get_code();
1287 if (err == CPL_ERROR_NONE)
1288 {
1289
1290 /* Actually perform the FFT */
1291 cpl_fft_image(image_ri_inv, image_in_inv,CPL_FFT_BACKWARD);
1292 cpl_image_delete(image_in_inv);
1293
1294 /* Get the module of the inversed signal */
1295 corr_image = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
1296 for (i = 1; i <= nx; i++)
1297 {
1298 for (j = 1; j <= ny; j++)
1299 {
1300 int rej = 0;
1301 double value =0;
1302 value = cpl_image_get(image_ri_inv, i, j, &rej);
1303 cpl_image_set(corr_image, i, j, value);
1304 }
1305 }
1306 cpl_image_delete(image_ri_inv);
1307 err = cpl_error_get_code();
1308 if (err == CPL_ERROR_NONE)
1309 {
1310 /* Reorganise the pixels to the output */
1311 cpl_image * image =
1312 cpl_image_extract(corr_image, nx / 2 + 1, 1, nx, ny);
1313 reorganised = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
1314
1315 cpl_image_copy(reorganised, image, 1, 1);
1316 cpl_image_delete(image);
1317 image = cpl_image_extract(corr_image, 1, 1, nx / 2, ny);
1318 cpl_image_copy(reorganised, image, nx / 2 + 1, 1);
1319 cpl_image_delete(image);
1320
1321 cpl_image_delete(corr_image);
1322
1323 corr_image = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
1324 image = cpl_image_extract(reorganised, 1, ny / 2 + 1, nx, ny);
1325 cpl_image_copy(corr_image, image, 1, 1);
1326 cpl_image_delete(image);
1327
1328 image = cpl_image_extract(reorganised, 1, 1, nx, ny / 2);
1329 cpl_image_copy(corr_image, image, 1, ny / 2 + 1);
1330 cpl_image_delete(image);
1331 /* Extract a window with the desired shifts */
1332 corr_image_window = cpl_image_extract(corr_image,
1333 nx / 2 + 1 - m,
1334 ny / 2 + 1 - n,
1335 nx / 2 + 1 + m, ny / 2 + 1 + n);
1336 }
1337 /* Free and return */
1338
1339 }
1340 cpl_image_delete(reorganised);
1341 cpl_image_delete(corr_image);
1342
1343 if(cpl_image_divide_scalar(corr_image_window,
1344 cpl_image_get_max(corr_image_window))) {
1345 cpl_image_delete(corr_image_window);
1346 return NULL;
1347 }
1348 }
1349 cpl_image_delete (image_ri1);
1350 cpl_image_delete (image_ri2);
1351 cpl_image_delete (image1_padded);
1352 cpl_image_delete (image2_padded);
1353 return corr_image_window;
1354}
1355
1356
1357
1358/*--------------------------------------------------------------------------*/
1359
1360/*
1361 * @brief Autocorrelate an image with a given range of shifts, using
1362 * cpl_image_fft()
1363 * @param input2 Input image
1364 * @param m Shift to apply on the x-axis
1365 * @param n Shift to apply on the y-axis
1366 * @return An image of size 2m+1 by 2n+1. Each pixel value
1367 * corresponds to the correlation of shift the position
1368 * of the pixel. Pixel in the centre (m+1, n+1),
1369 * corresponds to shift (0,0). Pixels to the left and
1370 * down correspond to negative shifts.
1371 */
1372
1373/*--------------------------------------------------------------------------*/
1374
1375cpl_image *
1376detmon_autocorrelate(const cpl_image * input2, const int m,
1377 const int n)
1378{
1379 cpl_image *im_re = NULL;
1380 cpl_image *im_im = NULL;
1381 int nx, ny;
1382 cpl_image *ifft_re = NULL;
1383 cpl_image *ifft_im = NULL;
1384 cpl_image *autocorr = NULL;
1385 cpl_image *autocorr_norm_double = NULL;
1386 cpl_image *autocorr_norm = NULL;
1387 cpl_image *reorganised = NULL;
1388 cpl_image *image = NULL;
1389 int p;
1390 cpl_error_code error;
1391 cpl_image *input;
1392
1393 cpl_ensure(input2 != NULL, CPL_ERROR_NULL_INPUT, NULL);
1394
1395 cpl_ensure(m > 0, CPL_ERROR_NULL_INPUT, NULL);
1396 cpl_ensure(n > 0, CPL_ERROR_NULL_INPUT, NULL);
1397
1398 nx = cpl_image_get_size_x(input2) + 2 * m;
1399 ny = cpl_image_get_size_y(input2) + 2 * n;
1400
1401 p = 128;
1402 while(nx > p || ny > p) {
1403 p *= 2;
1404 }
1405
1406 input = cpl_image_cast(input2, CPL_TYPE_DOUBLE);
1407
1408 im_re = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
1409 error = cpl_image_copy(im_re, input, 1, 1);
1410 cpl_image_delete(input);
1411
1412 cpl_ensure(!error, error, NULL);
1413
1414 im_im = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
1415
1416 error = cpl_image_fft(im_re, im_im, CPL_FFT_DEFAULT);
1417 cpl_ensure(!error, error, NULL);
1418
1419 ifft_re = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
1420 error = cpl_image_power(im_re, 2);
1421 cpl_ensure(!error, error, NULL);
1422
1423 error = cpl_image_add(ifft_re, im_re);
1424 cpl_ensure(!error, error, NULL);
1425
1426 cpl_image_delete(im_re);
1427
1428 error = cpl_image_power(im_im, 2);
1429 cpl_ensure(!error, error, NULL);
1430
1431 error = cpl_image_add(ifft_re, im_im);
1432 cpl_ensure(!error, error, NULL);
1433
1434 cpl_image_delete(im_im);
1435
1436 ifft_im = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
1437
1438 error = cpl_image_fft(ifft_re, ifft_im, CPL_FFT_INVERSE);
1439 cpl_ensure(!error, error, NULL);
1440
1441 autocorr = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
1442
1443 error = cpl_image_power(ifft_re, 2);
1444 cpl_ensure(!error, error, NULL);
1445
1446 error = cpl_image_add(autocorr, ifft_re);
1447 cpl_ensure(!error, error, NULL);
1448
1449 cpl_image_delete(ifft_re);
1450
1451 error = cpl_image_power(ifft_im, 2);
1452 cpl_ensure(!error, error, NULL);
1453
1454 error = cpl_image_add(autocorr, ifft_im);
1455 cpl_ensure(!error, error, NULL);
1456
1457 cpl_image_delete(ifft_im);
1458
1459 /* Reorganise the pixels to the output */
1460 reorganised = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
1461
1462 image = cpl_image_extract(autocorr, p / 2 + 1, 1, p, p);
1463 cpl_image_copy(reorganised, image, 1, 1);
1464 cpl_image_delete(image);
1465
1466 image = cpl_image_extract(autocorr, 1, 1, p / 2, p);
1467 cpl_image_copy(reorganised, image, p / 2 + 1, 1);
1468 cpl_image_delete(image);
1469
1470 cpl_image_delete(autocorr);
1471
1472 autocorr = cpl_image_new(p, p, CPL_TYPE_DOUBLE);
1473
1474 image = cpl_image_extract(reorganised, 1, p / 2 + 1, p, p);
1475 cpl_image_copy(autocorr, image, 1, 1);
1476 cpl_image_delete(image);
1477
1478 image = cpl_image_extract(reorganised, 1, 1, p, p / 2);
1479 cpl_image_copy(autocorr, image, 1, p / 2 + 1);
1480 cpl_image_delete(image);
1481
1482 cpl_image_delete(reorganised);
1483
1484 autocorr_norm_double =
1485 cpl_image_extract(autocorr, p / 2 + 1 - m, p / 2 + 1 - n,
1486 p / 2 + 1 + m, p / 2 + 1 + n);
1487
1488 cpl_image_delete(autocorr);
1489
1490 if(cpl_image_divide_scalar(autocorr_norm_double,
1491 cpl_image_get_max(autocorr_norm_double))) {
1492 cpl_image_delete(autocorr_norm_double);
1493 cpl_ensure(0, cpl_error_get_code(), NULL);
1494 }
1495
1496
1497 autocorr_norm = cpl_image_cast(autocorr_norm_double, CPL_TYPE_FLOAT);
1498 cpl_image_delete(autocorr_norm_double);
1499
1500 return autocorr_norm;
1501}
1502
1503/*---------------------------------------------------------------------------*/
1514/*---------------------------------------------------------------------------*/
1515cpl_error_code
1516detmon_lg_fill_parlist_nir_default(cpl_parameterlist * parlist,
1517 const char *recipe_name,
1518 const char *pipeline_name)
1519{
1520 const cpl_error_code error =
1521 detmon_lg_fill_parlist(parlist, recipe_name, pipeline_name,
1522 "PTC", /* --method */
1523 3, /* --order */
1524 3., /* --kappa */
1525 5, /* --niter */
1526 -1, /* --llx */
1527 -1, /* --lly */
1528 -1, /* --urx */
1529 -1, /* --ury */
1530 10000, /* --ref_level */
1531 "CPL_FALSE", /* --intermediate */
1532 "CPL_FALSE", /* --autocorr */
1533 "CPL_FALSE", /* --collapse */
1534 "CPL_TRUE", /* --rescale */
1535 "CPL_TRUE",/* --pix2pix */
1536 "CPL_FALSE", /* --bpmbin */
1537 -1, /* --filter */
1538 26, /* --m */
1539 26, /* --n */
1540 1e-3, /* --tolerance */
1541 "CPL_FALSE", /* --pafgen */
1542 recipe_name, /* --pafname */
1543 -1, /* --llx1 */
1544 -1, /* --lly1 */
1545 -1, /* --urx1 */
1546 -1, /* --ury1 */
1547 -1, /* --llx2 */
1548 -1, /* --lly2 */
1549 -1, /* --urx2 */
1550 -1, /* --ury2 */
1551 -1, /* --llx3 */
1552 -1, /* --lly3 */
1553 -1, /* --urx3 */
1554 -1, /* --ury3 */
1555 -1, /* --llx4 */
1556 -1, /* --lly4 */
1557 -1, /* --urx4 */
1558 -1, /* --ury4 */
1559 -1, /* --llx5 */
1560 -1, /* --lly5 */
1561 -1, /* --urx5 */
1562 -1, /* --ury5 */
1563 0, /* --exts */
1564 NIR); /* This is to specify OPT params */
1565
1566
1567 cpl_ensure_code(!error, error);
1568
1569 return cpl_error_get_code();
1570}
1571
1572/*---------------------------------------------------------------------------*/
1583/*---------------------------------------------------------------------------*/
1584cpl_error_code
1585detmon_lg_fill_parlist_opt_default(cpl_parameterlist * parlist,
1586 const char *recipe_name,
1587 const char *pipeline_name)
1588{
1589 const cpl_error_code error =
1590 detmon_lg_fill_parlist(parlist, recipe_name, pipeline_name,
1591 "PTC", /* --method */
1592 3, /* --order */
1593 3., /* --kappa */
1594 5, /* --niter */
1595 -1, /* --llx */
1596 -1, /* --lly */
1597 -1, /* --urx */
1598 -1, /* --ury */
1599 10000, /* --ref_level */
1600 "CPL_FALSE", /* --intermediate */
1601 "CPL_FALSE", /* --autocorr */
1602 "CPL_TRUE", /* --collapse */
1603 "CPL_TRUE", /* --rescale */
1604 "CPL_FALSE", /* --pix2pix */
1605 "CPL_FALSE", /* --bpmbin */
1606 -1, /* --filter */
1607 26, /* --m */
1608 26, /* --n */
1609 1e-3, /* --tolerance */
1610 "CPL_FALSE", /* --pafgen */
1611 recipe_name, /* --pafname */
1612 -1, /* --llx1 */
1613 -1, /* --lly1 */
1614 -1, /* --urx1 */
1615 -1, /* --ury1 */
1616 -1, /* --llx2 */
1617 -1, /* --lly2 */
1618 -1, /* --urx2 */
1619 -1, /* --ury2 */
1620 -1, /* --llx3 */
1621 -1, /* --lly3 */
1622 -1, /* --urx3 */
1623 -1, /* --ury3 */
1624 -1, /* --llx4 */
1625 -1, /* --lly4 */
1626 -1, /* --urx4 */
1627 -1, /* --ury4 */
1628 -1, /* --llx5 */
1629 -1, /* --lly5 */
1630 -1, /* --urx5 */
1631 -1, /* --ury5 */
1632 0, /* --exts */
1633 OPT); /* This is to specify OPT params */
1634
1635 cpl_ensure_code(!error, error);
1636
1637 return cpl_error_get_code();
1638}
1639
1640static cpl_error_code
1641detmon_lg_fill_parlist_default_mr(cpl_parameterlist * parlist,
1642 const char *recipe_name,
1643 const char *pipeline_name)
1644{
1645 char * group_name = cpl_sprintf("%s.%s", pipeline_name, recipe_name);
1646 char * par_name = cpl_sprintf("%s.%s", group_name, "regions-file");
1647 cpl_parameter * p = cpl_parameter_new_value(par_name, CPL_TYPE_STRING,
1648 "File containing regions, "
1649 "four comma separated points "
1650 "per line",
1651 group_name, "");
1652 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "regions-file");
1653 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
1654 cpl_parameterlist_append(parlist, p);
1655 cpl_free(par_name);
1656 cpl_free(group_name);
1657
1658 group_name = cpl_sprintf("%s.%s", pipeline_name, recipe_name);
1659 par_name = cpl_sprintf("%s.%s", group_name, "regions");
1660 p = cpl_parameter_new_value(par_name, CPL_TYPE_STRING,
1661 "Colon separated list of regions, four "
1662 "points each, comma separated: "
1663 "llx,lly,urx,ury:llx,...",
1664 group_name, "");
1665 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "regions");
1666 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
1667 cpl_parameterlist_append(parlist, p);
1668 cpl_free(par_name);
1669 cpl_free(group_name);
1670
1671 return cpl_error_get_code();
1672}
1673
1674cpl_error_code
1675detmon_lg_fill_parlist_opt_default_mr(cpl_parameterlist * parlist,
1676 const char *recipe_name,
1677 const char *pipeline_name)
1678{
1679 detmon_lg_fill_parlist_opt_default(parlist, recipe_name, pipeline_name);
1680 detmon_lg_fill_parlist_default_mr(parlist, recipe_name, pipeline_name);
1681 return cpl_error_get_code();
1682}
1683
1684cpl_error_code
1685detmon_lg_fill_parlist_nir_default_mr(cpl_parameterlist * parlist,
1686 const char *recipe_name,
1687 const char *pipeline_name)
1688{
1689 detmon_lg_fill_parlist_nir_default(parlist, recipe_name, pipeline_name);
1690 detmon_lg_fill_parlist_default_mr(parlist, recipe_name, pipeline_name);
1691
1692 return cpl_error_get_code();
1693}
1694
1695
1696/*---------------------------------------------------------------------------*/
1750/*---------------------------------------------------------------------------*/
1751cpl_error_code
1752detmon_lg_fill_parlist(cpl_parameterlist * parlist,
1753 const char *recipe_name, const char *pipeline_name,
1754 const char *method,
1755 int order,
1756 double kappa,
1757 int niter,
1758 int llx,
1759 int lly,
1760 int urx,
1761 int ury,
1762 int ref_level,
1763 const char *intermediate,
1764 const char *autocorr,
1765 const char *collapse,
1766 const char *rescale,
1767 const char *pix2pix,
1768 const char *bpmbin,
1769 int filter,
1770 int m,
1771 int n,
1772 double tolerance,
1773 const char *pafgen,
1774 const char * pafname,
1775 int llx1,
1776 int lly1,
1777 int urx1,
1778 int ury1,
1779 int llx2,
1780 int lly2,
1781 int urx2,
1782 int ury2,
1783 int llx3,
1784 int lly3,
1785 int urx3,
1786 int ury3,
1787 int llx4,
1788 int lly4,
1789 int urx4,
1790 int ury4,
1791 int llx5, int lly5, int urx5, int ury5, int exts,
1792 cpl_boolean opt_nir)
1793{
1794 const cpl_error_code error =
1795 detmon_fill_parlist(parlist, recipe_name, pipeline_name, 26,
1796 "method",
1797 "Method to be used when computing GAIN. Methods appliable: <PTC | MED>. By default PTC method will be applied.",
1798 "CPL_TYPE_STRING", method,
1799
1800 "order",
1801 "Polynomial order for the fit (Linearity)",
1802 "CPL_TYPE_INT", order,
1803 "kappa",
1804 "Kappa value for the kappa-sigma clipping (Gain)",
1805 "CPL_TYPE_DOUBLE", kappa,
1806 "niter",
1807 "Number of iterations to compute rms (Gain)",
1808 "CPL_TYPE_INT", niter,
1809 "llx",
1810 "x coordinate of the lower-left "
1811 "point of the region of interest. If not modified, default value will be 1.",
1812 "CPL_TYPE_INT", llx,
1813 "lly",
1814 "y coordinate of the lower-left "
1815 "point of the region of interest. If not modified, default value will be 1.",
1816 "CPL_TYPE_INT", lly,
1817 "urx",
1818 "x coordinate of the upper-right "
1819 "point of the region of interest. If not modified, default value will be X dimension of the input image.",
1820 "CPL_TYPE_INT", urx,
1821 "ury",
1822 "y coordinate of the upper-right "
1823 "point of the region of interest. If not modified, default value will be Y dimension of the input image.",
1824 "CPL_TYPE_INT", ury,
1825 "ref_level",
1826 "User reference level",
1827 "CPL_TYPE_INT", ref_level,
1828 "intermediate",
1829 "De-/Activate intermediate products",
1830 "CPL_TYPE_BOOL", intermediate,
1831
1832 "autocorr",
1833 "De-/Activate the autocorr option",
1834 "CPL_TYPE_BOOL", autocorr,
1835
1836 "collapse",
1837 "De-/Activate the collapse option",
1838 "CPL_TYPE_BOOL", collapse,
1839 "rescale",
1840 "De-/Activate the image rescale option",
1841 "CPL_TYPE_BOOL", rescale,
1842 "pix2pix",
1843 "De-/Activate the computation with pixel to pixel accuracy",
1844 "CPL_TYPE_BOOL", pix2pix,
1845 "bpmbin",
1846 "De-/Activate the binary bpm option",
1847 "CPL_TYPE_BOOL", bpmbin,
1848 "m",
1849 "Maximum x-shift for the autocorr",
1850 "CPL_TYPE_INT", m,
1851 "filter",
1852 "Upper limit of Median flux to be filtered",
1853 "CPL_TYPE_INT", filter,
1854 "n",
1855 "Maximum y-shift for the autocorr",
1856 "CPL_TYPE_INT", n,
1857 "tolerance",
1858 "Tolerance for pair discrimination",
1859 "CPL_TYPE_DOUBLE", tolerance,
1860
1861 "pafgen",
1862 "Generate PAF file",
1863 "CPL_TYPE_BOOL", pafgen,
1864 "pafname",
1865 "Specific name for PAF file",
1866 "CPL_TYPE_STRING", pafname,
1867
1868
1869 "exts",
1870 "Activate the multi-exts option. Choose -1 to process all extensions. Choose an extension number"
1871 " to process the appropriate extension.",
1872 "CPL_TYPE_INT", exts,
1873
1874 "fpn_method",
1875 "Method for computing Fixed Pattern Noise (SMOOTH or HISTOGRAM)",
1876 "CPL_TYPE_STRING", "HISTOGRAM",
1877
1878 "fpn_smooth",
1879 "template size in pixels for smoothing during FPN computation (only for SMOOTH method)",
1880 "CPL_TYPE_INT", 13,
1881
1882 "saturation_limit",
1883 "all frames with mean saturation above the limit would not be used in linearity calculation",
1884 "CPL_TYPE_DOUBLE", 65535.0,
1885
1886 "gain_threshold",
1887 "all frames with mean flux above the threshold would not be used in gain calculation",
1888 "CPL_TYPE_DOUBLE", 65535.0
1889
1890 );
1891 detmon_fill_parlist(parlist, recipe_name, pipeline_name, 1,
1892 "coeffs_cube_split",
1893 "if TRUE, the recipe writes as many "
1894 "COEFFS_CUBE_Pi (i=0..order) as the value of "
1895 "the order parameter in a separate file",
1896 "CPL_TYPE_BOOL", "CPL_FALSE");
1897 /* OPT specific parameters */
1898 if(opt_nir == FALSE) {
1899 const cpl_error_code erroropt =
1900 detmon_fill_parlist(parlist, recipe_name, pipeline_name, 20,
1901 "llx1",
1902 "x coord of the lower-left point of the first "
1903 "field used for contamination measurement. If not modified, default value will be 1.",
1904 "CPL_TYPE_INT", llx1,
1905 "lly1",
1906 "y coord of the lower-left point of the first "
1907 "field used for contamination measurement. If not modified, default value will be 1.",
1908 "CPL_TYPE_INT", lly1,
1909 "urx1",
1910 "x coord of the upper-right point of the first "
1911 "field used for contamination measurement. If not modified, default value will be X dimension of the input image.",
1912 "CPL_TYPE_INT", urx1,
1913 "ury1",
1914 "y coord of the upper-right point of the first "
1915 "field used for contamination measurement. If not modified, default value will be Y dimension of the input image.",
1916 "CPL_TYPE_INT", ury1,
1917 "llx2",
1918 "x coord of the lower-left point of the second "
1919 "field used for contamination measurement. If not modified, default value will be 1.",
1920 "CPL_TYPE_INT", llx2,
1921 "lly2",
1922 "y coord of the lower-left point of the second "
1923 "field used for contamination measurement. If not modified, default value will be 1.",
1924 "CPL_TYPE_INT", lly2,
1925 "urx2",
1926 "x coord of the upper-right point of the second "
1927 "field used for contamination measurement. If not modified, default value will be half of the X dimension of the input image.",
1928 "CPL_TYPE_INT", urx2,
1929 "ury2",
1930 "y coord of the upper-right point of the second "
1931 "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
1932 "CPL_TYPE_INT", ury2,
1933 "llx3",
1934 "x coord of the lower-left point of the third "
1935 "field used for contamination measurement. If not modified, default value will be 1.",
1936 "CPL_TYPE_INT", llx3,
1937 "lly3",
1938 "y coord of the lower-left point of the third "
1939 "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
1940 "CPL_TYPE_INT", lly3,
1941 "urx3",
1942 "x coord of the upper-right point of the third "
1943 "field used for contamination measurement. If not modified, default value will be half of X dimension of the image.",
1944 "CPL_TYPE_INT", urx3,
1945 "ury3",
1946 "y coord of the upper-right point of the third "
1947 "field used for contamination measurement. If not modified, default value will be Y dimension of the image.",
1948 "CPL_TYPE_INT", ury3,
1949 "llx4",
1950 "x coord of the lower-left point of the fourth "
1951 "field used for contamination measurement. If not modified, default value will be half of X dimension of the image.",
1952 "CPL_TYPE_INT", llx4,
1953 "lly4",
1954 "y coord of the lower-left point of the fourth "
1955 "field used for contamination measurement. If not modified, default value will be half of the Y dimension of the input image.",
1956 "CPL_TYPE_INT", lly4,
1957 "urx4",
1958 "x coord of the upper-right point of the fourth "
1959 "field used for contamination measurement. If not modified, default value will be X dimension of the image.",
1960 "CPL_TYPE_INT", urx4,
1961 "ury4",
1962 "y coord of the upper-right point of the fourth "
1963 "field used for contamination measurement. If not modified, default value will be Y dimension of the input image.",
1964 "CPL_TYPE_INT", ury4,
1965 "llx5",
1966 "x coord of the lower-left point of the fifth "
1967 "field used for contamination measurement. If not modified, default value will be half of the X dimension of the input image.",
1968 "CPL_TYPE_INT", llx5,
1969 "lly5",
1970 "y coord of the lower-left point of the fifth "
1971 "field used for contamination measurement. If not modified, default value will be 1.",
1972 "CPL_TYPE_INT", lly5,
1973 "urx5",
1974 "x coord of the upper-right point of the fifth "
1975 "field used for contamination measurement. If not modified, default value will be X dimension of the image.",
1976 "CPL_TYPE_INT", urx5,
1977
1978 "ury5",
1979 "y coord of the upper-right point of the fifth "
1980 "field used for contamination measurement. If not modified, default value will be half of Y dimension of the input image.",
1981 "CPL_TYPE_INT", ury5);
1982
1983
1984 cpl_ensure_code(!erroropt, erroropt);
1985 }
1986
1987 cpl_ensure_code(!error, error);
1988
1989 return cpl_error_get_code();
1990}
1991
1992/*---------------------------------------------------------------------------*/
2001/*---------------------------------------------------------------------------*/
2002static cpl_error_code
2003detmon_lg_retrieve_parlist(const char * pipeline_name,
2004 const char * recipe_name,
2005 const cpl_parameterlist * parlist,
2006 cpl_boolean opt_nir)
2007{
2008
2009 char * par_name;
2010 const cpl_parameter * par;
2011
2012 /* --method */
2013 par_name = cpl_sprintf("%s.%s.method", pipeline_name, recipe_name);
2014 assert(par_name != NULL);
2015 par = cpl_parameterlist_find_const(parlist, par_name);
2016 detmon_lg_config.method = cpl_parameter_get_string(par);
2017 cpl_free(par_name);
2018
2019 /* --order */
2020 detmon_lg_config.order =
2021 detmon_retrieve_par_int("order", pipeline_name, recipe_name,
2022 parlist);
2023
2024 /* --kappa */
2025 detmon_lg_config.kappa =
2026 detmon_retrieve_par_double("kappa", pipeline_name, recipe_name,
2027 parlist);
2028
2029 /* --niter */
2030 detmon_lg_config.niter =
2031 detmon_retrieve_par_int("niter", pipeline_name, recipe_name,
2032 parlist);
2033
2034 /* --llx */
2035 detmon_lg_config.llx =
2036 detmon_retrieve_par_int("llx", pipeline_name, recipe_name,
2037 parlist);
2038
2039 /* --lly */
2040 detmon_lg_config.lly =
2041 detmon_retrieve_par_int("lly", pipeline_name, recipe_name,
2042 parlist);
2043
2044 /* --urx */
2045 detmon_lg_config.urx =
2046 detmon_retrieve_par_int("urx", pipeline_name, recipe_name,
2047 parlist);
2048
2049 /* --ury */
2050 detmon_lg_config.ury =
2051 detmon_retrieve_par_int("ury", pipeline_name, recipe_name,
2052 parlist);
2053
2054 /* --ref_level */
2055 detmon_lg_config.ref_level =
2056 detmon_retrieve_par_int("ref_level", pipeline_name, recipe_name,
2057 parlist);
2058
2059 /* --intermediate */
2060 par_name =
2061 cpl_sprintf("%s.%s.intermediate", pipeline_name, recipe_name);
2062 assert(par_name != NULL);
2063 par = cpl_parameterlist_find_const(parlist, par_name);
2064 detmon_lg_config.intermediate = cpl_parameter_get_bool(par);
2065 cpl_free(par_name);
2066
2067 /* --autocorr */
2068 par_name = cpl_sprintf("%s.%s.autocorr", pipeline_name, recipe_name);
2069 assert(par_name != NULL);
2070 par = cpl_parameterlist_find_const(parlist, par_name);
2071 detmon_lg_config.autocorr = cpl_parameter_get_bool(par);
2072 cpl_free(par_name);
2073
2074 /* --coeffs_cube_split */
2075 par_name = cpl_sprintf("%s.%s.coeffs_cube_split", pipeline_name, recipe_name);
2076 assert(par_name != NULL);
2077 par = cpl_parameterlist_find_const(parlist, par_name);
2078 detmon_lg_config.split_coeffs = cpl_parameter_get_bool(par);
2079 cpl_free(par_name);
2080
2081 /* --collapse */
2082 par_name = cpl_sprintf("%s.%s.collapse", pipeline_name, recipe_name);
2083 assert(par_name != NULL);
2084 par = cpl_parameterlist_find_const(parlist, par_name);
2085 detmon_lg_config.collapse = cpl_parameter_get_bool(par);
2086 cpl_free(par_name);
2087
2088 /* --rescale */
2089 par_name = cpl_sprintf("%s.%s.rescale", pipeline_name, recipe_name);
2090 assert(par_name != NULL);
2091 par = cpl_parameterlist_find_const(parlist, par_name);
2092 detmon_lg_config.rescale = cpl_parameter_get_bool(par);
2093 cpl_free(par_name);
2094
2095 /* --pix2pix */
2096 par_name = cpl_sprintf("%s.%s.pix2pix", pipeline_name, recipe_name);
2097 assert(par_name != NULL);
2098 par = cpl_parameterlist_find_const(parlist, par_name);
2099 detmon_lg_config.pix2pix = cpl_parameter_get_bool(par);
2100 cpl_free(par_name);
2101
2102 /* --bpmbin */
2103 par_name = cpl_sprintf("%s.%s.bpmbin", pipeline_name, recipe_name);
2104 assert(par_name != NULL);
2105 par = cpl_parameterlist_find_const(parlist, par_name);
2106 detmon_lg_config.bpmbin = cpl_parameter_get_bool(par);
2107 cpl_free(par_name);
2108
2109 /* --filter */
2110 detmon_lg_config.filter =
2111 detmon_retrieve_par_int("filter", pipeline_name,
2112 recipe_name, parlist);
2113
2114 /* --m */
2115 detmon_lg_config.m =
2116 detmon_retrieve_par_int("m", pipeline_name, recipe_name, parlist);
2117
2118 /* --n */
2119 detmon_lg_config.n =
2120 detmon_retrieve_par_int("n", pipeline_name, recipe_name, parlist);
2121
2122 /* --tolerance */
2123 par_name = cpl_sprintf("%s.%s.tolerance", pipeline_name, recipe_name);
2124 assert(par_name != NULL);
2125 par = cpl_parameterlist_find_const(parlist, par_name);
2126 detmon_lg_config.tolerance = cpl_parameter_get_double(par);
2127 cpl_free(par_name);
2128
2129
2130 /* --pafgen */
2131 par_name = cpl_sprintf("%s.%s.pafgen", pipeline_name, recipe_name);
2132 assert(par_name != NULL);
2133 par = cpl_parameterlist_find_const(parlist, par_name);
2134 detmon_lg_config.pafgen = cpl_parameter_get_bool(par);
2135 cpl_free(par_name);
2136
2137 /* --pafname */
2138 par_name = cpl_sprintf("%s.%s.pafname", pipeline_name, recipe_name);
2139 assert(par_name != NULL);
2140 par = cpl_parameterlist_find_const(parlist, par_name);
2141 detmon_lg_config.pafname = cpl_parameter_get_string(par);
2142 cpl_free(par_name);
2143
2144 if(opt_nir == OPT) {
2145 /* --llx1 */
2146 detmon_lg_config.llx1 =
2147 detmon_retrieve_par_int("llx1", pipeline_name, recipe_name,
2148 parlist);
2149
2150 /* --lly1 */
2151 detmon_lg_config.lly1 =
2152 detmon_retrieve_par_int("lly1", pipeline_name, recipe_name,
2153 parlist);
2154
2155 /* --urx1 */
2156 detmon_lg_config.urx1 =
2157 detmon_retrieve_par_int("urx1", pipeline_name, recipe_name,
2158 parlist);
2159
2160 /* --ury1 */
2161 detmon_lg_config.ury1 =
2162 detmon_retrieve_par_int("ury1", pipeline_name, recipe_name,
2163 parlist);
2164
2165 /* --llx2 */
2166 detmon_lg_config.llx2 =
2167 detmon_retrieve_par_int("llx2", pipeline_name, recipe_name,
2168 parlist);
2169
2170 /* --lly2 */
2171 detmon_lg_config.lly2 =
2172 detmon_retrieve_par_int("lly2", pipeline_name, recipe_name,
2173 parlist);
2174
2175 /* --urx2 */
2176 detmon_lg_config.urx2 =
2177 detmon_retrieve_par_int("urx2", pipeline_name, recipe_name,
2178 parlist);
2179
2180 /* --ury2 */
2181 detmon_lg_config.ury2 =
2182 detmon_retrieve_par_int("ury2", pipeline_name, recipe_name,
2183 parlist);
2184
2185 /* --llx3 */
2186 detmon_lg_config.llx3 =
2187 detmon_retrieve_par_int("llx3", pipeline_name, recipe_name,
2188 parlist);
2189
2190 /* --lly3 */
2191 detmon_lg_config.lly3 =
2192 detmon_retrieve_par_int("lly3", pipeline_name, recipe_name,
2193 parlist);
2194
2195 /* --urx3 */
2196 detmon_lg_config.urx3 =
2197 detmon_retrieve_par_int("urx3", pipeline_name, recipe_name,
2198 parlist);
2199
2200 /* --ury3 */
2201 detmon_lg_config.ury3 =
2202 detmon_retrieve_par_int("ury3", pipeline_name, recipe_name,
2203 parlist);
2204
2205 /* --llx4 */
2206 detmon_lg_config.llx4 =
2207 detmon_retrieve_par_int("llx4", pipeline_name, recipe_name,
2208 parlist);
2209
2210 /* --lly4 */
2211 detmon_lg_config.lly4 =
2212 detmon_retrieve_par_int("lly4", pipeline_name, recipe_name,
2213 parlist);
2214
2215 /* --urx4 */
2216 detmon_lg_config.urx4 =
2217 detmon_retrieve_par_int("urx4", pipeline_name, recipe_name,
2218 parlist);
2219
2220 /* --ury4 */
2221 detmon_lg_config.ury4 =
2222 detmon_retrieve_par_int("ury4", pipeline_name, recipe_name,
2223 parlist);
2224
2225 /* --llx5 */
2226 detmon_lg_config.llx5 =
2227 detmon_retrieve_par_int("llx5", pipeline_name, recipe_name,
2228 parlist);
2229
2230 /* --lly5 */
2231 detmon_lg_config.lly5 =
2232 detmon_retrieve_par_int("lly5", pipeline_name, recipe_name,
2233 parlist);
2234
2235 /* --urx5 */
2236 detmon_lg_config.urx5 =
2237 detmon_retrieve_par_int("urx5", pipeline_name, recipe_name,
2238 parlist);
2239
2240 /* --ury5 */
2241 detmon_lg_config.ury5 =
2242 detmon_retrieve_par_int("ury5", pipeline_name, recipe_name,
2243 parlist);
2244 }
2245
2246 /* --exts */
2247 detmon_lg_config.exts =
2248 detmon_retrieve_par_int("exts", pipeline_name, recipe_name,
2249 parlist);
2250 /* --fpn_method */
2251 {
2252 detmon_lg_config.fpn_method = FPN_HISTOGRAM;
2253 par_name =
2254 cpl_sprintf("%s.%s.fpn_method", pipeline_name, recipe_name);
2255 assert(par_name != NULL);
2256 par = cpl_parameterlist_find_const(parlist, par_name);
2257 if (par)
2258 {
2259 const char * str_method = cpl_parameter_get_string(par);
2260 if (strcmp(str_method, "SMOOTH") == 0)
2261 {
2262 detmon_lg_config.fpn_method = FPN_SMOOTH;
2263 }
2264 else if (strcmp(str_method, "HISTOGRAM") == 0)
2265 {
2266 detmon_lg_config.fpn_method = FPN_HISTOGRAM;
2267 }
2268 }
2269 cpl_free(par_name);
2270 }
2271 /* --fpn_smooth */
2272 detmon_lg_config.fpn_smooth =
2273 detmon_retrieve_par_int("fpn_smooth", pipeline_name, recipe_name,
2274 parlist);
2275 /* --saturation_limit*/
2276 {
2277 detmon_lg_config.saturation_limit = 65535;
2278 par_name =
2279 cpl_sprintf("%s.%s.saturation_limit", pipeline_name, recipe_name);
2280 assert(par_name != NULL);
2281 par = cpl_parameterlist_find_const(parlist, par_name);
2282 if (par)
2283 {
2284 detmon_lg_config.saturation_limit = cpl_parameter_get_double(par);
2285 }
2286 cpl_free(par_name);
2287 }
2288
2289 /* --gain_threshold*/
2290 {
2291 detmon_lg_config.gain_threshold = 0;
2292 par_name =
2293 cpl_sprintf("%s.%s.gain_threshold", pipeline_name, recipe_name);
2294 assert(par_name != NULL);
2295 par = cpl_parameterlist_find_const(parlist, par_name);
2296 if (par)
2297 {
2298 detmon_lg_config.gain_threshold = cpl_parameter_get_double(par);
2299 }
2300 cpl_free(par_name);
2301 }
2302
2303 if(cpl_error_get_code())
2304 {
2305 cpl_msg_error(cpl_func, "Failed to retrieve the input parameters");
2306 cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
2307 }
2308
2309
2310 return cpl_error_get_code();
2311}
2312
2313/*---------------------------------------------------------------------------*/
2319/*---------------------------------------------------------------------------*/
2320static cpl_error_code
2321detmon_lg_check_defaults(const cpl_image * reference)
2322{
2323 const int nx = cpl_image_get_size_x(reference);
2324 const int ny = cpl_image_get_size_y(reference);
2325
2326 detmon_lg_config.nx = nx;
2327 detmon_lg_config.ny = ny;
2328
2329 detmon_lg_config.wholechip = CPL_FALSE;
2330
2331 if(detmon_lg_config.llx == -1)
2332 detmon_lg_config.llx = 1;
2333 if(detmon_lg_config.lly == -1)
2334 detmon_lg_config.lly = 1;
2335 if(detmon_lg_config.urx == -1)
2336 detmon_lg_config.urx = nx;
2337 if(detmon_lg_config.ury == -1)
2338 detmon_lg_config.ury = ny;
2339
2340 if (detmon_lg_config.llx == 1 &&
2341 detmon_lg_config.lly == 1 &&
2342 detmon_lg_config.urx == nx &&
2343 detmon_lg_config.ury == ny)
2344 detmon_lg_config.wholechip = CPL_TRUE;
2345
2346 if(detmon_lg_config.llx1 == -1)
2347 detmon_lg_config.llx1 = 1;
2348 if(detmon_lg_config.lly1 == -1)
2349 detmon_lg_config.lly1 = 1;
2350 if(detmon_lg_config.urx1 == -1)
2351 detmon_lg_config.urx1 = nx;
2352 if(detmon_lg_config.ury1 == -1)
2353 detmon_lg_config.ury1 = ny;
2354
2355 if(detmon_lg_config.llx2 == -1)
2356 detmon_lg_config.llx2 = 1;
2357 if(detmon_lg_config.lly2 == -1)
2358 detmon_lg_config.lly2 = 1;
2359 if(detmon_lg_config.urx2 == -1)
2360 detmon_lg_config.urx2 = nx / 2;
2361 if(detmon_lg_config.ury2 == -1)
2362 detmon_lg_config.ury2 = ny / 2;
2363
2364 if(detmon_lg_config.llx3 == -1)
2365 detmon_lg_config.llx3 = 1;
2366 if(detmon_lg_config.lly3 == -1)
2367 detmon_lg_config.lly3 = ny / 2;
2368 if(detmon_lg_config.urx3 == -1)
2369 detmon_lg_config.urx3 = nx / 2;
2370 if(detmon_lg_config.ury3 == -1)
2371 detmon_lg_config.ury3 = ny;
2372
2373 if(detmon_lg_config.llx4 == -1)
2374 detmon_lg_config.llx4 = nx / 2;
2375 if(detmon_lg_config.lly4 == -1)
2376 detmon_lg_config.lly4 = ny / 2;
2377 if(detmon_lg_config.urx4 == -1)
2378 detmon_lg_config.urx4 = nx;
2379 if(detmon_lg_config.ury4 == -1)
2380 detmon_lg_config.ury4 = ny;
2381
2382 if(detmon_lg_config.llx5 == -1)
2383 detmon_lg_config.llx5 = nx / 2;
2384 if(detmon_lg_config.lly5 == -1)
2385 detmon_lg_config.lly5 = 1;
2386 if(detmon_lg_config.urx5 == -1)
2387 detmon_lg_config.urx5 = nx;
2388 if(detmon_lg_config.ury5 == -1)
2389 detmon_lg_config.ury5 = ny / 2;
2390
2391 if(detmon_lg_config.intermediate == TRUE) {
2392 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.");
2393 detmon_lg_config.autocorr = TRUE;
2394 }
2395
2396
2397 detmon_lg_config.lamp_stability = 0.0;
2398
2399 detmon_lg_config.lamp_ok = FALSE;
2400
2401 detmon_lg_config.cr = 0.0;
2402
2403 return cpl_error_get_code();
2404}
2405
2406/*---------------------------------------------------------------------------*/
2417/*---------------------------------------------------------------------------*/
2418static cpl_error_code
2419detmon_lg_split_onoff(const cpl_frameset * cur_fset,
2420 cpl_frameset * cur_fset_on,
2421 cpl_frameset * cur_fset_off,
2422 const char *tag_on,
2423 const char *tag_off)
2424{
2425 int nframes;
2426 int i;
2427
2428 cpl_frame * cur_frame_dup = NULL;
2429
2430#if 0
2431 const cpl_frame * first;
2432 const cpl_frame * second;
2433 const char * first_tag;
2434 const char * second_tag;
2435 skip_if((first = cpl_frameset_get_position_const(cur_fset, 0)) == NULL);
2436 skip_if((second = cpl_frameset_get_position_const(cur_fset, 1)) == NULL);
2437
2438 skip_if((first_tag = cpl_frame_get_tag(first)) == NULL);
2439 skip_if((second_tag = cpl_frame_get_tag(second)) == NULL);
2440 if (opt_nir == OPT &&
2441 ((!strcmp(first_tag, tag_on ) && !strcmp(second_tag, tag_off)) ||
2442 (!strcmp(first_tag, tag_off) && !strcmp(second_tag, tag_on )))) {
2443 detmon_lg_config.lamp_ok = TRUE;
2444 }
2445#endif
2446
2447 nframes = cpl_frameset_get_size(cur_fset);
2448 for(i = detmon_lg_config.lamp_ok ? 2 : 0; i < nframes; i++) {
2449 const cpl_frame * cur_frame =
2450 cpl_frameset_get_position_const(cur_fset, i);
2451 char * tag;
2452
2453 /* Duplication is required for insertion to a different frameset */
2454 cur_frame_dup = cpl_frame_duplicate(cur_frame);
2455 tag = (char *) cpl_frame_get_tag(cur_frame_dup);
2456
2457 /* Insertion in the corresponding sub-frameset */
2458 if(!strcmp(tag, tag_on)) {
2459 skip_if(cpl_frameset_insert(cur_fset_on, cur_frame_dup));
2460 } else if(!strcmp(tag, tag_off)) {
2461 skip_if(cpl_frameset_insert(cur_fset_off, cur_frame_dup));
2462 } else {
2463 cpl_frame_delete(cur_frame_dup);
2464 cur_frame_dup = NULL;
2465 }
2466 }
2467 cur_frame_dup = NULL;
2468
2469 end_skip;
2470
2471 cpl_frame_delete(cur_frame_dup);
2472
2473 return cpl_error_get_code();
2474}
2475
2476/*--------------------------------------------------------------------------*/
2498/*--------------------------------------------------------------------------*/
2499
2500static cpl_error_code
2501detmon_lg_reduce(const cpl_frameset * set_on,
2502 const cpl_frameset * set_off,
2503 int* index_on, int* index_off,
2504 double* exptime_on, double* exptime_off,
2505 int *next_index_on, int* next_index_off,
2506 cpl_imagelist ** coeffs_ptr,
2507 cpl_table * gain_table,
2508 cpl_table * linear_table,
2509 cpl_image ** bpm_ptr,
2510 cpl_imagelist * autocorr_images,
2511 cpl_imagelist * diff_flats,
2512 cpl_propertylist * gaint_qclist,
2513 cpl_propertylist * lint_qclist,
2514 cpl_propertylist * linc_qclist,
2515 cpl_propertylist * bpm_qclist,
2516 int (* load_fset) (const cpl_frameset *,
2517 cpl_type,
2518 cpl_imagelist *),
2519 const cpl_boolean opt_nir,
2520 int whichext)
2521{
2522 cpl_errorstate prestate = cpl_errorstate_get();
2523 const double D_INVALID_VALUE = -999;
2524 int i;
2525 cpl_imagelist * linearity_inputs = NULL;
2526 cpl_imagelist * opt_offs = NULL;
2527 int nsets;
2528 cpl_propertylist * reflist = NULL;
2529 int dit_nskip = 0;
2530 int rows_linear_affected = 1;
2531 int rows_gain_affected = 1;
2532 int last_linear_best = 0;
2533 /* Test entries */
2534 cpl_ensure(set_on != NULL, CPL_ERROR_NULL_INPUT, CPL_ERROR_NULL_INPUT);
2535 cpl_ensure(set_off != NULL, CPL_ERROR_NULL_INPUT, CPL_ERROR_NULL_INPUT);
2536
2537 nsets = cpl_frameset_get_size(set_on) / 2;
2538
2539 detmon_lg_config.load_fset = load_fset;
2540 if(detmon_lg_config.collapse) {
2541 /*
2542 * When the 'collapse' option is used, there are no OFF pairs. We
2543 * construct a pair with the 2 first raw OFF frames, which will be
2544 * passed for each DIT value, to maintain the same API in the function
2545 * detmon_gain_table_fill_row().
2546 */
2547 const cpl_frame *first = cpl_frameset_get_position_const(set_off, 0);
2548 cpl_frame *dup_first = cpl_frame_duplicate(first);
2549
2550 const cpl_frame *second = cpl_frameset_get_position_const(set_off, 1);
2551 cpl_frame *dup_second = cpl_frame_duplicate(second);
2552
2553 cpl_frameset *raw_offs = cpl_frameset_new();
2554
2555 skip_if(cpl_frameset_insert(raw_offs, dup_first));
2556 skip_if(cpl_frameset_insert(raw_offs, dup_second));
2557
2558 opt_offs = cpl_imagelist_load_frameset(raw_offs, CPL_TYPE_FLOAT,
2559 0, whichext);
2560
2561 cpl_frameset_delete(raw_offs);
2562 if (opt_offs == NULL) {
2563 cpl_errorstate_set(prestate);
2564 return CPL_ERROR_CONTINUE;
2565 }
2566 }
2567
2568 skip_if(detmon_lg_reduce_init(gain_table,
2569 linear_table,
2570 &linearity_inputs,
2571 opt_nir));
2572/*
2573 if (!strcmp(detmon_lg_config.method, "PTC"))
2574 {
2575 cpl_msg_warning(cpl_func, "PTC method incompatible with lamp stability"
2576 "computation");
2577 }
2578*/
2579 /* do always lamp stability check */
2580 if(detmon_lg_lamp_stab(set_on, set_off,
2581 opt_nir, whichext)) {
2582 cpl_errorstate_set(prestate);
2583 }
2584
2585 if(!detmon_lg_config.collapse)
2586 {
2587 }
2588 /* Unselect all rows, to select only invalid ones */
2589 skip_if(cpl_table_unselect_all(linear_table));
2590 skip_if(cpl_table_unselect_all(gain_table));
2591
2592 /* Loop on every DIT value */
2593
2594 for(i = 0; i < nsets ; i++)
2595 {
2596 skip_if(detmon_lg_reduce_dit(set_on,
2597 index_on, exptime_on,
2598 i,
2599 &dit_nskip,
2600 set_off,
2601 index_off, exptime_off,
2602 next_index_on, next_index_off,
2603 linear_table,
2604 gain_table, linearity_inputs,
2605 lint_qclist, opt_nir,
2606 autocorr_images, diff_flats,
2607 opt_offs, whichext,
2608 &rows_linear_affected,&rows_gain_affected));
2609 /* TODO: the following if could be done directly inside the
2610 * function detmon_lg_reduce_dit
2611 */
2612 if (rows_linear_affected == 0)
2613 {
2614 cpl_msg_warning(cpl_func, "The rest frames would not be taken "
2615 "into linear calculation, check the messages above");
2616 cpl_table_select_row(linear_table, i);
2617 }
2618 else
2619 {
2620 last_linear_best = i;
2621 }
2622
2623 if (rows_gain_affected == 0)
2624 {
2625 cpl_msg_warning(cpl_func, "The rest frames would not be taken "
2626 "into gain calculation, check the messages above");
2627 cpl_table_select_row(gain_table, i);
2628 }
2629
2630
2631
2632 }
2633
2634 skip_if(detmon_add_adl_column(linear_table, opt_nir));
2635
2636 /*
2637 * Removal of rows corresponding to frames above --filter threshold.
2638 * See calls to cpl_table_select_row() in detmon_lg_reduce_dit().
2639 */
2640 skip_if(cpl_table_erase_selected(gain_table));
2641 skip_if(cpl_table_erase_selected(linear_table));
2642
2643
2644 reflist = cpl_propertylist_new();
2645 skip_if(cpl_propertylist_append_bool(reflist, "ADU", FALSE));
2646 skip_if(cpl_table_sort(gain_table, reflist));
2647 /*
2648 * --Final reduction--
2649 * The following call to detmon_lg_reduce_all() makes the
2650 * computations which are over all posible DIT values.
2651 */
2652 skip_if(detmon_lg_reduce_all(linear_table,
2653 gaint_qclist, lint_qclist, linc_qclist,
2654 bpm_qclist, coeffs_ptr, bpm_ptr,
2655 linearity_inputs,
2656 gain_table, whichext, opt_nir));
2657 {
2658 /*FPN Computation*/
2659 double gain = cpl_propertylist_get_double(gaint_qclist, DETMON_QC_GAIN);
2660 // cpl_propertylist_append_int(gaint_qclist, "NNNEXT", whichext);
2661 // cpl_msg_warning(cpl_func, "---------- ext %i" , whichext);
2662 cpl_error_code cplerr = cpl_error_get_code();
2663 if (cplerr != CPL_ERROR_NONE || (gain == 0.0))
2664 {
2665 cpl_msg_warning(cpl_func, "Cannot read gain from QC parameters - "
2666 "FPN will not be computed");
2667 cpl_error_reset();
2668 }
2669 else
2670 {
2671 detmon_fpn_compute(set_on, index_on, last_linear_best, lint_qclist,
2672 detmon_lg_config.llx,
2673 detmon_lg_config.lly,
2674 detmon_lg_config.urx,
2675 detmon_lg_config.ury,
2676 gain,
2677 whichext,
2678 detmon_lg_config.fpn_method,
2679 detmon_lg_config.fpn_smooth);
2680 }
2681 }
2682 /* change NaN in the gain table to the invalid value D_INVALID_VALUE*/
2683
2684 detmon_table_fill_invalid(gain_table, D_INVALID_VALUE);
2685 end_skip;
2686 cpl_imagelist_delete(linearity_inputs);
2687 cpl_imagelist_delete(opt_offs);
2688 cpl_propertylist_delete(reflist);
2689
2690 return cpl_error_get_code();
2691}
2692
2693static cpl_error_code detmon_table_fill_invalid(cpl_table* ptable, double code)
2694{
2695 int ncols = cpl_table_get_ncol(ptable);
2696 cpl_array* pnames = cpl_table_get_column_names(ptable);
2697 int nrows = cpl_table_get_nrow(ptable);
2698 int i = 0;
2699 for (i=0; i < ncols; i++)
2700 {
2701 int j = 0;
2702 for (j = 0; j< nrows; j++)
2703 {
2704 const char* colname = cpl_array_get_data_string_const(pnames)[i];
2705 int isnull;
2706 cpl_type type = cpl_table_get_column_type(ptable, colname);
2707 cpl_table_get(ptable, colname, j, &isnull);
2708 if(isnull == 1)
2709 {
2710 if (type == CPL_TYPE_DOUBLE)
2711 {
2712 cpl_table_set(ptable,colname,j, code);
2713 }
2714 else if (type == CPL_TYPE_FLOAT)
2715 {
2716 cpl_table_set_float(ptable,colname,j, (float)code);
2717 }
2718 }
2719 }
2720 }
2721 cpl_array_delete(pnames);
2722 return cpl_error_get_code();
2723}
2724
2725static cpl_error_code
2726detmon_fpn_compute(const cpl_frameset *set_on,
2727 int * index_on,
2728 int last_linear_best,
2729 cpl_propertylist *lint_qclist,
2730 int llx,
2731 int lly,
2732 int urx,
2733 int ury,
2734 double gain,
2735 int whichext,
2736 FPN_METHOD fpn_method,
2737 int smooth_size)
2738{
2739 double fpn = 0;
2740 const cpl_image* im1 = 0;
2741 int range[4];
2742 cpl_imagelist* ons = 0;
2743 cpl_frameset * pair_on = 0;
2744 int nsets_extracted = cpl_frameset_get_size(set_on);
2745 cpl_size * selection = NULL;
2746 double mse = 0;
2747 range[0] = llx;
2748 range[1] = lly;
2749 range[2] = urx;
2750 range[3] = ury;
2751
2752 /* Retrieve 2 ON frames with the highest DIT -
2753 * the last best 2 values in the index*/
2754 selection = cpl_malloc(sizeof(cpl_size) * nsets_extracted);
2755 memset(&selection[0], 0, sizeof(cpl_size) * nsets_extracted);
2756
2757 selection[index_on[last_linear_best*2 + 0] ] = 1;
2758 selection[index_on[last_linear_best*2 + 1] ] = 1;
2759 pair_on = cpl_frameset_extract(set_on, selection, 1);
2760 ons = detmon_lg_config.load_fset_wrp(pair_on, CPL_TYPE_FLOAT, whichext);
2761
2762 skip_if(ons == NULL);
2763 skip_if((im1 = cpl_imagelist_get_const(ons, 0)) == NULL);
2764
2765 fpn = irplib_fpn_lg(im1, range, gain, fpn_method, smooth_size, &mse);
2766 skip_if(cpl_propertylist_append_double(lint_qclist, DETMON_QC_FPN,
2767 fpn));
2768 skip_if(cpl_propertylist_append_double(lint_qclist, "ESO QC GAIN ERR",
2769 mse));
2770
2771 end_skip;
2772 cpl_frameset_delete(pair_on);
2773 cpl_imagelist_delete(ons);
2774 cpl_free(selection);
2775 return cpl_error_get_code();
2776}
2777
2778/*--------------------------------------------------------------------------*/
2786/*--------------------------------------------------------------------------*/
2787static cpl_error_code
2788detmon_lg_lamp_stab(const cpl_frameset * lamps,
2789 const cpl_frameset * darks,
2790 cpl_boolean opt_nir,
2791 int whichext)
2792{
2793
2794 /*
2795 * NOTE:
2796 * Most of this code is copied (and modified) from
2797 * isaac_img_detlin_load(), in isaac_img_detlin.c v.1.25
2798 */
2799
2800 int nb_lamps;
2801 int nb_darks;
2802
2803 cpl_vector * selection = NULL;
2804 cpl_propertylist * plist;
2805 double dit_lamp, dit_dark;
2806 int dit_stab;
2807 cpl_imagelist * lamps_data = NULL;
2808 cpl_imagelist * darks_data = NULL;
2809 double * stab_levels = NULL;
2810 int i, j;
2811 double * ditvals = NULL;
2812 int last_stab = 0; /* Avoid false uninit warning */
2813
2814 /* Check that there are as many lamp as darks */
2815 cpl_ensure_code((nb_lamps = cpl_frameset_get_size(lamps)) >= 3,
2816 CPL_ERROR_ILLEGAL_INPUT);
2817/*
2818 cpl_ensure_code(cpl_frameset_get_size(darks) == nb_lamps,
2819 CPL_ERROR_ILLEGAL_INPUT);
2820*/
2821 /* Check out that they have consistent integration times */
2822 cpl_msg_info(__func__, "Checking DIT consistency");
2823 selection = cpl_vector_new(nb_lamps);
2824 ditvals = cpl_malloc(nb_lamps * sizeof(double));
2825 dit_stab = 0;
2826 for (i = 0; i < nb_lamps; i++) {
2827 const cpl_frame * c_lamp;
2828 const cpl_frame * c_dark;
2829 /* Check if ok */
2830 skip_if (cpl_error_get_code());
2831
2832 /* DIT from LAMP */
2833 c_lamp = cpl_frameset_get_position_const(lamps, i);
2834 plist = cpl_propertylist_load(cpl_frame_get_filename(c_lamp), 0);
2835 if(opt_nir)
2836 dit_lamp = (double)detmon_pfits_get_dit(plist);
2837 else
2838 dit_lamp = (double)detmon_pfits_get_dit_opt(plist);
2839 cpl_propertylist_delete(plist);
2840 skip_if (cpl_error_get_code());
2841
2842 /* DIT from DARK */
2843 c_dark = cpl_frameset_get_position_const(darks, i);
2844 plist = cpl_propertylist_load(cpl_frame_get_filename(c_dark), 0);
2845 if(opt_nir)
2846 dit_dark = (double)detmon_pfits_get_dit(plist);
2847 else
2848 dit_dark = (double)detmon_pfits_get_dit_opt(plist);
2849 cpl_propertylist_delete(plist);
2850 skip_if (cpl_error_get_code());
2851
2852 /* Check consistency */
2853 if (fabs(dit_dark-dit_lamp) > 1e-3) {
2854 cpl_msg_error(__func__, "DIT not consistent between LAMP and DARK, skip lamp stability computation");
2855 /* FIXME: Should an error code be set here? */
2856
2857 skip_if(1);
2858 }
2859 ditvals[i] = dit_lamp;
2860 /* Set selection */
2861 if (i==0) {
2862 cpl_vector_set(selection, i, -1.0);
2863 dit_stab ++;
2864 last_stab = 0;
2865 } else {
2866 /*
2867 * The second condition is to make sure that frames taken into
2868 * account for lamp stability are not consecutive.
2869 */
2870 if (fabs(dit_lamp - ditvals[0]) < 1e-5 && i - last_stab > 3) {
2871 cpl_vector_set(selection, i, -1.0);
2872 dit_stab ++;
2873 last_stab = i;
2874 } else {
2875 cpl_vector_set(selection, i, 1.0);
2876 }
2877 }
2878 }
2879
2880 /* Check if there are enough DITs for stability check */
2881 if (dit_stab < 2) {
2882 cpl_msg_info(__func__, "Not enough frames for stability check");
2883 } else {
2884
2885 /* Load the data and compute lamp-dark */
2886 cpl_msg_info(__func__, "Compute the differences lamp - dark");
2887
2888
2889 lamps_data = detmon_load_frameset_window(lamps, CPL_TYPE_FLOAT, 0,
2890 whichext,
2891 detmon_lg_config.llx,
2892 detmon_lg_config.lly,
2893 detmon_lg_config.urx,
2894 detmon_lg_config.ury,
2895 -1, -1);
2896
2897 darks_data = detmon_load_frameset_window(lamps, CPL_TYPE_FLOAT, 0,
2898 whichext,
2899 detmon_lg_config.llx,
2900 detmon_lg_config.lly,
2901 detmon_lg_config.urx,
2902 detmon_lg_config.ury,
2903 -1, -1);
2904
2905 nb_darks=cpl_imagelist_get_size(darks_data);
2906 if(nb_darks==nb_lamps) {
2907 skip_if(cpl_imagelist_subtract(lamps_data,darks_data));
2908 } else {
2909 cpl_image* master_dark=cpl_imagelist_collapse_median_create(darks_data);
2910 cpl_imagelist_subtract_image(lamps_data,master_dark);
2911 cpl_image_delete(master_dark);
2912 }
2913 /* Check the lamp stability */
2914 cpl_msg_info(__func__, "Check the lamp stability");
2915 stab_levels = cpl_malloc(dit_stab * sizeof(double));
2916 j = 0;
2917 for (i=0; i<nb_lamps; i++) {
2918 if (cpl_vector_get(selection, i) < 0) {
2919 stab_levels[j] =
2920 cpl_image_get_mean(cpl_imagelist_get(lamps_data, i));
2921 j++;
2922 }
2923 }
2924
2925 /* Compute the lamp stability */
2926 for (i=1; i<dit_stab; i++) {
2927 if ((fabs(stab_levels[i]-stab_levels[0]) / stab_levels[0]) >
2928 detmon_lg_config.lamp_stability)
2929 detmon_lg_config.lamp_stability =
2930 fabs(stab_levels[i]-stab_levels[0]) / stab_levels[0];
2931 }
2932
2933
2934 /* Check the lamp stability */
2935 if (detmon_lg_config.lamp_stability > 0.01) {
2936 cpl_msg_warning(__func__,
2937 "Lamp stability level %g difference too high - proceed anyway",detmon_lg_config.lamp_stability);
2938 }
2939 }
2940 end_skip;
2941
2942
2943 cpl_free(ditvals);
2944 cpl_vector_delete(selection);
2945 cpl_imagelist_delete(lamps_data);
2946 cpl_imagelist_delete(darks_data);
2947 cpl_free(stab_levels);
2948
2949 return cpl_error_get_code();
2950}
2951
2952/*--------------------------------------------------------------------------*/
2975/*--------------------------------------------------------------------------*/
2976static cpl_error_code
2977detmon_lg_reduce_dit(const cpl_frameset * set_on,
2978 int* index_on, double* exptime_on,
2979 const int dit_nb,
2980 int * dit_nskip,
2981 const cpl_frameset * set_off,
2982 int * index_off, double* exptime_off,
2983 int* next_on, int* next_off,
2984 cpl_table * linear_table,
2985 cpl_table * gain_table,
2986 cpl_imagelist * linearity_inputs,
2987 cpl_propertylist * qclist,
2988 cpl_boolean opt_nir,
2989 cpl_imagelist * autocorr_images,
2990 cpl_imagelist * diff_flats,
2991 cpl_imagelist * opt_offs,
2992 int whichext,
2993 int* rows_linear_affected,
2994 int* rows_gain_affected)
2995{
2996 cpl_frameset * pair_on = NULL;
2997 cpl_frameset * pair_off = NULL;
2998 cpl_imagelist * ons = NULL;
2999 cpl_imagelist * offs = NULL;
3000 cpl_boolean follow = CPL_TRUE;
3001 unsigned mode = detmon_lg_config.autocorr ? IRPLIB_GAIN_WITH_AUTOCORR : 0;
3002 double c_dit;
3003 int c_ndit;
3004
3005 double current_dit = 0;
3006
3007 const char * filename;
3008
3009 cpl_propertylist * plist = NULL;
3010 cpl_propertylist* pDETlist = NULL;
3011
3012 mode = detmon_lg_config.collapse ?
3013 mode | IRPLIB_GAIN_COLLAPSE | IRPLIB_LIN_COLLAPSE:
3014 mode | IRPLIB_GAIN_NO_COLLAPSE | IRPLIB_LIN_NO_COLLAPSE;
3015 mode = detmon_lg_config.pix2pix ?
3016 mode | IRPLIB_LIN_PIX2PIX : mode;
3017 mode = opt_nir ?
3018 mode | IRPLIB_GAIN_NIR | IRPLIB_LIN_NIR :
3019 mode | IRPLIB_GAIN_OPT | IRPLIB_LIN_OPT ;
3020
3021
3022 /* ON pair extraction */
3023 skip_if(detmon_pair_extract_next(set_on, index_on, next_on, exptime_on, &pair_on, detmon_lg_config.tolerance));
3024 current_dit = exptime_on[*next_on - 1];
3025
3026 /* Load the ON images */
3027 ons = detmon_lg_config.load_fset_wrp(pair_on, CPL_TYPE_FLOAT, whichext);
3028 skip_if(ons == NULL);
3029 cpl_msg_debug(cpl_func, " Loaded ON images: %" CPL_SIZE_FORMAT
3030 ", exptime[%f]",cpl_imagelist_get_size(ons), current_dit );
3031 if(cpl_imagelist_get_size(ons) != 2)
3032 {
3033 cpl_msg_error(cpl_func, "cannot take ON pair, number of images[%"
3034 CPL_SIZE_FORMAT "]", cpl_imagelist_get_size(ons));
3035 skip_if(TRUE);
3036 }
3037 if(detmon_lg_config.filter > 0)
3038 {
3039 double med1 =
3040 cpl_image_get_median_window(cpl_imagelist_get(ons, 0),
3041 detmon_lg_config.llx,
3042 detmon_lg_config.lly,
3043 detmon_lg_config.urx,
3044 detmon_lg_config.ury);
3045 double med2 =
3046 cpl_image_get_median_window(cpl_imagelist_get(ons, 1),
3047 detmon_lg_config.llx,
3048 detmon_lg_config.lly,
3049 detmon_lg_config.urx,
3050 detmon_lg_config.ury);
3051
3052
3053
3054 if ( med1 > (double)detmon_lg_config.filter ||
3055 med2 > (double)detmon_lg_config.filter)
3056 {
3057 follow = CPL_FALSE;
3058 cpl_table_select_row(gain_table, dit_nb);
3059 cpl_table_select_row(linear_table, dit_nb);
3060 (*dit_nskip)++;
3061 cpl_msg_warning(cpl_func, "Frames of EXPTIME nb %d "
3062 "will not be taken into account for computation "
3063 "as the median of the on frames computed on the "
3064 "user defined region [%d,%d,%d,%d] are above "
3065 "--filter threshold (%d)",
3066 dit_nb,
3067 detmon_lg_config.llx,
3068 detmon_lg_config.lly,
3069 detmon_lg_config.urx,
3070 detmon_lg_config.ury,
3071 detmon_lg_config.filter);
3072 }
3073 }
3074
3075 if (follow || detmon_lg_config.filter < 0)
3076 {
3077
3078 /*
3079 * If the --collapse option is not activated by the user, the OFF
3080 * sub-frameset is also supposed to be organized into pairs and,
3081 * therefore, processed as the ON sub-frameset.
3082 */
3083 if(!detmon_lg_config.collapse)
3084 {
3085 /* TODO: We removed this check as with NACO data, that has an odd
3086 * number of input OFF frames it would stop with error
3087 * despite the recipe would reduce the data properly.
3088 * On the other side, on some data without such a check one may get
3089 * failures on another place.
3090 * we need to document such cases and understand how to better deal
3091 * in a robust way the case of odd input off frames
3092 *
3093 if (cpl_frameset_get_size(set_off) % 2 != 0) {
3094 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
3095 "If collapse is FALSE the OFF frameset"
3096 " must be organized in pairs.");
3097 skip_if(1);
3098 }
3099 */
3100 if (!strcmp(detmon_lg_config.method, "MED") ||
3101 cpl_frameset_get_size(set_on) == cpl_frameset_get_size(set_off))
3102 {
3103 skip_if(detmon_pair_extract_next(set_off, index_off, next_off, exptime_off, &pair_off, detmon_lg_config.tolerance));
3104 }
3105 else
3106 {
3107 skip_if(detmon_single_extract_next(set_off, index_off, next_off, exptime_off, &pair_off));
3108 }
3109 /* Load the OFF images */
3110 cpl_msg_debug(cpl_func, " Load the OFF images, ext[%d], exptime[%f]", whichext, exptime_off[*next_off - 1]);
3111 offs = detmon_lg_config.load_fset_wrp(pair_off, CPL_TYPE_FLOAT, whichext);
3112
3113 skip_if(offs == NULL);
3114 skip_if(cpl_error_get_code());
3115 }
3116 else {
3117 offs = (cpl_imagelist *) opt_offs;
3118 }
3119
3120 /* Rescaling */
3121 if(detmon_lg_config.rescale)
3122 {
3123 skip_if(detmon_lg_rescale(ons));
3124 if (!detmon_lg_config.collapse &&
3125 !strcmp(detmon_lg_config.method, "MED"))
3126 skip_if(detmon_lg_rescale(offs));
3127 }
3128 /* DIT or EXPTIME value extraction */
3129
3130 filename =
3131 cpl_frame_get_filename(cpl_frameset_get_position_const(pair_on, 0));
3132 skip_if ((plist = cpl_propertylist_load(filename, 0)) == NULL);
3133 /* Add columns to the tables DETi WINi UITi*/
3134 if (plist)
3135 {
3136 pDETlist = cpl_propertylist_new();
3137 cpl_propertylist_copy_property_regexp(pDETlist, plist, "DET[0-9]* WIN[0-9]* UIT[0-9]*",0);
3138 if (dit_nb == 0)
3139 {
3140 irplib_table_create_column(gain_table, pDETlist);
3141 irplib_table_create_column(linear_table, pDETlist);
3142 }
3143 }
3144 if(opt_nir == NIR) {
3145 c_dit = detmon_pfits_get_dit(plist);
3146 c_ndit = irplib_pfits_get_ndit(plist);
3147 } else {
3148 c_dit = irplib_pfits_get_exptime(plist);
3149 c_ndit=1;
3150 }
3151
3152 /*
3153 * --GAIN part for each DIT value--
3154 * The following call to detmon_gain_table_fill_row() fills
3155 * in the row nb i
3156 * of the GAIN table (output) and of the FIT table (by-product to be
3157 * used later for the polynomial computation of the GAIN)
3158 */
3159
3160 cpl_msg_info(cpl_func, "Computing GAIN for EXPTIME value nb %d",
3161 dit_nb + 1);
3162
3163 /* In case PTC is applied, this is allowed */
3164 if(cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE && dit_nb == 0)
3165 {
3166 cpl_table_erase_column(gain_table, "MEAN_OFF1");
3167 cpl_table_erase_column(gain_table, "MEAN_OFF2");
3168 cpl_table_erase_column(gain_table, "SIG_OFF_DIF");
3169 cpl_table_erase_column(gain_table, "GAIN");
3170 cpl_table_erase_column(gain_table, "GAIN_CORR");
3171 cpl_table_new_column(gain_table, "MEAN_OFF", CPL_TYPE_DOUBLE);
3172 }
3173
3174
3175 skip_if(detmon_gain_table_fill_row(gain_table,
3176 c_dit,c_ndit,
3177 autocorr_images,
3178 diff_flats, ons, offs,
3179 detmon_lg_config.kappa,
3180 detmon_lg_config.niter,
3181 detmon_lg_config.llx,
3182 detmon_lg_config.lly,
3183 detmon_lg_config.urx,
3184 detmon_lg_config.ury,
3185 detmon_lg_config.m,
3186 detmon_lg_config.n,
3187 detmon_lg_config.gain_threshold,
3188 dit_nb, mode, rows_gain_affected));
3189
3190
3191 skip_if(detmon_check_saturation_on_pair(autocorr_images,
3192 diff_flats,ons,
3193 detmon_lg_config.kappa,
3194 detmon_lg_config.niter,
3195 detmon_lg_config.llx,
3196 detmon_lg_config.lly,
3197 detmon_lg_config.urx,
3198 detmon_lg_config.ury,
3199 detmon_lg_config.saturation_limit,
3200 dit_nb, mode, rows_linear_affected));
3201
3202
3203 if (*rows_gain_affected)
3204 {
3205 /* fill DETi WINi OPTi columns - see DFS06921*/
3206 skip_if(irplib_fill_table_DETWINUIT(gain_table, pDETlist, dit_nb));
3207 /* Linearity reduction */
3208 cpl_msg_info(cpl_func, "Linearity reduction for nb %d",
3209 dit_nb + 1);
3210 }
3211 if (*rows_linear_affected) {
3212 skip_if(detmon_lin_table_fill_row(linear_table, c_dit,
3213 linearity_inputs, ons, offs,
3214 detmon_lg_config.llx,
3215 detmon_lg_config.lly,
3216 detmon_lg_config.urx,
3217 detmon_lg_config.ury,
3218 dit_nb, *dit_nskip, mode));
3219 /* fill DETi WINi OPTi columns - see DFS06921*/
3220 skip_if(irplib_fill_table_DETWINUIT(linear_table, pDETlist, dit_nb));
3221 }
3222
3223
3224 /* as we know only at this point if a frame is
3225 saturated or not, and we would like to compute the
3226 contamination only on the last non saturated frame,
3227 we need de facto to compute saturation on any non saturated
3228 frame, by overwriting the QC parameter. In the end it will
3229 remain only the last value corresponding to a non saturated
3230 frame */
3231
3232 if(opt_nir == OPT &&
3233 *rows_linear_affected != 0 ) {
3234 detmon_opt_contamination(ons, offs, mode, qclist);
3235 }
3236
3237 }
3238
3239 end_skip;
3240
3241 cpl_frameset_delete(pair_on);
3242 cpl_imagelist_delete(ons);
3243
3244 if(!detmon_lg_config.collapse ) {
3245 cpl_imagelist_delete(offs);
3246 }
3247
3248 if(!detmon_lg_config.collapse) {
3249 cpl_frameset_delete(pair_off);
3250 }
3251
3252 cpl_propertylist_delete(plist);
3253 cpl_propertylist_delete(pDETlist);
3254 return cpl_error_get_code();
3255}
3256
3257/*---------------------------------------------------------------------------*/
3263/*---------------------------------------------------------------------------*/
3264static cpl_error_code
3265detmon_add_adl_column(cpl_table * table,
3266 cpl_boolean opt_nir)
3267{
3268 cpl_error_code error;
3269 double mean_med_dit;
3270 double *dits;
3271
3272 cpl_ensure_code(table != NULL, CPL_ERROR_NULL_INPUT);
3273
3274 mean_med_dit = cpl_table_get_column_mean(table, "MED_DIT");
3275 if (opt_nir == OPT)
3276 dits = cpl_table_get_data_double(table, "EXPTIME");
3277 else
3278 dits = cpl_table_get_data_double(table, "DIT");
3279
3280 error = cpl_table_copy_data_double(table, "ADL", dits);
3281 cpl_ensure_code(!error, error);
3282 error = cpl_table_multiply_scalar(table, "ADL", mean_med_dit);
3283 cpl_ensure_code(!error, error);
3284
3285 return cpl_error_get_code();
3286}
3287
3288/*---------------------------------------------------------------------------*/
3296/*---------------------------------------------------------------------------*/
3297static cpl_error_code
3298detmon_lg_reduce_init(cpl_table * gain_table,
3299 cpl_table * linear_table,
3300 cpl_imagelist ** linearity_inputs,
3301 const cpl_boolean opt_nir)
3302{
3303 skip_if(detmon_gain_table_create(gain_table, opt_nir));
3304 skip_if(detmon_lin_table_create(linear_table, opt_nir));
3305
3306 if(detmon_lg_config.pix2pix) {
3307 *linearity_inputs = cpl_imagelist_new();
3308 skip_if(*linearity_inputs == NULL);
3309 }
3310
3311 end_skip;
3312
3313 return cpl_error_get_code();
3314}
3315
3316/*--------------------------------------------------------------------------*/
3322/*--------------------------------------------------------------------------*/
3323static double
3324detmon_pfits_get_dit(const cpl_propertylist * plist)
3325{
3326 if (cpl_propertylist_has(plist, "ESO DET DIT")) {
3327 /* FIERA Detector Controller */
3328 return irplib_pfits_get_prop_double(plist, "ESO DET DIT");
3329 } else {
3330 /* New Generation Detector Controller */
3331 return irplib_pfits_get_prop_double(plist, "ESO DET SEQ1 DIT");
3332 }
3333 (void)cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND, "FITS key "
3334 "ESO DET DIT or ESO DET DIT not found");
3335 return 0.0;
3336}
3337
3338/*--------------------------------------------------------------------------*/
3344/*--------------------------------------------------------------------------*/
3345static double
3346detmon_pfits_get_dit_opt(const cpl_propertylist * plist)
3347{
3348 if (cpl_propertylist_has(plist, "ESO DET WIN1 UIT1")) {
3349 /* FIERA Detector Controller */
3350 return irplib_pfits_get_prop_double(plist, "ESO DET WIN1 UIT1");
3351 } else if (cpl_propertylist_has(plist, "ESO DET UIT1")) {
3352 /* New Generation Detector Controller */
3353 return irplib_pfits_get_prop_double(plist, "ESO DET WIN1 UIT1");
3354 }
3355
3356 (void)cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND, "FITS key "
3357 "ESO DET WIN1 UIT1 or ESO DET UIT1 not found");
3358 return 0.0;
3359}
3360
3361
3362/*---------------------------------------------------------------------------*/
3367static cpl_propertylist*
3368detmon_load_pro_keys(const char* NAME_O)
3369{
3370 cpl_propertylist* pro_keys=NULL;
3371 pro_keys=cpl_propertylist_load_regexp(NAME_O,0,"^(ESO PRO)",0);
3372 return pro_keys;
3373}
3374
3375
3376static double irplib_pfits_get_prop_double(const cpl_propertylist * plist,
3377 const char* prop_name)
3378{
3379 double dit;
3380 dit = cpl_propertylist_get_double(plist, prop_name);
3381 if(cpl_error_get_code() != CPL_ERROR_NONE)
3382 {
3383 cpl_msg_error(cpl_func, "Cannot read property '%s', err[%s]",
3384 prop_name, cpl_error_get_where());
3385 }
3386 return dit;
3387}
3388
3389static cpl_error_code
3390detmon_gain_compute_qc(double kappa, int nclip, const int pos,
3391 const cpl_imagelist* offs, unsigned mode,
3392 double avg_on1, double avg_on2,
3393 double avg_off1, double avg_off2,
3394 double sig_off_dif, int c_ndit,
3395 double autocorr, cpl_image* on_dif,
3396 cpl_table* gain_table)
3397{
3398
3399 /* here detmon actually computes gain QC parameter */
3400 double double_adu;
3401 double avg_on_dif, sig_on_dif;
3402 irplib_ksigma_clip(on_dif, 1, 1, cpl_image_get_size_x(on_dif),
3403 cpl_image_get_size_y(on_dif), kappa, nclip, 1e-5,
3404 &avg_on_dif, &sig_on_dif);
3405 skip_if(
3406 cpl_table_set_double(gain_table, "SIG_ON_DIF", pos,
3407 sig_on_dif));
3408 if (cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE) {
3409 double_adu = (avg_on1 + avg_on2) - 2 * avg_off1;
3410 }
3411 else {
3412 double_adu = (avg_on1 + avg_on2) - (avg_off1 + avg_off2);
3413
3414 const double sigma
3415 = (sig_on_dif * sig_on_dif) - (sig_off_dif * sig_off_dif);
3416
3417 /* sigma_corr = autocorr * sigma; */
3418
3419 const double gain = double_adu / (c_ndit * sigma);
3420
3421 const double gain_corr = gain / (autocorr);
3422
3423 skip_if(cpl_table_set_double(gain_table, "GAIN", pos, gain));
3424 skip_if(
3425 cpl_table_set_double(gain_table, "GAIN_CORR", pos,
3426 gain_corr));
3427 }
3428 /* cpl_msg_info(cpl_func,"gain=%g gain_corr=%g autocorr=%g",gain,gain_corr,autocorr); */
3429 skip_if(cpl_table_set_double(gain_table, "AUTOCORR", pos, autocorr));
3430 skip_if(cpl_table_set_double(gain_table, "ADU", pos, double_adu / 2));
3431 /* FIXME: Remove the following 3 columns after testing period */
3432 skip_if(
3433 cpl_table_set_double(gain_table, "Y_FIT", pos,
3434 c_ndit * sig_on_dif * sig_on_dif));
3435 skip_if(
3436 cpl_table_set_double(gain_table, "Y_FIT_CORR", pos,
3437 c_ndit * sig_on_dif * sig_on_dif));
3438 skip_if(cpl_table_set_double(gain_table, "X_FIT", pos, double_adu));
3439 skip_if(
3440 cpl_table_set_double(gain_table, "X_FIT_CORR", pos,
3441 double_adu / autocorr));
3442
3443 end_skip;
3444
3445 return cpl_error_get_code();
3446}
3447
3448static double
3449detmon_gain_prepare_autocorr(unsigned mode, const int pos,
3450 int m, int n, cpl_imagelist* diff_flats,
3451 cpl_image* on_dif, cpl_imagelist* autocorr_images)
3452{
3453 double autocorr = 1.0;
3454
3455 if (mode & IRPLIB_GAIN_WITH_AUTOCORR) {
3456 if (diff_flats) {
3457 cpl_image * diff = cpl_image_duplicate(on_dif);
3458 skip_if(cpl_imagelist_set(diff_flats, diff, pos));
3459 }
3460 if (autocorr_images) {
3461 cpl_image * corr = NULL;
3462 autocorr = detmon_autocorr_factor(on_dif, &corr, m, n);
3463 if (corr) {
3464 skip_if(cpl_imagelist_set(autocorr_images, corr, pos));
3465 }
3466 else {
3467 detmon_lg_add_empty_image(autocorr_images, pos);
3468 }
3469 }
3470 else {
3471 autocorr = detmon_autocorr_factor(on_dif, NULL, m, n);
3472 }
3473 autocorr = isnan(autocorr) ? 1.0 : autocorr;
3474 }
3475 end_skip;
3476
3477 return autocorr;
3478}
3479
3480static double
3481detmon_gain_prepare_table(const cpl_imagelist* offs, unsigned mode, int llx,
3482 int lly, int urx, int ury, double kappa, int nclip,
3483 double std, const int pos,
3484 cpl_table* gain_table, double* avg_off2,
3485 double* sig_off_dif)
3486{
3487 double avg_off1 = 0.0;
3488
3489 /* prepare gain table to compute gain QC param */
3490 /* TODO: AMO sees that the condition (mode & IRPLIB_GAIN_NO_COLLAPSE)
3491 * is repeated in 2 if entries==> probably one should rewrite the if
3492 * construct
3493 */
3494 if (cpl_imagelist_get_size(offs) == 1 && mode & IRPLIB_GAIN_NO_COLLAPSE) {
3495
3496 skip_if(
3497 irplib_ksigma_clip(cpl_imagelist_get_const(offs, 0),
3498 llx, lly, urx, ury, kappa, nclip, 1e-5,
3499 &avg_off1, &std));
3500 skip_if(cpl_table_set_double(gain_table, "MEAN_OFF", pos, avg_off1));
3501
3502 }
3503 else if ((mode & IRPLIB_GAIN_NO_COLLAPSE)
3504 || (pos == 0 && mode & IRPLIB_GAIN_COLLAPSE)) {
3505 cpl_image * off_dif = NULL;
3506 double avg_off_dif;
3507 skip_if(
3508 irplib_ksigma_clip(cpl_imagelist_get_const(offs, 0),
3509 llx, lly, urx, ury, kappa, nclip, 1e-5,
3510 &avg_off1, &std));
3511 skip_if(cpl_table_set_double(gain_table, "MEAN_OFF1", pos, avg_off1));
3512 skip_if(
3513 irplib_ksigma_clip(cpl_imagelist_get_const(offs, 1),
3514 llx, lly, urx, ury, kappa, nclip, 1e-5,
3515 avg_off2, &std));
3516 skip_if(cpl_table_set_double(gain_table, "MEAN_OFF2", pos, *avg_off2));
3517 off_dif = detmon_subtract_create_window(
3518 cpl_imagelist_get_const(offs, 0),
3519 cpl_imagelist_get_const(offs, 1), llx, lly, urx, ury);
3520 skip_if(off_dif == NULL);
3521 irplib_ksigma_clip(off_dif, 1, 1, cpl_image_get_size_x(off_dif),
3522 cpl_image_get_size_y(off_dif), kappa, nclip, 1e-5,
3523 &avg_off_dif, sig_off_dif);
3524 cpl_image_delete(off_dif);
3525 skip_if(
3526 cpl_table_set_double(gain_table, "SIG_OFF_DIF", pos,
3527 *sig_off_dif));
3528 }
3529 else if (pos > 0 && (mode & IRPLIB_GAIN_COLLAPSE)) {
3530
3531 int status;
3532 avg_off1 = cpl_table_get_double(gain_table, "MEAN_OFF1", 0, &status);
3533 skip_if(cpl_table_set_double(gain_table, "MEAN_OFF1", pos, avg_off1));
3534 *avg_off2 = cpl_table_get_double(gain_table, "MEAN_OFF2", 0, &status);
3535 skip_if(cpl_table_set_double(gain_table, "MEAN_OFF2", pos, *avg_off2));
3536 *sig_off_dif = cpl_table_get_double(gain_table, "SIG_OFF_DIF", 0,
3537 &status);
3538 skip_if(
3539 cpl_table_set_double(gain_table, "SIG_OFF_DIF", pos,
3540 *sig_off_dif));
3541 }
3542
3543 end_skip;
3544
3545 return avg_off1;
3546}
3547
3548/*---------------------------------------------------------------------------*/
3583/*---------------------------------------------------------------------------*/
3584static cpl_error_code
3585detmon_gain_table_fill_row(cpl_table * gain_table,
3586 double c_dit,int c_ndit,
3587 cpl_imagelist * autocorr_images,
3588 cpl_imagelist * diff_flats,
3589 const cpl_imagelist * ons,
3590 const cpl_imagelist * offs,
3591 double kappa, int nclip,
3592 int llx, int lly, int urx, int ury,
3593 int m, int n,
3594 double gain_threshold,
3595 int pos, unsigned mode, int* rows_gain_affected)
3596{
3597 const cpl_image *image;
3598 cpl_image *on_dif = NULL;
3599 double std = 0;
3600 double avg_on1, avg_on2;
3601 double avg_off1, avg_off2;
3602 double autocorr;
3603
3604 cpl_table_set(gain_table, "FLAG", pos, 1);
3605 if (mode & IRPLIB_GAIN_NIR)
3606 {
3607 cpl_table_set(gain_table, "DIT", pos, c_dit);
3608 cpl_table_set(gain_table, "NDIT", pos, c_ndit);
3609 } else if (mode & IRPLIB_GAIN_OPT)
3610 {
3611 cpl_table_set(gain_table, "EXPTIME", pos, c_dit);
3612 } else
3613 {
3614 cpl_msg_error(cpl_func, "Mandatory mode (OPT or NIR) not provided");
3615 skip_if(1);
3616 }
3617 if(*rows_gain_affected == 0)
3618 {
3619 cpl_msg_info(cpl_func, "skip the frame #%d", pos + 1);
3620 cpl_table_set(gain_table, "FLAG", pos, 0);
3621 if(mode & IRPLIB_GAIN_WITH_AUTOCORR)
3622 {
3623 autocorr = -1;
3624 if (diff_flats)
3625 {
3626 detmon_lg_add_empty_image(diff_flats, pos);
3627 }
3628 if (autocorr_images)
3629 {
3630 detmon_lg_add_empty_image(autocorr_images, pos);
3631 }
3632 }
3633 return cpl_error_get_code();
3634 }
3635 skip_if((image = cpl_imagelist_get_const(ons, 0)) == NULL);
3636 skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
3637 nclip, 1e-5, &avg_on1, &std));
3638 skip_if((image = cpl_imagelist_get_const(ons, 1)) == NULL);
3639 skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
3640 nclip, 1e-5, &avg_on2, &std));
3641
3642 if (
3643 (avg_on1 > gain_threshold) ||
3644 (avg_on2 > gain_threshold)
3645 )
3646 {
3647 /* If frames has intensity above threshold write out warning and adjust
3648 * imagelists
3649 */
3650 if ( (avg_on1 > gain_threshold) || (avg_on2 > gain_threshold) )
3651 {
3652 cpl_msg_warning(cpl_func, "Average level is above the limit set by the gain_theshold parameter, "
3653 "the frames would not be taken into calculation");
3654
3655 cpl_msg_warning(cpl_func, "Average levels [%f ; %f], limit [%f]",
3656 avg_on1, avg_on2, gain_threshold);
3657 }
3658
3659 cpl_msg_info(cpl_func, "skip the frame #%d", pos + 1);
3660 cpl_table_set(gain_table, "FLAG", pos, 0);
3661 if(mode & IRPLIB_GAIN_WITH_AUTOCORR)
3662 {
3663 autocorr = -1;
3664 if (diff_flats)
3665 {
3666 detmon_lg_add_empty_image(diff_flats, pos);
3667 }
3668 if (autocorr_images)
3669 {
3670 detmon_lg_add_empty_image(autocorr_images, pos);
3671 }
3672 }
3673 *rows_gain_affected = 0;
3674 }
3675 else
3676 {
3677 /* we can compute gain: first computes relevant quantities to cover all
3678 * cases, then compute QC parameter.
3679 */
3680 double sig_off_dif;
3681 *rows_gain_affected = 1;
3682 skip_if(cpl_table_set_double(gain_table, "MEAN_ON1", pos, avg_on1));
3683 skip_if(cpl_table_set_double(gain_table, "MEAN_ON2", pos, avg_on2));
3684
3685 on_dif =
3686 detmon_subtract_create_window(cpl_imagelist_get_const(ons, 0),
3687 cpl_imagelist_get_const(ons, 1),
3688 llx, lly, urx, ury);
3689 skip_if(on_dif == NULL);
3690
3691 autocorr = detmon_gain_prepare_autocorr(mode, pos, m, n,
3692 diff_flats, on_dif, autocorr_images);
3693
3694 avg_off1 = detmon_gain_prepare_table(offs, mode, llx, lly, urx, ury,
3695 kappa, nclip, std, pos, gain_table, &avg_off2,
3696 &sig_off_dif);
3697
3698 detmon_gain_compute_qc(kappa, nclip, pos, offs, mode,
3699 avg_on1, avg_on2, avg_off1, avg_off2,
3700 sig_off_dif, c_ndit, autocorr, on_dif,
3701 gain_table);
3702 }
3703 end_skip;
3704
3705 cpl_image_delete(on_dif);
3706
3707 return cpl_error_get_code();
3708}
3709
3710
3711
3712/*---------------------------------------------------------------------------*/
3733/*---------------------------------------------------------------------------*/
3734static cpl_error_code
3735detmon_check_saturation_on_pair(cpl_imagelist * autocorr_images,
3736 cpl_imagelist * diff_flats,
3737 const cpl_imagelist * ons,
3738 double kappa, int nclip,
3739 int llx, int lly, int urx, int ury,
3740 double saturation_limit,
3741 const int pos, unsigned mode, int* rows_linear_affected)
3742{
3743 const cpl_image *image;
3744 double std = 0;
3745 double avg_on1, avg_on2;
3746
3747
3748 if(*rows_linear_affected == 0)
3749 {
3750 cpl_msg_info(cpl_func, "For linearity skip the frame #%d", pos + 1);
3751 if(mode & IRPLIB_GAIN_WITH_AUTOCORR)
3752 {
3753 if (diff_flats)
3754 {
3755 detmon_lg_add_empty_image(diff_flats, pos);
3756 }
3757 if (autocorr_images)
3758 {
3759 detmon_lg_add_empty_image(autocorr_images, pos);
3760 }
3761 }
3762 return cpl_error_get_code();
3763 }
3764 skip_if((image = cpl_imagelist_get_const(ons, 0)) == NULL);
3765 skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
3766 nclip, 1e-5, &avg_on1, &std));
3767 skip_if((image = cpl_imagelist_get_const(ons, 1)) == NULL);
3768 skip_if(irplib_ksigma_clip(image, llx, lly, urx, ury, kappa,
3769 nclip, 1e-5, &avg_on2, &std));
3770
3771 if (
3772 (avg_on1 > saturation_limit) ||
3773 (avg_on2 > saturation_limit)
3774 )
3775 {
3776 /* If frames has intensity above threshold write out warning and adjust
3777 * imagelists
3778 */
3779 if ( (avg_on1 > saturation_limit) || (avg_on2 > saturation_limit) )
3780 {
3781 cpl_msg_warning(cpl_func, "Average level is above the limit set by the saturation_limit parameter, "
3782 "the frames would not be taken into calculation");
3783
3784 cpl_msg_warning(cpl_func, "Average levels [%f ; %f], limit [%f]",
3785 avg_on1, avg_on2, saturation_limit);
3786 }
3787
3788 cpl_msg_info(cpl_func, "skip the frame #%d", pos + 1);
3789 *rows_linear_affected = 0;
3790 } else{
3791
3792 }
3793
3794 end_skip;
3795
3796 return cpl_error_get_code();
3797}
3798
3799
3800
3801
3802/*--------------------------------------------------------------------------*/
3809/*--------------------------------------------------------------------------*/
3810
3811static cpl_image *
3812detmon_bpixs(const cpl_imagelist * coeffs,
3813 cpl_boolean bpmbin,
3814 const double kappa,
3815 int *nbpixs)
3816{
3817
3818
3819 const cpl_image *first= cpl_imagelist_get_const(coeffs, 0);
3820
3821
3822
3823
3824
3825
3826 cpl_mask *mask = cpl_mask_new(cpl_image_get_size_x(first),
3827 cpl_image_get_size_y(first));
3828
3829 cpl_image *bpm = NULL; /* Avoid false uninit warning */
3830
3831
3832 int size = cpl_imagelist_get_size(coeffs);
3833
3834 if(!bpmbin) {
3835 bpm = cpl_image_new(cpl_image_get_size_x(first),
3836 cpl_image_get_size_y(first),
3837 CPL_TYPE_INT);
3838 }
3839
3840
3841 for(int i = 0; i < size; i++) {
3842 const cpl_image * cur_coeff = cpl_imagelist_get_const(coeffs, i);
3843
3844 cpl_stats* stats = cpl_stats_new_from_image(cur_coeff,
3845 CPL_STATS_MEAN | CPL_STATS_STDEV);
3846 double cur_mean = cpl_stats_get_mean(stats);
3847 double cur_stdev = cpl_stats_get_stdev(stats);
3848
3849 double lo_cut = cur_mean - kappa * cur_stdev;
3850 double hi_cut = cur_mean + kappa * cur_stdev;
3851
3852 cpl_mask* cur_mask = cpl_mask_threshold_image_create(cur_coeff, lo_cut, hi_cut);
3853 cpl_mask_not(cur_mask);
3854
3855 if(!bpmbin) {
3856 cpl_image* cur_image = cpl_image_new_from_mask(cur_mask);
3857 double p = pow(2, i);
3858 cpl_image_power(cur_image, p);
3859 cpl_image_add(bpm, cur_image);
3860 cpl_image_delete(cur_image);
3861 }
3862
3863 cpl_mask_or(mask, cur_mask);
3864
3865 cpl_mask_delete(cur_mask);
3866 cpl_stats_delete(stats);
3867 }
3868
3869 if(bpmbin) {
3870 bpm = cpl_image_new_from_mask(mask);
3871 }
3872
3873 *nbpixs = cpl_mask_count(mask);
3874
3875 cpl_mask_delete(mask);
3876
3877 return bpm;
3878}
3879
3880
3881/*--------------------------------------------------------------------------*/
3888/*--------------------------------------------------------------------------*/
3889/* Not used so we temporary comment it out
3890static cpl_image *
3891detmon_bpixs2(cpl_vector* x,const cpl_imagelist* y,
3892 const cpl_imagelist * coeffs,cpl_table* gain_table,
3893 const int order, const double kappa,cpl_boolean bpmbin,
3894 int *nbpixs)
3895{
3896
3897
3898 int size_x=0;
3899 int size_y=0;
3900 int size_c=0;
3901
3902
3903 int i=0;
3904 int j=0;
3905 cpl_size k=0;
3906 int z=0;
3907 int pix=0;
3908 int sx=0;
3909 int sy=0;
3910
3911 double* px=NULL;
3912 const float* pdata=NULL;
3913 const float* pcoeffs=NULL;
3914 double pfit=0.;
3915 double* pgain=NULL;
3916 cpl_binary* pmask=NULL;
3917 double gain=0;
3918 const cpl_image* img_data=NULL;
3919
3920 const cpl_image* img_coeffs=NULL;
3921 cpl_image* bpm=NULL;
3922 cpl_mask* mask=NULL;
3923
3924 cpl_polynomial* pol=NULL;
3925
3926 size_x = cpl_vector_get_size(x);
3927 size_y = cpl_imagelist_get_size(y);
3928 size_c = cpl_imagelist_get_size(coeffs);
3929 img_data = cpl_imagelist_get_const(coeffs, 0);
3930 sx = cpl_image_get_size_x(img_data);
3931 sy = cpl_image_get_size_y(img_data);
3932 mask = cpl_mask_new(sx,sy);
3933
3934 cpl_ensure(size_x == size_y, CPL_ERROR_NULL_INPUT, NULL);
3935
3936 cpl_ensure(size_c == (order+1), CPL_ERROR_NULL_INPUT, NULL);
3937
3938 px = cpl_vector_get_data(x);
3939 pmask=cpl_mask_get_data(mask);
3940 pgain=cpl_table_get_data_double(gain_table,"GAIN");
3941 pol=cpl_polynomial_new(1);
3942 for (z = 0; z < size_x; z++) {
3943
3944 img_data = cpl_imagelist_get_const(y, z);
3945 pdata = cpl_image_get_data_float_const(img_data);
3946 gain=pgain[z];
3947
3948 for (j = 0; j < sy; j++) {
3949
3950 for (i = 0; i < sx; i++) {
3951
3952 pix = j * sx + i;
3953
3954 for (k = size_c-1; k >= 0; k--) {
3955
3956 img_coeffs = cpl_imagelist_get_const(coeffs, k);
3957 pcoeffs = cpl_image_get_data_float_const(img_coeffs);
3958 cpl_polynomial_set_coeff(pol, &k, pcoeffs[pix]);
3959
3960 }
3961
3962 pfit = cpl_polynomial_eval_1d(pol,px[z],NULL);
3963 if (pdata[pix] > 0) {
3964 if (fabs(pdata[pix] - pfit) > kappa * sqrt(gain*pdata[pix])) {
3965 pmask[pix] = CPL_BINARY_1;
3966 } // check if point to be flagged
3967 } // check if pos intensity
3968 } // i loop
3969 } // j loop
3970
3971 //cpl_image_delete(img_data);
3972
3973 } // z loop
3974 cpl_polynomial_delete(pol);
3975 if (bpmbin) {
3976 bpm = cpl_image_new_from_mask(mask);
3977 }
3978
3979 *nbpixs += cpl_mask_count(mask);
3980
3981 cpl_mask_delete(mask);
3982
3983 return bpm;
3984}
3985
3986*/
3987/*---------------------------------------------------------------------------*/
3999/*---------------------------------------------------------------------------*/
4000
4001static double
4002detmon_autocorr_factor(const cpl_image * image,
4003 cpl_image ** autocorr_image, int m, int n)
4004{
4005 cpl_image * mycorr_image = NULL;
4006 double autocorr = 0;
4007
4008
4009 mycorr_image = detmon_image_correlate(image, image, m, n);
4010
4011 if (cpl_error_get_code() == CPL_ERROR_UNSUPPORTED_MODE)
4012 {
4013 cpl_msg_warning(cpl_func, "FFTW is not supported by CPL, autocorrelation "
4014 "would be computed using internal implementation");
4015 cpl_error_reset();
4016 if (mycorr_image)
4017 cpl_image_delete(mycorr_image);
4018 mycorr_image = detmon_autocorrelate(image, m, n);
4019 }
4020 if(mycorr_image == NULL) {
4021 return -1;
4022 }
4023
4024 cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), -1);
4025
4026 autocorr = cpl_image_get_flux(mycorr_image);
4027
4028 if (autocorr_image) *autocorr_image = mycorr_image;
4029 else cpl_image_delete(mycorr_image);
4030
4031 return autocorr;
4032}
4033
4034static cpl_propertylist*
4035detmon_lg_extract_qclist_4plane(cpl_propertylist* linc_qclist,const int ip)
4036{
4037
4038 cpl_propertylist* sub_set=NULL;
4039 char* qc_key=NULL;
4040
4041 sub_set=cpl_propertylist_new();
4042 qc_key=cpl_sprintf("QC LIN COEF%d",ip);
4043 cpl_propertylist_copy_property_regexp(sub_set,linc_qclist,qc_key,0);
4044
4045 cpl_free(qc_key);
4046 return sub_set;
4047
4048}
4049
4050
4060static cpl_error_code
4061detmon_lg_extract_extention_header(cpl_frameset* frameset,
4062 cpl_propertylist* gaint_qclist,
4063 cpl_propertylist* lint_qclist,
4064 cpl_propertylist* linc_qclist,
4065 cpl_propertylist* bpm_qclist,
4066 int whichext)
4067{
4068
4069 cpl_propertylist * xplist = NULL;
4070
4071 const char * filename =
4072 cpl_frame_get_filename(cpl_frameset_get_position(frameset, 0));
4073
4074 xplist = cpl_propertylist_load_regexp(filename, whichext,
4075 "ESO DET|EXTNAME", 0);
4076 if (detmon_lg_config.exts >= 0)
4077 {
4078 /* for one extension, copy only extname keyword (if any) - DFS09856 */
4079 cpl_property* propExtname = NULL;
4080 propExtname = cpl_propertylist_get_property(xplist, "EXTNAME");
4081 cpl_error_reset();
4082 if (NULL != propExtname)
4083 {
4084 propExtname = cpl_property_duplicate(propExtname);
4085 }
4086 cpl_propertylist_delete(xplist);
4087 xplist = NULL;
4088 if (NULL != propExtname)
4089 {
4090 xplist = cpl_propertylist_new();
4091 cpl_propertylist_append_property(xplist, propExtname);
4092 cpl_property_delete(propExtname);
4093 }
4094 }
4095 if (NULL != xplist)
4096 {
4097 cpl_propertylist_append(gaint_qclist, xplist);
4098 cpl_propertylist_append(lint_qclist, xplist);
4099 cpl_propertylist_append(linc_qclist, xplist);
4100 cpl_propertylist_append(bpm_qclist, xplist);
4101 cpl_propertylist_delete(xplist);
4102 }
4103
4104 return cpl_error_get_code();
4105}
4106
4107
4108
4109
4110
4111/*---------------------------------------------------------------------------*/
4120/*---------------------------------------------------------------------------*/
4121static cpl_error_code
4122detmon_lg_save_table_with_pro_keys(cpl_table* table,
4123 const char* name_o,
4124 cpl_propertylist* xheader,
4125 unsigned CPL_IO_MODE)
4126{
4127
4128 cpl_propertylist* pro_keys=NULL;
4129
4130 pro_keys=detmon_load_pro_keys(name_o);
4131 cpl_propertylist_append(xheader,pro_keys);
4132
4133 if(CPL_IO_MODE==CPL_IO_DEFAULT) {
4134 cpl_propertylist * pri_head=cpl_propertylist_load(name_o,0);
4135 cpl_table_save(table, pri_head,xheader,name_o,
4136 CPL_IO_DEFAULT);
4137 cpl_propertylist_delete(pri_head);
4138
4139 } else {
4140 cpl_table_save(table,NULL,xheader,name_o,
4141 CPL_IO_EXTEND);
4142 }
4143 cpl_propertylist_delete(pro_keys);
4144
4145 return cpl_error_get_code();
4146}
4147
4148/*---------------------------------------------------------------------------*/
4156/*---------------------------------------------------------------------------*/
4157static cpl_error_code
4158detmon_lg_save_image_with_pro_keys(cpl_image* image,
4159 const char* name_o,
4160 cpl_propertylist* xheader)
4161{
4162
4163 cpl_propertylist* pro_keys=NULL;
4164 pro_keys=detmon_load_pro_keys(name_o);
4165 cpl_propertylist_append(xheader,pro_keys);
4166
4167 cpl_image_save(image,name_o, CPL_BPP_IEEE_FLOAT,
4168 xheader,CPL_IO_EXTEND);
4169 cpl_propertylist_delete(pro_keys);
4170
4171
4172 return cpl_error_get_code();
4173}
4174
4175/*---------------------------------------------------------------------------*/
4183/*---------------------------------------------------------------------------*/
4184static cpl_error_code
4185detmon_lg_save_imagelist_with_pro_keys(cpl_imagelist* imagelist,
4186 const char* name_o,
4187 cpl_propertylist* xheader)
4188{
4189
4190 cpl_propertylist* pro_keys=NULL;
4191 pro_keys=detmon_load_pro_keys(name_o);
4192 cpl_propertylist_append(xheader,pro_keys);
4193
4194 cpl_imagelist_save(imagelist,name_o, CPL_BPP_IEEE_FLOAT,
4195 xheader,CPL_IO_EXTEND);
4196
4197 cpl_propertylist_delete(pro_keys);
4198
4199
4200 return cpl_error_get_code();
4201}
4202
4203/*---------------------------------------------------------------------------*/
4220static cpl_error_code
4221detmon_lg_save_plane(const cpl_parameterlist * parlist,
4222 cpl_frameset* frameset,
4223 const cpl_frameset * usedframes,
4224 int whichext,
4225 const char* recipe_name,
4226 cpl_propertylist* mypro_coeffscube,
4227 cpl_propertylist* linc_plane_qclist,
4228 const char* package,
4229 const char* NAME_O,
4230 cpl_image* plane)
4231{
4232 if(detmon_lg_config.exts == 0) {
4233 cpl_propertylist* plist=NULL;
4234 cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4235 NULL, NULL,
4236 CPL_BPP_IEEE_FLOAT, recipe_name,
4237 mypro_coeffscube, NULL,
4238 package, NAME_O);
4239 plist=cpl_propertylist_load(NAME_O,0);
4240 cpl_image_save(plane,NAME_O, CPL_BPP_IEEE_FLOAT,
4241 plist,CPL_IO_DEFAULT);
4242 cpl_propertylist_delete(plist);
4243
4244 } else if(detmon_lg_config.exts > 0) {
4245 cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4246 NULL, NULL,
4247 CPL_BPP_IEEE_FLOAT, recipe_name,
4248 mypro_coeffscube, NULL,
4249 package, NAME_O);
4250
4251 detmon_lg_save_image_with_pro_keys(plane,NAME_O,linc_plane_qclist);
4252 } else {
4253 if(whichext == 1)
4254 {
4255 cpl_dfs_save_image(frameset, NULL, parlist,
4256 usedframes,NULL, NULL,
4257 CPL_BPP_IEEE_FLOAT, recipe_name,
4258 mypro_coeffscube, NULL,
4259 package, NAME_O);
4260 detmon_lg_save_image_with_pro_keys(plane,NAME_O,linc_plane_qclist);
4261 } else {
4262
4263 detmon_lg_save_image_with_pro_keys(plane,NAME_O,linc_plane_qclist);
4264
4265 }
4266
4267 }
4268
4269 return cpl_error_get_code();
4270}
4271
4272
4273
4274/*---------------------------------------------------------------------------*/
4292static cpl_error_code
4293detmon_lg_save_cube(const cpl_parameterlist * parlist,
4294 cpl_frameset* frameset,
4295 const cpl_frameset * usedframes,
4296 int whichext,
4297 const char* recipe_name,
4298 cpl_propertylist* mypro_coeffscube,
4299 cpl_propertylist* linc_qclist,
4300 const char* package,
4301 const char* NAME_O,
4302 cpl_imagelist* coeffs)
4303{
4304
4305 if(detmon_lg_config.exts == 0) {
4306 cpl_propertylist_append(mypro_coeffscube, linc_qclist);
4307 detmon_lg_dfs_save_imagelist
4308 (frameset, parlist, usedframes, coeffs,
4309 recipe_name, mypro_coeffscube, package,
4310 NAME_O);
4311 } else if(detmon_lg_config.exts > 0) {
4312 cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4313 NULL, NULL,
4314 CPL_BPP_IEEE_FLOAT, recipe_name,
4315 mypro_coeffscube, NULL,
4316 package, NAME_O);
4317
4318 detmon_lg_save_imagelist_with_pro_keys(coeffs,NAME_O,linc_qclist);
4319
4320 } else {
4321 if(whichext == 1) {
4322 cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4323 NULL, NULL,
4324 CPL_BPP_IEEE_FLOAT, recipe_name,
4325 mypro_coeffscube, NULL,
4326 package, NAME_O);
4327 if (coeffs)
4328 detmon_lg_save_imagelist_with_pro_keys(coeffs,NAME_O,linc_qclist);
4329 else
4330 cpl_propertylist_save(linc_qclist, NAME_O, CPL_IO_EXTEND);
4331 } else {
4332 if (coeffs)
4333 detmon_lg_save_imagelist_with_pro_keys(coeffs,NAME_O,linc_qclist);
4334 else
4335 cpl_propertylist_save(linc_qclist, NAME_O, CPL_IO_EXTEND);
4336 }
4337 }
4338
4339 return cpl_error_get_code();
4340}
4341
4342static char*
4343detmon_lg_set_paf_name_and_header(cpl_frame* ref_frame,
4344 int flag_sets,int which_set,
4345 int whichext,
4346 const char* paf_suf,
4347 cpl_propertylist** plist)
4348{
4349 char * paf_name=NULL;
4350
4351 if(detmon_lg_config.exts >= 0)
4352 {
4353 *plist =cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4354 detmon_lg_config.exts);
4355
4356 if(!flag_sets)
4357 {
4358 paf_name=cpl_sprintf("%s_%s.paf", detmon_lg_config.pafname,paf_suf);
4359 }
4360 else
4361 {
4362 paf_name=cpl_sprintf("%s_%s_set%02d.paf",
4363 detmon_lg_config.pafname, paf_suf,which_set);
4364 }
4365 }
4366 else
4367 {
4368 *plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4369 whichext);
4370
4371
4372 if(!flag_sets)
4373 {
4374 paf_name=cpl_sprintf("%s_%s_ext%02d.paf",
4375 detmon_lg_config.pafname, paf_suf,whichext);
4376 }
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
4385 return paf_name;
4386}
4387
4388
4389static char*
4390detmon_lg_set_paf_name_and_header_ext(cpl_frame* ref_frame,
4391 int flag_sets,int which_set,
4392 int whichext,
4393 const char* paf_suf,
4394 cpl_propertylist** plist)
4395{
4396 char* paf_name=NULL;
4397
4398 if(detmon_lg_config.exts >= 0)
4399 {
4400 *plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4401 detmon_lg_config.exts);
4402
4403 if(!flag_sets)
4404 {
4405 paf_name=cpl_sprintf("%s_%s.paf", detmon_lg_config.pafname,paf_suf);
4406 } else
4407 {
4408 paf_name=cpl_sprintf("%s_%s_set%02d.paf",
4409 detmon_lg_config.pafname, paf_suf,which_set);
4410 }
4411 } else
4412 {
4413 *plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4414 whichext);
4415 if(!flag_sets)
4416 {
4417 paf_name=cpl_sprintf("%s_%s_ext%02d.paf",
4418 detmon_lg_config.pafname, paf_suf,whichext);
4419 } else
4420 {
4421 paf_name=cpl_sprintf("%s_%s_set%02d_ext%02d.paf",
4422 detmon_lg_config.pafname,paf_suf,
4423 which_set, whichext);
4424 }
4425 }
4426 return paf_name;
4427
4428}
4429
4430static cpl_error_code
4431detmon_lg_save_paf_product(cpl_frame* ref_frame,int flag_sets,
4432 int which_set,int whichext,
4433 const char* pafregexp,
4434 const char* procatg,
4435 const char* pipeline_name,
4436 const char* recipe_name,
4437 const char* paf_suf,
4438 cpl_propertylist* qclist,
4439 const int ext)
4440
4441{
4442 /* Set the file name for the linearity table PAF */
4443 char* paf_name=NULL;
4444 cpl_propertylist* plist=NULL;
4445 cpl_propertylist* paflist = NULL;
4446 cpl_propertylist* mainplist=NULL;
4447
4448 mainplist =cpl_propertylist_load(cpl_frame_get_filename(ref_frame),0);
4449 if(ext==0) {
4450 paf_name=detmon_lg_set_paf_name_and_header(ref_frame,flag_sets,
4451 which_set,whichext,
4452 paf_suf,&plist);
4453 } else {
4454 paf_name=detmon_lg_set_paf_name_and_header_ext(ref_frame,flag_sets,
4455 which_set,whichext,
4456 paf_suf,&plist);
4457 }
4458
4459
4460 paflist = cpl_propertylist_new();
4461 cpl_propertylist_append_string(paflist, CPL_DFS_PRO_CATG,procatg);
4462
4463 /* Get the keywords for the paf file */
4464 cpl_propertylist_copy_property_regexp(paflist, plist,pafregexp, 0);
4465 cpl_propertylist_copy_property_regexp(paflist, mainplist,pafregexp, 0);
4466 cpl_propertylist_append(paflist,qclist);
4467
4468 /* Save the PAF */
4469 cpl_dfs_save_paf(pipeline_name, recipe_name,paflist,paf_name);
4470
4471 /* free memory */
4472 cpl_propertylist_delete(mainplist);
4473 cpl_propertylist_delete(paflist);
4474 cpl_propertylist_delete(plist);
4475 cpl_free(paf_name);
4476
4477 return cpl_error_get_code();
4478
4479}
4480
4481
4482
4483/*---------------------------------------------------------------------------*/
4514static cpl_error_code
4515detmon_lg_save(const cpl_parameterlist * parlist,
4516 cpl_frameset * frameset,
4517 const char *recipe_name,
4518 const char *pipeline_name,
4519 const char *pafregexp,
4520 const cpl_propertylist * pro_lintbl,
4521 const cpl_propertylist * pro_gaintbl,
4522 const cpl_propertylist * pro_coeffscube,
4523 const cpl_propertylist * pro_bpm,
4524 const cpl_propertylist * pro_corr,
4525 const cpl_propertylist * pro_diff,
4526 const char *package,
4527 cpl_imagelist * coeffs,
4528 cpl_table * gain_table,
4529 cpl_table * linear_table,
4530 cpl_image * bpms,
4531 cpl_imagelist * autocorr_images,
4532 cpl_imagelist * diff_flats,
4533 cpl_propertylist * gaint_qclist,
4534 cpl_propertylist * lint_qclist,
4535 cpl_propertylist * linc_qclist,
4536 cpl_propertylist * bpm_qclist,
4537 const int flag_sets,
4538 const int which_set,
4539 const cpl_frameset * usedframes,
4540 int whichext)
4541{
4542
4543 cpl_frame *ref_frame;
4544 cpl_propertylist *plist = NULL;
4545 cpl_propertylist *mainplist = NULL;
4546 char* NAME_O=NULL;
4547 char* PREF_O=NULL;
4548 int nb_images;
4549 int i;
4550
4551 cpl_propertylist * xplist = NULL;
4552
4553 cpl_propertylist* linc_plane_qclist=NULL;
4554 cpl_image* plane=NULL;
4555 int ip=0;
4556 char* pcatg_plane=NULL;
4557
4558 cpl_propertylist * mypro_lintbl =
4559 cpl_propertylist_duplicate(pro_lintbl);
4560 cpl_propertylist * mypro_gaintbl =
4561 cpl_propertylist_duplicate(pro_gaintbl);
4562 cpl_propertylist * mypro_coeffscube =
4563 cpl_propertylist_duplicate(pro_coeffscube);
4564 cpl_propertylist * mypro_bpm =
4565 cpl_propertylist_duplicate(pro_bpm);
4566 cpl_propertylist * mypro_corr =
4567 cpl_propertylist_duplicate(pro_corr);
4568 cpl_propertylist * mypro_diff =
4569 cpl_propertylist_duplicate(pro_diff);
4570
4571 const char * procatg_lintbl =
4572 cpl_propertylist_get_string(mypro_lintbl, CPL_DFS_PRO_CATG);
4573
4574 const char * procatg_gaintbl =
4575 cpl_propertylist_get_string(mypro_gaintbl, CPL_DFS_PRO_CATG);
4576
4577 const char * procatg_coeffscube =
4578 cpl_propertylist_get_string(mypro_coeffscube, CPL_DFS_PRO_CATG);
4579 const char * procatg_bpm =
4580 cpl_propertylist_get_string(mypro_bpm, CPL_DFS_PRO_CATG);
4581
4582
4583 /* Extract extension headers if multi-extension */
4584 detmon_lg_extract_extention_header(frameset,gaint_qclist,lint_qclist,
4585 linc_qclist,bpm_qclist,whichext);
4586
4587 /* This is only used later for PAF and temporarily for COEFFS_CUBE
4588 (see if defined)*/
4589 /* Get FITS header from reference file */
4590 ref_frame = cpl_frameset_get_position(frameset, 0);
4591
4592 skip_if((mainplist =
4593 cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
4594 0)) == NULL);
4595
4596 /*******************************/
4597 /* Write the LINEARITY TABLE */
4598 /*******************************/
4599 cpl_msg_info(cpl_func,"Write the LINEARITY TABLE");
4600 /* Set the file name for the table */
4601 if(!flag_sets) {
4602 NAME_O=cpl_sprintf("%s_linearity_table.fits", recipe_name);
4603 } else {
4604 NAME_O=cpl_sprintf("%s_linearity_table_set%02d.fits", recipe_name,
4605 which_set);
4606 }
4607
4608 if (detmon_lg_config.exts >= 0) {
4609 /* Save the table */
4610 cpl_propertylist_append(mypro_lintbl, lint_qclist);
4611 skip_if(cpl_dfs_save_table(frameset, NULL,parlist, usedframes, NULL,
4612 linear_table,NULL, recipe_name,
4613 mypro_lintbl, NULL, package, NAME_O));
4614
4615 detmon_lg_save_table_with_pro_keys(linear_table,NAME_O,
4616 lint_qclist,CPL_IO_DEFAULT);
4617
4618 } else {
4619 if(whichext == 1) {
4620 /* Save the 1. extension table */
4621 skip_if(cpl_dfs_save_table(frameset,NULL, parlist, usedframes, NULL,
4622 linear_table,lint_qclist, recipe_name,
4623 mypro_lintbl,NULL, package, NAME_O));
4624 detmon_lg_save_table_with_pro_keys(linear_table,NAME_O,
4625 lint_qclist,CPL_IO_DEFAULT);
4626
4627
4628
4629
4630 } else {
4631
4632 detmon_lg_save_table_with_pro_keys(linear_table,NAME_O,
4633 lint_qclist,CPL_IO_EXTEND);
4634 }
4635 }
4636 irplib_free(&NAME_O);
4637 /**************************/
4638 /* Write the GAIN TABLE */
4639 /**************************/
4640 cpl_msg_info(cpl_func,"Write the GAIN TABLE");
4641 /* Set the file name for the table */
4642 if(!flag_sets) {
4643 NAME_O=cpl_sprintf("%s_gain_table.fits", recipe_name);
4644 } else {
4645 NAME_O=cpl_sprintf("%s_gain_table_set%02d.fits", recipe_name,
4646 which_set);
4647 }
4648
4649 if (detmon_lg_config.exts >= 0)
4650 {
4651 /* Save the table */
4652
4653 cpl_propertylist_append(mypro_gaintbl, gaint_qclist);
4654 skip_if(cpl_dfs_save_table(frameset, NULL, parlist, usedframes, NULL,
4655 gain_table,NULL, recipe_name, mypro_gaintbl,
4656 NULL, package, NAME_O));
4657 detmon_lg_save_table_with_pro_keys(gain_table,NAME_O,
4658 gaint_qclist,CPL_IO_DEFAULT);
4659
4660 }
4661 else
4662 {
4663 if(whichext == 1)
4664 {
4665 /* Save the 1. extension table */
4666 skip_if(cpl_dfs_save_table(frameset, NULL, parlist, usedframes, NULL, gain_table,
4667 gaint_qclist, recipe_name, mypro_gaintbl,
4668 NULL, package, NAME_O));
4669 detmon_lg_save_table_with_pro_keys(gain_table,NAME_O,
4670 gaint_qclist,CPL_IO_DEFAULT);
4671
4672 }
4673 else
4674 {
4675
4676 detmon_lg_save_table_with_pro_keys(gain_table,NAME_O,
4677 gaint_qclist,CPL_IO_EXTEND);
4678 }
4679 }
4680
4681 if(detmon_lg_config.pix2pix)
4682 {
4683
4684 /***************************/
4685 /* Write the COEFFS FITS */
4686 /***************************/
4687 cpl_msg_info(cpl_func,"Write the COEFFS FITS");
4688 irplib_free(&NAME_O);
4689 if(!flag_sets)
4690 {
4691 PREF_O=cpl_sprintf("%s_coeffs_cube", recipe_name);
4692 } else
4693 {
4694 PREF_O=cpl_sprintf("%s_coeffs_cube_set%02d",
4695 recipe_name, which_set);
4696 }
4697 if (detmon_lg_config.split_coeffs == 0) {
4698 NAME_O=cpl_sprintf("%s.fits", PREF_O);
4699 }
4700
4701
4702 /* Save the imagelist */
4703 if(detmon_lg_config.split_coeffs != 0){
4704
4705
4706 nb_images = cpl_imagelist_get_size(coeffs);
4707 for(ip=0;ip<nb_images;ip++) {
4708 NAME_O=cpl_sprintf("%s_P%d.fits", PREF_O,ip);
4709 pcatg_plane=cpl_sprintf("COEFFS_CUBE_P%d",ip);
4710 cpl_propertylist_delete(mypro_coeffscube);
4711 mypro_coeffscube=cpl_propertylist_duplicate(pro_coeffscube);
4712 cpl_propertylist_set_string(mypro_coeffscube,CPL_DFS_PRO_CATG,
4713 pcatg_plane);
4714 linc_plane_qclist=detmon_lg_extract_qclist_4plane(linc_qclist,ip);
4715 cpl_propertylist_append(mypro_coeffscube, linc_plane_qclist);
4716 plane=cpl_imagelist_get(coeffs,ip);
4717 detmon_lg_save_plane(parlist,frameset,usedframes,whichext,
4718 recipe_name,mypro_coeffscube,
4719 linc_plane_qclist,package,NAME_O,plane);
4720
4721 if(NULL!=linc_plane_qclist) {
4722 cpl_propertylist_delete(linc_plane_qclist);
4723 }
4724 irplib_free(&NAME_O);
4725
4726 } /* end for loop over cube planes */
4727 } else {
4728
4729 detmon_lg_save_cube(parlist,frameset,usedframes,whichext,
4730 recipe_name,mypro_coeffscube,
4731 linc_qclist,package,NAME_O,coeffs);
4732 }
4733
4734 /*******************************/
4735 /* Write the BAD PIXEL MAP */
4736 /*******************************/
4737 cpl_msg_info(cpl_func,"Write the BAD PIXEL MAP");
4738 irplib_free(&NAME_O);
4739 /* Set the file name for the bpm */
4740 if(!flag_sets)
4741 {
4742 NAME_O=cpl_sprintf("%s_bpm.fits", recipe_name);
4743 } else
4744 {
4745 NAME_O=cpl_sprintf("%s_bpm_set%02d.fits", recipe_name, which_set);
4746 }
4747
4748
4749 /* Save the image */
4750 if(detmon_lg_config.exts == 0) {
4751 cpl_propertylist_append(mypro_bpm, bpm_qclist);
4752 cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL, bpms,
4753 CPL_BPP_IEEE_FLOAT, recipe_name,
4754 mypro_bpm, NULL, package,
4755 NAME_O);
4756 }
4757 else if(detmon_lg_config.exts > 0)
4758 {
4759 skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,NULL, NULL,
4760 CPL_BPP_IEEE_FLOAT, recipe_name,
4761 mypro_bpm, NULL, package,
4762 NAME_O));
4763 detmon_lg_save_image_with_pro_keys(bpms,NAME_O,bpm_qclist);
4764
4765 } else
4766 {
4767 if (whichext == 1)
4768 {
4769 skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,NULL, NULL,
4770 CPL_BPP_IEEE_FLOAT, recipe_name,
4771 mypro_bpm, NULL, package,
4772 NAME_O));
4773 detmon_lg_save_image_with_pro_keys(bpms,NAME_O,bpm_qclist);
4774 } else
4775 {
4776 detmon_lg_save_image_with_pro_keys(bpms,NAME_O,bpm_qclist);
4777 }
4778 }
4779 } /* End of if(pix2pix) */
4780
4781 if(detmon_lg_config.intermediate)
4782 {
4783 /******************************/
4784 /* Write the AUTOCORRS FITS */
4785 /******************************/
4786 cpl_msg_info(cpl_func,"Write the AUTOCORRS FITS");
4787 nb_images = cpl_imagelist_get_size(autocorr_images);
4788 cpl_ensure_code(nb_images > 0, CPL_ERROR_DATA_NOT_FOUND);
4789 for(i = 0; i < nb_images; i++)
4790 {
4791 cpl_propertylist* pplist = cpl_propertylist_duplicate(mypro_corr);
4792 int inull = 0;
4793 cpl_array* pnames = cpl_table_get_column_names(linear_table);
4794 double ddit = 0;
4795 if(i < cpl_table_get_nrow(linear_table))
4796 {
4797 ddit = cpl_table_get_double(linear_table,
4798 cpl_array_get_data_string_const(pnames)[0], i, &inull);
4799 }
4800 cpl_array_delete(pnames);
4801 /*cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);*/
4802 /* Set the file name for each image */
4803 irplib_free(&NAME_O);
4804 if(!flag_sets)
4805 {
4806 NAME_O=cpl_sprintf("%s_autocorr_%d.fits", recipe_name, i);
4807 assert(NAME_O != NULL);
4808 } else
4809 {
4810 NAME_O=cpl_sprintf("%s_autocorr_%02d_set%02d.fits",
4811 recipe_name, i, which_set);
4812 assert(NAME_O != NULL);
4813 }
4814 /* Save the image */
4815 if(detmon_lg_config.exts > 0)
4816 {
4817 cpl_propertylist* pextlist = cpl_propertylist_new();
4818 cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4819 skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4820 NULL,NULL,CPL_BPP_IEEE_FLOAT,
4821 recipe_name, pplist, NULL,
4822 package, NAME_O));
4823
4824 detmon_lg_save_image_with_pro_keys(
4825 cpl_imagelist_get(autocorr_images, i),NAME_O,pextlist);
4826
4827 cpl_propertylist_delete(pextlist);
4828 } else
4829 if(detmon_lg_config.exts == 0)
4830 {
4831 cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);
4832 cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL,
4833 cpl_imagelist_get(autocorr_images, i),
4834 CPL_BPP_IEEE_FLOAT,
4835 recipe_name, pplist, NULL, package,
4836 NAME_O);
4837
4838 }
4839 else
4840 {
4841 cpl_propertylist* pextlist = cpl_propertylist_new();
4842 cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4843 if(whichext == 1)
4844 {
4845 skip_if(cpl_dfs_save_image(frameset, NULL, parlist,
4846 usedframes, NULL,NULL,
4847 CPL_BPP_IEEE_FLOAT, recipe_name,
4848 pplist, NULL,
4849 package, NAME_O));
4850
4851 detmon_lg_save_image_with_pro_keys(
4852 cpl_imagelist_get(autocorr_images, i),NAME_O,pextlist);
4853
4854 } else
4855 {
4856
4857 detmon_lg_save_image_with_pro_keys(
4858 cpl_imagelist_get(autocorr_images, i),NAME_O,pextlist);
4859 }
4860 cpl_propertylist_delete(pextlist);
4861 }
4862 cpl_propertylist_delete (pplist);
4863 }
4864 irplib_free(&NAME_O);
4865
4866
4867 /*
4868 cpl_msg_info(cpl_func, "-----before Write the DIFFS FITS %d", __LINE__);
4869 */
4870 /***************************/
4871 /* Write the DIFFS FITS */
4872 /***************************/
4873 cpl_msg_info(cpl_func,"Write the DIFFS FITS");
4874
4875 for(i = 0; i < nb_images; i++)
4876 {
4877 cpl_propertylist* pplist = cpl_propertylist_duplicate(mypro_diff);
4878 int inull = 0;
4879 cpl_array* pnames = cpl_table_get_column_names(linear_table);
4880 double ddit = 0;
4881 if(i < cpl_table_get_nrow(linear_table))
4882 {
4883 ddit = cpl_table_get_double(linear_table,
4884 cpl_array_get_data_string_const(pnames)[0], i, &inull);
4885 }
4886 cpl_array_delete(pnames);
4887 /*cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);*/
4888 /* Set the file name for each image */
4889 if(!flag_sets)
4890 {
4891 NAME_O=cpl_sprintf("%s_diff_flat_%d.fits", recipe_name, i);
4892 } else
4893 {
4894 NAME_O=cpl_sprintf("%s_diff_flat_%d_set%02d.fits",
4895 recipe_name, i, which_set);
4896 }
4897 /* Save the image */
4898 if(detmon_lg_config.exts > 0)
4899 {
4900 cpl_propertylist* pextlist = cpl_propertylist_new();
4901 cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4902 cpl_propertylist_append_double(mypro_diff, "ESO DET DIT", ddit);
4903 skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
4904 NULL,NULL,CPL_BPP_IEEE_FLOAT,
4905 recipe_name,
4906 mypro_diff, NULL,package, NAME_O));
4907
4908 detmon_lg_save_image_with_pro_keys(
4909 cpl_imagelist_get(diff_flats, i),NAME_O,pextlist);
4910
4911 cpl_propertylist_delete(pextlist);
4912 }
4913 else if(detmon_lg_config.exts == 0)
4914 {
4915 cpl_propertylist_append_double(pplist, "ESO DET DIT", ddit);
4916 cpl_dfs_save_image
4917 (frameset, NULL, parlist, usedframes, NULL,
4918 cpl_imagelist_get(diff_flats, i), CPL_BPP_IEEE_FLOAT,
4919 recipe_name, pplist, NULL, package,
4920 NAME_O);
4921
4922 } else
4923 {
4924 cpl_propertylist* pextlist = cpl_propertylist_new();
4925 cpl_propertylist_append_double(pextlist, "ESO DET DIT", ddit);
4926 if(whichext == 1)
4927 {
4928 cpl_propertylist_append_double(mypro_diff,"ESO DET DIT",ddit);
4929 // cpl_propertylist_erase(mypro_diff, "ESO DET DIT");
4930 skip_if(cpl_dfs_save_image(frameset, NULL, parlist,
4931 usedframes, NULL,NULL,
4932 CPL_BPP_IEEE_FLOAT, recipe_name,
4933 mypro_diff, NULL,package, NAME_O));
4934
4935 detmon_lg_save_image_with_pro_keys(
4936 cpl_imagelist_get(diff_flats, i),NAME_O,pextlist);
4937
4938 } else
4939 {
4940
4941 detmon_lg_save_image_with_pro_keys(
4942 cpl_imagelist_get(diff_flats, i),NAME_O,pextlist);
4943
4944 }
4945 cpl_propertylist_delete(pextlist);
4946 }
4947 cpl_propertylist_delete(pplist);
4948 irplib_free(&NAME_O);
4949 }
4950 } /* End of if(intermediate) */
4951
4952
4953 /*******************************/
4954 /* Write the PAF file(s) */
4955 /*******************************/
4956 cpl_msg_info(cpl_func,"Write the PAF file(s)");
4957
4958 if(detmon_lg_config.pafgen) {
4959
4960 detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,whichext,
4961 pafregexp,procatg_gaintbl,
4962 pipeline_name,recipe_name,
4963 "qc01",gaint_qclist,0);
4964
4965 detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,whichext,
4966 pafregexp,procatg_lintbl,
4967 pipeline_name,recipe_name,
4968 "qc02",lint_qclist,0);
4969
4970 if(detmon_lg_config.pix2pix)
4971 {
4972
4973 detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,
4974 whichext,pafregexp,
4975 procatg_coeffscube,
4976 pipeline_name,recipe_name,
4977 "qc03",linc_qclist,1);
4978
4979 detmon_lg_save_paf_product(ref_frame,flag_sets,which_set,
4980 whichext,pafregexp,procatg_bpm,
4981 pipeline_name,recipe_name,
4982 "qc04",bpm_qclist,1);
4983 }
4984 }
4985
4986 end_skip;
4987 cpl_msg_info(cpl_func,"exit");
4988
4989 cpl_propertylist_delete(xplist);
4990 if(plist!=NULL) {
4991 cpl_propertylist_delete(plist);
4992 plist=NULL;
4993 }
4994
4995 irplib_free(&NAME_O);
4996 cpl_free(PREF_O);
4997 cpl_free(pcatg_plane);
4998 cpl_propertylist_delete(mainplist);
4999 cpl_propertylist_delete(mypro_lintbl);
5000 cpl_propertylist_delete(mypro_gaintbl);
5001 cpl_propertylist_delete(mypro_coeffscube);
5002 cpl_propertylist_delete(mypro_bpm);
5003 cpl_propertylist_delete(mypro_corr);
5004 cpl_propertylist_delete(mypro_diff);
5005
5006 return cpl_error_get_code();
5007}
5008
5009
5010/*---------------------------------------------------------------------------*/
5018/*---------------------------------------------------------------------------*/
5019static cpl_error_code
5020detmon_opt_contamination(const cpl_imagelist * ons,
5021 const cpl_imagelist * offs,
5022 unsigned mode,
5023 cpl_propertylist * qclist)
5024{
5025 struct rect {
5026 size_t llx;
5027 size_t lly;
5028 size_t urx;
5029 size_t ury;
5030 };
5031 struct rect rects[5] = {
5032 (struct rect){ detmon_lg_config.llx1,
5033 detmon_lg_config.lly1,
5034 detmon_lg_config.urx1,
5035 detmon_lg_config.ury1},
5036 (struct rect){ detmon_lg_config.llx2,
5037 detmon_lg_config.lly2,
5038 detmon_lg_config.urx2,
5039 detmon_lg_config.ury2},
5040 (struct rect){ detmon_lg_config.llx3,
5041 detmon_lg_config.lly3,
5042 detmon_lg_config.urx3,
5043 detmon_lg_config.ury3},
5044 (struct rect){ detmon_lg_config.llx4,
5045 detmon_lg_config.lly4,
5046 detmon_lg_config.urx4,
5047 detmon_lg_config.ury4},
5048 (struct rect){ detmon_lg_config.llx5,
5049 detmon_lg_config.lly5,
5050 detmon_lg_config.urx5,
5051 detmon_lg_config.ury5},
5052 };
5053
5054 for (size_t i = 0; i < 5; i++) {
5055 cpl_image * dif_avg;
5056 const cpl_image * off2;
5057 double median;
5058 char kname[300];
5059 if (cpl_imagelist_get_size(offs) == 1 || mode & IRPLIB_LIN_COLLAPSE)
5060 off2 = cpl_imagelist_get_const(offs, 0);
5061 else
5062 off2 = cpl_imagelist_get_const(offs, 1);
5063
5064 dif_avg = detmon_subtracted_avg(cpl_imagelist_get_const(ons, 0),
5065 cpl_imagelist_get_const(offs, 0),
5066 cpl_imagelist_get_const(ons, 1),
5067 off2,
5068 rects[i].llx,
5069 rects[i].lly,
5070 rects[i].urx,
5071 rects[i].ury);
5072
5073 median = cpl_image_get_median(dif_avg);
5074 cpl_image_delete(dif_avg);
5075
5076 skip_if(0);
5077 sprintf(kname, DETMON_QC_CONTAM "%zd", i + 1);
5078
5079 if(cpl_propertylist_has(qclist,kname)){
5080 skip_if(cpl_propertylist_update_double(qclist,kname,median));
5081 } else {
5082 skip_if(cpl_propertylist_append_double(qclist,kname,median));
5083 skip_if(cpl_propertylist_set_comment(qclist,kname,DETMON_QC_CONTAM_C));
5084 }
5085 }
5086
5087 end_skip;
5088
5089 return cpl_error_get_code();
5090}
5091
5092/*---------------------------------------------------------------------------*/
5099/*---------------------------------------------------------------------------*/
5100/*
5101static cpl_error_code
5102detmon_opt_lampcr(cpl_frameset * cur_fset, int ext)
5103{
5104 cpl_image * on = NULL;
5105 cpl_image * off = NULL;
5106 cpl_frame * first_off = NULL;
5107 cpl_frame * first_on = NULL;
5108 cpl_propertylist * plist = NULL;
5109 double dit;
5110
5111 cpl_ensure_code(cur_fset != NULL, CPL_ERROR_NULL_INPUT);
5112
5113 skip_if((first_off = cpl_frameset_get_position(cur_fset, 0)) == NULL);
5114 skip_if((first_on = cpl_frameset_get_position(cur_fset, 1)) == NULL);
5115
5116 on = cpl_image_load(cpl_frame_get_filename(first_on),
5117 CPL_TYPE_FLOAT, 0, ext);
5118 off = cpl_image_load(cpl_frame_get_filename(first_off),
5119 CPL_TYPE_FLOAT, 0, ext);
5120 skip_if(cpl_image_subtract(on, off));
5121
5122 plist = cpl_propertylist_load(cpl_frame_get_filename(first_on), 0);
5123 skip_if(plist == NULL);
5124
5125 dit = detmon_pfits_get_dit_opt(plist);
5126
5127 detmon_lg_config.cr = cpl_image_get_mean(on) / dit;
5128
5129 end_skip;
5130
5131 cpl_image_delete(on);
5132 cpl_image_delete(off);
5133 cpl_propertylist_delete(plist);
5134
5135 return cpl_error_get_code();
5136}
5137*/
5138/*---------------------------------------------------------------------------*/
5146/*---------------------------------------------------------------------------*/
5147int
5148detmon_lg_dfs_set_groups(cpl_frameset * set,
5149 const char *tag_on, const char *tag_off)
5150{
5151
5152
5153
5154
5155
5156 /* Check entries */
5157 if(set == NULL)
5158 return -1;
5159
5160 /* Initialize */
5161 int nframes = cpl_frameset_get_size(set);
5162
5163 /* Loop on frames */
5164 for(int i = 0; i < nframes; i++) {
5165 cpl_frame* cur_frame = cpl_frameset_get_position(set, i);
5166 const char* tag = cpl_frame_get_tag(cur_frame);
5167
5168 /* RAW frames */
5169 if(!strcmp(tag, tag_on) || !strcmp(tag, tag_off))
5170 cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_RAW);
5171 /* CALIB frames */
5172
5173 /* else if (!strcmp(tag, IIINSTRUMENT_CALIB_FLAT))
5174 cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_CALIB);
5175 */
5176 }
5177 return 0;
5178}
5179
5180
5181/*---------------------------------------------------------------------------*/
5189/*---------------------------------------------------------------------------*/
5190static cpl_error_code
5191detmon_lg_fits_coeffs_and_bpm2chip(cpl_imagelist ** coeffs_ptr,
5192 cpl_image **bpms_ptr)
5193{
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203 int shift_idx=0;
5204
5205
5206
5207
5208 cpl_image* dummy_bpm = cpl_image_new(detmon_lg_config.nx,
5209 detmon_lg_config.ny,
5210 CPL_TYPE_INT);
5211 cpl_imagelist* dummy_coeffs = cpl_imagelist_new();
5212
5213 int* db_p = cpl_image_get_data_int(dummy_bpm);
5214 int* rb_p = cpl_image_get_data_int(*bpms_ptr);;
5215 float** dcs_p = cpl_malloc(sizeof(float *) * (detmon_lg_config.order + 1));
5216 float** rcs_p = cpl_malloc(sizeof(float *) * (detmon_lg_config.order + 1));
5217 int dlength = detmon_lg_config.nx;
5218
5219 int rlength = detmon_lg_config.urx - detmon_lg_config.llx + 1;
5220 for (int i = 0; i <= detmon_lg_config.order; i++)
5221 {
5222 cpl_image* dummy_coeff = cpl_image_new(detmon_lg_config.nx,
5223 detmon_lg_config.ny,
5224 CPL_TYPE_FLOAT);
5225
5226 cpl_imagelist_set(dummy_coeffs, dummy_coeff, i);
5227 dcs_p[i] = cpl_image_get_data_float(dummy_coeff);
5228 rcs_p[i] = cpl_image_get_data_float(cpl_imagelist_get(*coeffs_ptr, i));
5229 }
5230 /*copy the coefficients from temporary image to the dummy_bpm*/
5231 for (int i = detmon_lg_config.lly - 1; i < detmon_lg_config.ury; i++)
5232 {
5233 for (int j = detmon_lg_config.llx - 1; j < detmon_lg_config.urx; j++)
5234 {
5235 shift_idx=(i - detmon_lg_config.lly + 1) * rlength +
5236 j - detmon_lg_config.llx + 1;
5237 *(db_p + i * dlength + j) = *(rb_p + shift_idx);
5238 for (int k = 0; k <= detmon_lg_config.order; k++)
5239 {
5240 *(dcs_p[k] + i * dlength + j) =
5241 *(rcs_p[k] + (i - detmon_lg_config.lly + 1) * rlength +
5242 j - detmon_lg_config.llx + 1);
5243 }
5244 }
5245 }
5246 cpl_imagelist_delete(*coeffs_ptr);
5247 cpl_image_delete(*bpms_ptr);
5248 *coeffs_ptr = dummy_coeffs;
5249 *bpms_ptr = dummy_bpm;
5250 cpl_free(dcs_p);
5251 cpl_free(rcs_p);
5252
5253 return cpl_error_get_code();
5254}
5255
5256/* Not used so we temporaryly comment it out
5257static cpl_error_code
5258detmon_lg_qclog_lin_coeff(cpl_imagelist* coeffs_ptr, const int order, cpl_propertylist* linc_qclist)
5259{
5260 cpl_image* image=NULL;
5261 int i=0;
5262 double coeff=0;
5263 double * pcoeffs = cpl_malloc(sizeof(double)*(order + 1));
5264 char* name_o1=NULL;
5265 char* name_o2=NULL;
5266
5267 for(i = 0; i <= order; i++)
5268 {
5269 image = cpl_imagelist_get(coeffs_ptr, i);
5270 coeff = cpl_image_get_median(image);
5271 pcoeffs[i] = coeff;
5272 name_o1 = cpl_sprintf("ESO QC LIN COEF%d", i);
5273 name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", i);
5274 assert(name_o1 != NULL);
5275 assert(name_o2 != NULL);
5276 cpl_propertylist_append_double(linc_qclist, name_o1, coeff);
5277 cpl_propertylist_set_comment(linc_qclist,name_o1,DETMON_QC_LIN_COEF_C);
5278 cpl_free(name_o1);
5279 name_o1= NULL;
5280 cpl_propertylist_append_double(linc_qclist, name_o2,cpl_image_get_stdev(image));
5281 cpl_propertylist_set_comment(linc_qclist,name_o2,DETMON_QC_LIN_COEF_ERR_C);
5282 cpl_free(name_o2);
5283 name_o2= NULL;
5284 }
5285 cpl_free(pcoeffs);
5286
5287 return cpl_error_get_code();
5288}
5289*/
5290#ifdef DETMON_USE_DETECTOR_SHOTNOISE_MODEL
5291/*----------------------------------------------------------------------------*/
5312/*----------------------------------------------------------------------------*/
5313static cpl_error_code
5314detmon_detector_shotnoise_model(const cpl_image* ima_data, const double gain,
5315 const double ron, cpl_image ** ima_errs)
5316{
5317 cpl_ensure_code(ima_data, CPL_ERROR_NULL_INPUT);
5318 cpl_ensure_code(ima_errs, CPL_ERROR_NULL_INPUT);
5319 cpl_ensure_code(gain > 0., CPL_ERROR_ILLEGAL_INPUT);
5320 cpl_ensure_code(ron > 0., CPL_ERROR_ILLEGAL_INPUT);
5321
5322 *ima_errs = cpl_image_duplicate(ima_data);
5323 /* set negative values (= zero measurable electrons) to read out noise */
5324 cpl_image_threshold(*ima_errs, 0., INFINITY, ron, ron);
5325
5326 /* err_ADU = sqrt(counts/gain + ron * ron)*/
5327
5328 cpl_image_divide_scalar(*ima_errs, gain);
5329 cpl_image_add_scalar(*ima_errs, ron * ron);
5330 cpl_image_power(*ima_errs, 0.5);
5331
5332 return cpl_error_get_code();
5333}
5334#endif
5335
5336static int
5337detmon_compute_badpixmap(cpl_boolean opt_nir, const int nsets,
5338 const cpl_table* linear_table,
5339 const cpl_imagelist* linearity_inputs, int nbpixs,
5340 cpl_vector* x, cpl_propertylist* gaint_qclist,
5341 cpl_image** bpms_ptr)
5342{
5343 /* Here determines the bad pixel map
5344 * HDRL based version
5345 * AMO: this if is repeated: the following code should be up up
5346 */
5347 if (opt_nir == NIR) {
5348 x = cpl_vector_wrap(nsets,
5349 (double *) cpl_table_get_data_double_const(linear_table,
5350 "DIT"));
5351 }
5352 else {
5353 x = cpl_vector_wrap(nsets,
5354 (double *) cpl_table_get_data_double_const(linear_table,
5355 "EXPTIME"));
5356
5357 }
5358 int sz = cpl_imagelist_get_size(linearity_inputs);
5359 double kappa = detmon_lg_config.kappa;
5360 int niter = detmon_lg_config.niter;
5361 int llx = detmon_lg_config.llx;
5362 int urx = detmon_lg_config.urx;
5363 int lly = detmon_lg_config.lly;
5364 int ury = detmon_lg_config.ury;
5365 hdrl_parameter* p;
5366 const cpl_image *ima;
5367 cpl_image *err;
5368 // fit-chi-rel method
5369 // errors to be used with fit_chi_rel method
5370 cpl_imagelist* errors = cpl_imagelist_new();
5371 /*
5372 // case1: error proportional to sqrt(EXPTIME)
5373 for(int i=0;i<sz;i++) {
5374 err=cpl_image_new(sx,sy,CPL_TYPE_DOUBLE);
5375 cpl_image_add_scalar(err,1.);
5376 cpl_imagelist_set(errors,err,i);
5377 }
5378 */
5379 /*
5380 // case2:shot noise model to be used with fit_chi_rel method
5381 double gain=1.;
5382 double ron=1.;
5383 for(int i=0;i<sz;i++) {
5384 ima=cpl_imagelist_get(linearity_inputs,i);
5385 hdrldemo_detector_shotnoise_model(ima, gain, ron, &err);
5386 cpl_imagelist_set(errors,err,i);
5387 }
5388 */
5389 // case3: error obtained using mad error approximation
5390 double dmad;
5391 //cpl_msg_info(cpl_func,"sz=%d",sz);
5392 cpl_imagelist* linearity_scaled = cpl_imagelist_new();
5393 double gain = 0;
5394 gain = cpl_propertylist_get_double(gaint_qclist, DETMON_QC_GAIN);
5395 //cpl_msg_info(cpl_func,"ok1 gain=%g",gain);
5396 /* on simulations gain ,may be < 0: make sure it is > 0 */
5397 //cpl_msg_info(cpl_func,"ok1 gain=%g",gain);
5398 gain = (gain < 0) ? 1 : gain;
5399 double avg = 0;
5400 double rms = 0;
5401 skip_if(rms);
5402 //cpl_msg_info(cpl_func,"sz=%d",sz);
5403 //cpl_msg_info(cpl_func,"llx=%d lly=%d urx=%d ury=%d",llx,lly,urx,ury);
5404 for (int i = 0; i < sz; i++) {
5405 ima = cpl_imagelist_get_const(linearity_inputs, i);
5406 /*
5407 cpl_msg_info(cpl_func,"sx=%d sy=%d",
5408 cpl_image_get_size_x(ima),cpl_image_get_size_y(ima));
5409 */
5410 //cpl_msg_info(cpl_func,"max_x=%d max_y=%d",urx-llx+1,ury-lly+1);
5411 //median=cpl_image_get_median_window(ima,1,1,urx-llx+1,ury-lly+1);
5412 skip_if(
5413 irplib_ksigma_clip(ima, 1, 1, urx - llx + 1,
5414 ury - lly + 1, kappa, niter, 1e-5, &avg,
5415 &rms));
5416
5417 //cpl_msg_info(cpl_func,"avg=%g median=%g",avg,median);
5418 //cpl_msg_info(cpl_func,"thresh=%g", detmon_lg_config.saturation_limit);
5419 if (avg < detmon_lg_config.saturation_limit) {
5420
5421 //cpl_msg_info(cpl_func,">>>>i=%d", i);
5422 /*
5423 err=cpl_image_duplicate(ima);
5424 cpl_image_multiply_scalar(err, gain);
5425 cpl_image_power(err,0.5);
5426 */
5427 cpl_image_get_mad(ima, &dmad);
5428 err = cpl_image_duplicate(ima);
5429 cpl_image_multiply_scalar(err, 0);
5430 cpl_image_add_scalar(err, dmad * CPL_MATH_STD_MAD);
5431
5432 //detmon_detector_shotnoise_model(ima, gain_eff,ron, &err);
5433 /*
5434 cpl_msg_info(cpl_func,"err sx=%d",cpl_image_get_size_x(err));
5435 cpl_msg_info(cpl_func,"err sy=%d",cpl_image_get_size_y(err));
5436 cpl_msg_info(cpl_func,"ima sx=%d",cpl_image_get_size_x(ima));
5437 cpl_msg_info(cpl_func,"ima sy=%d",cpl_image_get_size_y(ima));
5438 cpl_msg_info(cpl_func,"sy=%d",cpl_image_get_size_y(err));
5439 */
5440 cpl_imagelist_set(errors, err, i);
5441 /*
5442 sprintf(dname,"data_%d.fits",i);
5443 sprintf(ename,"errs_%d.fits",i);
5444 cpl_image_save(err, ename, CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
5445 cpl_image_save(ima, dname, CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
5446 */
5447 skip_if(
5448 cpl_imagelist_set(linearity_scaled,
5449 cpl_image_duplicate(ima), i));
5450 }
5451 }
5452 hdrl_imagelist* hil = hdrl_imagelist_create(linearity_scaled, errors);
5453 /*
5454 cpl_imagelist_save(linearity_scaled,"lin_data.fits", CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
5455 cpl_imagelist_save(errors,"lin_errs.fits", CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
5456 */
5457 cpl_imagelist_delete(errors);
5458 /* P-val method */
5459 double pval = 0.001;
5460 p = hdrl_bpm_fit_parameter_create_pval(1, pval);
5461 /*
5462 p = hdrl_bpm_fit_parameter_create_rel_coef(1, 1., 1.);
5463 hdrl_parameter_delete(p);
5464 */
5465 /* chi-rel method
5466 int ord=detmon_lg_config.order;
5467 p = hdrl_bpm_fit_parameter_create_rel_chi(1, kappa, kappa);
5468 */
5469 hdrl_bpm_fit_compute(p, hil, x, bpms_ptr);
5470 //cpl_vector_dump(x,stdout);
5471 /*
5472 // bpm-3D method
5473 cpl_imagelist* linearity_scaled=cpl_imagelist_new();
5474
5475 for(int i=0;i<sz;i++) {
5476 ima=cpl_imagelist_get(linearity_inputs,i);
5477 median=cpl_image_get_median(ima);
5478 if(median < detmon_lg_config.saturation_limit) {
5479 cpl_image_divide_scalar(ima,median);
5480 cpl_imagelist_set(linearity_scaled,cpl_image_duplicate(ima),i);
5481 }
5482 }
5483 hdrl_imagelist* hil= hdrl_imagelist_create(linearity_scaled,NULL);
5484
5485
5486 // bpm-3D method
5487 hdrl_bpm_3d_method method = HDRL_BPM_3D_THRESHOLD_RELATIVE ;
5488 p=hdrl_bpm_3d_parameter_create(kappa, kappa, method) ;
5489 cpl_imagelist * out_imlist = hdrl_bpm_3d_compute(hil, p);
5490 *bpms_ptr = cpl_imagelist_collapse_create(out_imlist);
5491 cpl_msg_info(cpl_func,"BP map value: min=%g max=%g",
5492 cpl_image_get_min(*bpms_ptr),cpl_image_get_max(*bpms_ptr));
5493 */
5494 nbpixs = cpl_image_get_flux(*bpms_ptr);
5495 /* clean-up memory */
5496 hdrl_imagelist_delete(hil);
5497 cpl_imagelist_delete(linearity_scaled);
5498 cpl_vector_unwrap((cpl_vector*) x);
5499 hdrl_parameter_delete(p);
5500 // 3D method only
5501 //cpl_imagelist_delete(out_imlist);
5502 /* ORIGINAL BP MAP COMPUTATION
5503 *bpms_ptr = detmon_bpixs(*coeffs_ptr, detmon_lg_config.bpmbin,
5504 detmon_lg_config.kappa, &nbpixs);
5505 */
5506 /*
5507 *bpms_ptr = detmon_bpixs2(x,linearity_inputs,*coeffs_ptr,gain_table,
5508 detmon_lg_config.order,detmon_lg_config.bpmbin,detmon_lg_config.kappa,&nbpixs);
5509 */
5510 /*
5511 cpl_vector_unwrap((cpl_vector*)x);
5512 cpl_vector_unwrap((cpl_vector*)y);
5513 */
5514 //cpl_msg_info(cpl_func,"nbpixs=%d",nbpixs);
5515 skip_if(*bpms_ptr == NULL);
5516
5517 end_skip;
5518 return nbpixs;
5519}
5520
5521/*---------------------------------------------------------------------------*/
5535/*---------------------------------------------------------------------------*/
5536static cpl_error_code
5537detmon_lg_reduce_all(const cpl_table * linear_table,
5538 cpl_propertylist * gaint_qclist,
5539 cpl_propertylist * lint_qclist,
5540 cpl_propertylist * linc_qclist,
5541 cpl_propertylist * bpm_qclist,
5542 cpl_imagelist ** coeffs_ptr,
5543 cpl_image ** bpms_ptr,
5544 const cpl_imagelist * linearity_inputs,
5545 const cpl_table * gain_table,
5546 int which_ext, cpl_boolean opt_nir)
5547{
5548
5549 int nbpixs = 0;
5550 const int linear_nsets = cpl_table_get_nrow(linear_table);
5551 const int gain_nsets = cpl_table_get_nrow(gain_table);
5552 double autocorr;
5553 cpl_polynomial *poly_linfit = NULL;
5554 cpl_image *fiterror = NULL;
5555 char * name_o1 = NULL;
5556 char * name_o2 = NULL;
5557 double * pcoeffs = NULL;
5558 unsigned mode = detmon_lg_config.autocorr ? IRPLIB_GAIN_WITH_AUTOCORR : 0;
5559 double min_val=0;
5560 double max_val=0;
5561 cpl_vector *x =NULL;
5562 const cpl_vector *y =NULL;
5563
5564
5565 const cpl_image * first = NULL;
5566 int sizex = 0;
5567 int sizey = 0;
5568
5569 int vsize = 0;
5570 cpl_size deg=0;
5571 /* FIXME: This should go before the x and y vectors.
5572 Checking for all the inputs */
5573 cpl_ensure_code(gaint_qclist != NULL, CPL_ERROR_NULL_INPUT);
5574 cpl_ensure_code(lint_qclist != NULL, CPL_ERROR_NULL_INPUT);
5575 cpl_ensure_code(linc_qclist != NULL, CPL_ERROR_NULL_INPUT);
5576 cpl_ensure_code(bpm_qclist != NULL, CPL_ERROR_NULL_INPUT);
5577
5578 pcoeffs = cpl_malloc(sizeof(double)*(detmon_lg_config.order + 1));
5579
5580 skip_if(cpl_propertylist_append_string(gaint_qclist, DETMON_QC_METHOD,
5581 detmon_lg_config.method));
5582 skip_if(cpl_propertylist_set_comment(gaint_qclist, DETMON_QC_METHOD,
5583 DETMON_QC_METHOD_C));
5584
5585
5586 if (!strcmp(detmon_lg_config.method, "PTC")) {
5587 /* Computation of GAIN via polynomial fit */
5588 if (detmon_lg_config.exts >= 0) {
5589 cpl_msg_info(cpl_func,
5590 "Polynomial fitting for the GAIN (constant term method)");
5591 } else {
5592 cpl_msg_info(cpl_func,
5593 "Polynomial fitting for the GAIN (constant term method)"
5594 " for extension nb %d", which_ext);
5595 }
5596 skip_if(detmon_lg_qc_ptc(gain_table, gaint_qclist, mode, gain_nsets));
5597 } else {
5598 skip_if(detmon_lg_qc_med(gain_table, gaint_qclist, gain_nsets));
5599 }
5600
5601 /*^FIXME: This shouldn't be written when no applied */
5602 /* Lamp flux */
5603 if(detmon_lg_config.lamp_ok) {
5604 skip_if(cpl_propertylist_append_double(lint_qclist, DETMON_QC_LAMP_FLUX,
5605 detmon_lg_config.cr));
5606 skip_if(cpl_propertylist_set_comment(lint_qclist, DETMON_QC_LAMP_FLUX,
5607 DETMON_QC_LAMP_FLUX_C));
5608 }
5609
5610 /*^FIXME: This shouldn't be written when no applied */
5611 if(detmon_lg_config.autocorr == TRUE) {
5612 autocorr = cpl_table_get_column_median(gain_table, "AUTOCORR");
5613 skip_if(cpl_propertylist_append_double(gaint_qclist, DETMON_QC_AUTOCORR,
5614 autocorr));
5615 skip_if(cpl_propertylist_set_comment(gaint_qclist, DETMON_QC_AUTOCORR,
5616 DETMON_QC_AUTOCORR_C));
5617 }
5618 if (detmon_lg_config.exts >= 0) {
5619 cpl_msg_info(cpl_func, "Polynomial fitting pix-to-pix");
5620 } else {
5621 cpl_msg_info(cpl_func, "Polynomial fitting pix-to-pix"
5622 " for extension nb %d", which_ext);
5623 }
5624
5625 if(!detmon_lg_config.pix2pix) {
5626 const int order=detmon_lg_config.order;
5627
5628
5629
5630
5631
5632 double mse = 0;
5633 /* Computation of LINEARITY via polynomial fit */
5634 y = cpl_vector_wrap(linear_nsets,
5635 (double *)cpl_table_get_data_double_const(linear_table,
5636 "MED"));
5637
5638 if (opt_nir == NIR) {
5639 x = cpl_vector_wrap(linear_nsets,
5640 (double *)cpl_table_get_data_double_const(linear_table,
5641 "DIT"));
5642 } else {
5643 x = cpl_vector_wrap(linear_nsets,
5644 (double *)cpl_table_get_data_double_const(linear_table,
5645 "EXPTIME"));
5646 }
5647
5648 if(x == NULL || y == NULL) {
5649 cpl_vector_unwrap((cpl_vector *)x);
5650 cpl_vector_unwrap((cpl_vector *)y);
5651 /*
5652 * As x and y are const vectors, if they would be defined at the
5653 * beginning of the function (required for skip_if - end_skip
5654 * scheme), they couldn't be initialised to NULL (required too).
5655 * Therefore, they are considered apart from the scheme.
5656 */
5657 skip_if(1);
5658 }
5659
5660 cpl_msg_info(cpl_func, "Polynomial fitting for the LINEARITY");
5661 poly_linfit = irplib_polynomial_fit_1d_create(x, y,order,&mse);
5662
5663 if(order == cpl_vector_get_size(x) - 1) {
5664 cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
5665 mse = 0;
5666 }
5667
5668 if(poly_linfit == NULL) {
5669 cpl_vector_unwrap((cpl_vector *)x);
5670 cpl_vector_unwrap((cpl_vector *)y);
5671 /* See comment in previous error checking if() statement */
5672 skip_if(1);
5673 }
5674
5675
5676 min_val=cpl_vector_get_min(y);
5677 max_val=cpl_vector_get_max(y);
5678
5679 cpl_vector_unwrap((cpl_vector *)x);
5680 cpl_vector_unwrap((cpl_vector *)y);
5681
5682 for(deg = 0; deg <= order; deg++) {
5683 const double coeff =
5684 cpl_polynomial_get_coeff(poly_linfit, &deg);
5685 // FIXME Should not be hardcoded
5686 char *name_o =
5687 cpl_sprintf("ESO QC LIN COEF%" CPL_SIZE_FORMAT "", deg);
5688 assert(name_o != NULL);
5689 skip_if(cpl_propertylist_append_double(lint_qclist, name_o, coeff));
5690 skip_if(cpl_propertylist_set_comment(lint_qclist,name_o,
5691 DETMON_QC_LIN_COEF_C));
5692
5693 cpl_free(name_o);
5694 pcoeffs[deg] = coeff;
5695 }
5696 skip_if(cpl_propertylist_append_double(lint_qclist,DETMON_QC_ERRFIT, mse));
5697 skip_if(cpl_propertylist_set_comment(lint_qclist,DETMON_QC_ERRFIT,
5698 DETMON_QC_ERRFIT_MSE_C));
5699
5700
5701 } else {
5702 const int order=detmon_lg_config.order;
5703 /* pix2pix == TRUE */
5704 y = cpl_vector_wrap(linear_nsets,
5705 (double *)cpl_table_get_data_double_const(linear_table,
5706 "MED"));
5707
5708 if (opt_nir == NIR)
5709 {
5710 x = cpl_vector_wrap(linear_nsets,
5711 (double *)cpl_table_get_data_double_const(linear_table,
5712 "DIT"));
5713 } else {
5714 x = cpl_vector_wrap(linear_nsets,
5715 (double *)cpl_table_get_data_double_const(linear_table,
5716 "EXPTIME"));
5717
5718 }
5719
5720 first = cpl_imagelist_get_const(linearity_inputs, 0);
5721 sizex = cpl_image_get_size_x(first);
5722 sizey = cpl_image_get_size_y(first);
5723 vsize = cpl_vector_get_size(x);
5724 fiterror = cpl_image_new(sizex, sizey, CPL_TYPE_FLOAT);
5725 *coeffs_ptr =
5726 cpl_fit_imagelist_polynomial(x, linearity_inputs, 0,order, FALSE,
5727 CPL_TYPE_FLOAT, fiterror);
5728 min_val=cpl_vector_get_min(y);
5729 max_val=cpl_vector_get_max(y);
5730 cpl_vector_unwrap((cpl_vector*)x);
5731 cpl_vector_unwrap((cpl_vector*)y);
5732
5733 irplib_ensure(*coeffs_ptr != NULL, CPL_ERROR_UNSPECIFIED,
5734 "Failed polynomial fit");
5735 //detmon_lg_qclog_lin_coeff(*coeffs_ptr, order,linc_qclist);
5736
5737 for(deg = 0; deg <= order; deg++)
5738 {
5739 cpl_image *image = cpl_imagelist_get(*coeffs_ptr, deg);
5740 const double coeff = cpl_image_get_median(image);
5741 pcoeffs[deg] = coeff;
5742 // FIXME Should not be hardcoded
5743 name_o1 = cpl_sprintf("ESO QC LIN COEF%d", (int)deg);
5744 name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", (int)deg);
5745 assert(name_o1 != NULL);
5746 assert(name_o2 != NULL);
5747 skip_if(cpl_propertylist_append_double(linc_qclist, name_o1, coeff));
5748 skip_if(cpl_propertylist_set_comment(linc_qclist,name_o1,
5749 DETMON_QC_LIN_COEF_C));
5750 cpl_free(name_o1);
5751 name_o1= NULL;
5752 skip_if(cpl_propertylist_append_double(linc_qclist, name_o2,
5753 cpl_image_get_stdev(image)));
5754 skip_if(cpl_propertylist_set_comment(linc_qclist,name_o2,
5755 DETMON_QC_LIN_COEF_ERR_C));
5756 cpl_free(name_o2);
5757 name_o2= NULL;
5758 }
5759
5760
5761 if(order == vsize - 1)
5762 {
5763 cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
5764 skip_if(cpl_propertylist_append_double(linc_qclist,DETMON_QC_ERRFIT,
5765 0.0));
5766 skip_if(cpl_propertylist_set_comment(linc_qclist,DETMON_QC_ERRFIT,
5767 DETMON_QC_ERRFIT_C));
5768 } else
5769 {
5770 skip_if(cpl_propertylist_append_double(linc_qclist,DETMON_QC_ERRFIT,
5771 cpl_image_get_median(fiterror)));
5772 skip_if(cpl_propertylist_set_comment(linc_qclist,DETMON_QC_ERRFIT,
5773 DETMON_QC_ERRFIT_C));
5774 }
5775 } /* end case pix2pix == TRUE */
5776
5777 skip_if(cpl_propertylist_append_double(lint_qclist,DETMON_QC_COUNTS_MIN,
5778 min_val));
5779 skip_if(cpl_propertylist_set_comment(lint_qclist,DETMON_QC_COUNTS_MIN,
5780 DETMON_QC_COUNTS_MIN_C));
5781 skip_if(cpl_propertylist_append_double(lint_qclist,DETMON_QC_COUNTS_MAX,
5782 max_val));
5783 skip_if(cpl_propertylist_set_comment(lint_qclist,DETMON_QC_COUNTS_MAX,
5784 DETMON_QC_COUNTS_MAX_C));
5785 skip_if(detmon_lg_lineff(pcoeffs,lint_qclist,detmon_lg_config.ref_level,
5786 detmon_lg_config.order));
5787 /* Detection of bad pixels */
5788 if (detmon_lg_config.exts >= 0)
5789 {
5790 cpl_msg_info(cpl_func, "Bad pixel detection");
5791 } else
5792 {
5793 cpl_msg_info(cpl_func, "Bad pixel detection"
5794 " for extension nb %d", which_ext);
5795 }
5796 if(detmon_lg_config.pix2pix)
5797 {
5798
5799 /* Determines bad pixel map */
5800 nbpixs = detmon_compute_badpixmap(opt_nir, linear_nsets, linear_table,
5801 linearity_inputs, nbpixs, x,gaint_qclist, bpms_ptr);
5802 /* we still have to unwrapp x & y that we kept for bpixs2 function */
5803 }
5804
5805
5806 skip_if(cpl_propertylist_append_int(bpm_qclist, DETMON_QC_NUM_BPM, nbpixs));
5807 skip_if(cpl_propertylist_set_comment(bpm_qclist, DETMON_QC_NUM_BPM,
5808 DETMON_QC_NUM_BPM_C));
5809 cpl_msg_info(cpl_func,"stability=%g",detmon_lg_config.lamp_stability);
5810 if(detmon_lg_config.lamp_stability != 0.0)
5811 {
5812 skip_if(cpl_propertylist_append_double(lint_qclist, DETMON_QC_LAMP_STAB,
5813 detmon_lg_config.lamp_stability));
5814 skip_if(cpl_propertylist_set_comment(lint_qclist, DETMON_QC_LAMP_STAB,
5815 DETMON_QC_LAMP_STAB_C));
5816 }
5817 /* Fit COEFFS_CUBE and BPM outputs to whole-chip size images (DFS05711) */
5818 if (!detmon_lg_config.wholechip && detmon_lg_config.pix2pix)
5819 {
5820 detmon_lg_fits_coeffs_and_bpm2chip(coeffs_ptr,bpms_ptr);
5821 }
5822 end_skip;
5823
5824 cpl_free(pcoeffs);
5825 cpl_free(name_o1);
5826 cpl_free(name_o2);
5827 cpl_image_delete(fiterror);
5828 cpl_polynomial_delete(poly_linfit);
5829
5830
5831
5832 return cpl_error_get_code();
5833}
5834
5835/*---------------------------------------------------------------------------*/
5843/*---------------------------------------------------------------------------*/
5844static cpl_error_code
5845detmon_lg_lineff(double * pcoeffs,
5846 cpl_propertylist * qclist,
5847 int ref_level,
5848 int order)
5849{
5850 double lineff = 0;
5851 double root = 0;
5852 double residual, slope;
5853 int i;
5854 cpl_size deg=0;
5855 cpl_polynomial * poly = cpl_polynomial_new(1);
5856
5857
5858 /*
5859 * Construction of the polynomial F_m(F_r) from F_m(t),
5860 * using F_r = a_1 * t.
5861 */
5862 /*
5863 for (deg = 0; deg <= order; deg++) {
5864 cpl_msg_info(cpl_func,"coef[%d]=%g",deg,pcoeffs[deg]);
5865 }
5866 */
5867
5868
5869 pcoeffs[0] -= ref_level;
5870
5871 for (i = 2; i <= order; i++)
5872 {
5873 int j;
5874 for(j = 0; j < i; j++)
5875 {
5876 pcoeffs[i] /= pcoeffs[1];
5877 }
5878 }
5879
5880 pcoeffs[1] = 1;
5881
5882 for (deg = 0; deg <= order; deg++) {
5883 /*cpl_msg_info(cpl_func,"coef[%d]=%g",deg,pcoeffs[deg]);*/
5884 skip_if(cpl_polynomial_set_coeff(poly, &deg, pcoeffs[deg]));
5885 }
5886
5887 /*
5888 * Verification of validity of first guess (0).
5889 * The root to be found will be in the same interval of monotony
5890 * of the first guess; therefore, slope must be greater than 0.
5891 * Slope > 0 and poly(root) = 0 force also residual to be negative.
5892 */
5893 residual = cpl_polynomial_eval_1d(poly, 0.0, &slope);
5894
5895 if (slope <= 0.0 && residual >= 0.0) {
5896 cpl_msg_warning(cpl_func, "Reference level (--ref_level) outside"
5897 " linearity range of the detector. Cannot compute"
5898 " linearity efficiency (QC.LINEFF).");
5899 lineff = -1;
5900 }
5901 else
5902 {
5903 cpl_error_code err = cpl_polynomial_solve_1d(poly, 0.0, &root, 1);
5904 /*
5905 cpl_msg_info(cpl_func,"root=%g ref_level=%d lin_eff=%d",
5906 root,ref_level,ref_level);
5907 */
5908 if (err == CPL_ERROR_NONE)
5909 {
5910
5911 lineff = (root - ref_level) / ref_level;
5912 }
5913 else
5914 {
5915 cpl_error_reset();
5916 cpl_msg_warning(cpl_func,
5917 "Cannot compute linearity efficiency (QC.LINEFF)"
5918 "for the current combination "
5919 " of (--ref-level equal %d) and (--order equal %d) parameters. Try "
5920 "to decrease (--ref-level) value.", ref_level, order);
5921 }
5922 }
5923 cpl_msg_warning(cpl_func, "DETMON_QC_LIN_EFF=%f",lineff );
5924 skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LIN_EFF,
5925 lineff));
5926 skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LIN_EFF,
5927 DETMON_QC_LIN_EFF_C));
5928
5929 skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_LIN_EFF_FLUX,
5930 ref_level));
5931 skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_LIN_EFF_FLUX,
5932 DETMON_QC_LIN_EFF_FLUX_C));
5933
5934 end_skip;
5935
5936 cpl_polynomial_delete(poly);
5937
5938 return cpl_error_get_code();
5939}
5940
5941/*---------------------------------------------------------------------------*/
5948/*---------------------------------------------------------------------------*/
5949static cpl_error_code
5950detmon_lg_qc_ptc(const cpl_table * gain_table,
5951 cpl_propertylist * qclist, unsigned mode, int rows_in_gain)
5952{
5953 double mse = 0;
5954 cpl_polynomial *poly_fit = NULL;
5955 cpl_polynomial *poly_fit2 = NULL;
5956 cpl_size i;
5957 const int nsets = rows_in_gain;
5958
5959 cpl_vector *x = NULL;
5960 cpl_vector *y = NULL;
5961
5962 cpl_errorstate prestate;
5963 double coef = 0;
5964 cpl_ensure_code(gain_table != NULL, CPL_ERROR_NULL_INPUT);
5965 cpl_ensure_code(qclist != NULL, CPL_ERROR_NULL_INPUT);
5966
5967 x = cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT"));
5968
5969 y = cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
5970
5971 skip_if(x == NULL || y == NULL);
5972 if (0 == detmon_lg_check_before_gain(x, y))
5973 {
5974 if (x)
5975 {
5976 cpl_vector_unwrap(x);
5977 }
5978 if (y)
5979 {
5980 cpl_vector_unwrap(y);
5981 }
5982 return CPL_ERROR_NONE;
5983 }
5984 /*it is not really a MSE, but chi square of the fit, see cpl_vector_fill_polynomial_fit_residual for details*/
5985 poly_fit = irplib_polynomial_fit_1d_create_chiq(x, y, 1, &mse);
5986 skip_if(poly_fit == NULL);
5987
5988 /* Write the QC params corresponding to the fitting of the GAIN */
5989 i = 1;
5990 prestate = cpl_errorstate_get();
5991 coef = cpl_polynomial_get_coeff(poly_fit, &i);
5992 skip_if (!cpl_errorstate_is_equal(prestate) || coef==0);
5993 skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD, coef));
5994 skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD,
5995 DETMON_QC_CONAD_C));
5996 if (coef != 0)
5997 {
5998 skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN,
5999 1 / coef));
6000 skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN,
6001 DETMON_QC_GAIN_C));
6002 }
6003 /* MSE is removed - see DFS07358 for details
6004 skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_MSE, mse));
6005 skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_MSE,
6006 DETMON_QC_GAIN_MSE_C));
6007 */
6008 i = 0;
6009 /* QC.RON computation is disabled, see DFS05852 for details*/
6010
6011 /* * skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_RON,
6012 cpl_polynomial_get_coeff(poly_fit, &i)));
6013 skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_RON,
6014 DETMON_QC_RON_C));
6015 */
6016 if(mode & IRPLIB_GAIN_WITH_AUTOCORR){
6017 const cpl_vector *x2 =
6018 cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT_CORR"));
6019 const cpl_vector *y2 =
6020 cpl_vector_wrap(nsets, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
6021
6022 if(x2 == NULL || y2 == NULL) {
6023 cpl_vector_unwrap((cpl_vector *)x2);
6024 cpl_vector_unwrap((cpl_vector *)y2);
6025 /*
6026 * As x and y are const vectors, if they would be defined at the
6027 * beginning of the function (required for skip_if - end_skip
6028 * scheme), they couldn't be initialised to NULL (required too).
6029 * Therefore, they are considered apart from the scheme.
6030 */
6031 skip_if(1);
6032 }
6033
6034 /* Revise mse, maybe used afterwards */
6035 poly_fit2 = irplib_polynomial_fit_1d_create(x2, y2, 1, &mse);
6036 if(poly_fit2 == NULL) {
6037 cpl_vector_unwrap((cpl_vector *)x2);
6038 cpl_vector_unwrap((cpl_vector *)y2);
6039
6040 cpl_msg_error(cpl_func, "Error during polynomial fit, err[%s]", cpl_error_get_where());
6041 /* See comment in previous error checking if() statement */
6042 skip_if(1);
6043 }
6044 skip_if(cpl_error_get_code() != CPL_ERROR_NONE);
6045 cpl_vector_unwrap((cpl_vector *)x2);
6046 cpl_vector_unwrap((cpl_vector *)y2);
6047 skip_if(cpl_error_get_code() != CPL_ERROR_NONE);
6048 /* Write the QC params corresponding to the fitting of the GAIN */
6049 i = 1;
6050 prestate = cpl_errorstate_get();
6051 coef = cpl_polynomial_get_coeff(poly_fit2, &i);
6052 skip_if(cpl_error_get_code() != CPL_ERROR_NONE);
6053 skip_if (!cpl_errorstate_is_equal(prestate) || coef == 0);
6054
6055 skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD_CORR,
6056 coef));
6057 skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD_CORR,
6058 DETMON_QC_CONAD_CORR_C));
6059
6060 skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_CORR,
6061 1 / coef));
6062 skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_CORR,
6063 DETMON_QC_GAIN_CORR_C));
6064 }
6065
6066 end_skip;
6067
6068 /*cleanup*/
6069 cpl_vector_unwrap(x);
6070 cpl_vector_unwrap(y);
6071 cpl_polynomial_delete(poly_fit);
6072 cpl_polynomial_delete(poly_fit2);
6073
6074 return cpl_error_get_code();
6075}
6076
6083static int detmon_lg_check_before_gain(const cpl_vector* x, const cpl_vector* y)
6084{
6085 const double TOLERANCE = 1e-37;/*MINDOUBLE is not everywhere defined (Mac);*/
6086 double xmin = cpl_vector_get_min(x);
6087 double xmax = cpl_vector_get_max(x);
6088 double ymin = cpl_vector_get_min(y);
6089 double ymax = cpl_vector_get_max(y);
6090 double ystdev = cpl_vector_get_stdev(y);
6091 double xstdev = cpl_vector_get_stdev(x);
6092 int retval = 1;
6093 if (fabs(xmax-xmin) < TOLERANCE &&
6094 fabs(ymax - ymin) < TOLERANCE &&
6095 xstdev < TOLERANCE &&
6096 ystdev < TOLERANCE)
6097 {
6098 cpl_msg_warning(cpl_func, "An empty frame has been detected, linearity, coeffs, gain, FPN values will not be computed.");
6099 retval = 0;
6100 }
6101 return retval;
6102}
6103/*---------------------------------------------------------------------------*/
6112/*---------------------------------------------------------------------------*/
6113static cpl_error_code
6114detmon_lg_qc_med(const cpl_table * gain_table,
6115 cpl_propertylist * qclist, int rows_in_gain)
6116{
6117
6118 double gain=0;
6119 cpl_vector *x = NULL;
6120 cpl_vector *y = NULL;
6121 int check_result = 0;
6122
6123 if (rows_in_gain) {/* silence unused var */};
6124
6125 x = cpl_vector_wrap(rows_in_gain, (double *)cpl_table_get_data_double_const(gain_table, "X_FIT"));
6126 y = cpl_vector_wrap(rows_in_gain, (double *)cpl_table_get_data_double_const(gain_table, "Y_FIT"));
6127 check_result = detmon_lg_check_before_gain(x, y);
6128 if (x)
6129 {
6130 cpl_vector_unwrap(x);
6131 }
6132 if (y)
6133 {
6134 cpl_vector_unwrap(y);
6135 }
6136 if (0 == check_result)
6137 {
6138 return CPL_ERROR_NONE;
6139 }
6140
6141 gain=cpl_table_get_column_median(gain_table, "GAIN");
6142
6143 skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN,gain));
6144
6145 skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN,
6146 DETMON_QC_GAIN_C));
6147
6148 skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_MSE,
6149 cpl_table_get_column_stdev
6150 (gain_table, "GAIN")));
6151 skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_MSE,
6152 DETMON_QC_GAIN_MSE_C));
6153
6154 skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD,1./gain));
6155 skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD,
6156 DETMON_QC_CONAD_C));
6157
6158
6159 gain=cpl_table_get_column_median(gain_table, "GAIN_CORR");
6160
6161 skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_GAIN_CORR,
6162 gain));
6163 skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_GAIN_CORR,
6164 DETMON_QC_GAIN_CORR_C));
6165
6166
6167 skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_CONAD_CORR,1./gain));
6168 skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_CONAD_CORR,
6169 DETMON_QC_CONAD_CORR_C));
6170
6171
6172 end_skip;
6173
6174 return cpl_error_get_code();
6175}
6176
6177
6178/*---------------------------------------------------------------------------*/
6187/*---------------------------------------------------------------------------*/
6188static cpl_error_code
6189detmon_lg_rescale(cpl_imagelist * to_rescale)
6190{
6191 double med1 =
6192 cpl_image_get_median_window(cpl_imagelist_get(to_rescale, 0),
6193 detmon_lg_config.llx,
6194 detmon_lg_config.lly,
6195 detmon_lg_config.urx,
6196 detmon_lg_config.ury);
6197 double med2 =
6198 cpl_image_get_median_window(cpl_imagelist_get(to_rescale, 1),
6199 detmon_lg_config.llx,
6200 detmon_lg_config.lly,
6201 detmon_lg_config.urx,
6202 detmon_lg_config.ury);
6203
6204 skip_if(0);
6205
6206 if(fabs(med1 / med2 - 1) > 0.001) {
6207 if(med1 > med2)
6208 skip_if(cpl_image_divide_scalar(cpl_imagelist_get(to_rescale, 0),
6209 med1 / med2));
6210 else
6211 skip_if(cpl_image_divide_scalar(cpl_imagelist_get(to_rescale, 1),
6212 med2 / med1));
6213 }
6214
6215 end_skip;
6216
6217 return cpl_error_get_code();
6218}
6219
6220static cpl_error_code
6221detmon_pair_extract_next(const cpl_frameset * set,
6222 int* iindex,
6223 int* next_element,
6224 double* dit_array,
6225 cpl_frameset ** pair,
6226 double tolerance) /* detmon_lg_config.tolerance */
6227{
6228 double dit = -100;
6229 double dit_next = -100;
6230 cpl_size* selection;
6231 int nsets_extracted = 0;
6232 cpl_ensure_code(set != NULL, CPL_ERROR_NULL_INPUT);
6233 cpl_ensure_code(dit_array != NULL, CPL_ERROR_NULL_INPUT);
6234 cpl_ensure_code(iindex != NULL, CPL_ERROR_NULL_INPUT);
6235 cpl_ensure_code(pair != NULL, CPL_ERROR_NULL_INPUT);
6236
6237 nsets_extracted = cpl_frameset_get_size(set);
6238 selection = cpl_malloc(sizeof(cpl_size) * nsets_extracted);
6239 memset(&selection[0], 0, sizeof(cpl_size) * nsets_extracted);
6240
6241
6242 dit = dit_array[*next_element ];
6243 /* cpl_msg_info(cpl_func, "%d: dit %f",*next_element, dit ); */
6244 if (*next_element < nsets_extracted - 1)
6245 {
6246 dit_next = dit_array[*next_element + 1 ];
6247 /* cpl_msg_info(cpl_func, "%d: dit %f",*next_element + 1, dit_next ); */
6248 }
6249 /* one element would be returned always */
6250 selection[iindex[*next_element] ] = 1;
6251 if (fabs(dit - dit_next) < tolerance)
6252 {
6253 /* return a second element of the pair */
6254 selection[iindex[*next_element + 1] ] = 1;
6255 (*next_element)++;
6256 }
6257 else
6258 {
6259 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);
6260 }
6261 (*next_element)++;
6262 /* prepare frameset */
6263 cpl_frameset_delete(*pair);
6264 *pair = cpl_frameset_extract(set, selection, 1);
6265
6266
6267 cpl_free(selection);
6268 return cpl_error_get_code();
6269}
6270
6271static cpl_error_code
6272detmon_single_extract_next(const cpl_frameset * set,
6273 int* iindex,
6274 int* next_element,
6275 double* dit_array,
6276 cpl_frameset ** pair)
6277{
6278 cpl_size* selection;
6279 int nsets_extracted = 0;
6280 cpl_ensure_code(set != NULL, CPL_ERROR_NULL_INPUT);
6281 cpl_ensure_code(dit_array != NULL, CPL_ERROR_NULL_INPUT);
6282 cpl_ensure_code(iindex != NULL, CPL_ERROR_NULL_INPUT);
6283 cpl_ensure_code(pair != NULL, CPL_ERROR_NULL_INPUT);
6284
6285 nsets_extracted = cpl_frameset_get_size(set);
6286 selection = cpl_malloc(sizeof(cpl_size) * nsets_extracted);
6287 memset(&selection[0], 0, sizeof(cpl_size) * nsets_extracted);
6288
6289 /* only one element would be returned */
6290 selection[iindex[*next_element] ] = 1;
6291 (*next_element)++;
6292 /* prepare frameset */
6293 cpl_frameset_delete(*pair);
6294 *pair = cpl_frameset_extract(set, selection, 1);
6295
6296 cpl_free(selection);
6297 return cpl_error_get_code();
6298}
6299
6300
6301/*---------------------------------------------------------------------------*/
6392/*---------------------------------------------------------------------------*/
6393
6394cpl_table *
6395detmon_gain(const cpl_imagelist * imlist_on,
6396 const cpl_imagelist * imlist_off,
6397 const cpl_vector * exptimes,
6398 const cpl_vector * ndit,
6399 double tolerance,
6400 int llx,
6401 int lly,
6402 int urx,
6403 int ury,
6404 double kappa,
6405 int nclip,
6406 int xshift,
6407 int yshift,
6408 cpl_propertylist * qclist,
6409 unsigned mode,
6410 cpl_imagelist ** diff_imlist,
6411 cpl_imagelist ** autocorr_imlist)
6412{
6413 cpl_table * gain_table = NULL;
6414 cpl_imagelist * difflist = NULL;
6415 cpl_imagelist * autocorrlist = NULL;
6416 cpl_imagelist * c_onlist = NULL;
6417 cpl_imagelist * c_offlist = NULL;
6418 cpl_vector * diffdits = NULL;
6419 cpl_vector * diffndits = NULL;
6420 int rows_in_gain = 0;
6421 int ndiffdits, ndits;
6422 int i, j;
6423 cpl_boolean opt_nir = mode & IRPLIB_GAIN_OPT ? OPT : NIR;
6424 const char * method = mode & IRPLIB_GAIN_PTC ? "PTC" : "MED";
6425
6426 cpl_ensure(imlist_on != NULL, CPL_ERROR_NULL_INPUT, NULL);
6427 cpl_ensure(imlist_off != NULL, CPL_ERROR_NULL_INPUT, NULL);
6428 cpl_ensure(exptimes != NULL, CPL_ERROR_NULL_INPUT, NULL);
6429 cpl_ensure(qclist != NULL, CPL_ERROR_NULL_INPUT, NULL);
6430
6431 /* Create table with columns */
6432 gain_table = cpl_table_new(cpl_vector_get_size(exptimes) / 2);
6433 skip_if(detmon_gain_table_create(gain_table, opt_nir));
6434
6435
6436 /* Search for different EXPTIME values */
6437 skip_if(detmon_lg_find_dits_ndits(exptimes, ndit,tolerance,&diffdits,
6438 &diffndits));
6439 ndiffdits = cpl_vector_get_size(diffdits);
6440
6441 ndits = cpl_vector_get_size(exptimes);
6442
6443 /* AUTOCORR processing requires both. They will become outputs later. */
6444 if (mode & IRPLIB_GAIN_WITH_AUTOCORR && (diff_imlist || autocorr_imlist)) {
6445 difflist = cpl_imagelist_new();
6446 autocorrlist = cpl_imagelist_new();
6447 }
6448
6449 if (mode & IRPLIB_GAIN_COLLAPSE) {
6450 if (mode & IRPLIB_GAIN_WITH_RESCALE) {
6451 c_offlist = cpl_imagelist_duplicate(imlist_off);
6452 skip_if(detmon_lg_rescale(c_offlist));
6453 } else {
6454 c_offlist = (cpl_imagelist *) imlist_off;
6455 }
6456 }
6457
6458 /* Loop over the different DITs found in EXPTIMEs */
6459 for (i = 0; i < ndiffdits; i++) {
6460 int c_nons;
6461 int c_noffs = 0; /* False (uninit) warning */
6462
6463 double c_dit = 0;
6464 int c_ndit = 1;
6465
6466 c_dit=cpl_vector_get(diffdits, i);
6467
6468 if(opt_nir) {
6469 c_ndit=(int)cpl_vector_get(diffndits, i);
6470 }
6471
6472 c_onlist = cpl_imagelist_new();
6473 c_nons = 0;
6474
6475 if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
6476 c_offlist = cpl_imagelist_new();
6477 c_noffs = 0;
6478 }
6479
6480 /* Extraction of images of EXPTIME i */
6481 for(j = 0; j < ndits; j++) {
6482 if (fabs(c_dit - cpl_vector_get(exptimes, j)) <= tolerance) {
6483 /*
6484 * First we get the corresponding image from the ON imlist.
6485 * The option IRPLIB_GAIN_WITH_RESCALE requires to modify
6486 * the input pixel buffer; therefore we must duplicate it.
6487 * On the other hand, if this option is not required, there
6488 * is no need for that duplication. We must only care that
6489 * c_onlist must not be deleted but only unset.
6490 */
6491 cpl_image * im_on;
6492 if (mode & IRPLIB_GAIN_WITH_RESCALE) {
6493 const cpl_image * im =
6494 cpl_imagelist_get_const(imlist_on, j);
6495 im_on = cpl_image_duplicate(im);
6496 } else {
6497 im_on = (cpl_image *)cpl_imagelist_get_const(imlist_on, j);
6498 }
6499 skip_if(cpl_imagelist_set(c_onlist, im_on, c_nons));
6500 c_nons++;
6501
6502 /*
6503 * Same explanation as above but for OFF imlist.
6504 * Only necessary when IRPLIB_GAIN_NO_COLLAPSE required.
6505 */
6506 if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
6507 cpl_image * im_off;
6508 if (mode & IRPLIB_GAIN_WITH_RESCALE) {
6509 const cpl_image * im =
6510 cpl_imagelist_get_const(imlist_off, j);
6511 im_off = cpl_image_duplicate(im);
6512 } else {
6513 im_off =
6514 (cpl_image *) cpl_imagelist_get_const(imlist_off, j);
6515 }
6516 skip_if(cpl_imagelist_set(c_offlist, im_off, c_noffs));
6517 c_noffs++;
6518 }
6519 }
6520 }
6521
6522 /* If NO_COLLAPSE, must be the same number of images! */
6523 if (mode & IRPLIB_GAIN_NO_COLLAPSE)
6524 skip_if (c_nons != c_noffs);
6525
6526 /* There must be pairs! */
6527 skip_if (c_nons == 0 || c_nons % 2 != 0);
6528
6529 /* Rescaling */
6530 if(mode & IRPLIB_GAIN_WITH_RESCALE) {
6531 skip_if(detmon_lg_rescale(c_onlist));
6532 if (mode & IRPLIB_GAIN_NO_COLLAPSE)
6533 skip_if(detmon_lg_rescale(c_offlist));
6534 }
6535
6536 /* The following loop is necessary for the case of multiple pairs
6537 of same EXPTIME values */
6538 while(c_nons > 0) {
6539 int rows_affected = 1;
6540 skip_if(detmon_gain_table_fill_row(gain_table,
6541 c_dit,c_ndit,
6542 autocorrlist,
6543 difflist, c_onlist,
6544 c_offlist, kappa, nclip,
6545 llx, lly, urx, ury,
6546 xshift, yshift, 1E10, i,
6547 mode, &rows_affected));
6548 if (rows_affected)
6549 {
6550 rows_in_gain++;
6551 }
6552 if (mode & IRPLIB_GAIN_WITH_RESCALE) {
6553 cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
6554 cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
6555 if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
6556 cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
6557 cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
6558 }
6559 } else {
6560 cpl_imagelist_unset(c_onlist, 0);
6561 skip_if(0);
6562 cpl_imagelist_unset(c_onlist, 0);
6563 skip_if(0);
6564 if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
6565 cpl_imagelist_unset(c_offlist, 0);
6566 skip_if(0);
6567 cpl_imagelist_unset(c_offlist, 0);
6568 skip_if(0);
6569 }
6570 }
6571 skip_if(0);
6572 c_nons -= 2;
6573 }
6574
6575 cpl_imagelist_delete(c_onlist);
6576 if (mode & IRPLIB_GAIN_NO_COLLAPSE) {
6577 cpl_imagelist_delete(c_offlist);
6578 }
6579 }
6580
6581 skip_if(cpl_propertylist_append_string(qclist, DETMON_QC_METHOD, method));
6582 skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_METHOD,
6583 DETMON_QC_METHOD_C));
6584
6585 /* Computation of GAIN via polynomial fit */
6586 if (mode & IRPLIB_GAIN_PTC) {
6587 skip_if(detmon_lg_qc_ptc(gain_table, qclist, mode, rows_in_gain));
6588 } else {
6589 skip_if(detmon_lg_qc_med(gain_table, qclist, rows_in_gain));
6590 }
6591
6592 if(mode & IRPLIB_GAIN_WITH_AUTOCORR) {
6593 double autocorr = cpl_table_get_column_median(gain_table, "AUTOCORR");
6594 skip_if(cpl_propertylist_append_double(qclist, DETMON_QC_AUTOCORR,
6595 autocorr));
6596 skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_AUTOCORR,
6597 DETMON_QC_AUTOCORR_C));
6598 }
6599
6600 if (diff_imlist != NULL) *diff_imlist = difflist;
6601 if (autocorr_imlist != NULL) *autocorr_imlist = autocorrlist;
6602
6603 end_skip;
6604
6605 cpl_vector_delete(diffdits);
6606 cpl_vector_delete(diffndits);
6607
6608 return gain_table;
6609}
6610
6611static cpl_error_code
6612detmon_gain_table_create(cpl_table * gain_table,
6613 const cpl_boolean opt_nir)
6614{
6615 if (opt_nir == NIR) {
6616 skip_if(cpl_table_new_column(gain_table, "DIT", CPL_TYPE_DOUBLE));
6617 skip_if(cpl_table_new_column(gain_table, "NDIT", CPL_TYPE_INT));
6618 } else { /* OPT */
6619 skip_if(cpl_table_new_column(gain_table, "EXPTIME", CPL_TYPE_DOUBLE));
6620 }
6621 skip_if(cpl_table_new_column(gain_table, "MEAN_ON1", CPL_TYPE_DOUBLE));
6622 skip_if(cpl_table_new_column(gain_table, "MEAN_ON2", CPL_TYPE_DOUBLE));
6623 skip_if(cpl_table_new_column(gain_table, "MEAN_OFF1", CPL_TYPE_DOUBLE));
6624 skip_if(cpl_table_new_column(gain_table, "MEAN_OFF2", CPL_TYPE_DOUBLE));
6625 skip_if(cpl_table_new_column(gain_table, "SIG_ON_DIF", CPL_TYPE_DOUBLE));
6626 skip_if(cpl_table_new_column(gain_table, "SIG_OFF_DIF", CPL_TYPE_DOUBLE));
6627 skip_if(cpl_table_new_column(gain_table, "GAIN", CPL_TYPE_DOUBLE));
6628 skip_if(cpl_table_new_column(gain_table, "AUTOCORR", CPL_TYPE_DOUBLE));
6629 skip_if(cpl_table_new_column(gain_table, "GAIN_CORR", CPL_TYPE_DOUBLE));
6630 skip_if(cpl_table_new_column(gain_table, "ADU", CPL_TYPE_DOUBLE));
6631 skip_if(cpl_table_new_column(gain_table, "X_FIT", CPL_TYPE_DOUBLE));
6632 skip_if(cpl_table_new_column(gain_table, "X_FIT_CORR", CPL_TYPE_DOUBLE));
6633 skip_if(cpl_table_new_column(gain_table, "Y_FIT", CPL_TYPE_DOUBLE));
6634 skip_if(cpl_table_new_column(gain_table, "Y_FIT_CORR", CPL_TYPE_DOUBLE));
6635 skip_if(cpl_table_new_column(gain_table, "FLAG", CPL_TYPE_INT));
6636
6637 end_skip;
6638
6639 return cpl_error_get_code();
6640}
6641
6642static cpl_error_code
6643detmon_lin_table_create(cpl_table * lin_table,
6644 const cpl_boolean opt_nir)
6645{
6646 if (opt_nir == NIR) {
6647 skip_if(cpl_table_new_column(lin_table, "DIT", CPL_TYPE_DOUBLE));
6648 } else { /* OPT */
6649 skip_if(cpl_table_new_column(lin_table, "EXPTIME", CPL_TYPE_DOUBLE));
6650 }
6651 skip_if(cpl_table_new_column(lin_table, "MED", CPL_TYPE_DOUBLE));
6652 skip_if(cpl_table_new_column(lin_table, "MEAN", CPL_TYPE_DOUBLE));
6653 skip_if(cpl_table_new_column(lin_table, "MED_DIT", CPL_TYPE_DOUBLE));
6654 skip_if(cpl_table_new_column(lin_table, "MEAN_DIT", CPL_TYPE_DOUBLE));
6655 skip_if(cpl_table_new_column(lin_table, "ADL", CPL_TYPE_DOUBLE));
6656 end_skip;
6657
6658 return cpl_error_get_code();
6659}
6660
6661static cpl_vector *
6662detmon_lg_find_dits(const cpl_vector * exptimes,
6663 double tolerance)
6664{
6665 cpl_vector * dits = cpl_vector_new(cpl_vector_get_size(exptimes) / 2);
6666 int ndits = 0;
6667
6668 int i, j;
6669
6670 /* First different EXPTIME */
6671 cpl_vector_set(dits, 0, cpl_vector_get(exptimes, 0));
6672 ndits = 1;
6673
6674 /* Search for all different EXPTIMEs */
6675 for(i = 1; i < cpl_vector_get_size(exptimes); i++) {
6676 int ndiffs = 0;
6677 for (j = 0; j < ndits; j++) {
6678 if (fabs(cpl_vector_get(exptimes, i) -
6679 cpl_vector_get(dits, j)) > tolerance)
6680 ndiffs++;
6681 }
6682 if(ndiffs == ndits) {
6683 cpl_vector_set(dits, ndits, cpl_vector_get(exptimes, i));
6684 ndits++;
6685 }
6686 }
6687
6688 cpl_vector_set_size(dits, ndits);
6689
6690 return dits;
6691}
6692
6693
6694
6695
6696static cpl_error_code
6697detmon_lg_find_dits_ndits(const cpl_vector * exptimes,
6698 const cpl_vector * vec_ndits,
6699 double tolerance,
6700 cpl_vector** diff_dits,
6701 cpl_vector** diff_ndits)
6702{
6703 int ndits = 0;
6704
6705 int i, j;
6706 int size=0;
6707
6708
6709 * diff_dits = cpl_vector_new(cpl_vector_get_size(exptimes) / 2);
6710 * diff_ndits = cpl_vector_new(cpl_vector_get_size(*diff_dits));
6711
6712 /* First different EXPTIME */
6713 cpl_vector_set(*diff_dits, 0, cpl_vector_get(exptimes, 0));
6714 cpl_vector_set(*diff_ndits, 0, cpl_vector_get(vec_ndits, 0));
6715
6716 ndits = 1;
6717 size=cpl_vector_get_size(exptimes);
6718 /* Search for all different EXPTIMEs */
6719 for(i = 1; i < size; i++) {
6720 int ndiffs = 0;
6721 for (j = 0; j < ndits; j++) {
6722 if (fabs(cpl_vector_get(exptimes, i) -
6723 cpl_vector_get(*diff_dits,j)) > tolerance)
6724 ndiffs++;
6725 }
6726 if(ndiffs == ndits) {
6727 cpl_vector_set(*diff_dits, ndits, cpl_vector_get(exptimes, i));
6728 cpl_vector_set(*diff_ndits, ndits, cpl_vector_get(vec_ndits, i));
6729 ndits++;
6730 }
6731 }
6732
6733 cpl_vector_set_size(*diff_dits, ndits);
6734 cpl_vector_set_size(*diff_ndits, ndits);
6735
6736
6737 return cpl_error_get_code();
6738}
6739
6740
6741/*---------------------------------------------------------------------------*/
6824/*---------------------------------------------------------------------------*/
6825
6826cpl_table *
6827detmon_lin(const cpl_imagelist * imlist_on,
6828 const cpl_imagelist * imlist_off,
6829 const cpl_vector * exptimes,
6830 double tolerance,
6831 int llx,
6832 int lly,
6833 int urx,
6834 int ury,
6835 int order,
6836 int ref_level,
6837 double kappa,
6838 cpl_boolean bpmbin,
6839 cpl_propertylist * qclist,
6840 unsigned mode,
6841 cpl_imagelist ** coeffs_cube,
6842 cpl_image ** bpm)
6843{
6844 cpl_table * lin_table = NULL;
6845 cpl_imagelist * c_onlist = NULL;
6846 cpl_imagelist * c_offlist = NULL;
6847 cpl_vector * diffdits = NULL;
6848 cpl_imagelist * lin_inputs = NULL;
6849 cpl_polynomial * poly_linfit = NULL;
6850 cpl_image * fiterror = NULL;
6851 cpl_vector * vcoeffs = NULL;
6852 double * pcoeffs = NULL;
6853 int ndiffdits, ndits;
6854 int i, j;
6855 cpl_boolean opt_nir = mode & IRPLIB_LIN_OPT ? OPT : NIR;
6856 const cpl_vector *x = NULL;
6857 const cpl_vector *y = NULL;
6858
6859 const cpl_image * first = NULL;
6860 int sizex = 0;
6861 int sizey = 0;
6862
6863 cpl_size deg;
6864 double vsize = 0;
6865
6866
6867 cpl_ensure(imlist_on != NULL, CPL_ERROR_NULL_INPUT, NULL);
6868 cpl_ensure(imlist_off != NULL, CPL_ERROR_NULL_INPUT, NULL);
6869 cpl_ensure(exptimes != NULL, CPL_ERROR_NULL_INPUT, NULL);
6870 cpl_ensure(qclist != NULL, CPL_ERROR_NULL_INPUT, NULL);
6871 cpl_ensure(order > 0 , CPL_ERROR_ILLEGAL_INPUT, NULL);
6872
6873 vcoeffs = cpl_vector_new(order + 1);
6874 pcoeffs = cpl_vector_get_data(vcoeffs);
6875
6876 /* This mode requires optional outputs */
6877 if (mode & IRPLIB_LIN_PIX2PIX) {
6878 cpl_ensure(coeffs_cube != NULL, CPL_ERROR_NULL_INPUT, NULL);
6879 cpl_ensure(bpm != NULL, CPL_ERROR_NULL_INPUT, NULL);
6880 lin_inputs = cpl_imagelist_new();
6881 }
6882
6883 /* Create table with columns */
6884 lin_table = cpl_table_new(cpl_vector_get_size(exptimes) / 2);
6885 skip_if(detmon_lin_table_create(lin_table, opt_nir));
6886
6887 /* Search for different EXPTIME values */
6888 /* Search for different EXPTIME values */
6889 diffdits = detmon_lg_find_dits(exptimes, tolerance);
6890 ndiffdits = cpl_vector_get_size(diffdits);
6891
6892 ndits = cpl_vector_get_size(exptimes);
6893
6894
6895
6896
6897
6898
6899 /* TO BE IMPLEMENTED SIMILARLY TO UPPER LEVEL FUNCTION (search for nskip)
6900 if(filter > 0) {
6901 double med1 =
6902 cpl_image_get_median_window(cpl_imagelist_get(imlist_on, 0),
6903 llx,lly,urx,ury);
6904 double med2 =
6905 cpl_image_get_median_window(cpl_imagelist_get(imlist_on, 1),
6906 llx,lly,urx,ury);
6907 if ( med1 > (double)filter ||
6908 med2 > (double)filter) {
6909 follow = CPL_FALSE;
6910 cpl_table_select_row(lin_table, dit_nb);
6911 dit_nskip++;
6912 cpl_msg_warning(cpl_func, "Frames of EXPTIME nb %d "
6913 "will not be taken into account for computation "
6914 "as they are above --filter threshold", dit_nb);
6915 }
6916 }
6917 */
6918
6919
6920
6921
6922 if (mode & IRPLIB_LIN_COLLAPSE) {
6923 /*
6924 * The master bias is required only for
6925 * linearity computation in the OPT domain
6926 */
6927 cpl_image * collapse = cpl_imagelist_collapse_create(imlist_off);
6928 skip_if(collapse == NULL);
6929
6930 c_offlist = cpl_imagelist_new();
6931 skip_if(cpl_imagelist_set(c_offlist, collapse, 0));
6932 }
6933
6934 /* Loop over the different DITs found in EXPTIMEs */
6935 for (i = 0; i < ndiffdits; i++) {
6936 int c_nons;
6937 int c_noffs = 0; /* False (uninit) warning */
6938
6939 double c_dit = cpl_vector_get(diffdits, i);
6940
6941 c_onlist = cpl_imagelist_new();
6942 c_nons = 0;
6943
6944 if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6945 c_offlist = cpl_imagelist_new();
6946 c_noffs = 0;
6947 }
6948
6949 for(j = 0; j < ndits; j++) {
6950 if (fabs(c_dit - cpl_vector_get(exptimes, j)) <= tolerance) {
6951 /*
6952 * First we get the corresponding image from the ON imlist.
6953 * The option IRPLIB_GAIN_WITH_RESCALE requires to modify
6954 * the input pixel buffer; therefore we must duplicate it.
6955 * On the other hand, if this option is not required, there
6956 * is no need for that duplication. We must only care that
6957 * c_onlist must not be deleted but only unset.
6958 */
6959 cpl_image * im_on;
6960 if (mode & IRPLIB_LIN_WITH_RESCALE) {
6961 const cpl_image * im =
6962 cpl_imagelist_get_const(imlist_on, j);
6963 im_on = cpl_image_duplicate(im);
6964 } else {
6965 im_on = (cpl_image *)cpl_imagelist_get_const(imlist_on, j);
6966 }
6967 skip_if(cpl_imagelist_set(c_onlist, im_on, c_nons));
6968 c_nons++;
6969
6970 /*
6971 * Same explanation as above but for OFF imlist.
6972 * Only necessary when IRPLIB_GAIN_NO_COLLAPSE required.
6973 */
6974 if (mode & IRPLIB_LIN_NO_COLLAPSE) {
6975 cpl_image * im_off;
6976 if (mode & IRPLIB_LIN_WITH_RESCALE) {
6977 const cpl_image * im =
6978 cpl_imagelist_get_const(imlist_off, j);
6979 im_off = cpl_image_duplicate(im);
6980 } else {
6981 im_off =
6982 (cpl_image *) cpl_imagelist_get_const(imlist_off, j);
6983 }
6984 skip_if(cpl_imagelist_set(c_offlist, im_off, c_noffs));
6985 c_noffs++;
6986 }
6987 }
6988 }
6989
6990 /* If NO_COLLAPSE, must be the same number of images! */
6991 if (mode & IRPLIB_LIN_NO_COLLAPSE)
6992 skip_if (c_nons != c_noffs);
6993
6994 /* There must be pairs! */
6995 skip_if (c_nons == 0 || c_nons % 2 != 0);
6996
6997 /* Rescaling */
6998 if(mode & IRPLIB_LIN_WITH_RESCALE) {
6999 skip_if(detmon_lg_rescale(c_onlist));
7000 if (mode & IRPLIB_LIN_NO_COLLAPSE)
7001 skip_if(detmon_lg_rescale(c_offlist));
7002 }
7003
7004 /* The following loop is necessary for the case of multiple pairs
7005 of same EXPTIME values */
7006 while(c_nons > 0) {
7007
7008 skip_if(detmon_lin_table_fill_row(lin_table, c_dit,
7009 lin_inputs,
7010 c_onlist, c_offlist,
7011 llx, lly, urx, ury,
7012 i, 0, mode));
7013
7014 if (mode & IRPLIB_LIN_WITH_RESCALE) {
7015 cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
7016 cpl_image_delete(cpl_imagelist_unset(c_onlist, 0));
7017 if (mode & IRPLIB_LIN_NO_COLLAPSE) {
7018 cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
7019 cpl_image_delete(cpl_imagelist_unset(c_offlist, 0));
7020 }
7021 } else {
7022 cpl_imagelist_unset(c_onlist, 0);
7023 skip_if(0);
7024 cpl_imagelist_unset(c_onlist, 0);
7025 skip_if(0);
7026 if (mode & IRPLIB_LIN_NO_COLLAPSE) {
7027 cpl_imagelist_unset(c_offlist, 0);
7028 skip_if(0);
7029 cpl_imagelist_unset(c_offlist, 0);
7030 skip_if(0);
7031 }
7032 }
7033 skip_if(0);
7034 c_nons -= 2;
7035 }
7036
7037 cpl_imagelist_delete(c_onlist);
7038 if (mode & IRPLIB_LIN_NO_COLLAPSE) {
7039 cpl_imagelist_delete(c_offlist);
7040 }
7041 }
7042
7043 skip_if(detmon_add_adl_column(lin_table, opt_nir));
7044
7045 if(!(mode & IRPLIB_LIN_PIX2PIX)) {
7046 double mse = 0;
7047 /* Computation of LINEARITY via polynomial fit */
7048 y = cpl_vector_wrap(cpl_table_get_nrow(lin_table),
7049 (double *)cpl_table_get_data_double_const(lin_table,
7050 "MED"));
7051 if (opt_nir == NIR) {
7052 x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
7053 (double *)cpl_table_get_data_double_const(lin_table, "DIT"));
7054 } else {
7055 x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
7056 (double *)cpl_table_get_data_double_const(lin_table, "EXPTIME"));
7057 }
7058 if(x == NULL || y == NULL) {
7059 cpl_vector_unwrap((cpl_vector *)x);
7060 cpl_vector_unwrap((cpl_vector *)y);
7061 /*
7062 * As x and y are const vectors, if they would be defined at the
7063 * beginning of the function (required for skip_if - end_skip
7064 * scheme), they couldn't be initialised to NULL (required too).
7065 * Therefore, they are considered apart from the scheme.
7066 */
7067 skip_if(1);
7068 }
7069
7070 cpl_msg_info(cpl_func, "Polynomial fitting for the LINEARITY");
7071 poly_linfit = irplib_polynomial_fit_1d_create_chiq(x, y, order, &mse);
7072
7073 if(order == cpl_vector_get_size(x) - 1) {
7074 cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
7075 mse = 0;
7076 }
7077
7078 if(poly_linfit == NULL) {
7079 cpl_vector_unwrap((cpl_vector *)x);
7080 cpl_vector_unwrap((cpl_vector *)y);
7081 /* See comment in previous error checking if() statement */
7082 skip_if(1);
7083 }
7084
7085 cpl_vector_unwrap((cpl_vector *)x);
7086 cpl_vector_unwrap((cpl_vector *)y);
7087
7088 for(deg = 0; deg <= order; deg++) {
7089 const double coeff =
7090 cpl_polynomial_get_coeff(poly_linfit, &deg);
7091 char *name_o =
7092 cpl_sprintf("ESO QC LIN COEF%" CPL_SIZE_FORMAT "", deg);
7093 assert(name_o != NULL);
7094 skip_if(cpl_propertylist_append_double(qclist, name_o, coeff));
7095 skip_if(cpl_propertylist_set_comment(qclist,name_o,
7096 DETMON_QC_LIN_COEF_C));
7097 cpl_free(name_o);
7098 pcoeffs[deg] = coeff;
7099 }
7100 skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT, mse));
7101 skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
7102 DETMON_QC_ERRFIT_MSE_C));
7103
7104
7105 } else {
7106 if (opt_nir == NIR) {
7107 x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
7108 (double *)cpl_table_get_data_double_const(lin_table,
7109 "DIT"));
7110 } else {
7111 x=cpl_vector_wrap(cpl_table_get_nrow(lin_table),
7112 (double *)cpl_table_get_data_double_const(lin_table,
7113 "EXPTIME"));
7114 }
7115
7116
7117 first = cpl_imagelist_get_const(lin_inputs, 0);
7118 sizex = cpl_image_get_size_x(first);
7119 sizey = cpl_image_get_size_y(first);
7120
7121 vsize = cpl_vector_get_size(x);
7122
7123 fiterror = cpl_image_new(sizex, sizey, CPL_TYPE_FLOAT);
7124
7125 *coeffs_cube =
7126 cpl_fit_imagelist_polynomial(x, lin_inputs, 0,
7127 order, FALSE, CPL_TYPE_FLOAT,
7128 fiterror);
7129
7130 cpl_vector_unwrap((cpl_vector*)x);
7131 irplib_ensure(*coeffs_cube != NULL, CPL_ERROR_UNSPECIFIED,
7132 "Failed polynomial fit");
7133
7134 for(i = 0; i <= order; i++) {
7135 cpl_image *image = cpl_imagelist_get(*coeffs_cube, i);
7136 const double coeff = cpl_image_get_median(image);
7137 char * name_o1 = cpl_sprintf("ESO QC LIN COEF%d", i);
7138 char * name_o2 = cpl_sprintf("ESO QC LIN COEF%d ERR", i);
7139 pcoeffs[i] = coeff;
7140 assert(name_o1 != NULL);
7141 assert(name_o2 != NULL);
7142 skip_if(cpl_propertylist_append_double(qclist, name_o1, coeff));
7143 skip_if(cpl_propertylist_set_comment(qclist,name_o1,
7144 DETMON_QC_LIN_COEF_C));
7145 cpl_free(name_o1);
7146 name_o1= NULL;
7147 skip_if(cpl_propertylist_append_double(qclist, name_o2,
7148 cpl_image_get_stdev(image)));
7149 skip_if(cpl_propertylist_set_comment(qclist,name_o2,
7150 DETMON_QC_LIN_COEF_ERR_C));
7151 cpl_free(name_o2);
7152 name_o2= NULL;
7153 }
7154
7155 if(order == vsize - 1) {
7156 cpl_msg_warning(cpl_func, "The fitting is not over-determined.");
7157 skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT,
7158 0.0));
7159 skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
7160 DETMON_QC_ERRFIT_C));
7161
7162
7163 } else {
7164 skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_ERRFIT,
7165 cpl_image_get_median(fiterror)));
7166 skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_ERRFIT,
7167 DETMON_QC_ERRFIT_C));
7168
7169 }
7170 }
7171
7172 skip_if(detmon_lg_lineff(pcoeffs, qclist, ref_level, order));
7173
7174 if(mode & IRPLIB_LIN_PIX2PIX) {
7175 int nbpixs;
7176 *bpm = detmon_bpixs(*coeffs_cube, bpmbin, kappa, &nbpixs);
7177 skip_if(*bpm == NULL);
7178 skip_if(cpl_propertylist_append_int(qclist, DETMON_QC_NUM_BPM,
7179 nbpixs));
7180 skip_if(cpl_propertylist_set_comment(qclist, DETMON_QC_NUM_BPM,
7181 DETMON_QC_NUM_BPM_C));
7182 }
7183
7184 end_skip;
7185
7186 cpl_vector_delete(diffdits);
7187 cpl_polynomial_delete(poly_linfit);
7188 cpl_imagelist_delete(lin_inputs);
7189 cpl_vector_delete(vcoeffs);
7190 cpl_image_delete(fiterror);
7191
7192 return lin_table;
7193
7194}
7195
7196/*--------------------------------------------------------------------------*/
7219/*--------------------------------------------------------------------------*/
7220static cpl_error_code
7221detmon_lin_table_fill_row(cpl_table * lin_table, double c_dit,
7222 cpl_imagelist * linearity_inputs,
7223 const cpl_imagelist * ons,
7224 const cpl_imagelist * offs,
7225 int llx,
7226 int lly,
7227 int urx,
7228 int ury,
7229 const int pos,
7230 const int nskip,
7231 unsigned mode)
7232{
7233 cpl_image * extracted=NULL;
7234
7235 cpl_ensure_code(lin_table != NULL, CPL_ERROR_NULL_INPUT);
7236 cpl_ensure_code(ons != NULL, CPL_ERROR_NULL_INPUT);
7237 cpl_ensure_code(offs != NULL, CPL_ERROR_NULL_INPUT);
7238
7239 if (mode & IRPLIB_LIN_PIX2PIX) {
7240 cpl_msg_debug(cpl_func,"checking linearity inputs");
7241 cpl_ensure_code(linearity_inputs != NULL, CPL_ERROR_NULL_INPUT);
7242 }
7243
7244
7245 if (mode & IRPLIB_LIN_NIR) {
7246 cpl_table_set(lin_table, "DIT", pos, c_dit);
7247 } else if (mode & IRPLIB_LIN_OPT) { /*OPT */
7248 cpl_table_set(lin_table, "EXPTIME", pos, c_dit);
7249 } else {
7250 cpl_msg_error(cpl_func, "Mandatory mode not given");
7251 }
7252
7253 {
7254 const cpl_image * off2;
7255 if (cpl_imagelist_get_size(offs) == 1 || mode & IRPLIB_LIN_COLLAPSE)
7256 off2 = cpl_imagelist_get_const(offs, 0);
7257 else
7258 off2 = cpl_imagelist_get_const(offs, 1);
7259
7260 extracted = detmon_subtracted_avg(cpl_imagelist_get_const(ons, 0),
7261 cpl_imagelist_get_const(offs, 0),
7262 cpl_imagelist_get_const(ons, 1),
7263 off2,
7264 llx, lly, urx, ury);
7265 cpl_ensure_code(extracted != NULL, cpl_error_get_code());
7266 }
7267
7268 {
7269 double median = cpl_image_get_median(extracted);
7270 double mean= cpl_image_get_mean(extracted);
7271 cpl_table_set(lin_table, "MED", pos, median);
7272 cpl_table_set(lin_table, "MEAN", pos, mean);
7273
7274 cpl_table_set(lin_table, "MED_DIT", pos, median / c_dit);
7275 cpl_table_set(lin_table, "MEAN_DIT", pos, mean / c_dit);
7276 }
7277
7278 /* Insert to the imagelist used to fit the polynomial */
7279 if(mode & IRPLIB_LIN_PIX2PIX) {
7280 cpl_error_code error = cpl_imagelist_set(linearity_inputs, extracted,
7281 pos-nskip);
7282 cpl_ensure_code(!error, error);
7283 } else {
7284 cpl_image_delete(extracted);
7285 }
7286
7287 return cpl_error_get_code();
7288}
7289
7290static double irplib_calculate_total_noise_smooth(const cpl_image* pimage,
7291 int pattern_x, int pattern_y)
7292{
7293 cpl_image * p_tmp_image = 0;
7294 cpl_image * psmooth_image = 0;
7295 double ret_noise;
7296 cpl_mask * mask = cpl_mask_new(pattern_x, pattern_y);
7297 cpl_mask_not(mask);
7298 p_tmp_image = cpl_image_duplicate(pimage);
7299 cpl_image_filter_mask(p_tmp_image,pimage, mask,CPL_FILTER_MEDIAN ,CPL_BORDER_FILTER);
7300 cpl_image_divide_scalar(p_tmp_image, cpl_image_get_median(pimage));
7301 psmooth_image = cpl_image_divide_create(pimage,p_tmp_image);
7302 ret_noise = irplib_calculate_total_noise(psmooth_image);
7303 cpl_mask_delete(mask);
7304 cpl_image_delete(psmooth_image);
7305 cpl_image_delete(p_tmp_image);
7306 return ret_noise;
7307}
7308
7309static double irplib_calculate_total_noise(const cpl_image* pimage)
7310{
7311 double total_noise = -1;
7312 unsigned long max_bin_size = 1E5;
7313 const double hstart = cpl_image_get_min(pimage);
7314 const double hrange = cpl_image_get_max(pimage) - hstart;
7315 const unsigned long nbins = max_bin_size;
7316 cpl_error_code err;
7317 /* apply histogram method */
7318 irplib_hist * phist = 0;
7319 phist = irplib_hist_new();
7320 /* 2 extra-bins for possible out-of-range values */
7321
7322 irplib_hist_init(phist, nbins, hstart, hrange);
7323 err = irplib_hist_fill(phist, pimage);
7324 if (err == CPL_ERROR_NONE)
7325 {
7326 unsigned int i = 0;
7327 double x0 = 0;
7328 double area = 0;
7329 double offset = 0;
7330
7331 /* prepare vector */
7332 unsigned long n_bins = irplib_hist_get_nbins(phist);
7333 double start = irplib_hist_get_start(phist);
7334 double bin_size = irplib_hist_get_bin_size(phist);
7335 cpl_vector* pdata_vector = cpl_vector_new(n_bins);
7336 cpl_vector* ppos_vector = cpl_vector_new(n_bins);
7337 cpl_table* ptable = cpl_table_new(n_bins);
7338 cpl_table_new_column(ptable, "bin", CPL_TYPE_DOUBLE);
7339 cpl_table_new_column(ptable, "value", CPL_TYPE_DOUBLE);
7340 for(i = 0; i < n_bins; i++)
7341 {
7342 unsigned int value = irplib_hist_get_value(phist, i);
7343 double dvalue = (double)(value);
7344 cpl_vector_set(pdata_vector, i, dvalue);
7345 cpl_vector_set(ppos_vector, i, start + i * bin_size);
7346
7347 cpl_table_set(ptable, "bin", i, start + i * bin_size);
7348 cpl_table_set(ptable, "value", i, dvalue);
7349 }
7350 err = cpl_vector_fit_gaussian(ppos_vector, NULL, pdata_vector, NULL, CPL_FIT_ALL, &x0, &total_noise, &area, &offset, NULL, NULL, NULL );
7351 if (err == CPL_ERROR_NONE)
7352 {
7353 cpl_msg_info(cpl_func, "FPN Calculation: histogram x0[%f] total_noise[%f] area[%f] offset[%f]", x0, total_noise, area, offset);
7354 }
7355 else
7356 {
7357 cpl_msg_warning(cpl_func, "FPN could not be computed due failed Gaussian Fit, err msg [%s]", cpl_error_get_message());
7358 cpl_error_reset();
7359 }
7360 cpl_table_delete(ptable);
7361 cpl_vector_delete(ppos_vector);
7362 cpl_vector_delete(pdata_vector);
7363 }
7364 else
7365 {
7366 cpl_msg_warning(cpl_func, "FPN could not be computed due failed histogram computation, err msg [%s]", cpl_error_get_message());
7367 cpl_error_reset();
7368 }
7369 irplib_hist_delete(phist);
7370
7371 return total_noise;
7372}
7373
7374static double irplib_compute_err(double gain, double ron, double FA)
7375{
7376 double int_gain = (gain * gain - 1) / 12;
7377 if (int_gain < 0)
7378 {
7379 int_gain = 0;
7380 }
7381 return sqrt(ron * ron + FA / gain + int_gain);
7382}
7383
7384static double irplib_fpn_lg(const cpl_image* f1, int* range, double gain ,
7385 FPN_METHOD fpn_method, int smooth_size, double* mse)
7386{
7387 cpl_image* im_diff = 0;
7388 const cpl_image* im_f1 = f1;
7389 cpl_image* im_inrange1 = 0;
7390 double FA = 0;
7391 double s_tot = 0; /* absolute total noise */
7392 double s_fpn = 0; /* fixed pattern noise */
7393 double sr_fpn = 0; /* relative structural noise */
7394 /*che cinput*/
7395 if (gain<=0) {
7396 /* put dummy values Negative to indicate a problem occurred
7397 (FPN should be always positive) */
7398 cpl_msg_warning(cpl_func,"gain[%f]<0", gain);
7399 cpl_msg_warning(cpl_func,"We set dummy values for FPN");
7400 s_fpn=-999.;
7401 sr_fpn=-999;
7402 return sr_fpn;
7403 }
7404 if (range)
7405 {
7406 im_inrange1 = cpl_image_extract(f1, range[0], range[1], range[2], range[3]);
7407 im_f1 = im_inrange1;
7408 }
7409 FA = cpl_image_get_median(im_f1);
7410
7411 /* apply histogram method */
7412 /* Is this irplib function giving the right result?? */
7413 switch (fpn_method)
7414 {
7415 case FPN_SMOOTH:
7416 cpl_msg_info(cpl_func,"SMOOTH method is used for FPN, pattern size[%d x %d] pixels",smooth_size,smooth_size );
7417 s_tot = irplib_calculate_total_noise_smooth(im_f1,smooth_size,smooth_size);
7418 break;
7419 case FPN_HISTOGRAM:
7420 cpl_msg_info(cpl_func,"HISTOGRAM method is used for FPN");
7421 s_tot = irplib_calculate_total_noise(im_f1);
7422 break;
7423 default:
7424 s_tot = -1;
7425 sr_fpn = -1;
7426 cpl_msg_warning(cpl_func,"fpn_method is not defined");
7427 break;
7428 }
7429 if (s_tot > 0)
7430 {
7431 if (FA<0)
7432 {
7433 /* put dummy values Negative to indicate a problem occurred
7434 (FPN should be always positive) */
7435 cpl_msg_warning(cpl_func,"Median flux on sum of flats<0");
7436 cpl_msg_warning(cpl_func,"We set dummy values for FPN");
7437 s_fpn=-999.;
7438 sr_fpn=-999;
7439 }
7440
7441 if ((s_tot * s_tot - FA / gain) > 0)
7442 {
7443 s_fpn = sqrt(s_tot * s_tot - FA / gain);
7444 sr_fpn = s_fpn / FA;
7445 *mse = (irplib_compute_err(gain, 0, FA)) * gain / FA;
7446 } else {
7447 /* put dummy values Negative to indicate a problem occurred
7448 (FPN should be always positive) */
7449 cpl_msg_warning(cpl_func,"s_tot * s_tot < FA / gain");
7450 cpl_msg_warning(cpl_func,"We set dummy values for FPN");
7451 //s_fpn=-999.; /* in this case s_fpn value would be never used */
7452 sr_fpn=-999;
7453 *mse = -1;
7454 }
7455 /*
7456 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);
7457 */
7458 }
7459 cpl_image_delete(im_diff);
7460 if (range)
7461 {
7462 cpl_image_delete(im_inrange1);
7463 }
7464 return sr_fpn;
7465}
7466
7467
7468static cpl_imagelist * irplib_load_fset_wrp(const cpl_frameset * pframeset,
7469 cpl_type type , int whichext)
7470{
7471 /* FIXME: load image into window size from beginning to
7472 * save all the extracts */
7473 return detmon_load_frameset_window(pframeset, type, 0, whichext,
7474 detmon_lg_config.llx,
7475 detmon_lg_config.lly,
7476 detmon_lg_config.urx,
7477 detmon_lg_config.ury,
7478 detmon_lg_config.nx,
7479 detmon_lg_config.ny);
7480}
7481
7482static cpl_imagelist * irplib_load_fset_wrp_ext(const cpl_frameset * pframeset,
7483 cpl_type type , int whichext)
7484{
7485 int i = whichext; /* fake code to avoid compiler warning */
7486 cpl_imagelist* offs = cpl_imagelist_new();
7487 detmon_lg_config.load_fset(pframeset, type, offs);
7488 i++;
7489 return offs;
7490}
7491
7492static cpl_error_code irplib_table_create_column(cpl_table* ptable,
7493 cpl_propertylist* plist)
7494{
7495 if (ptable && plist)
7496 {
7497 int size = cpl_propertylist_get_size(plist);
7498 int i = 0;
7499 for (i = 0; i < size; i++)
7500 {
7501 cpl_property* pprop = cpl_propertylist_get(plist,i);
7502 if (pprop)
7503 {
7504 const char* pname = cpl_property_get_name(pprop);
7505 if (pname)
7506 {
7507 cpl_table_new_column(ptable, pname, cpl_property_get_type(pprop));
7508 if (cpl_error_get_code() != CPL_ERROR_NONE)
7509 {
7510 cpl_msg_warning(cpl_func, "cannot create new column[%s], err[%s]", pname, cpl_error_get_message());
7511 break; /* leave the cycle */
7512 }
7513 }
7514 }
7515 }
7516 }
7517 return cpl_error_get_code();
7518}
7519
7520static cpl_error_code irplib_fill_table_DETWINUIT(cpl_table* ptable,
7521 cpl_propertylist* plist, int row)
7522{
7523 cpl_error_code err = CPL_ERROR_NONE;
7524 if (ptable && plist)
7525 {
7526 int size = cpl_propertylist_get_size(plist);
7527 int i = 0;
7528 for (i = 0; i < size; i++)
7529 {
7530 cpl_property* pprop = cpl_propertylist_get(plist,i);
7531 if (pprop)
7532 {
7533 const char* pname = cpl_property_get_name(pprop);
7534 double value = cpl_property_get_double(pprop);
7535 if (pname)
7536 {
7537 cpl_table_set_double(ptable, pname, row, value);
7538 if (cpl_error_get_code() != CPL_ERROR_NONE)
7539 {
7540 cpl_msg_warning(cpl_func, "cannot write value to the table, column[%s] value[%f], err[%s]", pname, value, cpl_error_get_message());
7541 cpl_error_reset();
7542 break; /* leave the cycle */
7543 }
7544 }
7545 }
7546 }
7547 }
7548 return err;
7549}
7550
7551cpl_error_code detmon_check_order(const double *exptime, int sz,
7552 double tolerance, int order)
7553{
7554 int nsets = 0;
7555 int i = 0;
7556 /* 1. Determine number of groups */
7557 /* cpl_msg_warning(cpl_func, "detmon_check_order sz[%i]", sz);*/
7558 do
7559 {
7560 /* cpl_msg_warning(cpl_func, "detmon_check_order i[%i] exptime[%g]", i, exptime[i]); */
7561 nsets++;
7562 do
7563 {
7564 i++;
7565 if(i == sz - 1)
7566 {
7567 break;
7568 }
7569 } while(fabs(exptime[i-1] - exptime[i]) < tolerance);
7570 } while(i < sz - 1);
7571 /* the very last adjustment for the last group */
7572 if ( !( fabs(exptime[i-1] - exptime[i]) < tolerance ) ) nsets++;
7573 if(nsets <= order)
7574 {
7575 cpl_error_set_message(cpl_func,CPL_ERROR_INCOMPATIBLE_INPUT,
7576 "Not enough frames for the polynomial"
7577 " fitting. nsets = %d <= %d order",
7578 nsets,order);
7579 }
7580 return cpl_error_get_code();
7581}
7582
7583static cpl_error_code
7584detmon_lg_dfs_save_imagelist(
7585 cpl_frameset * frameset,
7586 const cpl_parameterlist * parlist,
7587 const cpl_frameset *usedframes,
7588 const cpl_imagelist *coeffs,
7589 const char *recipe_name,
7590 const cpl_propertylist *mypro_coeffscube,
7591 const char * package,
7592 const char * name_o)
7593{
7594 return(cpl_dfs_save_imagelist
7595 (frameset, NULL, parlist, usedframes, NULL,coeffs, CPL_BPP_IEEE_FLOAT,
7596 recipe_name, mypro_coeffscube, NULL, package,
7597 name_o));
7598}
7599
7600static void detmon_lg_add_empty_image(cpl_imagelist* imlist, int pos)
7601{
7602 const cpl_image* first = cpl_imagelist_get(imlist, 0);
7603 if (first)
7604 {
7605 int x = cpl_image_get_size_x(first);
7606 int y = cpl_image_get_size_y(first);
7607 cpl_type type = cpl_image_get_type(first);
7608 cpl_image * blank = cpl_image_new(x, y, type);
7609 cpl_imagelist_set(imlist, blank, pos);
7610 }
7611}
7612
7613
7614static cpl_error_code
7615detmon_lg_set_keyword_from_base_double(cpl_propertylist* pl,
7616 char* keyword_base,
7617 char* keyword_ext,
7618 char* comment_base,
7619 char* comment_ext,
7620 double value) {
7621 char* hkw = cpl_sprintf("%s %s", keyword_base, keyword_ext);
7622 char* hcm = cpl_sprintf("%s %s", comment_base, comment_ext);
7623
7624 cpl_propertylist_append_double(pl, hkw, value);
7625 cpl_propertylist_set_comment(pl, hkw, hcm);
7626
7627 cpl_free(hkw);
7628 cpl_free(hcm);
7629
7630 return cpl_error_get_code();
7631}
7632
7633static cpl_error_code
7634detmon_lg_set_keyword_from_insert_double(cpl_propertylist* pl,
7635 char* keyword_base,
7636 char* keyword_ins,
7637 char* comment_base,
7638 char* comment_ins,
7639 double value) {
7640 char* hkw = cpl_sprintf(keyword_base, keyword_ins);
7641 char* hcm = cpl_sprintf(comment_base, comment_ins);
7642
7643 cpl_propertylist_append_double(pl, hkw, value);
7644 cpl_propertylist_set_comment(pl, hkw, hcm);
7645
7646 cpl_free(hkw);
7647 cpl_free(hcm);
7648
7649 return cpl_error_get_code();
7650}
7651
7652cpl_error_code
7653detmon_lg_set_tag(cpl_frameset* set, const char** tag_on, const char** tag_off)
7654{
7655 int ntag_old=0;
7656 int ntag_new=0;
7657
7658 ntag_old=cpl_frameset_count_tags(set,DETMON_LG_ON_RAW_OLD);
7659 ntag_new=cpl_frameset_count_tags(set,DETMON_LG_ON_RAW_NEW);
7660 if(ntag_old) {
7661 *tag_on=DETMON_LG_ON_RAW_OLD;
7662 *tag_off=DETMON_LG_OFF_RAW_OLD;
7663 } else if (ntag_new) {
7664 *tag_on=DETMON_LG_ON_RAW_NEW;
7665 *tag_off=DETMON_LG_OFF_RAW_NEW;
7666 } else {
7667 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
7668 "Provide %s and %s (or %s and %s) input frames",
7669 DETMON_LG_ON_RAW_NEW,DETMON_LG_OFF_RAW_NEW,
7670 DETMON_LG_ON_RAW_OLD,DETMON_LG_OFF_RAW_OLD);
7671 }
7672
7673
7674 return cpl_error_get_code();
7675}
7676
7677cpl_error_code
7678detmon_lg_qc_params(cpl_table* linear_table, cpl_propertylist* lint_qclist,
7679 cpl_table* gain_table, cpl_propertylist* gaint_qclist,
7680 cpl_imagelist* coeffs, cpl_propertylist* linc_qclist,
7681 cpl_image* bpm, cpl_propertylist* bpm_qclist,
7682 const char * recipe_name) {
7683
7684 char* qc_contam = NULL ;
7685 char* qc_contam_ref = cpl_sprintf("%s%01d", DETMON_QC_CONTAM, 5);
7686
7687 cpl_msg_debug(cpl_func, "This is where I'll write the QC parameters");
7688
7689 if (linear_table != NULL && lint_qclist != NULL) {
7690 // QC.CONTAM<i>.NORM
7691 if (cpl_propertylist_has(
7692 lint_qclist, qc_contam_ref)) {
7693 for (int i=1; i<5; ++i) {
7694 qc_contam = cpl_sprintf("%s%01d", DETMON_QC_CONTAM, i);
7695 if (cpl_propertylist_has(lint_qclist, qc_contam_ref) &&
7696 cpl_propertylist_has(lint_qclist, qc_contam)) {
7697 cpl_propertylist_append_double(
7698 lint_qclist, cpl_sprintf(DETMON_QC_CONTAMi_NORM, i),
7699 cpl_propertylist_get_double(lint_qclist, qc_contam) /
7700 cpl_propertylist_get_double(lint_qclist, qc_contam_ref));
7701 cpl_propertylist_set_comment(
7702 lint_qclist, cpl_sprintf(DETMON_QC_CONTAMi_NORM, i),
7703 cpl_sprintf(DETMON_QC_CONTAMi_NORM_C, i)
7704 );
7705 }
7706 }
7707 }
7708 }
7709
7710 cpl_free(qc_contam);
7711 cpl_free(qc_contam_ref);
7712 return cpl_error_get_code();
7713}
7714
7715cpl_error_code
7716detmon_lg_qc_params_global_gain(const char * recipe_name, int nsets) {
7717 cpl_msg_debug(cpl_func, "Going to update gain table for recipe %s, nsets=%d",
7718 recipe_name, nsets);
7719
7720 char * fn ;
7721 cpl_error_code err ;
7722 if (nsets == 1) {
7723 fn = cpl_sprintf("%s_gain_table.fits", recipe_name) ;
7724 cpl_msg_debug(cpl_func, "Will be modifying %s", fn) ;
7725 err = detmon_lg_qc_params_global_gain_update(fn, recipe_name);
7726 cpl_free(fn);
7727 } else {
7728 int j;
7729 for (j=0; j<nsets; ++j) {
7730 fn = cpl_sprintf("%s_gain_table_set%02d.fits", recipe_name, j);
7731 cpl_msg_debug(cpl_func, "Will be modifying %s", fn);
7732 err = detmon_lg_qc_params_global_gain_update(fn, recipe_name);
7733 cpl_free(fn);
7734 }
7735 }
7736
7737 return err;
7738}
7739
7740
7741cpl_error_code
7742detmon_lg_qc_params_global_gain_update(const char * fn,
7743 const char * recipe_name) {
7744 cpl_msg_debug(cpl_func, "Now updating %s", fn);
7745
7746 cpl_propertylist* phu = cpl_propertylist_load(fn, 0);
7747 cpl_propertylist** ehus = NULL;
7748 cpl_table** gain_tables = NULL;
7749 cpl_array* gains = NULL;
7750 cpl_array* conads = NULL ;
7751 cpl_frame* fr = cpl_frame_new();
7752
7753 // Count the number of extensions in this file
7754 cpl_frame_set_filename(fr, fn);
7755 int nexts = cpl_frame_get_nextensions(fr);
7756 cpl_msg_debug(cpl_func, "Detected %d nexts", nexts);
7757 if (nexts < 1) {
7758 cpl_msg_warning(cpl_func, "No extensions in %s, so no QC "
7759 "keywords to write", fn);
7760 cpl_msg_warning(cpl_func, "Triggering goto cleanup");
7761 // FIXME Identify correct error(s) to check against
7762 if (1) {
7763 cpl_error_reset();
7764 // Reset the error caused when trying to get nexts
7765 }
7766 goto cleanup;
7767 }
7768 ehus = (cpl_propertylist**)cpl_malloc(nexts * sizeof(cpl_propertylist*));
7769 gain_tables = (cpl_table**)cpl_malloc(nexts * sizeof(cpl_table*));
7770
7771 // Load up
7772 int j;
7773 for (j=1; j <= nexts; j++) {
7774 cpl_msg_debug(cpl_func, "Loading EHU %d", j);
7775 ehus[j-1] = cpl_propertylist_load(fn, j);
7776 gain_tables[j-1] = cpl_table_load(fn, j, 1);
7777 }
7778
7779 // Compute values
7780 cpl_msg_debug(cpl_func, "Populating data arrays");
7781 gains = cpl_array_new(nexts, CPL_TYPE_DOUBLE);
7782 conads = cpl_array_new(nexts, CPL_TYPE_DOUBLE);
7783 for (j=1; j <= nexts; j++) {
7784 cpl_msg_debug(cpl_func, " %d", j);
7785 if (cpl_propertylist_has(ehus[j-1], DETMON_QC_GAIN)) {
7786 cpl_array_set(gains, j-1,
7787 cpl_propertylist_get_double(ehus[j-1],
7788 DETMON_QC_GAIN));
7789 }
7790 if (cpl_propertylist_has(ehus[j-1], DETMON_QC_CONAD)) {
7791 cpl_array_set(conads, j-1,
7792 cpl_propertylist_get_double(ehus[j-1],
7793 DETMON_QC_CONAD));
7794 }
7795 }
7796 cpl_msg_debug(cpl_func, "...populating complete!");
7797 // QC GAIN AVG
7798 cpl_propertylist_append_double(phu, DETMON_QC_GAIN_AVG,
7799 cpl_array_get_mean(gains));
7800 cpl_propertylist_set_comment(phu, DETMON_QC_GAIN_AVG,
7801 DETMON_QC_GAIN_AVG_C);
7802 // QC GAIN RMS
7803 cpl_propertylist_append_double(phu, DETMON_QC_GAIN_RMS,
7804 cpl_array_get_stdev(gains));
7805 cpl_propertylist_set_comment(phu, DETMON_QC_GAIN_RMS,
7806 DETMON_QC_GAIN_RMS_C);
7807
7808 // The remaining kw are for detmon_opt_lg and detmon_ir_lg only
7809 if (strcmp(recipe_name, "detmon_opt_lg_mr") != 0) {
7810
7811 // QC CONAD AVG
7812 cpl_propertylist_append_double(phu, DETMON_QC_CONAD_AVG,
7813 cpl_array_get_mean(conads));
7814 cpl_propertylist_set_comment(phu, DETMON_QC_CONAD_AVG,
7815 DETMON_QC_CONAD_AVG_C);
7816 // QC CONAD RMS
7817 cpl_propertylist_append_double(phu, DETMON_QC_CONAD_RMS,
7818 cpl_array_get_stdev(conads));
7819 cpl_propertylist_set_comment(phu, DETMON_QC_CONAD_RMS,
7820 DETMON_QC_CONAD_RMS_C);
7821 }
7822 cpl_msg_debug(cpl_func, "Calculations complete!");
7823
7824 // Write out
7825 for (j=1; j<=nexts; ++j) {
7826 if (j == 1) {
7827 cpl_table_save(gain_tables[j-1], phu,
7828 ehus[j-1], fn, CPL_IO_CREATE);
7829 } else {
7830 cpl_table_save(gain_tables[j-1], NULL,
7831 ehus[j-1], fn, CPL_IO_EXTEND);
7832 }
7833 cpl_propertylist_delete(ehus[j-1]);
7834 cpl_table_delete(gain_tables[j-1]);
7835 }
7836
7837
7838 // Cleanup
7839 cleanup:
7840
7841 cpl_msg_debug(cpl_func, "Cleaning up...");
7842 cpl_propertylist_delete(phu);
7843 cpl_msg_debug(cpl_func, " PHU gone");
7844 cpl_free(ehus);
7845 cpl_msg_debug(cpl_func, " ehus gone");
7846 cpl_free(gain_tables);
7847 cpl_msg_debug(cpl_func, " gain_tables gone");
7848 cpl_frame_delete(fr);
7849 cpl_msg_debug(cpl_func, " fr gone");
7850 cpl_array_delete(conads);
7851 cpl_msg_debug(cpl_func, " conads gone");
7852 cpl_array_delete(gains);
7853 cpl_msg_debug(cpl_func, " gains gone");
7854 cpl_msg_debug(cpl_func, "...done!");
7855
7856 return cpl_error_get_code();
7857}
7858
7859
7860cpl_error_code
7861detmon_lg_qc_params_global_lin(const char * recipe_name, int nsets) {
7862 cpl_msg_debug(cpl_func, "Going to update linearity table for "
7863 "recipe %s, nsets=%d",
7864 recipe_name, nsets);
7865
7866 char * fn ;
7867 if (nsets == 1) {
7868 fn = cpl_sprintf("%s_linearity_table.fits", recipe_name) ;
7869 cpl_msg_debug(cpl_func, "Will be modifying %s", fn, recipe_name) ;
7870 detmon_lg_qc_params_global_lin_update(fn, recipe_name);
7871 cpl_free(fn);
7872 } else {
7873 int j;
7874 for (j=0; j<nsets; ++j) {
7875 fn = cpl_sprintf("%s_linearity_table_set%02d.fits", recipe_name, j);
7876 cpl_msg_debug(cpl_func, "Will be modifying %s", fn);
7877 detmon_lg_qc_params_global_lin_update(fn, recipe_name);
7878 cpl_free(fn);
7879 }
7880 }
7881
7882 return cpl_error_get_code();
7883}
7884
7885
7886cpl_error_code
7887detmon_lg_qc_params_global_lin_update(const char * fn,
7888 const char * recipe_name) {
7889 cpl_msg_debug(cpl_func, "Now updating %s", fn);
7890
7891 cpl_propertylist* phu = cpl_propertylist_load(fn, 0);
7892 cpl_propertylist** ehus = NULL;
7893 cpl_table** lin_tables = NULL;
7894 cpl_array* gain_err = NULL;
7895 cpl_array* counts_min = NULL;
7896 cpl_array* counts_max = NULL;
7897 cpl_array* lin_eff = NULL;
7898 cpl_array* lin_eff_flux = NULL;
7899 int j, contam;
7900 cpl_array** contams = (cpl_array**)cpl_malloc(5 * sizeof(cpl_array*));
7901 for (contam=0; contam < 5; ++contam) {
7902 contams[contam] = NULL;
7903 }
7904 cpl_frame* fr = cpl_frame_new();
7905 char * coeff_kw = NULL ;
7906 char * coeff_comm = NULL ;
7907
7908 // Count the number of extensions in this file
7909 cpl_frame_set_filename(fr, fn);
7910 int nexts = cpl_frame_get_nextensions(fr);
7911 if (nexts < 1) {
7912 cpl_msg_warning(cpl_func, "No extensions in %s, so no QC "
7913 "keywords to write", fn);
7914 // FIXME Identify correct error(s) to check against
7915 if (1) {
7916 cpl_error_reset();
7917 // Reset the error caused when trying to get nexts
7918 }
7919 goto cleanup;
7920 }
7921 cpl_msg_debug(cpl_func, "Detected %d nexts", nexts);
7922 ehus = (cpl_propertylist**)cpl_malloc(nexts * sizeof(cpl_propertylist*));
7923 lin_tables = (cpl_table**)cpl_malloc(nexts * sizeof(cpl_table*));
7924
7925 // Load up
7926 gain_err = cpl_array_new(nexts, CPL_TYPE_DOUBLE);
7927 counts_min = cpl_array_new(nexts, CPL_TYPE_DOUBLE);
7928 counts_max = cpl_array_new(nexts, CPL_TYPE_DOUBLE);
7929 lin_eff = cpl_array_new(nexts, CPL_TYPE_DOUBLE);
7930 lin_eff_flux = cpl_array_new(nexts, CPL_TYPE_DOUBLE);
7931 for (contam=0; contam < 5; ++contam) {
7932 contams[contam] = cpl_array_new(nexts, CPL_TYPE_DOUBLE);
7933 }
7934 for (j=1; j <= nexts; ++j) {
7935 cpl_msg_debug(cpl_func, "Loading EHU %d", j);
7936 ehus[j-1] = cpl_propertylist_load(fn, j);
7937 lin_tables[j-1] = cpl_table_load(fn, j, 1);
7938
7939 cpl_msg_debug(cpl_func, "Doing non-CONTAM values");
7940
7941 if (cpl_propertylist_has(ehus[j-1], "ESO QC GAIN ERR")) {
7942 cpl_array_set_double(gain_err, j-1,
7943 cpl_propertylist_get_double(
7944 ehus[j-1], "ESO QC GAIN ERR"));
7945 }
7946 if (cpl_propertylist_has(ehus[j-1], DETMON_QC_COUNTS_MIN)) {
7947 cpl_array_set_double(counts_min, j-1,
7948 cpl_propertylist_get_double(
7949 ehus[j-1], DETMON_QC_COUNTS_MIN));
7950 }
7951 if (cpl_propertylist_has(ehus[j-1], DETMON_QC_COUNTS_MAX)) {
7952 cpl_array_set_double(counts_max, j-1,
7953 cpl_propertylist_get_double(
7954 ehus[j-1], DETMON_QC_COUNTS_MAX));
7955 }
7956 if (cpl_propertylist_has(ehus[j-1], DETMON_QC_LIN_EFF)) {
7957 cpl_array_set_double(lin_eff, j-1,
7958 cpl_propertylist_get_double(
7959 ehus[j-1], DETMON_QC_LIN_EFF));
7960 }
7961 if (cpl_propertylist_has(ehus[j-1], DETMON_QC_LIN_EFF_FLUX)) {
7962 cpl_array_set_double(lin_eff_flux, j-1,
7963 cpl_propertylist_get_double(
7964 ehus[j-1], DETMON_QC_LIN_EFF_FLUX));
7965 }
7966
7967 cpl_msg_debug(cpl_func, "Looping through contam values...");
7968 if (strcmp(recipe_name, "detmon_opt_lg") == 0) {
7969 for (contam=0; contam<5 ; ++contam) {
7970 coeff_kw = cpl_sprintf(DETMON_QC_CONTAM "%zd",
7971 contam+1);
7972 if (cpl_propertylist_has(ehus[j-1],
7973 coeff_kw)) {
7974 cpl_array_set_double(contams[contam], j-1,
7975 cpl_propertylist_get_double(
7976 ehus[j-1],
7977 coeff_kw));
7978 }
7979 cpl_free(coeff_kw);
7980 }
7981 }
7982 }
7983
7984 // Compute values
7985 cpl_msg_debug(cpl_func, "Computing & setting global values...");
7986 // QC GAIN ERR AVG
7987 cpl_propertylist_append_double(phu, DETMON_QC_GAIN_ERR_AVG,
7988 cpl_array_get_mean(gain_err));
7989 cpl_propertylist_set_comment(phu, DETMON_QC_GAIN_ERR_AVG,
7990 DETMON_QC_GAIN_ERR_AVG_C);
7991 // QC GAIN ERR RMS
7992 cpl_propertylist_append_double(phu, DETMON_QC_GAIN_ERR_RMS,
7993 cpl_array_get_stdev(gain_err));
7994 cpl_propertylist_set_comment(phu, DETMON_QC_GAIN_ERR_RMS,
7995 DETMON_QC_GAIN_ERR_RMS_C);
7996 // QC COUNTS MIN AVG
7997 cpl_propertylist_append_double(phu, DETMON_QC_COUNTS_MIN_AVG,
7998 cpl_array_get_mean(counts_min));
7999 cpl_propertylist_set_comment(phu, DETMON_QC_COUNTS_MIN_AVG,
8000 DETMON_QC_COUNTS_MIN_AVG_C);
8001 // QC COUNTS MIN RMS
8002 cpl_propertylist_append_double(phu, DETMON_QC_COUNTS_MIN_RMS,
8003 cpl_array_get_stdev(counts_min));
8004 cpl_propertylist_set_comment(phu, DETMON_QC_COUNTS_MIN_RMS,
8005 DETMON_QC_COUNTS_MIN_RMS_C);
8006 // QC COUNTS MAX AVG
8007 cpl_propertylist_append_double(phu, DETMON_QC_COUNTS_MAX_AVG,
8008 cpl_array_get_mean(counts_max));
8009 cpl_propertylist_set_comment(phu, DETMON_QC_COUNTS_MAX_AVG,
8010 DETMON_QC_COUNTS_MAX_AVG_C);
8011 // QC COUNTS MAX RMS
8012 cpl_propertylist_append_double(phu, DETMON_QC_COUNTS_MAX_RMS,
8013 cpl_array_get_stdev(counts_max));
8014 cpl_propertylist_set_comment(phu, DETMON_QC_COUNTS_MAX_RMS,
8015 DETMON_QC_COUNTS_MAX_RMS_C);
8016 // QC LIN EFF AVG
8017 cpl_propertylist_append_double(phu, DETMON_QC_LIN_EFF_AVG,
8018 cpl_array_get_mean(lin_eff));
8019 cpl_propertylist_set_comment(phu, DETMON_QC_LIN_EFF_AVG,
8020 DETMON_QC_LIN_EFF_AVG_C);
8021 // QC LIN EFF RMS
8022 cpl_propertylist_append_double(phu, DETMON_QC_LIN_EFF_RMS,
8023 cpl_array_get_stdev(lin_eff));
8024 cpl_propertylist_set_comment(phu, DETMON_QC_LIN_EFF_RMS,
8025 DETMON_QC_LIN_EFF_RMS_C);
8026 if (strcmp(recipe_name, "detmon_opt_lg") == 0) {
8027 cpl_msg_debug(cpl_func, " Computing additional detmon_opt_lg values...");
8028 // QC LIN EFF FLUX AVG
8029 cpl_propertylist_append_double(phu, DETMON_QC_LIN_EFF_FLUX_AVG,
8030 cpl_array_get_mean(lin_eff_flux));
8031 cpl_propertylist_set_comment(phu, DETMON_QC_LIN_EFF_FLUX_AVG,
8032 DETMON_QC_LIN_EFF_FLUX_AVG_C);
8033 // QC LIN EFF FLUX RMS
8034 cpl_propertylist_append_double(phu, DETMON_QC_LIN_EFF_FLUX_RMS,
8035 cpl_array_get_stdev(lin_eff_flux));
8036 cpl_propertylist_set_comment(phu, DETMON_QC_LIN_EFF_FLUX_RMS,
8037 DETMON_QC_LIN_EFF_FLUX_RMS_C);
8038
8039 // QC CONTAMi AVG & RMS
8040 for (contam=0 ; contam < 5; ++contam) {
8041 coeff_kw = cpl_sprintf(DETMON_QC_CONTAMi_AVG,
8042 contam+1);
8043 coeff_comm = cpl_sprintf(DETMON_QC_CONTAMi_AVG_C,
8044 contam+1);
8045 cpl_propertylist_append_double(phu,
8046 coeff_kw,
8047 cpl_array_get_mean(contams[contam]));
8048 cpl_propertylist_set_comment(phu,
8049 coeff_kw,
8050 coeff_comm);
8051 cpl_free(coeff_kw);
8052 cpl_free(coeff_comm);
8053
8054 coeff_kw = cpl_sprintf(DETMON_QC_CONTAMi_RMS,
8055 contam+1);
8056 coeff_comm = cpl_sprintf(DETMON_QC_CONTAMi_RMS_C,
8057 contam+1);
8058 cpl_propertylist_append_double(phu,
8059 coeff_kw,
8060 cpl_array_get_stdev(
8061 contams[contam]));
8062 cpl_propertylist_set_comment(phu,
8063 coeff_kw,
8064 coeff_comm);
8065 cpl_free(coeff_kw);
8066 cpl_free(coeff_comm);
8067
8068 }
8069 }
8070
8071 // Write out
8072 cpl_propertylist_save(phu, fn, CPL_IO_CREATE);
8073 for (j=1; j<=nexts; ++j) {
8074 if (j == 1) {
8075 cpl_table_save(lin_tables[j-1], phu,
8076 ehus[j-1], fn, CPL_IO_CREATE);
8077 } else {
8078 cpl_table_save(lin_tables[j-1], NULL,
8079 ehus[j-1], fn, CPL_IO_EXTEND);
8080 }
8081 cpl_propertylist_delete(ehus[j-1]);
8082 cpl_table_delete(lin_tables[j-1]);
8083 }
8084
8085 // Cleanup
8086 cleanup:
8087
8088 cpl_msg_debug(cpl_func, "Going into cleanup...");
8089 for (contam=0 ; contam<5 ; ++contam) {
8090 cpl_array_delete(contams[contam]);
8091 cpl_msg_debug(cpl_func, " contams array %d gone", contam);
8092 }
8093 cpl_msg_debug(cpl_func, " contams arrays gone");
8094 cpl_free(ehus);
8095 cpl_propertylist_delete(phu);
8096 cpl_msg_debug(cpl_func, " ehus gone");
8097 cpl_free(lin_tables);
8098 cpl_msg_debug(cpl_func, " lin_tables gone");
8099 cpl_free(contams);
8100 cpl_msg_debug(cpl_func, " contams gone");
8101 cpl_array_delete(gain_err);
8102 cpl_msg_debug(cpl_func, " gain_err gone");
8103 cpl_array_delete(counts_min);
8104 cpl_msg_debug(cpl_func, " counts_min gone");
8105 cpl_array_delete(counts_max);
8106 cpl_msg_debug(cpl_func, " counts_max gone");
8107 cpl_array_delete(lin_eff);
8108 cpl_msg_debug(cpl_func, " lin_eff gone");
8109 cpl_array_delete(lin_eff_flux);
8110 cpl_msg_debug(cpl_func, " lin_eff_flux gone");
8111 cpl_frame_delete(fr);
8112 cpl_msg_debug(cpl_func, " fr gone");
8113 cpl_msg_debug(cpl_func, "...done!");
8114
8115 return cpl_error_get_code();
8116}
8117
8118cpl_error_code
8119detmon_lg_qc_params_global_bpm(const char * recipe_name, int nsets) {
8120 cpl_msg_debug(cpl_func, "Going to update BPM image for "
8121 "recipe %s, nsets=%d",
8122 recipe_name, nsets);
8123
8124 char * fn ;
8125 cpl_error_code err;
8126 if (nsets == 1) {
8127 fn = cpl_sprintf("%s_bpm.fits", recipe_name) ;
8128 cpl_msg_debug(cpl_func, "Will be modifying %s", fn) ;
8129 err = detmon_lg_qc_params_global_bpm_update(fn, recipe_name);
8130 cpl_free(fn);
8131 } else {
8132 int j;
8133 for (j=0; j<nsets; ++j) {
8134 fn = cpl_sprintf("%s_bpm_set%02d.fits", recipe_name, j);
8135 cpl_msg_debug(cpl_func, "Will be modifying %s", fn);
8136 err = detmon_lg_qc_params_global_bpm_update(fn, recipe_name);
8137 cpl_free(fn);
8138 }
8139 }
8140
8141 return err;
8142}
8143
8144cpl_error_code
8145detmon_lg_qc_params_global_bpm_update(const char * fn,
8146 const char * recipe_name) {
8147 cpl_msg_debug(cpl_func, "Now updating %s", fn);
8148
8149 cpl_propertylist* phu = cpl_propertylist_load(fn, 0);
8150 cpl_propertylist** ehus = NULL ;
8151 cpl_image** bpm_imgs = NULL ;
8152 cpl_array* num_bpm = NULL;
8153 cpl_frame* fr = cpl_frame_new();
8154
8155 // Both recipes use this function the same way,
8156 // so no need to test recipe name
8157
8158 // No-op for the MR recipes
8159 if ((strcmp(recipe_name, "detmon_opt_lg_mr") == 0 ) ||
8160 (strcmp(recipe_name, "detmon_ir_lg_mr")) == 0) {
8161 goto cleanup ;
8162 }
8163
8164 // Count the number of extensions in this file
8165 cpl_frame_set_filename(fr, fn);
8166 int nexts = cpl_frame_get_nextensions(fr);
8167 if (nexts < 1) {
8168 cpl_msg_warning(cpl_func, "No extensions in %s, so no QC "
8169 "keywords to write", fn);
8170 // FIXME Identify correct error(s) to check against
8171 if (1) {
8172 cpl_error_reset();
8173 // Reset the error caused when trying to get nexts
8174 }
8175 goto cleanup;
8176 }
8177 cpl_msg_debug(cpl_func, "Detected %d nexts", nexts);
8178 ehus = (cpl_propertylist**)cpl_malloc(nexts * sizeof(cpl_propertylist*));
8179 bpm_imgs = (cpl_image**)cpl_malloc(nexts * sizeof(cpl_image*));
8180
8181 // Load up
8182 int j ;
8183 num_bpm = cpl_array_new(nexts, CPL_TYPE_INT);
8184
8185 for (j=1; j<=nexts; ++j) {
8186 cpl_msg_debug(cpl_func, "Loading ext %d", j);
8187 ehus[j-1] = cpl_propertylist_load(fn, j);
8188 bpm_imgs[j-1] = cpl_image_load(fn, CPL_BPP_IEEE_FLOAT, 0, j);
8189 if (cpl_propertylist_has(ehus[j-1], DETMON_QC_NUM_BPM)) {
8190 cpl_array_set_int(num_bpm, j-1,
8191 cpl_propertylist_get_int(ehus[j-1],
8192 DETMON_QC_NUM_BPM));
8193 }
8194 }
8195
8196 // Compute values
8197 // QC NUM BPM AVG
8198 cpl_propertylist_append_double(phu, DETMON_QC_NUM_BPM_AVG,
8199 cpl_array_get_mean(num_bpm));
8200 cpl_propertylist_set_comment(phu, DETMON_QC_NUM_BPM_AVG,
8201 DETMON_QC_NUM_BPM_AVG_C);
8202
8203 // Write out
8204 cpl_propertylist_save(phu, fn, CPL_IO_CREATE);
8205 for (j=1; j<=nexts; ++j) {
8206 cpl_image_save(bpm_imgs[j-1], fn, CPL_BPP_IEEE_FLOAT, ehus[j-1],
8207 CPL_IO_EXTEND);
8208 cpl_propertylist_delete(ehus[j-1]);
8209 cpl_image_delete(bpm_imgs[j-1]);
8210 }
8211
8212 // Cleanup
8213 cleanup:
8214
8215 cpl_msg_debug(cpl_func, "Doing cleanup");
8216 cpl_free(ehus);
8217 cpl_propertylist_delete(phu);
8218 cpl_msg_debug(cpl_func, " ehus gone");
8219 cpl_free(bpm_imgs);
8220 cpl_msg_debug(cpl_func, " bpm_imgs gone");
8221 cpl_array_delete(num_bpm);
8222 cpl_msg_debug(cpl_func, " num_bpm gone");
8223 cpl_frame_delete(fr);
8224 cpl_msg_debug(cpl_func, " fr gone");
8225 cpl_msg_debug(cpl_func, "...done!");
8226
8227 return cpl_error_get_code();
8228}
8229
8230
8231cpl_error_code
8232detmon_lg_qc_params_global_coeffs(const char * recipe_name, int nsets) {
8233 cpl_msg_debug(cpl_func, "Going to update coeffs image for "
8234 "recipe %s, nsets=%d",
8235 recipe_name, nsets);
8236
8237 cpl_error_code err = CPL_ERROR_NONE;
8238 char * fn ;
8239 if (nsets == 1) {
8240 fn = cpl_sprintf("%s_coeffs_cube.fits", recipe_name);
8241 cpl_msg_debug(cpl_func, "Will be modifying %s", fn) ;
8242 err = detmon_lg_qc_params_global_coeffs_update(fn, recipe_name);
8243 cpl_free(fn);
8244 } else {
8245 int j;
8246 for (j=0; j<nsets; ++j) {
8247 fn = cpl_sprintf("%s_coeffs_cube_set%02d.fits",
8248 recipe_name, j);
8249 cpl_msg_debug(cpl_func, "Will be modifying %s", fn);
8250 err = detmon_lg_qc_params_global_coeffs_update(fn, recipe_name);
8251 cpl_free(fn);
8252 }
8253 }
8254
8255 return err;
8256}
8257
8258cpl_error_code
8259detmon_lg_qc_params_global_coeffs_update(const char * fn,
8260 const char * recipe_name) {
8261 cpl_msg_debug(cpl_func, "Now updating %s", fn);
8262
8263 cpl_propertylist* phu = cpl_propertylist_load(fn, 0);
8264 cpl_propertylist** ehus = NULL;
8265 cpl_imagelist** coeff_cubes = NULL;
8266 cpl_frame* fr = NULL;
8267 cpl_array* lin_coeff = NULL;
8268 cpl_array* lin_coeff_err = NULL;
8269 cpl_array* errfit = NULL;
8270 char* coeff_kw = NULL ;
8271 char* coeff_kw_err = NULL ;
8272 char* coeff_str = NULL ;
8273
8274 // Count the number of extensions in this file
8275 fr = cpl_frame_new();
8276 cpl_frame_set_filename(fr, fn);
8277 int nexts = cpl_frame_get_nextensions(fr);
8278 if (nexts < 1) {
8279 cpl_msg_warning(cpl_func, "No extensions in %s, so no QC "
8280 "keywords to write", fn);
8281 // FIXME Identify correct error(s) to check against
8282 if (1) {
8283 cpl_error_reset();
8284 // Reset the error caused when trying to get nexts
8285 }
8286 goto cleanup;
8287 }
8288 // No-op for the MR recipes
8289 if ((strcmp(recipe_name, "detmon_opt_lg_mr") == 0 ) ||
8290 (strcmp(recipe_name, "detmon_ir_lg_mr")) == 0) {
8291 cpl_msg_debug(cpl_func, "Skipping %s for recipe %s",
8292 cpl_func, recipe_name);
8293// getchar();
8294 goto cleanup ;
8295 }
8296 cpl_msg_debug(cpl_func, "Detected %d nexts", nexts);
8297 ehus = (cpl_propertylist**)cpl_malloc(nexts * sizeof(cpl_propertylist*));
8298 coeff_cubes = (cpl_imagelist**)cpl_malloc(nexts * sizeof(cpl_imagelist*));
8299 cpl_msg_debug(cpl_func, "Malloc'd data structures for eventual re-write");
8300
8301 // Load up (headers only)
8302 int j, coeff, coeff_max ;
8303
8304 for (j=1; j<=nexts; ++j) {
8305 ehus[j-1] = cpl_propertylist_load(fn, j);
8306 }
8307 cpl_msg_debug(__func__, "Loaded extension headers");
8308
8309 // Compute
8310 cpl_msg_debug(__func__, "Creating lin_coeff and errfit arrays...");
8311 lin_coeff = cpl_array_new(nexts, CPL_TYPE_DOUBLE);
8312 lin_coeff_err = cpl_array_new(nexts, CPL_TYPE_DOUBLE);
8313 errfit = cpl_array_new(nexts, CPL_TYPE_DOUBLE);
8314 cpl_msg_debug(__func__, "...done!");
8315
8316 if (strcmp(recipe_name, "detmon_ir_lg") == 0) {
8317 coeff_max = 0 ;
8318
8319 cpl_msg_debug(cpl_func, "Populating errfit arrays");
8320 for (j=1; j<=nexts; ++j) {
8321 if (cpl_propertylist_has(ehus[j-1], DETMON_QC_ERRFIT)) {
8322 cpl_array_set_double(
8323 errfit, j-1,
8324 cpl_propertylist_get_double(ehus[j-1],
8325 DETMON_QC_ERRFIT));
8326 }
8327 }
8328
8329 cpl_msg_debug(cpl_func, "Setting keywords with new funcs");
8330 detmon_lg_set_keyword_from_base_double(phu,
8331 DETMON_QC_ERRFIT, "AVG",
8332 DETMON_QC_ERRFIT,
8333 "AVG over exts.",
8334 cpl_array_get_mean(errfit));
8335
8336 detmon_lg_set_keyword_from_base_double(phu,
8337 DETMON_QC_ERRFIT, "RMS",
8338 DETMON_QC_ERRFIT,
8339 "RMS over exts.",
8340 cpl_array_get_stdev(errfit));
8341
8342 } else {
8343 coeff_max = 4 ;
8344 }
8345
8346 for (coeff = 0 ; coeff < coeff_max + 1 ; ++coeff) {
8347 cpl_msg_debug(cpl_func, "Forming coeff keyword %d", coeff);
8348 coeff_kw = cpl_sprintf("ESO QC LIN COEF%d", coeff);
8349 coeff_kw_err = cpl_sprintf("ESO QC LIN COEF%d ERR",
8350 coeff);
8351 coeff_str = cpl_sprintf("%d", coeff);
8352 // Re-fill the input arrays from the headers
8353
8354 cpl_msg_debug(cpl_func, "Reading in the coeff values");
8355 for (j=1; j<=nexts; ++j) {
8356 // FIXME Should not be hardcoded
8357 if (cpl_propertylist_has(ehus[j-1],
8358 coeff_kw)) {
8359 cpl_array_set_double(
8360 lin_coeff,
8361 j-1,
8362 cpl_propertylist_get_double(
8363 ehus[j-1],
8364 coeff_kw
8365 ));
8366 cpl_msg_debug(cpl_func, "Added value %f to lin_coeff in pos %d",
8367 cpl_propertylist_get_double(
8368 ehus[j-1],
8369 coeff_kw
8370 ), j-1);
8371 }
8372 if (cpl_propertylist_has(ehus[j-1],
8373 coeff_kw_err)) {
8374 cpl_array_set_double(
8375 lin_coeff_err, j-1,
8376 cpl_propertylist_get_double(
8377 ehus[j-1],
8378 coeff_kw_err));
8379 }
8380
8381 cpl_msg_debug(__func__, "Insertions complete! (%d)", coeff);
8382
8383 }
8384
8385 // Write back the relevant header kws
8386 cpl_msg_debug(cpl_func, "Writing back header keywords for %d", coeff);
8387 // ESO QC COEFF<i> AVG
8388 if (cpl_array_count_invalid(lin_coeff) < (cpl_size)nexts) {
8389 detmon_lg_set_keyword_from_insert_double(
8390 phu,
8391 DETMON_QC_LIN_COEFF_AVG, coeff_str,
8392 DETMON_QC_LIN_COEFF_AVG_C, coeff_str,
8393 cpl_array_get_mean(lin_coeff)
8394 );
8395
8396 // ESO QC COEFF<i> RMS
8397 detmon_lg_set_keyword_from_insert_double(
8398 phu,
8399 DETMON_QC_LIN_COEFF_RMS, coeff_str,
8400 DETMON_QC_LIN_COEFF_RMS_C, coeff_str,
8401 cpl_array_get_stdev(lin_coeff)
8402 );
8403 }
8404
8405 if (cpl_array_count_invalid(lin_coeff_err) < (cpl_size)nexts) {
8406 // ESO QC COEFF<i> ERR AVG
8407 detmon_lg_set_keyword_from_insert_double(
8408 phu,
8409 DETMON_QC_LIN_COEFF_ERR_AVG, coeff_str,
8410 DETMON_QC_LIN_COEFF_ERR_AVG_C, coeff_str,
8411 cpl_array_get_mean(lin_coeff_err)
8412 );
8413
8414 // ESO QC COEFF<i> ERR RMS
8415 detmon_lg_set_keyword_from_insert_double(
8416 phu,
8417 DETMON_QC_LIN_COEFF_ERR_RMS, coeff_str,
8418 DETMON_QC_LIN_COEFF_ERR_RMS_C, coeff_str,
8419 cpl_array_get_stdev(lin_coeff_err)
8420 );
8421 }
8422
8423 cpl_msg_debug(__func__, "Data write complete! (%d)", coeff);
8424
8425 // Blank the input arrays
8426 cpl_array_fill_window_invalid(lin_coeff, 0, nexts);
8427 cpl_array_fill_window_invalid(lin_coeff_err, 0, nexts);
8428 cpl_msg_debug(__func__, "Arrays reset! (%d)", coeff);
8429
8430
8431 cpl_msg_debug(cpl_func, "Purging the coeff keywords");
8432 cpl_free(coeff_kw);
8433 cpl_free(coeff_kw_err);
8434 cpl_free(coeff_str);
8435 coeff_kw = NULL ;
8436 coeff_kw_err = NULL ;
8437 coeff_str = NULL ;
8438
8439 }
8440
8441 // Write out
8442 // Load up data (wait til here to save on memory)
8443 for (j=1; j<=nexts; ++j) {
8444 coeff_cubes[j-1] = cpl_imagelist_load(fn, CPL_BPP_IEEE_FLOAT, j);
8445 }
8446 cpl_propertylist_save(phu, fn, CPL_IO_CREATE);
8447 for (j=1; j<=nexts; ++j) {
8448 cpl_imagelist_save(coeff_cubes[j-1], fn, CPL_BPP_IEEE_FLOAT, ehus[j-1],
8449 CPL_IO_EXTEND);
8450// Memory improvement - remove them here
8451 cpl_propertylist_delete(ehus[j-1]);
8452 cpl_imagelist_delete(coeff_cubes[j-1]);
8453 }
8454 cpl_msg_debug(__func__, "Removed all file data in memory");
8455
8456 cleanup:
8457 // Cleanup
8458 cpl_msg_debug(cpl_func, "Doing cleanup...");
8459 cpl_free(ehus);
8460 cpl_msg_debug(cpl_func, " ehus gone");
8461 cpl_propertylist_delete(phu);
8462 cpl_msg_debug(cpl_func, " phus gone");
8463 cpl_free(coeff_cubes);
8464 cpl_msg_debug(cpl_func, " coeff_cubes gone");
8465 cpl_frame_delete(fr);
8466 cpl_msg_debug(cpl_func, " fr gone");
8467 cpl_array_delete(lin_coeff);
8468 cpl_msg_debug(cpl_func, " lin_coeff gone");
8469 cpl_array_delete(lin_coeff_err);
8470 cpl_msg_debug(cpl_func, " lin_coeff_err gone");
8471 cpl_array_delete(errfit);
8472 cpl_msg_debug(cpl_func, " errfit gone");
8473 cpl_msg_debug(cpl_func, "...done!");
8474 return cpl_error_get_code();
8475}
8476
8477cpl_error_code
8478detmon_lg_qc_set_kw_from_table_column(cpl_table* table,
8479 const char * column,
8480 const char * op,
8481 cpl_propertylist* header,
8482 const char * kw,
8483 const char * kw_comment) {
8484 double value ;
8485 if (strcmp(op, "mean") == 0) {
8486 value = cpl_table_get_column_mean(table, column);
8487 } else if (strcmp(op, "stdev") == 0) {
8488 value = cpl_table_get_column_stdev(table, column);
8489 } else {
8490 cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
8491 return cpl_error_get_code();
8492 }
8493
8494 cpl_propertylist_append_double(header, kw, value);
8495 if (kw_comment != NULL) {
8496 cpl_propertylist_set_comment(header, kw, kw_comment);
8497 }
8498 return cpl_error_get_code();
8499}
8500