1 /* Copyright 2002-2024 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 import java.util.ArrayList;
21 import java.util.List;
22 import java.util.stream.Stream;
23
24 import org.hipparchus.CalculusFieldElement;
25 import org.hipparchus.Field;
26 import org.hipparchus.util.FastMath;
27 import org.orekit.forces.ForceModel;
28 import org.orekit.propagation.events.handlers.FieldResetDerivativesOnEvent;
29 import org.orekit.propagation.events.handlers.ResetDerivativesOnEvent;
30 import org.orekit.propagation.semianalytical.dsst.forces.DSSTForceModel;
31 import org.orekit.time.AbsoluteDate;
32 import org.orekit.time.FieldAbsoluteDate;
33 import org.orekit.time.FieldTimeStamped;
34 import org.orekit.time.TimeStamped;
35 import org.orekit.utils.ParameterDriver;
36
37 /** Interface for building event detectors for force models and maneuver parameters.
38 *
39 * <p>
40 * Objects implementing this interface are mainly {@link ForceModel} and {@link DSSTForceModel}.
41 *
42 * @author Luc Maisonobe
43 * @author Melina Vanel
44 * @author Maxime Journot
45 * @since 12.0
46 */
47 public interface EventDetectorsProvider {
48
49 /** Accuracy of switching events dates (s). */
50 double DATATION_ACCURACY = 1.0e-10;
51
52 /** Get the discrete events related to the model.
53 *
54 * <p><b>This method is not intended to be called several time, only once by a propagator</b>,
55 * as it has the side effect of rebuilding the events detectors when called
56 *
57 * @return stream of event detectors
58 */
59 Stream<EventDetector> getEventDetectors();
60
61 /** Get the discrete events related to the model.
62 *
63 * <p><b>This method is not intended to be called several time, only once by a propagator</b>,
64 * as it has the side effect of rebuilding the events detectors when called
65 *
66 * @param field field to which the state belongs
67 * @param <T> extends CalculusFieldElement<T>
68 * @return stream of event detectors
69 */
70 <T extends CalculusFieldElement<T>> Stream<FieldEventDetector<T>> getFieldEventDetectors(Field<T> field);
71
72 /** Get the discrete events related to the model from a list of {@link ParameterDriver}
73 *
74 * <p>Date detectors are used to cleanly stop the propagator and reset
75 * the state derivatives at transition dates (if any) of the parameter drivers.
76 *
77 * <p><b>This method is not intended to be called several times, only once by a propagator</b>,
78 * as it has the side effect of rebuilding the events detectors when called.
79 *
80 * @param parameterDrivers list of parameter drivers
81 * @return stream of event detectors
82 */
83 default Stream<EventDetector> getEventDetectors(List<ParameterDriver> parameterDrivers) {
84 // If force model does not have parameter Driver, an empty stream is given as results
85 final ArrayList<TimeStamped> transitionDates = new ArrayList<>();
86 for (final ParameterDriver driver : parameterDrivers) {
87 // Get the transitions' dates from the TimeSpanMap
88 for (AbsoluteDate date : driver.getTransitionDates()) {
89 transitionDates.add(date);
90 }
91 }
92 // Either force model does not have any parameter driver or only contains parameter driver with only 1 span
93 if (transitionDates.size() == 0) {
94 return Stream.empty();
95
96 } else {
97 // Sort transition dates chronologically
98 transitionDates.sort(null);
99
100 // Find shortest duration between 2 consecutive dates
101 double shortestDuration = AbstractDetector.DEFAULT_MAXCHECK;
102 for (int i = 1; i < transitionDates.size(); i++) {
103 // Duration from current to previous date
104 shortestDuration = FastMath.min(shortestDuration,
105 transitionDates.get(i).durationFrom(transitionDates.get(i - 1)));
106 }
107
108 // Create the date detector containing all transition dates and return it
109 // Max check set to half the shortest duration between 2 consecutive dates
110 final DateDetector datesDetector = new DateDetector(transitionDates.toArray(new TimeStamped[0])).
111 withMaxCheck(0.5 * shortestDuration).
112 withMinGap(0.5 * shortestDuration).
113 withThreshold(DATATION_ACCURACY).
114 withHandler(new ResetDerivativesOnEvent());
115 return Stream.of(datesDetector);
116 }
117 }
118
119 /** Get the discrete events related to the model from a list of {@link ParameterDriver}
120 *
121 * <p>Date detectors are used to cleanly stop the propagator and reset
122 * the state derivatives at transition dates (if any) of the parameter drivers.
123 *
124 * <p><b>This method is not intended to be called several times, only once by a propagator</b>,
125 * as it has the side effect of rebuilding the events detectors when called.
126 *
127 * @param parameterDrivers list of parameter drivers
128 * @param field field to which the state belongs
129 * @param <T> extends CalculusFieldElement<T>
130 * @return stream of event detectors
131 */
132 default <T extends CalculusFieldElement<T>> Stream<FieldEventDetector<T>> getFieldEventDetectors(Field<T> field, List<ParameterDriver> parameterDrivers) {
133 // If force model does not have parameter Driver, an empty stream is given as results
134 final ArrayList<AbsoluteDate> transitionDates = new ArrayList<>();
135 for (ParameterDriver driver : parameterDrivers) {
136 // Get the transitions' dates from the TimeSpanMap
137 for (AbsoluteDate date : driver.getTransitionDates()) {
138 transitionDates.add(date);
139 }
140 }
141 // Either force model does not have any parameter driver or only contains parameter driver with only 1 span
142 if (transitionDates.size() == 0) {
143 return Stream.empty();
144
145 } else {
146 // Sort transition dates chronologically
147 transitionDates.sort(null);
148
149 // Find shortest duration between 2 consecutive dates
150 double shortestDuration = AbstractDetector.DEFAULT_MAXCHECK;
151 for (int i = 1; i < transitionDates.size(); i++) {
152 // Duration from current to previous date
153 shortestDuration = FastMath.min(shortestDuration,
154 transitionDates.get(i).durationFrom(transitionDates.get(i - 1)));
155 }
156
157 // Initialize the date detector
158 // Max check set to half the shortest duration between 2 consecutive dates
159 @SuppressWarnings("unchecked")
160 final FieldDateDetector<T> datesDetector =
161 new FieldDateDetector<>(field, (FieldTimeStamped<T>[]) Array.newInstance(FieldTimeStamped.class, 0)).
162 withMaxCheck(0.5 * shortestDuration).
163 withMinGap(0.5 * shortestDuration).
164 withThreshold(field.getZero().newInstance(DATATION_ACCURACY)).
165 withHandler(new FieldResetDerivativesOnEvent<>());
166 // Add all transitions' dates to the date detector
167 for (int i = 0; i < transitionDates.size(); i++) {
168 datesDetector.addEventDate(new FieldAbsoluteDate<>(field, transitionDates.get(i)));
169 }
170 // Return the detectors
171 return Stream.of(datesDetector);
172 }
173 }
174 }