Skip to content

Commit 36490eb

Browse files
committed
Minor improvements and new version.
1 parent e0a235b commit 36490eb

7 files changed

Lines changed: 665 additions & 12 deletions

File tree

examples/daes/particle.py

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import time
2+
import numpy as np
3+
import matplotlib.pyplot as plt
4+
from solve_dae.integrate import solve_dae, consistent_initial_conditions
5+
from scipy.integrate._ivp.tests.test_ivp import compute_error
6+
7+
8+
"""Modified particle on a circular track subject to tangential force, see Arevalo1995.
9+
We implement a stabilized index 1 formulation as proposed by Anantharaman1991.
10+
11+
References:
12+
-----------
13+
Arevalo1995: https://link.springer.com/article/10.1007/BF01732606 \\
14+
Anantharaman1991: https://doi.org/10.1002/nme.1620320803
15+
"""
16+
omega = 2 * np.pi
17+
18+
19+
def PHI(t):
20+
"""The time derivative of this function has to be phi_dot(t)**2."""
21+
return omega**2 * (t / 2 + np.sin(2 * t) / 4)
22+
23+
24+
def phi(t):
25+
return omega * np.sin(t)
26+
27+
28+
def phi_p(t):
29+
return omega * np.cos(t)
30+
31+
32+
def phi_pp(t):
33+
return -omega * np.sin(t)
34+
35+
36+
def F(t, vy, vyp):
37+
x, y, u, v, _, _ = vy
38+
x_dot, y_dot, u_dot, v_dot, Lap, Mup = vyp
39+
40+
force = phi_pp(t)
41+
42+
R = np.zeros(6, dtype=np.common_type(vy, vyp))
43+
R[0] = x_dot - (u + 2 * x * Mup)
44+
R[1] = y_dot - (v + 2 * y * Mup)
45+
R[2] = u_dot - (2 * x * Lap - y * force)
46+
R[3] = v_dot - (2 * y * Lap + x * force)
47+
R[4] = 2 * (x * u + y * v)
48+
R[5] = x**2 + y**2 - 1
49+
50+
return R
51+
52+
53+
def sol_true(t):
54+
y = np.array(
55+
[
56+
np.cos(phi(t)),
57+
np.sin(phi(t)),
58+
-np.sin(phi(t)) * phi_p(t),
59+
np.cos(phi(t)) * phi_p(t),
60+
-PHI(t) / 2,
61+
np.zeros_like(t),
62+
]
63+
)
64+
65+
yp = np.array(
66+
[
67+
-np.sin(phi(t)) * phi_p(t),
68+
np.cos(phi(t)) * phi_p(t),
69+
-np.cos(phi(t)) * phi_p(t) ** 2 - np.sin(phi(t)) * phi_pp(t),
70+
-np.sin(phi(t)) * phi_p(t) ** 2 + np.cos(phi(t)) * phi_pp(t),
71+
-phi_p(t) ** 2 / 2,
72+
np.zeros_like(t),
73+
]
74+
)
75+
76+
return y, yp
77+
78+
79+
if __name__ == "__main__":
80+
# time span
81+
t0 = 1
82+
t1 = 5
83+
t_span = (t0, t1)
84+
t_eval = np.linspace(t0, t1, num=int(1e3))
85+
86+
# method = "BDF"
87+
method = "Radau"
88+
89+
# initial conditions
90+
y0, yp0 = sol_true(t0)
91+
92+
yp0 = np.zeros_like(y0)
93+
print(f"y0: {y0}")
94+
print(f"yp0: {yp0}")
95+
y0, yp0, fnorm = consistent_initial_conditions(F, t0, y0, yp0)
96+
print(f"y0: {y0}")
97+
print(f"yp0: {yp0}")
98+
print(f"fnorm: {fnorm}")
99+
100+
# solver options
101+
atol = rtol = 1e-5
102+
103+
##############
104+
# dae solution
105+
##############
106+
start = time.time()
107+
sol = solve_dae(F, t_span, y0, yp0, atol=atol, rtol=rtol, method=method, t_eval=t_eval)
108+
end = time.time()
109+
print(f"elapsed time: {end - start}")
110+
t = sol.t
111+
y = sol.y
112+
yp = sol.yp
113+
success = sol.success
114+
status = sol.status
115+
message = sol.message
116+
print(f"success: {success}")
117+
print(f"status: {status}")
118+
print(f"message: {message}")
119+
print(f"nfev: {sol.nfev}")
120+
print(f"njev: {sol.njev}")
121+
print(f"nlu: {sol.nlu}")
122+
123+
y_true, yp_true = sol_true(t)
124+
e = compute_error(y[:, -1], y_true[:, -1], rtol, atol)
125+
ep = compute_error(yp[:, -1], yp_true[:, -1], rtol, atol)
126+
print(f"max(e): {e}")
127+
print(f"max(ep): {ep}")
128+
129+
# visualization
130+
fig, ax = plt.subplots(4, 1)
131+
132+
ax[0].plot(t, y[0], "-ok", label="x")
133+
ax[0].plot(t, y[1], "-ob", label="y")
134+
ax[0].plot(t, y_true[0], "--xr", label="x_true")
135+
ax[0].plot(t, y_true[1], "--xg", label="y_true")
136+
ax[0].legend()
137+
ax[0].grid()
138+
139+
ax[1].plot(t, y[2], "-ok", label="u")
140+
ax[1].plot(t, y[3], "-ob", label="v")
141+
ax[1].plot(t, y_true[2], "--xr", label="u_true")
142+
ax[1].plot(t, y_true[3], "--xg", label="v_true")
143+
ax[1].legend()
144+
ax[1].grid()
145+
146+
ax[2].plot(t, yp[4], "-ok", label="lap")
147+
ax[2].plot(t, yp_true[4], "--xr", label="lap_true")
148+
ax[2].legend()
149+
ax[2].grid()
150+
151+
ax[3].plot(t, yp[5], "-ok", label="mup")
152+
ax[3].plot(t, yp_true[5], "--xr", label="mup_true")
153+
ax[3].legend()
154+
ax[3].grid()
155+
156+
plt.show()

