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