1 //==============================================================================
2 //
3 //  This file is part of GPSTk, the GPS Toolkit.
4 //
5 //  The GPSTk 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 GPSTk 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 GPSTk; 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-2020, 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 
39 #include <list>
40 #include <string>
41 #include <iostream>
42 #include <fstream>
43 #include <iomanip>
44 #include <sstream>
45 
46 #include "SatID.hpp"
47 #include "Exception.hpp"
48 #include "CivilTime.hpp"
49 #include "CommonTime.hpp"
50 #include "SP3EphemerisStore.hpp"
51 #include "TestUtil.hpp"
52 
53 using namespace gpstk;
54 using namespace std;
55 
56 class SP3EphemerisStore_T
57 {
58 public:
SP3EphemerisStore_T()59    SP3EphemerisStore_T()
60    {
61       epsilon = 1E-12;
62    }
63 
64 //=============================================================================
65 // Initialize Test Data Filenames
66 //=============================================================================
init()67    void init()
68    {
69       std::string dataFilePath = gpstk::getPathData();
70       std::string tempFilePath = gpstk::getPathTestTemp();
71       std::string fileSep = gpstk::getFileSep();
72 
73       inputSP3Data = dataFilePath + fileSep +
74          "test_input_sp3_nav_ephemerisData.sp3";
75       inputSP3cData = dataFilePath + fileSep +
76          "test_input_SP3c.sp3";
77       inputAPCData = dataFilePath + fileSep +
78          "test_input_sp3_nav_apcData.sp3";
79       inputSixNinesData = dataFilePath + fileSep +
80          "inputs" + fileSep + "igs" + fileSep + "igr20354.sp3";
81       inputNotaFile = dataFilePath + fileSep + "NotaFILE";
82       outputDataDump = tempFilePath + fileSep + "SP3_DataDump.txt";
83 
84       inputComparisonOutput1 =
85          "x:(-1.51906e+07, -2.15539e+07, 3.31227e+06),"
86          " v:(488.793, 118.124, 3125.01), clk bias:1.68268e-05,"
87          " clk drift:1.93783e-11, relcorr:-8.45152e-09,"
88          " health:Unused";
89       inputComparisonOutput15 =
90          "x:(-1.57075e+07, 1.72951e+07, 1.24252e+07),"
91          " v:(408.54, -1568.11, 2651.16), clk bias:0.000411558,"
92          " clk drift:3.22901e-12, relcorr:1.32734e-08,"
93          " health:Unused";
94       inputComparisonOutput31 =
95          "x:(-1.69885e+07, 2.21265e+06, 2.02132e+07),"
96          " v:(-1670.69, -1985.6, -1151.13), clk bias:0.000294455,"
97          " clk drift:-5.8669e-11, relcorr:-1.60472e-08,"
98          " health:Unused";
99    }
100 
101 
102 //=============================================================================
103 // General test for the SP3EphemerisStore
104 // Makes sure SP3EphemerisStore can be instantiated and can load
105 // a file; also ensures that nonexistent files throw an exception
106 //=============================================================================
SP3ESTest()107    unsigned SP3ESTest()
108    {
109       TUDEF("SP3EphemerisStore", "Constructor");
110 
111          // Verify the consturctor builds the SP3EphemerisStore object
112       try
113       {
114          SP3EphemerisStore store;
115          TUPASS("SP3EphemerisStore object successfully created");
116       }
117       catch (...)
118       {
119          TUFAIL("SP3EphemerisStore object could not be created");
120       }
121 
122       SP3EphemerisStore store;
123 
124          // Verify opening an empty file throws an error
125       try
126       {
127          store.loadFile(inputNotaFile);
128          TUFAIL("Opening an empty file did not throw an exception");
129       }
130       catch (Exception& e)
131       {
132          TUPASS("Opening an empty file threw the correct exception");
133       }
134       catch (...)
135       {
136          TUFAIL("Opening an empty file caused an unexpected exception");
137       }
138 
139          // Verify opening a file works with no errors
140       try
141       {
142          store.loadFile(inputSP3Data);
143          TUPASS("Opening a valid file works with no exceptions");
144       }
145       catch (...)
146       {
147          TUFAIL("Exception thrown when opening a valid file");
148       }
149 
150          // Write the dump of the loaded file
151       ofstream dumpData;
152       dumpData.open (outputDataDump.c_str());
153       store.dump(dumpData,1);
154       dumpData.close();
155 
156       TURETURN();
157    }
158 
159 
160       /// test loading of SP3c data
sp3cTest()161    unsigned sp3cTest()
162    {
163       TUDEF("SP3EphemerisStore", "whatever");
164       SP3EphemerisStore store;
165       TUCATCH(store.loadFile(inputSP3cData));
166       TUASSERTE(size_t, 750, store.size());
167       TURETURN();
168    }
169 
170 
171 //=============================================================================
172 // Test for getXvt.
173 // Tests the getXvt method in SP3EphemerisStore by comparing known
174 // results with the method's output for various time stamps in an
175 // SP3 file; also ensures nonexistent SatIDs throw an exception
176 //=============================================================================
getXvtTest()177    unsigned getXvtTest()
178    {
179       TUDEF("SP3EphemerisStore", "getXvt");
180 
181       try
182       {
183          SP3EphemerisStore store;
184          store.loadFile(inputSP3Data);
185 
186          stringstream outputStream1;
187          stringstream outputStream15;
188          stringstream outputStream31;
189 
190          const short PRN0 = 0; // Nonexistent in SP3 file
191          const short PRN1 = 1;
192          const short PRN15 = 15;
193          const short PRN31 = 31;
194          const short PRN32 = 32; // Nonexistent in SP3 file
195 
196          SatID sid0(PRN0,SatelliteSystem::GPS);
197          SatID sid1(PRN1,SatelliteSystem::GPS);
198          SatID sid15(PRN15,SatelliteSystem::GPS);
199          SatID sid31(PRN31,SatelliteSystem::GPS);
200          SatID sid32(PRN32,SatelliteSystem::GPS);
201 
202          CivilTime eTimeCiv(1997,4,6,6,15,0); // Time stamp of one epoch
203          CommonTime eTime = eTimeCiv.convertToCommonTime();
204          CivilTime bTimeCiv(1997,4,6,0,0,0); // Time stamp of first epoch
205          CommonTime bTime = bTimeCiv.convertToCommonTime();
206 
207          try
208          {
209                // Verify that an InvalidRequest exception is thrown
210                // when SatID is not in the data
211             try
212             {
213                store.getXvt(sid0,bTime);
214                TUFAIL("No exception thrown when getXvt looks for an invalid"
215                       " SatID");
216             }
217             catch (InvalidRequest& e)
218             {
219                TUPASS("Expected exception thrown when getXvt looks for an"
220                       " invalid SatID");
221             }
222             catch (...)
223             {
224                TUFAIL("Unexpected exception thrown when getXvt looks for an"
225                       " invalid SatID");
226             }
227 
228                // Verify that an InvalidRequest exception is thrown
229                // when SatID is not in the data
230             try
231             {
232                store.getXvt(sid32,bTime);
233                TUFAIL("No exception thrown when getXvt looks for an invalid"
234                       " SatID");
235             }
236             catch (InvalidRequest& e)
237             {
238                TUPASS("Expected exception thrown when getXvt looks for an"
239                       " invalid SatID");
240             }
241             catch (...)
242             {
243                TUFAIL("Unexpected exception thrown when getXvt looks for an"
244                       " invalid SatID");
245             }
246 
247                // Verify that no exception is thrown for SatID in the data set
248             try
249             {
250                store.getXvt(sid1,eTime);
251                TUPASS("No exception thrown when getXvt looks for a valid"
252                       " SatID");
253             }
254             catch (...)
255             {
256                TUFAIL("Exception thrown when getXvt looks for a valid SatID");
257             }
258 
259             outputStream1 << store.getXvt(sid1,eTime);
260             outputStream15 << store.getXvt(sid15,eTime);
261             outputStream31 << store.getXvt(sid31,eTime);
262          }
263 
264          catch (Exception& e)
265          {
266             cout << e;
267          }
268 
269             // Were the values set to expectation using the explicit
270             //constructor?
271          TUASSERTE(std::string, inputComparisonOutput1, outputStream1.str());
272          TUASSERTE(std::string, inputComparisonOutput15, outputStream15.str());
273          TUASSERTE(std::string, inputComparisonOutput31, outputStream31.str());
274       }
275       catch (...)
276       {
277          TUFAIL("Unexpected exception");
278       }
279 
280       TURETURN();
281    }
282 
283 
284 //=============================================================================
285 // Test for computeXvt.
286 // Tests the computeXvt method in SP3EphemerisStore by comparing known
287 // results with the method's output for various time stamps in an
288 // SP3 file; also ensures nonexistent SatIDs throw an exception
289 //=============================================================================
computeXvtTest()290    unsigned computeXvtTest()
291    {
292       TUDEF("SP3EphemerisStore", "computeXvt");
293 
294       try
295       {
296          SP3EphemerisStore store;
297          stringstream outputStream1;
298          stringstream outputStream15;
299          stringstream outputStream31;
300          Xvt rv;
301          SatID sid0(0, SatelliteSystem::GPS);
302          SatID sid1(1, SatelliteSystem::GPS);
303          SatID sid15(15, SatelliteSystem::GPS);
304          SatID sid31(31, SatelliteSystem::GPS);
305          SatID sid32(32, SatelliteSystem::GPS);
306          CommonTime eTime = CivilTime(1997,4,6,6,15,0,gpstk::TimeSystem::GPS);
307          CommonTime bTime = CivilTime(1997,4,6,0,0,0,gpstk::TimeSystem::GPS);
308 
309          store.rejectBadPositions(false);
310          store.rejectBadClocks(false);
311          store.rejectPredPositions(false);
312          store.rejectPredClocks(false);
313          store.loadFile(inputSP3Data);
314 
315          TUCATCH(rv = store.computeXvt(sid0,bTime));
316          TUASSERTE(Xvt::HealthStatus, Xvt::HealthStatus::Unavailable,rv.health);
317          TUCATCH(rv = store.computeXvt(sid32,bTime));
318          TUASSERTE(Xvt::HealthStatus, Xvt::HealthStatus::Unavailable,rv.health);
319          TUCATCH(rv = store.computeXvt(sid1,eTime));
320          TUASSERTE(Xvt::HealthStatus, Xvt::HealthStatus::Unused, rv.health);
321          outputStream1 << store.computeXvt(sid1,eTime);
322          outputStream15 << store.computeXvt(sid15,eTime);
323          outputStream31 << store.computeXvt(sid31,eTime);
324 
325             // Were the values set to expectation using the explicit
326             //constructor?
327          TUASSERTE(std::string, inputComparisonOutput1, outputStream1.str());
328          TUASSERTE(std::string, inputComparisonOutput15, outputStream15.str());
329          TUASSERTE(std::string, inputComparisonOutput31, outputStream31.str());
330       }
331       catch (...)
332       {
333          TUFAIL("Unexpected exception");
334       }
335 
336       TURETURN();
337    }
338 
339 
340 //=============================================================================
341 // Test for getSVHealth.
342 // Tests the getSVHealth method in SP3EphemerisStore by comparing known
343 // results with the method's output for various time stamps in an
344 // SP3 file; also ensures nonexistent SatIDs throw an exception
345 //=============================================================================
getSVHealthTest()346    unsigned getSVHealthTest()
347    {
348       TUDEF("SP3EphemerisStore", "getSVHealth");
349 
350       try
351       {
352             // These are the same test queries used in computeXvt but
353             // the health results expected are different given that
354             // SP3 can provide Xvt data but not health data.
355          SP3EphemerisStore store;
356          Xvt::HealthStatus rv;
357          SatID sid0(0, SatelliteSystem::GPS);
358          SatID sid1(1, SatelliteSystem::GPS);
359          SatID sid15(15, SatelliteSystem::GPS);
360          SatID sid27(27, SatelliteSystem::GPS);
361          SatID sid31(31, SatelliteSystem::GPS);
362          SatID sid32(32, SatelliteSystem::GPS);
363          CommonTime eTime = CivilTime(1997,4,6,6,15,0,gpstk::TimeSystem::GPS);
364          CommonTime bTime = CivilTime(1997,4,6,0,0,0,gpstk::TimeSystem::GPS);
365 
366          store.rejectBadPositions(false);
367          store.rejectBadClocks(false);
368          store.rejectPredPositions(false);
369          store.rejectPredClocks(false);
370          store.loadFile(inputSP3Data);
371 
372          TUCATCH(rv = store.getSVHealth(sid0,bTime));
373          TUASSERTE(Xvt::HealthStatus, Xvt::HealthStatus::Unused, rv);
374          TUCATCH(rv = store.getSVHealth(sid32,bTime));
375          TUASSERTE(Xvt::HealthStatus, Xvt::HealthStatus::Unused, rv);
376          TUCATCH(rv = store.getSVHealth(sid1,eTime));
377          TUASSERTE(Xvt::HealthStatus, Xvt::HealthStatus::Unused, rv);
378 
379          store.clear();
380          TUASSERTE(int, 0, store.size());
381          store.loadFile(inputSixNinesData);
382          SatID sid4(4, SatelliteSystem::GPS);
383          CommonTime cTime = CivilTime(2019,1,10,1,5,0,gpstk::TimeSystem::GPS);
384             // PRN 4 has clock bias of 999999.999999 but a valid position
385          TUCATCH(rv = store.getSVHealth(sid4, cTime));
386          TUASSERTE(Xvt::HealthStatus, Xvt::HealthStatus::Unused, rv);
387             // PRN 27 has an invalid position and clock bias
388          TUCATCH(rv = store.getSVHealth(sid27, cTime));
389          TUASSERTE(Xvt::HealthStatus, Xvt::HealthStatus::Unused, rv);
390             // PRN 1 should be fine
391          TUCATCH(rv = store.getSVHealth(sid1, cTime));
392          TUASSERTE(Xvt::HealthStatus, Xvt::HealthStatus::Unused, rv);
393       }
394       catch (...)
395       {
396          TUFAIL("Unexpected exception");
397       }
398       TURETURN();
399    }
400 
401 
402 //=============================================================================
403 // Test for getInitialTime
404 // Tests getInitialTime method in SP3EphemerisStore by ensuring that
405 // the method outputs the initial time stamp in an SP3 file
406 //=============================================================================
getInitialTimeTest()407    unsigned getInitialTimeTest()
408    {
409       TUDEF("SP3EphemerisStore", "getInitialTime");
410 
411       try
412       {
413          SP3EphemerisStore store;
414          store.loadFile(inputSP3Data);
415 
416          CommonTime computedInitialTime = store.getInitialTime();
417 
418          CivilTime knownInitialTimeCiv(1997,4,6,0,0,0);
419          CommonTime knownInitialTime =
420             knownInitialTimeCiv.convertToCommonTime();
421 
422             // Check that the function returns the initial time from the file
423          TUASSERTE(CommonTime, knownInitialTime, computedInitialTime);
424       }
425       catch (...)
426       {
427          TUFAIL("Unexpected exception");
428       }
429 
430       TURETURN();
431    }
432 
433 
434 //=============================================================================
435 // Test for getFinalTime
436 // Tests getFinalTime method in SP3EphemerisStore by ensuring that
437 // the method outputs the final time stamp in an SP3 file
438 //=============================================================================
getFinalTimeTest()439    unsigned getFinalTimeTest()
440    {
441       TUDEF("SP3EphemerisStore", "getFinalTime");
442 
443       try
444       {
445          SP3EphemerisStore store;
446          store.loadFile(inputSP3Data);
447 
448          CommonTime computedFinalTime = store.getFinalTime();
449 
450          CivilTime knownFinalTimeCiv(1997,4,6,23,45,0);
451          CommonTime knownFinalTime = knownFinalTimeCiv.convertToCommonTime();
452 
453             // Check that the function returns the initial time from the file
454          TUASSERTE(CommonTime, knownFinalTime, computedFinalTime);
455       }
456       catch (...)
457       {
458          TUFAIL("Unexpected exception");
459       }
460 
461       TURETURN();
462    }
463 //=============================================================================
464 // Test for getPosition
465 // Tests getPosition method in SP3EphemerisStore by comparing the outputs
466 // of the method to known values in two SP3 files--one with position and
467 // velocity values and one with only position values
468 //=============================================================================
getPositionTest()469    unsigned getPositionTest()
470    {
471       TUDEF("SP3EphemerisStore", "getPosition");
472 
473       try
474       {
475          SP3EphemerisStore igsStore;
476          igsStore.loadFile(inputSP3Data);
477 
478          const short PRN1 = 1;
479          const short PRN31 = 31;
480 
481          CivilTime igsTimeCiv(1997,4,6,2,0,0);
482          CommonTime igsTime = igsTimeCiv.convertToCommonTime();
483 
484          SatID sid1(PRN1,SatelliteSystem::GPS);
485          SatID sid31(PRN31,SatelliteSystem::GPS);
486 
487          Triple computedPosition_igs1  = igsStore.getPosition(sid1,igsTime);
488          Triple computedPosition_igs31 = igsStore.getPosition(sid31,igsTime);
489 
490          Triple knownPosition_igs1(-17432922.132,6688018.407,-18768291.053);
491          Triple knownPosition_igs31(-5075919.490,25101160.691,-6633797.696);
492 
493          double relativeError;
494          std::stringstream testMessageStream;
495          std::string testMessageP1 =
496             "getPosition obtained the wrong position in the ";
497          std::string testMessageP2 = " direction for SatID 1";
498             // Check that the computed position matches the known
499             // value for SatID 1
500          for (unsigned i = 0; i < 3; i++)
501          {
502             testMessageStream << testMessageP1 << i << testMessageP2;
503             relativeError  =
504                fabs(knownPosition_igs1[i] - computedPosition_igs1[i]) /
505                fabs(knownPosition_igs1[i]);
506             testFramework.assert(relativeError < epsilon,
507                                  testMessageStream.str(),
508                                  __LINE__);
509             testMessageStream.str(std::string());
510          }
511 
512             //------------------------------------------------------------------
513             // Check that the computed position matches the known
514             // value for SatID 31
515             //------------------------------------------------------------------
516          testMessageP2 = " direction for SatID 31";
517          for (unsigned i = 0; i < 3; i++)
518          {
519             testMessageStream << testMessageP1 << i << testMessageP2;
520             relativeError  = fabs(knownPosition_igs31[i]  -
521                                   computedPosition_igs31[i]) /
522                fabs(knownPosition_igs31[i]);
523             testFramework.assert(relativeError < epsilon ,
524                                  testMessageStream.str() ,
525                                  __LINE__);
526             testMessageStream.str(std::string());
527          }
528 
529          SP3EphemerisStore apcStore;
530          apcStore.loadFile(inputAPCData);
531 
532          CivilTime apcTimeCiv(2001,7,22,2,0,0);
533          CommonTime apcTime = apcTimeCiv.convertToCommonTime();
534 
535          Triple computedPosition_apc1 = apcStore.getPosition(sid1,apcTime);
536          Triple computedPosition_apc31 = apcStore.getPosition(sid31,apcTime);
537 
538          Triple knownPosition_apc1(-5327654.053,-16633919.811,20164748.602);
539          Triple knownPosition_apc31(2170451.938,-22428932.839,-14059088.503);
540 
541             //------------------------------------------------------------------
542             // Check that the computed position matches the known
543             // value for SatID 1
544             //------------------------------------------------------------------
545          testMessageP2 = " direction for SatID 1";
546          for (unsigned i = 0; i < 3; i++)
547          {
548             testMessageStream << testMessageP1 << i << testMessageP2;
549             relativeError = fabs(knownPosition_apc1[i]  -
550                                  computedPosition_apc1[i]) /
551                fabs(knownPosition_apc1[i]);
552             testFramework.assert(relativeError < epsilon ,
553                                  testMessageStream.str() ,
554                                  __LINE__);
555             testMessageStream.str(std::string());
556          }
557 
558             //------------------------------------------------------------------
559             // Check that the computed position matches the known
560             // value for SatID 31
561             //------------------------------------------------------------------
562          testMessageP2 = " direction for SatID 31";
563          for (unsigned i = 0; i < 3; i++)
564          {
565             testMessageStream << testMessageP1 << i << testMessageP2;
566             relativeError = fabs(knownPosition_apc31[i]  -
567                                  computedPosition_apc31[i]) /
568                fabs(knownPosition_apc31[i]);
569             testFramework.assert(relativeError < epsilon ,
570                                  testMessageStream.str() ,
571                                  __LINE__);
572             testMessageStream.str(std::string());
573          }
574 
575 
576             //------------------------------------------------------------------
577             // Check that getSatList() and getIndexSet() return expected values
578             // The data set has data for 29 SVs with PRN 12, PRN 16,
579             // and PRN 32 missing
580             //------------------------------------------------------------------
581          set<SatID> expectedSet;
582          for (unsigned i=1;i<=31;i++)
583          {
584             if (i!=12 && i!=16 && i!=32)
585             {
586                SatID sid(i,SatelliteSystem::GPS);
587                expectedSet.insert(sid);
588             }
589          }
590 
591          vector<SatID> loadedList = apcStore.getSatList();
592          set<SatID> loadedSet = apcStore.getIndexSet();
593          TUASSERTE(unsigned,expectedSet.size(),loadedSet.size());
594          TUASSERTE(unsigned,expectedSet.size(),loadedList.size());
595 
596          set<SatID>::const_iterator cit;
597          for (cit=expectedSet.begin();cit!=expectedSet.end();cit++)
598          {
599             bool found = false;
600             const SatID& sidr = *cit;
601             if (loadedSet.find(sidr)!=loadedSet.end())
602                found = true;
603             TUASSERTE(bool,true,found);
604          }
605 
606          vector<SatID>::const_iterator citl;
607          for (citl=loadedList.begin();citl!=loadedList.end();citl++)
608          {
609             bool found = false;
610             const SatID& sidr = *citl;
611             if (expectedSet.find(sidr)!=expectedSet.end())
612                found = true;
613             TUASSERTE(bool,true,found);
614          }
615 
616       }
617       catch (...)
618       {
619          TUFAIL("Unexpected exception");
620       }
621 
622       TURETURN();
623    }
624 
625 //=============================================================================
626 // Test for getVelocity
627 // Tests getPosition method in SP3EphemerisStore by comparing the outputs
628 // of the method to known values in an SP3 files with position and
629 // velocity values
630 //=============================================================================
getVelocityTest()631    unsigned getVelocityTest()
632    {
633       TUDEF("SP3EphemerisStore", "getVelocity");
634 
635       try
636       {
637          SP3EphemerisStore Store;
638          Store.loadFile(inputAPCData);
639 
640          const short PRN1 = 1;
641          const short PRN31 = 31;
642 
643          CivilTime testTimeCiv(2001,7,22,2,0,0);
644          CommonTime testTime = testTimeCiv.convertToCommonTime();
645 
646          SatID sid1(PRN1,SatelliteSystem::GPS);
647          SatID sid31(PRN31,SatelliteSystem::GPS);
648 
649          Triple computedVelocity_1 = Store.getVelocity(sid1,testTime);
650          Triple computedVelocity_31 = Store.getVelocity(sid31,testTime);
651 
652          Triple knownVelocity_1(1541.6040306,-2000.8516260,-1256.4479944);
653          Triple knownVelocity_31(1165.3672035,-1344.4254143,2399.1497704);
654 
655          double relativeError;
656          std::stringstream testMessageStream;
657          std::string testMessageP2,
658             testMessageP1 = "getVelocity obtained the wrong velocity in the ";
659             //------------------------------------------------------------------
660             // Check that the computed position matches the known
661             // value for SatID 1
662             //------------------------------------------------------------------
663          testMessageP2 = " direction for SatID 1";
664          for (unsigned i = 0; i < 3; i++)
665          {
666             testMessageStream << testMessageP1 << i << testMessageP2;
667             relativeError = fabs(knownVelocity_1[i]  - computedVelocity_1[i]) /
668                fabs(computedVelocity_1[i]);
669             testFramework.assert(relativeError < epsilon ,
670                                  testMessageStream.str() ,
671                                  __LINE__);
672             testMessageStream.str(std::string());
673          }
674 
675             //------------------------------------------------------------------
676             // Check that the computed position matches the known
677             // value for SatID 1
678             //------------------------------------------------------------------
679          testMessageP2 = " direction for SatID 31";
680          for (unsigned i = 0; i < 3; i++)
681          {
682             testMessageStream << testMessageP1 << i << testMessageP2;
683             relativeError = fabs(knownVelocity_31[i] - computedVelocity_31[i])/
684                fabs(computedVelocity_31[i]);
685             testFramework.assert(relativeError < epsilon ,
686                                  testMessageStream.str() ,
687                                  __LINE__);
688             testMessageStream.str(std::string());
689          }
690       }
691       catch (...)
692       {
693          TUFAIL("Unexpected exception");
694       }
695 
696       TURETURN();
697    }
698 
699 private:
700    double epsilon; // Floating point error threshold
701    std::string dataFilePath;
702 
703    std::string inputSP3Data;
704    std::string inputSP3cData;
705    std::string inputAPCData;
706    std::string inputSixNinesData;
707 
708    std::string outputDataDump;
709 
710    std::string inputNotaFile;
711 
712    std::string inputComparisonOutput1;
713    std::string inputComparisonOutput15;
714    std::string inputComparisonOutput31;
715 };
716 
717 
main()718 int main() // Main function to initialize and run all tests above
719 {
720    unsigned errorTotal = 0;
721    SP3EphemerisStore_T testClass;
722    testClass.init();
723 
724    errorTotal += testClass.SP3ESTest();
725    errorTotal += testClass.sp3cTest();
726    errorTotal += testClass.getXvtTest();
727    errorTotal += testClass.computeXvtTest();
728    errorTotal += testClass.getSVHealthTest();
729    errorTotal += testClass.getInitialTimeTest();
730    errorTotal += testClass.getFinalTimeTest();
731    errorTotal += testClass.getPositionTest();
732    errorTotal += testClass.getVelocityTest();
733 
734    cout << "Total Failures for " << __FILE__ << ": " << errorTotal << endl;
735 
736    return errorTotal; // Return the total number of errors
737 }
738