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.FieldSpacecraftState;
36  import org.orekit.propagation.events.EventDetectionSettings;
37  import org.orekit.propagation.events.FieldDateDetector;
38  import org.orekit.propagation.events.FieldEventDetectionSettings;
39  import org.orekit.propagation.events.FieldEventDetector;
40  import org.orekit.propagation.events.handlers.FieldContinueOnEvent;
41  import org.orekit.propagation.events.handlers.FieldEventHandler;
42  import org.orekit.propagation.events.handlers.FieldStopOnEvent;
43  import org.orekit.time.AbsoluteDate;
44  import org.orekit.time.FieldAbsoluteDate;
45  import org.orekit.utils.Constants;
46  import org.orekit.utils.ParameterDriver;
47  
48  import java.util.Collections;
49  import java.util.List;
50  import java.util.stream.Stream;
51  
52  class FieldAbstractAnalyticalPropagatorTest {
53  
54      @ParameterizedTest
55      @EnumSource(value = Action.class, names = {"RESET_STATE", "RESET_DERIVATIVES"})
56      void testReset(final Action action) {
57          // GIVEN
58          final FieldAbsoluteDate<Complex> date = FieldAbsoluteDate.getArbitraryEpoch(ComplexField.getInstance());
59          final Orbit orbit = TestUtils.getDefaultOrbit(date.toAbsoluteDate());
60          final TestAnalyticalPropagator propagator = new TestAnalyticalPropagator(orbit);
61          final FieldEventHandler<Complex> handler = (s, detector, increasing) -> action;
62          final TestDetector detector = new TestDetector(date.shiftedBy(0.5), handler);
63          propagator.addEventDetector(detector);
64          // WHEN
65          propagator.propagate(propagator.getInitialState().getDate().shiftedBy(1.));
66          // THEN
67          Assertions.assertTrue(detector.resetted);
68      }
69  
70      private static class TestDetector extends FieldDateDetector<Complex> {
71          boolean resetted = false;
72  
73          TestDetector(final FieldAbsoluteDate<Complex> date, final FieldEventHandler<Complex> handler) {
74              super(new FieldEventDetectionSettings<>(date.getField(), EventDetectionSettings.getDefaultEventDetectionSettings()),
75                      handler, 1., date);
76          }
77  
78          @Override
79          public void reset(FieldSpacecraftState<Complex> state, FieldAbsoluteDate<Complex> target) {
80              resetted = true;
81          }
82      }
83  
84      @Test
85      void testInternalEventDetectors() {
86          // GIVEN
87          final Frame eme2000 = FramesFactory.getEME2000();
88          final AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH;
89          final Orbit orbit = new KeplerianOrbit(8000000.0, 0.01, 0.87, 2.44, 0.21, -1.05, PositionAngleType.MEAN,
90                  eme2000, date, Constants.EIGEN5C_EARTH_MU);
91          final TestAnalyticalPropagator propagator = new TestAnalyticalPropagator(orbit);
92          final FieldAbsoluteDate<Complex> interruptingDate = propagator.getInitialState().getDate().shiftedBy(1);
93          propagator.setAttitudeProvider(new InterruptingAttitudeProvider(interruptingDate.toAbsoluteDate()));
94          // WHEN
95          final FieldSpacecraftState<Complex> state = propagator.propagate(propagator.getInitialState().getDate().shiftedBy(10.));
96          // THEN
97          Assertions.assertEquals(state.getDate(), interruptingDate);
98      }
99  
100     @Test
101     void testFinish() {
102         // GIVEN
103         final Frame eme2000 = FramesFactory.getEME2000();
104         final AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH;
105         final Orbit orbit = new KeplerianOrbit(8000000.0, 0.01, 0.87, 2.44, 0.21, -1.05, PositionAngleType.MEAN,
106                 eme2000, date, Constants.EIGEN5C_EARTH_MU);
107         final TestAnalyticalPropagator propagator = new TestAnalyticalPropagator(orbit);
108         final TestHandler handler = new TestHandler();
109         final ComplexField field = ComplexField.getInstance();
110         propagator.addEventDetector(new FieldDateDetector<>(field, FieldAbsoluteDate.getArbitraryEpoch(field)).withHandler(handler));
111         // WHEN
112         propagator.propagate(propagator.getInitialState().getDate().shiftedBy(1.));
113         // THEN
114         Assertions.assertTrue(handler.isFinished);
115     }
116 
117     private static class TestAnalyticalPropagator extends FieldAbstractAnalyticalPropagator<Complex> {
118 
119         protected TestAnalyticalPropagator(Orbit orbit) {
120             super(ComplexField.getInstance(), new FrameAlignedProvider(FramesFactory.getGCRF()));
121             resetInitialState(new FieldSpacecraftState<>(new FieldCartesianOrbit<>(getField(), orbit)));
122         }
123 
124         @Override
125         protected Complex getMass(FieldAbsoluteDate<Complex> date) {
126             return Complex.ONE;
127         }
128 
129         @Override
130         protected void resetIntermediateState(FieldSpacecraftState<Complex> state, boolean forward) {
131 
132         }
133 
134         @Override
135         public FieldOrbit<Complex> propagateOrbit(
136                         FieldAbsoluteDate<Complex> date, Complex[] parameters) {
137             final FieldSpacecraftState<Complex> state = getInitialState();
138             return new FieldCartesianOrbit<>(state.getOrbit().getPVCoordinates(), getFrame(), date, state.getOrbit().getMu());
139         }
140 
141         @Override
142         public List<ParameterDriver> getParametersDrivers() {
143             return Collections.emptyList();
144         }
145     }
146 
147     private static class TestHandler extends FieldContinueOnEvent<Complex> {
148         boolean isFinished = false;
149 
150         @Override
151         public void finish(FieldSpacecraftState<Complex> finalState, FieldEventDetector<Complex> detector) {
152             isFinished = true;
153         }
154     }
155 
156     private static class InterruptingAttitudeProvider extends FrameAlignedProvider {
157 
158         private final AbsoluteDate interruptingDate;
159 
160         public InterruptingAttitudeProvider(final AbsoluteDate interruptingDate) {
161             super(Rotation.IDENTITY);
162             this.interruptingDate = interruptingDate;
163         }
164 
165         @Override
166         public <T extends CalculusFieldElement<T>> Stream<FieldEventDetector<T>> getFieldEventDetectors(Field<T> field) {
167             final FieldDateDetector<T> detector = new FieldDateDetector<>(new FieldAbsoluteDate<>(field, interruptingDate))
168                     .withHandler(new FieldStopOnEvent<>());
169             return Stream.of(detector);
170         }
171     }
172 }