/** {@inheritDoc} */ public void addEventHandler( final EventHandler function, final double maxCheckInterval, final double convergence, final int maxIterationCount) { eventsHandlersManager.addEventHandler( function, maxCheckInterval, convergence, maxIterationCount); }
/** * Add an event handler for end time checking. * * <p>This method can be used to simplify handling of integration end time. It leverages the * nominal stop condition with the exceptional stop conditions. * * @param endTime desired end time * @param manager manager containing the user-defined handlers * @return a new manager containing all the user-defined handlers plus a dedicated manager * triggering a stop event at entTime */ protected CombinedEventsManager addEndTimeChecker( final double startTime, final double endTime, final CombinedEventsManager manager) { CombinedEventsManager newManager = new CombinedEventsManager(); for (final EventState state : manager.getEventsStates()) { newManager.addEventHandler( state.getEventHandler(), state.getMaxCheckInterval(), state.getConvergence(), state.getMaxIterationCount()); } newManager.addEventHandler( new EndTimeChecker(endTime), Double.POSITIVE_INFINITY, Math.ulp(Math.max(Math.abs(startTime), Math.abs(endTime))), 100); return newManager; }
/** {@inheritDoc} */ public Collection<EventHandler> getEventHandlers() { return eventsHandlersManager.getEventsHandlers(); }
/** {@inheritDoc} */ public void clearEventHandlers() { eventsHandlersManager.clearEventsHandlers(); }
/** {@inheritDoc} */ @Override public double integrate( final FirstOrderDifferentialEquations equations, final double t0, final double[] y0, final double t, final double[] y) throws DerivativeException, IntegratorException { sanityChecks(equations, t0, y0, t, y); setEquations(equations); resetEvaluations(); final boolean forward = (t > t0); // create some internal working arrays final int stages = c.length + 1; if (y != y0) { System.arraycopy(y0, 0, y, 0, y0.length); } final double[][] yDotK = new double[stages][y0.length]; final double[] yTmp = new double[y0.length]; // set up an interpolator sharing the integrator arrays AbstractStepInterpolator interpolator; if (requiresDenseOutput() || (!eventsHandlersManager.isEmpty())) { final RungeKuttaStepInterpolator rki = (RungeKuttaStepInterpolator) prototype.copy(); rki.reinitialize(this, yTmp, yDotK, forward); interpolator = rki; } else { interpolator = new DummyStepInterpolator(yTmp, forward); } interpolator.storeTime(t0); // set up integration control objects stepStart = t0; double hNew = 0; boolean firstTime = true; for (StepHandler handler : stepHandlers) { handler.reset(); } CombinedEventsManager manager = addEndTimeChecker(t0, t, eventsHandlersManager); boolean lastStep = false; // main integration loop while (!lastStep) { interpolator.shift(); double error = 0; for (boolean loop = true; loop; ) { if (firstTime || !fsal) { // first stage computeDerivatives(stepStart, y, yDotK[0]); } if (firstTime) { final double[] scale; if (vecAbsoluteTolerance != null) { scale = vecAbsoluteTolerance; } else { scale = new double[y0.length]; Arrays.fill(scale, scalAbsoluteTolerance); } hNew = initializeStep( equations, forward, getOrder(), scale, stepStart, y, yDotK[0], yTmp, yDotK[1]); firstTime = false; } stepSize = hNew; // next stages for (int k = 1; k < stages; ++k) { for (int j = 0; j < y0.length; ++j) { double sum = a[k - 1][0] * yDotK[0][j]; for (int l = 1; l < k; ++l) { sum += a[k - 1][l] * yDotK[l][j]; } yTmp[j] = y[j] + stepSize * sum; } computeDerivatives(stepStart + c[k - 1] * stepSize, yTmp, yDotK[k]); } // estimate the state at the end of the step for (int j = 0; j < y0.length; ++j) { double sum = b[0] * yDotK[0][j]; for (int l = 1; l < stages; ++l) { sum += b[l] * yDotK[l][j]; } yTmp[j] = y[j] + stepSize * sum; } // estimate the error at the end of the step error = estimateError(yDotK, y, yTmp, stepSize); if (error <= 1.0) { // discrete events handling interpolator.storeTime(stepStart + stepSize); if (manager.evaluateStep(interpolator)) { final double dt = manager.getEventTime() - stepStart; if (Math.abs(dt) <= Math.ulp(stepStart)) { // rejecting the step would lead to a too small next step, we accept it loop = false; } else { // reject the step to match exactly the next switch time hNew = dt; } } else { // accept the step loop = false; } } else { // reject the step and attempt to reduce error by stepsize control final double factor = Math.min(maxGrowth, Math.max(minReduction, safety * Math.pow(error, exp))); hNew = filterStep(stepSize * factor, forward, false); } } // the step has been accepted final double nextStep = stepStart + stepSize; System.arraycopy(yTmp, 0, y, 0, y0.length); manager.stepAccepted(nextStep, y); lastStep = manager.stop(); // provide the step data to the step handler interpolator.storeTime(nextStep); for (StepHandler handler : stepHandlers) { handler.handleStep(interpolator, lastStep); } stepStart = nextStep; if (fsal) { // save the last evaluation for the next step System.arraycopy(yDotK[stages - 1], 0, yDotK[0], 0, y0.length); } if (manager.reset(stepStart, y) && !lastStep) { // some event handler has triggered changes that // invalidate the derivatives, we need to recompute them computeDerivatives(stepStart, y, yDotK[0]); } if (!lastStep) { // in some rare cases we may get here with stepSize = 0, for example // when an event occurs at integration start, reducing the first step // to zero; we have to reset the step to some safe non zero value stepSize = filterStep(stepSize, forward, true); // stepsize control for next step final double factor = Math.min(maxGrowth, Math.max(minReduction, safety * Math.pow(error, exp))); final double scaledH = stepSize * factor; final double nextT = stepStart + scaledH; final boolean nextIsLast = forward ? (nextT >= t) : (nextT <= t); hNew = filterStep(scaledH, forward, nextIsLast); } } final double stopTime = stepStart; resetInternalState(); return stopTime; }