FORS Pipeline Reference Manual  5.0.9
vimos_science.c
1 /* $Id: vimos_science.c,v 1.22 2010-09-14 07:38:16 cizzo Exp $
2  *
3  * This file is part of the FORS Data Reduction Pipeline
4  * Copyright (C) 2002-2010 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 02110-1301 USA
19  */
20 
21 /*
22  * $Author: cizzo $
23  * $Date: 2010-09-14 07:38:16 $
24  * $Revision: 1.22 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 #include <math.h>
33 #include <string.h>
34 #include <vimos_science_impl.h>
35 #include <cpl.h>
36 #include <moses.h>
37 #include <fors_stack.h>
38 #include <fors_tools.h>
39 #include <fors_dfs.h>
40 #include <fors_qc.h>
41 
42 static int vimos_science_create(cpl_plugin *);
43 static int vimos_science_exec(cpl_plugin *);
44 static int vimos_science_destroy(cpl_plugin *);
45 static int vimos_science(cpl_parameterlist *, cpl_frameset *);
46 
47 static char vimos_science_description[] =
48 "This recipe is used to reduce scientific spectra using the extraction\n"
49 "mask and the products created by the recipe vimos_calib. The spectra are\n"
50 "bias subtracted, flat fielded (if a normalised flat field is specified)\n"
51 "and remapped eliminating the optical distortions. The wavelength calibration\n"
52 "can be optionally upgraded using a number of sky lines: if no sky lines\n"
53 "catalog of wavelengths is specified, an internal one is used instead.\n"
54 "If the alignment to the sky lines is performed, the input dispersion\n"
55 "coefficients table is upgraded and saved to disk, and a new CCD wavelengths\n"
56 "map is created. A grism table (typically depending on the grism used)\n"
57 "may also be specified: this table contains a default recipe parameter\n"
58 "setting to control the way spectra are extracted for a specific instrument\n"
59 "mode, as it is used for automatic run of the pipeline on Paranal and in\n"
60 "Garching. If this table is specified, it will modify the default recipe\n"
61 "parameter setting, with the exception of those parameters which have been\n"
62 "explicitly modifyed on the command line. If a grism table is not specified,\n"
63 "the input recipe parameters values will always be read from the command\n"
64 "line, or from an esorex configuration file if present, or from their\n"
65 "generic default values (that are rarely meaningful).\n"
66 "MOS_SLIT_LOCATION and MOS_CURV_COEFF tables are not (yet) expected for\n"
67 "long-slit-like data.\n"
68 "Only in case of a standard star exposure input, the atmospheric extinction\n"
69 "table and a table with the physical fluxes of the observed standard star\n"
70 "must be specified in input.\n\n"
71 "Input files:\n\n"
72 " DO category: Type: Explanation: Required:\n"
73 " MOS_SCIENCE Raw Scientific exposure Y\n"
74 " or MOS_STANDARD Raw Standard star exposure Y\n"
75 "\n"
76 " MASTER_BIAS Calib Master bias Y\n"
77 " SKY_LINE_CATALOG Calib Sky lines catalog .\n"
78 " MOS_MASTER_SCREEN_FLAT Calib Normalised flat field .\n"
79 " MOS_DISP_COEFF Calib Inverse dispersion Y\n"
80 " MOS_CURV_COEFF Calib Spectral curvature Y\n"
81 " MOS_SLIT_LOCATION Calib Slits positions table Y\n"
82 " GRISM_TABLE Calib Grism table .\n"
83 "\n"
84 " In case MOS_STANDARD is specified in input,\n"
85 "\n"
86 " EXTINCT_TABLE Calib Atmospheric extinction Y\n"
87 " STD_FLUX_TABLE Calib Standard star flux Y\n"
88 "\n"
89 "Output files:\n\n"
90 " DO category: Data type: Explanation:\n"
91 " MOS_SCIENCE_REDUCED FITS image Extracted scientific spectra\n"
92 " or MOS_STANDARD_REDUCED FITS image Extracted standard star spectrum\n"
93 " MOS_SKY_REDUCED FITS image Extracted sky spectra\n"
94 " MOS_ERROR_REDUCED FITS image Errors on extracted spectra\n"
95 "\n"
96 " MOS_UNMAPPED_SCIENCE FITS image Sky subtracted scientific spectra\n"
97 " or MOS_UNMAPPED_STANDARD FITS image Sky subtracted standard spectrum\n"
98 "\n"
99 " MOS_SCIENCE_EXTRACTED FITS image Rectified scientific spectra\n"
100 " or MOS_STANDARD_EXTRACTED FITS image Rectified standard star spectrum\n"
101 "\n"
102 " MOS_SCIENCE_SKY_EXTRACTED FITS image Rectified science spectra with sky\n"
103 "or MOS_STANDARD_SKY_EXTRACTED FITS image Rectified std spectrum with sky\n"
104 "\n"
105 " MOS_SCIENCE_SKY FITS image Rectified sky spectra\n"
106 " MOS_UNMAPPED_SKY FITS image Sky on CCD\n"
107 " MOS_GLOBAL_SKY_SPECTRUM FITS table Global sky spectrum\n"
108 " OBJECT_TABLE FITS table Positions of detected objects\n"
109 "\n"
110 " Only if the sky-alignment of the wavelength solution is requested:\n"
111 " MOS_SKYLINES_OFFSETS_LONG FITS table Sky lines offsets (LSS-like data)\n"
112 "or MOS_SKYLINES_OFFSETS_SLIT FITS table Sky lines offsets (MOS-like data)\n"
113 " MOS_DISP_COEFF_SKY FITS table Upgraded dispersion coefficients\n"
114 " MOS_WAVELENGTH_MAP_SKY FITS image Upgraded wavelength map\n"
115 "\n"
116 " Only if a MOS_STANDARD is specified in input:\n"
117 " MOS_SPECPHOT_TABLE FITS table Efficiency and response curves\n\n";
118 
130 int cpl_plugin_get_info(cpl_pluginlist *list)
131 {
132  cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe );
133  cpl_plugin *plugin = &recipe->interface;
134 
135  cpl_plugin_init(plugin,
136  CPL_PLUGIN_API,
137  FORS_BINARY_VERSION,
138  CPL_PLUGIN_TYPE_RECIPE,
139  "vimos_science",
140  "Extraction of scientific spectra",
141  vimos_science_description,
142  "Carlo Izzo",
143  PACKAGE_BUGREPORT,
144  "This file is currently part of the FORS Instrument Pipeline\n"
145  "Copyright (C) 2002-2010 European Southern Observatory\n\n"
146  "This program is free software; you can redistribute it and/or modify\n"
147  "it under the terms of the GNU General Public License as published by\n"
148  "the Free Software Foundation; either version 2 of the License, or\n"
149  "(at your option) any later version.\n\n"
150  "This program is distributed in the hope that it will be useful,\n"
151  "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
152  "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
153  "GNU General Public License for more details.\n\n"
154  "You should have received a copy of the GNU General Public License\n"
155  "along with this program; if not, write to the Free Software Foundation,\n"
156  "Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n",
157  vimos_science_create,
158  vimos_science_exec,
159  vimos_science_destroy);
160 
161  cpl_pluginlist_append(list, plugin);
162 
163  return 0;
164 }
165 
166 
177 static int vimos_science_create(cpl_plugin *plugin)
178 {
179  cpl_recipe *recipe;
180  cpl_parameter *p;
181 
182 
183  /*
184  * Check that the plugin is part of a valid recipe
185  */
186 
187  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
188  recipe = (cpl_recipe *)plugin;
189  else
190  return -1;
191 
192  /*
193  * Create the parameters list in the cpl_recipe object
194  */
195 
196  recipe->parameters = cpl_parameterlist_new();
197 
198 
199  /*
200  * Dispersion
201  */
202 
203  p = cpl_parameter_new_value("fors.vimos_science.dispersion",
204  CPL_TYPE_DOUBLE,
205  "Resampling step (Angstrom/pixel)",
206  "fors.vimos_science",
207  0.0);
208  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dispersion");
209  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
210  cpl_parameterlist_append(recipe->parameters, p);
211 
212  /*
213  * Sky lines alignment
214  */
215 
216  p = cpl_parameter_new_value("fors.vimos_science.skyalign",
217  CPL_TYPE_INT,
218  "Polynomial order for sky lines alignment, "
219  "or -1 to avoid alignment",
220  "fors.vimos_science",
221  0);
222  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skyalign");
223  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
224  cpl_parameterlist_append(recipe->parameters, p);
225 
226  /*
227  * Line catalog table column containing the sky reference wavelengths
228  */
229 
230  p = cpl_parameter_new_value("fors.vimos_science.wcolumn",
231  CPL_TYPE_STRING,
232  "Name of sky line catalog table column "
233  "with wavelengths",
234  "fors.vimos_science",
235  "WLEN");
236  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wcolumn");
237  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
238  cpl_parameterlist_append(recipe->parameters, p);
239 
240  /*
241  * Start wavelength for spectral extraction
242  */
243 
244  p = cpl_parameter_new_value("fors.vimos_science.startwavelength",
245  CPL_TYPE_DOUBLE,
246  "Start wavelength in spectral extraction",
247  "fors.vimos_science",
248  0.0);
249  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startwavelength");
250  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
251  cpl_parameterlist_append(recipe->parameters, p);
252 
253  /*
254  * End wavelength for spectral extraction
255  */
256 
257  p = cpl_parameter_new_value("fors.vimos_science.endwavelength",
258  CPL_TYPE_DOUBLE,
259  "End wavelength in spectral extraction",
260  "fors.vimos_science",
261  0.0);
262  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "endwavelength");
263  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
264  cpl_parameterlist_append(recipe->parameters, p);
265 
266  /*
267  * Reference wavelength for wavelength calibration
268  */
269 
270  p = cpl_parameter_new_value("fors.vimos_science.reference",
271  CPL_TYPE_DOUBLE,
272  "Reference wavelength for calibration",
273  "fors.vimos_science",
274  0.0);
275  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "reference");
276  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
277  cpl_parameterlist_append(recipe->parameters, p);
278 
279  /*
280  * Flux conservation
281  */
282 
283  p = cpl_parameter_new_value("fors.vimos_science.flux",
284  CPL_TYPE_BOOL,
285  "Apply flux conservation",
286  "fors.vimos_science",
287  TRUE);
288  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux");
289  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
290  cpl_parameterlist_append(recipe->parameters, p);
291 
292  /*
293  * Apply flat field
294  */
295 
296  p = cpl_parameter_new_value("fors.vimos_science.flatfield",
297  CPL_TYPE_BOOL,
298  "Apply flat field",
299  "fors.vimos_science",
300  TRUE);
301  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flatfield");
302  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
303  cpl_parameterlist_append(recipe->parameters, p);
304 
305  /*
306  * Global sky subtraction
307  */
308 
309  p = cpl_parameter_new_value("fors.vimos_science.skyglobal",
310  CPL_TYPE_BOOL,
311  "Subtract global sky spectrum from CCD",
312  "fors.vimos_science",
313  FALSE);
314  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skyglobal");
315  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
316  cpl_parameterlist_append(recipe->parameters, p);
317 
318  /*
319  * Local sky subtraction on extracted spectra
320  */
321 
322  p = cpl_parameter_new_value("fors.vimos_science.skymedian",
323  CPL_TYPE_BOOL,
324  "Sky subtraction from extracted slit spectra",
325  "fors.vimos_science",
326  FALSE);
327  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skymedian");
328  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
329  cpl_parameterlist_append(recipe->parameters, p);
330 
331  /*
332  * Local sky subtraction on CCD spectra
333  */
334 
335  p = cpl_parameter_new_value("fors.vimos_science.skylocal",
336  CPL_TYPE_BOOL,
337  "Sky subtraction from CCD slit spectra",
338  "fors.vimos_science",
339  TRUE);
340  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skylocal");
341  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
342  cpl_parameterlist_append(recipe->parameters, p);
343 
344  /*
345  * Cosmic rays removal
346  */
347 
348  p = cpl_parameter_new_value("fors.vimos_science.cosmics",
349  CPL_TYPE_BOOL,
350  "Eliminate cosmic rays hits (only if global "
351  "or local sky subtraction is also requested)",
352  "fors.vimos_science",
353  TRUE);
354  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cosmics");
355  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
356  cpl_parameterlist_append(recipe->parameters, p);
357 
358  /*
359  * Slit margin
360  */
361 
362  p = cpl_parameter_new_value("fors.vimos_science.slit_margin",
363  CPL_TYPE_INT,
364  "Number of pixels to exclude at each slit "
365  "in object detection and extraction",
366  "fors.vimos_science",
367  3);
368  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "slit_margin");
369  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
370  cpl_parameterlist_append(recipe->parameters, p);
371 
372  /*
373  * Extraction radius
374  */
375 
376  p = cpl_parameter_new_value("fors.vimos_science.ext_radius",
377  CPL_TYPE_INT,
378  "Maximum extraction radius for detected "
379  "objects (pixel)",
380  "fors.vimos_science",
381  6);
382  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ext_radius");
383  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
384  cpl_parameterlist_append(recipe->parameters, p);
385 
386  /*
387  * Contamination radius
388  */
389 
390  p = cpl_parameter_new_value("fors.vimos_science.cont_radius",
391  CPL_TYPE_INT,
392  "Minimum distance at which two objects "
393  "of equal luminosity do not contaminate "
394  "each other (pixel)",
395  "fors.vimos_science",
396  0);
397  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cont_radius");
398  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
399  cpl_parameterlist_append(recipe->parameters, p);
400 
401  /*
402  * Object extraction method
403  */
404 
405  p = cpl_parameter_new_value("fors.vimos_science.ext_mode",
406  CPL_TYPE_INT,
407  "Object extraction method: 0 = aperture, "
408  "1 = Horne optimal extraction",
409  "fors.vimos_science",
410  1);
411  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ext_mode");
412  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
413  cpl_parameterlist_append(recipe->parameters, p);
414 
415  /*
416  * Normalise output by exposure time
417  */
418 
419  p = cpl_parameter_new_value("fors.vimos_science.time_normalise",
420  CPL_TYPE_BOOL,
421  "Normalise output spectra by the exposure time",
422  "fors.vimos_science",
423  TRUE);
424  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "time_normalise");
425  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
426  cpl_parameterlist_append(recipe->parameters, p);
427 
428  /*
429  * Look for a standard star in any frame classified as MOS_STANDARD
430  */
431 
432  p = cpl_parameter_new_value("fors.vimos_science.anyframe",
433  CPL_TYPE_BOOL,
434  "Look for a standard star in any frame "
435  "classified as MOS_STANDARD",
436  "fors.vimos_science",
437  FALSE);
438  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "anyframe");
439  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
440  cpl_parameterlist_append(recipe->parameters, p);
441 
442 
443  /*
444  * Order of polynomial modeling the instrument response.
445  */
446 
447  p = cpl_parameter_new_value("fors.vimos_science.response",
448  CPL_TYPE_INT,
449  "Order of polynomial modeling the "
450  "instrument response",
451  "fors.vimos_science",
452  5);
453  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "response");
454  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
455  cpl_parameterlist_append(recipe->parameters, p);
456 
457 
458  /*
459  * Type of alignment of dithered frames
460  */
461 
462  p = cpl_parameter_new_enum("fors.vimos_science.alignment",
463  CPL_TYPE_STRING,
464  "Type of alignment of dithered frames, "
465  "either to the nearest neighbour pixel "
466  "or to fractions of pixel",
467  "fors.vimos_science",
468  "integer", 2,
469  "integer", "float");
470  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "alignment");
471  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
472  cpl_parameterlist_append(recipe->parameters, p);
473 
474 
475  /*
476  * Stacking method of dithered frames
477  */
478 
479  fors_stack_define_parameters(recipe->parameters,
480  "fors.vimos_science", "average");
481 
482 
483  /*
484  * Fringing correction
485  */
486 
487  p = cpl_parameter_new_value("fors.vimos_science.fringing",
488  CPL_TYPE_BOOL,
489  "Apply fringing correction "
490  "(only for dithered observations)",
491  "fors.vimos_science",
492  TRUE);
493  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "fringing");
494  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
495  cpl_parameterlist_append(recipe->parameters, p);
496 
497 
498  /*
499  * Computation of QC1 parameters
500  */
501 
502  p = cpl_parameter_new_value("fors.vimos_science.qc",
503  CPL_TYPE_BOOL,
504  "Compute QC1 parameters",
505  "fors.vimos_science",
506  TRUE);
507  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "qc");
508  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
509  cpl_parameterlist_append(recipe->parameters, p);
510 
511 
512  return 0;
513 }
514 
515 
524 static int vimos_science_exec(cpl_plugin *plugin)
525 {
526  cpl_recipe *recipe;
527 
528  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
529  recipe = (cpl_recipe *)plugin;
530  else
531  return -1;
532 
533  return vimos_science(recipe->parameters, recipe->frames);
534 }
535 
536 
545 static int vimos_science_destroy(cpl_plugin *plugin)
546 {
547  cpl_recipe *recipe;
548 
549  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
550  recipe = (cpl_recipe *)plugin;
551  else
552  return -1;
553 
554  cpl_parameterlist_delete(recipe->parameters);
555 
556  return 0;
557 }
558 
559 
569 static int vimos_science(cpl_parameterlist *parlist, cpl_frameset *frameset)
570 {
571  const char *science_tag = "MOS_SCIENCE";
572  int mos = cpl_frameset_count_tags(frameset, science_tag);
573 
574  if (mos > 1) {
575  char version[80];
576  const char *curv_coeff_tag = "MOS_CURV_COEFF";
577  const char *slit_location_tag = "MOS_SLIT_LOCATION";
578  const char *disp_coeff_tag = "MOS_DISP_COEFF";
579  const char *unmapped_science_tag = "MOS_UNMAPPED_SCIENCE";
580  const char *mapped_science_tag = "MOS_SCIENCE_EXTRACTED";
581  const char *object_table_tag = "OBJECT_TABLE";
582  const char *unmapped_sky_tag = "MOS_UNMAPPED_SKY";
583  const char *mapped_sky_tag = "MOS_SCIENCE_SKY";
584  const char *reduced_science_tag = "MOS_SCIENCE_REDUCED";
585  const char *reduced_sky_tag = "MOS_SKY_REDUCED";
586  const char *reduced_error_tag = "MOS_ERROR_REDUCED";
587  const char *stack_method;
588  const char *alignment;
589  double refwave;
590  double startwavelength;
591  double endwavelength;
592  double dispersion;
593  int flux;
594  int fringing;
595  int cosmics;
596  int slit_margin;
597  int ext_radius;
598  int cont_radius;
599  int ext_mode;
600  int rotate = 1;
601  int rotate_back = -1;
602  cpl_frameset *work = cpl_frameset_duplicate(frameset);
603  cpl_frame **mos_science = cpl_calloc(mos, sizeof(cpl_frame*));
604  cpl_parameter *param;
605  cpl_table *reference = NULL;
606  cpl_table *objects = NULL;
607  cpl_image **images = NULL;
608  cpl_image *image = NULL;
609  cpl_image *sky_image = NULL;
610  cpl_imagelist *imagelist = NULL;
611  cpl_image *fringes = NULL;
612  cpl_image *stacked = NULL;
613  cpl_image *mapped = NULL;
614  cpl_image *smapped = NULL;
615  cpl_image *sky_stacked = NULL;
616  cpl_image *sky_mapped = NULL;
617  cpl_image *sky_smapped = NULL;
618  cpl_table *polytraces = NULL;
619  cpl_table *idscoeff = NULL;
620  cpl_table *slits = NULL;
621  cpl_table *grism_table = NULL;
622  cpl_propertylist *header = NULL;
623  char *name;
624  double offset;
625  double gain;
626  double ron;
627  int time_normal;
628  int min_reject;
629  int max_reject;
630  double klow;
631  double khigh;
632  int kiter;
633  int int_alignment = 0;
634  int status;
635  int nx, ny;
636  int i;
637 
638 
639  snprintf(version, 80, "%s-%s", PACKAGE, PACKAGE_VERSION);
640 
641  grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1);
642 
643  flux = dfs_get_parameter_bool(parlist, "fors.vimos_science.flux", NULL);
644 
645  cosmics = dfs_get_parameter_bool(parlist,
646  "fors.vimos_science.cosmics", NULL);
647 
648  dispersion = dfs_get_parameter_double(parlist,
649  "fors.vimos_science.dispersion", grism_table);
650 
651  refwave = dfs_get_parameter_double(parlist,
652  "fors.vimos_science.reference", grism_table);
653 
654  startwavelength = dfs_get_parameter_double(parlist,
655  "fors.vimos_science.startwavelength", grism_table);
656 
657  endwavelength = dfs_get_parameter_double(parlist,
658  "fors.vimos_science.endwavelength", grism_table);
659 
660  alignment = dfs_get_parameter_string(parlist,
661  "fors.vimos_science.alignment", NULL);
662 
663  if (strcmp(alignment, "integer") == 0) {
664  int_alignment = 1;
665  }
666 
667  stack_method = dfs_get_parameter_string(parlist,
668  "fors.vimos_science.stack_method", NULL);
669 
670  if (strcmp(stack_method, "minmax") == 0) {
671  min_reject = dfs_get_parameter_int(parlist,
672  "fors.vimos_science.minrejection", NULL);
673  if (min_reject < 0) {
674  cpl_msg_error("vimos_science",
675  "Invalid number of lower rejections");
676  return -1;
677  }
678 
679  max_reject = dfs_get_parameter_int(parlist,
680  "fors.vimos_science.maxrejection", NULL);
681 
682  if (max_reject < 0) {
683  cpl_msg_error("vimos_science",
684  "Invalid number of upper rejections");
685  return -1;
686  }
687  }
688 
689  if (strcmp(stack_method, "ksigma") == 0) {
690  klow = dfs_get_parameter_double(parlist,
691  "fors.vimos_science.klow", NULL);
692  if (klow < 0.1) {
693  cpl_msg_error("vimos_science",
694  "Invalid lower K-sigma");
695  return -1;
696  }
697 
698  khigh = dfs_get_parameter_double(parlist,
699  "fors.vimos_science.khigh", NULL);
700  if (khigh < 0.1) {
701  cpl_msg_error("vimos_science",
702  "Invalid lower K-sigma");
703  return -1;
704  }
705 
706  kiter = dfs_get_parameter_int(parlist,
707  "fors.vimos_science.kiter", NULL);
708  if (kiter < 1) {
709  cpl_msg_error("vimos_science",
710  "Invalid number of iterations");
711  return -1;
712  }
713  }
714 
715  slit_margin = dfs_get_parameter_int(parlist,
716  "fors.vimos_science.slit_margin",
717  NULL);
718  ext_radius = dfs_get_parameter_int(parlist,
719  "fors.vimos_science.ext_radius",
720  NULL);
721  cont_radius = dfs_get_parameter_int(parlist,
722  "fors.vimos_science.cont_radius",
723  NULL);
724  ext_mode = dfs_get_parameter_int(parlist,
725  "fors.vimos_science.ext_mode",
726  NULL);
727 
728  fringing = dfs_get_parameter_bool(parlist,
729  "fors.vimos_science.fringing", NULL);
730 
731  cpl_table_delete(grism_table); grism_table = NULL;
732 
733 
734  /*
735  * Disable time normalisation for single runs
736  */
737 
738  param = cpl_parameterlist_find(parlist,
739  "fors.vimos_science.time_normalise");
740  time_normal = cpl_parameter_get_bool(param);
741  cpl_parameter_set_bool(param, 0);
742 
743 
744  /*
745  * Collect all scientific frames from input SOF
746  */
747 
748  mos_science[0] = cpl_frameset_find(frameset, science_tag);
749  for (i = 1; i < mos; i++) {
750  mos_science[i] = cpl_frameset_find(frameset, NULL);
751  }
752 
753 
754  /*
755  * Process scientific frames one at a time
756  */
757 
758  for (i = 0; i < mos; i++) {
759  cpl_frameset_erase(work, science_tag);
760  cpl_frameset_insert(work, cpl_frame_duplicate(mos_science[i]));
761  vimos_science_impl(work, parlist);
762 
763 
764  /*
765  * Cleanup work SOF from products
766  * (not really necessary, but clean)
767  */
768 
769  cpl_frameset_erase(work, "MOS_SKYLINES_OFFSETS_SLIT");
770  cpl_frameset_erase(work, "MOS_SCIENCE_SKY_EXTRACTED");
771  cpl_frameset_erase(work, "MOS_UNMAPPED_SKY");
772  cpl_frameset_erase(work, "MOS_UNMAPPED_SCIENCE");
773  cpl_frameset_erase(work, "MOS_WAVELENGTH_MAP_SKY");
774  cpl_frameset_erase(work, "MOS_SCIENCE_SKY");
775  cpl_frameset_erase(work, "OBJECT_TABLE");
776  cpl_frameset_erase(work, "MOS_SCIENCE_REDUCED");
777  cpl_frameset_erase(work, "MOS_SKY_REDUCED");
778  cpl_frameset_erase(work, "MOS_ERROR_REDUCED");
779  cpl_frameset_erase(work, "MOS_DISP_COEFF_SKY");
780  cpl_frameset_erase(work, "MOS_SCIENCE_EXTRACTED");
781 
782 
783  /*
784  * Of all products, only keep the object tables, the
785  * unmapped sky, and the unmapped science.
786  */
787 
788  name = cpl_sprintf("object_table_%d.fits", i);
789  status = rename("object_table.fits", name);
790  cpl_free(name);
791  name = cpl_sprintf("mos_unmapped_sky_%d.fits", i);
792  status |= rename("mos_unmapped_sky.fits", name);
793  cpl_free(name);
794  name = cpl_sprintf("mos_unmapped_science_%d.fits", i);
795  status |= rename("mos_unmapped_science.fits", name);
796  cpl_free(name);
797 
798  if (status) {
799  cpl_msg_error("vimos_science", "Cannot rename product.");
800  cpl_free(mos_science);
801  cpl_frameset_delete(work);
802  return -1;
803  }
804  }
805 
806  cpl_free(mos_science);
807  cpl_frameset_delete(work);
808 
809  if (fringing) {
810 
811  /*
812  * Produce fringing map by median stacking
813  */
814 
815  imagelist = cpl_imagelist_new();
816 
817  for (i = 0; i < mos; i++) {
818  name = cpl_sprintf("mos_unmapped_science_%d.fits", i);
819  image = cpl_image_load(name, CPL_TYPE_FLOAT, 0, 0);
820  cpl_imagelist_set(imagelist, image,
821  cpl_imagelist_get_size(imagelist));
822  }
823 
824  fringes = cpl_imagelist_collapse_median_create(imagelist);
825  cpl_imagelist_delete(imagelist);
826  cpl_image_save(fringes, "fringes.fits",
827  CPL_BPP_IEEE_FLOAT, NULL, CPL_IO_DEFAULT);
828 
829  }
830 
831 
832  /*
833  * Now stack all frames and extract final objects
834  */
835 
836  reference = cpl_table_load("object_table_0.fits", 1, 1);
837  stacked = cpl_image_load("mos_unmapped_science_0.fits",
838  CPL_TYPE_FLOAT, 0, 0);
839  sky_stacked = cpl_image_load("mos_unmapped_sky_0.fits",
840  CPL_TYPE_FLOAT, 0, 0);
841  if (fringing) {
842  cpl_image_subtract(stacked, fringes);
843  cpl_image_add(sky_stacked, fringes);
844  }
845 
846 // Added just for eliminating wcs like in other images
847  cpl_image_save(stacked, "mos_unmapped_science_0.fits",
848  CPL_BPP_IEEE_FLOAT, NULL, CPL_IO_DEFAULT);
849 // end of debug line
850 
851  for (i = 1; i < mos; i++) {
852  name = cpl_sprintf("object_table_%d.fits", i);
853  objects = cpl_table_load(name, 1, 1);
854  cpl_free(name);
855  if (mos_compute_offset(reference, objects, &offset)) {
856  cpl_msg_error("vimos_science", "Cannot compute offset.");
857  cpl_table_delete(objects);
858  return -1;
859  }
860  cpl_table_delete(objects);
861  name = cpl_sprintf("mos_unmapped_science_%d.fits", i);
862  image = cpl_image_load(name, CPL_TYPE_FLOAT, 0, 0);
863 
864  if (fringing) {
865  cpl_image_subtract(image, fringes);
866  }
867 
868  cpl_msg_info("vimos_science",
869  "Frame %d offset relative "
870  "to frame 1: %.2f pix\n", i + 1, offset);
871 
872  if (int_alignment) {
873  offset = floor(offset + 0.5);
874  cpl_msg_info("vimos_science",
875  "Nearest neighbour offset applied is "
876  "%.0f pix\n", offset);
877  }
878 
879  mos_image_shift(image, offset, 0.0);
880  cpl_image_save(image, name, CPL_BPP_IEEE_FLOAT,
881  NULL, CPL_IO_DEFAULT);
882  cpl_free(name);
883 
884  /*
885  * Here stacking sky frames, they are always averaged
886  */
887 
888  name = cpl_sprintf("mos_unmapped_sky_%d.fits", i);
889  sky_image = cpl_image_load(name, CPL_TYPE_FLOAT, 0, 0);
890 
891  if (fringing) {
892  cpl_image_add(sky_image, fringes);
893  }
894 
895  mos_image_shift(sky_image, offset, 0.0);
896  cpl_free(name);
897  cpl_image_add(sky_stacked, sky_image);
898  cpl_image_delete(sky_image);
899 
900  if (strcmp(stack_method, "average") == 0) {
901  cpl_image_add(stacked, image);
902  cpl_image_delete(image);
903  }
904  else {
905  if (i == 1) {
906  imagelist = cpl_imagelist_new();
907  cpl_imagelist_set(imagelist, stacked,
908  cpl_imagelist_get_size(imagelist));
909  }
910  cpl_imagelist_set(imagelist, image,
911  cpl_imagelist_get_size(imagelist));
912  }
913  }
914  cpl_table_delete(reference);
915 
916  cpl_image_divide_scalar(sky_stacked, mos);
917 
918  if (fringing) {
919  cpl_image_delete(fringes);
920  }
921 
922  if (strcmp(stack_method, "average") == 0) {
923  cpl_image_divide_scalar(stacked, mos);
924  }
925 
926  if (strcmp(stack_method, "median") == 0) {
927  stacked = cpl_imagelist_collapse_median_create(imagelist);
928  cpl_imagelist_delete(imagelist);
929  }
930 
931  if (strcmp(stack_method, "minmax") == 0) {
932  stacked = cpl_imagelist_collapse_minmax_create(imagelist,
933  min_reject,
934  max_reject);
935  cpl_imagelist_delete(imagelist);
936  }
937 
938  if (strcmp(stack_method, "ksigma") == 0) {
939  stacked = mos_ksigma_stack(imagelist, klow, khigh, kiter, NULL);
940  cpl_imagelist_delete(imagelist);
941  }
942 
943  header = dfs_load_header(frameset, science_tag, 0);
944 
945  gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD");
946  ron = cpl_propertylist_get_double(header, "ESO DET OUT1 RON");
947  ron /= gain; /* Convert from electrons to ADU */
948 
949  if (dfs_save_image(frameset, stacked, unmapped_science_tag,
950  header, parlist, "vimos_science", version)) {
951  cpl_image_delete(stacked);
952  cpl_image_delete(sky_stacked);
953  cpl_propertylist_delete(header);
954  cpl_table_delete(slits);
955  return -1;
956  }
957 
958  if (dfs_save_image(frameset, sky_stacked, unmapped_sky_tag,
959  header, parlist, "vimos_science", version)) {
960  cpl_image_delete(stacked);
961  cpl_image_delete(sky_stacked);
962  cpl_propertylist_delete(header);
963  cpl_table_delete(slits);
964  return -1;
965  }
966 
967  cpl_parameter_set_bool(param, time_normal);
968 
969  cpl_image_turn(stacked, rotate);
970  cpl_image_turn(sky_stacked, rotate);
971 
972  nx = cpl_image_get_size_x(stacked);
973  ny = cpl_image_get_size_y(stacked);
974 
975  polytraces = dfs_load_table(frameset, curv_coeff_tag, 1);
976 
977  slits = dfs_load_table(frameset, slit_location_tag, 1);
978  mos_rotate_slits(slits, -rotate, nx, ny);
979 
980 // FIXME: Qui potremmo tirare su una tabella allineata al cielo, se esiste.
981  idscoeff = dfs_load_table(frameset, disp_coeff_tag, 1);
982 
983  cpl_msg_indent_less();
984  cpl_msg_info("vimos_science",
985  "Processing stacked scientific spectra...");
986  cpl_msg_indent_more();
987 
988  smapped = mos_spatial_calibration(stacked, slits, polytraces, refwave,
989  startwavelength, endwavelength,
990  dispersion, flux, NULL);
991 
992  cpl_image_delete(stacked);
993 
994  sky_smapped = mos_spatial_calibration(sky_stacked, slits, polytraces,
995  refwave, startwavelength,
996  endwavelength, dispersion,
997  flux, NULL);
998 
999  cpl_image_delete(sky_stacked);
1000  cpl_table_delete(polytraces);
1001 
1002  mapped = mos_wavelength_calibration(smapped, refwave,
1003  startwavelength, endwavelength,
1004  dispersion, idscoeff, flux);
1005 
1006  cpl_image_delete(smapped);
1007 
1008  sky_mapped = mos_wavelength_calibration(sky_smapped, refwave,
1009  startwavelength, endwavelength,
1010  dispersion, idscoeff, flux);
1011  cpl_table_delete(idscoeff);
1012 
1013  cpl_propertylist_update_double(header, "CRPIX1", 1.0);
1014  cpl_propertylist_update_double(header, "CRPIX2", 1.0);
1015  cpl_propertylist_update_double(header, "CRVAL1",
1016  startwavelength + dispersion/2);
1017  cpl_propertylist_update_double(header, "CRVAL2", 1.0);
1018  cpl_propertylist_update_double(header, "CD1_1", dispersion);
1019  cpl_propertylist_update_double(header, "CD1_2", 0.0);
1020  cpl_propertylist_update_double(header, "CD2_1", 0.0);
1021  cpl_propertylist_update_double(header, "CD2_2", 1.0);
1022  cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
1023  cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
1024 
1025 // Later, when you have alltime
1026 // if (time_normal) {
1027 // image = cpl_image_divide_scalar_create(mapped, alltime);
1028 // if (dfs_save_image(frameset, image, mapped_science_sky_tag, header,
1029 // parlist, recipe, version))
1030 // vimos_science_exit(NULL);
1031 // cpl_image_delete(image); image = NULL;
1032 // }
1033 // else {
1034 
1035  if (dfs_save_image(frameset, mapped, mapped_science_tag,
1036  header, parlist, "vimos_science", version)) {
1037  cpl_propertylist_delete(header);
1038  cpl_image_delete(mapped);
1039  cpl_image_delete(sky_mapped);
1040  cpl_table_delete(slits);
1041  return -1;
1042  }
1043 
1044  if (dfs_save_image(frameset, sky_mapped, mapped_sky_tag,
1045  header, parlist, "vimos_science", version)) {
1046  cpl_propertylist_delete(header);
1047  cpl_image_delete(mapped);
1048  cpl_image_delete(sky_mapped);
1049  cpl_table_delete(slits);
1050  return -1;
1051  }
1052 // }
1053 
1054  cpl_msg_indent_less();
1055  cpl_msg_info("vimos_science", "Final object detection...");
1056  cpl_msg_indent_more();
1057 
1058  if (cosmics || strcmp(stack_method, "average")) {
1059  image = mos_detect_objects(mapped, slits, slit_margin, ext_radius,
1060  cont_radius);
1061  }
1062  else {
1063  cpl_image *mapped_cleaned = cpl_image_duplicate(mapped);
1064  mos_clean_cosmics(mapped_cleaned, gain, -1., -1.);
1065  image = mos_detect_objects(mapped_cleaned, slits, slit_margin,
1066  ext_radius, cont_radius);
1067 
1068  cpl_image_delete(mapped_cleaned);
1069  }
1070 
1071  cpl_image_delete(image);
1072 
1073  mos_rotate_slits(slits, rotate, ny, nx);
1074  if (dfs_save_table(frameset, slits, object_table_tag, NULL, parlist,
1075  "vimos_science", version)) {
1076  cpl_propertylist_delete(header);
1077  cpl_image_delete(mapped);
1078  cpl_image_delete(sky_mapped);
1079  cpl_table_delete(slits);
1080  return -1;
1081  }
1082 
1083  cpl_msg_indent_less();
1084  cpl_msg_info("vimos_science", "Final object extraction...");
1085  cpl_msg_indent_more();
1086 
1087  images = mos_extract_objects(mapped, sky_mapped, slits,
1088  ext_mode, ron, gain, mos);
1089 
1090  cpl_image_delete(mapped);
1091  cpl_image_delete(sky_mapped);
1092  cpl_table_delete(slits);
1093 
1094  if (images) {
1095 // if (time_normalise)
1096 // cpl_image_divide_scalar(images[0], alltime);
1097 
1098  if (dfs_save_image(frameset, images[0], reduced_science_tag,
1099  header, parlist, "vimos_science", version)) {
1100  cpl_image_delete(images[0]);
1101  cpl_image_delete(images[1]);
1102  cpl_image_delete(images[2]);
1103  cpl_free(images);
1104  cpl_propertylist_delete(header);
1105  return -1;
1106  }
1107 
1108  cpl_image_delete(images[0]);
1109 
1110 // if (time_normalise)
1111 // cpl_image_divide_scalar(images[1], alltime);
1112 
1113  if (dfs_save_image(frameset, images[1], reduced_sky_tag, header,
1114  parlist, "vimos_science", version)) {
1115  cpl_image_delete(images[1]);
1116  cpl_image_delete(images[2]);
1117  cpl_free(images);
1118  cpl_propertylist_delete(header);
1119  return -1;
1120  }
1121 
1122  cpl_image_delete(images[1]);
1123 
1124 // if (time_normalise)
1125 // cpl_image_divide_scalar(images[2], alltime);
1126 
1127  if (dfs_save_image(frameset, images[2], reduced_error_tag, header,
1128  parlist, "vimos_science", version)) {
1129  cpl_image_delete(images[2]);
1130  cpl_free(images);
1131  cpl_propertylist_delete(header);
1132  return -1;
1133  }
1134 
1135  cpl_image_delete(images[2]);
1136 
1137  cpl_free(images);
1138  }
1139  else {
1140  cpl_msg_warning("vimos_science", "No objects found: the products "
1141  "%s, %s, and %s are not created",
1142  reduced_science_tag, reduced_sky_tag,
1143  reduced_error_tag);
1144  }
1145 
1146  cpl_propertylist_delete(header);
1147 
1148  return 0;
1149  }
1150 
1151  return vimos_science_impl(frameset, parlist);
1152 }
cpl_image * mos_spatial_calibration(cpl_image *spectra, cpl_table *slits, cpl_table *polytraces, double reference, double blue, double red, double dispersion, int flux, cpl_image *calibration)
Spatial remapping of CCD spectra eliminating the spectral curvature.
Definition: moses.c:8539
int cpl_plugin_get_info(cpl_pluginlist *list)
Build the list of available plugins, for this module.
Definition: fors_bias.c:62
const char * dfs_get_parameter_string(cpl_parameterlist *parlist, const char *name, const cpl_table *defaults)
Reading a recipe string parameter value.
Definition: fors_dfs.c:602
cpl_propertylist * dfs_load_header(cpl_frameset *frameset, const char *category, int ext)
Loading header associated to data of given category.
Definition: fors_dfs.c:964
cpl_error_code mos_rotate_slits(cpl_table *slits, int rotation, int nx, int ny)
Rotate a slit location table.
Definition: moses.c:6345
cpl_image * mos_wavelength_calibration(cpl_image *image, double refwave, double firstLambda, double lastLambda, double dispersion, cpl_table *idscoeff, int flux)
Remap at constant wavelength step an image of rectified scientific spectra.
Definition: moses.c:9697
cpl_image * mos_detect_objects(cpl_image *image, cpl_table *slits, int margin, int maxradius, int conradius)
Detect objects in rectified scientific frame.
Definition: moses.c:13944
int dfs_get_parameter_bool(cpl_parameterlist *parlist, const char *name, const cpl_table *defaults)
Reading a recipe boolean parameter value.
Definition: fors_dfs.c:701
cpl_error_code mos_image_shift(cpl_image *image, double dx, double dy)
Shift values in an image.
Definition: moses.c:18898
void fors_stack_define_parameters(cpl_parameterlist *parameters, const char *context, const char *default_method)
Define recipe parameters.
Definition: fors_stack.c:55
int dfs_save_image(cpl_frameset *frameset, const cpl_image *image, const char *category, cpl_propertylist *header, const cpl_parameterlist *parlist, const char *recipename, const char *version)
Saving image data of given category.
Definition: fors_dfs.c:1451
cpl_table * dfs_load_table(cpl_frameset *frameset, const char *category, int ext)
Loading table data of given category.
Definition: fors_dfs.c:916
int dfs_get_parameter_int(cpl_parameterlist *parlist, const char *name, const cpl_table *defaults)
Reading a recipe integer parameter value.
Definition: fors_dfs.c:407
int dfs_save_table(cpl_frameset *frameset, const cpl_table *table, const char *category, cpl_propertylist *header, const cpl_parameterlist *parlist, const char *recipename, const char *version)
Saving table data of given category.
Definition: fors_dfs.c:1575
Definition: list.c:74
cpl_image * mos_ksigma_stack(cpl_imagelist *imlist, double klow, double khigh, int kiter, cpl_image **good)
Stack images using k-sigma clipping.
Definition: moses.c:17980
cpl_image ** mos_extract_objects(cpl_image *science, cpl_image *science_var, cpl_image *sky, cpl_table *objects, int extraction, double ron, double gain, int ncombined)
Extract detected objects from rectified scientific frame.
Definition: moses.c:14295
cpl_error_code mos_clean_cosmics(cpl_image *image, float gain, float threshold, float ratio)
Remove cosmic rays from sky-subtracted CCD spectral exposure.
Definition: moses.c:13174
double dfs_get_parameter_double(cpl_parameterlist *parlist, const char *name, const cpl_table *defaults)
Reading a recipe double parameter value.
Definition: fors_dfs.c:504
int mos_compute_offset(cpl_table *reference, cpl_table *objects, double *offset)
Estimate offset between two object tables.
Definition: moses.c:18695