1 /* Copyright 2002-2022 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 * @param <T> class type for the generic version
38 * @author Luc Maisonobe
39 */
40 public class EventShifter<T extends EventDetector> extends AbstractDetector<EventShifter<T>> {
41
42 /** Event detector for the raw unshifted event. */
43 private final T detector;
44
45 /** Indicator for using shifted or unshifted states at event occurrence. */
46 private final boolean useShiftedStates;
47
48 /** Offset to apply to find increasing events. */
49 private final double increasingOffset;
50
51 /** Offset to apply to find decreasing events. */
52 private final double decreasingOffset;
53
54 /** Build a new instance.
55 * <p>The {@link #getMaxCheckInterval() max check interval}, the
56 * {@link #getThreshold() convergence threshold} of the raw unshifted
57 * events will be used for the shifted event. When an event occurs,
58 * the {@link #eventOccurred(SpacecraftState, boolean) eventOccurred}
59 * method of the raw unshifted events will be called (with spacecraft
60 * state at either the shifted or the unshifted event date depending
61 * on the <code>useShiftedStates</code> parameter).</p>
62 * @param detector event detector for the raw unshifted event
63 * @param useShiftedStates if true, the state provided to {@link
64 * #eventOccurred(SpacecraftState, boolean) eventOccurred} method of
65 * the <code>detector</code> will remain shifted, otherwise it will
66 * be <i>unshifted</i> to correspond to the underlying raw event.
67 * @param increasingTimeShift increasing events time shift.
68 * @param decreasingTimeShift decreasing events time shift.
69 */
70 public EventShifter(final T detector, final boolean useShiftedStates,
71 final double increasingTimeShift, final double decreasingTimeShift) {
72 this(detector.getMaxCheckInterval(), detector.getThreshold(),
73 detector.getMaxIterationCount(), new LocalHandler<T>(),
74 detector, useShiftedStates, increasingTimeShift, decreasingTimeShift);
75 }
76
77 /** Private constructor with full parameters.
78 * <p>
79 * This constructor is private as users are expected to use the builder
80 * API with the various {@code withXxx()} methods to set up the instance
81 * in a readable manner without using a huge amount of parameters.
82 * </p>
83 * @param maxCheck maximum checking interval (s)
84 * @param threshold convergence threshold (s)
85 * @param maxIter maximum number of iterations in the event time search
86 * @param handler event handler to call at event occurrences
87 * @param detector event detector for the raw unshifted event
88 * @param useShiftedStates if true, the state provided to {@link
89 * #eventOccurred(SpacecraftState, 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 6.1
95 */
96 private EventShifter(final double maxCheck, final double threshold,
97 final int maxIter, final EventHandler<? super EventShifter<T>> handler,
98 final T detector, final boolean useShiftedStates,
99 final double increasingTimeShift, final double decreasingTimeShift) {
100 super(maxCheck, threshold, maxIter, handler);
101 this.detector = detector;
102 this.useShiftedStates = useShiftedStates;
103 this.increasingOffset = -increasingTimeShift;
104 this.decreasingOffset = -decreasingTimeShift;
105 }
106
107 /** {@inheritDoc} */
108 @Override
109 protected EventShifter<T> create(final double newMaxCheck, final double newThreshold,
110 final int newMaxIter, final EventHandler<? super EventShifter<T>> newHandler) {
111 return new EventShifter<T>(newMaxCheck, newThreshold, newMaxIter, newHandler,
112 detector, useShiftedStates, -increasingOffset, -decreasingOffset);
113 }
114
115 /**
116 * Get the detector for the raw unshifted event.
117 * @return the detector for the raw unshifted event
118 * @since 11.1
119 */
120 public EventDetector getDetector() {
121 return detector;
122 }
123
124 /** Get the increasing events time shift.
125 * @return increasing events time shift
126 */
127 public double getIncreasingTimeShift() {
128 return -increasingOffset;
129 }
130
131 /** Get the decreasing events time shift.
132 * @return decreasing events time shift
133 */
134 public double getDecreasingTimeShift() {
135 return -decreasingOffset;
136 }
137
138 /** {@inheritDoc} */
139 public void init(final SpacecraftState s0,
140 final AbsoluteDate t) {
141 super.init(s0, t);
142 detector.init(s0, t);
143 }
144
145 /** {@inheritDoc} */
146 public double g(final SpacecraftState s) {
147 final double incShiftedG = detector.g(s.shiftedBy(increasingOffset));
148 final double decShiftedG = detector.g(s.shiftedBy(decreasingOffset));
149 return (increasingOffset >= decreasingOffset) ?
150 FastMath.max(incShiftedG, decShiftedG) : FastMath.min(incShiftedG, decShiftedG);
151 }
152
153 /** Local class for handling events. */
154 private static class LocalHandler<T extends EventDetector> implements EventHandler<EventShifter<T>> {
155
156 /** Shifted state at even occurrence. */
157 private SpacecraftState shiftedState;
158
159 /** {@inheritDoc} */
160 public Action eventOccurred(final SpacecraftState s, final EventShifter<T> shifter, final boolean increasing) {
161
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.eventOccurred(shiftedState, increasing);
172
173 }
174
175 /** {@inheritDoc} */
176 @Override
177 public SpacecraftState resetState(final EventShifter<T> shifter, final SpacecraftState oldState) {
178 return shifter.detector.resetState(shiftedState);
179 }
180
181 }
182
183 }