Tractography-Informed Dose Estimation
Individualised TMS intensity estimation from subject-specific tractography and SimNIBS electric-field modelling
SimNIBS • diffusion MRI tractography • activating function • TMS dosing
Important
Research use only. TIDE is research software for computational TMS modelling. It is not a medical device, has not been clinically validated for individual treatment decisions, and has no regulatory clearance. It must not be used for diagnosis, treatment planning, or clinical decision-making. The activating function and tractography-derived quantities used by TIDE are model-based proxies, not direct measurements of axonal recruitment.
Marco Tagliaferri — PhD Candidate in Neuroscience 🏛️ Center for Mind/Brain Sciences (CIMeC), University of Trento, Italy
If you use TIDE in your research, please cite the accompanying preprint:
APA:
Tagliaferri, M., Cattaneo, L., Miniussi, C., & Brancaccio, A. (2026). TIDE: Tractography-Informed Dose Estimation for individualised TMS intensity. bioRxiv. DOI:
10.1101/<BIOARXIV_DOI>
BibTeX:
@article{Tagliaferri_TIDE_2026,
author = {Tagliaferri, Marco and Cattaneo, Luigi and Miniussi, Carlo and Brancaccio, Arianna},
title = {{TIDE}: Tractography-Informed Dose Estimation for individualised TMS intensity},
journal = {bioRxiv},
year = {2026},
doi = {10.1101/<BIOARXIV_DOI>},
url = {https://doi.org/10.1101/<BIOARXIV_DOI>},
note = {Preprint}
}Note
Manuscript status. The manuscript describing TIDE is currently in preparation. The peer-reviewed article citation will replace the preprint citation once the manuscript is formally published.
The TIDE software release associated with this work is archived on Zenodo under DOI 10.5281/zenodo.22019737. Software metadata and the preferred preprint citation are provided in CITATION.cff and are available through GitHub's Cite this repository function.
TIDE uses SimNIBS as its finite-element electric-field modelling and TMS simulation backend. Therefore, publications using TIDE should cite the TIDE preprint above as the primary method citation and additionally cite the relevant SimNIBS publication(s) for the simulation components used.
For the SimNIBS TMS modelling framework, please cite:
Thielscher, A., Antunes, A., & Saturnino, G. B. (2015). Field modeling for transcranial magnetic stimulation: A useful tool to understand the physiological effects of TMS? 37th Annual International Conference of the IEEE Engineering in Medicine and Biology Society (EMBC), 222–225. https://doi.org/10.1109/EMBC.2015.7318340
If your TIDE configuration uses Auxiliary Dipole Method (ADM) coil-position optimisation (options.adm_optimization: true), please also cite:
Gomez, L. J., Dannhauer, M., & Peterchev, A. V. (2021). Fast computational optimization of TMS coil placement for individualized electric field targeting. NeuroImage, 228, 117696. https://doi.org/10.1016/j.neuroimage.2020.117696
For analyses relying on other SimNIBS-specific modules, head-model pipelines, or coil datasets, please follow the corresponding module-specific citation guidance in the SimNIBS documentation.
- Overview
- Key Features
- How TIDE Works
- Getting Started
- Configuration
- Workflows
- Python API
- Outputs
- Advanced Usage
- For Developers
- License
- Acknowledgments
- Contact
TIDE is an open-source, SimNIBS-based pipeline for estimating an individualised TMS intensity for a tractography-defined target pathway. It combines:
- an empirical resting motor threshold (RMT) measured at motor cortex;
- subject-specific finite-element electric-field modelling;
- diffusion MRI tractography of the corticospinal tract (CST) and target pathway;
- the gradient-term activating function (AF) evaluated along streamlines.
The CST at the motor hotspot provides the calibration reference. TIDE estimates the target intensity required to reproduce the bundle-level AF efficiency observed in the CST at the measured RMT.
TIDE is designed for research on pathway-informed TMS dosing. It does not model the full nonlinear biophysics of axonal excitation, and tractography streamlines must not be interpreted as direct anatomical measurements of individual axons.
Estimate a target-specific stimulation intensity in % of maximum stimulator output using each participant's measured RMT as the empirical calibration anchor.
Sample the SimNIBS vector E-field along subject-specific streamlines and compute the gradient activating function:
AF = d(E · T) / ds
where E is the electric-field vector, T is the local streamline tangent, and s is physical arc length.
Geometry and E-field samples are jointly interpolated to a common physical support (≤ 0.5 mm spacing), smoothed using a 2.5 mm physical Gaussian scale, and differentiated along arc length. AF polarity is preserved internally; magnitude is used for activation-threshold aggregation.
Evaluate multiple candidate target positions and generate a spatial map of TIDE-estimated intensity, together with per-point reproducibility configurations and QC information.
Optionally incorporate SIFT2 streamline weights and a FreeSurfer grey-white interface surface. Weighted and unweighted results are both retained for auditability.
After a successful estimation, optionally append the final target pose to a Softaxic .stmpx template.
Generate human-readable TXT reports, structured JSON sidecars, self-contained HTML reports, tractogram/NIfTI derivatives, optional 3D visualisations, and replayable YAML configurations.
Reuse deterministic SimNIBS results for identical fixed coil poses through a content-addressed cache without caching or approximating downstream AF calculations.
At a high level, TIDE applies the same numerical core to the motor calibration pathway and the target pathway:
CST at M1 Target pathway
│ │
├─ coil pose / optimisation ├─ coil pose / optimisation
├─ SimNIBS FEM E-field ├─ SimNIBS FEM E-field
├─ vector E-field sampling ├─ vector E-field sampling
├─ AF = d(E·T)/ds ├─ AF = d(E·T)/ds
└─ bundle-level AF metric └─ bundle-level AF metric
│ │
└──────────────┬───────────────────┘
│
RMT calibration
│
▼
target intensity estimate
For each surviving streamline, TIDE identifies the AF magnitude required to sustain activation over a configured contiguous length. The primary cross-streamline summary is the median of the top 5% of the resulting per-streamline threshold distribution. Optional SIFT2 weights produce a weighted counterpart.
If M_CST and M_target are the corresponding bundle metrics, the raw target estimate is:
I_TIDE,raw = RMT × (M_CST / M_target)
TIDE also reports the Stimulation Efficiency Index:
SEI = M_target / M_CST
SEI > 1 indicates that the target pathway is more efficient than the CST under the simulated configuration; SEI < 1 indicates lower efficiency.
The raw estimate is retained in the outputs. A configurable intensity clamp is additionally reported for QC/operational use; by default it is bounded relative to RMT and by the device maximum. Clamp status is explicit (WITHIN_RANGE, CLAMPED_LOW, CLAMPED_HIGH, or DEVICE_LIMITED).
Before running TIDE you need:
- SimNIBS installed separately (the reference development environment uses SimNIBS 4.5);
- Python 3.11–3.12 for the TIDE package/launcher; the reference computational runtime is the Python bundled with SimNIBS 4.5 (Python 3.11);
- a subject-specific SimNIBS
m2m_*head model containing a single.mshhead mesh; - the subject's T1-weighted anatomical image;
- a CST tractogram for motor calibration (
.trk, loaded in RASMM space); - a target tractogram (
.trk); - the measured motor threshold in
%maximum stimulator output; - a SimNIBS-compatible TMS coil model and the device maximum
dI/dt.
Optional inputs include SIFT2 weights, a FreeSurfer surface in scanner RAS, and a Softaxic STMPX template.
Tip
Generate a fresh annotated configuration anywhere with tide --init-config config.yml. The same canonical template is also available as config_template.yml in the repository.
TIDE intentionally uses different names for different distribution layers:
| Layer | Name |
|---|---|
| Research software / GitHub repository | TIDE |
| PyPI distribution | tide-pipeline |
| Python import package | tide |
| Command-line entry point | tide |
This means that users install the distribution as tide-pipeline but run the software with the shorter tide command.
Warning
The PyPI project named tide is an unrelated package. Do not use pip install tide to install this software; use tide-pipeline.
Skip this step when installing the published package from PyPI.
git clone https://github.com/marcotag93/TIDE.git
cd TIDETIDE is distributed on PyPI as tide-pipeline. The recommended approach for normal users is to keep the initial TIDE launcher isolated from existing scientific Python environments, then explicitly bootstrap the same published release into SimNIBS. With pipx:
pipx install --python 3.11 tide-pipeline
tide --bootstrapOr with uv:
uv tool install --python 3.11 tide-pipeline
tide --bootstrapThis avoids resolving TIDE's pinned numerical dependencies directly into an existing FSL, Conda, system-Python, or other research environment. tide --bootstrap then locates the SimNIBS Python explicitly, verifies its numerics-critical versions against TIDE's pins, and installs the matching non-editable tide-pipeline release there.
A conventional interpreter-specific installation is also supported when you deliberately want TIDE in that Python:
python -m pip install tide-pipeline
python -m tide --bootstrapUsing python -m tide --bootstrap guarantees that the bootstrap is executed by the same interpreter into which tide-pipeline was just installed. The bootstrap aborts on a SimNIBS dependency mismatch unless --force is explicitly supplied.
After a successful bootstrap:
tide --helpIf more than one tide executable exists on PATH, use the SimNIBS interpreter explicitly or inspect the selected launcher with type -a tide / command -v tide.
Warning
SimNIBS is a system dependency and is intentionally not installed from PyPI by TIDE. The computational workflows must execute under the SimNIBS Python environment.
For development or direct use of a source checkout, the recommended installation path is the bundled SimNIBS-aware installer:
python install.py --simnibs-env --editableThis command is intentionally safe to launch even from another Python environment (for example FSL or a system Python): install.py uses only the standard library to locate the SimNIBS installation, selects the SimNIBS Python explicitly, verifies the numerics-critical dependency versions against TIDE's pins, installs TIDE into that environment, and checks that import tide succeeds with the same interpreter.
After installation:
tide --helpIf your shell has multiple tide launchers on PATH, the interpreter-explicit form is always unambiguous:
/path/to/SimNIBS/simnibs_env/bin/python -m tide --helpIf you already know the exact SimNIBS interpreter and have independently verified its dependency versions, you may install directly with it:
/path/to/SimNIBS/simnibs_env/bin/python -m pip install -e .A standard pip install remains supported:
python -m pip install .This installs TIDE into that exact Python interpreter. It does not automatically redirect the installation into SimNIBS. This mode is useful for development, packaging checks, or for installing a temporary launcher that will subsequently bootstrap TIDE into SimNIBS. For normal source-based pipeline use, prefer python install.py --simnibs-env --editable.
If you deliberately use the current-environment route, verify it before invoking a console script:
python -c "import tide; print(tide.__version__, tide.__file__)"
python -m tide --helpImportant
Prefer python -m pip over a bare pip command. A bare pip, python, and tide can each resolve to different environments on neuroimaging workstations that expose FSL, SimNIBS, Conda, system Python, or user-local executables on the same PATH.
If the tide executable exists but immediately fails with ModuleNotFoundError, the most common cause is that the console script and the installed package come from different Python environments, or that the executable is stale from an older/failed installation. Diagnose the active command first:
type -a python python3 pip tide
pip --version
head -n 1 "$(command -v tide)"
python -m pip show tide-pipeline
python -c "import sys, site; print(sys.executable); print(site.getusersitepackages())"For a source checkout, the most reliable repair is to install directly with the SimNIBS interpreter and then invoke the command from the same environment:
/path/to/SimNIBS/simnibs_env/bin/python -m pip install -e .
/path/to/SimNIBS/simnibs_env/bin/python -c "import tide; print(tide.__version__, tide.__file__)"
/path/to/SimNIBS/simnibs_env/bin/python -m tide --help
/path/to/SimNIBS/simnibs_env/bin/tide --helpIf command -v tide still resolves to an older ~/.local/bin/tide, but the interpreter-explicit python -m tide --help command works, the installation itself is healthy and the problem is only command resolution. Refresh Bash's command cache (hash -r), remove/uninstall the stale launcher from the Python environment that created it, or place the intended environment's bin directory before ~/.local/bin on PATH. Do not copy a launcher manually between Python environments: console scripts are tied to the interpreter that generated them.
Generate the complete annotated template from any installation:
tide --init-config config.ymlIf no output path is supplied, TIDE writes ./config.yml:
tide --init-configFor safety, --init-config never overwrites an existing file. Replace every /path/to/... placeholder with an absolute path and edit the subject, coil, calibration, and target sections for your experiment.
tide --config config.yml --workflow estimationA successful CLI run exits with status 0 and prints PIPELINE COMPLETE only after the required workflow outputs have been written.
TIDE uses a YAML configuration file. Run tide --init-config config.yml to materialize the complete annotated reference from the installed package; the same canonical file is available as config_template.yml. The example below shows only the core fields required to understand a standard estimation run.
subject:
id: "sub-001"
derivatives_path: /absolute/path/to/derivatives/sub-001
m2m_path: /absolute/path/to/m2m_sub-001
files:
t1w: /absolute/path/to/sub-001_T1w.nii.gz
# weights_cst: /absolute/path/to/CST_weights.txt
# weights_target: /absolute/path/to/target_weights.txt
# surface: /absolute/path/to/lh.white.scanner.white
workflow: estimation
coil:
coil_model: "MagVenture_C-B60.ccd"
coil_path: "" # empty = auto-detect SimNIBS coil directory
coil_distance_mm: 4.0
device_didt_max: 161e6 # A/s; set this for your stimulator/coil
options:
roi_size_mm: 20.0
activation_length_mm: 6.0
field_mode: "af" # required for estimation and grid workflows
gwi_threshold_mm: 3.0
adm_optimization: true
mso_floor_ratio: 0.70
mso_ceiling_ratio: 1.40
generate_visualizations: true
generate_3d_visualization: false
experiment:
calibration:
label: "M1"
bundle_path: /absolute/path/to/CST_left.trk
coords: [-13.28, -26.71, 63.0]
scalp_coords: [-13.28, -26.71, 85.0]
orientation: "C3" # or [x, y, z] or a rigid 4x4 matsimnibs matrix
measured_rmt_mso: 38.0
target:
label: "TARGET"
bundle_path: /absolute/path/to/target_bundle.trk
coords: [-40.0, 35.0, 30.0]
scalp_coords: [-60.0, 35.0, 30.0]
orientation: "F3" # or [x, y, z] or a rigid 4x4 matrix
cortical_medoid: falseFor calibration and target sites, orientation accepts:
- Rigid 4×4
matsimnibsmatrix — used directly; optimisation is skipped. - Three-coordinate vector
[x, y, z]— used as the SimNIBSpos_ydirreference. - EEG 10–20 label such as
"F3"or"F8".
For --workflow grid, the target orientation must be a vector or EEG label, not a 4×4 matrix, because each grid point is independently optimised from the supplied seed.
field_mode: "af"is required forestimationandgrid.- Use absolute paths wherever possible.
- Tractograms are loaded in RASMM space using the T1w image as anatomical reference.
- A configured weight or surface file is treated as an explicit input: invalid/missing files fail rather than silently falling back.
- The final coil pose is checked for geometric QC before dose estimation.
- A saved estimation configuration contains the resolved final matrices and can be replayed without re-running optimisation.
| Workflow | Command | Purpose |
|---|---|---|
| Estimation | tide --config config.yml --workflow estimation |
Full CST-calibrated TIDE intensity estimation for one target. |
| Grid search | tide --config config.yml --workflow grid |
Evaluate a set of candidate target positions and produce a spatial intensity map. |
| Simulation | tide --config config.yml --workflow simulation |
Run a standard TMS E-field simulation; can map AF ore_parallel along a target bundle. |
| Optimization | tide --config config.yml --workflow optimization |
Run coil-position optimisation only. |
tide --config config.yml --workflow estimationThe estimation workflow processes M1/CST and target branches in parallel where possible, then combines their bundle metrics to produce weighted and unweighted intensity estimates, SEI, QC fields, and a reproducibility configuration.
Add a nested grid block under experiment.target:
experiment:
target:
label: "TARGET"
bundle_path: /absolute/path/to/target_bundle.trk
coords: [-40.0, 35.0, 30.0]
scalp_coords: [-60.0, 35.0, 30.0]
orientation: "F3"
grid:
search_radius_mm: 20.0
step_size_mm: 4.0
cortex_depth_mm: 2.0Then run:
tide --config config.yml --workflow gridEach successful grid point receives its own replayable estimation configuration containing the resolved coordinates, scalp position, and final 4×4 target pose.
tide --config config.yml --workflow simulationUse this workflow when you need a conventional simulation or bundle field mapping without forming the CST-to-target dose ratio. field_mode: "e_parallel" is supported here.
tide --config config.yml --workflow optimizationThis workflow returns the optimised coil pose without running the full TIDE dose-estimation pipeline.
The tide package can also be used programmatically. For most applications, the recommended API is to load the same YAML configuration used by the CLI and call a workflow entry point directly.
from tide.utils.config import SimNIBSConfig
from tide.workflows.estimation import run_estimation_workflow
config = SimNIBSConfig.from_yaml("config.yml")
run_estimation_workflow(config, console_ui=False)The main workflow entry points are:
from tide.workflows.estimation import run_estimation_workflow
from tide.workflows.grid_search import run_grid_search_workflow
from tide.workflows.standard import run_standard_optimization, run_standard_simulationEach accepts a SimNIBSConfig loaded with SimNIBSConfig.from_yaml(...). For library use, you can explicitly call validate_workflow_config(config, workflow) before dispatching a workflow; the estimation, grid-search, and simulation entry points also perform their own workflow validation.
For applications that need progress reporting during a grid search, run_grid_search_workflow() accepts a callback:
from tide.utils.config import SimNIBSConfig
from tide.workflows.grid_search import run_grid_search_workflow
config = SimNIBSConfig.from_yaml("config.yml")
def on_progress(completed: int, total: int, label: str) -> None:
print(f"{completed}/{total}: {label}")
run_grid_search_workflow(
config,
progress_callback=on_progress,
console_ui=False,
)Advanced users can access the numerical building blocks directly. Two useful entry points are:
from tide.core.physics import calculate_scalar_map
from tide.interfaces.unified_estimation import run_unified_estimationcalculate_scalar_map(...)computes signed activating-function orE_parallelvalues along streamlines.run_unified_estimation(...)performs CST-to-target intensity estimation from already generated AF tractograms, with optional SIFT2 weights and grey-white-interface surface constraints.
Note
The workflow API is the preferred programmatic interface because it applies TIDE's configuration preflight, SimNIBS orchestration, output handling, and workflow-level safety checks. Lower-level functions are intended for custom analyses by users who understand their input and unit contracts.
A typical estimation run writes:
<derivatives_path>/TIDE_<target>/
├── TIDE_Results_<target>.txt
├── TIDE_Results_<target>.json
├── TIDE_Results_<target>.html
├── config_estimation_*.yml
├── sim_m1/
│ ├── CST_M1_af.trk
│ └── CST_M1_af.nii.gz # when visualisation is enabled
├── sim_target/
│ ├── <target>_af.trk
│ └── <target>_af.nii.gz # when visualisation is enabled
└── visualizations/ # optional figures / interactive renders
The report includes, among other fields:
- raw and clamped weighted/unweighted intensity estimates;
- clamp/QC status;
- CST and target bundle AF metrics;
- weighted and unweighted SEI;
- intensity multipliers;
- coil matrices and pose QC;
- alignment/depth diagnostics;
- aggregator-sensitivity diagnostics; and
- provenance/configuration information.
A grid run additionally produces:
<derivatives_path>/TIDE_grid_search_<...>/
├── TIDE_grid_results.csv
├── TIDE_Grid_Summary_<target>.txt
├── TIDE_Grid_Summary_<target>.json
├── TIDE_Grid_Summary_<target>.html
├── calibration_m1/
├── simulations/
│ ├── grid_P01/
│ ├── grid_P02/
│ └── ...
├── QC/
└── visualization/
├── grid_mso_raw_map.nii.gz
├── grid_mso_map.nii.gz
├── grid_mso_flag_map.nii.gz
└── grid_interactive.html # when 3D visualisation is enabled
Historical machine-readable names containing mso are intentionally retained for backwards compatibility even though human-facing reports use intensity notation.
Provide one weight per original streamline:
subject:
files:
weights_cst: /absolute/path/to/CST_weights.txt
weights_target: /absolute/path/to/target_weights.txtTIDE tracks original streamline identities through filtering/dropping so surviving streamlines remain aligned with their corresponding weights.
Provide a FreeSurfer surface in scanner RAS:
subject:
files:
surface: /absolute/path/to/lh.white.scanner.white
options:
gwi_threshold_mm: 3.0The surface constraint is applied only when the surface is explicitly configured.
After a successful estimation:
tide --config config.yml --workflow estimation --stmpx /path/to/session.stmpxTIDE validates the template before the workflow starts and writes:
/path/to/session_updated.stmpx
The STMPX file is an output template, not a source of simulation pose parameters. The YAML configuration remains authoritative for the SimNIBS input pose.
TIDE caches deterministic SimNIBS artifacts for exact 4×4 fixed poses. The default cache root is:
$XDG_CACHE_HOME/tide/fixed_pose
or, when XDG_CACHE_HOME is not set:
~/.cache/tide/fixed_pose
Useful commands:
tide --cache-info
tide --cache-clear
tide --config config.yml --workflow estimation --no-cacheConfiguration equivalents:
subject:
cache_dir: /absolute/path/to/tide_cache # relocate
cache_max_size_gb: 100 # optional LRU cap; 0/omitted = unlimitedSet cache_dir: no to disable the fixed-pose cache from YAML.
# Standard output
tide --config config.yml --workflow estimation --verbosity standard
# More detail
tide --config config.yml --workflow estimation --verbosity verbose
# Minimal output
tide --config config.yml --workflow estimation --verbosity quiet
# Disable the rich grid console UI
tide --config config.yml --workflow grid --no-console-ui3D rendering is an optional dependency:
python -m pip install ".[viz]"Enable it in YAML:
options:
generate_3d_visualization: trueTIDE/
├── main.py # source-checkout CLI shim
├── config_template.yml # canonical annotated configuration template
├── install.py # installation convenience wrapper
├── pyproject.toml # package metadata and pinned direct dependencies
├── uv.lock # frozen development/reproduction environment
├── src/tide/
│ ├── cli.py # `tide` console entry point + --init-config
│ ├── core/ # AF, geometry, tractography, scientific I/O
│ ├── interfaces/ # SimNIBS, sampling, estimation, visualisation, STMPX
│ ├── workflows/ # estimation, grid, simulation, optimisation
│ ├── console/ # rich terminal UI / worker reporting
│ └── utils/ # config, logging, cache, SimNIBS discovery
├── tests/ # pytest suite
└── .github/workflows/ # CI and release automation
python -m pip install -e ".[dev]"Run the checks used by CI:
black --check --diff .
isort --check-only --diff .
flake8 . --select=E9,F63,F7,F82 --show-source --statistics
mypy src/tide
pytest tests/ --cov=tide --cov-branch --cov-fail-under=45SimNIBS-dependent end-to-end runs should be executed in a separate scratch output directory and must never overwrite reference derivatives.
The build backend is pinned to Hatchling 1.27.0 in pyproject.toml, matching TIDE's reproducibility-oriented policy of pinning the software versions that define its tested packaging and numerical environment.
pip install tide-pipeline resolves the direct dependency pins declared in pyproject.toml; it does not consume uv.lock. To reproduce the complete tested development environment from a checkout, use:
uv sync --locked --extra devEach GitHub Release also carries the exact uv.lock used for that release, the wheel and source distribution, and SHA256SUMS. SimNIBS remains a separately installed system dependency; the reference computational runtime is SimNIBS 4.5 with Python 3.11.
TIDE is released under the GNU General Public License v3.0 or later (GPL-3.0-or-later). See LICENSE for the full license text.
TIDE builds on open scientific software, including:
- SimNIBS for finite-element TMS modelling and coil optimisation;
- DIPY for tractography I/O and geometric processing;
- NiBabel for neuroimaging I/O;
- SciPy and NumPy for numerical computing; and
- PyVista / VTK for optional 3D visualisation.
For scientific or software questions, bug reports, or feature requests, please use the repository's GitHub Issues page or contact:
- Academic email: marco.tagliaferri@unitn.it
- Permanent email: marco.tagliaferri93@gmail.com
Made with ❤️ for the TMS research community
