/** * Initialize the integrator. Check for the existence of a director and an ODE solver. Set the * state to the value given by <i>initialState</i>. * * @exception IllegalActionException If there is no director, or the director has no ODE solver, * or the initialState parameter does not contain a valid token, or the superclass throws it. */ public void initialize() throws IllegalActionException { ContinuousDirector dir = (ContinuousDirector) getDirector(); if (dir == null) { throw new IllegalActionException(this, " no director available"); } ContinuousODESolver solver = dir._getODESolver(); if (solver == null) { throw new IllegalActionException(this, " no ODE solver available"); } super.initialize(); _lastRound = -1; _tentativeState = ((DoubleToken) initialState.getToken()).doubleValue(); _state = _tentativeState; if (_debugging) { _debug("Initialize: initial state = " + _tentativeState); } // The number of auxiliary variables that are used depends on // the solver. int n = solver.getIntegratorAuxVariableCount(); if ((_auxVariables == null) || (_auxVariables.length != n)) { _auxVariables = new double[n]; } }
/** * If the value at the <i>derivative</i> port is known, and the current step size is bigger than * 0, perform an integration. If the <i>impulse</i> port is known and has data, then add the value * provided to the state; if the <i>initialState</i> port is known and has data, then reset the * state to the provided value. If both <i>impulse</i> and <i>initialState</i> have data, then * <i>initialState</i> dominates. If either is unknown, then simply return, leaving the output * unknown. Note that the signals provided at these two ports are required to be purely discrete. * This is enforced by throwing an exception if the current microstep is zero when they have input * data. * * @exception IllegalActionException If the input is infinite or not a number, or if thrown by the * solver, or if data is present at either <i>impulse</i> or <i>initialState</i> and the step * size is greater than zero. */ public void fire() throws IllegalActionException { ContinuousDirector dir = (ContinuousDirector) getDirector(); double stepSize = dir.getCurrentStepSize(); int microstep = dir.getIndex(); if (_debugging) { Time currentTime = dir.getModelTime(); _debug( "Fire at time " + currentTime + " and microstep " + microstep + " with step size " + stepSize); } // First handle the impulse input. if (impulse.getWidth() > 0 && impulse.hasToken(0)) { double impulseValue = ((DoubleToken) impulse.get(0)).doubleValue(); if (_debugging) { _debug("-- impulse input received with value " + impulseValue); } if (impulseValue != 0.0) { if (microstep == 0) { throw new IllegalActionException( this, "Signal at the impulse port is not purely discrete."); } double currentState = getState() + impulseValue; setTentativeState(currentState); if (_debugging) { _debug("-- Due to impulse input, set state to " + currentState); } } } // Next handle the initialState port. ParameterPort initialStatePort = initialState.getPort(); if (initialStatePort.getWidth() > 0 && initialStatePort.hasToken(0)) { double initialValue = ((DoubleToken) initialStatePort.get(0)).doubleValue(); if (_debugging) { _debug("-- initialState input received with value " + initialValue); } if (microstep == 0.0) { throw new IllegalActionException( this, "Signal at the initialState port is not purely discrete."); } setTentativeState(initialValue); if (_debugging) { _debug("-- Due to initialState input, set state to " + initialValue); } } // Produce the current _tentativeState as output, if it // has not already been produced. if (!state.isKnown()) { double tentativeOutput = getTentativeState(); // If the round has not updated since the last output, then // just produce the same output as last time. int currentRound = dir._getODESolver()._getRound(); if (_lastRound == currentRound) { tentativeOutput = _lastOutput; } if (_debugging) { _debug("** Sending output " + tentativeOutput); } _lastOutput = tentativeOutput; state.broadcast(new DoubleToken(tentativeOutput)); } // The _tentativeSate is committed only in postfire(), // but multiple rounds will occur before postfire() is called. // At each round, this fire() method may be called multiple // times, and we want to make sure that the integration step // only runs once in the step. if (derivative.isKnown() && derivative.hasToken(0)) { int currentRound = dir._getODESolver()._getRound(); if (_lastRound < currentRound) { // This is the first fire() in a new round // where the derivative input is known and present. // Update the tentative state. Note that we will // have already produced an output, and so we // will not read the updated _tentativeState // again in subsequent invocations of fire() // in this round. So it is safe to update // _tentativeState. _lastRound = currentRound; double currentDerivative = getDerivative(); if (Double.isNaN(currentDerivative) || Double.isInfinite(currentDerivative)) { throw new IllegalActionException( this, "The provided derivative input is invalid: " + currentDerivative); } if (stepSize > 0.0) { // The following method changes the tentative state. dir._getODESolver().integratorIntegrate(this); } } } }