IonexStore.cpp

Go to the documentation of this file.
00001 #pragma ident "$Id: IonexStore.cpp 3044 2012-04-04 10:50:58Z coandrei $"
00002 
00010 //============================================================================
00011 //
00012 //  This file is part of GPSTk, the GPS Toolkit.
00013 //
00014 //  The GPSTk is free software; you can redistribute it and/or modify
00015 //  it under the terms of the GNU Lesser General Public License as published
00016 //  by the Free Software Foundation; either version 2.1 of the License, or
00017 //  any later version.
00018 //
00019 //  The GPSTk is distributed in the hope that it will be useful,
00020 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00021 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022 //  GNU Lesser General Public License for more details.
00023 //
00024 //  You should have received a copy of the GNU Lesser General Public
00025 //  License along with GPSTk; if not, write to the Free Software Foundation,
00026 //  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00027 //
00028 //  Octavian Andrei - FGI ( http://www.fgi.fi ). 2008, 2009, 2012
00029 //
00030 //============================================================================
00031 
00032 
00033 #include "IonexStore.hpp"
00034 
00035 using namespace gpstk::StringUtils;
00036 using namespace gpstk;
00037 using namespace std;
00038 
00039 namespace gpstk
00040 {
00041 
00042       // coefficient. See more in Seeber G.(2003), Satellite Geodesy
00043       // 2nd edition, Walter de Gruyter, p.52-54.
00044    static const double C2_FACT   = 40.3e+16;
00045 
00046 
00047       // Load the given IONEX file
00048    void IonexStore::loadFile( const std::string& filename )
00049       throw(FileMissingException)
00050    {
00051 
00052       try
00053       {
00054 
00055             // Stream creation
00056          IonexStream strm(filename.c_str(), std::ios::in);
00057 
00058          if (!strm)
00059          {
00060 
00061             FileMissingException e( "File " + filename +
00062                                     " could not be opened.");
00063             GPSTK_THROW(e);
00064 
00065          }
00066 
00067             // create the header object
00068          IonexHeader header;
00069          strm >> header;
00070 
00071          if ( !header.valid )
00072          {
00073 
00074             FileMissingException e( "File " + filename +
00075                                     " could not be opened. Check again " +
00076                                     "the path or the name provided!");
00077             GPSTK_THROW(e);
00078 
00079          }
00080 
00081             // keep an inventory of the loaded files 
00082          addFile(filename,header);
00083 
00084             // this map is useful in finding DCB value
00085          inxDCBMap[header.firstEpoch] = header.svsmap;
00086 
00087             // object data. If valid, add to the map
00088          IonexData iod;
00089          while ( strm >> iod && iod.isValid() )
00090          {
00091             addMap(iod);
00092          }
00093 
00094       }
00095       catch (gpstk::Exception& e)
00096       {
00097          GPSTK_RETHROW(e);
00098       }
00099 
00100    }  // End of method 'IonexStore::loadFile()'
00101 
00102 
00103 
00104       // Insert a new IonexData object into the store
00105    void IonexStore::addMap(const IonexData& iod)
00106       throw()
00107    {
00108 
00109       DayTime t(iod.time);
00110       IonexData::IonexValType type(iod.type);
00111 
00112       if (type != IonexData::UN)
00113       {
00114          inxMaps[t][type] = iod;
00115       }
00116 
00117       if (t < initialTime)
00118       {
00119          initialTime = t;
00120       }
00121       else if (t > finalTime)
00122       {
00123          finalTime = t;
00124       }
00125 
00126    }  // End of method 'IonexStore::addMap()'
00127 
00128 
00129 
00138    void IonexStore::dump( std::ostream& s,
00139                           short detail ) const
00140       throw()
00141    {
00142 
00143       s << "IonexStore dump() function" << std::endl;
00144 
00145       std::vector<std::string> fileNames = getFileNames();
00146       std::vector<std::string>::const_iterator f;
00147 
00148       for (f = fileNames.begin(); f != fileNames.end(); f++)
00149       {
00150          s << *f << std::endl;
00151       }
00152 
00153       s << std::endl;
00154 
00155 
00156       if (detail >= 0)
00157       {
00158 
00159          s << "Data stored for: " << std::endl;
00160          s << "  # " << fileNames.size() << " files." << std::endl;
00161          s << "  # " << inxMaps.size() << " epochs" << std::endl;
00162          s << "  # " << "over time span "<< getInitialTime()
00163            << " to " << getFinalTime() << "." << std::endl;
00164 
00165          s << std::endl;
00166 
00167          if (detail == 0)
00168          {
00169             return;
00170          }
00171 
00172          s << "--------------------" << std::endl;
00173          s << "EPOCH"
00174            << std::setw(21) << "TEC"
00175            << std::setw(5) << "RMS"<< std::endl;
00176          s << "--------------------" << std::endl;
00177 
00178          int ntec(0), nrms(0);
00179 
00180          IonexMap::const_iterator it;
00181 
00182          for (it=inxMaps.begin(); it != inxMaps.end(); it++)
00183          {
00184 
00185             s << it->first << "   ";
00186 
00187             if ( it->second.count(IonexData::TEC) )
00188             {
00189                ntec++;
00190                s << " YES ";
00191             }
00192             else
00193             {
00194                s << "   ";
00195             }
00196 
00197             if ( it->second.count(IonexData::RMS) )
00198             {
00199                nrms++;
00200                s << " YES ";
00201             }
00202             else
00203             {
00204                s << "     ";
00205             }
00206 
00207             s << std::endl;
00208 
00209          }  // End of 'for (it=inxMaps.begin(); it != inxMaps.end(); it++)...'
00210 
00211 
00212          s << "--------------------" << std::endl;
00213          s << "Total epochs:        "
00214            << std::setw(5) << ntec
00215            << std::setw(5) << nrms << std::endl;
00216          s << "--------------------" << std::endl;
00217 
00218       }  // End of 'if (detail >= 0)...'
00219 
00220 
00221       return;
00222 
00223 
00224    }  // End of method 'IonexStore::dump()'
00225 
00226 
00227 
00228       // Remove all data
00229    void IonexStore::clear()
00230       throw()
00231    {
00232 
00233       inxMaps.clear();
00234 
00235       initialTime = DayTime::END_OF_TIME;
00236       finalTime = DayTime::BEGINNING_OF_TIME;
00237 
00238       return;
00239 
00240    }  // End of method 'IonexStore::clear()'
00241 
00242 
00243 
00266    Triple IonexStore::getIonexValue( const DayTime& t,
00267                                      const Position& RX,
00268                                      int strategy ) const
00269       throw(InvalidRequest)
00270    {
00271 
00272          // Here we store the necessary IONEX-extracted values 
00273          // (i.e, TEC, RMS, ionosphere height)
00274       Triple tecval(0.0,0.0,0.0);
00275 
00276          // current time check
00277       if (t < getInitialTime())
00278       {
00279          InvalidRequest e("Inadequate data before requested time");
00280          GPSTK_THROW(e);
00281       }
00282 
00283       if (t > getFinalTime() )
00284       {
00285          InvalidRequest e("Inadequate data after requested time");
00286          GPSTK_THROW(e);
00287       }
00288 
00289          // this never should happen but just in case
00290       Position pos(RX);
00291       if ( pos.getSystemName() != "Geocentric" )
00292       {
00293 
00294          InvalidRequest e("Position object is not in GEOCENTRIC coordinates");
00295 
00296          GPSTK_THROW(e);
00297 
00298       }
00299 
00300          //let's define the number of maps to be considered
00301       int nmap;
00302       if      (strategy == 1) nmap = 1;
00303       else if (strategy == 2) nmap = 2;
00304       else if (strategy == 3) nmap = 2;
00305       else if (strategy == 4) nmap = 1;
00306       else
00307       {
00308          InvalidRequest e("Invalid interpolation stategy");
00309          GPSTK_THROW(e);
00310       }
00311 
00312          // let's look for valid Ionex maps
00313       DayTime T[2];
00314          // iterator
00315       IonexMap::const_iterator itm = inxMaps.find(t);
00316       try
00317       {
00318 
00319          if( itm != inxMaps.end() )              // exact match of t
00320          {
00321 
00322                // get the current map
00323             itm = inxMaps.lower_bound(t);
00324                // store current and next epoch
00325             T[0] = itm->first;
00326             T[1] = (++itm)->first;
00327 
00328          }
00329          else                                   // t is between two maps
00330          {
00331 
00332                // get the next valid map
00333             itm = inxMaps.lower_bound(t);
00334                // store the next and previous epoch
00335             T[1] = itm->first;
00336             T[0] = (--itm)->first;
00337 
00338          }  // end of 'if( itm != inxMaps.end() ) ... else ... '' 
00339 
00340       }
00341       catch (...)
00342       {
00343          InvalidRequest e("IonexStore::getIonexValue() ... Invalid time!");
00344          GPSTK_THROW(e);
00345       }
00346 
00347 
00348          // factors (As in Eq.(3), pag.2 of the manual)
00349       double f[2];
00350       f[0] = (T[1]-t   ) / (T[1]-T[0]);
00351       f[1] = (t   -T[0]) / (T[1]-T[0]);
00352 
00353          // if only one map, then we have to use the neareast
00354       if( nmap == 1 )
00355       {
00356 
00357             // closer to the next map
00358          if( f[1] > f[0] )
00359          {
00360             T[0] = T[1];
00361          }
00362 
00363             // than the factor is unit
00364          f[0] = 1.0;
00365 
00366       }  // if( nmap == 1 )
00367 
00368          // loop over the number of maps considered
00369       for(int imap = 0; imap < nmap; imap++)
00370       {
00371 
00372             // now let's determine if we keep fixed position or 
00373             // take into account the rotation around the Sun
00374          Position pos;
00375          if (strategy == 1 || strategy == 2)    // fixed position
00376          {
00377 
00378             pos = RX;
00379 
00380          }
00381          else                                   // rotate the position
00382          {
00383 
00384                // seconds of time to degree (360.0 / 86400.0)
00385             double sec2deg( 4.16666666666667e-3 );
00386 
00387                // count the rotation
00388             pos = RX;
00389             pos.theArray[1] = pos.theArray[1] + ( t - T[imap] ) * sec2deg;
00390 
00391          }  // End of 'if (strategy == 1 || strategy == 2)...'
00392 
00393 
00394             // iterator to the current map
00395          itm = inxMaps.find(T[imap]);
00396 
00397             // map to hold the IONEX types for the current map
00398          IonexValTypeMap ivtm = (*itm).second;
00399 
00400             // object to hold the corresponding data to the current map
00401          IonexData iod;
00402 
00403             // Compute TEC value
00404          if ( ivtm.find(IonexData::TEC) != ivtm.end() )
00405          {
00406 
00407             iod = ivtm[IonexData::TEC];
00408             tecval[0] = tecval[0] + f[imap]*iod.getValue(pos);
00409 
00410          }
00411 
00412             // Compute RMS value
00413          if ( ivtm.find(IonexData::RMS) != ivtm.end() )
00414          {
00415 
00416             iod = ivtm[IonexData::RMS];
00417             tecval[1] = tecval[1] + f[imap]*iod.getValue(pos);
00418 
00419          }
00420 
00421       }  // End of 'for(int imap = 0; imap < nmap; imap++)...'
00422 
00423 
00424          // ionosphere height in meters
00425       tecval[2] = RX.theArray[2];
00426 
00427       return tecval;
00428 
00429    }  // End of method 'IonexStore::getIonexValue()'
00430 
00431 
00432 
00445    double IonexStore::getSTEC( const double& elevation,
00446                                const double& tecval,
00447                                const std::string& ionoMapType ) const
00448       throw (InvalidParameter)
00449    {
00450 
00451       if (tecval < 0)
00452       {
00453          InvalidParameter e("Invalid TEC parameter.");
00454          GPSTK_THROW(e);
00455       }
00456 
00457       if( ionoMapType != "NONE" && ionoMapType != "SLM" && 
00458           ionoMapType != "MSLM" && ionoMapType != "ESM" )
00459       {
00460          InvalidParameter e("Invalid ionosphere mapping function.");
00461          GPSTK_THROW(e);
00462       }
00463 
00464       if (elevation < 0.0)
00465       {
00466 
00467          return 0.0;
00468 
00469       }
00470       else
00471       {
00472 
00473          return ( tecval * iono_mapping_function(elevation, ionoMapType) );
00474 
00475       }
00476 
00477    }  // End of method 'IonexStore::getSTEC()'
00478 
00479 
00480 
00491    double IonexStore::getIono( const double& elevation,
00492                                const double& tecval,
00493                                const double& freq,
00494                                const std::string& ionoMapType ) const
00495       throw (InvalidParameter)
00496    {
00497 
00498       if (tecval < 0)
00499       {
00500          InvalidParameter e("Invalid TEC parameter.");
00501          GPSTK_THROW(e);
00502       }
00503 
00504       if( ionoMapType != "NONE" && ionoMapType != "SLM" && 
00505           ionoMapType != "MSLM" && ionoMapType != "ESM" )
00506       {
00507          InvalidParameter e("Invalid ionosphere mapping function.");
00508          GPSTK_THROW(e);
00509       }
00510 
00511       if (elevation < 0.0)
00512       {
00513 
00514          return 0.0;
00515 
00516       }
00517       else
00518       {
00519 
00520          return ( C2_FACT / (freq * freq) * tecval
00521                          * iono_mapping_function(elevation, ionoMapType) );
00522 
00523       }
00524 
00525    }  // End of method 'IonexStore::getIono()'
00526 
00527 
00528 
00543    double IonexStore::iono_mapping_function( const double& elevation,
00544                                        const std::string& ionoMapType ) const
00545    {
00546 
00547          // map
00548       double map(1.0);
00549          // Earth's radius in KM
00550       double Re = 6371.0;
00551          // zenith angle
00552       double z0 = 90.0 - elevation;
00553 
00554       if( ionoMapType == "SLM" )
00555       {
00556 
00557             // As explained in: Hofmann-Wellenhof et al. (2004) - GPS Theory and
00558             // practice, 5th edition, SpringerWienNewYork, Chapter 6.3, pg. 102
00559 
00560             // ionosphere height in KM
00561          double ionoHeight = 450.0;
00562             // zenith angle of the ionospheric pierce point (IPP)
00563          double sinzipp  = Re / (Re + ionoHeight) * std::sin(z0*DEG_TO_RAD);
00564          double zipprad  = std::asin(sinzipp);
00565 
00566          map      = 1.0/std::cos(zipprad);
00567 
00568       }
00569       else if( ionoMapType == "MSLM" )
00570       {
00571          // maximum zenith distance is 80 degrees
00572          if( z0 <= 80.0 )
00573          {
00574            // ionosphere height in KM
00575            double ionoHeight = 506.7;
00576            double alfa       = 0.9782;
00577            // zenith angle of the ionospheric pierce point (IPP)
00578            double sinzipp = Re / (Re + ionoHeight)
00579                * std::sin(alfa * z0 * DEG_TO_RAD);
00580            double zipprad = std::asin(sinzipp);
00581 
00582            map = 1.0/std::cos(zipprad);
00583          }
00584 
00585       }
00586       else if( ionoMapType == "ESM" )
00587       {
00588          //TODO
00589       }
00590       else  // that means ionoMapType == "NONE"
00591       {
00592          // TODO
00593       }
00594 
00595 
00596       return map;
00597 
00598    }  // End of method 'IonexStore::iono_mapping_function()'
00599 
00600 
00601 
00611    double IonexStore::findDCB( const SatID sat,
00612                                const DayTime& time ) const
00613       throw(InvalidRequest)
00614    {
00615 
00616          // current time check. This is passed even if there are gaps
00617       if ( time < getInitialTime() )
00618       {
00619          InvalidRequest e("Inadequate data before requested time");
00620          GPSTK_THROW(e);
00621       }
00622 
00623       if ( time > getFinalTime() )
00624       {
00625          InvalidRequest e("Inadequate data after requested time");
00626          GPSTK_THROW(e);
00627       }
00628 
00629       double dt(0.0);
00630       IonexDCBMap::const_iterator itm = inxDCBMap.begin();
00631 
00632          // looping through the map
00633       while ( itm != inxDCBMap.end() )
00634       {
00635 
00636             // let's get the relative reference
00637          dt = time - itm->first;
00638 
00639             // this means we don't have maps for this day and there is a gap
00640          if( dt < 0.0 )
00641          {
00642 
00643             InvalidRequest e( "Inadequate data after requested time: " +
00644                               time.asString() );
00645             GPSTK_THROW(e);
00646 
00647          }  // works fine for consecutive files, otherwise last epoch is thrown
00648          else
00649          {
00650 
00651             if( dt < 86400.0 )
00652             {
00653 
00654                IonexHeader::SatDCBMap satdcb( itm->second );
00655                IonexHeader::SatDCBMap::const_iterator iprn( satdcb.find(sat) );
00656 
00657                   // if satellite is not found, throw
00658                if ( iprn == satdcb.end() )
00659                {
00660 
00661                   InvalidRequest e( "There is no DCB value for satellite " +
00662                                     asString(sat) );
00663                   GPSTK_THROW(e);
00664 
00665                }
00666                else     // ... otherwise, fetch the value
00667                {
00668 
00669                   return iprn->second.bias;
00670 
00671                }  // End of 'if ( iprn == satdcb.end() ) ... else ...'
00672 
00673             }
00674             else  // If everything is fine, then move forward in the map
00675             {
00676 
00677                itm++;
00678 
00679             }  // End of 'if( dt < 86400.0 ) ... else ...'
00680 
00681          }  // End of 'if( dt < 0.0 ) ... else ...'
00682 
00683       }  // End of 'while ( itm != inxDCBMap.end() )'
00684 
00685 
00686          // You should never get here, but just in case
00687       return 0.0;
00688 
00689    }  // End of method 'IonexStore::findDCB()'
00690 
00691 
00692 }  // End of namespace gpstk

Generated on Tue May 22 03:30:59 2012 for GPS ToolKit Software Library by  doxygen 1.3.9.1