Skip to content

Commit 5063094

Browse files
committed
Added new examples and improved old ones.
1 parent 2197b6f commit 5063094

File tree

6 files changed

+488
-7
lines changed

6 files changed

+488
-7
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,15 @@ More examples are given in the [examples](examples/) directory, which includes
9393
* [Robertson problem (index 1)](examples/daes/robertson.py)
9494
* [Stiff transistor amplifier (index 1)](examples/daes/stiff_transistor_amplifier.py)
9595
* [Brenan's problem (index 1)](examples/daes/brenan.py)
96+
* [Kvaernø's problem (index 1)](examples/daes/kvaerno.py)
9697
* [Jay's probem (index 2)](examples/daes/jay.py)
9798
* [Knife edge (index 2)](examples/daes/knife_edge.py)
9899
* [Cartesian pendulum (index 3)](examples/daes/pendulum.py)
99100
* [Particle on circular track (index 3)](examples/daes/arevalo.py)
101+
* [Andrews' squeezer mechanism (index 3)](examples/daes/andrews.py)
100102
* implicit differential equations (IDE's)
101103
* [Weissinger's implicit equation](examples/ides/weissinger.py)
104+
* [Problem I.542 of E. Kamke](examples/ides/kamke.py)
102105
* [Jackiewicz' implicit equation](examples/ides/jackiewicz.py)
103106
* [Kvaernø's problem (nonlinear index 1)](examples/ides/kvaerno.py)
104107

examples/daes/andrews.py

+324
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
import time
2+
import numpy as np
3+
import matplotlib.pyplot as plt
4+
from scipy_dae.integrate import solve_dae, consistent_initial_conditions
5+
6+
7+
"""This example investigates a flexible multibody system called Andrews'
8+
squeezer mechanism as outlined in [1]_ and [2]_. Since this is a system of
9+
differential algebraic equatons of index 3, we implement a stabilized index 1
10+
formulation as proposed by [3]_.
11+
12+
References:
13+
-----------
14+
.. [1] E. Hairer, G. Wanner, "Solving Ordinary Differential Equations II:
15+
Stiff and Differential-Algebraic Problems", p. 377.
16+
.. [2] https://archimede.uniba.it/~testset/problems/andrews.php
17+
.. [3] https://doi.org/10.1002/nme.1620320803
18+
"""
19+
20+
# parameters
21+
nq = 7
22+
nla = 6
23+
24+
m1 = 0.04325
25+
m2 = 0.00365
26+
m3 = 0.02373
27+
m4 = 0.00706
28+
m5 = 0.07050
29+
m6 = 0.00706
30+
m7 = 0.05498
31+
32+
I1 = 2.194e-6
33+
I2 = 4.410e-7
34+
I3 = 5.255e-6
35+
I4 = 5.667e-7
36+
I5 = 1.169e-5
37+
I6 = 5.667e-7
38+
I7 = 1.912e-5
39+
40+
xa = -0.06934
41+
ya = -0.00227
42+
43+
xb = -0.03635
44+
yb = 0.03273
45+
46+
xc = 0.014
47+
yc = 0.072
48+
49+
d = 0.028
50+
da = 0.0115
51+
e = 0.02
52+
53+
ea = 0.01421
54+
zf = 0.02
55+
fa = 0.01421
56+
57+
rr = 0.007
58+
ra = 0.00092
59+
ss = 0.035
60+
61+
sa = 0.01874
62+
sb = 0.01043
63+
sc = 0.018
64+
65+
sd = 0.02
66+
zt = 0.04
67+
ta = 0.02308
68+
69+
tb = 0.00916
70+
u = 0.04
71+
ua = 0.01228
72+
73+
ub = 0.00449
74+
c0 = 4530
75+
l0 = 0.07785
76+
77+
mom = 0.033
78+
79+
def F(t, y, yp):
80+
81+
def M(t, vq):
82+
M = np.zeros((nq, nq))
83+
84+
# beta, Theta, gamma, Phi, delta, Omega, epsilon
85+
q1, q2, q3, q4, q5, q6, q7 = vq
86+
87+
cos_Th = np.cos(q2)
88+
sin_Phi = np.sin(q4)
89+
sin_Om = np.sin(q6)
90+
91+
M[0, 0] = m1 * ra**2 + m2 * (rr**2 - 2 * da * rr * cos_Th + da**2) + I1 + I2
92+
M[1, 0] = M[0, 1] = m2 * (da**2 - da * rr * cos_Th) + I2
93+
M[1, 1] = m2 * da**2 + I2
94+
M[2, 2] = m3 * (sa**2 + sb**2) + I3
95+
M[3, 3] = m4 * (e - ea)**2 + I4
96+
M[4, 3] = M[3, 4] = m4 * ((e - ea)**2 + zt * (e - ea) * sin_Phi) + I4
97+
M[4, 4] = m4 * (zt**2 + 2 * zt * (e - ea) * sin_Phi + (e - ea)**2) + m5 * (ta**2 + tb**2) + I4 + I5
98+
M[5, 5] = m6 * (zf - fa)**2 + I6
99+
M[6, 5] = M[5, 6] = m6 * ((zf - fa)**2 - u * (zf - fa) * sin_Om) + I6
100+
M[6, 6] = m6 * ((zf - fa)**2 - 2 * u * (zf - fa) * sin_Om + u**2) + m7 * (ua**2 + ub**2) + I6 + I7
101+
102+
return M
103+
104+
def h(t, vq, vu):
105+
# beta, Theta, gamma, Phi, delta, Omega, epsilon
106+
q1, q2, q3, q4, q5, q6, q7 = vq
107+
u1, u2, u3, u4, u5, u6, u7 = vu
108+
109+
sin_Th = np.sin(q2)
110+
sin_ga = np.sin(q3)
111+
cos_ga = np.cos(q3)
112+
cos_Phi = np.cos(q4)
113+
cos_Om = np.cos(q6)
114+
115+
xd = sd * cos_ga + sc * sin_ga + xb
116+
yd = sd * sin_ga - sc * cos_ga + yb
117+
L = np.sqrt((xd - xc)**2 + (yd - yc)**2)
118+
F = -c0 * (L - l0) / L
119+
Fx = F * (xd - xc)
120+
Fy = F * (yd - yc)
121+
122+
h = np.zeros(nq)
123+
h[0] = mom - m2 * da * rr * u2 * (u2 + 2 * u1) * sin_Th
124+
h[1] = m2 * da * rr * u1**2 * sin_Th
125+
h[2] = Fx * (sc * cos_ga - sd * sin_ga) + Fy * (sd * cos_ga + sc * sin_ga)
126+
h[3] = m4 * zt * (e - ea) * u5**2 * cos_Phi
127+
h[4] = -m4 * zt * (e - ea) * u4 * (u4 + 2 * u5) * cos_Phi
128+
h[5] = -m6 * u * (zf - fa) * u7**2 * cos_Om
129+
h[6] = m6 * u * (zf - fa) * u6 * (u6 + 2 * u7) * cos_Om
130+
131+
return h
132+
133+
def g(t, vq):
134+
# beta, Theta, gamma, Phi, delta, Omega, epsilon
135+
q1, q2, q3, q4, q5, q6, q7 = vq
136+
137+
sin_be = np.sin(q1)
138+
cos_be = np.cos(q1)
139+
sin_ga = np.sin(q3)
140+
cos_ga = np.cos(q3)
141+
142+
sin_be_Th = np.sin(q1 + q2)
143+
cos_be_Th = np.cos(q1 + q2)
144+
sin_Ph_de = np.sin(q4 + q5)
145+
cos_Ph_de = np.cos(q4 + q5)
146+
sin_Om_ep = np.sin(q6 + q7)
147+
cos_Om_ep = np.cos(q6 + q7)
148+
149+
g = np.zeros(nla)
150+
g[0] = rr * cos_be - d * cos_be_Th - ss * sin_ga - xb
151+
g[1] = rr * sin_be - d * sin_be_Th + ss * cos_ga - yb
152+
g[2] = rr * cos_be - d * cos_be_Th - e * sin_Ph_de - zt * np.cos(q5) - xa
153+
g[3] = rr * sin_be - d * sin_be_Th + e * cos_Ph_de - zt * np.sin(q5) - ya
154+
g[4] = rr * cos_be - d * cos_be_Th - zf * cos_Om_ep - u * np.sin(q7) - xa
155+
g[5] = rr * sin_be - d * sin_be_Th - zf * sin_Om_ep + u * np.cos(q7) - ya
156+
return g
157+
158+
def g_q(t, vq):
159+
# beta, Theta, gamma, Phi, delta, Omega, epsilon
160+
q1, q2, q3, q4, q5, q6, q7 = vq
161+
162+
sin_be = np.sin(q1)
163+
cos_be = np.cos(q1)
164+
sin_ga = np.sin(q3)
165+
cos_ga = np.cos(q3)
166+
167+
sin_be_Th = np.sin(q1 + q2)
168+
cos_be_Th = np.cos(q1 + q2)
169+
sin_Ph_de = np.sin(q4 + q5)
170+
cos_Ph_de = np.cos(q4 + q5)
171+
sin_Om_ep = np.sin(q6 + q7)
172+
cos_Om_ep = np.cos(q6 + q7)
173+
174+
g_q = np.zeros((nla, nq))
175+
176+
g_q[0, 0] = -rr * sin_be + d * sin_be_Th
177+
g_q[0, 1] = d * sin_be_Th
178+
g_q[0, 2] = -ss * cos_ga
179+
180+
g_q[1, 0] = rr * cos_be - d * cos_be_Th
181+
g_q[1, 1] = - d * cos_be_Th
182+
g_q[1, 2] = -ss * sin_ga
183+
184+
g_q[2, 0] = -rr * sin_be + d * sin_be_Th
185+
g_q[2, 1] = d * sin_be_Th
186+
g_q[2, 3] = -e * cos_Ph_de
187+
g_q[2, 4] = -e * cos_Ph_de + zt * np.sin(q5)
188+
189+
g_q[3, 0] = rr * cos_be - d * cos_be_Th
190+
g_q[3, 1] = - d * cos_be_Th
191+
g_q[3, 3] = -e * sin_Ph_de
192+
g_q[3, 4] = -e * sin_Ph_de - zt * np.cos(q5)
193+
194+
g_q[4, 0] = -rr * sin_be + d * sin_be_Th
195+
g_q[4, 1] = d * sin_be_Th
196+
g_q[4, 5] = zf * sin_Om_ep
197+
g_q[4, 6] = zf * sin_Om_ep - u * np.cos(q7)
198+
199+
g_q[5, 0] = rr * cos_be - d * cos_be_Th
200+
g_q[5, 1] = -d * cos_be_Th
201+
g_q[5, 5] = -zf * cos_Om_ep
202+
g_q[5, 6] = -zf * cos_Om_ep - u * np.sin(q7)
203+
204+
return g_q
205+
206+
vq, vu, _, _ = np.split(y, [nq, 2 * nq, 2 * nq + nla])
207+
vq_dot, vu_dot, vla, vmu = np.split(yp, [nq, 2 * nq, 2 * nq + nla])
208+
209+
g_q = g_q(t, vq)
210+
211+
# # index 1
212+
# return np.concatenate([
213+
# vq_dot - vu,
214+
# M(t, vq) @ vu_dot - h(t, vq, vu) - g_q.T @ vla,
215+
# g_q @ vu,
216+
# vmu,
217+
# ])
218+
219+
# stabilized index 1
220+
return np.concatenate([
221+
vq_dot - vu + g_q.T @ vmu,
222+
M(t, vq) @ vu_dot - h(t, vq, vu) - g_q.T @ vla,
223+
g_q @ vu,
224+
g(t, vq),
225+
])
226+
227+
228+
if __name__ == "__main__":
229+
# time span
230+
t0 = 0
231+
t1 = 0.03
232+
t_span = (t0, t1)
233+
t_eval = np.linspace(t0, t1, num=int(1e3))
234+
235+
# tolerances
236+
rtol = atol = 1e-4
237+
238+
# initial conditions
239+
q0 = np.array([
240+
-0.0617138900142764496358948458001,
241+
0,
242+
0.455279819163070380255912382449,
243+
0.222668390165885884674473185609,
244+
0.487364979543842550225598953530,
245+
-0.222668390165885884674473185609,
246+
1.23054744454982119249735015568,
247+
])
248+
u0 = np.zeros(nq)
249+
la0 = np.zeros(nla)
250+
mu0 = np.zeros(nla)
251+
252+
qp0 = u0.copy()
253+
up0 = np.array([
254+
14222.4439199541138705911625887,
255+
-10666.8329399655854029433719415,
256+
0,
257+
0,
258+
0,
259+
0,
260+
0,
261+
])
262+
lap0 = np.array([
263+
-98.5668703962410896057654982170,
264+
6.12268834425566265503114393122,
265+
0,
266+
0,
267+
0,
268+
0,
269+
])
270+
mup0 = np.zeros(nla)
271+
272+
y0 = np.concatenate([q0, u0, la0, mu0])
273+
yp0 = np.concatenate([qp0, up0, lap0, mup0])
274+
F0 = F(t0, y0, yp0)
275+
print(f"y0: {y0}")
276+
print(f"yp0: {yp0}")
277+
# print(f"F0 = {F0}")
278+
print(f"||F0|| = {np.linalg.norm(F0)}")
279+
# exit()
280+
# y0, yp0, fnorm = consistent_initial_conditions(F, t0, y0, yp0)
281+
# print(f"y0: {y0}")
282+
# print(f"yp0: {yp0}")
283+
# print(f"fnorm: {fnorm}")
284+
# # exit()
285+
286+
##############
287+
# dae solution
288+
##############
289+
start = time.time()
290+
# method = "BDF"
291+
method = "Radau"
292+
sol = solve_dae(F, t_span, y0, yp0, atol=atol, rtol=rtol, method=method, t_eval=t_eval, stages=3)
293+
end = time.time()
294+
print(f"elapsed time: {end - start}")
295+
t = sol.t
296+
y = sol.y
297+
tp = t
298+
yp = sol.yp
299+
success = sol.success
300+
status = sol.status
301+
message = sol.message
302+
print(f"success: {success}")
303+
print(f"status: {status}")
304+
print(f"message: {message}")
305+
print(f"nfev: {sol.nfev}")
306+
print(f"njev: {sol.njev}")
307+
print(f"nlu: {sol.nlu}")
308+
309+
# visualization
310+
rows = 4
311+
cols = 2
312+
fig, ax = plt.subplots(rows, cols)
313+
314+
for i in range(7):
315+
ii = i // cols # Row index
316+
jj = i % cols # Column index
317+
318+
yi = y[i]
319+
yi = (yi + np.pi) % (2 * np.pi) - np.pi
320+
ax[ii, jj].plot(t, yi, label=f"y{i} mod(2π)")
321+
ax[ii, jj].grid()
322+
ax[ii, jj].legend()
323+
324+
plt.show()

0 commit comments

Comments
 (0)