UVES Pipeline Reference Manual  5.4.0
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 
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 
104 /*----------------------------------------------------------------------------*/
126 /*----------------------------------------------------------------------------*/
127 cpl_image *
128 uves_normalize_spectrum(const cpl_image *spectrum, const cpl_image *spectrum_error,
129  const uves_propertylist *spectrum_header,
130  const uves_propertylist *raw_header,
131  int n_traces,
132  enum uves_chip chip,
133  const cpl_table *atm_extinction,
134  bool correct_binning,
135  cpl_image **scaled_error)
136 {
137  cpl_image *scaled = NULL;
138  double exptime, gain;
139  int binx;
140  int norders, ny, nx;
141 
142  assure_nomsg( spectrum != NULL, CPL_ERROR_NULL_INPUT);
143  assure_nomsg( scaled_error == NULL || spectrum_error != NULL, CPL_ERROR_NULL_INPUT);
144  assure_nomsg( spectrum_header != NULL, CPL_ERROR_NULL_INPUT);
145 
146  nx = cpl_image_get_size_x(spectrum);
147  ny = cpl_image_get_size_y(spectrum);
148 
149  if (spectrum_error != NULL)
150  {
151  assure( nx == cpl_image_get_size_x(spectrum_error) &&
152  ny == cpl_image_get_size_y(spectrum_error), CPL_ERROR_INCOMPATIBLE_INPUT,
153  "Error spectrum geometry differs from spectrum: %" CPL_SIZE_FORMAT "x%" CPL_SIZE_FORMAT " vs. %d x %d",
154  cpl_image_get_size_x(spectrum_error),
155  cpl_image_get_size_y(spectrum_error),
156  nx, ny);
157  }
158 
159  assure( ny % n_traces == 0, CPL_ERROR_INCOMPATIBLE_INPUT,
160  "Spectrum image height (%d) is not a multiple of "
161  "the number of traces (%d). Confused, bailing out",
162  ny, n_traces);
163 
164  norders = ny / n_traces;
165 
166  /*
167  * Correct for exposure time, gain, bin
168  */
169  check( exptime = uves_pfits_get_exptime(raw_header),
170  "Could not read exposure time");
171 
172  check( gain = uves_pfits_get_gain(raw_header, chip),
173  "Could not read gain factor");
174 
175  if (correct_binning)
176  {
177  /* x-binning of rotated image is y-binning of raw image */
178  check( binx = uves_pfits_get_biny(raw_header),
179  "Could not read binning");
180  }
181  else
182  {
183  uves_msg("Spectrum will not be normalized to unit binning");
184  binx = 1;
185  }
186 
187  assure( exptime > 0, CPL_ERROR_ILLEGAL_INPUT, "Non-positive exposure time: %f s", exptime);
188  assure( gain > 0, CPL_ERROR_ILLEGAL_INPUT, "Non-positive gain: %f", gain);
189  assure( binx > 0, CPL_ERROR_ILLEGAL_INPUT, "Illegal binning: %d", binx);
190 
191  uves_msg("Correcting for exposure time = %f s, gain = %f, binx = %d", exptime, gain, binx);
192 
193  check( scaled = cpl_image_divide_scalar_create(spectrum, exptime * gain * binx),
194  "Error correcting spectrum for gain, exposure time, binning");
195 
196  if (scaled_error != NULL)
197  {
198  check( *scaled_error = cpl_image_divide_scalar_create(spectrum_error,
199  exptime * gain * binx),
200  "Error correcting rebinned spectrum for gain, exposure time, binning");
201  }
202 
203  /*
204  * Correct for atmospheric extinction
205  */
206  {
207  double airmass;
208  double dlambda, lambda_start;
209  int order;
210 
211  {
212  double airmass_start, airmass_end;
213 
214  check( airmass_start = uves_pfits_get_airmass_start(raw_header),
215  "Error reading airmass start");
216 
217  check( airmass_end = uves_pfits_get_airmass_end(raw_header),
218  "Error reading airmass end");
219 
220  /* Use arithmetic mean of airmass start/end */
221  airmass = (airmass_start + airmass_end) / 2;
222 
223  }
224 
225  uves_msg("Correcting for extinction through airmass %f", airmass);
226 
227  check( dlambda = uves_pfits_get_cdelt1(spectrum_header),
228  "Error reading bin width from header");
229 
230  for (order = 1; order <= norders; order++)
231  {
232  int trace;
233 
234  /* If spectrum was already merged, then read crval1,
235  * otherwise read wstart for each order
236  */
237 
238  if (norders == 1)
239  {
240  check( lambda_start = uves_pfits_get_crval1(spectrum_header),
241  "Error reading start wavelength from header");
242  }
243  else
244  {
245  check( lambda_start = uves_pfits_get_wstart(spectrum_header, order),
246  "Error reading start wavelength from header");
247  }
248 
249  for (trace = 1; trace <= n_traces; trace++)
250  {
251  int spectrum_row = (order - 1)*n_traces + trace;
252  int x;
253 
254  for (x = 1; x <= nx; x++)
255  {
256  int pis_rejected1;
257  int pis_rejected2;
258  double flux;
259  double dflux = 0;
260  double extinction;
261  double lambda;
262 
263  lambda = lambda_start + (x-1) * dlambda;
264 
265  flux = cpl_image_get(scaled, x, spectrum_row, &pis_rejected1);
266  if (scaled_error != NULL)
267  {
268  dflux = cpl_image_get(*scaled_error, x,
269  spectrum_row, &pis_rejected2);
270  }
271 
272  if (!pis_rejected1 && (scaled_error == NULL || !pis_rejected2))
273  {
274  int istart = 0;
275 
276  /* Read extinction (units: magnitude per airmass) */
277  check( extinction =
279  lambda, atm_extinction,
280  "LAMBDA", "LA_SILLA", &istart),
281  "Error interpolating extinction coefficient");
282 
283  /* Correct for extinction using
284  * the magnitude/flux relation
285  * m = -2.5 log_10 F
286  * =>
287  * F = 10^(-m*0.4)
288  *
289  * m_top-of-atmosphere = m - ext.coeff*airmass
290  * F_top-of-atmosphere = F * 10^(0.4 * ext.coeff*airmass)
291  */
292 
293  cpl_image_set(
294  scaled, x, spectrum_row,
295  flux * pow(10, 0.4 * extinction * airmass));
296  if (scaled_error != NULL)
297  {
298  cpl_image_set(
299  *scaled_error, x, spectrum_row,
300  dflux * pow(10, 0.4 * extinction * airmass));
301  }
302  }
303  else
304  {
305  cpl_image_reject(scaled, x, spectrum_row);
306  if (scaled_error != NULL)
307  {
308  cpl_image_reject(*scaled_error, x, spectrum_row);
309  }
310  }
311  } /* for each x */
312 
313  } /* for each (possibly only 1) trace */
314 
315  } /* for each (possibly only 1) order */
316  }
317 
318  cleanup:
319  if (cpl_error_get_code() != CPL_ERROR_NONE)
320  {
321  uves_free_image(&scaled);
322  if (scaled_error != NULL)
323  {
324  uves_free_image(scaled_error);
325  }
326  }
327 
328  return scaled;
329 }
330