IIINSTRUMENT Pipeline Reference Manual  1.3.12
detmon/detmon_ronbias.c
1 /* $Id: detmon.c,v 1.11 2013-07-19 12:00:24 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  * $Author: jtaylor $
23  * $Date: 2013-07-19 12:00:24 $
24  * $Revision: 1.11 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 /*---------------------------------------------------------------------------
33  Includes
34  ---------------------------------------------------------------------------*/
35 
36 #include "detmon_ronbias.h"
37 #include "detmon.h"
38 
39 #include "irplib_ksigma_clip.h"
40 #include "irplib_hist.h"
41 #include "irplib_utils.h"
42 
43 #include <math.h>
44 #include <string.h>
45 #include <assert.h>
46 #include <float.h>
47 
49 /*--------------------------------------------------------------------------*/
50 
51 /*
52  * @defgroup detmon Detector monitoring functions
53  */
54 
55 /*--------------------------------------------------------------------------*/
56 
57 /*---------------------------------------------------------------------------
58  Defines
59  ---------------------------------------------------------------------------*/
60 
61 /* Computes the square of an euclidean distance bet. 2 points */
62 #define pdist(x1,y1,x2,y2) (((x1-x2)*(x1-x2))+((y1-y2)*(y1-y2)))
63 
64 #define cpl_drand() ((double)rand()/(double)RAND_MAX)
65 
66 enum pixeltypes
67 {
68  HOT = 0,
69  DEAD = 1,
70  NOISY = 2
71 };
72 
73 enum stackingtypes
74 {
75  MINMAX = 0,
76  MEAN = 1,
77  MEDIAN = 2,
78  KSIGMA = 3
79 };
80 
81 enum readouts
82 {
83  HORIZONTAL = 1,
84  VERTICAL = 2
85 };
86 
87 
88 static struct
89 {
90  /* Inputs */
91  const char *method;
92  const char *pmethod;
93  irplib_ronbias_method method_bitmask;
94  int prescan_llx;
95  int prescan_lly;
96  int prescan_urx;
97  int prescan_ury;
98  int overscan_llx;
99  int overscan_lly;
100  int overscan_urx;
101  int overscan_ury;
102  cpl_size preoverscan_degree;
103  int random_nsamples;
104  int random_sizex;
105  int random_sizey;
106  int criteria;
107  int ref_llx;
108  int ref_lly;
109  int ref_urx;
110  int ref_ury;
111  const char *stacking_method;
112  int stacking_ks_low;
113  int stacking_ks_high;
114  int stacking_ks_iter;
115  int master_shift_x;
116  int master_shift_y;
117  int ron_llx;
118  int ron_lly;
119  int ron_urx;
120  int ron_ury;
121  int exts;
122  int nb_extensions;
123 } detmon_ronbias_config;
124 
125 #define NIR TRUE
126 #define OPT FALSE
127 
128 /*---------------------------------------------------------------------------
129  Private function prototypes
130  ---------------------------------------------------------------------------*/
131 
132 /* Functions for RON/Bias recipe, detmon_ronbias() */
133 
134 static cpl_error_code
135 detmon_ronbias_retrieve_parlist(const char *,
136  const char *,
137  const cpl_parameterlist *,
138  cpl_boolean);
139 
140 static cpl_error_code
141 detmon_ronbias_random(const cpl_imagelist *,
142  const cpl_image *, cpl_propertylist *);
143 
144 static cpl_error_code
145 detmon_ronbias_histo(const cpl_imagelist *,
146  const cpl_image *, cpl_propertylist *);
147 
148 static cpl_error_code
149 detmon_compute_bias_ron_and_stats_on_preoverscan(const cpl_imagelist *, /*const cpl_image *,*/
150  cpl_propertylist *, cpl_image **);
151 
152 static cpl_error_code
153 detmon_compute_bias_stats_and_ron_in_region(const cpl_imagelist *,
154  const cpl_image *, cpl_propertylist *);
155 
156 static cpl_image *
157 detmon_ronbias_master(const cpl_imagelist *,
158  cpl_mask **, cpl_mask **, cpl_mask **,
159  cpl_propertylist *);
160 
161 static cpl_error_code
162 detmon_ronbias_save(const cpl_parameterlist *,
163  cpl_frameset *,
164  const char *,
165  const char *,
166  const char *,
167  const cpl_propertylist *,
168  const cpl_propertylist *,
169  const cpl_propertylist *,
170  const cpl_propertylist *,
171  const cpl_propertylist *,
172  const cpl_propertylist *,
173  const cpl_propertylist *,
174  const char *,
175  const cpl_image *,
176  const cpl_image *,
177  const cpl_mask *,
178  const cpl_mask *,
179  const cpl_mask *,
180  cpl_propertylist *,
181  const int,
182  const int,
183  cpl_frameset *,
184  int);
185 
186 static int
187 detmon_ronbias_dfs_set_groups(cpl_frameset *, const char *);
188 
189 static cpl_image *
190 detmon_build_synthetic_from_pre_overscan(const cpl_image * prescan,
191  const cpl_image * overscan)
192  CPL_ATTR_ALLOC;
193 
194 static cpl_error_code
195 detmon_ronbias_dutycycl(const cpl_frameset *, cpl_propertylist *);
196 
197 
198 
199 /* The following 2 functions are duplicated from cpl_det */
200 
201 
202 
203 static cpl_bivector *
204 irplib_bivector_gen_rect_poisson(const int *r,
205  const int np,
206  const int homog);
207 
208 /* End of duplicated code */
209 
210 
211 cpl_error_code
212 detmon_ronbias_check_defaults(const cpl_frameset *, const int whichext);
213 
214 
215 /* RONBIAS FILLING PARLIST */
216 
217 
218 
219 /*---------------------------------------------------------------------------*/
220 
221 /*
222  * @brief Fill input parameters with default values
223  * @param parlist parameters list
224  * @param recipe_name recipe name
225  * @param pipeline_name pipeline name
226 
227  * @return CPL_ERROR_NONE on success.
228  */
229 
230 /*---------------------------------------------------------------------------*/
231 
232 cpl_error_code
233 detmon_ronbias_fill_parlist_default(cpl_parameterlist * parlist,
234  const char *recipe_name,
235  const char *pipeline_name)
236 {
237  const cpl_error_code error =
238  detmon_ronbias_fill_parlist(parlist, recipe_name, pipeline_name,
239  "ALL", /* --method */
240  "NORM",/* --pmethod */
241  1, /* --preoverscan_degree */
242  -1, /* --random_nsamples */
243  -1, /* --random_sizex */
244  -1, /* --random_sizey */
245  0, /* --criteria */
246  -1, /* --ref_llx */
247  -1, /* --ref_lly */
248  -1, /* --ref_urx */
249  -1, /* --ref_ury */
250  "MEAN",/* --stacking_method */
251  3, /* --stacking_ks_low */
252  3, /* --stacking_ks_high */
253  5, /* --stacking_ks_iter */
254  0, /* --master_shift_x */
255  0, /* --master_shift_y */
256  -1, /* --ron_llx */
257  -1, /* --ron_lly */
258  -1, /* --ron_urx */
259  -1, /* --ron_ury */
260  0, /* --exts */
261  OPT);
262  cpl_ensure_code(!error, error);
263 
264  return cpl_error_get_code();
265 }
266 
267 
268 
269 /*---------------------------------------------------------------------------*/
270 
271 /*
272  * @brief Fill input parameters with default values
273  * @param parlist parameters list
274  * @param recipe_name recipe name
275  * @param pipeline_name pipeline name
276  * @param method adopted method
277  * @param pmethod adopted pre-method
278  * @param preoverscan_degree degree used ti fit pre-overscan regions
279  * @param random_nsamples number of samples used for random computation
280  * @param random_sizex x size of rectangle area for random computation
281  * @param random_sizey x size of rectangle area for random computation
282  * @param criteria
283  * @param ref_llx reference region lower left x
284  * @param ref_lly reference region lower left y
285  * @param ref_urx reference region upper right x
286  * @param ref_ury reference region upper right y
287  * @param stacking_method frame stacking method
288  * @param stacking_ks_low kappa value to kappa sigma low intensity pixels
289  * @param stacking_ks_high kappa value to kappa sigma high intensity pixels
290  * @param stacking_ks_iter kappa value to kappa sigma number of iterations
291  * @param master_shift_x x shift value applied to master
292  * @param master_shift_y y shift value applied to master
293  * @param ron_llx reference region lower left x to compute RON
294  * @param ron_lly reference region lower left y to compute RON
295  * @param ron_urx reference region upper right x to compute RON
296  * @param ron_ury reference region upper right y to compute RON
297  * @param exts image extension to be reduced
298  * @param opt_nir switch to specify if in input are OPT or NIR data
299 
300  * @return CPL_ERROR_NONE on success.
301  */
302 
303 /*---------------------------------------------------------------------------*/
304 
305 cpl_error_code
306 detmon_ronbias_fill_parlist(cpl_parameterlist * parlist,
307  const char *recipe_name,
308  const char *pipeline_name,
309  const char * method,
310  const char * pmethod,
311  const int preoverscan_degree,
312  const int random_nsamples,
313  const int random_sizex,
314  const int random_sizey,
315  const int criteria,
316  const int ref_llx,
317  const int ref_lly,
318  const int ref_urx,
319  const int ref_ury,
320  const char * stacking_method,
321  const int stacking_ks_low,
322  const int stacking_ks_high,
323  const int stacking_ks_iter,
324  const int master_shift_x,
325  const int master_shift_y,
326  const int ron_llx,
327  const int ron_lly,
328  const int ron_urx,
329  const int ron_ury,
330  const int exts,
331  cpl_boolean opt_nir)
332 {
333 
334  const char * meth_desc_opt =
335  "Method to be used when computing bias. Methods appliable: "
336  "<RANDOM | HISTO | PREOVERSCAN | REGION | ALL>. By default ALL "
337  "methods are applied. More than a method can be chosen; in that "
338  "case selected methods must be separated by a single space and put "
339  "together between inverted commas (ex. --method=\"HISTO REGION\")."
340  "\n RANDOM: Bias is computed as the mean value on a given number "
341  "(--random.nsamples) of boxes (dimensions --random.sizex and "
342  "--random.sizey) randomly taken accross the detector.\n HISTO: "
343  "An histogram of the pixels of the image is built.\n PREOVERSCAN: "
344  "Mean, median and RMS values computed and designated areas. \n "
345  "REGION: Mean, median and RMS values on reference region.";
346 
347  const char * meth_desc_nir =
348  "Method to be used when computing bias. Methods appliable: "
349  "<RANDOM | HISTO | REGION | ALL>. By default ALL "
350  "methods are applied. More than a method can be chosen; in that "
351  "case selected methods must be separated by a single space and put "
352  "together between inverted commas (ex. --method=\"HISTO REGION\")."
353  "\n RANDOM: Bias is computed as the mean value on a given number "
354  "(--random.nsamples) of boxes (dimensions --random.sizex and "
355  "--random.sizey) randomly taken accross the detector.\n HISTO: "
356  "An histogram of the pixels of the image is built.\n "
357  "REGION: Mean, median and RMS values on reference region.";
358 
359  const char * method_desc = opt_nir == OPT ? meth_desc_opt : meth_desc_nir;
360 
361  const cpl_error_code error =
362  detmon_fill_parlist(parlist, recipe_name, pipeline_name, 22,
363  "method",
364  method_desc,
365  "CPL_TYPE_STRING", method,
366 
367  "pmethod",
368  "Pre-method for RANDOM, HISTO and REGION."
369  "Difference raw frames or not",
370  "CPL_TYPE_STRING", pmethod,
371 
372  "preoverscan.degree",
373  "Degree used for pre-overscan method",
374  "CPL_TYPE_INT", preoverscan_degree,
375 
376  "random.nsamples",
377  "Number of samples",
378  "CPL_TYPE_INT", random_nsamples,
379 
380  "random.sizex",
381  "X size of the boxes",
382  "CPL_TYPE_INT", random_sizex,
383 
384  "random.sizey",
385  "Y size of the boxes",
386  "CPL_TYPE_INT", random_sizey,
387 
388  "criteria",
389  "Criteria",
390  "CPL_TYPE_INT", criteria,
391 
392  "ref.llx",
393  "x coordinate of the lower-left point "
394  "of the reference region of the frame",
395  "CPL_TYPE_INT", ref_llx,
396 
397  "ref.lly",
398  "y coordinate of the lower-left point "
399  "of the reference region of the frame",
400  "CPL_TYPE_INT", ref_lly,
401 
402  "ref.urx",
403  "x coordinate of the upper-right point "
404  "of the reference region of the frame",
405  "CPL_TYPE_INT", ref_urx,
406 
407  "ref.ury",
408  "y coordinate of the upper-right point "
409  "of the reference region of the frame",
410  "CPL_TYPE_INT", ref_ury,
411 
412  "stacking.method",
413  "Method to be used when stacking the master. Posible values < MINMAX | MEAN | MEDIAN | KSIGMA >",
414  "CPL_TYPE_STRING", stacking_method,
415 
416  "stacking.ks.low",
417  "Low threshold for kappa-sigma clipping",
418  "CPL_TYPE_INT", stacking_ks_low,
419 
420  "stacking.ks.high",
421  "High threshold for kappa-sigma clipping",
422  "CPL_TYPE_INT", stacking_ks_high,
423 
424  "stacking.ks.iter",
425  "Nb of iterations for kappa-sigma clipping",
426  "CPL_TYPE_INT", stacking_ks_iter,
427 
428  "master.shift.x",
429  "Master shift X",
430  "CPL_TYPE_INT", master_shift_x,
431 
432  "master.shift.y",
433  "Master shift Y",
434  "CPL_TYPE_INT", master_shift_y,
435 
436  "ron.llx",
437  "x coordinate of the lower-left point "
438  "of the RON frame",
439  "CPL_TYPE_INT", ron_llx,
440 
441  "ron.lly",
442  "y coordinate of the lower-left point "
443  "of the RON frame",
444  "CPL_TYPE_INT", ron_lly,
445 
446  "ron.urx",
447  "x coordinate of the upper-right point "
448  "of the RON frame",
449  "CPL_TYPE_INT", ron_urx,
450 
451  "ron.ury",
452  "y coordinate of the upper-right point "
453  "of the RON frame", "CPL_TYPE_INT", ron_ury,
454 
455  "exts",
456  "Activate the multi-exts option",
457  "CPL_TYPE_INT", exts);
458 
459 
460  cpl_ensure_code(!error, error);
461 
462  return cpl_error_get_code();
463 }
464 
465 
466 
467 #define DETMON_MAX_PARAM 19
468 
469 /*---------------------------------------------------------------------------*/
470 
471 /*
472  * @brief Retrieve input parameters
473  * @param pipeline_name Input image
474  * @param recipe_name Input image
475  * @param parlist Shift to apply on the x-axis
476  * @param opt_nir switch to specify if in input are OPT or NIR data
477  * @return CPL_ERROR_NONE on success.
478  */
479 
480 /*---------------------------------------------------------------------------*/
481 static cpl_error_code
482 detmon_ronbias_retrieve_parlist(const char *pipeline_name,
483  const char *recipe_name,
484  const cpl_parameterlist * parlist,
485  cpl_boolean opt_nir)
486 {
487  char *par_name;
488  const cpl_parameter *par;
489 
490  char m1[DETMON_MAX_PARAM+1] = "";
491  char m2[DETMON_MAX_PARAM+1] = "";
492  char m3[DETMON_MAX_PARAM+1] = "";
493 
494  /* --method */
495  par_name = cpl_sprintf("%s.%s.method", pipeline_name, recipe_name);
496  assert(par_name != NULL);
497  par = cpl_parameterlist_find_const(parlist, par_name);
498  detmon_ronbias_config.method = cpl_parameter_get_string(par);
499  cpl_free(par_name);
500 
501  detmon_ronbias_config.method_bitmask = 0;
502 
503  sscanf(detmon_ronbias_config.method,
504  "%" CPL_STRINGIFY(DETMON_MAX_PARAM) "s "
505  "%" CPL_STRINGIFY(DETMON_MAX_PARAM) "s "
506  "%" CPL_STRINGIFY(DETMON_MAX_PARAM) "s", m1, m2, m3);
507 
508  if(!strcmp(m1, "RANDOM") || !strcmp(m2, "RANDOM")
509  || !strcmp(m3, "RANDOM"))
510  detmon_ronbias_config.method_bitmask += RANDOM;
511 
512  if(!strcmp(m1, "HISTO") || !strcmp(m2, "HISTO") || !strcmp(m3, "HISTO"))
513  detmon_ronbias_config.method_bitmask += HISTO;
514 
515  if(!strcmp(m1, "PREOVERSCAN") || !strcmp(m2, "PREOVERSCAN")
516  || !strcmp(m3, "PREOVERSCAN")) {
517  if (opt_nir == NIR) {
518  /* Just in case some advance user reads himself in the code and
519  tries to trick the interface providing an option no contained
520  in the man-page */
521  cpl_msg_warning(cpl_func, "PREOVERSCAN is not appliable for NIR");
522  } else {
523  detmon_ronbias_config.method_bitmask += PREOVERSCAN;
524  }
525  }
526  if(!strcmp(m1, "REGION") || !strcmp(m2, "REGION")
527  || !strcmp(m3, "REGION"))
528  detmon_ronbias_config.method_bitmask += REGION;
529 
530  if(!strcmp(m1, "ALL")) {
531  if (opt_nir == OPT) {
532  detmon_ronbias_config.method_bitmask =
533  RANDOM | HISTO | PREOVERSCAN | REGION;
534  } else {
535  detmon_ronbias_config.method_bitmask =
536  RANDOM | HISTO | REGION;
537  }
538  }
539 
540  /* --pmethod */
541  par_name = cpl_sprintf("%s.%s.pmethod", pipeline_name, recipe_name);
542  assert(par_name != NULL);
543  par = cpl_parameterlist_find_const(parlist, par_name);
544  detmon_ronbias_config.pmethod = cpl_parameter_get_string(par);
545  cpl_free(par_name);
546 
547  /* --preoverscan.degree */
548  detmon_ronbias_config.preoverscan_degree =
549  detmon_retrieve_par_int("preoverscan.degree", pipeline_name,
550  recipe_name, parlist);
551 
552  /* --nsamples */
553  detmon_ronbias_config.random_nsamples =
554  detmon_retrieve_par_int("random.nsamples", pipeline_name,
555  recipe_name, parlist);
556 
557  /* --sizex */
558  detmon_ronbias_config.random_sizex =
559  detmon_retrieve_par_int("random.sizex", pipeline_name,
560  recipe_name, parlist);
561 
562  /* --sizey */
563  detmon_ronbias_config.random_sizey =
564  detmon_retrieve_par_int("random.sizey", pipeline_name,
565  recipe_name, parlist);
566 
567  /* --criteria */
568  detmon_ronbias_config.criteria =
569  detmon_retrieve_par_int("criteria", pipeline_name, recipe_name,
570  parlist);
571 
572  /* --ref.llx */
573  detmon_ronbias_config.ref_llx =
574  detmon_retrieve_par_int("ref.llx", pipeline_name, recipe_name,
575  parlist);
576  /* --ref.lly */
577  detmon_ronbias_config.ref_lly =
578  detmon_retrieve_par_int("ref.lly", pipeline_name, recipe_name,
579  parlist);
580  /* --ref.urx */
581  detmon_ronbias_config.ref_urx =
582  detmon_retrieve_par_int("ref.urx", pipeline_name, recipe_name,
583  parlist);
584  /* --ref.ury */
585  detmon_ronbias_config.ref_ury =
586  detmon_retrieve_par_int("ref.ury", pipeline_name, recipe_name,
587  parlist);
588 
589  /* --stacking.method */
590  par_name =
591  cpl_sprintf("%s.%s.stacking.method", pipeline_name, recipe_name);
592  assert(par_name != NULL);
593  par = cpl_parameterlist_find_const(parlist, par_name);
594  detmon_ronbias_config.stacking_method = cpl_parameter_get_string(par);
595  cpl_free(par_name);
596 
597  /* --stacking.ks.low */
598  detmon_ronbias_config.stacking_ks_low =
599  detmon_retrieve_par_int("stacking.ks.low", pipeline_name,
600  recipe_name, parlist);
601  /* --stacking.ks.high */
602  detmon_ronbias_config.stacking_ks_high =
603  detmon_retrieve_par_int("stacking.ks.high", pipeline_name,
604  recipe_name, parlist);
605  /* --stacking.ks.iter */
606  detmon_ronbias_config.stacking_ks_iter =
607  detmon_retrieve_par_int("stacking.ks.iter", pipeline_name,
608  recipe_name, parlist);
609  /* --master.shift.x */
610  detmon_ronbias_config.master_shift_x =
611  detmon_retrieve_par_int("master.shift.x", pipeline_name,
612  recipe_name, parlist);
613  /* --master.shift.y */
614  detmon_ronbias_config.master_shift_y =
615  detmon_retrieve_par_int("master.shift.y", pipeline_name,
616  recipe_name, parlist);
617  /* --ron.llx */
618  detmon_ronbias_config.ron_llx =
619  detmon_retrieve_par_int("ron.llx", pipeline_name, recipe_name,
620  parlist);
621  /* --ron.lly */
622  detmon_ronbias_config.ron_lly =
623  detmon_retrieve_par_int("ron.lly", pipeline_name, recipe_name,
624  parlist);
625  /* --ron.urx */
626  detmon_ronbias_config.ron_urx =
627  detmon_retrieve_par_int("ron.urx", pipeline_name, recipe_name,
628  parlist);
629  /* --ron.ury */
630  detmon_ronbias_config.ron_ury =
631  detmon_retrieve_par_int("ron.ury", pipeline_name, recipe_name,
632  parlist);
633  /* --exts */
634  detmon_ronbias_config.exts =
635  detmon_retrieve_par_int("exts", pipeline_name, recipe_name,
636  parlist);
637 
638  if(cpl_error_get_code()) {
639  cpl_msg_error(cpl_func, "Failed to retrieve the input parameters");
640  cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
641  }
642 
643 
644  return CPL_ERROR_NONE;
645 }
646 
647 /*---------------------------------------------------------------------------*/
648 
649 /*
650  * @brief Check parameter defaults
651  * @param set Input set of frames
652  * @param whichext extension to be reduced
653  * @return CPL_ERROR_NONE on success.
654  */
655 
656 /*---------------------------------------------------------------------------*/
657 cpl_error_code
658 detmon_ronbias_check_defaults(const cpl_frameset * set,
659  const int whichext)
660 {
661  const cpl_frame * fr = cpl_frameset_get_position_const(set, 0);
662 
663  cpl_propertylist * plist =
664  cpl_propertylist_load(cpl_frame_get_filename(fr), whichext);
665 
666  const int naxis1 = cpl_propertylist_get_int(plist, "NAXIS1");
667  const int naxis2 = cpl_propertylist_get_int(plist, "NAXIS2");
668 
669  if(detmon_ronbias_config.method_bitmask & PREOVERSCAN)
670  {
671  const int nx = cpl_propertylist_get_int(plist, "ESO DET OUT1 NX");
672  const int ny = cpl_propertylist_get_int(plist, "ESO DET OUT1 NY");
673 
674  int prscsize;
675  int ovscsize;
676 
677  if (naxis1 != nx)
678  {
679  prscsize =
680  cpl_propertylist_get_int(plist, "ESO DET OUT1 PRSCX");
681  ovscsize =
682  cpl_propertylist_get_int(plist, "ESO DET OUT1 OVSCX");
683 
684  cpl_error_ensure(cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(), goto cleanup,"error");
685 
686  detmon_ronbias_config.prescan_llx = 1;
687  detmon_ronbias_config.prescan_lly = 1;
688  detmon_ronbias_config.prescan_urx = prscsize;
689  detmon_ronbias_config.prescan_ury = naxis2;
690  detmon_ronbias_config.overscan_llx = naxis1 - ovscsize;
691  detmon_ronbias_config.overscan_lly = 1;
692  detmon_ronbias_config.overscan_urx = naxis1;
693  detmon_ronbias_config.overscan_ury = naxis2;
694  } else if (naxis2 != ny)
695  {
696  prscsize =
697  cpl_propertylist_get_int(plist, "ESO DET OUT1 PRSCY");
698  ovscsize =
699  cpl_propertylist_get_int(plist, "ESO DET OUT1 OVSCY");
700  cpl_error_ensure(cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(), goto cleanup,"error");
701 
702  detmon_ronbias_config.prescan_llx = 1;
703  detmon_ronbias_config.prescan_lly = 1;
704  detmon_ronbias_config.prescan_urx = naxis1;
705  detmon_ronbias_config.prescan_ury = prscsize;
706  detmon_ronbias_config.overscan_llx = 1;
707  detmon_ronbias_config.overscan_lly = naxis2 - ovscsize;
708  detmon_ronbias_config.overscan_urx = naxis1;
709  detmon_ronbias_config.overscan_ury = naxis2;
710  } else
711  {
712  cpl_msg_error(cpl_func,
713  "No PREOVERSCAN areas found");
714  cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
715  goto cleanup;
716  }
717  }
718 
719  if(detmon_ronbias_config.ref_llx == -1)
720  detmon_ronbias_config.ref_llx = naxis1 / 8;
721  if(detmon_ronbias_config.ref_lly == -1)
722  detmon_ronbias_config.ref_lly = naxis2 / 8;
723  if(detmon_ronbias_config.ref_urx == -1)
724  detmon_ronbias_config.ref_urx = naxis1 * 7 / 8;
725  if(detmon_ronbias_config.ref_ury == -1)
726  detmon_ronbias_config.ref_ury = naxis2 * 7 / 8;
727 
728  if(detmon_ronbias_config.ron_llx == -1)
729  detmon_ronbias_config.ron_llx = 1;
730  if(detmon_ronbias_config.ron_lly == -1)
731  detmon_ronbias_config.ron_lly = 1;
732  if(detmon_ronbias_config.ron_urx == -1)
733  detmon_ronbias_config.ron_urx = naxis1;
734  if(detmon_ronbias_config.ron_ury == -1)
735  detmon_ronbias_config.ron_ury = naxis2;
736 
737 cleanup:
738  cpl_propertylist_delete(plist);
739  return cpl_error_get_code();
740 }
741 
742 
743 /*---------------------------------------------------------------------------*/
744 
745 /*
746  * @brief save a ronbias results on a FITS file
747  * @param parlist input parameters
748  * @param tag input frame tag
749  * @param recipe_name input recipe name
750  * @param pipeline_name input pipeline id
751  * @param pafregexp regular expression to remove from FITS header
752  *
753  * @param pro_master pro catg master frame
754  * @param pro_xstr pro catg xstructure
755  * @param pro_ystr pro catg ystructure
756  * @param pro_synth pro catg synthetic frame
757  * @param pro_bpmhot pro catg hot pix BPM
758  * @param pro_pmpcold pro catg cold pix BPM
759  * @param pro_ppmdev pro catg deviant pix BPM
760  *
761  * @param package package name
762  * @param compare function used for comparison
763  * @param opt_nir switch to specify if in input are OPT or NIR data
764 
765  * @return CPL_ERROR_NONE on success.
766  */
767 
768 /*---------------------------------------------------------------------------*/
769 cpl_error_code
770 detmon_ronbias(cpl_frameset * frameset,
771  const cpl_parameterlist * parlist,
772  const char *tag,
773  const char *recipe_name,
774  const char *pipeline_name,
775  const char *pafregexp,
776  const cpl_propertylist * pro_master,
777  const cpl_propertylist * pro_xstr, /* Unsupported*/
778  const cpl_propertylist * pro_ystr, /* Unsupported*/
779  const cpl_propertylist * pro_synth,
780  const cpl_propertylist * pro_bpmhot,
781  const cpl_propertylist * pro_bpmcold,
782  const cpl_propertylist * pro_bpmdev,
783  const char *package,
784  int (*compare) (const cpl_frame *, const cpl_frame *),
785  cpl_boolean opt_nir)
786 {
787 
788  cpl_size nsets;
789  int i;
790 
791  cpl_size * selection = NULL;
792  cpl_frameset * cur_fset = NULL;
793  cpl_propertylist * qclist = NULL;
794  cpl_image * synthetic = NULL;
795  cpl_image * masterbias = NULL;
796  cpl_imagelist * rawbiases = NULL;
797  cpl_mask * bpmhot = NULL;
798  cpl_mask * bpmcold = NULL;
799  cpl_mask * bpmdev = NULL;
800 
801  /* Test entries */
802  cpl_ensure_code(frameset != NULL, CPL_ERROR_NULL_INPUT);
803  cpl_ensure_code(parlist != NULL, CPL_ERROR_NULL_INPUT);
804  cpl_ensure_code(tag != NULL, CPL_ERROR_NULL_INPUT);
805  cpl_ensure_code(recipe_name != NULL, CPL_ERROR_NULL_INPUT);
806  cpl_ensure_code(pipeline_name != NULL, CPL_ERROR_NULL_INPUT);
807  cpl_ensure_code(pro_master != NULL, CPL_ERROR_NULL_INPUT);
808  cpl_ensure_code(pro_bpmhot != NULL, CPL_ERROR_NULL_INPUT);
809  cpl_ensure_code(pro_bpmcold != NULL, CPL_ERROR_NULL_INPUT);
810  cpl_ensure_code(pro_bpmdev != NULL, CPL_ERROR_NULL_INPUT);
811  cpl_ensure_code(package != NULL, CPL_ERROR_NULL_INPUT);
812 
813  if(detmon_ronbias_dfs_set_groups(frameset, tag)) {
814  cpl_msg_error(cpl_func, "Cannot identify RAW and CALIB frames");
815  }
816 
817  /*
818  * First of all test the entries.
819  * See if the selected method(s) is/are appliable.
820  * See if necessary parameters for those selected have been provided.
821  */
822 
823  /* clreturn_if(detmon_ronbias_test_entries());
824  */
825  /*
826  * This function reads all inputs parameters from parlist
827  * and stores them in a global variable detmon_ronbias_config.
828  * Similar to detmon_lg_retrieve_parlist(). See detmon.c
829  */
830  detmon_ronbias_retrieve_parlist(pipeline_name,
831  recipe_name, parlist, opt_nir);
832 
833  /* Extra input check for PREOVERSCAN */
834  if(detmon_ronbias_config.method_bitmask & PREOVERSCAN)
835  cpl_ensure_code(pro_synth != NULL, CPL_ERROR_NULL_INPUT);
836 
837 
838  /* Labelise all input frames */
839  if(compare == NULL)
840  nsets = 1;
841  else {
842  cpl_msg_info(cpl_func, "Identify the different settings");
843  selection = cpl_frameset_labelise(frameset, compare, &nsets);
844  if(selection == NULL)
845  cpl_msg_error(cpl_func, "Cannot labelise input frames");
846  }
847 
848  /* Extract settings and reduce each of them */
849  for(i = 0; i < nsets; i++) {
850  int j;
851  int first_ext = 0;
852  int last_ext = 1;
853 
854  detmon_ronbias_config.nb_extensions = 1;
855 
856  /* Reduce data set nb i */
857  cpl_msg_info(cpl_func, "Reduce data set nb %d out of %" CPL_SIZE_FORMAT "",
858  i + 1, nsets);
859 
860  cur_fset = nsets == 1 ?
861  cpl_frameset_duplicate(frameset) :
862  cpl_frameset_extract(frameset, selection, i);
863  skip_if(cur_fset == NULL);
864 
865  if(detmon_ronbias_config.exts > 0) {
866  first_ext = detmon_ronbias_config.exts;
867  last_ext = first_ext + 1;
868  } else if(detmon_ronbias_config.exts < 0) {
869  const cpl_frame *cur_frame =
870  cpl_frameset_get_position_const(cur_fset, 0);
871  /* Get the nb of extensions */
872  detmon_ronbias_config.nb_extensions =
873  cpl_frame_get_nextensions(cur_frame);
874  first_ext = 1;
875  last_ext = detmon_ronbias_config.nb_extensions + 1;
876  }
877 
878  if (last_ext - first_ext > 1) {
879  skip_if(detmon_ronbias_save(parlist, frameset,
880  recipe_name,
881  pipeline_name, pafregexp,
882  pro_master, pro_xstr,
883  pro_ystr, pro_synth,
884  pro_bpmhot,
885  pro_bpmcold, pro_bpmdev,
886  package, NULL, NULL, NULL,
887  NULL, NULL, NULL,
888  0, 0, cur_fset, 0));
889  }
890 
891  for(j = first_ext; j < last_ext; j++) {
892  int whichext;
893 
894  qclist = cpl_propertylist_new();
895 
896  rawbiases
897  = cpl_imagelist_load_frameset(cur_fset,
898  CPL_TYPE_FLOAT, 1, j);
899  skip_if(rawbiases == NULL);
900 
901  skip_if(detmon_ronbias_check_defaults(cur_fset, j));
902 
903  skip_if(detmon_ronbias_dutycycl(cur_fset, qclist));
904 
905  masterbias = detmon_ronbias_master(rawbiases,
906  &bpmhot, &bpmcold,
907  &bpmdev, qclist);
908  skip_if(masterbias == NULL);
909 
910  /*
911  * Following, a function corresponding each of the
912  * possible methods is to be found.
913  */
914 
915  if(detmon_ronbias_config.method_bitmask & RANDOM) {
916  skip_if(detmon_ronbias_random(rawbiases, masterbias,
917  qclist));
918  }
919 
920  if(detmon_ronbias_config.method_bitmask & HISTO) {
921  skip_if(detmon_ronbias_histo(rawbiases, masterbias,
922  qclist));
923  }
924 
925  if(detmon_ronbias_config.method_bitmask & PREOVERSCAN) {
926  skip_if(detmon_compute_bias_ron_and_stats_on_preoverscan(rawbiases,
927  /*masterbias,*/
928  qclist, &synthetic));
929  }
930 
931  if(detmon_ronbias_config.method_bitmask & REGION) {
932  skip_if(detmon_compute_bias_stats_and_ron_in_region(rawbiases,
933  masterbias,qclist));
934  }
935 
936  /*
937  * This function takes the QC list where all the results of the
938  * methods applied are stored, and compares them.
939  * No action defined yet if comparison reveals important differences.
940  */
941 #if 0
942  detmon_ronbias_check(qclist);
943 #endif
944 
945  /* Definition of the extension of the output where to save
946  the products. If input are multiextension but only
947  computation on a single extension is required, it is 0 */
948  whichext = first_ext > 1 ? 0 : j;
949 
950  skip_if(detmon_ronbias_save(parlist, frameset,
951  recipe_name,
952  pipeline_name, pafregexp,
953  pro_master, pro_xstr,
954  pro_ystr, pro_synth,
955  pro_bpmhot,
956  pro_bpmcold, pro_bpmdev,
957  package, masterbias, synthetic,
958  bpmhot, bpmcold, bpmdev,
959  qclist, 0, 0, cur_fset,
960  whichext));
961 
962  cpl_image_delete(synthetic);
963  cpl_image_delete(masterbias);
964  cpl_mask_delete(bpmhot);
965  cpl_mask_delete(bpmcold);
966  cpl_mask_delete(bpmdev);
967  cpl_imagelist_delete(rawbiases);
968  cpl_propertylist_delete(qclist);
969 
970  qclist = NULL;
971  rawbiases = NULL;
972  masterbias = NULL;
973  bpmhot = NULL;
974  bpmcold = NULL;
975  bpmdev = NULL;
976  synthetic = NULL;
977  } /* for each extension */
978 
979  cpl_frameset_delete(cur_fset);
980  cur_fset = NULL;
981 
982  } /* for each setting */
983 
984  end_skip;
985 
986  cpl_free(selection);
987 
988  cpl_frameset_delete(cur_fset);
989 
990  cpl_image_delete(synthetic);
991  cpl_image_delete(masterbias);
992  cpl_mask_delete(bpmhot);
993  cpl_mask_delete(bpmcold);
994  cpl_mask_delete(bpmdev);
995  cpl_imagelist_delete(rawbiases);
996  cpl_propertylist_delete(qclist);
997 
998  return cpl_error_get_code();
999 }
1000 
1001 /*---------------------------------------------------------------------------*/
1002 /*
1003  * @brief Computes bias RON using random sampling method
1004  * @param rawbiases input image list
1005  * @param masterbias input master bias
1006  * @param qclist input/output propertylist with QC parameters
1007  * @return CPL_ERROR_NONE on success.
1008 
1009  */
1010 /*---------------------------------------------------------------------------*/
1011 static cpl_error_code
1012 detmon_ronbias_random(const cpl_imagelist * rawbiases,
1013  const cpl_image * masterbias,
1014  cpl_propertylist * qclist)
1015 {
1016  int nraws = cpl_imagelist_get_size(rawbiases);
1017  int i;
1018  double bias = DBL_MAX; /* Avoid (false) uninit warning */
1019  double bias_error;
1020 
1021  double ron_error;
1022  double *ron =
1023  (double *) cpl_malloc(sizeof(double) * nraws);
1024 
1025  cpl_vector *v;
1026  double stdev = 0;
1027  cpl_error_code error = CPL_ERROR_NONE;
1028 
1029  /* As we are applying to diff frames instead of raw frames,
1030  there is one less to compute on */
1031  if(!strcmp(detmon_ronbias_config.pmethod, "DIF"))
1032  {
1033  nraws--;
1034  /* As we are applying to diff frames instead of raw frames,
1035  there is one less to compute on */
1036  for(i = 0; i < nraws; i++)
1037  {
1038  const cpl_image *c1_raw =
1039  cpl_imagelist_get_const(rawbiases, i);
1040  const cpl_image *c2_raw =
1041  cpl_imagelist_get_const(rawbiases, i + 1);
1042  /*FIXME: See if const modifier is necessary */
1043  const cpl_image *c_raw = cpl_image_subtract_create(c1_raw,
1044  c2_raw);
1045  error = cpl_flux_get_noise_window(c_raw, NULL,
1046  detmon_ronbias_config.random_sizex / 2,
1047  detmon_ronbias_config.random_nsamples,
1048  ron + i, &ron_error);
1049  cpl_image_delete((cpl_image*)c_raw);
1050  if (error != CPL_ERROR_NONE)
1051  {
1052  break;
1053  }
1054  }
1055  } else
1056  {
1057  for(i = 0; i < nraws; i++)
1058  {
1059  const cpl_image *c_raw = cpl_imagelist_get_const(rawbiases, i);
1060  skip_if(cpl_flux_get_noise_window(c_raw, NULL,
1061  detmon_ronbias_config.random_sizex / 2,
1062  detmon_ronbias_config.random_nsamples,
1063  ron + i, &ron_error));
1064  }
1065  }
1066 
1067  /*FIXME: Calls to noise_window could be out from if() and
1068  coded only once */
1069  if (error == CPL_ERROR_NONE)
1070  {
1071  irplib_flux_get_bias_window(masterbias, NULL,
1072  detmon_ronbias_config.random_sizex / 2,
1073  detmon_ronbias_config.random_nsamples,
1074  &bias, &bias_error);
1075 
1076  v = cpl_vector_wrap(nraws, ron);
1077  stdev = cpl_vector_get_median_const(v);
1078  cpl_vector_unwrap(v);
1079 
1080 
1081  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_RANDOM_VAL, bias));
1082  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_RANDOM_VAL,
1083  DETMON_QC_BIAS_RANDOM_VAL_C));
1084 
1085  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_RANDOM_RON, stdev));
1086  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_RANDOM_RON,
1087  DETMON_QC_BIAS_RANDOM_RON_C));
1088  }
1089 
1090  irplib_flux_get_bias_window(masterbias, NULL,
1091  detmon_ronbias_config.random_sizex / 2,
1092  detmon_ronbias_config.random_nsamples,
1093  &bias, &bias_error);
1094 
1095  v = cpl_vector_wrap(nraws, ron);
1096  if (v)
1097  {
1098  stdev = cpl_vector_get_median_const(v);
1099  cpl_vector_unwrap(v);
1100  }
1101 
1102  error = cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_RANDOM_VAL, bias);
1103  error = cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_RANDOM_VAL,
1104  DETMON_QC_BIAS_RANDOM_VAL_C);
1105 
1106 
1107  error = cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_RANDOM_RON, stdev);
1108  error = cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_RANDOM_RON,
1109  DETMON_QC_BIAS_RANDOM_RON_C);
1110 
1111  end_skip;
1112  if (ron)
1113  cpl_free(ron);
1114  return cpl_error_get_code();
1115 }
1116 /*
1117  * @brief Computes bias RON using histogram method
1118  * @param rawbiases input image list
1119  * @param masterbias input master bias
1120  * @param qclist input/output propertylist with QC parameters
1121  * @return CPL_ERROR_NONE on success.
1122 
1123  */
1124 static cpl_error_code
1125 detmon_ronbias_histo(const cpl_imagelist * rawbiases,
1126  const cpl_image * masterbias,
1127  cpl_propertylist * qclist)
1128 {
1129  int nraws = cpl_imagelist_get_size(rawbiases);
1130  int i;
1131 
1132  double mbias = DBL_MAX;
1133  double mfwhm = DBL_MAX;
1134  double mmax = DBL_MAX;
1135 
1136  cpl_vector * fwhms;
1137  cpl_vector * maxs;
1138 
1139  double mean_fwhm = DBL_MAX;
1140 
1141  if(!strcmp(detmon_ronbias_config.pmethod, "DIF")) nraws--;
1142 
1143  fwhms = cpl_vector_new(nraws);
1144  maxs = cpl_vector_new(nraws);
1145 
1146  for(i = 0; i < nraws; i++) {
1147  /*FIXME: See if it is necessary to have const */
1148  const cpl_image * c_raw;
1149  double bias = DBL_MAX;
1150  double fwhm = DBL_MAX;
1151  double max = DBL_MAX;
1152 
1153  if(strcmp(detmon_ronbias_config.pmethod, "DIF")) {
1154  c_raw = cpl_imagelist_get_const(rawbiases, i);
1155  } else {
1156  const cpl_image *c1_raw = cpl_imagelist_get_const(rawbiases, i);
1157  const cpl_image * c2_raw = cpl_imagelist_get_const(rawbiases, i+1);
1158  c_raw = cpl_image_subtract_create(c1_raw, c2_raw);
1159  }
1160 
1161  skip_if(detmon_ronbias_histo_reduce(c_raw, &bias, &fwhm, &max));
1162 
1163  skip_if(bias == DBL_MAX || fwhm == DBL_MAX || max == DBL_MAX);
1164 
1165  if(!strcmp(detmon_ronbias_config.pmethod, "DIF"))
1166  cpl_image_delete((cpl_image *)c_raw);
1167 
1168  skip_if(cpl_vector_set(maxs, i, max));
1169  skip_if(cpl_vector_set(fwhms, i, fwhm));
1170 
1171  /* FIXME: Add properly a hist-saving in debug-mode */
1172  }
1173 
1174  skip_if(cpl_vector_divide_scalar(fwhms, CPL_MATH_FWHM_SIG));
1175 
1176  detmon_ronbias_histo_reduce(masterbias, &mbias, &mfwhm, &mmax);
1177 
1178  skip_if(mbias == DBL_MAX || mfwhm == DBL_MAX || mmax == DBL_MAX);
1179 
1180  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_HISTO_VAL,
1181  mbias));
1182  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_HISTO_VAL,
1183  DETMON_QC_BIAS_HISTO_VAL_C));
1184  mean_fwhm = cpl_vector_get_mean(fwhms);
1185 
1186  skip_if(mean_fwhm == DBL_MAX);
1187  skip_if(cpl_error_get_code());
1188 
1189  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_HISTO_RON,
1190  mean_fwhm));
1191  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_HISTO_RON,
1192  DETMON_QC_BIAS_HISTO_RON_C));
1193 
1194  end_skip;
1195 
1196  cpl_vector_delete(fwhms);
1197  cpl_vector_delete(maxs);
1198 
1199  return cpl_error_get_code();
1200 }
1201 
1202 /*---------------------------------------------------------------------------*/
1203 
1204 /*
1205  * @brief Computes histogram on input image and get bias, fwhm and max
1206  * @param c_raw Input image
1207  * @param bias output bias of histogram
1208  * @param fwhm output fwhm of histogram
1209  * @param max output max of histogram
1210  * @return CPL_ERROR_NONE on success.
1211 
1212  */
1213 
1214 /*---------------------------------------------------------------------------*/
1215 cpl_error_code
1216 detmon_ronbias_histo_reduce(const cpl_image * c_raw,
1217  double * bias,
1218  double * fwhm,
1219  double * max)
1220 {
1221  unsigned long uj;
1222  irplib_hist *hist;
1223  unsigned long maxwhere = 0;
1224 
1225  cpl_image * dupi;
1226  unsigned long x1a = 1;
1227  unsigned long x2a = 1;
1228 
1229  double x1 = 0;
1230  double x2 = 0;
1231 
1232  double maxwhere_interp;
1233  double max_interp;
1234  double a, b, c;
1235  cpl_matrix * coeffs =cpl_matrix_new(3, 3);
1236  cpl_matrix * rhs =cpl_matrix_new(3, 1);
1237  int p, q;
1238  cpl_matrix * result = NULL;
1239 
1240  dupi = cpl_image_duplicate(c_raw);
1241 
1242  /* FIXME: Still to decide if it is necessary to remove bad pixels
1243  in advance or not*/
1244 
1245  hist = irplib_hist_new();
1246  irplib_hist_fill(hist, dupi);
1247 
1248  cpl_image_delete(dupi);
1249 
1250  irplib_hist_get_max(hist, &maxwhere);
1251 
1252  for( p = 0; p< 3; p++){
1253  unsigned long bi = irplib_hist_get_value(hist, maxwhere-1+p);
1254  cpl_matrix_set(rhs, p, 0, bi);
1255  for( q= 0; q< 3; q++) {
1256  cpl_matrix_set(coeffs, p,q,pow((maxwhere-1+p),q));
1257  }
1258  }
1259 
1260  result = cpl_matrix_solve(coeffs, rhs);
1261 
1262  a = cpl_matrix_get(result, 2, 0);
1263  b = cpl_matrix_get(result, 1, 0);
1264  c = cpl_matrix_get(result, 0, 0);
1265 
1266  maxwhere_interp = -0.5 * b / (2 * a);
1267  max_interp = -1 * b * b / (4 * a) + c;
1268 
1269  cpl_matrix_delete(coeffs);
1270  cpl_matrix_delete(rhs);
1271  cpl_matrix_delete(result);
1272 
1273  /* Look for the points of half-maximum */
1274  for(uj = 0; uj < maxwhere; uj++) {
1275  if(irplib_hist_get_value(hist, uj) <= max_interp / 2 &&
1276  irplib_hist_get_value(hist, uj + 1) > max_interp / 2) {
1277  x1a = uj;
1278  }
1279  }
1280  for(uj = maxwhere; uj < irplib_hist_get_nbins(hist)-1; uj++) {
1281  if(irplib_hist_get_value(hist, uj) >= max_interp / 2 &&
1282  irplib_hist_get_value(hist, uj + 1) < max_interp / 2) {
1283  x2a = uj;
1284  }
1285  }
1286 
1287  x1 = (max_interp / 2 - irplib_hist_get_value(hist, x1a)) /
1288  (irplib_hist_get_value(hist, x1a + 1) -
1289  irplib_hist_get_value(hist, x1a)) + x1a;
1290  x2 = (max_interp / 2 - irplib_hist_get_value(hist, x2a)) /
1291  (irplib_hist_get_value(hist, x2a + 1) -
1292  irplib_hist_get_value(hist, x2a)) + x2a;
1293 
1294  *fwhm = (x2 - x1) * irplib_hist_get_bin_size(hist);
1295 
1296  *max = max_interp;
1297 
1298  *bias = maxwhere_interp * irplib_hist_get_bin_size(hist) +
1299  irplib_hist_get_start(hist);
1300 
1301  irplib_hist_delete(hist);
1302 
1303  return cpl_error_get_code();
1304 }
1305 /*---------------------------------------------------------------------------*/
1306 
1307 /*
1308  * @brief Computes RON and statistics on pre/overscan bias regions
1309  * @param rawbiases Input image list
1310  * @param qclist input/output propertylist with QC parameters
1311  * @param synthetic input synthetic image
1312  * @return CPL_ERROR_NONE on success.
1313 
1314  */
1315 
1316 /*---------------------------------------------------------------------------*/
1317 static cpl_error_code
1318 detmon_compute_bias_ron_and_stats_on_preoverscan(const cpl_imagelist * rawbiases,
1319  cpl_propertylist * qclist,
1320  cpl_image ** synthetic)
1321 {
1322  int i;
1323  int nx, ny;
1324  int nraws;
1325 
1326  cpl_vector *meanspre;
1327  cpl_vector *medspre;
1328  cpl_vector *rmsspre;
1329  cpl_vector *meansover;
1330  cpl_vector *medsover;
1331  cpl_vector *rmssover;
1332 
1333  cpl_error_code error;
1334 
1335  nraws = cpl_imagelist_get_size(rawbiases);
1336  cpl_ensure_code(nraws != -1, CPL_ERROR_ILLEGAL_INPUT);
1337 
1338  nx = cpl_image_get_size_x(cpl_imagelist_get_const(rawbiases, 0));
1339  ny = cpl_image_get_size_y(cpl_imagelist_get_const(rawbiases, 0));
1340  cpl_ensure_code(nx != -1 && ny != -1, CPL_ERROR_ILLEGAL_INPUT);
1341 
1342  if(nx < detmon_ronbias_config.prescan_urx ||
1343  nx < detmon_ronbias_config.overscan_urx ||
1344  ny < detmon_ronbias_config.prescan_ury ||
1345  ny < detmon_ronbias_config.overscan_ury) {
1346  cpl_msg_warning(cpl_func, "PREOVERSCAN method not applied. Given "
1347  "limits of prescan and overscan area "
1348  "exceed image size. Please check and rerun.");
1349  return CPL_ERROR_NONE;
1350  }
1351 
1352  meanspre = cpl_vector_new(nraws);
1353  medspre = cpl_vector_new(nraws);
1354  rmsspre = cpl_vector_new(nraws);
1355  meansover = cpl_vector_new(nraws);
1356  medsover = cpl_vector_new(nraws);
1357  rmssover = cpl_vector_new(nraws);
1358 
1359  for(i = 0; i < nraws; i++) {
1360  double mean = 0;
1361  double stdev = 0;
1362  double median_prescan, median_overscan;
1363 
1364  cpl_image *prescan = NULL;
1365  cpl_image *overscan = NULL;
1366 
1367  const cpl_image *c_raw = cpl_imagelist_get_const(rawbiases, i);
1368 
1369  cpl_ensure_code(c_raw != NULL, CPL_ERROR_ILLEGAL_INPUT);
1370 
1371  prescan =
1372  cpl_image_extract(c_raw,
1373  detmon_ronbias_config.prescan_llx,
1374  detmon_ronbias_config.prescan_lly,
1375  detmon_ronbias_config.prescan_urx,
1376  detmon_ronbias_config.prescan_ury);
1377  cpl_ensure_code(prescan != NULL, CPL_ERROR_ILLEGAL_INPUT);
1378  overscan =
1379  cpl_image_extract(c_raw,
1380  detmon_ronbias_config.overscan_llx,
1381  detmon_ronbias_config.overscan_lly,
1382  detmon_ronbias_config.overscan_urx,
1383  detmon_ronbias_config.overscan_ury);
1384  cpl_ensure_code(overscan != NULL, CPL_ERROR_ILLEGAL_INPUT);
1385 
1386  if(i == 0) {
1387  *synthetic = detmon_build_synthetic_from_pre_overscan(prescan,
1388  overscan);
1389  cpl_msg_info(cpl_func, "Creating SYNTHETIC frame");
1390  if(*synthetic == NULL) {
1391  cpl_msg_error(cpl_func, "Error creating SYNTHETIC frame");
1392  return CPL_ERROR_UNSPECIFIED;
1393  }
1394  }
1395 
1396  median_prescan = cpl_image_get_median(prescan);
1397  median_overscan = cpl_image_get_median(overscan);
1398  cpl_image_delete(prescan);
1399  cpl_image_delete(overscan);
1400 
1401  error = irplib_ksigma_clip(c_raw,
1402  detmon_ronbias_config.
1403  prescan_llx,
1404  detmon_ronbias_config.
1405  prescan_lly,
1406  detmon_ronbias_config.
1407  prescan_urx,
1408  detmon_ronbias_config.
1409  prescan_ury,
1410  (double) detmon_ronbias_config.
1411  stacking_ks_low,
1412  detmon_ronbias_config.
1413  stacking_ks_iter, 1e-5,
1414  &mean, &stdev);
1415  cpl_ensure_code(!error, error);
1416 
1417  cpl_ensure_code(mean != 0 && stdev != 0, CPL_ERROR_UNSPECIFIED);
1418 
1419  error = cpl_vector_set(medspre, i, median_prescan);
1420  cpl_ensure_code(!error, error);
1421 
1422  error = cpl_vector_set(meanspre, i, mean);
1423  cpl_ensure_code(!error, error);
1424  error = cpl_vector_set(rmsspre, i, stdev);
1425  cpl_ensure_code(!error, error);
1426  error = irplib_ksigma_clip(c_raw,
1427  detmon_ronbias_config.
1428  overscan_llx,
1429  detmon_ronbias_config.
1430  overscan_lly,
1431  detmon_ronbias_config.
1432  overscan_urx,
1433  detmon_ronbias_config.
1434  overscan_ury,
1435  (double) detmon_ronbias_config.
1436  stacking_ks_low,
1437  detmon_ronbias_config.
1438  stacking_ks_iter, 1e-5,
1439  &mean, &stdev);
1440  cpl_ensure_code(!error, error);
1441 
1442  cpl_ensure_code(mean != 0 && stdev != 0, CPL_ERROR_UNSPECIFIED);
1443 
1444  error = cpl_vector_set(medsover, i, median_overscan);
1445  cpl_ensure_code(!error, error);
1446 
1447  error = cpl_vector_set(meansover, i, mean);
1448  cpl_ensure_code(!error, error);
1449  error = cpl_vector_set(rmssover, i, stdev);
1450  cpl_ensure_code(!error, error);
1451 
1452  }
1453 
1454  error = cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_PRESCAN_MEAN,
1455  cpl_vector_get_mean(meanspre));
1456 
1457  error = cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_PRESCAN_MEAN,
1458  DETMON_QC_BIAS_PRESCAN_MEAN_C);
1459 
1460  cpl_ensure_code(!error, error);
1461  error = cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_PRESCAN_MED,
1462  cpl_vector_get_mean(medspre));
1463  error = cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_PRESCAN_MED,
1464  DETMON_QC_BIAS_PRESCAN_MED_C);
1465 
1466  cpl_ensure_code(!error, error);
1467  error = cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_PRESCAN_RON,
1468  cpl_vector_get_mean(rmsspre));
1469 
1470  error = cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_PRESCAN_RON,
1471  DETMON_QC_BIAS_PRESCAN_RON_C);
1472  cpl_ensure_code(!error, error);
1473 
1474  error =
1475  cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_OVERSCAN_MEAN,
1476  cpl_vector_get_mean(meansover));
1477  error = cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_OVERSCAN_MEAN,
1478  DETMON_QC_BIAS_OVERSCAN_MEAN_C);
1479  cpl_ensure_code(!error, error);
1480  error = cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_OVERSCAN_MED,
1481  cpl_vector_get_mean(medsover));
1482  error = cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_OVERSCAN_MED,
1483  DETMON_QC_BIAS_OVERSCAN_MED_C);
1484  cpl_ensure_code(!error, error);
1485  error = cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_OVERSCAN_RON,
1486  cpl_vector_get_mean(rmssover));
1487  error = cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_OVERSCAN_RON,
1488  DETMON_QC_BIAS_OVERSCAN_RON_C);
1489  cpl_ensure_code(!error, error);
1490 
1491  /* The following seems not to be necessary.
1492  Pending of revision to be removed */
1493  /*
1494  error =
1495  cpl_propertylist_append_double(qclist,
1496  "ESO QC BIAS PRESCAN MEAN STDEV",
1497  cpl_vector_get_stdev(meanspre));
1498  cpl_ensure_code(!error, error);
1499  error =
1500  cpl_propertylist_append_double(qclist,
1501  "ESO QC BIAS PRESCAN MED STDEV",
1502  cpl_vector_get_stdev(medspre));
1503  cpl_ensure_code(!error, error);
1504  error =
1505  cpl_propertylist_append_double(qclist,
1506  "ESO QC BIAS PRESCAN RMS STDEV",
1507  cpl_vector_get_stdev(rmsspre));
1508  cpl_ensure_code(!error, error);
1509 
1510  error =
1511  cpl_propertylist_append_double(qclist,
1512  "ESO QC BIAS OVERSCAN MEAN STDEV",
1513  cpl_vector_get_stdev(meansover));
1514  cpl_ensure_code(!error, error);
1515  error =
1516  cpl_propertylist_append_double(qclist,
1517  "ESO QC BIAS OVERSCAN MED STDEV",
1518  cpl_vector_get_stdev(medsover));
1519  cpl_ensure_code(!error, error);
1520  error =
1521  cpl_propertylist_append_double(qclist,
1522  "ESO QC BIAS OVERSCAN RMS STDEV",
1523  cpl_vector_get_stdev(rmssover));
1524  cpl_ensure_code(!error, error);
1525  */
1526 
1527  cpl_vector_delete(meanspre);
1528  cpl_vector_delete(medspre);
1529  cpl_vector_delete(rmsspre);
1530  cpl_vector_delete(meansover);
1531  cpl_vector_delete(medsover);
1532  cpl_vector_delete(rmssover);
1533 
1534  return CPL_ERROR_NONE;
1535 }
1536 
1537 /*---------------------------------------------------------------------------*/
1538 
1539 /*
1540  * @brief Get RON on bias frames and statistics on master bias on region for QC
1541  * @param rawbiases Input image list
1542  * @param masterbias Input master bias
1543  * @param qclist input/output propertylist with QC parameters
1544  * @return CPL_ERROR_NONE on success.
1545  */
1546 
1547 /*---------------------------------------------------------------------------*/
1548 static cpl_error_code
1549 detmon_compute_bias_stats_and_ron_in_region(const cpl_imagelist * rawbiases,
1550  const cpl_image * masterbias,
1551  cpl_propertylist * qclist)
1552 {
1553 
1554  int nraws = cpl_imagelist_get_size(rawbiases);
1555  int i;
1556 
1557  int nx =
1558  cpl_image_get_size_x(cpl_imagelist_get_const(rawbiases, 0));
1559  int ny =
1560  cpl_image_get_size_y(cpl_imagelist_get_const(rawbiases, 0));
1561 
1562  cpl_vector *rmssreg;
1563  cpl_error_code error;
1564 
1565  const cpl_image * c_raw;
1566  double median, mbias, mstdev;
1567 
1568  if(!strcmp(detmon_ronbias_config.pmethod, "DIF")) nraws--;
1569 
1570  rmssreg = cpl_vector_new(nraws);
1571 
1572  if(nx < detmon_ronbias_config.ref_urx ||
1573  ny < detmon_ronbias_config.ref_ury) {
1574  cpl_msg_warning(cpl_func, "REGION method not applied. Given "
1575  "limits of prescan and overscan area "
1576  "exceed image size. Please check and rerun.");
1577  return CPL_ERROR_NONE;
1578  }
1579 
1580  for(i = 0; i < nraws; i++) {
1581  double mean = 0;
1582  double stdev = 0;
1583  if(strcmp(detmon_ronbias_config.pmethod, "DIF")) {
1584  c_raw = cpl_imagelist_get_const(rawbiases, i);
1585  } else {
1586  const cpl_image *c1_raw = cpl_imagelist_get_const(rawbiases, i);
1587  const cpl_image * c2_raw = cpl_imagelist_get_const(rawbiases, i+1);
1588  c_raw = cpl_image_subtract_create(c1_raw, c2_raw);
1589  }
1590  error = irplib_ksigma_clip(c_raw,
1591  detmon_ronbias_config.ref_llx,
1592  detmon_ronbias_config.ref_lly,
1593  detmon_ronbias_config.ref_urx,
1594  detmon_ronbias_config.ref_ury,
1595  (double) detmon_ronbias_config.
1596  stacking_ks_low,
1597  detmon_ronbias_config.
1598  stacking_ks_iter, 1e-5,
1599  &mean, &stdev);
1600  cpl_ensure_code(!error, error);
1601  /* cpl_vector_set(rmssreg, i, cpl_image_get_stdev_window(c_raw,
1602  detmon_ronbias_config.ref_llx,
1603  detmon_ronbias_config.ref_lly,
1604  detmon_ronbias_config.ref_urx,
1605  detmon_ronbias_config.ref_ury));
1606  */
1607  error = cpl_vector_set(rmssreg, i, stdev);
1608  cpl_ensure_code(!error, error);
1609  if(!strcmp(detmon_ronbias_config.pmethod, "DIF")) cpl_image_delete((cpl_image *)c_raw);
1610  }
1611 
1612  median = cpl_image_get_median_window(masterbias,
1613  detmon_ronbias_config.ref_llx,
1614  detmon_ronbias_config.ref_lly,
1615  detmon_ronbias_config.ref_urx,
1616  detmon_ronbias_config.ref_ury);
1617  error = irplib_ksigma_clip(masterbias,
1618  detmon_ronbias_config.ref_llx,
1619  detmon_ronbias_config.ref_lly,
1620  detmon_ronbias_config.ref_urx,
1621  detmon_ronbias_config.ref_ury,
1622  (double) detmon_ronbias_config.
1623  stacking_ks_low,
1624  detmon_ronbias_config.
1625  stacking_ks_iter, 1e-5,
1626  &mbias, &mstdev);
1627 
1628  error = cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_REGION_MED,
1629  median);
1630  error = cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_REGION_MED,
1631  DETMON_QC_BIAS_REGION_MED_C);
1632  cpl_ensure_code(!error, error);
1633 
1634  error = cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_REGION_VAL,
1635  mbias);
1636  error = cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_REGION_VAL,
1637  DETMON_QC_BIAS_REGION_VAL_C);
1638  cpl_ensure_code(!error, error);
1639  error = cpl_propertylist_append_double(qclist,DETMON_QC_BIAS_REGION_RON,
1640  cpl_vector_get_mean(rmssreg));
1641  error = cpl_propertylist_set_comment(qclist,DETMON_QC_BIAS_REGION_RON,
1642  DETMON_QC_BIAS_REGION_RON_C);
1643  cpl_ensure_code(!error, error);
1644  /*
1645  error =
1646  cpl_propertylist_append_double(qclist, "ESO QC BIAS REGION RMS STDEV",
1647  cpl_vector_get_stdev(rmssreg));
1648  cpl_ensure_code(!error, error);
1649  */
1650  cpl_vector_delete(rmssreg);
1651 
1652  return cpl_error_get_code();
1653 }
1654 
1655 /*---------------------------------------------------------------------------*/
1656 
1657 /*
1658  * @brief Determines master bias and QC parameters
1659  * @param rawbiases Input raw images
1660  * @param bpmhot hot pixel bpm
1661  * @param bpmcold cold pixel bpm
1662  * @param bpmdev deviant pixel bpm
1663  * @param qclist fits header
1664  * @return master bias on success or NULL
1665  */
1666 
1667 /*---------------------------------------------------------------------------*/
1668 static cpl_image *
1669 detmon_ronbias_master(const cpl_imagelist * rawbiases,
1670  cpl_mask ** bpmhot, cpl_mask ** bpmcold,
1671  cpl_mask ** bpmdev, cpl_propertylist * qclist)
1672 {
1673  double mean = 0;
1674  double stdev = 0;
1675  cpl_image *masterbias = NULL;
1676  double dark_med, stdev_med,lower, upper;
1677  int hotpix_nb, coldpix_nb, devpix_nb;
1678  cpl_image * stdev_im = NULL;
1679 
1680  if(!strcmp(detmon_ronbias_config.stacking_method, "MEAN"))
1681  masterbias = cpl_imagelist_collapse_create(rawbiases);
1682  if(!strcmp(detmon_ronbias_config.stacking_method, "MINMAX"))
1683  masterbias =
1684  cpl_imagelist_collapse_minmax_create(rawbiases, 0, 10000);
1685  if(!strcmp(detmon_ronbias_config.stacking_method, "KSIGMA"))
1686  masterbias =
1687  cpl_imagelist_collapse_sigclip_create(rawbiases, 3.0, 3.0, 0.9,
1688  CPL_COLLAPSE_MEAN, NULL);
1689  if(!strcmp(detmon_ronbias_config.stacking_method, "MEDIAN"))
1690  masterbias = cpl_imagelist_collapse_median_create(rawbiases);
1691 
1692  skip_if(masterbias == NULL);
1693 
1694  skip_if(irplib_ksigma_clip(masterbias, 1, 1,
1695  cpl_image_get_size_x(masterbias),
1696  cpl_image_get_size_y(masterbias),
1697  (double) detmon_ronbias_config.
1698  stacking_ks_low,
1699  detmon_ronbias_config.
1700  stacking_ks_iter, 1e-5,
1701  &mean, &stdev));
1702 
1703  if(irplib_isnan(mean))
1704  cpl_msg_error(cpl_func, "We have an error in mean");
1705  if(irplib_isnan(stdev))
1706  cpl_msg_error(cpl_func, "We have an error in stdev");
1707 
1708  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_MASTER_MEAN,
1709  mean));
1710  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_MASTER_MEAN,
1711  DETMON_QC_MASTER_MEAN_C));
1712 
1713  skip_if(cpl_propertylist_append_double(qclist,DETMON_QC_MASTER_RMS,
1714  stdev));
1715  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_MASTER_RMS,
1716  DETMON_QC_MASTER_RMS_C));
1717 
1718  /* Compute median-rms of the central part of the dark */
1719  dark_med = cpl_image_get_median(masterbias);
1720 
1721  lower = dark_med - stdev * detmon_ronbias_config.stacking_ks_low;
1722  upper = dark_med + stdev * detmon_ronbias_config.stacking_ks_high;
1723 
1724  /* Create the hot pixel map */
1725  cpl_mask_delete(*bpmhot);
1726  irplib_check(*bpmhot = cpl_mask_threshold_image_create(masterbias,
1727  upper, DBL_MAX),
1728  "Cannot compute the hot pixel map");
1729  hotpix_nb = cpl_mask_count(*bpmhot);
1730  skip_if (0);
1731 
1732  /* Create the cold pixel map */
1733  cpl_mask_delete(*bpmcold);
1734  irplib_check(*bpmcold = cpl_mask_threshold_image_create(masterbias,
1735  -FLT_MAX, lower),
1736  "Cannot compute the cold pixel map");
1737  coldpix_nb = cpl_mask_count(*bpmcold);
1738  skip_if (0);
1739 
1740  /* Create the deviant pixel map */
1741  stdev_im = irplib_imagelist_collapse_stdev_create(rawbiases);
1742  stdev_med = cpl_image_get_median(stdev_im);
1743 
1744  skip_if(irplib_ksigma_clip(stdev_im, 1, 1,
1745  cpl_image_get_size_x(stdev_im),
1746  cpl_image_get_size_y(stdev_im),
1747  (double) detmon_ronbias_config.
1748  stacking_ks_low,
1749  detmon_ronbias_config.
1750  stacking_ks_iter, 1e-5,
1751  &mean, &stdev));
1752 
1753  lower = stdev_med - stdev * detmon_ronbias_config.stacking_ks_low;
1754  upper = stdev_med + stdev * detmon_ronbias_config.stacking_ks_high;
1755 
1756  cpl_mask_delete(*bpmdev);
1757  irplib_check(*bpmdev = cpl_mask_threshold_image_create(stdev_im,
1758  lower, upper),
1759  "Cannot compute the cold pixel map");
1760  cpl_mask_not(*bpmdev);
1761  devpix_nb = cpl_mask_count(*bpmdev);
1762  skip_if (0);
1763 
1764 
1765  skip_if(cpl_propertylist_append_int(qclist,DETMON_QC_NBCOLDPIX,coldpix_nb));
1766  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_NBCOLDPIX,
1767  DETMON_QC_NBCOLDPIX_C));
1768 
1769  skip_if(cpl_propertylist_append_int(qclist,DETMON_QC_NBHOTPIX, hotpix_nb));
1770  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_NBHOTPIX,
1771  DETMON_QC_NBHOTPIX_C));
1772 
1773  skip_if(cpl_propertylist_append_int(qclist,DETMON_QC_NBDEVPIX, devpix_nb));
1774  skip_if(cpl_propertylist_set_comment(qclist,DETMON_QC_NBDEVPIX,
1775  DETMON_QC_NBDEVPIX_C));
1776 
1777  end_skip;
1778 
1779  cpl_image_delete(stdev_im);
1780 
1781  if (cpl_error_get_code()) {
1782  cpl_image_delete(masterbias);
1783  masterbias = NULL;
1784  }
1785 
1786  return masterbias;
1787 }
1788 
1789 /*---------------------------------------------------------------------------*/
1790 
1791 /*
1792  * @brief save a ronbias results on a FITS file
1793  * @param parlist input parameters
1794  * @param frameset input frames
1795  * @param recipe_name input recipe name
1796  * @param pipeline_name input pipeline id
1797  * @param pafregexp regular expression to remove from FITS header
1798  * @param pro_master pro catg master frame
1799  * @param pro_xstr pro catg xstructure
1800  * @param pro_ystr pro catg ystructure
1801  * @param pro_synth pro catg synthetic frame
1802  * @param pro_bpmhot pro catg hot pix BPM
1803  * @param pro_pmpcold pro catg cold pix BPM
1804  * @param pro_ppmdev pro catg deviant pix BPM
1805  * @param package package name
1806  * @param masterbias master bias
1807  * @param synthetic synthetic frame
1808  * @param bpmhot hot pixel bpm
1809  * @param bpmcold cold pixel bpm
1810  * @param bpmdev deviant pixel bpm
1811  * @param qclist qc parameter (header)
1812  * @param flag_sets switch
1813  * @param which_set id to specify a given set
1814  * @param usedframes used frames
1815  * @param whichset id to specify a given set
1816  * @return CPL_ERROR_NONE on success.
1817  */
1818 
1819 /*---------------------------------------------------------------------------*/
1820 static cpl_error_code
1821 detmon_ronbias_save(const cpl_parameterlist * parlist,
1822  cpl_frameset * frameset,
1823  const char *recipe_name,
1824  const char *pipeline_name,
1825  const char *pafregexp,
1826  const cpl_propertylist * pro_master,
1827  const cpl_propertylist * pro_xstr, /* Unsupported*/
1828  const cpl_propertylist * pro_ystr, /* Unsupported*/
1829  const cpl_propertylist * pro_synth,
1830  const cpl_propertylist * pro_bpmhot,
1831  const cpl_propertylist * pro_bpmcold,
1832  const cpl_propertylist * pro_bpmdev,
1833  const char *package,
1834  const cpl_image * masterbias,
1835  const cpl_image * synthetic,
1836  const cpl_mask * bpmhot,
1837  const cpl_mask * bpmcold,
1838  const cpl_mask * bpmdev,
1839  cpl_propertylist * qclist,
1840  const int flag_sets,
1841  const int which_set,
1842  cpl_frameset * usedframes,
1843  int whichext)
1844 {
1845 
1846  cpl_frame *ref_frame;
1847  cpl_propertylist *plist = NULL;
1848  char *name_o = NULL; /* Avoid (false) uninit warning */
1849 
1850  cpl_propertylist * paflist = NULL;
1851  cpl_propertylist * mainplist = NULL;
1852  cpl_propertylist * xplist = NULL;
1853  cpl_image * image = NULL;
1854 
1855  cpl_propertylist * mypro_master =
1856  cpl_propertylist_duplicate(pro_master);
1857 
1858  cpl_propertylist * mypro_synth = NULL;
1859  cpl_propertylist * mypro_bpmhot =
1860  cpl_propertylist_duplicate(pro_bpmhot);
1861  cpl_propertylist * mypro_bpmcold =
1862  cpl_propertylist_duplicate(pro_bpmcold);
1863  cpl_propertylist * mypro_bpmdev =
1864  cpl_propertylist_duplicate(pro_bpmdev);
1865 
1866  cpl_ensure_code(parlist != NULL, CPL_ERROR_NULL_INPUT);
1867  cpl_ensure_code(frameset != NULL, CPL_ERROR_NULL_INPUT);
1868  cpl_ensure_code(pafregexp != NULL, CPL_ERROR_NULL_INPUT);
1869  cpl_ensure_code(package != NULL, CPL_ERROR_NULL_INPUT);
1870  cpl_ensure_code(recipe_name != NULL, CPL_ERROR_NULL_INPUT);
1871  cpl_ensure_code(pipeline_name != NULL, CPL_ERROR_NULL_INPUT);
1872  cpl_ensure_code(usedframes != NULL, CPL_ERROR_NULL_INPUT);
1873 
1874  if (pro_synth)
1875  mypro_synth = cpl_propertylist_duplicate(pro_synth);
1876 
1877  /* Extra check while XSTR and YSTR are not supported */
1878  cpl_ensure_code(pro_xstr == NULL && pro_ystr == NULL,
1879  CPL_ERROR_UNSUPPORTED_MODE);
1880 
1881  /* Extract extension headers if multi-extension */
1882  if (detmon_ronbias_config.exts < 0) {
1883  const char * filename =
1884  cpl_frame_get_filename(cpl_frameset_get_position(frameset, 0));
1885 
1886 
1887  xplist = cpl_propertylist_load_regexp(filename, whichext,
1888  "ESO DET", 0);
1889  skip_if(cpl_propertylist_append(xplist, qclist));
1890  }
1891 
1892  cpl_msg_info(cpl_func,"dealing with extention %d",whichext);
1893 
1894  /* This is only used later for PAF */
1895  /* Get FITS header from reference file */
1896  ref_frame = cpl_frameset_get_position(frameset, 0);
1897  skip_if(ref_frame == NULL);
1898 
1899  skip_if((mainplist =
1900  cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
1901  0)) == NULL);
1902 
1903  /**************************/
1904  /* Write the MASTERBIAS */
1905  /**************************/
1906 
1907  /* Set the file name for the table */
1908  if(!flag_sets) {
1909  name_o = cpl_sprintf("%s_masterbias.fits", recipe_name);
1910  assert(name_o != NULL);
1911  } else {
1912  name_o =
1913  cpl_sprintf("%s_masterbias_set%02d.fits", recipe_name,
1914  which_set);
1915  assert(name_o != NULL);
1916  }
1917  /* Save the MASTERBIAS image */
1918  if (whichext == 0) {
1919  cpl_propertylist_append(mypro_master, qclist);
1920 
1921  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL,
1922  masterbias, CPL_BPP_IEEE_FLOAT, recipe_name,
1923  mypro_master, NULL, package, name_o));
1924  } else
1925  skip_if(cpl_image_save(masterbias,
1926  name_o, CPL_BPP_IEEE_FLOAT, xplist,
1927  CPL_IO_EXTEND));
1928 
1929  /* Free */
1930  cpl_free(name_o);
1931  name_o = NULL;
1932 
1933  /*****************************/
1934  /* Write the HOT PIXEL MAP */
1935  /*****************************/
1936 
1937  /* Set the file name for the table */
1938  if(!flag_sets) {
1939  name_o = cpl_sprintf("%s_hotpixmap.fits", recipe_name);
1940  assert(name_o != NULL);
1941  } else {
1942  name_o =
1943  cpl_sprintf("%s_hotpixmap_set%02d.fits", recipe_name,
1944  which_set);
1945  assert(name_o != NULL);
1946  }
1947  /* Save the HOTBPM image */
1948  skip_if(0);
1949  image = cpl_image_new_from_mask(bpmhot);
1950  cpl_error_reset();
1951 
1952  if (whichext == 0) {
1953  cpl_propertylist_append(mypro_bpmhot, qclist);
1954 
1955  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL,
1956  image, CPL_BPP_IEEE_FLOAT, recipe_name,
1957  mypro_bpmhot, NULL, package, name_o));
1958  } else
1959  skip_if(cpl_image_save(image,
1960  name_o, CPL_BPP_IEEE_FLOAT, xplist,
1961  CPL_IO_EXTEND));
1962 
1963  /* Free */
1964  cpl_free(name_o);
1965  cpl_image_delete(image);
1966  image = NULL;
1967  name_o = NULL;
1968 
1969  /*****************************/
1970  /* Write the COLD PIXEL MAP */
1971  /*****************************/
1972 
1973  /* Set the file name for the table */
1974  if(!flag_sets) {
1975  name_o = cpl_sprintf("%s_coldpixmap.fits", recipe_name);
1976  assert(name_o != NULL);
1977  } else {
1978  name_o =
1979  cpl_sprintf("%s_coldpixmap_set%02d.fits", recipe_name,
1980  which_set);
1981  assert(name_o != NULL);
1982  }
1983  /* Save the COLDBPM image */
1984  skip_if(0);
1985  image = cpl_image_new_from_mask(bpmcold);
1986  cpl_error_reset();
1987 
1988  if (whichext == 0) {
1989  cpl_propertylist_append(mypro_bpmcold, qclist);
1990 
1991  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes, NULL,
1992  image, CPL_BPP_IEEE_FLOAT, recipe_name,
1993  mypro_bpmcold, NULL, package, name_o));
1994  } else
1995  skip_if(cpl_image_save(image,
1996  name_o, CPL_BPP_IEEE_FLOAT, xplist,
1997  CPL_IO_EXTEND));
1998 
1999  /* Free */
2000  cpl_free(name_o);
2001  cpl_image_delete(image);
2002  image = NULL;
2003  name_o = NULL;
2004 
2005  /*****************************/
2006  /* Write the DEV PIXEL MAP */
2007  /*****************************/
2008 
2009  /* Set the file name for the table */
2010  if(!flag_sets) {
2011  name_o = cpl_sprintf("%s_devpixmap.fits", recipe_name);
2012  assert(name_o != NULL);
2013  } else {
2014  name_o =
2015  cpl_sprintf("%s_devpixmap_set%02d.fits", recipe_name,
2016  which_set);
2017  assert(name_o != NULL);
2018  }
2019  /* Save the DEVBPM image */
2020  skip_if(0);
2021  image = cpl_image_new_from_mask(bpmdev);
2022  cpl_error_reset();
2023 
2024  if (whichext == 0) {
2025  cpl_propertylist_append(mypro_bpmdev, qclist);
2026 
2027  skip_if(cpl_dfs_save_image(frameset, NULL,parlist, usedframes, NULL,
2028  image, CPL_BPP_IEEE_FLOAT, recipe_name,
2029  mypro_bpmdev, NULL, package, name_o));
2030  } else
2031  skip_if(cpl_image_save(image,
2032  name_o, CPL_BPP_IEEE_FLOAT, xplist,
2033  CPL_IO_EXTEND));
2034 
2035  /* Free */
2036  cpl_free(name_o);
2037  cpl_image_delete(image);
2038  image = NULL;
2039  name_o = NULL;
2040 
2041  /*******************************/
2042  /* Write the SYNTHETIC */
2043  /*******************************/
2044  if(detmon_ronbias_config.method_bitmask & PREOVERSCAN) {
2045  /* Set the file name for the table */
2046  if(!flag_sets) {
2047  name_o = cpl_sprintf("%s_synthetic.fits", recipe_name);
2048  assert(name_o != NULL);
2049  } else {
2050  name_o =
2051  cpl_sprintf("%s_synthetic_set%02d.fits", recipe_name,
2052  which_set);
2053  assert(name_o != NULL);
2054  }
2055 
2056  if (whichext == 0) {
2057  /* Save the SYNTHETIC image */
2058  cpl_propertylist_append(mypro_synth, qclist);
2059 
2060  skip_if(cpl_dfs_save_image(frameset, NULL, parlist, usedframes,
2061  NULL,synthetic, CPL_BPP_IEEE_DOUBLE,
2062  recipe_name, mypro_synth, NULL,
2063  package, name_o));
2064  } else
2065  skip_if(cpl_image_save(synthetic, name_o, CPL_BPP_IEEE_FLOAT,
2066  xplist, CPL_IO_EXTEND));
2067 
2068  /* Free */
2069  cpl_free(name_o);
2070  name_o = NULL;
2071  }
2072 
2073  /*******************************/
2074  /* Write the PAF file */
2075  /*******************************/
2076  if (qclist) {
2077  paflist = cpl_propertylist_new();
2078 
2079  /* Set the file name for the PAF */
2080  if(detmon_ronbias_config.exts >= 0) {
2081  skip_if((plist =
2082  cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
2083  detmon_ronbias_config.exts)) == NULL);
2084 
2085  if(!flag_sets) {
2086  name_o = cpl_sprintf("%s.paf", recipe_name);
2087  assert(name_o != NULL);
2088  } else {
2089  name_o = cpl_sprintf("%s_set%02d.paf",
2090  recipe_name, which_set);
2091  assert(name_o != NULL);
2092  }
2093  } else {
2094  skip_if((plist =
2095  cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
2096  whichext)) == NULL);
2097 
2098 
2099  if(!flag_sets) {
2100  name_o = cpl_sprintf("%s_ext%02d.paf",
2101  recipe_name, whichext);
2102  assert(name_o != NULL);
2103  } else {
2104  name_o = cpl_sprintf("%s_set%02d_ext%02d.paf",
2105  recipe_name,
2106  which_set, whichext);
2107  assert(name_o != NULL);
2108  }
2109  }
2110 
2111  /* Get the keywords for the paf file */
2112  skip_if(cpl_propertylist_copy_property_regexp(paflist, plist,
2113  pafregexp, 0));
2114  skip_if(cpl_propertylist_copy_property_regexp(paflist, mainplist,
2115  pafregexp, 0));
2116 
2117  skip_if(cpl_propertylist_append(paflist, qclist));
2118 
2119  /* Save the PAF */
2120  skip_if(cpl_dfs_save_paf(pipeline_name, recipe_name, paflist, name_o));
2121 
2122  }
2123 
2124  end_skip;
2125 
2126  cpl_propertylist_delete(plist);
2127  cpl_propertylist_delete(paflist);
2128  cpl_propertylist_delete(mainplist);
2129  cpl_propertylist_delete(xplist);
2130  cpl_free(name_o);
2131  cpl_image_delete(image);
2132 
2133  cpl_propertylist_delete(mypro_master);
2134  cpl_propertylist_delete(mypro_synth);
2135  cpl_propertylist_delete(mypro_bpmhot);
2136  cpl_propertylist_delete(mypro_bpmcold);
2137  cpl_propertylist_delete(mypro_bpmdev);
2138 
2139  return cpl_error_get_code();
2140 }
2141 
2142 /*---------------------------------------------------------------------------*/
2143 /*
2144  * @brief Classify input data with a given tag
2145  * @param set Input frameset
2146  * @param tag Input tag
2147  * @return 0 on success, -1 if failure
2148  */
2149 /*---------------------------------------------------------------------------*/
2150 static int
2151 detmon_ronbias_dfs_set_groups(cpl_frameset * set, const char *tag)
2152 {
2153 
2154 
2155  int nframes;
2156  int i;
2157 
2158  /* Check entries */
2159  if(set == NULL)
2160  return -1;
2161 
2162  /* Initialize */
2163  nframes = cpl_frameset_get_size(set);
2164 
2165  /* Loop on frames */
2166  for(i = 0; i < nframes; i++) {
2167  cpl_frame* cur_frame = cpl_frameset_get_position(set, i);
2168  const char* cur_tag = cpl_frame_get_tag(cur_frame);
2169 
2170  /* RAW frames */
2171  if(!strcmp(cur_tag, tag))
2172  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_RAW);
2173  /* CALIB frames */
2174 
2175  /* else if (!strcmp(tag, IIINSTRUMENT_CALIB_FLAT))
2176  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_CALIB) ;
2177  */
2178  }
2179  return 0;
2180 }
2181 
2182 /*---------------------------------------------------------------------------*/
2183 
2184 /*
2185  * @brief build synthetic frame from pre-overscan images
2186  *
2187  * @param prescan prescan image
2188  * @param overscan overscan image
2189  *
2190  * @return CPL_ERROR_NONE on success.
2191  */
2192 
2193 /*---------------------------------------------------------------------------*/
2194 static cpl_image *
2195 detmon_build_synthetic_from_pre_overscan(const cpl_image * prescan,
2196  const cpl_image * overscan)
2197 {
2198  cpl_size j;
2199 
2200  int distance = detmon_ronbias_config.overscan_urx -
2201  detmon_ronbias_config.prescan_llx + 1;
2202 
2203  double * mean_x = (double *) cpl_malloc(sizeof(double) * distance);
2204 
2205  double * xvalues = (double *) cpl_malloc(sizeof(double) * distance);
2206 
2207  cpl_vector *x = NULL;
2208  cpl_vector *y = NULL;
2209 
2210  cpl_polynomial *poly = NULL;
2211  cpl_polynomial *poly2 = NULL;
2212 
2213  cpl_matrix * samppos;
2214 
2215  cpl_size pows[2] = { 0, 0 };
2216 
2217  cpl_image * synthetic = NULL;
2218 
2219  double initial = 0;
2220 
2221  /* Initialize */
2222  for(j = 0; j < distance; j++) {
2223  *(mean_x + j) = 0;
2224  *(xvalues + j) = j;
2225  }
2226 
2227  for(j = 0; j < cpl_image_get_size_x(prescan); j++) {
2228  *(mean_x + j) =
2229  cpl_image_get_mean_window(prescan, j + 1, 1, j + 1,
2230  cpl_image_get_size_y(prescan));
2231  }
2232 
2233  for(j = 0; j < cpl_image_get_size_x(overscan); j++) {
2234  *(mean_x + distance - cpl_image_get_size_x(overscan) + j) =
2235  cpl_image_get_mean_window(overscan, j + 1, 1, j + 1,
2236  cpl_image_get_size_y(overscan));
2237  }
2238 
2239  x = cpl_vector_wrap(distance, xvalues);
2240  y = cpl_vector_wrap(distance, mean_x);
2241 
2242  poly = cpl_polynomial_new(1);
2243  samppos =
2244  cpl_matrix_wrap(1, cpl_vector_get_size(x), cpl_vector_get_data(x));
2245 
2246  cpl_polynomial_fit(poly, samppos, NULL, y, NULL,
2247  CPL_FALSE, NULL, &detmon_ronbias_config.preoverscan_degree);
2248 
2249  cpl_matrix_unwrap(samppos);
2250 
2251  cpl_vector_unwrap(x);
2252  cpl_vector_unwrap(y);
2253 
2254  initial = *mean_x;
2255 
2256  cpl_free(xvalues);
2257  cpl_free(mean_x);
2258 
2259  poly2 = cpl_polynomial_new(2);
2260 
2261  j = 0;
2262  cpl_polynomial_set_coeff(poly2, pows, cpl_polynomial_get_coeff(poly, &j));
2263 
2264  pows[0] = 1;
2265  j = 1;
2266  cpl_polynomial_set_coeff(poly2, pows, cpl_polynomial_get_coeff(poly, &j));
2267 
2268  cpl_polynomial_delete(poly);
2269 
2270  synthetic =
2271  cpl_image_new(distance, cpl_image_get_size_y(prescan),
2272  CPL_TYPE_DOUBLE);
2273 
2274  if(cpl_image_fill_polynomial(synthetic, poly2, initial, 1, 1, 1)) {
2275  cpl_msg_error(cpl_func, "Error creating the synthetic frame");
2276  cpl_polynomial_delete(poly2);
2277  return NULL;
2278  }
2279 
2280  cpl_polynomial_delete(poly2);
2281 
2282  return synthetic;
2283 }
2284 
2285 /*---------------------------------------------------------------------------*/
2286 
2287 /*
2288  * @brief computes dutycycle
2289  * @param frameset Input frameset
2290  * @param qclist header to hold qc parameter
2291  * @return CPL_ERROR_NONE on success.
2292  */
2293 
2294 /*---------------------------------------------------------------------------*/
2295 static cpl_error_code
2296 detmon_ronbias_dutycycl(const cpl_frameset * frameset,
2297  cpl_propertylist * qclist)
2298 {
2299  const cpl_frame *first = 0;
2300  cpl_propertylist *plistfirst = 0;
2301  double tfirst;
2302  int nraws;
2303  const cpl_frame *last = 0;
2304  cpl_propertylist *plistlast = 0;
2305  double tlast;
2306  double dutycycl;
2307  cpl_error_code error;
2308 
2309  first = cpl_frameset_get_position_const(frameset, 0);
2310  plistfirst = cpl_propertylist_load(cpl_frame_get_filename(first), 0);
2311  tfirst = cpl_propertylist_get_double(plistfirst, "MJD-OBS");
2312  nraws = cpl_frameset_get_size(frameset);
2313  last = cpl_frameset_get_position_const(frameset, nraws - 1);
2314  plistlast = cpl_propertylist_load(cpl_frame_get_filename(last), 0);
2315  tlast = cpl_propertylist_get_double(plistlast, "MJD-OBS");
2316  dutycycl = (tlast - tfirst) / (nraws - 1);
2317 
2318  error = cpl_error_get_code();
2319  if (error != CPL_ERROR_NONE)
2320  {
2321  goto cleanup;
2322  }
2323  cpl_propertylist_append_double(qclist,DETMON_QC_DUTYCYCL, dutycycl);
2324  error = cpl_propertylist_set_comment(qclist,DETMON_QC_DUTYCYCL,
2325  DETMON_QC_DUTYCYCL_C);
2326 
2327 cleanup:
2328 
2329  cpl_propertylist_delete(plistfirst);
2330  cpl_propertylist_delete(plistlast);
2331 
2332  return error;
2333 }
2334 
2335 
2336 /* Start duplicated code */
2337 
2338 #define RECT_RON_HS 4
2339 #define RECT_RON_SAMPLES 100
2340 
2341 /*---------------------------------------------------------------------------*/
2342 
2343 /*
2344  * @brief Computes bias level and ron in a region
2345  * @param diff Input difference image
2346  * @param zone_def Input zone definition
2347  * @param ron_hsize window half size to compute ron
2348  * @param ron_nsamp number of (randomly distributed) sampling windows
2349  * @param bias output bias level
2350  * @param error output error associated to bias level
2351  * @return CPL_ERROR_NONE on success.
2352  */
2353 
2354 /*---------------------------------------------------------------------------*/
2355 cpl_error_code
2356 irplib_flux_get_bias_window(const cpl_image * diff,
2357  const int *zone_def,
2358  int ron_hsize,
2359  int ron_nsamp, double *bias, double *error)
2360 {
2361  const int hsize = ron_hsize < 0 ? RECT_RON_HS : ron_hsize;
2362  const int nsamples =
2363  ron_nsamp < 0 ? RECT_RON_SAMPLES : ron_nsamp;
2364  cpl_bivector *sample_reg;
2365  cpl_vector *rms_list;
2366  int rect[4];
2367  int zone[4];
2368  double *px;
2369  double *py;
2370  double *pr;
2371  int i;
2372 
2373  /* Test entries */
2374  cpl_ensure_code(diff && bias, CPL_ERROR_NULL_INPUT);
2375 
2376  /* Generate nsamples window centers in the image */
2377  if(zone_def != NULL) {
2378  rect[0] = zone_def[0] + hsize + 1; /* xmin */
2379  rect[1] = zone_def[1] - hsize - 1; /* xmax */
2380  rect[2] = zone_def[2] + hsize + 1; /* ymin */
2381  rect[3] = zone_def[3] - hsize - 1; /* ymax */
2382  } else {
2383  rect[0] = hsize + 1; /* xmin */
2384  rect[1] = cpl_image_get_size_x(diff) - hsize - 1; /* xmax */
2385  rect[2] = hsize + 1; /* ymin */
2386  rect[3] = cpl_image_get_size_y(diff) - hsize - 1; /* ymax */
2387  }
2388 
2389  cpl_ensure_code(rect[0] < rect[1] && rect[2] < rect[3],
2390  CPL_ERROR_ILLEGAL_INPUT);
2391 
2392  /* Generate n+1 regions, because the first region is always at (0,0) */
2393  /* and it would bias the measurement. */
2394  sample_reg =
2395  irplib_bivector_gen_rect_poisson(rect, nsamples + 1, nsamples + 1);
2396  cpl_ensure(sample_reg != NULL, CPL_ERROR_ILLEGAL_INPUT,
2397  CPL_ERROR_ILLEGAL_INPUT);
2398 
2399  px = cpl_bivector_get_x_data(sample_reg);
2400  py = cpl_bivector_get_y_data(sample_reg);
2401 
2402  /* Now, for each window center, extract a vignette and compute the */
2403  /* signal RMS in it. Store this rms into a table. */
2404  rms_list = cpl_vector_new(nsamples);
2405  cpl_ensure(rms_list != NULL, CPL_ERROR_NULL_INPUT, CPL_ERROR_NULL_INPUT);
2406  pr = cpl_vector_get_data(rms_list);
2407 
2408  for(i = 0; i < nsamples; i++) {
2409  zone[0] = (int) px[i + 1] - hsize;
2410  zone[1] = (int) px[i + 1] + hsize;
2411  zone[2] = (int) py[i + 1] - hsize;
2412  zone[3] = (int) py[i + 1] + hsize;
2413  pr[i] = cpl_image_get_mean_window(diff,
2414  zone[0], zone[2], zone[1], zone[3]);
2415  }
2416  cpl_bivector_delete(sample_reg);
2417 
2418  /* The error is the rms of the rms */
2419  if(error != NULL)
2420  *error = cpl_vector_get_stdev(rms_list);
2421 
2422  /* The final computed RMS is the median of all values. */
2423  /* This call will modify the rms_list */
2424  *bias = cpl_vector_get_median(rms_list);
2425 
2426  cpl_vector_delete(rms_list);
2427 
2428  return CPL_ERROR_NONE;
2429 }
2430 
2431 #undef RECT_RON_HS
2432 #undef RECT_RON_SAMPLES
2433 
2434 /*---------------------------------------------------------------------------*/
2435 
2436 /*
2437  * @brief Generates Poisson distributed values
2438  * @param r Input values
2439  * @param np number of points
2440  * @param homog homogeneity factor
2441  * @return CPL_ERROR_NONE on success.
2442  */
2443 
2444 /*---------------------------------------------------------------------------*/
2445 static cpl_bivector *
2446 irplib_bivector_gen_rect_poisson(const int *r, const int np, const int homog)
2447 {
2448  double min_dist;
2449  int i;
2450  int gnp;
2451  cpl_bivector *list;
2452  double cand_x, cand_y;
2453  int ok;
2454  int start_ndx;
2455  int xmin, xmax, ymin, ymax;
2456 
2457  /* Corrected Homogeneity factor */
2458  const int homogc = 0 < homog && homog < np ? homog : np;
2459  double *px;
2460  double *py;
2461 
2462  /* error handling: test arguments are correct */
2463  cpl_ensure(r, CPL_ERROR_NULL_INPUT, NULL);
2464  cpl_ensure(np > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
2465 
2466  list = cpl_bivector_new(np);
2467  cpl_ensure(list, CPL_ERROR_NULL_INPUT, NULL);
2468  px = cpl_bivector_get_x_data(list);
2469  py = cpl_bivector_get_y_data(list);
2470 
2471  xmin = r[0];
2472  xmax = r[1];
2473  ymin = r[2];
2474  ymax = r[3];
2475 
2476  min_dist =
2477  CPL_MATH_SQRT1_2 * ((xmax - xmin) * (ymax - ymin) / (double) (homogc + 1));
2478  gnp = 1;
2479  px[0] = 0;
2480  py[0] = 0;
2481 
2482  /* First: generate <homog> points */
2483  while(gnp < homogc) {
2484  /* Pick a random point within requested range */
2485  cand_x = cpl_drand() * (xmax - xmin) + xmin;
2486  cand_y = cpl_drand() * (ymax - ymin) + ymin;
2487 
2488  /* Check the candidate obeys the minimal Poisson distance */
2489  ok = 1;
2490  for(i = 0; i < gnp; i++) {
2491  if(pdist(cand_x, cand_y, px[i], py[i]) < min_dist) {
2492  /* does not check Poisson law: reject point */
2493  ok = 0;
2494  break;
2495  }
2496  }
2497  if(ok) {
2498  /* obeys Poisson law: register the point as valid */
2499  px[gnp] = cand_x;
2500  py[gnp] = cand_y;
2501  gnp++;
2502  }
2503  }
2504 
2505  /* Iterative process: */
2506  /* Pick points out of Poisson distance of the last <homogc-1> points. */
2507  start_ndx = 0;
2508  while(gnp < np) {
2509  /* Pick a random point within requested range */
2510  cand_x = cpl_drand() * (xmax - xmin) + xmin;
2511  cand_y = cpl_drand() * (ymax - ymin) + ymin;
2512 
2513  /* Check the candidate obeys the minimal Poisson distance */
2514  ok = 1;
2515  for(i = 0; i < homogc; i++) {
2516  if(pdist(cand_x,
2517  cand_y,
2518  px[start_ndx + i], py[start_ndx + i]) < min_dist) {
2519  /* does not check Poisson law: reject point */
2520  ok = 0;
2521  break;
2522  }
2523  }
2524  if(ok) {
2525  /* obeys Poisson law: register the point as valid */
2526  px[gnp] = cand_x;
2527  py[gnp] = cand_y;
2528  gnp++;
2529  }
2530  }
2531 
2532  /* Iterative process: */
2533  /* Pick points out of Poisson distance of the last <homogc-1> points. */
2534  start_ndx = 0;
2535  while(gnp < np) {
2536  /* Pick a random point within requested range */
2537  cand_x = cpl_drand() * (xmax - xmin) + xmin;
2538  cand_y = cpl_drand() * (ymax - ymin) + ymin;
2539 
2540  /* Check the candidate obeys the minimal Poisson distance */
2541  ok = 1;
2542  for(i = 0; i < homogc; i++) {
2543  if(pdist(cand_x,
2544  cand_y,
2545  px[start_ndx + i], py[start_ndx + i]) < min_dist) {
2546  /* does not check Poisson law: reject point */
2547  ok = 0;
2548  break;
2549  }
2550  }
2551  if(ok) {
2552  /* obeys Poisson law: register the point as valid */
2553  px[gnp] = cand_x;
2554  py[gnp] = cand_y;
2555  gnp++;
2556  start_ndx++;
2557  }
2558  }
2559  return list;
2560 }
2561 
2562 /* End of duplicated code */
2563 
2564 
2565 /*---------------------------------------------------------------------------*/
2582 /*---------------------------------------------------------------------------*/
2583 cpl_image *
2584 irplib_imagelist_collapse_stdev_create(const cpl_imagelist * imlist)
2585 {
2586 
2587 
2588 
2589 
2590 
2591 
2592  /* Check inputs */
2593  cpl_ensure(imlist != NULL, CPL_ERROR_NULL_INPUT, NULL);
2594  cpl_ensure(cpl_imagelist_is_uniform(imlist) == 0, CPL_ERROR_ILLEGAL_INPUT,
2595  NULL);
2596 
2597  /* Create mean image with its first iterative value = first image */
2598  cpl_image* mean = cpl_image_duplicate(cpl_imagelist_get_const(imlist, 0));
2599  cpl_image_fill_rejected(mean, 0.0);
2600  cpl_image_accept_all(mean);
2601 
2602  cpl_image* stdev = cpl_image_new(cpl_image_get_size_x(mean),
2603  cpl_image_get_size_y(mean),
2604  CPL_TYPE_FLOAT);
2605 
2606  for (int i = 1; i < cpl_imagelist_get_size(imlist); i++) {
2607  cpl_image* delta = cpl_image_subtract_create(cpl_imagelist_get_const(imlist, i),
2608  mean);
2609  cpl_image_fill_rejected(delta, 0.0);
2610  cpl_image_accept_all(delta);
2611 
2612  cpl_image* sq_delta = cpl_image_multiply_create(delta, delta);
2613 
2614  cpl_image_multiply_scalar(sq_delta, ((double) i / (double)(i+1)));
2615  cpl_image_add(stdev, sq_delta);
2616 
2617  cpl_image_divide_scalar(delta, i + 1);
2618  cpl_image_add(mean, delta);
2619 
2620  cpl_image_delete(delta);
2621  cpl_image_delete(sq_delta);
2622  }
2623 
2624  cpl_image_divide_scalar(stdev, cpl_imagelist_get_size(imlist) - 1);
2625  cpl_image_power(stdev, 0.5);
2626 
2627  cpl_image_delete(mean);
2628 
2629  return stdev;
2630 }