Source code for pathsim.events.condition
#########################################################################################
##
## CONDITION EVENTS
## (events/condition.py)
##
## Milan Rother 2024
##
#########################################################################################
# IMPORTS ===============================================================================
import numpy as np
from ._event import Event
# EVENT MANAGER CLASS ===================================================================
[docs]
class Condition(Event):
"""Subclass of base 'Event' that triggers if the event function evaluates to 'True',
i.e. the condition is satisfied.
Monitors system state by evaluating an event function (func_evt) with boolean output.
The event is considered detected when the event function evaluates to 'True' for the
first time. Subsequent evaluations to 'True' are not considered unless the event is reset.
.. code-block::
func_evt(time) -> event?
If an event is detected, some action (func_act) is performed on the system state.
.. code-block::
func_evt(time) == True -> event -> func_act(time)
Note
----
Condition event functions evaluate to boolean and are therefore not smooth.
Therefore uses bisection method for event location instead of secant method.
Example
-------
Initialize a conditional event handler like this:
.. code-block:: python
#define the event function
def evt(t):
return t > 10
#define the action function (callback)
def act(t):
#do something at event resolution
pass
#initialize the event manager
E = Condition(
func_evt=evt, #the event function
func_act=act #the action function
)
"""
[docs]
def detect(self, t):
"""
Evaluate the event function and check if condition is satisfied.
The event function is not differentiable, so we use bisection to
narrow down its location to some tolerance.
Parameters
----------
t : float
evaluation time for detection
Returns
-------
detected : bool
was an event detected?
close : bool
are we close to the event?
ratio : float
adjust timestep to locate event
"""
#unpack history
_result, _t = self._history
#evaluate event function
result = self.func_evt(t)
#check if interval narrowed down sufficiently
close = result and (t - _t) < self.tolerance
#close enough to event
if close: return True, True, 1.0
#half the stepsize to creep closer to event (bisection)
return result, False, 0.5
[docs]
def resolve(self, t):
"""Resolve the event and record the time (t) at which it occurs.
Resolves event using the action function (func_act) if it is defined.
Deactivates the event tracking upon first resolution.
Parameters
----------
t : float
evaluation time for event resolution
"""
#save the time of event resolution
self._times.append(t)
#action function for event resolution
if self.func_act is not None:
self.func_act(t)
#deactivate condition tracking
self.off()