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