IIINSTRUMENT Pipeline Reference Manual  6.2.2
isaac_physicalmodel.c
1 /* $Id: isaac_physicalmodel.c,v 1.12 2013-03-12 08:06:48 llundin Exp $
2  *
3  * This file is part of the ISAAC Pipeline
4  * Copyright (C) 2002,2003 European Southern Observatory
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: llundin $
23  * $Date: 2013-03-12 08:06:48 $
24  * $Revision: 1.12 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 /*-----------------------------------------------------------------------------
33  Includes
34  -----------------------------------------------------------------------------*/
35 
36 #include <string.h>
37 #include <math.h>
38 #include <float.h>
39 #include <cpl.h>
40 
41 #include "irplib_utils.h"
42 
43 #include "isaac_physicalmodel.h"
44 #include "isaac_pfits.h"
45 
46 /*-----------------------------------------------------------------------------
47  Define
48  -----------------------------------------------------------------------------*/
49 
50 #define ISAAC_LR_DIR 7.0 /* angle in degrees */
51 #define ISAAC_MR_DIR 31.5 /* angle in degrees */
52 
53 #define ISAAC_LR_GRATING 40.0 /* grooves/mm */
54 #define ISAAC_MR_GRATING 210.0 /* grooves/mm */
55 
56 #define ISAAC_FOCAL_LENGTH_MM 175.0 /* mm */
57 
58 #define ISAAC_PIXEL_SIZE_S 18.5 /* microns */
59 #define ISAAC_PIXEL_SIZE_M 27.0 /* microns */
60 
61 #define ISAAC_BEAM_DIFF 2.72 /* angle in degrees */
62 #define ISAAC_PUPIL_SIZE_MM 100.0 /* mm */
63 
64 #define ISAAC_FLGTH_S1 1.75
65 #define ISAAC_FLGTH_S2 3.25
66 #define ISAAC_FLGTH_L1 1.56
67 #define ISAAC_FLGTH_L2 4.77
68 #define ISAAC_FLGTH_L3 9.88
69 
70 #define ANGLE_IN_DEFAULT 0.00
71 #define ANGLE_OUT_DEFAULT 0.00
72 
73 /*----------------------------------------------------------------------------*/
77 /*----------------------------------------------------------------------------*/
78 
79 /*-----------------------------------------------------------------------------
80  Function codes
81  -----------------------------------------------------------------------------*/
82 
85 /*----------------------------------------------------------------------------*/
98 /*----------------------------------------------------------------------------*/
99 double * isaac_get_disprel_estimate(const char * filename,
100  cpl_size poly_deg)
101 {
102  double * disprel = NULL;
103  cpl_propertylist * plist = cpl_propertylist_load(filename, 0);
104  const char * objective;
105  const char * resolution;
106  double wl_c;
107  int npix;
108  int order;
109 
110  cpl_matrix * x_val = NULL;
111  cpl_vector * y_val = NULL;
112  cpl_polynomial * poly_fit = NULL;
113  double * coefs = NULL;
114 
115 
116  bug_if(0);
117 
118  /* A polynomial fit is computed */
119  skip_if_lt (poly_deg, 0, "polynomial degree");
120 
121  /* Get the central wavelength */
122  wl_c = isaac_pfits_get_wlen(plist);
123  error_if(cpl_error_get_code(), cpl_error_get_code(),
124  "cannot get central wlen from [%s]", filename);
125 
126  wl_c *= 10000.0; /* microns to A */
127 
128  /* Get the objective */
129  objective = isaac_pfits_get_objective(plist);
130  error_if(cpl_error_get_code(), cpl_error_get_code(),
131  "cannot get objective from [%s]", filename);
132 
133  /* Get the grating name */
134  resolution = isaac_pfits_get_resolution(plist);
135  error_if(cpl_error_get_code(), cpl_error_get_code(),
136  "cannot get resolution from [%s]", filename);
137 
138  /* Display configuration */
139  cpl_msg_info(cpl_func, "configuration for ISAAC physical model: ");
140  cpl_msg_info(cpl_func, "resolution: %s", resolution);
141  cpl_msg_info(cpl_func, "lambda_c [Angstrom]: %g", wl_c);
142  cpl_msg_info(cpl_func, "objective : %s", objective);
143 
144  /* Get naxis1 */
145  npix = isaac_pfits_get_naxis1(plist);
146  error_if(cpl_error_get_code(), cpl_error_get_code(),
147  "cannot get NAXIS1 from [%s]", filename);
148 
149  skip_if_lt(npix, 2, "NAXIS1");
150 
151  /* Set the order - as in isaac_physical_model() */
152  if ( wl_c >= 8900 && wl_c < 9900 ) {
153  order = 6;
154  } else if ( wl_c >= 9900 && wl_c < 11000 ) {
155  order = 5;
156  } else if ( wl_c >= 11000 && wl_c < 14000 ) {
157  order = 4;
158  } else if ( wl_c >= 14000 && wl_c < 18500 ) {
159  order = 3;
160  } else if ( wl_c >= 18500 && wl_c < 25000 ) {
161  order = 2;
162  } else {
163  order = 1;
164  }
165 
166  disprel = (double*)cpl_malloc((poly_deg+1) * sizeof(double));
167 
168  if (poly_deg == 3 && resolution[0] == 'M' && 8900 <= wl_c && wl_c < 25000) {
169 
170  /* This method and the constants are provided by C. Lidman */
171 
172  const double a = -1.218717e-7;
173  const double b = 0.003395204;
174  const double c = 1337.455;
175  const double d = -1.617833e-4;
176  const double e = 3.132269;
177  const double f = -2.496095;
178 
179  const double c1 = wl_c;
180  const double c2 = (( a * (order*c1) + b) * (order*c1) + c) / order;
181  const double c3 = ( d * (order*c1) + e ) / order;
182  const double c4 = f / order;
183  double k0 = -(npix+1) / (double)(npix-1);
184  double k1 = 2 / (double)(npix-1);
185 
186  double * p = disprel;
187 
188  /* The polynomial in reduced coordinates, -1 <= z <= 1 */
189  p[0] = c1 - c3;
190  p[1] = c2 - 3*c4;
191  p[2] = 2*c3;
192  p[3] = 4*c4;
193  cpl_msg_debug(cpl_func,
194  "Reduced polynomial(%d:%d): %g + %g * z + %g * z^2 "
195  "+ %g * z^3\n", order, npix, p[0], p[1], p[2], p[3]);
196 
197  /* The polynomial in pixel coordinates, 1 <= pix <= npix */
198  p[0] += k0 * ( p[1] + k0 * ( p[2] + k0 * p[3]));
199 
200  p[1] += k0 * ( 2*p[2] + k0 * 3*p[3]);
201  p[1] *= k1;
202 
203  p[2] += k0 * 3*p[3];
204  p[2] *= k1*k1;
205 
206  p[3] *= k1*k1*k1;
207 
208  } else {
209  double * px_val;
210  const cpl_boolean sampsym = CPL_TRUE;
211  cpl_size i;
212 
213  /* coefs an array of npix doubles with the wavelength for each pix. */
214  coefs = isaac_physical_model(wl_c, objective, resolution, npix);
215  error_if (coefs == NULL, cpl_error_get_code(),
216  "cannot compute the physical model");
217 
218  y_val = cpl_vector_wrap(npix, coefs);
219 
220  x_val = cpl_matrix_new(1, npix);
221  px_val = cpl_matrix_get_data(x_val);
222 
223  for (i = 0; i < npix; i++) {
224  px_val[i] = (double)(i+1);
225  }
226 
227  /* Apply the fit */
228  poly_fit = cpl_polynomial_new(1);
229  skip_if(cpl_polynomial_fit(poly_fit, x_val, &sampsym, y_val, NULL,
230  CPL_FALSE, NULL, &poly_deg));
231  /* Extract coefs (FIXME: use cpl_polynomial...) */
232  for (i = 0; i <= poly_deg; i++) {
233  disprel[i] = cpl_polynomial_get_coeff(poly_fit, &i);
234  }
235  }
236 
237  end_skip;
238 
239  if (cpl_error_get_code()) {
240  cpl_free(disprel);
241  disprel = NULL;
242  }
243 
244  cpl_matrix_delete(x_val);
245  cpl_polynomial_delete(poly_fit);
246  (void)cpl_vector_unwrap(y_val);
247  cpl_free(coefs);
248 
249  cpl_propertylist_delete(plist);
250 
251  return disprel;
252 }
253 
254 /*----------------------------------------------------------------------------*/
276 /*----------------------------------------------------------------------------*/
277 double * isaac_physical_model(double lambda_c,
278  const char * objective,
279  const char * resolution,
280  int nbpix)
281 {
282  double beam_diff, focal_length, pixel_size, pupil;
283  double gr;
284  double isaacLRGrating, isaacMRGrating;
285  int order;
286  double * disp;
287  double x;
288  double angle_in, angle_out;
289  double a, b, det;
290  double loc_pi;
291  int i;
292 
293  /* Initialize */
294  isaacLRGrating = ISAAC_LR_GRATING;
295  isaacMRGrating = ISAAC_MR_GRATING;
296  focal_length = ISAAC_FOCAL_LENGTH_MM;
297  pixel_size = ISAAC_PIXEL_SIZE_S;
298  beam_diff = ISAAC_BEAM_DIFF;
299  pupil = ISAAC_PUPIL_SIZE_MM;
300  loc_pi = 3.1415926535897932384626433;
301 
302  /* Check objective */
303  if (objective[0] == 'S') {
304  if (objective[1] == '1') focal_length = pupil*ISAAC_FLGTH_S1;
305  if (objective[1] == '2') focal_length = pupil*ISAAC_FLGTH_S2;
306  pixel_size = ISAAC_PIXEL_SIZE_S;
307  } else if (objective[0] == 'L') {
308  if (objective[1] == '1') focal_length = pupil*ISAAC_FLGTH_L1;
309  if (objective[1] == '2') focal_length = pupil*ISAAC_FLGTH_L2;
310  if (objective[1] == '3') focal_length = pupil*ISAAC_FLGTH_L3;
311  pixel_size = ISAAC_PIXEL_SIZE_M;
312  } else {
313  cpl_msg_error(cpl_func, "unsupported objective");
314  return NULL;
315  }
316 
317  /* Convert mm to m */
318  focal_length *= 1e-3;
319 
320  /* Display configuration */
321  cpl_msg_info(cpl_func, "configuration for ISAAC physical model: ");
322  if (resolution[0]=='L') cpl_msg_info(cpl_func, "low resolution");
323  if (resolution[0]=='M') cpl_msg_info(cpl_func, "medium resolution");
324  cpl_msg_info(cpl_func, "lambda_c : %g", lambda_c);
325  cpl_msg_info(cpl_func, "objective : %s", objective);
326  cpl_msg_info(cpl_func, "focal length : %g", focal_length);
327 
328  /* Set the grating */
329  if (resolution[0] == 'L') { gr = isaacLRGrating;}
330  else if (resolution[0] == 'M') { gr = isaacMRGrating;}
331  else {
332  cpl_msg_error(cpl_func, "wrong grating! %c", resolution[0]);
333  return NULL;
334  }
335 
336  /* Convert gr to grove/nm */
337  gr *= 1e-6;
338  /* Convert beam_diff in radians. */
339  beam_diff *= loc_pi / 180.0;
340  /* Convert lambda_c : A->nm */
341  lambda_c /= 10;
342 
343  /* Set the order */
344  if ( lambda_c >= 890 && lambda_c < 8000) {
345  if ( lambda_c >= 890 && lambda_c < 990 ) {
346  order = 6;
347  } else if ( lambda_c >= 990 && lambda_c < 1100 ) {
348  order = 5;
349  } else if ( lambda_c >= 1100 && lambda_c < 1400 ) {
350  order = 4;
351  } else if ( lambda_c >= 1400 && lambda_c < 1850 ) {
352  order = 3;
353  } else if ( lambda_c >= 1850 && lambda_c < 2500 ) {
354  order = 2;
355  } else if ( lambda_c >= 2500 && lambda_c < 5500 ) {
356  order = 1;
357  } else {
358  order = 1;
359  }
360  } else {
361  order = (int)(0.5 + (sin(ANGLE_IN_DEFAULT) + sin(ANGLE_OUT_DEFAULT)) /
362  (lambda_c * gr));
363  if (order < 1) {
364  cpl_msg_error(cpl_func, "wrong order! %d", order);
365  return NULL;
366  }
367  }
368  cpl_msg_info(cpl_func, "order : %d", order);
369 
370  /* The following is the solution of the set of equations : */
371  /* (1) sin(angle_in) + sin(angle_out) = order*gr*lambda_c */
372  /* (2) angle_out - angle_in = beam_diff */
373  det = 2 * sin(beam_diff);
374  a = order * gr * lambda_c * sin(beam_diff);
375  b = sqrt(order * gr * lambda_c * order * gr * lambda_c *
376  (sin(beam_diff) * sin(beam_diff) + 2 * cos(beam_diff) - 2)
377  + 2 * sin(beam_diff) * sin(beam_diff) * (1-cos(beam_diff)));
378  angle_in = asin((a-b)/det);
379  angle_out = angle_in + beam_diff;
380 
381  disp = cpl_malloc(nbpix * sizeof(double));
382 
383  for (i=0; i<nbpix; i++) {
384  /* x in meters */
385  x = (double)(i-(nbpix/2.)) * pixel_size * 1e-6;
386  disp[i]=(sin(angle_in)+sin(angle_out+atan(x/focal_length)))/(order*gr);
387 
388  /* Convert disprel from nm to angstroms */
389  disp[i] *= 10;
390  }
391 
392  return disp;
393 }
394 
const char * isaac_pfits_get_objective(const cpl_propertylist *plist)
find out the objective
Definition: isaac_pfits.c:642
double isaac_pfits_get_wlen(const cpl_propertylist *plist)
find out the central wavelength
Definition: isaac_pfits.c:865
int isaac_pfits_get_naxis1(const cpl_propertylist *plist)
find out the NAXIS1 keyword
Definition: isaac_pfits.c:582
const char * isaac_pfits_get_resolution(const cpl_propertylist *plist)
find out the resolution
Definition: isaac_pfits.c:775
double * isaac_physical_model(double lambda_c, const char *objective, const char *resolution, int nbpix)
ISAAC physical model.
double * isaac_get_disprel_estimate(const char *filename, cpl_size poly_deg)
Estimate the instrument wavelength range.