Skip to content

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.

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

Bases: Enum

Simulation type: standard two-pair TI or multi-channel mTI.

Attributes

TI : str Standard 2-pair temporal interference. MTI : str Multi-channel temporal interference (4+ pairs).

See Also

Montage.simulation_mode : Auto-detects mode from pair count.

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 electrode pair definitions for a single montage. 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 electrode pairs: 2 pairs = standard TI, 4+ pairs = 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] List of electrode pairs. Each element is a tuple of two electrode identifiers (label strings or XYZ coordinate lists). 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 electrode pairs.

Returns

SimulationMode SimulationMode.TI for 2 pairs, SimulationMode.MTI for 4 or more (even) pairs.

Raises

ValueError If the pair count is not allowed by :func:tit.constants.is_valid_pair_count -- an even count of at least 2. One pair is tACS, not TI; an odd count leaves a channel with nothing to beat against.

See Also

SimulationMode : The returned enum type.

num_pairs property

num_pairs: int

Number of electrode pairs in this montage.

Returns

int Length of :attr:electrode_pairs.

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 = 4.0, rubber_thickness: float = 2.0, map_to_surf: bool = True, map_to_vol: bool = False, map_to_mni: bool = False, map_to_fsavg: bool = True, open_in_gmsh: bool = False, tissues_in_niftis: str = 'all', aniso_maxratio: float = 10.0, aniso_maxcond: float = 2.0, output_fields: list[str] = (lambda: [FIELD_TI_MAX])(), tissue_conductivities: dict[int, float] | None = None)

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 pairs per montage is TI, four or more (even) pairs 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 electrode pair in mA, in electrode_pairs order. A TI montage reads the first two values; an mTI montage needs one value per pair (len(intensities) >= num_pairs). A single value is not broadcast -- a 4-pair 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 layer thickness in mm. Default 4.0. rubber_thickness : float Rubber (silicone) layer thickness in mm. Default 2.0. map_to_surf : bool Map results onto the cortical surface. Must stay True (default) because the TI_normal calculation requires surface overlays. map_to_vol : bool Reserved for NIfTI output (handled externally by tit.tools.mesh2nii, not by SimNIBS SESSION). Default False. map_to_mni : bool Generate MNI-space field and T1 NIfTI outputs after simulation. Default False; subject-space NIfTI outputs are always generated. map_to_fsavg : bool After each TI montage finishes, project its surface fields (TI_max, TI_normal, hf_peak, hf_sar) onto fsaverage5 for group surface analysis. Default True; set False to skip. Failures are logged and never abort the simulation. open_in_gmsh : bool Open results in Gmsh after simulation. Default False. tissues_in_niftis : str Tissue selection for NIfTI export ("all" or a comma-separated list of tissue numbers). Default "all". 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_sar". "TI_max" maps to mTI_max on disk for mTI meshes. Defaults to ["TI_max"] only -- TI_avg and the safety fields (hf_peak, hf_sar) must be opted into. 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. Consumed by tit.sim.__main__ via TISSUE_COND_<n> environment variables (the mechanism tit.sim.base.BaseSimulation._apply_tissue_conductivities already reads) -- deprecated in favor of this field, which is visible in the job's config and its manifest instead of being an invisible process-environment side channel.

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 pair that is not exactly two electrodes, if intensities is shorter than a montage needs (2 for TI, one per pair for mTI), or if tissue_conductivities contains a non-positive value. 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.map_to_surf, cfg.output_fields (True, ['TI_max', 'hf_peak'])

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.

parse_intensities

parse_intensities(s: str) -> list[float]

Parse a comma-separated intensity string into a list of floats.

A single value is duplicated to form a pair ("2.0" becomes [2.0, 2.0]). Otherwise the value count must be even so that each electrode pair receives two intensities.

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.

Source code in tit/sim/config.py
def parse_intensities(s: str) -> list[float]:
    """Parse a comma-separated intensity string into a list of floats.

    A single value is duplicated to form a pair (``"2.0"`` becomes
    ``[2.0, 2.0]``).  Otherwise the value count must be even so that
    each electrode pair receives two intensities.

    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.
    """
    v = [float(x.strip()) for x in s.split(",")]
    n = len(v)
    if n == 1:
        return [v[0], v[0]]
    if n >= 2 and n % 2 == 0:
        return v
    raise ValueError(
        f"Invalid intensity format: expected 1 or an even number of values; got {n}: {s!r}"
    )