public abstract class QSSBase
extends java.lang.Object
A QSS integrator implements one of the "quantized state systems" methods for solving an initial-value problem (IVP) of a system of ordinary differential equations (ODEs).
A single QSS integrator may be responsible for an entire system of ODEs. Alternately, it may be responsible for a subset of a larger system. The latter approach allows building up a system from smaller components that represent interacting subsystems. Furthermore, each of those subsystems can be integrated by a different variation on the QSS family of methods.
The ODEs are represented using the DerivativeFcn
interface.
Class QSSBase
provides a general framework for running a
single QSS integrator.
This framework must be supplemented in a number of ways:
Quantized State System (QSS) methods solve a system of ordinary differential equations of the form
xdot = f{t, x, u}
where
To solve this system, QSS methods rewrite the system as
xdot = f{t, q, mu}
where
The quantized state, and the quantized input variables, are discretized versions of the state and input variables. The quantized version is a piecewise-continuous approximation, with a functional form chosen to simplify the integration of f.
The implementation here uses polynomial models to quantize the state and input variables. For example, QSS1 quantizes the state using a 0th-order polynomial (that is, as a constant). This means that for purposes of the integration, the state is held constant over discrete intervals of time. The method name, QSS1, arises since an internal, continuous version of the state is maintained as a 1st-order polynomial (that is, as a line).
The details of the methods are beyond the scope of this documentation. See:
Quantized state system methods expose a quantized state to users. Internally, however, they track a continuous state. Both are modeled using polynomials. The polynomial representing the internal, continuous state has one more coefficient than that for the external, quantized state (i.e., it is of order one greater). For example, QSS1 represents the quantized state as constant, but the continuous state as a linear function of time.
For the most part, the user does not need to be aware of this distinction.
In fact, for the most part the user only has access to the quantized state.
In particular, the user can access the ModelPoly
objects used
to track the quantized states.
However, the QSS integrator reserves to itself the right to change the
parameters that define those polynomial models.
In general, the API refers to an abstract "state" rather than to the "quantized state" or the "continuous state". However, some methods distinguish between the quantized and continuous states. For example:
evaluateStateModel(int, Time)
evaluates the quantized state model.
Since the user can access that model directly, this is mainly a convenience
method.evaluateStateModelContinuous(int, Time)
evaluates the
internal, continuous state model.
This is intended mainly for testing.
However, since the internal model does represent the state as a continuous
function of time, for some reporting purposes the internal state may be
preferred.The API and documentation presented here use some terms in specific ways. Furthermore these terms do not always correspond exactly with those used in the QSS method literature.
The QSS method literature refers to "states" and "quantized states". In order to avoid ambiguity, the code here refers to these as "continuous states" and "quantized states", respectively.
Variables for continuous states have names like cStateModel
.
Quantized states have names like qStateModel
.
TODO: Mention terms "rate-events", "state-events", and "quantization-events".
The simplest use of this class is as follows. First, initialize the solver as follows:
DerivativeFunction
, and pass
that into the initialize(DerivativeFunction, Time, Time, double, double, int)
method.setStateValue(int, double)
.getInputVariableModel(int)
.triggerQuantizationEvents(boolean)
.triggerRateEvent()
.predictQuantizationEventTimeEarliest()
.
Then, at each time step,
advanceToTime(Time)
.
This will return a list of state indexes that experience a quantization event
at the new simulation time, and you can retrieve the new values of those
state variables using getStateModel(int)
.
getInputVariableModel(int)
.triggerRateEvent()
.predictQuantizationEventTimeEarliest()
.
That should be the time of the next time step.
The following methods initialize a new integrator. They must be called before doing any work with the integrator:
The following methods inquire about fixed integrator parameters:
The following methods set up the exchange of models between an integrator and the rest of the simulation environment. In general, they should be called before starting a simulation. However, they may also be called during an integration:
The following methods configure the integrator. In general, they should be called before its first use. However, they may also be called during an integration:
setQuantizationTolerance(int, double, double)
setQuantizationTolerances(double, double)
setCurrentSimulationTime(Time)
setStateValue(int, double)
setQuantizationEventTimeMaximum(Time)
validate()
The following methods inquire about current values during a simulation:
The following methods prepare the integrator to take the next time step:
needQuantizationEventIndex()
needQuantizationEventIndexes(boolean[])
triggerQuantizationEvent(int)
triggerQuantizationEvents(boolean)
needRateEvent()
triggerRateEvent()
predictQuantizationEventTime(int)
predictQuantizationEventTimeEarliest()
The following methods take a time step:
The following methods primarily facilitate testing:
TODO: Describe the general time-stepping model.
Steps only accomplished via method stepToTime(Time)
.
All other methods elaborate on what happens between time steps.
The abstract methods that each subclass must fill in have names ending
in _work
.
This is meant to help distinguish them from the general entry-points
provided by this base class.
Modifier and Type | Field and Description |
---|---|
protected ModelPolynomial[] |
_cStateModels
Internal continuous state models.
|
protected Time |
_currSimTime
The simulation time of the last call.
|
protected DerivativeFunction |
_derivFcn
Derivative function.
|
protected double[] |
_dqs
Quanta.
|
protected int |
_evtIndCt
The event indicator count.
|
protected boolean |
_exactInputs
Flag indicating that the solver should assume that inputs are exact,
meaning that if derivatives are zero, then they are genuinely zero,
not just unknown.
|
protected int |
_ivCt
The count of input variables.
|
protected ModelPolynomial[] |
_ivModels
Input variables.
|
protected ModelPolynomial[] |
_qStateModels
External, quantized state models.
|
protected Time |
_quantEvtTimeMax
Maximum Time for predicted quantization-event times.
|
protected int |
_stateCt
The state count.
|
Constructor and Description |
---|
QSSBase() |
Modifier and Type | Method and Description |
---|---|
protected abstract void |
_initializeWorker()
Initialize object fields (QSS-specific).
|
protected static double |
_predictQuantizationEventDeltaTimeQSS2General(ModelPolynomial qStateModel,
ModelPolynomial cStateModel,
double dq,
boolean exactInputs)
Get the delta-time to the predicted quantization-event for a state under QSS2.
|
protected static double |
_predictQuantizationEventDeltaTimeQSS2QFromC(ModelPolynomial qStateModel,
ModelPolynomial cStateModel,
double dq,
boolean exactInputs)
Get the delta-time to the predicted quantization-event for a state under QSS2.
|
protected static double |
_predictQuantizationEventDeltaTimeQSS3General(ModelPolynomial qStateModel,
ModelPolynomial cStateModel,
double dq)
Get the delta-time to the predicted quantization-event for a state under QSS3.
|
protected static double |
_predictQuantizationEventDeltaTimeQSS3QFromC(ModelPolynomial qStateModel,
ModelPolynomial cStateModel,
double dq,
boolean exactInputs)
Get the delta-time to the predicted quantization-event for a state under QSS3.
|
protected abstract Time |
_predictQuantizationEventTimeWorker(int stateIdx,
Time quantEvtTimeMax)
Get the predicted quantization-event time for a state (QSS-specific).
|
protected abstract void |
_triggerQuantizationEventWorker(int stateIdx)
Form a new external, quantized state model (QSS-specific).
|
protected abstract void |
_triggerRateEventWorker()
Form new internal, continuous state models (QSS-specific).
|
protected abstract void |
_triggerRateEventWorkerEventDetection()
Form new internal, continuous state models (QSS-specific).
|
java.util.List<java.lang.Integer> |
advanceToTime(Time nextSimTime)
Advance simulation time to the specified time.
|
double |
evaluateStateModel(int stateIdx,
Time simTime)
Get the value of a state variable.
|
double |
evaluateStateModelContinuous(int stateIdx,
Time simTime)
Get the internal value of a state variable.
|
double |
findQuantum(int stateIdx)
Find the quantum for a state.
|
Time |
getCurrentSimulationTime()
Get the current simulation time for the QSS integrator.
|
int |
getEventIndicatorCount()
Return the count of event indicators.
|
boolean |
getExactInputs()
Return whether inputs are assumed to be exact.
|
int |
getInputVariableCount()
Return the count of input variables to the integrator.
|
ModelPolynomial |
getInputVariableModel(int input)
Return the input variable model for the specified index.
|
int |
getStateCount()
Return the count of states predicted by the integrator.
|
ModelPolynomial |
getStateModel(int stateIdx)
Get the external, quantized state model for a state predicted by the integrator.
|
abstract int |
getStateModelOrder()
Get the order of the external, quantized state models exposed by the integrator.
|
void |
initialize(DerivativeFunction derivativeFunction,
Time startTime,
Time maximumTime,
double absoluteTolerance,
double relativeTolerance,
int inputVariableOrder)
Initialize this solver, associating it with the specified
derivativeFunction object, which determines the number of state
variables and input variables and provides a method for calculating
the derivatives of the state variables.
|
void |
initializeDerivativeFunction(DerivativeFunction derivFcn)
Initialize a QSS integrator to use a
DerivativeFunction object. |
void |
initializeDerivativeFunction(DerivativeFunction derivFcn,
int numEvtInds)
Initialize a QSS integrator to use a
DerivativeFunction object. |
void |
initializeSimulationTime(Time initSimTime)
Initialize a QSS integrator with an initial time.
|
Time |
minimumTime(Time time1,
Time time2)
Compare and return the smalltest time between two time objects.
|
int |
needInputVariableModelIndex()
Return the index of an input variable for which the user has yet to add a model.
|
int |
needQuantizationEventIndex()
Return the first index of a state that needs a quantization-event.
|
void |
needQuantizationEventIndexes(boolean[] needQuantEvtIdxs)
Return array of booleans indicating all states that need a quantization-event.
|
boolean |
needRateEvent()
Determine whether the integrator needs a rate-event.
|
Time |
predictQuantizationEventTime(int stateIdx)
Get the predicted quantization-event time for a state.
|
Time |
predictQuantizationEventTimeEarliest()
Get the earliest predicted quantization-event time for all states.
|
Time |
predictQuantizationEventTimeEarliest(boolean[] quantEvtElts)
Get the earliest predicted quantization-event time for all states.
|
void |
setCurrentSimulationTime(Time newSimTime)
Set or reset the integrator's current time.
|
void |
setExactInputs(boolean exact)
Indicate whether inputs are exact.
|
void |
setInputVariableModel(int ivIdx,
ModelPolynomial ivModel)
Set the model for an input variable to the derivative function.
|
void |
setNumberOfEventIndicators(int numberEventIndicators)
Set the number of event indicators.
|
void |
setQuantizationEventTimeMaximum(Time quantEvtTimeMax)
Reset the maximum time for predicted quantization-events.
|
void |
setQuantizationTolerance(int stateIndex,
double absoluteTolerance,
double relativeTolerance)
Set the parameters used to determine the quantum for a state.
|
void |
setQuantizationTolerances(double absoluteTolerance,
double relativeTolerance)
Set the parameters used to determine the quantum for all states.
|
void |
setStateValue(int stateIdx,
double newValue)
Set the value of a state variable.
|
void |
stepToTime(Time nextSimTime)
Step to the next knot in the global simulation.
|
void |
stepToTime(Time nextSimTime,
int numberEventIndicators)
Step to the next knot in the global simulation for event detection.
|
java.lang.String |
stringifyStateModel(int stateIdx)
Get a string representation of the model for a state.
|
java.lang.String |
stringifyStateModelContinuous(int stateIdx)
Get a string representation of the internal model for a state.
|
void |
triggerQuantizationEvent(int stateIdx)
Form a new external, quantized state model.
|
void |
triggerQuantizationEvents(boolean forceAll)
Form new external, quantized state models.
|
void |
triggerRateEvent()
Form new internal, continuous state models.
|
void |
triggerRateEvent(int numberEventIndicators)
Form new internal, continuous state models.
|
java.lang.String |
validate()
Validate the QSS integrator has been properly set up.
|
protected boolean _exactInputs
protected DerivativeFunction _derivFcn
protected int _stateCt
protected int _evtIndCt
protected int _ivCt
protected ModelPolynomial[] _cStateModels
protected ModelPolynomial[] _qStateModels
protected ModelPolynomial[] _ivModels
protected double[] _dqs
protected Time _currSimTime
protected Time _quantEvtTimeMax
public final java.util.List<java.lang.Integer> advanceToTime(Time nextSimTime) throws java.lang.Exception
nextSimTime
- Global simulation time to which to step.java.lang.IllegalArgumentException
- If the specified time is not
strictly greater than the current simulation time, or if the
specified time is past the next event time, or if
there are states requiring a quantization event.java.lang.Exception
- If triggering a rate event causes an error
(this is dependent on the concrete implementation of this class).public final double evaluateStateModel(int stateIdx, Time simTime)
Evaluate the external, quantized state model at a specified time.
Note this method evaluates the external, quantized state model.
Alternately, the user could acquire the model, via
method getStateModel(int)
, and evaluate that model directly.
stateIdx
- The state index, 0 <= stateIdx < this.getStateCt().simTime
- Global simulation time.simTime
.public final double evaluateStateModelContinuous(int stateIdx, Time simTime)
Evaluate the internal, continuous state model at a specified time.
stateIdx
- The state index, 0 <= stateIdx < this.getStateCt().simTime
- Global simulation time.simTime
.public final double findQuantum(int stateIdx)
Finds the quantum, i.e., the maximum allowable difference between the external, quantized state model shared with the user, and the internal, continuous state model used by the integrator.
To change the parameters used to find the quantum, use
method setQuantizationTolerance(int, double, double)
or method setQuantizationTolerances(double, double)
.
The user should never have to call this method directly. The QSS integrator invokes it as needed.
This method does not store the quantum calculated. The QSS integrator is expected to take care of this.
The nominal policy is to find the quantum whenever the external, quantized state model gets updated. This is because, as calculated here, the quantum depends on the constant coefficient of the external, quantized state model.
In principle, the quantum could be based on the current value of the one of the state models, calculated at the time the quantum is needed. This differs from the policy outlined above, in that the current value of a state generally differs from its constant coefficient.
However, this more complicated policy would induce a lot of mostly needless calculations. If the external, quantized state changes by a large amount, but still tracks the internal, continuous state model well, then the quantum for this element doesn't matter much. If, on the other hand, the two models don't agree, then there will be a quantization-event, which will trigger a new call of this method.
stateIdx
- The state index, 0 <= stateIdx < this.getStateCt().public final Time getCurrentSimulationTime()
This is generally the last global simulation time for which
method stepToTime(Time)
was called.
Exceptions:
setCurrentSimulationTime(Time)
changes the value outright.setCurrentSimulationTime(Time)
public final int getEventIndicatorCount()
public final boolean getExactInputs()
setExactInputs(boolean)
with argument true,
then this will return true. A true value
asserts that all non-zero derivatives of the input model are provided.setExactInputs(boolean)
public final int getInputVariableCount()
public final ModelPolynomial getInputVariableModel(int input)
input
- The index of the input variable.setInputVariableModel(int, ModelPolynomial)
public final int getStateCount()
public final ModelPolynomial getStateModel(int stateIdx)
The QSS integrator uses this model to share the predicted state as a function of time, when integrating the derivative function.
The initial state model is constant at a value of 0.
Use method setStateValue(int, double)
to change this initial value.
Never change the model parameters directly. The QSS integrator claims exclusive write access to the model.
Notes on "write access" for the state model:
ModelPoly
.
This means it will control the trajectory of that model over time.
See method ModelPoly.claimWriteAccess().setStateValue(int, double)
, in order
to initialize the state, before starting the integration.Notes on sharing models between roles in the integration:
The design intention behind exposing the state models directly to the rest of the system is to make sharing state predictions as cheap as possible.
From an encapsulation viewpoint, the integrator does not have to
expose its state models to the rest of the simulation.
It could, instead, force the user to evaluate the quantized state models
using method evaluateStateModel(int, Time)
.
Alternately, it could copy the quantized state model to a user-supplied
model object, thus keeping the integrator's private copy hidden.
However, both these approaches are relatively high overhead, compared
to simply exposing the model for the user to evaluate as needed.
stateIdx
- The state index, 0 ≤ stateIdx < this.getStateCt().public abstract int getStateModelOrder()
This method returns the order of the ModelPolynomial
objects
that the integrator exposes to the user.
These states are the quantized state predictions (as opposed to the continuous state predictions the integrator uses internally). Therefore the order is one less than the nominal order of the QSS method.
For example, QSS1 uses a first-order (linear) polynomial to model each
state variable.
However, it does not expose that internal representation to the user.
The external, quantized, representation of the state is a constant (i.e.,
a 0th-order polynomial).
Therefore QSS1 should return 0
for this method.
public final void initialize(DerivativeFunction derivativeFunction, Time startTime, Time maximumTime, double absoluteTolerance, double relativeTolerance, int inputVariableOrder)
setStateValue(int, double)
and
setInputVariableModel(int, ModelPolynomial)
.
The caller of this method should then, after setting state and
input values, call triggerQuantizationEvents(boolean)
with argument true.
This is a convenience method wrapping a sequence of calls to more detailed methods.
derivativeFunction
- The object implementing the
function that provides the derivatives for
state variables that this solver is responsible for integrating.
This object also provides a method specifying the number of state
variables and the number of input variables.startTime
- The start time for the solver.maximumTime
- The maximum time for predicted events (e.g. the stop
time of the simulation). This may be infinite.absoluteTolerance
- The absolute tolerance for all state variables
(these can be modified later for individual states
using setQuantizationTolerance(int, double, double)
).relativeTolerance
- The relative tolerance for all state variables
(these can be modified later for individual states
using setQuantizationTolerance(int, double, double)
).inputVariableOrder
- The order (the number of derivatives provided)
for each input variable. If these differ by input variable, then the
caller may later modify the input variable models by calling
setInputVariableModel(int, ModelPolynomial)
.public final void initializeDerivativeFunction(DerivativeFunction derivFcn)
DerivativeFunction
object.
This method must be called before doing any work with the integrator. Furthermore, it can be called only once.
The derivative function is central to the integrator, and could very well be passed to the constructor. However, to accommodate a wide range of downstream users, a zero-argument constructor was desired. Of course, a constructor that takes the derivative function as an argument could be provided; it would simply call this method.
derivFcn
- Object that implements the DerivativeFcn interface.public final void initializeDerivativeFunction(DerivativeFunction derivFcn, int numEvtInds)
DerivativeFunction
object.
This method must be called before doing any work with the integrator. Furthermore, it can be called only once. This methods is used to determine when zero crossing happen.
The derivative function is central to the integrator, and could very well be passed to the constructor. However, to accommodate a wide range of downstream users, a zero-argument constructor was desired. Of course, a constructor that takes the derivative function as an argument could be provided; it would simply call this method.
derivFcn
- Object that implements the DerivativeFcn interface.numEvtInds
- Number of event indicators.public final void initializeSimulationTime(Time initSimTime)
This method must be called before doing any work with the integrator. Furthermore, it can be called only once.
For flexibility, the integrator represents time using objects of
class Time
(rather than, for example, a more
traditional double-precision variable).
This leaves the implementation open to the user.
However, it also means that the integrator cannot assume an exact
form of constructor for creating Time
objects.
Therefore the user has to construct and provide the initial time.
initSimTime
- The initial time.public final Time minimumTime(Time time1, Time time2)
time1
- Time object.time2
- Time object.public final int needInputVariableModelIndex()
The user must call setInputVariableModel(int, ModelPolynomial)
at least once for
every input variable taken by the derivative function.
This method checks whether that requirement has been met.
public final int needQuantizationEventIndex()
stepToTime(Time)
repeatedly
to iterate over the states on which triggerQuantizationEvent(int)
should be called. See advanceToTime(Time)
for a typical usage
pattern.
The integrator tracks which states need a quantization-event as a result of a time step. This method returns the index, if any, of such states.
The user should trigger the quantization-event, e.g., using
method triggerQuantizationEvent(int)
.
TODO: Put under unit test.
public final void needQuantizationEventIndexes(boolean[] needQuantEvtIdxs)
See comments to method needQuantizationEventIndex()
.
TODO: Put under unit test.
needQuantEvtIdxs
- (output) Vector showing true
for
each integrator state that needs a quantization-event.public final boolean needRateEvent()
This method only checks whether the integrator needs a rate-event due to a quantization-event. The integrator does not track changes in the parameters of its input variable models, so the integrator cannot warn of the need to trigger a rate-event after an input variable changes.
TODO: Statement above will change if provide ability to install listeners on input variables.public final Time predictQuantizationEventTime(int stateIdx)
stateIdx
- The state index, 0 <= stateIdx < this.getStateCt().public final Time predictQuantizationEventTimeEarliest()
public final Time predictQuantizationEventTimeEarliest(boolean[] quantEvtElts)
quantEvtElts
- (output) Vector showing true
for those
elements whose predicted quantization-event time is the minimum
from among all elements. At least one such element must be marked.public final void setCurrentSimulationTime(Time newSimTime)
newSimTime
- New time for the QSS integrator.getCurrentSimulationTime()
public final void setExactInputs(boolean exact)
exact
- True to indicate that inputs are exact.getExactInputs()
public final void setInputVariableModel(int ivIdx, ModelPolynomial ivModel)
Add a ModelPolynomial
for an input variable to the
derivative function.
The QSS method will use this model to evaluate the input variable as a
function of time, when integrating the derivative function.
The user must call this method at least once for every input variable taken by the derivative function. This must be done before starting the integration.
Notes on "write access" for the state model:
ModelPolynomial
.
This means it will control the trajectory of that model over time.
See ModelPolynomial.claimWriteAccess()
.Notes on selecting the input variable model order:
Notes on sharing models between roles in the integration:
getStateModel(int)
.Notes on providing a different model at a later time:
ivIdx
- The index of input variable, 0 ≤ ivIdx < this.getInputVarCt().ivModel
- The model to use.java.lang.IllegalArgumentException
- If the argument is null.getInputVariableModel(int)
public final void setNumberOfEventIndicators(int numberEventIndicators)
numberEventIndicators
- Number of event indicators.public final void setQuantizationTolerance(int stateIndex, double absoluteTolerance, double relativeTolerance)
The quantum for each state variable gets calculated as
q[j] = max{Ta, Tr*abs{x[j]}}
where
This method sets the tolerances used to find the quantum. It also updates the quantum to reflect the new tolerances.
stateIndex
- The state index, 0 ≤ stateIdx < this.getStateCt().absoluteTolerance
- The absolute tolerance, which is required to be > 0 [units of x[j]].relativeTolerance
- The relative tolerance, which is required to be ≥ 0 [1].java.lang.IllegalArgumentException
- If the absolute tolerance is not strictly positive, or
if the relative tolerance is negative.public final void setQuantizationTolerances(double absoluteTolerance, double relativeTolerance)
Apply the same tolerances to all the states the integrator predicts.
For details, see method setQuantizationTolerance(int, double, double)
.
absoluteTolerance
- The absolute tolerance, which is required to be > 0 [units of x[j]].relativeTolerance
- The relative tolerance, which is required to be ≥ 0 [1].public final void setStateValue(int stateIdx, double newValue)
Change the value component of the model for element stateIdx of the state vector. Note that this re-initializes the integrator for that component. That is, it discards any state models that the integrator might have formed, and creates a jump discontinuity in the state variable. This has the side effect of setting flags indicating that a new rate event is needed and that the specified state needs a quantization event.
The user may be tempted to set the value of the state variable directly in the state model, without going through the QSS integrator. However, doing so prevents the integrator from making the appropriate internal adjustments to the change in state.
stateIdx
- The state index, 0 <= stateIdx < this.getStateCt().newValue
- The new value of x[stateIdx].public final void setQuantizationEventTimeMaximum(Time quantEvtTimeMax)
The integrator will not predict quantization-event times past this
time.
Default value Time.POSITIVE_INFINITY
.
quantEvtTimeMax
- The maximum time for predicted quantization-events.public final void stepToTime(Time nextSimTime) throws java.lang.Exception
Don't complain if stepping past a predicted quantization-event time. Just report need to trigger a quantization-event before the next step.
nextSimTime
- Global simulation time to which to step,
nextSimTime > this.getCurrSimTime().java.lang.Exception
- If the simulation time must advance or if
there are state models waiting to be quantized,public final void stepToTime(Time nextSimTime, int numberEventIndicators) throws java.lang.Exception
Don't complain if stepping past a predicted quantization-event time. Just report need to trigger a quantization-event before the next step.
nextSimTime
- Global simulation time to which to step,
nextSimTime > this.getCurrSimTime().numberEventIndicators
- The number of event indicators.java.lang.Exception
- If the simulation time must advance or if
there are state models waiting to be quantized,public final java.lang.String stringifyStateModel(int stateIdx)
Invoke method ModelPoly.toString() on the external, quantized state model.
stateIdx
- The state index, 0 <= stateIdx < this.getStateCt().public final java.lang.String stringifyStateModelContinuous(int stateIdx)
Invoke method ModelPoly.toString() on the internal, continuous state model.
stateIdx
- The state index, 0 <= stateIdx < this.getStateCt().public final void triggerQuantizationEvent(int stateIdx)
Force the QSS integrator to form a new external, quantized state model (i.e., to experience a quantization-event). The new model will be available to the user immediately.
Note method triggerQuantizationEvents(boolean)
can requantize multiple
state models at once, and can requantize only those states that need it.
Form the model about the current simulation time, as returned by
method getCurrentSimulationTime()
.
Note this method can be invoked even if the external, quantized state model is still within quantum of the internal, continuous state model. The integrator will still update the quantized state model about the current time. Doing so can only improve the accuracy of the simulation (at the cost of some extra processing).
Note the state model of interest here is the
external, quantized state model.
In order to re-form the internal, continuous state model, use
method triggerRateEvent()
.
The proper sequence in which to call method triggerRateEvent()
and method triggerQuantizationEvent(int)
is a fraught topic.
In general, should requantize all states first, then trigger rate events.
Also, after triggering a rate event, get the new predicted quantization time.
TODO: Write up a higher-level description of the problem.
stateIdx
- The state index, 0 <= stateIdx < this.getStateCt().public final void triggerQuantizationEvents(boolean forceAll)
Convenience method to call method triggerQuantizationEvent(int)
on
all states predicted by this integrator.
Can apply only to those states that are marked for requantization, or can apply to all states.
Note that a state gets marked for requantization:
predictQuantizationEventTime(int)
.triggerRateEvent()
.To determine state(s) that need to be requantized, use either
method needQuantizationEventIndex()
or
method needQuantizationEventIndexes(boolean[])
.
forceAll
- If true, requantize all state models.public final void triggerRateEvent() throws java.lang.Exception
Force the QSS integrator to form new internal, continuous state models (i.e., to experience a rate-event). The rate models also get updated.
In general, this needs to be done whenever an argument to the derivative function has changed. A "change" in an argument to the derivative function means a change in any of the parameters to an argument's model. This may happen, for example, due to a quantization-event in the integrator that predicts an argument to this integrator. It may also happen due to a change in a boundary condition, for example provided by an external file.
Form the model about the current simulation time, as returned by
method getCurrentSimulationTime()
.
Note this method can be invoked even if no argument to the derivative function has had a change in its parameters. The integrator will still update the rate and state models about the current time. Doing so can only improve the accuracy of the simulation (at the cost of some extra processing).
Note the state model of interest here is the
internal, continuous state model.
In order to re-form the external, quantized state model, use
method triggerQuantizationEvent(int)
.
The proper sequence in which to call method triggerRateEvent()
and method triggerQuantizationEvent(int)
is a fraught topic.
In general, should requantize all states first, then trigger rate-events.
Also, after trigger a rate-event, get new predicted quantization-time.
TODO: Write up a higher-level description of the problem.
The way to handle a rate-event varies depending on the particular QSS method. Therefore this is an abstract method. Subclasses are expected take care of the following:
Note it's tempting to say should that handling a rate-event should force a quantization-event if one is needed, before handle any rate-event. The logic being that the quantization-event will then induce another rate-event that needs to be handled, anyway. The problem with that logic is that it imposes a policy on how to deal with potential loops in updating cycles. Thus it removes the user's ability to control when quantization happens, which might be important. Of course, if there are no loops, then it is certainly best to requantize before finding new rate and state models. That's because requantizing, always creates a rate-event (since quantized outputs are always arguments to the derivative function). TODO: Consider returning integer status, equal to return status of the derivative function (which should be zero if successful). Then get rid of the exception. TODO: Add a "force" flag so only triggers if needed.
java.lang.Exception
- If thrown while performing the work defined by
a specific member of the QSS family.public final void triggerRateEvent(int numberEventIndicators) throws java.lang.Exception
Force the QSS integrator to form new internal, continuous state models (i.e., to experience a rate-event). The rate models also get updated.
This method is similar to method triggerRateEvent()
.
The only difference is that it calls
method _triggerRateEventWorkerEventDetection()
to detect and handle state events.
numberEventIndicators
- The number of event indicators.java.lang.Exception
- If thrown while triggering the rate event.public final java.lang.String validate()
This method diagnoses setup problems with the integrator.
For example, if running the integrator causes a NullPointerException
,
then this method can pinpoint problems originating with the integrator.
It is not necessary to run this method in order to run the integrator.
protected abstract void _initializeWorker()
Perform one-time initializations at the beginning of the object lifetime.
The implementation of this "worker" method depends on the specific member of the QSS family.
protected abstract Time _predictQuantizationEventTimeWorker(int stateIdx, Time quantEvtTimeMax)
See comments to method predictQuantizationEventTime(int)
.
The implementation of this "worker" method depends on the specific member of the QSS family.
The method should not alter any instance variables.
stateIdx
- The state index, 0 <= stateIdx < this.getStateCt().quantEvtTimeMax
- The maximum time for the return value. May be
Time.POSITIVE_INFINITY.protected static final double _predictQuantizationEventDeltaTimeQSS2QFromC(ModelPolynomial qStateModel, ModelPolynomial cStateModel, double dq, boolean exactInputs)
Utility method for use by _predictQuantizationEventTimeWorker(int, Time)
.
Find the time step, from the most recent quantization-event time, of the predicted quantization-event for a state under QSS2. Assume the quantized state model was derived from the continuous state model, and therefore has the same value and slope at the quantization-event time.
TODO: Put this method under direct unit test.
Currently tested indirectly, through method _predictQuantizationEventTimeWorker(int, Time)
of each solver.
Testing directly will make it easier to check results, and will make it
easier to add testing for slope-aware quant-evt predictions.
qStateModel
- The model of external, quantized state.cStateModel
- The model of internal, continuous state.dq
- The quantum, i.e., the critical difference between the models, at
which the external state model must be re-formed.exactInputs
- If true, then the inputs are known to be exact.
If true, then do not fall back to QSS1.exactInputs
- True if exact inputs are expected.protected static final double _predictQuantizationEventDeltaTimeQSS2General(ModelPolynomial qStateModel, ModelPolynomial cStateModel, double dq, boolean exactInputs)
Utility method for use by _predictQuantizationEventTimeWorker(int, Time)
.
Find the time step, from the most recent state-event time, of the predicted quantization-event for a state under QSS2. Do not assume the quantized state model bears any particular relationship to the continuous state model.
TODO: Put this method under direct unit test.
Currently tested indirectly, through method _predictQuantizationEventTimeWorker(int, Time)
of each solver.
Testing directly will make it easier to check results, and will make it
easier to add testing for slope-aware quant-evt predictions.
qStateModel
- The model of external, quantized state.cStateModel
- The model of internal, continuous state.dq
- The quantum, i.e., the critical difference between the models, at
which the external state model must be re-formed.exactInputs
- True if exact inputs are expected.protected static final double _predictQuantizationEventDeltaTimeQSS3QFromC(ModelPolynomial qStateModel, ModelPolynomial cStateModel, double dq, boolean exactInputs)
Utility method for use by _predictQuantizationEventTimeWorker(int, Time)
.
Find the time step, from the most recent quantization-event time, of the predicted quantization-event for a state under QSS3. Assume the quantized state model was derived from the continuous state model, and therefore has the same value slope, and second derivative at the quantization-event time.
TODO: Put this method under direct unit test.
Currently tested indirectly, through method _predictQuantizationEventTimeWorker(int, Time)
of each solver.
Testing directly will make it easier to check results, and will make it
easier to add testing for slope-aware quant-evt predictions.
cStateModel
- The model of internal, continuous state.qStateModel
- The model of external, quantized state.dq
- The quantum, i.e., the critical difference between the models, at
which the external state model must be re-formed.protected static final double _predictQuantizationEventDeltaTimeQSS3General(ModelPolynomial qStateModel, ModelPolynomial cStateModel, double dq)
Utility method for use by _predictQuantizationEventTimeWorker(int, Time)
.
Find the time step, from the most recent state-event time, of the predicted quantization-event for a state under QSS3. Do not assume the quantized state model bears any particular relationship to the continuous state model.
TODO: Put this method under direct unit test.
Currently tested indirectly, through method _predictQuantizationEventTimeWorker(int, Time)
of each solver.
Testing directly will make it easier to check results, and will make it
easier to add testing for slope-aware quant-evt predictions.
cStateModel
- The model of internal, continuous state.qStateModel
- The model of external, quantized state.dq
- The quantum, i.e., the critical difference between the models, at
which the external state model must be re-formed.protected abstract void _triggerQuantizationEventWorker(int stateIdx)
See comments to method triggerQuantizationEvent(int)
.
The implementation of this "worker" method depends on the specific member of the QSS family.
stateIdx
- The state index, 0 <= stateIdx < this.getStateCount().protected abstract void _triggerRateEventWorker() throws java.lang.Exception
See comments to method triggerRateEvent()
.
The implementation of this "worker" method depends on the specific member of the QSS family.
java.lang.Exception
- If the rate event worker fails.protected abstract void _triggerRateEventWorkerEventDetection() throws java.lang.Exception
See comments to method triggerRateEvent()
.
The implementation of this "worker" method depends on the specific member of the QSS family.
java.lang.Exception
- If the rate event worker event detection fails.