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 }