CoSApp tutorials on multimode systems
Multimode ODE¶
In this example, we show a system defining a simple Ordinary Differential Equation, with an event-driven discontinuity.
[1]:
from cosapp.base import System
class ScalarOde(System):
"""System representing ODE df/dt = F(t)"""
def setup(self):
self.add_inward('df')
self.add_transient('f', der='df')
class MultimodeScalarOde(System):
def setup(self):
self.add_child(ScalarOde('ode'), pulling=['f', 'df'])
self.add_outward_modevar('snapped', False)
self.add_event('snap') # event defining mode var `snapped`
def transition(self):
if self.snap.present:
self.snapped = True
[2]:
from cosapp.drivers import RungeKutta
from cosapp.recorders import DataFrameRecorder
s = MultimodeScalarOde('s')
s.snap.trigger = "f > 0.547"
driver = s.add_driver(
RungeKutta(order=2, time_interval=(0, 1), dt=0.1)
)
driver.add_recorder(DataFrameRecorder(includes=['f', 'df', 'snapped']), period=0.1)
# Set scenario such that df/dt changes with mode
driver.set_scenario(
init = {'f': 0},
values = {'df': '2 * t if not snapped else 0'},
)
s.run_drivers()
# Retrieve recorded data
data = driver.recorder.export_data()
data = data.drop(['Section', 'Status', 'Error code'], axis=1)
[3]:
# Plot results
import plotly.graph_objs as go
def get_trace(col):
return go.Scatter(
x = data['time'],
y = data[col],
name = col,
mode = "lines+markers",
)
go.Figure(
data = [
get_trace('f'),
get_trace('df'),
],
layout = go.Layout(
xaxis = dict(title="Time"),
height = 450,
hovermode = "x",
),
)
Show recorded data¶
Note the double entry at snap time. When snapped
is False
, the solution is \(f(t) = t^2\), since the derivative is \(2t\), with initial condition \(f(0) = 0\). Event time is therefore \(t_{\rm snap} = \sqrt{0.547}\).
[4]:
from math import sqrt
print(f"{sqrt(0.547) = }")
sqrt(0.547) = 0.7395944834840239
[5]:
data
[5]:
Reference | df | f | snapped | time | |
---|---|---|---|---|---|
0 | t=0.0 | 0.000000 | 0.000 | False | 0.000000 |
1 | t=0.1 | 0.200000 | 0.010 | False | 0.100000 |
2 | t=0.2 | 0.400000 | 0.040 | False | 0.200000 |
3 | t=0.3 | 0.600000 | 0.090 | False | 0.300000 |
4 | t=0.4 | 0.800000 | 0.160 | False | 0.400000 |
5 | t=0.5 | 1.000000 | 0.250 | False | 0.500000 |
6 | t=0.6 | 1.200000 | 0.360 | False | 0.600000 |
7 | t=0.7 | 1.400000 | 0.490 | False | 0.700000 |
8 | t=0.73959448348402 | 1.479189 | 0.547 | False | 0.739594 |
9 | s.snap | 0.000000 | 0.547 | True | 0.739594 |
10 | t=0.8 | 0.000000 | 0.547 | True | 0.800000 |
11 | t=0.9 | 0.000000 | 0.547 | True | 0.900000 |
12 | t=1.0 | 0.000000 | 0.547 | True | 1.000000 |