public void testMinStep() {

    try {
      TestProblem1 pb = new TestProblem1();
      double minStep = 0.1 * (pb.getFinalTime() - pb.getInitialTime());
      double maxStep = pb.getFinalTime() - pb.getInitialTime();
      double[] vecAbsoluteTolerance = {1.0e-15, 1.0e-16};
      double[] vecRelativeTolerance = {1.0e-15, 1.0e-16};

      FirstOrderIntegrator integ =
          new HighamHall54Integrator(minStep, maxStep, vecAbsoluteTolerance, vecRelativeTolerance);
      TestProblemHandler handler = new TestProblemHandler(pb, integ);
      integ.addStepHandler(handler);
      integ.integrate(
          pb,
          pb.getInitialTime(),
          pb.getInitialState(),
          pb.getFinalTime(),
          new double[pb.getDimension()]);
      fail("an exception should have been thrown");
    } catch (DerivativeException de) {
      fail("wrong exception caught");
    } catch (IntegratorException ie) {
    }
  }
  public void testIncreasingTolerance() throws DerivativeException, IntegratorException {

    int previousCalls = Integer.MAX_VALUE;
    for (int i = -12; i < -2; ++i) {
      TestProblem1 pb = new TestProblem1();
      double minStep = 0;
      double maxStep = pb.getFinalTime() - pb.getInitialTime();
      double scalAbsoluteTolerance = Math.pow(10.0, i);
      double scalRelativeTolerance = 0.01 * scalAbsoluteTolerance;

      FirstOrderIntegrator integ =
          new HighamHall54Integrator(
              minStep, maxStep, scalAbsoluteTolerance, scalRelativeTolerance);
      TestProblemHandler handler = new TestProblemHandler(pb, integ);
      integ.addStepHandler(handler);
      integ.integrate(
          pb,
          pb.getInitialTime(),
          pb.getInitialState(),
          pb.getFinalTime(),
          new double[pb.getDimension()]);

      // the 1.3 factor is only valid for this test
      // and has been obtained from trial and error
      // there is no general relation between local and global errors
      assertTrue(handler.getMaximalValueError() < (1.3 * scalAbsoluteTolerance));
      assertEquals(0, handler.getMaximalTimeError(), 1.0e-12);

      int calls = pb.getCalls();
      assertEquals(integ.getEvaluations(), calls);
      assertTrue(calls <= previousCalls);
      previousCalls = calls;
    }
  }
  public void testEventsErrors() {

    final TestProblem1 pb = new TestProblem1();
    double minStep = 0;
    double maxStep = pb.getFinalTime() - pb.getInitialTime();
    double scalAbsoluteTolerance = 1.0e-8;
    double scalRelativeTolerance = 0.01 * scalAbsoluteTolerance;

    FirstOrderIntegrator integ =
        new HighamHall54Integrator(
            minStep, maxStep,
            scalAbsoluteTolerance, scalRelativeTolerance);
    TestProblemHandler handler = new TestProblemHandler(pb, integ);
    integ.addStepHandler(handler);

    integ.addEventHandler(
        new EventHandler() {
          public int eventOccurred(double t, double[] y, boolean increasing) {
            return EventHandler.CONTINUE;
          }

          public double g(double t, double[] y) throws EventException {
            double middle = (pb.getInitialTime() + pb.getFinalTime()) / 2;
            double offset = t - middle;
            if (offset > 0) {
              throw new EventException("Evaluation failed for argument = {0}", t);
            }
            return offset;
          }

          public void resetState(double t, double[] y) {}

          private static final long serialVersionUID = 935652725339916361L;
        },
        Double.POSITIVE_INFINITY,
        1.0e-8 * maxStep,
        1000);

    try {
      integ.integrate(
          pb,
          pb.getInitialTime(),
          pb.getInitialState(),
          pb.getFinalTime(),
          new double[pb.getDimension()]);
      fail("an exception should have been thrown");
    } catch (IntegratorException ie) {
      // expected behavior
    } catch (Exception e) {
      fail("wrong exception type caught");
    }
  }
  public void testEventsNoConvergence() {

    final TestProblem1 pb = new TestProblem1();
    double minStep = 0;
    double maxStep = pb.getFinalTime() - pb.getInitialTime();
    double scalAbsoluteTolerance = 1.0e-8;
    double scalRelativeTolerance = 0.01 * scalAbsoluteTolerance;

    FirstOrderIntegrator integ =
        new HighamHall54Integrator(
            minStep, maxStep,
            scalAbsoluteTolerance, scalRelativeTolerance);
    TestProblemHandler handler = new TestProblemHandler(pb, integ);
    integ.addStepHandler(handler);

    integ.addEventHandler(
        new EventHandler() {
          public int eventOccurred(double t, double[] y, boolean increasing) {
            return EventHandler.CONTINUE;
          }

          public double g(double t, double[] y) {
            double middle = (pb.getInitialTime() + pb.getFinalTime()) / 2;
            double offset = t - middle;
            return (offset > 0) ? (offset + 0.5) : (offset - 0.5);
          }

          public void resetState(double t, double[] y) {}

          private static final long serialVersionUID = 935652725339916361L;
        },
        Double.POSITIVE_INFINITY,
        1.0e-8 * maxStep,
        3);

    try {
      integ.integrate(
          pb,
          pb.getInitialTime(),
          pb.getInitialState(),
          pb.getFinalTime(),
          new double[pb.getDimension()]);
      fail("an exception should have been thrown");
    } catch (IntegratorException ie) {
      assertTrue(ie.getCause() != null);
      assertTrue(ie.getCause() instanceof ConvergenceException);
    } catch (Exception e) {
      fail("wrong exception type caught");
    }
  }
  public void testIncreasingTolerance() throws DerivativeException, IntegratorException {

    int previousCalls = Integer.MAX_VALUE;
    for (int i = -12; i < -4; ++i) {
      TestProblem1 pb = new TestProblem1();
      double minStep = 0;
      double maxStep = pb.getFinalTime() - pb.getInitialTime();
      double absTolerance = Math.pow(10.0, i);
      double relTolerance = absTolerance;

      FirstOrderIntegrator integ =
          new GraggBulirschStoerIntegrator(
              minStep, maxStep,
              absTolerance, relTolerance);
      TestProblemHandler handler = new TestProblemHandler(pb, integ);
      integ.addStepHandler(handler);
      integ.integrate(
          pb,
          pb.getInitialTime(),
          pb.getInitialState(),
          pb.getFinalTime(),
          new double[pb.getDimension()]);

      // the coefficients are only valid for this test
      // and have been obtained from trial and error
      // there is no general relation between local and global errors
      double ratio = handler.getMaximalValueError() / absTolerance;
      assertTrue(ratio < 2.4);
      assertTrue(ratio > 0.02);
      assertEquals(0, handler.getMaximalTimeError(), 1.0e-12);

      int calls = pb.getCalls();
      assertEquals(integ.getEvaluations(), calls);
      assertTrue(calls <= previousCalls);
      previousCalls = calls;
    }
  }