SimShowerProfileModel.cc
Go to the documentation of this file.
1 
10 
11 #include <utl/Reader.h>
12 #include <utl/ErrorLogger.h>
13 #include <utl/AugerException.h>
14 #include <utl/AugerUnits.h>
15 #include <utl/MathConstants.h>
16 #include <utl/TabulatedFunction.h>
17 #include <utl/PhysicalConstants.h>
18 #include <utl/PhysicalFunctions.h>
19 #include <utl/Vector.h>
20 #include <utl/Point.h>
21 #include <utl/ReferenceEllipsoid.h>
22 #include <utl/UTMPoint.h>
23 
24 #include <fwk/CentralConfig.h>
25 #include <fwk/RunController.h>
26 #include <fwk/LocalCoordinateSystem.h>
27 
28 #include <atm/ProfileResult.h>
29 
30 #include <evt/Event.h>
31 #include <evt/Header.h>
32 #include <evt/ShowerSimData.h>
33 #include <evt/RadioSimulation.h>
34 #include <evt/AtmosphereParameters.h>
35 
36 #include <iostream>
37 #include <iomanip>
38 #include <limits>
39 #include <string>
40 #include <sstream>
41 #include <vector>
42 
43 using namespace atm;
44 using namespace utl;
45 using namespace std;
46 using namespace fwk;
47 using namespace evt;
48 
49 
50 void
52 {
53  INFO("Using SimShowerProfileModel");
54 }
55 
56 
57 void
59  const
60 {
61  const Event& event = RunController::GetInstance().GetCurrentEvent();
62 
63  if (fInitialized && fCurrentEvent == event.GetHeader().GetId())
64  return;
65 
66  if (!(event.HasSimShower() && event.GetSimShower().HasAtmosphereParameters()))
67  throw NoDataForModelException("SimShowerProfileModel requires that the event has a simulated shower "
68  "with AtmosphereParameters. One of the two was not found.");
69 
70  const ShowerSimData& shower = event.GetSimShower();
71 
72  if (!shower.HasGeometry())
73  throw MissingEventDataException("The shower geometry is not defined yet.");
74 
75  fCurrentEvent = event.GetHeader().GetId();
76  fInitialized = true;
77 
78  // this is for paranoid people (like me): The shower coordinate
79  // system might now point "upward" like an AugerCorrdinateSystem
80  // in all possible cases. Thus, use the original reference frame of
81  // the air shower simulation program (ie CORSIKA)
83  const Point pCORSIKA(0, 0, 0, coordSys);
84  const Vector zCORSIKA(0, 0, 1, coordSys);
85  const CoordinateSystemPtr localSys = LocalCoordinateSystem::Create(pCORSIKA);
86  const Vector zLocal(0, 0, 1, localSys);
87  const double cosZenith = zCORSIKA.GetCosTheta(localSys);
88 
89  const double hObservationLevel = UTMPoint(pCORSIKA, ReferenceEllipsoid::eWGS84).GetHeight();
90 
91  const AtmosphereParameters& params = shower.GetAtmosphereParameters();
92  fHlay = params.GetLayerAltitudes();
93  fAatm = params.GetA();
94  fBatm = params.GetB();
95  fCatm = params.GetC();
96 
97  double refractiveIndexAtSeaLevel = 0;
98  if (shower.HasRadioSimulation()) {
99  const RadioSimulation& radioSim = shower.GetRadioSimulation();
100  refractiveIndexAtSeaLevel = radioSim.GetRefractiveIndexAtSeaLevel();
101  ostringstream info;
102  info << "Event has RadioSimulation, use refractive index at sea level from .reas file: n = "
103  << std::setprecision(10) << refractiveIndexAtSeaLevel;
104  INFO(info);
105  } else {
106  refractiveIndexAtSeaLevel = kRefractiveIndexSeaLevel;
107  }
108 
109  // make tabulated functions
110  TabulatedFunctionErrors tabRIVsHeight;
111  TabulatedFunctionErrors tabLogPressureVsHeight;
112  TabulatedFunctionErrors tabLogVaporPressureVsHeight;
113  TabulatedFunctionErrors tabTemperatureVsHeight;
114  TabulatedFunctionErrors tabLogDepthVsHeight;
115  TabulatedFunctionErrors tabLogDensityVsHeight;
116  TabulatedFunctionErrors tabHeightVsLogDepth;
117 
118  const double minLog = kLn10 * numeric_limits<double>::min_exponent10;
119  const double densityAtSeaLevel = GetDensityAtHeight(0);
120 
121  vector<double> heights;
122  vector<double> depths;
123 
124  /* Loop just over layer altitudes turned out to be insufficent.
125  With a more finer step-size results are much more accurate. */
126  const double heightStep = 10 * meter;
127  double height = -heightStep;
128  while (height < fHlay.back()) {
129  height += heightStep;
130 
131  if (height > fHlay.back())
132  height = fHlay.back();
133 
134  const double heightCORSIKA = height;
135  const double heightOffline = cosZenith * (heightCORSIKA - hObservationLevel) + hObservationLevel;
136 
137  const double depth = GetDepthAtHeight(heightCORSIKA);
138  const double pressure = depth * atmosphere / kOverburdenSeaLevel;
139  const double density = GetDensityAtHeight(heightCORSIKA);
140 
141  // by eye average, from GAP-2009-037
142  const double avgrelhumidity = 27 * percent;
143 
144  // assuming dry, clean atmosphere
145  // exploiting the molar ideal gas law
146 
147  const double temperature = pressure * kDryAirMolarMass / kMolarGasConstant / density;
148 
149  const double pSat = SaturationVaporPressure(temperature);
150  // from GDASProfileModel.cc
151  const double pVapor = avgrelhumidity * pSat;
152 
153  double refracIndex = 1;
154  if (shower.HasRadioSimulation()) {
155  // Gladstone-Dale law analogous to CoREAS
156  refracIndex = RefractionIndex::GladstoneDale(density, densityAtSeaLevel, refractiveIndexAtSeaLevel);
157  } else {
158  // analogous to GDASProfileModel.cc
159  refracIndex = RefractionIndex::LorentzLorentz(depth);
160  }
161 
162  tabLogDepthVsHeight.PushBack(heightOffline, 0, log(depth), minLog);
163 
164  tabLogPressureVsHeight.PushBack(heightOffline, 0, log(pressure), minLog);
165 
166  tabLogDensityVsHeight.PushBack(heightOffline, 0, log(density), minLog);
167 
168  tabRIVsHeight.PushBack(heightOffline, 0., log(refracIndex), minLog);
169 
170  tabLogVaporPressureVsHeight.PushBack(heightOffline, 0, log(pVapor), minLog);
171 
172  tabTemperatureVsHeight.PushBack(heightOffline, 0, temperature, 0);
173 
174  heights.push_back(heightOffline);
175  depths.push_back(depth);
176  }
177 
178  // have to fill tabulated functions in ascending order or ordinate (tabulated function should be fixed..)
179  for (int i = heights.size() - 1; i >= 0; --i)
180  tabHeightVsLogDepth.PushBack(log(depths[i]), minLog, heights[i], 0);
181 
182  // create profile results
183  *fTabLogPressureVsHeight =
184  ProfileResult(tabLogPressureVsHeight, ProfileResult::eLinear, ProfileResult::eLog);
185 
186  *fTabLogVaporPressureVsHeight =
187  ProfileResult(tabLogVaporPressureVsHeight, ProfileResult::eLinear, ProfileResult::eLog);
188 
189  *fTabTemperatureVsHeight =
191 
192  *fTabLogDensityVsHeight =
194 
195  *fTabLogDepthVsHeight =
197 
198  *fTabHeightVsLogDepth =
200 
201  *fTabRIVsHeight =
203 }
204 
205 
206 const ProfileResult&
208  const
209 {
210  LazyInit();
211  return *fTabLogPressureVsHeight;
212 }
213 
214 
215 const ProfileResult&
217  const
218 {
219  LazyInit();
220  return *fTabLogVaporPressureVsHeight;
221 }
222 
223 
224 const ProfileResult&
226  const
227 {
228  LazyInit();
229  return *fTabTemperatureVsHeight;
230 }
231 
232 
233 const ProfileResult&
235  const
236 {
237  LazyInit();
238  return *fTabLogDensityVsHeight;
239 }
240 
241 
242 const ProfileResult&
244  const
245 {
246  LazyInit();
247  return *fTabLogDepthVsHeight;
248 }
249 
250 
251 const ProfileResult&
253  const
254 {
255  LazyInit();
256  return *fTabHeightVsLogDepth;
257 }
258 
259 
260 const ProfileResult&
262  const
263 {
264  LazyInit();
265  return *fTabRIVsHeight;
266 }
267 
268 
269 double
271  const
272 {
273  const int n = fHlay.size();
274  for (int l = 0; l < n-1; ++l)
275  if (fHlay[l] <= height && height < fHlay[l+1])
276  return fBatm[l] * exp(-height/fCatm[l]) / fCatm[l];
277  if (height >= fHlay[n-1])
278  return fBatm[n-1] / fCatm[n-1];
279  return 0;
280 }
281 
282 
283 double
285  const
286 {
287  int section = 0;
288  const int n = fHlay.size();
289  for (int l = 0; l < n-1; ++l) {
290  if (fHlay[l] <= height && height < fHlay[l+1]) {
291  section = l;
292  break;
293  }
294  }
295  if (height >= fHlay[n-1])
296  section = n-1;
297 
298  const double hc = height / fCatm[section];
299  if (section < 4)
300  return fAatm[section] + fBatm[section] * exp(-hc);
301  return fAatm[section] - fBatm[section] * hc;
302 }
const ProfileResult & EvaluateVaporPressureVsHeight() const override
Table of H2O vapor pressure as a function of height.
const evt::AtmosphereParameters & GetAtmosphereParameters() const
Get the Atmosphere profile used to simulate the shower.
double GetDepthAtHeight(const double height) const
Point object.
Definition: Point.h:32
constexpr double atmosphere
Definition: AugerUnits.h:215
double GladstoneDale(const double density, const double densityAtSeaLevel, const double refractiveIndexAtSeaLevel)
Calculate the refraction index for a given density.
constexpr double kDryAirMolarMass
double GetDensityAtHeight(const double height) const
Class to hold and convert a point in geodetic coordinates.
Definition: UTMPoint.h:40
double GetCosTheta(const CoordinateSystemPtr &coordinateSystem) const
cos of zenith (theta) angle
Definition: BasicVector.h:251
const std::vector< double > & GetA() const
constexpr double kRefractiveIndexSeaLevel
Data structure for a radio simulation (including several SimRadioPulses)
constexpr double kOverburdenSeaLevel
const double meter
Definition: GalacticUnits.h:29
constexpr double percent
Definition: AugerUnits.h:283
#define INFO(message)
Macro for logging informational messages.
Definition: ErrorLogger.h:161
bool HasRadioSimulation() const
Check initialization of the RadioSimulation.
const std::vector< double > & GetB() const
double GetRefractiveIndexAtSeaLevel() const
const atm::ProfileResult & EvaluateDepthVsHeight() const override
Table of depth as a function of height.
Exception to use in a atmosphere model cannot find data it needs.
Interface class to access Shower Simulated parameters.
Definition: ShowerSimData.h:49
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
const atm::ProfileResult & EvaluateTemperatureVsHeight() const override
Table of temperature as a function of height.
double GetHeight() const
Get the height.
Definition: UTMPoint.h:212
Class describing the Atmospheric profile.
Definition: ProfileResult.h:25
utl::CoordinateSystemPtr GetGroundParticleCoordinateSystem() const
RadioSimulation & GetRadioSimulation()
Get the radio simulation data.
double SaturationVaporPressure(const double temperature)
Evaluate the saturation vapor pressure over ice or water.
void PushBack(const double x, const double xErr, const double y, const double yErr)
const atm::ProfileResult & EvaluateHeightVsDepth() const override
Table of height as a function of depth.
constexpr double kLn10
Definition: MathConstants.h:29
double LorentzLorentz(const double verticalDepth)
Calculate the refraction index for a given depth.
Base class for exceptions arising because required info not present in the Event. ...
const atm::ProfileResult & EvaluateRefractionIndexVsHeight() const override
Table of refraction index as a function of height.
constexpr double kMolarGasConstant
bool HasGeometry() const
check initialization of shower geometry
const std::vector< double > & GetLayerAltitudes() const
const atm::ProfileResult & EvaluatePressureVsHeight() const override
Table of air pressure as a function of height.
Vector object.
Definition: Vector.h:30
const atm::ProfileResult & EvaluateDensityVsHeight() const override
Table of density as a function of height.
const std::vector< double > & GetC() const
Class to hold the standard parameters used to specify an atmospheric profile.

, generated on Tue Sep 26 2023.