Skip to content

Commit 3143618

Browse files
committed
Update biv docs
1 parent 6234e44 commit 3143618

6 files changed

Lines changed: 19 additions & 131 deletions
21.2 KB
Loading
-220 KB
Binary file not shown.
-588 KB
Binary file not shown.

demo/geometries/biv_ellipsoid.py

Lines changed: 4 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -44,41 +44,28 @@
4444
#
4545
# We generate the mesh and fibers if they don't already exist.
4646
#
47-
# ### 1. Mesh Generation
48-
# `cardiac_geometries.mesh.biv_ellipsoid` creates the mesh with markers for:
49-
# * **LV_ENDO_FW**: LV Endocardium Free Wall
50-
# * **LV_SEPTUM**: LV Septum
51-
# * **RV_ENDO_FW**: RV Endocardium Free Wall
52-
# * **RV_SEPTUM**: RV Septum
53-
# * **LV_EPI_FW**: LV Epicardium Free Wall
54-
# * **RV_EPI_FW**: RV Epicardium Free Wall
55-
# * **BASE**: Base
56-
#
5747
# ### 2. Fiber Generation (LDRB)
5848
# The LDRB algorithm solves Laplace equations to define transmural and apicobasal coordinates.
5949
# Based on these coordinates, it assigns fiber angles (e.g., +60 to -60 degrees transmurally).
6050

6151
outdir = Path("biv_ellipsoid")
6252
outdir.mkdir(parents=True, exist_ok=True)
6353
geodir = outdir / "geometry"
64-
6554
if not geodir.exists():
6655
# Generate mesh
6756
geo = cardiac_geometries.mesh.biv_ellipsoid(outdir=geodir)
6857

69-
# Map mesh markers to the format expected by LDRB
70-
markers = cardiac_geometries.mesh.transform_biv_markers(geo.markers)
71-
7258
# Run LDRB algorithm
7359
system = ldrb.dolfinx_ldrb(
7460
mesh=geo.mesh,
7561
ffun=geo.ffun,
76-
markers=markers,
62+
markers=geo.markers,
7763
alpha_endo_lv=60, # Fiber angle at LV endocardium
7864
alpha_epi_lv=-60, # Fiber angle at LV epicardium
7965
beta_endo_lv=0, # Sheet angle (0 for now)
8066
beta_epi_lv=0,
8167
fiber_space="P_2",
68+
create_fibers=True,
8269
)
8370

8471
# Save microstructure to XDMF/H5
@@ -94,49 +81,6 @@
9481
folder=geodir,
9582
)
9683

97-
# ### Marker Consolidation
98-
# We group the detailed surface markers into broader categories for applying boundary conditions.
99-
#
100-
# * **ENDO_LV**: All LV endocardial surfaces (Free Wall + Septum).
101-
# * **ENDO_RV**: All RV endocardial surfaces (Free Wall + Septum).
102-
# * **EPI**: All epicardial surfaces.
103-
# * **BASE**: The base.
104-
105-
markers = {"ENDO_LV": [1, 2], "ENDO_RV": [2, 2], "BASE": [3, 2], "EPI": [4, 2]}
106-
107-
# Create a new marker array based on the old one
108-
marker_values = geo.ffun.values.copy()
109-
marker_indices = geo.ffun.indices
110-
111-
# Helper to update markers
112-
def update_marker(old_name, new_id):
113-
old_id = geo.markers[old_name][0]
114-
marker_values[np.isin(marker_indices, geo.ffun.find(old_id))] = new_id
115-
116-
# Update LV Endo
117-
update_marker("LV_ENDO_FW", markers["ENDO_LV"][0])
118-
update_marker("LV_SEPTUM", markers["ENDO_LV"][0])
119-
120-
# Update RV Endo
121-
update_marker("RV_ENDO_FW", markers["ENDO_RV"][0])
122-
update_marker("RV_SEPTUM", markers["ENDO_RV"][0])
123-
124-
# Update Base
125-
update_marker("BASE", markers["BASE"][0])
126-
127-
# Update Epi
128-
update_marker("LV_EPI_FW", markers["EPI"][0])
129-
update_marker("RV_EPI_FW", markers["EPI"][0])
130-
131-
# Assign back to geometry object
132-
geo.markers = markers
133-
geo.ffun = dolfinx.mesh.meshtags(
134-
geo.mesh,
135-
geo.ffun.dim,
136-
geo.ffun.indices,
137-
marker_values,
138-
)
139-
14084
# Scale the geometry from mm to meters (approximate scale factor)
14185
geo.mesh.geometry.x[:] *= 1.4e-2
14286

