OMEGA Pipeline Reference Manual  1.0.5
omega_readnoise.c
1 /* $Id: omega_readnoise.c,v 1.3 2012-03-26 08:42:09 agabasch Exp $
2  *
3  * This file is part of the OMEGA Pipeline
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: agabasch $
23  * $Date: 2012-03-26 08:42:09 $
24  * $Revision: 1.3 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 /*-----------------------------------------------------------------------------
33  Includes
34  -----------------------------------------------------------------------------*/
35 
36 #include "omega_recipe.h"
37 
38 /*----------------------------------------------------------------------------*/
59 /*----------------------------------------------------------------------------*/
62 /*-----------------------------------------------------------------------------
63  Functions prototypes
64  -----------------------------------------------------------------------------*/
65 
66 static int omega_readnoise_create(cpl_plugin *) ;
67 static int omega_readnoise_exec(cpl_plugin *) ;
68 static int omega_readnoise_destroy(cpl_plugin *) ;
69 static int omega_readnoise(cpl_frameset *,cpl_parameterlist *) ;
70 
71 /*-----------------------------------------------------------------------------
72  Private Functions
73  -----------------------------------------------------------------------------*/
74 int omega_readnoise_save(cpl_frameset *set, cpl_parameterlist *parlist);
75 static void omega_readnoise_init(void);
76 static void omega_readnoise_tidy(void);
77 
78 static struct {
79  /* Inputs. Parameters */
80  float rej_sig;
81  int niter;
82  int extnum;
83  int paf;
84 
85  /* Outputs. QC parameters */
86  double rnoise;
87  double mean_diff;
88  double median_diff;
89  double RawBias1Min;
90  double RawBias1Max;
91  double RawBias1Mean;
92  double RawBias1Median;
93  double RawBias1Stdev;
94 
95  double RawBias2Min;
96  double RawBias2Max;
97  double RawBias2Mean;
98  double RawBias2Median;
99  double RawBias2Stdev;
100 
101 }omega_readnoise_config;
102 
103 static struct {
104  cpl_size *labels;
105  cpl_frameset *biaslist;
106  omega_fits *biasfits1;
107  omega_fits *biasfits2;
108  cpl_stats *stats;
109 
110  /*Products*/
111  cpl_table *table;
112 } ps;
113 
114 /* Static variables */
115 
116 /* Static variables */
117 #define RECIPE "omega_readnoise"
118 
119 static cpl_frame *product_frame = NULL;
120 static int isfirst;
121 static int dummy;
122 static char outfile[100];
123 static char outpaf[100];
124 static const char *PROCATG = OMEGA_CALIB_RDNOISE;
125 
126 
127 /*----------------------------------------------------------------------------*/
135 /*----------------------------------------------------------------------------*/
136 int cpl_plugin_get_info(cpl_pluginlist * list)
137 {
138  cpl_recipe * recipe = cpl_calloc(1, sizeof(*recipe)) ;
139  cpl_plugin * plugin = &recipe->interface ;
140 
141  cpl_plugin_init(plugin,
142  CPL_PLUGIN_API,
143  OMEGA_BINARY_VERSION,
144  CPL_PLUGIN_TYPE_RECIPE,
145  "omega_readnoise",
146  "OMEGA - Calculate the read noise of the detector.",
147  "The read_noise is computed by subtracting two raw bias images, \n"
148  "and dividing the standard deviation by sqrt(2). The descriptor \n"
149  "value read_noise will be set to the computed value. The statistics \n"
150  "of the difference between the raw biases is computed iteratively. Bad \n"
151  "pixels are rejected if they differ more than process_params.REJECTION_THRESHOLD \n"
152  "sigma from the median. The maximum number of iteration is \n"
153  "process_params.MAXIMUM_ITERATIONS.",
154  "Sandra Castro",
155  "scastro@eso.org",
157  omega_readnoise_create,
158  omega_readnoise_exec,
159  omega_readnoise_destroy) ;
160 
161  cpl_pluginlist_append(list, plugin) ;
162 
163  return 0;
164 }
165 
166 /*----------------------------------------------------------------------------*/
175 /*----------------------------------------------------------------------------*/
176 static int omega_readnoise_create(cpl_plugin * plugin)
177 {
178  cpl_recipe * recipe;
179  cpl_parameter * p ;
180 
181  /* Do not create the recipe if an error code is already set */
182  if (cpl_error_get_code() != CPL_ERROR_NONE) {
183  cpl_msg_error(cpl_func, "%s():%d: An error is already set: %s",
184  cpl_func, __LINE__, cpl_error_get_where());
185  return (int)cpl_error_get_code();
186  }
187 
188  if (plugin == NULL) {
189  cpl_msg_error(cpl_func, "Null plugin");
190  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
191  }
192 
193  /* Verify plugin type */
194  if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
195  cpl_msg_error(cpl_func, "Plugin is not a recipe");
196  cpl_ensure_code(0, (int)CPL_ERROR_TYPE_MISMATCH);
197  }
198 
199  /* Get the recipe */
200  recipe = (cpl_recipe *)plugin;
201 
202  /* Create the parameters list in the cpl_recipe object */
203  recipe->parameters = cpl_parameterlist_new() ;
204 
205  if (recipe->parameters == NULL) {
206  cpl_msg_error(cpl_func, "Parameter list allocation failed");
207  cpl_ensure_code(0, (int)CPL_ERROR_ILLEGAL_OUTPUT);
208  }
209 
210  /* Fill the parameters list */
211  p = cpl_parameter_new_value("omega.omega_readnoise.ExtensionNumber",
212  CPL_TYPE_INT,
213  "FITS extension number to load (1 to 32). (-1 = all)",
214  "omega_readnoise",
215  -1) ;
216 
217  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"ext") ;
218  cpl_parameterlist_append(recipe->parameters, p) ;
219 
220  p = cpl_parameter_new_value("omega.omega_readnoise.PAF",
221  CPL_TYPE_BOOL,
222  "Boolean value to create PAF files. 1(Yes), 0(No)",
223  "omega_readnoise",
224  0) ;
225 
226  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI, "paf") ;
227  cpl_parameterlist_append(recipe->parameters, p) ;
228 
229  p = cpl_parameter_new_range("omega.omega_readnoise.NumberIter",
230  CPL_TYPE_INT,
231  "Maximum number of iterations",
232  "omega_readnoise",
233  5, 2, 10) ;
234 
235  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"niter") ;
236  cpl_parameterlist_append(recipe->parameters, p) ;
237 
238 
239  p = cpl_parameter_new_range("omega.omega_readnoise.RejSigma",
240  CPL_TYPE_DOUBLE,
241  "Sigma Clipping Threshold",
242  "omega_readnoise",
243  5.0, 1.0, 10.0) ;
244 
245  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI, "sig-clip") ;
246  cpl_parameterlist_append(recipe->parameters, p) ;
247 
248 
249  /* Return */
250  return 0;
251 }
252 
253 
254 /*----------------------------------------------------------------------------*/
260 /*----------------------------------------------------------------------------*/
261 static int omega_readnoise_exec(cpl_plugin * plugin)
262 {
263  cpl_recipe * recipe;
264  int recipe_status;
265 
266  /* Return immediately if an error code is already set */
267  if (cpl_error_get_code() != CPL_ERROR_NONE) {
268  cpl_msg_error(cpl_func, "%s():%d: An error is already set: %s",
269  cpl_func, __LINE__, cpl_error_get_where());
270  return (int)cpl_error_get_code();
271  }
272 
273  if (plugin == NULL) {
274  cpl_msg_error(cpl_func, "Null plugin");
275  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
276  }
277 
278  /* Verify plugin type */
279  if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
280  cpl_msg_error(cpl_func, "Plugin is not a recipe");
281  cpl_ensure_code(0, (int)CPL_ERROR_TYPE_MISMATCH);
282  }
283 
284  /* Get the recipe */
285  recipe = (cpl_recipe *)plugin;
286 
287  /* Verify parameter and frame lists */
288  if (recipe->parameters == NULL) {
289  cpl_msg_error(cpl_func, "Recipe invoked with NULL parameter list");
290  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
291  }
292  if (recipe->frames == NULL) {
293  cpl_msg_error(cpl_func, "Recipe invoked with NULL frame set");
294  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
295  }
296 
297  /* Invoke the recipe */
298  recipe_status = omega_readnoise(recipe->frames, recipe->parameters);
299 
300  /* Ensure DFS-compliance of the products */
301  if (cpl_dfs_update_product_header(recipe->frames)) {
302  if (!recipe_status) recipe_status = (int)cpl_error_get_code();
303  }
304 
305  return recipe_status;
306 
307 }
308 
309 /*----------------------------------------------------------------------------*/
315 /*----------------------------------------------------------------------------*/
316 static int omega_readnoise_destroy(cpl_plugin * plugin)
317 {
318  cpl_recipe *recipe;
319 
320  if (plugin == NULL) {
321  cpl_msg_error(cpl_func, "Null plugin");
322  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
323  }
324 
325  /* Verify plugin type */
326  if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
327  cpl_msg_error(cpl_func, "Plugin is not a recipe");
328  cpl_ensure_code(0, (int)CPL_ERROR_TYPE_MISMATCH);
329  }
330 
331  /* Get the recipe */
332  recipe = (cpl_recipe *)plugin;
333 
334  cpl_parameterlist_delete(recipe->parameters);
335 
336  return 0 ;
337 }
338 
339 
340 /**********************************************************************/
348 /*--------------------------------------------------------------------------*/
349 
350 static int omega_readnoise(cpl_frameset *set,cpl_parameterlist *pars)
351 {
352 
353  int j,jst,jfn,live;
354  cpl_size nlab;
355  float stdev = 0.0;
356 
357  const char *_id = "omega_readnoise";
358  const char *chipid = NULL;
359 
360  const cpl_frame *bias1, *bias2;
361  const cpl_image *rawbiasfits1, *rawbiasfits2=NULL;
362  cpl_image *biasim;
363  cpl_parameter *par;
364  cpl_propertylist *plist;
365 
366 
367  /*Start the recipe */
368 
369  if (pars == NULL) {
370  cpl_msg_error (_id, "Parameters list not found");
371  return -1;
372  }
373 
374  if (cpl_frameset_is_empty(set) == 1) {
375  cpl_msg_error (_id, "Frameset not found");
376  return -1;
377  }
378 
379 /* Initialise a few things */
380 
381  omega_readnoise_init();
382 
383 
384 /* Retrieve input parameters */
385 
386  par = cpl_parameterlist_find(pars, "omega.omega_readnoise.ExtensionNumber") ;
387  omega_readnoise_config.extnum = cpl_parameter_get_int(par) ;
388 
389  par = cpl_parameterlist_find(pars, "omega.omega_readnoise.NumberIter") ;
390  omega_readnoise_config.niter = cpl_parameter_get_int(par) ;
391 
392  par = cpl_parameterlist_find(pars, "omega.omega_readnoise.RejSigma") ;
393  omega_readnoise_config.rej_sig = cpl_parameter_get_double(par) ;
394 
395  par = cpl_parameterlist_find(pars, "omega.omega_readnoise.PAF") ;
396  omega_readnoise_config.paf = cpl_parameter_get_bool(par) ;
397 
398 /* Identify the RAW and CALIB frames in the input frameset */
399  if (oc_dfs_set_groups(set)) {
400  cpl_msg_error(_id, "Cannot identify RAW and CALIB frames") ;
401  omega_readnoise_tidy();
402  return -1 ;
403  }
404 
405 /* Verify the frameset contents. */
406 /*Make sure there are at least 2 bias */
407 
408  if ((ps.labels = cpl_frameset_labelise(set,omega_compare_tags,
409  &nlab)) == NULL) {
410  cpl_msg_error(_id,"Cannot labelise the input frameset");
411  omega_readnoise_tidy();
412  return -1;
413  }
414  if ((ps.biaslist = omega_frameset_subgroup(set,ps.labels,nlab,
415  RNOISE_RAW)) == NULL) {
416  cpl_msg_error(_id,"Cannot find bias frames in input frameset");
417  omega_readnoise_tidy();
418  return -1;
419  }
420  if (cpl_frameset_get_size(ps.biaslist) < 2) {
421  cpl_msg_error(_id,"Need exactly 2 (%s) frames to run this recipe",RNOISE_RAW);
422  omega_readnoise_tidy();
423  return -1;
424  }
425 
426  /* Set up some convenience variables */
427  bias1 = cpl_frameset_get_frame_const(ps.biaslist,0);
428  bias2 = cpl_frameset_get_frame_const(ps.biaslist,1);
429 
430  cpl_msg_info (_id,"Using %s frames: %s and %s",RNOISE_RAW,cpl_frame_get_filename(bias1),
431  cpl_frame_get_filename(bias2));
432 
433 /* Loop for each of the image extensions */
434  omega_exten_range(omega_readnoise_config.extnum,&jst,&jfn);
435  if(omega_readnoise_config.extnum == 0){
436  cpl_msg_error(cpl_func,"Unsupported extension request, %d",omega_readnoise_config.extnum);
437  omega_readnoise_tidy();
438  return -1;
439  }
440 
441  /* Check which instrument */
442  if(omega_pfits_check_instrume(cpl_frameset_get_first_const(set)) == 1 &&
443  omega_readnoise_config.extnum == 0 && jfn == 32)
444  jfn = 8;
445 
446  for (j = jst; j <= jfn; j++) {
447  cpl_msg_info(_id,"Beginning work on extension %d",j);
448  isfirst = (j == jst);
449  omega_readnoise_config.rnoise = 0.0;
450  omega_readnoise_config.mean_diff = 0.0;
451  omega_readnoise_config.median_diff = 0.0;
452  omega_readnoise_config.RawBias1Min=0.;
453  omega_readnoise_config.RawBias1Max=0.;
454  omega_readnoise_config.RawBias1Mean=0.;
455  omega_readnoise_config.RawBias1Median=0.;
456  omega_readnoise_config.RawBias1Stdev=0.;
457  omega_readnoise_config.RawBias2Min=0.;
458  omega_readnoise_config.RawBias2Max=0.;
459  omega_readnoise_config.RawBias2Mean=0.;
460  omega_readnoise_config.RawBias2Median=0.;
461  omega_readnoise_config.RawBias2Stdev=0.;
462 
463  ps.biasfits1 = omega_fits_load(bias1,CPL_TYPE_FLOAT,j);
464  ps.biasfits2 = omega_fits_load(bias2,CPL_TYPE_FLOAT,j);
465 
466  if (ps.biasfits1 == NULL || ps.biasfits2 == NULL) {
467  cpl_msg_error(_id,"NULL image input for extension %d",j);
468  /*save dummy extension*/
469  freefits(ps.biasfits1);
470  freefits(ps.biasfits2);
471  continue;
472  }
473 
474 
475  /* Check that this detector is live*/
476  plist = cpl_propertylist_load(cpl_frame_get_filename(bias1),j);
477  omega_pfits_get_detlive(plist,&live);
478  if (! live) {
479  cpl_msg_warning(_id,"First bias image detector not live");
480  /*save dummy extension*/
481  freefits(ps.biasfits1);
482  freefits(ps.biasfits2);
483  freeplist(plist);
484  continue;
485  }
486  freeplist(plist);
487 
488  plist = cpl_propertylist_load(cpl_frame_get_filename(bias2),j);
489  omega_pfits_get_detlive(plist,&live);
490  if (! live) {
491  cpl_msg_warning(_id,"Second bias image detector not live");
492  /*save dummy extension*/
493  freefits(ps.biasfits1);
494  freefits(ps.biasfits2);
495  freeplist(plist);
496  continue;
497  }
498  freeplist(plist);
499 
500  /* Get the raw images and derive some QC parameter */
501 
502  rawbiasfits1=omega_fits_get_image(ps.biasfits1);
503  rawbiasfits2=omega_fits_get_image(ps.biasfits2);
504  omega_readnoise_config.RawBias1Min =cpl_image_get_min(rawbiasfits1);
505  omega_readnoise_config.RawBias1Max =cpl_image_get_max(rawbiasfits1);
506  omega_readnoise_config.RawBias1Mean =cpl_image_get_mean(rawbiasfits1);
507  omega_readnoise_config.RawBias1Median=cpl_image_get_median(rawbiasfits1);
508  omega_readnoise_config.RawBias1Stdev =cpl_image_get_stdev(rawbiasfits1);
509  omega_readnoise_config.RawBias2Min =cpl_image_get_min(rawbiasfits2);
510  omega_readnoise_config.RawBias2Max =cpl_image_get_max(rawbiasfits2);
511  omega_readnoise_config.RawBias2Mean =cpl_image_get_mean(rawbiasfits2);
512  omega_readnoise_config.RawBias2Median=cpl_image_get_median(rawbiasfits2);
513  omega_readnoise_config.RawBias2Stdev =cpl_image_get_stdev(rawbiasfits2);
514 
515 
516  /* Get the difference image */
517  biasim = cpl_image_subtract_create(omega_fits_get_image(ps.biasfits1),
518  omega_fits_get_image(ps.biasfits2));
519 
520  freefits(ps.biasfits2);
521 
522  /*Calculate statistics iteratively*/
523  ps.stats = omega_iter_stat(biasim,omega_readnoise_config.rej_sig,omega_readnoise_config.niter);
524 
525  /* Now the read noise */
526  if(ps.stats != NULL){
527  stdev = cpl_stats_get_stdev(ps.stats);
528  omega_readnoise_config.rnoise = stdev / sqrt(2);
529  omega_readnoise_config.mean_diff = cpl_stats_get_mean(ps.stats);
530  omega_readnoise_config.median_diff = cpl_stats_get_median(ps.stats);
531  }
532  else{
533  cpl_msg_warning(_id,"Cannot calculate statistics iteratively");
534  }
535 
536  plist = cpl_propertylist_load(cpl_frame_get_filename(bias1),j);
537  chipid = omega_pfits_get_chipid(plist);
538 
539  cpl_msg_info(_id,"The read noise of %s is: %5.3g", chipid, omega_readnoise_config.rnoise);
540  cpl_msg_info(_id,"Difference between bias frames is: %5.3g (mean), %5.3g (median)",
541  omega_readnoise_config.mean_diff, omega_readnoise_config.median_diff);
542 
543  freeimage(biasim);
544  freestats(ps.stats);
545  freeplist(plist);
546 
547  /* Create the product */
548  ps.table = cpl_table_new(1);
549  cpl_table_new_column(ps.table, "READNOISE", CPL_TYPE_DOUBLE);
550  cpl_table_new_column(ps.table, "MEAN_DIFF", CPL_TYPE_DOUBLE);
551  cpl_table_new_column(ps.table, "MEDIAN_DIFF", CPL_TYPE_DOUBLE);
552  cpl_table_set_double(ps.table, "READNOISE", 0, omega_readnoise_config.rnoise);
553  cpl_table_set_double(ps.table, "MEAN_DIFF", 0, omega_readnoise_config.mean_diff);
554  cpl_table_set_double(ps.table, "MEDIAN_DIFF", 0, omega_readnoise_config.median_diff);
555 
556  /* Save the product */
557  if(omega_readnoise_save(set, pars) == -1){
558  cpl_msg_error(_id,"Cannot save this extension product");
559  omega_readnoise_tidy();
560  return -1;
561  }
562 
563  freefits(ps.biasfits1);
564  freetable(ps.table);
565  } /* Work on next extension */
566 
567  omega_readnoise_tidy();
568 
569  return 0;
570 
571 }
572 
573 /*----------------------------------------------------------------------------*/
582 /*----------------------------------------------------------------------------*/
583 int omega_readnoise_save(cpl_frameset *set,
584  cpl_parameterlist *parlist)
585 {
586 
587  const char *fctid = "omega_readnoise_save";
588  cpl_propertylist *plist;
589  cpl_propertylist *qclist;
590 
591 
592  /* If it is the first time, setup initial frame */
593  if (isfirst) {
594 
595  /* Get the name of the instrument */
596  if(omega_pfits_check_instrume(cpl_frameset_get_first_const(set)) == 1)
597  sprintf(INSTRUME,"wfi");
598 
599  /* Set the file name*/
600  sprintf(outfile, "%s_%s.fits",INSTRUME,PROCATG) ;
601 
602  /* Create a new product frame object and define some tags */
603  product_frame = cpl_frame_new();
604  cpl_frame_set_filename(product_frame,outfile);
605  cpl_frame_set_tag(product_frame,PROCATG);
606  cpl_frame_set_type(product_frame,CPL_FRAME_TYPE_TABLE);
607  cpl_frame_set_group(product_frame,CPL_FRAME_GROUP_PRODUCT);
608  cpl_frame_set_level(product_frame,CPL_FRAME_LEVEL_FINAL);
609 
610  plist = cpl_propertylist_new();
611 
612  /* Add DataFlow keywords in primary header */
613  if (cpl_dfs_setup_product_header(plist, product_frame, set, parlist,
614  RECIPE,PIPEID,DICID,NULL) != CPL_ERROR_NONE) {
615 
616  cpl_msg_warning(fctid, "Problem in the main header of product DFS-compliance") ;
617  }
618 
619  /* Once CPL recalculates these values, the following
620  * line should be removed
621  */
622  cpl_propertylist_erase_regexp(plist,REM_PRIM_KEYS,0);
623 
624  /* Save the empty primary unit */
625  if (cpl_propertylist_save(plist,outfile,CPL_IO_DEFAULT) != CPL_ERROR_NONE){
626  cpl_msg_error(fctid,"Cannot save product PHU");
627  cpl_frame_delete(product_frame);
628  freeplist(plist);
629  return -1;
630  }
631 
632  freeplist(plist);
633  cpl_frameset_insert(set,product_frame);
634  }
635 
636  /* Setup the extension */
637  plist = cpl_propertylist_duplicate(omega_fits_get_ehu(ps.biasfits1));
638  qclist = cpl_propertylist_new();
639 
640  /* Add DataFlow keywords in extension header */
641  if (cpl_dfs_setup_product_header(plist, product_frame, set, parlist,
642  RECIPE,PIPEID,DICID,NULL) != CPL_ERROR_NONE) {
643 
644  cpl_msg_warning(fctid, "Problem in the extension header of product DFS-compliance") ;
645  }
646 
647  /*Remove undesired keywords from extension header*/
648  cpl_propertylist_erase_regexp(plist, REM_EXT_KEYS, 0);
649 
650 
651  /* Now add the QC data... */
652 
653  cpl_propertylist_update_float(qclist,"ESO QC READNOISE",
654  omega_readnoise_config.rnoise);
655  cpl_propertylist_update_float(qclist,"ESO QC READNOISE MEAN DIFF",
656  omega_readnoise_config.mean_diff);
657  cpl_propertylist_update_float(qclist,"ESO QC READNOISE MEDIAN DIFF",
658  omega_readnoise_config.median_diff);
659 
660  cpl_propertylist_update_float(qclist,"ESO QC RAW BIAS1 MIN" , omega_readnoise_config.RawBias1Min );
661  cpl_propertylist_update_float(qclist,"ESO QC RAW BIAS1 MAX" , omega_readnoise_config.RawBias1Max );
662  cpl_propertylist_update_float(qclist,"ESO QC RAW BIAS1 MEAN" , omega_readnoise_config.RawBias1Mean );
663  cpl_propertylist_update_float(qclist,"ESO QC RAW BIAS1 MEDIAN", omega_readnoise_config.RawBias1Median);
664  cpl_propertylist_update_float(qclist,"ESO QC RAW BIAS1 STDEV" , omega_readnoise_config.RawBias1Stdev );
665  cpl_propertylist_update_float(qclist,"ESO QC RAW BIAS2 MIN" , omega_readnoise_config.RawBias2Min );
666  cpl_propertylist_update_float(qclist,"ESO QC RAW BIAS2 MAX" , omega_readnoise_config.RawBias2Max );
667  cpl_propertylist_update_float(qclist,"ESO QC RAW BIAS2 MEAN" , omega_readnoise_config.RawBias2Mean );
668  cpl_propertylist_update_float(qclist,"ESO QC RAW BIAS2 MEDIAN", omega_readnoise_config.RawBias2Median);
669  cpl_propertylist_update_float(qclist,"ESO QC RAW BIAS2 STDEV ", omega_readnoise_config.RawBias2Stdev );
670 
671  cpl_propertylist_set_comment(qclist,"ESO QC RAW BIAS1 MIN" , "minimum value of first frame");
672  cpl_propertylist_set_comment(qclist,"ESO QC RAW BIAS1 MAX" , "maximum value of first frame");
673  cpl_propertylist_set_comment(qclist,"ESO QC RAW BIAS1 MEAN" , "mean value of first frame");
674  cpl_propertylist_set_comment(qclist,"ESO QC RAW BIAS1 MEDIAN", "median value of first frame");
675  cpl_propertylist_set_comment(qclist,"ESO QC RAW BIAS1 STDEV" , "standard deviation of first frame");
676  cpl_propertylist_set_comment(qclist,"ESO QC RAW BIAS2 MIN" , "minimum value of second frame");
677  cpl_propertylist_set_comment(qclist,"ESO QC RAW BIAS2 MAX" , "maximum value of second frame");
678  cpl_propertylist_set_comment(qclist,"ESO QC RAW BIAS2 MEAN" , "mean value of second frame");
679  cpl_propertylist_set_comment(qclist,"ESO QC RAW BIAS2 MEDIAN", "median value of second frame");
680  cpl_propertylist_set_comment(qclist,"ESO QC RAW BIAS2 STDEV ", "standard deviation of second frame");
681 
682  /* Append it to the extension header */
683  cpl_propertylist_append(plist, qclist);
684 
685  /* Add comments to QC parameters in extension header*/
686  cpl_propertylist_set_comment(plist,"ESO QC READNOISE",
687  "Calculated detector readnoise");
688  cpl_propertylist_set_comment(plist,"ESO QC READNOISE MEAN DIFF",
689  "Calculated mean of difference");
690  cpl_propertylist_set_comment(plist,"ESO QC READNOISE MEDIAN DIFF",
691  "Calculated median of difference");
692 
693  /* 'Save' the product */
694  if (cpl_table_save(ps.table,NULL,plist,outfile,CPL_IO_EXTEND) != CPL_ERROR_NONE) {
695  cpl_msg_error(fctid,"Cannot save product. %s", cpl_error_get_message());
696  freeplist(plist);
697  freeplist(qclist);
698  return -1;
699  }
700 
701  /* Save the paf file */
702  if(omega_readnoise_config.paf){
703  int xtnum = omega_fits_get_extnum(ps.biasfits1);
704  const char pafcopy[] = "^(DATE-OBS|ARCFILE|ESO TPL ID|ESO DET WIN1 DIT1|MJD-OBS|EXTNAME|ESO PRO CATG)$";
705  sprintf(outpaf, "%s_%s_%d.paf",INSTRUME,PROCATG,xtnum) ;
706  cpl_frame *fframe = cpl_frameset_get_first(set);
707  cpl_propertylist *mlist = cpl_propertylist_load_regexp(cpl_frame_get_filename(fframe),0,pafcopy, 0);
708  cpl_propertylist_copy_property_regexp(qclist, mlist, pafcopy, 0);
709  if(cpl_propertylist_copy_property_regexp(qclist, plist,
710  pafcopy, 0) != CPL_ERROR_NONE){
711  cpl_msg_warning(fctid,"Some mandatory keywords are missing in PAF file");
712  }
713 
714  cpl_dfs_save_paf(INSTRUME, RECIPE, qclist, outpaf);
715  freeplist(mlist);
716  }
717 
718  freeplist(plist);
719  freeplist(qclist);
720 
721  return 0;
722 }
723 
724 
725 /*---------------------------------------------------------------------------*/
729 /*---------------------------------------------------------------------------*/
730 
731 static void omega_readnoise_init(void) {
732  ps.labels = NULL;
733  ps.biaslist = NULL;
734  ps.biasfits1 = NULL;
735  ps.biasfits2 = NULL;
736  ps.stats = NULL;
737  ps.table = NULL;
738  return;
739 }
740 
741 /*---------------------------------------------------------------------------*/
745 /*---------------------------------------------------------------------------*/
746 
747 static void omega_readnoise_tidy(void) {
748  freespace(ps.labels);
749  freeframeset(ps.biaslist);
750  freefits(ps.biasfits1);
751  freefits(ps.biasfits2);
752  freetable(ps.table);
753  freestats(ps.stats);
754  return;
755 }