UVES Pipeline Reference Manual  5.4.0
uves_physmod_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  * $Id: uves_physmod_utils.c,v 1.19 2010-09-24 09:32:07 amodigli Exp $
21  * $Name: not supported by cvs2svn $
22  * $Revision: 1.19 $
23  * $Log: not supported by cvs2svn $
24  * Revision 1.17 2007/12/03 10:41:38 amodigli
25  * added uves_msg_debug on some function
26  *
27  * Revision 1.16 2007/11/26 15:28:29 amodigli
28  * display more info
29  *
30  * Revision 1.15 2007/06/06 08:17:33 amodigli
31  * replace tab with 4 spaces
32  *
33  * Revision 1.14 2006/11/06 15:19:41 jmlarsen
34  * Removed unused include directives
35  *
36  * Revision 1.13 2006/08/23 15:41:06 amodigli
37  * removed warning from checks on line length
38  *
39  * Revision 1.12 2006/08/23 09:33:03 jmlarsen
40  * Renamed local variables shadowing POSIX reserved names
41  *
42  * Revision 1.11 2006/06/20 10:56:56 amodigli
43  * cleaned output, added units
44  *
45  * Revision 1.10 2006/06/20 08:40:57 amodigli
46  * fixed doxigen warnings
47  *
48  * Revision 1.9 2006/06/08 11:01:50 amodigli
49  * fixed some warnings
50  *
51  * Revision 1.8 2006/06/07 12:50:44 jmlarsen
52  * Removed doxygen tag addtogroup
53  *
54  * Revision 1.7 2006/06/07 12:45:19 jmlarsen
55  * Added missing doxygen endmarker
56  *
57  * Revision 1.6 2006/06/05 08:51:55 amodigli
58  * cleaned some warnings from static checks
59  *
60  * Revision 1.5 2006/06/01 14:43:17 jmlarsen
61  * Added missing documentation
62  *
63  * Revision 1.4 2006/06/01 14:26:14 amodigli
64  * fixed typo
65  *
66  * Revision 1.3 2006/06/01 14:22:07 amodigli
67  * added Doxigen doc
68  *
69  * Revision 1.2 2006/04/24 09:22:16 jmlarsen
70  * Added doxygen tag: addtogroup
71  *
72  * Revision 1.1 2006/02/03 07:46:30 jmlarsen
73  * Moved recipe implementations to ./uves directory
74  *
75  * Revision 1.18 2006/01/05 14:29:59 jmlarsen
76  * Removed newline characters from output strings
77  *
78  * Revision 1.17 2005/12/05 16:11:47 amodigli
79  * Fixed some warning
80  *
81  * Revision 1.16 2005/12/02 12:56:09 amodigli
82  * Fixed compilation problems on mac
83  *
84  * Revision 1.15 2005/11/28 15:36:34 amodigli
85  * Renamed global variables and global function with prefix uves_physmod
86  *
87  * Revision 1.14 2005/11/28 08:37:27 amodigli
88  * Fixed compilation warnings
89  *
90  * Revision 1.13 2005/11/25 08:05:15 amodigli
91  * Added plotting facility in physmod. Commented out some strange things in utils.
92  *
93  * Revision 1.12 2005/11/18 11:49:22 amodigli
94  * More verbosity
95  *
96  * Revision 1.11 2005/11/17 08:25:49 amodigli
97  * Removed uves_necregr.c
98  *
99  * Revision 1.10 2005/10/19 13:18:43 jmlarsen
100  * General update
101  *
102  * Revision 1.9 2005/10/18 10:08:01 amodigli
103  * Removed fctid
104  *
105  * Revision 1.8 2005/10/07 11:17:35 amodigli
106  * Cleaned compilation warnings
107  *
108  * Revision 1.7 2005/10/03 07:32:44 amodigli
109  * Fixed bugs to support RED CCD
110  *
111  * Revision 1.6 2005/09/28 12:28:14 jmlarsen
112  * Replaced fctid -> __func__
113  *
114  * Revision 1.5 2005/09/18 14:24:10 amodigli
115  * Updated
116  *
117  * Revision 1.4 2005/08/29 10:05:08 jmlarsen
118  * Conversion to/from electrons when calculating photonic noise
119  *
120  * Revision 1.3 2005/08/29 08:27:58 amodigli
121  * Put into repository updates on physical model
122  *
123  * Revision 1.2 2005/06/17 12:02:04 amodigli
124  * Fixed compilation problem
125  *
126  * Revision 1.1 2005/06/17 11:34:34 amodigli
127  * First release
128  *
129  *
130  * ===========================================================================
131  */
132 /*----------------------------------------------------------------------------*/
136 /*----------------------------------------------------------------------------*/
137 
138 #ifdef HAVE_CONFIG_H
139 # include <config.h>
140 #endif
141 
142 /*+++ uves_physmod_utils.c +++++++++++++++++++++++++++++++++++++++++++++++++++
143 
144  .COPYRIGHT (C) 1998 European Southern Observatory
145 
146  .IDENT
147 
148  .KEYWORDS uves physical model, spectroscopy, echelle,
149 
150  .USAGE .
151 
152  .INPUT .
153 
154  .OUTPUT .
155 
156  .RETURN Q1: 0: successful return
157  -1: a successful return failed
158 
159  .PURPOSE Library of UVES Physical Model Functions.
160 
161  .ALGORITHM UVES Physical Model.
162 
163  .ENVIRON MIDAS, UVES context
164 
165  .LANGUAGE C
166 
167  .AUTHOR Pascal Ballester, Olivier BOITQUIN, ESO-DMD
168 
169  .VERSION 1.0 1999/07/01 Creation
170  1999/09/30-SW Binning implemented.
171  1999/10/27-OB Bugs with n index fixed.
172 
173  .COMMENT
174 ----------------------------------------------------------------------------*/
175 
176 
177 /*-----------------------------------------------------------------------------
178  Includes
179  -----------------------------------------------------------------------------*/
180 #include <uves_physmod_utils.h>
181 
182 #include <uves_utils.h>
183 #include <uves_utils_wrappers.h>
184 #include <uves_error.h>
185 #include <uves_msg.h>
186 
187 #include <cpl.h>
188 
189 #include <stdio.h>
190 #include <math.h>
191 
192 /*-----------------------------------------------------------------------------
193  Functions prototypes
194  -----------------------------------------------------------------------------*/
195 static void
196 beta2lamb(double uves_beta_ech, double uves_beta_cd, double* plambda, int m);
197 
198 static double
199 cameraFocal(double lm);
200 
201 static void
202 uves_physmod_find_alpha_beta(double lm,
203  int m,
204  double k,
205  double theta,
206  double *alpha,
207  double *beta);
208 
209 static double
210 uves_physmod_find_lambda(double k, double alpha, double beta);
211 
212 static double
213 uves_physmod_find_order_lambda(double k, double alpha, double beta);
214 /* not used:
215 static void
216 uves_physmod_lambda_model(double* plambda,
217  int m,
218  double fc,
219  double x,
220  double y);
221 */
222 static void
223 uves_physmod_lambda_order_beta(double* plambda,
224  int* pm,
225  double x,
226  double y,
227  double* puves_beta_ech,
228  double* puves_beta_cd);
229 
230 static void
231 uves_physmod_lambda_order_focus_model(double* plambda,
232  double* pdm,
233  double fc,
234  double x,
235  double y);
236 
237 static double uves_physmod_wave_bin(double l, int m);
238 
239 static void uves_physmod_xy2beta(double* puves_beta_ech,
240  double* puves_beta_cd,
241  double fc,
242  double x,
243  double y);
244 
245 static void uves_physmod_set_binning(float binx, float biny);
246 
247 static double dsqrarg;
248 
249 /*-----------------------------------------------------------------------------
250  Defines
251  -----------------------------------------------------------------------------*/
252 
253 #define DSQR(a) ((dsqrarg=(a)) == 0.0 ? 0.0 : dsqrarg*dsqrarg)
254 
255 #define PROID "physmod.c"
256 
257 
258 
259 
260 enum uves_arm_ident {UVES_ARM_UNDEF,UVES_ARM_BLUE,UVES_ARM_RED};
261 enum uves_arm_ident uves_arm_ident = UVES_ARM_UNDEF;
262 
263 
264 /* for messout function: no "static" (clear) -
265  no "extern" (otherwise redeclaration in all files neccessary) */
266 
267 /* globals declared as extern in physmod.h */
268 
269 float uves_bin[2] = {1, 1}; /* binning of exposure in x and y */
270 static double uves_physmod_pix_size[2] = {15e-6, 15e-6}; /* meters */
271 static double delta[2] = {75.04, 76.0};
272 
273 static double cdgroov[4] = {1000.0e-6, 660.0e-6, 600.0e-6, 312.5e-6}; /* grooves/nm */
274 static double uves_ech_groov[2] = {31.6e-6, 41.59e-6}; /* grooves/nm */
275 /*double uves_ech_blaze[2] = {75.04, 75.9}; degrees */
276 /*double uves_ech_blaze[2] = {74.74, 76.1};*/
277 static double uves_ech_blaze[2] = {74.57, 75.9}; /* degrees */
278 /*double cdbeam[2] = {45.336, 45.0}; degrees */
279 /*double cdbeam[2] = {45.336, 45.9};*/
280 /*double cdbeam[2] = {45.336, 45.0}; degrees */
281 static double cdbeam[2] = {45.336, 46.0}; /* degrees */
282 /*double uves_ccd_rot[2] = {0.7, -0.45}; degrees */
283 /*double uves_ccd_rot[2] = {-1.0, -1.50}; */
284 /*double uves_ccd_rot[2] = {0.2, -0.45}; degrees */
285 double uves_ccd_rot[2] = {0.3, -0.55}; /* degrees old */
286 /* blue detector upgrade 2004-10-13 */
287 /* double uves_ccd_rot[2] = {0.3, -0.10}; degrees new */
288 static int imsize[2] = {4096, 3000}; /* pixels */
289 static int uves_physmod_row_size[2] = {2048, 2048}; /* pixels */
290 
291 /* Configurations
292  1:Blue CD1, 2:Blue CD2,
293  3:Red CD 3 EEV, 4:Red CD 4 EEV,
294  5:Red CD3 MIT, 6: Red CD4 MIT
295 */
296 
297 /* old */
298 double uves_physmod_offsetx[6]={1391.0,1385.0,1852.0,1835.0,1852.0,1834.0};
299 double uves_physmod_offsety[6]={1030.0,1025.0,2098.0,2104.0,-52.0,-49.0};
300 
301 /* blue detector upgrade 2004-10-13 */
302 /* double uves_physmod_offsetx[6]={1355.0,1350.0,1852.0,1835.0,1852.0,1834.0}; new */
303 /* double uves_physmod_offsety[6]={1030.0,1023.0,2098.0,2104.0,-52.0,-49.0}; new */
304 
305 static double flipx = 1.;
306 static double flipy = -1.;
307 double uves_airt = 25; /* Celsius */
308 double uves_airp = 760; /* mmHg */
309 double uves_airw = 3; /* mmHg */
310 
311 int uves_cfg_indx = 0;
312 int uves_x_disp_id = 0;
313 static int uves_ech_id = 0;
314 double uves_alpha0_cd, uves_beta0_cd;
315 char uves_arm_id = 'x';
316 
317 static double uves_deg2rad = M_PI/180.;
318 
319 /* For history, please keep track HERE of the previous offset used:
320 Garching 1:
321 double uves_physmod_offsetx[6]={1470.0,1450.0,2130.0,2140.0,2130.0,2140.0};
322 double uves_physmod_offsetx[6]={1515.0,1514.0,2010.0,2000.0,2010.0,2000.0};
323 
324 Comissioning 1:
325 double uves_physmod_offsetx[6]={1474.0,1471.0,1960.0,1948.0,1961.0,1949.0};
326 
327 Comissioning 2, Dec 2000:
328 double uves_physmod_offsetx[6]={1390.0,1386.0,1849.0,1840.0,1854.0,1840.0};
329 
330 Paranal 2, Feb 2000:
331 double uves_physmod_offsetx[6]={1390.0,1384.0,1851.0,1840.0,1851.0,1839.0};
332 
333 Garching 1:
334 double uves_physmod_offsety[6]={1030.0,1030.0,2020.0,2020.0,-125.0,-115.0};
335 double uves_physmod_offsety[6]={1029.0,1025.0,2072.0,2080.0,-74.0,-65.0};
336 
337 Comissioning 1:
338 double uves_physmod_offsety[6]={1027.0,1024.0,2069.0,2077.0,-74.0,-65.0};
339 
340 Comissioning 2, Dec 2000:
341 double uves_physmod_offsety[6]={1027.0,1025.0,2084.0,2094.0,-65.0,-54.0};
342 
343 Paranal 2, Feb 2000:
344 double uves_physmod_offsety[6]={1030.0,1025.0,2088.0,2094.0,-57.0,-54.0};
345 
346 The gap between the EEV and MIT chips is estimated to 95 pixels */
347 /*
348 Mean pixel-scales for the 6 configurations:
349  pixscale : 0.252396, 0.246, 0.182, 0.175266, 0.182, 0.175266 */
350 
351 /*---------------------------------------------------------------------*/
352 
353 
365 void
366 uves_physmod_set_incidence(double echred,
367  double echblue,
368  double xred,
369  double xblue)
370 {
371  uves_ech_blaze[0] += echred;
372  uves_ech_blaze[1] += echblue;
373  cdbeam[0] += xred;
374  cdbeam[1] += xblue;
375  uves_msg_debug("uves_ech_blaze=%f,%f ccdbeam=%f,%f",
376  uves_ech_blaze[0],uves_ech_blaze[1],cdbeam[0],cdbeam[1]);
377 }
378 
385 void
386 uves_set_ccd_rot(double* ccdrot,
387  double uves_ccd_rot_off_red,
388  double uves_ccd_rot_off_blue)
389 {
390  uves_ccd_rot[0] =ccdrot[0];
391  uves_ccd_rot[1] =ccdrot[1];
392 
393  uves_ccd_rot[0] += uves_ccd_rot_off_red;
394  uves_ccd_rot[1] += uves_ccd_rot_off_blue;
395 
396  uves_msg_debug("uves_ccd_rot[0,1]=%f,%f uves_ccd_rot_off: red,blue=%f,%f",
397  uves_ccd_rot[0],uves_ccd_rot[1],uves_ccd_rot_off_red,uves_ccd_rot_off_blue);
398 
399 }
400 
410 void
411 uves_physmod_set_offset(double offset_x,
412  double offset_y,
413  double uves_physmod_x_off,
414  double yoff)
415 {
416  uves_physmod_offsetx[uves_cfg_indx-1]=offset_x;
417  uves_physmod_offsety[uves_cfg_indx-1]=offset_y;
418 /*
419  uves_msg("offset_x=%f offset_y=%f",offset_x,offset_y);
420  uves_msg("uves_physmod_offsetx=%f
421  uves_physmod_offsety=%f
422  uves_physmod_x_off=%f
423  yoff=%f",
424  uves_physmod_offsetx[uves_cfg_indx-1],
425  uves_physmod_offsety[uves_cfg_indx-1],
426  uves_physmod_x_off,
427  yoff);
428 */
429  uves_physmod_offsetx[uves_cfg_indx-1] += uves_physmod_x_off;
430  uves_physmod_offsety[uves_cfg_indx-1] += yoff;
431  /*
432  uves_msg("uves_physmod_offsetx=%f
433  uves_physmod_offsety=%f
434  uves_physmod_x_off=%f
435  yoff=%f",
436  uves_physmod_offsetx[uves_cfg_indx-1],
437  uves_physmod_offsety[uves_cfg_indx-1],
438  uves_physmod_x_off,
439  yoff);
440  */
441 }
442 
443 
450 void uves_physmod_set_binning(float binx, float biny)
451 {
452  uves_bin[0] = binx;
453  uves_bin[1] = biny;
454 }
455 
456 
467 void uves_air_config(double p, double t, double w)
468 {
469  uves_airt = t;
470  uves_airp = p;
471  uves_airw = w;
472  uves_msg_debug("uves_airt=%f uves_airp=%f uves_airw=%f",
473  uves_airt,uves_airp,uves_airw);
474 }
475 
480 double uves_air_index(double lambda)
481 {
482  /* wavelength is expected in nanometers. */
483  double t1, t2, t3, airdx;
484 
485  t1 = 1.0e-6/lambda/lambda; /* 1e-6 for nm to um conversion, squared */
486 
487  t2 = (64.328+29498.1/(146.0-t1)+255.4/(41.0-t1))*uves_airp*
488  (1.0+1.0e-6*(1.049-0.0157*uves_airt)*uves_airp)/
489  (720.883*(1.0+0.003661*uves_airt));
490 
491  t3 = t2 - uves_airw*(0.0624 - 0.000680*t1)/(1+0.003661*uves_airt);
492 
493  airdx = 1.0+ t3*1.0e-6;
494  /* airdx = 1.0; */
495  /*
496  uves_msg_debug("uves_airt=%f uves_airp=%f uves_airw=%f",
497  uves_airt,uves_airp,uves_airw);
498  uves_msg_debug("lambda=%f t1=%g t2=%g t3=%g airdx=%g",
499  lambda,t1,t2,t3,airdx);
500  */
501  return(airdx);
502 }
503 
504 
514 void
515 uves_physmod_find_alpha_beta(double lm,
516  int m,
517  double k,
518  double theta,
519  double *alpha,
520  double *beta)
521 {
522 
523  /* Solves sin(alpha) + sin(beta) = m*k*lm, given beta - alpha = theta */
524  uves_msg_debug("lm, m, k, theta : %f %d %f %f",lm,m,k,theta);
525 
526  lm /= uves_air_index(lm);
527 
528  *alpha = 0.5* ( 2*asin( m*k*lm/2/cos(theta*uves_deg2rad/2) ) +
529  theta*uves_deg2rad );
530  *beta = 0.5* ( 2*asin( m*k*lm/2/cos(theta*uves_deg2rad/2) ) -
531  theta*uves_deg2rad );
532  *alpha /= uves_deg2rad;
533  *beta /= uves_deg2rad;
534 }
535 
551 int
552 uves_config(char uves_arm,
553  char uves_ccd_id,
554  int disp,
555  double waveCent,
556  float binx,
557  float biny)
558 {
559 
560  int cfg = 0;
561  uves_ech_id = 2;
562  uves_x_disp_id = disp;
563  uves_arm_id = uves_arm;
564 
565 /* uves_msg("Configuring:
566  Arm %c
567  CCD %c
568  Xdisp %d
569  Wave %f",
570  uves_arm,
571  uves_ccd_id,
572  disp,
573  waveCent);
574 */
575  uves_msg("Cfg: Arm %c CCD %c Xdisp %d Wave %f",
576  uves_arm,uves_ccd_id,disp,waveCent);
577 
578  if (uves_arm == 'b' && disp == 1) cfg = 1;
579  if (uves_arm == 'b' && disp == 2) cfg = 2;
580 
581  if (uves_arm == 'r' && disp == 3) {
582  uves_ech_id = 1;
583  if (uves_ccd_id == 'e') cfg = 3;
584  if (uves_ccd_id == 'm') cfg = 5;
585  }
586  if (uves_arm == 'r' && disp == 4) {
587  uves_ech_id = 1;
588  if (uves_ccd_id == 'e') cfg = 4;
589  if (uves_ccd_id == 'm') cfg = 6;
590  }
591 
592  if (cfg == 0) {
593  cpl_msg_error(__func__,"Wrong configuration!");
594  return -1;
595  }
596 
597  uves_cfg_indx = cfg;
598 
599  (void) uves_physmod_set_binning(binx, biny);
600  (void) uves_physmod_find_alpha_beta(waveCent, 1, cdgroov[uves_x_disp_id-1],
601  cdbeam[uves_ech_id-1], &uves_alpha0_cd, &uves_beta0_cd);
602 
603 
604  uves_msg("alpha, beta for Xdisp: %f %f\nin config %d and CCD-ID %c",
605  uves_alpha0_cd, uves_beta0_cd,cfg, uves_ccd_id);
606 
607  return(cfg);
608 
609 }
619 int
620 uves_config_cpl_new(int uves_arm,
621  int upper,
622  int disp,
623  double waveCent,
624  float binx,
625  float biny)
626 {
627  int cfg = 0;
628  uves_ech_id = 2;
629  uves_x_disp_id = disp;
630 
631 /* uves_msg("Configuring:
632  Arm %c
633  CCD %c
634  Xdisp %d
635  Wave %f",
636  uves_arm,
637  uves_ccd_id,
638  disp,
639  waveCent);
640 */
641  uves_msg("New Cfg: Arm [b/r] %d CCD eev/mit %d Xdisp %d Wave %f",
642  uves_arm,upper,disp,waveCent);
643 
644  if (uves_arm == ARM_BLUE && disp == 1) cfg = 1;
645  if (uves_arm == ARM_BLUE && disp == 2) cfg = 2;
646 
647  if (uves_arm == ARM_RED && disp == 3) {
648  uves_ech_id = 1;
649  if (upper == 0) cfg = 3;
650  if (upper == 1) cfg = 5;
651  }
652  if (uves_arm == ARM_RED && disp == 4) {
653  uves_ech_id = 1;
654  if (upper == 0) cfg = 4;
655  if (upper == 1) cfg = 6;
656  }
657 
658  if (cfg == 0) {
659  cpl_msg_error(__func__,"Wrong configuration!");
660  return -1;
661  }
662 
663  uves_cfg_indx = cfg;
664 
665  (void) uves_physmod_set_binning(binx, biny);
666  (void) uves_physmod_find_alpha_beta(waveCent, 1, cdgroov[uves_x_disp_id-1],
667  cdbeam[uves_ech_id-1], &uves_alpha0_cd, &uves_beta0_cd);
668 
669 
670  uves_msg("alpha, beta for Xdisp: %f %f\nin config %d and CCD-ID %c",
671  uves_alpha0_cd, uves_beta0_cd,cfg, upper == 0 ? 'e' : 'm');
672 
673  return(cfg);
674 
675 }
676 
695 int
696 uves_config_cpl(int blue,
697  int upper,
698  int disp,
699  double waveCent,
700  float binx,
701  float biny)
702 {
703 
704 
705  int cfg = 0;
706  uves_ech_id = 2;
707  uves_x_disp_id = disp;
708 
709 /* uves_msg("Configuring:
710  Arm %c
711  CCD %c
712  Xdisp %d
713  Wave %f",
714  uves_arm,
715  uves_ccd_id,
716  disp,
717  waveCent);
718 */
719  uves_msg("Cfg cpl: Arm [b/r] %d CCD eev/mit %d Xdisp %d Wave %f",
720  blue,upper,disp,waveCent);
721 
722  if (blue == 1 && disp == 1) cfg = 1;
723  if (blue == 1 && disp == 2) cfg = 2;
724 
725  if (blue == 0 && disp == 3) {
726  uves_ech_id = 1;
727  if (upper == 0) cfg = 3;
728  if (upper == 1) cfg = 5;
729  }
730  if (blue == 0 && disp == 4) {
731  uves_ech_id = 1;
732  if (upper == 0) cfg = 4;
733  if (upper == 1) cfg = 6;
734  }
735 
736  if (cfg == 0) {
737  uves_msg_error("Wrong configuration!");
738  return -1;
739  }
740 
741  uves_cfg_indx = cfg;
742 
743  (void) uves_physmod_set_binning(binx, biny);
744  (void) uves_physmod_find_alpha_beta(waveCent, 1, cdgroov[uves_x_disp_id-1],
745  cdbeam[uves_ech_id-1], &uves_alpha0_cd, &uves_beta0_cd);
746 
747 
748  uves_msg("alpha, beta for Xdisp: %f %f\nin config %d and CCD-ID %c",
749  uves_alpha0_cd, uves_beta0_cd,cfg, upper == 0 ? 'e': 'u');
750 
751  return(cfg);
752 
753 }
754 
774 double cameraFocal(double lm)
775 
776 {
777  double nfk=0.;
778  /*uves_msg("lm = %f ", lm);*/
779  /* uves_msg_debug("lm=%g uves_air_index(lm)=%g",lm,uves_air_index(lm)); */
780 
781  lm /= uves_air_index(lm);
782  /* uves_msg_debug("uves_arm=%d",uves_arm_ident); */
783  if (uves_arm_id == 'b' ) {
784  /* uves_msg_debug("uves_arm blue"); */
785  nfk=5.3961886e-7*lm*lm*lm-0.00079597882*lm*lm+0.41122805*lm+287.89644;
786  }
787 
788  if (uves_arm_id == 'r' ) {
789  /* uves_msg_debug("uves_arm red"); */
790  nfk=6.0172051e-13*lm*lm*lm*lm*lm-2.5623231e-9*lm*lm*lm*lm+
791  4.3585543e-6*lm*lm*lm -0.0037286381*lm*lm+
792  1.6289971*lm + 210.06767;
793 
794  }
795  /* uves_msg_debug("lm=%g nfk=%g",lm,nfk); */
796 
797  /*uves_msg("Nfk = %f, lm = %f",nfk/1000.,lm); */
798 return(nfk/1000.);
799 
800 }
801 
802 
808 int uves_physmod_find_order(double lm)
809 {
810  int order;
811  double k, alpha, beta;
812 
813  lm /= uves_air_index(lm);
814 
815  k = uves_ech_groov[uves_ech_id-1];
816  alpha = uves_ech_blaze[uves_ech_id-1];
817  beta = uves_ech_blaze[uves_ech_id-1];
818  order = (int)((sin(alpha*uves_deg2rad) + sin(beta*uves_deg2rad))/k/lm + 0.5);
819  /*
820  uves_msg_debug("uves_ech_id=%d lm %g airindex %g k=%g alpha=%g beta=%g
821  order=%d",uves_ech_id,lm,uves_air_index(lm),k,alpha,beta,order);
822  */
823  return order;
824 }
825 
833 double uves_physmod_find_order_lambda(double k, double alpha, double beta)
834 {
835  double ML;
836  ML = ( ( sin(alpha*uves_deg2rad) + sin(beta*uves_deg2rad) )/k);
837  ML *= uves_air_index(ML);
838  return(ML);
839 }
840 
841 
848 double uves_physmod_find_lambda(double k, double alpha, double beta)
849 {
850  double L;
851  L = (sin(alpha*uves_deg2rad) + sin(beta*uves_deg2rad) )/k ;
852  L *= uves_air_index(L);
853  return(L);
854 }
855 
863 double uves_physmod_find_beta(int m, double k, double l, double alpha)
864 {
865  /* uves_msg ("m, k, l, alpha: %d %f %f %f",m, k, l, alpha); */
866 
867  l /= uves_air_index(l);
868 
869  /* I check that the argument of asin is <=0 otherwhise return
870  a dummy angle (~89 deg) which will produce (x,y) pos out
871  of detector so the line will be discarted
872  */
873  /*
874  uves_msg_debug("l=%g m*k*l=%g alpha=%g",l,m*k*l,alpha);
875  */
876  if ( (m*k*l - sin(alpha*uves_deg2rad)) <=1.0 )
877  {
878  return( (asin(m*k*l - sin(alpha*uves_deg2rad)))/uves_deg2rad );
879  }
880  else
881  {
882  return( (asin(0.999))/uves_deg2rad );
883  }
884 }
885 
894 void
895 uves_physmod_lambda_order2beta(double lambda,
896  int m,
897  double* puves_beta_ech,
898  double* puves_beta_cd,
899  double* pfc)
900 {
901  /* uves_msg ("Disp: %d Ech: %d",uves_x_disp_id,uves_ech_id-1); */
902 
903 /* lambda /= uves_air_index(lambda); bog fixed ! */
904 
905  *pfc = cameraFocal(lambda);
906 
907  /* uves_msg ("New Camera focal (m) : %f",fc); */
908 
909  *puves_beta_ech = uves_physmod_find_beta(m, uves_ech_groov[uves_ech_id-1],
910  lambda, uves_ech_blaze[uves_ech_id-1]);
911 
912  *puves_beta_cd = uves_physmod_find_beta(1, cdgroov[uves_x_disp_id-1],
913  lambda, uves_alpha0_cd);
914  /* uves_msg_debug("fc=%g uves_beta_ech=%g uves_beta_cd=%g"
915  ,*pfc,*puves_beta_ech,*puves_beta_cd); */
916 
917 }
918 
927 void
928 uves_beta2xy(double uves_beta_cd,
929  double uves_beta_ech,
930  double fc,
931  double* px,
932  double* py)
933 {
934  double xd, yd, xr, yr, angle;
935 
936  xd = fc*tan( (uves_beta_ech - uves_ech_blaze[uves_ech_id-1])*
937  uves_deg2rad )/
938  uves_physmod_pix_size[0]/uves_bin[0];
939  yd = fc*tan( (uves_alpha0_cd - uves_beta_cd -
940  cdbeam[uves_ech_id-1])*uves_deg2rad )/
941  uves_physmod_pix_size[1]/uves_bin[1];
942 
943  //CHECK
944  uves_msg_debug("beta(CD), yorg: %f %f", uves_beta_cd, yd);
945 
946  xd = xd*flipx;
947  yd = yd*flipy;
948  uves_msg_debug ("Positions after flip: %f %f",xd,yd);
949 
950  angle = uves_ccd_rot[uves_ech_id-1]*uves_deg2rad;
951  xr = xd*cos(angle) + yd*sin(angle);
952  yr = -xd*sin(angle) + yd*cos(angle);
953 
954  uves_msg_debug ("Rotated positions %f %f",xr,yr);
955 
956  *px = uves_physmod_offsetx[uves_cfg_indx-1] / uves_bin[0] + xr;
957  *py = uves_physmod_offsety[uves_cfg_indx-1] / uves_bin[1] + yr;
958 
959 
960 }
961 
972 void
973 uves_physmod_photo_beta(double lambda,
974  double uves_beta_ech,
975  double uves_beta_cd,
976  double* puves_physmod_rech,
977  double* puves_physmod_rcd,
978  double* pblz)
979 {
980  double gam;
981  /*
982  uves_msg("uves_ech_id = %d, uves_ech_blaze = %f",
983  uves_ech_id,uves_ech_blaze[uves_ech_id-1]);
984  uves_msg("uves_deg2rad=%f uves_beta_ech=%f uves_alpha0_cd=%f",
985  uves_deg2rad,uves_beta_ech,uves_alpha0_cd);
986  */
987  *puves_physmod_rech = cos(uves_ech_blaze[uves_ech_id-1]*uves_deg2rad)/
988  cos(uves_beta_ech*uves_deg2rad);
989 
990  *puves_physmod_rcd = cos(uves_alpha0_cd*uves_deg2rad)/
991  cos(uves_beta_cd*uves_deg2rad);
992  /*
993  uves_msg("puves_physmod_rech=%f *puves_physmod_rcd=%f",
994  *puves_physmod_rech,*puves_physmod_rcd);
995  */
996  /* Computes the blaze function */
997  gam = M_PI / uves_ech_groov[uves_ech_id-1] *
998  cos(delta[uves_ech_id-1]*uves_deg2rad) *
999  (sin((uves_beta_ech-delta[uves_ech_id-1])*uves_deg2rad)-
1000  sin((uves_ech_blaze[uves_ech_id-1]-delta[uves_ech_id-1])*
1001  uves_deg2rad))
1002  / lambda/ uves_air_index(lambda);
1003  *pblz = DSQR(sin(gam)/gam);
1004  /*
1005  uves_msg("gamma = %f, Blaze function = %g ",gam,blz);
1006  */
1007 }
1008 
1032 void uves_physmod_pixscl(
1033  double wave,
1034  int order,
1035  double uves_physmod_rech,
1036  double uves_physmod_rcd,
1037  float binx,
1038  float biny,
1039  double fc,
1040  double slitwidth,
1041  double slitlength,
1042  double* pbinsize,
1043  double* ppixscale,
1044  double* ppixscalCD,
1045  double* plinewidpx,
1046  double* plinelenpx,
1047  double* plinewidth,
1048  double* presol)
1049 {
1050  double binsize, pixscale, pixscalCD, linewidpx, linelenpx, linewidth, resol;
1051  static double scale;
1052 
1053  if (!(scale)) scale = (206265.0*15.0*0.015*200*1e-3*binx)/120000;
1054 
1055  /*
1056  uves_msg("scale=%f
1057  wave=%f
1058  order=%d
1059  fc=%f
1060  uves_physmod_rech=%f
1061  binx=%f
1062  biny=%f
1063  uves_physmod_rcd=%f",
1064  scale,
1065  wave,
1066  order,
1067  fc,
1068  uves_physmod_rech,
1069  binx,
1070  biny,
1071  uves_physmod_rcd);
1072  */
1073 /* Computes the width (in pixel and A) and resolution lines */
1074  binsize = uves_physmod_wave_bin(wave, order) * 1e4; /* in mA */
1075  pixscale = scale/(fc*uves_physmod_rech); /* in arcsec/pixel */
1076  pixscalCD = pixscale *(biny/binx) *uves_physmod_rech/uves_physmod_rcd; /* in arcsec/pixel */
1077  linewidpx = slitwidth / pixscale; /* pixel */
1078  linelenpx = slitlength /pixscalCD; /* pixel */
1079  linewidth = binsize * linewidpx * 1e-3; /* in A (* pixel) */
1080  resol = wave * 10.0 / linewidth; /* without unit */
1081  /* (10.0: conversion factor from nm to A)*/
1082 
1083  /*
1084  uves_msg("slitwidth=%f slitlength=%f binsize=%f pixscale=%f pixscaleCD=%f",
1085  slitwidth, slitlength, binsize, pixscale, pixscalCD);
1086 
1087  uves_msg("linewidpx=%f linewidth=%f resol=%f",
1088  linewidpx, linewidth, resol);
1089  */
1090  *pbinsize = binsize;
1091  *ppixscale = pixscale;
1092  *ppixscalCD = pixscalCD;
1093  *plinewidpx = linewidpx;
1094  *plinelenpx = linelenpx;
1095  *plinewidth = linewidth;
1096  *presol = resol;
1097 
1098 }
1099 
1107 void
1108 uves_physmod_xy_model(double lambda, int m, double* px, double* py)
1109 {
1110  double fc, uves_beta_ech, uves_beta_cd;
1111  //CHECK
1112  uves_physmod_lambda_order2beta(lambda, m, &uves_beta_ech, &uves_beta_cd, &fc);
1113  uves_msg_debug("lambda=%f m=%d uves_beta_ech=%f,uves_beta_cd=%f,fc=%f",
1114  lambda,m,uves_beta_ech,uves_beta_cd,fc);
1115 
1116  uves_beta2xy(uves_beta_cd, uves_beta_ech, fc, px, py);
1117  uves_msg_debug("px=%f py=%f",*px,*py);
1118 
1119 /* exemple :
1120  uves_physmod_photo_beta(lambda, uves_beta_ech, uves_beta_cd,
1121  puves_physmod_rech, puves_physmod_rcd, pblz);
1122 */
1123 
1124 }
1125 
1134 void
1135 uves_physmod_xy2beta(double* puves_beta_ech,
1136  double* puves_beta_cd,
1137  double fc,
1138  double x,
1139  double y)
1140 {
1141  double xr, yr, xd, yd, angle;
1142 
1143  angle = uves_ccd_rot[uves_ech_id-1]*uves_deg2rad;
1144 
1145  xr = (x - uves_physmod_offsetx[uves_cfg_indx-1]/uves_bin[0]);
1146  yr = (y - uves_physmod_offsety[uves_cfg_indx-1]/uves_bin[1]);
1147 
1148  xd = xr*cos(angle) - yr*sin(angle);
1149  yd = xr*sin(angle) + yr*cos(angle);
1150 
1151  xd /= flipx;
1152  yd /= flipy;
1153 
1154  *puves_beta_ech = atan(xd*uves_physmod_pix_size[0]*uves_bin[0]/fc)/
1155  uves_deg2rad + uves_ech_blaze[uves_ech_id-1];
1156  *puves_beta_cd = uves_alpha0_cd - cdbeam[uves_ech_id-1] -
1157  atan(yd*uves_physmod_pix_size[1]*uves_bin[1]/fc)/
1158  uves_deg2rad;
1159 
1160 }
1161 
1170 static void
1171 beta2lamb(double uves_beta_ech,
1172  double uves_beta_cd,
1173  double* plambda,
1174  int m)
1175 {
1176  uves_beta_cd=uves_beta_cd;
1177  *plambda = uves_physmod_find_lambda(m*uves_ech_groov[uves_ech_id-1],
1178  uves_ech_blaze[uves_ech_id-1], uves_beta_ech);
1179 
1180 }
1181 
1194 void
1195 uves_physmod_lambda_order_focus_model(double* plambda,
1196  double* pdm,
1197  double fc,
1198  double x,
1199  double y)
1200 {
1201 
1202  double uves_beta_ech, uves_beta_cd;
1203 
1204  uves_physmod_xy2beta(&uves_beta_ech, &uves_beta_cd, fc, x, y);
1205 
1206  *plambda = uves_physmod_find_order_lambda(cdgroov[uves_x_disp_id-1],
1207  uves_alpha0_cd, uves_beta_cd);
1208  *pdm = uves_physmod_find_order_lambda(uves_ech_groov[uves_ech_id-1],
1209  uves_ech_blaze[uves_ech_id-1], uves_beta_ech)/(*plambda);
1210 /*
1211  uves_msg(" m= %f, lambda= %f, position (x,y)= (%f , %f)",
1212  *pdm,*plambda, x,y);
1213 */
1214 }
1215 
1216 /*************************************************************************
1217  * Finds the couple lambda,m corresponding to a given position (x,y),
1218  * assuming the focal of the camera for this wavelength is fc.
1219  *************************************************************************
1220  */
1221 /* Not used:
1222 void
1223 uves_physmod_lambda_model(double* plambda,
1224  int m,
1225  double fc,
1226  double x,
1227  double y)
1228 {
1229 
1230  double uves_beta_ech, uves_beta_cd;
1231 
1232  uves_physmod_xy2beta(&uves_beta_ech, &uves_beta_cd, fc, x, y);
1233 
1234 
1235  beta2lamb(uves_beta_ech, uves_beta_cd, plambda, m);
1236 
1237 }
1238 */
1239 
1254 void
1255 uves_physmod_lambda_order_beta(double* plambda,
1256  int* pm,
1257  double x,
1258  double y,
1259  double* puves_beta_ech,
1260  double* puves_beta_cd)
1261 {
1262 
1263 double fcguess=0., wave=0., mdbl=0., xe=0., ye=0., xd=0., yd=0.;
1264 int i=0;
1265 
1266 if (uves_arm_id == 'b') fcguess = 0.360;/*0.35722;*/
1267 if (uves_arm_id == 'r') fcguess = 0.500;
1268 
1269 uves_physmod_lambda_order_focus_model(&wave,&mdbl,fcguess,x,y);
1270 /*
1271 if (x == 1500.) {
1272  uves_msg("m= %f, lambda= %f, position (x,y)= (%f , %f)",mdbl,wave, x,y);
1273  uves_msg("focal guess= %f",fcguess);
1274 }
1275 */
1276 do {
1277 
1278  fcguess = cameraFocal(wave);
1279  /*
1280  if (x == 1500.) {
1281  uves_msg("i= %d, focal = %f, m= %f, lambda= %f", i,fcguess,mdbl,wave);
1282  }
1283  */
1284  if (*pm <= 0) *pm = (int)(mdbl+0.5);
1285 /* uves_physmod_lambda_model(&wave,*pm,fcguess,x,y); */
1286  uves_physmod_xy2beta(puves_beta_ech, puves_beta_cd, fcguess, x, y);
1287  beta2lamb(*puves_beta_ech, *puves_beta_cd, &wave, *pm);
1288 
1289  /*
1290  if (x == 1500.) {
1291  uves_msg("i= %d, focal = %f, m= %d, lambda= %f", i,fcguess,*pm,wave);
1292  }
1293  */
1294 
1295  uves_physmod_xy_model(wave,(int)(mdbl+0.5), &xe, &ye);
1296  /*
1297  if (x == 1500.) {
1298  uves_msg("m= %f, lambda= %f, position (xe,ye)= (%f , %f)",
1299  mdbl,wave, xe,ye);
1300  uves_msg("focal = %f",fcguess);
1301  }
1302  */
1303  i++;
1304 
1305  xd = fabs(x-xe);
1306  yd = fabs(y-ye);
1307 
1308  } while (!((xd < 1.) && (yd < 1.)) && (i <= 4));
1309 
1310 *plambda = wave;
1311 
1312 /*uves_msg("i= %d", i);*/
1313 /* uves_physmod_photo_beta(wave, *puves_beta_ech, *puves_beta_cd,
1314  puves_physmod_rech, puves_physmod_rcd, pblz);
1315 uves_msg("uves_physmod_lambda_order_beta(%f, %d, %f, %f, %f, %f)",
1316  wave, *pm, x, y, *puves_beta_ech, *puves_beta_cd);
1317 */
1318 
1319 }
1320 
1334 void
1335 uves_physmod_lambda_order_model(double* plambda, int* pm, double x, double y)
1336 {
1337 
1338  double uves_beta_ech, uves_beta_cd;
1339 
1340  uves_physmod_lambda_order_beta(plambda, pm, x, y,
1341  &uves_beta_ech, &uves_beta_cd);
1342 
1343 /* exemple :
1344  uves_physmod_photo_beta(*plambda, &uves_beta_ech, &uves_beta_cd,
1345  puves_physmod_rech, puves_physmod_rcd, pblz);
1346 
1347 uves_msg("uves_physmod_lambda_order_beta(%f, %d, %f, %f, %f, %f)",
1348  *plambda, *pm, x, y, uves_beta_ech, uves_beta_cd);
1349 */
1350 }
1351 
1360 void
1361 uves_physmod_find_FSR(int m, double* lambdaC, double* fsrStart, double* fsrEnd)
1362 {
1363 
1364  double tmp_delta;
1365 
1366  *lambdaC = 2*sin(uves_ech_blaze[uves_ech_id-1]*uves_deg2rad)/
1367  m/uves_ech_groov[uves_ech_id-1];
1368 
1369  tmp_delta = *lambdaC/m;
1370 
1371  *fsrStart = *lambdaC - tmp_delta/2.;
1372  *fsrEnd = *lambdaC + tmp_delta/2.;
1373 
1374 }
1375 
1381 double uves_physmod_wave_bin(double l, int m)
1382 {
1383 
1384  double dl, x0,y_0,x1,y_1;
1385 
1386  dl = 20e-4; /* Wavelength increment in nm (nearly one pixel)*/
1387 
1388  uves_physmod_xy_model( l, m,&x0,&y_0);
1389  uves_physmod_xy_model((l+dl),m,&x1,&y_1);
1390 
1391  return( dl/(x1-x0) );
1392 }
1393 
1399 void uves_ccd_size(int* nx, int* ny)
1400 {
1401  /*
1402  uves_msg("imsize[uves_ech_id-1]=%d
1403  uves_physmod_row_size[uves_ech_id-1]=%d
1404  uves_bin[0]=%f uves_bin[1]=%f",
1405  imsize[uves_ech_id-1],
1406  uves_physmod_row_size[uves_ech_id-1],
1407  uves_bin[0],
1408  uves_bin[1]);
1409  */
1410  *nx = imsize[uves_ech_id-1] / uves_bin[0];
1411  *ny = uves_physmod_row_size[uves_ech_id-1] / uves_bin[1];
1412 }
1413 
1424 void uves_physmod_xy_regres(double x,double y,double* px,double* py)
1425 {
1426  double xdiff=0;
1427  double ydiff=0;
1428  int xnpix=0;
1429  int ynpix=0;
1430 
1431  goto simplified;
1432  /* We comment the following to remove a compilation warning
1433  Anyway the code would not be executed due to goto statement
1434  xdiff = xcoef[uves_cfg_indx-1][8]*DSQR(x*y) +
1435  xcoef[uves_cfg_indx-1][7]*x*DSQR(y) +
1436  xcoef[uves_cfg_indx-1][6]*DSQR(y) +
1437  xcoef[uves_cfg_indx-1][5]*DSQR(x)*y +
1438  xcoef[uves_cfg_indx-1][4]*x*y +
1439  xcoef[uves_cfg_indx-1][3]*y +
1440  xcoef[uves_cfg_indx-1][2]*DSQR(x) +
1441  xcoef[uves_cfg_indx-1][1]*x +
1442  xcoef[uves_cfg_indx-1][0];
1443 
1444  ydiff = ycoef[uves_cfg_indx-1][8]*DSQR(x*y) +
1445  ycoef[uves_cfg_indx-1][7]*x*DSQR(y) +
1446  ycoef[uves_cfg_indx-1][6]*DSQR(y) +
1447  ycoef[uves_cfg_indx-1][5]*DSQR(x)*y +
1448  ycoef[uves_cfg_indx-1][4]*x*y +
1449  ycoef[uves_cfg_indx-1][3]*y +
1450  ycoef[uves_cfg_indx-1][2]*DSQR(x) +
1451  ycoef[uves_cfg_indx-1][1]*x +
1452  ycoef[uves_cfg_indx-1][0];
1453  */
1454 
1455  /* New, simplified correction */
1456  simplified: {
1457  uves_ccd_size(&xnpix, &ynpix);
1458  /* uves_msg("xnpix=%d ynpix=%d",xnpix,ynpix); */
1459  xdiff = (-7.)*(x-(double)xnpix/2.)/((double)xnpix/2.);
1460  /* ydiff = (5.)*pow((x-(double)xnpix/2.)/((double)xnpix/2.),2.); */
1461  ydiff = (5.)*DSQR((x-(double)xnpix/2.)/((double)xnpix/2.));
1462  /* uves_msg("xdiff=%f ydiff=%f",xdiff,ydiff); */
1463  *px = x + xdiff;
1464  *py = y + ydiff;
1465  }
1466 }
1467