1 /* Copyright 2002-2021 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.util.ArrayList;
20
21 import org.hipparchus.ode.events.Action;
22 import org.orekit.errors.OrekitIllegalArgumentException;
23 import org.orekit.errors.OrekitMessages;
24 import org.orekit.propagation.SpacecraftState;
25 import org.orekit.propagation.events.handlers.EventHandler;
26 import org.orekit.propagation.events.handlers.StopOnEvent;
27 import org.orekit.time.AbsoluteDate;
28 import org.orekit.time.TimeStamped;
29
30 /** Finder for date events.
31 * <p>This class finds date events (i.e. occurrence of some predefined dates).</p>
32 * <p>As of version 5.1, it is an enhanced date detector:</p>
33 * <ul>
34 * <li>it can be defined without prior date ({@link #DateDetector(double, double, TimeStamped...)})</li>
35 * <li>several dates can be added ({@link #addEventDate(AbsoluteDate)})</li>
36 * </ul>
37 * <p>The gap between the added dates must be more than the maxCheck.</p>
38 * <p>The default implementation behavior is to {@link Action#STOP stop}
39 * propagation at the first event date occurrence. This can be changed by calling
40 * {@link #withHandler(EventHandler)} after construction.</p>
41 * @see org.orekit.propagation.Propagator#addEventDetector(EventDetector)
42 * @author Luc Maisonobe
43 * @author Pascal Parraud
44 */
45 public class DateDetector extends AbstractDetector<DateDetector> implements TimeStamped {
46
47 /** Last date for g computation. */
48 private AbsoluteDate gDate;
49
50 /** List of event dates. */
51 private final ArrayList<EventDate> eventDateList;
52
53 /** Current event date. */
54 private int currentIndex;
55
56 /** Build a new instance.
57 * <p>First event dates are set here, but others can be
58 * added later with {@link #addEventDate(AbsoluteDate)}.</p>
59 * @param maxCheck maximum checking interval (s)
60 * @param threshold convergence threshold (s)
61 * @param dates list of event dates
62 * @see #addEventDate(AbsoluteDate)
63 */
64 public DateDetector(final double maxCheck, final double threshold, final TimeStamped... dates) {
65 this(maxCheck, threshold, DEFAULT_MAX_ITER, new StopOnEvent<DateDetector>(), dates);
66 }
67
68 /** Build a new instance.
69 * <p>This constructor is dedicated to single date detection.
70 * {@link #getMaxCheckInterval() max check interval} is set to 1.0e10, so almost
71 * no other date can be added. Tolerance is set to 1.0e-9.</p>
72 * @param target target date
73 * @see #addEventDate(AbsoluteDate)
74 */
75 public DateDetector(final AbsoluteDate target) {
76 this(1.0e10, 1.e-9, target);
77 }
78
79 /** Private constructor with full parameters.
80 * <p>
81 * This constructor is private 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 maxCheck maximum checking interval (s)
86 * @param threshold convergence threshold (s)
87 * @param maxIter maximum number of iterations in the event time search
88 * @param handler event handler to call at event occurrences
89 * @param dates list of event dates
90 * @since 6.1
91 */
92 private DateDetector(final double maxCheck, final double threshold,
93 final int maxIter, final EventHandler<? super DateDetector> handler,
94 final TimeStamped... dates) {
95 super(maxCheck, threshold, maxIter, handler);
96 this.currentIndex = -1;
97 this.gDate = null;
98 this.eventDateList = new ArrayList<DateDetector.EventDate>(dates.length);
99 for (final TimeStamped ts : dates) {
100 addEventDate(ts.getDate());
101 }
102 }
103
104 /** {@inheritDoc} */
105 @Override
106 protected DateDetector create(final double newMaxCheck, final double newThreshold,
107 final int newMaxIter, final EventHandler<? super DateDetector> newHandler) {
108 return new DateDetector(newMaxCheck, newThreshold, newMaxIter, newHandler,
109 eventDateList.toArray(new EventDate[eventDateList.size()]));
110 }
111
112 /** Compute the value of the switching function.
113 * This function measures the difference between the current and the target date.
114 * @param s the current state information: date, kinematics, attitude
115 * @return value of the switching function
116 */
117 public double g(final SpacecraftState s) {
118 gDate = s.getDate();
119 if (currentIndex < 0) {
120 return -1.0;
121 } else {
122 final EventDate event = getClosest(gDate);
123 return event.isgIncrease() ? gDate.durationFrom(event.getDate()) : event.getDate().durationFrom(gDate);
124 }
125 }
126
127 /** Get the current event date according to the propagator.
128 * @return event date
129 */
130 public AbsoluteDate getDate() {
131 return currentIndex < 0 ? null : eventDateList.get(currentIndex).getDate();
132 }
133
134 /** Add an event date.
135 * <p>The date to add must be:</p>
136 * <ul>
137 * <li>less than the smallest already registered event date minus the maxCheck</li>
138 * <li>or more than the largest already registered event date plus the maxCheck</li>
139 * </ul>
140 * @param target target date
141 * @throws IllegalArgumentException if the date is too close from already defined interval
142 * @see #DateDetector(double, double, TimeStamped...)
143 */
144 public void addEventDate(final AbsoluteDate target) throws IllegalArgumentException {
145 final boolean increasing;
146 if (currentIndex < 0) {
147 increasing = (gDate == null) ? true : target.durationFrom(gDate) > 0.0;
148 currentIndex = 0;
149 eventDateList.add(new EventDate(target, increasing));
150 } else {
151 final int lastIndex = eventDateList.size() - 1;
152 final AbsoluteDate firstDate = eventDateList.get(0).getDate();
153 final AbsoluteDate lastDate = eventDateList.get(lastIndex).getDate();
154 if (firstDate.durationFrom(target) > getMaxCheckInterval()) {
155 increasing = !eventDateList.get(0).isgIncrease();
156 eventDateList.add(0, new EventDate(target, increasing));
157 currentIndex++;
158 } else if (target.durationFrom(lastDate) > getMaxCheckInterval()) {
159 increasing = !eventDateList.get(lastIndex).isgIncrease();
160 eventDateList.add(new EventDate(target, increasing));
161 } else {
162 throw new OrekitIllegalArgumentException(OrekitMessages.EVENT_DATE_TOO_CLOSE,
163 target,
164 firstDate,
165 lastDate,
166 getMaxCheckInterval(),
167 firstDate.durationFrom(target),
168 target.durationFrom(lastDate));
169 }
170 }
171 }
172
173 /** Get the closest EventDate to the target date.
174 * @param target target date
175 * @return current EventDate
176 */
177 private EventDate getClosest(final AbsoluteDate target) {
178 final double dt = target.durationFrom(eventDateList.get(currentIndex).getDate());
179 if (dt < 0.0 && currentIndex > 0) {
180 boolean found = false;
181 while (currentIndex > 0 && !found) {
182 if (target.durationFrom(eventDateList.get(currentIndex - 1).getDate()) < eventDateList.get(currentIndex).getDate().durationFrom(target)) {
183 currentIndex--;
184 } else {
185 found = true;
186 }
187 }
188 } else if (dt > 0.0 && currentIndex < eventDateList.size() - 1) {
189 final int maxIndex = eventDateList.size() - 1;
190 boolean found = false;
191 while (currentIndex < maxIndex && !found) {
192 if (target.durationFrom(eventDateList.get(currentIndex + 1).getDate()) > eventDateList.get(currentIndex).getDate().durationFrom(target)) {
193 currentIndex++;
194 } else {
195 found = true;
196 }
197 }
198 }
199 return eventDateList.get(currentIndex);
200 }
201
202 /** Event date specification. */
203 private static class EventDate implements TimeStamped {
204
205 /** Event date. */
206 private final AbsoluteDate eventDate;
207
208 /** Flag for g function way around event date. */
209 private final boolean gIncrease;
210
211 /** Simple constructor.
212 * @param date date
213 * @param increase if true, g function increases around event date
214 */
215 EventDate(final AbsoluteDate date, final boolean increase) {
216 this.eventDate = date;
217 this.gIncrease = increase;
218 }
219
220 /** Getter for event date.
221 * @return event date
222 */
223 public AbsoluteDate getDate() {
224 return eventDate;
225 }
226
227 /** Getter for g function way at event date.
228 * @return g function increasing flag
229 */
230 public boolean isgIncrease() {
231 return gIncrease;
232 }
233
234 }
235
236 }