Skip to main content

sknm

A Python implementation of the Simplified Kirchhoff Network Model (SKNM) of Jæger & Tveito, Scientific Reports 13:16434 (2023), together with KNM and SKNM(uₑ=0) so that the paper's model comparisons can be reproduced.

The domain is cell-based cardiac and islet electrophysiology: excitable cells coupled through gap junctions, resolved per cell rather than homogenized into a continuum. See CONTEXT.md for the vocabulary this codebase uses.

Status: early development. The model, the solvers and the analysis are implemented, and the scripts in examples/ reproduce the paper's figures for both of its cell types, hiPSC-derived cardiomyocytes and pancreatic β cells. The homogenized bidomain and monodomain comparisons (Figures 6 to 9) are reproduced too, through dolfinx and fenicsx-beat rather than in sknm itself: those four scripts need both installed and report what is missing when they are not.

Installation

python -m pip install sknm

Runtime dependencies are numpy, scipy and pint. matplotlib arrives with the examples extra, and gotranx with the codegen extra, which is needed only to regenerate the membrane models (the generated Python is committed).

Two membrane models ship: base_model_IM, an hiPSC-CM model, and PBM, the phantom bursting model of the pancreatic β cell. Both are generated from the .ode sources in the repository root and checked against the authors' C++ elementwise.

Usage

Every dimensional argument carries a unit; a bare number is refused. This reproduces the conduction velocity of Table S1 of the supplementary, 3.73 cm/s, in about two seconds:

from sknm import Simulation, Variant, analysis, presets
from sknm.membrane import base_model_IM, from_gotranx
from sknm.units import ms, mV

network = presets.hipsc_sheet(40, 40, alpha=1.0)
model = from_gotranx(base_model_IM)
sim = Simulation(network, model, variant=Variant.SKNM, dt=0.02 * ms)
sim.set_parameter("stim_amplitude", presets.hipsc_stimulus_amplitude(40, 40))

path = presets.hipsc_conduction_path(40, 40, alpha=1.0)
recorder = analysis.ActivationRecorder(sim, threshold=-20 * mV, stop_when_activated=path.end)
sim.run(50 * ms, record=(), callback=recorder)

print(analysis.conduction_velocity(recorder, path))
print(recorder.max_upstroke_velocity[presets.hipsc_centre_cell(40, 40)], "V/s")

Run the same network as Variant.KNM to solve for the extracellular potential as well.

The β cell setup is the same shape, through presets.beta_*, and reproduces Table S4's 0.0243 cm/s:

from sknm import Simulation, Variant, analysis, presets
from sknm.units import ms

network = presets.beta_sheet(15, 15)
sim = Simulation(network, presets.beta_membrane_model(), variant=Variant.SKNM, dt=0.02 * ms)
sim.set_parameter("gkatpbar", presets.beta_stimulus_conductance(15, 15))

path = presets.beta_conduction_path(15, 15)
recorder = analysis.ActivationRecorder(
    sim, threshold=presets.BETA_THRESHOLD, stop_when_activated=path.end
)
sim.run(1000 * ms, record=(), callback=recorder)

print(analysis.conduction_velocity(recorder, path))

ActivationRecorder has no default threshold. The two cell types activate at −20 mV and −50 mV, and a β action potential peaks at about −19.5 mV, so the cardiac threshold applied to a β sheet leaves the measurement cell unactivated. presets.HIPSC_THRESHOLD and presets.BETA_THRESHOLD are the two values.

Examples

Each script in examples/ reproduces one of the paper's figures, writing it to examples/figures/ and printing the numbers it plotted.

Script Reproduces
fig02_travelling_wave.py Figure 2: snapshots of a wave crossing 40×40 cells, KNM against SKNM
fig03_anisotropy.py Figure 3: conduction velocity against cell length-to-width ratio
fig04_gap_junction_variation.py Figures 4 and S2: conduction velocity against gap junction variation
fig05_sources_of_difference.py Figure 5: the two factors that make KNM and SKNM differ
fig10_beta_travelling_wave.py Figure 10: snapshots of a wave crossing 15×15 β cells
fig11_beta_variable_coupling.py Figure 11: the same, at γ = 1 and 2% extracellular volume
fig12_beta_gap_junction_variation.py Figures 12 and S1: β conduction velocity against gap junction variation
python -m pip install -e ".[examples]"
python examples/fig03_anisotropy.py                       # a reduced sample, about a minute
SKNM_EXAMPLES_FULL=1 python examples/fig03_anisotropy.py  # the paper's whole sample

