Skip to main content

cuNIBS

pypi

cuNIBS computes transcranial magnetic stimulation (TMS) electric fields in tetrahedral head models. Use it for a single placement simulation, repeated placement studies, conductivity uncertainty analysis, and coil-placement optimization on NVIDIA GPUs. See the accompanying manuscript for the numerical method and its validation.

Installation

python -m pip install cunibs

cuNIBS requires Python 3.12 or later, an NVIDIA GPU, and a driver compatible with CUDA 13 (r580 or later). Wheels are available for x86-64 Linux and Windows, for CPython 3.12 through 3.14, including free-threaded Python 3.14. The package installs the required CUDA and CuPy wheels; a separate CUDA toolkit installation is not required.

Quick start

from cunibs import Placement, Subject
from cunibs.coil import Coil, MAGSTIM_D70

subject = Subject.from_mesh("subject.msh")
coil = Coil.load(MAGSTIM_D70)

placement = Placement(
    center_mm=[0.0, 20.0, 80.0],
    handle_mm=[0.0, 70.0, 80.0],
    distance_mm=4.0,
)

result = subject.simulate(coil, placement, didt=1.0e6)

print(result.peak_magnE())
print(result.peak_location_mm())
print(result.focality(frac=0.5))

center_mm is the intended scalp target and handle_mm specifies the positive handle direction. cuNIBS projects the target onto the scalp and places the coil distance_mm above the local surface. The handle point must not lie on the surface normal through the target.

didt is the coil-current rate of change in A/s. Fields scale linearly with this value. Bundled coil models provide their rated peak value as coil.didt_max.

Input data

Head mesh

Subject.from_mesh reads binary Gmsh 2.2 meshes containing first-order tetrahedra and an oriented scalp surface with tag 1005. Coordinates must be in millimetres. The volume tag selects the built-in tissue conductivity; unrelated surface triangles are ignored. Invalid mesh references, non-finite coordinates, and zero-volume tetrahedra are rejected.

Create individualized head models with the SimNIBS CHARM pipeline:

charm subject_id T1w.nii.gz T2w.nii.gz

CHARM writes m2m_subject_id/subject_id.msh. A T1-weighted image is sufficient; a T2-weighted image can improve skull segmentation. Inspect the segmentation before simulation.

The built-in conductivities match the standard SimNIBS values.

Tag Tissue Conductivity (S/m) Source
1 White matter 0.126 Wagner et al. (2004)
2 Gray matter 0.275 Wagner et al. (2004)
3 Cerebrospinal fluid 1.654 Wagner et al. (2004)
4 Average bone 0.010 Wagner et al. (2004)
5 Scalp 0.465 Wagner et al. (2004)
6 Eye 0.500 Opitz et al. (2015)
7 Cortical bone 0.008 Opitz et al. (2015)
8 Cancellous bone 0.025 Opitz et al. (2015)
9 Blood 0.600 Gabriel et al. (2009)
10 Muscle 0.160 Gabriel et al. (2009)

Coil models

The package includes the 25 validated coil models from Drakaki et al. (2022). Import a bundled-model constant from cunibs.coil and pass it to Coil.load. Custom coil models use an HDF5 dipole format, with positions in metres and moments in A m². Convert a SimNIBS CCD coil as follows:

from pathlib import Path

from cunibs.coil import Coil, encode_ccd

encode_ccd(Path("coil.ccd"), Path("coil.h5"))
coil = Coil.load("coil.h5")

Simulating placements

Use simulate for one placement. Use iter_simulate for a sequence; it yields results in input order and reuses the subject setup.

placements = [
    Placement([0.0, 20.0, 80.0], [0.0, 70.0, 80.0]),
    Placement([20.0, 0.0, 80.0], [70.0, 0.0, 80.0]),
]

for result in subject.iter_simulate(coil, placements, didt=1.0e6):
    print(result.peak_magnE())

The iterator computes results only as they are requested. It releases each result as the loop advances unless you retain it. Use list(...) when all results are needed in memory.

block_k controls how many placements are processed together (default 8). Reduce it to lower peak memory use, or increase it when GPU memory permits. It does not change the field returned for a placement.

for result in subject.iter_simulate(coil, placements, didt=1.0e6, block_k=4):
    ...

Many subjects

A Subject retains GPU resources until it is freed. Use a context manager, or call subject.free(), when processing multiple meshes.

from pathlib import Path

