1   package org.orekit.propagation;
2   
3   import org.hipparchus.geometry.euclidean.threed.Rotation;
4   import org.hipparchus.geometry.euclidean.threed.Vector3D;
5   import org.hipparchus.ode.nonstiff.AdaptiveStepsizeIntegrator;
6   import org.hipparchus.ode.nonstiff.DormandPrince853Integrator;
7   import org.hipparchus.util.FastMath;
8   import org.junit.jupiter.api.Assertions;
9   import org.junit.jupiter.api.BeforeEach;
10  import org.junit.jupiter.api.Test;
11  import org.orekit.Utils;
12  import org.orekit.attitudes.Attitude;
13  import org.orekit.forces.gravity.potential.GravityFieldFactory;
14  import org.orekit.forces.gravity.potential.SHMFormatReader;
15  import org.orekit.frames.FramesFactory;
16  import org.orekit.orbits.EquinoctialOrbit;
17  import org.orekit.orbits.Orbit;
18  import org.orekit.orbits.OrbitType;
19  import org.orekit.propagation.analytical.BrouwerLyddanePropagator;
20  import org.orekit.propagation.numerical.NumericalPropagator;
21  import org.orekit.propagation.semianalytical.dsst.DSSTPropagator;
22  import org.orekit.time.AbsoluteDate;
23  import org.orekit.utils.PVCoordinates;
24  
25  class AdditionalDataProviderTest {
26      private static final double DURATION = 600.0;
27      private static final String STRING_BEFORE = "Let's go!";
28      private static final String STRING_AFTER = "Good job!";
29      private AbsoluteDate initDate;
30      private SpacecraftState initialState;
31      private AdaptiveStepsizeIntegrator integrator;
32  
33      @BeforeEach
34      public void setUp() {
35          Utils.setDataRoot("regular-data:potential/shm-format");
36          GravityFieldFactory.addPotentialCoefficientsReader(new SHMFormatReader("^eigen_cg03c_coef$", false));
37          final double mu = GravityFieldFactory.getUnnormalizedProvider(0, 0).getMu();
38          final Vector3D position = new Vector3D(7.0e6, 1.0e6, 4.0e6);
39          final Vector3D velocity = new Vector3D(-500.0, 8000.0, 1000.0);
40          initDate = AbsoluteDate.J2000_EPOCH;
41          final Orbit orbit = new EquinoctialOrbit(new PVCoordinates(position, velocity), FramesFactory.getEME2000(), initDate, mu);
42          initialState = new SpacecraftState(orbit);
43          double[][] tolerance = ToleranceProvider.getDefaultToleranceProvider(0.001).getTolerances(orbit, OrbitType.EQUINOCTIAL);
44          integrator = new DormandPrince853Integrator(0.001, 200, tolerance[0], tolerance[1]);
45          integrator.setInitialStepSize(60);
46      }
47  
48      @Test
49      public void testModifyMainState() {
50  
51          // Create propagator
52          final NumericalPropagator propagator = new NumericalPropagator(integrator);
53          propagator.setInitialState(initialState);
54  
55          // Create state modifier
56          final MainStateModifier modifier = new MainStateModifier();
57  
58          // Add the provider to the propagator
59          propagator.addAdditionalDataProvider(modifier);
60  
61          // Propagate
62          final double dt = 600.0;
63          final SpacecraftState propagated = propagator.propagate(initDate.shiftedBy(dt));
64  
65          // Verify
66          Assertions.assertEquals(2 * SpacecraftState.DEFAULT_MASS, propagated.getMass(), 1.0e-12);
67          Assertions.assertEquals(FastMath.PI,
68                  propagated.getAttitude().getRotation().getAngle(),
69                  1.0e-15);
70  
71      }
72  
73      @Test
74      public void testIssue900Numerical() {
75  
76          // Create propagator
77          final NumericalPropagator propagator = new NumericalPropagator(integrator);
78          propagator.setInitialState(initialState);
79  
80          // Create additional state provider
81          final String name          = "init";
82          final TimeDifferenceProvider provider = new TimeDifferenceProvider(name);
83          Assertions.assertFalse(provider.wasCalled());
84  
85          // Add the provider to the propagator
86          propagator.addAdditionalDataProvider(provider);
87  
88          // Propagate
89          final double dt = 600.0;
90          final SpacecraftState propagated = propagator.propagate(initDate.shiftedBy(dt));
91  
92          // Verify
93          Assertions.assertTrue(provider.wasCalled());
94          Assertions.assertEquals(dt, propagated.getAdditionalState(name)[0], 0.01);
95  
96      }
97  
98      @Test
99      public void testIssue900Dsst() {
100 
101         // Initialize propagator
102         final DSSTPropagator propagator = new DSSTPropagator(integrator);
103         propagator.setInitialState(initialState, PropagationType.MEAN);
104 
105         // Create additional state provider
106         final String name          = "init";
107         final TimeDifferenceProvider provider = new TimeDifferenceProvider(name);
108         Assertions.assertFalse(provider.wasCalled());
109 
110         // Add the provider to the propagator
111         propagator.addAdditionalDataProvider(provider);
112 
113         // Propagate
114         final double dt = 600.0;
115         final SpacecraftState propagated = propagator.propagate(initialState.getDate().shiftedBy(dt));
116 
117         // Verify
118         Assertions.assertTrue(provider.wasCalled());
119         Assertions.assertEquals(dt, propagated.getAdditionalState(name)[0], 0.01);
120 
121     }
122 
123     @Test
124     public void testIssue900BrouwerLyddane() {
125 
126         // Initialize propagator
127         BrouwerLyddanePropagator propagator = new BrouwerLyddanePropagator(initialState.getOrbit(), Utils.defaultLaw(),
128                 GravityFieldFactory.getUnnormalizedProvider(5, 0), BrouwerLyddanePropagator.M2);
129 
130         // Create additional state provider
131         final String name          = "init";
132         final TimeDifferenceProvider provider = new TimeDifferenceProvider(name);
133         Assertions.assertFalse(provider.wasCalled());
134 
135         // Add the provider to the propagator
136         propagator.addAdditionalDataProvider(provider);
137 
138         // Propagate
139         final double dt = 600.0;
140         final SpacecraftState propagated = propagator.propagate(initialState.getDate().shiftedBy(dt));
141 
142         // Verify
143         Assertions.assertTrue(provider.wasCalled());
144         Assertions.assertEquals(dt, propagated.getAdditionalState(name)[0], 0.01);
145 
146     }
147 
148     @Test
149     public void testPropagateAdditionalStringData() {
150         final NumericalPropagator propagator = new NumericalPropagator(integrator);
151         propagator.setInitialState(initialState);
152 
153         final MainStringDataModifier modifier = new MainStringDataModifier();
154         propagator.addAdditionalDataProvider(modifier);
155 
156         final SpacecraftState propagated = propagator.propagate(initDate.shiftedBy(DURATION));
157         Assertions.assertEquals(STRING_AFTER, propagated.getAdditionalData(MainStringDataModifier.class.getSimpleName()));
158     }
159 
160     @Test
161     public void testInterpolationAdditionalStringData() {
162         final NumericalPropagator propagator = new NumericalPropagator(integrator);
163         propagator.setInitialState(initialState);
164 
165         final MainStringDataModifier modifier = new MainStringDataModifier();
166         propagator.addAdditionalDataProvider(modifier);
167         EphemerisGenerator generator = propagator.getEphemerisGenerator();
168         propagator.propagate(initDate.shiftedBy(DURATION));
169         BoundedPropagator ephemeris = generator.getGeneratedEphemeris();
170 
171         Assertions.assertEquals(STRING_BEFORE, getAdditionalDataAt(ephemeris, initDate.shiftedBy(DURATION / 2 - 0.1)));
172         Assertions.assertEquals(STRING_AFTER, getAdditionalDataAt(ephemeris, initDate.shiftedBy(DURATION / 2)));
173         Assertions.assertEquals(STRING_AFTER, getAdditionalDataAt(ephemeris, initDate.shiftedBy(DURATION / 2 + 0.1)));
174     }
175 
176     private Object getAdditionalDataAt(Propagator propagator, AbsoluteDate date) {
177         return propagator.propagate(date).getAdditionalData(MainStringDataModifier.class.getSimpleName());
178     }
179 
180     private class MainStringDataModifier implements AdditionalDataProvider<String> {
181 
182         private String value;
183 
184         @Override
185         public void init(SpacecraftState initialState, AbsoluteDate target) {
186             value = target.getDate().isBefore(initDate.shiftedBy(DURATION / 2)) ? STRING_BEFORE : STRING_AFTER;
187         }
188 
189         @Override
190         public String getAdditionalData(SpacecraftState state) {
191             return value;
192         }
193 
194         @Override
195         public String getName() {
196             return MainStringDataModifier.class.getSimpleName();
197         }
198     }
199 
200     private static class MainStateModifier extends AbstractStateModifier {
201         /** {@inheritDoc} */
202         @Override
203         public SpacecraftState change(final SpacecraftState state) {
204             return new SpacecraftState(state.getOrbit(),
205                     new Attitude(state.getDate(),
206                             state.getFrame(),
207                             new Rotation(0, 0, 0, 1, false),
208                             Vector3D.ZERO,
209                             Vector3D.ZERO),
210                     2 * SpacecraftState.DEFAULT_MASS);
211         }
212     }
213 
214     private static class TimeDifferenceProvider implements AdditionalDataProvider<double[]> {
215 
216         private final String  name;
217         private boolean called;
218         private double  dt;
219 
220         public TimeDifferenceProvider(final String name) {
221             this.name   = name;
222             this.called = false;
223             this.dt     = 0.0;
224         }
225 
226         @Override
227         public void init(SpacecraftState initialState, AbsoluteDate target) {
228             this.called = true;
229             this.dt     = target.durationFrom(initialState.getDate());
230         }
231 
232         @Override
233         public String getName() {
234             return name;
235         }
236 
237         @Override
238         public double[] getAdditionalData(SpacecraftState state) {
239             return new double[] {
240                     dt
241             };
242         }
243 
244         public boolean wasCalled() {
245             return called;
246         }
247 
248     }
249 
250 }