Changeset 1722 for trunk/MagicSoft/Simulation/Detector/ReflectorII/atm.c
- Timestamp:
- 01/21/03 15:02:35 (22 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/MagicSoft/Simulation/Detector/ReflectorII/atm.c
r1614 r1722 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 1 28 #include <stdio.h> 2 29 #include <string.h> 3 30 #include <math.h> 31 32 #include "atm.h" 4 33 #include "diag.h" 5 #include "atm.h"6 34 #include "init.h" 7 35 8 36 /* random numbers */ 9 37 #define RandomNumber ranf() 10 11 /* AM Nov 2002: atmModel is now an external variable: */ 12 int atmModel=0; /* current atm. model */ 38 #define STEPTHETA 1.74533e-2 /* aprox. 1 degree */ 39 40 #define MIN(x,y) ((x)<(y)? (x) : (y)) 13 41 14 42 /* Function declarations */ 15 43 static float atm(float wavelength, float height, float theta); 16 void SetAtmModel( char *model);44 void SetAtmModel(int model, float ol); 17 45 int absorption(float wlen, float height, float theta); 18 extern void attenu_(float *, float *, float *, float * ); /* in Fortran */46 extern void attenu_(float *, float *, float *, float *, float *); /* in Fortran */ 19 47 extern float ranf(void); 20 48 21 void SetAtmModel(char *model) 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 */ 55 static 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 */ 62 static float ozone_path[501][90]; 63 64 static float obslev; /* observation level in cm */ 65 static double rt; /* Earth radius in cm */ 66 static int atmModel; 67 68 void SetAtmModel(int model, float ol) 22 69 { 23 while (strcmp(model, AtmModelNames[atmModel])) 24 if (++atmModel == sizeof(AtmModelNames)/sizeof(AtmModelNames[0])) 25 { atmModel = 0; 26 Error(ATM__NFND__ERR, model); 27 break; } 28 29 Log(ATM__SET___LOG, AtmModelNames[atmModel]); 30 31 /* 'erfc' must be inited, so keep the following line. */ 32 Debug("Initing 'erfc': ret=%g\n", erfc(M_PI)); 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 33 134 } /* end of SetAtmModel */ 34 135 35 136 static float atm(float wavelength, float height, float theta) 36 { float transmittance = 1.0; /* final atm transmittance (ret. value) */ 37 38 switch(atmModel) 39 { case ATM_NOATMOSPHERE: /* no atm at all: transmittance = 100% */ 40 break; 41 case ATM_90PERCENT: /* atm. with transmittance = 90% */ 42 transmittance = 0.9; 43 break; 44 case ATM_ISOTHERMAL: /* isothermal approximation */ 45 /********************/ 46 break; 47 case ATM_CORSIKA: /* atmosphere as defined in CORSIKA */ 48 attenu_(&wavelength, &height, &theta, &transmittance); 49 break; 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 50 238 } /* end of atm switch */ 51 239 52 return transmittance; 240 241 return transmittance; 242 53 243 } /* end of atm */ 54 244 55 245 int absorption(float wlen, float height, float theta) 56 { int ret = 0; /* 0: passed, 1: absorbed */ 246 { 247 int ret = 0; /* 0: passed, 1: absorbed */ 57 248 58 59 60 249 if (RandomNumber > atm(wlen, height, theta)) ret=1; 250 251 return ret; 61 252 } /* end of absorption */ 253 254 255
Note:
See TracChangeset
for help on using the changeset viewer.