Skip to content

Commit deadef2

Browse files
committed
fix minilimo naming and add dynamic coupling case
1 parent 970c384 commit deadef2

5 files changed

Lines changed: 595 additions & 78 deletions

File tree

minilimo/README.md

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,32 @@
11
## miniLIMO setups
22

3-
1. `limo_dynamic_coupled.jl`: works, dynamic morphing (damped) and then static Lie-Trotter coupling (weak) with the WK3 model.Pact max reaches 400 mmHg.
4-
2. `limo_dynamic_kostas_single.jl`: static inflation for Kostas' project. Runs well via command line Pact arguments
5-
3. `limo_dynamic_coupled_transient.jl`: dynamic morphing (damped) and then dynamic Lie-Trotter coupling (weak) with the WK3 model.
6-
4. `limo_dynamic_coupled_strong.jl`: dynamic morphing (damped) and then dynamic, stronlgy coupled Lie-Trotter coupling with the WK3 model.
7-
5. `limo_dynamic_full.jl` same as the `1`, but with the full geometry, no symmetry plane.
8-
6. `utils`: store some repeated functions that are used across these files
3+
### 3D–0D Windkessel-coupled beat
4+
5+
The four coupled scripts are named `limo_coupled_<static|dynamic>_<weak|strong>.jl`, spanning a
6+
2×2 design space — **structure inertia** (static equilibrium vs. dynamic HHT-α with `M·ä`) ×
7+
**coupling strength** (weak vs. strong):
8+
9+
| | **weak** (Lie–Trotter split, black-box ODE integrator, Plv/Vlv lagged one substep) | **strong** (monolithic Newton on `(u, Plv, Pa, Pv)`, embedded implicit-Euler 0D) |
10+
|--------------------|---|---|
11+
| **static** structure | `limo_coupled_static_weak.jl` | `limo_coupled_static_strong.jl` |
12+
| **dynamic** structure | `limo_coupled_dynamic_weak.jl` | `limo_coupled_dynamic_strong.jl` |
13+
14+
All four share the Phase-1 dynamic HHT-α morph (damped) and reload the morphed state from
15+
`limo_dynamic_coupled_u0.jld2`; they differ only in the Phase-2 coupled beat.
16+
17+
1. `limo_coupled_static_weak.jl`: works, static weakly-coupled (Lie–Trotter) beat. Pact max reaches 400 mmHg. Carries `S_min`/`δp` diagnostics (Schur-complement collapse under refinement).
18+
2. `limo_coupled_dynamic_weak.jl`: dynamic weakly-coupled (Lie–Trotter) beat; inertia + damping retained in Phase 2.
19+
3. `limo_coupled_dynamic_strong.jl`: dynamic strongly (monolithically) coupled beat; HHT-α structure + implicit-Euler 0D as one Newton per step.
20+
4. `limo_coupled_static_strong.jl`: static counterpart of `3` — quasi-static equilibrium + implicit-Euler 0D as one Newton (drops `M·ä`/damping, `v2 = K_eff⁻¹F_plv` with no `1−α` factor).
21+
22+
> Note: Godunov splitting ≡ Lie–Trotter. The genuine weak↔strong middle ground would be a
23+
> sub-iterated partitioned scheme (fixed-point Plv↔Vlv, optionally under-relaxed/Aitken) — not yet implemented.
24+
25+
### Other setups
26+
27+
5. `limo_dynamic_kostas_single.jl`: static inflation for Kostas' project. Runs well via command line Pact arguments.
28+
6. `limo_dynamic_full.jl`: same as `limo_coupled_static_weak`, but with the full geometry, no symmetry plane.
29+
7. `util.jl`: shared functions (mesh, edge-morph IC, RM assembly helpers) used across these files.
930

1031
## old files
1132

Lines changed: 49 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ include(joinpath(@__DIR__, "util.jl"))
33

44
# Strongly (monolithically) coupled dynamic miniLIMO: HHT-α structure + 0D Windkessel
55
# solved together in ONE Newton system per time step. Counterpart of the weakly-coupled
6-
# `limo_dynamic_coupled_transient.jl` (Lie–Trotter split with a black-box ODE integrator).
6+
# `limo_coupled_dynamic_weak.jl` (Lie–Trotter split with a black-box ODE integrator).
77
#
88
# PHASE 1 — dynamic morph (t ∈ [0, T_sim], HHT-α) [identical to the transient file]
99
# Morph the edge onto the elliptic arc + fill Plv → morphed state u = un, v, a, Plv=p_max.
@@ -194,12 +194,12 @@ u = zeros(N_dof); apply!(u, ch)
194194
v = zeros(N_dof)
195195
a = zeros(N_dof)
196196

