Leadfield matrix generator for TI optimization.
Integrates with SimNIBS to create leadfield matrices via
TDCSLEADFIELD. The leadfield encodes each electrode's
contribution to the electric field at every mesh element, enabling
fast objective-function evaluation during optimization without
re-running the full FEM solver.
Public API
LeadfieldGenerator
Object-oriented interface for leadfield generation, listing, and
electrode-name extraction.
See Also
tit.opt.flex.flex.run_flex_search : Uses the leadfield indirectly via SimNIBS.
tit.opt.ex.engine.ExSearchEngine : Loads the leadfield for exhaustive search.
LeadfieldGenerator
LeadfieldGenerator(subject_id: str, electrode_cap: str = 'EEG10-10', progress_callback: Callable | None = None, termination_flag: Callable[[], bool] | None = None)
Generate and list leadfield matrices for TI optimization.
Wraps SimNIBS TDCSLEADFIELD to produce HDF5 leadfield files
that the exhaustive-search and flex-search pipelines consume.
Parameters
subject_id : str
Subject identifier (e.g. "101").
electrode_cap : str
EEG cap name without .csv (e.g. "GSN-HydroCel-185").
progress_callback : callable or None
Optional callback(message, level) for GUI progress updates.
termination_flag : callable or None
Optional callable returning True when the user cancels.
See Also
tit.opt.ex.engine.ExSearchEngine : Consumes the generated leadfield.
Source code in tit/opt/leadfield.py
| def __init__(
self,
subject_id: str,
electrode_cap: str = "EEG10-10",
progress_callback: Callable | None = None,
termination_flag: Callable[[], bool] | None = None,
) -> None:
self.subject_id = subject_id
self.electrode_cap = electrode_cap
self._progress_callback = progress_callback
self._termination_flag = termination_flag
self.pm = get_path_manager()
|
generate
generate(output_dir: str | Path | None = None, tissues: list[int] | None = None, cleanup: bool = True) -> Path
Generate a leadfield matrix via SimNIBS.
Parameters
output_dir : str or Path or None
Output directory. Defaults to
pm.leadfields(subject_id).
tissues : list of int or None
Tissue tags (1 = WM, 2 = GM). Default: [1, 2].
cleanup : bool
Remove stale SimNIBS artefacts before running.
Returns
Path
Path to the generated HDF5 leadfield file.
Raises
InterruptedError
If cancelled via termination_flag.
Source code in tit/opt/leadfield.py
| def generate(
self,
output_dir: str | Path | None = None,
tissues: list[int] | None = None,
cleanup: bool = True,
) -> Path:
"""Generate a leadfield matrix via SimNIBS.
Parameters
----------
output_dir : str or Path or None
Output directory. Defaults to
``pm.leadfields(subject_id)``.
tissues : list of int or None
Tissue tags (1 = WM, 2 = GM). Default: ``[1, 2]``.
cleanup : bool
Remove stale SimNIBS artefacts before running.
Returns
-------
Path
Path to the generated HDF5 leadfield file.
Raises
------
InterruptedError
If cancelled via *termination_flag*.
"""
from simnibs import sim_struct
import simnibs
tissues = [1, 2]
m2m_dir = Path(self.pm.m2m(self.subject_id))
output_dir = Path(
output_dir or self.pm.ensure(self.pm.leadfields(self.subject_id))
)
output_dir.mkdir(parents=True, exist_ok=True)
self._cleanup(output_dir, m2m_dir)
tdcs_lf = sim_struct.TDCSLEADFIELD()
tdcs_lf.fnamehead = str(m2m_dir / f"{self.subject_id}.msh")
tdcs_lf.subpath = str(m2m_dir)
tdcs_lf.pathfem = str(output_dir)
tdcs_lf.interpolation = None
tdcs_lf.map_to_surf = False
tdcs_lf.tissues = tissues
tdcs_lf.eeg_cap = str(
Path(self.pm.eeg_positions(self.subject_id)) / f"{self.electrode_cap}.csv"
)
if self._termination_flag and self._termination_flag():
raise InterruptedError("Leadfield generation cancelled before starting")
self._log(
f"Generating leadfield for {self.subject_id} (cap={self.electrode_cap})"
)
simnibs.run_simnibs(tdcs_lf)
if self._termination_flag and self._termination_flag():
raise InterruptedError("Leadfield generation cancelled after SimNIBS")
hdf5_path = next(output_dir.glob("*.hdf5"))
self._log(f"Leadfield ready: {hdf5_path}")
return hdf5_path
|
list_leadfields
List available leadfield HDF5 files for a subject.
Parameters
subject_id : str or None
Subject ID. Defaults to self.subject_id.
Returns
list of tuple[str, str, float]
Sorted list of (net_name, hdf5_path, size_gb) tuples.
Source code in tit/opt/leadfield.py
| def list_leadfields(
self, subject_id: str | None = None
) -> list[tuple[str, str, float]]:
"""List available leadfield HDF5 files for a subject.
Parameters
----------
subject_id : str or None
Subject ID. Defaults to ``self.subject_id``.
Returns
-------
list of tuple[str, str, float]
Sorted list of ``(net_name, hdf5_path, size_gb)`` tuples.
"""
sid = subject_id or self.subject_id
leadfields_dir = Path(self.pm.leadfields(sid))
out: list[tuple[str, str, float]] = []
for item in leadfields_dir.iterdir():
if item.suffix != ".hdf5":
continue
stem = item.stem
if "_leadfield_" in stem:
net_name = stem.split("_leadfield_", 1)[-1]
elif stem.endswith("_leadfield"):
net_name = stem[: -len("_leadfield")]
else:
net_name = stem
for prefix in (f"{sid}_", sid):
if net_name.startswith(prefix):
net_name = net_name[len(prefix) :]
break
net_name = net_name.strip("_") or "unknown"
out.append((net_name, str(item), item.stat().st_size / (1024**3)))
return sorted(out)
|
get_electrode_names
get_electrode_names(cap_name: str | None = None) -> list[str]
Extract electrode labels from an EEG cap via SimNIBS.
Parameters
cap_name : str or None
EEG cap name (without .csv). Defaults to
self.electrode_cap.
Returns
list of str
Sorted list of electrode label strings.
Source code in tit/opt/leadfield.py
| def get_electrode_names(self, cap_name: str | None = None) -> list[str]:
"""Extract electrode labels from an EEG cap via SimNIBS.
Parameters
----------
cap_name : str or None
EEG cap name (without ``.csv``). Defaults to
``self.electrode_cap``.
Returns
-------
list of str
Sorted list of electrode label strings.
"""
from simnibs.utils.csv_reader import eeg_positions
cap_name = cap_name or self.electrode_cap
eeg_pos = eeg_positions(str(self.pm.m2m(self.subject_id)), cap_name=cap_name)
return sorted(eeg_pos.keys())
|