OMEGA Pipeline Reference Manual  1.0.5
omega_nightsky_flat.c
1 /* $Id: omega_nightsky_flat.c,v 1.2 2012-01-12 12:05: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-01-12 12:05:09 $
24  * $Revision: 1.2 $
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 #include "omega_wcscor.h"
38 
62 /*-----------------------------------------------------------------------------
63  Functions prototypes
64  -----------------------------------------------------------------------------*/
65 
66 static int omega_nightsky_flat_create(cpl_plugin *) ;
67 static int omega_nightsky_flat_exec(cpl_plugin *) ;
68 static int omega_nightsky_flat_destroy(cpl_plugin *) ;
69 static int omega_nightsky_flat(cpl_frameset *, cpl_parameterlist *) ;
70 cpl_image *omega_nsky_process(omega_fits *scifits, cpl_image *bias, cpl_image *flat,
71  cpl_image *bpm, cpl_parameterlist *pars, int ext);
72 
73 static int omega_nsky_load_calib(int ext);
74 static void omega_nsky_init(void);
75 static void omega_nsky_tidy(int level);
76 
77 
78 /* Input and Output structures */
79 static struct {
80  /* Inputs. Parameters */
81  int extnum;
82  int oc;
83 
84 }omega_nsky_config;
85 
86 static struct {
87 
88  /* Calib frames */
89  cpl_size *labels;
90  const cpl_frame *mbiasfr;
91  const cpl_frame *mflatfr;
92  const cpl_frame *bpmfr;
93  cpl_frameset *sciset;
94  omega_fits *scifits;
95 
96  /* Products */
97  cpl_image *bpm;
98  cpl_image *mbias;
99  cpl_image *mflat;
100  cpl_image *nsky;
101 
102 }ps;
103 
104 #define RECIPE "omega_nightsky_flat"
105 
106 /*----------------------------------------------------------------------------*/
115 /*----------------------------------------------------------------------------*/
116 int cpl_plugin_get_info(cpl_pluginlist * list)
117 {
118  cpl_recipe * recipe = cpl_calloc(1, sizeof(*recipe)) ;
119  cpl_plugin * plugin = &recipe->interface ;
120 
121  cpl_plugin_init(plugin,
122  CPL_PLUGIN_API,
123  OMEGA_BINARY_VERSION,
124  CPL_PLUGIN_TYPE_RECIPE,
125  "omega_nightsky_flat",
126  "OMEGA - Create Master Night Sky Flat.",
127  "This recipe is used to create a Master Night Sky Flat or also called \n"
128  "a Blank Sky Flat. The recipe always takes as input a list of at least 3 \n"
129  "science frames, a master bias and a master flat. In addition to these, \n"
130  "an optional Bad Pixels Map may be provided.",
131  "Sandra Castro",
132  "scastro@eso.org",
134  omega_nightsky_flat_create,
135  omega_nightsky_flat_exec,
136  omega_nightsky_flat_destroy) ;
137 
138  cpl_pluginlist_append(list, plugin) ;
139 
140  return 0;
141 }
142 
143 /*----------------------------------------------------------------------------*/
152 /*----------------------------------------------------------------------------*/
153 static int omega_nightsky_flat_create(cpl_plugin * plugin)
154 {
155  cpl_recipe * recipe;
156  cpl_parameter * p ;
157 
158  /* Do not create the recipe if an error code is already set */
159  if (cpl_error_get_code() != CPL_ERROR_NONE) {
160  cpl_msg_error(cpl_func, "%s():%d: An error is already set: %s",
161  cpl_func, __LINE__, cpl_error_get_where());
162  return (int)cpl_error_get_code();
163  }
164 
165  if (plugin == NULL) {
166  cpl_msg_error(cpl_func, "Null plugin");
167  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
168  }
169 
170  /* Verify plugin type */
171  if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
172  cpl_msg_error(cpl_func, "Plugin is not a recipe");
173  cpl_ensure_code(0, (int)CPL_ERROR_TYPE_MISMATCH);
174  }
175 
176  /* Get the recipe */
177  recipe = (cpl_recipe *)plugin;
178 
179  /* Create the parameters list in the cpl_recipe object */
180  recipe->parameters = cpl_parameterlist_new() ;
181  if (recipe->parameters == NULL) {
182  cpl_msg_error(cpl_func, "Parameter list allocation failed");
183  cpl_ensure_code(0, (int)CPL_ERROR_ILLEGAL_OUTPUT);
184  }
185 
186  /* Fill the parameters list */
187  p = cpl_parameter_new_value("omega.omega_nightsky_flat.ExtensionNumber",
188  CPL_TYPE_INT,
189  "FITS extension number to load (1 to 32). (-1 == all)",
190  "omega_nightsky_flat",
191  -1) ;
192 
193  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"ext") ;
194  cpl_parameterlist_append(recipe->parameters, p) ;
195 
196  p = cpl_parameter_new_range("omega.omega_nightsky_flat.OverscanMethod",
197  CPL_TYPE_INT,
198  "Overscan Correction Method",
199  "omega_nightsky_flat",
200  0, 0, 6);
201  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI, "oc-meth") ;
202  cpl_parameterlist_append(recipe->parameters, p) ;
203 
204  /* Return */
205  return 0;
206 }
207 
208 /*----------------------------------------------------------------------------*/
214 /*----------------------------------------------------------------------------*/
215 static int omega_nightsky_flat_exec(cpl_plugin * plugin)
216 {
217  cpl_recipe * recipe;
218  int recipe_status;
219 
220  /* Return immediately if an error code is already set */
221  if (cpl_error_get_code() != CPL_ERROR_NONE) {
222  cpl_msg_error(cpl_func, "%s():%d: An error is already set: %s",
223  cpl_func, __LINE__, cpl_error_get_where());
224  return (int)cpl_error_get_code();
225  }
226 
227  if (plugin == NULL) {
228  cpl_msg_error(cpl_func, "Null plugin");
229  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
230  }
231 
232  /* Verify plugin type */
233  if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
234  cpl_msg_error(cpl_func, "Plugin is not a recipe");
235  cpl_ensure_code(0, (int)CPL_ERROR_TYPE_MISMATCH);
236  }
237 
238  /* Get the recipe */
239  recipe = (cpl_recipe *)plugin;
240 
241  /* Verify parameter and frame lists */
242  if (recipe->parameters == NULL) {
243  cpl_msg_error(cpl_func, "Recipe invoked with NULL parameter list");
244  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
245  }
246  if (recipe->frames == NULL) {
247  cpl_msg_error(cpl_func, "Recipe invoked with NULL frame set");
248  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
249  }
250 
251  /* Invoke the recipe */
252  recipe_status = omega_nightsky_flat(recipe->frames, recipe->parameters);
253 
254  /* Ensure DFS-compliance of the products */
255  if (cpl_dfs_update_product_header(recipe->frames)) {
256  if (!recipe_status) recipe_status = (int)cpl_error_get_code();
257  }
258 
259  return recipe_status;
260 }
261 
262 /*----------------------------------------------------------------------------*/
268 /*----------------------------------------------------------------------------*/
269 static int omega_nightsky_flat_destroy(cpl_plugin * plugin)
270 {
271  cpl_recipe * recipe;
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  cpl_parameterlist_delete(recipe->parameters) ;
288 
289  return 0 ;
290 }
291 
292 /*----------------------------------------------------------------------------*/
299 /*----------------------------------------------------------------------------*/
300 static int omega_nightsky_flat(cpl_frameset *set, cpl_parameterlist *pars)
301 {
302 
303  int i,j,jst,jfn,isfirst;
304  cpl_size nlab;
305  int nraw = 0;
306  char *outfile = NULL;
307 
308  cpl_frame *sciframe, *product_frame;
309  cpl_parameter *par;
310  cpl_image *image;
311  cpl_imagelist *ilist;
312  cpl_propertylist *qclist;
313  cpl_stats *stats;
314 
315 
316  /*Start the recipe */
317  if (!pars) {
318  cpl_msg_error (cpl_func, "Parameters list not found");
319  return -1;
320  }
321 
322  if (cpl_frameset_is_empty(set) == 1) {
323  cpl_msg_error (cpl_func, "Frameset not found");
324  return -1;
325  }
326 
327  /* Retrieve input parameters */
328  par = cpl_parameterlist_find(pars, "omega.omega_nightsky_flat.ExtensionNumber") ;
329  omega_nsky_config.extnum = cpl_parameter_get_int(par) ;
330 
331  /* Identify the RAW and CALIB frames in the input frameset */
332  if (oc_dfs_set_groups(set)) {
333  cpl_msg_error(cpl_func, "Cannot identify RAW and CALIB frames") ;
334  return -1 ;
335  }
336 
337  /*Initialized things*/
338  omega_nsky_init();
339 
340  /* Verify the frameset contents. */
341  if ((ps.labels = cpl_frameset_labelise(set,omega_compare_tags,
342  &nlab)) == NULL) {
343  cpl_msg_error(cpl_func,"Cannot labelise the input frameset");
344  omega_nsky_tidy(0);
345  return -1;
346  }
347  if ((ps.sciset = omega_frameset_subgroup(set,ps.labels,nlab,
348  NSKY_RAW)) == NULL) {
349  cpl_msg_error(cpl_func,"Cannot find night sky frames in input frameset");
350  omega_nsky_tidy(0);
351  return -1;
352  }
353 
354 
355  /* Verify the frameset contents. */
356  nraw = cpl_frameset_count_tags(ps.sciset, NSKY_RAW);
357  if (nraw < 3) {
358  cpl_msg_error (cpl_func, "Need at least 3 (%s) frames to run "
359  "this recipe", NSKY_RAW);
360  omega_nsky_tidy(0);
361  return -1;
362  }
363 
364  cpl_msg_info (cpl_func,"There are %d %s frames in frame set",nraw, NSKY_RAW);
365 
366  /* Check for calibration frames */
367  /* Master Bias */
368  ps.mbiasfr = cpl_frameset_find_const(set, OMEGA_CALIB_BIAS);
369  if (ps.mbiasfr == NULL) {
370  cpl_msg_error(cpl_func,"Cannot find %s frame in frame set", OMEGA_CALIB_BIAS);
371  omega_nsky_tidy(0);
372  }
373  cpl_msg_info(cpl_func,"Using %s %s",OMEGA_CALIB_BIAS, cpl_frame_get_filename(ps.mbiasfr));
374 
375  /* Master Flat */
376  ps.mflatfr = cpl_frameset_find_const(set, OMEGA_CALIB_FLAT);
377  if(ps.mflatfr == NULL) {
378  cpl_msg_error(cpl_func,"Cannot find %s frame in frame set", OMEGA_CALIB_FLAT);
379  omega_nsky_tidy(0);
380  return -1;
381  }
382  cpl_msg_info(cpl_func,"Using %s %s", OMEGA_CALIB_FLAT, cpl_frame_get_filename(ps.mflatfr));
383 
384  /* Bad Pixels Map */
385  ps.bpmfr = cpl_frameset_find (set,OMEGA_CALIB_BPM);
386  if(ps.bpmfr != NULL)
387  cpl_msg_info(cpl_func,"Using %s %s",OMEGA_CALIB_BPM,cpl_frame_get_filename(ps.bpmfr));
388 
389  /* Get first frame from frame set */
390  sciframe = cpl_frameset_get_first(ps.sciset);
391 
392  /* Loop for each of the image extensions */
393  omega_extensions(sciframe, omega_nsky_config.extnum,&jst,&jfn);
394  if(omega_nsky_config.extnum == 0){
395  cpl_msg_error(cpl_func,"Unsupported extension request, %d",omega_nsky_config.extnum);
396  omega_nsky_tidy(0);
397  return -1;
398  }
399 
400  for (j = jst; j <= jfn; j++) {
401  isfirst = (j == jst);
402  cpl_msg_indent_more();
403  cpl_msg_info(cpl_func,".....Working on extension %d.....",j);
404  cpl_msg_indent_less();
405 
406  /* Load calibration frames */
407  if(omega_nsky_load_calib(j) != 0){
408  cpl_msg_error(cpl_func,"Cannot load calibration frame(s)");
409  freespace(outfile);
410  omega_nsky_tidy(0);
411  return -1;
412  }
413 
414  ilist = cpl_imagelist_new();
415 
416  sciframe = cpl_frameset_get_first(ps.sciset);
417  for(i = 0; i < nraw; i++) {
418  /* Load omega_fits structure for this extension */
419  ps.scifits = omega_fits_load(sciframe, CPL_TYPE_FLOAT, j);
420 
421  /* Call processing routine */
422  image = omega_nsky_process(ps.scifits,ps.mbias,ps.mflat,ps.bpm, pars, j);
423  if(image == NULL){
424  cpl_msg_error(cpl_func,"Cannot reduce image %d of %d",i,nraw);
425  freespace(outfile);
426  freeilist(ilist);
427  omega_nsky_tidy(0);
428  return -1;
429  }
430 
431  cpl_imagelist_set(ilist, image,i);
432  sciframe = cpl_frameset_get_next(ps.sciset);
433  freefits(ps.scifits);
434  ps.scifits = NULL;
435 
436  }
437  ps.nsky = omega_nsky_create(ilist,ps.bpm,nraw);
438  freeilist(ilist);
439 
440  if(isfirst){
441  outfile = cpl_sprintf("%s_%s.fits", INSTRUME,NSKY_PROCATG);
442  product_frame = omega_product_frame(outfile, NSKY_PROCATG, CPL_FRAME_TYPE_IMAGE);
443  }
444 
445  stats = cpl_stats_new_from_image(ps.nsky, CPL_STATS_ALL);
446  qclist = cpl_propertylist_new();
447  cpl_propertylist_append_double(qclist, "HIERARCH ESO QC NSKYMIN", cpl_stats_get_min(stats));
448  cpl_propertylist_append_double(qclist, "HIERARCH ESO QC NSKYMAX", cpl_stats_get_max(stats));
449  cpl_propertylist_append_double(qclist, "HIERARCH ESO QC NSKYMEAN", cpl_stats_get_mean(stats));
450  cpl_propertylist_append_double(qclist, "HIERARCH ESO QC NSKYDEV", cpl_stats_get_stdev(stats));
451  cpl_propertylist_append_double(qclist, "HIERARCH ESO QC NSKYMED", cpl_stats_get_median(stats));
452  freestats(stats);
453 
454  cpl_msg_info(cpl_func,"Saving Night Sky Flat");
455  /* Save Night Sky Flat */
456  if(omega_save_image(ps.nsky,set,pars,NULL,qclist,CPL_BPP_IEEE_FLOAT,outfile,
457  RECIPE,product_frame,NULL,isfirst) == -1){
458  cpl_msg_error(cpl_func,"Cannot save product %s",NSKY_PROCATG);
459  freeplist(qclist);
460  freespace(outfile);
461  omega_nsky_tidy(0);
462  return -1;
463  }
464 
465  freeplist(qclist);
466  omega_nsky_tidy(1);
467  }
468 
469  freespace(outfile);
470  omega_nsky_tidy(0);
471 
472  return 0;
473 }
474 
487 cpl_image *omega_nsky_process(omega_fits *scifits, cpl_image *mbias, cpl_image *mflat,
488  cpl_image *bpm, cpl_parameterlist *pars, int ext)
489 {
490  int oc = 0;
491 
492  cpl_image *nsky;
493  cpl_parameter *p;
494  cpl_propertylist *xlist;
495 
496  if((scifits == NULL) || (mbias == NULL) || (mflat == NULL) ||
497  (bpm == NULL))
498  return NULL;
499 
500  /* Get a few parameters */
501  p = cpl_parameterlist_find(pars, "omega.omega_nightsky_flat.OverscanMethod") ;
502  omega_nsky_config.oc = cpl_parameter_get_int(p);
503 
504  /* Check overscan correction method consistency */
505  oc = omega_pfits_get_overscan(ps.mbiasfr, ext);
506  if(oc != omega_nsky_config.oc) {
507  cpl_msg_warning (cpl_func, "Overscan correction mode for Master Bias (oc = %d) differs from "
508  "the one used here (oc = %d)", oc, omega_nsky_config.oc);
509  }
510 
511  /* Trim and overscan correct all images */
512  if((nsky = omega_trim_oscan_correct(scifits, omega_nsky_config.oc)) == NULL){
513  cpl_msg_error(cpl_func,"Unable to trim image");
514  return NULL;
515  }
516 
517  /* Correct coordinates after trimming */
518  xlist = omega_fits_get_ehu(scifits);
519  omega_shift_refpix(omega_fits_get_frame(scifits), ext, xlist);
520 
521  /* Subtract the bias */
522  omega_biascor(nsky, mbias);
523 
524  /* Divide by the flat */
525  if(omega_flatcor(nsky, mflat, NULL) != 0){
526  cpl_msg_error(cpl_func,"Error in flat correction");
527  freeimage(nsky);
528  xlist = NULL;
529  return NULL;
530  }
531 
532  xlist = NULL;
533 
534  return nsky;
535 }
536 
537 
538 static int omega_nsky_load_calib(int ext)
539 {
540 
541  /* Load mandatory calibration frames */
542  /* master bias */
543  ps.mbias = cpl_image_load(cpl_frame_get_filename(ps.mbiasfr), CPL_TYPE_FLOAT, 0, ext);
544  if(ps.mbias == NULL){
545  cpl_msg_error(cpl_func,"Cannot load Master Bias. %s", cpl_error_get_message());
546  return -1;
547  }
548  /* master flat */
549  ps.mflat = cpl_image_load(cpl_frame_get_filename(ps.mflatfr),CPL_TYPE_FLOAT,0,ext);
550  if (ps.mflat == NULL){
551  cpl_msg_error(cpl_func,"Cannot load Master Flat. %s",cpl_error_get_message());
552  return -1;
553  }
554 
555  /* Optional */
556  /* bad pixels map */
557  if(ps.bpmfr != NULL){
558  ps.bpm = cpl_image_load(cpl_frame_get_filename(ps.bpmfr), CPL_TYPE_INT, 0, ext);
559  if(ps.bpm == NULL)
560  cpl_msg_warning(cpl_func, "Cannot load BPM. %s", cpl_error_get_message());
561 
562  }
563 
564  return 0;
565 }
566 
567 /* Initialize the pointers */
568 static void omega_nsky_init(void)
569 {
570  ps.sciset = NULL;
571  ps.bpmfr = NULL;
572  ps.mbiasfr = NULL;
573  ps.mflatfr = NULL;
574  ps.scifits = NULL;
575  ps.labels = NULL;
576  ps.mbias = NULL;
577  ps.mflat = NULL;
578  ps.bpm = NULL;
579  ps.nsky = NULL;
580 }
581 
582 /*
583  * Free any allocated memory
584  */
585 static void omega_nsky_tidy(int level)
586 {
587  freeimage(ps.mbias);
588  freeimage(ps.mflat);
589  freeimage(ps.bpm);
590  freeimage(ps.nsky);
591  if(level == 1)
592  return;
593 
594  freeframeset(ps.sciset);
595  freespace(ps.labels);
596  freefits(ps.scifits);
597 }
598