FORS Pipeline Reference Manual  4.12.5
vimos_science_impl.c
1 /* $Id: vimos_science_impl.c,v 1.4 2013-04-24 14:17:05 cgarcia 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: cgarcia $
23  * $Date: 2013-04-24 14:17:05 $
24  * $Revision: 1.4 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 #include <vimos_science_impl.h>
33 
34 #include <math.h>
35 #include <cpl.h>
36 #include <moses.h>
37 #include <fors_tools.h>
38 #include <fors_dfs.h>
39 #include <fors_qc.h>
40 
41 #define vimos_science_exit(message) \
42 { \
43 if (message) cpl_msg_error(recipe, message); \
44 cpl_free(exptime); \
45 cpl_image_delete(dummy); \
46 cpl_image_delete(mapped); \
47 cpl_image_delete(mapped_sky); \
48 cpl_image_delete(mapped_cleaned); \
49 cpl_image_delete(skylocalmap); \
50 cpl_image_delete(skymap); \
51 cpl_image_delete(smapped); \
52 cpl_table_delete(offsets); \
53 cpl_table_delete(sky); \
54 cpl_image_delete(bias); \
55 cpl_image_delete(spectra); \
56 cpl_image_delete(coordinate); \
57 cpl_image_delete(norm_flat); \
58 cpl_image_delete(rainbow); \
59 cpl_image_delete(rectified); \
60 cpl_image_delete(wavemap); \
61 cpl_propertylist_delete(header); \
62 cpl_propertylist_delete(save_header); \
63 cpl_table_delete(grism_table); \
64 cpl_table_delete(idscoeff); \
65 cpl_table_delete(maskslits); \
66 cpl_table_delete(overscans); \
67 cpl_table_delete(polytraces); \
68 cpl_table_delete(slits); \
69 cpl_table_delete(wavelengths); \
70 cpl_vector_delete(lines); \
71 cpl_msg_indent_less(); \
72 return -1; \
73 }
74 
81 int vimos_science_impl(cpl_frameset *frameset, cpl_parameterlist *parlist)
82 {
83  const char *recipe = "vimos_science";
84 
85 
86  /*
87  * Input parameters
88  */
89 
90  double dispersion;
91  int skyalign;
92  const char *wcolumn;
93  double startwavelength;
94  double endwavelength;
95  double reference;
96  int flux;
97  int flatfield;
98  int skyglobal;
99  int skylocal;
100  int skymedian;
101  int cosmics;
102  int slit_margin;
103  int ext_radius;
104  int cont_radius;
105  int ext_mode;
106  int time_normalise;
107  int anyframe;
108  int res_order;
109  int qc;
110 
111  /*
112  * CPL objects
113  */
114 
115  cpl_imagelist *all_science;
116  cpl_image **images;
117 
118  cpl_image *bias = NULL;
119  cpl_image *norm_flat = NULL;
120  cpl_image *spectra = NULL;
121  cpl_image *rectified = NULL;
122  cpl_image *coordinate = NULL;
123  cpl_image *rainbow = NULL;
124  cpl_image *mapped = NULL;
125  cpl_image *mapped_sky = NULL;
126  cpl_image *mapped_cleaned = NULL;
127  cpl_image *smapped = NULL;
128  cpl_image *wavemap = NULL;
129  cpl_image *skymap = NULL;
130  cpl_image *skylocalmap = NULL;
131  cpl_image *dummy = NULL;
132 
133  cpl_table *grism_table = NULL;
134  cpl_table *overscans = NULL;
135  cpl_table *wavelengths = NULL;
136  cpl_table *idscoeff = NULL;
137  cpl_table *slits = NULL;
138  cpl_table *maskslits = NULL;
139  cpl_table *polytraces = NULL;
140  cpl_table *offsets = NULL;
141  cpl_table *sky = NULL;
142 
143  cpl_vector *lines = NULL;
144 
145  cpl_propertylist *header = NULL;
146  cpl_propertylist *save_header = NULL;
147  cpl_propertylist *qclist = NULL;
148 
149  /*
150  * Auxiliary variables
151  */
152 
153  char version[80];
154  char *instrume = NULL;
155  const char *science_tag;
156  const char *master_norm_flat_tag;
157  const char *disp_coeff_tag;
158  const char *disp_coeff_sky_tag;
159  const char *wavelength_map_tag;
160  const char *wavelength_map_sky_tag;
161  const char *curv_coeff_tag;
162  const char *slit_location_tag;
163  const char *reduced_science_tag;
164  const char *reduced_sky_tag;
165  const char *reduced_error_tag;
166  const char *mapped_science_tag;
167  const char *unmapped_science_tag;
168  const char *mapped_science_sky_tag;
169  const char *mapped_sky_tag;
170  const char *unmapped_sky_tag;
171  const char *global_sky_spectrum_tag;
172  const char *object_table_tag;
173  const char *skylines_offsets_tag;
174  const char *specphot_tag;
175  const char *key_gris_name;
176  const char *key_gris_id;
177  const char *key_filt_name;
178  const char *key_filt_id;
179  int mos;
180  int nexp, expno;
181  int treat_as_lss = 0;
182  int nslits;
183  int nscience;
184  int quadrant;
185  double *xpos;
186  double *exptime = NULL;
187  double airmass;
188  double alltime;
189  double mxpos;
190  double mean_rms;
191  int nlines;
192  double *line;
193  int nx, ny;
194  double gain;
195  double ron;
196  int standard;
197  int highres;
198  int rotate = 1;
199  int rotate_back = -1;
200  int i;
201  double wstart;
202  double wstep;
203  int wcount;
204 
205 
206  snprintf(version, 80, "%s-%s", PACKAGE, PACKAGE_VERSION);
207 
208  cpl_msg_set_indentation(2);
209 
210 
211  /*
212  * Get configuration parameters
213  */
214 
215  cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe);
216  cpl_msg_indent_more();
217 
218  if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1)
219  vimos_science_exit("Too many in input: GRISM_TABLE");
220 
221  grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1);
222 
223  dispersion = dfs_get_parameter_double(parlist,
224  "fors.vimos_science.dispersion", grism_table);
225 
226  if (dispersion <= 0.0)
227  vimos_science_exit("Invalid resampling step");
228 
229  skyalign = dfs_get_parameter_int(parlist,
230  "fors.vimos_science.skyalign", NULL);
231 
232  if (skyalign > 2)
233  vimos_science_exit("Max polynomial degree for sky alignment is 2");
234 
235  wcolumn = dfs_get_parameter_string(parlist,
236  "fors.vimos_science.wcolumn", NULL);
237 
238  startwavelength = dfs_get_parameter_double(parlist,
239  "fors.vimos_science.startwavelength", grism_table);
240  if (startwavelength < 3000.0 || startwavelength > 13000.0)
241  vimos_science_exit("Invalid wavelength");
242 
243  endwavelength = dfs_get_parameter_double(parlist,
244  "fors.vimos_science.endwavelength", grism_table);
245  if (endwavelength < 3000.0 || endwavelength > 13000.0)
246  vimos_science_exit("Invalid wavelength");
247 
248  if (endwavelength - startwavelength <= 0.0)
249  vimos_science_exit("Invalid wavelength interval");
250 
251  reference = dfs_get_parameter_double(parlist,
252  "fors.vimos_science.reference", grism_table);
253 
254  if (reference < startwavelength || reference > endwavelength)
255  vimos_science_exit("Invalid reference wavelength");
256 
257  flux = dfs_get_parameter_bool(parlist, "fors.vimos_science.flux", NULL);
258 
259  flatfield = dfs_get_parameter_bool(parlist, "fors.vimos_science.flatfield",
260  NULL);
261 
262  skyglobal = dfs_get_parameter_bool(parlist, "fors.vimos_science.skyglobal",
263  NULL);
264  skylocal = dfs_get_parameter_bool(parlist, "fors.vimos_science.skylocal",
265  NULL);
266  skymedian = dfs_get_parameter_bool(parlist, "fors.vimos_science.skymedian",
267  NULL);
268 
269  if (skylocal && skyglobal)
270  vimos_science_exit("Cannot do both local and global sky subtraction");
271 
272  if (skylocal && skymedian)
273  vimos_science_exit("Cannot do sky subtraction both on extracted "
274  "and non-extracted spectra");
275 
276  cosmics = dfs_get_parameter_bool(parlist,
277  "fors.vimos_science.cosmics", NULL);
278 
279  if (cosmics)
280  if (!(skyglobal || skylocal))
281  vimos_science_exit("Cosmic rays correction requires "
282  "either skylocal=true or skyglobal=true");
283 
284  slit_margin = dfs_get_parameter_int(parlist,
285  "fors.vimos_science.slit_margin",
286  NULL);
287  if (slit_margin < 0)
288  vimos_science_exit("Value must be zero or positive");
289 
290  ext_radius = dfs_get_parameter_int(parlist,
291  "fors.vimos_science.ext_radius",
292  NULL);
293  if (ext_radius < 0)
294  vimos_science_exit("Value must be zero or positive");
295 
296  cont_radius = dfs_get_parameter_int(parlist,
297  "fors.vimos_science.cont_radius",
298  NULL);
299  if (cont_radius < 0)
300  vimos_science_exit("Value must be zero or positive");
301 
302  ext_mode = dfs_get_parameter_int(parlist, "fors.vimos_science.ext_mode",
303  NULL);
304  if (ext_mode < 0 || ext_mode > 1)
305  vimos_science_exit("Invalid object extraction mode");
306 
307  time_normalise = dfs_get_parameter_bool(parlist,
308  "fors.vimos_science.time_normalise", NULL);
309 
310  res_order = dfs_get_parameter_int(parlist, "fors.vimos_science.response",
311  NULL);
312  if (res_order < 2 || res_order > 10)
313  vimos_science_exit("Invalid instrument response modeling polynomial");
314 
315  anyframe = dfs_get_parameter_bool(parlist, "fors.vimos_science.anyframe",
316  NULL);
317 
318  qc = dfs_get_parameter_bool(parlist, "fors.vimos_science.qc", NULL);
319 
320  cpl_table_delete(grism_table); grism_table = NULL;
321 
322  if (cpl_error_get_code())
323  vimos_science_exit("Failure getting the configuration parameters");
324 
325 
326  /*
327  * Check input set-of-frames
328  */
329 
330  cpl_msg_indent_less();
331  cpl_msg_info(recipe, "Check input set-of-frames:");
332  cpl_msg_indent_more();
333 
334  if (!dfs_equal_keyword(frameset, "ESO OCS CON QUAD"))
335  vimos_science_exit("Input frames are not from the same quadrant");
336 
337  mos = cpl_frameset_count_tags(frameset, "MOS_SCIENCE");
338  standard = 0;
339 
340  if (mos == 0) {
341  mos = cpl_frameset_count_tags(frameset, "MOS_STANDARD");
342  standard = 1;
343  }
344 
345  if (mos == 0)
346  vimos_science_exit("Missing input scientific frame");
347 
348  nscience = mos;
349 
350  if (standard) {
351  science_tag = "MOS_STANDARD";
352  reduced_science_tag = "MOS_STANDARD_REDUCED";
353  unmapped_science_tag = "MOS_UNMAPPED_STANDARD";
354  mapped_science_tag = "MOS_STANDARD_EXTRACTED";
355  mapped_science_sky_tag = "MOS_STANDARD_SKY_EXTRACTED";
356  mapped_sky_tag = "MOS_STANDARD_SKY";
357  specphot_tag = "MOS_SPECPHOT_TABLE";
358 
359  }
360  else {
361  science_tag = "MOS_SCIENCE";
362  reduced_science_tag = "MOS_SCIENCE_REDUCED";
363  unmapped_science_tag = "MOS_UNMAPPED_SCIENCE";
364  mapped_science_tag = "MOS_SCIENCE_EXTRACTED";
365  mapped_science_sky_tag = "MOS_SCIENCE_SKY_EXTRACTED";
366  mapped_sky_tag = "MOS_SCIENCE_SKY";
367  }
368 
369  reduced_sky_tag = "MOS_SKY_REDUCED";
370  reduced_error_tag = "MOS_ERROR_REDUCED";
371  master_norm_flat_tag = "MOS_MASTER_SCREEN_FLAT";
372  disp_coeff_sky_tag = "MOS_DISP_COEFF_SKY";
373  wavelength_map_sky_tag = "MOS_WAVELENGTH_MAP_SKY";
374  disp_coeff_tag = "MOS_DISP_COEFF";
375  wavelength_map_tag = "WAVELENGTH_MAP_MXU";
376  curv_coeff_tag = "MOS_CURV_COEFF";
377  slit_location_tag = "MOS_SLIT_LOCATION";
378  skylines_offsets_tag = "MOS_SKYLINES_OFFSETS_SLIT";
379  unmapped_sky_tag = "MOS_UNMAPPED_SKY";
380  global_sky_spectrum_tag = "MOS_GLOBAL_SKY_SPECTRUM";
381  object_table_tag = "OBJECT_TABLE";
382 
383  if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") == 0)
384  vimos_science_exit("Missing required input: MASTER_BIAS");
385 
386  if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") > 1)
387  vimos_science_exit("Too many in input: MASTER_BIAS");
388 
389  if (skyalign >= 0)
390  if (cpl_frameset_count_tags(frameset, "SKY_LINE_CATALOG") > 1)
391  vimos_science_exit("Too many in input: SKY_LINE_CATALOG");
392 
393  if (cpl_frameset_count_tags(frameset, disp_coeff_tag) == 0) {
394  cpl_msg_error(recipe, "Missing required input: %s", disp_coeff_tag);
395  vimos_science_exit(NULL);
396  }
397 
398  if (cpl_frameset_count_tags(frameset, disp_coeff_tag) > 1) {
399  cpl_msg_error(recipe, "Too many in input: %s", disp_coeff_tag);
400  vimos_science_exit(NULL);
401  }
402 
403  if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) > 1) {
404  if (flatfield) {
405  cpl_msg_error(recipe, "Too many in input: %s",
406  master_norm_flat_tag);
407  vimos_science_exit(NULL);
408  }
409  else {
410  cpl_msg_warning(recipe, "%s in input are ignored, "
411  "since flat field correction was not requested",
412  master_norm_flat_tag);
413  }
414  }
415 
416  if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) == 1) {
417  if (!flatfield) {
418  cpl_msg_warning(recipe, "%s in input is ignored, "
419  "since flat field correction was not requested",
420  master_norm_flat_tag);
421  }
422  }
423 
424  if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) == 0) {
425  if (flatfield) {
426  cpl_msg_error(recipe, "Flat field correction was requested, "
427  "but no %s are found in input",
428  master_norm_flat_tag);
429  vimos_science_exit(NULL);
430  }
431  }
432 
433  if (standard) {
434 
435  if (cpl_frameset_count_tags(frameset, "EXTINCT_TABLE") == 0) {
436  cpl_msg_warning(recipe, "An EXTINCT_TABLE was not found in input: "
437  "instrument response curve will not be produced.");
438  standard = 0;
439  }
440 
441  if (cpl_frameset_count_tags(frameset, "EXTINCT_TABLE") > 1)
442  vimos_science_exit("Too many in input: EXTINCT_TABLE");
443 
444  if (cpl_frameset_count_tags(frameset, "STD_FLUX_TABLE") == 0) {
445  cpl_msg_warning(recipe, "A STD_FLUX_TABLE was not found in input: "
446  "instrument response curve will not be produced.");
447  standard = 0;
448  }
449 
450  if (cpl_frameset_count_tags(frameset, "STD_FLUX_TABLE") > 1)
451  vimos_science_exit("Too many in input: STD_FLUX_TABLE");
452 
453  if (!dfs_equal_keyword(frameset, "ESO OBS TARG NAME")) {
454  cpl_msg_warning(recipe, "The target name of observation does not "
455  "match the standard star catalog: "
456  "instrument response curve will not be produced.");
457  standard = 0;
458  }
459  }
460 
461  cpl_msg_indent_less();
462 
463 
464  /*
465  * Loading input data
466  */
467 
468  exptime = cpl_calloc(nscience, sizeof(double));
469 
470  if (nscience > 1) {
471 
472  cpl_msg_info(recipe, "Load %d scientific frames and median them...",
473  nscience);
474  cpl_msg_indent_more();
475 
476  all_science = cpl_imagelist_new();
477 
478  header = dfs_load_header(frameset, science_tag, 0);
479 
480  if (header == NULL)
481  vimos_science_exit("Cannot load scientific frame header");
482 
483  alltime = exptime[0] = cpl_propertylist_get_double(header, "EXPTIME");
484 
485  if (cpl_error_get_code() != CPL_ERROR_NONE)
486  vimos_science_exit("Missing keyword EXPTIME in scientific "
487  "frame header");
488 
489  if (standard) {
490  airmass = fors_get_airmass(header);
491  if (airmass < 0.0)
492  vimos_science_exit("Missing airmass information in "
493  "scientific frame header");
494  }
495 
496  instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME");
497  if (instrume == NULL)
498  vimos_science_exit("Missing keyword INSTRUME "
499  "in scientific frame header");
500 
501  cpl_propertylist_delete(header); header = NULL;
502 
503  cpl_msg_info(recipe, "Scientific frame 1 exposure time: %.2f s",
504  exptime[0]);
505 
506  for (i = 1; i < nscience; i++) {
507 
508  header = dfs_load_header(frameset, NULL, 0);
509 
510  if (header == NULL)
511  vimos_science_exit("Cannot load scientific frame header");
512 
513  exptime[i] = cpl_propertylist_get_double(header, "EXPTIME");
514 
515  alltime += exptime[i];
516 
517  if (cpl_error_get_code() != CPL_ERROR_NONE)
518  vimos_science_exit("Missing keyword EXPTIME in scientific "
519  "frame header");
520 
521  cpl_propertylist_delete(header); header = NULL;
522 
523  cpl_msg_info(recipe, "Scientific frame %d exposure time: %.2f s",
524  i+1, exptime[i]);
525  }
526 
527  spectra = dfs_load_image(frameset, science_tag, CPL_TYPE_FLOAT, 0, 0);
528 
529  if (spectra == NULL)
530  vimos_science_exit("Cannot load scientific frame");
531 
532  cpl_image_divide_scalar(spectra, exptime[0]);
533  cpl_imagelist_set(all_science, spectra, 0);
534 
535  for (i = 1; i < nscience; i++) {
536 
537  spectra = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0);
538 
539  if (spectra) {
540  cpl_image_divide_scalar(spectra, exptime[i]);
541  cpl_imagelist_set(all_science, spectra, i);
542  }
543  else
544  vimos_science_exit("Cannot load scientific frame");
545 
546  }
547 
548  spectra = cpl_imagelist_collapse_median_create(all_science);
549  cpl_image_multiply_scalar(spectra, alltime);
550 
551  cpl_imagelist_delete(all_science);
552  }
553  else {
554  cpl_msg_info(recipe, "Load scientific exposure...");
555  cpl_msg_indent_more();
556 
557  header = dfs_load_header(frameset, science_tag, 0);
558 
559  if (header == NULL)
560  vimos_science_exit("Cannot load scientific frame header");
561 
562  alltime = exptime[0] = cpl_propertylist_get_double(header, "EXPTIME");
563 
564  if (cpl_error_get_code() != CPL_ERROR_NONE)
565  vimos_science_exit("Missing keyword EXPTIME in scientific "
566  "frame header");
567 
568  if (standard) {
569  airmass = fors_get_airmass(header);
570  if (airmass < 0.0)
571  vimos_science_exit("Missing airmass information in "
572  "scientific frame header");
573  }
574 
575  instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME");
576  if (instrume == NULL)
577  vimos_science_exit("Missing keyword INSTRUME "
578  "in scientific frame header");
579 
580  cpl_propertylist_delete(header); header = NULL;
581 
582  cpl_msg_info(recipe, "Scientific frame exposure time: %.2f s",
583  exptime[0]);
584 
585  spectra = dfs_load_image(frameset, science_tag, CPL_TYPE_FLOAT, 0, 0);
586  }
587 
588  if (spectra == NULL)
589  vimos_science_exit("Cannot load scientific frame");
590 
591  cpl_free(exptime); exptime = NULL;
592 
593  cpl_msg_indent_less();
594 
595 
596  /*
597  * Get some info from header
598  */
599 
600  header = dfs_load_header(frameset, science_tag, 0);
601 
602  if (header == NULL)
603  vimos_science_exit("Cannot load scientific frame header");
604 
605  quadrant = cpl_propertylist_get_int(header, "ESO OCS CON QUAD");
606 
607  switch (quadrant) {
608  case 1:
609  key_gris_name = "ESO INS GRIS1 NAME";
610  key_gris_id = "ESO INS GRIS1 ID";
611  key_filt_name = "ESO INS FILT1 NAME";
612  key_filt_id = "ESO INS FILT1 ID";
613  break;
614  case 2:
615  key_gris_name = "ESO INS GRIS2 NAME";
616  key_gris_id = "ESO INS GRIS2 ID";
617  key_filt_name = "ESO INS FILT2 NAME";
618  key_filt_id = "ESO INS FILT2 ID";
619  break;
620  case 3:
621  key_gris_name = "ESO INS GRIS3 NAME";
622  key_gris_id = "ESO INS GRIS3 ID";
623  key_filt_name = "ESO INS FILT3 NAME";
624  key_filt_id = "ESO INS FILT3 ID";
625  break;
626  case 4:
627  key_gris_name = "ESO INS GRIS4 NAME";
628  key_gris_id = "ESO INS GRIS4 ID";
629  key_filt_name = "ESO INS FILT4 NAME";
630  key_filt_id = "ESO INS FILT4 ID";
631  break;
632  }
633 
634  if (standard) {
635  if (!anyframe) {
636 
637  /*
638  * As a default this recipe wouldn't reduce a frame belonging
639  * to a quadrant that is not expected to contain a standard
640  * star. The current template for getting data for photometric
641  * calibration consists of a sequence of 4 exposures, where
642  * the same standard star is moved through all quadrants.
643  * The first exposure has the standard star in quadrant 1,
644  * the second exposure in quadrant 2, and so on. So a standard
645  * star will be reduced only if it is part of a template of
646  * 4 exposures (i.e., TPL NEXP == 4), and if its sequence
647  * number in the template is equal to its quadrant number
648  * (i.e., TPL EXPNO == OCS CON QUAD).
649  */
650 
651  nexp = cpl_propertylist_get_int(header, "ESO TPL NEXP");
652 
653  if (cpl_error_get_code() != CPL_ERROR_NONE)
654  vimos_science_exit("Missing keyword ESO TPL NEXP in "
655  "scientific frame header");
656 
657  if (nexp == 4) {
658  expno = cpl_propertylist_get_int(header, "ESO TPL EXPNO");
659 
660  if (cpl_error_get_code() != CPL_ERROR_NONE)
661  vimos_science_exit("Missing keyword ESO TPL EXPNO in "
662  "scientific frame header");
663  }
664 
665  if (quadrant != expno) {
666  cpl_msg_warning(recipe, "The MOS_STANDARD frame is not "
667  "expected to contain a standard star: "
668  "instrument response curve will not be "
669  "produced. Set --anyframe=true to skip "
670  "this check.");
671  standard = 0;
672  }
673  }
674  }
675 
676 /*
677  if (!dfs_equal_keyword(frameset, key_gris_id))
678  vimos_science_exit("Input frames are not from the same grism");
679 
680  if (!dfs_equal_keyword(frameset, key_filt_id))
681  vimos_science_exit("Input frames are not from the same filter");
682 */
683 
684  gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD");
685 
686  if (cpl_error_get_code() != CPL_ERROR_NONE)
687  vimos_science_exit("Missing keyword ESO DET OUT1 CONAD in scientific "
688  "frame header");
689 
690  cpl_msg_info(recipe, "The gain factor is: %.2f e-/ADU", gain);
691 
692  ron = cpl_propertylist_get_double(header, "ESO DET OUT1 RON");
693 
694  if (cpl_error_get_code() != CPL_ERROR_NONE)
695  vimos_science_exit("Missing keyword ESO DET OUT1 RON in scientific "
696  "frame header");
697 
698  ron /= gain; /* Convert from electrons to ADU */
699 
700  cpl_msg_info(recipe, "The read-out-noise is: %.2f ADU", ron);
701 
702  /*
703  * In VIMOS data are "never" LSS. This is why this part is
704  * commented out.
705  */
706 
707 // maskslits = mos_load_slits_vimos(header);
708 //
709 // /*
710 // * Check if all slits have the same X offset: in such case,
711 // * treat the observation as a long-slit one!
712 // */
713 //
714 // mxpos = cpl_table_get_column_median(maskslits, "ytop");
715 // xpos = cpl_table_get_data_double(maskslits, "ytop");
716 // nslits = cpl_table_get_nrow(maskslits);
717 //
718 // treat_as_lss = 1;
719 // for (i = 0; i < nslits; i++) {
720 // if (fabs(mxpos-xpos[i]) > 0.01) {
721 // treat_as_lss = 0;
722 // break;
723 // }
724 // }
725 //
726 // treat_as_lss = 0; // FIXME Prevent LSS treatment for the moment!!!
727 //
728 // cpl_table_delete(maskslits); maskslits = NULL;
729 //
730 // if (treat_as_lss) {
731 // cpl_msg_warning(recipe, "All MOS slits have the same offset: %.2f\n"
732 // "The LSS data reduction strategy is applied!",
733 // mxpos);
734 // skylines_offsets_tag = "MOS_SKYLINES_OFFSETS_LONG";
735 // }
736 
737  if (treat_as_lss) {
738  if (skylocal) {
739  if (cosmics)
740  vimos_science_exit("Cosmic rays correction for long-slit-like "
741  "data requires --skyglobal=true");
742  skymedian = skylocal;
743  skylocal = 0;
744  }
745  }
746  else {
747  if (cpl_frameset_count_tags(frameset, curv_coeff_tag) == 0) {
748  cpl_msg_error(recipe, "Missing required input: %s", curv_coeff_tag);
749  vimos_science_exit(NULL);
750  }
751 
752  if (cpl_frameset_count_tags(frameset, curv_coeff_tag) > 1) {
753  cpl_msg_error(recipe, "Too many in input: %s", curv_coeff_tag);
754  vimos_science_exit(NULL);
755  }
756 
757  if (cpl_frameset_count_tags(frameset, slit_location_tag) == 0) {
758  cpl_msg_error(recipe, "Missing required input: %s",
759  slit_location_tag);
760  vimos_science_exit(NULL);
761  }
762 
763  if (cpl_frameset_count_tags(frameset, slit_location_tag) > 1) {
764  cpl_msg_error(recipe, "Too many in input: %s", slit_location_tag);
765  vimos_science_exit(NULL);
766  }
767  }
768 
769  /* Leave the header on for the next step... */
770 
771 
772  /*
773  * Remove the master bias
774  */
775 
776  cpl_msg_info(recipe, "Remove the master bias...");
777 
778  bias = dfs_load_image(frameset, "MASTER_BIAS", CPL_TYPE_FLOAT, 0, 1);
779 
780  if (bias == NULL)
781  vimos_science_exit("Cannot load master bias");
782 
783  overscans = mos_load_overscans_vimos(header, 1);
784  cpl_propertylist_delete(header); header = NULL;
785  dummy = mos_remove_bias(spectra, bias, overscans);
786  cpl_image_delete(spectra); spectra = dummy; dummy = NULL;
787  cpl_image_delete(bias); bias = NULL;
788  cpl_table_delete(overscans); overscans = NULL;
789 
790  if (spectra == NULL)
791  vimos_science_exit("Cannot remove bias from scientific frame");
792 
793  /*
794  * Rotate frames horizontally with red to the right
795  */
796 
797  cpl_image_turn(spectra, rotate);
798 
799  nx = cpl_image_get_size_x(spectra);
800  ny = cpl_image_get_size_y(spectra);
801 
802  cpl_msg_indent_less();
803  cpl_msg_info(recipe, "Load normalised flat field (if present)...");
804  cpl_msg_indent_more();
805 
806  if (flatfield) {
807 
808  norm_flat = dfs_load_image(frameset, master_norm_flat_tag,
809  CPL_TYPE_FLOAT, 0, 1);
810 
811  if (norm_flat) {
812  cpl_image_turn(norm_flat, rotate);
813  cpl_msg_info(recipe, "Apply flat field correction...");
814  if (cpl_image_divide(spectra, norm_flat) != CPL_ERROR_NONE) {
815  cpl_msg_error(recipe, "Failure of flat field correction: %s",
816  cpl_error_get_message());
817  vimos_science_exit(NULL);
818  }
819  cpl_image_delete(norm_flat); norm_flat = NULL;
820  }
821  else {
822  cpl_msg_error(recipe, "Cannot load input %s for flat field "
823  "correction", master_norm_flat_tag);
824  vimos_science_exit(NULL);
825  }
826 
827  }
828 
829 
830  if (skyalign >= 0) {
831  cpl_msg_indent_less();
832  cpl_msg_info(recipe, "Load input sky line catalog...");
833  cpl_msg_indent_more();
834 
835  wavelengths = dfs_load_table(frameset, "SKY_LINE_CATALOG", 1);
836 
837  if (wavelengths) {
838 
839  /*
840  * Cast the wavelengths into a (double precision) CPL vector
841  */
842 
843  nlines = cpl_table_get_nrow(wavelengths);
844 
845  if (nlines == 0)
846  vimos_science_exit("Empty input sky line catalog");
847 
848  if (cpl_table_has_column(wavelengths, wcolumn) != 1) {
849  cpl_msg_error(recipe, "Missing column %s in input line "
850  "catalog table", wcolumn);
851  vimos_science_exit(NULL);
852  }
853 
854  line = cpl_malloc(nlines * sizeof(double));
855 
856  for (i = 0; i < nlines; i++)
857  line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL);
858 
859  cpl_table_delete(wavelengths); wavelengths = NULL;
860 
861  lines = cpl_vector_wrap(nlines, line);
862  }
863  else {
864  cpl_msg_info(recipe, "No sky line catalog found in input - fine!");
865  }
866  }
867 
868 
869  /*
870  * Load the spectral curvature table, or provide a dummy one
871  * in case of LSS-like data (single slit with flat curvature)
872  */
873 
874  if (!treat_as_lss) {
875  polytraces = dfs_load_table(frameset, curv_coeff_tag, 1);
876  if (polytraces == NULL)
877  vimos_science_exit("Cannot load spectral curvature table");
878  }
879 
880 
881  /*
882  * Load the slit location table, or provide a dummy one in case
883  * of LSS-like data (single slit spanning whole image)
884  */
885 
886  if (treat_as_lss) {
887  slits = cpl_table_new(1);
888  cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
889  cpl_table_set_int(slits, "slit_id", 0, 1);
890  cpl_table_new_column(slits, "position", CPL_TYPE_INT);
891  cpl_table_set_int(slits, "position", 0, 0);
892  cpl_table_new_column(slits, "length", CPL_TYPE_INT);
893  cpl_table_set_int(slits, "length", 0, ny);
894  }
895  else {
896  slits = dfs_load_table(frameset, slit_location_tag, 1);
897  if (slits == NULL)
898  vimos_science_exit("Cannot load slits location table");
899  mos_rotate_slits(slits, -rotate, nx, ny);
900  }
901 
902 
903  /*
904  * Load the wavelength calibration table
905  */
906 
907  idscoeff = dfs_load_table(frameset, disp_coeff_tag, 1);
908  if (idscoeff == NULL)
909  vimos_science_exit("Cannot load wavelength calibration table");
910 
911  cpl_msg_indent_less();
912  cpl_msg_info(recipe, "Processing scientific spectra...");
913  cpl_msg_indent_more();
914 
915  /*
916  * This one will also generate the spatial map from the spectral
917  * curvature table (in the case of multislit data)
918  */
919 
920  if (treat_as_lss) {
921  smapped = cpl_image_duplicate(spectra);
922  }
923  else {
924  coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
925 
926  smapped = mos_spatial_calibration(spectra, slits, polytraces, reference,
927  startwavelength, endwavelength,
928  dispersion, flux, coordinate);
929  }
930 
931 
932  /*
933  * Generate a rectified wavelength map from the wavelength calibration
934  * table
935  */
936 
937  rainbow = mos_map_idscoeff(idscoeff, nx, reference, startwavelength,
938  endwavelength);
939 
940  if (dispersion > 1.0)
941  highres = 0;
942  else
943  highres = 1;
944 
945  if (skyalign >= 0) {
946  if (skyalign) {
947  cpl_msg_info(recipe, "Align wavelength solution to reference "
948  "skylines applying %d order residual fit...", skyalign);
949  }
950  else {
951  cpl_msg_info(recipe, "Align wavelength solution to reference "
952  "skylines applying median offset...");
953  }
954 
955  if (treat_as_lss) {
956  offsets = mos_wavelength_align_lss(smapped, reference,
957  startwavelength, endwavelength,
958  idscoeff, lines, highres,
959  skyalign, rainbow, 4);
960  }
961  else {
962  offsets = mos_wavelength_align(smapped, slits, reference,
963  startwavelength, endwavelength,
964  idscoeff, lines, highres, skyalign,
965  rainbow, 4);
966  }
967 
968  cpl_vector_delete(lines); lines = NULL;
969 
970  if (offsets) {
971  if (standard)
972  cpl_msg_warning(recipe, "Alignment of the wavelength solution "
973  "to reference sky lines may be unreliable in "
974  "this case!");
975 
976  if (dfs_save_table(frameset, offsets, skylines_offsets_tag, NULL,
977  parlist, recipe, version))
978  vimos_science_exit(NULL);
979 
980  cpl_table_delete(offsets); offsets = NULL;
981  }
982  else {
983  cpl_msg_warning(recipe, "Alignment of the wavelength solution "
984  "to reference sky lines could not be done!");
985  skyalign = -1;
986  }
987 
988  }
989 
990  if (treat_as_lss) {
991  wavemap = rainbow;
992  rainbow = NULL;
993  }
994  else {
995  wavemap = mos_map_wavelengths(coordinate, rainbow, slits,
996  polytraces, reference,
997  startwavelength, endwavelength,
998  dispersion);
999  }
1000 
1001  cpl_image_delete(rainbow); rainbow = NULL;
1002  cpl_image_delete(coordinate); coordinate = NULL;
1003 
1004  /*
1005  * Here the wavelength calibrated slit spectra are created. This frame
1006  * contains sky_science.
1007  */
1008 
1009  mapped_sky = mos_wavelength_calibration(smapped, reference,
1010  startwavelength, endwavelength,
1011  dispersion, idscoeff, flux);
1012 
1013  cpl_msg_indent_less();
1014  cpl_msg_info(recipe, "Check applied wavelength against skylines...");
1015  cpl_msg_indent_more();
1016 
1017  mean_rms = mos_distortions_rms(mapped_sky, NULL, startwavelength,
1018  dispersion, 6, highres);
1019 
1020  cpl_msg_info(recipe, "Mean residual: %f", mean_rms);
1021 
1022  mean_rms = cpl_table_get_column_mean(idscoeff, "error");
1023 
1024  cpl_msg_info(recipe, "Mean model accuracy: %f pixel (%f A)",
1025  mean_rms, mean_rms * dispersion);
1026 
1027  header = cpl_propertylist_new();
1028  cpl_propertylist_update_double(header, "CRPIX1", 1.0);
1029  cpl_propertylist_update_double(header, "CRPIX2", 1.0);
1030  cpl_propertylist_update_double(header, "CRVAL1",
1031  startwavelength + dispersion/2);
1032  cpl_propertylist_update_double(header, "CRVAL2", 1.0);
1033  /* cpl_propertylist_update_double(header, "CDELT1", dispersion);
1034  cpl_propertylist_update_double(header, "CDELT2", 1.0); */
1035  cpl_propertylist_update_double(header, "CD1_1", dispersion);
1036  cpl_propertylist_update_double(header, "CD1_2", 0.0);
1037  cpl_propertylist_update_double(header, "CD2_1", 0.0);
1038  cpl_propertylist_update_double(header, "CD2_2", 1.0);
1039  cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
1040  cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
1041 
1042  if (time_normalise) {
1043  dummy = cpl_image_divide_scalar_create(mapped_sky, alltime);
1044  if (dfs_save_image(frameset, dummy, mapped_science_sky_tag, header,
1045  parlist, recipe, version))
1046  vimos_science_exit(NULL);
1047  cpl_image_delete(dummy); dummy = NULL;
1048  }
1049  else {
1050  if (dfs_save_image(frameset, mapped_sky, mapped_science_sky_tag,
1051  header, parlist, recipe, version))
1052  vimos_science_exit(NULL);
1053  }
1054 
1055  if (skyglobal == 0 && skymedian == 0 && skylocal == 0) {
1056  cpl_image_delete(mapped_sky); mapped_sky = NULL;
1057  }
1058 
1059  if (skyglobal || skylocal) {
1060 
1061  cpl_msg_indent_less();
1062 
1063  if (skyglobal) {
1064  cpl_msg_info(recipe, "Global sky determination...");
1065  cpl_msg_indent_more();
1066  skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
1067  sky = mos_sky_map_super(spectra, wavemap, dispersion,
1068  2.0, 50, skymap);
1069  if (sky)
1070  cpl_image_subtract(spectra, skymap);
1071  else
1072  cpl_image_delete(skymap); skymap = NULL;
1073  }
1074  else {
1075  cpl_msg_info(recipe, "Local sky determination...");
1076  cpl_msg_indent_more();
1077  skymap = mos_subtract_sky(spectra, slits, polytraces, reference,
1078  startwavelength, endwavelength, dispersion);
1079  }
1080 
1081  if (skymap) {
1082  if (skyglobal) {
1083  if (time_normalise)
1084  cpl_table_divide_scalar(sky, "sky", alltime);
1085  if (dfs_save_table(frameset, sky, global_sky_spectrum_tag,
1086  NULL, parlist, recipe, version))
1087  vimos_science_exit(NULL);
1088 
1089  cpl_table_delete(sky); sky = NULL;
1090  }
1091 
1092  save_header = dfs_load_header(frameset, science_tag, 0);
1093 
1094  if (time_normalise)
1095  cpl_image_divide_scalar(skymap, alltime);
1096  cpl_image_turn(skymap, rotate_back);
1097  if (dfs_save_image(frameset, skymap, unmapped_sky_tag,
1098  save_header, parlist, recipe, version))
1099  vimos_science_exit(NULL);
1100 
1101  cpl_image_delete(skymap); skymap = NULL;
1102 
1103  cpl_image_turn(spectra, rotate_back);
1104 
1105  if (cosmics) {
1106  cpl_msg_info(recipe, "Removing cosmic rays...");
1107  mos_clean_cosmics(spectra, gain, -1., -1.);
1108  }
1109 
1110  if (dfs_save_image(frameset, spectra, unmapped_science_tag,
1111  save_header, parlist, recipe, version))
1112  vimos_science_exit(NULL);
1113  cpl_image_turn(spectra, rotate);
1114 
1115  cpl_propertylist_delete(save_header); save_header = NULL;
1116 /* Cosmics was here */
1117  /*
1118  * The spatially rectified image, that contained the sky,
1119  * is replaced by a sky-subtracted spatially rectified image:
1120  */
1121 
1122  cpl_image_delete(smapped); smapped = NULL;
1123 
1124  if (treat_as_lss) {
1125  smapped = cpl_image_duplicate(spectra);
1126  }
1127  else {
1128  smapped = mos_spatial_calibration(spectra, slits, polytraces,
1129  reference, startwavelength,
1130  endwavelength, dispersion,
1131  flux, NULL);
1132  }
1133  }
1134  else {
1135  cpl_msg_warning(recipe, "Sky subtraction failure");
1136  if (cosmics)
1137  cpl_msg_warning(recipe, "Cosmic rays removal not performed!");
1138  cosmics = skylocal = skyglobal = 0;
1139  }
1140  }
1141 
1142  cpl_image_delete(spectra); spectra = NULL;
1143  cpl_table_delete(polytraces); polytraces = NULL;
1144 
1145  if (skyalign >= 0) {
1146  save_header = dfs_load_header(frameset, science_tag, 0);
1147  cpl_image_turn(wavemap, rotate_back);
1148  if (dfs_save_image(frameset, wavemap, wavelength_map_sky_tag,
1149  save_header, parlist, recipe, version))
1150  vimos_science_exit(NULL);
1151  cpl_propertylist_delete(save_header); save_header = NULL;
1152  }
1153 
1154  cpl_image_delete(wavemap); wavemap = NULL;
1155 
1156  mapped = mos_wavelength_calibration(smapped, reference,
1157  startwavelength, endwavelength,
1158  dispersion, idscoeff, flux);
1159 
1160  cpl_image_delete(smapped); smapped = NULL;
1161 
1162  if (skymedian) {
1163  cpl_msg_indent_less();
1164  cpl_msg_info(recipe, "Local sky determination...");
1165  cpl_msg_indent_more();
1166 
1167  skylocalmap = mos_sky_local_old(mapped, slits);
1168  cpl_image_subtract(mapped, skylocalmap);
1169  cpl_image_delete(skylocalmap); skylocalmap = NULL;
1170  }
1171 
1172  if (skyglobal || skymedian || skylocal) {
1173 
1174  skylocalmap = cpl_image_subtract_create(mapped_sky, mapped);
1175 
1176  cpl_image_delete(mapped_sky); mapped_sky = NULL;
1177 
1178  if (time_normalise) {
1179  dummy = cpl_image_divide_scalar_create(skylocalmap, alltime);
1180  if (dfs_save_image(frameset, dummy, mapped_sky_tag, header,
1181  parlist, recipe, version))
1182  vimos_science_exit(NULL);
1183  cpl_image_delete(dummy); dummy = NULL;
1184  }
1185  else {
1186  if (dfs_save_image(frameset, skylocalmap, mapped_sky_tag, header,
1187  parlist, recipe, version))
1188  vimos_science_exit(NULL);
1189  }
1190 
1191  cpl_msg_indent_less();
1192  cpl_msg_info(recipe, "Object detection...");
1193  cpl_msg_indent_more();
1194 
1195  if (cosmics || nscience > 1) {
1196  dummy = mos_detect_objects(mapped, slits, slit_margin, ext_radius,
1197  cont_radius);
1198  }
1199  else {
1200  mapped_cleaned = cpl_image_duplicate(mapped);
1201  mos_clean_cosmics(mapped_cleaned, gain, -1., -1.);
1202  dummy = mos_detect_objects(mapped_cleaned, slits, slit_margin,
1203  ext_radius, cont_radius);
1204 
1205  cpl_image_delete(mapped_cleaned); mapped_cleaned = NULL;
1206  }
1207 
1208  cpl_image_delete(dummy); dummy = NULL;
1209 
1210  mos_rotate_slits(slits, rotate, ny, nx);
1211  if (dfs_save_table(frameset, slits, object_table_tag, NULL, parlist,
1212  recipe, version))
1213  vimos_science_exit(NULL);
1214 
1215  cpl_msg_indent_less();
1216  cpl_msg_info(recipe, "Object extraction...");
1217  cpl_msg_indent_more();
1218 
1219  images = mos_extract_objects(mapped, skylocalmap, slits,
1220  ext_mode, ron, gain, 1);
1221 
1222  cpl_image_delete(skylocalmap); skylocalmap = NULL;
1223 
1224  if (images) {
1225  if (standard) {
1226  cpl_table *photcal = NULL;
1227  cpl_table *ext_table = NULL;
1228  cpl_table *flux_table = NULL;
1229 
1230  ext_table = dfs_load_table(frameset, "EXTINCT_TABLE", 1);
1231  flux_table = dfs_load_table(frameset, "STD_FLUX_TABLE", 1);
1232 
1233  photcal = mos_photometric_calibration(images[0],
1234  startwavelength,
1235  dispersion, gain,
1236  alltime, ext_table,
1237  airmass, flux_table,
1238  res_order);
1239 
1240  cpl_table_delete(ext_table);
1241  cpl_table_delete(flux_table);
1242 
1243  if (photcal) {
1244 
1245  if (qc) {
1246 
1247  float *data;
1248  char *pipefile = NULL;
1249  char keyname[30];
1250 
1251  qclist = dfs_load_header(frameset, science_tag, 0);
1252 
1253  if (qclist == NULL)
1254  vimos_science_exit("Cannot reload scientific "
1255  "frame header");
1256 
1257  fors_qc_start_group(qclist, "2.0", instrume);
1258 
1259 
1260  /*
1261  * QC1 group header
1262  */
1263 
1264  if (fors_qc_write_string("PRO.CATG", specphot_tag,
1265  "Product category", instrume))
1266  vimos_science_exit("Cannot write product category "
1267  "to QC log file");
1268 
1269  if (fors_qc_keyword_to_paf(qclist, "ESO DPR TYPE", NULL,
1270  "DPR type", instrume))
1271  vimos_science_exit("Missing keyword DPR TYPE in "
1272  "scientific frame header");
1273 
1274  if (fors_qc_keyword_to_paf(qclist, "ESO TPL ID", NULL,
1275  "Template", instrume))
1276  vimos_science_exit("Missing keyword TPL ID in "
1277  "scientific frame header");
1278 
1279  if (fors_qc_keyword_to_paf(qclist,
1280  key_gris_name, NULL,
1281  "Grism name", instrume)) {
1282  cpl_msg_error(recipe, "Missing keyword %s in "
1283  "scientific frame header",
1284  key_gris_name);
1285  vimos_science_exit(NULL);
1286  }
1287 
1288  if (fors_qc_keyword_to_paf(qclist,
1289  "ESO INS GRIS1 ID", NULL,
1290  "Grism identifier",
1291  instrume)) {
1292  cpl_msg_error(recipe, "Missing keyword %s in "
1293  "scientific frame header",
1294  key_gris_id);
1295  vimos_science_exit(NULL);
1296  }
1297 
1298  if (cpl_propertylist_has(qclist, key_filt_name))
1299  fors_qc_keyword_to_paf(qclist, key_filt_name, NULL,
1300  "Filter name", instrume);
1301 
1302  if (fors_qc_keyword_to_paf(qclist,
1303  "ESO DET CHIP1 ID", NULL,
1304  "Chip identifier",
1305  instrume))
1306  vimos_science_exit("Missing keyword DET CHIP1 ID "
1307  "in scientific frame header");
1308 
1309  if (fors_qc_keyword_to_paf(qclist, "ARCFILE", NULL,
1310  "Archive name of input data",
1311  instrume))
1312  vimos_science_exit("Missing keyword ARCFILE in "
1313  "scientific frame header");
1314 
1315  pipefile = dfs_generate_filename_tfits(specphot_tag);
1316 
1317  if (fors_qc_write_string("PIPEFILE", pipefile,
1318  "Pipeline product name",
1319  instrume))
1320  vimos_science_exit("Cannot write PIPEFILE to "
1321  "QC log file");
1322  cpl_free(pipefile);
1323 
1324 
1325  /*
1326  * QC1 parameters
1327  */
1328 
1329  wstart = 3700.;
1330  wstep = 400.;
1331  wcount = 15;
1332 
1333  dummy = cpl_image_new(wcount, 1, CPL_TYPE_FLOAT);
1334  data = cpl_image_get_data_float(dummy);
1335  map_table(dummy, wstart, wstep, photcal,
1336  "WAVE", "EFFICIENCY");
1337 
1338  for (i = 0; i < wcount; i++) {
1339  sprintf(keyname, "QC.MOS.EFFICIENCY%d.LAMBDA",
1340  i + 1);
1341  if (fors_qc_write_qc_double(qclist,
1342  wstart + wstep * i,
1343  keyname, "Angstrom",
1344  "Wavelength of "
1345  "efficiency evaluation",
1346  instrume)) {
1347  vimos_science_exit("Cannot write wavelength of "
1348  "efficiency evaluation");
1349  }
1350 
1351  sprintf(keyname, "QC.MOS.EFFICIENCY%d", i + 1);
1352  if (fors_qc_write_qc_double(qclist,
1353  data[i],
1354  keyname, "e-/photon",
1355  "Efficiency",
1356  instrume)) {
1357  vimos_science_exit("Cannot write wavelength of "
1358  "efficiency evaluation");
1359  }
1360  }
1361 
1362  cpl_image_delete(dummy); dummy = NULL;
1363 
1365 
1366  } /* End of QC1 computation */
1367 
1368  if (dfs_save_table(frameset, photcal, specphot_tag, qclist,
1369  parlist, recipe, version)) {
1370  cpl_table_delete(photcal);
1371  vimos_science_exit(NULL);
1372  }
1373  cpl_propertylist_delete(qclist); qclist = NULL;
1374  cpl_table_delete(photcal);
1375  }
1376  }
1377 
1378  if (time_normalise)
1379  cpl_image_divide_scalar(images[0], alltime);
1380 
1381  if (dfs_save_image(frameset, images[0], reduced_science_tag, header,
1382  parlist, recipe, version))
1383  vimos_science_exit(NULL);
1384 
1385  cpl_image_delete(images[0]);
1386 
1387  if (time_normalise)
1388  cpl_image_divide_scalar(images[1], alltime);
1389 
1390  if (dfs_save_image(frameset, images[1], reduced_sky_tag, header,
1391  parlist, recipe, version))
1392  vimos_science_exit(NULL);
1393 
1394  cpl_image_delete(images[1]);
1395 
1396  if (time_normalise)
1397  cpl_image_divide_scalar(images[2], alltime);
1398 
1399  if (dfs_save_image(frameset, images[2], reduced_error_tag, header,
1400  parlist, recipe, version))
1401  vimos_science_exit(NULL);
1402 
1403  cpl_image_delete(images[2]);
1404 
1405  cpl_free(images);
1406  }
1407  else {
1408  cpl_msg_warning(recipe, "No objects found: the products "
1409  "%s, %s, and %s are not created",
1410  reduced_science_tag, reduced_sky_tag,
1411  reduced_error_tag);
1412  }
1413 
1414  }
1415 
1416  cpl_table_delete(slits); slits = NULL;
1417 
1418  if (skyalign >= 0) {
1419  if (dfs_save_table(frameset, idscoeff, disp_coeff_sky_tag, NULL,
1420  parlist, recipe, version))
1421  vimos_science_exit(NULL);
1422  }
1423 
1424  cpl_table_delete(idscoeff); idscoeff = NULL;
1425 
1426  if (skyglobal || skymedian || skylocal) {
1427  if (time_normalise)
1428  cpl_image_divide_scalar(mapped, alltime);
1429  if (dfs_save_image(frameset, mapped, mapped_science_tag, header,
1430  parlist, recipe, version))
1431  vimos_science_exit(NULL);
1432  }
1433 
1434  cpl_image_delete(mapped); mapped = NULL;
1435  cpl_propertylist_delete(header); header = NULL;
1436 
1437  if (cpl_error_get_code()) {
1438  cpl_msg_error(cpl_error_get_where(), cpl_error_get_message());
1439  vimos_science_exit(NULL);
1440  }
1441  else
1442  return 0;
1443 }
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:8264
cpl_table * mos_photometric_calibration(cpl_image *spectra, double startwave, double dispersion, double gain, double exptime, cpl_table *ext_table, double airmass, cpl_table *flux_table, int order)
Produce instrument response curve, with some ancillary information.
Definition: moses.c:17204
cpl_image * dfs_load_image(cpl_frameset *frameset, const char *category, cpl_type type, int ext, int calib)
Loading image data of given category.
Definition: fors_dfs.c:845
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:587
double mos_distortions_rms(cpl_image *rectified, cpl_vector *lines, double wavestart, double dispersion, int radius, int highres)
Estimate the spectral distortion modeling goodness.
Definition: moses.c:10754
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:951
cpl_image ** mos_extract_objects(cpl_image *science, cpl_image *sky, cpl_table *objects, int extraction, double ron, double gain, int ncombined)
Extract detected objects from rectified scientific frame.
Definition: moses.c:14002
cpl_error_code fors_qc_write_qc_double(cpl_propertylist *header, double value, const char *name, const char *unit, const char *comment, const char *instrument)
Write an integer value to the active QC1 PAF object and to a header.
Definition: fors_qc.c:604
cpl_error_code mos_rotate_slits(cpl_table *slits, int rotation, int nx, int ny)
Rotate a slit location table.
Definition: moses.c:6074
cpl_image * mos_map_wavelengths(cpl_image *spatial, cpl_image *calibration, cpl_table *slits, cpl_table *polytraces, double reference, double blue, double red, double dispersion)
Remapping of spatially rectified wavelengths to original CCD pixels.
Definition: moses.c:11087
cpl_error_code fors_qc_keyword_to_paf(cpl_propertylist *header, const char *name, const char *unit, const char *comment, const char *instrument)
Copy a keyword value to the currently active QC1 PAF object.
Definition: fors_qc.c:425
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:9412
cpl_table * mos_sky_map_super(cpl_image *spectra, cpl_image *wavemap, double dispersion, double factor, int minpoints, cpl_image *skymap)
Create a CCD median sky map.
Definition: moses.c:11849
cpl_table * mos_wavelength_align(cpl_image *image, cpl_table *slits, double refwave, double firstLambda, double lastLambda, cpl_table *idscoeff, cpl_vector *skylines, int highres, int order, cpl_image *calibration, int sradius)
Modify the input wavelength solution to match reference sky lines.
Definition: moses.c:9693
cpl_error_code fors_qc_start_group(cpl_propertylist *header, const char *qcdic_version, const char *instrument)
Initiate a new QC1 group.
Definition: fors_qc.c:77
cpl_image * mos_remove_bias(cpl_image *image, cpl_image *bias, cpl_table *overscans)
Subtract the bias from a CCD exposure.
Definition: moses.c:3422
cpl_error_code fors_qc_write_string(const char *name, const char *value, const char *comment, const char *instrument)
Add string parameter to current QC1 group.
Definition: fors_qc.c:235
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:13651
cpl_image * mos_sky_local_old(cpl_image *spectra, cpl_table *slits)
Local determination of sky.
Definition: moses.c:12424
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:686
int dfs_equal_keyword(cpl_frameset *frameset, const char *keyword)
Saving table data of given category.
Definition: fors_dfs.c:1685
cpl_table * mos_wavelength_align_lss(cpl_image *image, double refwave, double firstLambda, double lastLambda, cpl_table *idscoeff, cpl_vector *skylines, int highres, int order, cpl_image *calibration, int sradius)
Modify the input wavelength solution to match reference sky lines (LSS).
Definition: moses.c:10246
cpl_image * mos_subtract_sky(cpl_image *science, cpl_table *slits, cpl_table *polytraces, double reference, double blue, double red, double dispersion)
Subtract the sky from the scientific CCD exposure.
Definition: moses.c:1969
cpl_image * mos_map_idscoeff(cpl_table *idscoeff, int xsize, double reference, double blue, double red)
Create a wavelengths map from an IDS coefficients table.
Definition: moses.c:10976
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:1447
cpl_table * dfs_load_table(cpl_frameset *frameset, const char *category, int ext)
Loading table data of given category.
Definition: fors_dfs.c:901
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:392
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:1574
cpl_error_code fors_qc_end_group(void)
Close current QC1 PAF file.
Definition: fors_qc.c:200
double fors_get_airmass(const cpl_propertylist *header)
Compute average airmass.
Definition: fors_tools.c:398
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:12881
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:489
cpl_table * mos_load_overscans_vimos(const cpl_propertylist *header, int check_consistency)
Get the overscan positions from FITS header of VIMOS data.
Definition: moses.c:15426