IIINSTRUMENT Pipeline Reference Manual  1.3.12b
detmon/detmon_pernoise.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 /* Must include first to ensure declaration of complex CPL functions */
37 #include <complex.h>
38 
39 #include "detmon_pernoise.h"
40 #include "detmon.h"
41 
42 #include "irplib_ksigma_clip.h"
43 #include "irplib_hist.h"
44 #include "irplib_utils.h"
45 
46 #include <math.h>
47 #include <string.h>
48 #include <assert.h>
49 #include <float.h>
50 
51 /*----------------------------------------------------------------------------
52  Defines
53  ----------------------------------------------------------------------------*/
54 
55 /* Computes the square of an euclidean distance bet. 2 points */
56 #define pdist(x1,y1,x2,y2) (((x1-x2)*(x1-x2))+((y1-y2)*(y1-y2)))
57 
58 #define cpl_drand() ((double)rand()/(double)RAND_MAX)
60 /*--------------------------------------------------------------------------*/
61 
62 /*
63  * @defgroup detmon Detector monitoring functions
64  */
65 
66 /*--------------------------------------------------------------------------*/
67 
68 /*---------------------------------------------------------------------------
69  Defines
70  ---------------------------------------------------------------------------*/
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 
95 static struct
96 {
97  int mode;
98  cpl_boolean direction;
99  double speed;
100  int llx;
101  int lly;
102  int urx;
103  int ury;
104  int kappa;
105  int exts;
106  int nb_extensions;
107 } detmon_pernoise_config;
108 
109 
110 #define NIR TRUE
111 #define OPT FALSE
112 
113 /*---------------------------------------------------------------------------
114  Private function prototypes
115  ---------------------------------------------------------------------------*/
116 
117 /* Functions for Periodic Noise Characterisation, detmon_pernoise() */
118 
119 int
120 detmon_pernoise_dfs_set_groups(cpl_frameset *,
121  const char *);
122 
123 static cpl_error_code
124 detmon_pernoise_retrieve_parlist(const char *,
125  const char *,
126  const cpl_parameterlist *);
127 
128 static cpl_error_code
129 detmon_pernoise_qc(cpl_propertylist *,
130  cpl_table *,
131  int);
132 
133 static cpl_error_code
134 detmon_pernoise_save(const cpl_parameterlist *,
135  cpl_frameset *,
136  const char *,
137  const char *,
138  const char *,
139  const char *,
140  cpl_table **,
141  cpl_propertylist **,
142  const int,
143  const int,
144  const cpl_frameset *);
145 
146 cpl_error_code
147 detmon_pernoise_rm_bg(cpl_image *,
148  int,
149  int);
150 
151 /*--------------------------------------------------------------------------*/
152 
153 /*
154  * @brief Reduce periodic noise
155  * @param image Input image
156  *
157  * @return 1-d image, representing the distribution of noise. NULL if failed.
158  */
159 
160 /*--------------------------------------------------------------------------*/
161 
162 
163 #define HORIZONTAL TRUE
164 
165 cpl_table *
166 detmon_pernoise_reduce(cpl_image * image)
167 {
168  int nsamples, nffts;
169  int i, j;
170 
171  int status;
172  float * hanning = 0;
173  float * power = 0;
174  cpl_image * power_im = 0;
175  cpl_image * output = 0;
176  cpl_image * pos_spec = 0;
177  cpl_table * table = 0;
178  cpl_image* fourier_im = 0;
179  double freq;
180  cpl_error_code error = CPL_ERROR_NONE;
181  cpl_image * sub_image = 0;
182  int nffts_old;
183 
184 
185  if(detmon_pernoise_config.direction == HORIZONTAL) {
186  error = cpl_image_flip(image, 1);
187  cpl_ensure(!error, error, NULL);
188  }
189 
190  nsamples = cpl_image_get_size_x(image);
191  nffts = cpl_image_get_size_y(image);
192 
193 
194  /* Rewrite the previous lines with a better style (: ...) */
195 
196  /*
197  * 1. preprocessing task:
198  * Estimate the background fitting the image to a
199  * 2-D polynomial and substract it from the image.
200  */
201 
202  error = detmon_pernoise_rm_bg(image, nsamples, nffts);
203  cpl_ensure(!error, error, NULL);
204 
205  sub_image = cpl_image_extract(image, nsamples/8 + 1, nffts/8+1,
206  nsamples*7/8, nffts*7/8);
207  nffts_old = nffts;
208  nsamples = cpl_image_get_size_x(sub_image);
209  nffts = cpl_image_get_size_y(sub_image);
210 
211  /*
212  * 2. preprocessing task:
213  * Remove the effect of hot and dark pixels, replacing their values by
214  * the average value of the neighbouring pixels.
215  */
216 
217  /*
218  * 3. preprocessing task:
219  * Apply a Hanning vector
220  */
221 
222  hanning = cpl_malloc(sizeof(float) * nsamples);
223 
224  for(i = 0; i < nsamples; i++) {
225  *(hanning + i) = 0.5 - 0.5 * cos(2 * CPL_MATH_PI * (float) i / nsamples);
226  for(j = 0; j < nffts; j++) {
227  double value =
228  cpl_image_get(sub_image, i + 1, j + 1, &status);
229  error = cpl_image_set(sub_image, i + 1, j + 1, (*(hanning + i)) * value);
230  }
231  }
232 
233  cpl_free(hanning);
234  if (error != CPL_ERROR_NONE)
235  {
236  goto cleanup;
237  }
238 
239  power = (float *) cpl_calloc(sizeof(float), nsamples * nffts);
240 
241 
242  fourier_im = cpl_image_new(nsamples,nffts, CPL_TYPE_FLOAT_COMPLEX);
243  error = cpl_fft_image(fourier_im, sub_image, CPL_FFT_FORWARD);
244 
245  for(i = 1; i <= nffts; i++) {
246  for(j = 1; j <= nsamples; j++) {
247  int rej = 0;
248  double complex cvalue = cpl_image_get_complex(fourier_im,j, i, &rej );
249  double value = cabs(cvalue);
250  /*
251  *(power + j + i * nsamples) = *((float complex *)fourier + j + i * nsamples) *
252  conjf(*((float complex *)fourier +j + i * nsamples));
253  */
254  cpl_image_set(power_im, j, i, value);
255  }
256  /* Is it necessary to divide here by 2 * pi? */
257  }
258  cpl_image_delete(fourier_im);
259 
260  output = cpl_image_collapse_create(power_im, 0);
261  pos_spec = cpl_image_extract(output, 1, 1, nsamples/2, 1);
262 
263  cpl_image_delete(power_im);
264  cpl_free(power);
265 
266  cpl_image_delete(output);
267 
268  table = cpl_table_new(nsamples/2);
269  cpl_table_new_column(table, "FREQ", CPL_TYPE_DOUBLE);
270  cpl_table_new_column(table, "POW", CPL_TYPE_DOUBLE);
271 
272  freq = detmon_pernoise_config.speed*1000/nffts_old;
273 
274  for(i = 0; i < nsamples/2; i++) {
275  error = cpl_table_set(table, "FREQ", i, freq/(nsamples/2)*i);
276  error = cpl_table_set(table, "POW", i, cpl_image_get(pos_spec, i+1, 1, &status));
277  }
278 
279  for(i= 0; i < 5; i++) {
280  error = cpl_table_set(table, "POW", i, 0.0);
281  }
282 
283 
284 cleanup:
285  cpl_image_delete(pos_spec);
286 
287  cpl_image_delete(sub_image);
288  if (error != CPL_ERROR_NONE)
289  {
290  cpl_table_delete(table);
291  table = 0;
292  }
293  return table;
294 }
295 #undef HORIZONTAL
296 
297 
298 
299 /*---------------------------------------------------------------------------*/
300 
301 /*
302  * @brief Measure persistence noise
303  * @param frameset Input set of frames
304  * @param parlist Input parameterlist
305  * @param tag Input tag
306  * @param recipe_name input recipe name
307  * @param pipeline_name input pipeline id
308  * @param ptrocatg_tbl input table with pro catgs
309  * @param package package id
310  * @param comapre comparison function
311  * @return CPL_ERROR_NONE on success.
312  */
313 
314 /*---------------------------------------------------------------------------*/
315 cpl_error_code
316 detmon_pernoise(cpl_frameset * frameset,
317  const cpl_parameterlist * parlist,
318  const char * tag,
319  const char * recipe_name,
320  const char * pipeline_name,
321  const char * procatg_tbl,
322  const char * package,
323  int (*compare)(const cpl_frame *,
324  const cpl_frame *))
325 {
326  cpl_size nsets;
327 
328  int i;
329  cpl_error_code error;
330 
331  if(detmon_pernoise_dfs_set_groups(frameset, tag)) {
332  cpl_msg_error(cpl_func, "Cannot identify RAW and CALIB frames");
333  }
334 
335  /*
336  * This function reads all inputs parameters from parlist
337  * and stores them in a global variable detmon_ronbias_config.
338  * Similar to detmon_lg_retrieve_parlist(). See detmon.c
339  */
340  error = detmon_pernoise_retrieve_parlist(pipeline_name,
341  recipe_name, parlist);
342  cpl_ensure_code(!error, error);
343 
344  /* Labelise all input frames */
345  if(compare == NULL)
346  nsets = 1;
347  else {
348  cpl_msg_info(cpl_func, "Identify the different settings");
349  cpl_size* selection = cpl_frameset_labelise(frameset, compare, &nsets);
350  if(selection == NULL)
351  cpl_msg_error(cpl_func, "Cannot labelise input frames");
352  }
353 
354  detmon_pernoise_config.nb_extensions = 1;
355  if(detmon_pernoise_config.exts < 0) {
356  const cpl_frame *cur_frame =
357  cpl_frameset_get_position_const(frameset, 0);
358  /* Get the nb of extensions */
359  detmon_pernoise_config.nb_extensions =
360  cpl_frame_get_nextensions(cur_frame);
361  }
362 
363  /* Extract settings and reduce each of them */
364  for(i = 0; i < nsets; i++)
365  {
366  int j;
367  cpl_table ** freq_table;
368  cpl_propertylist ** qclist =
369  (cpl_propertylist **)
370  cpl_malloc(detmon_pernoise_config.nb_extensions *
371  sizeof(cpl_propertylist *));
372 
373  cpl_imagelist ** raws = (cpl_imagelist **) cpl_malloc(detmon_pernoise_config.nb_extensions * sizeof(cpl_imagelist *));
374  cpl_image ** input = (cpl_image **) cpl_malloc(detmon_pernoise_config.nb_extensions * sizeof(cpl_image *));
375 
376  /* Initialise memory for products */
377  if(detmon_pernoise_config.mode == 1)
378  {
379  freq_table =
380  (cpl_table **) cpl_malloc(detmon_pernoise_config.nb_extensions *
381  4 * sizeof(cpl_table *));
382  } else
383  {
384  freq_table =
385  (cpl_table **) cpl_malloc(detmon_pernoise_config.nb_extensions *
386  sizeof(cpl_table *));
387  }
388 
389  if(detmon_pernoise_config.exts >= 0)
390  {
391  *raws =
392  cpl_imagelist_load_frameset(frameset, CPL_TYPE_FLOAT, 1,
393  detmon_pernoise_config.exts);
394  *input = cpl_image_subtract_create(cpl_imagelist_get(*raws,0),
395  cpl_imagelist_get(*raws,1));
396  } else
397  {
398  cpl_imagelist *raws_all_exts =
399  cpl_imagelist_load_frameset(frameset, CPL_TYPE_FLOAT, 1,
400  -1);
401  for(j = 0; j < detmon_pernoise_config.nb_extensions; j++)
402  {
403  int nframes = cpl_frameset_get_size(frameset);
404  int k;
405  for(k = 0; k < nframes; k++)
406  {
407  cpl_image *image =
408  cpl_imagelist_unset(raws_all_exts,
409  (detmon_pernoise_config.
410  nb_extensions - 1 - j) * k);
411  cpl_imagelist_set(raws[j], image, k);
412  }
413  input[j] =
414  cpl_image_subtract_create(cpl_imagelist_get(raws[j],0),
415  cpl_imagelist_get(raws[j],1));
416  }
417  }
418 
419  for(j = 0; j < detmon_pernoise_config.nb_extensions; j++) {
420  cpl_msg_info(cpl_func, "Starting reduction");
421  qclist[j] = cpl_propertylist_new();
422  if(detmon_pernoise_config.mode == 1)
423  {
424  int nx = cpl_image_get_size_x(input[j]);
425  int ny = cpl_image_get_size_y(input[j]);
426  int k = 0;
427  cpl_image* quad[4];
428 
429  quad[0] = cpl_image_extract(input[j], 1, 1, nx/2, ny/2);
430  quad[1] = cpl_image_extract(input[j], 1, ny/2+1, nx/2, ny);
431  quad[2] = cpl_image_extract(input[j], nx/2+1, 1, nx, ny/2);
432  quad[3] = cpl_image_extract(input[j], nx/2+1, ny/2+1, nx, ny);
433 
434  for (k = 0; k < 4; k++)
435  {
436  freq_table[j * 4 + k] = detmon_pernoise_reduce(quad[k]);
437  }
438  for(k = 0; k < 4; k++)
439  {
440  error = detmon_pernoise_qc(qclist[j], freq_table[j + k], k+1);
441  if (error != CPL_ERROR_NONE)
442  break;
443  }
444  for (k = 0; k < 4; k++)
445  {
446  cpl_image_delete(quad[k]);
447  }
448  } else
449  {
450  freq_table[j] = detmon_pernoise_reduce(input[j]);
451  if(freq_table[j] != NULL)
452  {
453  error = detmon_pernoise_qc(qclist[j], freq_table[j], 0);
454  }
455  }
456  if (error != CPL_ERROR_NONE)
457  {
458  break;
459  }
460  }
461  if (error == CPL_ERROR_NONE)
462  {
463  error = detmon_pernoise_save(parlist, frameset, recipe_name,
464  pipeline_name, procatg_tbl,
465  package, freq_table, qclist, 0,
466  0, frameset);
467  }
468 
469  for(j = 0; j < detmon_pernoise_config.nb_extensions; j++)
470  {
471  cpl_propertylist_delete(qclist[j]);
472  cpl_imagelist_delete(raws[j]);
473  cpl_image_delete(input[j]);
474  }
475  cpl_free(qclist);
476  cpl_free(raws);
477  cpl_free(input);
478  if(detmon_pernoise_config.mode == 1)
479  {
480  for(j= 0; j < detmon_pernoise_config.nb_extensions * 4; j++) {
481  cpl_table_delete(freq_table[j]);
482  }
483  } else {
484  for(j= 0; j < detmon_pernoise_config.nb_extensions; j++) {
485  cpl_table_delete(freq_table[j]);
486  }
487  }
488  cpl_free(freq_table);
489  if (error != CPL_ERROR_NONE)
490  {
491  break;
492  }
493  }
494 
495  return cpl_error_get_code();
496 }
497 
498 /*---------------------------------------------------------------------------*/
499 
500 /*
501  * @brief classifies input frames matching input tag
502  * @param set input frameset
503  * @param tag input tag
504  * @return 0 on success, else -1
505  */
506 
507 /*---------------------------------------------------------------------------*/
508 int
509 detmon_pernoise_dfs_set_groups(cpl_frameset * set, const char *tag)
510 {
511 
512 
513  int nframes;
514  int i;
515 
516  /* Check entries */
517  if(set == NULL)
518  return -1;
519 
520  /* Initialize */
521  nframes = cpl_frameset_get_size(set);
522 
523  /* Loop on frames */
524  for(i = 0; i < nframes; i++) {
525  cpl_frame* cur_frame = cpl_frameset_get_position(set, i);
526  const char* cur_tag = cpl_frame_get_tag(cur_frame);
527 
528  /* RAW frames */
529  if(!strcmp(cur_tag, tag))
530  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_RAW);
531  /* CALIB frames */
532 
533  /* else if (!strcmp(tag, IIINSTRUMENT_CALIB_FLAT))
534  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_CALIB) ;
535  */
536  }
537  return 0;
538 }
539 
540 /*---------------------------------------------------------------------------*/
541 
542 /*
543  * @brief Initialize pernoise recipe parameters structure
544  * @param parlist input parameter list
545  * @param recipe_name Input recipe name
546  * @param pipeline_name Input pipeline name
547  * @param mode mode to indicate if pix2pix,opt/nir,etc
548  * @param direction read-out direction
549  * @param speed read-out speed
550  * @param llx lower-left X coordinate
551  * @param lly lower-left Y coordinate
552  * @param urx upper-right X coordinate
553  * @param ury upper-right Y coordinate
554  * @param kappa kappa value in kappa-sigma clip
555  * @param exts extension id
556 
557  * @return CPL_ERROR_NONE on success.
558  */
559 
560 /*---------------------------------------------------------------------------*/
561  cpl_error_code
562 detmon_fill_pernoise_params(cpl_parameterlist * parlist,
563  const char *recipe_name,
564  const char *pipeline_name,
565  int mode,
566  const char * direction,
567  double speed,
568  int llx,
569  int lly,
570  int urx,
571  int ury,
572  double kappa,
573  int exts)
574 {
575  detmon_fill_parlist(parlist, recipe_name, pipeline_name, 9,
576 
577  "mode",
578  "Mode",
579  "CPL_TYPE_INT", mode,
580 
581  "direction",
582  "Readout direction",
583  "CPL_TYPE_BOOL", direction,
584 
585  "speed",
586  "Readout speed",
587  "CPL_TYPE_DOUBLE", speed,
588 
589  "llx",
590  "(yet unsupported) x coordinate of the lower-left "
591  "point of the region of interest. If not modified, default value will be 1.",
592  "CPL_TYPE_INT", llx,
593  "lly",
594  "(yet unsupported) y coordinate of the lower-left "
595  "point of the region of interest. If not modified, default value will be 1.",
596  "CPL_TYPE_INT", lly,
597  "urx",
598  "(yet unsupported) x coordinate of the upper-right "
599  "point of the region of interest. If not modified, default value will be X dimension of the input image.",
600  "CPL_TYPE_INT", urx,
601  "ury",
602  "(yet unsupported) y coordinate of the upper-right "
603  "point of the region of interest. If not modified, default value will be Y dimension of the input image.",
604  "CPL_TYPE_INT", ury,
605 
606  "kappa",
607  "Kappa used for determining threshold of bad (hot, cold) pixels",
608  "CPL_TYPE_DOUBLE", kappa,
609 
610  "exts",
611  "Activate the multi-exts option",
612  "CPL_TYPE_INT", exts);
613 
614  return 0;
615 }
616 
617 /*---------------------------------------------------------------------------*/
618 /*
619  * @brief initialise pernoise parameter structure
620  * @param parlist Shift to apply on the x-axis
621  * @param recipe_name Input recipe id
622  * @param pipeline_name Input pipeline id
623  * @return 0 .
624  */
625 
626 /*---------------------------------------------------------------------------*/
627 int
628 detmon_fill_pernoise_params_default(cpl_parameterlist * parlist,
629  const char *recipe_name,
630  const char *pipeline_name)
631 {
632  detmon_fill_pernoise_params(parlist, recipe_name, pipeline_name,
633  1, /* --mode */
634  "CPL_TRUE", /* --direction */
635  84.5, /* --speed */
636  -1, /* --llx */
637  -1, /* --lly */
638  -1, /* --urx */
639  -1, /* --ury */
640  100, /* --kappa */
641  0); /* --exts */
642 
643  return 0;
644 
645 }
646 
647 /*---------------------------------------------------------------------------*/
648 /*
649  * @brief Retrieve pernoise parameter structure values
650  * @param pipeline_name Input pipeline id
651  * @param recipe_name Input recipe id
652  * @param parlist Shift to apply on the x-axis
653  * @return 0 .
654  */
655 /*---------------------------------------------------------------------------*/
656 
657 static cpl_error_code
658 detmon_pernoise_retrieve_parlist(const char *pipeline_name,
659  const char *recipe_name,
660  const cpl_parameterlist * parlist)
661 {
662  char *par_name;
663  const cpl_parameter *par;
664 
665  /* --mode */
666  detmon_pernoise_config.mode =
667  detmon_retrieve_par_int("mode", pipeline_name, recipe_name,
668  parlist);
669 
670  /* --direction */
671  par_name = cpl_sprintf("%s.%s.direction", pipeline_name, recipe_name);
672  assert(par_name != NULL);
673  par = cpl_parameterlist_find_const(parlist, par_name);
674  detmon_pernoise_config.direction = cpl_parameter_get_bool(par);
675  cpl_free(par_name);
676 
677  /* --speed */
678  par_name = cpl_sprintf("%s.%s.speed", pipeline_name, recipe_name);
679  assert(par_name != NULL);
680  par = cpl_parameterlist_find_const(parlist, par_name);
681  detmon_pernoise_config.speed = cpl_parameter_get_double(par);
682  cpl_free(par_name);
683 
684  /* --llx */
685  detmon_pernoise_config.llx =
686  detmon_retrieve_par_int("llx", pipeline_name, recipe_name,
687  parlist);
688 
689  /* --lly */
690  detmon_pernoise_config.lly =
691  detmon_retrieve_par_int("lly", pipeline_name, recipe_name,
692  parlist);
693  /* --urx */
694  detmon_pernoise_config.urx =
695  detmon_retrieve_par_int("urx", pipeline_name, recipe_name,
696  parlist);
697  /* --ury */
698  detmon_pernoise_config.ury =
699  detmon_retrieve_par_int("ury", pipeline_name, recipe_name,
700  parlist);
701  /* --kappa */
702  detmon_pernoise_config.kappa =
703  detmon_retrieve_par_double("kappa", pipeline_name, recipe_name,
704  parlist);
705 
706  /* --exts */
707  detmon_pernoise_config.exts =
708  detmon_retrieve_par_int("exts", pipeline_name, recipe_name,
709  parlist);
710 
711  if(cpl_error_get_code()) {
712  cpl_msg_error(cpl_func, "Failed to retrieve the input parameters");
713  cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
714  }
715 
716  return cpl_error_get_code();
717 }
718 
719 /*---------------------------------------------------------------------------*/
720 /*
721  * @brief Save results of pernoise recipe
722  * @param parlist input parameter list
723  * @param frameset input frameset
724  * @param recipe_name input recipe name
725  * @param pipeline_name input pipeline name
726  * @param procatg_tbl input procategory table
727  * @param package input package id
728  * @param freq_table computed frequency table
729  * @param qclist computed QC parameters
730  * @param flag_sets switch
731  * @param which_sets specifier
732  * @param usedframes used frames
733 
734  * @return CPL_ERROR_NONE on success.
735  */
736 /*---------------------------------------------------------------------------*/
737 static cpl_error_code
738 detmon_pernoise_save(const cpl_parameterlist * parlist,
739  cpl_frameset * frameset,
740  const char *recipe_name,
741  const char *pipeline_name,
742  const char *procatg_tbl,
743  const char *package,
744  cpl_table ** freq_table,
745  cpl_propertylist ** qclist,
746  const int flag_sets,
747  const int which_set,
748  const cpl_frameset * usedframes)
749 {
750 
751  cpl_frame *ref_frame;
752  cpl_propertylist *plist;
753  char *name_o = NULL; /* Avoid (false) uninit warning */
754  int i;
755  cpl_propertylist *paflist;
756  cpl_error_code error;
757 
758  cpl_propertylist * pro_tbl = cpl_propertylist_new();
759 
760  cpl_propertylist_append_string(pro_tbl,
761  CPL_DFS_PRO_CATG, procatg_tbl);
762 
763  cpl_propertylist_append(pro_tbl, qclist[0]);
764 
765  /*******************************/
766  /* Write the FREQ TABLE */
767 
768  /*******************************/
769 
770  if(detmon_pernoise_config.mode != 1) {
771  /* Set the file name for the table */
772  if(!flag_sets) {
773  name_o = cpl_sprintf("%s_freq_table.fits", recipe_name);
774  assert(name_o != NULL);
775  } else {
776  name_o =
777  cpl_sprintf("%s_freq_table_set%02d.fits", recipe_name,
778  which_set);
779  assert(name_o != NULL);
780  }
781 
782  /* Save the table */
783  if(cpl_dfs_save_table(frameset, NULL, parlist, usedframes, NULL, freq_table[0],
784  NULL, recipe_name, pro_tbl, NULL,
785  package, name_o)) {
786  cpl_msg_error(cpl_func, "Cannot save the product: %s", name_o);
787  cpl_free(name_o);
788  cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
789  }
790 
791  if(detmon_pernoise_config.exts < 0) {
792 
793  for(i = 1; i < detmon_pernoise_config.nb_extensions; i++) {
794  error =
795  cpl_table_save(freq_table[i], NULL, qclist[i], name_o,
796  CPL_IO_EXTEND);
797  cpl_ensure_code(!error, error);
798  }
799  }
800 
801  /* Free */
802  cpl_free(name_o);
803 
804  } else {
805  for (int j = 1; j <= 4; j++) {
806  /* Set the file name for the table */
807  if(!flag_sets) {
808  name_o = cpl_sprintf("%s_freq_table_quad%02d.fits",
809  recipe_name, j);
810  assert(name_o != NULL);
811  } else {
812  name_o =
813  cpl_sprintf("%s_freq_table_quad%02d_set%02d.fits",
814  recipe_name, j, which_set);
815  assert(name_o != NULL);
816  }
817 
818  /* Save the table */
819  if(cpl_dfs_save_table(frameset, NULL, parlist, usedframes, NULL,
820  freq_table[j - 1],
821  NULL, recipe_name, pro_tbl, NULL,
822  package, name_o)) {
823  cpl_msg_error(cpl_func, "Cannot save the product: %s", name_o);
824  cpl_free(name_o);
825  cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
826  }
827 
828  if(detmon_pernoise_config.exts < 0) {
829  for(i = 1; i < detmon_pernoise_config.nb_extensions; i++) {
830  error = cpl_table_save(freq_table[(j-1) + 4 * i],
831  NULL, qclist[i], name_o,
832  CPL_IO_EXTEND);
833  cpl_ensure_code(!error, error);
834  }
835  }
836 
837  /* Free */
838  cpl_free(name_o);
839  }
840 
841  }
842  /*******************************/
843  /* Write the PAF file(s) */
844  /*******************************/
845 
846  /* Get FITS header from reference file */
847  ref_frame = cpl_frameset_get_position(frameset, 0);
848  if((plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
849  0)) == NULL) {
850  cpl_msg_error(cpl_func, "getting header from reference frame");
851  cpl_ensure_code(0, cpl_error_get_code());
852  }
853 
854  /* Get the keywords for the paf file */
855  paflist = cpl_propertylist_new();
856  cpl_propertylist_copy_property_regexp(paflist, plist,
857  "^(ARCFILE|MJD-OBS|ESO TPL ID|"
858  "DATE-OBS|ESO DET DIT|ESO DET NDIT|"
859  "ESO DET NCORRS|"
860  "ESO DET MODE NAME)$", 0);
861 
862  for(i = 0; i < detmon_pernoise_config.nb_extensions; i++) {
863  cpl_propertylist * c_paflist = cpl_propertylist_duplicate(paflist);
864  error = cpl_propertylist_append(c_paflist, qclist[i]);
865  cpl_ensure_code(!error, error);
866 
867  /* Set the file name for the bpm */
868  if(detmon_pernoise_config.exts >= 0) {
869  if(!flag_sets) {
870  name_o = cpl_sprintf("%s.paf", recipe_name);
871  assert(name_o != NULL);
872  } else {
873  name_o = cpl_sprintf("%s_set%02d.paf", recipe_name, which_set);
874  assert(name_o != NULL);
875  }
876  } else {
877  if(!flag_sets) {
878  name_o = cpl_sprintf("%s_ext%02d.paf", recipe_name, i+1);
879  assert(name_o != NULL);
880  } else {
881  name_o = cpl_sprintf("%s_set%02d_ext%02d.paf", recipe_name, which_set, i+1);
882  assert(name_o != NULL);
883  }
884  }
885  /* Save the PAF */
886  if(cpl_dfs_save_paf(pipeline_name, recipe_name, c_paflist, name_o)) {
887  cpl_msg_error(cpl_func, "Cannot save the product: %s", name_o);
888  cpl_free(name_o);
889  cpl_propertylist_delete(paflist);
890  cpl_propertylist_delete(plist);
891  cpl_free(name_o);
892  cpl_ensure_code(0, CPL_ERROR_FILE_NOT_CREATED);
893  }
894  cpl_propertylist_delete(c_paflist);
895  cpl_free(name_o);
896  }
897 
898  cpl_propertylist_delete(plist);
899  cpl_propertylist_delete(paflist);
900  cpl_propertylist_delete(pro_tbl);
901  return cpl_error_get_code();
902 }
903 /*---------------------------------------------------------------------------*/
904 /*
905  * @brief Computes QC for pernoise recipe
906 
907  * @param qclist computed QC parameters
908  * @param table input table
909  * @param iquad input frame quadrant id
910 
911  * @return CPL_ERROR_NONE on success.
912  */
913 /*---------------------------------------------------------------------------*/
914 
915 static cpl_error_code
916 detmon_pernoise_qc(cpl_propertylist * qclist,
917  cpl_table * table,
918  int iquad)
919 {
920  cpl_error_code error;
921  char * propname;
922 
923  double freqs[3] = {0, 0, 0};
924  double pows[3] = {0, 0, 0};
925 
926  /* error = cpl_propertylist_append_bool(reflist, "POW", TRUE);
927  cpl_ensure_code(!error, error);
928 
929  error = cpl_table_sort(table, reflist);
930  cpl_ensure_code(!error, error);
931  */
932 
933  int nrows = cpl_table_get_nrow(table);
934  int i;
935 
936  double * all_freqs = cpl_table_get_data_double(table, "FREQ");
937  double * all_pows = cpl_table_get_data_double(table, "POW");
938 
939  for ( i= 1; i< nrows-1; i++){
940  if (all_pows[i] > pows[0]) {
941  if(all_pows[i-1] < all_pows[i] && all_pows[i] > all_pows[i+1]){
942  pows[2]=pows[1];
943  pows[1]=pows[0];
944  pows[0]=all_pows[i];
945 
946  freqs[2]=freqs[1];
947  freqs[1]=freqs[0];
948  freqs[0]=all_freqs[i];
949  }
950  } else if (all_pows[i] > pows[1]) {
951  if(all_pows[i-1] < all_pows[i] && all_pows[i] > all_pows[i+1]){
952  pows[2]=pows[1];
953  pows[1]=all_pows[i];
954 
955  freqs[2]=freqs[1];
956  freqs[1]=all_freqs[i];
957  }
958 
959  } else if(all_pows[i] > pows[2]) {
960  if(all_pows[i-1] < all_pows[i] && all_pows[i] > all_pows[i+1]){
961  pows[2]=all_pows[i];
962 
963  freqs[2]=all_freqs[i];
964  }
965 
966  }
967  }
968 
969  if (detmon_pernoise_config.mode == 1) {
970  propname = cpl_sprintf("ESO QC FREQ1 %d", iquad);
971  assert(propname != NULL);
972  } else {
973  propname = cpl_sprintf("ESO QC FREQ1");
974  }
975 
976  error = cpl_propertylist_append_double(qclist, propname, freqs[0]);
977  error = cpl_propertylist_set_comment(qclist,propname,DETMON_QC_FREQ_C);
978  cpl_ensure_code(!error, error);
979 
980  cpl_free(propname);
981 
982  if (detmon_pernoise_config.mode == 1) {
983  propname = cpl_sprintf("ESO QC FREQ2 %d", iquad);
984  assert(propname != NULL);
985  } else {
986  propname = cpl_sprintf("ESO QC FREQ2");
987  }
988 
989  error = cpl_propertylist_append_double(qclist, propname, freqs[1]);
990  error = cpl_propertylist_set_comment(qclist,propname,DETMON_QC_FREQ_C);
991  cpl_ensure_code(!error, error);
992 
993  cpl_free(propname);
994 
995  if (detmon_pernoise_config.mode == 1) {
996  propname = cpl_sprintf("ESO QC FREQ3 %d", iquad);
997  assert(propname != NULL);
998  } else {
999  propname = cpl_sprintf("ESO QC FREQ3");
1000  }
1001 
1002  error = cpl_propertylist_append_double(qclist, propname, freqs[2]);
1003  error = cpl_propertylist_set_comment(qclist,propname,DETMON_QC_FREQ_C);
1004  cpl_ensure_code(!error, error);
1005 
1006  cpl_free(propname);
1007 
1008  if (detmon_pernoise_config.mode == 1) {
1009  propname = cpl_sprintf("ESO QC POW1 %d", iquad);
1010  assert(propname != NULL);
1011  } else {
1012  propname = cpl_sprintf("ESO QC POW1");
1013  }
1014 
1015  error = cpl_propertylist_append_double(qclist, propname, pows[0]);
1016  error = cpl_propertylist_set_comment(qclist,propname,DETMON_QC_POW_C);
1017  cpl_ensure_code(!error, error);
1018 
1019  cpl_free(propname);
1020 
1021  if (detmon_pernoise_config.mode == 1) {
1022  propname = cpl_sprintf("ESO QC POW2 %d", iquad);
1023  assert(propname != NULL);
1024  } else {
1025  propname = cpl_sprintf("ESO QC POW2");
1026  }
1027 
1028  error = cpl_propertylist_append_double(qclist, propname, pows[1]);
1029  error = cpl_propertylist_set_comment(qclist,propname,DETMON_QC_POW_C);
1030  cpl_ensure_code(!error, error);
1031 
1032  cpl_free(propname);
1033 
1034  if (detmon_pernoise_config.mode == 1) {
1035  propname = cpl_sprintf("ESO QC POW3 %d", iquad);
1036  assert(propname != NULL);
1037  } else {
1038  propname = cpl_sprintf("ESO QC POW3");
1039  }
1040 
1041  error = cpl_propertylist_append_double(qclist, propname, pows[2]);
1042  error = cpl_propertylist_set_comment(qclist,propname,DETMON_QC_POW_C);
1043  cpl_ensure_code(!error, error);
1044 
1045 
1046  cpl_free(propname);
1047 
1048  return cpl_error_get_code();
1049 }
1050 
1051 /*---------------------------------------------------------------------------*/
1052 
1053 /*
1054  * @brief Remove background
1055  * @param image Input image
1056  * @param nsamples Input number of (random)samples
1057  * @param nffts input number of FFTs
1058  * @return CPL_ERROR_NONE on success.
1059  */
1060 
1061 /*---------------------------------------------------------------------------*/
1062 cpl_error_code
1063 detmon_pernoise_rm_bg(cpl_image * image, int nsamples, int nffts)
1064 {
1065  cpl_vector *values = cpl_vector_new(nsamples * nffts);
1066 
1067  int rejected;
1068  int i, j;
1069  cpl_vector *xy_pos = cpl_vector_new(nsamples * nffts * 2);
1070  cpl_polynomial * poly_2d = 0;
1071  cpl_image * poly_ima = 0;
1072  cpl_size degree = 3;
1073  cpl_error_code error = CPL_ERROR_NONE;
1074  cpl_matrix * samppos = 0;
1075 
1076  for(i = 1; i <= nffts; i++) {
1077  for(j = 1; j <= nsamples; j++) {
1078  cpl_vector_set(xy_pos, (i - 1) * nsamples + (j - 1), j);
1079  cpl_vector_set(xy_pos, (i - 1) * nsamples + (j - 1) + nsamples * nffts, i);
1080  cpl_vector_set(values, (i - 1) * nsamples + (j - 1),
1081  cpl_image_get(image, j, i, &rejected));
1082  error = cpl_error_get_code();
1083  if (error != CPL_ERROR_NONE)
1084  {
1085  break;
1086  }
1087  }
1088  if (error != CPL_ERROR_NONE)
1089  {
1090  break;
1091  }
1092  }
1093  if (error != CPL_ERROR_NONE)
1094  {
1095  goto cleanup;
1096  }
1097 
1098  poly_2d = cpl_polynomial_new(2);
1099  samppos =
1100  cpl_matrix_wrap(2, nsamples * nffts, cpl_vector_get_data(xy_pos));
1101 
1102  cpl_polynomial_fit(poly_2d, samppos, NULL, values, NULL,
1103  CPL_FALSE, NULL, &degree);
1104 
1105  cpl_matrix_unwrap(samppos);
1106 
1107  poly_ima = cpl_image_new(nsamples, nffts, CPL_TYPE_FLOAT);
1108 
1109  cpl_image_fill_polynomial(poly_ima, poly_2d, 1, 1, 1, 1);
1110 
1111  cpl_image_subtract(image, poly_ima);
1112 
1113 cleanup:
1114  cpl_polynomial_delete(poly_2d);
1115  cpl_image_delete(poly_ima);
1116  cpl_vector_delete(xy_pos);
1117  cpl_vector_delete(values);
1118 
1119  return cpl_error_get_code();
1120 }
1121