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