@@ -195,10 +139,10 @@ def update_marker(old_name, new_id):
195139
# * $P_{RV}$ on $\Gamma_{endo, RV}$
196140

197141
lvp = dolfinx.fem.Constant(geometry.mesh, dolfinx.default_scalar_type(0.0))
198-
neumann_lv = pulse.NeumannBC(traction=lvp, marker=geometry.markers["ENDO_LV"][0])
142+
neumann_lv = pulse.NeumannBC(traction=lvp, marker=geometry.markers["LV"][0])
199143

200144
rvp = dolfinx.fem.Constant(geometry.mesh, dolfinx.default_scalar_type(0.0))
201-
neumann_rv = pulse.NeumannBC(traction=rvp, marker=geometry.markers["ENDO_RV"][0])
145+
neumann_rv = pulse.NeumannBC(traction=rvp, marker=geometry.markers["RV"][0])
202146

203147
# ### Robin BC: Pericardial Constraint
204148
# We model the pericardium as a spring-like boundary condition on the epicardium.

demo/time_dependent/time_dependent_bestel_biv.py

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -53,31 +53,10 @@
5353

5454
geo.mesh.geometry.x[:] *= 1.5e-2
5555

56-
# Now we need to redefine the markers to have so that facets on the endo- and epicardium combine both
57-
# free wall and the septum.
58-
59-
markers = {"ENDO_LV": [1, 2], "ENDO_RV": [2, 2], "BASE": [3, 2], "EPI": [4, 2]}
60-
marker_values = geo.ffun.values.copy()
61-
marker_values[np.isin(geo.ffun.indices, geo.ffun.find(geo.markers["LV_ENDO_FW"][0]))] = markers["ENDO_LV"][0]
62-
marker_values[np.isin(geo.ffun.indices, geo.ffun.find(geo.markers["LV_SEPTUM"][0]))] = markers["ENDO_LV"][0]
63-
marker_values[np.isin(geo.ffun.indices, geo.ffun.find(geo.markers["RV_ENDO_FW"][0]))] = markers["ENDO_RV"][0]
64-
marker_values[np.isin(geo.ffun.indices, geo.ffun.find(geo.markers["RV_SEPTUM"][0]))] = markers["ENDO_RV"][0]
65-
marker_values[np.isin(geo.ffun.indices, geo.ffun.find(geo.markers["BASE"][0]))] = markers["BASE"][0]
66-
marker_values[np.isin(geo.ffun.indices, geo.ffun.find(geo.markers["LV_EPI_FW"][0]))] = markers["EPI"][0]
67-
marker_values[np.isin(geo.ffun.indices, geo.ffun.find(geo.markers["RV_EPI_FW"][0]))] = markers["EPI"][0]
68-
geo.markers = markers
69-
ffun = dolfinx.mesh.meshtags(
70-
geo.mesh,
71-
geo.ffun.dim,
72-
geo.ffun.indices,
73-
marker_values,
74-
)
75-
geo.ffun = ffun
76-
7756
# We create the geometry object and print the volumes of the LV and RV cavities
7857

7958
geometry = pulse.HeartGeometry.from_cardiac_geometries(geo, metadata={"quadrature_degree": 6})
80-
print(geometry.volume("ENDO_LV") * 1e6, geometry.volume("ENDO_RV") * 1e6)
59+
print(geometry.volume("LV") * 1e6, geometry.volume("RV") * 1e6)
8160

8261
material_params = pulse.HolzapfelOgden.orthotropic_parameters()
8362
material = pulse.HolzapfelOgden(f0=geo.f0, s0=geo.s0, **material_params) # type: ignore
@@ -96,10 +75,10 @@
9675
# One difference with the LV example is that we now have two different pressure boundary conditions, one for the LV and one for the RV
9776

