ex
tit.opt.ex ¶
TI Exhaustive Search Module.
ExConfig
dataclass
¶
ExConfig(subject_id: str, leadfield_hdf: str, roi_name: str, electrodes: BucketElectrodes | PoolElectrodes, total_current: float = 2.0, current_step: float = 0.5, channel_limit: float | None = None, roi_radius: float = 3.0, roi_names: list[str] | None = None, roi_atlas: list[AtlasROI] | None = None, roi_coordinate_space: Literal['subject', 'mni'] = 'subject', run_name: str | None = None, n_jobs: int = -1, symmetric_bucket: bool = False, symmetry_eeg_csv: str | None = None, symmetry_pairing: str = 'within_pairs')
Full configuration for exhaustive search optimization.
Exhaustive search evaluates every valid electrode combination from a user-defined pool or bucket set, sweeping current amplitudes at discrete steps.
Attributes¶
subject_id : str
Subject identifier matching the m2m directory name.
leadfield_hdf : str
Filename of the precomputed leadfield HDF5 (e.g.
"ernie_leadfield_EEG10-10_UI_Jurak_2007.hdf5"), resolved under
the subject's leadfields/ directory
(:meth:tit.paths.PathManager.leadfields); an absolute path is
also accepted.
roi_name : str
ROI CSV filename (e.g. "target.csv") in the subject's ROIs/
directory (:meth:tit.paths.PathManager.rois). The ".csv"
suffix is appended automatically if missing. Used as the
metric-key prefix and (with the net name) the output-directory
label.
roi_names : list of str or None
Optional list of ROI CSV filenames to union into a single
target. When provided (combined mode), the spherical masks of
every listed ROI are OR-folded into one region. None
(default) keeps single-ROI behavior driven by roi_name. An
explicit empty list means "no spherical centers at all" -- useful
for a purely atlas-driven ROI (roi_atlas only). Each entry gets
the ".csv" suffix appended if missing.
roi_atlas : list of AtlasROI or None
Volumetric atlas or mask ROI(s) to union with the spherical
centers from roi_name/roi_names. None (default) keeps
the existing spherical-only behavior.
roi_coordinate_space : str
Space of the roi_name/roi_names CSV centers -- "subject"
(default) or "mni". MNI centers are transformed to subject
space with simnibs.mni2subject_coords before the search runs.
Does not affect roi_atlas, which declares its own atlas_space.
electrodes : BucketElectrodes or PoolElectrodes
Electrode specification, either a single shared pool
(:class:PoolElectrodes) or separate per-channel buckets
(:class:BucketElectrodes). A plain dict is auto-converted
in __post_init__.
total_current : float
Total injected current in mA, split across the two channels.
Default 2.0.
current_step : float
Current amplitude step size in mA for the sweep. Default 0.5.
channel_limit : float or None
Maximum current per channel in mA. None (default) means
total_current - current_step.
roi_radius : float
Spherical ROI radius in mm for the target region. Default 3.0.
run_name : str or None
Optional name for this run. Defaults to a datetime stamp. The
run name is the output directory, so a repeated name overwrites
the earlier run in place.
n_jobs : int
Worker processes evaluating candidates in parallel. -1
(default) uses the global CPU limit (Settings; 70 % of the
container's cores by default, see :func:tit.cpu.cpu_limit);
a larger explicit value is clamped to that limit; 1
evaluates in-process. Results and CSV ordering do not depend
on it.
symmetric_bucket : bool
When True in bucket mode, evaluate only left/right mirrored
montages (see :func:tit.opt.ex.buckets.build_electrode_mirror_map).
symmetry_eeg_csv : str or None
EEG-position CSV used to derive mirrored electrode pairs. If
unset, it is inferred from the leadfield's net name.
symmetry_pairing : str
Symmetry interpretation when symmetric_bucket is True.
"within_pairs": each pair's minus electrode is the mirror of
its plus electrode (e.g. F7-F8). "cross_pairs": pair 2 is the
mirror image of pair 1 (e2+ = mirror(e1+), e2- = mirror(e1-)).
Raises¶
ValueError
If current_step, total_current, or channel_limit are
non-positive, if symmetric_bucket is set with pool electrodes,
if symmetry_pairing is not "within_pairs"/"cross_pairs",
or if roi_coordinate_space is not "subject" or "mni".
Examples¶
from tit.opt import ExConfig cfg = ExConfig( ... subject_id="ernie", ... leadfield_hdf="ernie_leadfield_EEG10-10_UI_Jurak_2007.hdf5", ... roi_name="L-Insula", # ".csv" is appended ... electrodes=ExConfig.PoolElectrodes( ... electrodes=["Fp1", "Fp2", "C3", "C4", "Cz", "Pz", "T7", "T8"]), ... total_current=2.0, current_step=0.5, channel_limit=1.2, ... roi_coordinate_space="mni", ... ) cfg.roi_name 'L-Insula.csv'
Per-channel buckets instead of one pool:
ExConfig.BucketElectrodes(e1_plus=["F7"], e1_minus=["F8"], ... e2_plus=["P7"], e2_minus=["P8"]).e2_minus ['P8']
Then run_ex_search(cfg) (needs the leadfield HDF5 under the
subject's leadfield folder).
See Also¶
ExResult : Result container returned by :func:~tit.opt.ex.ex.run_ex_search.
tit.opt.ex.ex.run_ex_search : Consumes this config.
AtlasROI
dataclass
¶
AtlasROI(atlas_path: str, label: int | None = None, atlas_space: Literal['subject', 'mni'] = 'subject')
Volumetric atlas or mask ROI, unioned with the spherical center(s).
Attributes¶
atlas_path : str
Path to a volumetric atlas or mask file -- NIfTI (.nii,
.nii.gz) or FreeSurfer (.mgz), e.g. one discovered by
:class:tit.atlas.voxel.VoxelAtlasManager.
label : int or None
Integer label to select within the atlas (elements are
included where the voxel value equals label). None
treats the whole file as a binary mask (voxel value > 0).
atlas_space : str
Space of the atlas file, "subject" (default) or "mni".
MNI masks are warped to subject space before the search.
Raises¶
ValueError
If atlas_space is not "subject" or "mni".
BucketElectrodes
dataclass
¶
Separate electrode lists for each bipolar channel position.
Attributes¶
e1_plus : list of str Candidate electrodes for channel 1 anode. e1_minus : list of str Candidate electrodes for channel 1 cathode. e2_plus : list of str Candidate electrodes for channel 2 anode. e2_minus : list of str Candidate electrodes for channel 2 cathode.
ExResult
dataclass
¶
ExResult(success: bool, output_dir: str, n_combinations: int, results_csv: str | None = None, config_json: str | None = None)
Result from an exhaustive search run.
Attributes¶
success : bool
True if the search completed without error.
output_dir : str
Absolute path to the output directory.
n_combinations : int
Total number of electrode/current combinations evaluated.
results_csv : str or None
Path to the CSV file containing ranked results. None if the
run failed before writing results.
config_json : str or None
Path to the saved configuration JSON. None if the run failed
before writing config.
See Also¶
ExConfig : Configuration consumed by :func:~tit.opt.ex.ex.run_ex_search.
tit.opt.ex.ex.run_ex_search : Returns this result.
ExSearchEngine ¶
ExSearchEngine(leadfield_hdf: str, roi_file: str | tuple[str, int] | list[str | tuple[str, int]], roi_name: str, logger: Logger)
Exhaustive TI electrode search engine.
Owns the full pipeline: leadfield loading, ROI resolution, simulation loop, and ROI CRUD.
Source code in tit/opt/ex/engine.py
initialize ¶
initialize(roi_radius: float = 3.0) -> None
Load leadfield, resolve the ROI (CSV/mask/atlas), find ROI + GM elements.
Source code in tit/opt/ex/engine.py
compute_ti_fields ¶
compute_ti_fields(e1_plus: str, e1_minus: str, e2_plus: str, e2_minus: str, current_ratios: list[tuple[float, float]]) -> list[dict[str, float]]
ROI metrics of one electrode montage at every current split.
The field is linear in the injected current, so each channel's
unit-current field is gathered once and scaled per split -- the
same current * (lf[a] - lf[b]) arithmetic TI.get_field
performs, restricted to the elements the metrics read.
Source code in tit/opt/ex/engine.py
compute_ti_field ¶
compute_ti_field(e1_plus: str, e1_minus: str, current_ch1_mA: float, e2_plus: str, e2_minus: str, current_ch2_mA: float) -> dict[str, float]
Compute TI field for one montage and return ROI metrics.
Source code in tit/opt/ex/engine.py
run ¶
run(e1_plus: list[str], e1_minus: list[str], e2_plus: list[str], e2_minus: list[str], current_ratios: list[tuple[float, float]], all_combinations: bool, output_dir: str, n_jobs: int = 1, symmetry_mirror_map: dict[str, str] | None = None, symmetry_pairing: str = 'within_pairs') -> dict[str, dict[str, float]]
Run the full simulation loop. Returns {mesh_key: metrics}.
Candidates are evaluated in enumeration order, one electrode
montage (all its current splits) per task, on n_jobs forked
workers (n_jobs < 1: the job's CPU budget, see
:func:tit.opt.ex.parallel.resolve_n_jobs; 1: in-process).
A symmetry_mirror_map (bucket mode) restricts the enumeration to
left/right mirrored montages (see :mod:tit.opt.ex.symmetry).
Source code in tit/opt/ex/engine.py
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 | |
get_available_rois
staticmethod
¶
List ROI CSV files for a subject.
Source code in tit/opt/ex/engine.py
create_roi
staticmethod
¶
Create an ROI CSV from coordinates.
Source code in tit/opt/ex/engine.py
delete_roi
staticmethod
¶
Delete an ROI file and remove from roi_list.txt.
Source code in tit/opt/ex/engine.py
get_roi_coordinates
staticmethod
¶
Read ROI center coordinates from CSV.
Source code in tit/opt/ex/engine.py
run_ex_search ¶
Run an exhaustive two-pair TI search over a precomputed leadfield.
Enumerates every electrode-pair combination allowed by
config.electrodes and every current split allowed by
total_current/current_step/channel_limit, scores each
against the ROI, and writes a ranked CSV plus a config JSON to the
run directory under the subject's ex-search/ folder.
Parameters¶
config : ExConfig Fully specified search configuration (subject, leadfield file, ROI, electrode pool or buckets, current sweep).
Returns¶
ExResult
success, output_dir, n_combinations evaluated, and the
results_csv / config_json paths.
Raises¶
ValueError
If no candidate montage can be enumerated (empty pool/buckets or
an over-restrictive symmetry rule), or a referenced ROI CSV or
atlas file does not exist.
FileNotFoundError
If config.leadfield_hdf cannot be found under the subject's
leadfields/ directory.
Examples¶
from tit.opt import ExConfig, run_ex_search cfg = ExConfig( ... subject_id="ernie", ... leadfield_hdf="ernie_leadfield_EEG10-10_UI_Jurak_2007.hdf5", ... roi_name="L-Insula", ... electrodes=ExConfig.PoolElectrodes(electrodes=["Fp1", "Fp2", "C3", "C4"]), ... total_current=2.0, current_step=0.5, channel_limit=1.2, ... run_name="insula_pool", ... ) res = run_ex_search(cfg) # doctest: +SKIP res.success, res.n_combinations, res.results_csv # doctest: +SKIP (True, 18, '.../ex-search/insula_pool/final_output.csv')
See Also¶
ExConfig : Configuration dataclass for this search. ExResult : Returned container. tit.opt.mex.mex.run_m_ex_search : Four-pair (mTI) variant.