Every script is fast by default: it sweeps every other point of its parameter range unless SKNM_EXAMPLES_FULL is set. The reduction drops points and never makes a point cheaper. Each point plotted is computed on the paper's own 40×40 sheet at its own 0.02 ms time step, so a full run adds markers rather than moving them. Results are cached under examples/results/ and reused, so restyling a figure costs no simulation. The cache is keyed on the parameters of a run and cannot see that sknm itself has changed, so set SKNM_EXAMPLES_NO_CACHE=1 or delete the directory after changing the library.

Each script is also a page of the documentation site, so it is run both as a script and, by the docs build, as a notebook. A notebook's process belongs to the Jupyter kernel and its command line describes the kernel rather than the script, so these are environment variables rather than options: SKNM_EXAMPLES_FULL, SKNM_EXAMPLES_NO_CACHE and SKNM_EXAMPLES_OUTPUT_DIR.

The gap junction draws differ between the two cell types, and the difference is measurable. The cardiac figures seed a generator rather than using the paper's own random numbers: on a 40×40 sheet with a 25-cell conduction path the choice of draws moves a velocity by about 2%, so those curves sit very close to the published ones rather than on top of them. The authors' draws can be passed to presets.vary_conductances instead, if you have them.

The β figures cannot do that. A 15×15 sheet has 420 connections and an 8-cell path, so at γ = 1 the draws move the velocity by 20%, and every seed tried fell below the axis of the published Figure S1. Those scripts therefore read the authors' own 420 draws, committed with their provenance under examples/data/. No number the test suite asserts depends on them: every published target is at γ = 0, where the draws cancel out of the formula.

Development

pytest                      # tests
pre-commit run --all-files  # ruff lint, ruff format, mypy

Requires Python 3.11 or newer.

Attribution

This is an independent Python reimplementation. It is not the authors' code and is not endorsed by them. The model, its equations and its reference parameters are due to:

Jæger, K.H., Tveito, A. The simplified Kirchhoff network model (SKNM): a cell-based reaction–diffusion model of excitable tissue. Scientific Reports 13, 16434 (2023). https://doi.org/10.1038/s41598-023-43444-9

The authors' own C++ implementation (found https://doi.org/10.5281/zenodo.8340201) is distributed under CC-BY-4.0 and was used as the ground truth for every numerical choice made here. Please cite the paper above in any work that uses this package; see CITATION.cff.

The paper above is derrived from the paper

Jæger, K. H., & Tveito, A. (2023). *Efficient, cell-based simulations of cardiac electrophysiology; the Kirchhoff Network Model (KNM). NPJ systems biology and applications, 9(1), 25. https://doi.org/10.1038/s41540-023-00288-3

with it's implementation in C++ found at https://doi.org/10.5281/zenodo.7848664.

Licence

MIT. See LICENSE.

Metadata

Release files for sknm 0.1.1

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

Source distribution (sdist)

Source distribution for sknm 0.1.1
File Size Uploaded
sknm-0.1.1.tar.gz 503.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sknm 0.1.1
File Interpreter ABI Platform
sknm-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 569.6 kB

Release files / sknm-0.1.1.tar.gz

Download URL sknm-0.1.1.tar.gz
Size 503.3 kB
Tags Source
SHA-256 checksum
How to use checksums
f8442e468cd5b4817d06dc9414e1cf0cb5a8b1c8ffacc41c4a6ba0556d1015f0
BLAKE2b-256 checksum
How to use checksums
ae8dc04fee113d880da8f41f5da62978be8596271912b7ca3f754e21fe24c9fa
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 Sep 26, 2026.

Transparency log

Release files / sknm-0.1.1-py3-none-any.whl

Download URL sknm-0.1.1-py3-none-any.whl
Size 66.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
eb574ac5c589400491e7ea06e9a766eef456e5886f214006f297f823ae917935
BLAKE2b-256 checksum
How to use checksums
2bdefeb649230ee35d584f778b0754fb043d513b12b31f6c03027161e8ee673c
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 Sep 26, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

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