9877
traction_lv = pulse.Variable(dolfinx.fem.Constant(geometry.mesh, dolfinx.default_scalar_type(0.0)), "Pa")
99-
neumann_lv = pulse.NeumannBC(traction=traction_lv, marker=geometry.markers["ENDO_LV"][0])
78+
neumann_lv = pulse.NeumannBC(traction=traction_lv, marker=geometry.markers["LV"][0])
10079

10180
traction_rv = pulse.Variable(dolfinx.fem.Constant(geometry.mesh, dolfinx.default_scalar_type(0.0)), "Pa")
102-
neumann_rv = pulse.NeumannBC(traction=traction_rv, marker=geometry.markers["ENDO_RV"][0])
81+
neumann_rv = pulse.NeumannBC(traction=traction_rv, marker=geometry.markers["RV"][0])
10382

10483
# Otherwize we have the same Robin boundary conditions as in the LV example
10584

@@ -204,8 +183,8 @@
204183
vtx.write(0.0)
205184

206185
volume_form = geometry.volume_form(u=problem.u)
207-
lv_volume_form = dolfinx.fem.form(volume_form * geometry.ds(geometry.markers["ENDO_LV"][0]))
208-
rv_volume_form = dolfinx.fem.form(volume_form * geometry.ds(geometry.markers["ENDO_RV"][0]))
186+
lv_volume_form = dolfinx.fem.form(volume_form * geometry.ds(geometry.markers["LV"][0]))
187+
rv_volume_form = dolfinx.fem.form(volume_form * geometry.ds(geometry.markers["RV"][0]))
209188

210189
lv_volumes = []
211190
rv_volumes = []

demo/time_dependent/time_dependent_land_circ_biv.py

Lines changed: 10 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -61,43 +61,8 @@
6161
folder=geodir,
6262
)
6363
# Scale the geometry to meters and adjust the size so that LV and RV volumes are reasonable
64-
geo.mesh.geometry.x[:] *= 1.5e-2
65-
66-
# Now we need to redefine the markers to have so that facets on the endo- and epicardium combine both
67-
# free wall and the septum.
68-
69-
markers = {"ENDO_LV": [1, 2], "ENDO_RV": [2, 2], "BASE": [3, 2], "EPI": [4, 2]}
70-
marker_values = geo.ffun.values.copy()
71-
marker_values[
72-
np.isin(geo.ffun.indices, geo.ffun.find(geo.markers["LV_ENDO_FW"][0]))
73-
] = markers["ENDO_LV"][0]
74-
marker_values[np.isin(geo.ffun.indices, geo.ffun.find(geo.markers["LV_SEPTUM"][0]))] = (
75-
markers["ENDO_LV"][0]
76-
)
77-
marker_values[
78-
np.isin(geo.ffun.indices, geo.ffun.find(geo.markers["RV_ENDO_FW"][0]))
79-
] = markers["ENDO_RV"][0]
80-
marker_values[np.isin(geo.ffun.indices, geo.ffun.find(geo.markers["RV_SEPTUM"][0]))] = (
81-
markers["ENDO_RV"][0]
82-
)
83-
marker_values[np.isin(geo.ffun.indices, geo.ffun.find(geo.markers["BASE"][0]))] = (
84-
markers["BASE"][0]
85-
)
86-
marker_values[np.isin(geo.ffun.indices, geo.ffun.find(geo.markers["LV_EPI_FW"][0]))] = (
87-
markers["EPI"][0]
88-
)
89-
marker_values[np.isin(geo.ffun.indices, geo.ffun.find(geo.markers["RV_EPI_FW"][0]))] = (
90-
markers["EPI"][0]
91-
)
64+
geo.mesh.geometry.x[:] *= 1.6e-2
9265

93-
geo.markers = markers
94-
ffun = dolfinx.mesh.meshtags(
95-
geo.mesh,
96-
geo.ffun.dim,
97-
geo.ffun.indices,
98-
marker_values,
99-
)
100-
geo.ffun = ffun
10166

