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.0.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.0-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.0-cp314-cp314-win_amd64.whl (2.8 MB view details)

Uploaded CPython 3.14Windows x86-64

cunibs-0.4.0-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.0-cp313-cp313-win_amd64.whl (2.8 MB view details)

Uploaded CPython 3.13Windows x86-64

cunibs-0.4.0-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.0-cp312-cp312-win_amd64.whl (2.8 MB view details)

Uploaded CPython 3.12Windows x86-64

cunibs-0.4.0-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.0.tar.gz.

File metadata

  • Download URL: cunibs-0.4.0.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.0.tar.gz
Algorithm Hash digest
SHA256 26a3d06a8f02f99b2fdec9f7005961a2db6ea69e64666eab8fe66f9b67945e4c
MD5 031936875d38c19d7d55daf11257eddc
BLAKE2b-256 5e95325ba79d76694d69e88a64e3f8a877fe2b5540cc25fcf67af1f0dea0629c

See more details on using hashes here.

Provenance

The following attestation bundles were made for cunibs-0.4.0.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.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for cunibs-0.4.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 0e4ceef0c173939545dc96637c3ee1729da74591040b640db6ffa087fe2ccc6a
MD5 11bd2da10311fdf79fb4fcd2ead7107a
BLAKE2b-256 94951fe43b35aef119543012db2d817ef285c2bc110c6d64eaa9a8e3f7540035

See more details on using hashes here.

Provenance

The following attestation bundles were made for cunibs-0.4.0-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.0-cp314-cp314-win_amd64.whl.

File metadata

  • Download URL: cunibs-0.4.0-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.0-cp314-cp314-win_amd64.whl
Algorithm Hash digest
SHA256 5054042b5514cc29c00f9eff197d9146543b83c829803f034f2a37b4a68ee470
MD5 462f49058f24dedff4d868f5f2359ce0
BLAKE2b-256 e42e999eae879140f5abba9cf4caceddb985369d63263da451a9eaacc79a719c

See more details on using hashes here.

Provenance

The following attestation bundles were made for cunibs-0.4.0-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.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for cunibs-0.4.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 641820c9aa2b9d92a463666b4603e8d2c4628883c050a64706cf204ae93e7396
MD5 c9109cfcf5998c8d9c9ae5ee3dbbeb9b
BLAKE2b-256 3821d632661b8d6da323300bf3d73544513bda0ffa95a2d40e8cfa2e4de97e67

See more details on using hashes here.

Provenance

The following attestation bundles were made for cunibs-0.4.0-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.0-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: cunibs-0.4.0-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.0-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 6cceceafc3140507ce9eef29f47af20b436a51d2075f062d3e873b1cdbb4930b
MD5 8f5296b078fe30af8ad88aaf874171f9
BLAKE2b-256 c8fdf76a2d1a922ca5996b823a10302a3d0e3f05e914d60069952c751787d747

See more details on using hashes here.

Provenance

The following attestation bundles were made for cunibs-0.4.0-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.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for cunibs-0.4.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 47764552377df0dd40c72fe9c68cfbb69126a1945e5ce30593d8b11cc822fd38
MD5 09ae49128c28eb5d8a7bd93aabd44321
BLAKE2b-256 904c9166cd366cec593e327fcca0f63166c0804ef1571249e365520b0b45c428

See more details on using hashes here.

Provenance

The following attestation bundles were made for cunibs-0.4.0-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.0-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: cunibs-0.4.0-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.0-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 6843b06ddf2a410fc144fd989b050a9c7c099028f08d27af77e232ed81e99fc5
MD5 6b18e5560789273cbba477c6f899370e
BLAKE2b-256 bcafb725de87d67e725f5bb53e5c3b72f4af063531ebee61227e24f528b0658f

See more details on using hashes here.

Provenance

The following attestation bundles were made for cunibs-0.4.0-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.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for cunibs-0.4.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 ed454775ea4f20d883b86d0ff835ee3cb3e08b7645a690c52688d4d88447b52c
MD5 239911d9d762dcf9c24b684688ab0377
BLAKE2b-256 3bcf0c46aa02664b4b9614437dbd63a4a41766c23377b3bb85aa519a409764d3

See more details on using hashes here.

Provenance

The following attestation bundles were made for cunibs-0.4.0-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

0.4.1

8 files

This release

0.4.0 This release

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