Events
What is an Event?
An event is a condition that triggers an action.
Conditions are boolean Temporal Variables.
Actions are triggered at time points when the condition is True
. They are defined through event creation
functions.
Events are created through the following functions and methods. The trigger
argument is for the condition:
terminate_on(trigger)
: Terminate the simulation when triggered.IntegratedVar.reset_on(trigger, new_value)
: Set the Integrated Variable value tonew_value
when triggered.execute_on(trigger, f)
: Execute the functionf
when triggered.
Example: Bouncing Ball
Consider a bouncing ball:
- Condition: The ball hits the ground. We use the
.crossed()
method to create a Temporal Variable that returns True when the contact with the ground occurs. - Action: The bounce, which is the reversing of the ball's velocity. We use the
.reset_on(trigger, new_value)
method on the velocity to change the value of the velocity when it hits the ground.
Crossing Trigger Variables
In physical systems, where variables are continuous, you should use Crossing Trigger Variables for your event conditions.
Crossing Trigger Variables detects the exact time at which a crossing between a Temporal Variable and a value occurs.
To create a Crossing Trigger Variable, use the .crosses(value, direction)
method:
# Create the system
acceleration = vip.temporal(-9.81)
velocity = vip.integrate(acceleration, x0=0)
height = vip.integrate(velocity, x0=2)
hit_ground = height.crosses(0, "falling")
The value
argument can be a Temporal Variable.
Crossing Direction
Use the direction
argument to filter triggers:
"rising"
: triggered when the value crosses the threshold from below."falling"
: triggered when crossing from above."both"
(default): triggered regardless of crossing direction.
Temporal Triggers
Two functions are available to create Crossing Trigger Variable from the system clock:
timeout_trigger(delay)
: Triggers whensimulation_time==delay
.interval_trigger(delay)
: Triggers regularly at every interval ofdelay
.
The delay
argument is a duration in seconds.
Conditional Triggers
Use logical operators on the Temporal Variables you use as a trigger to create a conditional trigger variable:
v_min = 0.5 # Minimum velocity for the ball to bounce when hitting the ground
# Create the system
acceleration = vip.temporal(-9.81)
velocity = vip.integrate(acceleration, x0=0)
height = vip.integrate(velocity, x0=2)
hit_ground = height.crosses(0, "falling")
trigger_stop = hit_ground & (abs(velocity) <= v_min)
Creating Events
Terminal Events
Use terminate_on(trigger)
to terminate the simulation when a triggers occurs:
acceleration = vip.temporal(-9.81)
velocity = vip.integrate(acceleration, x0=0)
height = vip.integrate(velocity, x0=10)
hit_ground = height.crosses(0, "falling")
vip.terminate_on(hit_ground)
height.to_plot()
vip.solve(10, time_step=0.01)
Reset an Integrated Variable
Use the .reset_on(trigger, value)
of an Integrated Variable to instantly change its state:
a = vip.temporal(-9.81)
v = vip.integrate(a, 0)
y = vip.integrate(v, 10)
hit_ground = y.crosses(0, "falling")
v.reset_on(hit_ground, -v) # Reverse velocity
Custom Events
You can trigger any function with execute_on(trigger, f)
. The function f
must be a function with side-effects.
vip.execute_on(hit_ground, lambda: print("Hello world"))
Output:
Hello world
To access the event time, add an argument to the input function:
def log_time(t):
print(f"Collision at {t}.")
# ...
vip.execute_on(hit_ground, log_time)
Output:
Collision at 1.4278431229270645.