1   /* Copyright 2002-2025 CS GROUP
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.orekit.files.stk;
19  
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  import static org.junit.jupiter.api.Assertions.assertThrows;
22  
23  import java.io.StringReader;
24  import java.util.EnumMap;
25  import java.util.List;
26  
27  import org.hipparchus.geometry.euclidean.threed.Vector3D;
28  import org.junit.jupiter.api.BeforeAll;
29  import org.junit.jupiter.api.Test;
30  import org.orekit.Utils;
31  import org.orekit.data.DataSource;
32  import org.orekit.errors.OrekitException;
33  import org.orekit.files.stk.STKEphemerisFile.STKCoordinateSystem;
34  import org.orekit.files.stk.STKEphemerisFile.STKEphemeris;
35  import org.orekit.files.stk.STKEphemerisFile.STKEphemerisSegment;
36  import org.orekit.frames.Frame;
37  import org.orekit.frames.FramesFactory;
38  import org.orekit.time.AbsoluteDate;
39  import org.orekit.time.TimeScalesFactory;
40  import org.orekit.time.UTCScale;
41  import org.orekit.utils.CartesianDerivativesFilter;
42  import org.orekit.utils.Constants;
43  import org.orekit.utils.TimeStampedPVCoordinates;
44  
45  /**
46   * Unit tests for {@link STKEphemerisFileParser}.
47   */
48  public final class STKEphemerisFileParserTest {
49  
50    private static final double MU = Constants.WGS84_EARTH_MU;
51    private static UTCScale UTC;
52  
53    @BeforeAll
54    public static void setUp() {
55        Utils.setDataRoot("regular-data");
56        UTC = TimeScalesFactory.getUTC();
57    }
58  
59    /**
60     * Tests {@link STKEphemerisFileParser#parse(DataSource)} throws an exception if the file is empty.
61     */
62    @Test
63    public void testParseEmptyFile() {
64      final EnumMap<STKCoordinateSystem, Frame> frameMapping = new EnumMap<>(STKCoordinateSystem.class);
65      final Frame frame = FramesFactory.getGCRF();
66      frameMapping.put(STKCoordinateSystem.ICRF, frame);
67      final DataSource source = new DataSource("", () -> new StringReader(""));
68      final STKEphemerisFileParser parser = new STKEphemerisFileParser("99999", MU, UTC, frameMapping);
69      assertThrows(OrekitException.class, () -> parser.parse(source));
70    }
71  
72    /**
73     * Tests {@link STKEphemerisFileParser#parse(DataSource)} correctly parses a file using the
74     * EphemerisTimePos format and which has a single segment.
75     */
76    @Test
77    public void testParseEphemerisTimePosWithSingleSegment() {
78      final String ex = "/stk/stk_02674_p.e";
79      final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
80  
81      final String satelliteId = "02674";
82      final EnumMap<STKCoordinateSystem, Frame> frameMapping = new EnumMap<>(STKCoordinateSystem.class);
83      final Frame frame = FramesFactory.getEME2000();
84      frameMapping.put(STKCoordinateSystem.J2000, frame);
85  
86      final STKEphemerisFileParser parser = new STKEphemerisFileParser(satelliteId, MU, UTC, frameMapping);
87  
88      final STKEphemerisFile file = parser.parse(source);
89  
90      assertEquals("stk.v.12.0", file.getSTKVersion());
91      assertEquals(1, file.getSatellites().size());
92  
93      final AbsoluteDate startDate = new AbsoluteDate(2007, 01, 12, 00, 00, 00.000883, UTC);
94      final AbsoluteDate stopDate = new AbsoluteDate(2007, 01, 12, 00, 10, 00.000883, UTC);
95  
96      final STKEphemeris ephemeris = file.getSatellites().get(satelliteId);
97      assertEquals(satelliteId, ephemeris.getId());
98      assertEquals(MU, ephemeris.getMu());
99      assertEquals(startDate, ephemeris.getStart());
100     assertEquals(stopDate, ephemeris.getStop());
101     assertEquals(1, ephemeris.getSegments().size());
102 
103     final STKEphemerisSegment segment = ephemeris.getSegments().get(0);
104     assertEquals(frame, segment.getFrame());
105     assertEquals(MU, segment.getMu());
106     assertEquals(startDate, segment.getStart());
107     assertEquals(stopDate, segment.getStop());
108     assertEquals(6, segment.getInterpolationSamples());
109     assertEquals(CartesianDerivativesFilter.USE_P, segment.getAvailableDerivatives());
110     assertEquals(11, segment.getCoordinates().size());
111 
112     final List<TimeStampedPVCoordinates> coordinates = segment.getCoordinates();
113 
114     assertEquals(startDate, coordinates.get(0).getDate());
115     assertEquals(new Vector3D(-4.2001828159554983e+06, -3.9105939267270239e+06, -4.5819301444368772e+06),
116         coordinates.get(0).getPosition());
117     assertEquals(Vector3D.ZERO, coordinates.get(0).getVelocity());
118     assertEquals(Vector3D.ZERO, coordinates.get(0).getAcceleration());
119 
120     assertEquals(new AbsoluteDate(2007, 01, 12, 00, 05, 00.000883, UTC), coordinates.get(5).getDate());
121     assertEquals(new Vector3D(-2.3930847437297828e+06, -5.1030332553920103e+06, -4.6952642374704480e+06),
122         coordinates.get(5).getPosition());
123     assertEquals(Vector3D.ZERO, coordinates.get(5).getVelocity());
124     assertEquals(Vector3D.ZERO, coordinates.get(5).getAcceleration());
125 
126     assertEquals(stopDate, coordinates.get(10).getDate());
127     assertEquals(new Vector3D(-3.7051401425713405e+05, -5.8354092318012062e+06, -4.3842831794793038e+06),
128         coordinates.get(10).getPosition());
129     assertEquals(Vector3D.ZERO, coordinates.get(10).getVelocity());
130     assertEquals(Vector3D.ZERO, coordinates.get(10).getAcceleration());
131   }
132 
133   /**
134    * Tests {@link STKEphemerisFileParser#parse(DataSource)} correctly parses a file using the
135    * EphemerisTimePosVel format and which has a single segment.
136    */
137   @Test
138   public void testParseEphemerisTimePosVelWithSingleSegment() {
139     final String ex = "/stk/stk_02674_pv.e";
140     final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
141 
142     final String satelliteId = "02674";
143     final EnumMap<STKCoordinateSystem, Frame> frameMapping = new EnumMap<>(STKCoordinateSystem.class);
144     final Frame frame = FramesFactory.getEME2000();
145     frameMapping.put(STKCoordinateSystem.J2000, frame);
146 
147     final STKEphemerisFileParser parser = new STKEphemerisFileParser(satelliteId, MU, UTC, frameMapping);
148 
149     final STKEphemerisFile file = parser.parse(source);
150 
151     assertEquals("stk.v.12.0", file.getSTKVersion());
152     assertEquals(1, file.getSatellites().size());
153 
154     final AbsoluteDate startDate = new AbsoluteDate(2007, 01, 12, 00, 00, 00.000883, UTC);
155     final AbsoluteDate stopDate = new AbsoluteDate(2007, 01, 12, 00, 10, 00.000883, UTC);
156 
157     final STKEphemeris ephemeris = file.getSatellites().get(satelliteId);
158     assertEquals(satelliteId, ephemeris.getId());
159     assertEquals(MU, ephemeris.getMu());
160     assertEquals(startDate, ephemeris.getStart());
161     assertEquals(stopDate, ephemeris.getStop());
162     assertEquals(1, ephemeris.getSegments().size());
163 
164     final STKEphemerisSegment segment = ephemeris.getSegments().get(0);
165     assertEquals(frame, segment.getFrame());
166     assertEquals(MU, segment.getMu());
167     assertEquals(startDate, segment.getStart());
168     assertEquals(stopDate, segment.getStop());
169     assertEquals(6, segment.getInterpolationSamples());
170     assertEquals(CartesianDerivativesFilter.USE_PV, segment.getAvailableDerivatives());
171     assertEquals(11, segment.getCoordinates().size());
172 
173     final List<TimeStampedPVCoordinates> coordinates = segment.getCoordinates();
174 
175     assertEquals(startDate, coordinates.get(0).getDate());
176     assertEquals(new Vector3D(-4.2001828159554983e+06, -3.9105939267270239e+06, -4.5819301444368772e+06),
177         coordinates.get(0).getPosition());
178     assertEquals(new Vector3D(5.4770282903204152e+03, -4.6296785954320931e+03, -1.0817325337227874e+03),
179         coordinates.get(0).getVelocity());
180     assertEquals(Vector3D.ZERO, coordinates.get(0).getAcceleration());
181 
182     assertEquals(new AbsoluteDate(2007, 01, 12, 00, 05, 00.000883, UTC), coordinates.get(5).getDate());
183     assertEquals(new Vector3D(-2.3930847437297828e+06, -5.1030332553920103e+06, -4.6952642374704480e+06),
184         coordinates.get(5).getPosition());
185     assertEquals(new Vector3D(6.4794691416813621e+03, -3.2589590411954355e+03, 3.3269516839203544e+02),
186         coordinates.get(5).getVelocity());
187     assertEquals(Vector3D.ZERO, coordinates.get(5).getAcceleration());
188 
189     assertEquals(stopDate, coordinates.get(10).getDate());
190     assertEquals(new Vector3D(-3.7051401425713405e+05, -5.8354092318012062e+06, -4.3842831794793038e+06),
191         coordinates.get(10).getPosition());
192     assertEquals(new Vector3D(6.9022331002597584e+03, -1.5830164360578574e+03, 1.7272100173740068e+03),
193         coordinates.get(10).getVelocity());
194     assertEquals(Vector3D.ZERO, coordinates.get(10).getAcceleration());
195   }
196 
197   /**
198    * Tests {@link STKEphemerisFileParser#parse(DataSource)} correctly parses a file using the
199    * EphemerisTimePosVel format and which has multiple segments.
200    */
201   @Test
202   public void testParseEphemerisTimePosVelWithMultipleSegments() {
203     final String ex = "/stk/stk_impulsive_maneuver.e";
204     final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
205 
206     final String satelliteId = "02674";
207     final EnumMap<STKCoordinateSystem, Frame> frameMapping = new EnumMap<>(STKCoordinateSystem.class);
208     final Frame frame = FramesFactory.getEME2000();
209     frameMapping.put(STKCoordinateSystem.J2000, frame);
210 
211     final STKEphemerisFileParser parser = new STKEphemerisFileParser(satelliteId, MU, UTC, frameMapping);
212 
213     final STKEphemerisFile file = parser.parse(source);
214 
215     assertEquals("stk.v.12.0", file.getSTKVersion());
216     assertEquals(1, file.getSatellites().size());
217 
218     final AbsoluteDate startDate = new AbsoluteDate(2007, 01, 12, 00, 00, 00.000883, UTC);
219     final AbsoluteDate stopDate = new AbsoluteDate(2007, 01, 12, 00, 10, 00.000883, UTC);
220 
221     final STKEphemeris ephemeris = file.getSatellites().get(satelliteId);
222     assertEquals(satelliteId, ephemeris.getId());
223     assertEquals(MU, ephemeris.getMu());
224     assertEquals(startDate, ephemeris.getStart());
225     assertEquals(stopDate, ephemeris.getStop());
226     assertEquals(2, ephemeris.getSegments().size());
227 
228     final STKEphemerisSegment segment1 = ephemeris.getSegments().get(0);
229     assertEquals(frame, segment1.getFrame());
230     assertEquals(MU, segment1.getMu());
231     assertEquals(startDate, segment1.getStart());
232     assertEquals(5, segment1.getInterpolationSamples());
233     assertEquals(new AbsoluteDate(2007, 01, 12, 00, 05, 00.000883, UTC), segment1.getStop());
234     assertEquals(CartesianDerivativesFilter.USE_PV, segment1.getAvailableDerivatives());
235     assertEquals(6, segment1.getCoordinates().size());
236 
237     final List<TimeStampedPVCoordinates> coordinates1 = segment1.getCoordinates();
238 
239     assertEquals(startDate, coordinates1.get(0).getDate());
240     assertEquals(new Vector3D(6.9999999999999553e+06, -1.2559721622877134e-03, -7.9186900106575397e-01),
241         coordinates1.get(0).getPosition());
242     assertEquals(new Vector3D(4.1824064674153972e-04, 6.7895303333415395e+03, 3.6864141134955967e+03),
243         coordinates1.get(0).getVelocity());
244     assertEquals(Vector3D.ZERO, coordinates1.get(0).getAcceleration());
245 
246     assertEquals(new AbsoluteDate(2007, 01, 12, 00, 01, 00.000883, UTC), coordinates1.get(1).getDate());
247     assertEquals(new Vector3D(6.9853436721346313e+06, 4.0708747687269317e+05, 2.2102922871869511e+05),
248         coordinates1.get(1).getPosition());
249     assertEquals(new Vector3D(-4.8834963369038530e+02, 6.7753160807054328e+03, 3.6786747792111828e+03),
250         coordinates1.get(1).getVelocity());
251     assertEquals(Vector3D.ZERO, coordinates1.get(1).getAcceleration());
252 
253     assertEquals(new AbsoluteDate(2007, 01, 12, 00, 05, 00.000883, UTC), coordinates1.get(5).getDate());
254     assertEquals(new Vector3D(6.6370788283674866e+06, 2.0015702515387577e+06, 1.0867112801511162e+06),
255         coordinates1.get(5).getPosition());
256     assertEquals(new Vector3D(-2.3954153910685013e+03, 6.4383927907853858e+03, 3.4952501591096920e+03),
257         coordinates1.get(5).getVelocity());
258     assertEquals(Vector3D.ZERO, coordinates1.get(5).getAcceleration());
259 
260     final STKEphemerisSegment segment2 = ephemeris.getSegments().get(1);
261     assertEquals(frame, segment2.getFrame());
262     assertEquals(MU, segment2.getMu());
263     assertEquals(new AbsoluteDate(2007, 01, 12, 00, 05, 00.000883, UTC), segment2.getStart());
264     assertEquals(stopDate, segment2.getStop());
265     assertEquals(5, segment2.getInterpolationSamples());
266     assertEquals(CartesianDerivativesFilter.USE_PV, segment2.getAvailableDerivatives());
267     assertEquals(6, segment2.getCoordinates().size());
268 
269     final List<TimeStampedPVCoordinates> coordinates2 = segment2.getCoordinates();
270 
271     assertEquals(new AbsoluteDate(2007, 01, 12, 00, 05, 00.000883, UTC), coordinates2.get(0).getDate());
272     assertEquals(new Vector3D(6.6370788283674866e+06, 2.0015702515387577e+06, 1.0867112801511162e+06),
273         coordinates2.get(0).getPosition());
274     assertEquals(new Vector3D(-2.4109546214707530e+03, 6.4801591037886537e+03, 3.5179240960554193e+03),
275         coordinates2.get(0).getVelocity());
276     assertEquals(Vector3D.ZERO, coordinates2.get(0).getAcceleration());
277 
278     assertEquals(new AbsoluteDate(2007, 01, 12, 00, 06, 00.000883, UTC), coordinates2.get(1).getDate());
279     assertEquals(new Vector3D(6.4787418082331438e+06, 2.3859551936109182e+06, 1.2953780350291547e+06),
280         coordinates2.get(1).getPosition());
281     assertEquals(new Vector3D(-2.8648687835270284e+03, 6.3283234273332882e+03, 3.4352673416780117e+03),
282         coordinates2.get(1).getVelocity());
283     assertEquals(Vector3D.ZERO, coordinates2.get(1).getAcceleration());
284 
285     assertEquals(stopDate, coordinates2.get(5).getDate());
286     assertEquals(new Vector3D(5.5862903748328788e+06, 3.8099552373593030e+06, 2.0682393977866683e+06),
287         coordinates2.get(5).getPosition());
288     assertEquals(new Vector3D(-4.5259006372314416e+03, 5.4761825144401137e+03, 2.9714200584292998e+03),
289         coordinates2.get(5).getVelocity());
290     assertEquals(Vector3D.ZERO, coordinates2.get(5).getAcceleration());
291   }
292 
293   /**
294    * Tests {@link STKEphemerisFileParser#parse(DataSource)} correctly parses a file using the
295    * EphemerisTimePosVelAcc format and which has a single segment.
296    */
297   @Test
298   public void testParseEphemerisTimePosVelAccWithSingleSegment() {
299     final String ex = "/stk/stk_02674_pva.e";
300     final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
301 
302     final String satelliteId = "02674";
303     final EnumMap<STKCoordinateSystem, Frame> frameMapping = new EnumMap<>(STKCoordinateSystem.class);
304     final Frame frame = FramesFactory.getEME2000();
305     frameMapping.put(STKCoordinateSystem.J2000, frame);
306 
307     final STKEphemerisFileParser parser = new STKEphemerisFileParser(satelliteId, MU, UTC, frameMapping);
308 
309     final STKEphemerisFile file = parser.parse(source);
310 
311     assertEquals("stk.v.12.0", file.getSTKVersion());
312     assertEquals(1, file.getSatellites().size());
313 
314     final AbsoluteDate startDate = new AbsoluteDate(2007, 01, 12, 00, 00, 00.000883, UTC);
315     final AbsoluteDate stopDate = new AbsoluteDate(2007, 01, 12, 00, 10, 00.000883, UTC);
316 
317     final STKEphemeris ephemeris = file.getSatellites().get(satelliteId);
318     assertEquals(satelliteId, ephemeris.getId());
319     assertEquals(MU, ephemeris.getMu());
320     assertEquals(startDate, ephemeris.getStart());
321     assertEquals(stopDate, ephemeris.getStop());
322     assertEquals(1, ephemeris.getSegments().size());
323 
324     final STKEphemerisSegment segment = ephemeris.getSegments().get(0);
325     assertEquals(frame, segment.getFrame());
326     assertEquals(MU, segment.getMu());
327     assertEquals(startDate, segment.getStart());
328     assertEquals(stopDate, segment.getStop());
329     assertEquals(6, segment.getInterpolationSamples());
330     assertEquals(CartesianDerivativesFilter.USE_PVA, segment.getAvailableDerivatives());
331     assertEquals(11, segment.getCoordinates().size());
332 
333     final List<TimeStampedPVCoordinates> coordinates = segment.getCoordinates();
334 
335     assertEquals(startDate, coordinates.get(0).getDate());
336     assertEquals(new Vector3D(-4.2001828159554983e+06, -3.9105939267270239e+06, -4.5819301444368772e+06),
337         coordinates.get(0).getPosition());
338     assertEquals(new Vector3D(5.4770282903204152e+03, -4.6296785954320931e+03, -1.0817325337227874e+03),
339         coordinates.get(0).getVelocity());
340     assertEquals(new Vector3D(4.2195714111001097e+00, 3.9335215635670262e+00, 4.6186527996456137e+00),
341         coordinates.get(0).getAcceleration());
342 
343     assertEquals(new AbsoluteDate(2007, 01, 12, 00, 05, 00.000883, UTC), coordinates.get(5).getDate());
344     assertEquals(new Vector3D(-2.3930847437297828e+06, -5.1030332553920103e+06, -4.6952642374704480e+06),
345         coordinates.get(5).getPosition());
346     assertEquals(new Vector3D(6.4794691416813621e+03, -3.2589590411954355e+03, 3.3269516839203544e+02),
347         coordinates.get(5).getVelocity());
348     assertEquals(new Vector3D(2.4098478990321057e+00, 5.1474331925129251e+00, 4.7467936751027020e+00),
349         coordinates.get(5).getAcceleration());
350 
351     assertEquals(stopDate, coordinates.get(10).getDate());
352     assertEquals(new Vector3D(-3.7051401425713405e+05, -5.8354092318012062e+06, -4.3842831794793038e+06),
353         coordinates.get(10).getPosition());
354     assertEquals(new Vector3D(6.9022331002597584e+03, -1.5830164360578574e+03, 1.7272100173740068e+03),
355         coordinates.get(10).getVelocity());
356     assertEquals(new Vector3D(3.7440376244610168e-01, 5.9536789668958612e+00, 4.4833066969906747e+00),
357         coordinates.get(10).getAcceleration());
358   }
359 
360   /**
361    * Tests {@link STKEphemerisFileParser#parse(DataSource)} when the coordinate system is invalid.
362    */
363   @Test
364   public void testParseInvalidCoordinateSystem() {
365     final String ex = "/stk/stk_invalid_coordinate_system.e";
366     final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
367 
368     final String satelliteId = "02674";
369     final EnumMap<STKCoordinateSystem, Frame> frameMapping = new EnumMap<>(STKCoordinateSystem.class);
370     final Frame frame = FramesFactory.getEME2000();
371     frameMapping.put(STKCoordinateSystem.J2000, frame);
372 
373     final STKEphemerisFileParser parser = new STKEphemerisFileParser(satelliteId, MU, UTC, frameMapping);
374     assertThrows(OrekitException.class, () -> parser.parse(source));
375   }
376 
377   /**
378    * Tests {@link STKEphemerisFileParser#parse(DataSource)} when the coordinate system is not mapped.
379    */
380   @Test
381   public void testParseUnmappedCoordinateSystem() {
382     final String ex = "/stk/stk_02674_p.e";
383     final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
384 
385     final String satelliteId = "02674";
386     final EnumMap<STKCoordinateSystem, Frame> frameMapping = new EnumMap<>(STKCoordinateSystem.class);
387     final Frame frame = FramesFactory.getGCRF();
388     frameMapping.put(STKCoordinateSystem.ICRF, frame);
389 
390     final STKEphemerisFileParser parser = new STKEphemerisFileParser(satelliteId, MU, UTC, frameMapping);
391     final OrekitException exception = assertThrows(OrekitException.class, () -> parser.parse(source));
392     assertEquals("STK coordinate system \"J2000\" has not been mapped to an Orekit frame", exception.getMessage());
393   }
394 
395 }