UVES Pipeline Reference Manual  5.4.6
uves_reduce.c
1 /* *
2  * This file is part of the ESO UVES Pipeline *
3  * Copyright (C) 2004,2005 European Southern Observatory *
4  * *
5  * This library is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the Free Software *
17  * Foundation, 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA *
18  * */
19 
20 /*
21  * $Author: amodigli $
22  * $Date: 2013-08-08 13:36:46 $
23  * $Revision: 1.125 $
24  * $Name: not supported by cvs2svn $
25  *
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 # include <config.h>
30 #endif
31 
32 /*----------------------------------------------------------------------------*/
38 /*----------------------------------------------------------------------------*/
42 /*-----------------------------------------------------------------------------
43  Includes
44  -----------------------------------------------------------------------------*/
45 
46 #include "uves_reduce.h"
47 
48 #include <uves.h>
49 #include <uves_extract.h>
50 #include <uves_backsub.h>
51 #include <uves_parameters.h>
52 #include <uves_flatfield.h>
53 #include <uves_rebin.h>
54 #include <uves_merge.h>
55 #include <uves_utils_cpl.h>
56 #include <uves_utils_wrappers.h>
57 #include <uves_pfits.h>
58 #include <uves_dfs.h>
59 #include <uves_dump.h>
60 #include <uves_qclog.h>
61 #include <uves_plot.h>
62 #include <uves_error.h>
63 
64 #include <cpl.h>
65 #include <float.h>
66 #include <string.h>
67 /*-----------------------------------------------------------------------------
68  Functions prototypes
69  -----------------------------------------------------------------------------*/
70 #define UVES_MIN_LINE_ROWS_TO_MAKE_FIT 5
71 #define UVES_BLAZE_DUMMY_VAL 999.
72 static cpl_error_code
73 extract_ff_rebin_merge(cpl_image *back_subbed,
74  cpl_image *backsubbed_noise,
75  const uves_propertylist *backsubbed_header,
76  const cpl_image *master_flat,
77  cpl_image *mflat_noise,
78  const cpl_table *ordertable,
79  const polynomial *order_locations,
80  const cpl_table *linetable,
81  const uves_propertylist *linetable_header[3],
82  const polynomial *dispersion_relation[3],
83  double slit_length,
84  double slit_offset,
85  int window,
86  enum uves_chip chip,
87  bool blaze_correct,
88  bool tilt_corr,
89  bool debug_mode,
90  const cpl_parameterlist *parameters,
91  const char *context,
92  const char *mode,
93  flatfielding_method ff_method,
94  extract_method ee_method,
95  merge_method m_method,
96  /* Output */
97  cpl_image **x,
98  uves_propertylist **x_header,
99  cpl_image **fx,
100  cpl_table **cosmic_mask,
101  cpl_image **wave_map,
102  cpl_image **flatfielded_variance,
103  uves_propertylist **flatfielded_variance_header,
104  cpl_image **resampled_spectrum,
105  cpl_image **resampled_mf,
106  cpl_image **merged_sky,
107  cpl_image **rebinned_spectrum,
108  cpl_image **rebinned_noise,
109  uves_propertylist **rebinned_header,
110  cpl_image **merged_spectrum,
111  cpl_image **merged_noise,
112  uves_propertylist **merged_header,
113  cpl_table** info_tbl,
114  cpl_table **order_trace);
115 
116 static cpl_image *
117 subtract_sky(cpl_image *rebinned_obj,
118  cpl_image *rebinned_obj_noise,
119  uves_propertylist *rebinned_obj_header,
120  const cpl_image *rebinned_sky1,
121  const cpl_image *rebinned_sky1_noise,
122  const uves_propertylist *rebinned_sky1_header,
123  const cpl_image *rebinned_sky2,
124  const cpl_image *rebinned_sky2_noise,
125  const uves_propertylist *rebinned_sky2_header,
126  cpl_image **merged_obj,
127  cpl_image **merged_obj_noise,
128  uves_propertylist *merged_obj_header,
129  const cpl_image *merged_sky1,
130  const cpl_image *merged_sky1_noise,
131  const uves_propertylist *merged_sky1_header,
132  const cpl_image *merged_sky2,
133  const cpl_image *merged_sky2_noise,
134  const uves_propertylist *merged_sky2_header,
135  double obj_slit,
136  double sky1_slit,
137  double sky2_slit);
138 
139 
140 static cpl_image *
141 subtract_sky_row(cpl_image *obj,
142  cpl_image *obj_noise,
143  double obj_start,
144  double obj_end,
145  double obj_slit,
146  const cpl_image *sky1,
147  const cpl_image *sky1_noise,
148  double sky1_start,
149  double sky1_end,
150  double sky1_slit,
151  const cpl_image *sky2,
152  const cpl_image *sky2_noise,
153  double sky2_start,
154  double sky2_end,
155  double sky2_slit,
156  int row,
157  double wavestep,
158  double *common_start,
159  double *common_end);
160 
161 static double get_offset(const cpl_image *back_subbed,
162  const cpl_table *ordertable,
163  const polynomial *order_locations,
164  double search_range,
165  int nsamples,
166  double *doffset);
167 
168 static cpl_image *
169 uves_get_blaze_ratio(const cpl_image *spectrum,
170  const cpl_image *spectrum_noise);
171 
172 /*-----------------------------------------------------------------------------
173  Implementation
174  -----------------------------------------------------------------------------*/
175 
176 
177 
178 /*----------------------------------------------------------------------------*/
185 /*----------------------------------------------------------------------------*/
186 
187 cpl_parameterlist *
189 {
190  const char *name = "";
191  char *full_name = NULL;
192  cpl_parameterlist *parameters = NULL;
193  cpl_parameter *p = NULL;
194 
195  parameters = cpl_parameterlist_new();
196 
197  /**************
198  * Backsub *
199  **************/
200  if (cpl_error_get_code() == CPL_ERROR_NONE)
201  {
202  uves_propagate_parameters_step(UVES_BACKSUB_ID, parameters,
203  UVES_REDUCE_ID, NULL);
204  }
205 
206 
207  /*****************
208  * Extraction *
209  *****************/
210  if (cpl_error_get_code() == CPL_ERROR_NONE)
211  {
212  uves_propagate_parameters_step(UVES_EXTRACT_ID, parameters,
213  UVES_REDUCE_ID, NULL);
214  }
215 
216 
217  /******************
218  * Slit geometry *
219  ******************/
220  if (cpl_error_get_code() == CPL_ERROR_NONE)
221  {
222  name = "slitlength";
223  full_name = uves_sprintf("%s.%s", UVES_REDUCE_ID, name);
224 
225  uves_parameter_new_range(p, full_name,
226  CPL_TYPE_DOUBLE,
227  "Extraction slit length (in pixels). "
228  "If negative, the value "
229  "inferred from the raw frame header is used",
230  UVES_REDUCE_ID,
231  -1.0,
232  -2.0, DBL_MAX);
233 
234  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
235  cpl_parameterlist_append(parameters, p);
236  cpl_free(full_name);
237  }
238 
239  if (cpl_error_get_code() == CPL_ERROR_NONE)
240  {
241  name = "skysub";
242  full_name = uves_sprintf("%s.%s", UVES_REDUCE_ID, name);
243 
244  uves_parameter_new_value(p, full_name,
245  CPL_TYPE_BOOL,
246  "Do sky-subtraction (only applicable to linear "
247  "and average extractions)?",
248  UVES_REDUCE_ID,
249  true);
250 
251  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
252  cpl_parameterlist_append(parameters, p);
253  cpl_free(full_name);
254  }
255 
256  if (cpl_error_get_code() == CPL_ERROR_NONE)
257  {
258  name = "objoffset";
259  full_name = uves_sprintf("%s.%s", UVES_REDUCE_ID, name);
260 
261  uves_parameter_new_value(p, full_name,
262  CPL_TYPE_DOUBLE,
263  "Offset (in pixels) of extraction slit "
264  "with respect to center of order. "
265  "This parameter applies to linear/average/"
266  "optimal extraction. "
267  "For linear/average extraction, if the related "
268  "parameter objslit is negative, the offset is "
269  "automatically determined by measuring the "
270  "actual object position. ",
271  UVES_REDUCE_ID,
272  0.0);
273 
274  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
275  cpl_parameterlist_append(parameters, p);
276  cpl_free(full_name);
277  }
278 
279  if (cpl_error_get_code() == CPL_ERROR_NONE)
280  {
281  name = "objslit";
282  full_name = uves_sprintf("%s.%s", UVES_REDUCE_ID, name);
283 
284  uves_parameter_new_range(p, full_name,
285  CPL_TYPE_DOUBLE,
286  "Object window size (in pixels). This must "
287  "be less than the total slit length. If "
288  "negative, the default value (half of full "
289  "slit length) is used. The upper and lower "
290  "sky windows are defined as the part of the "
291  "full slit (if any) outside the object "
292  "window. The center of the object window "
293  "is determined by the offset parameter. "
294  "This parameter does not apply to optimal "
295  "extraction.",
296  UVES_REDUCE_ID,
297  -1.0,
298  -2.0, DBL_MAX);
299 
300  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
301  cpl_parameterlist_append(parameters, p);
302  cpl_free(full_name);
303  }
304 
305  if (cpl_error_get_code() == CPL_ERROR_NONE)
306  {
307  name = "tiltcorr";
308  full_name = uves_sprintf("%s.%s", UVES_REDUCE_ID, name);
309 
310  uves_parameter_new_value(p, full_name,
311  CPL_TYPE_BOOL,
312  "If enabled (recommended), the provided "
313  "dispersion solutions "
314  "obtained at different slit positions are "
315  "interpolated linearly at the actually "
316  "measured position of the object/sky. "
317  "Line tilt correction is currently not supported "
318  "for 2d extraction, in which case the "
319  "dispersion solution obtained at the middle of "
320  "the slit is always used.",
321  UVES_REDUCE_ID,
322  true);
323 
324  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
325  cpl_parameterlist_append(parameters, p);
326  cpl_free(full_name);
327  }
328 
329 
330 
331  /*****************
332  * Flatfielding *
333  *****************/
334 
335  if (cpl_error_get_code() == CPL_ERROR_NONE)
336  {
337  name = "ffmethod";
338  full_name = uves_sprintf("%s.%s", UVES_REDUCE_ID, name);
339 
340  uves_parameter_new_enum(p, full_name,
341  CPL_TYPE_STRING,
342  "Flat-fielding method. If set to 'pixel', "
343  "flat-fielding is done in pixel-pixel space "
344  "(before extraction); if set to 'extract', "
345  "flat-fielding is performed in pixel-order "
346  "space (i.e. after extraction). If set to "
347  "'no', no flat-field correction is done",
348  UVES_REDUCE_ID,
349  "extract", /* 'Pixel' method is usually preferred,
350  but do like UVES/MIDAS */
351  3,
352  "pixel", "extract", "no");
353 
354  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
355  cpl_parameterlist_append(parameters, p);
356  cpl_free(full_name);
357  }
358 
359  /*****************
360  * Blaze corr. *
361  *****************/
362 
363  if (cpl_error_get_code() == CPL_ERROR_NONE)
364  {
365 /*
366  name = "blazecorr";
367  full_name = uves_sprintf("%s.%s", UVES_REDUCE_ID, name);
368 
369  uves_parameter_new_value(p, full_name,
370  CPL_TYPE_BOOL,
371  "(highly experimental, recommended=false) "
372  "Apply a correction for the different shapes "
373  "of flat-field and science blaze functions? "
374  "For this to be possible, flat-fielding method "
375  "must be different from 'no'.",
376  UVES_REDUCE_ID,
377  false);
378 
379  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
380  cpl_parameterlist_append(parameters, p);
381  cpl_free(full_name);
382 */
383  }
384 
385  /*****************
386  * Rebinning *
387  *****************/
388  if (cpl_error_get_code() == CPL_ERROR_NONE)
389  {
390  uves_propagate_parameters_step(UVES_REBIN_ID, parameters,
391  UVES_REDUCE_ID, NULL);
392  }
393 
394 
395  /*****************
396  * Merging *
397  *****************/
398  if (cpl_error_get_code() == CPL_ERROR_NONE)
399  {
400  name = "merge";
401  full_name = uves_sprintf("%s.%s", UVES_REDUCE_ID, name);
402 
403  uves_parameter_new_enum(p, full_name,
404  CPL_TYPE_STRING,
405  "Order merging method. If 'optimal', the "
406  "flux in the overlapping region is set "
407  "to the (optimally computed, using the "
408  "uncertainties) average of single order "
409  "spectra. If 'sum', the flux in the "
410  "overlapping region is computed as the "
411  "sum of the single order spectra. If 'noappend' "
412  "the spectrum is simply rebinned but not merged."
413  "If flat-fielding is done, method 'optimal' "
414  "is recommended, otherwise 'sum'.",
415  UVES_REDUCE_ID,
416  "optimal",
417  3,
418  "optimal", "sum", "noappend");
419 
420  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
421  cpl_parameterlist_append(parameters, p);
422  cpl_free(full_name);
423 
424 
425  name = "merge_delt1";
426  full_name = uves_sprintf("%s.%s", UVES_REDUCE_ID, name);
427 
428  uves_parameter_new_range(p, full_name,
429  CPL_TYPE_DOUBLE,
430  "Order merging left hand (short wavelength) "
431  "cut. To reduce the amount of order "
432  "overlapping regions we allow to cut short and "
433  "long wavelength ranges. "
434  "This may reduce the ripple possibly "
435  "introduced by the order merging. "
436  "Suggested values are: "
437  "10 (W<=390), 12 (390<W<=437, 520<W<=564), "
438  "14 (437<W<=520, 564<W) ",
439  UVES_REDUCE_ID,
440  0.,0.,20.);
441 
442  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
443  cpl_parameterlist_append(parameters, p);
444  cpl_free(full_name);
445 
446 
447  name = "merge_delt2";
448  full_name = uves_sprintf("%s.%s", UVES_REDUCE_ID, name);
449 
450  uves_parameter_new_range(p, full_name,
451  CPL_TYPE_DOUBLE,
452  "Order merging right hand (long wavelength) "
453  "cut. To reduce the amount of order "
454  "overlapping regions we allow to cut short and "
455  "long wavelength ranges. "
456  "This may reduce the ripple possibly "
457  "introduced by the order merging. "
458  "Suggested values is 4",
459  UVES_REDUCE_ID,
460  0.,0.,20.);
461 
462  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
463  cpl_parameterlist_append(parameters, p);
464  cpl_free(full_name);
465 
466 
467 
468  }
469 
470  if (cpl_error_get_code() != CPL_ERROR_NONE)
471  {
472  cpl_msg_error(__func__, "Creation of reduction parameters failed: '%s'",
473  cpl_error_get_where());
474  cpl_parameterlist_delete(parameters);
475  return NULL;
476  }
477 
478 
479  return parameters;
480 }
481 
482 /*----------------------------------------------------------------------------*/
573 /*----------------------------------------------------------------------------*/
574 
575 cpl_error_code uves_reduce(const cpl_image *raw_image,
576  const uves_propertylist *raw_header,
577  const uves_propertylist *rotated_header,
578  const cpl_image *master_bias,
579  const uves_propertylist *mbias_header,
580  const cpl_image *master_dark,
581  const uves_propertylist *mdark_header,
582  const cpl_image *master_flat,
583  const uves_propertylist *mflat_header,
584  const cpl_table *ordertable,
585  const polynomial *order_locations,
586  const cpl_table *linetable[3],
587  const uves_propertylist *linetable_header[3],
588  const polynomial *dispersion_relation[3],
589  enum uves_chip chip,
590  /* General */
591  bool debug_mode,
592  /* Backsub */
593  /* Flat fielding */
594  /* Extraction */
595  /* Rebinning */
596  const cpl_parameterlist *parameters,
597  const char *rec_id,
598  const char *mode,
599  /* Output */
600  cpl_image **x, uves_propertylist **x_header,
601  cpl_image **fx,
602  cpl_table **cosmic_mask,
603  cpl_image **wave_map,
604  cpl_image **background,
605  cpl_image **flatfielded_variance,
606  uves_propertylist **flatfielded_variance_header,
607  cpl_image **resampled_spectrum,
608  cpl_image **resampled_mf,
609  cpl_image **merged_sky,
610  /* Before sky-subtraction */
611  cpl_image **rebinned_spectrum,
612  cpl_image **rebinned_noise,
613  uves_propertylist **rebinned_header,
614  cpl_image **merged_spectrum ,
615  cpl_image **merged_noise,
616  uves_propertylist **merged_header,
617  /* After sky-subtraction */
618  cpl_image **reduced_rebinned_spectrum,
619  cpl_image **reduced_rebinned_noise,
620  cpl_image **reduced_spectrum ,
621  cpl_image **reduced_noise,
622  cpl_table **info_tbl,
623  double *extraction_slit,
624  cpl_table **order_trace)
625 {
626  /* Recipe parameters */
627  char context[80];
628  flatfielding_method ff_method;
629  merge_method m_method;
630  extract_method ex_method;
631  bool blaze_corr=false;
632  bool sky_sub;
633  bool tilt_corr;
634  double full_slit;
635  double obj_slit;
636  double obj_offset;
637  double exptime=0;
638  cpl_image *back_subbed = NULL; /* Image before extraction */
639  cpl_image *backsubbed_noise = NULL;
640 
641  cpl_image *mflat_noise = NULL; /* Master flat noise */
642 
643  cpl_image *simple_extracted = NULL; /* Needed only for blaze-correction */
644  cpl_image *simple_extracted_mf = NULL;
645 
646  cpl_image *sky_lo = NULL; /* Merged sky spectra */
647  cpl_image *sky_lo_noise = NULL;
648  cpl_image *sky_hi = NULL;
649  cpl_image *sky_hi_noise = NULL;
650  uves_propertylist *sky_lo_header = NULL;
651  uves_propertylist *sky_hi_header = NULL;
652 
653  cpl_image *sky_lo_rebinned = NULL; /* Rebinned sky spectra */
654  cpl_image *sky_lo_rebinned_noise = NULL;
655  cpl_image *sky_hi_rebinned = NULL;
656  cpl_image *sky_hi_rebinned_noise = NULL;
657  uves_propertylist *sky_lo_rebinned_header = NULL;
658  uves_propertylist *sky_hi_rebinned_header = NULL;
659 
660  char *subcontext = NULL;
661  double header_full_slit; /* Slit length in pixels
662  from FITS header */
663  char *ex_method_string = NULL;
664  double dnoise=-999;
665  double bnoise=-999;
666  bool has_fnoise=false;
667  double fnoise=0;
668  uves_propertylist* local_raw_header=NULL;
669  /* Check, initialize input */
670  passure( background != NULL, " "); *background = NULL;
671  /* resampled_spectrum, resampled_mf may be NULL */
672  passure( rebinned_spectrum != NULL, " "); *rebinned_spectrum = NULL;
673  passure( rebinned_noise != NULL, " "); *rebinned_noise = NULL;
674  passure( rebinned_header != NULL, " "); *rebinned_header = NULL;
675  passure( merged_spectrum != NULL, " "); *merged_spectrum = NULL;
676  passure( merged_sky != NULL, " "); *merged_sky = NULL;
677  passure( merged_noise != NULL, " "); *merged_noise = NULL;
678  passure( merged_header != NULL, " "); *merged_header = NULL;
679  passure( reduced_rebinned_spectrum != NULL, " "); *reduced_rebinned_spectrum = NULL;
680  passure( reduced_rebinned_noise != NULL, " "); *reduced_rebinned_noise = NULL;
681  passure( reduced_spectrum != NULL, " "); *reduced_spectrum = NULL;
682  passure( reduced_noise != NULL, " "); *reduced_noise = NULL;
683 
684  passure( (flatfielded_variance == NULL) == (flatfielded_variance_header == NULL),
685  "%d %d", flatfielded_variance == NULL, flatfielded_variance_header == NULL);
686 
687  assure_nomsg( extraction_slit != NULL, CPL_ERROR_NULL_INPUT );
688 
689  /* Get flat-fielding/extract method (recipe parameters)
690  These parameters determine the overall reduction strategy. */
691  {
692  if(strcmp(mode,".efficiency")==0) {
693  sprintf(context,"%s%s",rec_id,mode);
694  } else {
695  sprintf(context,"%s",rec_id);
696  }
697  check( ff_method = uves_get_flatfield_method(parameters, context, UVES_REDUCE_ID),
698  "Could not read flat-fielding method");
699 
700  assure( ff_method == FF_NO || master_flat != NULL, CPL_ERROR_NULL_INPUT,
701  "Flat-fielding requested, but no flat field provided");
702 
703  /* Read extract method from <context>.<uves_reduce>.<extract>.method */
704  check( ex_method = uves_get_extract_method(parameters, context,
705  UVES_REDUCE_ID "." UVES_EXTRACT_ID),
706  "Could not get extraction method");
707 
708  assure( ex_method != EXTRACT_WEIGHTED, CPL_ERROR_ILLEGAL_INPUT,
709  "Weighted extraction is used only internally, "
710  "as a part of optimal extraction");
711 
712  check( m_method = uves_get_merge_method(parameters, context, UVES_REDUCE_ID),
713  "Could not get merging method");
714 
715 /*
716  check( uves_get_parameter(parameters, rec_id, UVES_REDUCE_ID,
717  "blazecorr", CPL_TYPE_BOOL, &blaze_corr),
718  "Could not read parameter");
719 */
720  /*Forcing blazecorection to be off */
721  blaze_corr=false;
722  check( uves_get_parameter(parameters, rec_id, UVES_REDUCE_ID,
723  "skysub", CPL_TYPE_BOOL, &sky_sub),
724  "Could not read parameter");
725 
726  check( uves_get_parameter(parameters, rec_id, UVES_REDUCE_ID,
727  "tiltcorr", CPL_TYPE_BOOL, &tilt_corr),
728  "Could not read parameter");
729 
730  assure( !blaze_corr || ff_method != FF_NO, CPL_ERROR_INCOMPATIBLE_INPUT,
731  "Sorry, cannot apply blaze function "
732  "correction when no flatfielding is done");
733 
734  if (blaze_corr && ex_method == EXTRACT_2D)
735  {
736  uves_msg_warning("There will be no blaze function correction "
737  "for 2d extraction");
738  }
739 
740  if (ff_method == FF_NO && m_method == MERGE_OPTIMAL)
741  {
742  uves_msg_warning("No flat-fielding done, but merge method = optimal. "
743  "Is this really what you want?");
744  }
745  if (ff_method != FF_NO && m_method == MERGE_SUM)
746  {
747  uves_msg_warning("Flat-fielding will be done, but merge method = sum. "
748  "Is this really what you want?");
749  }
750 
751  check( uves_get_parameter(parameters, rec_id, UVES_REDUCE_ID, "slitlength",
752  CPL_TYPE_DOUBLE, &full_slit), "Could not read parameter");
753 
754  check( uves_get_parameter(parameters, rec_id, UVES_REDUCE_ID, "objoffset",
755  CPL_TYPE_DOUBLE, &obj_offset),
756  "Could not read parameter");
757  check( uves_get_parameter(parameters, rec_id, UVES_REDUCE_ID, "objslit",
758  CPL_TYPE_DOUBLE, &obj_slit),
759  "Could not read parameter");
760  }
761 
762  /* Append '.uves_reduce' to context */
763  subcontext = uves_sprintf("%s.%s", rec_id, UVES_REDUCE_ID);
764 
765  /* Subtract bias */
766  check( back_subbed = cpl_image_duplicate(raw_image),
767  "Error copying raw image");
768 
769  local_raw_header=(uves_propertylist* )raw_header;
770  if (master_bias != NULL)
771  {
772  uves_msg("Subtracting master bias");
773  check( uves_subtract_bias(back_subbed, master_bias),
774  "Error subtracting master bias");
775 
776 
777  int pn = PORT_ID(chip);
778  char key_name[80];
779  sprintf(key_name, "ESO QC OUT%d RON MASTER", pn);
780 
781  if(uves_propertylist_has(mbias_header,key_name)) {
782  bnoise=uves_propertylist_get_double(mbias_header,key_name);
783  } else {
784  uves_msg("key %s not found, compute it on the fly",key_name);
785  double bmax=0;
786  double bmin=0;
787  double bavg=0;
788  double brms=0;
789  int kappa=5;
790  int niter=3;
791  cpl_mask* msk=NULL;
792 
793  for(int i=0;i<niter;i++){
794  bmin=cpl_image_get_min(master_bias);
795  bmax=cpl_image_get_max(master_bias);
796  bavg=cpl_image_get_mean(master_bias);
797  brms=cpl_image_get_stdev(master_bias);
798  msk=cpl_mask_threshold_image_create(master_bias,bavg-kappa*brms,bavg+kappa*brms);
799  cpl_mask_not(msk);
800  cpl_image_reject_from_mask(master_bias, msk);
801  cpl_mask_delete(msk);
802  }
803 
804  bnoise=cpl_image_get_stdev(master_bias);
805 
806  }
807 
808  uves_propertylist_append_c_double(local_raw_header,UVES_BNOISE,bnoise,
809  "Master bias RMS on frame");
810 
811 
812 
813 
814  }
815  else
816  {
817  uves_msg("Skipping bias subtraction");
818  }
819 
820  /* Subtract dark if available */
821  if (master_dark != NULL)
822  {
823  uves_msg("Subtracting master dark");
824  check( uves_subtract_dark(back_subbed, raw_header,
825  master_dark, mdark_header),
826  "Error subtracting master dark");
827 
828  double dmax=0;
829  double dmin=0;
830  double davg=0;
831  double drms=0;
832  int kappa=5;
833  int niter=3;
834  cpl_mask* msk=NULL;
835 
836  for(int i=0;i<niter;i++){
837  dmin=cpl_image_get_min(master_dark);
838  dmax=cpl_image_get_max(master_dark);
839  davg=cpl_image_get_mean(master_dark);
840  drms=cpl_image_get_stdev(master_dark);
841  msk=cpl_mask_threshold_image_create(master_dark,davg-kappa*drms,davg+kappa*drms);
842  cpl_mask_not(msk);
843  cpl_image_reject_from_mask(master_dark, msk);
844  cpl_mask_delete(msk);
845  }
846 
847 
848  dnoise=cpl_image_get_stdev(master_dark);
849  uves_msg_warning("noise master dark (not rescaled) %g",dnoise);
850  exptime=uves_pfits_get_exptime(mdark_header);
851  uves_msg_warning("Exptime master dark %g",exptime);
852 
853  uves_propertylist_append_c_double(local_raw_header,UVES_DNOISE,dnoise,
854  "Master dark RMS on frame");
855  uves_propertylist_append_c_double(local_raw_header,UVES_DTIME,exptime,
856  "Master dark RMS on frame");
857  }
858  else
859  {
860  uves_msg("Skipping dark subtraction");
861  }
862 
863  if (master_flat != NULL)
864  {
865  has_fnoise=uves_propertylist_contains(mflat_header,UVES_FNOISE);
866  if(has_fnoise) {
867  fnoise=uves_propertylist_get_double(mflat_header,UVES_FNOISE);
868  }
869  }
870  if (debug_mode) check( uves_save_image_local("Bias/dark subtracted raw image", "pre",
871  back_subbed, chip, -1, -1, rotated_header, true),
872  "Error saving image");
873 
874  uves_msg("Creating noise image");
875 
876  /* Define/initialize input image noise (r.o.n. and photonic) */
877  check( backsubbed_noise = uves_define_noise(back_subbed, raw_header,
878  1, chip),
879  "Could not calculate noise image");
880 
881  /* Save noise image */
882  if (debug_mode) check( uves_save_image_local("Background subtracted raw image noise",
883  "errb", backsubbed_noise,
884  chip, -1, -1, rotated_header, true),
885  "Error saving image");
886 
887  /* Subtract background */
888  uves_msg("Subtracting inter-order background");
889 
890  check( uves_backsub_spline(back_subbed, raw_header,
891  ordertable, order_locations,
892  parameters, subcontext,
893  chip,
894  false, /* Use flat-field parameters? */
895  background),
896  "Error subtracting background");
897 
898  /* Save bias, dark, background subtracted frame */
899  if (debug_mode) check( uves_save_image_local("Background subtracted raw image", "b",
900  back_subbed, chip, -1, -1, rotated_header, true),
901  "Error saving image");
902 
903 
904  /*
905  * Initialize flat-field noise (if necessary)
906  */
907  if (ff_method == FF_NO)
908  {
909  uves_msg("Skipping flat-field correction");
910  }
911 
912  if (ff_method != FF_NO || resampled_mf != NULL)
913  {
914  int mflat_datancom;
915 
916  /* Save master flat image */
917  if (debug_mode)
918  {
919  check( uves_save_image_local("Master flat image", "mf",
920  master_flat,
921  chip, -1, -1, rotated_header, true),
922  "Error saving master flat image");
923  }
924 
925 
926  /* Define master flat noise */
927  check( mflat_datancom = uves_pfits_get_datancom(mflat_header),
928  "Error reading number of raw flat field frames "
929  "used for master flat image");
930 
931  uves_msg("Creating master flat noise image");
932 
933  check( mflat_noise = uves_define_noise(master_flat, mflat_header,
934  mflat_datancom,chip),
935  "Could not define master flat noise");
936 
937 
938  /* Save master flat noise image */
939  if (debug_mode)
940  {
941  check( uves_save_image_local("Master flat noise", "errmf", mflat_noise,
942  chip, -1, -1, rotated_header, true),
943  "Error saving master flat image");
944  }
945  }
946 
947 
948  /*
949  * Get full slit length
950  */
951  check( header_full_slit = uves_pfits_get_slitlength_pixels(raw_header, chip),
952  "Could not read slit length");
953 
954  /* If user didn't specify slit length, use header value */
955  if (full_slit < 0)
956  {
957  /* Avoid pixels at the edge of the slit
958  * which are likely to be noisy
959  */
960  full_slit = uves_max_double(1.0, header_full_slit - 2);
961  }
962  else
963  {
964  /* Warn if user specified value is larger than header value */
965  if (full_slit > header_full_slit)
966  {
967  uves_msg_warning("Specified full slit length (%e pixels) "
968  "is larger than input header slit "
969  "length (%e pixels)",
970  full_slit, header_full_slit);
971  }
972  }
973 
974  uves_msg("Slit length = %.2f pixels", full_slit);
975  *extraction_slit = full_slit;
976 
977  if (ff_method == FF_PIXEL)
978  {
979  uves_msg("Dividing by normalized master flat-field (method = pixel)");
980 
981  check( uves_flatfielding(back_subbed, backsubbed_noise,
982  master_flat, mflat_noise),
983  "Could not perform flat-fielding");
984 
985  /* Save flat-fielded image + noise */
986  if (debug_mode)
987  {
988  check( uves_save_image_local("Flat-fielded image", "fb",
989  back_subbed, chip, -1, -1,
990  rotated_header, true),
991  "Error saving flat-fielded image");
992 
993  check( uves_save_image_local("Flat-fielded image noise", "errfb",
994  backsubbed_noise, chip, -1, -1,
995  rotated_header, true),
996  "Error saving noise of flat-fielded image");
997  }
998  }
999 
1000  /* Extract the object window (+ sky windows depending on method) */
1001  switch(ex_method)
1002  {
1003  case EXTRACT_OPTIMAL:
1004  {
1005  int window_number = 2;
1006 
1007  check( extract_ff_rebin_merge(back_subbed,
1008  backsubbed_noise,
1009  raw_header,
1010  master_flat,
1011  mflat_noise,
1012  ordertable,
1013  order_locations,
1014  linetable[window_number-1],
1015  linetable_header,
1016  dispersion_relation,
1017  full_slit,
1018  obj_offset,
1019  window_number,
1020  chip,
1021  blaze_corr,
1022  tilt_corr,
1023  debug_mode,
1024  parameters,
1025  subcontext,
1026  mode,
1027  ff_method,
1028  ex_method,
1029  m_method,
1030  NULL,
1031  NULL,
1032  NULL,
1033  cosmic_mask,
1034  wave_map,
1035  flatfielded_variance,
1036  flatfielded_variance_header,
1037  resampled_spectrum,
1038  resampled_mf,
1039  merged_sky,
1040  /* merged_sky will be computed
1041  during optimal extraction */
1042  rebinned_spectrum,
1043  rebinned_noise,
1044  rebinned_header,
1045  merged_spectrum,
1046  merged_noise,
1047  merged_header,
1048  info_tbl,
1049  order_trace),
1050  "Error during reduction");
1051 
1052  /* The sky-subtracted spectra are just the optimally extracted spectra
1053  * (since sky-subtraction is done during extraction)
1054  */
1055  check(( *reduced_spectrum = cpl_image_duplicate(*merged_spectrum),
1056  *reduced_noise = cpl_image_duplicate(*merged_noise),
1057  *reduced_rebinned_spectrum = cpl_image_duplicate(*rebinned_spectrum),
1058  *reduced_rebinned_noise = cpl_image_duplicate(*rebinned_noise)),
1059  "Error creating sky-subtracted spectra");
1060  }
1061  break;
1062  case EXTRACT_LINEAR: /* Same as average (pass ex-method to uves_extract) */
1063  case EXTRACT_AVERAGE:
1064  {
1065  /* Average/linear extraction.
1066  * Define sky+object+sky windows,
1067  * extract, rebin, merge, subtract
1068  */
1069 
1070  const char *slicer_name;
1071  double doffset = 0;
1072  double obj_hi, obj_lo;
1073  double sky_lo_slit, sky_hi_slit;
1074  int window_number;
1075 
1076  /*
1077  * See if there's an image slicer
1078  * Extract sky only if not
1079  */
1080 
1081  check( slicer_name = uves_pfits_get_slit1_name(raw_header),
1082  "Could not read slicer id");
1083 
1084  uves_msg("Slicer name = '%s'%s", slicer_name,
1085  (strcmp(slicer_name, "FREE") == 0) ? " (no slicer)" : "");
1086 
1087  if ( strncmp(slicer_name, "SLIC", 4) == 0)
1088  {
1089  /*
1090  * Use full slit for object, no sky
1091  */
1092 
1093  obj_hi = uves_min_double(+full_slit/2, obj_offset + full_slit/2);
1094  obj_lo = uves_max_double(-full_slit/2, obj_offset - full_slit/2);
1095 
1096  obj_slit = obj_hi - obj_lo;
1097 
1098  sky_lo_slit = -1; /* Don't extract sky */
1099  sky_hi_slit = -1;
1100 
1101  uves_msg("Extraction slits (full slit = %.2f pixels)", full_slit);
1102  uves_msg("|* Sky 1 *|******** Obj ********|* Sky 2 *|");
1103  uves_msg("|* %-5.1f *|******* %-5.1f *******|* %-5.1f *|",
1104  0.0, obj_slit, 0.0);
1105  }
1106  else
1107  {
1108  /* There's no slicer */
1109  assure( strncmp(slicer_name, "FREE", 4) == 0, CPL_ERROR_UNSUPPORTED_MODE,
1110  "Unrecognized slicer name: '%s'. "
1111  "Recognized names include 'FREE', 'SLIC#1', 'SLIC#2', 'SLIC#3'.",
1112  slicer_name);
1113 
1114  /* Measure offset if user didn't specify */
1115  if (obj_slit < 0)
1116  {
1117  check( obj_offset =
1118  get_offset(back_subbed,
1119  ordertable, order_locations,
1120  full_slit/2, /* Offset search range */
1121  10, /* Samples per order */
1122  &doffset),
1123  "Could not find object offset");
1124 
1125  uves_msg("Measured object position = %.2f +- %.2f pixels",
1126  obj_offset, doffset);
1127 
1128  if (sky_sub)
1129  {
1130  /* Define object extraction slit length
1131  as half of full slit. */
1132  obj_hi = uves_min_double(+full_slit/2,
1133  obj_offset + full_slit/4.0);
1134  obj_lo = uves_max_double(-full_slit/2,
1135  obj_offset - full_slit/4.0);
1136  }
1137  else
1138  /* No sky subtraction. Object = full slit */
1139  {
1140  obj_hi = uves_min_double(+full_slit/2,
1141  obj_offset + full_slit/2.0);
1142  obj_lo = uves_max_double(-full_slit/2,
1143  obj_offset - full_slit/2.0);
1144  }
1145  obj_slit = obj_hi - obj_lo;
1146  }
1147  else
1148  /* User specified object slit */
1149  {
1150  uves_msg("Object offset = %.2f pixels", obj_offset);
1151 
1152  obj_hi = obj_offset + obj_slit / 2;
1153  obj_lo = obj_offset - obj_slit / 2;
1154  }
1155 
1156  uves_msg("Object slit = %.2f pixels", obj_slit);
1157 
1158  assure( -full_slit / 2 < obj_offset && obj_offset < full_slit / 2,
1159  CPL_ERROR_ILLEGAL_INPUT,
1160  "Object is outside slit! Offset = %f, Slit length = %f",
1161  obj_offset, full_slit);
1162 
1163  /* Sky slits (might be negative if object has large offset) */
1164  if (sky_sub)
1165  {
1166  sky_lo_slit = obj_lo - (-full_slit/2);
1167  sky_hi_slit = full_slit/2 - obj_hi;
1168 
1169  assure( sky_lo_slit > 0 || sky_hi_slit > 0, CPL_ERROR_ILLEGAL_INPUT,
1170  "At least one sky slit length must be positive. "
1171  "They are %f and %f pixels", sky_lo_slit, sky_hi_slit);
1172  }
1173  else
1174  {
1175  sky_lo_slit = -1; /* Don't extract sky */
1176  sky_hi_slit = -1;
1177  }
1178 
1179  uves_msg("Extraction slits (full slit = %.2f pixels)", full_slit);
1180  uves_msg("|*** Sky 1 **%s|**** Obj ****|%s** Sky 2 ***|",
1181  (obj_lo > -obj_hi) ? "*" : "",
1182  (obj_lo > -obj_hi) ? "" : "*");
1183  uves_msg("|*** %-5.1f **%s|*** %-5.1f ***|%s** %-5.1f ***|",
1184  sky_lo_slit, (obj_lo > -obj_hi) ? "*" : "",
1185  obj_slit , (obj_lo > -obj_hi) ? "" : "*",
1186  sky_hi_slit);
1187  }
1188 
1189  /* The window geometry has now been deermined. Extract spectra.
1190 
1191  It is important to use the same rebinning step size,
1192  for sky and object (otherwise the sky spectrum cannot (easily)
1193  be subtracted). If this step size is not specified (i.e. is negative)
1194  in the parameter list, it is determined from the
1195  average pixelsize, which is read from the line table.
1196  Therefore pass the object's line table also for the sky windows
1197  (but still use different dispersion relations for sky/object)
1198  */
1199 
1200  /* Extract sky 1 */
1201  window_number = 1;
1202  if ( sky_lo_slit > 0 )
1203  {
1204  uves_msg("Processing sky 1 window");
1205  check( extract_ff_rebin_merge(back_subbed,
1206  backsubbed_noise,
1207  raw_header,
1208  master_flat,
1209  mflat_noise,
1210  ordertable,
1211  order_locations,
1212  linetable[2-1], /* Object linetable */
1213  linetable_header,
1214  dispersion_relation,
1215  sky_lo_slit, /* Slit length (pixels) */
1216  -full_slit/2 + sky_lo_slit/2,
1217  /* Slit center offset */
1218  window_number,
1219  chip,
1220  blaze_corr,
1221  tilt_corr,
1222  debug_mode,
1223  parameters,
1224  subcontext,
1225  mode,
1226  ff_method,
1227  ex_method,
1228  m_method,
1229  NULL,
1230  NULL,
1231  NULL,
1232  NULL,
1233  wave_map,
1234  NULL,
1235  NULL,
1236  NULL,
1237  NULL,
1238  NULL,
1239  &sky_lo_rebinned,
1240  &sky_lo_rebinned_noise,
1241  &sky_lo_rebinned_header,
1242  &sky_lo,
1243  &sky_lo_noise,
1244  &sky_lo_header,
1245  NULL,
1246  NULL),
1247  "Error processing lower sky window");
1248  }
1249  else
1250  {
1251  uves_msg("Skipping sky 1 window");
1252  sky_lo_rebinned = NULL;
1253  sky_lo = NULL;
1254  }
1255 
1256  /* Extract sky 2 */
1257  window_number = 3;
1258  if ( sky_hi_slit > 0 )
1259  {
1260  uves_msg("Processing sky 2 window");
1261 
1262  uves_free_propertylist(rebinned_header);
1263  check( extract_ff_rebin_merge(back_subbed,
1264  backsubbed_noise,
1265  raw_header,
1266  master_flat,
1267  mflat_noise,
1268  ordertable,
1269  order_locations,
1270  linetable[2-1], /* Object linetable */
1271  linetable_header,
1272  dispersion_relation,
1273  sky_hi_slit, /* Slit length (pixels) */
1274  full_slit/2 - sky_hi_slit/2,
1275  /* Slit center offset */
1276  window_number,
1277  chip,
1278  blaze_corr,
1279  tilt_corr,
1280  debug_mode,
1281  parameters,
1282  subcontext,
1283  mode,
1284  ff_method,
1285  ex_method,
1286  m_method,
1287  NULL,
1288  NULL,
1289  NULL,
1290  NULL,
1291  wave_map,
1292  NULL,
1293  NULL,
1294  NULL,
1295  NULL,
1296  NULL,
1297  &sky_hi_rebinned,
1298  &sky_hi_rebinned_noise,
1299  &sky_hi_rebinned_header,
1300  &sky_hi,
1301  &sky_hi_noise,
1302  &sky_hi_header,
1303  NULL,
1304  NULL),
1305  "Error processing upper sky window");
1306  }
1307  else
1308  {
1309  uves_msg("Skipping sky 2 window");
1310  sky_hi_rebinned = NULL;
1311  sky_hi = NULL;
1312  }
1313 
1314  /* Extract object */
1315  window_number = 2;
1316  uves_msg("Processing object window");
1317  uves_free_propertylist(rebinned_header);
1318  check( extract_ff_rebin_merge(back_subbed, backsubbed_noise, raw_header,
1319  master_flat, mflat_noise,
1320  ordertable, order_locations,
1321  linetable[window_number-1],
1322  linetable_header,
1323  dispersion_relation,
1324  obj_slit, /* Slit length (pixels) */
1325  obj_offset,
1326  /* Slit center offset */
1327  window_number,
1328  chip,
1329  blaze_corr,
1330  tilt_corr,
1331  debug_mode,
1332  parameters,
1333  subcontext,
1334  mode,
1335  ff_method,
1336  ex_method,
1337  m_method,
1338  NULL,
1339  NULL,
1340  NULL,
1341  NULL,
1342  wave_map,
1343  flatfielded_variance,
1344  flatfielded_variance_header,
1345  resampled_spectrum,
1346  resampled_mf,
1347  NULL,
1348  rebinned_spectrum,
1349  rebinned_noise,
1350  rebinned_header,
1351  merged_spectrum,
1352  merged_noise,
1353  merged_header,
1354  info_tbl,
1355  NULL),
1356  "Error processing object window");
1357 
1358  if (info_tbl != NULL && *info_tbl != NULL)
1359  {
1360  /* Compute obj. position from sky_lo_slit
1361  for consistency with optimal extraction */
1362  int i;
1363  for (i = 0; i < cpl_table_get_nrow(*info_tbl); i++)
1364  {
1365  cpl_table_set_double(*info_tbl, "ObjPosOnSlit", i,
1366  cpl_table_get_double(*info_tbl, "ObjPosOnSlit", i, NULL)
1367  +
1368  ((sky_lo_slit >= 0) ? sky_lo_slit : 0));
1369 
1370  }
1371  }
1372 
1373 
1374  /* Now subtract sky from both rebinned spectrum and merged spectrum */
1375 
1376  /* Duplicate, then subtract */
1377 
1378  /* 1d spectrum */
1379  check(( *reduced_spectrum = cpl_image_duplicate(*merged_spectrum),
1380  *reduced_noise = cpl_image_duplicate(*merged_noise)),
1381  "Error allocating sky-subtracted spectra");
1382 
1383  /* 2d (wavelength, order) spectrum */
1384  check(( *reduced_rebinned_spectrum =
1385  cpl_image_duplicate(*rebinned_spectrum),
1386  *reduced_rebinned_noise =
1387  cpl_image_duplicate(*rebinned_noise)),
1388  "Error allocating sky-subtracted spectra");
1389 
1390  if (sky_lo != NULL || sky_hi != NULL)
1391  {
1392  uves_msg("Subtracting sky");
1393 
1394  check( *merged_sky =
1395  subtract_sky(*reduced_rebinned_spectrum,
1396  *reduced_rebinned_noise, *rebinned_header,
1397  sky_lo_rebinned, sky_lo_rebinned_noise,
1398  sky_lo_rebinned_header,
1399  sky_hi_rebinned, sky_hi_rebinned_noise,
1400  sky_hi_rebinned_header,
1401  reduced_spectrum, reduced_noise, *merged_header,
1402  sky_lo, sky_lo_noise, sky_lo_header,
1403  sky_hi, sky_hi_noise, sky_hi_header,
1404  (ex_method == EXTRACT_AVERAGE) ? 1.0 : obj_slit,
1405  (ex_method == EXTRACT_AVERAGE) ? 1.0 : sky_lo_slit,
1406  (ex_method == EXTRACT_AVERAGE) ? 1.0 : sky_hi_slit),
1407  "Could not subtract sky");
1408 
1409  if (*merged_sky == NULL)
1410  {
1411  uves_msg_warning("Could not subtract sky");
1412  }
1413  }
1414  else
1415  {
1416  uves_msg_low("Skipping sky subtraction");
1417 
1418  /* Return no sky spectrum */
1419  *merged_sky = NULL;
1420  }
1421  } /* Simple extraction */
1422  break;
1423  case EXTRACT_2D:
1424  {
1425  int window_number = 2; /* Use middle line table for entire
1426  slit length (like MIDAS) */
1427 
1428  int half_slit_length; /* The slit length is
1429  2*half_slit_length = an even number */
1430 
1431  /* Round to nearest integer, remove (noisy) edge (~2 pixels) */
1432  half_slit_length =
1433  uves_max_int(1, uves_round_double(header_full_slit/2) - 1);
1434 
1435  check( extract_ff_rebin_merge(back_subbed,
1436  backsubbed_noise,
1437  raw_header,
1438  master_flat,
1439  mflat_noise,
1440  ordertable,
1441  order_locations,
1442  linetable[window_number-1],
1443  linetable_header,
1444  dispersion_relation,
1445  2*half_slit_length,
1446  0, /* offset is not used when method=2d */
1447  window_number,
1448  chip,
1449  blaze_corr,
1450  tilt_corr,
1451  debug_mode,
1452  parameters,
1453  subcontext,
1454  mode,
1455  ff_method,
1456  ex_method,
1457  m_method,
1458  x,
1459  x_header,
1460  fx, /* 2d-ex. output */
1461  NULL, NULL,
1462  NULL, /* Optimal-ex. output */
1463  NULL,
1464  NULL, /* Don't want resampled_spectrum,
1465  resampled_mf */
1466  NULL, /* Don't want sky spectrum */
1467  NULL, /* Don't want
1468  flatfielded_variance+header */
1469  rebinned_spectrum,
1470  rebinned_noise,
1471  rebinned_header,
1472  merged_spectrum,
1473  merged_noise,
1474  merged_header,
1475  info_tbl,
1476  NULL),
1477  "Error during reduction");
1478 
1479  if (x_header != NULL)
1480  {
1481  uves_pfits_set_hs(*x_header,
1482  uves_round_double(2*half_slit_length));
1483  }
1484  if (rebinned_header != NULL)
1485  {
1486  uves_pfits_set_hs(*rebinned_header,
1487  uves_round_double(2*half_slit_length));
1488  }
1489  if (merged_header != NULL)
1490  {
1491  uves_pfits_set_hs(*merged_header,
1492  uves_round_double(2*half_slit_length));
1493  }
1494 
1495 
1496  /* No sky-subtraction done. Just copy the merged spectra
1497  * to get the 'reduced' (i.e. sky-subtracted) spectra
1498  */
1499  check(( *reduced_spectrum = cpl_image_duplicate(*merged_spectrum),
1500  *reduced_noise = cpl_image_duplicate(*merged_noise),
1501  *reduced_rebinned_spectrum = cpl_image_duplicate(*rebinned_spectrum),
1502  *reduced_rebinned_noise = cpl_image_duplicate(*rebinned_noise)),
1503  "Error allocating reduced spectra");
1504  }
1505  break;
1506  default:
1507  assure( false, CPL_ERROR_ILLEGAL_INPUT,
1508  "Unknown extraction method: %d", ex_method);
1509  break;
1510  } /* switch extraction method optimal/simple/2d */
1511 
1512  cleanup:
1513  uves_free_image(&back_subbed);
1514  uves_free_image(&backsubbed_noise);
1515  uves_free_image(&mflat_noise);
1516  uves_free_image(&simple_extracted);
1517  uves_free_image(&simple_extracted_mf);
1518  uves_free_image(&sky_lo);
1519  uves_free_image(&sky_lo_noise);
1520  uves_free_image(&sky_hi);
1521  uves_free_image(&sky_hi_noise);
1522  uves_free_image(&sky_lo_rebinned);
1523  uves_free_image(&sky_lo_rebinned_noise);
1524  uves_free_image(&sky_hi_rebinned);
1525  uves_free_image(&sky_hi_rebinned_noise);
1526  uves_free_propertylist(&sky_lo_header);
1527  uves_free_propertylist(&sky_hi_header);
1528  uves_free_propertylist(&sky_lo_rebinned_header);
1529  uves_free_propertylist(&sky_hi_rebinned_header);
1530 
1531  cpl_free(subcontext);
1532  cpl_free(ex_method_string);
1533 
1534  if (cpl_error_get_code() != CPL_ERROR_NONE)
1535  {
1536  uves_free_image(background);
1537  uves_free_image(flatfielded_variance);
1538  uves_free_propertylist(flatfielded_variance_header);
1539  uves_free_image(resampled_spectrum);
1540  uves_free_image(resampled_mf);
1541  uves_free_image(merged_sky);
1542  uves_free_image(rebinned_spectrum);
1543  uves_free_image(rebinned_noise);
1544  uves_free_propertylist(rebinned_header);
1545 
1546  uves_free_image(merged_noise);
1547  uves_free_image(merged_spectrum);
1548  uves_free_propertylist(merged_header);
1549  }
1550 
1551  return cpl_error_get_code();
1552 }
1553 
1554 
1555 /*----------------------------------------------------------------------------*/
1565 /*----------------------------------------------------------------------------*/
1566 static polynomial *
1567 interpolate_wave(const polynomial *dispersion_relation[3],
1568  const uves_propertylist *linetable_header[3],
1569  double objoffset)
1570 {
1571  polynomial *dispersion = NULL;
1572  polynomial *q1 = NULL;
1573  polynomial *q2 = NULL;
1574  cpl_table *offset = cpl_table_new(3);
1575  int ilow, ihigh;
1576  double offset1, offset2;
1577 
1578  /* We need the sort pattern. Use a table for that */
1579  cpl_table_new_column(offset, "Index", CPL_TYPE_INT);
1580  cpl_table_new_column(offset, "Offset", CPL_TYPE_DOUBLE);
1581 
1582  {
1583  int i;
1584  bool reverse;
1585  for (i = 0; i < 3; i++) {
1586  cpl_table_set_int(offset, "Index", i, i);
1587  cpl_table_set_double(offset, "Offset", i,
1588  uves_pfits_get_offset(linetable_header[i]));
1589 
1590  uves_msg_debug("Wavecal %d offset is %f pixels", i,
1591  cpl_table_get_double(offset, "Offset", i, NULL));
1592  }
1593 
1594  reverse = false;
1595  uves_sort_table_1(offset, "Offset", reverse);
1596  }
1597 
1598  /* Find indices of the two dispersion solutions neares to the object position */
1599  if (objoffset <= cpl_table_get_double(offset, "Offset", 1, NULL))
1600  {
1601  ilow = cpl_table_get_int(offset, "Index", 0, NULL);
1602  ihigh = cpl_table_get_int(offset, "Index", 1, NULL);
1603  offset1 = cpl_table_get_double(offset, "Offset", 0, NULL);
1604  offset2 = cpl_table_get_double(offset, "Offset", 1, NULL);
1605  }
1606  else
1607  {
1608  ilow = cpl_table_get_int(offset, "Index", 1, NULL);
1609  ihigh = cpl_table_get_int(offset, "Index", 2, NULL);
1610  offset1 = cpl_table_get_double(offset, "Offset", 1, NULL);
1611  offset2 = cpl_table_get_double(offset, "Offset", 2, NULL);
1612  }
1613 
1614  uves_msg("Interpolating dispersion relation at offset = %.2f",
1615  objoffset);
1616 
1617  uves_msg_debug("Using previous solutions at %.2f and %.2f pixels",
1618  offset1, offset2);
1619 
1620  /* Fail cleanly if 2 dispersion solution were obtained at the same offset
1621  (rather than silently dividing by zero) */
1622  assure( offset1 < offset2,
1623  CPL_ERROR_DIVISION_BY_ZERO,
1624  "Dispersion solution %d offset = %.2f pixels; "
1625  "dispersion solution %d offset = %.2f pixels; cannot extrapolate",
1626  ilow, offset1,
1627  ihigh, offset2);
1628 
1629  /* Do simple linear interpolation =
1630  p = a p1 + b p2
1631  where
1632  a = (offset2 - offset) / (offset2 - offset1)
1633  b = (offset1 - offset) / (offset1 - offset2)
1634 
1635  which corrects for any line tilt to 1st order.
1636 
1637  A 2nd order line tilt correction (distortions) is probably overkill
1638  because of UVES' short slit and very straight arclines.
1639  */
1640  {
1641  double a = (offset2 - objoffset) / (offset2 - offset1);
1642  double b = (offset1 - objoffset) / (offset1 - offset2);
1643 
1644  q1 = uves_polynomial_duplicate(dispersion_relation[ilow]);
1645  uves_polynomial_rescale(q1, 0, a);
1646  /* q1 = a p1 */
1647 
1648  q2 = uves_polynomial_duplicate(dispersion_relation[ihigh]);
1649  uves_polynomial_rescale(q2, 0, b);
1650  /* q2 = b p2 */
1651 
1652  dispersion = uves_polynomial_add_2d(q1, q2);
1653  }
1654 
1655  cleanup:
1656  uves_free_table(&offset);
1659  return dispersion;
1660 }
1661 
1662 
1663 /*----------------------------------------------------------------------------*/
1742 /*----------------------------------------------------------------------------*/
1743 
1744 static cpl_error_code
1745 extract_ff_rebin_merge(cpl_image *back_subbed,
1746  cpl_image *backsubbed_noise,
1747  const uves_propertylist *backsubbed_header,
1748  const cpl_image *master_flat,
1749  cpl_image *mflat_noise,
1750  const cpl_table *ordertable,
1751  const polynomial *order_locations,
1752  const cpl_table *linetable,
1753  const uves_propertylist *linetable_header[3],
1754  const polynomial *dispersion_relation[3],
1755  double slit_length,
1756  double slit_offset,
1757  int window,
1758  enum uves_chip chip,
1759  bool blaze_correct,
1760  bool tilt_corr,
1761  bool debug_mode,
1762  const cpl_parameterlist *parameters,
1763  const char *context,
1764  const char *mode,
1765  flatfielding_method ff_method,
1766  extract_method ex_method,
1767  merge_method m_method,
1768  /* Output */
1769  cpl_image **x, uves_propertylist **x_header,
1770  cpl_image **fx,
1771  cpl_table **cosmic_mask,
1772  cpl_image **wave_map,
1773  cpl_image **flatfielded_variance,
1774  uves_propertylist **flatfielded_variance_header,
1775  cpl_image **resampled_spectrum,
1776  cpl_image **resampled_mf,
1777  cpl_image **merged_sky,
1778  cpl_image **rebinned_spectrum,
1779  cpl_image **rebinned_noise,
1780  uves_propertylist **rebinned_header,
1781  cpl_image **merged_spectrum,
1782  cpl_image **merged_noise,
1783  uves_propertylist **merged_header,
1784  cpl_table **info_tbl,
1785  cpl_table **order_trace)
1786 {
1787  cpl_image *extracted = NULL;
1788  cpl_image *extracted_noff = NULL;
1789  cpl_image *extracted_noise = NULL;
1790  cpl_image *extracted_sky = NULL; /* For optimal extraction */
1791  cpl_image *extracted_sky_noise = NULL;
1792  cpl_image *blaze_ratio = NULL; /* The (per-order normalized)
1793  ratio of blaze functions */
1794 
1795  cpl_image *cosmic_image = NULL;
1796  cpl_image *weights = NULL;
1797  cpl_table *profile_table = NULL;
1798  uves_propertylist *extracted_header = NULL;
1799 
1800  cpl_image *extracted_mf = NULL;
1801  cpl_image *extracted_mf_noise = NULL;
1802 
1803  cpl_image *rebinned_sky = NULL;
1804  cpl_image *rebinned_sky_noise = NULL;
1805  cpl_image *merged_sky_noise = NULL;
1806 
1807  polynomial *dispersion_int = NULL; /* interpolated at object position */
1808  polynomial *dispersion_int_sky = NULL; /* if sky was extracted simultaneously
1809  with the object (optimal extraction)
1810  this is the dispersion at the average
1811  sky position */
1812  cpl_table *poly_table = NULL;
1813  cpl_image *temp_image = NULL;
1814 
1815  int n_traces; /* Number of traces. Equal to 1,
1816  unless for 2d reduction */
1817  int first_abs_order, last_abs_order;
1818  int filename_window; /* The window number appended to
1819  the filenames of local products */
1820  //const char* recipe_id=make_str(UVES_SCIRED_ID);
1821  double delt1=0;
1822  double delt2=0;
1823 
1824 
1825  /* If ff_method is FF_EXTRACT, or if resampled_mf is requested,
1826  then master flat must be provided */
1827  passure((ff_method != FF_EXTRACT && resampled_mf == NULL)
1828  ||
1829  master_flat != NULL, " ");
1830 
1831  /* Blaze correction only makes sense if flat-fielding,
1832  */
1833  passure( !blaze_correct || ff_method != FF_NO, " ");
1834 
1835  passure( ex_method != EXTRACT_OPTIMAL || merged_sky != NULL, " ");
1836  passure( ex_method != EXTRACT_OPTIMAL || cosmic_mask != NULL, " ");
1837 
1838  passure(1 <= window && window <= 3, "Illegal window: %d", window);
1839 
1840  passure( (x == NULL) == (x_header == NULL) &&
1841  (x == NULL) == (fx == NULL), " ");
1842 
1843 
1844 
1845 
1846 
1847  check( uves_get_parameter(parameters, NULL,
1848  context, "merge_delt1",
1849  CPL_TYPE_DOUBLE, &delt1),
1850  "Could not read parameter delt1");
1851 
1852  check( uves_get_parameter(parameters, NULL,
1853  context, "merge_delt2",
1854  CPL_TYPE_DOUBLE, &delt2),
1855  "Could not read parameter delt2");
1856 
1857 
1858 
1859 
1860 
1861 
1862  if (ex_method == EXTRACT_OPTIMAL || ex_method == EXTRACT_2D)
1863  {
1864  /* Don't append window number if optimal/2d extraction.
1865  There's only one window in these cases, and
1866  it allows the response/efficiency recipe to save
1867  both optimally and linearly extracted spectra
1868  (without overwriting). */
1869 
1870  filename_window = -1; /* -1 means don't append window
1871  number to filename */
1872  }
1873  else
1874  {
1875  filename_window = window;
1876  }
1877 
1878  n_traces = (ex_method == EXTRACT_2D) ? uves_round_double(slit_length) : 1;
1879 
1880  check( first_abs_order = uves_pfits_get_firstabsorder(linetable_header[0]),
1881  "Could not read order numbers from line table header");
1882  check( last_abs_order = uves_pfits_get_lastabsorder (linetable_header[0]),
1883  "Could not read order numbers from line table header");
1884 
1885  if (window == 2)
1886  {
1887  uves_msg("Extracting object");
1888  }
1889  if( ff_method == FF_EXTRACT ) {
1890  check_nomsg(cosmic_image=uves_image_mflat_detect_blemishes(master_flat,
1891  backsubbed_header));
1892  }
1893 
1894  check( extracted =
1895  uves_extract(back_subbed,
1896  backsubbed_noise,
1897  backsubbed_header,
1898  ordertable,
1899  order_locations,
1900  slit_length, /* Slit length (pixels) */
1901  slit_offset, /* Slit center offset */
1902  parameters,
1903  context, /* Extraction method, kappa */
1904  mode,
1905  false, /* Don't extract partial bins */
1906  debug_mode,
1907  chip,
1908  &extracted_header, /* Spectrum header */
1909  &extracted_noise, /* Spectrum noise */
1910  /* Optimal extraction parameters: */
1911  &extracted_sky, /* Sky */
1912  &extracted_sky_noise, /* Sky */
1913  cosmic_mask,
1914  &cosmic_image,
1915  (debug_mode) ?
1916  &profile_table : NULL,
1917  &weights, /* If optimal, weights
1918  are defined */
1919  info_tbl,
1920  order_trace),
1921  "Error extracting spectrum");
1922 
1923  if (x != NULL) {
1924  *x = cpl_image_duplicate(extracted);
1925  *x_header = uves_propertylist_duplicate(extracted_header);
1926  }
1927 
1928  if (ex_method == EXTRACT_OPTIMAL) {
1929  uves_msg_low("%" CPL_SIZE_FORMAT " hot pixels were detected during optimal extraction",
1930  cpl_table_get_nrow(*cosmic_mask));
1931 
1932  if (cpl_table_get_nrow(*cosmic_mask) > 0) {
1933  check( uves_plot_table(*cosmic_mask, "X", "Y",
1934  "%" CPL_SIZE_FORMAT "hot/cold pixels",
1935  cpl_table_get_nrow(*cosmic_mask)),
1936  "Plotting failed");
1937  }
1938  }
1939 
1940  /* Save extracted spectrum + noise + sky + noise, and
1941  if optimal: weightmap + crmask + order_trace */
1942  if (debug_mode) {
1943  /* This (bit ugly) code selects filename
1944  * and description string depending on
1945  * whether flat-fielding was already done
1946  */
1947 
1948 
1949 
1951  backsubbed_header,
1952  "^ESO ",0),"error copying hierarch keys");
1953 
1954 
1955  check( uves_save_image_local((ff_method == FF_PIXEL) ?
1956  "Extracted, flatfielded spectrum" :
1957  "Extracted spectrum",
1958  (ff_method == FF_PIXEL) ?
1959  "xfb" : "xb",
1960  extracted, chip, -1,
1961  filename_window, extracted_header, true),
1962  "Error saving extracted%s spectrum",
1963  (ff_method == FF_PIXEL) ? ", flatfielded" : "");
1964 
1965  check( uves_save_image_local((ff_method == FF_PIXEL) ?
1966  "Extracted, flatfielded spectrum noise" :
1967  "Extracted spectrum noise",
1968  (ff_method == FF_PIXEL) ?
1969  "errxfb" : "errxb",
1970  extracted_noise, chip, -1,
1971  filename_window, extracted_header, true),
1972  "Error saving noise of extracted%s spectrum",
1973  (ff_method == FF_PIXEL) ? ", flatfielded" : "");
1974 
1975  if (extracted_sky != NULL)
1976  {
1977  check( uves_save_image_local((ff_method == FF_PIXEL) ?
1978  "Extracted, flatfielded sky" :
1979  "Extracted sky",
1980  (ff_method == FF_PIXEL) ?
1981  "xfsky" : "xsky",
1982  extracted_sky, chip, -1,
1983  filename_window, extracted_header, true),
1984  "Error saving extracted%s sky",
1985  (ff_method == FF_PIXEL) ? ", flatfielded" : "");
1986 
1987  check( uves_save_image_local((ff_method == FF_PIXEL) ?
1988  "Noise of extracted, flatfielded sky" :
1989  "Noise of extracted sky",
1990  (ff_method == FF_PIXEL) ?
1991  "errxfsky" : "errxsky",
1992  extracted_sky_noise, chip, -1,
1993  filename_window, extracted_header, true),
1994  "Error saving extracted%s sky noise",
1995  (ff_method == FF_PIXEL) ? ", flatfielded" : "");
1996  }
1997 
1998  if (ex_method == EXTRACT_OPTIMAL)
1999  {
2000  check( uves_save_image_local("Optimal extraction weights",
2001  "weights",
2002  weights, chip, -1,
2003  filename_window,
2004  backsubbed_header, true),
2005  "Error saving weights map");
2006 
2007  check( uves_save_table_local("Cosmic ray table", "crmask",
2008  *cosmic_mask, chip, -1,
2009  filename_window,
2010  backsubbed_header, NULL),
2011  "Error saving cosmic ray mask");
2012 
2013  check( uves_save_image_local("Cosmic ray image", "crimage",
2014  cosmic_image, chip, -1,
2015  filename_window,
2016  backsubbed_header, true),
2017  "Error saving cosmic ray mask");
2018 
2019  if (profile_table != NULL)
2020  {
2021  check( uves_save_table_local("Profile table", "profile",
2022  profile_table, chip, -1,
2023  filename_window,
2024  backsubbed_header, NULL),
2025  "Error saving profile table");
2026  }
2027  }
2028  }
2029 
2030  /* Extract + resample master flat, only if necessary */
2031  if (master_flat != NULL && (ff_method == FF_EXTRACT || resampled_mf != NULL))
2032  {
2033  uves_msg("Extracting master flat field");
2034 
2035  /* Extract the master flat spectrum.
2036  If object was extracted with method=optimal,
2037  then temporarily set method=weighted */
2038 
2039  if (ex_method == EXTRACT_OPTIMAL)
2040  {
2041  const char *temp_method = "weighted";
2042 
2043  /* Cast to non-const is okay. After extraction, the
2044  parameter is set to 'optimal' (see below), so there
2045  is not net change (unless the extraction fails, in
2046  which case parameter list will change).
2047  */
2048  check( uves_set_parameter((cpl_parameterlist *) parameters,
2049  context, UVES_EXTRACT_ID ".method",
2050  CPL_TYPE_STRING, &temp_method),
2051  "Error setting extraction method to '%s'", temp_method);
2052  }
2053 
2054  check( extracted_mf =
2055  uves_extract((cpl_image *)master_flat, /* const-cast ok,
2056  outlier pixels are
2057  flagged bad only in
2058  optimal extraction */
2059  mflat_noise,
2060  NULL, /* FITS header */
2061  ordertable,
2062  order_locations,
2063  slit_length, /* Slit length (pixels) */
2064  slit_offset, /* Slit center offset */
2065  parameters, context, /* Extraction method,
2066  kappa */
2067  mode,
2068  false, /* Extraction partial bins? */
2069  debug_mode,
2070  chip,
2071  NULL, /* Spectrum header */
2072  &extracted_mf_noise, /* Spectrum noise */
2073  NULL,
2074  NULL, /* Sky */
2075  NULL,
2076  NULL,
2077  NULL, /* Cosmic ray table/image,
2078  profile */
2079  &weights, /* Weights are used unchanged */
2080  NULL,
2081  NULL),
2082  "Error extracting master flat spectrum");
2083 
2084  /* Reset parameter to previous value
2085  (parameter list is declared const) */
2086  if (ex_method == EXTRACT_OPTIMAL) {
2087  const char *method = "optimal";
2088 
2089  /* Cast to non-const is okay. On successful termination,
2090  there is no net change in the parameter list (see above). */
2091  check( uves_set_parameter((cpl_parameterlist *) parameters,
2092  context, UVES_EXTRACT_ID ".method",
2093  CPL_TYPE_STRING, &method),
2094  "Error resetting extraction method to '%s'", method);
2095  }
2096 
2097  if (debug_mode) {
2098  double ff_mean;
2099 
2100  /* Save normalized master flat spectrum + noise */
2101  uves_free_image(&temp_image);
2102 
2103  ff_mean = cpl_image_get_mean(extracted_mf);
2104 
2105  check( temp_image =
2106  cpl_image_divide_scalar_create(extracted_mf, ff_mean),
2107  "Could not normalize master flat spectrum");
2108 
2109  check( uves_save_image_local("Normalized master flat spectrum",
2110  "xmf",
2111  temp_image, chip, -1,
2112  filename_window, extracted_header, true),
2113  "Error saving image");
2114 
2115  /* Also rescale noise before saving */
2116  uves_free_image(&temp_image);
2117  check( temp_image =
2118  cpl_image_divide_scalar_create(extracted_mf_noise,
2119  ff_mean),
2120  "Could not rescale master flat noise spectrum");
2121 
2122  check( uves_save_image_local("Noise of normalized "
2123  "master flat spectrum", "errxmf",
2124  temp_image, chip, -1,
2125  filename_window, extracted_header, true),
2126  "Error saving image");
2127 
2128  uves_free_image(&temp_image);
2129  }
2130 
2131  /* Rebin master flat */
2132  if (resampled_mf != NULL) {
2133  uves_msg("Rebinning master flat spectrum");
2134 
2135 
2136  /* Use dispersion solution obtained at slit center
2137  * (high accuracy is non-essential here, the resampled
2138  * flat-field is not used in further processing
2139  */
2140 
2141  check( *resampled_mf = uves_rebin(extracted_mf,
2142  parameters, context,
2143  linetable,
2144  dispersion_relation[1],
2145  first_abs_order,
2146  last_abs_order,
2147  n_traces,
2148  false,
2149  false,
2150  rebinned_header),
2151  "Error resampling master flat");
2152 
2153 
2154  check( *wave_map = uves_get_wave_map(back_subbed,
2155  context,
2156  parameters,
2157  ordertable,
2158  linetable,
2159  order_locations,
2160  dispersion_relation[1],
2161  first_abs_order,
2162  last_abs_order,
2163  slit_length),
2164  "Error generating wave map");
2165 
2166  check( uves_save_image_local("Wave map",
2167  "wave_map",
2168  *wave_map, chip, -1,
2169  filename_window,
2170  extracted_header, true),
2171  "Error saving wavemap image");
2172 
2173 
2174 
2175  if (debug_mode) {
2176 
2178  backsubbed_header,
2179  "^ESO ", 0),"error copying hierarch keys");
2180 
2181 
2182  check( uves_save_image_local("Resampled master flat spectrum",
2183  "wxmf", *resampled_mf, chip, -1,
2184  filename_window, *rebinned_header, true),
2185  "Error saving image");
2186  }
2187  }
2188  } /* Extract, rebin master flat */
2189 
2190  /* If we didn't already, divide by the flat field */
2191  if (ff_method == FF_EXTRACT)
2192  {
2193 
2194  uves_msg("Dividing by normalized master flat-field (method = extract)");
2195 
2196  /* Remember this for later */
2197  extracted_noff = cpl_image_duplicate(extracted);
2198 
2199  check( uves_flatfielding(extracted , extracted_noise,
2200  extracted_mf, extracted_mf_noise),
2201  "Could not perform flat-fielding");
2202 
2203  if (extracted_sky != NULL)
2204  {
2205  check( uves_flatfielding(extracted_sky, extracted_sky_noise,
2206  extracted_mf, extracted_mf_noise),
2207  "Could not perform flat-fielding");
2208  }
2209 
2210  /* Save flat-fielded spectrum + noise */
2211  if (debug_mode)
2212  {
2213  check( uves_save_image_local("Flat-fielded spectrum", "fxb",
2214  extracted, chip, -1, filename_window,
2215  extracted_header, true),
2216  "Error saving image");
2217 
2218  check( uves_save_image_local("Flat-fielded spectrum noise",
2219  "errfxb", extracted_noise, chip,
2220  -1, filename_window, extracted_header, true),
2221  "Error saving noise of flat-fielded image");
2222  }
2223 
2224  if (debug_mode && extracted_sky != NULL)
2225  {
2226  check( uves_save_image_local("Flat-fielded sky", "fxsky",
2227  extracted_sky, chip, -1,
2228  filename_window, extracted_header, true),
2229  "Error saving image");
2230 
2231  check( uves_save_image_local("Flat-fielded sky noise", "errfxsky",
2232  extracted_sky_noise, chip, -1,
2233  filename_window, extracted_header, true),
2234  "Error saving noise of flat-fielded image");
2235  }
2236  }
2237 
2238  if (fx != NULL)
2239  {
2240  *fx = cpl_image_duplicate(extracted);
2241  }
2242 
2243  /* Variance of flat-fielded, pre-rebinned spectrum
2244  is a product of science recipe (for whatever reason...) */
2245  if (flatfielded_variance != NULL)
2246  {
2247 
2248  check( *flatfielded_variance =
2249  cpl_image_multiply_create(extracted_noise,
2250  extracted_noise),
2251  "Error creating variance of flatfielded spectrum");
2252 
2253  passure(flatfielded_variance_header != NULL, " ");
2254  check( *flatfielded_variance_header =
2255  uves_propertylist_duplicate(extracted_header),
2256  "Could not copy extracted spectrum header");
2257  }
2258 
2259  if (blaze_correct)
2260  {
2261  if (ex_method == EXTRACT_2D)
2262  {
2263  /* It requires an extracted spectrum which we don't have in 2d mode */
2264  uves_msg_low("Skipping blaze function correction for 2d extraction mode");
2265  }
2266  else
2267  {
2268  uves_msg("Calculating blaze function correction");
2269 
2270  check( blaze_ratio = uves_get_blaze_ratio(extracted, extracted_noise),
2271  "Error calculating blaze function correction");
2272 
2273  uves_msg("Applying blaze function correction");
2274 
2275  check(( cpl_image_divide(extracted , blaze_ratio),
2276  cpl_image_divide(extracted_noise, blaze_ratio)),
2277  "Error applying blaze function correction");
2278 
2279  if (extracted_sky != NULL) /* If sky was extracted (optimal) */
2280  {
2281  check(( cpl_image_multiply(extracted_sky, blaze_ratio),
2282  cpl_image_multiply(extracted_sky_noise, blaze_ratio)),
2283  "Error applying blaze function correction");
2284  }
2285  }
2286  }
2287 
2288  /* Rebin from (x, order) to (wavelength, order) */
2289  uves_msg("Rebinning spectrum");
2290  if (ex_method == EXTRACT_2D) {
2291  if (tilt_corr) {
2292  uves_msg_warning("Line tilt correction in rebinning "
2293  "of 2d spectra is unsupported");
2294  }
2295  dispersion_int = uves_polynomial_duplicate(dispersion_relation[window-1]);
2296  }
2297  else if (tilt_corr) {
2298  double objoffset;
2299 
2300  if (info_tbl != NULL) {
2301  objoffset = cpl_table_get_column_median(*info_tbl, "ObjPosOnSlit");
2302  /* This is the object position measured from the bottom of
2303  the of specified extraction window.
2304  Need to convert this to the same coordinates as used in the wavecal.
2305  */
2306 
2307  uves_msg_debug("Object position (from bottom of extraction window) = %.2f pixels",
2308  objoffset);
2309 
2310  objoffset -= slit_length / 2;
2311  /* Now wrt middle of specified window */
2312 
2313  objoffset += slit_offset;
2314  /* Now wrt order trace center */
2315 
2316  uves_msg_debug("Object position (from slit center) = %.2f pixels",
2317  objoffset);
2318  }
2319  else {
2320  /* Sky windows */
2321  uves_msg_debug("Object offset not measured during extraction, "
2322  "using %.2f pixels", slit_offset);
2323  objoffset = slit_offset;
2324  }
2325 
2326  check( dispersion_int = interpolate_wave(dispersion_relation,
2327  linetable_header,
2328  objoffset),
2329  "Could not interpolate dispersion solutions");
2330 
2331  if (debug_mode) {
2332  check( poly_table = uves_polynomial_convert_to_table(dispersion_int),
2333  "Error converting polynomial to table");
2334 
2335  check( uves_save_table_local("Interpolated dispersion relation",
2336  "intdisp",
2337  poly_table, chip, -1,
2338  filename_window, backsubbed_header, NULL),
2339  "Error saving interpolated dispersion solution");
2340  }
2341  }
2342  else {
2343  dispersion_int = uves_polynomial_duplicate(dispersion_relation[window-1]);
2344  }
2345 
2346  uves_free_propertylist(rebinned_header);
2347  check( *rebinned_spectrum = uves_rebin(extracted,
2348  parameters, context,
2349  linetable, dispersion_int,
2350  first_abs_order,
2351  last_abs_order,
2352  n_traces,
2353  false,
2354  false,
2355  rebinned_header),
2356  "Could not rebin spectrum");
2357 
2358  uves_msg("Rebinning spectrum noise");
2359 
2360  /* As in UVES/MIDAS the noise spectrum is rebinned to the same
2361  * level. It is not propagated using error propagation formula.
2362  * In other words, after this step, the noise level no longer
2363  * describes the empirical noise actually observed in the spectrum
2364  * (which does change during rebinning depending on the bin width)
2365  */
2366 
2367  {
2368  bool threshold_to_positive = true;
2369 
2370  uves_free_propertylist(rebinned_header);
2371  check( *rebinned_noise = uves_rebin(extracted_noise,
2372  parameters, context,
2373  linetable, dispersion_int,
2374  first_abs_order,
2375  last_abs_order,
2376  n_traces,
2377  threshold_to_positive,
2378  true,
2379  rebinned_header),
2380  "Could not rebin spectrum noise");
2381  }
2382 
2383  if (extracted_sky != NULL) {
2384  uves_msg("Rebinning sky spectrum");
2385 
2386  if (tilt_corr) {
2387  /* Optimal extraction extracts an average of the sky
2388  in the entire extraction window.
2389 
2390  Calibrate the sky spectrum using the dispersion solution
2391  at the extraction window center, i.e. at offset = slit_offset
2392  */
2393 
2394  check( dispersion_int_sky = interpolate_wave(dispersion_relation,
2395  linetable_header,
2396  slit_offset),
2397  "Could not interpolate dispersion solutions");
2398  }
2399  else {
2400  /* Use middle solution */
2401  dispersion_int_sky = uves_polynomial_duplicate(dispersion_relation[1]);
2402  }
2403 
2404  /* Re-use the same rebinned_header */
2405  uves_free_propertylist(rebinned_header);
2406  check( rebinned_sky = uves_rebin(extracted_sky,
2407  parameters, context,
2408  linetable, dispersion_int_sky,
2409  first_abs_order,
2410  last_abs_order,
2411  n_traces,
2412  false,
2413  false,
2414  rebinned_header),
2415  "Could not rebin sky noise");
2416 
2417  uves_msg("Rebinning sky spectrum noise");
2418 
2419  uves_free_propertylist(rebinned_header);
2420  check( rebinned_sky_noise = uves_rebin(extracted_sky_noise,
2421  parameters, context,
2422  linetable, dispersion_int_sky,
2423  first_abs_order,
2424  last_abs_order,
2425  n_traces,
2426  true,
2427  true,
2428  rebinned_header),
2429  "Could not rebin sky noise");
2430  }
2431 
2432  /* Save rebinned spectrum + noise */
2433  if (debug_mode)
2434  {
2435  const char *filename = "";
2436  const char *filename_err = "";
2437  const char *filename_sky = "";
2438  const char *filename_sky_err = "";
2439  if (ff_method == FF_PIXEL)
2440  {
2441  filename = "wxfb";
2442  filename_err = "errwxfb";
2443  filename_sky = "wxfsky";
2444  filename_sky_err = "errwxfsky";
2445  }
2446  else if (ff_method == FF_EXTRACT)
2447  {
2448  filename = "wfxb";
2449  filename_err = "errwfxb";
2450  filename_sky = "wfxsky";
2451  filename_sky_err = "errwfxsky";
2452  }
2453  else if (ff_method == FF_NO)
2454  {
2455  filename = "wxb";
2456  filename_err = "errwxb";
2457  filename_sky = "wxsky";
2458  filename_sky_err = "errwxsky";
2459  }
2460  else
2461  {
2462  passure( false, "Unknown ff_method: %d", ff_method);
2463  }
2464 
2466  backsubbed_header,
2467  "^ESO ", 1),"error copying hierarch keys");
2468 
2469 
2470  check( uves_save_image_local("Rebinned spectrum",
2471  filename, *rebinned_spectrum,
2472  chip, -1, filename_window, *rebinned_header, true),
2473  "Error saving image");
2474 
2475  check( uves_save_image_local("Noise of rebinned spectrum", filename_err,
2476  *rebinned_noise, chip, -1, filename_window,
2477  *rebinned_header, true),
2478  "Error saving image");
2479 
2480  if (extracted_sky != NULL)
2481  {
2482  check( uves_save_image_local("Rebinned sky", filename_sky,
2483  rebinned_sky, chip, -1,
2484  filename_window, *rebinned_header, true),
2485  "Error saving image");
2486 
2487  check( uves_save_image_local("Noise of rebinned sky",
2488  filename_sky_err,
2489  rebinned_sky_noise, chip, -1,
2490  filename_window, *rebinned_header, true),
2491  "Error saving image");
2492  }
2493  }
2494 
2495  /* We also need to produce the rebinned-immediately-after-extraction
2496  (but non flat-fielded) spectrum,
2497  which is a product of the science recipe.
2498  This is trivial unless ff_method is FF_EXTRACT
2499  */
2500  if (resampled_spectrum != NULL) /* Not for sky windows */
2501  {
2502  if (ff_method == FF_EXTRACT)
2503  {
2504  /* Rebin the extracted spectrum (before flatfielding) */
2505  uves_msg("Rebinning pre-flatfielded spectrum");
2506 
2507  uves_free_propertylist(rebinned_header);
2508  check( *resampled_spectrum =
2509  uves_rebin(extracted_noff,
2510  parameters, context,
2511  linetable, dispersion_int,
2512  first_abs_order,
2513  last_abs_order,
2514  n_traces,
2515  false,
2516  false,
2517  rebinned_header),
2518  "Could not rebin spectrum");
2519 
2520  if (debug_mode) {
2521 
2522  check( uves_save_image_local("Rebinned, extracted spectrum",
2523  "wx", *resampled_spectrum,
2524  chip, -1, filename_window,
2525  *rebinned_header, true),
2526  "Error saving image");
2527  }
2528 
2529  }
2530  else
2531  {
2532  check( *resampled_spectrum = cpl_image_duplicate(*rebinned_spectrum),
2533  "Error copying rebinned spectrum");
2534  }
2535  }
2536 
2537  /* Merge orders to 1D spectrum */
2538  if (extracted_sky != NULL)
2539  {
2540  uves_msg("Merging sky");
2541  check( *merged_sky = uves_merge_orders(rebinned_sky,
2542  rebinned_sky_noise,
2543  *rebinned_header,
2544  m_method,
2545  n_traces,
2546  merged_header,
2547  delt1,delt2,chip,
2548  &merged_sky_noise),
2549  "Error merging sky");
2550  }
2551 
2552  uves_msg("Merging spectrum");
2553  uves_free_propertylist(merged_header);
2554  check( *merged_spectrum = uves_merge_orders(*rebinned_spectrum,
2555  *rebinned_noise,
2556  *rebinned_header,
2557  m_method,
2558  n_traces,
2559  merged_header,
2560  delt1,delt2,chip,
2561  merged_noise),
2562  "Error merging orders");
2563 
2565  backsubbed_header,
2566  "^ESO ", 0),"error copying hierarch keys");
2567 
2568  if (debug_mode)
2569  {
2570  check( uves_save_image_local("Merged spectrum", "m", *merged_spectrum,
2571  chip, -1, filename_window, *merged_header, true),
2572  "Error saving image");
2573 
2574  check( uves_save_image_local("Noise of merged spectrum", "errm",
2575  *merged_noise, chip, -1,
2576  filename_window, *merged_header, true),
2577  "Error saving image");
2578  }
2579 
2580  if (debug_mode && extracted_sky != NULL)
2581  {
2582  check( uves_save_image_local("Merged sky", "msky", *merged_sky,
2583  chip, -1,
2584  filename_window, *merged_header, true),
2585  "Error saving image");
2586 
2587  check( uves_save_image_local("Noise of merged sky", "errmsky",
2588  merged_sky_noise, chip, -1,
2589  filename_window, *merged_header, true),
2590  "Error saving image");
2591  }
2592 
2593  cleanup:
2594  uves_free_image(&extracted);
2595  uves_free_image(&extracted_noff);
2596  uves_free_image(&extracted_noise);
2597  uves_free_image(&extracted_sky);
2598  uves_free_image(&extracted_sky_noise);
2599  uves_free_image(&cosmic_image);
2600  uves_free_image(&blaze_ratio);
2601  uves_free_image(&weights);
2602  uves_polynomial_delete(&dispersion_int);
2603  uves_polynomial_delete(&dispersion_int_sky);
2604  uves_free_table(&poly_table);
2605  uves_free_propertylist(&extracted_header);
2606  uves_free_table(&profile_table);
2607  uves_free_image(&extracted_mf);
2608  uves_free_image(&extracted_mf_noise);
2609  uves_free_image(&rebinned_sky);
2610  uves_free_image(&rebinned_sky_noise);
2611  uves_free_image(&merged_sky_noise);
2612 
2613  uves_free_image(&temp_image);
2614 
2615  return cpl_error_get_code();
2616 }
2617 
2618 
2619 /*----------------------------------------------------------------------------*/
2655 /*----------------------------------------------------------------------------*/
2656 
2657 static cpl_image *
2658 subtract_sky(cpl_image *rebinned_obj, cpl_image *rebinned_obj_noise,
2659  uves_propertylist *rebinned_obj_header,
2660  const cpl_image *rebinned_sky1, const cpl_image *rebinned_sky1_noise,
2661  const uves_propertylist *rebinned_sky1_header,
2662  const cpl_image *rebinned_sky2, const cpl_image *rebinned_sky2_noise,
2663  const uves_propertylist *rebinned_sky2_header,
2664  cpl_image **merged_obj, cpl_image **merged_obj_noise,
2665  uves_propertylist *merged_obj_header,
2666  const cpl_image *merged_sky1, const cpl_image *merged_sky1_noise,
2667  const uves_propertylist *merged_sky1_header,
2668  const cpl_image *merged_sky2, const cpl_image *merged_sky2_noise,
2669  const uves_propertylist *merged_sky2_header,
2670  double obj_slit, double sky1_slit, double sky2_slit)
2671 {
2672  double wavestep;
2673  int norders;
2674 
2675  cpl_image *merged_sky = NULL; /* Result */
2676 
2677  passure( rebinned_obj != NULL, " ");
2678  passure( rebinned_obj_noise != NULL, " ");
2679  passure( rebinned_obj_header != NULL, " ");
2680  passure( merged_obj != NULL, " ");
2681  passure( merged_obj_noise != NULL, " ");
2682  passure( merged_obj_header != NULL, " ");
2683  passure( *merged_obj != NULL, " ");
2684  passure( *merged_obj_noise != NULL, " ");
2685  /* Sky spectra may be NULL (if not extracted) */
2686 
2687  check( wavestep = uves_pfits_get_cdelt1(rebinned_obj_header),
2688  "Error reading wavelength step");
2689  norders = cpl_image_get_size_y(rebinned_obj);
2690 
2691  /* Do some consistency checking
2692  (that 'wavestep' and 'norders' is same for all spectra) */
2693  assure((rebinned_sky1 == NULL || norders == cpl_image_get_size_y(rebinned_sky1)) &&
2694  (rebinned_sky2 == NULL || norders == cpl_image_get_size_y(rebinned_sky2)),
2695  CPL_ERROR_ILLEGAL_INPUT,
2696  "Different number of orders in object/sky spectra: obj = %d, "
2697  "sky1 = %" CPL_SIZE_FORMAT ", sky3 = %" CPL_SIZE_FORMAT "",
2698  norders,
2699  cpl_image_get_size_y(rebinned_sky1),
2700  cpl_image_get_size_y(rebinned_sky2));
2701 
2702  if (rebinned_sky1 != NULL)
2703  {
2704  double wavestep1;
2705  check( wavestep1 = uves_pfits_get_cdelt1(rebinned_sky1_header),
2706  "Error reading wavelength step");
2707  assure( fabs(wavestep1 - wavestep) / wavestep < 0.01,
2708  CPL_ERROR_ILLEGAL_INPUT,
2709  "Different bin widths: sky1 = %f ; obj = %f",
2710  wavestep1, wavestep);
2711  }
2712  if (rebinned_sky2 != NULL)
2713  {
2714  double wavestep2;
2715  check( wavestep2 = uves_pfits_get_cdelt1(rebinned_sky2_header),
2716  "Error reading wavelength step");
2717  assure( fabs(wavestep2 - wavestep) / wavestep < 0.01,
2718  CPL_ERROR_ILLEGAL_INPUT,
2719  "Different bin widths: sky3 = %f ; obj = %f",
2720  wavestep2, wavestep);
2721  }
2722 
2723  /* Subtract sky (rebinned spectrum) */
2724  {
2725  int order;
2726  for (order = 1; order <= norders; order++)
2727  {
2728  double obj_start , obj_end;
2729  double sky1_start , sky1_end;
2730  double sky2_start , sky2_end;
2731  double common_start, common_end;
2732 
2733  check( obj_start = uves_pfits_get_wstart(rebinned_obj_header, order),
2734  "Error reading start wavelength for order #%d", order);
2735  check( obj_end = uves_pfits_get_wend (rebinned_obj_header, order),
2736  "Error reading end wavelength for order #%d", order);
2737 
2738  if (rebinned_sky1 != NULL)
2739  {
2740  check( sky1_start =
2741  uves_pfits_get_wstart(rebinned_sky1_header, order),
2742  "Error reading start wavelength for order #%d", order);
2743  check( sky1_end =
2744  uves_pfits_get_wend (rebinned_sky1_header, order),
2745  "Error reading end wavelength for order #%d", order);
2746  }
2747  else
2748  {
2749  sky1_start = obj_start;
2750  sky1_end = obj_end;
2751  }
2752 
2753  if (rebinned_sky2 != NULL)
2754  {
2755  check( sky2_start =
2756  uves_pfits_get_wstart(rebinned_sky2_header, order),
2757  "Error reading start wavelength for order #%d", order);
2758  check( sky2_end =
2759  uves_pfits_get_wend (rebinned_sky2_header, order),
2760  "Error reading end wavelength for order #%d", order);
2761  }
2762  else
2763  {
2764  sky2_start = obj_start;
2765  sky2_end = obj_end;
2766  }
2767 
2768  check( merged_sky =
2769  subtract_sky_row(rebinned_obj , rebinned_obj_noise ,
2770  obj_start , obj_end, obj_slit,
2771  rebinned_sky1, rebinned_sky1_noise,
2772  sky1_start, sky1_end, sky1_slit,
2773  rebinned_sky2, rebinned_sky2_noise,
2774  sky2_start, sky2_end, sky2_slit,
2775  order, wavestep, &common_start,
2776  &common_end),
2777  "Could not subtract sky for rebinned spectrum order #%d", order);
2778  uves_free_image(&merged_sky);
2779 
2780  check( uves_pfits_set_wstart(rebinned_obj_header, order, common_start),
2781  "Error updating start wavelength for order #%d", order);
2782  check( uves_pfits_set_wend (rebinned_obj_header, order, common_end ),
2783  "Error updating start wavelength for order #%d", order);
2784  }
2785  }
2786 
2787  /* Subtract sky (merged spectrum) */
2788  {
2789  double obj_start , obj_end;
2790  double sky1_start , sky1_end;
2791  double sky2_start , sky2_end;
2792  double common_start, common_end;
2793 
2794  obj_start = uves_pfits_get_crval1(merged_obj_header);
2795  obj_end = obj_start + wavestep * (cpl_image_get_size_x(*merged_obj) - 1);
2796 
2797  if (merged_sky1 != NULL)
2798  {
2799  sky1_start = uves_pfits_get_crval1(merged_sky1_header);
2800  sky1_end = sky1_start +
2801  wavestep * (cpl_image_get_size_x(merged_sky1) - 1);
2802  }
2803  else
2804  {
2805  sky1_start = obj_start;
2806  sky1_end = obj_end;
2807  }
2808 
2809  if (merged_sky2 != NULL)
2810  {
2811  sky2_start = uves_pfits_get_crval1(merged_sky2_header);
2812  sky2_end = sky2_start +
2813  wavestep * (cpl_image_get_size_x(merged_sky2) - 1);
2814  }
2815  else
2816  {
2817  sky2_start = obj_start;
2818  sky2_end = obj_end;
2819  }
2820 
2821  /* Subtract sky for image row 1 (the only row in the image) */
2822  check( merged_sky = subtract_sky_row(*merged_obj, *merged_obj_noise,
2823  obj_start , obj_end, obj_slit,
2824  merged_sky1, merged_sky1_noise,
2825  sky1_start, sky1_end, sky1_slit,
2826  merged_sky2, merged_sky2_noise,
2827  sky2_start, sky2_end, sky2_slit,
2828  1, wavestep, &common_start,
2829  &common_end),
2830  "Error subtracting sky of merged spectrum");
2831 
2832  check( uves_pfits_set_crval1(merged_obj_header, common_start),
2833  "Could not update start wavelength");
2834 
2835  /* Make sure that the last bin corresponds to 'common_end' wavelength */
2836  check( uves_crop_image(merged_obj,
2837  1, 1,
2838  1 + uves_round_double((common_end -
2839  common_start)/wavestep),
2840  1),
2841  "Error cropping merged spectrum");
2842 
2843  check( uves_crop_image(merged_obj_noise,
2844  1, 1,
2845  1 + uves_round_double((common_end -
2846  common_start)/wavestep),
2847  1),
2848  "Error cropping merged spectrum noise");
2849 
2850  if (merged_sky != NULL)
2851  {
2852  /* The image header also applies for the sky */
2853  assure( cpl_image_get_size_x(merged_sky) ==
2854  cpl_image_get_size_x(*merged_obj), CPL_ERROR_ILLEGAL_OUTPUT,
2855  "Sky and object spectrum sizes differ, "
2856  "sky = %" CPL_SIZE_FORMAT " bins, obj = %" CPL_SIZE_FORMAT " bins",
2857  cpl_image_get_size_x(merged_sky),
2858  cpl_image_get_size_x(*merged_obj));
2859  }
2860  }
2861 
2862  cleanup:
2863  if (cpl_error_get_code() != CPL_ERROR_NONE)
2864  {
2865  uves_free_image(&merged_sky);
2866  }
2867  return merged_sky;
2868 }
2869 
2870 /*----------------------------------------------------------------------------*/
2902 /*----------------------------------------------------------------------------*/
2903 
2904 static cpl_image *
2905 subtract_sky_row(cpl_image *obj, cpl_image *obj_noise,
2906  double obj_start, double obj_end, double obj_slit,
2907  const cpl_image *sky1, const cpl_image *sky1_noise,
2908  double sky1_start, double sky1_end, double sky1_slit,
2909  const cpl_image *sky2, const cpl_image *sky2_noise,
2910  double sky2_start, double sky2_end, double sky2_slit,
2911  int row, double wavestep,
2912  double *common_start, double *common_end)
2913 {
2914  int first_bin_obj;
2915  int first_bin_sky1;
2916  int first_bin_sky2;
2917  int nbins;
2918  cpl_image *common_obj = NULL; /* Extract the common wavelength range ... */
2919  cpl_image *common_sky1 = NULL; /* ... to these 1D images */
2920  cpl_image *common_sky2 = NULL;
2921  cpl_image *common_obj_noise = NULL;
2922  cpl_image *common_sky1_noise = NULL;
2923  cpl_image *common_sky2_noise = NULL;
2924  bool is_good1, is_good2; /* Do the two sky images contain valid pixels? */
2925 
2926  cpl_image *common_sky = NULL; /* The combined sky spectrum normalized
2927  to object slit length (returned) */
2928  cpl_image *common_sky_noise = NULL;
2929 
2930  cpl_image *temp = NULL;
2931 
2932  *common_start = uves_max_double(obj_start, uves_max_double(sky1_start, sky2_start));
2933  *common_end = uves_min_double(obj_end , uves_min_double(sky1_end , sky2_end ));
2934 
2935  if (*common_start <= *common_end)
2936  {
2937  nbins = 1 + uves_round_double((*common_end - *common_start) / wavestep);
2938 
2939  uves_msg_debug("Lower sky range: %f - %f w.l.u.", sky1_start, sky1_end);
2940  uves_msg_debug("Upper sky range: %f - %f w.l.u.", sky2_start, sky2_end);
2941  uves_msg_debug("Object sky range: %f - %f w.l.u.", obj_start, obj_end);
2942  uves_msg_debug("Sky/object common wavelength range in order %d: "
2943  "%f - %f w.l.u. (%d bins)",
2944  row, *common_start, *common_end, nbins);
2945 
2946  first_bin_obj = 1 + uves_round_double((*common_start - obj_start )/wavestep);
2947  first_bin_sky1 = 1 + uves_round_double((*common_start - sky1_start)/wavestep);
2948  first_bin_sky2 = 1 + uves_round_double((*common_start - sky2_start)/wavestep);
2949 
2950  /* Extract common bins, normalize sky windows to object slit length */
2951  check( common_obj = cpl_image_extract(obj,
2952  first_bin_obj, row,
2953  first_bin_obj + nbins-1, row),
2954  "Error extracting common rows (object)");
2955 
2956  check( common_obj_noise = cpl_image_extract(obj_noise,
2957  first_bin_obj, row,
2958  first_bin_obj + nbins-1, row),
2959  "Error extracting common rows (object noise)");
2960 
2961  if (sky1 != NULL)
2962  {
2963  check( common_sky1 =
2964  cpl_image_extract(sky1,
2965  first_bin_sky1, row,
2966  first_bin_sky1 + nbins-1, row),
2967  "Error extracting common rows (lower sky)");
2968 
2969  check( common_sky1_noise =
2970  cpl_image_extract(sky1_noise,
2971  first_bin_sky1, row,
2972  first_bin_sky1 + nbins-1, row),
2973  "Error extracting common rows (lower sky noise)");
2974 
2975  check(( cpl_image_multiply_scalar(common_sky1 , obj_slit / sky1_slit),
2976  cpl_image_multiply_scalar(common_sky1_noise, obj_slit / sky1_slit)),
2977  "Error normalizing sky flux");
2978 
2979  is_good1 =
2980  cpl_image_count_rejected(common_sky1) <
2981  cpl_image_get_size_x(common_sky1)*
2982  cpl_image_get_size_y(common_sky1) &&
2983  /* Note order of evaluation. cpl_image_get_min() would fail if
2984  there were no good pixels */
2985  cpl_image_get_min(common_sky1_noise) > 0;
2986  }
2987  else
2988  {
2989  is_good1 = false;
2990  }
2991  if (sky2 != NULL)
2992  {
2993  check( common_sky2 = cpl_image_extract(sky2,
2994  first_bin_sky2, row,
2995  first_bin_sky2 + nbins-1, row),
2996  "Error extracting common rows (upper sky)");
2997 
2998  check( common_sky2_noise = cpl_image_extract(sky2_noise,
2999  first_bin_sky2, row,
3000  first_bin_sky2 + nbins-1, row),
3001  "Error extracting common rows (upper sky noise)");
3002 
3003  check(( cpl_image_multiply_scalar(common_sky2 , obj_slit / sky2_slit),
3004  cpl_image_multiply_scalar(common_sky2_noise, obj_slit / sky2_slit)),
3005  "Error normalizing sky flux");
3006 
3007  is_good2 =
3008  cpl_image_count_rejected(common_sky2) <
3009  cpl_image_get_size_x(common_sky2)*
3010  cpl_image_get_size_y(common_sky2) &&
3011  cpl_image_get_min(common_sky2_noise) > 0;
3012  }
3013  else
3014  {
3015  is_good2 = false;
3016  }
3017 
3018 
3019  /* Optimally average the two sky windows
3020  (one of which might not have been extracted) */
3021  if (is_good1 && is_good2)
3022  {
3023  check( common_sky =
3024  uves_average_images(common_sky1, common_sky1_noise,
3025  common_sky2, common_sky2_noise,
3026  &common_sky_noise),
3027  "Error combining sky windows");
3028  }
3029  else if (is_good1 && !is_good2)
3030  {
3031  common_sky = cpl_image_duplicate(common_sky1);
3032  common_sky_noise = cpl_image_duplicate(common_sky1_noise);
3033  }
3034  else if (!is_good1 && is_good2)
3035  {
3036  common_sky = cpl_image_duplicate(common_sky2);
3037  common_sky_noise = cpl_image_duplicate(common_sky2_noise);
3038  }
3039  else
3040  {
3041  common_sky = NULL;
3042  }
3043 
3044  if (common_sky != NULL)
3045  {
3046  /* Do the subtraction, threshold to [0 ; oo [ */
3047  /* Commented out as we should not lower threshold to 0
3048  check(( cpl_image_subtract (common_obj, common_sky),
3049  cpl_image_threshold(common_obj,
3050  0, DBL_MAX,
3051  0, DBL_MAX)),
3052  "Error subtracting combined sky");
3053  */
3054  check(( cpl_image_subtract (common_obj, common_sky)),
3055  "Error subtracting combined sky");
3056 
3057  /* Propagate noise:
3058  obj_noise := sqrt( obj_noise^2 + sky_noise^2 ) */
3059  check(( cpl_image_power(common_obj_noise, 2),
3060  cpl_image_power(common_sky_noise, 2),
3061  cpl_image_add (common_obj_noise, common_sky_noise),
3062  cpl_image_power(common_obj_noise, 0.5)),
3063  "Error propagating noise during sky subtration");
3064 
3065  /* Copy results to relevant row of input spectrum */
3066  check(( cpl_image_copy(obj,
3067  common_obj,
3068  1, row),
3069  cpl_image_copy(obj_noise,
3070  common_obj_noise,
3071  1, row)),
3072  "Error writing subtracted flux to row %d of spectrum", row);
3073  }
3074 
3075  } /* Object and both sky windows do have an overlap in this order */
3076  else
3077  {
3078  int x;
3079 
3080  uves_msg_low("Extracted object and sky spectra have no overlap in order #%d. "
3081  "Order marked as bad", row);
3082 
3083  for (x = 1; x <= cpl_image_get_size_x(obj); x++)
3084  {
3085  check(( cpl_image_reject(obj , x, row),
3086  cpl_image_reject(obj_noise, x, row)),
3087  "Error rejecting sky-subtracted spectrum "
3088  "at (x, row) = (%d, %d)", x, row);
3089  }
3090  }
3091 
3092  cleanup:
3093  uves_free_image(&common_obj);
3094  uves_free_image(&common_sky1);
3095  uves_free_image(&common_sky2);
3096  uves_free_image(&common_obj_noise);
3097  uves_free_image(&common_sky_noise);
3098  uves_free_image(&common_sky1_noise);
3099  uves_free_image(&common_sky2_noise);
3100  uves_free_image(&temp);
3101  if (cpl_error_get_code() != CPL_ERROR_NONE)
3102  {
3103  uves_free_image(&common_sky);
3104  }
3105 
3106  return common_sky;
3107 }
3108 
3109 /*----------------------------------------------------------------------------*/
3126 /*----------------------------------------------------------------------------*/
3127 static double get_offset(const cpl_image *back_subbed,
3128  const cpl_table *ordertable,
3129  const polynomial *order_locations,
3130  double search_range, int nsamples, double *doffset)
3131 {
3132  cpl_image *chunk = NULL; /* Chunks */
3133  cpl_image *chunk_col = NULL; /* Chunks median collapsed along x */
3134 
3135  int minorder, maxorder;
3136  int order, x, nx, ny;
3137  double sum = 0, sum_o = 0, sum_oo = 0; /* Zero'th, first and
3138  second moment of offsets */
3139  int s_r_int = uves_round_double(search_range); /* Search range as an integer */
3140 
3141  passure( back_subbed != NULL, " ");
3142  passure( ordertable != NULL, " ");
3143  passure( order_locations != NULL, " ");
3144  /* doffset may be NULL */
3145  assure( nsamples >= 1, CPL_ERROR_ILLEGAL_INPUT,
3146  "Illegal number of sample points per order: %d", nsamples);
3147 
3148  minorder = cpl_table_get_column_min(ordertable, "Order");
3149  maxorder = cpl_table_get_column_max(ordertable, "Order");
3150  nx = cpl_image_get_size_x(back_subbed);
3151  ny = cpl_image_get_size_y(back_subbed);
3152 
3153  sum = 0;
3154  sum_o = 0;
3155  sum_oo = 0;
3156  for (order = minorder; order <= maxorder; order++)
3157  {
3158  int stepx = nx / nsamples;
3159 
3160  for (x = stepx/2; x <= nx; x += stepx)
3161  {
3162  int y = uves_round_double(
3163  uves_polynomial_evaluate_2d(order_locations, x, order));
3164 
3165  if (1 <= y - s_r_int && y + s_r_int <= ny)
3166  {
3167  double offset;
3168 
3169  /* Get centroid.pos. of median collapsed window */
3170 
3171  chunk =
3172  cpl_image_extract(back_subbed,
3173  uves_max_int(1 , x - stepx/2),
3174  y - s_r_int,
3175  uves_min_int(nx, x + stepx/2),
3176  y + s_r_int);
3177 
3178  chunk_col =
3179  /* Result is single column image */
3180  cpl_image_collapse_median_create(chunk,
3181  1,
3182  0, 0); /* No filtering */
3183 
3184 
3185  /* Offset in world coordinates: row=1 in 'chunk_col'
3186  corresponds to row=(y - s_r_int) in 'back_subbed' */
3187  offset = (y - s_r_int - 1) +
3188  cpl_image_get_centroid_y_window(chunk_col,
3189  1, 1,
3190  1,
3191  cpl_image_get_size_y(chunk_col));
3192 
3193  /* Get offset relative to slit center */
3194  offset -= y;
3195 
3196  uves_free_image(&chunk);
3197  uves_free_image(&chunk_col);
3198 
3199  sum += 1;
3200  sum_o += offset;
3201  sum_oo += offset*offset;
3202  }
3203  }
3204  }
3205 
3206  /* This should never happen, but if it does
3207  fail cleanly instead of dividing by zero */
3208  assure( sum > 0, CPL_ERROR_ILLEGAL_OUTPUT,
3209  "No evaluation points inside image!");
3210 
3211  if (doffset != NULL)
3212  {
3213  *doffset = sqrt(sum_oo/(1.0*sum) -
3214  (sum_o*sum_o) / (sum*1.0*sum));
3215  }
3216 
3217  cleanup:
3218  uves_free_image(&chunk);
3219  uves_free_image(&chunk_col);
3220 
3221  return (1.0*sum_o) / sum;
3222 }
3223 
3224 
3225 /*----------------------------------------------------------------------------*/
3247 /*----------------------------------------------------------------------------*/
3248 static cpl_image *
3249 uves_get_blaze_ratio(const cpl_image *spectrum,
3250  const cpl_image *spectrum_noise)
3251 {
3252  int nx, ny;
3253  int smooth_x, smooth_y;
3254 
3255  cpl_image *blaze_ratio = NULL;
3256  cpl_image *blaze_ratio_noise = NULL;
3257 
3258  cpl_table *values = NULL;
3259  polynomial *p = NULL;
3260 
3261  passure( spectrum != NULL, " ");
3262  passure( spectrum_noise != NULL, " ");
3263 
3264  nx = cpl_image_get_size_x(spectrum);
3265  ny = cpl_image_get_size_y(spectrum);
3266 
3267  blaze_ratio = cpl_image_duplicate(spectrum);
3268  blaze_ratio_noise = cpl_image_duplicate(spectrum_noise);
3269  assure_mem( blaze_ratio );
3270  assure_mem( blaze_ratio_noise );
3271 
3272  /* Normalize each row in ratio to median = 1,
3273  so that the overall normalization doesn't change
3274  */
3275 
3276 
3277  {
3278  int x, y;
3279 
3280  for (y = 1; y <= ny; y++)
3281  {
3282  double median = cpl_image_get_median_window(blaze_ratio,
3283  1, y,
3284  nx, y);
3285 
3286  if (median == 0)
3287  {
3288  /* The cpl_image_get_median_window function is broken;
3289  it doesn't take bad pixels into account. That sometimes
3290  leads to a zero median */
3291 
3292  /* This mostly happens for the first and last orders */
3293 
3294  double max_noise = cpl_image_get_max(blaze_ratio_noise);
3295 
3296  for (x = 1; x <= nx; x++)
3297  {
3298  cpl_image_set(blaze_ratio , x, y, 1);
3299 
3300  /* effectively exclude from fit: */
3301  cpl_image_set(blaze_ratio_noise, x, y, max_noise);
3302  }
3303  }
3304  else
3305  {
3306  /* Divide this row by median,
3307  Exclude pixels deviating more than a factor of, say, 5 */
3308  double exclude = 2;
3309 
3310  for (x = 1; x <= nx; x++)
3311  {
3312  int pis_rejected1, pis_rejected2;
3313  double val1, val2;
3314 
3315  val1 = cpl_image_get(blaze_ratio ,
3316  x, y, &pis_rejected1);
3317  val2 = cpl_image_get(blaze_ratio_noise,
3318  x, y, &pis_rejected2);
3319 
3320  if (!pis_rejected1 && !pis_rejected2 &&
3321  val1/median < exclude && val1/median > 1/exclude)
3322  {
3323  cpl_image_set(blaze_ratio ,
3324  x, y, val1 / median);
3325  cpl_image_set(blaze_ratio_noise,
3326  x, y, val2 / median);
3327  }
3328  else
3329  {
3330  /* Set to 1, then reject. This is to deal with
3331  a plotter that might plot bad pixels */
3332  cpl_image_set (blaze_ratio , x, y, 1);
3333 
3334  cpl_image_reject(blaze_ratio , x, y);
3335  cpl_image_reject(blaze_ratio_noise, x, y);
3336  }
3337  }
3338  }
3339  }
3340 
3341  uves_plot_image_rows(blaze_ratio, 1, ny, ny/10,
3342  "x", "y", "ratio (normalized to 1)");
3343  }
3344 
3345  smooth_x = nx / 20 + 1; /* >0 */
3346  smooth_y = ny / 20 + 1; /* >0 */
3347  check( uves_filter_image_median(&blaze_ratio,
3348  smooth_x, smooth_y, /* x-radius, y-radius */
3349  false), /* extrapolate border pixels? */
3350  "Error creating smoothed ratio");
3351 
3352  uves_plot_image_rows(blaze_ratio, 1, ny, ny/10, "x", "y", "ratio (smoothed)");
3353 
3354 
3355  /* For each x, fit polynomial as function of y.
3356  * Use kappa-sigma clipping to eliminate single order
3357  * spectral featues. This should leave only the
3358  * systematics (i.e. the ratio of obj/flat blaze profiles)
3359  */
3360  {
3361  int x, y;
3362  double interpolated=0;
3363  for (x = 1; x <= nx; x++)
3364  {
3365  int current_row;
3366 
3367  /* Table rows are removed when kappa-sigma clipping,
3368  so we have to create a new table for each column */
3369 
3370  uves_free_table(&values);
3371  values = cpl_table_new(ny);
3372  cpl_table_new_column(values, "Y", CPL_TYPE_INT);
3373  cpl_table_new_column(values, "Ratio", CPL_TYPE_DOUBLE);
3374  cpl_table_new_column(values, "dRatio", CPL_TYPE_DOUBLE);
3375 
3376  assure_mem( values );
3377 
3378  current_row = 0;
3379  for (y = 1; y <= ny; y++)
3380  {
3381  double ratio=0., dratio=0.;
3382  int pis_rejected1=0, pis_rejected2=0;
3383 
3384  ratio = cpl_image_get(blaze_ratio ,
3385  x, y, &pis_rejected1);
3386  check_nomsg(dratio = cpl_image_get(blaze_ratio_noise,
3387  x, y, &pis_rejected2));
3388 /*
3389  uves_msg("x=%d, y=%d, rej1=%d rej2=%d",
3390  x,y,pis_rejected1,pis_rejected2);
3391 */
3392  if (!pis_rejected1 && !pis_rejected2)
3393  {
3394  cpl_table_set_int (values, "Y" ,
3395  current_row, y);
3396  cpl_table_set_double(values, "Ratio" ,
3397  current_row, ratio);
3398  cpl_table_set_double(values, "dRatio",
3399  current_row, dratio);
3400  current_row += 1;
3401  }
3402  else
3403  {
3404  /* Ignore current order */
3405  }
3406  }
3407 
3408  cpl_table_set_size(values, current_row);
3409  if(current_row>UVES_MIN_LINE_ROWS_TO_MAKE_FIT)
3410  {
3411  int degree = 2;
3412  double kappa = 2;
3413 
3415  p = uves_polynomial_regression_1d(values,
3416  "Y", "Ratio", "dRatio",
3417  degree,
3418  NULL, NULL, /* fit, residual^2 */
3419  NULL, /* mse */
3420  kappa);
3421 
3422  /* If fitting failed because there were too few points,
3423  * or matrix was singular */
3424  if (cpl_error_get_code() == CPL_ERROR_ILLEGAL_INPUT ||
3425  cpl_error_get_code() == CPL_ERROR_ILLEGAL_OUTPUT)
3426  {
3427  uves_error_reset();
3428 
3429  /* Then set p(x) = 1
3430  * by fitting a line through (1,1) - (2,1)
3431  */
3432 
3433 
3434  /* The table is in a 'dirty' state (contains
3435  temporary columns) if fitting routine failed
3436  (that routine is not exception safe),
3437  so don't try to reuse current table */
3438 
3439  uves_free_table(&values);
3440  values = cpl_table_new(2);
3441  cpl_table_new_column(values, "Y", CPL_TYPE_INT);
3442  cpl_table_new_column(values, "Ratio", CPL_TYPE_DOUBLE);
3443  cpl_table_set_int (values, "Y" , 0, 1);
3444  cpl_table_set_double(values, "Ratio" , 0, 1);
3445  cpl_table_set_int (values, "Y" , 1, 2);
3446  cpl_table_set_double(values, "Ratio" , 1, 1);
3447 
3448  degree = 2;
3449  kappa = -1;
3451  p = uves_polynomial_regression_1d(values,
3452  "Y", "Ratio", NULL,
3453  degree,
3454  NULL, NULL, /* fit, residual^2 */
3455  NULL, /* mse */
3456  kappa);
3457  }
3458  assure( cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
3459  "Could not fit %d. degree polynomial to column %d", degree, x);
3460 
3461  } else {
3462  interpolated=UVES_BLAZE_DUMMY_VAL;
3463  }
3464 
3465  for (y = 1; y <= ny; y++)
3466  {
3467  if(current_row>UVES_MIN_LINE_ROWS_TO_MAKE_FIT) {
3468  interpolated = uves_polynomial_evaluate_1d(p, y);
3469  }
3470  cpl_image_set(blaze_ratio, x, y, fabs(interpolated));
3471  }
3472 
3473  }
3474 
3475  /* post smooth */
3476  check( uves_filter_image_median(&blaze_ratio,
3477  2*smooth_x, 2*smooth_y, /* x-radius, y-radius */
3478  false), /* extrapolate at border? */
3479  "Error creating smoothed ratio");
3480 
3481  uves_plot_image_rows(blaze_ratio, 1, ny, ny/10, "x", "y", "ratio (poly. fit)");
3482 
3483  }
3484 
3485 
3486  /*
3487  printf("ratio\n");
3488  cpl_stats_dump(cpl_stats_new_from_image(ratio, CPL_STATS_ALL), CPL_STATS_ALL, stdout);
3489  printf("image\n");
3490  cpl_stats_dump(cpl_stats_new_from_image(image, CPL_STATS_ALL), CPL_STATS_ALL, stdout);
3491  printf("noise\n");
3492  cpl_stats_dump(cpl_stats_new_from_image(noise, CPL_STATS_ALL), CPL_STATS_ALL, stdout);
3493 
3494  passure(false, "");
3495 
3496  */
3497 
3498  cleanup:
3499  uves_free_table(&values);
3501  uves_free_image(&blaze_ratio_noise);
3502 
3503  if (cpl_error_get_code() != CPL_ERROR_NONE)
3504  {
3505  uves_free_image(&blaze_ratio);
3506  }
3507  return blaze_ratio;
3508 }
3509 
3510 
int uves_pfits_get_firstabsorder(const uves_propertylist *plist)
Get first absolute order number.
Definition: uves_pfits.c:1734
cpl_error_code uves_pfits_set_wstart(uves_propertylist *plist, int order, double wstart)
Write the wstart keyword.
Definition: uves_pfits.c:2972
int uves_pfits_get_datancom(const uves_propertylist *plist)
Find out the number of input raw frames.
Definition: uves_pfits.c:1212
cpl_error_code uves_filter_image_median(cpl_image **image, int xwindow, int ywindow, bool extrapolate_border)
Median filter.
void uves_polynomial_delete(polynomial **p)
Delete a polynomial.
#define uves_msg_warning(...)
Print an warning message.
Definition: uves_msg.h:87
cpl_image * uves_get_wave_map(cpl_image *ima_sci, const char *context, const cpl_parameterlist *parameters, const cpl_table *ordertable, const cpl_table *linetable, const polynomial *order_locations, const polynomial *dispersion_relation, const int first_abs_order, const int last_abs_order, const int slit_size)
Generates wave map.
Definition: uves_utils.c:452
static cpl_image * subtract_sky(cpl_image *rebinned_obj, cpl_image *rebinned_obj_noise, uves_propertylist *rebinned_obj_header, const cpl_image *rebinned_sky1, const cpl_image *rebinned_sky1_noise, const uves_propertylist *rebinned_sky1_header, const cpl_image *rebinned_sky2, const cpl_image *rebinned_sky2_noise, const uves_propertylist *rebinned_sky2_header, cpl_image **merged_obj, cpl_image **merged_obj_noise, uves_propertylist *merged_obj_header, const cpl_image *merged_sky1, const cpl_image *merged_sky1_noise, const uves_propertylist *merged_sky1_header, const cpl_image *merged_sky2, const cpl_image *merged_sky2_noise, const uves_propertylist *merged_sky2_header, double obj_slit, double sky1_slit, double sky2_slit)
Subtract sky from extracted spectrum.
Definition: uves_reduce.c:2658
void uves_pfits_set_hs(uves_propertylist *plist, int hs)
Write the 2d extractino slit length.
Definition: uves_pfits.c:2952
polynomial * uves_polynomial_add_2d(const polynomial *p1, const polynomial *p2)
Add two polynomials.
double uves_pfits_get_slitlength_pixels(const uves_propertylist *plist, enum uves_chip chip)
Read the slit length in pixels.
Definition: uves_pfits.c:3141
double uves_propertylist_get_double(const uves_propertylist *self, const char *name)
Get the double value of the given property list entry.
int uves_pfits_get_lastabsorder(const uves_propertylist *plist)
Get last absolute order number.
Definition: uves_pfits.c:1764
cpl_image * uves_define_noise(const cpl_image *image, const uves_propertylist *image_header, int ncom, enum uves_chip chip)
Create noise image.
Definition: uves_utils.c:2226
#define check_nomsg(CMD)
Definition: uves_error.h:204
static cpl_image * subtract_sky_row(cpl_image *obj, cpl_image *obj_noise, double obj_start, double obj_end, double obj_slit, const cpl_image *sky1, const cpl_image *sky1_noise, double sky1_start, double sky1_end, double sky1_slit, const cpl_image *sky2, const cpl_image *sky2_noise, double sky2_start, double sky2_end, double sky2_slit, int row, double wavestep, double *common_start, double *common_end)
Subtract sky from 1 row of spectrum.
Definition: uves_reduce.c:2905
cpl_error_code uves_pfits_set_crval1(uves_propertylist *plist, double crval1)
Write the crval1 keyword.
Definition: uves_pfits.c:2829
cpl_error_code uves_subtract_bias(cpl_image *image, const cpl_image *master_bias)
Subtract bias.
Definition: uves_utils.c:2394
#define passure(BOOL,...)
Definition: uves_error.h:207
cpl_image * uves_image_mflat_detect_blemishes(const cpl_image *flat, const uves_propertylist *head)
Flag blemishes in a flat image.
Definition: uves_utils.c:5176
cpl_table * uves_polynomial_convert_to_table(const polynomial *p)
Convert a polynomial to a table.
static polynomial * interpolate_wave(const polynomial *dispersion_relation[3], const uves_propertylist *linetable_header[3], double objoffset)
1st order line tilt correction
Definition: uves_reduce.c:1567
const char * uves_pfits_get_slit1_name(const uves_propertylist *plist)
Get image slicer name.
Definition: uves_pfits.c:3116
double uves_pfits_get_wstart(const uves_propertylist *plist, int order)
Read the wstart keyword.
Definition: uves_pfits.c:3004
cpl_error_code uves_subtract_dark(cpl_image *image, const uves_propertylist *image_header, const cpl_image *master_dark, const uves_propertylist *mdark_header)
Subtract dark.
Definition: uves_utils.c:2438
flatfielding_method uves_get_flatfield_method(const cpl_parameterlist *parameters, const char *context, const char *subcontext)
Read flat-field method from parameter list.
#define uves_msg(...)
Print a message on 'info' or 'debug' level.
Definition: uves_msg.h:119
polynomial * uves_polynomial_duplicate(const polynomial *p)
Copy a polynomial.
cpl_image * uves_extract(cpl_image *image, cpl_image *image_noise, const uves_propertylist *image_header, const cpl_table *ordertable, const polynomial *order_locations_raw, double slit_length, double offset, const cpl_parameterlist *parameters, const char *context, const char *mode, bool extract_partial, bool debug_mode, enum uves_chip chip, uves_propertylist **header, cpl_image **spectrum_noise, cpl_image **sky_spectrum, cpl_image **sky_spectrum_noise, cpl_table **cosmic_mask, cpl_image **cosmic_image, cpl_table **profile_table, cpl_image **weights, cpl_table **info_tbl, cpl_table **order_trace)
Extract a spectrum.
Definition: uves_extract.c:569
static cpl_image * uves_get_blaze_ratio(const cpl_image *spectrum, const cpl_image *spectrum_noise)
Get (normalized) object to flat-field blaze function ratio.
Definition: uves_reduce.c:3249
cpl_error_code uves_propertylist_copy_property_regexp(uves_propertylist *self, const uves_propertylist *other, const char *regexp, int invert)
Copy matching properties from another property list.
static cpl_error_code extract_ff_rebin_merge(cpl_image *back_subbed, cpl_image *backsubbed_noise, const uves_propertylist *backsubbed_header, const cpl_image *master_flat, cpl_image *mflat_noise, const cpl_table *ordertable, const polynomial *order_locations, const cpl_table *linetable, const uves_propertylist *linetable_header[3], const polynomial *dispersion_relation[3], double slit_length, double slit_offset, int window, enum uves_chip chip, bool blaze_correct, bool tilt_corr, bool debug_mode, const cpl_parameterlist *parameters, const char *context, const char *mode, flatfielding_method ff_method, extract_method ee_method, merge_method m_method, cpl_image **x, uves_propertylist **x_header, cpl_image **fx, cpl_table **cosmic_mask, cpl_image **wave_map, cpl_image **flatfielded_variance, uves_propertylist **flatfielded_variance_header, cpl_image **resampled_spectrum, cpl_image **resampled_mf, cpl_image **merged_sky, cpl_image **rebinned_spectrum, cpl_image **rebinned_noise, uves_propertylist **rebinned_header, cpl_image **merged_spectrum, cpl_image **merged_noise, uves_propertylist **merged_header, cpl_table **info_tbl, cpl_table **order_trace)
Reduce one extraction window.
Definition: uves_reduce.c:1745
cpl_error_code uves_polynomial_rescale(polynomial *p, int varno, double scale)
Rescale a polynomial.
double uves_pfits_get_exptime(const uves_propertylist *plist)
Find out the exposure time in seconds.
Definition: uves_pfits.c:922
extract_method uves_get_extract_method(const cpl_parameterlist *parameters, const char *context, const char *subcontext)
Read extraction method from parameter list.
Definition: uves_extract.c:462
#define assure_mem(PTR)
Definition: uves_error.h:181
double uves_polynomial_evaluate_2d(const polynomial *p, double x1, double x2)
Evaluate a 2d polynomial.
double uves_polynomial_evaluate_1d(const polynomial *p, double x)
Evaluate a 1d polynomial.
cpl_image * uves_average_images(const cpl_image *image1, const cpl_image *noise1, const cpl_image *image2, const cpl_image *noise2, cpl_image **noise)
Optimally average images.
Definition: uves_utils.c:2046
merge_method uves_get_merge_method(const cpl_parameterlist *parameters, const char *context, const char *subcontext)
Read merging method from parameter list.
Definition: uves_merge.c:777
cpl_parameterlist * uves_reduce_define_parameters(void)
Define recipe parameters used for reducing a frame.
Definition: uves_reduce.c:188
polynomial * uves_polynomial_regression_1d(cpl_table *t, const char *X, const char *Y, const char *sigmaY, int degree, const char *polynomial_fit, const char *residual_square, double *mean_squared_error, double kappa)
Fit a 1d polynomial to two table columns.
Definition: uves_utils.c:2590
cpl_image * uves_rebin(const cpl_image *spectrum, const cpl_parameterlist *parameters, const char *context, const cpl_table *linetable, const polynomial *dispersion_relation, int first_abs_order, int last_abs_order, int n_traces, bool threshold_to_positive, bool is_noise, uves_propertylist **rebinned_header)
Rebin a spectrum.
Definition: uves_rebin.c:348
cpl_image * uves_merge_orders(const cpl_image *spectrum, const cpl_image *spectrum_noise, const uves_propertylist *spectrum_header, merge_method m_method, int n_traces, uves_propertylist **merged_header, const double delt1, const double delt2, enum uves_chip chip, cpl_image **merged_noise)
Merge orders.
Definition: uves_merge.c:239
#define uves_error_reset()
Definition: uves_error.h:215
#define uves_msg_low(...)
Print a message on a lower message level.
Definition: uves_msg.h:105
#define uves_msg_debug(...)
Print a debug message.
Definition: uves_msg.h:97
double uves_pfits_get_cdelt1(const uves_propertylist *plist)
Find out the cdelt1.
Definition: uves_pfits.c:2465
double uves_pfits_get_crval1(const uves_propertylist *plist)
Find out the crval1.
Definition: uves_pfits.c:2393
uves_propertylist * uves_propertylist_duplicate(const uves_propertylist *self)
Create a copy of the given property list.
#define assure_nomsg(BOOL, CODE)
Definition: uves_error.h:177
cpl_error_code uves_pfits_set_wend(uves_propertylist *plist, int order, double wend)
Write the wend keyword.
Definition: uves_pfits.c:3035
cpl_error_code uves_flatfielding(cpl_image *image, cpl_image *noise, const cpl_image *master_flat, const cpl_image *mflat_noise)
Divide by flat field.
int uves_propertylist_contains(const uves_propertylist *self, const char *name)
Check whether a property is present in a property list.
cpl_error_code uves_propertylist_append_c_double(uves_propertylist *self, const char *name, double value, const char *comment)
Append a double value to a property list.
#define check(CMD,...)
Definition: uves_error.h:198
static double get_offset(const cpl_image *back_subbed, const cpl_table *ordertable, const polynomial *order_locations, double search_range, int nsamples, double *doffset)
Measure object offset w.r.t. slit center.
Definition: uves_reduce.c:3127
double uves_pfits_get_offset(const uves_propertylist *plist)
Get the trace offset.
Definition: uves_pfits.c:1902
int uves_propertylist_has(const uves_propertylist *self, const char *name)
Check whether a property is present in a property list.
cpl_error_code uves_reduce(const cpl_image *raw_image, const uves_propertylist *raw_header, const uves_propertylist *rotated_header, const cpl_image *master_bias, const uves_propertylist *mbias_header, const cpl_image *master_dark, const uves_propertylist *mdark_header, const cpl_image *master_flat, const uves_propertylist *mflat_header, const cpl_table *ordertable, const polynomial *order_locations, const cpl_table *linetable[3], const uves_propertylist *linetable_header[3], const polynomial *dispersion_relation[3], enum uves_chip chip, bool debug_mode, const cpl_parameterlist *parameters, const char *rec_id, const char *mode, cpl_image **x, uves_propertylist **x_header, cpl_image **fx, cpl_table **cosmic_mask, cpl_image **wave_map, cpl_image **background, cpl_image **flatfielded_variance, uves_propertylist **flatfielded_variance_header, cpl_image **resampled_spectrum, cpl_image **resampled_mf, cpl_image **merged_sky, cpl_image **rebinned_spectrum, cpl_image **rebinned_noise, uves_propertylist **rebinned_header, cpl_image **merged_spectrum, cpl_image **merged_noise, uves_propertylist **merged_header, cpl_image **reduced_rebinned_spectrum, cpl_image **reduced_rebinned_noise, cpl_image **reduced_spectrum, cpl_image **reduced_noise, cpl_table **info_tbl, double *extraction_slit, cpl_table **order_trace)
Reduce a science frame.
Definition: uves_reduce.c:575
double uves_pfits_get_wend(const uves_propertylist *plist, int order)
Read the wend keyword.
Definition: uves_pfits.c:3067