for mesh_file in Path("subjects").glob("m2m_*/*.msh"):
    with Subject.from_mesh(mesh_file) as subject:
        result = subject.simulate(coil, placement, didt=1.0e6)
        print(result.peak_magnE())

Results

Each FieldResult provides gray-matter summary metrics by default:

result.peak_magnE()
result.focality(0.5)
result.summary["distribution"]["p99"]

The metric API includes peak field and location, stimulated volume, field-weighted centre of gravity, and volume-weighted distribution statistics. peak_magnE() reports the maximum |E|. focality(frac) reports the volume at or above frac times the volume-weighted 99.9th percentile of |E|.

Full-volume arrays are not retained unless requested. Request only the data needed for downstream analysis:

result = subject.simulate(coil, placement, didt=1.0e6, magnitude=True)

for result in subject.iter_simulate(
    coil, placements, magnitude=True, vectors=True, potential=True
):
    ...

result.magnE, result.E, and result.v are None unless the corresponding array was requested. Retaining magnitude also enables summary_for(region) for a non-default tissue and focality(frac) at an arbitrary fraction.

gray_matter = result.summary_for("gray_matter")
whole_model = result.summary_for("all")

Results are returned as NumPy arrays. For device-resident fields, use cunibs.fem.solve_placements_block directly.

Attribute Description Units
E Electric field per tetrahedron V/m
magnE Electric-field magnitude per tetrahedron V/m
v Electric scalar potential per node V
transform Coil-to-head affine transform translation in mm
vols Tetrahedron volumes
tet_tags Volume tissue tags dimensionless
barycenters_mm Tetrahedron barycentres mm
didt Coil-current rate of change A/s
recovery Recovery method used for E, magnE, and summary dimensionless
E_slots Recovered field per slot when nodal=True V/m
slot_node Mesh node for each slot when nodal=True dimensionless
slot_tag Tissue tag for each slot, or None for node slots dimensionless
n_nodes Mesh node count dimensionless

Save a result and its retained fields to HDF5:

result.save("placement.h5")

from cunibs import FieldResult

loaded = FieldResult.load("placement.h5")

Fields that were not retained are absent from the file and load as None.

Field recovery

The raw finite-element field is constant within each tetrahedron. The recovery argument selects the reported field:

recovery Use case
"harmonic" Default. Use for cuNIBS analyses, particularly near tissue interfaces.
"raw" Use the unprocessed per-tetrahedron field.
"spr_tissue" Use when comparing with SimNIBS surface or volume overlays.
"spr_global" Use the SimNIBS continuous=True convention.
result = subject.simulate(coil, placement, didt=1.0e6, magnitude=True)
raw = subject.simulate(coil, placement, didt=1.0e6, magnitude=True, recovery="raw")

E, magnE, and summary always describe the selected recovery method. The raw field is not retained alongside a recovered field.

Nodal fields

Request nodal=True when interpolating a recovered field to a cortical surface or another node-based representation:

result = subject.simulate(coil, placement, magnitude=True, nodal=True)

gray_field = result.nodal_field()
csf_field = result.nodal_field("csf")

For tissue-restricted recovery, a boundary node can hold one value for each incident tissue. nodal_field(region) returns the requested tissue value and uses NaN where that tissue does not reach the node. region="all" is not available for these recovery modes. E_slots, slot_node, and slot_tag provide the underlying arrays.

Conductivity uncertainty quantification

simulate_conductivity_uq estimates the effect of uncertain tissue conductivities for one placement or a placement sequence. Configure independent tissue distributions with ConductivityUQConfig; conductivities are sampled from lognormal distributions by default.

from cunibs import ConductivityUQConfig, Placement, Subject
from cunibs.coil import Coil, MAGSTIM_D70

subject = Subject.from_mesh("subject.msh")
coil = Coil.load(MAGSTIM_D70)

config = ConductivityUQConfig(
    n_samples=500,
    tissue_cov={2: 0.15, 3: 0.05, 7: 0.35, 8: 0.35},
    seed=1,
)

uq_result = subject.simulate_conductivity_uq(coil, placement, config, didt=1.0e6)

print(uq_result.peak_mean_magnE())
print(uq_result.max_local_cov())

The result includes summary metrics for the per-tetrahedron mean field. Pass moments=True to retain mean_magnE, std_magnE, and cov_magnE arrays. Use iter_simulate_conductivity_uq to stream placements.

