UVES Pipeline Reference Manual  5.4.6
uves_reduce_utils.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-10-11 12:43:10 $
23  * $Revision: 1.17 $
24  * $Name: not supported by cvs2svn $
25  * $Log: not supported by cvs2svn $
26  * Revision 1.15 2012/03/02 16:49:48 amodigli
27  * fixed warning related to upgrade to CPL6
28  *
29  * Revision 1.14 2011/12/08 14:05:48 amodigli
30  * Fix warnings with CPL6
31  *
32  * Revision 1.13 2010/09/24 09:32:07 amodigli
33  * put back QFITS dependency to fix problem spot by NRI on FIBER mode (with MIDAS calibs) data
34  *
35  * Revision 1.11 2007/06/06 08:17:33 amodigli
36  * replace tab with 4 spaces
37  *
38  * Revision 1.10 2007/04/24 12:50:29 jmlarsen
39  * Replaced cpl_propertylist -> uves_propertylist which is much faster
40  *
41  * Revision 1.9 2007/04/10 07:09:37 jmlarsen
42  * Changed interface of uves_spline_hermite()
43  *
44  * Revision 1.8 2006/11/06 15:19:41 jmlarsen
45  * Removed unused include directives
46  *
47  * Revision 1.7 2006/08/17 13:56:53 jmlarsen
48  * Reduced max line length
49  *
50  * Revision 1.6 2006/05/12 15:10:07 jmlarsen
51  * Shortened lines
52  *
53  * Revision 1.5 2006/04/10 12:38:13 jmlarsen
54  * Bugfix: don't read uninitialized memory (caused atmospheric extinction step
55  * to be randomly disabled)
56  *
57  * Revision 1.4 2006/04/06 08:49:23 jmlarsen
58  * Propagate errors when normalizing spectrum
59  *
60  * Revision 1.3 2005/12/19 16:17:56 jmlarsen
61  * Replaced bool -> int
62  *
63  * Revision 1.2 2005/12/16 14:22:23 jmlarsen
64  * Removed midas test data; Added sof files
65  *
66  * Revision 1.1 2005/11/11 13:18:54 jmlarsen
67  * Reorganized code, renamed source files
68  *
69  */
70 
71 #ifdef HAVE_CONFIG_H
72 # include <config.h>
73 #endif
74 
75 /*----------------------------------------------------------------------------*/
79 /*----------------------------------------------------------------------------*/
82 /*-----------------------------------------------------------------------------
83  Includes
84  -----------------------------------------------------------------------------*/
85 
86 #include <uves_reduce_utils.h>
87 #include <math.h>
88 #include <uves_pfits.h>
89 #include <uves_utils.h>
90 #include <uves_utils_wrappers.h>
91 #include <uves_error.h>
92 #include <uves_msg.h>
93 
94 #include <cpl.h>
95 
96 /*-----------------------------------------------------------------------------
97  Functions prototypes
98  -----------------------------------------------------------------------------*/
99 
100 /*-----------------------------------------------------------------------------
101  Implementation
102  -----------------------------------------------------------------------------*/
103 static double
104 uves_get_airmass(const double z) {
105  /* http://en.wikipedia.org/wiki/Air_mass_%28astronomy%29 */
106 
107  /* X= sec z * ( 1-0.0012( (sec z)^2 -1 ) ) */
108  double x=z/180.*CPL_MATH_PI;
109 
110  double sec=1./cos(x);
111  return ( sec * ( 1.-0.0012 * ( sec*sec-1. ) ) );
112 
113  /* Yung 1994
114  double A= 1.002432*cos(x)*cos(x)+0.148386*cos(z)+0.0096467;
115  double B= cos(x)*cos(x)*cos(x)+0.149864*cos(x)*cos(x)+0.0102963*cos(x)+0.000303978;
116  return A/B;
117  */
118 
119 
120 }
121 
122 /*----------------------------------------------------------------------------*/
144 /*----------------------------------------------------------------------------*/
145 cpl_image *
146 uves_normalize_spectrum(const cpl_image *spectrum, const cpl_image *spectrum_error,
147  const uves_propertylist *spectrum_header,
148  const uves_propertylist *raw_header,
149  int n_traces,
150  enum uves_chip chip,
151  const cpl_table *atm_extinction,
152  bool correct_binning,
153  cpl_image **scaled_error)
154 {
155  cpl_image *scaled = NULL;
156  double exptime, gain;
157  int binx;
158  int norders, ny, nx;
159 
160  assure_nomsg( spectrum != NULL, CPL_ERROR_NULL_INPUT);
161  assure_nomsg( scaled_error == NULL || spectrum_error != NULL, CPL_ERROR_NULL_INPUT);
162  assure_nomsg( spectrum_header != NULL, CPL_ERROR_NULL_INPUT);
163 
164  nx = cpl_image_get_size_x(spectrum);
165  ny = cpl_image_get_size_y(spectrum);
166 
167  if (spectrum_error != NULL)
168  {
169  assure( nx == cpl_image_get_size_x(spectrum_error) &&
170  ny == cpl_image_get_size_y(spectrum_error), CPL_ERROR_INCOMPATIBLE_INPUT,
171  "Error spectrum geometry differs from spectrum: %" CPL_SIZE_FORMAT "x%" CPL_SIZE_FORMAT " vs. %d x %d",
172  cpl_image_get_size_x(spectrum_error),
173  cpl_image_get_size_y(spectrum_error),
174  nx, ny);
175  }
176 
177  assure( ny % n_traces == 0, CPL_ERROR_INCOMPATIBLE_INPUT,
178  "Spectrum image height (%d) is not a multiple of "
179  "the number of traces (%d). Confused, bailing out",
180  ny, n_traces);
181 
182  norders = ny / n_traces;
183 
184  /*
185  * Correct for exposure time, gain, bin
186  */
187  check( exptime = uves_pfits_get_exptime(raw_header),
188  "Could not read exposure time");
189 
190  check( gain = uves_pfits_get_gain(raw_header, chip),
191  "Could not read gain factor");
192 
193  if (correct_binning)
194  {
195  /* x-binning of rotated image is y-binning of raw image */
196  check( binx = uves_pfits_get_biny(raw_header),
197  "Could not read binning");
198  }
199  else
200  {
201  uves_msg("Spectrum will not be normalized to unit binning");
202  binx = 1;
203  }
204 
205  assure( exptime > 0, CPL_ERROR_ILLEGAL_INPUT, "Non-positive exposure time: %f s", exptime);
206  assure( gain > 0, CPL_ERROR_ILLEGAL_INPUT, "Non-positive gain: %f", gain);
207  assure( binx > 0, CPL_ERROR_ILLEGAL_INPUT, "Illegal binning: %d", binx);
208 
209  uves_msg("Correcting for exposure time = %f s, gain = %f, binx = %d", exptime, gain, binx);
210 
211  check( scaled = cpl_image_divide_scalar_create(spectrum, exptime * gain * binx),
212  "Error correcting spectrum for gain, exposure time, binning");
213 
214  if (scaled_error != NULL)
215  {
216  check( *scaled_error = cpl_image_divide_scalar_create(spectrum_error,
217  exptime * gain * binx),
218  "Error correcting rebinned spectrum for gain, exposure time, binning");
219  }
220 
221  /*
222  * Correct for atmospheric extinction
223  */
224  {
225  double airmass;
226  double dlambda, lambda_start;
227  int order;
228  int miss_airm_start=0;
229  int miss_airm_end=0;
230  {
231  double airmass_start, airmass_end;
232  if(cpl_propertylist_has(raw_header,UVES_AIRMASS_START)) {
233  check( airmass_start = uves_pfits_get_airmass_start(raw_header),
234  "Error reading airmass start");
235  } else {
236  double alt = uves_pfits_get_tel_alt_start(raw_header);
237  double z=90.-alt;
238  miss_airm_start=1;
239 
240  airmass_start=uves_get_airmass(z);
241  uves_msg_warning("Missing %s approximate it", UVES_AIRMASS_START);
242 
243  }
244  if(cpl_propertylist_has(raw_header,UVES_AIRMASS_END)) {
245  check( airmass_end = uves_pfits_get_airmass_end(raw_header),
246  "Error reading airmass end");
247  } else {
248  double alt = uves_pfits_get_tel_alt_start(raw_header);
249  double z=90.-alt;
250  miss_airm_end=1;
251  airmass_end=uves_get_airmass(z);
252  uves_msg_warning("Missing %s approximate it", UVES_AIRMASS_END);
253 
254  }
255  if(miss_airm_start && miss_airm_end) {
256  uves_msg_error("Both airmass start and end aere missing. Stop");
257  cpl_error_set(cpl_func,CPL_ERROR_ILLEGAL_INPUT);
258  } else {
259  /* Use arithmetic mean of airmass start/end */
260  airmass = (airmass_start + airmass_end) / 2;
261  }
262 
263  }
264 
265  uves_msg("Correcting for extinction through airmass %f", airmass);
266 
267  check( dlambda = uves_pfits_get_cdelt1(spectrum_header),
268  "Error reading bin width from header");
269 
270  for (order = 1; order <= norders; order++)
271  {
272  int trace;
273 
274  /* If spectrum was already merged, then read crval1,
275  * otherwise read wstart for each order
276  */
277 
278  if (norders == 1)
279  {
280  check( lambda_start = uves_pfits_get_crval1(spectrum_header),
281  "Error reading start wavelength from header");
282  }
283  else
284  {
285  check( lambda_start = uves_pfits_get_wstart(spectrum_header, order),
286  "Error reading start wavelength from header");
287  }
288 
289  for (trace = 1; trace <= n_traces; trace++)
290  {
291  int spectrum_row = (order - 1)*n_traces + trace;
292  int x;
293 
294  for (x = 1; x <= nx; x++)
295  {
296  int pis_rejected1;
297  int pis_rejected2;
298  double flux;
299  double dflux = 0;
300  double extinction;
301  double lambda;
302 
303  lambda = lambda_start + (x-1) * dlambda;
304 
305  flux = cpl_image_get(scaled, x, spectrum_row, &pis_rejected1);
306  if (scaled_error != NULL)
307  {
308  dflux = cpl_image_get(*scaled_error, x,
309  spectrum_row, &pis_rejected2);
310  }
311 
312  if (!pis_rejected1 && (scaled_error == NULL || !pis_rejected2))
313  {
314  int istart = 0;
315 
316  /* Read extinction (units: magnitude per airmass) */
317  check( extinction =
319  lambda, atm_extinction,
320  "LAMBDA", "LA_SILLA", &istart),
321  "Error interpolating extinction coefficient");
322 
323  /* Correct for extinction using
324  * the magnitude/flux relation
325  * m = -2.5 log_10 F
326  * =>
327  * F = 10^(-m*0.4)
328  *
329  * m_top-of-atmosphere = m - ext.coeff*airmass
330  * F_top-of-atmosphere = F * 10^(0.4 * ext.coeff*airmass)
331  */
332 
333  cpl_image_set(
334  scaled, x, spectrum_row,
335  flux * pow(10, 0.4 * extinction * airmass));
336  if (scaled_error != NULL)
337  {
338  cpl_image_set(
339  *scaled_error, x, spectrum_row,
340  dflux * pow(10, 0.4 * extinction * airmass));
341  }
342  }
343  else
344  {
345  cpl_image_reject(scaled, x, spectrum_row);
346  if (scaled_error != NULL)
347  {
348  cpl_image_reject(*scaled_error, x, spectrum_row);
349  }
350  }
351  } /* for each x */
352 
353  } /* for each (possibly only 1) trace */
354 
355  } /* for each (possibly only 1) order */
356  }
357 
358  cleanup:
359  if (cpl_error_get_code() != CPL_ERROR_NONE)
360  {
361  uves_free_image(&scaled);
362  if (scaled_error != NULL)
363  {
364  uves_free_image(scaled_error);
365  }
366  }
367 
368  return scaled;
369 }
370 
#define uves_msg_error(...)
Print an error message.
Definition: uves_msg.h:64
#define uves_msg_warning(...)
Print an warning message.
Definition: uves_msg.h:87
double uves_pfits_get_tel_alt_start(const uves_propertylist *plist)
Find out the start telescope altitude.
Definition: uves_pfits.c:781
double uves_pfits_get_gain(const uves_propertylist *plist, enum uves_chip chip)
Find out the gain.
Definition: uves_pfits.c:887
double uves_pfits_get_wstart(const uves_propertylist *plist, int order)
Read the wstart keyword.
Definition: uves_pfits.c:3004
double uves_spline_hermite_table(double xp, const cpl_table *t, const char *column_x, const char *column_y, int *istart)
Spline interpolation based on Hermite polynomials.
Definition: uves_utils.c:3683
#define uves_msg(...)
Print a message on 'info' or 'debug' level.
Definition: uves_msg.h:119
int uves_pfits_get_biny(const uves_propertylist *plist)
Find out the y binning factor.
Definition: uves_pfits.c:1194
double uves_pfits_get_exptime(const uves_propertylist *plist)
Find out the exposure time in seconds.
Definition: uves_pfits.c:922
cpl_image * uves_normalize_spectrum(const cpl_image *spectrum, const cpl_image *spectrum_error, const uves_propertylist *spectrum_header, const uves_propertylist *raw_header, int n_traces, enum uves_chip chip, const cpl_table *atm_extinction, bool correct_binning, cpl_image **scaled_error)
Normalize a spectrum.
double uves_pfits_get_airmass_end(const uves_propertylist *plist)
Find out the end airmass.
Definition: uves_pfits.c:820
double uves_pfits_get_cdelt1(const uves_propertylist *plist)
Find out the cdelt1.
Definition: uves_pfits.c:2465
double uves_pfits_get_crval1(const uves_propertylist *plist)
Find out the crval1.
Definition: uves_pfits.c:2393
#define assure_nomsg(BOOL, CODE)
Definition: uves_error.h:177
#define check(CMD,...)
Definition: uves_error.h:198
double uves_pfits_get_airmass_start(const uves_propertylist *plist)
Find out the start airmass.
Definition: uves_pfits.c:801