1   /* Copyright 2022-2025 Romain Serra
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.integration;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.Field;
21  import org.hipparchus.complex.Complex;
22  import org.hipparchus.complex.ComplexField;
23  import org.hipparchus.ode.FieldODEIntegrator;
24  import org.hipparchus.ode.nonstiff.ClassicalRungeKuttaFieldIntegrator;
25  import org.hipparchus.util.Binary64;
26  import org.hipparchus.util.Binary64Field;
27  import org.junit.jupiter.api.Assertions;
28  import org.junit.jupiter.api.Test;
29  import org.mockito.Mockito;
30  import org.orekit.TestUtils;
31  import org.orekit.attitudes.AttitudeProvider;
32  import org.orekit.frames.Frame;
33  import org.orekit.frames.FramesFactory;
34  import org.orekit.orbits.EquinoctialOrbit;
35  import org.orekit.orbits.FieldCartesianOrbit;
36  import org.orekit.orbits.FieldEquinoctialOrbit;
37  import org.orekit.orbits.FieldOrbit;
38  import org.orekit.orbits.Orbit;
39  import org.orekit.orbits.OrbitType;
40  import org.orekit.orbits.PositionAngleType;
41  import org.orekit.propagation.FieldSpacecraftState;
42  import org.orekit.propagation.PropagationType;
43  import org.orekit.propagation.events.EventDetectionSettings;
44  import org.orekit.propagation.events.FieldDateDetector;
45  import org.orekit.propagation.events.FieldEventDetectionSettings;
46  import org.orekit.propagation.events.handlers.FieldEventHandler;
47  import org.orekit.propagation.events.handlers.FieldResetDerivativesOnEvent;
48  import org.orekit.propagation.numerical.FieldNumericalPropagator;
49  import org.orekit.time.AbsoluteDate;
50  import org.orekit.time.FieldAbsoluteDate;
51  import org.orekit.utils.Constants;
52  
53  class FieldAbstractIntegratedPropagatorTest {
54  
55      @Test
56      void testIntegrateWithResetDerivativesAndEvents() {
57          // GIVEN
58          final Orbit initialOrbit = TestUtils.getDefaultOrbit(AbsoluteDate.ARBITRARY_EPOCH);
59          final Binary64Field field = Binary64Field.getInstance();
60          final FieldOrbit<Binary64> fieldOrbit = new FieldCartesianOrbit<>(Binary64Field.getInstance(), initialOrbit);
61          final FieldNumericalPropagator<Binary64> propagator = new FieldNumericalPropagator<>(field,
62                  new ClassicalRungeKuttaFieldIntegrator<>(field,
63                  fieldOrbit.getDate().getField().getZero().newInstance(100.)));
64          propagator.setInitialState(new FieldSpacecraftState<>(fieldOrbit));
65          final TestDetector detector = new TestDetector(fieldOrbit.getDate().shiftedBy(10.));
66          propagator.addEventDetector(detector);
67          // WHEN
68          propagator.propagate(fieldOrbit.getDate().shiftedBy(100));
69          // THEN
70          Assertions.assertTrue(detector.resetted);
71      }
72  
73      private static class TestDetector extends FieldDateDetector<Binary64> {
74          boolean resetted = false;
75  
76          public TestDetector(FieldAbsoluteDate<Binary64> fieldAbsoluteDate) {
77              super(fieldAbsoluteDate);
78          }
79  
80          @Override
81          public void reset(FieldSpacecraftState<Binary64> state, FieldAbsoluteDate<Binary64> target) {
82              super.reset(state, target);
83              resetted = true;
84          }
85  
86          @Override
87          public FieldEventHandler<Binary64> getHandler() {
88              return new FieldResetDerivativesOnEvent<>();
89          }
90  
91          @Override
92          public FieldEventDetectionSettings<Binary64> getDetectionSettings() {
93              return new FieldEventDetectionSettings<>(Binary64Field.getInstance(),
94                      EventDetectionSettings.getDefaultEventDetectionSettings());
95          }
96      }
97  
98      @Test
99      void testGetResetAtEndTrue() {
100         testGetResetAtEnd(true);
101     }
102 
103     @Test
104     void testGetResetAtEndFalse() {
105         testGetResetAtEnd(false);
106     }
107 
108     void testGetResetAtEnd(final boolean expectedResetAtEnd) {
109         // GIVEN
110         final TestFieldAbstractIntegratedPropagator testAbstractIntegratedPropagator = new TestFieldAbstractIntegratedPropagator();
111         // WHEN
112         testAbstractIntegratedPropagator.setResetAtEnd(expectedResetAtEnd);
113         // THEN
114         final boolean actualResetAtEnd = testAbstractIntegratedPropagator.getResetAtEnd();
115         Assertions.assertEquals(expectedResetAtEnd, actualResetAtEnd);
116     }
117     
118     /** Test issue 1461.
119      * <p>Test for the new generic method AbstractIntegratedPropagator.reset(SpacecraftState, PropagationType)
120      */
121     @Test
122     void testIssue1461() {
123         doTestIssue1461(Binary64Field.getInstance());
124     }
125     
126     /** Method for running test for issue 1461. */
127     private <T extends CalculusFieldElement<T>> void doTestIssue1461(Field<T> field) {
128         // GIVEN
129         
130         final T zero = field.getZero();
131         // GEO orbit
132         final FieldOrbit<T> startOrbit = new FieldEquinoctialOrbit<>(field,
133                         new EquinoctialOrbit(42165765.0, 0.0, 0.0, 0.0, 0.0, 0.0, PositionAngleType.TRUE,
134                                              FramesFactory.getEME2000(), AbsoluteDate.J2000_EPOCH,
135                                              Constants.IERS2010_EARTH_MU));
136 
137         // Init numerical propagator
138         final FieldSpacecraftState<T> state = new FieldSpacecraftState<>(startOrbit);
139         final FieldNumericalPropagator<T> propagator = new FieldNumericalPropagator<>(field,
140                         new ClassicalRungeKuttaFieldIntegrator<T>(field, zero.newInstance(300.)));
141         propagator.setInitialState(state);
142 
143         // WHEN
144         propagator.resetInitialState(state, PropagationType.OSCULATING);
145         final FieldSpacecraftState<T> oscState = propagator.getInitialState();
146         
147         propagator.resetInitialState(state, PropagationType.MEAN);
148         final FieldSpacecraftState<T> meanState = propagator.getInitialState();
149 
150         // THEN
151         
152         // Check that all three states are identical
153         final double dpOsc = oscState.getPosition().distance(state.getPosition()).getReal();
154         final double dvOsc = oscState.getPVCoordinates().getVelocity().distance(state.getPVCoordinates().getVelocity()).getReal();
155         
156         final double dpMean = meanState.getPosition().distance(state.getPosition()).getReal();
157         final double dvMean = meanState.getPVCoordinates().getVelocity().distance(state.getPVCoordinates().getVelocity()).getReal();
158         
159         Assertions.assertEquals(0., dpOsc, 0.);
160         Assertions.assertEquals(0., dvOsc, 0.);
161         Assertions.assertEquals(0., dpMean, 0.);
162         Assertions.assertEquals(0., dvMean, 0.);
163     }
164 
165     private static class TestFieldAbstractIntegratedPropagator extends FieldAbstractIntegratedPropagator<Complex> {
166 
167         @SuppressWarnings("unchecked")
168         protected TestFieldAbstractIntegratedPropagator() {
169             super(ComplexField.getInstance(), Mockito.mock(FieldODEIntegrator.class), PropagationType.OSCULATING);
170         }
171 
172         @Override
173         protected FieldStateMapper<Complex> createMapper(FieldAbsoluteDate<Complex> referenceDate, Complex mu,
174                                                          OrbitType orbitType, PositionAngleType positionAngleType,
175                                                          AttitudeProvider attitudeProvider, Frame frame) {
176             return null;
177         }
178 
179         @Override
180         protected MainStateEquations<Complex> getMainStateEquations(FieldODEIntegrator<Complex> integ) {
181             return null;
182         }
183     }
184 
185 }