197-
pvd = paraview_collection("minilimo-dynamic-coupled-strong")
197+
pvd = paraview_collection("minilimo-coupled-dynamic-strong")
198198
vtk_step = Ref(0)
199199
resu = zeros(3, getnnodes(dh.grid))
200200
resθ = zeros(2, getnnodes(dh.grid))
201201
d, G3 = director_field(dh, scv, u)
202-
VTKGridFile("minilimo-dynamic-coupled-strong-0", dh) do vtk
202+
VTKGridFile("minilimo-coupled-dynamic-strong-0", dh) do vtk
203203
write_solution(vtk, dh, u)
204204
Ferrite.write_node_data(vtk, resu, "ru")
205205
Ferrite.write_node_data(vtk, resθ, "")
@@ -245,7 +245,7 @@ un = zeros(N_dof)
245245
# end
246246
# end
247247
# d, G3 = director_field(dh, scv, u)
248-
# VTKGridFile("minilimo-dynamic-coupled-strong-$(vtk_step[])", dh) do vtk
248+
# VTKGridFile("minilimo-coupled-dynamic-strong-$(vtk_step[])", dh) do vtk
249249
# write_solution(vtk, dh, u)
250250
# Ferrite.write_node_data(vtk, resu, "ru")
251251
# Ferrite.write_node_data(vtk, resθ, "rθ")
@@ -272,6 +272,7 @@ un .= load("limo_dynamic_coupled_u0.jld2")["u"]
272272
# Freeze the fully-morphed edge configuration (t·5 ≥ T_morph → ramp = 1) for the coupled
273273
# phase; the Dirichlet morph is held constant from here on (u, v, a carried forward).
274274
Ferrite.update!(ch, T_sim * 5)
275+
u .= un
275276
apply!(u, ch)
276277

277278
# actuation waveform (normalized to [0,1])
@@ -289,13 +290,13 @@ wk = (; Ra, Rp, Rv, Ca, Cv, Pscale = p_max)
289290

290291
# coupling controls
291292
tol_cpl = 1e-4
292-
max_iter = 20
293-
dt_cpl = 0.01 # doubles as the HHT-α time step in the coupled phase
293+
max_iter = 50
294+
dt_cpl = 0.001 # doubles as the HHT-α time step in the coupled phase
294295
T_beat = 4.0 # total coupled duration [s]
295296

296297
# storages
297298
vols = Float64[]; pres = Float64[]; pact = Float64[]
298-
paos = Float64[]; pvns = Float64[]
299+
paos = Float64[]; pvns = Float64[]; tsav = Float64[]
299300

