Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .cspell_dict.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ caplog
cardiomyocytes
cellname
Chiara
CMAME
cntl
cofac
cofnorm
Expand Down
13 changes: 11 additions & 2 deletions .github/workflows/test_package_coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,18 @@ jobs:
steps:
- uses: actions/checkout@v6

- name: Install package
- name: Install build dependencies
run: |
python3 -m pip install -r https://raw.githubusercontent.com/scientificcomputing/scifem/refs/heads/main/build-requirements.txt

- name: Install development versions of dependencies
if: ${{ matrix.container == 'ghcr.io/fenics/dolfinx/dolfinx:nightly' }}
run: |
python3 -m pip install git+https://github.com/jorgensd/adios4dolfinx.git
python3 -m pip install git+https://github.com/scientificcomputing/scifem.git

- name: Install package
run: |
python3 -m pip install scifem --no-build-isolation
python3 -m pip install .[test]

Expand All @@ -42,7 +51,7 @@ jobs:
echo "total=$TOTAL" >> $GITHUB_ENV

- name: Upload HTML report.
if: ${{ matrix.container == 'ghcr.io/fenics/dolfinx/dolfinx:v0.9.0' }}
if: ${{ matrix.container == 'ghcr.io/fenics/dolfinx/dolfinx:stable' }}
uses: actions/upload-artifact@v6
with:
name: html-report
Expand Down
4 changes: 2 additions & 2 deletions demo/geometries/ukb_mesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,7 @@ def dirichlet_bc(V: dolfinx.fem.FunctionSpace):

vtx = dolfinx.io.VTXWriter(geometry.mesh.comm, outdir / "displacement.bp", [problem.u], engine="BP4")
vtx.write(0.0)

pressures = [0.5, 1.0, 1.5] # kPa
pressures = [0.5, 1.0, 1.5] # kPa
for i, plv in enumerate(pressures, start=1):
print(f"Solving for pressure: {plv} kPa")
traction_lv.assign(plv)
Expand All @@ -262,6 +261,7 @@ def dirichlet_bc(V: dolfinx.fem.FunctionSpace):
vtx.write(float(i))

# Visualize Passive Inflation

try:
import pyvista
except ImportError:
Expand Down
9 changes: 2 additions & 7 deletions demo/prestress/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ where $\mathbf{x} \in \Omega_t$. The deformation gradient $\mathbf{F}$ is comput

* **Class:** `pulse.unloading.PrestressProblem`
* **Demo:** [Pre-stressing a Bi-Ventricular Geometry](prestress_biv.py)
* **Reference:** The method is described in {cite}`barnafi2024reconstructing`.
* **Reference:** Barnafi et al., *Reconstructing relaxed configurations in elastic bodies: Mathematical formulations and numerical methods for cardiac modeling*, CMAME (2024).

## Method 2: Fixed-Point Iteration (Backward Displacement)

Expand All @@ -46,7 +46,7 @@ This method is intuitive as it reuses the standard forward solver, but it may re

* **Class:** `pulse.unloading.FixedPointUnloader`
* **Demo:** [Pre-stressing with Fixed-Point Iteration](prestress_fixedpoint_unloader.py)
* **Reference:** The method is described in {cite}`SELLIER20111461`
* **Reference:** Sellier, M. *An iterative method for the inverse elasto-static problem.* Journal of Fluids and Structures 27.8 (2011).

## Summary of Differences

Expand All @@ -57,8 +57,3 @@ This method is intuitive as it reuses the standard forward solver, but it may re
| **Computational Cost** | Generally lower (one system solve) | Higher (multiple forward solves) |
| **Implementation** | Requires specific inverse forms | Wraps standard forward solver |
| **Pulse Class** | `PrestressProblem` | `FixedPointUnloader` |


# References
```{bibliography}
:filter: docname in docnames
5 changes: 4 additions & 1 deletion demo/prestress/prestress_fixedpoint_unloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
cardiac_geometries.mesh.lv_ellipsoid(
outdir=geodir,
create_fibers=True,
fiber_space="P_2",
fiber_space="Quadrature_6",
r_short_endo=0.025,
r_short_epi=0.035,
r_long_endo=0.09,
Expand Down Expand Up @@ -98,6 +98,7 @@
# * **Neumann**: Endocardial pressure (Target = 2000 Pa).
# * **Robin**: Epicardial and Basal springs to mimic tissue support.


def setup_problem(geometry, f0, s0, n0, target_pressure=2000.0):

material = pulse.material_models.Usyk(f0=f0, s0=s0, n0=n0)
Expand Down Expand Up @@ -129,7 +130,9 @@ def setup_problem(geometry, f0, s0, n0, target_pressure=2000.0):
bcs = pulse.BoundaryConditions(neumann=(neumann,), robin=(robin_epi, robin_base))
return model, bcs, pressure, target_pressure


# Initialize model with fibers from the target geometry

model, bcs, pressure, target_pressure = setup_problem(geometry, geo.f0, geo.s0, geo.n0)

# Define the loading target for the unloader
Expand Down
8 changes: 6 additions & 2 deletions src/pulse/unloading.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ def default_parameters(self) -> dict[str, typing.Any]:
"max_iter": 10,
"tol": 1e-4,
"ramp_steps": 20,
"update_model_fields": True,
}

def unload(self) -> dolfinx.fem.Function:
Expand All @@ -136,6 +137,7 @@ def unload(self) -> dolfinx.fem.Function:

max_iter = self.unload_parameters["max_iter"]
tol = self.unload_parameters["tol"]
update_model_fields = self.unload_parameters["update_model_fields"]
comm = self.geometry.mesh.comm

for i in range(max_iter):
Expand Down Expand Up @@ -197,9 +199,11 @@ def unload(self) -> dolfinx.fem.Function:
# This effectively moves the reference configuration 'backwards' by the displacement
# required to reach the target from the current guess.
self.geometry.mesh.geometry.x[:] = self._target_coords - u_at_nodes

# Deforming the fields seems to cause issues with convergence, so we skip it for now.
u.x.array[:] *= -1.0
self._update_model_fields(u)
if update_model_fields:
u.x.array[:] *= -1.0
self._update_model_fields(u)

else:
logger.warning("FixedPointUnloader reached maximum iterations without converging.")
Expand Down
11 changes: 9 additions & 2 deletions src/pulse/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
import numpy.typing as npt
import scifem
import ufl
from packaging.version import Version

from .kinematics import DeformationGradient

logger = logging.getLogger(__name__)
_dolfinx_version = Version(dolfinx.__version__)


def map_vector_field(
Expand Down Expand Up @@ -38,6 +40,11 @@ def map_vector_field(
"""
f_new = dolfinx.fem.Function(f.function_space, name=name)

if _dolfinx_version >= Version("0.10"):
points = f.function_space.element.interpolation_points
else:
points = f.function_space.element.interpolation_points()

if u is None:
f_new.interpolate(f)
else:
Expand All @@ -48,11 +55,11 @@ def map_vector_field(
f_normalized = f_map / f_norm
f_expr = dolfinx.fem.Expression(
f_normalized,
f.function_space.element.interpolation_points,
points,
)

else:
f_expr = dolfinx.fem.Expression(f_map, f.function_space.element.interpolation_points)
f_expr = dolfinx.fem.Expression(f_map, points)
f_new.interpolate(f_expr)
return f_new

Expand Down
Loading