For statistics of scalar outcomes across draws, record regions of interest or use the supplied sample arrays:

m1 = subject.roi([-45.0, -5.0, 25.0], radius_mm=5.0, region="gray_matter")

uq_result = subject.simulate_conductivity_uq(
    coil, placement, config, didt=1.0e6, record_rois={"M1": m1}
)

uq_result.roi_samples["M1"]
uq_result.peak_samples
uq_result.focality_samples
uq_result.peak_location_samples
uq_result.tissue_sensitivity("peak")

peak_mean_magnE and max_local_cov summarize the moment fields, rather than the distribution of a metric across draws. tissue_sensitivity is a prior-weighted linear-in-log sensitivity index, not a Sobol estimator.

Save and load uncertainty results with uq_result.save(path) and ConductivityUQResult.load(path).

Coil-placement optimization

cunibs.adm implements the Auxiliary Dipole Method (Gomez et al., 2021) for searching candidate coil positions and in-plane rotations without a forward FEM solve for every candidate.

import numpy as np

from cunibs import Subject, Target, adm
from cunibs.coil import Coil, MAGSTIM_D70

subject = Subject.from_mesh("subject.msh")
coil = Coil.load(MAGSTIM_D70)

target = Target(position_mm=[-45.0, -5.0, 25.0], region="gray_matter")
centers = np.array([[x, y, 80.0] for x in range(-30, 31, 5) for y in range(-30, 31, 5)])

result = adm.optimize(subject.context, coil, target, centers)

result.best_objective
result.best_center_mm
result.best_angle_rad

Omit Target.direction to maximize |E|; provide a direction to maximize its component along that direction. Candidate centres are projected onto the scalp.

For repeated searches with the same target and candidate centres, build and reuse the reciprocity field:

recip = adm.build_reciprocity(subject.context, coil, target, centers)
E = adm.evaluate(recip, coil, placements, didt=1.0e6)

Reproducibility

A placement result is determined by the mesh, coil model, placement, didt, solve tolerance, and recovery method. It is independent of block_k, placement order, and other placements in a sweep. Repeating the same calculation on the same software and hardware configuration reproduces the result bitwise.

Results can differ across GPU architectures, CUDA versions, compiler versions, and dependency versions. A conductivity-UQ draw depends only on its conductivity vector; the same seed reproduces the same draws at any n_samples.

Citation

No archival citation is available yet. For reproducible academic use, cite the software name, author, version, and Git commit. Archive the input mesh, coil model, placement parameters, and analysis settings with the study data.

References

Download files

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

Source Distribution

cunibs-0.4.1.tar.gz (1.3 MB view details)

Uploaded Source

Built Distributions

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

cunibs-0.4.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (2.6 MB view details)

Uploaded CPython 3.14tmanylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

cunibs-0.4.1-cp314-cp314-win_amd64.whl (2.8 MB view details)

Uploaded CPython 3.14Windows x86-64

cunibs-0.4.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (2.6 MB view details)

Uploaded CPython 3.14manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

cunibs-0.4.1-cp313-cp313-win_amd64.whl (2.8 MB view details)

Uploaded CPython 3.13Windows x86-64

