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