1 /*
2 * Licensed to the Hipparchus project under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The Hipparchus project 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 * https://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
18 package org.hipparchus.ode.events;
19
20 import org.hipparchus.analysis.UnivariateFunction;
21 import org.hipparchus.analysis.solvers.BracketedUnivariateSolver;
22 import org.hipparchus.ode.ODEStateAndDerivative;
23
24 /** This interface represents a detector for discrete events triggered
25 * during ODE integration.
26 *
27 * <p>Some events can be triggered at discrete times as an ODE problem
28 * is solved. This occurs for example when the integration process
29 * should be stopped as some state is reached (G-stop facility) when the
30 * precise date is unknown a priori, or when the derivatives have
31 * discontinuities, or simply when the user wants to monitor some
32 * states boundaries crossings.
33 * </p>
34 *
35 * <p>These events are defined as occurring when a <code>g</code>
36 * switching function sign changes.</p>
37 *
38 * <p>Since events are only problem-dependent and are triggered by the
39 * independent <i>time</i> variable and the state vector, they can
40 * occur at virtually any time, unknown in advance. The integrators will
41 * take care to avoid sign changes inside the steps, they will reduce
42 * the step size when such an event is detected in order to put this
43 * event exactly at the end of the current step. This guarantees that
44 * step interpolation (which always has a one step scope) is relevant
45 * even in presence of discontinuities. This is independent from the
46 * stepsize control provided by integrators that monitor the local
47 * error (this event handling feature is available for all integrators,
48 * including fixed step ones).</p>
49 *
50 * <p>
51 * Note that prior to Hipparchus 3.0, the methods in this interface were
52 * in the {@link ODEEventHandler} interface and the defunct
53 * {@code EventHandlerConfiguration} interface. The interfaces have been
54 * reorganized to allow different objects to be used in event detection
55 * and event handling, hence allowing users to reuse predefined events
56 * detectors with custom handlers.
57 * </p>
58 *
59 * @see org.hipparchus.ode.events
60 * @since 3.0
61 */
62 public interface ODEEventDetector {
63
64 /** Get the maximal time interval between events handler checks.
65 * @return maximal time interval between events handler checks
66 */
67 AdaptableInterval getMaxCheckInterval();
68
69 /** Get the upper limit in the iteration count for event localization.
70 * @return upper limit in the iteration count for event localization
71 */
72 int getMaxIterationCount();
73
74 /** Get the root-finding algorithm to use to detect state events.
75 * @return root-finding algorithm to use to detect state events
76 */
77 BracketedUnivariateSolver<UnivariateFunction> getSolver();
78
79 /** Get the underlying event handler.
80 * @return underlying event handler
81 */
82 ODEEventHandler getHandler();
83
84 /** Initialize event detector at the start of an ODE integration.
85 * <p>
86 * This method is called once at the start of the integration. It
87 * may be used by the event detector to initialize some internal data
88 * if needed.
89 * </p>
90 * <p>
91 * The default implementation initializes the handler
92 * </p>
93 * @param initialState initial time, state vector and derivative
94 * @param finalTime target time for the integration
95 */
96 default void init(ODEStateAndDerivative initialState, double finalTime) {
97 getHandler().init(initialState, finalTime, this);
98 }
99
100 /** Reset event detector during integration.
101 * <p>
102 * This method is called during integration if the derivatives or the state variables themselves are reset.
103 * </p>
104 * <p>
105 * The default implementation does nothing.
106 * </p>
107 * @param intermediateState intermediate time, state vector and derivative
108 * @param finalTime target time for the integration
109 * @since 4.0
110 */
111 default void reset(ODEStateAndDerivative intermediateState, double finalTime) {
112 // nothing by default
113 }
114
115 /** Compute the value of the switching function.
116
117 * <p>The discrete events are generated when the sign of this
118 * switching function changes. The integrator will take care to change
119 * the stepsize in such a way these events occur exactly at step boundaries.
120 * The switching function must be continuous in its roots neighborhood
121 * (but not necessarily smooth), as the integrator will need to find its
122 * roots to locate precisely the events.</p>
123 *
124 * <p>Also note that for the integrator to detect an event the sign of the switching
125 * function must have opposite signs just before and after the event. If this
126 * consistency is not preserved the integrator may not detect any events.
127 *
128 * <p>This need for consistency is sometimes tricky to achieve. A typical
129 * example is using an event to model a ball bouncing on the floor. The first
130 * idea to represent this would be to have {@code g(state) = h(state)} where h is the
131 * height above the floor at time {@code state.getTime()}. When {@code g(state)}
132 * reaches 0, the ball is on the floor, so it should bounce and the typical way to do this is
133 * to reverse its vertical velocity. However, this would mean that before the
134 * event {@code g(state)} was decreasing from positive values to 0, and after the
135 * event {@code g(state)} would be increasing from 0 to positive values again.
136 * Consistency is broken here! The solution here is to have {@code g(state) = sign
137 * * h(state)}, where sign is a variable with initial value set to {@code +1}. Each
138 * time {@link ODEEventHandler#eventOccurred(ODEStateAndDerivative,
139 * ODEEventDetector, boolean) eventOccurred} is called,
140 * {@code sign} is reset to {@code -sign}. This allows the {@code g(state)}
141 * function to remain continuous (and even smooth) even across events, despite
142 * {@code h(state)} is not. Basically, the event is used to <em>fold</em> {@code h(state)}
143 * at bounce points, and {@code sign} is used to <em>unfold</em> it back, so the
144 * solvers sees a {@code g(state)} function which behaves smoothly even across events.</p>
145 *
146 * <p>This method is idempotent, that is calling this multiple times with the same
147 * state will result in the same value, with two exceptions. First, the definition of
148 * the g function may change when an {@link ODEEventHandler#eventOccurred(ODEStateAndDerivative,
149 * ODEEventDetector, boolean) event occurs} on the handler, as in the above example.
150 * Second, the definition of the g function may change when the {@link
151 * ODEEventHandler#eventOccurred(ODEStateAndDerivative, ODEEventDetector, boolean) eventOccurred}
152 * method of any other event handler in the same integrator returns {@link Action#RESET_EVENTS},
153 * {@link Action#RESET_DERIVATIVES}, or {@link Action#RESET_STATE}.
154 *
155 * @param state current value of the independent <i>time</i> variable, state vector
156 * and derivative
157 * @return value of the g switching function
158 * @see org.hipparchus.ode.events
159 */
160 double g(ODEStateAndDerivative state);
161
162 }