300301
bufs_cpl = (; K_int, r_int, K_plv, F_plv, K_pact, F_pact, K_plvpact, F_plvpact, M, K_eff,
301302
res, rhs, v1, v2, dVdu, a_new, v_new, Ma, Mv, F_lu, free, g_old,
@@ -381,32 +382,50 @@ end
381382
V_LV0 = -2 * compute_volume(dh, scv, u; cellset=Plv_srf) #
382383
println("Initial volume of the device: ", round(V_LV0 * m3_to_ml; digits=4), " ml")
383384

384-
println("\nPHASE 2 — monolithic strong 3D-0D coupling (dt_cpl=$(dt_cpl) s)")
385-
println(" t [s] | p [mmHg] | Vlv_full [ml] | Pact [mmHg] | iters")
385+
println("\nPHASE 2 — monolithic strong 3D-0D coupling (adaptive Δt, Δt₀=$(dt_cpl) s)")
386+
println(" t [s] | p [mmHg] | Vlv_full [ml] | Pact [mmHg] | iters | Δt [s]")
386387

387-
# initial 0D state (Pa): filled ventricle, arterial at 80 mmHg
388-
@time let V_LVₙ = V_LV0, Paₙ = Pa, Pvₙ = Pv, t_cpl = 0.0, Plv=p_max, Pa = 80.0 / Pa2mmHg, Pv = p_max
388+
# initial 0D state [Pa]: filled ventricle (Plv=Pv=p_max), arterial at 80 mmHg
389+
Pa0 = 80.0 / Pa2mmHg
390+
Pv0 = p_max
391+
# Adaptive Δt driven by 3D-0D coupling convergence (same policy as the Phase-1 morph):
392+
# a converged monolithic step commits and grows Δt by 1.2× (capped at Δt_max); a failed
393+
# step is discarded (structural + 0D history untouched), Δt halved, and the step retried.
394+
@time let V_LVₙ = V_LV0, Paₙ = Pa0, Pvₙ = Pv0, t_cpl = 0.0, Plv = p_max, Pa = Pa0, Pv = Pv0
389395
step = 0
390-
while t_cpl < T_beat - dt_cpl / 2
391-
step += 1
392-
t_cpl += dt_cpl
396+
Δt_cur = dt_cpl
397+
while t_cpl < T_beat - Δt_min
398+
t_new = min(t_cpl + Δt_cur, T_beat)
399+
Δt_cur = t_new - t_cpl # clip the final step to land exactly on T_beat
393400

394-
Pact_mmHg = 200 * ϕᵢ(t_cpl; tC=0.1, tR=0.4, TC=0.3, TR=0.3)
401+
Pact_mmHg = 600 * ϕᵢ(t_new; tC=0.1, tR=0.4, TC=0.3, TR=0.3)
395402
Pact = Pact_mmHg / Pa2mmHg
396403

397-
# HHT-α predictors (Δt = dt_cpl), morph BC frozen.
398-
@. ũ = u + dt_cpl * v + (dt_cpl^2 * (0.5 - β_hht)) * a
399-
@.= v + (dt_cpl * (1 - γ_hht)) * a
404+
# HHT-α predictors (Δt = Δt_cur), morph BC frozen.
405+
@. ũ = u + Δt_cur * v + (Δt_cur^2 * (0.5 - β_hht)) * a
406+
@.= v + (Δt_cur * (1 - γ_hht)) * a
400407
u_new .= ũ
401408
apply!(u_new, ch)
402409

403-
Plv, Pa, Pv, n_iter, converged, V₃D = solve_coupled_strong_step!(
404-
u_new, ũ, ṽ, Plv, Pa, Pv, V_LVₙ, Paₙ, Pvₙ, Pact, dt_cpl, dh, scv, mat, ch,
410+
# Trial pressures start from the last committed 0D state; only adopted on success.
411+
Plv_t, Pa_t, Pv_t, n_iter, converged, V₃D = solve_coupled_strong_step!(
412+
u_new, ũ, ṽ, Plv, Pa, Pv, V_LVₙ, Paₙ, Pvₙ, Pact, Δt_cur, dh, scv, mat, ch,
405413
Plv_srf, Pact_srf, PlvPact_srf, wk, bufs_cpl; max_iter=max_iter, tol=tol_cpl, verbose=false)
406414

415+
if !converged
416+
Δt_cur /= 2
417+
Δt_cur < Δt_min && error("minimum Δt reached at t=$(round(t_cpl, digits=4)) s")
418+
@warn @sprintf("coupling did not converge at t=%.4f s — retrying with Δt=%.3e s", t_new, Δt_cur)
419+
continue # discard trial state (u, v, a, 0D history all unchanged), retry
420+
end
421+
422+
step += 1
423+
t_cpl = t_new
424+
Plv, Pa, Pv = Plv_t, Pa_t, Pv_t
425+
407426
# commit dynamic structural state + advance 0D history
408-
@. a = (u_new - ũ) / (β_hht * dt_cpl^2)
409-
@. v =+ (dt_cpl * γ_hht) * a
427+
@. a = (u_new - ũ) / (β_hht * Δt_cur^2)
428+
@. v =+ (Δt_cur * γ_hht) * a
410429
mul!(Mv, M, v)
411430
@. g_old = α_damp * Mv + r_int - (Plv * F_plv + Pact * F_pact - Pact * F_plvpact)
412431
u .= u_new
@@ -421,7 +440,7 @@ println(" t [s] | p [mmHg] | Vlv_full [ml] | Pact [mmHg] | iters")
421440
end
422441
end
423442
d, G3 = director_field(dh, scv, u)
424-
VTKGridFile("minilimo-dynamic-coupled-strong-$(vtk_step[])", dh) do vtk
443+
VTKGridFile("minilimo-coupled-dynamic-strong-$(vtk_step[])", dh) do vtk
425444
write_solution(vtk, dh, u)
426445
Ferrite.write_node_data(vtk, resu, "ru")
427446
Ferrite.write_node_data(vtk, resθ, "")
@@ -430,25 +449,26 @@ println(" t [s] | p [mmHg] | Vlv_full [ml] | Pact [mmHg] | iters")
430449
for ID in 1:3; color(vtk, grid, "SRF_$ID"); end
431450
pvd[T_sim + t_cpl] = vtk
432451
end
433-
@printf(" %9.4f | %11.4f | %14.4f | %14.4f | %d\n",
434-
t_cpl, Plv * Pa2mmHg, 2V₃D * m3_to_ml, Pact_mmHg, n_iter)
435-
436-
!converged && (@warn "coupling step $step (t=$(t_cpl)) did not converge"; break)
452+
@printf(" %9.4f | %11.4f | %14.4f | %14.4f | %5d | %.3e\n",
453+
t_cpl, Plv * Pa2mmHg, 2V₃D * m3_to_ml, Pact_mmHg, n_iter, Δt_cur)
437454

455+
push!(tsav, t_cpl) # actual (non-uniform) sample time [s]
438456
push!(vols, 2V₃D * m3_to_ml) # full LV volume [ml]
439457
push!(pres, Plv * Pa2mmHg) # LV pressure [mmHg]
440458
push!(pact, Pact_mmHg)
441459
push!(paos, Pa * Pa2mmHg)
442460
push!(pvns, Pv * Pa2mmHg)
461+
462+
Δt_cur = min(Δt_cur * 1.2, Δt_max) # grow after a converged step
443463
end
444464
end
445465
close(pvd)
446466

447467
using Plots
448-
times = collect(dt_cpl:dt_cpl:dt_cpl*length(pres))
468+
times = tsav # adaptive Δt → non-uniform sample times
449469
p1 = plot(times, [vols, pres, pact, paos, pvns], xlabel="Time [s]",
450470
label=["Vlv" "Plv" "Pact" "Pao" "Pv"], lw=2, legend=:right)
451471
p2 = plot(vols, pres, label=:none, xlim=extrema(vols).+(-10,10), ylims=(0, 100),
452472
xlabel="Volume [ml]", ylabel="Pressure [mmHg]", lw=2, linez=times./maximum(times))
453473
plot(p1, p2)
454-
# savefig("minilimo-dynamic-coupled-strong-N$Np.png")
474+
# savefig("minilimo-coupled-dynamic-strong-N$Np.png")

minilimo/limo_dynamic_coupled_transient.jl renamed to minilimo/limo_coupled_dynamic_weak.jl

Lines changed: 55 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import OrdinaryDiffEq as ODE
44

55
# Fully-dynamic (HHT-α throughout) morphing + 3D-0D Windkessel-coupled beat of the
66
# miniLIMO, on the rectangular multi-surface mesh built by `make_minilimo_grid`. This is
7-
# the transient counterpart of `limo_dynamic_coupled.jl`: there the coupled phase is a
7+
# the transient counterpart of `limo_coupled_static_weak.jl`: there the coupled phase is a
88
# quasi-static Schur solve; here inertia and damping are retained in the coupled phase too.
99
#
1010
# PHASE 1 — dynamic morph (t ∈ [0, T_sim], HHT-α)
@@ -186,12 +186,12 @@ u = zeros(N_dof); apply!(u, ch)
186186
v = zeros(N_dof)
187187
a = zeros(N_dof)
188188

189-
pvd = paraview_collection("minilimo-dynamic-coupled-transient")
189+
pvd = paraview_collection("minilimo-coupled-dynamic-weak")
190190
vtk_step = Ref(0)
191191
resu = zeros(3, getnnodes(dh.grid))
192192
resθ = zeros(2, getnnodes(dh.grid))
193193
d, G3 = director_field(dh, scv, u)
194-
VTKGridFile("minilimo-dynamic-coupled-transient-0", dh) do vtk
194+
VTKGridFile("minilimo-coupled-dynamic-weak-0", dh) do vtk
195195
write_solution(vtk, dh, u)
196196
Ferrite.write_node_data(vtk, resu, "ru")
197197
Ferrite.write_node_data(vtk, resθ, "")
@@ -237,7 +237,7 @@ let t = 0.0; step = 0; Δt_cur = Δt; p = 0.0
237237
end
238238
end
239239
d, G3 = director_field(dh, scv, u)
240-
VTKGridFile("minilimo-dynamic-coupled-transient-$(vtk_step[])", dh) do vtk
240+
VTKGridFile("minilimo-coupled-dynamic-weak-$(vtk_step[])", dh) do vtk
241241
write_solution(vtk, dh, u)
242242
Ferrite.write_node_data(vtk, resu, "ru")
243243
Ferrite.write_node_data(vtk, resθ, "")
@@ -308,7 +308,7 @@ dt_cpl = 0.01 # doubles as the HHT-α time step in the coupled phase
308308

309309
# storages
310310
vols = Float64[]; pres = Float64[]; pact = Float64[]
311-
paos = Float64[]; pvns = Float64[]; vtarget = Float64[]
311+
paos = Float64[]; pvns = Float64[]; vtarget = Float64[]; tsav = Float64[]
312312

313313
bufs_cpl = (; K_int, r_int, K_plv, F_plv, K_pact, F_pact, K_plvpact, F_plvpact, M, K_eff,
314314
res, rhs, v1, v2, dVdu, a_new, v_new, Ma, Mv, F_lu, free, g_old,
@@ -366,42 +366,70 @@ end
366366

367367
dt_cpl = 0.005
368368

369-
println("\nPHASE 2 — dynamic HHT-α 3D-0D coupling (dt_cpl=$(dt_cpl) s)")
370-
println(" t [s] | p [mmHg] | Vlv_full [ml] | Pact [mmHg] | iters")
369+
println("\nPHASE 2 — dynamic HHT-α 3D-0D coupling (adaptive Δt, Δt₀=$(dt_cpl) s)")
370+
println(" t [s] | p [mmHg] | Vlv_full [ml] | Pact [mmHg] | iters | Δt [s]")
371371

372+
# Adaptive Δt driven by 3D-0D coupling convergence (same policy as the Phase-1 morph):
373+
# a converged bordered-Newton step commits and grows Δt by 1.2× (capped at Δt_max); a failed
374+
# step is discarded — the 0D integrator is rolled back with `reinit!`, the structural state
375+
# (u, v, a) is left untouched, Δt is halved, and the step is retried.
372376
@time let p = p_max
373377
step = 0
374-
while integrator.t < tspan[2] - dt_cpl / 2
375-
step += 1
378+
Δt_cur = dt_cpl
379+
u_ode_save = zeros(length(integrator.u))
380+
while integrator.t < tspan[2] - Δt_min
381+
Δt_cur = min(Δt_cur, tspan[2] - integrator.t) # clip to land exactly on tspan[2]
382+
383+
# snapshot the 0D state so a failed structural solve can be rolled back
384+
t_ode_save = integrator.t
385+
u_ode_save .= integrator.u
376386

377-
# advance Windkessel by dt_cpl (Plv = integrator.u[4] held fixed).
378-
ODE.step!(integrator, dt_cpl, true)
387+
# advance Windkessel by Δt_cur (Plv = integrator.u[4] held fixed).
388+
ODE.step!(integrator, Δt_cur, true)
379389

380390
# target half-model volume (m³) from the full-LV volume the ODE tracks.
381391
V_target = 0.5 * integrator.u[1] / m3_to_ml
382-
push!(vtarget, integrator.u[1])
383392

384393
# actuator pressure at this time [mmHg] → Pa
385394
Pact_mmHg = 200 * ϕᵢ(integrator.t; tC=0.1, tR=0.4, TC=0.3, TR=0.3)
386395
Pact = Pact_mmHg / Pa2mmHg
387396

388-
# HHT-α predictors for this step (Δt = dt_cpl), morph BC frozen.
389-
@. ũ = u + dt_cpl * v + (dt_cpl^2 * (0.5 - β_hht)) * a
390-
@.= v + (dt_cpl * (1 - γ_hht)) * a
397+
# HHT-α predictors for this step (Δt = Δt_cur), morph BC frozen.
398+
@. ũ = u + Δt_cur * v + (Δt_cur^2 * (0.5 - β_hht)) * a
399+
@.= v + (Δt_cur * (1 - γ_hht)) * a
391400
u_new .= ũ
392401
apply!(u_new, ch)
393402

394-
p, n_iter, converged, V₃D = solve_coupled_dyn_step!(u_new, ũ, ṽ, p, Pact, V_target, dt_cpl,
403+
# trial Plv starts from the last committed value; only adopted on success.
404+
p_t, n_iter, converged, V₃D = solve_coupled_dyn_step!(u_new, ũ, ṽ, p, Pact, V_target, Δt_cur,
395405
dh, scv, mat, ch, Plv_srf, Pact_srf, PlvPact_srf, bufs_cpl;
396406
max_iter=max_iter, tol=tol_cpl, verbose=false)
397407

408+
if !converged
409+
# roll the 0D integrator back to the pre-step state and retry with a smaller Δt;
410+
# u, v, a and p are all left at their last committed values.
411+
ODE.reinit!(integrator, u_ode_save; t0=t_ode_save)
412+
@warn @sprintf("coupling did not converge for step to t=%.4f s — halving Δt %.3e → %.3e",
413+
t_ode_save + Δt_cur, Δt_cur, Δt_cur / 2)
414+
Δt_cur /= 2
415+
Δt_cur < Δt_min && error("minimum Δt reached at t=$(round(t_ode_save, digits=4)) s")
416+
continue
417+
end
418+
419+
step += 1
420+
p = p_t
421+
398422
# commit dynamic state (velocity/accel updates + HHT history g_old).
399-
@. a = (u_new - ũ) / (β_hht * dt_cpl^2)
400-
@. v =+ (dt_cpl * γ_hht) * a
423+
@. a = (u_new - ũ) / (β_hht * Δt_cur^2)
424+
@. v =+ (Δt_cur * γ_hht) * a
401425
mul!(Mv, M, v)
402426
@. g_old = α_damp * Mv + r_int - (p * F_plv + Pact * F_pact - Pact * F_plvpact)
403427
u .= u_new
404428

429+
# feed the converged LV pressure back into the ODE state.
430+
integrator.u[4] = p * Pa2mmHg
431+
ODE.u_modified!(integrator, true)
432+
405433
if step%50 == 0
406434
vtk_step[] += 1
407435
for cell in CellIterator(dh)
@@ -412,7 +440,7 @@ println(" t [s] | p [mmHg] | Vlv_full [ml] | Pact [mmHg] | iters")
412440
end
413441
end
414442
d, G3 = director_field(dh, scv, u)
415-
VTKGridFile("minilimo-dynamic-coupled-transient-$(vtk_step[])", dh) do vtk
443+
VTKGridFile("minilimo-coupled-dynamic-weak-$(vtk_step[])", dh) do vtk
416444
write_solution(vtk, dh, u)
417445
Ferrite.write_node_data(vtk, resu, "ru")
418446
Ferrite.write_node_data(vtk, resθ, "")
@@ -422,29 +450,27 @@ println(" t [s] | p [mmHg] | Vlv_full [ml] | Pact [mmHg] | iters")
422450
pvd[T_sim + integrator.t] = vtk
423451
end
424452
end
425-
@printf(" %9.4f | %11.4f | %14.4f | %14.4f | %d\n",
426-
integrator.t, p * Pa2mmHg, 2V₃D * m3_to_ml, Pact_mmHg, n_iter)
427-
428-
!converged && (@warn "coupling step $step (t=$(integrator.t)) did not converge"; break)
429-
430-
# feed the converged LV pressure back into the ODE state.
431-
integrator.u[4] = p * Pa2mmHg
432-
ODE.u_modified!(integrator, true)
453+
@printf(" %9.4f | %11.4f | %14.4f | %14.4f | %5d | %.3e\n",
454+
integrator.t, p * Pa2mmHg, 2V₃D * m3_to_ml, Pact_mmHg, n_iter, Δt_cur)
433455

456+
push!(tsav, integrator.t) # actual (non-uniform) sample time [s]
457+
push!(vtarget, integrator.u[1])
434458
push!(vols, 2V₃D * m3_to_ml) # full LV volume [ml]
435459
push!(pres, p * Pa2mmHg) # LV pressure [mmHg]
436460
push!(pact, Pact_mmHg)
437461
push!(paos, integrator.u[2])
438462
push!(pvns, integrator.u[3])
463+
464+
Δt_cur = min(Δt_cur * 1.2, Δt_max) # grow after a converged step
439465
end
440466
end
441467
close(pvd)
442468

443469
using Plots
444-
times = collect(0:dt_cpl:integrator.t)[1:length(pres)]
470+
times = tsav # adaptive Δt → non-uniform sample times
445471
p1 = plot(times, [vols, pres, pact, paos, pvns], xlabel="Time [s]",
446472
label=["Vlv" "Plv" "Pact" "Pao" "Pv"], lw=2, legend=:right)
447473
p2 = plot(vols, pres, label=:none, xlim=extrema(vols).+(-10,10), ylims=(0, 100),
448474
xlabel="Volume [ml]", ylabel="Pressure [mmHg]", lw=2, linez=times./maximum(times))
449475
plot(p1, p2)
450-
# savefig("minilimo-dynamic-coupled-transient-N$Np.png")
476+
# savefig("minilimo-coupled-dynamic-weak-N$Np.png")

0 commit comments

Comments
 (0)