config
tit.sim.config ¶
Configuration dataclasses for TI/mTI simulations.
Defines the primary configuration types consumed by
:func:tit.sim.run_simulation:
- :class:
SimulationConfig-- full run parameters (subject, conductivity, electrode geometry, mapping flags). - :class:
Montage-- a named electrode montage with pair definitions. - :class:
SimulationMode-- enum distinguishing TI from mTI. - :func:
parse_intensities-- helper to parse intensity strings from the CLI or GUI. - :func:
check_electrode_pairs-- the electrode rules every saved or simulated montage meets (pair shape, 2-12 pairs, each electrode its own point).SimulationConfigalso refuses two montages with one name and a zero or non-finite current on a channel a montage uses.
See Also¶
tit.sim.utils.run_simulation : Consumes SimulationConfig to drive
the simulation pipeline.
tit.sim.base.BaseSimulation : Uses SimulationConfig and Montage
at runtime.
SimulationMode ¶
MontageMode ¶
Bases: Enum
How electrode positions are specified.
NET and FLEX_MAPPED use EEG-cap label names resolved against an
EEG-net CSV. FLEX_FREE and FREEHAND use raw 3-D XYZ
coordinates (no net required).
Attributes¶
NET : str Standard EEG-cap electrode labels. FLEX_MAPPED : str Flex-search result mapped back to EEG-cap labels. FLEX_FREE : str Flex-search result with free XYZ coordinates. FREEHAND : str User-specified XYZ coordinates (manual placement).
Montage
dataclass
¶
Montage(name: str, mode: MontageMode, electrode_pairs: list[tuple[str | list[float], str | list[float]]], eeg_net: str | None = None, display_name: str | None = None, electrode_poses: list[list[list[float]]] | None = None, provenance: dict[str, str] | None = None)
A named electrode montage used in a TI/mTI simulation.
Wraps the channel definitions of a single montage: one electrode pair
per channel, channel k being electrodes Ek+ and Ek-. Electrodes
may be referenced by EEG-cap label names (NET / FLEX_MAPPED
modes) or by 3-D XYZ coordinates (FLEX_FREE / FREEHAND modes).
The simulation type is auto-detected from the number of channels: 2 channels = standard TI, 4 or more (even) = multi-channel mTI.
Attributes¶
name : str
Human-readable montage name (e.g. "M1_left").
mode : MontageMode
How electrode positions are specified. See :class:MontageMode.
electrode_pairs : list[tuple]
One entry per channel, in channel order. Each element is a tuple of
two electrode identifiers (label strings or XYZ coordinate lists),
(Ek+, Ek-).
eeg_net : str or None
Filename of the EEG-net CSV (e.g. "GSN-HydroCel-185.csv").
Required for NET and FLEX_MAPPED modes, ignored otherwise.
display_name : str or None
Optional user-facing label. name remains the storage and lookup key.
electrode_poses : list[list[list[float]]] or None
Optional full 4x4 homogeneous pose (row-major) per electrode, one
per XYZ position in electrode_pairs order. Only meaningful for
XYZ modes; preserves rectangular-electrode orientation when a
flex-search candidate is replayed. None (default) lets SimNIBS
orient the electrodes itself.
provenance : dict[str, str] or None
Free-form origin metadata (e.g. {"head_mesh_sha256": ...})
checked by :func:run_simulation when present.
Raises¶
ValueError
If electrode_poses is given for a label-based montage, does not
contain exactly one 4x4 right-handed homogeneous transform per
electrode, or its translations do not match electrode_pairs.
Examples¶
from tit.sim import Montage, MontageMode m = Montage( ... name="L_Insula", ... mode=MontageMode.NET, ... electrode_pairs=[("E010", "E011"), ("E012", "E013")], ... eeg_net="GSN-HydroCel-185.csv", ... ) m.num_pairs, m.simulation_mode.value, m.is_xyz (2, 'TI', False)
A free-hand montage uses subject-space millimetre coordinates and no net:
free = Montage( ... name="custom", ... mode=MontageMode.FREEHAND, ... electrode_pairs=[([-60.0, 10.0, 40.0], [60.0, 10.0, 40.0]), ... ([-60.0, -40.0, 40.0], [60.0, -40.0, 40.0])], ... ) free.is_xyz True
See Also¶
SimulationConfig : Holds one or more Montage instances.
load_montages : Build Montage objects from montage_list.json.
is_xyz
property
¶
is_xyz: bool
Whether electrodes are specified as 3-D XYZ coordinates.
Returns¶
bool
True for FLEX_FREE and FREEHAND modes.
simulation_mode
property
¶
simulation_mode: SimulationMode
Infer TI vs mTI from the number of channels (electrode pairs).
Returns¶
SimulationMode
SimulationMode.TI for 2 channels, SimulationMode.MTI
for 4 or more (even).
Raises¶
ValueError
If the channel count is not allowed by
:func:tit.constants.is_valid_pair_count -- an even count of at
least 2. One channel is tACS, not TI; an odd count leaves a channel
with nothing to beat against.
See Also¶
SimulationMode : The returned enum type.
SimulationConfig
dataclass
¶
SimulationConfig(subject_id: str, montages: list[Montage], conductivity: str = 'scalar', intensities: list[float] = (lambda: [1.0, 1.0])(), electrode_shape: str = 'ellipse', electrode_dimensions: list[float] = (lambda: [8.0, 8.0])(), gel_thickness: float = 1.0, rubber_thickness: float = 2.0, map_to_vol: bool = False, map_to_mni: bool = False, map_to_fsavg: bool = True, aniso_maxratio: float = 10.0, aniso_maxcond: float = 2.0, output_fields: list[str] | None = None, tissue_conductivities: dict[int, float] | None = None, carrier_only: bool = False)
Full configuration for a TI or mTI simulation run.
Passed to :func:tit.sim.run_simulation to execute one or more
montage simulations for a single subject. Electrode geometry,
conductivity model, and output mapping options are all set here.
Attributes¶
subject_id : str
Subject identifier without the sub- prefix (e.g. "ernie",
"101"); must match an existing m2m_<subject_id> directory.
montages : list[Montage]
One or more :class:Montage definitions to simulate. Two channels
(electrode pairs) is TI, four or more (even) is mTI -- detected
per montage, so a list may mix both.
conductivity : str
Tissue conductivity model. One of:
- ``"scalar"`` -- isotropic scalar conductivities (default).
- ``"vn"`` -- volume-normalized anisotropic conductivities.
- ``"dir"`` -- directly-mapped anisotropic conductivities.
- ``"mc"`` -- mean-conductivity anisotropic conductivities.
The anisotropic modes (``"vn"``, ``"dir"``, ``"mc"``) require
DTI tensors registered to the head mesh.
intensities : list[float]
Current per channel in mA, in electrode_pairs order (one value
per channel). A TI montage reads the first two values; an mTI montage
needs one value per channel (len(intensities) >= num_pairs). A
single value is not broadcast -- a 4-channel montage with the default
two values is rejected. Default [1.0, 1.0].
electrode_shape : str
Electrode shape, "ellipse" or "rect". Default
"ellipse".
electrode_dimensions : list[float]
[width, height] of each electrode in mm. Default
[8.0, 8.0].
gel_thickness : float
Conductive-gel (saline) layer thickness in mm, between the skin and
the rubber. Default 1.0.
rubber_thickness : float
Rubber (silicone) layer thickness in mm. Default 2.0.
map_to_vol : bool
Write NIfTI volumes of the field meshes (SimNIBS's own meaning of the
name; tit.tools.mesh2nii does the conversion after the run): one
3-D <mesh>_subject_<field>.nii.gz per field of each field mesh --
the brain-tissue mesh and its grey- and white-matter copies -- so the
NIfTI set is the mesh field set, name for name, plus each channel's
magnE. Default False: the field meshes are the output, and a
step that needs a NIfTI (a voxel analysis, the group tools) writes the
one it reads on demand (:mod:tit.volume_fields).
map_to_mni : bool
Also write each field NIfTI in MNI space (<mesh>_MNI_MNI_<field>.nii.gz)
and the T1 in MNI space. MNI output is itself a NIfTI, so True turns
map_to_vol on as well (subject and MNI NIfTIs). Default False.
map_to_fsavg : bool
After each TI montage finishes, project its surface fields
(TI_max, TI_normal, hf_peak, hf_rms) onto fsaverage5
for group surface analysis. Default True; set False to
skip. Failures are logged and never abort the simulation.
aniso_maxratio : float
Maximum eigenvalue ratio clamp for anisotropic conductivity
tensors. Default 10.0.
aniso_maxcond : float
Maximum absolute conductivity clamp (S/m) for anisotropic
tensors. Default 2.0.
output_fields : list[str]
Which volume-mesh fields to compute and write. Logical names from
:data:tit.constants.SELECTABLE_OUTPUT_FIELDS: "TI_max",
"TI_avg", "hf_peak", "hf_rms", "hf_power_density".
"TI_max" maps to mTI_max on disk for mTI meshes. None
(the default) is :data:tit.constants.DEFAULT_OUTPUT_FIELDS --
["TI_max", "hf_peak", "hf_rms"], the envelope and the carrier
fields an analysis's carrier metrics read -- or, for a carrier_only
run, which has no envelope, ["hf_peak", "hf_rms"]. TI_avg and
hf_power_density are opt-in; a field not saved here is computed
later, from the kept channel meshes, by the step that needs it
(hf_power_density excepted: its conductivity is not kept).
hf_power_density (W/m^3) uses the conductivity of this run's own
solve, the full tensor under the anisotropic models.
tissue_conductivities : dict[int, float] or None
Per-tissue conductivity overrides (S/m), keyed by SimNIBS tissue
number (1-based, matching tdcs.cond index + 1). None (the
default) uses SimNIBS's own tissue defaults for every tissue.
JSON object keys are always strings, so this round-trips as
{"<tissue number>": <S/m>} on disk; :func:tit.config_io.deserialize_config
coerces the keys back to int, and this dataclass's own
__post_init__ does the same for an instance built directly
with string keys. Applied to every channel's TDCS list by
tit.sim.base.BaseSimulation._apply_tissue_conductivities and
recorded in the run's config.json.
carrier_only : bool
Carrier-only control: both channels run at the same frequency, in
phase (ΔF = 0), so there is no beat. The carrier fields hf_peak,
hf_rms and hf_power_density then add the two channel fields
coherently (|E1+E2|, see :func:tit.calc.hf_peak) and no envelope
field (TI_max, TI_avg, TI_normal) is computed. Requires a
two-channel TI montage; an explicit output_fields must be drawn
from those carrier fields (the default already is). Default False.
Raises¶
ValueError
If conductivity is not one of the valid model names, if
output_fields contains an unknown name or is empty, if any
montage has a channel that is not exactly two electrodes, if
intensities is shorter than a montage needs (2 for TI, one per
channel for mTI), if tissue_conductivities contains a tissue
number outside 1..1000 or a non-positive value, if electrode_shape is not
"ellipse" or "rect" or any electrode dimension, gel_thickness
or rubber_thickness is not a finite number above 0, if carrier_only is set with an envelope
output field or a montage that is not two-channel TI. Filesystem checks (the m2m directory, the
EEG-net CSV) happen later, in :func:run_simulation.
Examples¶
from tit.sim import SimulationConfig, Montage, MontageMode montage = Montage( ... name="L_Insula", mode=MontageMode.NET, ... electrode_pairs=[("E010", "E011"), ("E012", "E013")], ... eeg_net="GSN-HydroCel-185.csv", ... ) cfg = SimulationConfig( ... subject_id="ernie", ... montages=[montage], ... conductivity="scalar", ... intensities=[1.0, 1.0], ... electrode_shape="ellipse", ... electrode_dimensions=[8.0, 8.0], ... output_fields=["TI_max", "hf_peak"], ... ) cfg.output_fields ['TI_max', 'hf_peak']
A carrier-only control of the same montage (both channels at one frequency, in phase; no envelope, so only carrier fields):
sham = SimulationConfig( ... subject_id="ernie", montages=[montage], intensities=[1.0, 1.0], ... carrier_only=True, ... ) sham.output_fields ['hf_peak', 'hf_rms']
Then run_simulation(cfg) (needs SimNIBS and the subject's m2m
directory).
See Also¶
Montage : Electrode montage contained in montages.
run_simulation : Entry point that consumes this config.
parse_intensities : Helper to build the intensities list.
check_electrode_pairs ¶
check_electrode_pairs(pairs, *, xyz: bool) -> None
Raise ValueError unless pairs is a montage SimNIBS can place.
The rules a montage's electrodes must meet wherever it is saved or run:
every pair holds exactly two electrodes; the pair count is an allowed one
(:func:tit.constants.is_valid_pair_count) and at most
:data:tit.constants.MAX_MTI_CHANNELS; every electrode is its own point -- a label is
a non-empty string used once in the montage (an electrode cannot be its own
return, and two channels cannot share one), an XYZ electrode is three
finite numbers at least :data:MIN_ELECTRODE_SEPARATION_MM from every other.
Parameters¶
pairs : sequence
The montage's electrode pairs, in channel order.
xyz : bool
True when electrodes are [x, y, z] coordinates, False for
EEG-cap labels.
Raises¶
ValueError Naming the first rule the montage breaks.
Source code in tit/sim/config.py
parse_intensities ¶
Parse a comma-separated intensity string into a list of floats.
Intensities are one current per channel (electrode pair). A single
value is used for both channels of a TI montage ("2.0" becomes
[2.0, 2.0]). Otherwise the value count must be even: two channels
for TI, four or more for mTI.
Parameters¶
s : str
Comma-separated intensity values (e.g. "1.0,2.0").
Returns¶
list[float] List of floats with an even number of elements.
Raises¶
ValueError If the number of values is odd and greater than 1.
See Also¶
SimulationConfig.intensities : Field populated by this function.