Skip to main content

_

MIT PyPI version Test package Pre-commit Deploy static content to Pages Code style: black Create and publish a Docker image Coverage

fenicsx-pulse

fenicsx-pulse is a cardiac mechanics solver based on FEniCSx. It is a successor of pulse which is a cardiac mechanics solver based on FEniCS.

Install

You can install the library with pip

python3 -m pip install fenicsx-pulse

or with conda

conda install -c conda-forge fenicsx-pulse

Note that installing with pip requires FEniCSx already installed

We also provide a pre-built docker image with FEniCSx and fenicsx_pulse installed. You pull this image using the command

docker pull ghcr.io/finsberg/fenicsx-pulse:v0.7.0

Getting started

Here is a minimal example of how to use fenicsx-pulse to solve a simple cardiac mechanics problem.

import numpy as np
import dolfinx
import cardiac_geometries
import pulse

# Create a geometry with cardiac-geometries
geo = cardiac_geometries.mesh.lv_ellipsoid(
    outdir="geometry",
    create_fibers=True,
    fiber_space="Quadrature_6",
)
# Convert the geometry to a pulse.Geometry
geometry = pulse.HeartGeometry.from_cardiac_geometries(geo, metadata={"quadrature_degree": 6})

# Create a material model
material_params = pulse.HolzapfelOgden.transversely_isotropic_parameters()
material = pulse.HolzapfelOgden(f0=geo.f0, s0=geo.s0, **material_params)

# Define model for active contraction
Ta = pulse.Variable(dolfinx.fem.Constant(geometry.mesh, dolfinx.default_scalar_type(0.0)), "kPa")
active_model = pulse.ActiveStress(geo.f0, activation=Ta)

# Define model for compressibility
comp_model = pulse.Incompressible()

# Assemble into a cardiac model
model = pulse.CardiacModel(
    material=material,
    active=active_model,
    compressibility=comp_model,
)

# Define boundary conditions
traction = pulse.Variable(
    dolfinx.fem.Constant(geometry.mesh, dolfinx.default_scalar_type(0.0)), "kPa"
)
neumann = pulse.NeumannBC(traction=traction, marker=geometry.markers["ENDO"][0])


def dirichlet_bc(V: dolfinx.fem.FunctionSpace):
    # Find facets for the BASE marker
    facets = geo.ffun.find(geo.markers["BASE"][0])
    # Locate degrees of freedom for the x-component (sub(0)) on these facets
    dofs = dolfinx.fem.locate_dofs_topological(V.sub(0), geo.mesh.topology.dim - 1, facets)
    # Return the Dirichlet BC object
    return [dolfinx.fem.dirichletbc(0.0, dofs, V.sub(0))]


robin_epi = pulse.RobinBC(
    value=pulse.Variable(
        dolfinx.fem.Constant(geometry.mesh, dolfinx.default_scalar_type(1e3)),
        "Pa / m",
    ),
    marker=geometry.markers["EPI"][0],
)
robin_base = pulse.RobinBC(
    value=pulse.Variable(
        dolfinx.fem.Constant(geometry.mesh, dolfinx.default_scalar_type(1e3)),
        "Pa / m",
    ),
    marker=geometry.markers["BASE"][0],
)

bcs = pulse.BoundaryConditions(neumann=(neumann,), dirichlet=(dirichlet_bc,), robin=(robin_base, robin_epi))

# Create a mechanics problem
problem = pulse.StaticProblem(
    model=model,
    geometry=geometry,
    bcs=bcs,
)
# Perform an initial solve
problem.solve()

# Create a file for storing the solution
vtx = dolfinx.io.VTXWriter(geometry.mesh.comm, "displacement.bp", [problem.u], engine="BP4")
vtx.write(0.0)

# Assign a pressure and activation and ramp them up in steps
target_pressure = 5.0  # kPa
target_activation = 5.0  # kPa
num_steps = 5
for i, (pressure, activation) in enumerate(
    zip(np.linspace(0, target_pressure, num_steps), np.linspace(0, target_activation, num_steps))
):
    traction.assign(pressure)  # kPa
    Ta.assign(activation)  # kPa
    problem.solve()
    # Save the displacement field
    vtx.write(i + 1)
vtx.close()

_

A more realistic example is visualized here:

https://github.com/user-attachments/assets/8e2f5d85-3fbf-4e30-9574-22e7f718230c

Check out the demos in the documentation for more examples.

Using with Claude

This repo ships a Claude Agent Skill at .claude/skills/fenicsx-pulse/SKILL.md that teaches Claude the fenicsx-pulse composition model (CardiacModel, StaticProblem/DynamicProblem, materials, active contraction, boundary conditions, units, ...) so it can write and review code against this library more accurately.

To use it in your own project with Claude Code, copy the skill into your project's .claude/skills/ directory:

mkdir -p .claude/skills/fenicsx-pulse
curl -o .claude/skills/fenicsx-pulse/SKILL.md \
    https://raw.githubusercontent.com/finsberg/fenicsx-pulse/main/.claude/skills/fenicsx-pulse/SKILL.md

Claude will then automatically load it whenever your prompt or code touches fenicsx-pulse/pulse. To install it globally for all your projects, copy it to ~/.claude/skills/fenicsx-pulse/ instead.

Contributing

See https://finsberg.github.io/fenicsx-pulse/CONTRIBUTING.html

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fenicsx_pulse-0.7.0.tar.gz (54.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fenicsx_pulse-0.7.0-py3-none-any.whl (52.4 kB view details)

Uploaded Python 3

File details

Details for the file fenicsx_pulse-0.7.0.tar.gz.

File metadata

  • Download URL: fenicsx_pulse-0.7.0.tar.gz
  • Upload date:
  • Size: 54.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for fenicsx_pulse-0.7.0.tar.gz
Algorithm Hash digest
SHA256 7bc18a98281cafef649a5523ea291c5738eba1a2b08705319c39ce7c90943ba4
MD5 71de641f48f91c26e6fd6520ed2b2e9e
BLAKE2b-256 e26d0ceab9fe42c49b262cb67f07f8a0d004bd08e4684d452f56dee173c2b3d2

See more details on using hashes here.

Provenance

The following attestation bundles were made for fenicsx_pulse-0.7.0.tar.gz:

Publisher: pypi.yml on finsberg/fenicsx-pulse

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fenicsx_pulse-0.7.0-py3-none-any.whl.

File metadata

  • Download URL: fenicsx_pulse-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 52.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for fenicsx_pulse-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c34a81c0ad1c16c92a844aac3e3e4cf0a9173cc9d79143d7dbbdd1be59cf2a10
MD5 f154a78c97c52e163f3d533642833627
BLAKE2b-256 863faf9f21bf2dd9d23e5dface1e7f97000f9298b8ebcac815fdcbfc694e8ff0

See more details on using hashes here.

Provenance

The following attestation bundles were made for fenicsx_pulse-0.7.0-py3-none-any.whl:

Publisher: pypi.yml on finsberg/fenicsx-pulse

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.7.0 This release

2 files

0.6.1

2 files

0.6.0

2 files

0.5.3

2 files

0.5.2

2 files

0.5.1

2 files

0.5.0

2 files

0.4.1

2 files

0.4.0

2 files

0.3.1

2 files

0.3.0

2 files

0.2.1

2 files

0.2.0

2 files

0.1.9

2 files

0.1.8

2 files

0.1.5

2 files

0.1.4

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page