1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.bodies;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.util.HashSet;
22 import java.util.Locale;
23 import java.util.Scanner;
24 import java.util.Set;
25
26 import org.hamcrest.MatcherAssert;
27 import org.hamcrest.Matchers;
28 import org.hipparchus.geometry.euclidean.threed.Vector3D;
29 import org.junit.jupiter.api.Assertions;
30 import org.junit.jupiter.api.BeforeEach;
31 import org.junit.jupiter.api.Test;
32 import org.junit.jupiter.params.ParameterizedTest;
33 import org.junit.jupiter.params.provider.EnumSource;
34 import org.orekit.Utils;
35 import org.orekit.data.DataContext;
36 import org.orekit.errors.OrekitException;
37 import org.orekit.frames.Frame;
38 import org.orekit.frames.FramesFactory;
39 import org.orekit.time.AbsoluteDate;
40 import org.orekit.time.TimeScale;
41 import org.orekit.time.TimeScalesFactory;
42 import org.orekit.utils.Constants;
43 import org.orekit.utils.PVCoordinates;
44
45 public class JPLEphemeridesLoaderTest {
46
47 @Test
48 void testConstantsJPL() {
49 Utils.setDataRoot("regular-data/de405-ephemerides");
50
51 JPLEphemeridesLoader loader =
52 new JPLEphemeridesLoader(JPLEphemeridesLoader.DEFAULT_DE_SUPPORTED_NAMES,
53 JPLEphemeridesLoader.EphemerisType.SUN);
54 Assertions.assertEquals(149597870691.0, loader.getLoadedAstronomicalUnit(), 0.1);
55 Assertions.assertEquals(81.30056, loader.getLoadedEarthMoonMassRatio(), 1.0e-8);
56 Assertions.assertTrue(Double.isNaN(loader.getLoadedConstant("not-a-constant")));
57 }
58
59 @Test
60 void testConstantsInpop() {
61 Utils.setDataRoot("inpop");
62 JPLEphemeridesLoader loader =
63 new JPLEphemeridesLoader(JPLEphemeridesLoader.DEFAULT_INPOP_SUPPORTED_NAMES,
64 JPLEphemeridesLoader.EphemerisType.SUN);
65 Assertions.assertEquals(149597870691.0, loader.getLoadedAstronomicalUnit(), 0.1);
66 Assertions.assertEquals(81.30057, loader.getLoadedEarthMoonMassRatio(), 1.0e-8);
67 }
68
69 @Test
70 void testGMJPL() {
71 Utils.setDataRoot("regular-data/de405-ephemerides");
72
73 JPLEphemeridesLoader loader =
74 new JPLEphemeridesLoader(JPLEphemeridesLoader.DEFAULT_DE_SUPPORTED_NAMES,
75 JPLEphemeridesLoader.EphemerisType.SUN);
76 Assertions.assertEquals(22032.080e9,
77 loader.getLoadedGravitationalCoefficient(JPLEphemeridesLoader.EphemerisType.MERCURY),
78 1.0e6);
79 Assertions.assertEquals(324858.599e9,
80 loader.getLoadedGravitationalCoefficient(JPLEphemeridesLoader.EphemerisType.VENUS),
81 1.0e6);
82 Assertions.assertEquals(42828.314e9,
83 loader.getLoadedGravitationalCoefficient(JPLEphemeridesLoader.EphemerisType.MARS),
84 1.0e6);
85 Assertions.assertEquals(126712767.863e9,
86 loader.getLoadedGravitationalCoefficient(JPLEphemeridesLoader.EphemerisType.JUPITER),
87 6.0e7);
88 Assertions.assertEquals(37940626.063e9,
89 loader.getLoadedGravitationalCoefficient(JPLEphemeridesLoader.EphemerisType.SATURN),
90 2.0e6);
91 Assertions.assertEquals(5794549.007e9,
92 loader.getLoadedGravitationalCoefficient(JPLEphemeridesLoader.EphemerisType.URANUS),
93 1.0e6);
94 Assertions.assertEquals(6836534.064e9,
95 loader.getLoadedGravitationalCoefficient(JPLEphemeridesLoader.EphemerisType.NEPTUNE),
96 1.0e6);
97 Assertions.assertEquals(981.601e9,
98 loader.getLoadedGravitationalCoefficient(JPLEphemeridesLoader.EphemerisType.PLUTO),
99 1.0e6);
100 Assertions.assertEquals(132712440017.987e9,
101 loader.getLoadedGravitationalCoefficient(JPLEphemeridesLoader.EphemerisType.SUN),
102 1.0e6);
103 Assertions.assertEquals(4902.801e9,
104 loader.getLoadedGravitationalCoefficient(JPLEphemeridesLoader.EphemerisType.MOON),
105 1.0e6);
106 Assertions.assertEquals(403503.233e9,
107 loader.getLoadedGravitationalCoefficient(JPLEphemeridesLoader.EphemerisType.EARTH_MOON),
108 1.0e6);
109 }
110
111 @Test
112 void testGMInpop() {
113
114 Utils.setDataRoot("inpop");
115
116 JPLEphemeridesLoader loader =
117 new JPLEphemeridesLoader("^inpop.*TCB.*littleendian.*\\.dat$",
118 JPLEphemeridesLoader.EphemerisType.SUN);
119 Assertions.assertEquals(22032.081e9,
120 loader.getLoadedGravitationalCoefficient(JPLEphemeridesLoader.EphemerisType.MERCURY),
121 1.0e6);
122 Assertions.assertEquals(324858.597e9,
123 loader.getLoadedGravitationalCoefficient(JPLEphemeridesLoader.EphemerisType.VENUS),
124 1.0e6);
125 Assertions.assertEquals(42828.376e9,
126 loader.getLoadedGravitationalCoefficient(JPLEphemeridesLoader.EphemerisType.MARS),
127 1.0e6);
128 Assertions.assertEquals(126712764.535e9,
129 loader.getLoadedGravitationalCoefficient(JPLEphemeridesLoader.EphemerisType.JUPITER),
130 6.0e7);
131 Assertions.assertEquals(37940585.443e9,
132 loader.getLoadedGravitationalCoefficient(JPLEphemeridesLoader.EphemerisType.SATURN),
133 2.0e6);
134 Assertions.assertEquals(5794549.099e9,
135 loader.getLoadedGravitationalCoefficient(JPLEphemeridesLoader.EphemerisType.URANUS),
136 1.0e6);
137 Assertions.assertEquals(6836527.128e9,
138 loader.getLoadedGravitationalCoefficient(JPLEphemeridesLoader.EphemerisType.NEPTUNE),
139 1.0e6);
140 Assertions.assertEquals(971.114e9,
141 loader.getLoadedGravitationalCoefficient(JPLEphemeridesLoader.EphemerisType.PLUTO),
142 1.0e6);
143 Assertions.assertEquals(132712442110.032e9,
144 loader.getLoadedGravitationalCoefficient(JPLEphemeridesLoader.EphemerisType.SUN),
145 1.0e6);
146 Assertions.assertEquals(4902.800e9,
147 loader.getLoadedGravitationalCoefficient(JPLEphemeridesLoader.EphemerisType.MOON),
148 1.0e6);
149 Assertions.assertEquals(403503.250e9,
150 loader.getLoadedGravitationalCoefficient(JPLEphemeridesLoader.EphemerisType.EARTH_MOON),
151 1.0e6);
152 }
153
154 @Test
155 void testDerivative405() {
156 Utils.setDataRoot("regular-data/de405-ephemerides");
157 checkDerivative(JPLEphemeridesLoader.DEFAULT_DE_SUPPORTED_NAMES,
158 new AbsoluteDate(1969, 6, 25, TimeScalesFactory.getTT()),
159 691200.0);
160 }
161
162 @Test
163 void testDerivative406() {
164 Utils.setDataRoot("regular-data:regular-data/de406-ephemerides");
165 checkDerivative(JPLEphemeridesLoader.DEFAULT_DE_SUPPORTED_NAMES,
166 new AbsoluteDate(2964, 9, 26, TimeScalesFactory.getTT()),
167 1382400.0);
168 }
169
170 @Test
171 void testDummyEarth() {
172 Utils.setDataRoot("regular-data/de405-ephemerides");
173 JPLEphemeridesLoader loader =
174 new JPLEphemeridesLoader(JPLEphemeridesLoader.DEFAULT_DE_SUPPORTED_NAMES,
175 JPLEphemeridesLoader.EphemerisType.EARTH);
176 CelestialBody body = loader.loadCelestialBody(CelestialBodyFactory.EARTH);
177 AbsoluteDate date = new AbsoluteDate(1950, 1, 12, TimeScalesFactory.getTT());
178 Frame eme2000 = FramesFactory.getEME2000();
179 for (double h = 0; h < 86400; h += 60.0) {
180 PVCoordinates pv = body.getPVCoordinates(date, eme2000);
181 Assertions.assertEquals(0, pv.getPosition().getNorm(), 1.0e-15);
182 Assertions.assertEquals(0, pv.getVelocity().getNorm(), 1.0e-15);
183 }
184 }
185
186 @Test
187 void testEndianness() {
188 Utils.setDataRoot("inpop");
189 JPLEphemeridesLoader.EphemerisType type = JPLEphemeridesLoader.EphemerisType.MARS;
190 JPLEphemeridesLoader loaderInpopTCBBig =
191 new JPLEphemeridesLoader("^inpop.*_TCB_.*_bigendian\\.dat$", type);
192 CelestialBody bodysInpopTCBBig = loaderInpopTCBBig.loadCelestialBody(CelestialBodyFactory.MARS);
193 Assertions.assertEquals(1.0, loaderInpopTCBBig.getLoadedConstant("TIMESC"), 1.0e-10);
194 JPLEphemeridesLoader loaderInpopTCBLittle =
195 new JPLEphemeridesLoader("^inpop.*_TCB_.*_littleendian\\.dat$", type);
196 CelestialBody bodysInpopTCBLittle = loaderInpopTCBLittle.loadCelestialBody(CelestialBodyFactory.MARS);
197 Assertions.assertEquals(1.0, loaderInpopTCBLittle.getLoadedConstant("TIMESC"), 1.0e-10);
198 AbsoluteDate t0 = new AbsoluteDate(1969, 7, 17, 10, 43, 23.4, TimeScalesFactory.getTT());
199 Frame eme2000 = FramesFactory.getEME2000();
200 for (double dt = 0; dt < 30 * Constants.JULIAN_DAY; dt += 3600) {
201 AbsoluteDate date = t0.shiftedBy(dt);
202 Vector3D pInpopTCBBig = bodysInpopTCBBig.getPosition(date, eme2000);
203 Vector3D pInpopTCBLittle = bodysInpopTCBLittle.getPosition(date, eme2000);
204 Assertions.assertEquals(0.0, pInpopTCBBig.distance(pInpopTCBLittle), 1.0e-10);
205 }
206 for (String name : DataContext.getDefault().getDataProvidersManager().getLoadedDataNames()) {
207 Assertions.assertTrue(name.contains("inpop"));
208 }
209 }
210
211 @Test
212 void testInpopvsJPL() {
213 Utils.setDataRoot("regular-data:inpop");
214 JPLEphemeridesLoader.EphemerisType type = JPLEphemeridesLoader.EphemerisType.MARS;
215 JPLEphemeridesLoader loaderDE405 =
216 new JPLEphemeridesLoader("^unxp(\\d\\d\\d\\d)\\.405$", type);
217 CelestialBody bodysDE405 = loaderDE405.loadCelestialBody(CelestialBodyFactory.MARS);
218 JPLEphemeridesLoader loaderInpopTDBBig =
219 new JPLEphemeridesLoader("^inpop.*_TDB_.*_bigendian\\.dat$", type);
220 CelestialBody bodysInpopTDBBig = loaderInpopTDBBig.loadCelestialBody(CelestialBodyFactory.MARS);
221 Assertions.assertEquals(0.0, loaderInpopTDBBig.getLoadedConstant("TIMESC"), 1.0e-10);
222 JPLEphemeridesLoader loaderInpopTCBBig =
223 new JPLEphemeridesLoader("^inpop.*_TCB_.*_bigendian\\.dat$", type);
224 CelestialBody bodysInpopTCBBig = loaderInpopTCBBig.loadCelestialBody(CelestialBodyFactory.MARS);
225 Assertions.assertEquals(1.0, loaderInpopTCBBig.getLoadedConstant("TIMESC"), 1.0e-10);
226 AbsoluteDate t0 = new AbsoluteDate(1969, 7, 17, 10, 43, 23.4, TimeScalesFactory.getTT());
227 Frame eme2000 = FramesFactory.getEME2000();
228 for (double dt = 0; dt < 30 * Constants.JULIAN_DAY; dt += 3600) {
229 AbsoluteDate date = t0.shiftedBy(dt);
230 Vector3D pDE405 = bodysDE405.getPosition(date, eme2000);
231 Vector3D pInpopTDBBig = bodysInpopTDBBig.getPosition(date, eme2000);
232 Vector3D pInpopTCBBig = bodysInpopTCBBig.getPosition(date, eme2000);
233 Assertions.assertTrue(pDE405.distance(pInpopTDBBig) > 650.0);
234 Assertions.assertTrue(pDE405.distance(pInpopTDBBig) < 1050.0);
235 Assertions.assertTrue(pDE405.distance(pInpopTCBBig) > 1000.0);
236 Assertions.assertTrue(pDE405.distance(pInpopTCBBig) < 2000.0);
237 }
238
239 }
240
241 @Test
242 void testOverlappingEphemeridesData() throws IOException {
243 Utils.setDataRoot("overlapping-data/data.zip");
244
245
246
247
248
249
250
251
252
253 CelestialBody moon = CelestialBodyFactory.getMoon();
254
255
256 final AbsoluteDate initDate = new AbsoluteDate(1999, 12, 31, 00, 00, 00, TimeScalesFactory.getUTC());
257 moon.getPVCoordinates(initDate, FramesFactory.getGCRF());
258
259
260 final AbsoluteDate otherDate = new AbsoluteDate(2000, 02, 01, 00, 00, 00, TimeScalesFactory.getUTC());
261 moon.getPVCoordinates(otherDate, FramesFactory.getGCRF());
262
263
264 AbsoluteDate currentDate = new AbsoluteDate(1999, 12, 01, 00, 00, 00, TimeScalesFactory.getTAI());
265 AbsoluteDate finalDate = new AbsoluteDate(2000, 03, 14, 00, 00, 00, TimeScalesFactory.getTAI());
266
267 while (currentDate.compareTo(finalDate) < 0) {
268 currentDate = currentDate.shiftedBy(Constants.JULIAN_DAY);
269 moon.getPVCoordinates(currentDate, FramesFactory.getGCRF());
270 }
271
272 }
273
274
275
276
277
278
279 @Test
280 public void testPo431() throws IOException {
281
282 Utils.setDataRoot("regular-data/de431-ephemerides");
283 final int nChecked = testPo("/bodies/testpo.431");
284 MatcherAssert.assertThat(nChecked, Matchers.is(5));
285 }
286
287
288
289
290
291
292 @Test
293 public void testPo405() throws IOException {
294 Utils.setDataRoot("regular-data/de405-ephemerides");
295 final int nChecked = testPo("/bodies/testpo.405");
296 MatcherAssert.assertThat(nChecked, Matchers.is(5));
297 }
298
299
300
301
302
303
304 @Test
305 public void testPo440() throws IOException {
306 Utils.setDataRoot("2007");
307 final int nChecked = testPo("/2007/testpo.440");
308 MatcherAssert.assertThat(nChecked, Matchers.is(11));
309 }
310
311
312
313
314
315
316
317 @ParameterizedTest
318 @EnumSource(JPLEphemeridesLoader.EphemerisType.class)
319 public void Test2021FormatParsing(final JPLEphemeridesLoader.EphemerisType ephemerisType) {
320
321
322 Utils.setDataRoot("regular-data/de440-ephemerides");
323
324
325 JPLEphemeridesLoader loaderWithout2021Format =
326 new JPLEphemeridesLoader(JPLEphemeridesLoader.DEFAULT_DE_SUPPORTED_NAMES, ephemerisType);
327
328 JPLEphemeridesLoader loaderWith2021Format =
329 new JPLEphemeridesLoader(JPLEphemeridesLoader.DEFAULT_DE_2021_SUPPORTED_NAMES, ephemerisType);
330
331
332 Assertions.assertThrows(OrekitException.class, loaderWithout2021Format::getLoadedAstronomicalUnit);
333 Assertions.assertDoesNotThrow(loaderWith2021Format::getLoadedAstronomicalUnit);
334 }
335
336 private int testPo(String name) throws IOException {
337 JPLEphemeridesLoader loader = new JPLEphemeridesLoader(
338 JPLEphemeridesLoader.DEFAULT_DE_SUPPORTED_NAMES,
339 JPLEphemeridesLoader.EphemerisType.SUN);
340 final double au = loader.getLoadedAstronomicalUnit();
341 final double day = Constants.JULIAN_DAY;
342 final TimeScale tdb = TimeScalesFactory.getTDB();
343 final double tolS = 1e-13;
344 final double tolP = 1e-13 * au;
345 final double tolV = 1e-13 * au / day;
346 final Frame gcrf = FramesFactory.getGCRF();
347 final Frame icrf = FramesFactory.getICRF();
348 final Set<Integer> nearEarth = new HashSet<>();
349 nearEarth.add(3);
350 nearEarth.add(10);
351 nearEarth.add(13);
352
353 int i = 0;
354
355 try(InputStream is = this.getClass().getResourceAsStream(name);
356 final Scanner scanner = new Scanner(is, "UTF-8"))
357 {
358 scanner.useLocale(Locale.ROOT);
359 while (scanner.hasNext()) {
360 final int version = scanner.nextInt();
361 final String dateString = scanner.next().replace('.', '-');
362 final AbsoluteDate date = new AbsoluteDate(dateString, tdb);
363 final double jd = scanner.nextDouble();
364 final String message = version + " " + dateString;
365 MatcherAssert.assertThat(
366 message,
367 date.getJD(tdb),
368 Matchers.closeTo(jd, tolS));
369 final int targetInt = scanner.nextInt();
370 final int centerInt = scanner.nextInt();
371 final String targetName = getName(targetInt);
372 final String centerName = getName(centerInt);
373 if (targetName == null || centerName == null) {
374 scanner.nextLine();
375 continue;
376 }
377 CelestialBody target = CelestialBodyFactory.getBody(targetName);
378 CelestialBody center = CelestialBodyFactory.getBody(centerName);
379 Frame frame;
380 if (nearEarth.contains(targetInt) || nearEarth.contains(centerInt)) {
381 frame = gcrf;
382 } else {
383 frame = icrf;
384 }
385 PVCoordinates targetPv = target.getPVCoordinates(date, frame);
386 PVCoordinates centerPv = center.getPVCoordinates(date, frame);
387 final int coordinate = scanner.nextInt();
388 double actual = getCoordinate(targetPv, centerPv, coordinate);
389 final double expected = scanner.nextDouble();
390 if (coordinate < 4) {
391
392 MatcherAssert.assertThat(
393 message,
394 actual,
395 Matchers.closeTo(expected * au, tolP));
396 } else {
397
398 MatcherAssert.assertThat(
399 message,
400 actual,
401 Matchers.closeTo(expected * au / day, tolV));
402 }
403 i++;
404 scanner.nextLine();
405 }
406 }
407 return i;
408 }
409
410
411
412
413
414
415
416
417
418 private double getCoordinate(PVCoordinates targetPv,
419 PVCoordinates centerPv,
420 int coordinate) {
421 final Vector3D d;
422 if (coordinate < 4) {
423 d = targetPv.getPosition().subtract(centerPv.getPosition());
424 } else {
425 d = targetPv.getVelocity().subtract(centerPv.getVelocity());
426 coordinate -= 3;
427 }
428
429 switch (coordinate) {
430 case 1:
431 return d.getX();
432 case 2:
433 return d.getY();
434 case 3:
435 return d.getZ();
436 default:
437 throw new RuntimeException("Unknown coordinate: " + coordinate);
438 }
439 }
440
441
442
443
444
445
446
447
448 private static String getName(int body) {
449
450
451
452
453
454 switch (body) {
455 case 1:
456 return CelestialBodyFactory.MERCURY;
457 case 2:
458 return CelestialBodyFactory.VENUS;
459 case 3:
460 return CelestialBodyFactory.EARTH;
461 case 4:
462 return CelestialBodyFactory.MARS;
463 case 5:
464 return CelestialBodyFactory.JUPITER;
465 case 6:
466 return CelestialBodyFactory.SATURN;
467 case 7:
468 return CelestialBodyFactory.URANUS;
469 case 8:
470 return CelestialBodyFactory.NEPTUNE;
471 case 9:
472 return CelestialBodyFactory.PLUTO;
473 case 10:
474 return CelestialBodyFactory.MOON;
475 case 11:
476 return CelestialBodyFactory.SUN;
477 case 12:
478 return CelestialBodyFactory.SOLAR_SYSTEM_BARYCENTER;
479 case 13:
480 return CelestialBodyFactory.EARTH_MOON;
481 default:
482
483 return null;
484 }
485 }
486
487 private void checkDerivative(String supportedNames, AbsoluteDate date, double maxChunkDuration)
488 {
489 JPLEphemeridesLoader loader =
490 new JPLEphemeridesLoader(supportedNames, JPLEphemeridesLoader.EphemerisType.MERCURY);
491 CelestialBody body = loader.loadCelestialBody(CelestialBodyFactory.MERCURY);
492 double h = 20;
493
494
495 Frame eme2000 = FramesFactory.getEME2000();
496 Vector3D pm4h = body.getPosition(date.shiftedBy(-4 * h), eme2000);
497 Vector3D pm3h = body.getPosition(date.shiftedBy(-3 * h), eme2000);
498 Vector3D pm2h = body.getPosition(date.shiftedBy(-2 * h), eme2000);
499 Vector3D pm1h = body.getPosition(date.shiftedBy( -h), eme2000);
500 Vector3D pp1h = body.getPosition(date.shiftedBy( h), eme2000);
501 Vector3D pp2h = body.getPosition(date.shiftedBy( 2 * h), eme2000);
502 Vector3D pp3h = body.getPosition(date.shiftedBy( 3 * h), eme2000);
503 Vector3D pp4h = body.getPosition(date.shiftedBy( 4 * h), eme2000);
504 Vector3D d4 = pp4h.subtract(pm4h);
505 Vector3D d3 = pp3h.subtract(pm3h);
506 Vector3D d2 = pp2h.subtract(pm2h);
507 Vector3D d1 = pp1h.subtract(pm1h);
508 double c = 1.0 / (840 * h);
509 Vector3D estimatedV = new Vector3D(-3 * c, d4, 32 * c, d3, -168 * c, d2, 672 * c, d1);
510
511 Vector3D loadedV = body.getPVCoordinates(date, eme2000).getVelocity();
512 Assertions.assertEquals(0, loadedV.subtract(estimatedV).getNorm(), 3.5e-10 * loadedV.getNorm());
513 Assertions.assertEquals(maxChunkDuration, loader.getMaxChunksDuration(), 1.0e-10);
514 }
515
516 @BeforeEach
517 public void setUp() {
518 Utils.setDataRoot("regular-data");
519 }
520
521 }