1dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond/*
2dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * Licensed to the Apache Software Foundation (ASF) under one or more
3dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * contributor license agreements.  See the NOTICE file distributed with
4dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * this work for additional information regarding copyright ownership.
5dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * The ASF licenses this file to You under the Apache License, Version 2.0
6dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * (the "License"); you may not use this file except in compliance with
7dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * the License.  You may obtain a copy of the License at
8dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *
9dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *      http://www.apache.org/licenses/LICENSE-2.0
10dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *
11dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * Unless required by applicable law or agreed to in writing, software
12dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * distributed under the License is distributed on an "AS IS" BASIS,
13dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * See the License for the specific language governing permissions and
15dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * limitations under the License.
16dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond */
17dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
18dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondpackage org.apache.commons.math.ode.sampling;
19dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
20dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport java.io.IOException;
21dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport java.io.ObjectInput;
22dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport java.io.ObjectOutput;
23dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport java.util.Arrays;
24dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
25dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.ode.DerivativeException;
26dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.linear.Array2DRowRealMatrix;
27dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.util.FastMath;
28dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
29dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond/**
30dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * This class implements an interpolator for integrators using Nordsieck representation.
31dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *
32dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <p>This interpolator computes dense output around the current point.
33dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * The interpolation equation is based on Taylor series formulas.
34dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *
35dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * @see org.apache.commons.math.ode.nonstiff.AdamsBashforthIntegrator
36dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * @see org.apache.commons.math.ode.nonstiff.AdamsMoultonIntegrator
37dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * @version $Revision: 1073158 $ $Date: 2011-02-21 22:46:52 +0100 (lun. 21 févr. 2011) $
38dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * @since 2.0
39dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond */
40dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
41dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondpublic class NordsieckStepInterpolator extends AbstractStepInterpolator {
42dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
43dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Serializable version identifier */
44dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private static final long serialVersionUID = -7179861704951334960L;
45dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
46dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** State variation. */
47dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    protected double[] stateVariation;
48dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
49dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Step size used in the first scaled derivative and Nordsieck vector. */
50dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private double scalingH;
51dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
52dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Reference time for all arrays.
53dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>Sometimes, the reference time is the same as previousTime,
54dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * sometimes it is the same as currentTime, so we use a separate
55dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * field to avoid any confusion.
56dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * </p>
57dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
58dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private double referenceTime;
59dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
60dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** First scaled derivative. */
61dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private double[] scaled;
62dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
63dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Nordsieck vector. */
64dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private Array2DRowRealMatrix nordsieck;
65dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
66dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Simple constructor.
67dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * This constructor builds an instance that is not usable yet, the
68dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * {@link AbstractStepInterpolator#reinitialize} method should be called
69dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * before using the instance in order to initialize the internal arrays. This
70dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * constructor is used only in order to delay the initialization in
71dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * some cases.
72dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
73dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public NordsieckStepInterpolator() {
74dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
75dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
76dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Copy constructor.
77dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param interpolator interpolator to copy from. The copy is a deep
78dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * copy: its arrays are separated from the original arrays of the
79dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * instance
80dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
81dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public NordsieckStepInterpolator(final NordsieckStepInterpolator interpolator) {
82dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        super(interpolator);
83dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        scalingH      = interpolator.scalingH;
84dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        referenceTime = interpolator.referenceTime;
85dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (interpolator.scaled != null) {
86dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            scaled = interpolator.scaled.clone();
87dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
88dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (interpolator.nordsieck != null) {
89dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            nordsieck = new Array2DRowRealMatrix(interpolator.nordsieck.getDataRef(), true);
90dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
91dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (interpolator.stateVariation != null) {
92dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            stateVariation = interpolator.stateVariation.clone();
93dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
94dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
95dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
96dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
97dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    @Override
98dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    protected StepInterpolator doCopy() {
99dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return new NordsieckStepInterpolator(this);
100dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
101dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
102dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Reinitialize the instance.
103dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>Beware that all arrays <em>must</em> be references to integrator
104dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * arrays, in order to ensure proper update without copy.</p>
105dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param y reference to the integrator array holding the state at
106dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * the end of the step
107dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param forward integration direction indicator
108dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
109dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    @Override
110dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public void reinitialize(final double[] y, final boolean forward) {
111dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        super.reinitialize(y, forward);
112dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        stateVariation = new double[y.length];
113dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
114dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
115dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Reinitialize the instance.
116dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>Beware that all arrays <em>must</em> be references to integrator
117dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * arrays, in order to ensure proper update without copy.</p>
118dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param time time at which all arrays are defined
119dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param stepSize step size used in the scaled and nordsieck arrays
120dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param scaledDerivative reference to the integrator array holding the first
121dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * scaled derivative
122dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param nordsieckVector reference to the integrator matrix holding the
123dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * nordsieck vector
124dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
125dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public void reinitialize(final double time, final double stepSize,
126dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                             final double[] scaledDerivative,
127dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                             final Array2DRowRealMatrix nordsieckVector) {
128dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        this.referenceTime = time;
129dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        this.scalingH      = stepSize;
130dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        this.scaled        = scaledDerivative;
131dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        this.nordsieck     = nordsieckVector;
132dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
133dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // make sure the state and derivatives will depend on the new arrays
134dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        setInterpolatedTime(getInterpolatedTime());
135dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
136dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
137dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
138dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Rescale the instance.
139dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>Since the scaled and Nordiseck arrays are shared with the caller,
140dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * this method has the side effect of rescaling this arrays in the caller too.</p>
141dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param stepSize new step size to use in the scaled and nordsieck arrays
142dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
143dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public void rescale(final double stepSize) {
144dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
145dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final double ratio = stepSize / scalingH;
146dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int i = 0; i < scaled.length; ++i) {
147dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            scaled[i] *= ratio;
148dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
149dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
150dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final double[][] nData = nordsieck.getDataRef();
151dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        double power = ratio;
152dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int i = 0; i < nData.length; ++i) {
153dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            power *= ratio;
154dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final double[] nDataI = nData[i];
155dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int j = 0; j < nDataI.length; ++j) {
156dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                nDataI[j] *= power;
157dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
158dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
159dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
160dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        scalingH = stepSize;
161dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
162dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
163dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
164dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
165dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Get the state vector variation from current to interpolated state.
166dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>This method is aimed at computing y(t<sub>interpolation</sub>)
167dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * -y(t<sub>current</sub>) accurately by avoiding the cancellation errors
168dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * that would occur if the subtraction were performed explicitly.</p>
169dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>The returned vector is a reference to a reused array, so
170dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * it should not be modified and it should be copied if it needs
171dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * to be preserved across several calls.</p>
172dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return state vector at time {@link #getInterpolatedTime}
173dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @see #getInterpolatedDerivatives()
174dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws DerivativeException if this call induces an automatic
175dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * step finalization that throws one
176dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
177dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public double[] getInterpolatedStateVariation()
178dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        throws DerivativeException {
179dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // compute and ignore interpolated state
180dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // to make sure state variation is computed as a side effect
181dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        getInterpolatedState();
182dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return stateVariation;
183dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
184dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
185dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
186dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    @Override
187dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    protected void computeInterpolatedStateAndDerivatives(final double theta, final double oneMinusThetaH) {
188dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
189dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final double x = interpolatedTime - referenceTime;
190dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final double normalizedAbscissa = x / scalingH;
191dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
192dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        Arrays.fill(stateVariation, 0.0);
193dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        Arrays.fill(interpolatedDerivatives, 0.0);
194dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
195dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // apply Taylor formula from high order to low order,
196dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // for the sake of numerical accuracy
197dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final double[][] nData = nordsieck.getDataRef();
198dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int i = nData.length - 1; i >= 0; --i) {
199dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final int order = i + 2;
200dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final double[] nDataI = nData[i];
201dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final double power = FastMath.pow(normalizedAbscissa, order);
202dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int j = 0; j < nDataI.length; ++j) {
203dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final double d = nDataI[j] * power;
204dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                stateVariation[j]          += d;
205dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                interpolatedDerivatives[j] += order * d;
206dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
207dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
208dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
209dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int j = 0; j < currentState.length; ++j) {
210dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            stateVariation[j] += scaled[j] * normalizedAbscissa;
211dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            interpolatedState[j] = currentState[j] + stateVariation[j];
212dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            interpolatedDerivatives[j] =
213dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                (interpolatedDerivatives[j] + scaled[j] * normalizedAbscissa) / x;
214dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
215dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
216dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
217dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
218dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
219dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    @Override
220dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public void writeExternal(final ObjectOutput out)
221dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        throws IOException {
222dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
223dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // save the state of the base class
224dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        writeBaseExternal(out);
225dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
226dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // save the local attributes
227dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        out.writeDouble(scalingH);
228dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        out.writeDouble(referenceTime);
229dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
230dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int n = (currentState == null) ? -1 : currentState.length;
231dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (scaled == null) {
232dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            out.writeBoolean(false);
233dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        } else {
234dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            out.writeBoolean(true);
235dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int j = 0; j < n; ++j) {
236dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                out.writeDouble(scaled[j]);
237dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
238dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
239dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
240dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (nordsieck == null) {
241dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            out.writeBoolean(false);
242dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        } else {
243dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            out.writeBoolean(true);
244dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            out.writeObject(nordsieck);
245dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
246dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
247dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // we don't save state variation, it will be recomputed
248dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
249dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
250dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
251dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
252dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    @Override
253dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public void readExternal(final ObjectInput in)
254dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        throws IOException, ClassNotFoundException {
255dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
256dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // read the base class
257dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final double t = readBaseExternal(in);
258dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
259dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // read the local attributes
260dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        scalingH      = in.readDouble();
261dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        referenceTime = in.readDouble();
262dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
263dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int n = (currentState == null) ? -1 : currentState.length;
264dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final boolean hasScaled = in.readBoolean();
265dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (hasScaled) {
266dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            scaled = new double[n];
267dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            for (int j = 0; j < n; ++j) {
268dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                scaled[j] = in.readDouble();
269dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
270dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        } else {
271dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            scaled = null;
272dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
273dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
274dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final boolean hasNordsieck = in.readBoolean();
275dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (hasNordsieck) {
276dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            nordsieck = (Array2DRowRealMatrix) in.readObject();
277dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        } else {
278dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            nordsieck = null;
279dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
280dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
281dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (hasScaled && hasNordsieck) {
282dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // we can now set the interpolated time and state
283dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            stateVariation = new double[n];
284dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            setInterpolatedTime(t);
285dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        } else {
286dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            stateVariation = null;
287dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
288dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
289dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
290dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
291dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond}
292