/** * Advances the ODE as usual, except if an event takes place. Then it finds the event point and * applies the actions * * @return The actual step taken */ public double step() { // Step from t=a to t=b(=a+dt) errorCode = ODEAdaptiveSolver.NO_ERROR; eventHappened = false; double t = 0, origDt = solver.getStepSize(); do { triggerOde.readRealState(); // Prepare the faked ODE System.arraycopy(triggerOde.getState(), 0, statea, 0, size); // Set // statea // values at b double dt = solver.step(); double[] state = triggerOde.getState(); // Find which events have happened happened.clear(); for (Enumeration<StateEvent> e = eventList.elements(); e.hasMoreElements(); ) { StateEvent evt = e.nextElement(); if (evt.evaluate(state) <= -evt.getTolerance()) { happened.add(evt); // This event actually happened! } } // Check for no event if (happened.size() == 0) { triggerOde.updateRealState(); solver.setStepSize(origDt); return dt; } eventHappened = true; // System.out.println ("An event!"); // else System.out.println // ("N of events = "+happened.size()+" First is = "+happened.elementAt(0)); /* * This is the moment of truth! We need to find the precise instant * of time for the first event */ // Go back to statea triggerOde.setState(statea); // Check first for a itself // This is to make sure that when two events happen at the same // time they will be found at the exact same instant. // This is important for accuracy of results and better performance. StateEvent eventFound = null; for (StateEvent evt : happened) { if (Math.abs(evt.evaluate(statea)) < evt.getTolerance()) { // Found // at // a // itself eventFound = evt; // System.out.println("Found at a = " + state[state.length - // 1]); break; // No need to continue } } if (eventFound == null) { // Now find by subdivision // This synchronizes our triggerOde state with the state of the // ODEInterpolatorSolver if (solver instanceof ODEInterpolationSolver) solver.initialize(solver.getStepSize()); for (int i = 0; i < MAX; i++) { // Start the subdivision // System.out.println ("Subdividing i = "+i+ // " t = "+state[state.length-1]); solver.setStepSize(dt *= 0.5); // Take half the step double c = solver.step(); state = triggerOde.getState(); StateEvent previousFound = null; for (StateEvent evt : happened) { double f_i = evt.evaluate(state); if (f_i <= -evt.getTolerance()) { previousFound = evt; break; } if (f_i < evt.getTolerance()) { eventFound = evt; // Do not break in case there is a // previous one } } if (previousFound != null) { /* * Eliminate events that may come later (This is not so * necessary) */ for (StateEvent evt : happened) { if (evt != previousFound && (evt.evaluate(state) > -evt.getTolerance())) { happened.remove(evt); } } triggerOde.setState(statea); // go back to a // This synchronizes our triggerOde state with the state // of the ODEInterpolatorSolver if (solver instanceof ODEInterpolationSolver) solver.initialize(solver.getStepSize()); } else { // Advance to new position t = t + c; System.arraycopy(state, 0, statea, 0, size); if (eventFound != null) { // We found it! // System.out.println // ("Found at "+state[state.length-1]); break; } } } // End of the subdivision scheme // The event is any of those which remain in the list of // happened if (eventFound == null) { // If this happens, the event is most // likely poorly designed! eventFound = (StateEvent) happened.elementAt(0); System.err.println( "BisectionEventSolver Warning : Event not found after " + MAX + " subdivisions!!!"); System.err.println(" Event = " + eventFound); System.err.println( " Please check your event algorithm or decrease the initial stepTime."); errorCode = ODEAdaptiveSolver.BISECTION_EVENT_NOT_FOUND; } } // System.out.println ("We are at time = "+state[state.length-1]); // Update real ODE triggerOde.updateRealState(); if (eventFound.action()) { if (solver instanceof ODEInterpolationSolver) { triggerOde.readRealState(); solver.initialize(origDt); } else solver.setStepSize(origDt); return t; } // System.out.println("t = " + t); if (solver instanceof ODEInterpolationSolver) { triggerOde.readRealState(); solver.initialize(origDt - t); } else solver.setStepSize(origDt - t); } while (t < origDt); solver.setStepSize(origDt); return t; }
public void setStepSize(final double stepSize) { solver.setStepSize(stepSize); // Defer to the real solver }