source: trunk/MagicSoft/Simulation/Detector/ReflectorII/atm.c@ 9492

Last change on this file since 9492 was 1722, checked in by moralejo, 22 years ago
*** empty log message ***
File size: 7.5 KB
Line 
1/********************************************************************
2* *
3* File: atm.c *
4* Authors: J.C. Gonzalez, A. Moralejo *
5* *
6* January 2002, A. Moralejo: lots of changes. Moved the code for *
7* the Mie scattering and ozone absorption from attenu.f to *
8* here, after some bugs were found. Now the implementation *
9* is different, we now precalculate the slant paths for the *
10* aerosol and Ozone vertical profiles, and then do an *
11* interpolation in wavelength for every photon to get the *
12* optical depths. The parameters used, defined below, *
13* have been taken from "Atmospheric Optics", by L. Elterman *
14* and R.B. Toolin, chapter 7 of the "Handbook of geophysics *
15* and Space environments". (S.L. Valley, editor). *
16* McGraw-Hill, NY 1965. *
17* *
18* WARNING: the Mie scattering and the Ozone absorption are *
19* implemented to work only with photons produced at a *
20* height a.s.l larger than the observation level. So this *
21* is not expected to work well for simulating the telescope *
22* pointing at theta > 90 deg (for instance for neutrino *
23* studies. Rayleigh scattering works even for light coming *
24* from below. *
25* *
26*********************************************************************/
27
28#include <stdio.h>
29#include <string.h>
30#include <math.h>
31
32#include "atm.h"
33#include "diag.h"
34#include "init.h"
35
36/* random numbers */
37#define RandomNumber ranf()
38#define STEPTHETA 1.74533e-2 /* aprox. 1 degree */
39
40#define MIN(x,y) ((x)<(y)? (x) : (y))
41
42/* Function declarations */
43static float atm(float wavelength, float height, float theta);
44void SetAtmModel(int model, float ol);
45int absorption(float wlen, float height, float theta);
46extern void attenu_(float *, float *, float *, float *, float *); /* in Fortran */
47extern float ranf(void);
48
49/* aerosol_path contains the path integrals for the aerosol number
50 * density (relative to the number density at sea level) between the
51 * observation level and a height h for different zenith angles. The
52 * first index indicate height above sea level in units of 100m, the
53 * second is the zenith angle in degrees.
54 */
55static float aerosol_path[301][90];
56
57/* ozone_path contains the path integrals for the ozone concentration
58 * between the observation level and a height h for different zenith
59 * angles. The first index indicate height above sea level in units
60 * of 100m, the second is the zenith angle in degrees.
61 */
62static float ozone_path[501][90];
63
64static float obslev; /* observation level in cm */
65static double rt; /* Earth radius in cm */
66static int atmModel;
67
68void SetAtmModel(int model, float ol)
69{
70 float Rcos2, sin2, rtsq, path_slant, h, dh, theta;
71 int j;
72
73 atmModel = model;
74 obslev = ol;
75 rt= 6371315.E2; /* Earth radius (same as in Corsika) in cm */
76
77 if (atmModel == ATM_CORSIKA)
78 {
79 /* It follows a precalculation of the slant path integrals we need
80 * for the estimate of the Mie scattering and Ozone absorption:
81 */
82
83 rtsq = sqrt(rt);
84 dh = 1.e3;
85
86 /* Mie (aerosol): */
87
88 for (j = 0; j < 90; j++)
89 {
90 theta = j * STEPTHETA; /* aprox. steps of 1 deg */
91
92 path_slant = 0;
93 Rcos2 = rt * cos(theta)*cos(theta);
94 sin2 = sin(theta)*sin(theta);
95
96 for (h = obslev; h <= 30e5; h += dh)
97 {
98 if (fmod(h,1e4) == 0)
99 aerosol_path[(int)(h/1e4)][j] = path_slant;
100
101 path_slant +=
102 (aero_n[(int)floor(h/1.e5)] + (h/1.e5 - floor(h/1.e5))*
103 (aero_n[(int)ceil(h/1.e5)]-aero_n[(int)floor(h/1.e5)]))
104 /aero_n[0] * dh * (rt+h) /
105 sqrt((rt+h)*(rt+h)-(rt+obslev)*(rt+obslev)*sin2);
106
107 }
108 }
109
110 /* Ozone absorption */
111
112 for (j = 0; j < 90; j++)
113 {
114 theta = j * STEPTHETA; /* aprox. steps of 1 deg */
115 path_slant = 0;
116 Rcos2 = rt * cos(theta)*cos(theta);
117 sin2 = sin(theta)*sin(theta);
118
119 for (h = obslev; h <= 50e5; h += dh)
120 {
121 if (fmod(h,1e4) == 0)
122 ozone_path[(int)(h/1e4)][j] = path_slant;
123
124 path_slant +=
125 (oz_conc[(int)floor(h/1.e5)] + (h/1.e5 - floor(h/1.e5))*
126 (oz_conc[(int)ceil(h/1.e5)]-oz_conc[(int)floor(h/1.e5)]))
127 * dh * (rt+h) /
128 sqrt((rt+h)*(rt+h)-(rt+obslev)*(rt+obslev)*sin2);
129 }
130 }
131
132 }
133
134} /* end of SetAtmModel */
135
136static float atm(float wavelength, float height, float theta)
137{
138 float transmittance = 1.0; /* final atm transmittance (ret. value) */
139 float T_Ray, T_Mie, T_Oz;
140
141 float h; /* True height a.s.l. of the photon emission point in cm */
142 float tdist;
143 float beta0, path;
144
145 int index;
146
147 switch(atmModel)
148 {
149 case ATM_NOATMOSPHERE: /* no atm at all: transmittance = 100% */
150 break;
151 case ATM_90PERCENT: /* atm. with transmittance = 90% */
152 transmittance = 0.9;
153 break;
154 case ATM_CORSIKA: /* atmosphere as defined in CORSIKA */
155
156 /* Distance to telescope: */
157 tdist = (height-obslev)/cos(theta);
158
159 /* Avoid problems if photon is very close to telescope: */
160 if (fabs(tdist) < 1.)
161 {
162 transmittance = 1.;
163 break;
164 }
165
166 /*** We calculate h, the true emission height above sea level: ***/
167
168 h = -rt + sqrt((rt+obslev)*(rt+obslev) + tdist*tdist +
169 (2*(rt+obslev)*(height-obslev)));
170
171 /******* Rayleigh scattering: *******/
172
173 attenu_(&wavelength, &h, &obslev, &theta, &T_Ray);
174
175
176 /******* Ozone absorption: *******/
177
178 if (h > 50.e5)
179 h = 50.e5;
180
181 /* First we get Vigroux Ozone absorption coefficient for the given
182 * wavelength, through a linear interpolation:
183 */
184
185 for (index = 1; index < 11; index++)
186 if (wavelength < wl[index])
187 break;
188
189 beta0 = oz_vigroux[index-1]+(oz_vigroux[index]-oz_vigroux[index-1])*
190 (wavelength-wl[index-1])/(wl[index]-wl[index-1]);
191
192 /* from km^-1 to cm^-1 : */
193 beta0 *= 1e-5;
194
195 /* Now use the pre-calculated values of the path integral
196 * for h and theta: */
197
198 path = ozone_path[(int)floor(0.5+h/1e4)]
199 [(int)MIN(89,floor(0.5+theta/STEPTHETA))];
200
201 T_Oz = exp(-beta0*path);
202
203
204 /******* Mie (aerosol): *******/
205
206 if (h > 30.e5)
207 h = 30.e5;
208
209 /* First get Mie absorption coefficient at sea level for the given
210 * wavelength, through a linear interpolation:
211 */
212
213 for (index = 1; index < 11; index++)
214 if (wavelength < wl[index])
215 break;
216
217 beta0 = aero_betap[index-1]+(aero_betap[index]-aero_betap[index-1])*
218 (wavelength-wl[index-1])/(wl[index]-wl[index-1]);
219
220 /* from km^-1 to cm^-1 : */
221 beta0 *= 1e-5;
222
223 /* Now use the pre-calculated values of the path integral
224 * for h and theta: */
225
226 path = aerosol_path[(int)floor(0.5+h/1e4)]
227 [(int)MIN(89,floor(0.5+theta/STEPTHETA))];
228
229 T_Mie = exp(-beta0*path);
230
231
232 /* Calculate final transmission coefficient: */
233
234 transmittance = T_Ray * T_Oz * T_Mie;
235
236 break;
237
238 } /* end of atm switch */
239
240
241 return transmittance;
242
243} /* end of atm */
244
245int absorption(float wlen, float height, float theta)
246{
247 int ret = 0; /* 0: passed, 1: absorbed */
248
249 if (RandomNumber > atm(wlen, height, theta)) ret=1;
250
251 return ret;
252} /* end of absorption */
253
254
255
Note: See TracBrowser for help on using the repository browser.