1   /* Copyright 2002-2020 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  package org.orekit.files.general;
18  
19  import static org.junit.Assert.assertEquals;
20  import static org.junit.Assert.assertNotNull;
21  
22  import java.io.BufferedWriter;
23  import java.io.IOException;
24  import java.nio.charset.StandardCharsets;
25  import java.nio.file.Files;
26  import java.nio.file.Paths;
27  import java.util.ArrayList;
28  import java.util.List;
29  
30  import org.hipparchus.geometry.euclidean.threed.Rotation;
31  import org.junit.Assert;
32  import org.junit.Before;
33  import org.junit.Test;
34  import org.orekit.Utils;
35  import org.orekit.attitudes.Attitude;
36  import org.orekit.attitudes.AttitudeProvider;
37  import org.orekit.attitudes.InertialProvider;
38  import org.orekit.bodies.CelestialBody;
39  import org.orekit.bodies.CelestialBodyFactory;
40  import org.orekit.data.DataContext;
41  import org.orekit.errors.OrekitIllegalArgumentException;
42  import org.orekit.errors.OrekitMessages;
43  import org.orekit.files.ccsds.AEMParser;
44  import org.orekit.files.ccsds.AEMWriter;
45  import org.orekit.files.general.AttitudeEphemerisFile.AttitudeEphemerisSegment;
46  import org.orekit.files.general.OrekitAttitudeEphemerisFile.OrekitSatelliteAttitudeEphemeris;
47  import org.orekit.frames.Frame;
48  import org.orekit.frames.FramesFactory;
49  import org.orekit.orbits.KeplerianOrbit;
50  import org.orekit.orbits.PositionAngle;
51  import org.orekit.propagation.SpacecraftState;
52  import org.orekit.propagation.analytical.KeplerianPropagator;
53  import org.orekit.time.AbsoluteDate;
54  import org.orekit.utils.AngularDerivativesFilter;
55  import org.orekit.utils.TimeStampedAngularCoordinates;
56  
57  public class OrekitAttitudeEphemerisFileTest {
58  
59      @Before
60      public void setUp() throws Exception {
61          Utils.setDataRoot("regular-data");
62      }
63  
64      @Test
65      public void testGetSatellites() {
66          final String id1 = "ID1";
67          final String id2 = "ID2";
68          OrekitAttitudeEphemerisFile file = new OrekitAttitudeEphemerisFile();
69          OrekitSatelliteAttitudeEphemeris ephem1 = file.addSatellite(id1);
70          assertNotNull(ephem1);
71          OrekitSatelliteAttitudeEphemeris ephem2 = file.addSatellite(id2);
72          assertNotNull(ephem2);
73      }
74  
75      @Test
76      public void testWritingToAEM() throws IOException {
77          final double quaternionTolerance = 1e-5;
78          final String satId = "SATELLITE1";
79          final double sma = 10000000;
80          final double inc = Math.toRadians(45.0);
81          final double ecc = 0.1;
82          final double raan = 0.0;
83          final double pa = 0.0;
84          final double ta = 0.0;
85          final AbsoluteDate date = new AbsoluteDate();
86          final Frame frame = FramesFactory.getEME2000();
87          final CelestialBody body = CelestialBodyFactory.getEarth();
88          final double mu = body.getGM();
89          KeplerianOrbit initialOrbit = new KeplerianOrbit(sma, ecc, inc, pa, raan, ta, PositionAngle.TRUE,
90                                                           frame, date, mu);
91  
92          // Initialize a Keplerian propagator with an Inertial attitude provider
93          // It is expected that all attitude data lines will have the same value
94          final Rotation refRot = new Rotation(0.72501, -0.64585, 0.018542, -0.23854, false);
95          AttitudeProvider inertialPointing = new InertialProvider(refRot);
96          KeplerianPropagator propagator = new KeplerianPropagator(initialOrbit, inertialPointing);
97  
98          final double propagationDurationSeconds = 1200.0;
99          final double stepSizeSeconds = 60.0;
100         List<SpacecraftState> states = new ArrayList<SpacecraftState>();
101 
102         for (double dt = 0.0; dt < propagationDurationSeconds; dt += stepSizeSeconds) {
103             states.add(propagator.propagate(date.shiftedBy(dt)));
104         }
105 
106         OrekitAttitudeEphemerisFile ephemerisFile = new OrekitAttitudeEphemerisFile();
107         OrekitSatelliteAttitudeEphemeris satellite = ephemerisFile.addSatellite(satId);
108         satellite.addNewSegment(states);
109 
110         // Test of all getters for OrekitSatelliteAttitudeEphemeris
111         assertEquals(satId, satellite.getId());
112         assertEquals(0.0, states.get(0).getDate().durationFrom(satellite.getStart()), 1.0e-15);
113         assertEquals(0.0, states.get(states.size() - 1).getDate().durationFrom(satellite.getStop()), 1.0e-15);
114 
115         // Test of all getters for OrekitAttitudeEphemerisSegment
116         AttitudeEphemerisSegment segment = satellite.getSegments().get(0);
117         assertEquals(OrekitSatelliteAttitudeEphemeris.DEFAULT_INTERPOLATION_METHOD, segment.getInterpolationMethod());
118         assertEquals(OrekitSatelliteAttitudeEphemeris.DEFAULT_INTERPOLATION_SIZE, segment.getInterpolationSamples());
119         assertEquals(OrekitSatelliteAttitudeEphemeris.DEFAULT_ATTITUDE_TYPE, segment.getAttitudeType());
120         assertEquals(OrekitSatelliteAttitudeEphemeris.DEFAULT_IS_FIRST, segment.isFirst());
121         assertEquals(OrekitSatelliteAttitudeEphemeris.DEFAULT_ROTATION_ORDER, segment.getRotationOrder());
122         assertEquals(OrekitSatelliteAttitudeEphemeris.DEFAULT_REF_FRAME_A, segment.getRefFrameAString());
123         assertEquals(OrekitSatelliteAttitudeEphemeris.DEFAULT_REF_FRAME_B, segment.getRefFrameBString());
124         assertEquals(OrekitSatelliteAttitudeEphemeris.DEFAULT_ATTITUDE_DIR, segment.getAttitudeDirection());
125         assertEquals(DataContext.getDefault().getCelestialBodies().getEarth().getName(), segment.getFrameCenterString());
126         assertEquals(DataContext.getDefault().getTimeScales().getUTC().getName(), segment.getTimeScaleString());
127         assertEquals(DataContext.getDefault().getTimeScales().getUTC(), segment.getTimeScale());
128         assertEquals(0.0, states.get(0).getDate().durationFrom(segment.getStart()), 1.0e-15);
129         assertEquals(0.0, states.get(states.size() - 1).getDate().durationFrom(segment.getStop()), 1.0e-15);
130         Assert.assertEquals(AngularDerivativesFilter.USE_R, segment.getAvailableDerivatives());
131 
132         // Verify attitude
133         final Attitude attitude = segment.getAttitudeProvider().getAttitude(initialOrbit, date, frame);
134         Assert.assertEquals(frame, attitude.getReferenceFrame());
135         Assert.assertEquals(refRot.getQ0(), attitude.getRotation().getQ0(), quaternionTolerance);
136         Assert.assertEquals(refRot.getQ1(), attitude.getRotation().getQ1(), quaternionTolerance);
137         Assert.assertEquals(refRot.getQ2(), attitude.getRotation().getQ2(), quaternionTolerance);
138         Assert.assertEquals(refRot.getQ3(), attitude.getRotation().getQ3(), quaternionTolerance);
139 
140         String tempAemFile = Files.createTempFile("OrekitAttitudeEphemerisFileTest", ".aem").toString();
141         try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(tempAemFile), StandardCharsets.UTF_8)) {
142             new AEMWriter().write(writer, ephemerisFile);
143         }
144 
145         AttitudeEphemerisFile ephemerisFromFile = new AEMParser().parse(tempAemFile);
146         Files.delete(Paths.get(tempAemFile));
147         
148         segment = ephemerisFromFile.getSatellites().get(satId).getSegments().get(0);
149         assertEquals(states.get(0).getDate(), segment.getStart());
150         assertEquals(states.get(states.size() - 1).getDate(), segment.getStop());
151         assertEquals(states.size(), segment.getAngularCoordinates().size());
152         assertEquals(body.getName().toUpperCase(), segment.getFrameCenterString());
153         for (int i = 0; i < states.size(); i++) {
154             TimeStampedAngularCoordinates expected = states.get(i).getAttitude().getOrientation();
155             TimeStampedAngularCoordinates actual = segment.getAngularCoordinates().get(i);
156             assertEquals(expected.getDate(), actual.getDate());
157             assertEquals(0.0, Rotation.distance(refRot, actual.getRotation()), quaternionTolerance);
158         }
159 
160     }
161 
162     @Test
163     public void testNoStates() {
164 
165         // Satellite ID
166         final String satId = "SATELLITE1";
167 
168         // Create an empty list of states
169         List<SpacecraftState> states = new ArrayList<SpacecraftState>();
170 
171         // Create a new satellite attitude ephemeris
172         OrekitAttitudeEphemerisFile ephemerisFile = new OrekitAttitudeEphemerisFile();
173         OrekitSatelliteAttitudeEphemeris satellite = ephemerisFile.addSatellite(satId);
174 
175         // Try to add a new segment
176         try {
177             satellite.addNewSegment(states);
178         } catch (OrekitIllegalArgumentException oiae) {
179             Assert.assertEquals(OrekitMessages.NULL_ARGUMENT, oiae.getSpecifier());
180         }
181 
182 
183     }
184 
185     @Test
186     public void testNoEnoughDataForInterpolation() {
187 
188         // Create a spacecraft state
189         final String satId = "SATELLITE1";
190         final double sma = 10000000;
191         final double inc = Math.toRadians(45.0);
192         final double ecc = 0.1;
193         final double raan = 0.0;
194         final double pa = 0.0;
195         final double ta = 0.0;
196         final AbsoluteDate date = new AbsoluteDate();
197         final Frame frame = FramesFactory.getEME2000();
198         final CelestialBody body = CelestialBodyFactory.getEarth();
199         final double mu = body.getGM();
200         KeplerianOrbit initialOrbit = new KeplerianOrbit(sma, ecc, inc, pa, raan, ta, PositionAngle.TRUE,
201                                                          frame, date, mu);
202         SpacecraftState state = new SpacecraftState(initialOrbit);
203 
204         // Add the state to the list of spacecraft states
205         List<SpacecraftState> states = new ArrayList<SpacecraftState>();
206         states.add(state);
207 
208         // Create a new satellite attitude ephemeris
209         OrekitAttitudeEphemerisFile ephemerisFile = new OrekitAttitudeEphemerisFile();
210         OrekitSatelliteAttitudeEphemeris satellite = ephemerisFile.addSatellite(satId);
211 
212         // Try to add a new segment
213         try {
214             satellite.addNewSegment(states, "LINEAR", 1);
215         } catch (OrekitIllegalArgumentException oiae) {
216             Assert.assertEquals(OrekitMessages.NOT_ENOUGH_DATA_FOR_INTERPOLATION, oiae.getSpecifier());
217         }
218     }
219 
220 }
221