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 org.hipparchus.analysis.UnivariateFunction;
26  import org.hipparchus.analysis.solvers.BracketedUnivariateSolver;
27  import org.hipparchus.analysis.solvers.BracketingNthOrderBrentSolver;
28  import org.hipparchus.ode.events.Action;
29  import org.hipparchus.ode.events.AdaptableInterval;
30  import org.hipparchus.ode.events.ODEEventDetector;
31  import org.hipparchus.ode.events.ODEEventHandler;
32  import org.hipparchus.util.FastMath;
33  
34  /**
35   * This class is used in the junit tests for the ODE integrators.
36  
37   * <p>This specific problem is the following differential equation :
38   * <pre>
39   *    x'' = -x
40   * </pre>
41   * And when x decreases down to 0, the state should be changed as follows :
42   * <pre>
43   *   x' → -x'
44   * </pre>
45   * The theoretical solution of this problem is x = |sin(t+a)|
46   * </p>
47  
48   */
49  public class TestProblem4 extends TestProblemAbstract {
50  
51      private static final double OFFSET = 1.2;
52  
53      /** Time offset. */
54      private double a;
55  
56      /** Simple constructor. */
57      public TestProblem4() {
58          super(0.0, new double[] { FastMath.sin(OFFSET), FastMath.cos(OFFSET) },
59                15, new double[] { 1.0, 0.0 });
60          a = OFFSET;
61      }
62  
63      @Override
64      public ODEEventDetector[] getEventDetectors(final double maxCheck, final double threshold, final int maxIter) {
65          return new ODEEventDetector[] {
66              new Bounce(maxCheck, threshold, maxIter),
67              new Stop(maxCheck, threshold, maxIter)
68          };
69      }
70  
71      /**
72       * Get the theoretical events times.
73       * @return theoretical events times
74       */
75      @Override
76      public double[] getTheoreticalEventsTimes() {
77          return new double[] {
78                               1 * FastMath.PI - a,
79                               2 * FastMath.PI - a,
80                               3 * FastMath.PI - a,
81                               4 * FastMath.PI - a,
82                               12.0
83          };
84      }
85  
86      @Override
87      public double[] doComputeDerivatives(double t, double[] y) {
88          return new double[] {
89            y[1], -y[0]
90          };
91      }
92  
93      @Override
94      public double[] computeTheoreticalState(double t) {
95          double sin = FastMath.sin(t + a);
96          double cos = FastMath.cos(t + a);
97          return new double[] {
98              FastMath.abs(sin),
99              (sin >= 0) ? cos : -cos
100         };
101     }
102 
103     private static abstract class BaseDetector implements ODEEventDetector, ODEEventHandler {
104 
105         final double                                        maxCheck;
106         final int                                           maxIter;
107         final BracketedUnivariateSolver<UnivariateFunction> solver;
108 
109         protected BaseDetector(final double maxCheck, final double threshold, final int maxIter) {
110             this.maxCheck  = maxCheck;
111             this.maxIter   = maxIter;
112             this.solver    = new BracketingNthOrderBrentSolver(0, threshold, 0, 5);
113         }
114 
115         public AdaptableInterval getMaxCheckInterval() {
116             return s -> maxCheck;
117         }
118 
119         public int getMaxIterationCount() {
120             return maxIter;
121         }
122 
123         public BracketedUnivariateSolver<UnivariateFunction> getSolver() {
124             return solver;
125         }
126 
127         public ODEEventHandler getHandler() {
128             return this;
129         }
130 
131     }
132 
133     private static class Bounce extends BaseDetector {
134 
135         private int sign;
136 
137         public Bounce(final double maxCheck, final double threshold, final int maxIter) {
138             super(maxCheck, threshold, maxIter);
139             sign = +1;
140         }
141 
142         public double g(ODEStateAndDerivative s) {
143             return sign * s.getPrimaryState()[0];
144         }
145 
146         public Action eventOccurred(ODEStateAndDerivative s, ODEEventDetector detector, boolean increasing) {
147             // this sign change is needed because the state will be reset soon
148             sign = -sign;
149             return Action.RESET_STATE;
150         }
151 
152         public ODEStateAndDerivative resetState(ODEEventDetector detector, ODEStateAndDerivative s) {
153             final double[] y    = s.getPrimaryState();
154             final double[] yDot = s.getPrimaryDerivative();
155             y[0]    = -y[0];
156             y[1]    = -y[1];
157             yDot[0] = -yDot[0];
158             yDot[1] = -yDot[1];
159             return new ODEStateAndDerivative(s.getTime(), y, yDot);
160         }
161 
162     }
163 
164     private static class Stop extends BaseDetector {
165 
166         public Stop(final double maxCheck, final double threshold, final int maxIter) {
167             super(maxCheck, threshold, maxIter);
168         }
169 
170         public double g(ODEStateAndDerivative s) {
171             return s.getTime() - 12.0;
172         }
173 
174         public Action eventOccurred(ODEStateAndDerivative s, ODEEventDetector detector, boolean increasing) {
175             return Action.STOP;
176         }
177 
178     }
179 
180 }