blob: 42e8363665b5e4d08aabb90d08d642ef39093ab1 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.math3.ode.nonstiff;
import org.apache.commons.math3.analysis.UnivariateFunction;
import org.apache.commons.math3.analysis.polynomials.PolynomialFunction;
import org.apache.commons.math3.linear.Array2DRowRealMatrix;
import org.junit.Assert;
import org.junit.Test;
public class AdamsNordsieckTransformerTest {
@Test
public void testPolynomialExtraDerivative() {
checkNordsieckStart(new PolynomialFunction(new double[] { 6, 5, 4, 3, 2, 1 }),
5, 0.0, 0.125, 3.2e-16);
}
@Test
public void testPolynomialRegular() {
checkNordsieckStart(new PolynomialFunction(new double[] { 6, 5, 4, 3, 2, 1 }),
4, 0.0, 0.125, 3.1e-16);
}
@Test
public void testPolynomialMissingLastDerivative() {
// this test intentionally uses not enough start points,
// the Nordsieck vector is therefore not expected to match the exact scaled derivatives
checkNordsieckStart(new PolynomialFunction(new double[] { 6, 5, 4, 3, 2, 1 }),
3, 0.0, 0.125, 1.6e-4);
}
@Test
public void testTransformExact() {
// a 5 steps transformer handles a degree 5 polynomial exactly
// the Nordsieck vector holds the full information about the function
// transforming the vector from t0 to t0+h or recomputing it from scratch
// at t0+h yields the same result
checkTransform(new PolynomialFunction(new double[] { 6, 5, 4, 3, 2, 1 }), 5, 2.567e-15);
}
@Test
public void testTransformInexact() {
// a 4 steps transformer cannot handle a degree 5 polynomial exactly
// the Nordsieck vector lacks some high degree information about the function
// transforming the vector from t0 to t0+h or recomputing it from scratch
// at t0+h yields different results
checkTransform(new PolynomialFunction(new double[] { 6, 5, 4, 3, 2, 1 }), 4, 5.658e-4);
}
private void checkNordsieckStart(final PolynomialFunction polynomial, final int nbSteps, final double t0,
final double h, final double epsilon) {
final AdamsNordsieckTransformer transformer = AdamsNordsieckTransformer.getInstance(nbSteps);
PolynomialFunction derivative = polynomial.polynomialDerivative();
final Array2DRowRealMatrix nordsieck = start(transformer, nbSteps, t0, h, polynomial, derivative);
Assert.assertEquals(nbSteps - 1, nordsieck.getRowDimension());
double coeff = h;
for (int i = 0; i < nordsieck.getRowDimension(); ++i) {
coeff *= h / (i + 2);
derivative = derivative.polynomialDerivative();
Assert.assertEquals(derivative.value(t0) * coeff, nordsieck.getEntry(i, 0), epsilon);
}
}
private void checkTransform(final PolynomialFunction polynomial, final int nbSteps, final double expectedError) {
final AdamsNordsieckTransformer transformer = AdamsNordsieckTransformer.getInstance(nbSteps);
final PolynomialFunction derivative = polynomial.polynomialDerivative();
final double t0 = 0.0;
final double h = 0.125;
final Array2DRowRealMatrix n0 = start(transformer, nbSteps, t0, h, polynomial, derivative);
final Array2DRowRealMatrix n1 = transformer.updateHighOrderDerivativesPhase1(n0);
transformer.updateHighOrderDerivativesPhase2(new double[] { h * derivative.value(t0) },
new double[] { h * derivative.value(t0 + h) },
n1);
final Array2DRowRealMatrix n2 = start(transformer, nbSteps, t0 + h, h, polynomial, derivative);
Assert.assertEquals(expectedError, n2.subtract(n1).getNorm(), expectedError * 0.001);
}
private Array2DRowRealMatrix start(final AdamsNordsieckTransformer transformer, final int nbSteps,
final double t0, final double h,
final UnivariateFunction f0, final UnivariateFunction f1) {
final int nbStartPoints = (nbSteps + 3) / 2;
final double[] t = new double[nbStartPoints];
final double[][] y = new double[nbStartPoints][1];
final double[][] yDot = new double[nbStartPoints][1];
for (int i = 0; i < nbStartPoints; ++i) {
t[i] = t0 + i * h;
y[i][0] = f0.value(t[i]);
yDot[i][0] = f1.value(t[i]);
}
return transformer.initializeHighOrderDerivatives(h, t, y, yDot);
}
}