You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by lu...@apache.org on 2015/12/09 17:17:00 UTC

[20/50] [abbrv] [math] Prepared testing framework for step interpolators.

Prepared testing framework for step interpolators.

Project: http://git-wip-us.apache.org/repos/asf/commons-math/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-math/commit/90960027
Tree: http://git-wip-us.apache.org/repos/asf/commons-math/tree/90960027
Diff: http://git-wip-us.apache.org/repos/asf/commons-math/diff/90960027

Branch: refs/heads/MATH_3_X
Commit: 90960027a4deebb9f264e6022164a91d9efede47
Parents: 4a23959
Author: Luc Maisonobe <lu...@apache.org>
Authored: Thu Dec 3 18:11:23 2015 +0100
Committer: Luc Maisonobe <lu...@apache.org>
Committed: Thu Dec 3 18:11:23 2015 +0100

----------------------------------------------------------------------
 ...ractRungeKuttaFieldStepInterpolatorTest.java | 190 +++++++++++++++++++
 .../EulerFieldStepInterpolatorTest.java         |  44 +++++
 .../ode/sampling/StepInterpolatorTestUtils.java |  51 +++++
 3 files changed, 285 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-math/blob/90960027/src/test/java/org/apache/commons/math3/ode/nonstiff/AbstractRungeKuttaFieldStepInterpolatorTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/math3/ode/nonstiff/AbstractRungeKuttaFieldStepInterpolatorTest.java b/src/test/java/org/apache/commons/math3/ode/nonstiff/AbstractRungeKuttaFieldStepInterpolatorTest.java