cunibs-0.4.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (2.6 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

cunibs-0.4.1-cp312-cp312-win_amd64.whl (2.8 MB view details)

Uploaded CPython 3.12Windows x86-64

cunibs-0.4.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (2.6 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

File details

Details for the file cunibs-0.4.1.tar.gz.

File metadata

  • Download URL: cunibs-0.4.1.tar.gz
  • Upload date:
  • Size: 1.3 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for cunibs-0.4.1.tar.gz
Algorithm Hash digest
SHA256 f06d59d87eef30bc3555a508720fb72e81990205d03192a2a9c521021eeec8ec
MD5 d48e42aed531d5f0ec67d03c0a281150
BLAKE2b-256 7f8515f6ff5770f74ff8b4df6df8e57a3eff26d4a79cb23e42abf6c69070b9a4

See more details on using hashes here.

Provenance

The following attestation bundles were made for cunibs-0.4.1.tar.gz:

Publisher: wheels.yml on vcubiomag/cunibs

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

File details

Details for the file cunibs-0.4.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for cunibs-0.4.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 88e7971001d408e2d99c3222b3b7c2a4db087703340fb534af860eea9c173ac2
MD5 2e782fefea9c42995088eecf833d77a7
BLAKE2b-256 2590ef2cdc395a6d96dbc9041c81b3cc7514cfb0e6ccb8d6b203b83b339cbca7

See more details on using hashes here.

Provenance

The following attestation bundles were made for cunibs-0.4.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:

Publisher: wheels.yml on vcubiomag/cunibs

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

File details

Details for the file cunibs-0.4.1-cp314-cp314-win_amd64.whl.

File metadata

  • Download URL: cunibs-0.4.1-cp314-cp314-win_amd64.whl
  • Upload date:
  • Size: 2.8 MB
  • Tags: CPython 3.14, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for cunibs-0.4.1-cp314-cp314-win_amd64.whl
Algorithm Hash digest
SHA256 537a15db385085f332751d0cc3f56513225786c87265f8b9131f7a940e4d4744
MD5 357a050988ab1389ac0ceadfa55d8cc1
BLAKE2b-256 9f3faa2dc6243e995fa8fb03947bbcd6857388e84377d76c16fd58cd0d35b277

See more details on using hashes here.

Provenance

The following attestation bundles were made for cunibs-0.4.1-cp314-cp314-win_amd64.whl:

Publisher: wheels.yml on vcubiomag/cunibs

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

File details

Details for the file cunibs-0.4.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for cunibs-0.4.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 484cc808ee1701c2767143d9b6d8cfd39b9e1c5bfbf88f47a17d1acd2acbf511
MD5 5048bdd597a501ea45117d38dcad9777
BLAKE2b-256 acddd65be08bd61da303c78f808f71c9fd483d47830d1a448382e8c1d23866fd

See more details on using hashes here.

Provenance

The following attestation bundles were made for cunibs-0.4.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:

Publisher: wheels.yml on vcubiomag/cunibs

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

File details

Details for the file cunibs-0.4.1-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: cunibs-0.4.1-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 2.8 MB
  • Tags: CPython 3.13, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for cunibs-0.4.1-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 1682e3b368a5f1d6527de3a180efa57b6ae54f258a4a62f57b7eb8d172f41c3f
MD5 17fbe77924a9dfda01e9d6eba9a14965
BLAKE2b-256 a60298c78c2a30f1ce3dfdf6f06aa21148506adc41710ef4fca49043a91c91c0

See more details on using hashes here.

Provenance

The following attestation bundles were made for cunibs-0.4.1-cp313-cp313-win_amd64.whl:

Publisher: wheels.yml on vcubiomag/cunibs

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

File details

Details for the file cunibs-0.4.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for cunibs-0.4.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 266bf4e3e09eaec9f840ee5a40ef8fbafe3f3314ac53a2a1fa3927ea8fef98e2
MD5 c5e5e18df497f1ffc027a18c9d06d366
BLAKE2b-256 983cde91b121d49a136efd44a3ca8bf69830e4901db80a104121e2f0f3fcaaf8

See more details on using hashes here.

Provenance

The following attestation bundles were made for cunibs-0.4.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:

Publisher: wheels.yml on vcubiomag/cunibs

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

File details

Details for the file cunibs-0.4.1-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: cunibs-0.4.1-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 2.8 MB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for cunibs-0.4.1-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 33ebcd84f2a8ee5e10e9febbb709a46002a8b4d2ae3d700857c3fb4e4eef2d05
MD5 31034c5422e9188d25e612903c6a7469
BLAKE2b-256 c5e98b554e060e38cdcb43458fce1181dcb0375026f362782f1c1fea3024ba41

See more details on using hashes here.

Provenance

The following attestation bundles were made for cunibs-0.4.1-cp312-cp312-win_amd64.whl:

Publisher: wheels.yml on vcubiomag/cunibs

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

File details

Details for the file cunibs-0.4.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for cunibs-0.4.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 91347a44e48ff70645a9423e2bdf825ede411bcc667c042dced0c127d2a0efa5
MD5 0e040dc2b0570e9b37f32b7ea5ae7523
BLAKE2b-256 d27a2227475134330ca5b95002c615fc79e8c26cd81670473e4aecbc631e2f3e

See more details on using hashes here.

Provenance

The following attestation bundles were made for cunibs-0.4.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:

Publisher: wheels.yml on vcubiomag/cunibs

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.4.1 This release

8 files

0.4.0

8 files

0.3.0

8 files

0.2.0

8 files

0.1.0

5 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