1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.files.rinex.observation;
18
19 import java.io.ByteArrayInputStream;
20 import java.io.CharArrayWriter;
21 import java.io.IOException;
22 import java.nio.charset.StandardCharsets;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.function.BiFunction;
26 import java.util.function.Function;
27
28 import org.hipparchus.geometry.euclidean.threed.Vector3D;
29 import org.hipparchus.util.FastMath;
30 import org.hipparchus.util.Precision;
31 import org.junit.jupiter.api.Assertions;
32 import org.junit.jupiter.api.BeforeEach;
33 import org.junit.jupiter.api.Test;
34 import org.orekit.Utils;
35 import org.orekit.annotation.DefaultDataContext;
36 import org.orekit.data.DataContext;
37 import org.orekit.data.DataSource;
38 import org.orekit.errors.OrekitException;
39 import org.orekit.errors.OrekitMessages;
40 import org.orekit.estimation.measurements.QuadraticClockModel;
41 import org.orekit.files.rinex.AppliedDCBS;
42 import org.orekit.files.rinex.AppliedPCVS;
43 import org.orekit.files.rinex.section.RinexComment;
44 import org.orekit.gnss.ObservationTimeScale;
45 import org.orekit.gnss.ObservationType;
46 import org.orekit.gnss.PredefinedObservationType;
47 import org.orekit.gnss.SatInSystem;
48 import org.orekit.gnss.SatelliteSystem;
49 import org.orekit.time.AbsoluteDate;
50 import org.orekit.time.ConstantOffsetTimeScale;
51 import org.orekit.time.TimeOffset;
52 import org.orekit.time.TimeScale;
53 import org.orekit.time.TimeScales;
54
55 public class RinexObservationWriterTest {
56
57 @BeforeEach
58 public void setUp() {
59 Utils.setDataRoot("regular-data");
60 }
61
62 @DefaultDataContext
63 @Test
64 public void testWriteHeaderTwice() throws IOException {
65 final RinexObservation robs = load("rinex/bbbb0000.00o",
66 PredefinedObservationType::valueOf,
67 (system, timeScales) -> system.getObservationTimeScale().getTimeScale(timeScales),
68 DataContext.getDefault().getTimeScales());
69 final CharArrayWriter caw = new CharArrayWriter();
70 try (RinexObservationWriter writer = new RinexObservationWriter(caw, "dummy")) {
71 writer.setReceiverClockModel(robs.extractClockModel(2));
72 writer.prepareComments(robs.getComments());
73 writer.writeHeader(robs.getHeader());
74 writer.writeHeader(robs.getHeader());
75 Assertions.fail("an exception should have been thrown");
76 } catch (OrekitException oe) {
77 Assertions.assertEquals(OrekitMessages.HEADER_ALREADY_WRITTEN, oe.getSpecifier());
78 Assertions.assertEquals("dummy", oe.getParts()[0]);
79 }
80 }
81
82 @DefaultDataContext
83 @Test
84 public void testTooLongAgency() throws IOException {
85 final RinexObservation robs = load("rinex/bbbb0000.00o",
86 PredefinedObservationType::valueOf,
87 (system, timeScales) -> system.getObservationTimeScale().getTimeScale(timeScales),
88 DataContext.getDefault().getTimeScales());
89 robs.getHeader().setAgencyName("much too long agency name exceeding 40 characters");
90 final CharArrayWriter caw = new CharArrayWriter();
91 try (RinexObservationWriter writer = new RinexObservationWriter(caw, "dummy")) {
92 writer.setReceiverClockModel(robs.extractClockModel(2));
93 writer.prepareComments(robs.getComments());
94 writer.writeHeader(robs.getHeader());
95 Assertions.fail("an exception should have been thrown");
96 } catch (OrekitException oe) {
97 Assertions.assertEquals(OrekitMessages.FIELD_TOO_LONG, oe.getSpecifier());
98 Assertions.assertEquals("much too long agency name exceeding 40 characters", oe.getParts()[0]);
99 Assertions.assertEquals(40, (Integer) oe.getParts()[1]);
100 }
101 }
102
103 @DefaultDataContext
104 @Test
105 public void testNoWriteHeader() throws IOException {
106 final RinexObservation robs = load("rinex/aiub0000.00o",
107 PredefinedObservationType::valueOf,
108 (system, timeScales) -> system.getObservationTimeScale().getTimeScale(timeScales),
109 DataContext.getDefault().getTimeScales());
110 final CharArrayWriter caw = new CharArrayWriter();
111 try (RinexObservationWriter writer = new RinexObservationWriter(caw, "dummy")) {
112 writer.setReceiverClockModel(robs.extractClockModel(2));
113 writer.writeObservationDataSet(robs.getObservationDataSets().get(0));
114 Assertions.fail("an exception should have been thrown");
115 } catch (OrekitException oe) {
116 Assertions.assertEquals(OrekitMessages.HEADER_NOT_WRITTEN, oe.getSpecifier());
117 Assertions.assertEquals("dummy", oe.getParts()[0]);
118 }
119 }
120
121 @DefaultDataContext
122 @Test
123 public void testRoundTripRinex2A() throws IOException {
124 doTestRoundTrip("rinex/aiub0000.00o", 0.0);
125 }
126
127 @DefaultDataContext
128 @Test
129 public void testRoundTripRinex2B() throws IOException {
130 doTestRoundTrip("rinex/cccc0000.07o", 0.0);
131 }
132
133 @DefaultDataContext
134 @Test
135 public void testRoundTripRinex3A() throws IOException {
136 doTestRoundTrip("rinex/bbbb0000.00o", 0.0);
137 }
138
139 @DefaultDataContext
140 @Test
141 public void testRoundTripRinex3B() throws IOException {
142 doTestRoundTrip("rinex/dddd0000.01o", 0.0);
143 }
144
145 @DefaultDataContext
146 @Test
147 public void testRoundTripDcbs() throws IOException {
148 doTestRoundTrip("rinex/dcbs.00o", 0.0);
149 }
150
151 @DefaultDataContext
152 @Test
153 public void testRoundTripPcvs() throws IOException {
154 doTestRoundTrip("rinex/pcvs.00o", 0.0);
155 }
156
157 @DefaultDataContext
158 @Test
159 public void testRoundTripScaleFactor() throws IOException {
160 doTestRoundTrip("rinex/bbbb0000.00o", 0.0);
161 }
162
163 @DefaultDataContext
164 @Test
165 public void testRoundTripObsScaleFactor() throws IOException {
166 doTestRoundTrip("rinex/ice12720-scaled.07o", 0.0);
167 }
168
169 @DefaultDataContext
170 @Test
171 public void testRoundTripLeapSecond() throws IOException {
172 doTestRoundTrip("rinex/jnu10110.17o", 0.0);
173 }
174
175 @DefaultDataContext
176 @Test
177 public void testRoundTripUPC() throws IOException {
178 doTestRoundTrip("gnss/filtering/UPC33510.08O_trunc", 0.0);
179 }
180
181 @DefaultDataContext
182 @Test
183 public void testContinuationPhaseShift() throws IOException {
184 doTestRoundTrip("rinex/continuation-phase-shift.23o", 0.0);
185 }
186
187 @DefaultDataContext
188 @Test
189 public void testCustomSystem() throws IOException {
190 doTestRoundTrip("rinex/custom-system.01o", 0.0,
191 CustomType::new,
192 (system, timeScales) -> {
193 final ObservationTimeScale ots = system.getObservationTimeScale();
194 return ots != null ?
195 ots.getTimeScale(timeScales) :
196 new ConstantOffsetTimeScale(system.name(), new TimeOffset(45, TimeOffset.SECOND));
197 },
198 DataContext.getDefault().getTimeScales());
199 }
200
201 private RinexObservation load(final String name,
202 final Function<? super String, ? extends ObservationType> typeBuilder,
203 final BiFunction<SatelliteSystem, TimeScales, ? extends TimeScale> timeScaleBuilder,
204 final TimeScales timeScales) {
205 final DataSource dataSource = new DataSource(name, () -> Utils.class.getClassLoader().getResourceAsStream(name));
206 return new RinexObservationParser(typeBuilder, timeScaleBuilder, timeScales).parse(dataSource);
207 }
208
209 @DefaultDataContext
210 private void doTestRoundTrip(final String resourceName, double expectedDt) throws IOException {
211 doTestRoundTrip(resourceName, expectedDt,
212 PredefinedObservationType::valueOf,
213 (system, timeScales) -> system.getObservationTimeScale() == null ?
214 null :
215 system.getObservationTimeScale().getTimeScale(timeScales),
216 DataContext.getDefault().getTimeScales());
217 }
218
219 private void doTestRoundTrip(final String resourceName, double expectedDt,
220 final Function<? super String, ? extends ObservationType> typeBuilder,
221 final BiFunction<SatelliteSystem, TimeScales, ? extends TimeScale> timeScaleBuilder,
222 final TimeScales timeScales) throws IOException {
223
224 final RinexObservation robs = load(resourceName, typeBuilder, timeScaleBuilder, timeScales);
225 final CharArrayWriter caw = new CharArrayWriter();
226 try (RinexObservationWriter writer = new RinexObservationWriter(caw, "dummy", timeScaleBuilder, timeScales)) {
227 writer.setReceiverClockModel(robs.extractClockModel(2));
228 RinexObservation patched = load(resourceName, typeBuilder, timeScaleBuilder, timeScales);
229 patched.getHeader().setClockOffsetApplied(robs.getHeader().getClockOffsetApplied());
230 if (FastMath.abs(expectedDt) > 1.0e-15) {
231 writer.setReceiverClockModel(new QuadraticClockModel(robs.getHeader().getTFirstObs(),
232 expectedDt, 0.0, 0.0));
233 }
234 writer.writeCompleteFile(patched);
235 }
236
237
238 final byte[] bytes = caw.toString().getBytes(StandardCharsets.UTF_8);
239 final DataSource source = new DataSource("", () -> new ByteArrayInputStream(bytes));
240 final RinexObservation rebuilt = new RinexObservationParser(typeBuilder, timeScaleBuilder, timeScales).parse(source);
241
242 checkRinexFile(robs, rebuilt, expectedDt);
243
244 }
245
246 private void checkRinexFile(final RinexObservation first, final RinexObservation second,
247 final double expectedDt) {
248 checkRinexHeader(first.getHeader(), second.getHeader(), expectedDt);
249
250 Assertions.assertTrue(first.getComments().size() >= second.getComments().size());
251 for (int i = 0; i < second.getComments().size(); ++i) {
252 checkRinexComments(first.getComments().get(i), second.getComments().get(i));
253 }
254 Assertions.assertEquals(first.getObservationDataSets().size(), second.getObservationDataSets().size());
255 for (int i = 0; i < first.getObservationDataSets().size(); ++i) {
256 checkRinexObs(first.getObservationDataSets().get(i), second.getObservationDataSets().get(i), expectedDt);
257 }
258 }
259
260 private void checkRinexHeader(final RinexObservationHeader first, final RinexObservationHeader second,
261 final double expectedDt) {
262 Assertions.assertEquals(first.getFormatVersion(), second.getFormatVersion(), 0.001);
263 Assertions.assertEquals(first.getSatelliteSystem(), second.getSatelliteSystem());
264 Assertions.assertEquals(first.getProgramName(), second.getProgramName());
265 Assertions.assertEquals(first.getRunByName(), second.getRunByName());
266 Assertions.assertEquals(first.getCreationDateComponents(), second.getCreationDateComponents());
267 Assertions.assertEquals(first.getCreationTimeZone(), second.getCreationTimeZone());
268 checkDate(first.getCreationDate(), second.getCreationDate(), 0.0);
269 Assertions.assertEquals(first.getDoi(), second.getDoi());
270 Assertions.assertEquals(first.getLicense(), second.getLicense());
271 Assertions.assertEquals(first.getStationInformation(), second.getStationInformation());
272 Assertions.assertEquals(first.getMarkerName(), second.getMarkerName());
273 Assertions.assertEquals(first.getMarkerNumber(), second.getMarkerNumber());
274 Assertions.assertEquals(first.getObserverName(), second.getObserverName());
275 Assertions.assertEquals(first.getAgencyName(), second.getAgencyName());
276 Assertions.assertEquals(first.getReceiverNumber(), second.getReceiverNumber());
277 Assertions.assertEquals(first.getReceiverType(), second.getReceiverType());
278 Assertions.assertEquals(first.getReceiverVersion(), second.getReceiverVersion());
279 Assertions.assertEquals(first.getAntennaNumber(), second.getAntennaNumber());
280 Assertions.assertEquals(first.getAntennaType(), second.getAntennaType());
281 checkVector(first.getApproxPos(), second.getApproxPos());
282 Assertions.assertEquals(first.getAntennaHeight(), second.getAntennaHeight(), 1.0e-12);
283 Assertions.assertEquals(first.getEccentricities().getX(), second.getEccentricities().getX(), 1.0e-12);
284 Assertions.assertEquals(first.getEccentricities().getY(), second.getEccentricities().getY(), 1.0e-12);
285 Assertions.assertEquals(first.getClockOffsetApplied(), second.getClockOffsetApplied());
286 Assertions.assertEquals(first.getInterval(), second.getInterval(), 1.0e-12);
287 checkDate(first.getTFirstObs(), second.getTFirstObs(), expectedDt);
288 checkDate(first.getTLastObs(), second.getTLastObs(), expectedDt);
289 Assertions.assertEquals(first.getLeapSeconds(), second.getLeapSeconds());
290 Assertions.assertEquals(first.getMarkerType(), second.getMarkerType());
291 checkVector(first.getAntennaReferencePoint(), second.getAntennaReferencePoint());
292 Assertions.assertEquals(first.getObservationCode(), second.getObservationCode());
293 checkVector(first.getAntennaPhaseCenter(), second.getAntennaPhaseCenter());
294 checkVector(first.getAntennaBSight(), second.getAntennaBSight());
295 Assertions.assertEquals(first.getAntennaAzimuth(), second.getAntennaAzimuth(), 1.0e-12);
296 checkVector(first.getAntennaZeroDirection(), second.getAntennaZeroDirection());
297 checkVector(first.getCenterMass(), second.getCenterMass());
298 Assertions.assertEquals(first.getSignalStrengthUnit(), second.getSignalStrengthUnit());
299 Assertions.assertEquals(first.getLeapSecondsFuture(), second.getLeapSecondsFuture());
300 Assertions.assertEquals(first.getLeapSecondsWeekNum(), second.getLeapSecondsWeekNum());
301 Assertions.assertEquals(first.getLeapSecondsDayNum(), second.getLeapSecondsDayNum());
302 Assertions.assertEquals(first.getListAppliedDCBS().size(), second.getListAppliedDCBS().size());
303 for (int i = 0; i < first.getListAppliedDCBS().size(); ++i) {
304 checkDCB(first.getListAppliedDCBS().get(i), second.getListAppliedDCBS().get(i));
305 }
306 Assertions.assertEquals(first.getListAppliedPCVS().size(), second.getListAppliedPCVS().size());
307 for (int i = 0; i < first.getListAppliedPCVS().size(); ++i) {
308 checkPCV(first.getListAppliedPCVS().get(i), second.getListAppliedPCVS().get(i));
309 }
310 Assertions.assertEquals(first.getPhaseShiftCorrections().size(), second.getPhaseShiftCorrections().size());
311 for (int i = 0; i < first.getPhaseShiftCorrections().size(); ++i) {
312 checkPhaseShiftCorrection(first.getPhaseShiftCorrections().get(i), second.getPhaseShiftCorrections().get(i));
313 }
314 for (SatelliteSystem system : SatelliteSystem.values()) {
315 Assertions.assertEquals(first.getScaleFactorCorrections(system).size(), second.getScaleFactorCorrections(system).size());
316 for (int i = 0; i < first.getScaleFactorCorrections(system).size(); ++i) {
317 checkScaleFactorCorrection(first.getScaleFactorCorrections(system).get(i),
318 second.getScaleFactorCorrections(system).get(i));
319 }
320 }
321 Assertions.assertEquals(first.getGlonassChannels().size(), second.getGlonassChannels().size());
322 for (int i = 0; i < first.getGlonassChannels().size(); ++i) {
323 checkGlonassChannel(first.getGlonassChannels().get(i), second.getGlonassChannels().get(i));
324 }
325 Assertions.assertEquals(first.getNbSat(), second.getNbSat());
326 Assertions.assertEquals(first.getNbObsPerSat().size(), second.getNbObsPerSat().size());
327 for (final Map.Entry<SatInSystem, Map<ObservationType, Integer>> firstE : first.getNbObsPerSat().entrySet()) {
328 Map<ObservationType, Integer> firstV = firstE.getValue();
329 Map<ObservationType, Integer> secondV = second.getNbObsPerSat().get(firstE.getKey());
330 Assertions.assertEquals(firstV.size(), secondV.size());
331 for (final Map.Entry<ObservationType, Integer> firstF : firstV.entrySet()) {
332 Assertions.assertEquals(firstF.getValue(), secondV.get(firstF.getKey()));
333 }
334 }
335 Assertions.assertEquals(first.getTypeObs().size(), second.getTypeObs().size());
336 for (final Map.Entry<SatelliteSystem, List<ObservationType>> firstE : first.getTypeObs().entrySet()) {
337 List<ObservationType> firstT = firstE.getValue();
338 List<ObservationType> secondT = second.getTypeObs().get(firstE.getKey());
339 Assertions.assertEquals(firstT.size(), secondT.size());
340 for (int i = 0; i < firstT.size(); ++i) {
341 Assertions.assertEquals(firstT.get(i), secondT.get(i));
342 }
343 }
344 Assertions.assertTrue(Precision.equalsIncludingNaN(first.getC1cCodePhaseBias(), second.getC1cCodePhaseBias(), 1.0e-12));
345 Assertions.assertTrue(Precision.equalsIncludingNaN(first.getC1pCodePhaseBias(), second.getC1pCodePhaseBias(), 1.0e-12));
346 Assertions.assertTrue(Precision.equalsIncludingNaN(first.getC2cCodePhaseBias(), second.getC2cCodePhaseBias(), 1.0e-12));
347 Assertions.assertTrue(Precision.equalsIncludingNaN(first.getC2pCodePhaseBias(), second.getC2pCodePhaseBias(), 1.0e-12));
348
349 }
350
351 private void checkRinexComments(final RinexComment first, final RinexComment second) {
352 Assertions.assertEquals(first.getLineNumber(), second.getLineNumber());
353 Assertions.assertEquals(first.getText(), second.getText());
354 }
355
356 private void checkRinexObs(final ObservationDataSet first, final ObservationDataSet second,
357 final double expectedDt) {
358 Assertions.assertEquals(first.getSatellite().getSystem(), second.getSatellite().getSystem());
359 Assertions.assertEquals(first.getSatellite().getPRN(), second.getSatellite().getPRN());
360 checkDate(first.getDate(), second.getDate(), expectedDt);
361 Assertions.assertEquals(first.getEventFlag(), second.getEventFlag());
362 Assertions.assertEquals(first.getObservationData().size(), second.getObservationData().size());
363 for (int i = 0; i < first.getObservationData().size(); ++i) {
364 final ObservationData firstO = first.getObservationData().get(i);
365 final ObservationData secondO = second.getObservationData().get(i);
366 Assertions.assertEquals(firstO.getValue(), secondO.getValue(), 1.0e-12);
367 Assertions.assertEquals(firstO.getLossOfLockIndicator(), secondO.getLossOfLockIndicator());
368 Assertions.assertEquals(firstO.getSignalStrength(), secondO.getSignalStrength());
369 }
370 Assertions.assertTrue(Precision.equalsIncludingNaN(first.getRcvrClkOffset(), second.getRcvrClkOffset(), 1.0e-12));
371 }
372
373 private void checkDCB(final AppliedDCBS first, final AppliedDCBS second) {
374 Assertions.assertEquals(first.getSatelliteSystem(), second.getSatelliteSystem());
375 Assertions.assertEquals(first.getProgDCBS(), second.getProgDCBS());
376 Assertions.assertEquals(first.getSourceDCBS(), second.getSourceDCBS());
377 }
378
379 private void checkPCV(final AppliedPCVS first, final AppliedPCVS second) {
380 Assertions.assertEquals(first.getSatelliteSystem(), second.getSatelliteSystem());
381 Assertions.assertEquals(first.getProgPCVS(), second.getProgPCVS());
382 Assertions.assertEquals(first.getSourcePCVS(), second.getSourcePCVS());
383 }
384
385 private void checkPhaseShiftCorrection(final PhaseShiftCorrection first, final PhaseShiftCorrection second) {
386 Assertions.assertEquals(first.getSatelliteSystem(), second.getSatelliteSystem());
387 Assertions.assertEquals(first.getTypeObs(), second.getTypeObs());
388 Assertions.assertEquals(first.getCorrection(), second.getCorrection(), 1.0e-12);
389 Assertions.assertEquals(first.getSatsCorrected().size(), second.getSatsCorrected().size());
390 for (int i = 0; i < first.getSatsCorrected().size(); ++i) {
391 Assertions.assertEquals(first.getSatsCorrected().get(i).getSystem(), second.getSatsCorrected().get(i).getSystem());
392 Assertions.assertEquals(first.getSatsCorrected().get(i).getPRN(), second.getSatsCorrected().get(i).getPRN());
393 }
394 }
395
396 private void checkScaleFactorCorrection(final ScaleFactorCorrection first, final ScaleFactorCorrection second) {
397 Assertions.assertEquals(first.getCorrection(), second.getCorrection(), 1.0e-12);
398 Assertions.assertEquals(first.getTypesObsScaled().size(), second.getTypesObsScaled().size());
399 for (int i = 0; i < first.getTypesObsScaled().size(); ++i) {
400 Assertions.assertEquals(first.getTypesObsScaled().get(i), second.getTypesObsScaled().get(i));
401 }
402 }
403
404 private void checkGlonassChannel(final GlonassSatelliteChannel first, final GlonassSatelliteChannel second) {
405 Assertions.assertEquals(first.getSatellite().getSystem(), second.getSatellite().getSystem());
406 Assertions.assertEquals(first.getSatellite().getPRN(), second.getSatellite().getPRN());
407 Assertions.assertEquals(first.getK(), second.getK());
408 }
409
410 private void checkDate(final AbsoluteDate first, final AbsoluteDate second,
411 final double expectedDt) {
412 if (first == null) {
413 Assertions.assertNull(second);
414 } else if (Double.isInfinite(first.durationFrom(AbsoluteDate.ARBITRARY_EPOCH))) {
415 Assertions.assertEquals(first, second);
416 } else {
417 Assertions.assertEquals(expectedDt, second.durationFrom(first), 1.0e-6);
418 }
419 }
420
421 private void checkVector(final Vector3D first, final Vector3D second) {
422 if (first == null) {
423 Assertions.assertNull(second);
424 } else {
425 Assertions.assertEquals(0.0, Vector3D.distance(first, second), 1.0e-12 * first.getNorm());
426 }
427 }
428
429 }