10267
geometry = pulse.HeartGeometry.from_cardiac_geometries(
10368
geo, metadata={"quadrature_degree": 6},
@@ -131,7 +96,7 @@
13196
)
13297

13398
alpha_epi = pulse.Variable(
134-
dolfinx.fem.Constant(geometry.mesh, dolfinx.default_scalar_type(1e8)),
99+
dolfinx.fem.Constant(geometry.mesh, dolfinx.default_scalar_type(1e6)),
135100
"Pa / m",
136101
)
137102
robin_epi = pulse.RobinBC(value=alpha_epi, marker=geometry.markers["EPI"][0])
@@ -142,17 +107,17 @@
142107
robin_base = pulse.RobinBC(value=alpha_base, marker=geometry.markers["BASE"][0])
143108

144109

145-
lvv_initial = geo.mesh.comm.allreduce(geometry.volume("ENDO_LV"), op=MPI.SUM)
110+
lvv_initial = geo.mesh.comm.allreduce(geometry.volume("LV"), op=MPI.SUM)
146111
lv_volume = dolfinx.fem.Constant(
147112
geometry.mesh, dolfinx.default_scalar_type(lvv_initial),
148113
)
149-
lv_cavity = pulse.problem.Cavity(marker="ENDO_LV", volume=lv_volume)
114+
lv_cavity = pulse.problem.Cavity(marker="LV", volume=lv_volume)
150115

151-
rvv_initial = geo.mesh.comm.allreduce(geometry.volume("ENDO_RV"), op=MPI.SUM)
116+
rvv_initial = geo.mesh.comm.allreduce(geometry.volume("RV"), op=MPI.SUM)
152117
rv_volume = dolfinx.fem.Constant(
153118
geometry.mesh, dolfinx.default_scalar_type(rvv_initial),
154119
)
155-
rv_cavity = pulse.problem.Cavity(marker="ENDO_RV", volume=rv_volume)
120+
rv_cavity = pulse.problem.Cavity(marker="RV", volume=rv_volume)
156121

157122

158123
cavities = [lv_cavity, rv_cavity]
@@ -284,7 +249,7 @@ def get_activation(t: float):
284249

285250
def callback(model, i: int, t: float, save=True):
286251
Ta_history.append(get_activation(t))
287-
if save and i % 100 == 0:
252+
if save and i % 10 == 0:
288253
io4dolfinx.write_function(filename, problem.u, time=t, name="displacement")
289254
vtx.write(t)
290255

@@ -363,19 +328,18 @@ def p_BiV_func(V_LV, V_RV, t):
363328
mL = circulation.units.ureg("mL")
364329
add_units = False
365330
lvv_init = (
366-
geo.mesh.comm.allreduce(geometry.volume("ENDO_LV", u=problem.u), op=MPI.SUM)
331+
geo.mesh.comm.allreduce(geometry.volume("LV", u=problem.u), op=MPI.SUM)
367332
* 1e6
368333
* 1.0
369334
) # Increase the volume by 5%
370335
rvv_init = (
371-
geo.mesh.comm.allreduce(geometry.volume("ENDO_RV", u=problem.u), op=MPI.SUM)
336+
geo.mesh.comm.allreduce(geometry.volume("RV", u=problem.u), op=MPI.SUM)
372337
* 1e6
373338
* 1.0
374339
) # Increase the volume by 5%
375340
logger.info(f"Initial volume (LV): {lvv_init} mL and (RV): {rvv_init} mL")
376341
init_state = {"V_LV": lvv_initial * 1e6 * mL, "V_RV": rvv_initial * 1e6 * mL}
377342

378-
379343
circulation_model_3D = circulation.regazzoni2020.Regazzoni2020(
380344
add_units=add_units,
381345
callback=callback,
@@ -385,6 +349,7 @@ def p_BiV_func(V_LV, V_RV, t):
385349
outdir=outdir,
386350
initial_state=init_state,
387351
)
352+
# exit()
388353
# Set end time for early stopping if running in CI
389354
end_time = 2 * dt if os.getenv("CI") else None
390355
circulation_model_3D.solve(

0 commit comments

Comments
 (0)