SINFONI Pipeline Reference Manual  2.5.2
sinfo_atmo_disp.c
1 /*
2  * This file is part of the ESO SINFONI Pipeline
3  * Copyright (C) 2004-2009 European Southern Observatory
4  *
5  * This program 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: 2011-12-08 16:15:40 $
23  * $Revision: 1.7 $
24  */
25 
26 #ifdef HAVE_CONFIG_H
27 #include <config.h> /* allows the program compilation */
28 #endif
29 
30 #include <cpl.h>
31 #include <string.h>
32 #include <math.h>
33 #include <sinfo_msg.h>
34 #include <sinfo_utils_wrappers.h>
35 #include "sinfo_atmo_disp.h"
36 #include "sinfo_resampling.h"
37 #include "sinfo_image_ops.h"
38 
39 struct _disp_data
40 {
41  double p1;
42  double d1;
43  double d2;
44  double N0;
45  double predelta;
46  double parallactic_shiftX;
47  double parallactic_shiftY;
48 };
49 typedef struct _disp_data disp_data;
50 static double sinfo_disp_calc_N(const disp_data* pdata, double lambda);
51 static void
52 sinfo_disp_prepare_data(disp_data* pdata,
53  double lambda0,
54  double Tc,
55  double rh,
56  double airm,
57  double p,
58  double parallactic,
59  double pixelscale );
60 
61 static void
62 sinfo_disp_calc(disp_data* pdata, double lambda, double *shiftx, double *shiftY);
63 static void
64 sinfo_atmo_rotate_point(double* x_value, double * y_value, double rot_angle);
65 /*------------------------------------------------------------------------------------*/
66 
67 static double
68 sinfo_disp_calc_N(const disp_data* pdata, double lambda)
69 {
70  double s = 1.0 /lambda;
71  double s2 = s * s;
72  double s3 = s2 * s;
73  double s4 = s3 * s;
74  double s5 = s4 * s;
75  double s6 = s5 * s;
76 
77  double a = 83939.7/(130 - s2);
78  double b = 4547.3/(38.99 - s2);
79  double c = 6487.31 + 58.058*s2 - 0.71150*s4 + 0.08851*s6;
80  double N = 1e-8 * ( ((2371.34 + a + b) * pdata->d1) + ( c * pdata->d2));
81  return N;
82 
83 }
84 static void
85 sinfo_disp_prepare_data(disp_data* pdata,
86  double lambda0,
87  double Tc,
88  double rh,
89  double airm,
90  double p,
91  double parallactic,
92  double pixelscale )
93 {
94  double ps,p2,p1,T,T2,T3;
95  double zenith;
96  // const double PI_NUMBer = 3.1415926535;
97 
98  T = Tc + 273.15;T2 = T * T; T3 = T2 * T;
99  ps = -10474 + (116.43 * T) - (0.43284 *T2) + (0.00053840 * T3);
100  p2 = (rh/100)*ps;
101  p1 = p - p2;
102  pdata->d1 = (p1/T)*(1+p1*( (57.90e-8) - ((9.3250e-4)/T) + (0.25844/T2)));
103  pdata->d2 = (p2/T)*(1+p2*(1+3.7e-4*p2)*( (-2.37321e-3) + (2.23366/T) - (710.792/T2) + ((7.75141e-4)/T3) )) ;
104  pdata->N0 = sinfo_disp_calc_N(pdata, lambda0);
105  zenith = acos(1/airm);
106  pdata->predelta = ((tan(zenith)) / (PI_NUMB/180)) * 3600;
107  pdata->parallactic_shiftX = sin ( (parallactic)* (PI_NUMB/180) ) / pixelscale;
108  pdata->parallactic_shiftY = cos ( (parallactic)* (PI_NUMB/180) ) / pixelscale;
109  sinfo_msg_warning("atm disp N0[%f] d1[%f] d2[%f] pshiftX[%f] pshiftY[%f]",
110  pdata->N0,pdata->d1, pdata->d2, pdata->parallactic_shiftX ,
111  pdata->parallactic_shiftY);
112 }
113 static void
114 sinfo_disp_calc(disp_data* pdata, double lambda, double *shiftx, double *shifty)
115 {
116  double n = sinfo_disp_calc_N(pdata, lambda);
117  double delta = pdata->predelta * (n - pdata->N0);
118  *shiftx = -delta * pdata->parallactic_shiftX;
119  *shifty = delta * pdata->parallactic_shiftY ;
120 }
121 
122 cpl_error_code
123 sinfo_atm_dispersion_cube(cpl_imagelist* pCube,
124  int centpix, // central plane in the cube CRPIX3
125  double centlambda, // wavelength of the central plane CRVAL3
126  double Tc, // temperature in Celsius TEL.AMBI.TEMP
127  double Rh, // relative humidity in % TEL.AMBI.RHUM
128  double airm, // airmass for the moment of observation TEL.AMBI.PRES
129  double p, // atmospheric pressure TEL.AMBI.PRES
130  double parallactic, // TEL.PARANG
131  double pixelscale, // could be for SINFONI 0.025, 0.100, 0.250
132  double pixelsz // microns per pixel CDELT3
133 )
134 {
135  cpl_error_code err = CPL_ERROR_NONE;
136  int cubesize = cpl_imagelist_get_size(pCube);
137  double * kernel = sinfo_generate_interpolation_kernel("default");
138  disp_data ddata;
139  int i = 0;
140 
141  sinfo_disp_prepare_data(&ddata, centlambda, Tc, Rh, airm, p, parallactic, pixelscale);
142 
143  for (i = 0; i < cubesize; i++)
144  {
145  double shiftx = 0;
146  double shifty = 0;
147 
148  cpl_image* pnewImage = 0;
149  // 1. get an image
150  cpl_image* plane = cpl_imagelist_get(pCube, i);
151 
152  // 2. calculate dispersion and shift
153  double lambda = centlambda - (centpix - i) * pixelsz;
154  sinfo_disp_calc(&ddata, lambda, &shiftx, &shifty);
155  // 3. aplly shift
156  // int szx = cpl_image_get_size_x(plane);
157  //int szy = cpl_image_get_size_y(plane);
158  //if (i % 10 == 0)
159  sinfo_msg_warning(" shift image #%d, dx[%f] dy[%f]", i, shiftx, shifty);
160  pnewImage = sinfo_new_shift_image(
161  plane,
162  shiftx,
163  shifty,
164  kernel);
165  err = cpl_imagelist_set(pCube, pnewImage, i);
166  if (err != CPL_ERROR_NONE)
167  break;
168  }
169  cpl_free(kernel);
170  return err;
171 
172 }
173 
174 
175 /*----------------------------------------------------
176  * Atmospheric correction using polynomial fit
177  *----------------------------------------------------*/
178 cpl_polynomial*
179 sinfo_atmo_load_polynom(const char* filename)
180 {
181  const char* COL_NAME_TEMPLATE = "col_%d";
182  const char* COL_NAME_VALUE = "value";
183  cpl_polynomial* poly = NULL;
184  cpl_table* ptable = NULL;
185 
186  ptable = cpl_table_load(filename, 1, 0);
187  if (ptable)
188  {
189  int dim = 0;
190  int nrows = 0;
191  int i = 0;
192  cpl_size* expo = NULL;
193 
194  dim = cpl_table_get_ncol(ptable) - 1;
195  poly = cpl_polynomial_new(dim );
196  nrows = cpl_table_get_nrow(ptable);
197  expo = cpl_malloc(dim * sizeof(expo[0]));
198  memset(&expo[0], 0, dim * sizeof(expo[0]));
199  for (i = 0; i < nrows; i++)
200  {
201  int j = 0;
202  int inull = 0;
203  double value = 0;
204  for (j = 0; j < dim; j++)
205  {
206  char col_name[255];
207  sprintf(col_name, COL_NAME_TEMPLATE, j);
208  expo[j] = cpl_table_get_int(ptable, col_name, i, &inull);
209  }
210  value = cpl_table_get(ptable, COL_NAME_VALUE, i, &inull);
211  cpl_polynomial_set_coeff(poly, expo, value);
212  if (cpl_error_get_code() != CPL_ERROR_NONE)
213  {
214  if (poly)
215  {
216  sinfo_free_polynomial(&poly);
217  }
218  break;
219  }
220  }
221  cpl_free(expo);
222  }
223  sinfo_free_table(&ptable);
224  return poly;
225 }
226 
227 static void
228 sinfo_atmo_rotate_point(double* x_value, double * y_value, double rot_angle)
229 {
230  double newx = *x_value * cos(rot_angle) - *y_value * sin(rot_angle);
231  double newy = *x_value * sin(rot_angle) + *y_value * cos(rot_angle);
232  *x_value = newx;
233  *y_value = newy;
234 }
235 
236 cpl_imagelist*
237 sinfo_atmo_apply_cube_polynomial_shift(
238  cpl_polynomial* poly,
239  cpl_imagelist* pCube,
240  double lambda0,
241  double airmass,
242  double parallactic, // should be in radian
243  double pixelsz,
244  int centpix)
245 {
246  cpl_imagelist* retcube = NULL;
247  cpl_error_code err = CPL_ERROR_NONE;
248  cpl_vector* vparams = NULL;
249  double * kernel = sinfo_generate_interpolation_kernel("default");
250  int cubesize = 0;
251  int i = 0;
252  // the following two parameters are necessary for computing the shift
253  // in case when polynom for H+K band is used for H or K
254  double l0_shift_x = 0; // shift for the central point by X
255  double l0_shift_y = 0; // shift for the central point by Y
256 
257  vparams = cpl_vector_new(2);
258  cpl_vector_set(vparams, 0, airmass);
259  cpl_vector_set(vparams, 1, lambda0);
260  err = cpl_error_get_code();
261  if (err == CPL_ERROR_NONE)
262  {
263  l0_shift_y = cpl_polynomial_eval(poly, vparams); // North - South
264  l0_shift_x = 0; // (EAST-WEST direction)
265  // rotate the shift
266  sinfo_atmo_rotate_point(&l0_shift_x, &l0_shift_y, parallactic);
267  cubesize = cpl_imagelist_get_size(pCube);
268  err = cpl_error_get_code();
269  }
270  if (err == CPL_ERROR_NONE)
271  {
272  retcube = cpl_imagelist_new();
273  for (i = 0; i < cubesize; i++)
274  {
275  // calculate the wavelength
276  double lambda = lambda0 - (centpix - i) * pixelsz;
277  double shift_y = 0;
278  double shift_x = 0;
279 
280  cpl_vector_set(vparams, 1, lambda);
281  // calc the shift
282  shift_y = cpl_polynomial_eval(poly, vparams); // North - South
283  err = cpl_error_get_code();
284  if (err == CPL_ERROR_NONE)
285  {
286  double res_shift_x = -(shift_x - l0_shift_x);
287  double res_shift_y = -(shift_y - l0_shift_y);
288  cpl_image* plane = NULL;
289  cpl_image* pimresult = NULL;
290  // rotate the shift
291  sinfo_atmo_rotate_point(&res_shift_x, &res_shift_y, parallactic);
292  plane = cpl_imagelist_get(pCube, i);
293  pimresult = sinfo_new_shift_image(
294  plane,
295  res_shift_x, // x shift
296  res_shift_y, // y shift
297  kernel);
298  if (err == CPL_ERROR_NONE)
299  {
300  err = cpl_imagelist_set(retcube, pimresult, i);
301  }
302  else
303  {
304  sinfo_msg_error("Error sinfo_new_shift_image, %s",
305  cpl_error_get_where());
306  }
307  if (err != CPL_ERROR_NONE)
308  break;
309  }
310  else
311  {
312  sinfo_msg_error("Error polynomial_eval, %s",
313  cpl_error_get_where());
314  }
315  if (err != CPL_ERROR_NONE)
316  break;
317  }
318  }
319  if (err != CPL_ERROR_NONE)
320  {
321  sinfo_free_imagelist(&retcube);
322  sinfo_msg_error("Error during shift planes in the cube, %s",
323  cpl_error_get_where());
324  }
325  sinfoni_free_vector(&vparams);
326  cpl_free(kernel);
327  return retcube;
328 }