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    *      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  
18  package org.apache.commons.math4.legacy.ode.nonstiff;
19  
20  import java.io.IOException;
21  import java.io.ObjectInput;
22  import java.io.ObjectOutput;
23  
24  import org.apache.commons.math4.legacy.ode.AbstractIntegrator;
25  import org.apache.commons.math4.legacy.ode.EquationsMapper;
26  import org.apache.commons.math4.legacy.ode.sampling.AbstractStepInterpolator;
27  
28  /** This class represents an interpolator over the last step during an
29   * ODE integration for Runge-Kutta and embedded Runge-Kutta integrators.
30   *
31   * @see RungeKuttaIntegrator
32   * @see EmbeddedRungeKuttaIntegrator
33   *
34   * @since 1.2
35   */
36  
37  abstract class RungeKuttaStepInterpolator
38    extends AbstractStepInterpolator {
39  
40      /** Previous state. */
41      protected double[] previousState;
42  
43      /** Slopes at the intermediate points. */
44      protected double[][] yDotK;
45  
46      /** Reference to the integrator. */
47      protected AbstractIntegrator integrator;
48  
49    /** Simple constructor.
50     * This constructor builds an instance that is not usable yet, the
51     * {@link #reinitialize} method should be called before using the
52     * instance in order to initialize the internal arrays. This
53     * constructor is used only in order to delay the initialization in
54     * some cases. The {@link RungeKuttaIntegrator} and {@link
55     * EmbeddedRungeKuttaIntegrator} classes use the prototyping design
56     * pattern to create the step interpolators by cloning an
57     * uninitialized model and latter initializing the copy.
58     */
59    protected RungeKuttaStepInterpolator() {
60      previousState = null;
61      yDotK         = null;
62      integrator    = null;
63    }
64  
65    /** Copy constructor.
66  
67    * <p>The copied interpolator should have been finalized before the
68    * copy, otherwise the copy will not be able to perform correctly any
69    * interpolation and will throw a {@link NullPointerException}
70    * later. Since we don't want this constructor to throw the
71    * exceptions finalization may involve and since we don't want this
72    * method to modify the state of the copied interpolator,
73    * finalization is <strong>not</strong> done automatically, it
74    * remains under user control.</p>
75  
76    * <p>The copy is a deep copy: its arrays are separated from the
77    * original arrays of the instance.</p>
78  
79    * @param interpolator interpolator to copy from.
80  
81    */
82    RungeKuttaStepInterpolator(final RungeKuttaStepInterpolator interpolator) {
83  
84      super(interpolator);
85  
86      if (interpolator.currentState != null) {
87  
88        previousState = interpolator.previousState.clone();
89  
90        yDotK = new double[interpolator.yDotK.length][];
91        for (int k = 0; k < interpolator.yDotK.length; ++k) {
92          yDotK[k] = interpolator.yDotK[k].clone();
93        }
94      } else {
95        previousState = null;
96        yDotK = null;
97      }
98  
99      // we cannot keep any reference to the equations in the copy
100     // the interpolator should have been finalized before
101     integrator = null;
102   }
103 
104   /** Reinitialize the instance
105    * <p>Some Runge-Kutta integrators need fewer functions evaluations
106    * than their counterpart step interpolators. So the interpolator
107    * should perform the last evaluations they need by themselves. The
108    * {@link RungeKuttaIntegrator RungeKuttaIntegrator} and {@link
109    * EmbeddedRungeKuttaIntegrator EmbeddedRungeKuttaIntegrator}
110    * abstract classes call this method in order to let the step
111    * interpolator perform the evaluations it needs. These evaluations
112    * will be performed during the call to <code>doFinalize</code> if
113    * any, i.e. only if the step handler either calls the {@link
114    * AbstractStepInterpolator#finalizeStep finalizeStep} method or the
115    * {@link AbstractStepInterpolator#getInterpolatedState
116    * getInterpolatedState} method (for an interpolator which needs a
117    * finalization) or if it clones the step interpolator.</p>
118    * @param rkIntegrator integrator being used
119    * @param y reference to the integrator array holding the state at
120    * the end of the step
121    * @param yDotArray reference to the integrator array holding all the
122    * intermediate slopes
123    * @param forward integration direction indicator
124    * @param primaryMapper equations mapper for the primary equations set
125    * @param secondaryMappers equations mappers for the secondary equations sets
126    */
127   public void reinitialize(final AbstractIntegrator rkIntegrator,
128                            final double[] y, final double[][] yDotArray, final boolean forward,
129                            final EquationsMapper primaryMapper,
130                            final EquationsMapper[] secondaryMappers) {
131     reinitialize(y, forward, primaryMapper, secondaryMappers);
132     this.previousState = null;
133     this.yDotK = yDotArray;
134     this.integrator = rkIntegrator;
135   }
136 
137   /** {@inheritDoc} */
138   @Override
139   public void shift() {
140     previousState = currentState.clone();
141     super.shift();
142   }
143 
144   /** {@inheritDoc} */
145   @Override
146   public void writeExternal(final ObjectOutput out)
147     throws IOException {
148 
149     // save the state of the base class
150     writeBaseExternal(out);
151 
152     // save the local attributes
153     final int n = (currentState == null) ? -1 : currentState.length;
154     for (int i = 0; i < n; ++i) {
155       out.writeDouble(previousState[i]);
156     }
157 
158     final int kMax = (yDotK == null) ? -1 : yDotK.length;
159     out.writeInt(kMax);
160     for (int k = 0; k < kMax; ++k) {
161       for (int i = 0; i < n; ++i) {
162         out.writeDouble(yDotK[k][i]);
163       }
164     }
165 
166     // we do not save any reference to the equations
167   }
168 
169   /** {@inheritDoc} */
170   @Override
171   public void readExternal(final ObjectInput in)
172     throws IOException, ClassNotFoundException {
173 
174     // read the base class
175     final double t = readBaseExternal(in);
176 
177     // read the local attributes
178     final int n = (currentState == null) ? -1 : currentState.length;
179     if (n < 0) {
180       previousState = null;
181     } else {
182       previousState = new double[n];
183       for (int i = 0; i < n; ++i) {
184         previousState[i] = in.readDouble();
185       }
186     }
187 
188     final int kMax = in.readInt();
189     yDotK = (kMax < 0) ? null : new double[kMax][];
190     for (int k = 0; k < kMax; ++k) {
191       yDotK[k] = (n < 0) ? null : new double[n];
192       for (int i = 0; i < n; ++i) {
193         yDotK[k][i] = in.readDouble();
194       }
195     }
196 
197     integrator = null;
198 
199     if (currentState != null) {
200         // we can now set the interpolated time and state
201         setInterpolatedTime(t);
202     } else {
203         interpolatedTime = t;
204     }
205   }
206 }