Repository: commons-math Updated Branches: refs/heads/field-ode e3827069c -> 779e52410
Field-based version of Dormand-Prince 8(5, 3) method for solving ODE. Project: http://git-wip-us.apache.org/repos/asf/commons-math/repo Commit: http://git-wip-us.apache.org/repos/asf/commons-math/commit/779e5241 Tree: http://git-wip-us.apache.org/repos/asf/commons-math/tree/779e5241 Diff: http://git-wip-us.apache.org/repos/asf/commons-math/diff/779e5241 Branch: refs/heads/field-ode Commit: 779e52410e365f7223bfc5d6e5ad63092a93547f Parents: e382706 Author: Luc Maisonobe <l...@apache.org> Authored: Sun Nov 15 21:58:17 2015 +0100 Committer: Luc Maisonobe <l...@apache.org> Committed: Sun Nov 15 21:58:17 2015 +0100 ---------------------------------------------------------------------- .../DormandPrince853FieldIntegrator.java | 301 ++++++++++++ .../DormandPrince853FieldStepInterpolator.java | 476 +++++++++++++++++++ 2 files changed, 777 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/commons-math/blob/779e5241/src/main/java/org/apache/commons/math3/ode/nonstiff/DormandPrince853FieldIntegrator.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/math3/ode/nonstiff/DormandPrince853FieldIntegrator.java b/src/main/java/org/apache/commons/math3/ode/nonstiff/DormandPrince853FieldIntegrator.java new file mode 100644 index 0000000..c4a574c --- /dev/null +++ b/src/main/java/org/apache/commons/math3/ode/nonstiff/DormandPrince853FieldIntegrator.java @@ -0,0 +1,301 @@ +/* + * 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.util.FastMath; +import org.apache.commons.math3.util.MathUtils; + + +/** + * This class implements the 8(5,3) Dormand-Prince integrator for Ordinary + * Differential Equations. + * + * <p>This integrator is an embedded Runge-Kutta integrator + * of order 8(5,3) used in local extrapolation mode (i.e. the solution + * is computed using the high order formula) with stepsize control + * (and automatic step initialization) and continuous output. This + * method uses 12 functions evaluations per step for integration and 4 + * evaluations for interpolation. However, since the first + * interpolation evaluation is the same as the first integration + * evaluation of the next step, we have included it in the integrator + * rather than in the interpolator and specified the method was an + * <i>fsal</i>. Hence, despite we have 13 stages here, the cost is + * really 12 evaluations per step even if no interpolation is done, + * and the overcost of interpolation is only 3 evaluations.</p> + * + * <p>This method is based on an 8(6) method by Dormand and Prince + * (i.e. order 8 for the integration and order 6 for error estimation) + * modified by Hairer and Wanner to use a 5th order error estimator + * with 3rd order correction. This modification was introduced because + * the original method failed in some cases (wrong steps can be + * accepted when step size is too large, for example in the + * Brusselator problem) and also had <i>severe difficulties when + * applied to problems with discontinuities</i>. This modification is + * explained in the second edition of the first volume (Nonstiff + * Problems) of the reference book by Hairer, Norsett and Wanner: + * <i>Solving Ordinary Differential Equations</i> (Springer-Verlag, + * ISBN 3-540-56670-8).</p> + * + * @param <T> the type of the field elements + * @since 3.6 + */ + +public class DormandPrince853FieldIntegrator<T extends RealFieldElement<T>> + extends EmbeddedRungeKuttaFieldIntegrator<T> { + + /** Integrator method name. */ + private static final String METHOD_NAME = "Dormand-Prince 8 (5, 3)"; + + /** Time steps Butcher array. */ + private static final double[] STATIC_C = { + (12.0 - 2.0 * FastMath.sqrt(6.0)) / 135.0, (6.0 - FastMath.sqrt(6.0)) / 45.0, (6.0 - FastMath.sqrt(6.0)) / 30.0, + (6.0 + FastMath.sqrt(6.0)) / 30.0, 1.0/3.0, 1.0/4.0, 4.0/13.0, 127.0/195.0, 3.0/5.0, + 6.0/7.0, 1.0, 1.0 + }; + + /** Internal weights Butcher array. */ + private static final double[][] STATIC_A = { + + // k2 + {(12.0 - 2.0 * FastMath.sqrt(6.0)) / 135.0}, + + // k3 + {(6.0 - FastMath.sqrt(6.0)) / 180.0, (6.0 - FastMath.sqrt(6.0)) / 60.0}, + + // k4 + {(6.0 - FastMath.sqrt(6.0)) / 120.0, 0.0, (6.0 - FastMath.sqrt(6.0)) / 40.0}, + + // k5 + {(462.0 + 107.0 * FastMath.sqrt(6.0)) / 3000.0, 0.0, + (-402.0 - 197.0 * FastMath.sqrt(6.0)) / 1000.0, (168.0 + 73.0 * FastMath.sqrt(6.0)) / 375.0}, + + // k6 + {1.0 / 27.0, 0.0, 0.0, (16.0 + FastMath.sqrt(6.0)) / 108.0, (16.0 - FastMath.sqrt(6.0)) / 108.0}, + + // k7 + {19.0 / 512.0, 0.0, 0.0, (118.0 + 23.0 * FastMath.sqrt(6.0)) / 1024.0, + (118.0 - 23.0 * FastMath.sqrt(6.0)) / 1024.0, -9.0 / 512.0}, + + // k8 + {13772.0 / 371293.0, 0.0, 0.0, (51544.0 + 4784.0 * FastMath.sqrt(6.0)) / 371293.0, + (51544.0 - 4784.0 * FastMath.sqrt(6.0)) / 371293.0, -5688.0 / 371293.0, 3072.0 / 371293.0}, + + // k9 + {58656157643.0 / 93983540625.0, 0.0, 0.0, + (-1324889724104.0 - 318801444819.0 * FastMath.sqrt(6.0)) / 626556937500.0, + (-1324889724104.0 + 318801444819.0 * FastMath.sqrt(6.0)) / 626556937500.0, + 96044563816.0 / 3480871875.0, 5682451879168.0 / 281950621875.0, + -165125654.0 / 3796875.0}, + + // k10 + {8909899.0 / 18653125.0, 0.0, 0.0, + (-4521408.0 - 1137963.0 * FastMath.sqrt(6.0)) / 2937500.0, + (-4521408.0 + 1137963.0 * FastMath.sqrt(6.0)) / 2937500.0, + 96663078.0 / 4553125.0, 2107245056.0 / 137915625.0, + -4913652016.0 / 147609375.0, -78894270.0 / 3880452869.0}, + + // k11 + {-20401265806.0 / 21769653311.0, 0.0, 0.0, + (354216.0 + 94326.0 * FastMath.sqrt(6.0)) / 112847.0, + (354216.0 - 94326.0 * FastMath.sqrt(6.0)) / 112847.0, + -43306765128.0 / 5313852383.0, -20866708358144.0 / 1126708119789.0, + 14886003438020.0 / 654632330667.0, 35290686222309375.0 / 14152473387134411.0, + -1477884375.0 / 485066827.0}, + + // k12 + {39815761.0 / 17514443.0, 0.0, 0.0, + (-3457480.0 - 960905.0 * FastMath.sqrt(6.0)) / 551636.0, + (-3457480.0 + 960905.0 * FastMath.sqrt(6.0)) / 551636.0, + -844554132.0 / 47026969.0, 8444996352.0 / 302158619.0, + -2509602342.0 / 877790785.0, -28388795297996250.0 / 3199510091356783.0, + 226716250.0 / 18341897.0, 1371316744.0 / 2131383595.0}, + + // k13 should be for interpolation only, but since it is the same + // stage as the first evaluation of the next step, we perform it + // here at no cost by specifying this is an fsal method + {104257.0/1920240.0, 0.0, 0.0, 0.0, 0.0, 3399327.0/763840.0, + 66578432.0/35198415.0, -1674902723.0/288716400.0, + 54980371265625.0/176692375811392.0, -734375.0/4826304.0, + 171414593.0/851261400.0, 137909.0/3084480.0} + + }; + + /** Propagation weights Butcher array. */ + private static final double[] STATIC_B = { + 104257.0/1920240.0, + 0.0, + 0.0, + 0.0, + 0.0, + 3399327.0/763840.0, + 66578432.0/35198415.0, + -1674902723.0/288716400.0, + 54980371265625.0/176692375811392.0, + -734375.0/4826304.0, + 171414593.0/851261400.0, + 137909.0/3084480.0, + 0.0 + }; + + /** First error weights array, element 1. */ + private static final double E1_01 = 116092271.0 / 8848465920.0; + + // elements 2 to 5 are zero, so they are neither stored nor used + + /** First error weights array, element 6. */ + private static final double E1_06 = -1871647.0 / 1527680.0; + + /** First error weights array, element 7. */ + private static final double E1_07 = -69799717.0 / 140793660.0; + + /** First error weights array, element 8. */ + private static final double E1_08 = 1230164450203.0 / 739113984000.0; + + /** First error weights array, element 9. */ + private static final double E1_09 = -1980813971228885.0 / 5654156025964544.0; + + /** First error weights array, element 10. */ + private static final double E1_10 = 464500805.0 / 1389975552.0; + + /** First error weights array, element 11. */ + private static final double E1_11 = 1606764981773.0 / 19613062656000.0; + + /** First error weights array, element 12. */ + private static final double E1_12 = -137909.0 / 6168960.0; + + + /** Second error weights array, element 1. */ + private static final double E2_01 = -364463.0 / 1920240.0; + + // elements 2 to 5 are zero, so they are neither stored nor used + + /** Second error weights array, element 6. */ + private static final double E2_06 = 3399327.0 / 763840.0; + + /** Second error weights array, element 7. */ + private static final double E2_07 = 66578432.0 / 35198415.0; + + /** Second error weights array, element 8. */ + private static final double E2_08 = -1674902723.0 / 288716400.0; + + /** Second error weights array, element 9. */ + private static final double E2_09 = -74684743568175.0 / 176692375811392.0; + + /** Second error weights array, element 10. */ + private static final double E2_10 = -734375.0 / 4826304.0; + + /** Second error weights array, element 11. */ + private static final double E2_11 = 171414593.0 / 851261400.0; + + /** Second error weights array, element 12. */ + private static final double E2_12 = 69869.0 / 3084480.0; + + /** Simple constructor. + * Build an eighth order Dormand-Prince integrator with the given step bounds + * @param field field to which the time and state vector elements belong + * @param minStep minimal step (sign is irrelevant, regardless of + * integration direction, forward or backward), the last step can + * be smaller than this + * @param maxStep maximal step (sign is irrelevant, regardless of + * integration direction, forward or backward), the last step can + * be smaller than this + * @param scalAbsoluteTolerance allowed absolute error + * @param scalRelativeTolerance allowed relative error + */ + public DormandPrince853FieldIntegrator(final Field<T> field, + final double minStep, final double maxStep, + final double scalAbsoluteTolerance, + final double scalRelativeTolerance) { + super(field, METHOD_NAME, true, STATIC_C, STATIC_A, STATIC_B, + new DormandPrince853FieldStepInterpolator<T>(), + minStep, maxStep, scalAbsoluteTolerance, scalRelativeTolerance); + } + + /** Simple constructor. + * Build an eighth order Dormand-Prince integrator with the given step bounds + * @param field field to which the time and state vector elements belong + * @param minStep minimal step (sign is irrelevant, regardless of + * integration direction, forward or backward), the last step can + * be smaller than this + * @param maxStep maximal step (sign is irrelevant, regardless of + * integration direction, forward or backward), the last step can + * be smaller than this + * @param vecAbsoluteTolerance allowed absolute error + * @param vecRelativeTolerance allowed relative error + */ + public DormandPrince853FieldIntegrator(final Field<T> field, + final double minStep, final double maxStep, + final double[] vecAbsoluteTolerance, + final double[] vecRelativeTolerance) { + super(field, METHOD_NAME, true, STATIC_C, STATIC_A, STATIC_B, + new DormandPrince853FieldStepInterpolator<T>(), + minStep, maxStep, vecAbsoluteTolerance, vecRelativeTolerance); + } + + /** {@inheritDoc} */ + @Override + public int getOrder() { + return 8; + } + + /** {@inheritDoc} */ + @Override + protected T estimateError(final T[][] yDotK, final T[] y0, final T[] y1, final T h) { + T error1 = h.getField().getZero(); + T error2 = h.getField().getZero(); + + for (int j = 0; j < mainSetDimension; ++j) { + final T errSum1 = yDotK[ 0][j].multiply(E1_01). + add(yDotK[ 5][j].multiply(E1_06)). + add(yDotK[ 6][j].multiply(E1_07)). + add(yDotK[ 7][j].multiply(E1_08)). + add(yDotK[ 8][j].multiply(E1_09)). + add(yDotK[ 9][j].multiply(E1_10)). + add(yDotK[10][j].multiply(E1_11)). + add(yDotK[11][j].multiply(E1_12)); + final T errSum2 = yDotK[ 0][j].multiply(E2_01). + add(yDotK[ 5][j].multiply(E2_06)). + add(yDotK[ 6][j].multiply(E2_07)). + add(yDotK[ 7][j].multiply(E2_08)). + add(yDotK[ 8][j].multiply(E2_09)). + add(yDotK[ 9][j].multiply(E2_10)). + add(yDotK[10][j].multiply(E2_11)). + add(yDotK[11][j].multiply(E2_12)); + + final T yScale = MathUtils.max(y0[j].abs(), y1[j].abs()); + final T tol = vecAbsoluteTolerance == null ? + yScale.multiply(scalRelativeTolerance).add(scalAbsoluteTolerance) : + yScale.multiply(vecRelativeTolerance[j]).add(vecAbsoluteTolerance[j]); + final T ratio1 = errSum1.divide(tol); + error1 = error1.add(ratio1.multiply(ratio1)); + final T ratio2 = errSum2.divide(tol); + error2 = error2.add(ratio2.multiply(ratio2)); + } + + T den = error1.add(error2.multiply(0.01)); + if (den.getReal() <= 0.0) { + den = h.getField().getOne(); + } + + return h.abs().multiply(error1).divide(den.multiply(mainSetDimension).sqrt()); + + } + +} http://git-wip-us.apache.org/repos/asf/commons-math/blob/779e5241/src/main/java/org/apache/commons/math3/ode/nonstiff/DormandPrince853FieldStepInterpolator.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/math3/ode/nonstiff/DormandPrince853FieldStepInterpolator.java b/src/main/java/org/apache/commons/math3/ode/nonstiff/DormandPrince853FieldStepInterpolator.java new file mode 100644 index 0000000..b777b4d --- /dev/null +++ b/src/main/java/org/apache/commons/math3/ode/nonstiff/DormandPrince853FieldStepInterpolator.java @@ -0,0 +1,476 @@ +/* + * 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.exception.MaxCountExceededException; +import org.apache.commons.math3.ode.FieldEquationsMapper; +import org.apache.commons.math3.ode.FieldODEStateAndDerivative; +import org.apache.commons.math3.util.MathArrays; + +/** + * This class represents an interpolator over the last step during an + * ODE integration for the 8(5,3) Dormand-Prince integrator. + * + * @see DormandPrince853FieldIntegrator + * + * @param <T> the type of the field elements + * @since 3.6 + */ + +class DormandPrince853FieldStepInterpolator<T extends RealFieldElement<T>> + extends RungeKuttaFieldStepInterpolator<T> { + + /** Propagation weights, element 1. */ + private static final double B_01 = 104257.0 / 1920240.0; + + // elements 2 to 5 are zero, so they are neither stored nor used + + /** Propagation weights, element 6. */ + private static final double B_06 = 3399327.0 / 763840.0; + + /** Propagation weights, element 7. */ + private static final double B_07 = 66578432.0 / 35198415.0; + + /** Propagation weights, element 8. */ + private static final double B_08 = -1674902723.0 / 288716400.0; + + /** Propagation weights, element 9. */ + private static final double B_09 = 54980371265625.0 / 176692375811392.0; + + /** Propagation weights, element 10. */ + private static final double B_10 = -734375.0 / 4826304.0; + + /** Propagation weights, element 11. */ + private static final double B_11 = 171414593.0 / 851261400.0; + + /** Propagation weights, element 12. */ + private static final double B_12 = 137909.0 / 3084480.0; + + /** Time step for stage 14 (interpolation only). */ + private static final double C14 = 1.0 / 10.0; + + /** Internal weights for stage 14, element 1. */ + private static final double K14_01 = 13481885573.0 / 240030000000.0 - B_01; + + // elements 2 to 5 are zero, so they are neither stored nor used + + /** Internal weights for stage 14, element 6. */ + private static final double K14_06 = 0.0 - B_06; + + /** Internal weights for stage 14, element 7. */ + private static final double K14_07 = 139418837528.0 / 549975234375.0 - B_07; + + /** Internal weights for stage 14, element 8. */ + private static final double K14_08 = -11108320068443.0 / 45111937500000.0 - B_08; + + /** Internal weights for stage 14, element 9. */ + private static final double K14_09 = -1769651421925959.0 / 14249385146080000.0 - B_09; + + /** Internal weights for stage 14, element 10. */ + private static final double K14_10 = 57799439.0 / 377055000.0 - B_10; + + /** Internal weights for stage 14, element 11. */ + private static final double K14_11 = 793322643029.0 / 96734250000000.0 - B_11; + + /** Internal weights for stage 14, element 12. */ + private static final double K14_12 = 1458939311.0 / 192780000000.0 - B_12; + + /** Internal weights for stage 14, element 13. */ + private static final double K14_13 = -4149.0 / 500000.0; + + /** Time step for stage 15 (interpolation only). */ + private static final double C15 = 1.0 / 5.0; + + + /** Internal weights for stage 15, element 1. */ + private static final double K15_01 = 1595561272731.0 / 50120273500000.0 - B_01; + + // elements 2 to 5 are zero, so they are neither stored nor used + + /** Internal weights for stage 15, element 6. */ + private static final double K15_06 = 975183916491.0 / 34457688031250.0 - B_06; + + /** Internal weights for stage 15, element 7. */ + private static final double K15_07 = 38492013932672.0 / 718912673015625.0 - B_07; + + /** Internal weights for stage 15, element 8. */ + private static final double K15_08 = -1114881286517557.0 / 20298710767500000.0 - B_08; + + /** Internal weights for stage 15, element 9. */ + private static final double K15_09 = 0.0 - B_09; + + /** Internal weights for stage 15, element 10. */ + private static final double K15_10 = 0.0 - B_10; + + /** Internal weights for stage 15, element 11. */ + private static final double K15_11 = -2538710946863.0 / 23431227861250000.0 - B_11; + + /** Internal weights for stage 15, element 12. */ + private static final double K15_12 = 8824659001.0 / 23066716781250.0 - B_12; + + /** Internal weights for stage 15, element 13. */ + private static final double K15_13 = -11518334563.0 / 33831184612500.0; + + /** Internal weights for stage 15, element 14. */ + private static final double K15_14 = 1912306948.0 / 13532473845.0; + + /** Time step for stage 16 (interpolation only). */ + private static final double C16 = 7.0 / 9.0; + + + /** Internal weights for stage 16, element 1. */ + private static final double K16_01 = -13613986967.0 / 31741908048.0 - B_01; + + // elements 2 to 5 are zero, so they are neither stored nor used + + /** Internal weights for stage 16, element 6. */ + private static final double K16_06 = -4755612631.0 / 1012344804.0 - B_06; + + /** Internal weights for stage 16, element 7. */ + private static final double K16_07 = 42939257944576.0 / 5588559685701.0 - B_07; + + /** Internal weights for stage 16, element 8. */ + private static final double K16_08 = 77881972900277.0 / 19140370552944.0 - B_08; + + /** Internal weights for stage 16, element 9. */ + private static final double K16_09 = 22719829234375.0 / 63689648654052.0 - B_09; + + /** Internal weights for stage 16, element 10. */ + private static final double K16_10 = 0.0 - B_10; + + /** Internal weights for stage 16, element 11. */ + private static final double K16_11 = 0.0 - B_11; + + /** Internal weights for stage 16, element 12. */ + private static final double K16_12 = 0.0 - B_12; + + /** Internal weights for stage 16, element 13. */ + private static final double K16_13 = -1199007803.0 / 857031517296.0; + + /** Internal weights for stage 16, element 14. */ + private static final double K16_14 = 157882067000.0 / 53564469831.0; + + /** Internal weights for stage 16, element 15. */ + private static final double K16_15 = -290468882375.0 / 31741908048.0; + + /** Interpolation weights. + * (beware that only the non-null values are in the table) + */ + private static final double[][] D = { + + { -17751989329.0 / 2106076560.0, 4272954039.0 / 7539864640.0, + -118476319744.0 / 38604839385.0, 755123450731.0 / 316657731600.0, + 3692384461234828125.0 / 1744130441634250432.0, -4612609375.0 / 5293382976.0, + 2091772278379.0 / 933644586600.0, 2136624137.0 / 3382989120.0, + -126493.0 / 1421424.0, 98350000.0 / 5419179.0, + -18878125.0 / 2053168.0, -1944542619.0 / 438351368.0}, + + { 32941697297.0 / 3159114840.0, 456696183123.0 / 1884966160.0, + 19132610714624.0 / 115814518155.0, -177904688592943.0 / 474986597400.0, + -4821139941836765625.0 / 218016305204281304.0, 30702015625.0 / 3970037232.0, + -85916079474274.0 / 2800933759800.0, -5919468007.0 / 634310460.0, + 2479159.0 / 157936.0, -18750000.0 / 602131.0, + -19203125.0 / 2053168.0, 15700361463.0 / 438351368.0}, + + { 12627015655.0 / 631822968.0, -72955222965.0 / 188496616.0, + -13145744952320.0 / 69488710893.0, 30084216194513.0 / 56998391688.0, + -296858761006640625.0 / 25648977082856624.0, 569140625.0 / 82709109.0, + -18684190637.0 / 18672891732.0, 69644045.0 / 89549712.0, + -11847025.0 / 4264272.0, -978650000.0 / 16257537.0, + 519371875.0 / 6159504.0, 5256837225.0 / 438351368.0}, + + { -450944925.0 / 17550638.0, -14532122925.0 / 94248308.0, + -595876966400.0 / 2573655959.0, 188748653015.0 / 527762886.0, + 2545485458115234375.0 / 27252038150535163.0, -1376953125.0 / 36759604.0, + 53995596795.0 / 518691437.0, 210311225.0 / 7047894.0, + -1718875.0 / 39484.0, 58000000.0 / 602131.0, + -1546875.0 / 39484.0, -1262172375.0 / 8429834.0} + + }; + + /** Last evaluations. */ + private T[][] yDotKLast; + + /** Vectors for interpolation. */ + private T[][] v; + + /** Initialization indicator for the interpolation vectors. */ + private boolean vectorsInitialized; + + /** Simple constructor. + * This constructor builds an instance that is not usable yet, the + * {@link #reinitialize} method should be called before using the + * instance in order to initialize the internal arrays. This + * constructor is used only in order to delay the initialization in + * some cases. The {@link EmbeddedRungeKuttaIntegrator} uses the + * prototyping design pattern to create the step interpolators by + * cloning an uninitialized model and latter initializing the copy. + */ + DormandPrince853FieldStepInterpolator() { + super(); + yDotKLast = null; + v = null; + vectorsInitialized = false; + } + + /** Copy constructor. + * @param interpolator interpolator to copy from. The copy is a deep + * copy: its arrays are separated from the original arrays of the + * instance + */ + DormandPrince853FieldStepInterpolator(final DormandPrince853FieldStepInterpolator<T> interpolator) { + + super(interpolator); + + if (interpolator.currentState == null) { + + yDotKLast = null; + v = null; + vectorsInitialized = false; + + } else { + + final int dimension = interpolator.currentState.length; + final Field<T> field = interpolator.getGlobalPreviousState().getTime().getField(); + + yDotKLast = MathArrays.buildArray(field, 3, dimension); + for (int k = 0; k < yDotKLast.length; ++k) { + System.arraycopy(interpolator.yDotKLast[k], 0, yDotKLast[k], 0, + dimension); + } + + v = MathArrays.buildArray(field, 7, dimension); + for (int k = 0; k < v.length; ++k) { + System.arraycopy(interpolator.v[k], 0, v[k], 0, dimension); + } + + vectorsInitialized = interpolator.vectorsInitialized; + + } + + } + + /** {@inheritDoc} */ + @Override + protected DormandPrince853FieldStepInterpolator<T> doCopy() { + return new DormandPrince853FieldStepInterpolator<T>(this); + } + + /** {@inheritDoc} */ + @Override + public void reinitialize(final T[] y, final boolean isForward, final FieldEquationsMapper<T> equationsMapper) { + + super.reinitialize(y, isForward, equationsMapper); + + final int dimension = currentState.length; + + yDotKLast = MathArrays.buildArray(y[0].getField(), 3, dimension); + v = MathArrays.buildArray(y[0].getField(), 7, dimension); + + vectorsInitialized = false; + + } + + /** {@inheritDoc} */ + @Override + public void storeState(final FieldODEStateAndDerivative<T> state) { + super.storeState(state); + vectorsInitialized = false; + } + + /** {@inheritDoc} */ + @Override + protected FieldODEStateAndDerivative<T> computeInterpolatedStateAndDerivatives(final FieldEquationsMapper<T> mapper, + final T time, final T theta, + final T oneMinusThetaH) + throws MaxCountExceededException { + + if (! vectorsInitialized) { + + if (v == null) { + v = MathArrays.buildArray(time.getField(), 7, previousState.length); + } + + // perform the last evaluations if they have not been done yet + finalizeStep(); + + // compute the interpolation vectors for this time step + for (int i = 0; i < previousState.length; ++i) { + final T yDot01 = yDotK[0][i]; + final T yDot06 = yDotK[5][i]; + final T yDot07 = yDotK[6][i]; + final T yDot08 = yDotK[7][i]; + final T yDot09 = yDotK[8][i]; + final T yDot10 = yDotK[9][i]; + final T yDot11 = yDotK[10][i]; + final T yDot12 = yDotK[11][i]; + final T yDot13 = yDotK[12][i]; + final T yDot14 = yDotKLast[0][i]; + final T yDot15 = yDotKLast[1][i]; + final T yDot16 = yDotKLast[2][i]; + v[0][i] = yDot01.multiply(B_01). + add(yDot06.multiply(B_06)). + add(yDot07.multiply(B_07)). + add(yDot08.multiply(B_08)). + add(yDot09.multiply(B_09)). + add(yDot10.multiply(B_10)). + add(yDot11.multiply(B_11)). + add(yDot12.multiply(B_12)); + v[1][i] = yDot01.subtract(v[0][i]); + v[2][i] = v[0][i].subtract(v[1][i]).subtract(yDotK[12][i]); + for (int k = 0; k < D.length; ++k) { + v[k+3][i] = yDot01.multiply(D[k][ 0]). + add(yDot06.multiply(D[k][ 1])). + add(yDot07.multiply(D[k][ 2])). + add(yDot08.multiply(D[k][ 3])). + add(yDot09.multiply(D[k][ 4])). + add(yDot10.multiply(D[k][ 5])). + add(yDot11.multiply(D[k][ 6])). + add(yDot12.multiply(D[k][ 7])). + add(yDot13.multiply(D[k][ 8])). + add(yDot14.multiply(D[k][ 9])). + add(yDot15.multiply(D[k][10])). + add(yDot16.multiply(D[k][11])); + } + } + + vectorsInitialized = true; + + } + + final T one = theta.getField().getOne(); + final T eta = one.subtract(theta); + final T twoTheta = theta.multiply(2); + final T theta2 = theta.multiply(theta); + final T dot1 = one.subtract(twoTheta); + final T dot2 = theta.multiply(theta.multiply(-3).add(2)); + final T dot3 = twoTheta.multiply(theta.multiply(twoTheta.subtract(3)).add(1)); + final T dot4 = theta2.multiply(theta.multiply(theta.multiply(5).subtract(8)).add(3)); + final T dot5 = theta2.multiply(theta.multiply(theta.multiply(theta.multiply(-6).add(15)).subtract(12)).add(3)); + final T dot6 = theta2.multiply(theta.multiply(theta.multiply(theta.multiply(theta.multiply(-7).add(18)).subtract(15)).add(4))); + final T[] interpolatedState = MathArrays.buildArray(theta.getField(), previousState.length); + final T[] interpolatedDerivatives = MathArrays.buildArray(theta.getField(), previousState.length); + + if ((previousState != null) && (theta.getReal() <= 0.5)) { + for (int i = 0; i < interpolatedState.length; ++i) { + interpolatedState[i] = previousState[i]. + add(theta.multiply(h.multiply(v[0][i]. + add(eta.multiply(v[1][i]. + add(theta.multiply(v[2][i]. + add(eta.multiply(v[3][i]. + add(theta.multiply(v[4][i]. + add(eta.multiply(v[5][i]. + add(theta.multiply(v[6][i]))))))))))))))); + interpolatedDerivatives[i] = v[0][i]. + add(dot1.multiply(v[1][i])). + add(dot2.multiply(v[2][i])). + add(dot3.multiply(v[3][i])). + add(dot4.multiply(v[4][i])). + add(dot5.multiply(v[5][i])). + add(dot6.multiply(v[6][i])); + } + } else { + for (int i = 0; i < interpolatedState.length; ++i) { + interpolatedState[i] = currentState[i]. + subtract(oneMinusThetaH.multiply(v[0][i]. + subtract(theta.multiply(v[1][i]. + add(theta.multiply(v[2][i]. + add(eta.multiply(v[3][i]. + add(theta.multiply(v[4][i]. + add(eta.multiply(v[5][i]. + add(theta.multiply(v[6][i])))))))))))))); + interpolatedDerivatives[i] = v[0][i]. + add(dot1.multiply(v[1][i])). + add(dot2.multiply(v[2][i])). + add(dot3.multiply(v[3][i])). + add(dot4.multiply(v[4][i])). + add(dot5.multiply(v[5][i])). + add(dot6.multiply(v[6][i])); + } + } + + return new FieldODEStateAndDerivative<T>(time, interpolatedState, yDotK[0]); + + } + + /** {@inheritDoc} */ + @Override + protected void doFinalize() throws MaxCountExceededException { + + if (currentState == null) { + // we are finalizing an uninitialized instance + return; + } + + T s; + final T pT = getGlobalPreviousState().getTime(); + final T[] yTmp = MathArrays.buildArray(pT.getField(), currentState.length); + + // k14 + for (int j = 0; j < currentState.length; ++j) { + s = yDotK[ 0][j].multiply(K14_01). + add(yDotK[ 5][j].multiply(K14_06)). + add(yDotK[ 6][j].multiply(K14_07)). + add(yDotK[ 7][j].multiply(K14_08)). + add(yDotK[ 8][j].multiply(K14_09)). + add(yDotK[ 9][j].multiply(K14_10)). + add(yDotK[10][j].multiply(K14_11)). + add(yDotK[11][j].multiply(K14_12)). + add(yDotK[12][j].multiply(K14_13)); + yTmp[j] = currentState[j].add(h.multiply(s)); + } + yDotKLast[0] = integrator.computeDerivatives(pT.add(h.multiply(C14)), yTmp); + + // k15 + for (int j = 0; j < currentState.length; ++j) { + s = yDotK[ 0][j].multiply(K15_01). + add(yDotK[ 5][j].multiply(K15_06)). + add(yDotK[ 6][j].multiply(K15_07)). + add(yDotK[ 7][j].multiply(K15_08)). + add(yDotK[ 8][j].multiply(K15_09)). + add(yDotK[ 9][j].multiply(K15_10)). + add(yDotK[10][j].multiply(K15_11)). + add(yDotK[11][j].multiply(K15_12)). + add(yDotK[12][j].multiply(K15_13)). + add(yDotKLast[0][j].multiply(K15_14)); + yTmp[j] = currentState[j].add(h.multiply(s)); + } + yDotKLast[1] = integrator.computeDerivatives(pT.add(h.multiply(C15)), yTmp); + + // k16 + for (int j = 0; j < currentState.length; ++j) { + s = yDotK[ 0][j].multiply(K16_01). + add(yDotK[ 5][j].multiply(K16_06)). + add(yDotK[ 6][j].multiply(K16_07)). + add(yDotK[ 7][j].multiply(K16_08)). + add(yDotK[ 8][j].multiply(K16_09)). + add(yDotK[ 9][j].multiply(K16_10)). + add(yDotK[10][j].multiply(K16_11)). + add(yDotK[11][j].multiply(K16_12)). + add(yDotK[12][j].multiply(K16_13)). + add(yDotKLast[0][j].multiply(K16_14)). + add(yDotKLast[0][j].multiply(K16_15)); + yTmp[j] = currentState[j].add(h.multiply(s)); + } + yDotKLast[2] = integrator.computeDerivatives(pT.add(h.multiply(C16)), yTmp); + + } + +}