solve_dae/integrate/_dae/benchmarks/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ target_link_libraries(knife_edge PRIVATE ${SUNDIALS_LIB})
2525
add_executable(arevalo arevalo/arevalo.c)
2626
target_link_libraries(arevalo PRIVATE ${SUNDIALS_LIB})
2727

28+
# - index 3 DAE
29+
add_executable(particle particle/particle.c)
30+
target_link_libraries(particle PRIVATE ${SUNDIALS_LIB})
31+
2832
# - IDE
2933
add_executable(weissinger weissinger/weissinger.c)
3034
target_link_libraries(weissinger PRIVATE ${SUNDIALS_LIB})

solve_dae/integrate/_dae/benchmarks/common.py

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,18 @@
88
("Radau", {"stages": 3}),
99
("Radau", {"stages": 5}),
1010
("Radau", {"stages": 7}),
11-
("BDF", {"NDF_strategy": "stability"}),
12-
("BDF", {"NDF_strategy": "accuracy"}),
13-
("BDF", {"NDF_strategy": None}),
11+
# ("BDF", {"NDF_strategy": "stability"}),
12+
# ("BDF", {"NDF_strategy": "accuracy"}),
13+
# ("BDF", {"NDF_strategy": None}),
1414
]
1515

1616

17-
def benchmark(t0, t1, y0, yp0, F, rtols, atols, h0s, name, y_ref=None, y_idx=None):
17+
def benchmark(t0, t1, y0, yp0, F, rtols, atols, h0s, name, y_ref=None, yp_ref=None, y_idx=None):
1818
# time span
1919
t_span = (t0, t1)
2020

2121
# benchmark results
22-
results = np.zeros((len(solvers), len(rtols), 2))
22+
results = np.zeros((len(solvers), len(rtols), 3))
2323

2424
if y_ref is None:
2525
sol = solve_dae(
@@ -33,6 +33,7 @@ def benchmark(t0, t1, y0, yp0, F, rtols, atols, h0s, name, y_ref=None, y_idx=Non
3333
stages=5,
3434
)
3535
y_ref = sol.y[:, -1]
36+
yp_ref = sol.yp[:, -1]
3637
print(sol)
3738
assert sol.success
3839

@@ -64,13 +65,17 @@ def benchmark(t0, t1, y0, yp0, F, rtols, atols, h0s, name, y_ref=None, y_idx=Non
6465

6566
# error
6667
if y_idx is not None:
67-
diff = y_ref[y_idx] - sol.y[y_idx, -1]
68+
diff_y = y_ref[y_idx] - sol.y[y_idx, -1]
69+
diff_yp = yp_ref[y_idx] - sol.yp[y_idx, -1]
6870
else:
69-
diff = y_ref - sol.y[:, -1]
70-
error = np.linalg.norm(diff)
71-
print(f" => error: {error}")
71+
diff_y = y_ref - sol.y[:, -1]
72+
diff_yp = yp_ref - sol.yp[:, -1]
73+
error_y = np.linalg.norm(diff_y)
74+
print(f" => error_y: {error_y}")
75+
error_yp = np.linalg.norm(diff_yp)
76+
print(f" => error_yp: {error_yp}")
7277

73-
results[i, j] = (error, elapsed_time)
78+
results[i, j] = (elapsed_time, error_y, error_y)
7479

7580
fig, ax = plt.subplots(figsize=(12, 9))
7681

@@ -93,11 +98,27 @@ def benchmark(t0, t1, y0, yp0, F, rtols, atols, h0s, name, y_ref=None, y_idx=Non
9398
result_IDA = np.loadtxt("solve_dae/integrate/_dae/benchmarks/arevalo/arevalo_errors_IDA.csv", delimiter=',')
9499
result_IDA[:, 1] *= 100 # scale elapsed time by 100
95100
ax.plot(*result_IDA.T, label="sundials IDA (elapsed time *= 100)")
101+
elif name == "Particle":
102+
result_IDA = np.loadtxt("solve_dae/integrate/_dae/benchmarks/particle/particle_errors_IDA.csv", delimiter=',')
103+
result_IDA[:, 1] *= 100 # scale elapsed time by 100
104+
ax.plot(*result_IDA[: :2].T, label="sundials IDA (elapsed time *= 100)")
96105
elif name == "Weissinger":
97106
result_IDA = np.loadtxt("solve_dae/integrate/_dae/benchmarks/weissinger/weissinger_errors_IDA.csv", delimiter=',')
98107
result_IDA[:, 1] *= 500 # scale elapsed time by 500
99108
ax.plot(*result_IDA.T, label="sundials IDA (elapsed time *= 500)")
100109

110+
# export errors and elapsed time
111+
for i, ri in enumerate(results):
112+
np.savetxt(
113+
f"{name}_{solvers[i]}.txt",
114+
ri,
115+
delimiter=", ",
116+
header="t, error_y, error_yp",
117+
comments="",
118+
)
119+
120+
# ax.plot(ri[:, 0], ri[:, 1], label=solvers[i])
121+
101122
ax.set_title(f"work-precision: {name}")
102123
ax.set_xscale("log")
103124
ax.set_yscale("log")

0 commit comments

Comments
 (0)