Home | History | Annotate | Download | only in nonstiff
      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.math.ode.nonstiff;
     19 
     20 import java.io.IOException;
     21 import java.io.ObjectInput;
     22 import java.io.ObjectOutput;
     23 
     24 import org.apache.commons.math.ode.AbstractIntegrator;
     25 import 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 
     37 abstract 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