Ignore:
Timestamp:
01/21/03 15:02:35 (22 years ago)
Author:
moralejo
Message:
*** empty log message ***
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
    128#include <stdio.h>
    229#include <string.h>
    330#include <math.h>
     31
     32#include "atm.h"
    433#include "diag.h"
    5 #include "atm.h"
    634#include "init.h"
    735
    836/*  random numbers  */
    937#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))
    1341
    1442/*  Function declarations  */
    1543static float atm(float wavelength, float height, float theta);
    16 void SetAtmModel(char *model);
     44void SetAtmModel(int model, float ol);
    1745int absorption(float wlen, float height, float theta);
    18 extern void attenu_(float *, float *, float *, float *);  /* in Fortran */
     46extern void attenu_(float *, float *, float *, float *, float *);  /* in Fortran        */
    1947extern float ranf(void);
    2048
    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 */
     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)
    2269{
    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
    33134}   /*  end of SetAtmModel  */
    34            
     135
    35136static 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
    50238    }   /*  end of atm switch   */
    51239
    52     return transmittance;
     240
     241  return transmittance;
     242
    53243}   /*  end of atm  */
    54244
    55245int absorption(float wlen, float height, float theta)
    56 {   int ret = 0;        /*  0: passed, 1: absorbed  */
     246{
     247  int ret = 0;  /*  0: passed, 1: absorbed  */
    57248   
    58     if (RandomNumber > atm(wlen, height, theta)) ret=1;
    59 
    60     return ret;
     249  if (RandomNumber > atm(wlen, height, theta)) ret=1;
     250
     251  return ret;
    61252}   /*  end of absorption  */
     253
     254
     255
Note: See TracChangeset for help on using the changeset viewer.