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