public void testEvents() throws DerivativeException, IntegratorException {

    TestProblem4 pb = new TestProblem4();
    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);
    EventHandler[] functions = pb.getEventsHandlers();
    for (int l = 0; l < functions.length; ++l) {
      integ.addEventHandler(functions[l], Double.POSITIVE_INFINITY, 1.0e-8 * maxStep, 1000);
    }
    assertEquals(functions.length, integ.getEventHandlers().size());
    integ.integrate(
        pb,
        pb.getInitialTime(),
        pb.getInitialState(),
        pb.getFinalTime(),
        new double[pb.getDimension()]);

    assertTrue(handler.getMaximalValueError() < 1.0e-7);
    assertEquals(0, handler.getMaximalTimeError(), 1.0e-12);
    assertEquals(12.0, handler.getLastTime(), 1.0e-8 * maxStep);
    integ.clearEventHandlers();
    assertEquals(0, integ.getEventHandlers().size());
  }
  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 testBackward() throws DerivativeException, IntegratorException {

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

    FirstOrderIntegrator integ =
        new GraggBulirschStoerIntegrator(
            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()]);

    assertTrue(handler.getLastError() < 9.0e-10);
    assertTrue(handler.getMaximalValueError() < 9.0e-10);
    assertEquals(0, handler.getMaximalTimeError(), 1.0e-12);
    assertEquals("Gragg-Bulirsch-Stoer", integ.getName());
  }
  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 testUnstableDerivative() throws DerivativeException, IntegratorException {
   final StepProblem stepProblem = new StepProblem(0.0, 1.0, 2.0);
   FirstOrderIntegrator integ = new GraggBulirschStoerIntegrator(0.1, 10, 1.0e-12, 0.0);
   integ.addEventHandler(stepProblem, 1.0, 1.0e-12, 1000);
   double[] y = {Double.NaN};
   integ.integrate(stepProblem, 0.0, new double[] {0.0}, 10.0, y);
   assertEquals(8.0, y[0], 1.0e-12);
 }
  public void testModelsMerging() throws DerivativeException, IntegratorException {

    // theoretical solution: y[0] = cos(t), y[1] = sin(t)
    FirstOrderDifferentialEquations problem =
        new FirstOrderDifferentialEquations() {
          public void computeDerivatives(double t, double[] y, double[] dot)
              throws DerivativeException {
            dot[0] = -y[1];
            dot[1] = y[0];
          }

          public int getDimension() {
            return 2;
          }
        };

    // integrate backward from &pi; to 0;
    ContinuousOutputModel cm1 = new ContinuousOutputModel();
    FirstOrderIntegrator integ1 = new DormandPrince853Integrator(0, 1.0, 1.0e-8, 1.0e-8);
    integ1.setStepHandler(cm1);
    integ1.integrate(problem, Math.PI, new double[] {-1.0, 0.0}, 0, new double[2]);

    // integrate backward from 2&pi; to &pi;
    ContinuousOutputModel cm2 = new ContinuousOutputModel();
    FirstOrderIntegrator integ2 = new DormandPrince853Integrator(0, 0.1, 1.0e-12, 1.0e-12);
    integ2.setStepHandler(cm2);
    integ2.integrate(problem, 2.0 * Math.PI, new double[] {1.0, 0.0}, Math.PI, new double[2]);

    // merge the two half circles
    ContinuousOutputModel cm = new ContinuousOutputModel();
    cm.append(cm2);
    cm.append(new ContinuousOutputModel());
    cm.append(cm1);

    // check circle
    assertEquals(2.0 * Math.PI, cm.getInitialTime(), 1.0e-12);
    assertEquals(0, cm.getFinalTime(), 1.0e-12);
    assertEquals(cm.getFinalTime(), cm.getInterpolatedTime(), 1.0e-12);
    for (double t = 0; t < 2.0 * Math.PI; t += 0.1) {
      cm.setInterpolatedTime(t);
      double[] y = cm.getInterpolatedState();
      assertEquals(Math.cos(t), y[0], 1.0e-7);
      assertEquals(Math.sin(t), y[1], 1.0e-7);
    }
  }
 private double getMaxError(FirstOrderIntegrator integrator, TestProblemAbstract pb)
     throws DerivativeException, IntegratorException {
   TestProblemHandler handler = new TestProblemHandler(pb, integrator);
   integrator.addStepHandler(handler);
   integrator.integrate(
       pb,
       pb.getInitialTime(),
       pb.getInitialState(),
       pb.getFinalTime(),
       new double[pb.getDimension()]);
   return handler.getMaximalValueError();
 }
  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 testKepler() throws DerivativeException, IntegratorException {

    final TestProblem3 pb = new TestProblem3(0.9);
    double minStep = 0;
    double maxStep = pb.getFinalTime() - pb.getInitialTime();
    double[] vecAbsoluteTolerance = {1.0e-8, 1.0e-8, 1.0e-10, 1.0e-10};
    double[] vecRelativeTolerance = {1.0e-10, 1.0e-10, 1.0e-8, 1.0e-8};

    FirstOrderIntegrator integ =
        new HighamHall54Integrator(minStep, maxStep, vecAbsoluteTolerance, vecRelativeTolerance);
    integ.addStepHandler(new KeplerHandler(pb));
    integ.integrate(
        pb,
        pb.getInitialTime(),
        pb.getInitialState(),
        pb.getFinalTime(),
        new double[pb.getDimension()]);
    assertEquals("Higham-Hall 5(4)", integ.getName());
  }
  public void testVariableSteps() throws DerivativeException, IntegratorException {

    final TestProblem3 pb = new TestProblem3(0.9);
    double minStep = 0;
    double maxStep = pb.getFinalTime() - pb.getInitialTime();
    double absTolerance = 1.0e-8;
    double relTolerance = 1.0e-8;
    FirstOrderIntegrator integ =
        new GraggBulirschStoerIntegrator(
            minStep, maxStep,
            absTolerance, relTolerance);
    integ.addStepHandler(new VariableStepHandler());
    double stopTime =
        integ.integrate(
            pb,
            pb.getInitialTime(),
            pb.getInitialState(),
            pb.getFinalTime(),
            new double[pb.getDimension()]);
    assertEquals(pb.getFinalTime(), stopTime, 1.0e-10);
    assertEquals("Gragg-Bulirsch-Stoer", integ.getName());
  }
  public void testKepler() throws DerivativeException, IntegratorException {

    final TestProblem3 pb = new TestProblem3(0.9);
    double minStep = 0;
    double maxStep = pb.getFinalTime() - pb.getInitialTime();
    double absTolerance = 1.0e-6;
    double relTolerance = 1.0e-6;

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

    assertEquals(integ.getEvaluations(), pb.getCalls());
    assertTrue(pb.getCalls() < 2150);
  }
  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;
    }
  }
  public void testSanityChecks() {
    try {
      final TestProblem3 pb = new TestProblem3(0.9);
      double minStep = 0;
      double maxStep = pb.getFinalTime() - pb.getInitialTime();

      try {
        FirstOrderIntegrator integ =
            new HighamHall54Integrator(minStep, maxStep, new double[4], new double[4]);
        integ.integrate(
            pb,
            pb.getInitialTime(),
            new double[6],
            pb.getFinalTime(),
            new double[pb.getDimension()]);
        fail("an exception should have been thrown");
      } catch (IntegratorException ie) {
        // expected behavior
      }

      try {
        FirstOrderIntegrator integ =
            new HighamHall54Integrator(minStep, maxStep, new double[4], new double[4]);
        integ.integrate(
            pb, pb.getInitialTime(), pb.getInitialState(), pb.getFinalTime(), new double[6]);
        fail("an exception should have been thrown");
      } catch (IntegratorException ie) {
        // expected behavior
      }

      try {
        FirstOrderIntegrator integ =
            new HighamHall54Integrator(minStep, maxStep, new double[2], new double[4]);
        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
      }

      try {
        FirstOrderIntegrator integ =
            new HighamHall54Integrator(minStep, maxStep, new double[4], new double[2]);
        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
      }

      try {
        FirstOrderIntegrator integ =
            new HighamHall54Integrator(minStep, maxStep, new double[4], new double[4]);
        integ.integrate(
            pb,
            pb.getInitialTime(),
            pb.getInitialState(),
            pb.getInitialTime(),
            new double[pb.getDimension()]);
        fail("an exception should have been thrown");
      } catch (IntegratorException ie) {
        // expected behavior
      }

    } catch (Exception e) {
      fail("wrong exception caught: " + e.getMessage());
    }
  }