1   /* Copyright 2002-2022 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.propagation.events;
18  
19  import java.lang.reflect.Array;
20  
21  import org.hipparchus.CalculusFieldElement;
22  import org.hipparchus.Field;
23  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
24  import org.hipparchus.ode.events.Action;
25  import org.hipparchus.ode.nonstiff.AdaptiveStepsizeFieldIntegrator;
26  import org.hipparchus.ode.nonstiff.DormandPrince853FieldIntegrator;
27  import org.hipparchus.util.Decimal64Field;
28  import org.hipparchus.util.MathArrays;
29  import org.junit.Assert;
30  import org.junit.Before;
31  import org.junit.Test;
32  import org.orekit.Utils;
33  import org.orekit.frames.FramesFactory;
34  import org.orekit.orbits.FieldEquinoctialOrbit;
35  import org.orekit.orbits.FieldOrbit;
36  import org.orekit.orbits.OrbitType;
37  import org.orekit.propagation.FieldSpacecraftState;
38  import org.orekit.propagation.events.handlers.FieldContinueOnEvent;
39  import org.orekit.propagation.events.handlers.FieldEventHandler;
40  import org.orekit.propagation.integration.FieldAdditionalDerivativesProvider;
41  import org.orekit.propagation.numerical.FieldNumericalPropagator;
42  import org.orekit.propagation.sampling.FieldOrekitStepInterpolator;
43  import org.orekit.time.AbsoluteDate;
44  import org.orekit.time.FieldAbsoluteDate;
45  import org.orekit.time.FieldTimeStamped;
46  import org.orekit.time.TimeScalesFactory;
47  import org.orekit.utils.FieldPVCoordinates;
48  
49  public class FieldDateDetectorTest {
50  
51      private int evtno = 0;
52      private double maxCheck;
53      private double threshold;
54      private double dt;
55      private double mu;
56      private AbsoluteDate nodeDate;
57  
58      @Test
59      public void testSimpleTimer() {
60          doTestSimpleTimer(Decimal64Field.getInstance());
61      }
62      @Test
63      public void testEmbeddedTimer() {
64          doTestEmbeddedTimer(Decimal64Field.getInstance());
65      }
66      @Test
67      public void testAutoEmbeddedTimer() {
68          doTestAutoEmbeddedTimer(Decimal64Field.getInstance());
69      }
70      @Test(expected=IllegalArgumentException.class)
71      public void testExceptionTimer() {
72          doTestExceptionTimer(Decimal64Field.getInstance());
73      }
74      @Test
75      public void testGenericHandler() {
76          doTestGenericHandler(Decimal64Field.getInstance());
77      }
78  
79      private <T extends CalculusFieldElement<T>> void doTestSimpleTimer(final Field<T> field) {
80          T zero = field.getZero();
81          final FieldVector3D<T> position  = new FieldVector3D<>(zero.add(-6142438.668), zero.add( 3492467.560), zero.add( -25767.25680));
82          final FieldVector3D<T> velocity  = new FieldVector3D<>(zero.add(505.8479685), zero.add(942.7809215), zero.add(7435.922231));
83          FieldAbsoluteDate<T> iniDate  = new FieldAbsoluteDate<>(field, 1969, 7, 28, 4, 0, 0.0, TimeScalesFactory.getTT());
84          FieldOrbit<T> iniOrbit = new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(position, velocity),
85                                                               FramesFactory.getEME2000(), iniDate, zero.add(mu));
86          FieldSpacecraftState<T> initialState = new FieldSpacecraftState<>(iniOrbit);
87          double[] absTolerance = {
88              0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001
89          };
90          double[] relTolerance = {
91              1.0e-7, 1.0e-4, 1.0e-4, 1.0e-7, 1.0e-7, 1.0e-7, 1.0e-7
92          };
93          AdaptiveStepsizeFieldIntegrator<T> integrator =
94              new DormandPrince853FieldIntegrator<>(field, 0.001, 1000, absTolerance, relTolerance);
95          integrator.setInitialStepSize(60);
96          FieldNumericalPropagator<T> propagator = new FieldNumericalPropagator<>(field, integrator);
97          propagator.addAdditionalDerivativesProvider(new FieldAdditionalDerivativesProvider<T>() {
98              public String getName()                              { return "dummy"; }
99              public int    getDimension()                         { return 1; }
100             public T[]    derivatives(FieldSpacecraftState<T> s) { return MathArrays.buildArray(field, 1); }
101         });
102         propagator.getMultiplexer().add(interpolator -> {
103             FieldSpacecraftState<T> prev = interpolator.getPreviousState();
104             FieldSpacecraftState<T> curr = interpolator.getCurrentState();
105             T dt = curr.getDate().durationFrom(prev.getDate());
106             FieldOrekitStepInterpolator<T> restricted =
107                             interpolator.restrictStep(prev.shiftedBy(dt.multiply(+0.25)),
108                                                       curr.shiftedBy(dt.multiply(-0.25)));
109             FieldSpacecraftState<T> restrictedPrev = restricted.getPreviousState();
110             FieldSpacecraftState<T> restrictedCurr = restricted.getCurrentState();
111             T restrictedDt = restrictedCurr.getDate().durationFrom(restrictedPrev.getDate());
112             Assert.assertEquals(dt.multiply(0.5).getReal(), restrictedDt.getReal(), 1.0e-10);
113         });
114         propagator.setOrbitType(OrbitType.EQUINOCTIAL);
115         propagator.setInitialState(initialState.addAdditionalState("dummy", MathArrays.buildArray(field, 1)));
116 
117         FieldDateDetector<T>  dateDetector = new FieldDateDetector<>(zero.add(maxCheck), zero.add(threshold),
118                                                                      toArray(iniDate.shiftedBy(2.0*dt)));
119         Assert.assertEquals(2 * dt, dateDetector.getDate().durationFrom(iniDate).getReal(), 1.0e-10);
120         propagator.addEventDetector(dateDetector);
121         final FieldSpacecraftState<T> finalState = propagator.propagate(iniDate.shiftedBy(100.*dt));
122 
123         Assert.assertEquals(2.0*dt, finalState.getDate().durationFrom(iniDate).getReal(), threshold);
124     }
125 
126 
127     private <T extends CalculusFieldElement<T>> void doTestEmbeddedTimer(Field<T> field) {
128         T zero = field.getZero();
129         final FieldVector3D<T> position  = new FieldVector3D<>(zero.add(-6142438.668), zero.add( 3492467.560), zero.add( -25767.25680));
130         final FieldVector3D<T> velocity  = new FieldVector3D<>(zero.add(505.8479685), zero.add(942.7809215), zero.add(7435.922231));
131         FieldAbsoluteDate<T> iniDate  = new FieldAbsoluteDate<>(field, 1969, 7, 28, 4, 0, 0.0, TimeScalesFactory.getTT());
132         FieldOrbit<T> iniOrbit = new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(position, velocity),
133                                                              FramesFactory.getEME2000(), iniDate, zero.add(mu));
134         FieldSpacecraftState<T> initialState = new FieldSpacecraftState<>(iniOrbit);
135         double[] absTolerance = {
136             0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001
137         };
138         double[] relTolerance = {
139             1.0e-7, 1.0e-4, 1.0e-4, 1.0e-7, 1.0e-7, 1.0e-7, 1.0e-7
140         };
141         AdaptiveStepsizeFieldIntegrator<T> integrator =
142             new DormandPrince853FieldIntegrator<>(field, 0.001, 1000, absTolerance, relTolerance);
143         integrator.setInitialStepSize(60);
144         FieldNumericalPropagator<T> propagator = new FieldNumericalPropagator<>(field, integrator);
145         propagator.setOrbitType(OrbitType.EQUINOCTIAL);
146         propagator.setInitialState(initialState);
147         @SuppressWarnings("unchecked")
148         FieldDateDetector<T> dateDetector = new FieldDateDetector<>(zero.add(maxCheck), zero.add(threshold),
149                                                                     (FieldTimeStamped<T>[]) Array.newInstance(FieldTimeStamped.class, 0));
150         Assert.assertNull(dateDetector.getDate());
151         FieldEventDetector<T> nodeDetector = new FieldNodeDetector<>(iniOrbit, iniOrbit.getFrame()).
152                 withHandler(new FieldContinueOnEvent<FieldNodeDetector<T>, T>() {
153                     public Action eventOccurred(FieldSpacecraftState<T> s, FieldNodeDetector<T> nd, boolean increasing)
154                         {
155                         if (increasing) {
156                             nodeDate = s.getDate().toAbsoluteDate();
157                             dateDetector.addEventDate(s.getDate().shiftedBy(dt));
158                         }
159                         return Action.CONTINUE;
160                     }
161                 });
162 
163         propagator.addEventDetector(nodeDetector);
164         propagator.addEventDetector(dateDetector);
165         final FieldSpacecraftState<T> finalState = propagator.propagate(iniDate.shiftedBy(100.*dt));
166 
167         Assert.assertEquals(dt, finalState.getDate().durationFrom(nodeDate).getReal(), threshold);
168     }
169 
170 
171     private <T extends CalculusFieldElement<T>> void doTestAutoEmbeddedTimer(Field<T> field) {
172         T zero = field.getZero();
173         final FieldVector3D<T> position  = new FieldVector3D<>(zero.add(-6142438.668), zero.add( 3492467.560), zero.add( -25767.25680));
174         final FieldVector3D<T> velocity  = new FieldVector3D<>(zero.add(505.8479685), zero.add(942.7809215), zero.add(7435.922231));
175         FieldAbsoluteDate<T> iniDate  = new FieldAbsoluteDate<>(field, 1969, 7, 28, 4, 0, 0.0, TimeScalesFactory.getTT());
176         FieldOrbit<T> iniOrbit = new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(position, velocity),
177                                                              FramesFactory.getEME2000(), iniDate, zero.add(mu));
178         FieldSpacecraftState<T> initialState = new FieldSpacecraftState<>(iniOrbit);
179         double[] absTolerance = {
180             0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001
181         };
182         double[] relTolerance = {
183             1.0e-7, 1.0e-4, 1.0e-4, 1.0e-7, 1.0e-7, 1.0e-7, 1.0e-7
184         };
185         AdaptiveStepsizeFieldIntegrator<T> integrator =
186             new DormandPrince853FieldIntegrator<>(field, 0.001, 1000, absTolerance, relTolerance);
187         integrator.setInitialStepSize(60);
188         FieldNumericalPropagator<T> propagator = new FieldNumericalPropagator<>(field, integrator);
189         propagator.setOrbitType(OrbitType.EQUINOCTIAL);
190         propagator.setInitialState(initialState);
191 
192         FieldDateDetector<T> dateDetector = new FieldDateDetector<>(zero.add(maxCheck), zero.add(threshold),
193                                                                     toArray(iniDate.shiftedBy(-dt))).
194                 withHandler(new FieldContinueOnEvent<FieldDateDetector<T>, T >() {
195                     public Action eventOccurred(FieldSpacecraftState<T> s, FieldDateDetector<T>  dd,  boolean increasing)
196                             {
197                         FieldAbsoluteDate<T> nextDate = s.getDate().shiftedBy(-dt);
198                         dd.addEventDate(nextDate);
199                         ++evtno;
200                         return Action.CONTINUE;
201                     }
202                 });
203         propagator.addEventDetector(dateDetector);
204         propagator.propagate(iniDate.shiftedBy(-100.*dt));
205 
206         Assert.assertEquals(100, evtno);
207     }
208 
209     private <T extends CalculusFieldElement<T>> void doTestExceptionTimer(Field<T> field) {
210         T zero = field.getZero();
211         final FieldVector3D<T> position  = new FieldVector3D<>(zero.add(-6142438.668), zero.add( 3492467.560), zero.add( -25767.25680));
212         final FieldVector3D<T> velocity  = new FieldVector3D<>(zero.add(505.8479685), zero.add(942.7809215), zero.add(7435.922231));
213         FieldAbsoluteDate<T> iniDate  = new FieldAbsoluteDate<>(field, 1969, 7, 28, 4, 0, 0.0, TimeScalesFactory.getTT());
214         FieldOrbit<T> iniOrbit = new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(position, velocity),
215                                                              FramesFactory.getEME2000(), iniDate, zero.add(mu));
216         FieldSpacecraftState<T> initialState = new FieldSpacecraftState<>(iniOrbit);
217         double[] absTolerance = {
218             0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001
219         };
220         double[] relTolerance = {
221             1.0e-7, 1.0e-4, 1.0e-4, 1.0e-7, 1.0e-7, 1.0e-7, 1.0e-7
222         };
223         AdaptiveStepsizeFieldIntegrator<T> integrator =
224             new DormandPrince853FieldIntegrator<>(field, 0.001, 1000, absTolerance, relTolerance);
225         integrator.setInitialStepSize(60);
226         FieldNumericalPropagator<T> propagator = new FieldNumericalPropagator<>(field, integrator);
227         propagator.setOrbitType(OrbitType.EQUINOCTIAL);
228         propagator.setInitialState(initialState);
229 
230         FieldDateDetector<T> dateDetector = new FieldDateDetector<>(zero.add(maxCheck), zero.add(threshold),
231                                                                     toArray(iniDate.shiftedBy(dt))).
232                 withHandler(new FieldContinueOnEvent<FieldDateDetector<T>, T >() {
233                     public Action eventOccurred(FieldSpacecraftState<T> s, FieldDateDetector<T>  dd, boolean increasing)
234                         {
235                         double step = (evtno % 2 == 0) ? 2.*maxCheck : maxCheck/2.;
236                         FieldAbsoluteDate<T> nextDate = s.getDate().shiftedBy(step);
237                         dd.addEventDate(nextDate);
238                         ++evtno;
239                         return Action.CONTINUE;
240                     }
241                 });
242         propagator.addEventDetector(dateDetector);
243         propagator.propagate(iniDate.shiftedBy(100.*dt));
244     }
245 
246     /**
247      * Check that a generic event handler can be used with an event detector.
248      */
249 
250     private <T extends CalculusFieldElement<T>> void doTestGenericHandler(Field<T> field) {
251         T zero = field.getZero();
252         final FieldVector3D<T> position  = new FieldVector3D<>(zero.add(-6142438.668), zero.add( 3492467.560), zero.add( -25767.25680));
253         final FieldVector3D<T> velocity  = new FieldVector3D<>(zero.add(505.8479685), zero.add(942.7809215), zero.add(7435.922231));
254         FieldAbsoluteDate<T> iniDate  = new FieldAbsoluteDate<>(field, 1969, 7, 28, 4, 0, 0.0, TimeScalesFactory.getTT());
255         FieldOrbit<T> iniOrbit = new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(position, velocity),
256                                                              FramesFactory.getEME2000(), iniDate, zero.add(mu));
257         FieldSpacecraftState<T> initialState = new FieldSpacecraftState<>(iniOrbit);
258         double[] absTolerance = {
259             0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001
260         };
261         double[] relTolerance = {
262             1.0e-7, 1.0e-4, 1.0e-4, 1.0e-7, 1.0e-7, 1.0e-7, 1.0e-7
263         };
264         AdaptiveStepsizeFieldIntegrator<T> integrator =
265             new DormandPrince853FieldIntegrator<>(field, 0.001, 1000, absTolerance, relTolerance);
266         integrator.setInitialStepSize(60);
267         FieldNumericalPropagator<T> propagator = new FieldNumericalPropagator<>(field, integrator);
268         propagator.setOrbitType(OrbitType.EQUINOCTIAL);
269         propagator.setInitialState(initialState);
270 
271         //setup
272         final FieldDateDetector<T> dateDetector = new FieldDateDetector<>(zero.add(maxCheck), zero.add(threshold),
273                                                                           toArray(iniDate.shiftedBy(dt)));
274         // generic event handler that works with all detectors.
275         FieldEventHandler<FieldEventDetector<T>, T> handler = new FieldEventHandler<FieldEventDetector<T>, T>() {
276             @Override
277             public Action eventOccurred(FieldSpacecraftState<T> s,
278                                         FieldEventDetector<T> detector,
279                                         boolean increasing)
280                     {
281                 return Action.STOP;
282             }
283 
284             @Override
285             public FieldSpacecraftState<T> resetState(FieldEventDetector<T> detector,
286                                               FieldSpacecraftState<T> oldState)
287                     {
288                 throw new RuntimeException("Should not be called");
289             }
290         };
291 
292         //action
293         final FieldDateDetector<T> dateDetector2;
294 
295         dateDetector2 = dateDetector.withHandler(handler);
296 
297         propagator.addEventDetector(dateDetector2);
298         FieldSpacecraftState<T> finalState = propagator.propagate(iniDate.shiftedBy(100 * dt));
299 
300         //verify
301         Assert.assertEquals(dt, finalState.getDate().durationFrom(iniDate).getReal(), threshold);
302     }
303 
304     private <T extends CalculusFieldElement<T>> FieldTimeStamped<T>[] toArray(final FieldAbsoluteDate<T> date) {
305         @SuppressWarnings("unchecked")
306         final FieldTimeStamped<T>[] array = (FieldTimeStamped<T>[]) Array.newInstance(FieldTimeStamped.class, 1);
307         array[0] = date;
308         return array;
309     }
310 
311     @Before
312     public void setUp() {
313             Utils.setDataRoot("regular-data");
314             mu = 3.9860047e14;
315             dt = 60.;
316             maxCheck  = 10.;
317             threshold = 10.e-7;
318             evtno = 0;
319     }
320 
321 }