IonexStore.cpp
Go to the documentation of this file.
1 //==============================================================================
2 //
3 // This file is part of GNSSTk, the ARL:UT GNSS Toolkit.
4 //
5 // The GNSSTk is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published
7 // by the Free Software Foundation; either version 3.0 of the License, or
8 // any later version.
9 //
10 // The GNSSTk is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with GNSSTk; if not, write to the Free Software Foundation,
17 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
18 //
19 // This software was developed by Applied Research Laboratories at the
20 // University of Texas at Austin.
21 // Copyright 2004-2022, The Board of Regents of The University of Texas System
22 //
23 //==============================================================================
24 
25 //==============================================================================
26 //
27 // This software was developed by Applied Research Laboratories at the
28 // University of Texas at Austin, under contract to an agency or agencies
29 // within the U.S. Department of Defense. The U.S. Government retains all
30 // rights to use, duplicate, distribute, disclose, or release this software.
31 //
32 // Pursuant to DoD Directive 523024
33 //
34 // DISTRIBUTION STATEMENT A: This software has been approved for public
35 // release, distribution is unlimited.
36 //
37 //==============================================================================
38 
47 #include "IonexStore.hpp"
48 
49 using namespace gnsstk::StringUtils;
50 using namespace gnsstk;
51 using namespace std;
52 
53 namespace gnsstk
54 {
55  // coefficient. See more in Seeber G.(2003), Satellite Geodesy
56  // 2nd edition, Walter de Gruyter, p.52-54.
57  static const double C2_FACT = 40.3e+16;
58 
61  : initialTime(CommonTime::END_OF_TIME),
62  finalTime(CommonTime::BEGINNING_OF_TIME)
63  {
64  }
65 
66 
69  {
70  }
71 
72 
73  // Load the given IONEX file
74  void IonexStore ::
75  loadFile( const std::string& filename )
76  {
77  try
78  {
79  // Stream creation
80  IonexStream strm(filename.c_str(), std::ios::in);
81 
82  if (!strm)
83  {
84  FileMissingException e( "File " + filename +
85  " could not be opened.");
86  GNSSTK_THROW(e);
87  }
88 
89  // create the header object
91  strm >> header;
92 
93  if ( !header.valid )
94  {
95  FileMissingException e( "File " + filename +
96  " could not be opened. Check again " +
97  "the path or the name provided!");
98  GNSSTK_THROW(e);
99  }
100 
101  // keep an inventory of the loaded files
102  addFile(filename,header);
103 
104  // this map is useful in finding DCB value
105  inxDCBMap[header.firstEpoch] = header.svsmap;
106 
107  // object data. If valid, add to the map
108  IonexData iod;
109  while ( strm >> iod && iod.isValid() )
110  {
111  addMap(iod);
112  }
113  }
114  catch (gnsstk::Exception& e)
115  {
116  GNSSTK_RETHROW(e);
117  }
118  } // End of method 'IonexStore::loadFile()'
119 
120 
121 
122  // Insert a new IonexData object into the store
123  void IonexStore ::
124  addMap(const IonexData& iod)
125  {
126  CommonTime t(iod.time);
127  IonexData::IonexValType type(iod.type);
128 
129  if (type != IonexData::UN)
130  {
131  inxMaps[t][type] = iod;
132  }
133 
134  if (t < initialTime)
135  {
136  initialTime = t;
137  }
138  else if (t > finalTime)
139  {
140  finalTime = t;
141  }
142  } // End of method 'IonexStore::addMap()'
143 
144 
145  void IonexStore ::
146  dump( std::ostream& s,
147  short detail ) const
148  {
149  s << "IonexStore dump() function" << std::endl;
150 
151  std::vector<std::string> fileNames = getFileNames();
152  std::vector<std::string>::const_iterator f;
153 
154  for (f = fileNames.begin(); f != fileNames.end(); f++)
155  {
156  s << *f << std::endl;
157  }
158 
159  s << std::endl;
160 
161  if (detail >= 0)
162  {
163  s << "Data stored for: " << std::endl;
164  s << " # " << fileNames.size() << " files." << std::endl;
165  s << " # " << inxMaps.size() << " epochs" << std::endl;
166  s << " # " << "over time span "<< getInitialTime()
167  << " to " << getFinalTime() << "." << std::endl;
168 
169  s << std::endl;
170 
171  if (detail == 0)
172  {
173  return;
174  }
175 
176  s << "--------------------" << std::endl;
177  s << "EPOCH"
178  << std::setw(21) << "TEC"
179  << std::setw(5) << "RMS"<< std::endl;
180  s << "--------------------" << std::endl;
181 
182  int ntec(0), nrms(0);
183 
184  IonexMap::const_iterator it;
185 
186  for (it=inxMaps.begin(); it != inxMaps.end(); it++)
187  {
188  s << it->first << " ";
189 
190  if ( it->second.count(IonexData::TEC) )
191  {
192  ntec++;
193  s << " YES ";
194  }
195  else
196  {
197  s << " ";
198  }
199 
200  if ( it->second.count(IonexData::RMS) )
201  {
202  nrms++;
203  s << " YES ";
204  }
205  else
206  {
207  s << " ";
208  }
209 
210  s << std::endl;
211  } // End of 'for (it=inxMaps.begin(); it != inxMaps.end(); it++)...'
212 
213  s << "--------------------" << std::endl;
214  s << "Total epochs: "
215  << std::setw(5) << ntec
216  << std::setw(5) << nrms << std::endl;
217  s << "--------------------" << std::endl;
218  } // End of 'if (detail >= 0)...'
219  } // End of method 'IonexStore::dump()'
220 
221 
222 
223  // Remove all data
224  void IonexStore ::
226  {
227  inxMaps.clear();
228 
231  } // End of method 'IonexStore::clear()'
232 
233 
234 
237  const Position& RX,
238  IonexStoreStrategy strategy ) const
239  {
240  // Here we store the necessary IONEX-extracted values
241  // (i.e, TEC, RMS, ionosphere height)
242  Triple tecval(0.0,0.0,0.0);
243 
244  // current time check
245  if (t < getInitialTime())
246  {
247  InvalidRequest e("Inadequate data before requested time");
248  GNSSTK_THROW(e);
249  }
250 
251  if (t > getFinalTime() )
252  {
253  InvalidRequest e("Inadequate data after requested time");
254  GNSSTK_THROW(e);
255  }
256 
257  // this never should happen but just in case
258  Position pos(RX);
259  if ( pos.getSystemName() != "Geocentric" )
260  {
261  InvalidRequest e("Position object is not in GEOCENTRIC coordinates");
262  GNSSTK_THROW(e);
263  }
264 
265  //let's define the number of maps to be considered
266  int nmap;
267  switch (strategy)
268  {
271  nmap = 1;
272  break;
275  nmap = 2;
276  break;
277  default:
278  {
279  InvalidRequest e("Invalid interpolation stategy");
280  GNSSTK_THROW(e);
281  break;
282  }
283  }
284 
285  // let's look for valid Ionex maps
286  CommonTime T[2];
287  // iterator
288  IonexMap::const_iterator itm = inxMaps.find(t);
289  try
290  {
291  if( itm != inxMaps.end() ) // exact match of t
292  {
293  // get the current map
294  itm = inxMaps.lower_bound(t);
295  // store current and next epoch
296  T[0] = itm->first;
297  T[1] = (++itm)->first;
298  }
299  else // t is between two maps
300  {
301  // get the next valid map
302  itm = inxMaps.lower_bound(t);
303  // store the next and previous epoch
304  T[1] = itm->first;
305  T[0] = (--itm)->first;
306  } // end of 'if( itm != inxMaps.end() ) ... else ... ''
307  }
308  catch (...)
309  {
310  InvalidRequest e("IonexStore::getIonexValue() ... Invalid time!");
311  GNSSTK_THROW(e);
312  }
313 
314  // factors (As in Eq.(3), pag.2 of the manual)
315  double f[2];
316  f[0] = (T[1]-t ) / (T[1]-T[0]);
317  f[1] = (t -T[0]) / (T[1]-T[0]);
318 
319  // if only one map, then we have to use the neareast
320  if( nmap == 1 )
321  {
322  // closer to the next map
323  if( f[1] > f[0] )
324  {
325  T[0] = T[1];
326  }
327 
328  // than the factor is unit
329  f[0] = 1.0;
330  } // if( nmap == 1 )
331 
332  // loop over the number of maps considered
333  for(int imap = 0; imap < nmap; imap++)
334  {
335  // now let's determine if we keep fixed position or
336  // take into account the rotation around the Sun
337  Position pos;
338  if ((strategy == IonexStoreStrategy::Nearest) ||
339  (strategy == IonexStoreStrategy::Consecutive)) // fixed position
340  {
341  pos = RX;
342  }
343  else // rotate the position
344  {
345  // seconds of time to degree (360.0 / 86400.0)
346  double sec2deg( 4.16666666666667e-3 );
347 
348  // count the rotation
349  pos = RX;
350  pos.theArray[1] = pos.theArray[1] + ( t - T[imap] ) * sec2deg;
351  } // End of 'if (strategy == Nearest || strategy == Consecutive)...'
352 
353 
354  // iterator to the current map
355  itm = inxMaps.find(T[imap]);
356 
357  // map to hold the IONEX types for the current map
358  IonexValTypeMap ivtm = (*itm).second;
359 
360  // object to hold the corresponding data to the current map
361  IonexData iod;
362 
363  // Compute TEC value
364  if ( ivtm.find(IonexData::TEC) != ivtm.end() )
365  {
366  iod = ivtm[IonexData::TEC];
367  tecval[0] = tecval[0] + f[imap]*iod.getValue(pos);
368  }
369 
370  // Compute RMS value
371  if ( ivtm.find(IonexData::RMS) != ivtm.end() )
372  {
373  iod = ivtm[IonexData::RMS];
374  tecval[1] = tecval[1] + f[imap]*iod.getValue(pos);
375  }
376  } // End of 'for(int imap = 0; imap < nmap; imap++)...'
377 
378  // ionosphere height in meters
379  tecval[2] = RX.theArray[2];
380 
381  return tecval;
382  } // End of method 'IonexStore::getIonexValue()'
383 
384 
385  double IonexStore ::
386  getSTEC( double elevation,
387  double tecval,
388  const std::string& ionoMapType ) const
389  {
390  if (tecval < 0)
391  {
392  InvalidParameter e("Invalid TEC parameter.");
393  GNSSTK_THROW(e);
394  }
395 
396  if( ionoMapType != "NONE" && ionoMapType != "SLM" &&
397  ionoMapType != "MSLM" && ionoMapType != "ESM" )
398  {
399  InvalidParameter e("Invalid ionosphere mapping function.");
400  GNSSTK_THROW(e);
401  }
402 
403  if (elevation < 0.0)
404  {
405  return 0.0;
406  }
407  else
408  {
409  return ( tecval * ionoMappingFunction(elevation, ionoMapType) );
410  }
411  } // End of method 'IonexStore::getSTEC()'
412 
413 
414  double IonexStore ::
415  getIono( double elevation,
416  double tecval,
417  double freq,
418  const std::string& ionoMapType ) const
419  {
420  if (tecval < 0)
421  {
422  InvalidParameter e("Invalid TEC parameter.");
423  GNSSTK_THROW(e);
424  }
425 
426  if( ionoMapType != "NONE" && ionoMapType != "SLM" &&
427  ionoMapType != "MSLM" && ionoMapType != "ESM" )
428  {
429  InvalidParameter e("Invalid ionosphere mapping function.");
430  GNSSTK_THROW(e);
431  }
432 
433  if (elevation < 0.0)
434  {
435  return 0.0;
436  }
437  else
438  {
439  return ( C2_FACT / (freq * freq) * tecval
440  * ionoMappingFunction(elevation, ionoMapType) );
441  }
442  } // End of method 'IonexStore::getIono()'
443 
444 
445  double IonexStore ::
446  ionoMappingFunction( double elevation,
447  const std::string& ionoMapType ) const
448  {
449  // map
450  double imap(1.0);
451  // Earth's radius in KM
452  double Re = 6371.0;
453  // zenith angle
454  double z0 = 90.0 - elevation;
455 
456  if( ionoMapType == "SLM" )
457  {
458  // As explained in: Hofmann-Wellenhof et al. (2004) - GPS Theory and
459  // practice, 5th edition, SpringerWienNewYork, Chapter 6.3, pg. 102
460 
461  // ionosphere height in KM
462  double ionoHeight = 450.0;
463  // zenith angle of the ionospheric pierce point (IPP)
464  double sinzipp = Re / (Re + ionoHeight) * std::sin(z0*DEG_TO_RAD);
465  double zipprad = std::asin(sinzipp);
466 
467  imap = 1.0/std::cos(zipprad);
468  }
469  else if( ionoMapType == "MSLM" )
470  {
471  // maximum zenith distance is 80 degrees
472  if( z0 <= 80.0 )
473  {
474  // ionosphere height in KM
475  double ionoHeight = 506.7;
476  double alfa = 0.9782;
477  // zenith angle of the ionospheric pierce point (IPP)
478  double sinzipp = Re / (Re + ionoHeight)
479  * std::sin(alfa * z0 * DEG_TO_RAD);
480  double zipprad = std::asin(sinzipp);
481 
482  imap = 1.0/std::cos(zipprad);
483  }
484  }
485  else if( ionoMapType == "ESM" )
486  {
488  }
489  else // that means ionoMapType == "NONE"
490  {
492  }
493 
494  return imap;
495  } // End of method 'IonexStore::ionoMappingFunction()'
496 
497 
498  double IonexStore ::
499  findDCB( const SatID& sat,
500  const CommonTime& time ) const
501  {
502  // current time check. This is passed even if there are gaps
503  if ( time < getInitialTime() )
504  {
505  InvalidRequest e("Inadequate data before requested time");
506  GNSSTK_THROW(e);
507  }
508 
509  if ( time > getFinalTime() )
510  {
511  InvalidRequest e("Inadequate data after requested time");
512  GNSSTK_THROW(e);
513  }
514 
515  double dt(0.0);
516  IonexDCBMap::const_iterator itm = inxDCBMap.begin();
517 
518  // looping through the map
519  while ( itm != inxDCBMap.end() )
520  {
521  // let's get the relative reference
522  dt = time - itm->first;
523 
524  // this means we don't have maps for this day and there is a gap
525  if( dt < 0.0 )
526  {
527  InvalidRequest e( "Inadequate data after requested time: " +
528  time.asString() );
529  GNSSTK_THROW(e);
530  } // works fine for consecutive files, otherwise last epoch is thrown
531  else
532  {
533  if( dt < 86400.0 )
534  {
535  IonexHeader::SatDCBMap satdcb( itm->second );
536  IonexHeader::SatDCBMap::const_iterator iprn( satdcb.find(sat) );
537 
538  // if satellite is not found, throw
539  if ( iprn == satdcb.end() )
540  {
541  InvalidRequest e( "There is no DCB value for satellite " +
542  asString(sat) );
543  GNSSTK_THROW(e);
544  }
545  else // ... otherwise, fetch the value
546  {
547  return iprn->second.bias;
548  } // End of 'if ( iprn == satdcb.end() ) ... else ...'
549  }
550  else // If everything is fine, then move forward in the map
551  {
552  itm++;
553  } // End of 'if( dt < 86400.0 ) ... else ...'
554  } // End of 'if( dt < 0.0 ) ... else ...'
555  } // End of 'while ( itm != inxDCBMap.end() )'
556 
557  // You should never get here, but just in case
558  return 0.0;
559  } // End of method 'IonexStore::findDCB()'
560 
561 } // End of namespace gnsstk
gnsstk::IonexData::time
CommonTime time
the time corresponding to the current data records
Definition: IonexData.hpp:133
gnsstk::IonexStore::getIonexValue
Triple getIonexValue(const CommonTime &t, const Position &RX, IonexStoreStrategy strategy=IonexStoreStrategy::ConsRot) const
Definition: IonexStore.cpp:236
gnsstk::IonexStoreStrategy::Consecutive
@ Consecutive
Interpolate between two consecutive maps.
gnsstk::FileStore< IonexHeader >::addFile
void addFile(const std::string &fn, IonexHeader &header)
Definition: FileStore.hpp:89
gnsstk::IonexHeader
Definition: IonexHeader.hpp:70
example3.header
header
Definition: example3.py:22
gnsstk::IonexStore::getIono
double getIono(double elevation, double tecval, double freq, const std::string &ionoMapType) const
Definition: IonexStore.cpp:415
gnsstk::IonexStore::clear
void clear()
Remove all data.
Definition: IonexStore.cpp:225
gnsstk::BEGINNING_OF_TIME
const Epoch BEGINNING_OF_TIME(CommonTime::BEGINNING_OF_TIME)
Earliest representable Epoch.
gnsstk::IonexStore::ionoMappingFunction
double ionoMappingFunction(double elevation, const std::string &ionoMapType) const
Definition: IonexStore.cpp:446
gnsstk::IonexStore::inxDCBMap
IonexDCBMap inxDCBMap
Map of DCB values (IonexHeader.firstEpoch, IonexHeader.svsmap)
Definition: IonexStore.hpp:324
gnsstk::FileStore< IonexHeader >::getFileNames
std::vector< std::string > getFileNames() const
Get a list of all the file names in the store, as a vector<string>
Definition: FileStore.hpp:78
gnsstk::SatID
Definition: SatID.hpp:89
gnsstk::StringUtils::asString
std::string asString(IonexStoreStrategy e)
Convert a IonexStoreStrategy to a whitespace-free string name.
Definition: IonexStoreStrategy.cpp:46
gnsstk::IonexStore::findDCB
double findDCB(const SatID &sat, const CommonTime &time) const
Definition: IonexStore.cpp:499
gnsstk::IonexStoreStrategy::Rotated
@ Rotated
Take nearest rotated map.
gnsstk::IonexStoreStrategy::Nearest
@ Nearest
Take nearest map.
gnsstk::CommonTime::BEGINNING_OF_TIME
static const GNSSTK_EXPORT CommonTime BEGINNING_OF_TIME
earliest representable CommonTime
Definition: CommonTime.hpp:102
gnsstk::Triple::theArray
std::valarray< double > theArray
Definition: Triple.hpp:251
gnsstk::Triple
Definition: Triple.hpp:68
gnsstk::IonexStore::initialTime
CommonTime initialTime
Definition: IonexStore.hpp:309
gnsstk
For Sinex::InputHistory.
Definition: BasicFramework.cpp:50
std::sin
double sin(gnsstk::Angle x)
Definition: Angle.hpp:144
gnsstk::IonexStore::IonexValTypeMap
std::map< IonexData::IonexValType, IonexData > IonexValTypeMap
The key to this map is IonexValType.
Definition: IonexStore.hpp:312
gnsstk::IonexStore::getSTEC
double getSTEC(double elevation, double tecval, const std::string &ionoMapType) const
Definition: IonexStore.cpp:386
gnsstk::Exception
Definition: Exception.hpp:151
gnsstk::IonexData::UN
static const GNSSTK_EXPORT IonexValType UN
Definition: IonexData.hpp:119
gnsstk::CommonTime::END_OF_TIME
static const GNSSTK_EXPORT CommonTime END_OF_TIME
latest representable CommonTime
Definition: CommonTime.hpp:104
gnsstk::IonexStore::IonexStore
IonexStore()
Default constructor.
Definition: IonexStore.cpp:60
gnsstk::IonexStream
Definition: IonexStream.hpp:61
gnsstk::IonexStore::dump
void dump(std::ostream &s=std::cout, short detail=0) const
Definition: IonexStore.cpp:146
gnsstk::IonexStore::inxMaps
IonexMap inxMaps
Map of IONEX maps.
Definition: IonexStore.hpp:318
IonexStore.hpp
example4.time
time
Definition: example4.py:103
gnsstk::IonexData::RMS
static const GNSSTK_EXPORT IonexValType RMS
Definition: IonexData.hpp:123
gnsstk::IonexData::IonexValType
A structure used to store IONEX Value Types.
Definition: IonexData.hpp:101
gnsstk::IonexData
Definition: IonexData.hpp:70
gnsstk::IonexData::type
IonexValType type
Type of data either TEC or RMS.
Definition: IonexData.hpp:135
gnsstk::CommonTime
Definition: CommonTime.hpp:84
gnsstk::IonexStore::addMap
void addMap(const IonexData &iod)
Insert a new IonexData object into the store.
Definition: IonexStore.cpp:124
std::cos
double cos(gnsstk::Angle x)
Definition: Angle.hpp:146
gnsstk::END_OF_TIME
const Epoch END_OF_TIME(CommonTime::END_OF_TIME)
Latest Representable Epoch.
GNSSTK_RETHROW
#define GNSSTK_RETHROW(exc)
Definition: Exception.hpp:369
example4.pos
pos
Definition: example4.py:125
gnsstk::IonexStore::~IonexStore
virtual ~IonexStore()
destructor
Definition: IonexStore.cpp:68
gnsstk::StringUtils
Definition: IonexStoreStrategy.cpp:44
gnsstk::IonexData::TEC
static const GNSSTK_EXPORT IonexValType TEC
Definition: IonexData.hpp:121
gnsstk::IonexHeader::SatDCBMap
std::map< SatID, DCB > SatDCBMap
The key to this map is the svid of the satellite (usually the prn)
Definition: IonexHeader.hpp:229
std
Definition: Angle.hpp:142
gnsstk::IonexStore::getInitialTime
CommonTime getInitialTime() const
Definition: IonexStore.hpp:276
gnsstk::Position
Definition: Position.hpp:136
GNSSTK_THROW
#define GNSSTK_THROW(exc)
Definition: Exception.hpp:366
gnsstk::IonexStoreStrategy::ConsRot
@ ConsRot
Interpolate between two consecutive rotated maps.
gnsstk::IonexData::getValue
double getValue(const Position &pos) const
Definition: IonexData.cpp:519
gnsstk::IonexStore::loadFile
virtual void loadFile(const std::string &filename)
Definition: IonexStore.cpp:75
gnsstk::IonexData::isValid
virtual bool isValid() const
Am I an valid object?
Definition: IonexData.hpp:160
gnsstk::IonexStoreStrategy
IonexStoreStrategy
Enumeration used for IonexStore::getIonexValue().
Definition: IonexStoreStrategy.hpp:51
gnsstk::IonexStore::finalTime
CommonTime finalTime
Definition: IonexStore.hpp:309
gnsstk::C2_FACT
static const double C2_FACT
Definition: IonexStore.cpp:57
gnsstk::IonexStore::getFinalTime
CommonTime getFinalTime() const
Definition: IonexStore.hpp:287
gnsstk::DEG_TO_RAD
static const double DEG_TO_RAD
Conversion Factor from degrees to radians (units: degrees^-1)
Definition: GNSSconstants.hpp:76


gnsstk
Author(s):
autogenerated on Wed Oct 25 2023 02:40:39