UVES Pipeline Reference Manual  5.4.6
uves_wavecal_body.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:47 $
23  * $Revision: 1.103 $
24  * $Name: not supported by cvs2svn $
25  *
26  */
27 
28 /*-----------------------------------------------------------------------------
29  Includes
30  -----------------------------------------------------------------------------*/
31 
32 #ifdef HAVE_CONFIG_H
33 # include <config.h>
34 #endif
35 /*----------------------------------------------------------------------------*/
39 /*----------------------------------------------------------------------------*/
40 
41 #include <uves_wavecal_body.h>
42 
43 /* Definitions */
44 #include <uves.h>
45 
46 /* Macro steps */
47 #include <uves_extract.h>
48 #include <uves_flatfield.h>
49 #include <uves_wavecal_search.h>
50 #include <uves_wavecal_firstsolution.h>
51 #include <uves_wavecal_identify.h>
52 #include <uves_rebin.h>
53 #include <uves_merge.h>
54 
55 /* Utility functions */
56 #include <uves_wavecal_utils.h>
57 #include <uves_utils.h>
58 #include <uves_utils_wrappers.h>
59 #include <uves_plot.h>
60 #include <uves_parameters.h>
61 #include <uves_dfs.h>
62 #include <uves_pfits.h>
63 #include <uves_qclog.h>
64 #include <uves_recipe.h>
65 #include <uves_error.h>
66 #include <flames_reduce_vcorrel.h>
67 
68 #include <cpl.h>
69 
70 #include <stdbool.h>
71 #include <float.h>
72 #include <string.h>
73 /*-----------------------------------------------------------------------------
74  Defines
75  -----------------------------------------------------------------------------*/
76 /* threshold values for maximum pixel saturation */
77 #define DRS_PTHRES_MAX 55000
78 #define DRS_PTHRES_MIN -20
79 #define DRS_CVEL_MIN -6.
80 #define DRS_CVEL_MAX +6.
81 #define N_FIBRES_MAX 9
82 /*-----------------------------------------------------------------------------
83  Functions prototypes
84  -----------------------------------------------------------------------------*/
85 static void uves_wavecal_qclog(const cpl_table* table,
86  int firstabs,
87  int lastabs,
88  const cpl_image *arclamp,
89  const uves_propertylist* raw_header,
90  bool flames,
91  int trace_number,
92  int fibre_mask,
93  double offset,
94  enum uves_chip chip,
95  cpl_table* qclog);
96 
97 static void uves_wavecal_qclog_intmon(cpl_table* table,
98  const cpl_table *line_intmon,
99  const uves_propertylist* raw_header,
100  bool flames,
101  int fibre,
102  enum uves_chip chip,
103  cpl_table* qclog);
104 
105 /*-----------------------------------------------------------------------------
106  Recipe standard code
107  -----------------------------------------------------------------------------*/
108 
109 const char * const uves_wavecal_desc_short = "Performs the wavelength calibration";
110 
111 const char * const uves_wavecal_desc =
112 "The recipe performs a wavelength calibration for each extraction window.\n"
113 "Conceptually, each chip contains a number of order lines, each of which\n"
114 "contains a number of fibre traces, each of which contains a number of\n"
115 "extraction windows. For UVES data, there is only one trace per order and\n"
116 "three extraction windows (sky, object, sky). For FLAMES/UVES data there\n"
117 "are multiple traces per order but only one extraction window per trace.\n"
118 "The number of traces is defined in the order table while the geometry of\n"
119 "the extraction windows is specified by recipe parameters (see below).\n"
120 "\n"
121 "Expected input for this recipe is an arc lamp frame, ARC_LAMP_xxx or\n"
122 "ECH_ARC_LAMP_xxx (where xxx=BLUE, RED), order table(s) for each chip,\n"
123 "ORDER_TABLE_xxxx (where xxxx=BLUE, REDL, REDU), 'guess' line table(s)\n"
124 "for each chip, LINE_TABLE_xxxx, a wavelength catalogue table, \n"
125 "LINE_REFER_TABLE, and optionally a wavelength table of bright lines,\n"
126 "LINE_INTMON_TABLE, used only for computing Quality Control parameters.\n"
127 "\n"
128 "The output line table(s), LINE_TABLE_xxxx, contains the columns\n"
129 "X : Horizontal position (from Gaussian fit) of detected line\n"
130 "dX : Uncertainty (one sigma) of X\n"
131 "Ynew : Vertical position of detected line\n"
132 "XWidth : Width (in pixels) of detected line from Gaussian fit\n"
133 "Peak : Intensity of detected line\n"
134 "Background : Fitted background (ADU) of detected line\n"
135 "Slope : Linear background slope (ADU/pixel) of detected line\n"
136 " from Gaussian fit\n"
137 "Intensity : Intensity of detected line scaled to unit exposure\n"
138 " time. (This column only present if a LINE_INTMON_TABLE\n"
139 " is provided.)\n"
140 "Order : Absolute order number of detected line\n"
141 "Y : Relative order number of detected line\n"
142 " (it's not a very descriptive column name)\n"
143 "WaveC : Wavelength of this line (computed using the resulting\n"
144 " dispersion relation)\n"
145 "dLambdaC : Uncertainty (one sigma) of 'WaveC'.\n"
146 "Pixel : The width in w.l.u. of a pixel (computed locally).\n"
147 "Residual : Residual (in w.l.u.) of this line\n"
148 "Residual_pix : Residual (in pixels) of this line\n"
149 "Lambda_candidate : Nearest line in catalogue\n"
150 "dLambda_cat_sq : Squared distance to nearest catalogue line\n"
151 "dLambda_nn_sq : Squared distance to nearest neighbour multiplied by ALPHA\n"
152 "Ident : The wavelength associated with this emission line,\n"
153 " or invalid if this line was not identified\n"
154 "dIdent : Uncertainty of catalogue wavelength\n"
155 "Select : 1 if the line was identified, 0 otherwise\n"
156 "NLinSol : 1 if the line was identified and accepted for the\n"
157 " polynomial fit, 0 otherwise\n"
158 "Intensity : Intensity of detected line scaled to unit exposure\n"
159 " time. (This column is present only if a LINE_INTMON_TABLE\n"
160 " is provided.)\n"
161 "\n"
162 "The 2nd table extension contains the dispersion relation (a 2d polynomial).\n"
163 "The 3rd table extension contains the map from (pixel, pixel)-space to\n"
164 " physical order numbers (used internally by the calibration recipe; \n"
165 "another 2d polynomial).\n"
166 "\n"
167 "If there is more than one extraction window, the results of each calibration\n"
168 "is stored in subsequent table extensions of the same FITS file. For \n"
169 "example, extensions 4, 5 and 6 would contain the resulting line table \n"
170 "(and its two associated polynomials) for the second extraction window. \n"
171 "The results for the calibration of the n'th extraction window is stored \n"
172 "in extensions (3*n - 2) to 3*n.\n";
175 /*-----------------------------------------------------------------------------
176  Functions code
177  -----------------------------------------------------------------------------*/
178 
179 /*----------------------------------------------------------------------------*/
187 /*----------------------------------------------------------------------------*/
188 int
189 uves_wavecal_define_parameters_body(cpl_parameterlist *parameters,
190  const char *recipe_id, double slit)
191 {
192  const char *subcontext;
193 
194  /*****************
195  * General *
196  *****************/
197 
198  if (uves_define_global_parameters(parameters) != CPL_ERROR_NONE)
199  {
200  return -1;
201  }
202 
203  /*****************
204  * Extraction *
205  *****************/
206 
207  subcontext = NULL;
208 
209  /* nwindows */
210  uves_par_new_range("nwindows",
211  CPL_TYPE_INT,
212  "Number of extraction windows per trace. "
213  "The windows will be aligned (i.e. no overlap "
214  "and no spacing between adjacent windows). "
215  "Unless an offset is specified, the middle "
216  "window(s) is centered on the trace",
217  strcmp(recipe_id, "flames_cal_wavecal") == 0 ?
218  1 : 3, /* FLAMES: 1; UVES: 3 */
219  1, INT_MAX);
220 
221  /* length */
222  uves_par_new_range("length",
223  CPL_TYPE_DOUBLE,
224  "Length (in pixels) of each extraction window. "
225  "This parameter is also equal to the seperation of "
226  "adjacent window centers, causing the extraction "
227  "windows to always be aligned. The parameter is "
228  "automatically adjusted according to the binning "
229  "of the input raw frame. If negative, the extraction "
230  "window length is determined automatically "
231  "to cover the full slit",
232  slit, -2.0, DBL_MAX);
233 
234  /* offset */
235  uves_par_new_range("offset",
236  CPL_TYPE_DOUBLE,
237  "A global offset (in pixels) of all extraction windows",
238  0.0, -25., 25.);
239 
240  /* method */
241  if (uves_propagate_parameters_step(UVES_EXTRACT_ID, parameters,
242  recipe_id, NULL) != 0)
243  {
244  return -1;
245  }
246 
247  /* Override default optimal extraction profile. Assume constant profile */
248 #if 0
249  /* this should perhaps be enabled but doesn't work properly in the moment.
250 
251  ChangeLog:
252  uves_cal_wavecal: The arc lamp spectrum is now extracted using
253  average extraction and weighting each pixel with its inverse
254  variance. This is equivalent to doing an optimal extraction under
255  the assumption of a constant spatial profile, and is implemented
256  as such. This was a necessary change in order to be robust against
257  interorder noisy pixels caused by dividing by the flat-field.
258 
259  */
260  {
261  const char *profile = "constant";
262  double kappa = -1;
263 
264  if (uves_set_parameter_default(parameters,
265  recipe_id, UVES_EXTRACT_ID ".profile",
266  CPL_TYPE_STRING, &profile)
267  != CPL_ERROR_NONE)
268  {
269  return -1;
270  }
271 
272  /* Disable cosmic ray rejection, it does not work well for
273  this particular profile and very high S/N */
274  if (uves_set_parameter_default(parameters,
275  recipe_id, UVES_EXTRACT_ID ".kappa",
276  CPL_TYPE_DOUBLE, &kappa)
277  != CPL_ERROR_NONE)
278  {
279  return -1;
280  }
281  }
282 #else
283  {
284  const char *method = "average";
285 
286  if (uves_set_parameter_default(parameters,
287  recipe_id, UVES_EXTRACT_ID ".method",
288  CPL_TYPE_STRING, &method)
289  != CPL_ERROR_NONE)
290  {
291  return -1;
292  }
293 
294  }
295 #endif
296 
297  /*****************
298  * Search *
299  *****************/
300 
301  subcontext = "search";
302 
303  /* range */
304  uves_par_new_range("range",
305  CPL_TYPE_INT,
306  "Width (pix) of search window is 2*range + 1. "
307  "This parameter is automatically adjusted "
308  "according to binning.",
309  8, 1, INT_MAX);
310 
311  /* minlines */
312  uves_par_new_range("minlines",
313  CPL_TYPE_INT,
314  "Minimum number of lines to detect. If zero, "
315  "the default value (1100 for BLUE/REDL chips; "
316  "1000 for REDU chip) is used.",
317  0, 0, INT_MAX);
318 
319  /* maxlines */
320  uves_par_new_range("maxlines",
321  CPL_TYPE_INT,
322  "Maximum number of lines to detect. If zero, "
323  "the default value (1600 for BLUE/REDL chip; "
324  "1400 for REDU chip) is used.",
325  0, 0, INT_MAX);
326 
327  /* centeringmethod */
328 /* Temporally removed as 'gravity' do not work and it does not make
329  sense a parameter with only one option
330 
331  uves_par_new_enum("centeringmethod",
332  CPL_TYPE_STRING,
333  "Line centering method",
334  "gaussian", // Default
335  1, // Number of options
336  "gaussian"); // List of options
337 
338 */
339  /* old setting allowed gravity "gaussian", "gravity"); */
340 
341  /*******************
342  * First solution *
343  *******************/
344 
345  subcontext = "first";
346 
347  /* shiftmax */
348  uves_par_new_range("shiftmax",
349  CPL_TYPE_DOUBLE,
350  "The maximum shift (pix) in either direction compared to "
351  "guess solution. This parameter is automatically "
352  "corrected for binning",
353  10.0, 0.0, DBL_MAX);
354 
355  /* shiftstep */
356  uves_par_new_range("shiftstep",
357  CPL_TYPE_DOUBLE,
358  "The step size (pix) used when searching "
359  "for the optimum shift. This parameter is "
360  "automatically corrected for binning",
361  0.1, 0.0, DBL_MAX);
362 
363  /* shifttoler */
364  uves_par_new_range("shifttoler",
365  CPL_TYPE_DOUBLE,
366  "Tolerance (pix) when matching shifted lines. "
367  "This parameter is not adjusted according to binning",
368  0.05, 0.0, DBL_MAX);
369 
370 
371  /*****************
372  * Identify *
373  *****************/
374 
375  subcontext = "identify";
376 
377  /* alpha */
378  uves_par_new_range("alpha",
379  CPL_TYPE_DOUBLE,
380  "The parameter that controls the distance to the "
381  "nearest neighbours",
382  0.1, 0.0, 1.0);
383 
384  /* maxerror */
385  uves_par_new_range("maxerror",
386  CPL_TYPE_DOUBLE,
387  "This parameter controls the graceful exit of "
388  "the identification loop. If the RMS of the "
389  "global fit exceeds this value (pix) the "
390  "iteration stops",
391  20.0, 0.0, DBL_MAX);
392 
393  /* degree */
394  uves_par_new_range("degree",
395  CPL_TYPE_INT,
396  "Degrees of the global 2d dispersion polynomial. If "
397  "a negative number is specified, the polynomial "
398  "degrees are automatically selected by starting from "
399  "(1, 1) and inreasing the degrees as long as the RMS "
400  "residual decreases significantly",
401  4, -2, INT_MAX);
402 
403 
404  /*****************
405  * Calibration *
406  *****************/
407 
408  subcontext = "calibrate";
409 
410  /* tolerance */
411  uves_par_new_value("tolerance",
412  CPL_TYPE_DOUBLE,
413  "Tolerance of fit. If positive, the tolerance "
414  "is in pixel units. If negative, abs(tolerance) "
415  "is in wavelength units. Lines with residuals "
416  "worse than the tolerance are excluded from the "
417  "final fit. Unlike in previous versions, this "
418  "parameter is not corrected for CCD binning. "
419  "This rejection based on the absolute residual in "
420  "pixel can be effectively disabled by setting the "
421  "tolerance to a very large number (e.g. 9999). In "
422  "that case outliers will be rejected using only "
423  "kappa sigma clipping.",
424  0.6);
425 /* 0.07); */
426 /* 9999.0);*/
427 
428 
429  /* kappa */
430  uves_par_new_range("kappa",
431  CPL_TYPE_DOUBLE,
432  "Lines with residuals more then kappa stdev "
433  "are rejected from the final fit",
434  4.0,0.,100.);
435 
436  /***************
437  * Rebinning *
438  ***************/
439  if (uves_propagate_parameters_step(UVES_REBIN_ID, parameters,
440  recipe_id, NULL) != 0)
441  {
442  return -1;
443  }
444 
445  return (cpl_error_get_code() != CPL_ERROR_NONE);
446 }
447 
448 /*----------------------------------------------------------------------------*/
519 /*----------------------------------------------------------------------------*/
520 static cpl_table *
521 uves_wavecal_process_window(const cpl_image *arclamp,
522  const cpl_image *arclamp_noise,
523  const uves_propertylist *rotated_header,
524  const cpl_table *ordertable,
525  const polynomial *order_locations,
526  bool flat_fielded,
527  cpl_image *weights,
528  /* const cpl_table *drs_table, Not used */
529  const cpl_table *guess,
530  const cpl_table *line_refer,
531  bool flames,
532  int tab_in_out_oshift,
533  double tab_in_out_yshift,
534  enum uves_chip chip, int bin_disp,
535  int trace, int window, int NWINDOWS,
536  /* General */
537  bool debug_mode,
538  /* Extraction */
539  double offset,
540  double slitlength,
541  const cpl_parameterlist *parameters,
542  const char *recipe_id,
543  /* Search */
544  int RANGE,
545  int MINLINES,
546  int MAXLINES,
547  centering_method CENTERING_METHOD,
548  /* First solution */
549  double SHIFT_MAX,
550  double SHIFT_STEP,
551  double SHIFT_TOLERANCE,
552  /* Identify */
553  double ALPHA,
554  double MAXERROR,
555  int DEGREE,
556  /* Calibrate */
557  double TOLERANCE,
558  double kappa,
559  cpl_frame* corvel_frm,
560  cpl_table** flames_qclog,
561  /* Result */
562  polynomial **dispersion_relation,
563  polynomial **absolute_order,
564  int *first_absolute_order,
565  int *last_absolute_order)
566 {
567  cpl_table *linetable = NULL; /* Result */
568  cpl_table *temp = NULL;
569  cpl_image *spectrum = NULL;
570  cpl_image *spectrum_noise = NULL;
571  cpl_image *debug_image = NULL;
572  polynomial *initial_dispersion = NULL;
573  int *relative_order = NULL; /* Map from physical
574  order to relative order */
575  uves_propertylist *spectrum_header = NULL;
576 
577  cpl_image *rebinned = NULL; /* Used for calculating
578  the instrument resolution */
579  cpl_image *rebinned_noise = NULL; /* Used for calculating
580  the instrument resolution */
581  uves_propertylist *rebinned_header = NULL;
582  cpl_image *merged = NULL;
583  cpl_image *merged_noise = NULL;
584  uves_propertylist *merged_header = NULL;
585  cpl_table *info_tbl = NULL;
586 
587  /* Needed for optimal extraction */
588  cpl_image *weights_opt = NULL;
589  cpl_table *cr_table = NULL;
590  cpl_image *cr_image = NULL;
591  cpl_table *order_trace = NULL;
592 
593  merge_method m_method = flat_fielded ? MERGE_OPTIMAL : MERGE_SUM;
594 
595  /* Extract the spectrum */
596  uves_free_table(&info_tbl);
597 
598 
599  check( spectrum = uves_extract((cpl_image *)arclamp,/* Const-casts are okay,
600  the image (bpm) + error bars
601  is changed
602  only in optimal extraction */
603  (cpl_image *)arclamp_noise,
604  NULL, /* Header (optimal only) */
605  ordertable,
606  order_locations,
607  slitlength, /* Slit length (pixels) */
608  offset, /* Slit center offset */
609  parameters, /* Extraction method */
610  recipe_id,
611  "",
612  true, /* Extraction partial bins? */
613  debug_mode,
614  chip,
615  &spectrum_header,
616  &spectrum_noise,
617  NULL,
618  NULL, /* Optimal: sky+noise */
619  &cr_table,
620  &cr_image,
621  NULL,
622  (weights != NULL) ? &weights : &weights_opt,
623  &info_tbl,
624  &order_trace),
625  "Error extracting spectrum");
626  uves_free_table(&info_tbl);
627 
628 
630  rotated_header,
631  "^ESO ", 0),"error copying hierarch keys");
632 
633  /* Set bad pixels to 0, so that the search algorithm doesn't
634  fail because of bad pixels (but simply does not detect anything)
635  */
636  cpl_image_fill_rejected(spectrum, 0);
637  cpl_image_accept_all(spectrum);
638  cpl_image_fill_rejected(spectrum_noise, 1);
639  cpl_image_accept_all(spectrum_noise);
640 
641  /* Save spectrum + noise */
642  if (debug_mode)
643  {
644 
645 
646  check(uves_propertylist_copy_property_regexp(spectrum_header, rotated_header,
647  "^ESO ", 0),
648  "Error copying hieararch keys");
649 
650  check( uves_save_image_local("Extracted spectrum", "spectrum",
651  spectrum, chip, trace, window, spectrum_header, true),
652  "Error saving spectrum");
653 
654  check( uves_save_image_local("Extracted spectrum noise", "spectrum_noise",
655  spectrum_noise, chip, trace, window, spectrum_header, true),
656  "Error saving spectrum");
657  }
658 
659  /* Locate lines */
660  debug_image = cpl_image_duplicate(arclamp);
661  check( linetable = uves_wavecal_search(spectrum,
662  spectrum_noise,
663  spectrum_header,
664  flat_fielded,
665  order_locations,
666  debug_image,
667  RANGE,
668  MINLINES,
669  MAXLINES,
670  CENTERING_METHOD,
671  bin_disp,trace,window,
672  flames_qclog[0]),
673  "Line search failed");
674 
675  /* Read first solution from guess line table */
676  {
677  int degree = 5; /* for the initial solution only. For the
678  final solution the degree given as recipe
679  parameter is used */
680  uves_polynomial_delete(&initial_dispersion);
681  cpl_free(relative_order);
682  check( initial_dispersion = uves_wavecal_firstsolution(linetable,
683  guess,
684  absolute_order,
685  ordertable,
686  order_locations,
687  flames,
688  offset,
689  &relative_order,
690  degree,
691  SHIFT_MAX,
692  SHIFT_STEP,
693  SHIFT_TOLERANCE,
694  MAXERROR,
695  first_absolute_order,
696  last_absolute_order),
697  "Could not get first solution");
698  }
699 
700 
701  if (flames)
702  {
703  /* !AM: To correct eventual residual shifts between Guess and Final order
704  ! (and line) table
705  compute/table {LINTAB} :YNEW =
706  :YNEW - {{ORDTAB},TAB_IN_OUT_YSHIFT} - {{OLDORDTAB},FIBREPOS({i1})}
707  compute/table {LINTAB} :Y = :Y +{{ORDTAB},TAB_IN_OUT_OSHIFT}
708  */
709 
710  cpl_table_add_scalar(linetable, "Y", tab_in_out_oshift);
711  cpl_table_add_scalar(linetable, "Ynew", - tab_in_out_yshift - offset);
712  }
713 
714  /* Calibrate */
715  check( *dispersion_relation = uves_wavecal_identify(linetable, /* Guess solution */
716  line_refer,
717  initial_dispersion,
718  DEGREE,
719  TOLERANCE, ALPHA,
720  MAXERROR,
721  kappa,trace,window,flames_qclog[0]),
722  "Could not calibrate orders");
723 
724  if (flames)
725  {
726  /* AM: To have correct split of fibres in line table:
727  > compute/table {LINTAB} :YNEW = :YNEW + {{ORDTAB},TAB_IN_OUT_YSHIFT}
728  + {{OLDORDTAB},FIBREPOS({i1})}
729  */
730 
731  cpl_table_add_scalar(linetable, "Ynew", + tab_in_out_yshift + offset);
732  }
733 
734  /* UVES: make plots (resolution + etc.) for the central window,
735  * FLAMES: all fibres
736  */
737  if (flames || (trace == 0 && window == 2)|| (window == 1 && NWINDOWS == 1))
738  {
739  /* Create x-FWHM column: FWHM = 2.3548 sigma */
740  check(( cpl_table_duplicate_column(linetable, "deltaX", linetable, "Xwidth"),
741  cpl_table_multiply_scalar (linetable, "deltaX", TWOSQRT2LN2)),
742  "Error creating FWHM column");
743 
744 
745  check_nomsg( temp = uves_extract_table_rows(
746  linetable, "NLinSol", CPL_NOT_EQUAL_TO, 0) );
747 
748  check( uves_plot_table(temp, "Order", LINETAB_RESIDUAL, "Residual of fit"),
749  "Plotting failed");
750 
751  check( uves_plot_table(temp, "X", "deltaX", "line FWHM (mean = %.2f pixels)",
752  cpl_table_get_column_mean(linetable, "deltaX")),
753  "Plotting failed");
754  /*
755  check( uves_plot_table(linetable, "Y", "deltaX",
756  "line FWHM (mean FWHM = %.2f pixels)",
757  cpl_table_get_column_mean(linetable, "deltaX")), "Plotting failed");
758  */
759 
760 
761  /* Compute resolution as as lambda / deltalambda where deltalambda
762  is the peak FWHM in wavelength space (after resampling using
763  WAVESTEP = average pixelsize)
764  */
765 
766  {
767  /* Rebin using steps of median pixelsize */
768  double wavestep;
769  double lambda_start = 0;
770  int n_traces = 1; /* We didn't do a 2d extraction;
771  there's only 1 trace
772  per order */
773  int i, nbins;
774  bool threshold_to_positive = true;
775 
776  cpl_table_new_column(linetable, "deltaLambda", CPL_TYPE_DOUBLE);
777 
778  check( rebinned_noise = uves_rebin(spectrum_noise,
779  parameters,
780  recipe_id,
781  linetable,
782  *dispersion_relation,
783  *first_absolute_order,
784  *last_absolute_order,
785  n_traces,
786  threshold_to_positive,
787  true,
788  &rebinned_header),
789  "Could not rebin noise of arc lamp spectrum");
790 
791  threshold_to_positive = false;
792  uves_free_propertylist(&rebinned_header);
793  check( rebinned = uves_rebin(spectrum,
794  parameters,
795  recipe_id,
796  linetable,
797  *dispersion_relation,
798  *first_absolute_order,
799  *last_absolute_order,
800  n_traces,
801  threshold_to_positive,
802  false,
803  &rebinned_header),
804  "Could not rebin arc lamp spectrum");
805 
806  /* Save order-by-order rebinned spectrum+noise */
807  if (debug_mode)
808  {
809  check( uves_save_image_local("Rebinned spectrum",
810  "wxb", rebinned, chip,
811  trace, window, rebinned_header, true),
812  "Error saving rebinned spectrum");
813 
814  check( uves_save_image_local("Noise of rebinned spectrum",
815  "errwxb", rebinned_noise, chip,
816  trace, window, rebinned_header, true),
817  "Error saving noise of rebinned spectrum");
818  }
819 
820  check( merged = uves_merge_orders(rebinned,
821  rebinned_noise,
822  rebinned_header,
823  m_method,
824  n_traces,
825  &merged_header,
826  0,0,chip,
827  &merged_noise),
828  "Could not merge arc lamp spectrum");
829 
830  check( uves_plot_image_rows(merged, 1, 1, 1,
831  "Wavelength (arbitrary units)",
832  "Flux", "Resampled arc lamp spectrum"),
833  "Plotting failed");
834 
835  /* Save merged arc lamp spectrum */
836  if (debug_mode)
837  {
838  check( uves_save_image_local("Rebinned, merged spectrum",
839  "merged", merged, chip,
840  trace, window, merged_header, true),
841  "Error saving merged spectrum");
842  }
843 
844  nbins = cpl_image_get_size_x(merged);
845 
846  check( wavestep = uves_pfits_get_cdelt1(merged_header),
847  "Error reading resampling step size");
848 
849  check( lambda_start = uves_pfits_get_crval1(merged_header),
850  "Could not read start wavelength of merged spectrum");
851 
852 
853  //Begin commented region
854 
855  if (flames && trace == 0 && corvel_frm != NULL)
856  {
857  //The following (flames_reduce.VCORREL) calculates
858  //a cross correlation and does some QC
859 
860 
861 //> !To support simcal Mode
862 //> if i1 .eq. 1 then
863 //> w/o "DRS_CVEL_SWITCH={DRS_CVEL_SWITCH}"
864 //> if "{DRS_CVEL_SWITCH}" .eq. "Y" then
865 //> w/o "To support simcal Mode"
866 //> define/local ord_min/i/1/1 0
867 //> define/local ord_max/i/1/1 0
868 //> define/local rsample/d/1/1 0
869 //> statistic/table {ORDTAB} :ORDER >Null
870 //> ord_min = outputr(1)
871 //> ord_max = outputr(2)
872 //> rsample = {{LINTAB},PIXEL(1)}
873 //> rsample = 2./3. * rsample
874 //> rebin/echelle {ofrm} w{ofrm} {rsample} NONL {LINTAB} {SESSOUTV}
875 //> mercut/echelle w{ofrm} mw{ofrm} {ord_min},{ord_max} NOAPPEND
876 //> !corvel stuff
877 //> define/local OLD_CVEL_MAX/d/1/1 {DRS_CVEL_MAX}
878 //> define/local OLD_CVEL_MIN/d/1/1 {DRS_CVEL_MIN}
879 //> @p flames_reduce,VCORREL x1_rbf_ cvel1 0 {ord_max} {parCorVelTab} _0 _{chip({PATHID})} 0
880 //> DRS_CVEL_MAX = DRS_CVEL_MAX + {q1}
881 //> DRS_CVEL_MIN = DRS_CVEL_MIN + {q1}
882 //>
883 //> @p flames_reduce,VCORREL x1_rbf_ cvel2 0 {ord_max} {parCorVelTab} _0 _{chip({PATHID})} 0
884 //> cvel_0 = {q1}
885 //> DRS_CVEL_MAX = OLD_CVEL_MAX
886 //> DRS_CVEL_MIN = OLD_CVEL_MIN
887 //> endif
888 //> write/keyword DRS_CVEL_SWITCH Y
889 //> endif
890 
891 
892 
893 
894 
895 
896 
897  const char* drs_base_name=NULL;
898  const char* prefid=NULL;
899  double ccf_posmax_zero_point=0;
900  double ccf_posmax_zero_point_iter0=0;
901  double cvel_max=0;
902  double cvel_sig=0;
903  if(chip == UVES_CHIP_REDL) {
904  prefid="l";
905  } else {
906  prefid="u";
907  }
908  const char* name=NULL;
909  const char* file=NULL;
910  cpl_propertylist* plist=NULL;
911  double drs_cvel_min=0;
912  double drs_cvel_max=0;
913 
914 
915  check( uves_save_image_local("Rebinned spectrum",
916  "wxb", rebinned, chip,
917  trace, window, rebinned_header, true),
918  "Error saving rebinned spectrum");
919 
920  check( uves_save_image_local("Rebinned, merged spectrum",
921  "mwxb", merged, chip,
922  trace, window, merged_header, true),
923  "Error saving merged spectrum");
924 
925 
926  check( file = uves_local_filename("wxb", chip, trace, window),
927  "Error getting filename");
928  check_nomsg(plist=cpl_propertylist_load(file,0));
929 
930  name=uves_sprintf("wfxb_%s%s%4.4d%s",prefid,"_raw",1,".fits");
931  drs_base_name=uves_sprintf("fxb_%s",prefid);
932 
933  cpl_image_save(rebinned,name, CPL_BPP_IEEE_FLOAT,plist,
934  CPL_IO_DEFAULT);
935 
936 
937  name=uves_sprintf("mwfxb_%s%s%4.4d%s",prefid,"_raw",1,".fits");
938  cpl_image_save(merged,name, CPL_BPP_IEEE_FLOAT,plist,
939  CPL_IO_DEFAULT);
940 
941  cpl_propertylist_delete(plist);
942 
943 
944  int ord_max=(*first_absolute_order-*last_absolute_order)+1;
945 
946  uves_msg("cvel max:%g %g",DRS_CVEL_MAX,DRS_CVEL_MIN);
947  drs_cvel_max =DRS_CVEL_MAX;
948  drs_cvel_min =DRS_CVEL_MIN;
949 
950  check_nomsg(flames_reduce_vcorrel(drs_base_name,
951  "cvel2",
952  prefid,
953  ord_max,
954  corvel_frm,
955  "_raw0001",
956  "_raw0001",
957  DRS_CVEL_MIN,
958  DRS_CVEL_MAX,
959  &ccf_posmax_zero_point,
960  &cvel_max,
961  &cvel_sig,
962  flames_qclog[0]));
963 
964  drs_cvel_max +=cvel_max;
965  drs_cvel_min +=cvel_max;
966  ccf_posmax_zero_point_iter0 =cvel_max;
967  uves_msg("cvel max:%g %g",drs_cvel_max,drs_cvel_min);
968 
969  check_nomsg(flames_reduce_vcorrel(drs_base_name,
970  "cvel2",
971  prefid,
972  ord_max,
973  corvel_frm,
974  "_raw0001",
975  "_raw0001",
976  drs_cvel_min,
977  drs_cvel_max,
978  &ccf_posmax_zero_point,
979  &cvel_max,
980  &cvel_sig,
981  flames_qclog[1]));
982 
983  drs_cvel_max +=cvel_max;
984  drs_cvel_min +=cvel_max;
985  ccf_posmax_zero_point =ccf_posmax_zero_point_iter0;
986  ck0_nomsg(uves_qclog_add_double(flames_qclog[1],
987  "QC CCF POSOFF",
988  ccf_posmax_zero_point,
989  "CCF pos avg from ThAr calibration",
990  "%f"));
991 
992 
993  uves_msg("cvel max:%g min: %g zp: %g",
994  drs_cvel_max,drs_cvel_min,ccf_posmax_zero_point);
995 
996 
997  }
998  //End commented region
999 
1000 
1001  /* For all identified lines fit the line width in the
1002  merged spectrum to get the resolution */
1003  for (i = 0; i < cpl_table_get_nrow(linetable); i++)
1004  {
1005  double lambda = cpl_table_get_double(
1006  linetable, LINETAB_LAMBDAC, i, NULL);
1007  double width =
1008  cpl_table_get_double(linetable, "Xwidth" , i, NULL) *
1009  fabs(cpl_table_get_double(linetable, LINETAB_PIXELSIZE, i, NULL));
1010  /* in wlu */
1011 
1012  /* Convert line wavelength and width to 'bin' units */
1013  int bin = 1 +
1014  uves_round_double((lambda - lambda_start) / wavestep);
1015  double width_bin = width / wavestep;
1016 
1017  /* Set fitting window to +-5 sigma */
1018  int first_bin = uves_max_int( 1, uves_round_double(bin - 5*width_bin));
1019  int last_bin = uves_min_int(nbins, uves_round_double(bin + 5*width_bin));
1020 
1021  double my, sigma, norm, background; /* Results of fit */
1022  double lambda_fwhm;
1023 
1024  if (cpl_table_is_valid(linetable, "Ident", i) && first_bin < last_bin)
1025  {
1026  /* Fit a gaussian to the merged arc spectrum */
1027  uves_fit_1d_image(merged,
1028 #if 1
1029  merged_noise,
1030 #else /* Unweighted fit like MIDAS which gives larger sigma */
1031  NULL,
1032 #endif
1033  NULL,
1034  true, /* Horizontal? */
1035  false, /* Fix background?*/
1036  false, /* Fit background?*/
1037  first_bin,
1038  last_bin,
1039  1, /* xlo, xhi, y */
1040  &my,
1041  &sigma,
1042  &norm,
1043  &background, NULL, /* slope */
1044  NULL,
1045  NULL,
1046  NULL, /* mse, red_chisq,
1047  covariance */
1048  uves_gauss,
1050  4);
1051 
1052  if (cpl_error_get_code() == CPL_ERROR_CONTINUE)
1053  {
1054  uves_error_reset();
1055  uves_msg_debug("Gaussian fitting failed "
1056  "at lambda = %f wlu, bins = "
1057  "%d - %d, ignoring line",
1058  lambda, first_bin, last_bin);
1059 
1060  cpl_table_set_invalid(linetable, "deltaLambda", i);
1061 
1062  }
1063  else
1064  {
1065  assure(cpl_error_get_code() == CPL_ERROR_NONE,
1066  cpl_error_get_code(), "Gaussian fitting failed");
1067 
1068  /* Convert from bins to wavelength */
1069  lambda_fwhm = TWOSQRT2LN2 * sigma * wavestep;
1070 
1071  cpl_table_set_double(linetable, "deltaLambda",
1072  i, lambda_fwhm);
1073 
1074  }
1075  }
1076  else
1077  {
1078  cpl_table_set_invalid(linetable, "deltaLambda", i);
1079  }
1080  }
1081 
1082 
1083  /* Create column 'Resol'(ution) = lambda / deltalambda */
1084  check(( cpl_table_duplicate_column(linetable, "Resol",
1085  linetable, LINETAB_LAMBDAC),
1086  cpl_table_divide_columns (linetable, "Resol",
1087  "deltaLambda")),
1088  "Error creating 'Resol' column");
1089 
1090  /* Filter out extreme outliers (due to bad gaussian fit) */
1091  {
1092 
1093  int ninvalid=0;
1094  int nrows=0;
1095  double resol_avg = 0;
1096  double resol_stdev = 0;
1097  double kappar = 10.0;
1098  nrows=cpl_table_get_nrow(linetable);
1099  ninvalid=cpl_table_count_invalid(linetable,"Resol");
1100  assure(ninvalid < nrows,CPL_ERROR_ILLEGAL_INPUT,
1101  "No valid elements in Resol column. "
1102  "You must decrease parameter rebin.wavestep");
1103  check_nomsg(resol_avg=cpl_table_get_column_median(linetable, "Resol"));
1104  check_nomsg(resol_stdev=cpl_table_get_column_stdev (linetable, "Resol"));
1105 
1106  for (i = 0; i < cpl_table_get_nrow(linetable); i++)
1107  {
1108  double r = cpl_table_get_double(linetable, "Resol", i, NULL);
1109  if (r < resol_avg - kappar*resol_stdev ||
1110  r > resol_avg + kappar*resol_stdev)
1111  {
1112  cpl_table_set_invalid(linetable, "Resol", i);
1113  cpl_table_set_invalid(linetable, "deltaLambda", i);
1114  }
1115  }
1116  }
1117 
1118  /* check( uves_plot_table(linetable, "X", "Resol",
1119  "(x, l / dl)"), "Plotting failed");
1120  check( uves_plot_table(linetable, "Y", "Resol",
1121  "(y, l / dl)"), "Plotting failed");
1122  */
1123  check( uves_plot_table(linetable, LINETAB_LAMBDAC, "Resol",
1124  "(l, l / dl)"), "Plotting failed");
1125  }
1126 
1127  /* Plot identifications */
1128  uves_free_table(&temp);
1129  check( temp = cpl_table_duplicate(linetable),
1130  "Error copying line table");
1131  check( uves_erase_invalid_table_rows(temp, "Ident"),
1132  "Error removing un-identified lines");
1133  check( uves_plot_table(temp, "X", "Ynew",
1134  "Line identifications"),
1135  "Plotting failed");
1136  uves_free_table(&temp);
1137 
1138  } /* Plots for middle (object) window */
1139 
1140  if (debug_mode)
1141  {
1142  /* Results of uves_wavecal_search are already
1143  drawn on debug_image */
1144 
1145  /* Draw guess table lines using the initial solution */
1146  if (0) check( uves_draw_lines(debug_image, initial_dispersion,
1147  order_locations, guess,
1148  "Ident", "Order", relative_order,
1149  -1, -1,
1150  false, /* true = vertical */
1151  12), "Error drawing guess solution");
1152 
1153  /* Draw catalogue lines using the initial solution */
1154  check( uves_draw_lines(debug_image, initial_dispersion, order_locations,
1155  line_refer, "Wave", NULL, relative_order,
1156  uves_min_int(*first_absolute_order, *last_absolute_order),
1157  uves_max_int(*first_absolute_order, *last_absolute_order),
1158  true, /* true = vertical */
1159  8), "Error drawing catalogue lines");
1160 
1161  /* Draw catalogue lines using the final solution */
1162  check( uves_draw_lines(debug_image, *dispersion_relation, order_locations,
1163  line_refer, "Wave", NULL, relative_order,
1164  uves_min_int(*first_absolute_order, *last_absolute_order),
1165  uves_max_int(*first_absolute_order, *last_absolute_order),
1166  true, /* true = vertical */
1167  16), "Error drawing catalogue lines");
1168 
1169  /* Draw detected lines using initial solution */
1170  if (0) check( uves_draw_lines(debug_image, initial_dispersion,
1171  order_locations, linetable,
1172  LINETAB_LAMBDAC, "Order", relative_order,
1173  -1, -1,
1174  false, /* true = vertical */
1175  -16), "Error drawing detected lines");
1176 
1177  /* Draw IDed lines */
1178  uves_free_table(&temp);
1179  check(( temp = cpl_table_duplicate(linetable),
1180  /* Delete rows with invalid 'Ident' */
1181  uves_erase_invalid_table_rows(temp, "Ident")),
1182  "Error duplicating table");
1183 
1184  check( uves_draw_lines(debug_image, *dispersion_relation, order_locations,
1185  temp, LINETAB_LAMBDAC, "Order", relative_order,
1186  -1, -1,
1187  true, /* true = vertical */
1188  0), "Error drawing detected lines");
1189 
1190 
1191  /* Explanation of drawing produced by code above:
1192  The output frame emission lines will look like this
1193 
1194 
1195  #### |1
1196  #### |2
1197  #|3#
1198  -+--
1199  #|##
1200  ####
1201  ####
1202 
1203 
1204  Legend:
1205 
1206  ##: The emmission line
1207  --: (horizontal line) The line was detected
1208  |1: (vertical line) Predicted position (final solution)
1209  |2: (vertical line) Predicted position (initial solution)
1210  |3: (vertical line) Is drawn iff the line was identified
1211 
1212 
1213 
1214  */
1215 
1216  /* Save the raw arc frame with detected emission lines marked */
1217  check( uves_save_image_local("Debug image", "rawdebug",
1218  debug_image, chip, trace, window,
1219  rotated_header, true),
1220  "Error saving spectrum");
1221  }
1222 
1223  if (flames)
1224  {
1225  int start = 0;
1226  int count = cpl_table_get_nrow(linetable);
1227 
1228  check_nomsg( cpl_table_new_column(linetable, "Fibre", CPL_TYPE_INT) );
1229 
1230  cpl_table_fill_column_window(linetable, "Fibre",
1231  start, count,
1232  trace + 1); /* Write value in range 1-9 */
1233  }
1234 
1235  cleanup:
1236 
1237  uves_free_table(&info_tbl);
1238  uves_free_table(&temp);
1239  uves_free_image(&weights_opt);
1240  uves_free_table(&cr_table);
1241  uves_free_image(&cr_image);
1242  uves_free_image(&spectrum);
1243  uves_free_image(&spectrum_noise);
1244  uves_free_image(&debug_image);
1245  uves_free_image(&rebinned);
1246  uves_free_image(&rebinned_noise);
1247  uves_free_image(&merged);
1248  uves_free_image(&merged_noise);
1249  uves_free_propertylist(&spectrum_header);
1250  uves_free_propertylist(&rebinned_header);
1251  uves_free_propertylist(&merged_header);
1252  cpl_free(relative_order);
1253  uves_polynomial_delete(&initial_dispersion);
1254  uves_free_table(&order_trace);
1255 
1256  return linetable;
1257 }
1258 
1259 
1260 
1261 /*----------------------------------------------------------------------------*/
1286 /*----------------------------------------------------------------------------*/
1287 void
1288 uves_wavecal_exe_body(cpl_frameset *frames,
1289  bool flames,
1290  const char *recipe_id,
1291  const cpl_parameterlist *parameters,
1292  const char *starttime)
1293 {
1294  /*
1295  * Variables containg the values of recipe parameters
1296  */
1297 
1298  /* General */
1299  bool debug_mode;
1300 
1301  /* Extraction */
1302  int NWINDOWS;
1303  double OFFSET;
1304  double SLITLENGTH_par; /* slitlength given by user */
1305 
1306  /* Search */
1307  int RANGE;
1308  int MAXLINES;
1309  int MINLINES;
1310  centering_method CENTERING_METHOD;
1311 
1312  /* First solution */
1313  double SHIFT_MAX;
1314  double SHIFT_STEP;
1315  double SHIFT_TOLERANCE;
1316 
1317  /* Identify */
1318  double ALPHA;
1319  double MAXERROR;
1320  int DEGREE;
1321  /* Calibrate */
1322  double TOLERANCE;
1323  double KAPPA;
1324 
1325  /* Input */
1326  cpl_image *arclamp[2] = {NULL, NULL};
1327  cpl_image *arclamp_noise = NULL;
1328  uves_propertylist *arclamp_header[2] = {NULL, NULL};
1329  uves_propertylist *rotated_header[2] = {NULL, NULL};
1330 
1331  /* Order table */
1332  cpl_table *ordertable = NULL;
1333  uves_propertylist *ordertable_header = NULL;
1334  polynomial *order_locations = NULL;
1335  cpl_table *traces = NULL;
1336 
1337  /* Bias */
1338  cpl_image *master_bias = NULL;
1339  uves_propertylist *master_bias_header = NULL;
1340 
1341  /* Flat field */
1342  cpl_image *master_flat = NULL;
1343  cpl_image *mflat_noise = NULL;
1344  uves_propertylist *master_flat_header = NULL;
1345 
1346  /* Weight map */
1347  cpl_image *weights = NULL;
1348 
1349  /* DRS guess table is not used */
1350  /*
1351  cpl_table *drs_table = NULL;
1352  uves_propertylist *drs_header = NULL;
1353  */
1354 
1355  //FLAMES-DRS specific descriptors
1356  int* fibres_mask=NULL;
1357  double* fibres_pos=NULL;
1358 
1359  /* Guess line table */
1360  cpl_table *guess = NULL;
1361  polynomial *absolute_order = NULL;
1362 
1363  /* Velocity correction table */
1364  cpl_table *corvel = NULL;
1365  cpl_frame *corvel_frm = NULL;
1366  uves_propertylist *corvel_header = NULL;
1367 
1368  /* Reference catalogue */
1369  cpl_table *line_refer = NULL;
1370  cpl_table *line_intmon = NULL;
1371 
1372  /* Output */
1373  lt_type *linetable = NULL;
1374 
1375  uves_propertylist *primary_header = NULL;
1376  uves_propertylist *table_header = NULL;
1377  /* QC for resolution + intmon + NULL */
1378  cpl_table *qclog[3] = {NULL, NULL, NULL};
1379 
1380  /* Local variables */
1381  cpl_image *absorder_image = NULL;
1382  const char *arclamp_filename = "";
1383  const char *line_refer_filename = "";
1384  const char *line_intmon_filename = "";
1385  char *product_filename = NULL;
1386  char *temp = NULL;
1387  bool blue = false;
1388  bool sim_cal = false;
1389  enum uves_chip chip;
1390  int binx = 0;
1391  int biny = 0;
1392  bool drs_cvel_sw=false;
1393  const char* PROCESS_CHIP=NULL;
1394  extract_method em;
1395 
1396  /* Read recipe parameters */
1397  {
1398  const char *centering_m = "gaussian";
1399  const char *profile = "";
1400 
1401 
1402 
1403  /* General */
1404  check( uves_get_parameter(parameters, NULL, "uves", "debug",
1405  CPL_TYPE_BOOL, &debug_mode), "Could not read parameter");
1406 
1407  check( uves_get_parameter(parameters, NULL, "uves", "process_chip", CPL_TYPE_STRING, &PROCESS_CHIP),
1408  "Could not read parameter");
1409  uves_string_toupper((char*)PROCESS_CHIP);
1410 
1411  /* Extraction */
1412  check( uves_get_parameter(parameters, NULL, recipe_id, "nwindows",
1413  CPL_TYPE_INT , &NWINDOWS ), "Could not read parameter");
1414  check( uves_get_parameter(parameters, NULL, recipe_id, "length",
1415  CPL_TYPE_DOUBLE, &SLITLENGTH_par), "Could not read parameter");
1416  check( uves_get_parameter(parameters, NULL, recipe_id, "offset",
1417  CPL_TYPE_DOUBLE, &OFFSET ), "Could not read parameter");
1418 
1419  /* Don't allow optimal extraction. This requires that
1420  additional arguments (weight image, ..) are passed to uves_extract */
1421  temp = uves_sprintf("%s.%s", recipe_id, UVES_EXTRACT_ID);
1422  check( em = uves_get_extract_method(parameters, NULL, temp),
1423  "Could not read extraction method");
1424 
1425  check( uves_get_parameter(parameters, NULL, recipe_id, UVES_EXTRACT_ID ".profile",
1426  CPL_TYPE_STRING, &profile), "Could not read parameter");
1427 
1428  assure( em == EXTRACT_LINEAR || em == EXTRACT_AVERAGE || em == EXTRACT_WEIGHTED ||
1429  (em == EXTRACT_OPTIMAL && strcmp(profile, "constant") == 0),
1430  CPL_ERROR_UNSUPPORTED_MODE,
1431  "Only linear/average/weighted/optimal(constant profile) extraction "
1432  "methods are supported by this recipe");
1433 
1434  /* Search */
1435  check( uves_get_parameter(parameters, NULL, recipe_id, "search.range",
1436  CPL_TYPE_INT , &RANGE ), "Could not read parameter");
1437  check( uves_get_parameter(parameters, NULL, recipe_id, "search.minlines",
1438  CPL_TYPE_INT , &MINLINES ), "Could not read parameter");
1439  check( uves_get_parameter(parameters, NULL, recipe_id, "search.maxlines",
1440  CPL_TYPE_INT , &MAXLINES ), "Could not read parameter");
1441 /*
1442  check( uves_get_parameter(parameters, NULL, recipe_id, "search.centeringmethod",
1443  CPL_TYPE_STRING, &centering_m ), "Could not read parameter");
1444 */
1445  if (strcmp(centering_m, "gravity" ) == 0) CENTERING_METHOD = CENTERING_GRAVITY;
1446  else if (strcmp(centering_m, "gaussian") == 0) CENTERING_METHOD = CENTERING_GAUSSIAN;
1447  else
1448  {
1449  /* Impossible */ assure(false, CPL_ERROR_ILLEGAL_INPUT,
1450  "Unrecognized parameter value '%s'", centering_m);
1451  }
1452 
1453  /* First solution */
1454  check( uves_get_parameter(parameters, NULL, recipe_id, "first.shiftmax",
1455  CPL_TYPE_DOUBLE , &SHIFT_MAX ),
1456  "Could not read parameter");
1457  check( uves_get_parameter(parameters, NULL, recipe_id, "first.shiftstep",
1458  CPL_TYPE_DOUBLE , &SHIFT_STEP ),
1459  "Could not read parameter");
1460  check( uves_get_parameter(parameters, NULL, recipe_id, "first.shifttoler",
1461  CPL_TYPE_DOUBLE , &SHIFT_TOLERANCE),
1462  "Could not read parameter");
1463 
1464  /* Identify */
1465  check( uves_get_parameter(parameters, NULL, recipe_id, "identify.alpha",
1466  CPL_TYPE_DOUBLE , &ALPHA ), "Could not read parameter");
1467  check( uves_get_parameter(parameters, NULL, recipe_id, "identify.maxerror",
1468  CPL_TYPE_DOUBLE , &MAXERROR ), "Could not read parameter");
1469  check( uves_get_parameter(parameters, NULL, recipe_id, "identify.degree",
1470  CPL_TYPE_INT , &DEGREE ), "Could not read parameter");
1471 
1472  /* Calibrate */
1473  check( uves_get_parameter(parameters, NULL, recipe_id, "calibrate.tolerance",
1474  CPL_TYPE_DOUBLE, &TOLERANCE ), "Could not read parameter");
1475  check( uves_get_parameter(parameters, NULL, recipe_id, "calibrate.kappa",
1476  CPL_TYPE_DOUBLE, &KAPPA ), "Could not read parameter");
1477 
1478  /* Additional checks */
1479  if (CENTERING_METHOD == CENTERING_GRAVITY)
1480  {
1481  uves_msg_warning("Centering method 'gravity' might lead to inaccurate "
1482  "results. Recommended is 'gaussian'");
1483  }
1484  }
1485 
1486  /* Load raw image and header, and identify input frame as red or blue */
1487  check( uves_load_arclamp(frames, flames, &arclamp_filename, arclamp, arclamp_header,
1488  rotated_header, &blue, &sim_cal), "Error loading raw frame");
1489 
1490  /* Load reference line table */
1491  check( uves_load_linerefertable(frames, &line_refer_filename, &line_refer, NULL),
1492  "Could not load line reference table");
1493  uves_msg("Using line reference table '%s'", line_refer_filename);
1494 
1495  /* Load INTensity MONitoring table if present */
1496  if (cpl_frameset_find(frames, UVES_LINE_INTMON_TABLE) != NULL)
1497  {
1498  uves_free_table(&line_intmon);
1499  check( uves_load_lineintmon(frames, &line_intmon_filename,
1500  &line_intmon),
1501  "Error loading line reference table");
1502 
1503  uves_msg("Using bright line table '%s'", line_intmon_filename);
1504  }
1505 
1506  /*
1507  * Adjust parameters according to binning
1508  */
1509  check (binx = uves_pfits_get_binx(arclamp_header[0]),
1510  "Could not read x binning factor from input header");
1511  check (biny = uves_pfits_get_biny(arclamp_header[0]),
1512  "Could not read y binning factor from input header");
1513  SLITLENGTH_par /= (1.0*binx); /* Extraction slit length */
1514  RANGE /= (1.0*biny); /* Search window */
1515  SHIFT_MAX /= (1.0*binx); /* Max shift compared to guess solution */
1516  SHIFT_STEP /= (1.0*binx);
1517 
1518  /* After the default tolerance was lowered to 0.07, do not adjust it according to binning,
1519  which would cause too many lines to be rejected
1520 
1521  TOLERANCE /= (1.0*biny);
1522  */
1523 
1524 
1525  /* Loop over one or two chips, over traces and
1526  over extraction windows */
1527  for (chip = uves_chip_get_first(blue);
1528  chip != UVES_CHIP_INVALID;
1529  chip = uves_chip_get_next(chip)) {
1530 
1531 
1532  if(strcmp(PROCESS_CHIP,"REDU") == 0) {
1533  chip = uves_chip_get_next(chip);
1534  }
1535 
1536  const char *ordertable_filename = "";
1537  const char *corvel_filename = "";
1538  const char *master_flat_filename = "";
1539  const char *master_bias_filename = "";
1540  const char *weights_filename = "";
1541  /* const char *drs_filename = ""; not used */
1542  const char *guess_filename = "";
1543  const char *chip_name = "";
1544  int ntraces;
1545  int tracerow; /* Index of table row */
1546  int raw_index = uves_chip_get_index(chip);
1547  int current_linetable_extension;
1548  int tab_in_out_oshift = -1;
1549  double tab_in_out_yshift = -1;
1550  double slitlength;
1551 
1552  uves_msg("Processing %s chip in '%s'",
1553  uves_chip_tostring_upper(chip), arclamp_filename);
1554 
1555  check_nomsg( chip_name = uves_pfits_get_chipid(arclamp_header[raw_index], chip));
1556 
1557 
1558  uves_msg_debug("binning = %dx%d", binx, biny);
1559 
1560 
1561  /* Load the order table for this chip */
1562  uves_free_table (&ordertable);
1563  uves_free_propertylist(&ordertable_header);
1564  uves_polynomial_delete(&order_locations);
1565  uves_free_table (&traces);
1566 
1567 
1568  check( uves_load_ordertable(frames,
1569  flames,
1570  chip_name,
1571  &ordertable_filename,
1572  &ordertable,
1573  &ordertable_header,
1574  NULL,
1575  &order_locations,
1576  &traces,
1577  (flames) ? &tab_in_out_oshift : NULL,
1578  (flames) ? &tab_in_out_yshift : NULL,
1579  &fibres_mask,
1580  &fibres_pos, /* fibre_pos,fibre_mask */
1581  chip,
1582  false /* load guess table? */),
1583  "Could not load order table");
1584  uves_msg("Using order table in '%s'", ordertable_filename);
1585  ntraces = cpl_table_get_nrow(traces);
1586  uves_free_double(&fibres_pos);
1587  uves_free_int(&fibres_mask);
1588 
1589  /* Load master bias if present */
1590  uves_free_image(&master_bias);
1591  uves_free_propertylist(&master_bias_header);
1592  if (cpl_frameset_find(frames, UVES_MASTER_BIAS(chip)) != NULL)
1593  {
1594  check( uves_load_mbias(frames, chip_name, &master_bias_filename, &master_bias,
1595  &master_bias_header, chip),
1596  "Error loading master bias");
1597 
1598  uves_msg_low("Using master bias in '%s'", master_bias_filename);
1599  }
1600  else
1601  {
1602  uves_msg_warning("Master bias not provided. Bias subtraction not done");
1603  }
1604 
1605 
1606  /* Load master flat if present */
1607  uves_free_image(&master_flat);
1608  uves_free_propertylist(&master_flat_header);
1609  if ((cpl_frameset_find(frames, UVES_MASTER_FLAT(chip)) != NULL ||
1610  cpl_frameset_find(frames, UVES_MASTER_DFLAT(chip)) != NULL ||
1611  cpl_frameset_find(frames, UVES_MASTER_IFLAT(chip)) != NULL ||
1612  cpl_frameset_find(frames, UVES_MASTER_TFLAT(chip)) != NULL))
1613  {
1614  check( uves_load_mflat(frames, chip_name, &master_flat_filename, &master_flat,
1615  &master_flat_header, chip, NULL),
1616  "Error loading master flat");
1617 
1618  uves_msg_low("Using master flat in '%s'", master_flat_filename);
1619  }
1620  else
1621  {
1622  uves_msg_warning("Master flat not provided. Flat-fielding not done");
1623  }
1624 
1625  /* Load weight map if present */
1626  if (em == EXTRACT_WEIGHTED) {
1627  uves_free_image(&weights);
1628  check( weights = uves_load_weights(frames, &weights_filename, chip),
1629  "Error loading weight map");
1630 
1631  uves_msg_low("Using weight map %s", weights_filename);
1632  }
1633 
1634  if (flames)
1635  /* Load CORVEL table */
1636  {
1637  if ((corvel_frm=cpl_frameset_find(frames, FLAMES_CORVEL_MASK)))
1638  {
1639  check( uves_load_corvel(frames,
1640  &corvel, &corvel_header,
1641  &corvel_filename),
1642  "Could not load velocity correction table");
1643 
1644  uves_msg("Using velocity correction table %s", corvel_filename);
1645  drs_cvel_sw=true;
1646 
1647 
1648  }
1649  else
1650  {
1651  uves_msg("No corvel table found. Switch off corvel");
1652  corvel = NULL;
1653  }
1654  }
1655 
1656  /* Allocate all line tables for this chip */
1657  uves_lt_delete(&linetable);
1658  linetable = uves_lt_new(NWINDOWS, ntraces);
1659 
1660 
1661  /* Init QC tables for this chip */
1662  uves_qclog_delete(&qclog[0]); qclog[0] = uves_qclog_init(arclamp_header[raw_index], chip);
1663  uves_qclog_delete(&qclog[1]); qclog[1] = uves_qclog_init(arclamp_header[raw_index], chip);
1664 
1665  /* Saving the rotated raw arc frame */
1666  if (debug_mode) check( uves_save_image_local("Arc lamp frame", "raw",
1667  arclamp[raw_index],
1668  chip, -1, -1, rotated_header[raw_index], true),
1669  "Error saving arc lamp frame");
1670 
1671  if (master_bias != NULL)
1672  {
1673  uves_msg("Subtracting master bias");
1674 
1675  check( uves_subtract_bias(arclamp[raw_index], master_bias),
1676  "Error during bias subtraction");
1677  }
1678  else {
1679  /* In lack of a real master bias frame, one might subtract the bias by estimating it
1680  as the median value across the chip (which should be okay for arc lamp frames)
1681  */
1682 
1683  /* Disabled. Would need to be tested. probably doesn't make any big difference anyway
1684  double bias = cpl_image_get_median(ff);
1685  uves_msg_debug("Estimated bias level is %f ADU", bias);
1686  cpl_image_subtract_scalar(ff, bias);
1687  */
1688  }
1689 
1690 
1691  /* Define arc lamp noise */
1692  uves_free_image(&arclamp_noise);
1693  check( arclamp_noise = uves_define_noise(arclamp[raw_index],
1694  arclamp_header[raw_index], 1, chip),
1695  "Could not set arc lamp noise");
1696 
1697  if (master_flat != NULL)
1698  {
1699  uves_msg("Dividing by master flat");
1700 
1701  uves_free_image(&mflat_noise);
1702  check( mflat_noise =
1703  uves_define_noise(master_flat, master_flat_header,
1704  uves_pfits_get_datancom(master_flat_header),
1705  chip),
1706  "Could not set master flat error bars");
1707 
1708  check( uves_flatfielding(arclamp[raw_index], arclamp_noise,
1709  master_flat, mflat_noise),
1710  "Error while dividing by flat field");
1711  }
1712 
1713  if (debug_mode) check( uves_save_image_local("Pre-processed arc lamp frame",
1714  "preproc",
1715  arclamp[raw_index], chip, -1, -1,
1716  rotated_header[raw_index], true),
1717  "Error saving arc lamp frame");
1718 
1719  /* Set appropriate slitlength if user did not */
1720  if (SLITLENGTH_par < 0) {
1721 
1722  double header_full_slit;
1723 
1724  check( header_full_slit =
1725  uves_pfits_get_slitlength_pixels(arclamp_header[raw_index], chip),
1726  "Could not read slit length");
1727 
1728  /* Avoid pixels at the edge of the slit
1729  * which are likely to be noisy
1730  */
1731  slitlength = uves_max_double(1.0, (header_full_slit - 2)/NWINDOWS);
1732 
1733  uves_msg("Full slit = %.2f pixels", header_full_slit);
1734  }
1735  else {
1736  slitlength = SLITLENGTH_par;
1737  }
1738 
1739 
1740  /* Loop over traces */
1741  for(tracerow = 0; tracerow < ntraces; tracerow++) {
1742  double trace_offset;
1743  int trace_number;
1744  int trace_enabled;
1745 
1746  trace_offset = cpl_table_get_double(traces, "Offset" , tracerow, NULL);
1747  trace_number = cpl_table_get_int (traces, "TraceID" , tracerow, NULL);
1748  trace_enabled = cpl_table_get_int (traces, "Tracemask", tracerow, NULL);
1749 
1750  if (ntraces > 1) {
1751  uves_msg("Processing trace %d", trace_number);
1752  }
1753 
1754  if (flames && sim_cal)
1755  {
1756  /* Only calibrate SIMCAL fibre in SIMCAL mode */
1757  trace_enabled = (trace_number == 1) ? 1 : 0;
1758  }
1759 
1760  uves_msg_low("Trace offset = %.2f pixels ; enabled = %d",
1761  trace_offset, trace_enabled);
1762 
1763  assure( flames || trace_number == 0, CPL_ERROR_ILLEGAL_INPUT,
1764  "%s: UVES trace number must be 0, it is %d",
1765  ordertable_filename, trace_number );
1766 
1767 
1768  if (trace_enabled != 0) {
1769  int window; /* window number */
1770 
1771  /* Load guess line table for this trace, any window */
1772  uves_free_table (&guess);
1773  uves_polynomial_delete(&absolute_order);
1774 
1775  check( uves_load_linetable(
1776  frames, flames, chip_name, order_locations,
1777  cpl_table_get_column_min(ordertable, "Order"),
1778  cpl_table_get_column_max(ordertable, "Order"),
1779  &guess_filename, &guess,
1780  NULL, NULL,
1781  &absolute_order, chip, trace_number, -1),
1782  "Could not load guess line table for trace number %d",
1783  trace_number);
1784  uves_msg("Using guess line table '%s'", guess_filename);
1785 
1786  if (debug_mode)
1787  {
1788  /* Create an image showing the polynomial m = f(x,y)
1789  where m is the absolute order number
1790  */
1791  int x, y;
1792 
1793  absorder_image = cpl_image_new(cpl_image_get_size_x(arclamp[raw_index]),
1794  cpl_image_get_size_y(arclamp[raw_index]),
1795  CPL_TYPE_FLOAT);
1796  assure_mem(absorder_image);
1797 
1798  for (y = 1; y <= cpl_image_get_size_y(arclamp[raw_index]); y++)
1799  {
1800  for (x = 1; x <= cpl_image_get_size_x(arclamp[raw_index]); x++)
1801  {
1802  double absorder =
1803  uves_polynomial_evaluate_2d(absolute_order, x, y);
1804 
1805  cpl_image_set(absorder_image, x, y, absorder);
1806  }
1807  }
1808 
1809  check( uves_save_image_local("Absolute order image", "absord",
1810  absorder_image, chip, trace_number,
1811  1, rotated_header[raw_index], true),
1812  "Error saving absolute order image");
1813 
1814  uves_free_image(&absorder_image);
1815  }
1816 
1817  /* Loop over sky windows */
1818  for (window = 1; window <= NWINDOWS; window ++) {
1819  /*
1820  | -trace_offs- |
1821  | | -win_offs- |
1822  | | |
1823  | | | -glb_offs- |
1824  order_loc.=0 |
1825  |
1826  window_loc.
1827  */
1828 
1829  /* Adjacent windows are separated by slitlength,
1830  and offset is zero when window_number = (NWINDOWS+1)/2,
1831  so the formula is */
1832  double window_offset =
1833  slitlength * (window - (NWINDOWS+1) / 2.0);
1834 
1835  /* Total offset (see sketch) */
1836  double offset = trace_offset + window_offset + OFFSET;
1837 
1838  /* Number of lines to detect. Use defaults if
1839  parameter values are negative */
1840 #if 0
1841  int lines_min = (MINLINES >= 1) ? MINLINES :
1842  (chip == UVES_CHIP_REDU) ? 1000 : 2000;
1843  int lines_max = (MAXLINES >= 1) ? MAXLINES :
1844  (chip == UVES_CHIP_REDU) ? 1400 : 2400;
1845 #else
1846 /* like MIDAS (fewer lines): */
1847  int lines_min = (MINLINES >= 1) ? MINLINES :
1848  (chip == UVES_CHIP_REDU) ? 1000 : 1100;
1849  int lines_max = (MAXLINES >= 1) ? MAXLINES :
1850  (chip == UVES_CHIP_REDU) ? 1400 : 1600;
1851 #endif
1852 
1853  assure( lines_min <= lines_max , CPL_ERROR_ILLEGAL_INPUT,
1854  "Minimum and maximum number of requested line "
1855  "detections don't make sense (min = %d; max = %d)",
1856  lines_min, lines_max);
1857 
1858  if (NWINDOWS > 1) {
1859  uves_msg("Processing window %d of %d", window, NWINDOWS);
1860  }
1861 
1862  passure( *(uves_lt_get_disprel(linetable, window, trace_number))
1863  == NULL, "%d %d", window, trace_number);
1864  passure( *(uves_lt_get_absord (linetable, window, trace_number))
1865  == NULL, "%d %d", window, trace_number);
1866 
1867 
1868  if (weights != NULL) {
1869  /* Object weighted extraction, use offset = 0 three times */
1870  offset = 0;
1871  }
1872 
1873  /* Set absord guess solution */
1874  *uves_lt_get_absord(linetable, window, trace_number) =
1875  uves_polynomial_duplicate(absolute_order);
1876 
1877  /* Execute macrosteps */
1878  check( *uves_lt_get_table(linetable, window, trace_number) =
1879  uves_wavecal_process_window(
1880  /* Raw */
1881  arclamp[raw_index],
1882  arclamp_noise,
1883  rotated_header[raw_index],
1884  /* Calibration */
1885  ordertable, order_locations,
1886  master_flat != NULL,
1887  weights,
1888  /* drs_table, not used */
1889  guess,
1890  line_refer,
1891  flames,
1892  tab_in_out_oshift,
1893  tab_in_out_yshift,
1894  /* Which window? */
1895  chip, biny, trace_number, window,NWINDOWS,
1896  /* Parameters */
1897  debug_mode,
1898  /* Extract */
1899  offset, slitlength, parameters, recipe_id,
1900  /* Search */
1901  RANGE, lines_min, lines_max, CENTERING_METHOD,
1902  /* First solution */
1903  SHIFT_MAX, SHIFT_STEP, SHIFT_TOLERANCE,
1904  /* Identify */
1905  ALPHA, MAXERROR, DEGREE,
1906  /* Calibrate */
1907  TOLERANCE, KAPPA,
1908  corvel_frm,qclog,
1909  /* Returned */
1910  uves_lt_get_disprel(linetable, window, trace_number),
1911  uves_lt_get_absord (linetable, window, trace_number),
1912  uves_lt_get_firstabs(linetable, window, trace_number),
1913  uves_lt_get_lastabs(linetable, window, trace_number)),
1914  "Wavelength calibration failed");
1915 
1916 
1917  //If CORVEL map is provided we perform the
1918  //corresponding analysis
1919  if(drs_cvel_sw) {
1920  /*
1921  define/local ord_min/i/1/1 0
1922  define/local ord_max/i/1/1 0
1923  define/local rsample/d/1/1 0
1924  statistic/table {ORDTAB} :ORDER >Null
1925  ord_min = outputr(1)
1926  ord_max = outputr(2)
1927  rsample = {{LINTAB},PIXEL(1)}
1928  rsample = 2./3. * rsample
1929  rebin/echelle {ofrm} w{ofrm} {rsample} NONL {LINTAB} {SESSOUTV}
1930  mercut/echelle w{ofrm} mw{ofrm} {ord_min},{ord_max} NOAPPEND
1931  !corvel stuff
1932  define/local OLD_CVEL_MAX/d/1/1 {DRS_CVEL_MAX}
1933  define/local OLD_CVEL_MIN/d/1/1 {DRS_CVEL_MIN}
1934  @p flames_reduce,VCORREL x1_rbf_ cvel1 0 {ord_max} {parCorVelTab} _0 _{chip({PATHID})} 0
1935  DRS_CVEL_MAX = DRS_CVEL_MAX + {q1}
1936  DRS_CVEL_MIN = DRS_CVEL_MIN + {q1}
1937 
1938  @p flames_reduce,VCORREL x1_rbf_ cvel2 0 {ord_max} {parCorVelTab} _0 _{chip({PATHID})} 0
1939  cvel_0 = {q1}
1940  DRS_CVEL_MAX = OLD_CVEL_MAX
1941  DRS_CVEL_MIN = OLD_CVEL_MIN
1942  */
1943 
1944 
1945  }
1946 
1947 
1948 
1949  if (flames || /* FLAMES: all fibres */
1950  (window == 2 && trace_number == 0)|| /* UVES: central window */
1951  (window == 1 && NWINDOWS == 1)) { /* UVES: special user setting */
1952 
1953  check( uves_wavecal_qclog(
1955  linetable,
1956  window,
1957  trace_number),
1958  *uves_lt_get_firstabs(linetable, window, trace_number),
1959  *uves_lt_get_lastabs(linetable, window, trace_number),
1960  arclamp[raw_index],
1961  arclamp_header[raw_index],
1962  flames,
1963  trace_number, trace_enabled, trace_offset,
1964  chip,
1965  qclog[0]),
1966  "Could not calculate resolution QC parameters");
1967 
1968  if (line_intmon != NULL) {
1969  check( uves_wavecal_qclog_intmon(
1971  linetable,
1972  window,
1973  trace_number),
1974  line_intmon,
1975  arclamp_header[raw_index],
1976  flames, trace_number,
1977  chip,
1978  qclog[1]),
1979  "Could not calculate int.mon. QC parameters");
1980  }
1981  else
1982  {
1983  /* Kill initialization and set pointer to NULL */
1984  uves_qclog_delete(&qclog[1]);
1985  }
1986  }
1987 
1988  /* Finished processing. Save later (because
1989  all QC parameters must be available
1990  when the product file is first created). */
1991 
1992  }/* for each window... */
1993 
1994  }/* if trace enabled? */
1995  else
1996  {
1997  uves_msg("Skipping trace number %d", trace_number);
1998  }
1999  }/* for each trace... */
2000 
2001  /* Finished calculating all line tables for current chip. Now save. */
2002 
2003  /* Prepare product filename
2004  (which need not be calculated for each trace and window) */
2005  cpl_free(product_filename);
2006  check( product_filename = uves_line_table_filename(chip), "Error getting filename");
2007  current_linetable_extension = 1;
2008 
2009  /* Loop over traces */
2010  char extname[80];
2011  for(tracerow = 0; tracerow < cpl_table_get_nrow(traces); tracerow++)
2012  {
2013  int trace_number;
2014  double trace_offset;
2015  int trace_enabled;
2016 
2017  trace_offset = cpl_table_get_double(traces, "Offset" , tracerow, NULL);
2018  trace_number = cpl_table_get_int (traces, "TraceID" , tracerow, NULL);
2019  trace_enabled = cpl_table_get_int (traces, "Tracemask" , tracerow, NULL);
2020 
2021  if (trace_enabled != 0)
2022  {
2023  int window;
2024 
2025  /* Loop over sky windows */
2026  for (window = 1; window <= NWINDOWS; window ++)
2027  {
2028  double window_offset =
2029  slitlength * (window - (NWINDOWS+1) / 2.0);
2030 
2031  double offset = trace_offset + window_offset + OFFSET;
2032 
2033  /* Table header */
2034  uves_free_propertylist(&table_header);
2035  table_header = uves_propertylist_new();
2036  check( uves_pfits_set_traceid ( table_header, trace_number),
2037  "Error writing trace ID to product header");
2038  check( uves_pfits_set_offset ( table_header, offset),
2039  "Error writing trace offset to product header");
2040  check( uves_pfits_set_windownumber( table_header, window),
2041  "Error writing window number to product header");
2042 
2043  sprintf(extname,"LINE_T%d_W%d_X%d",trace_number,window,
2044  current_linetable_extension);
2045  uves_pfits_set_extname(table_header,extname);
2046 
2047  check( uves_pfits_set_firstabsorder( table_header,
2049  linetable,
2050  window,
2051  trace_number)),
2052  "Error writing order number to product header");
2053  check( uves_pfits_set_lastabsorder( table_header,
2055  linetable,
2056  window,
2057  trace_number)),
2058  "Error writing order number to product header");
2059 
2060  /* Save line table + 2 polynomials (in 3 extensions) */
2061 
2062  if (current_linetable_extension == 1) {
2063  uves_free_propertylist(&primary_header);
2064  primary_header = uves_propertylist_new();
2065 
2066  if (flames)
2067  {
2068  char values[80];
2069  /* The MIDAS pipeline writes this QC to the
2070  header (always zero), but not as part of
2071  the QC logging */
2073  primary_header, 0.0) );
2074  //Add descriptors needed for science reduction
2075  /* FIBREMASK */
2076 
2077  uves_propertylist_append_string(primary_header,
2078  "HISTORY",
2079  "'FIBREMASK','I*4'");
2080 
2081  {
2082  int i;
2083  for (i = 0; i < N_FIBRES_MAX; i++) {
2084  snprintf(values, 80, "%1.1d ",
2085  cpl_table_get_int(traces,"Tracemask",
2086  i,NULL));
2087  uves_propertylist_append_string(primary_header,
2088  "HISTORY", values);
2089  uves_msg_debug("value=%d",
2090  cpl_table_get_int(traces,
2091  "Tracemask",
2092  i,NULL));
2093  }
2094  }
2095  uves_propertylist_append_string(primary_header,
2096  "HISTORY", " ");
2097 
2098 
2099  /* PIXEL */
2100  double pixelsize;
2101  double wavestep;
2102 
2103  check( pixelsize =
2104  cpl_table_get_column_mean(
2106  linetable,
2107  window,
2108  trace_number),
2109  LINETAB_PIXELSIZE),
2110  "Error reading mean pixelsize");
2111  uves_msg_warning("Average pixelsize = %f w.l.u.",
2112  pixelsize);
2113 
2114  wavestep = pixelsize*2.0/3;
2115 
2116  uves_propertylist_append_string(primary_header,
2117  "HISTORY",
2118  "'PIXEL','R*4'");
2119  snprintf(values,80,"%14.7g %14.7g",pixelsize,pixelsize);
2120  uves_propertylist_append_string(primary_header,
2121  "HISTORY", values);
2122  uves_propertylist_append_string(primary_header,
2123  "HISTORY", " ");
2124 
2125 
2126 
2127  }
2128 
2129  uves_msg("Creating line table '%s'", product_filename);
2130  uves_pfits_set_extname(primary_header,"wavelength calibration solution");
2131  sprintf(extname,"LINE_T%d_W%d_X%d",trace_number,window,
2132  current_linetable_extension);
2133  uves_pfits_set_extname(table_header,extname);
2134 
2135  check( uves_frameset_insert(
2136  frames,
2138  linetable,
2139  window,
2140  trace_number),
2141  CPL_FRAME_GROUP_PRODUCT,
2142  CPL_FRAME_TYPE_TABLE,
2143  CPL_FRAME_LEVEL_INTERMEDIATE,
2144  product_filename,
2145  UVES_LINE_TABLE(flames, chip),
2146  arclamp_header[raw_index],
2147  primary_header,
2148  table_header,
2149  parameters,
2150  recipe_id,
2151  PACKAGE "/" PACKAGE_VERSION,
2152  qclog, starttime, true, 0),
2153  "Could not add line table '%s' (%s) to frameset",
2154  product_filename, UVES_LINE_TABLE(flames, chip));
2155 
2156  uves_msg("Line table '%s' (%s) added to frameset",
2157  product_filename, UVES_LINE_TABLE(flames, chip));
2158  }
2159  else /* If this is not the first line table,
2160  append to the existing file */
2161  {
2162  check( uves_table_save(
2163  *uves_lt_get_table(linetable,
2164  window,
2165  trace_number),
2166  NULL, /* Primary header,
2167  ignored when mode
2168  is IO_EXTEND */
2169  table_header, /* Extension header */
2170  product_filename,/* This file
2171  already exists */
2172  CPL_IO_EXTEND), /* Append to
2173  existing file */
2174  "Error appending table to file '%s'",
2175  product_filename);
2176  }
2177  current_linetable_extension += 1;
2178  sprintf(extname,"LINE_T%d_W%d_X%d",trace_number,window,
2179  current_linetable_extension);
2180  uves_pfits_set_extname(table_header,extname);
2181  /* Save in next extension */
2182  check( uves_save_polynomial(*uves_lt_get_disprel(
2183  linetable,
2184  window,
2185  trace_number),
2186  product_filename,
2187  table_header),
2188  "Could not write polynomial to file '%s'",
2189  product_filename);
2190  current_linetable_extension += 1;
2191  sprintf(extname,"LINE_T%d_W%d_X%d",trace_number,window,
2192  current_linetable_extension);
2193  uves_pfits_set_extname(table_header,extname);
2194  /* Save in next extension */
2195  check( uves_save_polynomial(*uves_lt_get_absord(
2196  linetable,
2197  window,
2198  trace_number),
2199  product_filename,
2200  table_header),
2201  "Could not write polynomial to file '%s'",
2202  product_filename);
2203  current_linetable_extension += 1;
2204 
2205  uves_msg("Line table for trace %d, window #%d "
2206  "saved to extensions %d-%d of '%s'",
2207  trace_number, window,
2208  current_linetable_extension - 3,
2209  current_linetable_extension - 1,
2210  product_filename);
2211 
2212  } /* for each window */
2213  } /* if trace enabled */
2214  } /* for each trace */
2215 
2216  if(strcmp(PROCESS_CHIP,"REDL") == 0) {
2217  chip = uves_chip_get_next(chip);
2218  }
2219 
2220 
2221  }/* For each chip */
2222 
2223  cleanup:
2224 
2225  /* Input */
2226  uves_free_image(&arclamp[0]);
2227  uves_free_image(&arclamp[1]);
2228  uves_free_image(&arclamp_noise);
2229  uves_free_image(&absorder_image);
2230  uves_free_propertylist(&arclamp_header[0]);
2231  uves_free_propertylist(&arclamp_header[1]);
2232  uves_free_propertylist(&rotated_header[0]);
2233  uves_free_propertylist(&rotated_header[1]);
2234 
2235 
2236  uves_free_table(&ordertable);
2237  uves_free_propertylist(&ordertable_header);
2238  uves_free_table(&corvel);
2239  uves_free_propertylist(&corvel_header);
2240  uves_polynomial_delete(&order_locations);
2241  uves_polynomial_delete(&absolute_order);
2242  uves_free_table(&traces);
2243 
2244 
2245  uves_free_image(&master_bias);
2246  uves_free_propertylist(&master_bias_header);
2247  uves_free_image(&master_flat);
2248  uves_free_image(&mflat_noise);
2249  uves_free_propertylist(&master_flat_header);
2250  uves_free_image(&weights);
2251 
2252 
2253  /* DRS not used
2254  uves_free_table(&drs_table);
2255  uves_free_propertylist(&drs_header);
2256  */
2257 
2258  uves_free_table(&guess);
2259 
2260  uves_free_table(&line_refer);
2261  uves_free_table(&line_intmon);
2262 
2263 
2264  /* Output */
2265  uves_lt_delete(&linetable);
2266  uves_free_propertylist(&primary_header);
2267  uves_free_propertylist(&table_header);
2268  uves_qclog_delete(&qclog[0]);
2269  uves_qclog_delete(&qclog[1]);
2270 
2271  cpl_free(product_filename);
2272  cpl_free(temp);
2273 
2274  return;
2275 }
2276 
2277 
2290 static void uves_wavecal_qclog(const cpl_table* linetable,
2291  int firstabs,
2292  int lastabs,
2293  const cpl_image *arclamp,
2294  const uves_propertylist* raw_header,
2295  bool flames,
2296  int trace_number,
2297  int fibre_mask,
2298  double offset,
2299  enum uves_chip chip,
2300  cpl_table* qclog)
2301 {
2302 
2303  const char *qc_fib_drsno_name= uves_qclog_get_qc_name("DRSNO", flames, trace_number);
2304  const char *qc_fib_seq_name = uves_qclog_get_qc_name("SEQ", flames, trace_number);
2305  const char *qc_fib_pos_name = uves_qclog_get_qc_name("POS", flames, trace_number);
2306  const char *qc_fib_msk_name = uves_qclog_get_qc_name("MSK", flames, trace_number);
2307  const char *qc_fwhmavg_name = uves_qclog_get_qc_name("FWHMAVG", flames, trace_number);
2308  const char *qc_fwhmrms_name = uves_qclog_get_qc_name("FWHMRMS", flames, trace_number);
2309  const char *qc_fwhmmed_name = uves_qclog_get_qc_name("FWHMMED", flames, trace_number);
2310  const char *qc_resolavg_name = uves_qclog_get_qc_name("RESOLAVG", flames, trace_number);
2311  const char *qc_resolrms_name = uves_qclog_get_qc_name("RESOLRMS", flames, trace_number);
2312  const char *qc_resolmed_name = uves_qclog_get_qc_name("RESOLMED", flames, trace_number);
2313  const char *qc_wlenmin_name = uves_qclog_get_qc_name("WLENMIN", flames, trace_number);
2314  const char *qc_wlenmax_name = uves_qclog_get_qc_name("WLENMAX", flames, trace_number);
2315  const char *qc_ordmin_name = uves_qclog_get_qc_name("ORDMIN", flames, trace_number);
2316  const char *qc_ordmax_name = uves_qclog_get_qc_name("ORDMAX", flames, trace_number);
2317  const char *qc_detected_ordmin_name = uves_qclog_get_qc_name("ORDMIN DETECTED", flames, trace_number);
2318  const char *qc_detected_ordmax_name = uves_qclog_get_qc_name("ORDMAX DETECTED", flames, trace_number);
2319  const char *qc_nlintot_name = uves_qclog_get_qc_name("NLINTOT", flames, trace_number);
2320  const char *qc_nlinsel_name = uves_qclog_get_qc_name("NLINSEL", flames, trace_number);
2321  const char *qc_nlinsol_name = uves_qclog_get_qc_name("NLINSOL", flames, trace_number);
2322  const char *qc_line_werr_name = uves_qclog_get_qc_name("LINE WAVEERR", flames, trace_number);
2323  const char *qc_line_wsys_name = uves_qclog_get_qc_name("LINE SYSERR", flames, trace_number);
2324  const char *qc_nlinres1_name = uves_qclog_get_qc_name("NLINRES1", flames, trace_number);
2325  const char *qc_lineresidavg_name =
2326  uves_qclog_get_qc_name("LINE RESIDAVG", flames, trace_number);
2327  const char *qc_lineresidrms_name =
2328  uves_qclog_get_qc_name("LINE RESIDRMS", flames, trace_number);
2329  char comment[80];
2330  cpl_table *selected = NULL;
2331  double wmin=0;
2332  double wmax=0;
2333  double wcen=0;
2334  int nfinal=0;
2335 
2336  char test_id[80];
2337  sprintf(test_id,"%sResolution-Test-Results",flames ? "Fibre-" : "");
2338 
2340  "QC TEST1 ID",
2341  test_id,
2342  "Name of QC test",
2343  "%s"));
2344 
2345  check_nomsg( uves_qclog_add_common_wave(raw_header, chip, qclog) );
2346 
2347  if (flames)
2348  {
2349  /* Fibre ID */
2351  qc_fib_drsno_name,
2352  trace_number + 1,
2353  "DRS det. fibre seq. pos.",
2354  "%d"));
2355 
2356  /* Index */
2358  qc_fib_seq_name,
2359  trace_number + 1,
2360  "det. fibre seq. no.",
2361  "%d"));
2362 
2364  qc_fib_pos_name,
2365  offset,
2366  "det. fibre seq. rel. pos.",
2367  "%.4f"));
2368 
2370  qc_fib_msk_name,
2371  fibre_mask,
2372  "DRS det. fibre mask value",
2373  "%d"));
2374 
2375  {
2376 
2377  double exptime;
2378 
2379  check( exptime = uves_flames_pfits_get_dit(raw_header),
2380  "Error reading exposure time");
2381 
2383  "QC FIB ABSTRANS",
2384  cpl_image_get_flux(arclamp) / exptime,
2385  "abs. trans. countrate",
2386  "%.4f"));
2387  }
2388  {
2389  int n_hpix;
2390  int x, y;
2391 
2392  n_hpix = 0;
2393  for (y = 1; y <= cpl_image_get_size_y(arclamp); y++)
2394  for (x = 1; x <= cpl_image_get_size_x(arclamp); x++)
2395  {
2396  int pis_rejected;
2397  int value = cpl_image_get(arclamp, x, y, &pis_rejected);
2398 
2399  if (!pis_rejected &&
2400  (value < DRS_PTHRES_MIN || value > DRS_PTHRES_MAX))
2401  {
2402  n_hpix += 1;
2403  }
2404  }
2405 
2407  "QC NHOTPIX",
2408  n_hpix,
2409  "no. of hot pixels",
2410  "%d"));
2411 
2412  }
2413 
2414  {
2415  int plate_id;
2416  check( plate_id = uves_flames_pfits_get_plateid(raw_header),
2417  "Error reading plate ID");
2419  "QC PLATENO",
2420  plate_id,
2421  "Plate Id.",
2422  "%d"));
2423  }
2424 
2425  } /* if flames */
2426 
2427  /* FLAMES + UVES common QC params */
2428  selected = uves_extract_table_rows(linetable, "NLinSol", CPL_NOT_EQUAL_TO, 0);
2429  /* FWHM in pixels */
2430  sprintf(comment,"average FWHM in X of sel lines on TRACE%d WIN2 [pix]",trace_number);
2432  qc_fwhmavg_name,
2433  cpl_table_get_column_mean(selected,"Xwidth")*TWOSQRT2LN2,
2434  comment,
2435  "%.2f"));
2436 
2437  sprintf(comment,"stdev FWHM in X of sel lines on TRACE%d WIN2 [pix]",trace_number);
2439  qc_fwhmrms_name,
2440  cpl_table_get_column_stdev(selected,"Xwidth")*TWOSQRT2LN2,
2441  comment,
2442  "%.4f"));
2443 
2444  sprintf(comment,"median FWHM in X of sel lines on TRACE%d WIN2 [pix]",trace_number);
2446  qc_fwhmmed_name,
2447  cpl_table_get_column_median(selected,"Xwidth")*TWOSQRT2LN2,
2448  comment,
2449  "%.4f"));
2450 
2451  sprintf(comment,"mean R of sel lines on TRACE%d WIN2",trace_number);
2453  qc_resolavg_name,
2454  cpl_table_get_column_mean(selected,"Resol"),
2455  comment,
2456  "%.4f"));
2457 
2458  sprintf(comment,"stdev R of sel lines on TRACE%d WIN2",trace_number);
2460  qc_resolrms_name,
2461  cpl_table_get_column_stdev(selected,"Resol"),
2462  comment,
2463  "%.4f"));
2464 
2465  sprintf(comment,"median R of sel lines on TRACE%d WIN2",trace_number);
2467  qc_resolmed_name,
2468  cpl_table_get_column_median(selected,"Resol"),
2469  comment,
2470  "%.4f"));
2471 
2472  /* Convert A -> picometers */
2473  sprintf(comment,"mean line pos resid on TRACE%d WIN2 [pm]",trace_number);
2475  qc_lineresidavg_name,
2476  cpl_table_get_column_mean(selected, LINETAB_RESIDUAL)*100,
2477  comment,
2478  "%.4f"));
2479 
2480  sprintf(comment,"sigma line pos resid on TRACE%d WIN2 [pm]",trace_number);
2482  qc_lineresidrms_name,
2483  cpl_table_get_column_stdev(selected, LINETAB_RESIDUAL)*100,
2484  comment,
2485  "%.4f"));
2486 
2487  /* Convert A -> nm */
2488  wmin=cpl_table_get_column_min(linetable,LINETAB_LAMBDAC)/10.0;
2489  sprintf(comment,"minimum wavelength on TRACE%d WIN2 [nm]",trace_number);
2491  qc_wlenmin_name,
2492  wmin,
2493  comment,
2494  "%.4f"));
2495 
2496  wmax=cpl_table_get_column_max(linetable,LINETAB_LAMBDAC)/10.0;
2497  sprintf(comment,"maximum wavelength on TRACE%d WIN2 [nm]",trace_number);
2499  qc_wlenmax_name,
2500  wmax,
2501  comment,
2502  "%.4f"));
2503 
2504  sprintf(comment,"minimum order number expected on TRACE%d WIN2",trace_number);
2506  qc_ordmin_name,
2507  uves_min_int(firstabs, lastabs),
2508  comment,
2509  "%d"));
2510 
2511  sprintf(comment,"maximum order number expected on TRACE%d WIN2",trace_number);
2513  qc_ordmax_name,
2514  uves_max_int(firstabs, lastabs),
2515  comment,
2516  "%d"));
2517 
2518 
2519  sprintf(comment,"minimum order number detected on TRACE%d WIN2",trace_number);
2521  qc_detected_ordmin_name,
2522  cpl_table_get_column_min(linetable,"Order"),
2523  comment,
2524  "%d"));
2525 
2526  sprintf(comment,"maximum order number detected on TRACE%d WIN2",trace_number);
2528  qc_detected_ordmax_name,
2529  cpl_table_get_column_max(linetable,"Order"),
2530  comment,
2531  "%d"));
2532 
2533  sprintf(comment,"No. of lines found on TRACE%d WIN2",trace_number);
2535  qc_nlintot_name,
2536  cpl_table_get_nrow(linetable),
2537  comment,
2538  "%d"));
2539 
2540  sprintf(comment,"No. of lines selected on TRACE%d WIN2",trace_number);
2542  qc_nlinsel_name,
2543  cpl_table_get_nrow(linetable) -
2544  cpl_table_count_invalid(linetable, "Ident"),
2545  comment,
2546  "%d"));
2547 
2548  nfinal=cpl_table_get_nrow(selected);
2549  sprintf(comment,"Final No. of lines used on TRACE%d WIN2",trace_number);
2551  qc_nlinsol_name,
2552  nfinal,
2553  comment,
2554  "%d"));
2555 
2556  cpl_table* extracted=NULL;
2557  double rms_wlu=0;
2558  const char* rms_wlu_alpha=NULL;
2559  double lines_sqrt=0;
2560  double lines_werr=0;
2561  int next=0;
2562  wcen=0.5*(wmin+wmax);
2563  check_nomsg(next=cpl_table_and_selected_string(qclog,"key_name",
2564  CPL_EQUAL_TO,
2565  "QC LINE RESIDRMS WLU"));
2566  check_nomsg(extracted=cpl_table_extract_selected(qclog));
2567 
2568  check_nomsg(rms_wlu_alpha=cpl_table_get_string(extracted,"key_value",0));
2569  rms_wlu=atof(rms_wlu_alpha);
2570  lines_sqrt=sqrt(nfinal);
2571  lines_werr=rms_wlu/lines_sqrt;
2572  sprintf(comment,"Wavelength error on TRACE%d [Angstrom]",trace_number);
2574  qc_line_werr_name,
2575  lines_werr,
2576  comment,
2577  "%.3g"));
2578 
2579  uves_free_table(&extracted);
2580  uves_free_table(&selected);
2581  selected = cpl_table_duplicate(linetable);
2582  assure_mem( selected );
2583 
2584 
2585  sprintf(comment,"Wavelength systematic error on TRACE%d [Angstrom]",trace_number);
2587  qc_line_wsys_name,
2588  wcen*100./SPEED_OF_LIGHT,
2589  comment,
2590  "%f"));
2591 
2592 
2593  /* Remove unidentified lines and
2594  lines with residual > 1 A */
2595  check_nomsg( uves_erase_invalid_table_rows(selected, "Ident") );
2596  check_nomsg( uves_erase_table_rows(selected, LINETAB_RESIDUAL,
2597  CPL_NOT_LESS_THAN,
2598  1.0) );
2599 
2600  sprintf(comment,"No. of lines with residuals < 0.1 nm on TRACE%d",trace_number);
2602  qc_nlinres1_name,
2603  cpl_table_get_nrow(selected),
2604  comment,
2605  "%d"));
2606 
2607 
2608  cleanup:
2609 
2610  uves_free_string_const(&qc_fib_drsno_name);
2611  uves_free_string_const(&qc_fib_seq_name);
2612  uves_free_string_const(&qc_fib_pos_name);
2613  uves_free_string_const(&qc_fib_msk_name);
2614  uves_free_string_const(&qc_fwhmavg_name);
2615  uves_free_string_const(&qc_fwhmrms_name);
2616  uves_free_string_const(&qc_fwhmmed_name);
2617 
2618  uves_free_string_const(&qc_resolavg_name);
2619  uves_free_string_const(&qc_resolrms_name);
2620  uves_free_string_const(&qc_resolmed_name);
2621  uves_free_string_const(&qc_wlenmin_name);
2622  uves_free_string_const(&qc_wlenmax_name);
2623  uves_free_string_const(&qc_ordmin_name);
2624  uves_free_string_const(&qc_ordmax_name);
2625  uves_free_string_const(&qc_nlintot_name);
2626  uves_free_string_const(&qc_nlinsel_name);
2627  uves_free_string_const(&qc_line_werr_name);
2628  uves_free_string_const(&qc_line_wsys_name);
2629  uves_free_string_const(&qc_nlinsol_name);
2630  uves_free_string_const(&qc_nlinres1_name);
2631  uves_free_string_const(&qc_lineresidavg_name);
2632  uves_free_string_const(&qc_lineresidrms_name);
2633  uves_free_string_const(&qc_detected_ordmin_name);
2634  uves_free_string_const(&qc_detected_ordmax_name);
2635 
2636  uves_free_table(&selected);
2637 
2638  return;
2639 
2640 }
2641 
2650 static void uves_wavecal_qclog_intmon(cpl_table* table,
2651  const cpl_table *line_intmon,
2652  const uves_propertylist* raw_header,
2653  bool flames,
2654  int fibre,
2655  enum uves_chip chip,
2656  cpl_table* qclog)
2657 {
2658  const char *qc_intavg_name = NULL;
2659  const char *qc_nlinint_name = NULL;
2660 
2661  cpl_table *temp = NULL;
2662 
2664  "QC TEST2 ID",
2665  flames ? "Fibre-Line-Intensity-Test-Results"
2666  : "Line-Intensity-Test-Results",
2667  "Name of QC test",
2668  "%s"));
2669 
2671  chip, qclog) );
2672 
2673  {
2674  double tolerance = 0.001; /* (A)
2675  The lines in the line table
2676  and intmon table are considered
2677  identical if the difference
2678  is less than this number.
2679  */
2680 
2681  double exptime;
2682 
2683  int N_bright = cpl_table_get_nrow(line_intmon);
2684  int i;
2685 
2686  check( exptime = uves_pfits_get_exptime(raw_header),
2687  "Could not get exposure time");
2688 
2689  cpl_table_new_column(table, "Intensity", CPL_TYPE_DOUBLE);
2690  for (i = 0; i < cpl_table_get_nrow(table); i++)
2691  {
2692  int is_null;
2693  double ident = cpl_table_get_double(table, "Ident", i, &is_null);
2694 
2695  if (!is_null)
2696  {
2697  int bright_index = uves_wavecal_find_nearest(
2698  line_intmon, ident, 0, N_bright-1);
2699 
2700  double bright = cpl_table_get_double(
2701  line_intmon, "Wave", bright_index, NULL);
2702 
2703  if (fabs(bright - ident) < tolerance)
2704  {
2705  double peak = cpl_table_get_double(table, "Peak", i, NULL);
2706  double pixelsize =
2707  fabs(cpl_table_get_double(table, LINETAB_PIXELSIZE, i, NULL));
2708 
2709  double lambda_fwhm = cpl_table_get_double(table, "Xwidth", i, NULL)
2710  * TWOSQRT2LN2 * pixelsize;
2711  /* Line FWHM in wlu */
2712 
2713  double intensity = peak * lambda_fwhm / exptime;
2714  /* Same formula as in MIDAS */
2715 
2716  cpl_table_set_double(table, "Intensity", i, intensity);
2717  }
2718  else
2719  {
2720  cpl_table_set_invalid(table, "Intensity", i);
2721  }
2722  }
2723  else
2724  {
2725  cpl_table_set_invalid(table, "Intensity", i);
2726  }
2727  }
2728  }
2729 
2730  uves_free_table(&temp);
2731  temp = cpl_table_duplicate(table);
2732  uves_erase_invalid_table_rows(temp, "Intensity");
2733 
2734  {
2735  double mean;
2736  if (cpl_table_get_nrow(temp) == 0)
2737  {
2738  uves_msg_warning("No bright lines found!");
2739  mean = 0;
2740  }
2741  else
2742  {
2743  mean = cpl_table_get_column_mean(temp, "Intensity");
2744  }
2745 
2746  if (flames)
2747  {
2748  qc_intavg_name = uves_sprintf("QC FIB%d INTAVG", fibre+1); /* Count 1-9 */
2749  qc_nlinint_name = uves_sprintf("QC FIB%d NLININT", fibre+1);
2750  }
2751  else
2752  {
2753  qc_intavg_name = uves_sprintf("QC INTAVG");
2754  qc_nlinint_name = uves_sprintf("QC NLININT");
2755  }
2756 
2758  qc_intavg_name,
2759  mean,
2760  "average intensity of line list on TRACE0 WIN2",
2761  "%.4f"));
2762 
2764  qc_nlinint_name,
2765  cpl_table_get_nrow(temp),
2766  "No. of lines to measure INTAVG on TRACE0 WIN2",
2767  "%d"));
2768  }
2769 
2770  cleanup:
2771  uves_free_string_const(&qc_intavg_name);
2772  uves_free_string_const(&qc_nlinint_name);
2773  uves_free_table(&temp);
2774  return;
2775 }
2776 
2777 
cpl_table ** uves_lt_get_table(const lt_type *lt, int window, int trace)
Get the table structure.
int uves_pfits_get_datancom(const uves_propertylist *plist)
Find out the number of input raw frames.
Definition: uves_pfits.c:1212
void uves_polynomial_delete(polynomial **p)
Delete a polynomial.
#define uves_msg_warning(...)
Print an warning message.
Definition: uves_msg.h:87
int uves_flames_pfits_get_plateid(const uves_propertylist *raw_header)
read the plate id
Definition: uves_pfits.c:3201
void uves_pfits_set_windownumber(uves_propertylist *plist, int window_number)
Write the window number.
Definition: uves_pfits.c:1944
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
int * uves_lt_get_lastabs(const lt_type *lt, int window, int trace)
Get last absolute order.
int uves_qclog_add_string(cpl_table *table, const char *key_name, const char *value, const char *key_help, const char *format)
Add string key to QC-LOG table.
Definition: uves_qclog.c:683
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
lt_type * uves_lt_new(int windows, int traces)
Allocate line table.
cpl_error_code uves_subtract_bias(cpl_image *image, const cpl_image *master_bias)
Subtract bias.
Definition: uves_utils.c:2394
int uves_qclog_delete(cpl_table **table)
delete QC-LOG table
Definition: uves_qclog.c:716
#define passure(BOOL,...)
Definition: uves_error.h:207
int uves_gauss_derivative(const double x[], const double a[], double result[])
Evaluate the derivatives of a gaussian.
Definition: uves_utils.c:4346
int uves_qclog_add_double(cpl_table *table, const char *key_name, const double value, const char *key_help, const char *format)
Add double key to QC-LOG table.
Definition: uves_qclog.c:641
int uves_qclog_add_int(cpl_table *table, const char *key_name, const int value, const char *key_help, const char *format)
Add integer key to QC-LOG table.
Definition: uves_qclog.c:521
polynomial ** uves_lt_get_disprel(const lt_type *lt, int window, int trace)
Get dispersion relation.
uves_propertylist * uves_propertylist_new(void)
Create an empty property list.
int uves_pfits_get_binx(const uves_propertylist *plist)
Find out the x binning factor.
Definition: uves_pfits.c:1176
#define uves_msg(...)
Print a message on 'info' or 'debug' level.
Definition: uves_msg.h:119
int uves_gauss(const double x[], const double a[], double *result)
Evaluate a gaussian.
Definition: uves_utils.c:4291
void uves_pfits_set_traceid(uves_propertylist *plist, int trace_id)
Write the trace ID.
Definition: uves_pfits.c:1888
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
polynomial * uves_wavecal_identify(cpl_table *linetable, const cpl_table *line_refer, const polynomial *guess_dispersion, int DEGREE, double TOLERANCE, double ALPHA, double MAXERROR, double kappa, const int trace, const int window, cpl_table *qclog)
Obtain final dispersion relation.
int uves_pfits_get_biny(const uves_propertylist *plist)
Find out the y binning factor.
Definition: uves_pfits.c:1194
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.
double uves_flames_pfits_get_dit(const uves_propertylist *plist)
Find out the integration time.
Definition: uves_pfits.c:3254
cpl_error_code uves_draw_lines(cpl_image *image, polynomial *dispersion, const polynomial *order_locations, const cpl_table *t, const char *lambda_column, const char *abs_order, const int *relative_order, int minorder, int maxorder, bool vertical, int offset)
Draw lines in an echelle image.
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
cpl_table * uves_wavecal_search(const cpl_image *spectrum, const cpl_image *noise, const uves_propertylist *spectrum_header, bool flat_fielded, const polynomial *order_locations, cpl_image *arcframe, int RANGE, int MINLINES, int MAXLINES, centering_method CENTERING_METHOD, int bin_disp, const int trace, const int window, cpl_table *qclog)
Search for a given number of emission lines.
double uves_polynomial_evaluate_2d(const polynomial *p, double x1, double x2)
Evaluate a 2d polynomial.
int uves_chip_get_index(enum uves_chip chip)
Convert to integer.
Definition: uves_chip.c:124
int * uves_lt_get_firstabs(const lt_type *lt, int window, int trace)
Get first absolute order.
enum uves_chip uves_chip_get_first(bool blue)
Get first chip for blue or red arm.
Definition: uves_chip.c:92
cpl_error_code uves_pfits_set_extname(uves_propertylist *plist, const char *extname)
Write the EXTNAME keyword.
Definition: uves_pfits.c:2736
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
void uves_lt_delete(lt_type **lt)
Deallocate line table.
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
void uves_pfits_set_lastabsorder(uves_propertylist *plist, int last_abs_order)
Write the last absolute order number.
Definition: uves_pfits.c:1750
enum uves_chip uves_chip_get_next(enum uves_chip chip)
Get next chip.
Definition: uves_chip.c:108
#define uves_msg_debug(...)
Print a debug message.
Definition: uves_msg.h:97
const char * uves_chip_tostring_upper(enum uves_chip chip)
Convert to string.
Definition: uves_chip.c:156
double uves_pfits_get_cdelt1(const uves_propertylist *plist)
Find out the cdelt1.
Definition: uves_pfits.c:2465
int uves_wavecal_find_nearest(const cpl_table *line_refer, double lambda, int lo, int hi)
Find best matching catalogue wavelength.
double uves_pfits_get_crval1(const uves_propertylist *plist)
Find out the crval1.
Definition: uves_pfits.c:2393
const char * uves_string_toupper(char *s)
Convert all lowercase characters in a string into uppercase characters.
Definition: uves_utils.c:1493
void uves_qclog_add_common_wave(const uves_propertylist *raw_header, enum uves_chip chip, cpl_table *qclog)
Write common QC parameters.
Definition: uves_qclog.c:942
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.
#define check(CMD,...)
Definition: uves_error.h:198
cpl_table * uves_qclog_init(const uves_propertylist *raw_header, enum uves_chip chip)
Init QC-LOG table.
Definition: uves_qclog.c:410
polynomial ** uves_lt_get_absord(const lt_type *lt, int window, int trace)
Get absolute order polynomial.
const char * uves_qclog_get_qc_name(const char *name, bool flames, int trace_number)
Create QC parameter name.
Definition: uves_qclog.c:985
const char * uves_pfits_get_chipid(const uves_propertylist *plist, enum uves_chip chip)
Find out the chip ID.
Definition: uves_pfits.c:619
void uves_pfits_set_firstabsorder(uves_propertylist *plist, int first_abs_order)
Write the first absolute order number.
Definition: uves_pfits.c:1717
void uves_flames_pfits_set_ccfposmax(uves_propertylist *plist, double ccfposmax)
Write the ccfposmax keyword (what is it?)
Definition: uves_pfits.c:2917
void uves_pfits_set_offset(uves_propertylist *plist, double trace_offset)
Write the trace offset.
Definition: uves_pfits.c:1929