new file mode 100644
index 0000000..43dfddf
--- /dev/null
+++ b/src/test/java/org/apache/commons/math3/ode/nonstiff/AbstractRungeKuttaFieldStepInterpolatorTest.java
@@ -0,0 +1,190 @@
+/*
+ * 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 java.lang.reflect.InvocationTargetException;
+
+import org.apache.commons.math3.Field;
+import org.apache.commons.math3.RealFieldElement;
+import org.apache.commons.math3.ode.FieldEquationsMapper;
+import org.apache.commons.math3.ode.FieldExpandableODE;
+import org.apache.commons.math3.ode.FieldFirstOrderDifferentialEquations;
+import org.apache.commons.math3.ode.FieldODEStateAndDerivative;
+import org.apache.commons.math3.util.FastMath;
+import org.apache.commons.math3.util.MathArrays;
+import org.junit.Assert;
+import org.junit.Test;
+
+public abstract class AbstractRungeKuttaFieldStepInterpolatorTest {
+
+    protected abstract <T extends RealFieldElement<T>> RungeKuttaFieldStepInterpolator<T>
+        createInterpolator(Field<T> field, boolean forward, FieldEquationsMapper<T> mapper);
+
+    @Test
+    public abstract void interpolationAtBounds();
+
+    protected <T extends RealFieldElement<T>> void doInterpolationAtBounds(final Field<T> field, double epsilon) {
+
+        RungeKuttaFieldStepInterpolator<T> interpolator = setUpInterpolator(field,
+                                                                            new SinCos<>(field),
+                                                                            0.0, new double[] { 0.0, 1.0 }, 0.125);
+
+        Assert.assertEquals(0.0, interpolator.getPreviousState().getTime().getReal(), 1.0e-15);
+        for (int i = 0; i < 2; ++i) {
+            Assert.assertEquals(interpolator.getPreviousState().getState()[i].getReal(),
+                                interpolator.getInterpolatedState(interpolator.getPreviousState().getTime()).getState()[i].getReal(),
+                                epsilon);
+        }
+        Assert.assertEquals(0.125, interpolator.getCurrentState().getTime().getReal(), 1.0e-15);
+        for (int i = 0; i < 2; ++i) {
+            Assert.assertEquals(interpolator.getCurrentState().getState()[i].getReal(),
+                                interpolator.getInterpolatedState(interpolator.getCurrentState().getTime()).getState()[i].getReal(),
+                                epsilon);
+        }
+
+    }
+
+    @Test
+    public abstract void interpolationInside();
+
+    protected <T extends RealFieldElement<T>> void doInterpolationInside(final Field<T> field,
+                                                                         double epsilonSin, double epsilonCos) {
+
+        RungeKuttaFieldStepInterpolator<T> interpolator = setUpInterpolator(field,
+                                                                            new SinCos<>(field),
+                                                                            0.0, new double[] { 0.0, 1.0 }, 0.125);
+
+        int n = 100;
+        double maxErrorSin = 0;
+        double maxErrorCos = 0;
+        for (int i = 0; i <= n; ++i) {
+            T t =     interpolator.getPreviousState().getTime().multiply(n - i).
+                  add(interpolator.getCurrentState().getTime().multiply(i)).
+                  divide(n);
+            FieldODEStateAndDerivative<T> state = interpolator.getInterpolatedState(t);
+            maxErrorSin = FastMath.max(maxErrorSin, state.getState()[0].subtract(t.sin()).abs().getReal());
+            maxErrorCos = FastMath.max(maxErrorCos, state.getState()[1].subtract(t.cos()).abs().getReal());
+        }
+        Assert.assertEquals(0.0, maxErrorSin, epsilonSin);
+        Assert.assertEquals(0.0, maxErrorCos, epsilonCos);
+
+    }
+
+    private <T extends RealFieldElement<T>>
+    RungeKuttaFieldStepInterpolator<T> setUpInterpolator(final Field<T> field,
+                                                         final FieldFirstOrderDifferentialEquations<T> eqn,
+                                                         final double t0, final double[] y0,
+                                                         final double t1) {
+
+        RungeKuttaFieldStepInterpolator<T> interpolator = createInterpolator(field, t1 > t0,
+                                                                             new FieldExpandableODE<T>(eqn).getMapper());
+        // get the Butcher arrays from the field integrator
+        String interpolatorName = interpolator.getClass().getName();
+        String integratorName = interpolatorName.replaceAll("StepInterpolator", "Integrator");
+
+        RungeKuttaFieldIntegrator<T> fieldIntegrator = null;
+        try {
+            @SuppressWarnings("unchecked")
+            Class<RungeKuttaFieldIntegrator<T>> clz = (Class<RungeKuttaFieldIntegrator<T>>) Class.forName(integratorName);
+            try {
+                fieldIntegrator = clz.getConstructor(Field.class, RealFieldElement.class).newInstance(field,
+                                                                                                      field.getOne());
+            } catch (NoSuchMethodException nsme) {
+                try {
+                    fieldIntegrator = clz.getConstructor(Field.class, RealFieldElement.class,
+                                                         RealFieldElement.class, RealFieldElement.class).newInstance(field,
+                                                                                                                     field.getZero().add(0.001),
+                                                                                                                     field.getOne(),
+                                                                                                                     field.getOne(),
+                                                                                                                     field.getOne());
+                } catch (NoSuchMethodException e) {
+                    Assert.fail(e.getLocalizedMessage());
+                }
+            }
+        } catch (InvocationTargetException ite) {
+            Assert.fail(ite.getLocalizedMessage());
+        } catch (IllegalAccessException iae) {
+            Assert.fail(iae.getLocalizedMessage());
+        } catch (InstantiationException ie) {
+            Assert.fail(ie.getLocalizedMessage());
+        } catch (ClassNotFoundException cnfe) {
+            Assert.fail(cnfe.getLocalizedMessage());
+        }
+        T[][] a = fieldIntegrator.getA();
+        T[]   b = fieldIntegrator.getB();
+        T[]   c = fieldIntegrator.getC();
+
+        // store initial state
+        T     t          = field.getZero().add(t0);
+        T[]   fieldY     = MathArrays.buildArray(field, eqn.getDimension());
+        T[][] fieldYDotK = MathArrays.buildArray(field, b.length, -1);
+        for (int i = 0; i < y0.length; ++i) {
+            fieldY[i] = field.getZero().add(y0[i]);
+        }
+        fieldYDotK[0] = eqn.computeDerivatives(t, fieldY);
+        interpolator.storeState(new FieldODEStateAndDerivative<T>(t, fieldY, fieldYDotK[0]));
+        interpolator.shift();
+
+        // perform one integration step, in order to get consistent derivatives
+        T h = field.getZero().add(t1 - t0);
+        for (int k = 0; k < a.length; ++k) {
+            for (int i = 0; i < y0.length; ++i) {
+                fieldY[i] = field.getZero().add(y0[i]);
+                for (int s = 0; s < k; ++s) {
+                    fieldY[i] = fieldY[i].add(h.multiply(a[s][i].multiply(fieldYDotK[s][i])));
+                }
+            }
+            fieldYDotK[k + 1] = eqn.computeDerivatives(h.multiply(c[k]).add(t0), fieldY);
+        }
+        interpolator.setSlopes(fieldYDotK);
+
+        // store state at step end
+        for (int i = 0; i < y0.length; ++i) {
+            fieldY[i] = field.getZero().add(y0[i]);
+            for (int s = 0; s < b.length; ++s) {
+                fieldY[i] = fieldY[i].add(h.multiply(b[s].multiply(fieldYDotK[s][i])));
+            }
+        }
+        interpolator.storeState(new FieldODEStateAndDerivative<T>(field.getZero().add(t1),
+                                                                  fieldY,
+                                                                  eqn.computeDerivatives(field.getZero().add(t1), fieldY)));
+
+        return interpolator;
+
+    }
+
+    private static class SinCos<T extends RealFieldElement<T>> implements FieldFirstOrderDifferentialEquations<T> {
+        private final Field<T> field;
+        protected SinCos(final Field<T> field) {
+            this.field = field;
+        }
+        public int getDimension() {
+            return 2;
+        }
+        public void init(final T t0, final T[] y0, final T finalTime) {
+        }
+        public T[] computeDerivatives(final T t, final T[] y) {
+            T[] yDot = MathArrays.buildArray(field, 2);
+            yDot[0] = y[1];
+            yDot[1] = y[0].negate();
+            return yDot;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-math/blob/90960027/src/test/java/org/apache/commons/math3/ode/nonstiff/EulerFieldStepInterpolatorTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/math3/ode/nonstiff/EulerFieldStepInterpolatorTest.java b/src/test/java/org/apache/commons/math3/ode/nonstiff/EulerFieldStepInterpolatorTest.java
new file mode 100644
index 0000000..5e1aecd
--- /dev/null
+++ b/src/test/java/org/apache/commons/math3/ode/nonstiff/EulerFieldStepInterpolatorTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.Field;
+import org.apache.commons.math3.RealFieldElement;
+import org.apache.commons.math3.ode.FieldEquationsMapper;
+import org.apache.commons.math3.util.Decimal64Field;
+import org.junit.Test;
+
+public class EulerFieldStepInterpolatorTest extends AbstractRungeKuttaFieldStepInterpolatorTest {
+
+    protected <T extends RealFieldElement<T>> RungeKuttaFieldStepInterpolator<T>
+    createInterpolator(Field<T> field, boolean forward, FieldEquationsMapper<T> mapper) {
+        return new EulerFieldStepInterpolator<>(field, forward, mapper);
+    }
+
+    @Test
+    public void interpolationAtBounds() {
+        doInterpolationAtBounds(Decimal64Field.getInstance(), 1.0e-15);
+    }
+
+    @Test
+    public void interpolationInside() {
+        doInterpolationInside(Decimal64Field.getInstance(), 3.3e-4, 7.9e-3);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-math/blob/90960027/src/test/java/org/apache/commons/math3/ode/sampling/StepInterpolatorTestUtils.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/math3/ode/sampling/StepInterpolatorTestUtils.java b/src/test/java/org/apache/commons/math3/ode/sampling/StepInterpolatorTestUtils.java
index 9a98a59..ba47738 100644
--- a/src/test/java/org/apache/commons/math3/ode/sampling/StepInterpolatorTestUtils.java
+++ b/src/test/java/org/apache/commons/math3/ode/sampling/StepInterpolatorTestUtils.java
@@ -17,11 +17,16 @@
 package org.apache.commons.math3.ode.sampling;
 
 
+import org.apache.commons.math3.RealFieldElement;
 import org.apache.commons.math3.exception.DimensionMismatchException;
 import org.apache.commons.math3.exception.MaxCountExceededException;
 import org.apache.commons.math3.exception.NoBracketingException;
 import org.apache.commons.math3.exception.NumberIsTooSmallException;
+import org.apache.commons.math3.ode.FieldExpandableODE;
+import org.apache.commons.math3.ode.FieldFirstOrderIntegrator;
+import org.apache.commons.math3.ode.FieldODEStateAndDerivative;
 import org.apache.commons.math3.ode.FirstOrderIntegrator;
+import org.apache.commons.math3.ode.TestFieldProblemAbstract;
 import org.apache.commons.math3.ode.TestProblemAbstract;
 import org.apache.commons.math3.util.FastMath;
 import org.junit.Assert;
@@ -85,5 +90,51 @@ public class StepInterpolatorTestUtils {
                              problem.getFinalTime(), new double[problem.getDimension()]);
 
     }
+
+    public static <T extends RealFieldElement<T>> void checkDerivativesConsistency(final FieldFirstOrderIntegrator<T> integrator,
+                                                                                   final TestFieldProblemAbstract<T> problem,
+                                                                                   final double threshold) {
+        integrator.addStepHandler(new FieldStepHandler<T>() {
+
+            public void handleStep(FieldStepInterpolator<T> interpolator, boolean isLast)
+                throws MaxCountExceededException {
+
+                final T h = interpolator.getCurrentState().getTime().subtract(interpolator.getPreviousState().getTime()).multiply(0.001);
+                final T t = interpolator.getCurrentState().getTime().subtract(h.multiply(300));
+
+                if (h.abs().subtract(FastMath.ulp(t.getReal()) * 10).getReal() < 0) {
+                    return;
+                }
+
+                final T[] yM4h = interpolator.getInterpolatedState(t.add(h.multiply(-4))).getState();
+                final T[] yM3h = interpolator.getInterpolatedState(t.add(h.multiply(-3))).getState();
+                final T[] yM2h = interpolator.getInterpolatedState(t.add(h.multiply(-2))).getState();
+                final T[] yM1h = interpolator.getInterpolatedState(t.add(h.multiply(-1))).getState();
+                final T[] yP1h = interpolator.getInterpolatedState(t.add(h.multiply( 1))).getState();
+                final T[] yP2h = interpolator.getInterpolatedState(t.add(h.multiply( 2))).getState();
+                final T[] yP3h = interpolator.getInterpolatedState(t.add(h.multiply( 3))).getState();
+                final T[] yP4h = interpolator.getInterpolatedState(t.add(h.multiply( 4))).getState();
+
+                final T[] yDot = interpolator.getInterpolatedState(t).getDerivative();
+
+                for (int i = 0; i < yDot.length; ++i) {
+                    final T approYDot =     yP4h[i].subtract(yM4h[i]).multiply(  -3).
+                                        add(yP3h[i].subtract(yM3h[i]).multiply(  32)).
+                                        add(yP2h[i].subtract(yM2h[i]).multiply(-168)).
+                                        add(yP1h[i].subtract(yM1h[i]).multiply( 672)).
+                                        divide(h.multiply(840));
+                    Assert.assertEquals(approYDot.getReal(), yDot[i].getReal(), threshold);
+                }
+
+            }
+
+            public void init(FieldODEStateAndDerivative<T> state0, T t) {
+            }
+
+        });
+
+        integrator.integrate(new FieldExpandableODE<>(problem), problem.getInitialState(), problem.getFinalTime());
+
+    }
 }