From 92f005ad13c989d70da393072c4f3d66798e4a1b Mon Sep 17 00:00:00 2001
From: Luc Maisonobe
Date: Fri, 23 Jul 2010 08:59:37 +0000
Subject: [PATCH] Added a feature allowing error estimation to be computed only
on a subset of Ordinary Differential Equations, considered as the main set,
the remaining equations being considered only as an extension set that should
not influence the ODE integration algorithm JIRA: MATH-388
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@967007 13f79535-47bb-0310-9956-ffa450edef68
---
...tendedFirstOrderDifferentialEquations.java | 66 +++++++++++++++++++
.../commons/math/ode/MultistepIntegrator.java | 7 +-
.../FirstOrderIntegratorWithJacobians.java | 11 +++-
.../math/ode/jacobians/ParameterizedODE.java | 3 +-
.../nonstiff/AdamsBashforthIntegrator.java | 4 +-
.../ode/nonstiff/AdamsMoultonIntegrator.java | 18 ++---
.../nonstiff/AdaptiveStepsizeIntegrator.java | 38 ++++++++---
.../nonstiff/DormandPrince54Integrator.java | 4 +-
.../nonstiff/DormandPrince853Integrator.java | 4 +-
.../EmbeddedRungeKuttaIntegrator.java | 2 +-
.../GraggBulirschStoerIntegrator.java | 14 ++--
.../GraggBulirschStoerStepInterpolator.java | 4 +-
.../ode/nonstiff/HighamHall54Integrator.java | 4 +-
src/site/xdoc/changes.xml | 6 ++
...FirstOrderIntegratorWithJacobiansTest.java | 56 ++++++++--------
15 files changed, 171 insertions(+), 70 deletions(-)
create mode 100644 src/main/java/org/apache/commons/math/ode/ExtendedFirstOrderDifferentialEquations.java
diff --git a/src/main/java/org/apache/commons/math/ode/ExtendedFirstOrderDifferentialEquations.java b/src/main/java/org/apache/commons/math/ode/ExtendedFirstOrderDifferentialEquations.java
new file mode 100644
index 000000000..94da709f4
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/ode/ExtendedFirstOrderDifferentialEquations.java
@@ -0,0 +1,66 @@
+/*
+ * 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.math.ode;
+
+
+/** This interface represents a first order differential equations set
+ * with a main set of equations and an extension set.
+ *
+ *
+ * This interface is a simple extension on the {@link
+ * FirstOrderDifferentialEquations} that allows to identify which part
+ * of a complete set of differential equations correspond to the main
+ * set and which part correspond to the extension set.
+ *
+ *
+ * One typical use case is the computation of Jacobians. The main
+ * set of equations correspond to the raw ode, and we add to this set
+ * another bunch of equations which represent the jacobians of the
+ * main set. In that case, we want the integrator to use only
+ * the main set to estimate the errors and hence the step sizes. It should
+ * not use the additional equations in this computation. If the
+ * complete ode implements this interface, the {@link FirstOrderIntegrator
+ * integrator} will be able to know where the main set ends and where the
+ * extended set begins.
+ *
+ *
+ * We consider that the main set always corresponds to the first equations
+ * and the extended set to the last equations.
+ *
+ *
+ * @see FirstOrderDifferentialEquations
+ *
+ * @version $Revision$ $Date$
+ * @since 2.2
+ */
+
+public interface ExtendedFirstOrderDifferentialEquations extends FirstOrderDifferentialEquations {
+
+ /** Return the dimension of the main set of equations.
+ *
+ * The main set of equations represent the first part of an ODE state.
+ * The error estimations and adaptive step size computation should be
+ * done on this first part only, not on the final part of the state
+ * which represent an extension set of equations which are considered
+ * secondary.
+ *
+ * @return dimension of the main set of equations, must be lesser than or
+ * equal to the {@link #getDimension() total dimension}
+ */
+ int getMainSetDimension();
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/commons/math/ode/MultistepIntegrator.java b/src/main/java/org/apache/commons/math/ode/MultistepIntegrator.java
index 5ec05c675..836b897ea 100644
--- a/src/main/java/org/apache/commons/math/ode/MultistepIntegrator.java
+++ b/src/main/java/org/apache/commons/math/ode/MultistepIntegrator.java
@@ -378,7 +378,7 @@ public abstract class MultistepIntegrator extends AdaptiveStepsizeIntegrator {
}
/** Wrapper for differential equations, ensuring start evaluations are counted. */
- private class CountingDifferentialEquations implements FirstOrderDifferentialEquations {
+ private class CountingDifferentialEquations implements ExtendedFirstOrderDifferentialEquations {
/** Dimension of the problem. */
private final int dimension;
@@ -400,6 +400,11 @@ public abstract class MultistepIntegrator extends AdaptiveStepsizeIntegrator {
public int getDimension() {
return dimension;
}
+
+ /** {@inheritDoc} */
+ public int getMainSetDimension() {
+ return mainSetDimension;
+ }
}
}
diff --git a/src/main/java/org/apache/commons/math/ode/jacobians/FirstOrderIntegratorWithJacobians.java b/src/main/java/org/apache/commons/math/ode/jacobians/FirstOrderIntegratorWithJacobians.java
index f8b6c2cfc..15a8d8712 100644
--- a/src/main/java/org/apache/commons/math/ode/jacobians/FirstOrderIntegratorWithJacobians.java
+++ b/src/main/java/org/apache/commons/math/ode/jacobians/FirstOrderIntegratorWithJacobians.java
@@ -27,6 +27,7 @@ import java.util.Collection;
import org.apache.commons.math.MathRuntimeException;
import org.apache.commons.math.MaxEvaluationsExceededException;
import org.apache.commons.math.ode.DerivativeException;
+import org.apache.commons.math.ode.ExtendedFirstOrderDifferentialEquations;
import org.apache.commons.math.ode.FirstOrderDifferentialEquations;
import org.apache.commons.math.ode.FirstOrderIntegrator;
import org.apache.commons.math.ode.IntegratorException;
@@ -354,7 +355,7 @@ public class FirstOrderIntegratorWithJacobians {
}
/** Wrapper class used to map state and jacobians into compound state. */
- private class MappingWrapper implements FirstOrderDifferentialEquations {
+ private class MappingWrapper implements ExtendedFirstOrderDifferentialEquations {
/** Current state. */
private final double[] y;
@@ -388,6 +389,11 @@ public class FirstOrderIntegratorWithJacobians {
return n * (1 + n + k);
}
+ /** {@inheritDoc} */
+ public int getMainSetDimension() {
+ return ode.getDimension();
+ }
+
/** {@inheritDoc} */
public void computeDerivatives(final double t, final double[] z, final double[] zDot)
throws DerivativeException {
@@ -442,8 +448,7 @@ public class FirstOrderIntegratorWithJacobians {
}
/** Wrapper class to compute jacobians by finite differences for ODE which do not compute them themselves. */
- private class FiniteDifferencesWrapper
- implements ODEWithJacobians {
+ private class FiniteDifferencesWrapper implements ODEWithJacobians {
/** Raw ODE without jacobians computation. */
private final ParameterizedODE ode;
diff --git a/src/main/java/org/apache/commons/math/ode/jacobians/ParameterizedODE.java b/src/main/java/org/apache/commons/math/ode/jacobians/ParameterizedODE.java
index a3ad45477..6c0020945 100644
--- a/src/main/java/org/apache/commons/math/ode/jacobians/ParameterizedODE.java
+++ b/src/main/java/org/apache/commons/math/ode/jacobians/ParameterizedODE.java
@@ -29,8 +29,7 @@ import org.apache.commons.math.ode.FirstOrderDifferentialEquations;
* @since 2.1
*/
-public interface ParameterizedODE
- extends FirstOrderDifferentialEquations {
+public interface ParameterizedODE extends FirstOrderDifferentialEquations {
/** Get the number of parameters.
* @return number of parameters
diff --git a/src/main/java/org/apache/commons/math/ode/nonstiff/AdamsBashforthIntegrator.java b/src/main/java/org/apache/commons/math/ode/nonstiff/AdamsBashforthIntegrator.java
index 6ee9bd56c..2e9ccafd3 100644
--- a/src/main/java/org/apache/commons/math/ode/nonstiff/AdamsBashforthIntegrator.java
+++ b/src/main/java/org/apache/commons/math/ode/nonstiff/AdamsBashforthIntegrator.java
@@ -235,7 +235,7 @@ public class AdamsBashforthIntegrator extends AdamsIntegrator {
// evaluate error using the last term of the Taylor expansion
error = 0;
- for (int i = 0; i < y0.length; ++i) {
+ for (int i = 0; i < mainSetDimension; ++i) {
final double yScale = Math.abs(y[i]);
final double tol = (vecAbsoluteTolerance == null) ?
(scalAbsoluteTolerance + scalRelativeTolerance * yScale) :
@@ -243,7 +243,7 @@ public class AdamsBashforthIntegrator extends AdamsIntegrator {
final double ratio = nordsieck.getEntry(lastRow, i) / tol;
error += ratio * ratio;
}
- error = Math.sqrt(error / y0.length);
+ error = Math.sqrt(error / mainSetDimension);
if (error <= 1.0) {
diff --git a/src/main/java/org/apache/commons/math/ode/nonstiff/AdamsMoultonIntegrator.java b/src/main/java/org/apache/commons/math/ode/nonstiff/AdamsMoultonIntegrator.java
index e0e2f0d2c..684a2e2c1 100644
--- a/src/main/java/org/apache/commons/math/ode/nonstiff/AdamsMoultonIntegrator.java
+++ b/src/main/java/org/apache/commons/math/ode/nonstiff/AdamsMoultonIntegrator.java
@@ -419,7 +419,7 @@ public class AdamsMoultonIntegrator extends AdamsIntegrator {
}
/**
- * End visiting te Nordsieck vector.
+ * End visiting the Nordsieck vector.
* The correction is used to control stepsize. So its amplitude is
* considered to be an error, which must be normalized according to
* error control settings. If the normalized value is greater than 1,
@@ -432,15 +432,17 @@ public class AdamsMoultonIntegrator extends AdamsIntegrator {
double error = 0;
for (int i = 0; i < after.length; ++i) {
after[i] += previous[i] + scaled[i];
- final double yScale = Math.max(Math.abs(previous[i]), Math.abs(after[i]));
- final double tol = (vecAbsoluteTolerance == null) ?
- (scalAbsoluteTolerance + scalRelativeTolerance * yScale) :
- (vecAbsoluteTolerance[i] + vecRelativeTolerance[i] * yScale);
- final double ratio = (after[i] - before[i]) / tol;
- error += ratio * ratio;
+ if (i < mainSetDimension) {
+ final double yScale = Math.max(Math.abs(previous[i]), Math.abs(after[i]));
+ final double tol = (vecAbsoluteTolerance == null) ?
+ (scalAbsoluteTolerance + scalRelativeTolerance * yScale) :
+ (vecAbsoluteTolerance[i] + vecRelativeTolerance[i] * yScale);
+ final double ratio = (after[i] - before[i]) / tol;
+ error += ratio * ratio;
+ }
}
- return Math.sqrt(error / after.length);
+ return Math.sqrt(error / mainSetDimension);
}
}
diff --git a/src/main/java/org/apache/commons/math/ode/nonstiff/AdaptiveStepsizeIntegrator.java b/src/main/java/org/apache/commons/math/ode/nonstiff/AdaptiveStepsizeIntegrator.java
index 9811c1497..65348069e 100644
--- a/src/main/java/org/apache/commons/math/ode/nonstiff/AdaptiveStepsizeIntegrator.java
+++ b/src/main/java/org/apache/commons/math/ode/nonstiff/AdaptiveStepsizeIntegrator.java
@@ -19,6 +19,7 @@ package org.apache.commons.math.ode.nonstiff;
import org.apache.commons.math.ode.AbstractIntegrator;
import org.apache.commons.math.ode.DerivativeException;
+import org.apache.commons.math.ode.ExtendedFirstOrderDifferentialEquations;
import org.apache.commons.math.ode.FirstOrderDifferentialEquations;
import org.apache.commons.math.ode.IntegratorException;
import org.apache.commons.math.util.LocalizedFormats;
@@ -36,14 +37,22 @@ import org.apache.commons.math.util.LocalizedFormats;
* where absTol_i is the absolute tolerance for component i of the
* state vector and relTol_i is the relative tolerance for the same
* component. The user can also use only two scalar values absTol and
- * relTol which will be used for all components.
+ * relTol which will be used for all components.
+ *
+ *
+ * If the Ordinary Differential Equations is an {@link ExtendedFirstOrderDifferentialEquations
+ * extended ODE} rather than a {@link FirstOrderDifferentialEquations basic ODE},
+ * then only the {@link ExtendedFirstOrderDifferentialEquations#getMainSetDimension()
+ * main set} part of the state vector is used for stepsize control, not the complete
+ * state vector.
+ *
*
* If the estimated error for ym+1 is such that
*
* sqrt((sum (errEst_i / threshold_i)^2 ) / n) < 1
*
*
- * (where n is the state vector dimension) then the step is accepted,
+ * (where n is the main set dimension) then the step is accepted,
* otherwise the step is rejected and a new attempt is made with a new
* stepsize.
*
@@ -76,6 +85,9 @@ public abstract class AdaptiveStepsizeIntegrator
/** Maximal step. */
private final double maxStep;
+ /** Main set dimension. */
+ protected int mainSetDimension;
+
/** Build an integrator with the given stepsize bounds.
* The default step handler does nothing.
* @param name name of the method
@@ -171,14 +183,20 @@ public abstract class AdaptiveStepsizeIntegrator
super.sanityChecks(equations, t0, y0, t, y);
- if ((vecAbsoluteTolerance != null) && (vecAbsoluteTolerance.length != y0.length)) {
- throw new IntegratorException(
- LocalizedFormats.DIMENSIONS_MISMATCH_SIMPLE, y0.length, vecAbsoluteTolerance.length);
+ if (equations instanceof ExtendedFirstOrderDifferentialEquations) {
+ mainSetDimension = ((ExtendedFirstOrderDifferentialEquations) equations).getMainSetDimension();
+ } else {
+ mainSetDimension = equations.getDimension();
}
- if ((vecRelativeTolerance != null) && (vecRelativeTolerance.length != y0.length)) {
+ if ((vecAbsoluteTolerance != null) && (vecAbsoluteTolerance.length != mainSetDimension)) {
throw new IntegratorException(
- LocalizedFormats.DIMENSIONS_MISMATCH_SIMPLE, y0.length, vecRelativeTolerance.length);
+ LocalizedFormats.DIMENSIONS_MISMATCH_SIMPLE, mainSetDimension, vecAbsoluteTolerance.length);
+ }
+
+ if ((vecRelativeTolerance != null) && (vecRelativeTolerance.length != mainSetDimension)) {
+ throw new IntegratorException(
+ LocalizedFormats.DIMENSIONS_MISMATCH_SIMPLE, mainSetDimension, vecRelativeTolerance.length);
}
}
@@ -187,7 +205,7 @@ public abstract class AdaptiveStepsizeIntegrator
* @param equations differential equations set
* @param forward forward integration indicator
* @param order order of the method
- * @param scale scaling vector for the state vector
+ * @param scale scaling vector for the state vector (can be shorter than state vector)
* @param t0 start time
* @param y0 state vector at t0
* @param yDot0 first time derivative of y0
@@ -213,7 +231,7 @@ public abstract class AdaptiveStepsizeIntegrator
double ratio;
double yOnScale2 = 0;
double yDotOnScale2 = 0;
- for (int j = 0; j < y0.length; ++j) {
+ for (int j = 0; j < scale.length; ++j) {
ratio = y0[j] / scale[j];
yOnScale2 += ratio * ratio;
ratio = yDot0[j] / scale[j];
@@ -234,7 +252,7 @@ public abstract class AdaptiveStepsizeIntegrator
// estimate the second derivative of the solution
double yDDotOnScale = 0;
- for (int j = 0; j < y0.length; ++j) {
+ for (int j = 0; j < scale.length; ++j) {
ratio = (yDot1[j] - yDot0[j]) / scale[j];
yDDotOnScale += ratio * ratio;
}
diff --git a/src/main/java/org/apache/commons/math/ode/nonstiff/DormandPrince54Integrator.java b/src/main/java/org/apache/commons/math/ode/nonstiff/DormandPrince54Integrator.java
index 7ed175a6a..49d161b80 100644
--- a/src/main/java/org/apache/commons/math/ode/nonstiff/DormandPrince54Integrator.java
+++ b/src/main/java/org/apache/commons/math/ode/nonstiff/DormandPrince54Integrator.java
@@ -135,7 +135,7 @@ public class DormandPrince54Integrator extends EmbeddedRungeKuttaIntegrator {
double error = 0;
- for (int j = 0; j < y0.length; ++j) {
+ for (int j = 0; j < mainSetDimension; ++j) {
final double errSum = E1 * yDotK[0][j] + E3 * yDotK[2][j] +
E4 * yDotK[3][j] + E5 * yDotK[4][j] +
E6 * yDotK[5][j] + E7 * yDotK[6][j];
@@ -149,7 +149,7 @@ public class DormandPrince54Integrator extends EmbeddedRungeKuttaIntegrator {
}
- return Math.sqrt(error / y0.length);
+ return Math.sqrt(error / mainSetDimension);
}
diff --git a/src/main/java/org/apache/commons/math/ode/nonstiff/DormandPrince853Integrator.java b/src/main/java/org/apache/commons/math/ode/nonstiff/DormandPrince853Integrator.java
index 2d6b17e29..ebcc9914d 100644
--- a/src/main/java/org/apache/commons/math/ode/nonstiff/DormandPrince853Integrator.java
+++ b/src/main/java/org/apache/commons/math/ode/nonstiff/DormandPrince853Integrator.java
@@ -249,7 +249,7 @@ public class DormandPrince853Integrator extends EmbeddedRungeKuttaIntegrator {
double error1 = 0;
double error2 = 0;
- for (int j = 0; j < y0.length; ++j) {
+ for (int j = 0; j < mainSetDimension; ++j) {
final double errSum1 = E1_01 * yDotK[0][j] + E1_06 * yDotK[5][j] +
E1_07 * yDotK[6][j] + E1_08 * yDotK[7][j] +
E1_09 * yDotK[8][j] + E1_10 * yDotK[9][j] +
@@ -274,7 +274,7 @@ public class DormandPrince853Integrator extends EmbeddedRungeKuttaIntegrator {
den = 1.0;
}
- return Math.abs(h) * error1 / Math.sqrt(y0.length * den);
+ return Math.abs(h) * error1 / Math.sqrt(mainSetDimension * den);
}
diff --git a/src/main/java/org/apache/commons/math/ode/nonstiff/EmbeddedRungeKuttaIntegrator.java b/src/main/java/org/apache/commons/math/ode/nonstiff/EmbeddedRungeKuttaIntegrator.java
index e03be9ed0..2c0f3a8fe 100644
--- a/src/main/java/org/apache/commons/math/ode/nonstiff/EmbeddedRungeKuttaIntegrator.java
+++ b/src/main/java/org/apache/commons/math/ode/nonstiff/EmbeddedRungeKuttaIntegrator.java
@@ -242,7 +242,7 @@ public abstract class EmbeddedRungeKuttaIntegrator
}
if (firstTime) {
- final double[] scale = new double[y0.length];
+ final double[] scale = new double[mainSetDimension];
if (vecAbsoluteTolerance == null) {
for (int i = 0; i < scale.length; ++i) {
scale[i] = scalAbsoluteTolerance + scalRelativeTolerance * Math.abs(y[i]);
diff --git a/src/main/java/org/apache/commons/math/ode/nonstiff/GraggBulirschStoerIntegrator.java b/src/main/java/org/apache/commons/math/ode/nonstiff/GraggBulirschStoerIntegrator.java
index 90c1073d3..5d8045f3c 100644
--- a/src/main/java/org/apache/commons/math/ode/nonstiff/GraggBulirschStoerIntegrator.java
+++ b/src/main/java/org/apache/commons/math/ode/nonstiff/GraggBulirschStoerIntegrator.java
@@ -429,7 +429,7 @@ public class GraggBulirschStoerIntegrator extends AdaptiveStepsizeIntegrator {
/** Update scaling array.
* @param y1 first state vector to use for scaling
* @param y2 second state vector to use for scaling
- * @param scale scaling array to update
+ * @param scale scaling array to update (can be shorter than state)
*/
private void rescale(final double[] y1, final double[] y2, final double[] scale) {
if (vecAbsoluteTolerance == null) {
@@ -451,7 +451,7 @@ public class GraggBulirschStoerIntegrator extends AdaptiveStepsizeIntegrator {
* @param y0 initial value of the state vector at t0
* @param step global step
* @param k iteration number (from 0 to sequence.length - 1)
- * @param scale scaling array
+ * @param scale scaling array (can be shorter than state)
* @param f placeholder where to put the state vector derivatives at each substep
* (element 0 already contains initial derivative)
* @param yMiddle placeholder where to put the state vector at the middle of the step
@@ -500,12 +500,12 @@ public class GraggBulirschStoerIntegrator extends AdaptiveStepsizeIntegrator {
// stability check
if (performTest && (j <= maxChecks) && (k < maxIter)) {
double initialNorm = 0.0;
- for (int l = 0; l < y0.length; ++l) {
+ for (int l = 0; l < scale.length; ++l) {
final double ratio = f[0][l] / scale[l];
initialNorm += ratio * ratio;
}
double deltaNorm = 0.0;
- for (int l = 0; l < y0.length; ++l) {
+ for (int l = 0; l < scale.length; ++l) {
final double ratio = (f[j+1][l] - f[0][l]) / scale[l];
deltaNorm += ratio * ratio;
}
@@ -607,7 +607,7 @@ public class GraggBulirschStoerIntegrator extends AdaptiveStepsizeIntegrator {
}
// initial scaling
- final double[] scale = new double[y0.length];
+ final double[] scale = new double[mainSetDimension];
rescale(y, y, scale);
// initial order selection
@@ -709,11 +709,11 @@ public class GraggBulirschStoerIntegrator extends AdaptiveStepsizeIntegrator {
// estimate the error at the end of the step.
error = 0;
- for (int j = 0; j < y0.length; ++j) {
+ for (int j = 0; j < mainSetDimension; ++j) {
final double e = Math.abs(y1[j] - y1Diag[0][j]) / scale[j];
error += e * e;
}
- error = Math.sqrt(error / y0.length);
+ error = Math.sqrt(error / mainSetDimension);
if ((error > 1.0e15) || ((k > 1) && (error > maxError))) {
// error is too big, we reduce the global step
diff --git a/src/main/java/org/apache/commons/math/ode/nonstiff/GraggBulirschStoerStepInterpolator.java b/src/main/java/org/apache/commons/math/ode/nonstiff/GraggBulirschStoerStepInterpolator.java
index 737131c2b..e91002b81 100644
--- a/src/main/java/org/apache/commons/math/ode/nonstiff/GraggBulirschStoerStepInterpolator.java
+++ b/src/main/java/org/apache/commons/math/ode/nonstiff/GraggBulirschStoerStepInterpolator.java
@@ -297,11 +297,11 @@ class GraggBulirschStoerStepInterpolator
public double estimateError(final double[] scale) {
double error = 0;
if (currentDegree >= 5) {
- for (int i = 0; i < currentState.length; ++i) {
+ for (int i = 0; i < scale.length; ++i) {
final double e = polynoms[currentDegree][i] / scale[i];
error += e * e;
}
- error = Math.sqrt(error / currentState.length) * errfac[currentDegree-5];
+ error = Math.sqrt(error / scale.length) * errfac[currentDegree - 5];
}
return error;
}
diff --git a/src/main/java/org/apache/commons/math/ode/nonstiff/HighamHall54Integrator.java b/src/main/java/org/apache/commons/math/ode/nonstiff/HighamHall54Integrator.java
index c78afeadd..8203d554f 100644
--- a/src/main/java/org/apache/commons/math/ode/nonstiff/HighamHall54Integrator.java
+++ b/src/main/java/org/apache/commons/math/ode/nonstiff/HighamHall54Integrator.java
@@ -108,7 +108,7 @@ public class HighamHall54Integrator extends EmbeddedRungeKuttaIntegrator {
double error = 0;
- for (int j = 0; j < y0.length; ++j) {
+ for (int j = 0; j < mainSetDimension; ++j) {
double errSum = STATIC_E[0] * yDotK[0][j];
for (int l = 1; l < STATIC_E.length; ++l) {
errSum += STATIC_E[l] * yDotK[l][j];
@@ -123,7 +123,7 @@ public class HighamHall54Integrator extends EmbeddedRungeKuttaIntegrator {
}
- return Math.sqrt(error / y0.length);
+ return Math.sqrt(error / mainSetDimension);
}
diff --git a/src/site/xdoc/changes.xml b/src/site/xdoc/changes.xml
index 441ed69f1..2a1336f33 100644
--- a/src/site/xdoc/changes.xml
+++ b/src/site/xdoc/changes.xml
@@ -52,6 +52,12 @@ The type attribute can be add,update,fix,remove.
If the output is not quite correct, check for invisible trailing spaces!
-->
+
+ Added a feature allowing error estimation to be computed only on a subset of
+ Ordinary Differential Equations, considered as the main set, the remaining equations
+ being considered only as an extension set that should not influence the ODE integration
+ algorithm
+
Fixed bug in precondition check (method "setMicrosphereElements").
diff --git a/src/test/java/org/apache/commons/math/ode/jacobians/FirstOrderIntegratorWithJacobiansTest.java b/src/test/java/org/apache/commons/math/ode/jacobians/FirstOrderIntegratorWithJacobiansTest.java
index 436ac9bfd..efbfb8f49 100644
--- a/src/test/java/org/apache/commons/math/ode/jacobians/FirstOrderIntegratorWithJacobiansTest.java
+++ b/src/test/java/org/apache/commons/math/ode/jacobians/FirstOrderIntegratorWithJacobiansTest.java
@@ -40,7 +40,7 @@ public class FirstOrderIntegratorWithJacobiansTest {
// Solving Ordinary Differential Equations I (Nonstiff problems),
// the curves dy/dp = g(b) are in figure 6.5
FirstOrderIntegrator integ =
- new DormandPrince54Integrator(1.0e-8, 100.0, 1.0e-4, 1.0e-4);
+ new DormandPrince54Integrator(1.0e-8, 100.0, new double[] { 1.0e-4, 1.0e-4 }, new double[] { 1.0e-4, 1.0e-4 });
double hP = 1.0e-12;
SummaryStatistics residualsP0 = new SummaryStatistics();
SummaryStatistics residualsP1 = new SummaryStatistics();
@@ -64,7 +64,7 @@ public class FirstOrderIntegratorWithJacobiansTest {
public void testHighAccuracyExternalDifferentiation()
throws IntegratorException, DerivativeException {
FirstOrderIntegrator integ =
- new DormandPrince54Integrator(1.0e-8, 100.0, 1.0e-10, 1.0e-10);
+ new DormandPrince54Integrator(1.0e-8, 100.0, new double[] { 1.0e-10, 1.0e-10 }, new double[] { 1.0e-10, 1.0e-10 });
double hP = 1.0e-12;
SummaryStatistics residualsP0 = new SummaryStatistics();
SummaryStatistics residualsP1 = new SummaryStatistics();
@@ -92,7 +92,7 @@ public class FirstOrderIntegratorWithJacobiansTest {
public void testInternalDifferentiation()
throws IntegratorException, DerivativeException {
FirstOrderIntegrator integ =
- new DormandPrince54Integrator(1.0e-8, 100.0, 1.0e-4, 1.0e-4);
+ new DormandPrince54Integrator(1.0e-8, 100.0, new double[] { 1.0e-4, 1.0e-4 }, new double[] { 1.0e-4, 1.0e-4 });
double hP = 1.0e-12;
SummaryStatistics residualsP0 = new SummaryStatistics();
SummaryStatistics residualsP1 = new SummaryStatistics();
@@ -109,23 +109,23 @@ public class FirstOrderIntegratorWithJacobiansTest {
extInt.setMaxEvaluations(5000);
extInt.integrate(0, z, new double[][] { { 0.0 }, { 1.0 } }, 20.0, z, dZdZ0, dZdP);
Assert.assertEquals(5000, extInt.getMaxEvaluations());
- Assert.assertTrue(extInt.getEvaluations() > 2000);
- Assert.assertTrue(extInt.getEvaluations() < 2500);
+ Assert.assertTrue(extInt.getEvaluations() > 1500);
+ Assert.assertTrue(extInt.getEvaluations() < 2100);
Assert.assertEquals(4 * integ.getEvaluations(), extInt.getEvaluations());
residualsP0.addValue(dZdP[0][0] - brusselator.dYdP0());
residualsP1.addValue(dZdP[1][0] - brusselator.dYdP1());
}
- Assert.assertTrue((residualsP0.getMax() - residualsP0.getMin()) < 0.006);
- Assert.assertTrue(residualsP0.getStandardDeviation() < 0.0009);
- Assert.assertTrue((residualsP1.getMax() - residualsP1.getMin()) < 0.009);
- Assert.assertTrue(residualsP1.getStandardDeviation() < 0.0014);
+ Assert.assertTrue((residualsP0.getMax() - residualsP0.getMin()) < 0.02);
+ Assert.assertTrue(residualsP0.getStandardDeviation() < 0.003);
+ Assert.assertTrue((residualsP1.getMax() - residualsP1.getMin()) < 0.05);
+ Assert.assertTrue(residualsP1.getStandardDeviation() < 0.01);
}
@Test
public void testAnalyticalDifferentiation()
throws IntegratorException, DerivativeException {
FirstOrderIntegrator integ =
- new DormandPrince54Integrator(1.0e-8, 100.0, 1.0e-4, 1.0e-4);
+ new DormandPrince54Integrator(1.0e-8, 100.0, new double[] { 1.0e-4, 1.0e-4 }, new double[] { 1.0e-4, 1.0e-4 });
SummaryStatistics residualsP0 = new SummaryStatistics();
SummaryStatistics residualsP1 = new SummaryStatistics();
for (double b = 2.88; b < 3.08; b += 0.001) {
@@ -139,22 +139,22 @@ public class FirstOrderIntegratorWithJacobiansTest {
extInt.setMaxEvaluations(5000);
extInt.integrate(0, z, new double[][] { { 0.0 }, { 1.0 } }, 20.0, z, dZdZ0, dZdP);
Assert.assertEquals(5000, extInt.getMaxEvaluations());
- Assert.assertTrue(extInt.getEvaluations() > 510);
- Assert.assertTrue(extInt.getEvaluations() < 610);
+ Assert.assertTrue(extInt.getEvaluations() > 350);
+ Assert.assertTrue(extInt.getEvaluations() < 510);
Assert.assertEquals(integ.getEvaluations(), extInt.getEvaluations());
residualsP0.addValue(dZdP[0][0] - brusselator.dYdP0());
residualsP1.addValue(dZdP[1][0] - brusselator.dYdP1());
}
- Assert.assertTrue((residualsP0.getMax() - residualsP0.getMin()) < 0.004);
- Assert.assertTrue(residualsP0.getStandardDeviation() < 0.0008);
- Assert.assertTrue((residualsP1.getMax() - residualsP1.getMin()) < 0.005);
- Assert.assertTrue(residualsP1.getStandardDeviation() < 0.0010);
+ Assert.assertTrue((residualsP0.getMax() - residualsP0.getMin()) < 0.014);
+ Assert.assertTrue(residualsP0.getStandardDeviation() < 0.003);
+ Assert.assertTrue((residualsP1.getMax() - residualsP1.getMin()) < 0.05);
+ Assert.assertTrue(residualsP1.getStandardDeviation() < 0.01);
}
@Test
public void testFinalResult() throws IntegratorException, DerivativeException {
FirstOrderIntegrator integ =
- new DormandPrince54Integrator(1.0e-8, 100.0, 1.0e-10, 1.0e-10);
+ new DormandPrince54Integrator(1.0e-8, 100.0, new double[] { 1.0e-10, 1.0e-10 }, new double[] { 1.0e-10, 1.0e-10 });
double[] y = new double[] { 0.0, 1.0 };
Circle circle = new Circle(y, 1.0, 1.0, 0.1);
double[][] dydy0 = new double[2][2];
@@ -164,16 +164,16 @@ public class FirstOrderIntegratorWithJacobiansTest {
new FirstOrderIntegratorWithJacobians(integ, circle);
extInt.integrate(0, y, circle.exactDyDp(0), t, y, dydy0, dydp);
for (int i = 0; i < y.length; ++i) {
- Assert.assertEquals(circle.exactY(t)[i], y[i], 1.0e-10);
+ Assert.assertEquals(circle.exactY(t)[i], y[i], 1.0e-9);
}
for (int i = 0; i < dydy0.length; ++i) {
for (int j = 0; j < dydy0[i].length; ++j) {
- Assert.assertEquals(circle.exactDyDy0(t)[i][j], dydy0[i][j], 1.0e-10);
+ Assert.assertEquals(circle.exactDyDy0(t)[i][j], dydy0[i][j], 1.0e-9);
}
}
for (int i = 0; i < dydp.length; ++i) {
for (int j = 0; j < dydp[i].length; ++j) {
- Assert.assertEquals(circle.exactDyDp(t)[i][j], dydp[i][j], 1.0e-8);
+ Assert.assertEquals(circle.exactDyDp(t)[i][j], dydp[i][j], 1.0e-7);
}
}
}
@@ -181,7 +181,7 @@ public class FirstOrderIntegratorWithJacobiansTest {
@Test
public void testStepHandlerResult() throws IntegratorException, DerivativeException {
FirstOrderIntegrator integ =
- new DormandPrince54Integrator(1.0e-8, 100.0, 1.0e-10, 1.0e-10);
+ new DormandPrince54Integrator(1.0e-8, 100.0, new double[] { 1.0e-10, 1.0e-10 }, new double[] { 1.0e-10, 1.0e-10 });
double[] y = new double[] { 0.0, 1.0 };
final Circle circle = new Circle(y, 1.0, 1.0, 0.1);
double[][] dydy0 = new double[2][2];
@@ -207,16 +207,16 @@ public class FirstOrderIntegratorWithJacobiansTest {
Assert.assertEquals(interpolator.getPreviousTime(), extInt.getCurrentStepStart(), 1.0e-10);
Assert.assertTrue(extInt.getCurrentSignedStepsize() < 0.5);
for (int i = 0; i < y.length; ++i) {
- Assert.assertEquals(circle.exactY(t)[i], y[i], 1.0e-10);
+ Assert.assertEquals(circle.exactY(t)[i], y[i], 1.0e-9);
}
for (int i = 0; i < dydy0.length; ++i) {
for (int j = 0; j < dydy0[i].length; ++j) {
- Assert.assertEquals(circle.exactDyDy0(t)[i][j], dydy0[i][j], 1.0e-10);
+ Assert.assertEquals(circle.exactDyDy0(t)[i][j], dydy0[i][j], 1.0e-9);
}
}
for (int i = 0; i < dydp.length; ++i) {
for (int j = 0; j < dydp[i].length; ++j) {
- Assert.assertEquals(circle.exactDyDp(t)[i][j], dydp[i][j], 1.0e-8);
+ Assert.assertEquals(circle.exactDyDp(t)[i][j], dydp[i][j], 3.0e-8);
}
}
@@ -225,16 +225,16 @@ public class FirstOrderIntegratorWithJacobiansTest {
double[][] dydpDot = interpolator.getInterpolatedDyDpDot();
for (int i = 0; i < yDot.length; ++i) {
- Assert.assertEquals(circle.exactYDot(t)[i], yDot[i], 1.0e-11);
+ Assert.assertEquals(circle.exactYDot(t)[i], yDot[i], 1.0e-10);
}
for (int i = 0; i < dydy0Dot.length; ++i) {
for (int j = 0; j < dydy0Dot[i].length; ++j) {
- Assert.assertEquals(circle.exactDyDy0Dot(t)[i][j], dydy0Dot[i][j], 1.0e-11);
+ Assert.assertEquals(circle.exactDyDy0Dot(t)[i][j], dydy0Dot[i][j], 1.0e-10);
}
}
for (int i = 0; i < dydpDot.length; ++i) {
for (int j = 0; j < dydpDot[i].length; ++j) {
- Assert.assertEquals(circle.exactDyDpDot(t)[i][j], dydpDot[i][j], 1.0e-9);
+ Assert.assertEquals(circle.exactDyDpDot(t)[i][j], dydpDot[i][j], 3.0e-9);
}
}
}
@@ -245,7 +245,7 @@ public class FirstOrderIntegratorWithJacobiansTest {
@Test
public void testEventHandler() throws IntegratorException, DerivativeException {
FirstOrderIntegrator integ =
- new DormandPrince54Integrator(1.0e-8, 100.0, 1.0e-10, 1.0e-10);
+ new DormandPrince54Integrator(1.0e-8, 100.0, new double[] { 1.0e-10, 1.0e-10 }, new double[] { 1.0e-10, 1.0e-10 });
double[] y = new double[] { 0.0, 1.0 };
final Circle circle = new Circle(y, 1.0, 1.0, 0.1);
double[][] dydy0 = new double[2][2];