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 }