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.events;
18
19 import org.hipparchus.CalculusFieldElement;
20 import org.hipparchus.ode.events.Action;
21 import org.hipparchus.util.FastMath;
22 import org.orekit.propagation.FieldSpacecraftState;
23 import org.orekit.propagation.SpacecraftState;
24 import org.orekit.propagation.events.handlers.EventHandler;
25 import org.orekit.propagation.events.handlers.FieldEventHandler;
26
27 /** Wrapper shifting events occurrences times.
28 * <p>This class wraps an {@link FieldEventDetector event detector} to slightly
29 * shift the events occurrences times. A typical use case is for handling
30 * operational delays before or after some physical event really occurs.</p>
31 * <p>For example, the satellite attitude mode may be switched from sun pointed
32 * to spin-stabilized a few minutes before eclipse entry, and switched back
33 * to sun pointed a few minutes after eclipse exit. This behavior is handled
34 * by wrapping an {@link FieldEclipseDetector eclipse detector} into an instance
35 * of this class with a positive times shift for increasing events (eclipse exit)
36 * and a negative times shift for decreasing events (eclipse entry).</p>
37 * @see org.orekit.propagation.FieldPropagator#addEventDetector(FieldEventDetector)
38 * @see FieldEventDetector
39 * @see EventShifter
40 * @author Luc Maisonobe
41 * @author Romain Serra
42 * @since 13.0
43 */
44 public class FieldEventShifter<T extends CalculusFieldElement<T>> implements FieldDetectorModifier<T> {
45
46 /** Event detector for the raw unshifted event. */
47 private final FieldEventDetector<T> detector;
48
49 /** Indicator for using shifted or unshifted states at event occurrence. */
50 private final boolean useShiftedStates;
51
52 /** Offset to apply to find increasing events. */
53 private final T increasingOffset;
54
55 /** Offset to apply to find decreasing events. */
56 private final T decreasingOffset;
57
58 /** Specialized event handler. */
59 private final LocalHandler<T> handler;
60
61 /** Event detection settings. */
62 private final FieldEventDetectionSettings<T> detectionSettings;
63
64 /** Build a new instance.
65 * <p>The {@link #getMaxCheckInterval() max check interval}, the
66 * {@link #getThreshold() convergence threshold} of the raw unshifted
67 * events will be used for the shifted event. When an event occurs,
68 * the {@link EventHandler#eventOccurred(SpacecraftState, EventDetector, boolean) eventOccurred}
69 * method of the raw unshifted events will be called (with spacecraft
70 * state at either the shifted or the unshifted event date depending
71 * on the <code>useShiftedStates</code> parameter).</p>
72 * @param detector event detector for the raw unshifted event
73 * @param useShiftedStates if true, the state provided to {@link
74 * EventHandler#eventOccurred(SpacecraftState, EventDetector, boolean) eventOccurred} method of
75 * the associated {@code handler} will remain shifted, otherwise it will
76 * be <i>unshifted</i> to correspond to the underlying raw event.
77 * @param increasingTimeShift increasing events time shift.
78 * @param decreasingTimeShift decreasing events time shift.
79 */
80 public FieldEventShifter(final FieldEventDetector<T> detector, final boolean useShiftedStates,
81 final T increasingTimeShift, final T decreasingTimeShift) {
82 this(detector.getDetectionSettings(), detector, useShiftedStates, increasingTimeShift, decreasingTimeShift);
83 }
84
85 /** Constructor with full parameters.
86 * @param detectionSettings event detection settings
87 * @param detector event detector for the raw unshifted event
88 * @param useShiftedStates if true, the state provided to {@link
89 * EventHandler#eventOccurred(SpacecraftState, EventDetector, boolean) eventOccurred} method of
90 * the <code>detector</code> will remain shifted, otherwise it will
91 * be <i>unshifted</i> to correspond to the underlying raw event.
92 * @param increasingTimeShift increasing events time shift.
93 * @param decreasingTimeShift decreasing events time shift.
94 * @since 13.0
95 */
96 public FieldEventShifter(final FieldEventDetectionSettings<T> detectionSettings,
97 final FieldEventDetector<T> detector, final boolean useShiftedStates,
98 final T increasingTimeShift, final T decreasingTimeShift) {
99 this.detectionSettings = detectionSettings;
100 this.handler = new LocalHandler<>();
101 this.detector = detector;
102 this.useShiftedStates = useShiftedStates;
103 this.increasingOffset = increasingTimeShift.negate();
104 this.decreasingOffset = decreasingTimeShift.negate();
105 }
106
107 @Override
108 public FieldEventHandler<T> getHandler() {
109 return handler;
110 }
111
112 @Override
113 public FieldEventDetectionSettings<T> getDetectionSettings() {
114 return detectionSettings;
115 }
116
117 /**
118 * Get the detector for the raw unshifted event.
119 * @return the detector for the raw unshifted event
120 */
121 public FieldEventDetector<T> getDetector() {
122 return detector;
123 }
124
125 /** Get the increasing events time shift.
126 * @return increasing events time shift
127 */
128 public T getIncreasingTimeShift() {
129 return increasingOffset.negate();
130 }
131
132 /** Get the decreasing events time shift.
133 * @return decreasing events time shift
134 */
135 public T getDecreasingTimeShift() {
136 return decreasingOffset.negate();
137 }
138
139 /**
140 * Builds a new instance from the input detection settings.
141 * @param settings event detection settings to be used
142 * @return a new detector
143 */
144 public FieldEventShifter<T> withDetectionSettings(final FieldEventDetectionSettings<T> settings) {
145 return new FieldEventShifter<>(settings, detector, useShiftedStates, getIncreasingTimeShift(), getDecreasingTimeShift());
146 }
147
148 /** {@inheritDoc} */
149 @Override
150 public T g(final FieldSpacecraftState<T> s) {
151 final T incShiftedG = detector.g(s.shiftedBy(increasingOffset));
152 final T decShiftedG = detector.g(s.shiftedBy(decreasingOffset));
153 return (increasingOffset.getReal() >= decreasingOffset.getReal()) ?
154 FastMath.max(incShiftedG, decShiftedG) : FastMath.min(incShiftedG, decShiftedG);
155 }
156
157 /** Local class for handling events. */
158 private static class LocalHandler<W extends CalculusFieldElement<W>> implements FieldEventHandler<W> {
159
160 /** Shifted state at even occurrence. */
161 private FieldSpacecraftState<W> shiftedState;
162
163 /** {@inheritDoc} */
164 public Action eventOccurred(final FieldSpacecraftState<W> s, final FieldEventDetector<W> detector,
165 final boolean increasing) {
166
167 final FieldEventShifter<W> shifter = (FieldEventShifter<W>) detector;
168 if (shifter.useShiftedStates) {
169 // the state provided by the caller already includes the time shift
170 shiftedState = s;
171 } else {
172 // we need to "unshift" the state
173 final W offset = increasing ? shifter.increasingOffset : shifter.decreasingOffset;
174 shiftedState = s.shiftedBy(offset);
175 }
176
177 return shifter.detector.getHandler().eventOccurred(shiftedState, shifter.detector, increasing);
178
179 }
180
181 /** {@inheritDoc} */
182 @Override
183 public FieldSpacecraftState<W> resetState(final FieldEventDetector<W> detector,
184 final FieldSpacecraftState<W> oldState) {
185 final FieldEventShifter<W> shifter = (FieldEventShifter<W>) detector;
186 return shifter.detector.getHandler().resetState(shifter.detector, shiftedState);
187 }
188
189 }
190
191 }