IIINSTRUMENT Pipeline Reference Manual 1.3.14
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
72enum pixeltypes
73{
74 HOT = 0,
75 DEAD = 1,
76 NOISY = 2
77};
78
79enum stackingtypes
80{
81 MINMAX = 0,
82 MEAN = 1,
83 MEDIAN = 2,
84 KSIGMA = 3
85};
86
87enum readouts
88{
89 HORIZONTAL = 1,
90 VERTICAL = 2
91};
92
93
94
95static 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
119int
120detmon_pernoise_dfs_set_groups(cpl_frameset *,
121 const char *);
122
123static cpl_error_code
124detmon_pernoise_retrieve_parlist(const char *,
125 const char *,
126 const cpl_parameterlist *);
127
128static cpl_error_code
129detmon_pernoise_qc(cpl_propertylist *,
130 cpl_table *,
131 int);
132
133static cpl_error_code
134detmon_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
146cpl_error_code
147detmon_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
165cpl_table *
166detmon_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
284cleanup:
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/*---------------------------------------------------------------------------*/
315cpl_error_code
316detmon_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/*---------------------------------------------------------------------------*/
508int
509detmon_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
562detmon_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/*---------------------------------------------------------------------------*/
627int
628detmon_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
657static cpl_error_code
658detmon_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/*---------------------------------------------------------------------------*/
737static cpl_error_code
738detmon_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
915static cpl_error_code
916detmon_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/*---------------------------------------------------------------------------*/
1062cpl_error_code
1063detmon_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
1113cleanup:
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