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.CalculusFieldElement; 21 import org.hipparchus.analysis.solvers.BracketedRealFieldUnivariateSolver; 22 import org.hipparchus.ode.FieldODEStateAndDerivative; 23 24 /** This interface represents a handler 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 * states boundaries crossings. 32 * </p> 33 * 34 * <p>These events are defined as occurring when a <code>g</code> 35 * switching function sign changes.</p> 36 * 37 * <p>Since events are only problem-dependent and are triggered by the 38 * independent <i>time</i> variable and the state vector, they can 39 * occur at virtually any time, unknown in advance. The integrators will 40 * take care to avoid sign changes inside the steps, they will reduce 41 * the step size when such an event is detected in order to put this 42 * event exactly at the end of the current step. This guarantees that 43 * step interpolation (which always has a one step scope) is relevant 44 * even in presence of discontinuities. This is independent from the 45 * stepsize control provided by integrators that monitor the local 46 * error (this event handling feature is available for all integrators, 47 * including fixed step ones).</p> 48 * 49 * <p> 50 * Note that prior to Hipparchus 3.0, the methods in this interface were 51 * in the {@link FieldODEEventHandler} interface and the defunct 52 * {@code FieldEventHandlerConfiguration} interface. The interfaces have been 53 * reorganized to allow different objects to be used in event detection 54 * and event handling, hence allowing users to reuse predefined events 55 * detectors with custom handlers. 56 * </p> 57 * 58 * @see org.hipparchus.ode.events 59 * @since 3.0 60 * @param <T> the type of the field elements 61 */ 62 public interface FieldODEEventDetector<T extends CalculusFieldElement<T>> { 63 64 /** Get the maximal time interval between events handler checks. 65 * @return maximal time interval between events handler checks 66 */ 67 FieldAdaptableInterval<T> 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 BracketedRealFieldUnivariateSolver<T> getSolver(); 78 79 /** Get the underlying event handler. 80 * @return underlying event handler 81 */ 82 FieldODEEventHandler<T> getHandler(); 83 84 /** Initialize event handler 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 handler to initialize some internal data 88 * if needed. 89 * </p> 90 * <p> 91 * The default implementation does nothing 92 * </p> 93 * @param initialState initial time, state vector and derivative 94 * @param finalTime target time for the integration 95 */ 96 default void init(FieldODEStateAndDerivative<T> initialState, T finalTime) { 97 // nothing by default 98 } 99 100 /** Compute the value of the switching function. 101 102 * <p>The discrete events are generated when the sign of this 103 * switching function changes. The integrator will take care to change 104 * the stepsize in such a way these events occur exactly at step boundaries. 105 * The switching function must be continuous in its roots neighborhood 106 * (but not necessarily smooth), as the integrator will need to find its 107 * roots to locate precisely the events.</p> 108 * <p>Also note that the integrator expect that once an event has occurred, 109 * the sign of the switching function at the start of the next step (i.e. 110 * just after the event) is the opposite of the sign just before the event. 111 * This consistency between the steps <strong>must</strong> be preserved, 112 * otherwise {@link org.hipparchus.exception.MathIllegalArgumentException 113 * exceptions} related to root not being bracketed will occur.</p> 114 * <p>This need for consistency is sometimes tricky to achieve. A typical 115 * example is using an event to model a ball bouncing on the floor. The first 116 * idea to represent this would be to have {@code g(state) = h(state)} where h is the 117 * height above the floor at time {@code state.getTime()}. When {@code g(state)} reaches 0, the 118 * ball is on the floor, so it should bounce and the typical way to do this is 119 * to reverse its vertical velocity. However, this would mean that before the 120 * event {@code g(state)} was decreasing from positive values to 0, and after the 121 * event {@code g(state)} would be increasing from 0 to positive values again. 122 * Consistency is broken here! The solution here is to have {@code g(state) = sign 123 * * h(state)}, where sign is a variable with initial value set to {@code +1}. Each 124 * time {@link FieldODEEventHandler#eventOccurred(FieldODEStateAndDerivative, 125 * FieldODEEventDetector, boolean) eventOccurred} 126 * method is called, {@code sign} is reset to {@code -sign}. This allows the 127 * {@code g(state)} function to remain continuous (and even smooth) even across events, 128 * despite {@code h(state)} is not. Basically, the event is used to <em>fold</em> 129 * {@code h(state)} at bounce points, and {@code sign} is used to <em>unfold</em> it 130 * back, so the solvers sees a {@code g(state)} function which behaves smoothly even 131 * across events.</p> 132 * 133 * <p>This method is idempotent, that is calling this multiple times with the same 134 * state will result in the same value, with two exceptions. First, the definition of 135 * the g function may change when an {@link 136 * FieldODEEventHandler#eventOccurred(FieldODEStateAndDerivative, FieldODEEventDetector, 137 * boolean) event occurs} on the handler, as in the above example. Second, the 138 * definition of the g function may change when the {@link 139 * FieldODEEventHandler#eventOccurred(FieldODEStateAndDerivative, FieldODEEventDetector, 140 * boolean) event occurs} method of any other event handler in the same integrator returns 141 * {@link Action#RESET_EVENTS}, {@link Action#RESET_DERIVATIVES}, or {@link Action#RESET_STATE}. 142 * 143 * @param state current value of the independent <i>time</i> variable, state vector 144 * and derivative 145 * @return value of the g switching function 146 */ 147 T g(FieldODEStateAndDerivative<T> state); 148 149 }