View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) 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 ASF 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  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  
23  package org.hipparchus.ode;
24  
25  import java.lang.reflect.Array;
26  
27  import org.hipparchus.CalculusFieldElement;
28  import org.hipparchus.Field;
29  import org.hipparchus.analysis.solvers.BracketedRealFieldUnivariateSolver;
30  import org.hipparchus.analysis.solvers.FieldBracketingNthOrderBrentSolver;
31  import org.hipparchus.ode.events.Action;
32  import org.hipparchus.ode.events.FieldAdaptableInterval;
33  import org.hipparchus.ode.events.FieldODEEventDetector;
34  import org.hipparchus.ode.events.FieldODEEventHandler;
35  import org.hipparchus.util.FastMath;
36  import org.hipparchus.util.MathArrays;
37  
38  /**
39   * This class is used in the junit tests for the ODE integrators.
40  
41   * <p>This specific problem is the following differential equation :
42   * <pre>
43   *    x'' = -x
44   * </pre>
45   * And when x decreases down to 0, the state should be changed as follows :
46   * <pre>
47   *   x' → -x'
48   * </pre>
49   * The theoretical solution of this problem is x = |sin(t+a)|
50   * </p>
51  
52   * @param <T> the type of the field elements
53   */
54  public class TestFieldProblem4<T extends CalculusFieldElement<T>>
55      extends TestFieldProblemAbstract<T> {
56  
57      private static final double OFFSET = 1.2;
58  
59      /** Time offset. */
60      private T a;
61  
62      /** Simple constructor.
63       * @param field field to which elements belong
64       */
65      public TestFieldProblem4(Field<T> field) {
66          super(convert(field, 0.0),
67                createY0(field),
68                convert(field, 15),
69                convert(field, 1.0, 0.0));
70          a = convert(field, OFFSET);
71      }
72  
73      private static <T extends CalculusFieldElement<T>> T[] createY0(final Field<T> field) {
74          final T a = convert(field, OFFSET);
75          T[] y0 = MathArrays.buildArray(field, 2);
76          y0[0] = a.sin();
77          y0[1] = a.cos();
78          return y0;
79      }
80  
81      @Override
82      public FieldODEEventDetector<T>[] getEventDetectors(final double maxCheck, final T threshold, final int maxIter) {
83          @SuppressWarnings("unchecked")
84          FieldODEEventDetector<T>[] handlers =
85                          (FieldODEEventDetector<T>[]) Array.newInstance(FieldODEEventDetector.class, 2);
86          handlers[0] = new Bounce<>(maxCheck, threshold, maxIter);
87          handlers[1] = new Stop<>(maxCheck, threshold, maxIter);
88          return handlers;
89      }
90  
91      /**
92       * Get the theoretical events times.
93       * @return theoretical events times
94       */
95      @Override
96      public T[] getTheoreticalEventsTimes() {
97          T[] array = MathArrays.buildArray(getField(), 5);
98          array[0] = a.negate().add(1 * FastMath.PI);
99          array[1] = a.negate().add(2 * FastMath.PI);
100         array[2] = a.negate().add(3 * FastMath.PI);
101         array[3] = a.negate().add(4 * FastMath.PI);
102         array[4] = convert(a.getField(), 120.0);
103         return array;
104     }
105 
106     @Override
107     public T[] doComputeDerivatives(T t, T[] y) {
108         final T[] yDot = MathArrays.buildArray(getField(), getDimension());
109         yDot[0] = y[1];
110         yDot[1] = y[0].negate();
111         return yDot;
112     }
113 
114     @Override
115     public T[] computeTheoreticalState(T t) {
116         T sin = t.add(a).sin();
117         T cos = t.add(a).cos();
118         final T[] y = MathArrays.buildArray(getField(), getDimension());
119         y[0] = sin.abs();
120         y[1] = (sin.getReal() >= 0) ? cos : cos.negate();
121         return y;
122     }
123 
124     private static abstract class BaseDetector<T extends CalculusFieldElement<T>>
125         implements FieldODEEventDetector<T>, FieldODEEventHandler<T> {
126 
127         final double                                maxCheck;
128         final int                                   maxIter;
129         final BracketedRealFieldUnivariateSolver<T> solver;
130 
131         protected BaseDetector(final double maxCheck, final T threshold, final int maxIter) {
132             this.maxCheck  = maxCheck;
133             this.maxIter   = maxIter;
134             this.solver    = new FieldBracketingNthOrderBrentSolver<>(threshold.getField().getZero(),
135                                                                       threshold,
136                                                                       threshold.getField().getZero(),
137                                                                       5);
138         }
139 
140         public FieldAdaptableInterval<T> getMaxCheckInterval() {
141             return s -> maxCheck;
142         }
143 
144         public int getMaxIterationCount() {
145             return maxIter;
146         }
147 
148         public BracketedRealFieldUnivariateSolver<T> getSolver() {
149             return solver;
150         }
151 
152         public FieldODEEventHandler<T> getHandler() {
153             return this;
154         }
155 
156     }
157 
158     private static class Bounce<T extends CalculusFieldElement<T>> extends BaseDetector<T> {
159 
160         private int sign;
161 
162         public Bounce(final double maxCheck, final T threshold, final int maxIter) {
163             super(maxCheck, threshold, maxIter);
164             sign = +1;
165         }
166 
167         public void init(FieldODEStateAndDerivative<T> state0, T t) {
168         }
169 
170         public T g(FieldODEStateAndDerivative<T> state) {
171             return state.getPrimaryState()[0].multiply(sign);
172         }
173 
174         public Action eventOccurred(FieldODEStateAndDerivative<T> state,
175                                     FieldODEEventDetector<T> detector,
176                                     boolean increasing) {
177             // this sign change is needed because the state will be reset soon
178             sign = -sign;
179             return Action.RESET_STATE;
180         }
181 
182         public FieldODEState<T> resetState(FieldODEEventDetector<T> detector,
183                                            FieldODEStateAndDerivative<T> state) {
184             T[] y = state.getPrimaryState();
185             y[0] = y[0].negate();
186             y[1] = y[1].negate();
187             return new FieldODEState<T>(state.getTime(), y);
188         }
189 
190     }
191 
192     private static class Stop<T extends CalculusFieldElement<T>> extends BaseDetector<T> {
193 
194         public Stop(final double maxCheck, final T threshold, final int maxIter) {
195             super(maxCheck, threshold, maxIter);
196         }
197 
198         public void init(FieldODEStateAndDerivative<T> state0, T t) {
199         }
200 
201         public T g(FieldODEStateAndDerivative<T> state) {
202             return state.getTime().subtract(12.0);
203         }
204 
205         public Action eventOccurred(FieldODEStateAndDerivative<T> state,
206                                     FieldODEEventDetector<T> detector,
207                                     boolean increasing) {
208             return Action.STOP;
209         }
210 
211         public FieldODEState<T> resetState(FieldODEEventDetector<T> detector,
212                                            FieldODEStateAndDerivative<T> state) {
213             return state;
214         }
215 
216     }
217 
218 }