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.analytical;
18  
19  
20  import org.hipparchus.CalculusFieldElement;
21  import org.hipparchus.Field;
22  import org.hipparchus.complex.Complex;
23  import org.hipparchus.complex.ComplexField;
24  import org.hipparchus.geometry.euclidean.threed.Rotation;
25  import org.hipparchus.ode.events.Action;
26  import org.junit.jupiter.api.Assertions;
27  import org.junit.jupiter.api.Test;
28  import org.junit.jupiter.params.ParameterizedTest;
29  import org.junit.jupiter.params.provider.EnumSource;
30  import org.orekit.TestUtils;
31  import org.orekit.attitudes.FrameAlignedProvider;
32  import org.orekit.frames.Frame;
33  import org.orekit.frames.FramesFactory;
34  import org.orekit.orbits.*;
35  import org.orekit.propagation.FieldAdditionalDataProvider;
36  import org.orekit.propagation.FieldSpacecraftState;
37  import org.orekit.propagation.events.EventDetectionSettings;
38  import org.orekit.propagation.events.FieldDateDetector;
39  import org.orekit.propagation.events.FieldEventDetectionSettings;
40  import org.orekit.propagation.events.FieldEventDetector;
41  import org.orekit.propagation.events.handlers.FieldContinueOnEvent;
42  import org.orekit.propagation.events.handlers.FieldEventHandler;
43  import org.orekit.propagation.events.handlers.FieldStopOnEvent;
44  import org.orekit.time.AbsoluteDate;
45  import org.orekit.time.FieldAbsoluteDate;
46  import org.orekit.utils.Constants;
47  import org.orekit.utils.ParameterDriver;
48  
49  import java.util.Collections;
50  import java.util.List;
51  import java.util.stream.Stream;
52  
53  class FieldAbstractAnalyticalPropagatorTest {
54  
55      @Test
56      void testRemoveAdditionalDataProvider() {
57          // GIVEN
58          final AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH;
59          final Orbit orbit = TestUtils.getDefaultOrbit(date);
60          final TestAnalyticalPropagator propagator = new TestAnalyticalPropagator(orbit);
61          final String name = "a";
62          final FieldAdditionalDataProvider<Boolean, Complex> dataProvider = new FieldAdditionalDataProvider<Boolean, Complex>() {
63              @Override
64              public String getName() {
65                  return name;
66              }
67  
68              @Override
69              public Boolean getAdditionalData(FieldSpacecraftState<Complex> state) {
70                  return Boolean.TRUE;
71              }
72          };
73          // WHEN & THEN
74          propagator.addAdditionalDataProvider(dataProvider);
75          Assertions.assertFalse(propagator.getAdditionalDataProviders().isEmpty());
76          propagator.removeAdditionalDataProvider(dataProvider.getName());
77          Assertions.assertTrue(propagator.getAdditionalDataProviders().isEmpty());
78      }
79  
80      @ParameterizedTest
81      @EnumSource(value = Action.class, names = {"RESET_STATE", "RESET_DERIVATIVES"})
82      void testReset(final Action action) {
83          // GIVEN
84          final FieldAbsoluteDate<Complex> date = FieldAbsoluteDate.getArbitraryEpoch(ComplexField.getInstance());
85          final Orbit orbit = TestUtils.getDefaultOrbit(date.toAbsoluteDate());
86          final TestAnalyticalPropagator propagator = new TestAnalyticalPropagator(orbit);
87          final FieldEventHandler<Complex> handler = (s, detector, increasing) -> action;
88          final TestDetector detector = new TestDetector(date.shiftedBy(0.5), handler);
89          propagator.addEventDetector(detector);
90          // WHEN
91          propagator.propagate(propagator.getInitialState().getDate().shiftedBy(1.));
92          // THEN
93          Assertions.assertTrue(detector.resetted);
94      }
95  
96      private static class TestDetector extends FieldDateDetector<Complex> {
97          boolean resetted = false;
98  
99          TestDetector(final FieldAbsoluteDate<Complex> date, final FieldEventHandler<Complex> handler) {
100             super(new FieldEventDetectionSettings<>(date.getField(), EventDetectionSettings.getDefaultEventDetectionSettings()),
101                     handler, 1., date);
102         }
103 
104         @Override
105         public void reset(FieldSpacecraftState<Complex> state, FieldAbsoluteDate<Complex> target) {
106             resetted = true;
107         }
108     }
109 
110     @Test
111     void testInternalEventDetectors() {
112         // GIVEN
113         final Frame eme2000 = FramesFactory.getEME2000();
114         final AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH;
115         final Orbit orbit = new KeplerianOrbit(8000000.0, 0.01, 0.87, 2.44, 0.21, -1.05, PositionAngleType.MEAN,
116                 eme2000, date, Constants.EIGEN5C_EARTH_MU);
117         final TestAnalyticalPropagator propagator = new TestAnalyticalPropagator(orbit);
118         final FieldAbsoluteDate<Complex> interruptingDate = propagator.getInitialState().getDate().shiftedBy(1);
119         propagator.setAttitudeProvider(new InterruptingAttitudeProvider(interruptingDate.toAbsoluteDate()));
120         // WHEN
121         final FieldSpacecraftState<Complex> state = propagator.propagate(propagator.getInitialState().getDate().shiftedBy(10.));
122         // THEN
123         Assertions.assertEquals(state.getDate(), interruptingDate);
124     }
125 
126     @Test
127     void testFinish() {
128         // GIVEN
129         final Frame eme2000 = FramesFactory.getEME2000();
130         final AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH;
131         final Orbit orbit = new KeplerianOrbit(8000000.0, 0.01, 0.87, 2.44, 0.21, -1.05, PositionAngleType.MEAN,
132                 eme2000, date, Constants.EIGEN5C_EARTH_MU);
133         final TestAnalyticalPropagator propagator = new TestAnalyticalPropagator(orbit);
134         final TestHandler handler = new TestHandler();
135         final ComplexField field = ComplexField.getInstance();
136         propagator.addEventDetector(new FieldDateDetector<>(field, FieldAbsoluteDate.getArbitraryEpoch(field)).withHandler(handler));
137         // WHEN
138         propagator.propagate(propagator.getInitialState().getDate().shiftedBy(1.));
139         // THEN
140         Assertions.assertTrue(handler.isFinished);
141     }
142 
143     private static class TestAnalyticalPropagator extends FieldAbstractAnalyticalPropagator<Complex> {
144 
145         protected TestAnalyticalPropagator(Orbit orbit) {
146             super(ComplexField.getInstance(), new FrameAlignedProvider(FramesFactory.getGCRF()));
147             resetInitialState(new FieldSpacecraftState<>(new FieldCartesianOrbit<>(getField(), orbit)));
148         }
149 
150         @Override
151         protected Complex getMass(FieldAbsoluteDate<Complex> date) {
152             return Complex.ONE;
153         }
154 
155         @Override
156         protected void resetIntermediateState(FieldSpacecraftState<Complex> state, boolean forward) {
157 
158         }
159 
160         @Override
161         public FieldOrbit<Complex> propagateOrbit(
162                         FieldAbsoluteDate<Complex> date, Complex[] parameters) {
163             final FieldSpacecraftState<Complex> state = getInitialState();
164             return new FieldCartesianOrbit<>(state.getOrbit().getPVCoordinates(), getFrame(), date, state.getOrbit().getMu());
165         }
166 
167         @Override
168         public List<ParameterDriver> getParametersDrivers() {
169             return Collections.emptyList();
170         }
171     }
172 
173     private static class TestHandler extends FieldContinueOnEvent<Complex> {
174         boolean isFinished = false;
175 
176         @Override
177         public void finish(FieldSpacecraftState<Complex> finalState, FieldEventDetector<Complex> detector) {
178             isFinished = true;
179         }
180     }
181 
182     private static class InterruptingAttitudeProvider extends FrameAlignedProvider {
183 
184         private final AbsoluteDate interruptingDate;
185 
186         public InterruptingAttitudeProvider(final AbsoluteDate interruptingDate) {
187             super(Rotation.IDENTITY);
188             this.interruptingDate = interruptingDate;
189         }
190 
191         @Override
192         public <T extends CalculusFieldElement<T>> Stream<FieldEventDetector<T>> getFieldEventDetectors(Field<T> field) {
193             final FieldDateDetector<T> detector = new FieldDateDetector<>(new FieldAbsoluteDate<>(field, interruptingDate))
194                     .withHandler(new FieldStopOnEvent<>());
195             return Stream.of(detector);
196         }
197     }
198 }