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