GDASProfileModel.cc
Go to the documentation of this file.
1 
9 #include <iostream>
10 #include <string>
11 #include <sstream>
12 #include <vector>
13 #include <deque>
14 #include <limits>
15 
16 #include <utl/Reader.h>
17 #include <utl/ErrorLogger.h>
18 #include <utl/AugerException.h>
19 #include <utl/AugerUnits.h>
20 #include <utl/MathConstants.h>
21 #include <utl/TabulatedFunction.h>
22 #include <utl/TimeStamp.h>
23 #include <utl/PhysicalConstants.h>
24 #include <utl/PhysicalFunctions.h>
25 
26 #include <fwk/CentralConfig.h>
27 
28 #include <atm/GDASProfileModel.h>
29 #include <atm/ProfileResult.h>
30 #include <atm/MolecularDB.h>
31 #include <atm/MolecularLayer.h>
32 #include <atm/MolecularZone.h>
33 #include <atm/ProfileResult.h>
34 #include <det/Detector.h>
35 
36 #include <utl/ErrorLogger.h>
37 
38 using namespace atm;
39 using namespace utl;
40 using namespace std;
41 using namespace fwk;
42 
43 // For some reason, CLHEP SystemOfUnits.h
44 // #defines pascal to hep_pascal, putting it in
45 // the global namespace and screwing up our own
46 // definition of pascal from AugerUnits.h. It appears
47 // the CLHEP units are being pulled in via the geometry
48 // package. The following line undoes the CLHEP sabotage.
49 #undef pascal
50 
52  VProfileModel(),
53  fCurrentTime(0),
54  fDbIsEmptyNow(false)
55 {
56 }
57 
58 
59 void
61 {
62 }
63 
64 
65 bool
67  const
68 {
69  return CheckForUpdates();
70 }
71 
72 
73 bool
75  const
76 {
77  // check if detector has been updated and fill
78  // various lookup tables if so
79  //
80  if (fCurrentTime == det::Detector::GetInstance().GetTime() &&
82  return !fDbIsEmptyNow;
83 
84  fCurrentTime = det::Detector::GetInstance().GetTime();
85  fDbIsEmptyNow = false;
86 
87  // Atmosphere state is changing: clean up calculated refraction indices
89 
90  TabulatedFunctionErrors tabRIVsHeight;
91  TabulatedFunctionErrors tabLogPressureVsHeight;
92  TabulatedFunctionErrors tabLogVaporPressureVsHeight;
93  TabulatedFunctionErrors tabTemperatureVsHeight;
94  TabulatedFunctionErrors tabLogDepthVsHeight;
95  TabulatedFunctionErrors tabLogDensityVsHeight;
96  TabulatedFunctionErrors tabHeightVsLogDepth;
97 
98  const MolecularDB& mDB =
99  det::Detector::GetInstance().GetAtmosphere().GetMolecularDB(MolecularIds::eMalargueGDAS);
100 
101  // Fill tabulated functions. Perform conversions into Auger base units.
102  int nZonesCheck = 0;
103  const double minLog = kLn10 * numeric_limits<double>::min_exponent10;
104 
105  for (MolecularDB::ZoneIterator zIt = mDB.ZonesBegin();
106  zIt != mDB.ZonesEnd(); ++zIt) {
107 
108  for (MolecularZone::LayerIterator lIt = zIt->LayersBegin();
109  lIt != zIt->LayersEnd(); ++lIt) {
110 
111  // Skip everything above 900hPa (below ~1000m a.s.l.)
112  // since InclinedAtmosphericProfile bitches otherwise
113  //if(lIt->GetPressure() > 900*hPa)
114  // continue;
115  // Should be fine with new DB filler
116 
117  // TEMPORARY.. skip of unordered entries
118  bool skip = false;
119  if (lIt != zIt->LayersBegin()) {
120  MolecularZone::LayerIterator newIt = lIt;
121  if (newIt->GetHeight() <= (--newIt)->GetHeight())
122  skip = true;
123  }
124  if (skip)
125  break;
126  // END TEMPORARY
127 
128  tabLogDepthVsHeight.PushBack(lIt->GetHeight(), lIt->GetHeightError(),
129  log(lIt->GetDepth()),
130  lIt->GetDepthError() / lIt->GetDepth());
131 
132  const double refracIndex = utl::RefractionIndex::LorentzLorentz(lIt->GetDepth());
133  tabRIVsHeight.PushBack(lIt->GetHeight(), lIt->GetHeightError(),
134  refracIndex, 0.);
135 
136  tabLogPressureVsHeight.PushBack(lIt->GetHeight(), lIt->GetHeightError(),
137  log(lIt->GetPressure()),
138  lIt->GetPressureError() / lIt->GetPressure());
139 
140  // Convert relative humidity to vapor pressure
141  const double pSat = utl::SaturationVaporPressure(lIt->GetTemperature());
142  const double pVapor = lIt->GetHumidity() * pSat;
143  const double dpVapor = lIt->GetHumidityError() * pSat; // Ignore dT...
144 
145  tabLogVaporPressureVsHeight.PushBack(
146  lIt->GetHeight(), lIt->GetHeightError(),
147  (pVapor > 0.) ? log(pVapor) : minLog,
148  (pVapor > 0. && dpVapor > 0.) ? pVapor / dpVapor : minLog);
149 
150  tabTemperatureVsHeight.PushBack(lIt->GetHeight(), lIt->GetHeightError(),
151  lIt->GetTemperature(),
152  lIt->GetTemperatureError());
153 
154  tabLogDensityVsHeight.PushBack(lIt->GetHeight(), lIt->GetHeightError(),
155  log(lIt->GetAirDensity()),
156  lIt->GetAirDensityError() / lIt->GetAirDensity());
157 
158  }
159  ++nZonesCheck;
160  }
161 
162  if (nZonesCheck == 0) {
163  fDbIsEmptyNow = true;
164 
165  ostringstream msg;
166  msg << "GDAS model requested data from database, "
167  << "but no data found for time "
168  << det::Detector::GetInstance().GetTime();
169  DEBUGLOG(msg);
170 
171  return false;
172  }
173 
174  if (nZonesCheck != 1) {
175  // some kind of error here.
176  }
177 
178 
179  // Extrapolate to ground level
180  const double groundHeight = 1. * km;
181  const double minHeight = tabTemperatureVsHeight.GetX(0);
182  const int nLayers = distance(tabTemperatureVsHeight.Begin(),
183  tabTemperatureVsHeight.End());
184 
185  if (nLayers > 2 && minHeight > groundHeight) {
186  const double h1 = tabTemperatureVsHeight.GetX(0);
187  const double h2 = tabTemperatureVsHeight.GetX(1);
188  const double relH = (groundHeight-h1)/(h2-h1);
189 
190  // Linear extrapolation
191  const double groundLogDepth = tabLogDepthVsHeight.GetY(0) +
192  (tabLogDepthVsHeight.GetY(1) - tabLogDepthVsHeight.GetY(0)) * relH;
193 
194  const double groundLogDensity = tabLogDensityVsHeight.GetY(0) +
195  (tabLogDensityVsHeight.GetY(1) - tabLogDensityVsHeight.GetY(0)) * relH;
196 
197  const double groundLogPressure = tabLogPressureVsHeight.GetY(0) +
198  (tabLogPressureVsHeight.GetY(1) - tabLogPressureVsHeight.GetY(0)) * relH;
199 
200  const double groundLogVaporPressure = tabLogVaporPressureVsHeight.GetY(0) +
201  (tabLogVaporPressureVsHeight.GetY(1) - tabLogVaporPressureVsHeight.GetY(0)) * relH;
202 
203  const double groundTemperature = tabTemperatureVsHeight.GetY(0) +
204  (tabTemperatureVsHeight.GetY(1) - tabTemperatureVsHeight.GetY(0)) * relH;
205 
206  const double groundRefIndex = tabRIVsHeight.GetY(0) +
207  (tabRIVsHeight.GetY(1) - tabRIVsHeight.GetY(0)) * relH;
208 
209  // Insert the ground level values
210  tabLogDepthVsHeight.Insert(tabLogDepthVsHeight.Begin(),
211  groundHeight, 0., groundLogDepth, minLog);
212 
213  tabLogDensityVsHeight.Insert(tabLogDensityVsHeight.Begin(),
214  groundHeight, 0., groundLogDensity, minLog);
215 
216  tabLogPressureVsHeight.Insert(tabLogPressureVsHeight.Begin(),
217  groundHeight, 0., groundLogPressure, minLog);
218 
219  tabLogVaporPressureVsHeight.Insert(tabLogVaporPressureVsHeight.Begin(),
220  groundHeight, 0., groundLogVaporPressure, minLog);
221 
222  tabTemperatureVsHeight.Insert(tabTemperatureVsHeight.Begin(),
223  groundHeight, 0., groundTemperature, 0.);
224 
225  tabRIVsHeight.Insert(tabRIVsHeight.Begin(),
226  groundHeight, 0., groundRefIndex, 0.);
227  }
228 
229  // If the database contains values below 1000 meters the linear extrapolation
230  // is skipped and nLayers is not increased, causing the next loop to crash
231  const int nLayersDepth = distance(tabLogDepthVsHeight.Begin(),
232  tabLogDepthVsHeight.End());
233 
234  // Fill the log depth vs height profile, starting from the top layer
235  for (int i = nLayersDepth-1; i >= 0; --i)
236  tabHeightVsLogDepth.PushBack(
237  tabLogDepthVsHeight.GetY(i), tabLogDepthVsHeight.GetYErr(i),
238  tabLogDepthVsHeight.GetX(i), tabLogDepthVsHeight.GetXErr(i));
239 
240  // Create profile results
242  ProfileResult(tabLogPressureVsHeight, ProfileResult::eLinear, ProfileResult::eLog);
243 
245  ProfileResult(tabLogVaporPressureVsHeight, ProfileResult::eLinear, ProfileResult::eLog);
246 
249 
252 
255 
258 
259  *fTabRIVsHeight =
261 
262  // Extend all tables to a height of 100 km
264 
265  return true;
266 }
267 
268 
269 const ProfileResult&
271  const
272 {
273  if (!CheckForUpdates())
274  throw NoDataForModelException("No GDAS data found for pressure");
275  return *fTabLogPressureVsHeight;
276 }
277 
278 
279 const ProfileResult&
281  const
282 {
283  if (!CheckForUpdates())
284  throw NoDataForModelException("No GDAS data found for temperature");
285  return *fTabTemperatureVsHeight;
286 }
287 
288 
289 const ProfileResult&
291  const
292 {
293  if (!CheckForUpdates())
294  throw NoDataForModelException("No GDAS data found for humidity");
296 }
297 
298 
299 const ProfileResult&
301  const
302 {
303  if (!CheckForUpdates())
304  throw NoDataForModelException("No GDAS data found for density");
305  return *fTabLogDensityVsHeight;
306 }
307 
308 
309 const ProfileResult&
311  const
312 {
313  if (!CheckForUpdates())
314  throw NoDataForModelException("No GDAS data for depth");
315  return *fTabLogDepthVsHeight;
316 }
317 
318 
319 const ProfileResult&
321  const
322 {
323  if (!CheckForUpdates())
324  throw NoDataForModelException("No GDAS data for height vs depth");
325  return *fTabHeightVsLogDepth;
326 }
327 
328 
329 const ProfileResult&
331  const
332 {
333  if (!CheckForUpdates())
334  throw NoDataForModelException("No GDAS data for refraction index");
335  return *fTabRIVsHeight;
336 }
337 
utl::TimeStamp fCurrentTime
boost::transform_iterator< InternalZoneFunctor, InternalZoneIterator, const MolecularZone & > ZoneIterator
ZoneIterator returns a pointer to a MolecularZone.
Definition: MolecularDB.h:52
const atm::ProfileResult & EvaluateTemperatureVsHeight() const
Table of temperature as a function of height.
ProfileResult * fTabRIVsHeight
Definition: VProfileModel.h:74
ProfileResult * fTabLogDepthVsHeight
Definition: VProfileModel.h:68
ZoneIterator ZonesEnd() const
End of the collection of valid Zones.
Definition: MolecularDB.h:59
Detector description interface for data in the Atm_Molecular database.
Definition: MolecularDB.h:29
const ProfileResult & EvaluateVaporPressureVsHeight() const
Table of vapor pressure as a function of height.
void CleanRIVsWavelength() const
Clean up refraction indices. Derived modules decide when to do this.
ProfileResult * fTabTemperatureVsHeight
Definition: VProfileModel.h:72
Exception to use in a atmosphere model cannot find data it needs.
const double & GetYErr(const unsigned int idx) const
void ExtendProfilesTo100km() const
const atm::ProfileResult & EvaluateRefractionIndexVsHeight() const
Table of refraction index as a function of height.
Class describing the Atmospheric profile.
Definition: ProfileResult.h:25
#define DEBUGLOG(message)
Macro for logging debugging messages.
Definition: ErrorLogger.h:157
bool HasData() const
True if a data source is for the given model.
ProfileResult * fTabLogVaporPressureVsHeight
Definition: VProfileModel.h:71
double SaturationVaporPressure(const double temperature)
Evaluate the saturation vapor pressure over ice or water.
ProfileResult * fTabLogDensityVsHeight
Definition: VProfileModel.h:73
const double km
const ProfileResult & EvaluateDepthVsHeight() const
Table of depth as a function of height.
void PushBack(const double x, const double xErr, const double y, const double yErr)
const double & GetXErr(const unsigned int idx) const
constexpr double kLn10
Definition: MathConstants.h:29
const double & GetY(const unsigned int idx) const
ZoneIterator ZonesBegin() const
Beginning of the collection of valid Zones.
Definition: MolecularDB.h:55
double LorentzLorentz(const double verticalDepth)
Calculate the refraction index for a given depth.
boost::indirect_iterator< InternalLayerIterator, const MolecularLayer & > LayerIterator
Layer iterator returns a pointer to the molecular data slice for this zone.
Definition: MolecularZone.h:43
ProfileResult * fTabLogPressureVsHeight
Definition: VProfileModel.h:70
bool CheckForUpdates() const
IteratorErr Insert(const IteratorErr &pos, const double x, const double xErr, const double y, const double yErr)
const atm::ProfileResult & EvaluateHeightVsDepth() const
Table of height as a function of depth.
const double & GetX(const unsigned int idx) const
const atm::ProfileResult & EvaluateDensityVsHeight() const
Table of density as a function of height.
GDAS data for Malargue.
Definition: MolecularIds.h:39
ProfileResult * fTabHeightVsLogDepth
Definition: VProfileModel.h:69
const atm::ProfileResult & EvaluatePressureVsHeight() const
Table of air pressure as a function of height.
Base class for a Profile Model.
Definition: VProfileModel.h:26

, generated on Tue Sep 26 2023.