DormandPrince853FieldIntegrator.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      https://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. /*
  18.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */

  21. package org.hipparchus.ode.nonstiff;

  22. import org.hipparchus.CalculusFieldElement;
  23. import org.hipparchus.Field;
  24. import org.hipparchus.ode.FieldEquationsMapper;
  25. import org.hipparchus.ode.FieldODEStateAndDerivative;
  26. import org.hipparchus.ode.nonstiff.interpolators.DormandPrince853FieldStateInterpolator;
  27. import org.hipparchus.util.FastMath;
  28. import org.hipparchus.util.MathArrays;


  29. /**
  30.  * This class implements the 8(5,3) Dormand-Prince integrator for Ordinary
  31.  * Differential Equations.
  32.  *
  33.  * <p>This integrator is an embedded Runge-Kutta integrator
  34.  * of order 8(5,3) used in local extrapolation mode (i.e. the solution
  35.  * is computed using the high order formula) with stepsize control
  36.  * (and automatic step initialization) and continuous output. This
  37.  * method uses 12 functions evaluations per step for integration and 4
  38.  * evaluations for interpolation. However, since the first
  39.  * interpolation evaluation is the same as the first integration
  40.  * evaluation of the next step, we have included it in the integrator
  41.  * rather than in the interpolator and specified the method was an
  42.  * <i>fsal</i>. Hence, despite we have 13 stages here, the cost is
  43.  * really 12 evaluations per step even if no interpolation is done,
  44.  * and the overcost of interpolation is only 3 evaluations.</p>
  45.  *
  46.  * <p>This method is based on an 8(6) method by Dormand and Prince
  47.  * (i.e. order 8 for the integration and order 6 for error estimation)
  48.  * modified by Hairer and Wanner to use a 5th order error estimator
  49.  * with 3rd order correction. This modification was introduced because
  50.  * the original method failed in some cases (wrong steps can be
  51.  * accepted when step size is too large, for example in the
  52.  * Brusselator problem) and also had <i>severe difficulties when
  53.  * applied to problems with discontinuities</i>. This modification is
  54.  * explained in the second edition of the first volume (Nonstiff
  55.  * Problems) of the reference book by Hairer, Norsett and Wanner:
  56.  * <i>Solving Ordinary Differential Equations</i> (Springer-Verlag,
  57.  * ISBN 3-540-56670-8).</p>
  58.  *
  59.  * @param <T> the type of the field elements
  60.  */

  61. public class DormandPrince853FieldIntegrator<T extends CalculusFieldElement<T>>
  62.     extends EmbeddedRungeKuttaFieldIntegrator<T> {

  63.     /** Name of integration scheme. */
  64.     public static final String METHOD_NAME = DormandPrince853Integrator.METHOD_NAME;

  65.     /** Simple constructor.
  66.      * Build an eighth order Dormand-Prince integrator with the given step bounds
  67.      * @param field field to which the time and state vector elements belong
  68.      * @param minStep minimal step (sign is irrelevant, regardless of
  69.      * integration direction, forward or backward), the last step can
  70.      * be smaller than this
  71.      * @param maxStep maximal step (sign is irrelevant, regardless of
  72.      * integration direction, forward or backward), the last step can
  73.      * be smaller than this
  74.      * @param scalAbsoluteTolerance allowed absolute error
  75.      * @param scalRelativeTolerance allowed relative error
  76.      */
  77.     public DormandPrince853FieldIntegrator(final Field<T> field,
  78.                                            final double minStep, final double maxStep,
  79.                                            final double scalAbsoluteTolerance,
  80.                                            final double scalRelativeTolerance) {
  81.         super(field, METHOD_NAME, 12,
  82.               minStep, maxStep, scalAbsoluteTolerance, scalRelativeTolerance);
  83.     }

  84.     /** Simple constructor.
  85.      * Build an eighth order Dormand-Prince integrator with the given step bounds
  86.      * @param field field to which the time and state vector elements belong
  87.      * @param minStep minimal step (sign is irrelevant, regardless of
  88.      * integration direction, forward or backward), the last step can
  89.      * be smaller than this
  90.      * @param maxStep maximal step (sign is irrelevant, regardless of
  91.      * integration direction, forward or backward), the last step can
  92.      * be smaller than this
  93.      * @param vecAbsoluteTolerance allowed absolute error
  94.      * @param vecRelativeTolerance allowed relative error
  95.      */
  96.     public DormandPrince853FieldIntegrator(final Field<T> field,
  97.                                            final double minStep, final double maxStep,
  98.                                            final double[] vecAbsoluteTolerance,
  99.                                            final double[] vecRelativeTolerance) {
  100.         super(field, DormandPrince853Integrator.METHOD_NAME, 12,
  101.               minStep, maxStep, vecAbsoluteTolerance, vecRelativeTolerance);
  102.     }

  103.     /** {@inheritDoc} */
  104.     @Override
  105.     public T[] getC() {

  106.         final T sqrt6 = getField().getOne().newInstance(6).sqrt();

  107.         final T[] c = MathArrays.buildArray(getField(), 15);
  108.         c[ 0] = sqrt6.add(-6).divide(-67.5);
  109.         c[ 1] = sqrt6.add(-6).divide(-45.0);
  110.         c[ 2] = sqrt6.add(-6).divide(-30.0);
  111.         c[ 3] = sqrt6.add( 6).divide( 30.0);
  112.         c[ 4] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 1, 3);
  113.         c[ 5] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 1, 4);
  114.         c[ 6] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 4, 13);
  115.         c[ 7] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 127, 195);
  116.         c[ 8] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 3, 5);
  117.         c[ 9] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 6, 7);
  118.         c[10] = getField().getOne();
  119.         c[11] = getField().getOne();
  120.         c[12] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 1.0, 10.0);
  121.         c[13] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 1.0, 5.0);
  122.         c[14] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),7.0, 9.0);

  123.         return c;

  124.     }

  125.     /** {@inheritDoc} */
  126.     @Override
  127.     public T[][] getA() {

  128.         final T sqrt6 = getField().getOne().newInstance(6).sqrt();

  129.         final T[][] a = MathArrays.buildArray(getField(), 15, -1);
  130.         for (int i = 0; i < a.length; ++i) {
  131.             a[i] = MathArrays.buildArray(getField(), i + 1);
  132.         }

  133.         a[ 0][ 0] = sqrt6.add(-6).divide(-67.5);

  134.         a[ 1][ 0] = sqrt6.add(-6).divide(-180);
  135.         a[ 1][ 1] = sqrt6.add(-6).divide( -60);

  136.         a[ 2][ 0] = sqrt6.add(-6).divide(-120);
  137.         a[ 2][ 1] = getField().getZero();
  138.         a[ 2][ 2] = sqrt6.add(-6).divide( -40);

  139.         a[ 3][ 0] = sqrt6.multiply(107).add(462).divide( 3000);
  140.         a[ 3][ 1] = getField().getZero();
  141.         a[ 3][ 2] = sqrt6.multiply(197).add(402).divide(-1000);
  142.         a[ 3][ 3] = sqrt6.multiply( 73).add(168).divide(  375);

  143.         a[ 4][ 0] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 1, 27);
  144.         a[ 4][ 1] = getField().getZero();
  145.         a[ 4][ 2] = getField().getZero();
  146.         a[ 4][ 3] = sqrt6.add( 16).divide( 108);
  147.         a[ 4][ 4] = sqrt6.add(-16).divide(-108);

  148.         a[ 5][ 0] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 19, 512);
  149.         a[ 5][ 1] = getField().getZero();
  150.         a[ 5][ 2] = getField().getZero();
  151.         a[ 5][ 3] = sqrt6.multiply( 23).add(118).divide(1024);
  152.         a[ 5][ 4] = sqrt6.multiply(-23).add(118).divide(1024);
  153.         a[ 5][ 5] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), -9, 512);

  154.         a[ 6][ 0] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 13772, 371293);
  155.         a[ 6][ 1] = getField().getZero();
  156.         a[ 6][ 2] = getField().getZero();
  157.         a[ 6][ 3] = sqrt6.multiply( 4784).add(51544).divide(371293);
  158.         a[ 6][ 4] = sqrt6.multiply(-4784).add(51544).divide(371293);
  159.         a[ 6][ 5] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), -5688, 371293);
  160.         a[ 6][ 6] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),  3072, 371293);

  161.         a[ 7][ 0] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 58656157643.0, 93983540625.0);
  162.         a[ 7][ 1] = getField().getZero();
  163.         a[ 7][ 2] = getField().getZero();
  164.         a[ 7][ 3] = sqrt6.multiply(-318801444819.0).add(-1324889724104.0).divide(626556937500.0);
  165.         a[ 7][ 4] = sqrt6.multiply( 318801444819.0).add(-1324889724104.0).divide(626556937500.0);
  166.         a[ 7][ 5] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 96044563816.0, 3480871875.0);
  167.         a[ 7][ 6] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 5682451879168.0, 281950621875.0);
  168.         a[ 7][ 7] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), -165125654.0, 3796875.0);

  169.         a[ 8][ 0] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),8909899.0, 18653125.0);
  170.         a[ 8][ 1] = getField().getZero();
  171.         a[ 8][ 2] = getField().getZero();
  172.         a[ 8][ 3] = sqrt6.multiply(-1137963.0).add(-4521408.0).divide(2937500.0);
  173.         a[ 8][ 4] = sqrt6.multiply( 1137963.0).add(-4521408.0).divide(2937500.0);
  174.         a[ 8][ 5] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 96663078.0, 4553125.0);
  175.         a[ 8][ 6] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 2107245056.0, 137915625.0);
  176.         a[ 8][ 7] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), -4913652016.0, 147609375.0);
  177.         a[ 8][ 8] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), -78894270.0, 3880452869.0);

  178.         a[ 9][ 0] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), -20401265806.0, 21769653311.0);
  179.         a[ 9][ 1] = getField().getZero();
  180.         a[ 9][ 2] = getField().getZero();
  181.         a[ 9][ 3] = sqrt6.multiply( 94326.0).add(354216.0).divide(112847.0);
  182.         a[ 9][ 4] = sqrt6.multiply(-94326.0).add(354216.0).divide(112847.0);
  183.         a[ 9][ 5] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), -43306765128.0, 5313852383.0);
  184.         a[ 9][ 6] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), -20866708358144.0, 1126708119789.0);
  185.         a[ 9][ 7] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 14886003438020.0, 654632330667.0);
  186.         a[ 9][ 8] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 35290686222309375.0, 14152473387134411.0);
  187.         a[ 9][ 9] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), -1477884375.0, 485066827.0);

  188.         a[10][ 0] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 39815761.0, 17514443.0);
  189.         a[10][ 1] = getField().getZero();
  190.         a[10][ 2] = getField().getZero();
  191.         a[10][ 3] = sqrt6.multiply(-960905.0).add(-3457480.0).divide(551636.0);
  192.         a[10][ 4] = sqrt6.multiply( 960905.0).add(-3457480.0).divide(551636.0);
  193.         a[10][ 5] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), -844554132.0, 47026969.0);
  194.         a[10][ 6] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),8444996352.0, 302158619.0);
  195.         a[10][ 7] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), -2509602342.0, 877790785.0);
  196.         a[10][ 8] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), -28388795297996250.0, 3199510091356783.0);
  197.         a[10][ 9] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 226716250.0, 18341897.0);
  198.         a[10][10] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 1371316744.0, 2131383595.0);

  199.         // the following stage is both for interpolation and the first stage in next step
  200.         // (the coefficients are identical to the B array)
  201.         a[11][ 0] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 104257.0, 1920240.0);
  202.         a[11][ 1] = getField().getZero();
  203.         a[11][ 2] = getField().getZero();
  204.         a[11][ 3] = getField().getZero();
  205.         a[11][ 4] = getField().getZero();
  206.         a[11][ 5] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 3399327.0, 763840.0);
  207.         a[11][ 6] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 66578432.0, 35198415.0);
  208.         a[11][ 7] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), -1674902723.0, 288716400.0);
  209.         a[11][ 8] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 54980371265625.0, 176692375811392.0);
  210.         a[11][ 9] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), -734375.0, 4826304.0);
  211.         a[11][10] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 171414593.0, 851261400.0);
  212.         a[11][11] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 137909.0, 3084480.0);

  213.         // the following stages are for interpolation only
  214.         a[12][ 0] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),       13481885573.0, 240030000000.0);
  215.         a[12][ 1] = getField().getZero();
  216.         a[12][ 2] = getField().getZero();
  217.         a[12][ 3] = getField().getZero();
  218.         a[12][ 4] = getField().getZero();
  219.         a[12][ 5] = getField().getZero();
  220.         a[12][ 6] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),      139418837528.0, 549975234375.0);
  221.         a[12][ 7] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),   -11108320068443.0, 45111937500000.0);
  222.         a[12][ 8] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), -1769651421925959.0, 14249385146080000.0);
  223.         a[12][ 9] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),          57799439.0, 377055000.0);
  224.         a[12][10] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),      793322643029.0, 96734250000000.0);
  225.         a[12][11] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),        1458939311.0, 192780000000.0);
  226.         a[12][12]  = FieldExplicitRungeKuttaIntegrator.fraction(getField(),             -4149.0, 500000.0);

  227.         a[13][ 0] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),     1595561272731.0, 50120273500000.0);
  228.         a[13][ 1] = getField().getZero();
  229.         a[13][ 2] = getField().getZero();
  230.         a[13][ 3] = getField().getZero();
  231.         a[13][ 4] = getField().getZero();
  232.         a[13][ 5] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),      975183916491.0, 34457688031250.0);
  233.         a[13][ 6] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),    38492013932672.0, 718912673015625.0);
  234.         a[13][ 7] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), -1114881286517557.0, 20298710767500000.0);
  235.         a[13][ 8] = getField().getZero();
  236.         a[13][ 9] = getField().getZero();
  237.         a[13][10] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),    -2538710946863.0, 23431227861250000.0);
  238.         a[13][11] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),        8824659001.0, 23066716781250.0);
  239.         a[13][12] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),      -11518334563.0, 33831184612500.0);
  240.         a[13][13] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),        1912306948.0, 13532473845.0);

  241.         a[14][ 0] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),      -13613986967.0, 31741908048.0);
  242.         a[14][ 1] = getField().getZero();
  243.         a[14][ 2] = getField().getZero();
  244.         a[14][ 3] = getField().getZero();
  245.         a[14][ 4] = getField().getZero();
  246.         a[14][ 5] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),       -4755612631.0, 1012344804.0);
  247.         a[14][ 6] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),    42939257944576.0, 5588559685701.0);
  248.         a[14][ 7] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),    77881972900277.0, 19140370552944.0);
  249.         a[14][ 8] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),    22719829234375.0, 63689648654052.0);
  250.         a[14][ 9] = getField().getZero();
  251.         a[14][10] = getField().getZero();
  252.         a[14][11] = getField().getZero();
  253.         a[14][12] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),       -1199007803.0, 857031517296.0);
  254.         a[14][13] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),      157882067000.0, 53564469831.0);
  255.         a[14][14] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),     -290468882375.0, 31741908048.0);

  256.         return a;

  257.     }

  258.     /** {@inheritDoc} */
  259.     @Override
  260.     public T[] getB() {
  261.         final T[] b = MathArrays.buildArray(getField(), 16);
  262.         b[ 0] = FieldExplicitRungeKuttaIntegrator.fraction(getField(), 104257, 1920240);
  263.         b[ 1] = getField().getZero();
  264.         b[ 2] = getField().getZero();
  265.         b[ 3] = getField().getZero();
  266.         b[ 4] = getField().getZero();
  267.         b[ 5] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),         3399327.0,          763840.0);
  268.         b[ 6] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),        66578432.0,        35198415.0);
  269.         b[ 7] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),     -1674902723.0,       288716400.0);
  270.         b[ 8] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),  54980371265625.0, 176692375811392.0);
  271.         b[ 9] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),         -734375.0,         4826304.0);
  272.         b[10] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),       171414593.0,       851261400.0);
  273.         b[11] = FieldExplicitRungeKuttaIntegrator.fraction(getField(),          137909.0,         3084480.0);
  274.         b[12] = getField().getZero();
  275.         b[13] = getField().getZero();
  276.         b[14] = getField().getZero();
  277.         b[15] = getField().getZero();
  278.         return b;
  279.     }

  280.     /** {@inheritDoc} */
  281.     @Override
  282.     protected DormandPrince853FieldStateInterpolator<T>
  283.         createInterpolator(final boolean forward, T[][] yDotK,
  284.                            final FieldODEStateAndDerivative<T> globalPreviousState,
  285.                            final FieldODEStateAndDerivative<T> globalCurrentState, final FieldEquationsMapper<T> mapper) {
  286.         return new DormandPrince853FieldStateInterpolator<>(getField(), forward, yDotK,
  287.                                                             globalPreviousState, globalCurrentState,
  288.                                                             globalPreviousState, globalCurrentState,
  289.                                                             mapper);
  290.     }

  291.     /** {@inheritDoc} */
  292.     @Override
  293.     public int getOrder() {
  294.         return 8;
  295.     }

  296.     /** {@inheritDoc} */
  297.     @Override
  298.     protected double estimateError(final T[][] yDotK, final T[] y0, final T[] y1, final T h) {

  299.         final StepsizeHelper helper = getStepSizeHelper();
  300.         double error1 = 0;
  301.         double error2 = 0;

  302.         for (int j = 0; j < helper.getMainSetDimension(); ++j) {
  303.             final double errSum1 = DormandPrince853Integrator.E1_01 * yDotK[ 0][j].getReal() + DormandPrince853Integrator.E1_06 * yDotK[ 5][j].getReal() +
  304.                                    DormandPrince853Integrator.E1_07 * yDotK[ 6][j].getReal() + DormandPrince853Integrator.E1_08 * yDotK[ 7][j].getReal() +
  305.                                    DormandPrince853Integrator.E1_09 * yDotK[ 8][j].getReal() + DormandPrince853Integrator.E1_10 * yDotK[ 9][j].getReal() +
  306.                                    DormandPrince853Integrator.E1_11 * yDotK[10][j].getReal() + DormandPrince853Integrator.E1_12 * yDotK[11][j].getReal();
  307.             final double errSum2 = DormandPrince853Integrator.E2_01 * yDotK[ 0][j].getReal() + DormandPrince853Integrator.E2_06 * yDotK[ 5][j].getReal() +
  308.                                    DormandPrince853Integrator.E2_07 * yDotK[ 6][j].getReal() + DormandPrince853Integrator.E2_08 * yDotK[ 7][j].getReal() +
  309.                                    DormandPrince853Integrator.E2_09 * yDotK[ 8][j].getReal() + DormandPrince853Integrator.E2_10 * yDotK[ 9][j].getReal() +
  310.                                    DormandPrince853Integrator.E2_11 * yDotK[10][j].getReal() + DormandPrince853Integrator.E2_12 * yDotK[11][j].getReal();
  311.             final double tol     = helper.getTolerance(j, FastMath.max(FastMath.abs(y0[j].getReal()), FastMath.abs(y1[j].getReal())));
  312.             final double ratio1  = errSum1 / tol;
  313.             error1        += ratio1 * ratio1;
  314.             final double ratio2  = errSum2 / tol;
  315.             error2        += ratio2 * ratio2;

  316.         }

  317.         double den = error1 + 0.01 * error2;
  318.         if (den <= 0.0) {
  319.             den = 1.0;
  320.         }

  321.         return FastMath.abs(h.getReal()) * error1 / FastMath.sqrt(helper.getMainSetDimension() * den);

  322.     }

  323. }