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.12.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],
)
# u_x = 0 already fixes the base's normal displacement: resist its in-plane motion instead
robin_base = pulse.RobinBC(
    value=pulse.Variable(
        dolfinx.fem.Constant(geometry.mesh, dolfinx.default_scalar_type(1e3)),
        "Pa / m",
    ),
    marker=geometry.markers["BASE"][0],
    perpendicular=True,
)

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:

monolithic_3d0d_biv

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

Metadata

Release files for fenicsx-pulse 0.12.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fenicsx-pulse 0.12.0
File Size Uploaded
fenicsx_pulse-0.12.0.tar.gz 199.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for fenicsx-pulse 0.12.0
File Interpreter ABI Platform
fenicsx_pulse-0.12.0-py3-none-any.whl Python 3 none any Details

Total release size: 370.0 kB

Release files / fenicsx_pulse-0.12.0.tar.gz

Download URL fenicsx_pulse-0.12.0.tar.gz
Size 199.1 kB
Tags Source
SHA-256 checksum
How to use checksums
e0cb93e4582e8dd17b8feaef9149c4f34248069372f431543163721b42f2a8b2
BLAKE2b-256 checksum
How to use checksums
8a107cc0e49960a7ebf674f3602027247ac88ef136da9deb973d703379537012
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / fenicsx_pulse-0.12.0-py3-none-any.whl

Download URL fenicsx_pulse-0.12.0-py3-none-any.whl
Size 170.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2239d51656a90477b632c983adb2fff629964cdd9c67ff8e3e89eda39b52a276
BLAKE2b-256 checksum
How to use checksums
74a744cc0a85a138cf35670e621687049f048424d14c5f96d6ad8302f897dc39
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.12.0 This release

2 release files

0.10.0

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.3

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release 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