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 /// This utility assumes that epochs are in ascending time order
40
41 #include "FileFilterFrameWithHeader.hpp"
42 #include "Rinex3ObsStream.hpp"
43 #include "Rinex3ObsFilterOperators.hpp"
44
45 #include "DiffFrame.hpp"
46
47 #include "YDSTime.hpp"
48
49 using namespace std;
50 using namespace gpstk;
51
52 class ROWDiff : public DiffFrame
53 {
54 public:
55 /// Input file does not exist exit code
56 static const int EXIST_ERROR = 2;
57 /// Differences found in input files
58 static const int DIFFS_CODE = 1;
ROWDiff(char * arg0)59 ROWDiff(char* arg0) : DiffFrame(arg0, std::string("RINEX Obs")),
60 precisionOption('p',"precision","Limit data comparison to n decimal places. "
61 "Default = 5")
62 {}
63 virtual bool initialize(int argc, char* argv[]) throw();
64
65 protected:
66 virtual void process();
67 gpstk::CommandOptionWithAnyArg precisionOption;
68
69 private:
70 int precision;
71 static const int DEFAULT_PRECISION = 5;
72 };
73
initialize(int argc,char * argv[])74 bool ROWDiff::initialize(int argc, char* argv[]) throw()
75 {
76 if (!DiffFrame::initialize(argc, argv))
77 {
78 return false;
79 }
80 if (precisionOption.getCount())
81 {
82 precision = atoi(precisionOption.getValue()[0].c_str());
83 }
84 else
85 {
86 precision = DEFAULT_PRECISION;
87 }
88 return true;
89 }
90
process()91 void ROWDiff::process()
92 {
93 gpstk::FileFilterFrameWithHeader<Rinex3ObsStream, Rinex3ObsData, Rinex3ObsHeader>
94 ff1(inputFileOption.getValue()[0]), ff2(inputFileOption.getValue()[1]);
95
96 // no data? FIX make this program faster.. if one file
97 // doesn't exist, there's little point in reading any.
98 if (ff1.emptyHeader())
99 cerr << "No header information for " << inputFileOption.getValue()[0]
100 << endl;
101 if (ff2.emptyHeader())
102 cerr << "No header information for " << inputFileOption.getValue()[1]
103 << endl;
104 if (ff1.emptyHeader() || ff2.emptyHeader())
105 {
106 cerr << "Check that files exist." << endl;
107 cerr << "diff failed." << endl;
108 exitCode = EXIST_ERROR;
109 return;
110 }
111
112 // determine whether the two input files have the same observation types
113
114 Rinex3ObsHeader header1, header2;
115 Rinex3ObsStream ros1(inputFileOption.getValue()[0]), ros2(inputFileOption.getValue()[1]);
116
117 ros1 >> header1;
118 ros2 >> header2;
119
120 // find the obs data intersection
121
122 if(header1.version != header2.version)
123 {
124 cout << "File 1 and file 2 are not the same RINEX version" << endl;
125 // Reading a R2 file in translates/guesses its obsTypes into R3-style obsIDs,
126 // but translating the R3 obsIDs to R2 is more likely to match.
127 // So map R3 -> R2 then change the R2 header to match.
128 if (header1.version < 3 && header2.version >= 3)
129 {
130 header2.prepareVer2Write();
131 Rinex3ObsHeader::RinexObsVec r3ov;
132 Rinex3ObsHeader::StringVec::iterator r2it = header1.R2ObsTypes.begin();
133 while (r2it != header1.R2ObsTypes.end())
134 {
135 r3ov.push_back(header2.mapSysR2toR3ObsID["G"][*r2it]);
136 r2it++;
137 }
138 header1.mapObsTypes["G"] = r3ov;
139 ff1.frontHeader().mapObsTypes["G"] = r3ov;
140 }
141 else if (header2.version < 3 && header1.version >= 3)
142 {
143 header1.prepareVer2Write();
144 Rinex3ObsHeader::RinexObsVec r3ov;
145 Rinex3ObsHeader::StringVec::iterator r2it = header2.R2ObsTypes.begin();
146 while (r2it != header2.R2ObsTypes.end())
147 {
148 r3ov.push_back(header1.mapSysR2toR3ObsID["G"][*r2it]);
149 r2it++;
150 }
151 header2.mapObsTypes["G"] = r3ov;
152 ff2.frontHeader().mapObsTypes["G"] = r3ov;
153 }
154 }
155
156 // Find out what obs IDs header 1 has that header 2 does/ doesn't have
157 // add those to intersectionRom/ diffRom respectively.
158 cout << "Comparing the following fields:" << endl;
159 Rinex3ObsHeader::RinexObsMap diffRom;
160 Rinex3ObsHeader::RinexObsMap intersectRom;
161 for (Rinex3ObsHeader::RinexObsMap::iterator mit = header1.mapObsTypes.begin();
162 mit != header1.mapObsTypes.end();
163 mit++)
164 {
165 string sysChar = mit->first;
166 cout << sysChar << ": ";
167 for(Rinex3ObsHeader::RinexObsVec::iterator ID1 = mit->second.begin();
168 ID1 != mit->second.end();
169 ID1++)
170 {
171 try
172 {
173 header2.getObsIndex(sysChar, *ID1);
174 intersectRom[sysChar].push_back(*ID1);
175 cout << " " << ID1->asString();
176 }
177 catch(...)
178 {
179 diffRom[sysChar].push_back(*ID1);
180 }
181 }
182 cout << endl;
183 }
184
185 // Find out what obs IDs header 2 has that header 1 doesn't
186 // and add them to diffRom
187 for (Rinex3ObsHeader::RinexObsMap::iterator mit = header2.mapObsTypes.begin();
188 mit != header2.mapObsTypes.end();
189 mit++)
190 {
191 string sysChar = mit->first;
192 for(Rinex3ObsHeader::RinexObsVec::iterator ID2 = mit->second.begin();
193 ID2 != mit->second.end();
194 ID2++)
195 {
196 try
197 {
198 header1.getObsIndex(sysChar, *ID2);
199 }
200 catch(...)
201 {
202 diffRom[sysChar].push_back(*ID2);
203 }
204 }
205 }
206
207 // Print out the differences between the obs IDs in header1 and header2
208 if(!diffRom.empty())
209 {
210 cout << "Ignoring unshared obs:" << endl;
211 for (Rinex3ObsHeader::RinexObsMap::iterator mit = diffRom.begin();
212 mit != diffRom.end();
213 mit++)
214 {
215 string sysChar = mit->first;
216 cout << sysChar << ": ";
217 for (Rinex3ObsHeader::RinexObsVec::iterator ID = mit->second.begin();
218 ID != mit->second.end();
219 ID++)
220 {
221 cout << ID->asString() << " ";
222 }
223 cout << endl;
224 }
225 }
226
227 std::list<Rinex3ObsData> a =
228 ff1.halfDiff(ff2,Rinex3ObsDataOperatorLessThanFull(intersectRom), precision);
229 std::list<Rinex3ObsData> b =
230 ff2.halfDiff(ff1, Rinex3ObsDataOperatorLessThanFull(intersectRom), precision);
231
232 pair< list<Rinex3ObsData>, list<Rinex3ObsData> > difflist =
233 pair< list<Rinex3ObsData>, list<Rinex3ObsData> >( a, b);
234
235 if (difflist.first.empty() && difflist.second.empty())
236 {
237 //Indicate to the user, before exiting, that rowdiff
238 //performed properly and no differences were found.
239 cout << "For the observation types that were compared, "
240 << "no differences were found." << endl;
241 exitCode = 0;
242 return;
243 }
244
245 // differences found
246 exitCode = DIFFS_CODE;
247
248 list<Rinex3ObsData>::iterator firstDiffItr = difflist.first.begin();
249 list<Rinex3ObsData>::iterator secondDiffItr = difflist.second.begin();
250 while(firstDiffItr != difflist.first.end() || secondDiffItr != difflist.second.end())
251 {
252 //Epoch in both files
253 if(firstDiffItr->time == secondDiffItr->time)
254 {
255 Rinex3ObsData::DataMap::iterator firstObsItr = firstDiffItr->obs.begin();
256 Rinex3ObsData::DataMap::iterator secondObsItr = secondDiffItr->obs.begin();
257 // For each satellite
258 while(firstObsItr != firstDiffItr->obs.end() || secondObsItr != secondDiffItr->obs.end())
259 {
260 // Both files have data for that satellite
261 if(firstObsItr->first == secondObsItr->first)
262 {
263 string sysString = string(1,firstObsItr->first.systemChar());
264 cout << "-" << setw(3) << (static_cast<YDSTime>(firstDiffItr->time))
265 << ' ' << setw(2) << firstObsItr->first << ' ';
266 Rinex3ObsHeader::RinexObsVec::iterator romIt;
267 for (romIt = intersectRom[sysString].begin();
268 romIt != intersectRom[sysString].end();
269 romIt++)
270 {
271 size_t idx1 = header1.getObsIndex(sysString,*romIt);
272 size_t idx2 = header2.getObsIndex(sysString,*romIt);
273 cout << setw(15) << setprecision(3) << fixed
274 << firstObsItr->second[idx1].data - secondObsItr->second[idx2].data
275 << ' ' << romIt->asString() << ' ';
276 }
277 firstObsItr++;
278 secondObsItr++;
279 }
280 // Only file 1 has data for that satellite
281 else if (
282 (firstObsItr != firstDiffItr->obs.end()) &&
283 (
284 (secondObsItr == secondDiffItr->obs.end()) ||
285 (firstObsItr->first.id < secondObsItr->first.id))
286 )
287 {
288 string sysString = string(1,firstObsItr->first.systemChar());
289 cout << "<" << setw(3) << (static_cast<YDSTime>(firstDiffItr->time))
290 << ' ' << setw(2) << firstObsItr->first << ' ';
291 Rinex3ObsHeader::RinexObsVec::iterator romIt;
292 for (romIt = intersectRom[sysString].begin();
293 romIt != intersectRom[sysString].end();
294 romIt++)
295 {
296 size_t idx = header1.getObsIndex(sysString,*romIt);
297 cout << setw(15) << setprecision(3) << fixed
298 << firstObsItr->second[idx].data << ' ' << romIt->asString() << ' ';
299 }
300 firstObsItr++;
301 }
302 // Only file 2 has data for that satellite
303 else if (secondObsItr != secondDiffItr->obs.end())
304 {
305 string sysString = string(1,secondObsItr->first.systemChar());
306 cout << ">" << setw(3) << (static_cast<YDSTime>(secondDiffItr->time))
307 << ' ' << setw(2) << secondObsItr->first << ' ';
308 Rinex3ObsHeader::RinexObsVec::iterator romIt;
309 for (romIt = intersectRom[sysString].begin();
310 romIt != intersectRom[sysString].end();
311 romIt++)
312 {
313 size_t idx = header2.getObsIndex(sysString,*romIt);
314 cout << setw(15) << setprecision(3) << fixed
315 << secondObsItr->second[idx].data << ' ' << romIt->asString() << ' ';
316 }
317 secondObsItr++;
318 }
319 cout << endl;
320 }
321
322 firstDiffItr++;
323 secondDiffItr++;
324 }
325 //Epoch only in first file
326 else if((firstDiffItr != difflist.first.end()) && firstDiffItr->time < secondDiffItr->time)
327 {
328 Rinex3ObsData::DataMap::iterator firstObsItr = firstDiffItr->obs.begin();
329 for (;firstObsItr != firstDiffItr->obs.end(); firstObsItr++)
330 {
331 cout << "<" << setw(3) << (static_cast<YDSTime>(firstDiffItr->time))
332 << ' ' << setw(2) << firstObsItr->first << ' ';
333 string sysString = string(1,firstObsItr->first.systemChar());
334 Rinex3ObsHeader::RinexObsVec::iterator romIt;
335 for (romIt = intersectRom[sysString].begin();
336 romIt != intersectRom[sysString].end();
337 romIt++)
338 {
339 size_t idx = header1.getObsIndex(sysString,*romIt);
340 cout << setw(15) << setprecision(3) << fixed
341 << firstObsItr->second[idx].data << ' ' << romIt->asString() << ' ';
342 }
343 cout << endl;
344 }
345 firstDiffItr++;
346 }
347 //Epoch only in second file
348 else if (secondDiffItr != difflist.second.end()) // && (secondDiffItr->time < firstDiffItr->time)
349 {
350 Rinex3ObsData::DataMap::iterator secondObsItr = secondDiffItr->obs.begin();
351 for (;secondObsItr != secondDiffItr->obs.end(); secondObsItr++)
352 {
353 cout << ">" << setw(3) << (static_cast<YDSTime>(secondDiffItr->time))
354 << ' ' << setw(2) << secondObsItr->first << ' ';
355 string sysString = string(1,secondObsItr->first.systemChar());
356 Rinex3ObsHeader::RinexObsVec::iterator romIt;
357 for (romIt = intersectRom[sysString].begin();
358 romIt != intersectRom[sysString].end();
359 romIt++)
360 {
361 size_t idx = header2.getObsIndex(sysString,*romIt);
362 cout << setw(15) << setprecision(3) << fixed
363 << secondObsItr->second[idx].data << ' ' << romIt->asString() << ' ';
364 }
365 cout << endl;
366 }
367 secondDiffItr++;
368 }
369 }
370 }
371
main(int argc,char * argv[])372 int main(int argc, char* argv[])
373 {
374 try
375 {
376 ROWDiff m(argv[0]);
377 if (!m.initialize(argc, argv))
378 return m.exitCode;
379 if (!m.run())
380 return m.exitCode;
381
382 return m.exitCode;
383 }
384 catch(Exception& e)
385 {
386 cout << e << endl;
387 }
388 catch(std::exception& e)
389 {
390 cout << e.what() << endl;
391 }
392 catch(...)
393 {
394 cout << "unknown error" << endl;
395 }
396 // only reach this point if an exception was caught
397 return BasicFramework::EXCEPTION_ERROR;
398 }
399