1   /* Copyright 2002-2025 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 org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.Field;
21  import org.hipparchus.util.Binary64;
22  import org.hipparchus.util.Binary64Field;
23  import org.hipparchus.util.FastMath;
24  import org.junit.jupiter.api.Assertions;
25  import org.junit.jupiter.api.BeforeEach;
26  import org.junit.jupiter.api.Test;
27  import org.orekit.Utils;
28  import org.orekit.frames.Frame;
29  import org.orekit.frames.FramesFactory;
30  import org.orekit.orbits.FieldKeplerianOrbit;
31  import org.orekit.orbits.PositionAngleType;
32  import org.orekit.propagation.FieldBoundedPropagator;
33  import org.orekit.propagation.FieldEphemerisGenerator;
34  import org.orekit.propagation.FieldSpacecraftState;
35  import org.orekit.propagation.analytical.FieldKeplerianPropagator;
36  import org.orekit.propagation.events.handlers.FieldContinueOnEvent;
37  import org.orekit.propagation.events.handlers.FieldCountAndContinue;
38  import org.orekit.time.FieldAbsoluteDate;
39  import org.orekit.time.TimeScalesFactory;
40  import org.orekit.utils.Constants;
41  
42  public class FieldNodeDetectorTest {
43  
44      @Test
45      public void testIssue138() {
46          doTestIssue138(Binary64Field.getInstance());
47      }
48  
49      @Test
50      public void testIssue158() {
51          doTestIssue158(Binary64Field.getInstance());
52      }
53  
54      private <T extends CalculusFieldElement<T>>void doTestIssue138(Field<T> field) {
55          T zero = field.getZero();
56          T a = zero.add(800000 + Constants.WGS84_EARTH_EQUATORIAL_RADIUS);
57          T e = zero.add(0.0001);
58          T i = zero.add(FastMath.toRadians(98));
59          T w = zero.add(-90);
60          T raan = zero;
61          T v = zero;
62          Frame inertialFrame = FramesFactory.getEME2000();
63          FieldAbsoluteDate<T> initialDate = new FieldAbsoluteDate<>(field, 2014, 01, 01, 0, 0, 0, TimeScalesFactory.getUTC());
64          FieldAbsoluteDate<T> finalDate = initialDate.shiftedBy(5000);
65          FieldKeplerianOrbit<T> initialOrbit = new FieldKeplerianOrbit<>(a, e, i, w, raan, v, PositionAngleType.TRUE, inertialFrame, initialDate, zero.add(Constants.WGS84_EARTH_MU));
66          FieldSpacecraftState<T> initialState = new FieldSpacecraftState<>(initialOrbit).withMass(zero.add(1000));
67          FieldKeplerianPropagator<T> propagator = new FieldKeplerianPropagator<>(initialOrbit);
68  
69          // Define 2 instances of NodeDetector:
70          FieldEventDetector<T> rawDetector =
71                  new FieldNodeDetector<>(zero.add(1e-6), initialState.getOrbit(), initialState.getFrame()).
72                  withHandler(new FieldContinueOnEvent<>());
73  
74          FieldEventsLogger<T> logger1 = new FieldEventsLogger<>();
75          FieldEventDetector<T> node1 = logger1.monitorDetector(rawDetector);
76          FieldEventsLogger<T> logger2 = new FieldEventsLogger<>();
77          FieldEventDetector<T> node2 = logger2.monitorDetector(rawDetector);
78  
79          propagator.addEventDetector(node1);
80          propagator.addEventDetector(node2);
81  
82          // First propagation
83          final FieldEphemerisGenerator<T> generator = propagator.getEphemerisGenerator();
84          propagator.propagate(finalDate);
85          Assertions.assertEquals(2, logger1.getLoggedEvents().size());
86          Assertions.assertEquals(2, logger2.getLoggedEvents().size());
87          logger1.clearLoggedEvents();
88          logger2.clearLoggedEvents();
89          FieldBoundedPropagator<T> postpro = generator.getGeneratedEphemeris();
90  
91          // Post-processing
92          postpro.addEventDetector(node1);
93          postpro.addEventDetector(node2);
94          postpro.propagate(finalDate);
95          Assertions.assertEquals(2, logger1.getLoggedEvents().size());
96          Assertions.assertEquals(2, logger2.getLoggedEvents().size());
97  
98      }
99  
100     @Test
101     void testIssue642() {
102         // GIVEN
103         final Frame frame = FramesFactory.getEME2000();
104         final Binary64Field field = Binary64Field.getInstance();
105         final FieldNodeDetector<Binary64> fieldNodeDetector = new FieldNodeDetector<>(field, frame);
106         final FieldKeplerianOrbit<Binary64> fieldOrbit = new FieldKeplerianOrbit<>(new Binary64(-1e7),
107                 new Binary64(1.2), Binary64.ONE, Binary64.ZERO, Binary64.ZERO, Binary64.ONE.negate(), PositionAngleType.MEAN,
108                 frame, FieldAbsoluteDate.getArbitraryEpoch(field), new Binary64(Constants.WGS84_EARTH_MU));
109         final FieldKeplerianPropagator<Binary64> propagator = new FieldKeplerianPropagator<>(fieldOrbit);
110         final FieldCountAndContinue<Binary64> countAndContinue = new FieldCountAndContinue<>(0);
111         propagator.addEventDetector(fieldNodeDetector.withHandler(countAndContinue));
112         // WHEN
113         propagator.propagate(fieldOrbit.getDate().shiftedBy(1e6));
114         // THEN
115         Assertions.assertNotEquals(0, countAndContinue.getCount());
116     }
117 
118     private <T extends CalculusFieldElement<T>>void doTestIssue158(Field<T> field) {
119         T zero = field.getZero();
120         FieldAbsoluteDate<T> date = new FieldAbsoluteDate<>(field);
121 
122         T a          = zero.add(3.0e7);
123         T e1         = zero.add( 0.8);
124         T e2         = zero.add( 1.0e-4);
125         T i          = zero.add(1.0);
126         T pa         = zero.add(1.5 * FastMath.PI);
127         T raan       = zero.add(5.0);
128         T m          = zero.add(0);
129         Frame frame       = FramesFactory.getEME2000();
130         double mu         = Constants.EIGEN5C_EARTH_MU;
131 
132         // highly eccentric, inclined orbit
133         final FieldKeplerianOrbit<T> orbit1 =
134                 new FieldKeplerianOrbit<>(a, e1, i, pa, raan, m, PositionAngleType.MEAN, frame, date, zero.add(mu));
135         FieldEventDetector<T> detector1 = new FieldNodeDetector<>(orbit1, orbit1.getFrame());
136         T t1 = orbit1.getKeplerianPeriod();
137         Assertions.assertEquals(t1.getReal() / 28.82, detector1.getMaxCheckInterval().currentInterval(null, true), t1.getReal() / 10000);
138 
139         // nearly circular, inclined orbit
140         final FieldKeplerianOrbit<T> orbit2 =
141                 new FieldKeplerianOrbit<>(a, e2, i, pa, raan, m, PositionAngleType.MEAN, frame, date, zero.add(mu));
142         FieldEventDetector<T> detector2 = new FieldNodeDetector<>(orbit2, orbit2.getFrame());
143         T t2 = orbit2.getKeplerianPeriod();
144         Assertions.assertEquals(t1.getReal(), t2.getReal(), t1.getReal() / 10000);
145         Assertions.assertEquals(t2.getReal() / 3, detector2.getMaxCheckInterval().currentInterval(null, true), t2.getReal() / 10000);
146 
147     }
148 
149     @BeforeEach
150     public void setUp() {
151         Utils.setDataRoot("regular-data");
152     }
153 
154 }
155