IIINSTRUMENT Pipeline Reference Manual 6.2.5
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/*----------------------------------------------------------------------------*/
99double * 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/*----------------------------------------------------------------------------*/
277double * 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.