VProfileModel.cc
Go to the documentation of this file.
1 
9 #include <atm/VProfileModel.h>
10 #include <atm/ProfileResult.h>
11 
12 #include <utl/AugerUnits.h>
13 #include <utl/MathConstants.h>
14 #include <utl/PhysicalConstants.h>
15 #include <utl/PhysicalFunctions.h>
16 #include <utl/TabulatedFunctionErrors.h>
17 
18 #include <iostream>
19 #include <limits>
20 
21 using namespace utl;
22 using namespace std;
23 
24 
25 // For some reason, CLHEP SystemOfUnits.h #defines pascal to hep_pascal,
26 // putting it in the global namespace and screwing up our own definition of
27 // pascal from AugerUnits.h. It appears the CLHEP units are being pulled in
28 // via the geometry package. The following line undoes the CLHEP sabotage.
29 #undef pascal
30 
31 
32 namespace atm {
33 
34  VProfileModel::VProfileModel() :
35  fTabLogDepthVsHeight(new ProfileResult),
36  fTabHeightVsLogDepth(new ProfileResult),
37  fTabLogPressureVsHeight(new ProfileResult),
38  fTabLogVaporPressureVsHeight(new ProfileResult),
39  fTabTemperatureVsHeight(new ProfileResult),
40  fTabLogDensityVsHeight(new ProfileResult),
41  fTabRIVsHeight(new ProfileResult)
42  { }
43 
44 
46  {
47  delete fTabLogDepthVsHeight;
48  delete fTabHeightVsLogDepth;
53  delete fTabRIVsHeight;
54 
56  }
57 
58 
59  const ProfileResult&
61  const
62  {
63  // eventually, all calculations of refraction indices could be moved
64  // here (since calculation is same for all the derived classes).
65  // Unfortunately doing so is best left until after we have
66  // TabulatedFunction and TabulatedFunctionErrors classes which
67  // do not suck so severely.
68 
69  // Where the relation : (n^2-1)/(n^2+2) = const.*density
70  // double d = (((n0*n0) - 1)/((n0*n0) + 2))/overburdenSeaLevel;
71 
72  // ProfileResult rProf = EvaluateDepthVsHeight();
73 
74  // for (TabulatedFunction::Iterator it = fTabLogDepthVsHeight->Begin();
75  // it != fTabLogDepthVsHeight->End() ; ++it){
76 
77  // // it->Y() = sqrt
78 
79  // }
80  return *fTabRIVsHeight;
81  }
82 
83 
84  const
87  const
88  {
89  // Find wavelength profile if already stored
90  const AltWLFunction::const_iterator profIt = fTabRIVsHeightAndWaveLength.find(waveLength);
91  if (profIt != fTabRIVsHeightAndWaveLength.end())
92  return *profIt->second;
93 
94  // Else, evaluate the profile, assuming other tables have been filled already
95  TabulatedFunctionErrors tabRefIndex;
96  for (TabulatedFunction::Array::const_iterator heightIt = fTabTemperatureVsHeight->fProfile.XBegin();
97  heightIt != fTabTemperatureVsHeight->fProfile.XEnd(); ++heightIt) {
98  const double temperature = fTabTemperatureVsHeight->Y(*heightIt);
99  const double pressure = fTabLogPressureVsHeight->Y(*heightIt);
100  const double vaporPressure = fTabLogVaporPressureVsHeight->Y(*heightIt);
101 
102  const double nAir = utl::RefractionIndex::Ciddor95(waveLength, temperature, pressure, vaporPressure);
103 
104  tabRefIndex.PushBack(*heightIt, 0, nAir, 0); // Ignore errors for now
105  }
106 
107  ProfileResult* const refIndex =
109  fTabRIVsHeightAndWaveLength[waveLength] = refIndex;
110 
111  return *refIndex;
112  }
113 
114 
115  double
116  VProfileModel::GetVerticalTimeOfFlight(const double h1, const double h2)
117  const
118  {
119  const double height1 = min(h1, h2);
120  const double height2 = max(h1, h2);
121 
122  // Average Malargue atmosphere parameterization
123  // (here we use the April atmosphere from GAP-2005-021)
124  const int nLayers = 6;
125  const double borders[nLayers + 1] = {
127  0*m,
128  9900*m,
129  12100*m,
130  38000*m,
131  100000*m,
133  };
134 
135  const double bParams[nLayers] = {
136  0,
137  1174.1385*g/cm2,
138  1215.7355*g/cm2,
139  1425.6919*g/cm2,
140  503.93170*g/cm2,
141  0
142  };
143 
144  const double cParams[nLayers] = {
145  0,
146  967164.96*cm,
147  768155.10*cm,
148  621852.25*cm,
149  785601.62*cm,
150  0
151  };
152 
153  enum Layers {
154  eBelowSeaLevel = 0,
155  eSeaLevel = 1,
156  eVacuum = nLayers-1
157  };
158 
159  const double rho0 = bParams[eSeaLevel] / cParams[eSeaLevel];
160 
161  // difference to c_vaccum at sea level
162  const double deltaN = kRefractiveIndexSeaLevel - 1;
163 
164  // integrate from height1 to height2
165  // (see GAP-2007-99, Eq. (6.25), but note the wrong sign!)
166 
167  double verticalLength = 0;
168 
169  for (int i = 0; i < nLayers; ++i) {
170 
171  if (height1 > borders[i] && height1 <= borders[i+1]) {
172 
173  double startHeight = height1;
174 
175  for (int j = i; j < nLayers; ++j) {
176 
177  const double stopHeight =
178  (height2 > borders[j] && height2 <= borders[j+1]) ? height2 : borders[j+1];
179 
180  const double deltaH = stopHeight - startHeight;
181 
182  if (j == eBelowSeaLevel)
183  verticalLength += kRefractiveIndexSeaLevel * deltaH;
184  else if (j == eVacuum)
185  verticalLength += deltaH;
186  else
187  verticalLength += deltaH +
188  deltaN*bParams[j]/rho0 * (exp(-startHeight / cParams[j]) - exp(-stopHeight / cParams[j]));
189 
190  if (stopHeight == height2)
191  break;
192 
193  startHeight = stopHeight;
194 
195  }
196  break;
197 
198  }
199 
200  }
201 
202  return verticalLength / kSpeedOfLight;
203  }
204 
205 
206  void
208  {
209  // Remove stored wavelength-dependent refraction index height profiles
210  for (const auto& ref : fTabRIVsHeightAndWaveLength)
211  delete ref.second;
212 
213  fTabRIVsHeightAndWaveLength.clear();
214  }
215 
216 
217  void
219  const
220  {
221  // Extend all tables to 100 km
222  // DEPRECATED: when Atm_Molecular_0_A is REPLACED, this will be removed...
227 
228  const double maxHeight = logDepthVsHeight.XBack();
229  const double minLog = kLn10 * numeric_limits<double>::min_exponent10;
230 
231  // Balloon profiles may not extend above the troposphere
232  if (maxHeight < 11*km) {
233  logDepthVsHeight.PushBack(11*km, 0, log(231.81*g/cm2), minLog);
234  tempVsHeight.PushBack(11*km, 0, 216.65*kelvin, 0.);
235  logPVsHeight.PushBack(11*km, 0, log(22633*pascal), minLog);
236  logDensityVsHeight.PushBack(11*km, 0, log(0.3638*kg/m3), minLog);
237  }
238 
239  if (maxHeight < 20*km) {
240  logDepthVsHeight.PushBack(20*km, 0, log(56.24*g/cm2), minLog);
241  tempVsHeight.PushBack(20*km, 0, 216.65*kelvin, 0);
242  logPVsHeight.PushBack(20*km, 0, log(5475*pascal), minLog);
243  logDensityVsHeight.PushBack(20*km, 0, log(0.088*kg/m3), minLog);
244  }
245 
246  // Monthly DBs usually extend to 30 km only
247  logDepthVsHeight.PushBack( 32*km, 0, log(8.95*g/cm2), minLog);
248  logDepthVsHeight.PushBack( 47*km, 0, log(1.15*g/cm2), minLog);
249  logDepthVsHeight.PushBack( 51*km, 0, log(0.68*g/cm2), minLog);
250  logDepthVsHeight.PushBack( 71*km, 0, log(0.04*g/cm2), minLog);
251  logDepthVsHeight.PushBack(100*km, 0, log(1e-3*g/cm2), minLog);
252 
253  tempVsHeight.PushBack( 32*km, 0, 228.00*kelvin, 0);
254  tempVsHeight.PushBack( 47*km, 0, 270.65*kelvin, 0);
255  tempVsHeight.PushBack( 51*km, 0, 270.65*kelvin, 0);
256  tempVsHeight.PushBack( 71*km, 0, 214.65*kelvin, 0);
257  tempVsHeight.PushBack(100*km, 0, 214.65*kelvin, 0);
258 
259  logPVsHeight.PushBack( 32*km, 0, log(868*pascal), minLog);
260  logPVsHeight.PushBack( 47*km, 0, log(111*pascal), minLog);
261  logPVsHeight.PushBack( 51*km, 0, log( 66*pascal), minLog);
262  logPVsHeight.PushBack( 71*km, 0, log( 4*pascal), minLog);
263  logPVsHeight.PushBack(100*km, 0, log(0.1*pascal), minLog);
264 
265  logDensityVsHeight.PushBack( 32*km, 0, log(0.0132*kg/m3), minLog);
266  logDensityVsHeight.PushBack( 47*km, 0, log(0.0014*kg/m3), minLog);
267  logDensityVsHeight.PushBack( 51*km, 0, log(0.0009*kg/m3), minLog);
268  logDensityVsHeight.PushBack( 71*km, 0, log(0.0001*kg/m3), minLog);
269  logDensityVsHeight.PushBack(100*km, 0, log(0.00001*kg/m3), minLog);
270 
271  fTabLogVaporPressureVsHeight->fProfile.PushBack(100*km, 0, minLog, minLog);
272  fTabRIVsHeight->fProfile.PushBack(100*km, 0, 1 + std::numeric_limits<double>::epsilon(), 0);
273 
274  // Fill log(depth) table to height of 100 km (NOTE: use reverse order)
276  TabulatedFunctionErrIterator hxIt = heightVsLogDepth.Begin();
277 
278  if (maxHeight < 11*km)
279  hxIt = heightVsLogDepth.Insert(hxIt, log(231.81*g/cm2), minLog, 11*km, 0);
280  if (maxHeight < 20*km)
281  hxIt = heightVsLogDepth.Insert(hxIt, log(56.24*g/cm2), minLog, 20*km, 0);
282 
283  hxIt = heightVsLogDepth.Insert(hxIt, log(8.95*g/cm2), minLog, 32*km, 0);
284  hxIt = heightVsLogDepth.Insert(hxIt, log(1.15*g/cm2), minLog, 47*km, 0);
285  hxIt = heightVsLogDepth.Insert(hxIt, log(0.68*g/cm2), minLog, 51*km, 0);
286  hxIt = heightVsLogDepth.Insert(hxIt, log(0.04*g/cm2), minLog, 71*km, 0);
287  hxIt = heightVsLogDepth.Insert(hxIt, log(1e-3*g/cm2), minLog, 100*km, 0);
288  }
289 
290 }
ArrayConstReference XBack() const
read-only reference to back of array of X
ProfileResult * fTabRIVsHeight
Definition: VProfileModel.h:74
virtual ~VProfileModel()
ArrayIterator XEnd()
end of array of X
constexpr double kRefractiveIndexSeaLevel
ProfileResult * fTabLogDepthVsHeight
Definition: VProfileModel.h:68
void CleanRIVsWavelength() const
Clean up refraction indices. Derived modules decide when to do this.
ProfileResult * fTabTemperatureVsHeight
Definition: VProfileModel.h:72
double Y(const double x) const
Get the Y value (coordinate) for given X (ordinate)
virtual const ProfileResult & EvaluateRefractionIndexVsHeight() const
Return a table of wavelength-independent refractive index vs. altitude.
#define max(a, b)
void ExtendProfilesTo100km() const
constexpr double pascal
Definition: AugerUnits.h:212
Class describing the Atmospheric profile.
Definition: ProfileResult.h:25
constexpr double m3
Definition: AugerUnits.h:123
ProfileResult * fTabLogVaporPressureVsHeight
Definition: VProfileModel.h:71
ProfileResult * fTabLogDensityVsHeight
Definition: VProfileModel.h:73
const double km
constexpr double g
Definition: AugerUnits.h:200
void PushBack(const double x, const double xErr, const double y, const double yErr)
constexpr double kLn10
Definition: MathConstants.h:29
constexpr double kelvin
Definition: AugerUnits.h:259
constexpr double kSpeedOfLight
ProfileResult * fTabLogPressureVsHeight
Definition: VProfileModel.h:70
double Ciddor95(const double wl, const double temperature, const double pressure, const double vaporPressure)
Wavelength-dependent index of refraction for humid air.
ArrayIterator XBegin()
begin of array of X
virtual double GetVerticalTimeOfFlight(const double height1, const double height2) const
Evaluate light signal time-of-flight between two altitudes.
IteratorErr Insert(const IteratorErr &pos, const double x, const double xErr, const double y, const double yErr)
constexpr double cm
Definition: AugerUnits.h:117
utl::TabulatedFunctionErrors fProfile
Definition: ProfileResult.h:65
ProfileResult * fTabHeightVsLogDepth
Definition: VProfileModel.h:69
AltWLFunction fTabRIVsHeightAndWaveLength
Definition: VProfileModel.h:77
constexpr double m
Definition: AugerUnits.h:121
constexpr double kg
Definition: AugerUnits.h:199
constexpr double cm2
Definition: AugerUnits.h:118

, generated on Tue Sep 26 2023.