RadiosondeDBProfileModel.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/RadiosondeDBProfileModel.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::eRadiosonde);
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  // TEMPORARY.. skip of unordered entries
112  bool skip = false;
113  if (lIt != zIt->LayersBegin()) {
114  MolecularZone::LayerIterator newIt = lIt;
115  if (newIt->GetHeight() <= (--newIt)->GetHeight())
116  skip = true;
117  }
118  if (skip)
119  break;
120  // END TEMPORARY
121 
122  tabLogDepthVsHeight.PushBack(lIt->GetHeight(), lIt->GetHeightError(),
123  log(lIt->GetDepth()),
124  lIt->GetDepthError() / lIt->GetDepth());
125 
126  const double refracIndex = utl::RefractionIndex::LorentzLorentz(lIt->GetDepth());
127  tabRIVsHeight.PushBack(lIt->GetHeight(), lIt->GetHeightError(),
128  refracIndex, 0.);
129 
130  tabLogPressureVsHeight.PushBack(lIt->GetHeight(), lIt->GetHeightError(),
131  log(lIt->GetPressure()),
132  lIt->GetPressureError() / lIt->GetPressure());
133 
134  // Convert relative humidity to vapor pressure
135  const double pSat = utl::SaturationVaporPressure(lIt->GetTemperature());
136  const double pVapor = lIt->GetHumidity() * pSat;
137  const double dpVapor = lIt->GetHumidityError() * pSat; // Ignore dT...
138 
139  tabLogVaporPressureVsHeight.PushBack(
140  lIt->GetHeight(), lIt->GetHeightError(),
141  (pVapor > 0.) ? log(pVapor) : minLog,
142  (pVapor > 0. && dpVapor > 0.) ? pVapor / dpVapor : minLog);
143 
144  tabTemperatureVsHeight.PushBack(lIt->GetHeight(), lIt->GetHeightError(),
145  lIt->GetTemperature(),
146  lIt->GetTemperatureError());
147 
148  tabLogDensityVsHeight.PushBack(lIt->GetHeight(), lIt->GetHeightError(),
149  log(lIt->GetAirDensity()),
150  lIt->GetAirDensityError() / lIt->GetAirDensity());
151 
152  }
153  ++nZonesCheck;
154  }
155 
156  if (nZonesCheck == 0) {
157  fDbIsEmptyNow = true;
158 
159  ostringstream msg;
160  msg << "Radiosonde model requested data from database, "
161  << "but no data found for time "
162  << det::Detector::GetInstance().GetTime();
163  DEBUGLOG(msg);
164 
165  return false;
166  }
167 
168  if (nZonesCheck != 1) {
169  // some kind of error here.
170  }
171 
172  // Extrapolate to ground level
173  const double groundHeight = 1. * km;
174  const double minHeight = tabTemperatureVsHeight.GetX(0);
175  const int nLayers = distance(tabTemperatureVsHeight.Begin(),
176  tabTemperatureVsHeight.End());
177 
178  if (nLayers > 2 && minHeight > groundHeight) {
179  const double h1 = tabTemperatureVsHeight.GetX(0);
180  const double h2 = tabTemperatureVsHeight.GetX(1);
181  const double relH = (groundHeight-h1)/(h2-h1);
182 
183  // Linear extrapolation
184  const double groundLogDepth = tabLogDepthVsHeight.GetY(0) +
185  (tabLogDepthVsHeight.GetY(1) - tabLogDepthVsHeight.GetY(0)) * relH;
186 
187  const double groundLogDensity = tabLogDensityVsHeight.GetY(0) +
188  (tabLogDensityVsHeight.GetY(1) - tabLogDensityVsHeight.GetY(0)) * relH;
189 
190  const double groundLogPressure = tabLogPressureVsHeight.GetY(0) +
191  (tabLogPressureVsHeight.GetY(1) - tabLogPressureVsHeight.GetY(0)) * relH;
192 
193  const double groundLogVaporPressure = tabLogVaporPressureVsHeight.GetY(0) +
194  (tabLogVaporPressureVsHeight.GetY(1) - tabLogVaporPressureVsHeight.GetY(0)) * relH;
195 
196  const double groundTemperature = tabTemperatureVsHeight.GetY(0) +
197  (tabTemperatureVsHeight.GetY(1) - tabTemperatureVsHeight.GetY(0)) * relH;
198 
199  const double groundRefIndex = tabRIVsHeight.GetY(0) +
200  (tabRIVsHeight.GetY(1) - tabRIVsHeight.GetY(0)) * relH;
201 
202  // Insert the ground level values
203  tabLogDepthVsHeight.Insert(tabLogDepthVsHeight.Begin(),
204  groundHeight, 0., groundLogDepth, minLog);
205 
206  tabLogDensityVsHeight.Insert(tabLogDensityVsHeight.Begin(),
207  groundHeight, 0., groundLogDensity, minLog);
208 
209  tabLogPressureVsHeight.Insert(tabLogPressureVsHeight.Begin(),
210  groundHeight, 0., groundLogPressure, minLog);
211 
212  tabLogVaporPressureVsHeight.Insert(tabLogVaporPressureVsHeight.Begin(),
213  groundHeight, 0., groundLogVaporPressure, minLog);
214 
215  tabTemperatureVsHeight.Insert(tabTemperatureVsHeight.Begin(),
216  groundHeight, 0., groundTemperature, 0.);
217 
218  tabRIVsHeight.Insert(tabRIVsHeight.Begin(),
219  groundHeight, 0., groundRefIndex, 0.);
220  }
221 
222  // Fill the log depth vs height profile, starting from the top layer
223  for (int i = nLayers; i >= 0; --i)
224  tabHeightVsLogDepth.PushBack(
225  tabLogDepthVsHeight.GetY(i), tabLogDepthVsHeight.GetYErr(i),
226  tabLogDepthVsHeight.GetX(i), tabLogDepthVsHeight.GetXErr(i));
227 
228  // Create profile results
230  ProfileResult(tabLogPressureVsHeight, ProfileResult::eLinear, ProfileResult::eLog);
231 
233  ProfileResult(tabLogVaporPressureVsHeight, ProfileResult::eLinear, ProfileResult::eLog);
234 
237 
240 
243 
246 
247  *fTabRIVsHeight =
249 
250  // Extend all tables to a height of 100 km
251  // THIS IS DEPRECATED pending the update to DB version Atm_Molecular_1_A
253 
254  return true;
255 }
256 
257 
258 const ProfileResult&
260  const
261 {
262  if (!CheckForUpdates())
263  throw NoDataForModelException("No radiosonde data found for pressure");
264  return *fTabLogPressureVsHeight;
265 }
266 
267 
268 const ProfileResult&
270  const
271 {
272  if (!CheckForUpdates())
273  throw NoDataForModelException("No radiosonde data found for temperature");
274  return *fTabTemperatureVsHeight;
275 }
276 
277 
278 const ProfileResult&
280  const
281 {
282  if (!CheckForUpdates())
283  throw NoDataForModelException("No radiosonde data found for humidity");
285 }
286 
287 
288 const ProfileResult&
290  const
291 {
292  if (!CheckForUpdates())
293  throw NoDataForModelException("No radiosonde data found for density");
294  return *fTabLogDensityVsHeight;
295 }
296 
297 
298 const ProfileResult&
300  const
301 {
302  if (!CheckForUpdates())
303  throw NoDataForModelException("No radiosonde data for depth");
304  return *fTabLogDepthVsHeight;
305 }
306 
307 
308 const ProfileResult&
310  const
311 {
312  if (!CheckForUpdates())
313  throw NoDataForModelException("No radiosonde data for height vs depth");
314  return *fTabHeightVsLogDepth;
315 }
316 
317 
318 const ProfileResult&
320  const
321 {
322  if (!CheckForUpdates())
323  throw NoDataForModelException("No radiosonde data for refraction index");
324  return *fTabRIVsHeight;
325 }
326 
boost::transform_iterator< InternalZoneFunctor, InternalZoneIterator, const MolecularZone & > ZoneIterator
ZoneIterator returns a pointer to a MolecularZone.
Definition: MolecularDB.h:52
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
void CleanRIVsWavelength() const
Clean up refraction indices. Derived modules decide when to do this.
bool HasData() const
True if a data source is for the given model.
ProfileResult * fTabTemperatureVsHeight
Definition: VProfileModel.h:72
const atm::ProfileResult & EvaluatePressureVsHeight() const
Table of air pressure as a function of height.
Exception to use in a atmosphere model cannot find data it needs.
const ProfileResult & EvaluateVaporPressureVsHeight() const
Table of vapor pressure as a function of height.
const double & GetYErr(const unsigned int idx) const
const atm::ProfileResult & EvaluateHeightVsDepth() const
Table of height as a function of depth.
void ExtendProfilesTo100km() const
Class describing the Atmospheric profile.
Definition: ProfileResult.h:25
#define DEBUGLOG(message)
Macro for logging debugging messages.
Definition: ErrorLogger.h:157
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
void PushBack(const double x, const double xErr, const double y, const double yErr)
const atm::ProfileResult & EvaluateTemperatureVsHeight() const
Table of temperature as a function of height.
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
IteratorErr Insert(const IteratorErr &pos, const double x, const double xErr, const double y, const double yErr)
const atm::ProfileResult & EvaluateDensityVsHeight() const
Table of density as a function of height.
const double & GetX(const unsigned int idx) const
from radiosonde
Definition: MolecularIds.h:13
const ProfileResult & EvaluateDepthVsHeight() const
Table of depth as a function of height.
ProfileResult * fTabHeightVsLogDepth
Definition: VProfileModel.h:69
const atm::ProfileResult & EvaluateRefractionIndexVsHeight() const
Table of refraction index as a function of height.
Base class for a Profile Model.
Definition: VProfileModel.h:26

, generated on Tue Sep 26 2023.