montage_sources
tit.sim.montage_sources ¶
Resolve non-montage_list.json montage sources into Montage objects.
Extracted from the former PyQt SimulatorTab (as of the v3 audit): the pure logic that turns a flex-search run
selection, or a freehand stim_configs/*.json file, into a concrete
:class:~tit.sim.config.Montage -- the same shape a plain
montage_list.json entry produces via :func:tit.sim.utils.load_montages.
Nothing here touches Qt; every function takes a :class:~tit.paths.PathManager
and plain values instead of reading widget state, so it is reusable from
:mod:tit.server.routes.plan, notebooks, and future non-Qt UIs alike.
Two sources, two resolvers¶
- Flex-search (:func:
resolve_flex_montage): a run underflex-search/<subject>/<run_name>/has anelectrode_positions.jsonwith the optimizer's raw XYZ output.electrode_type="optimized"uses those coordinates directly (Montage.Mode.FLEX_FREE);electrode_type="mapped"maps them onto the nearest electrodes of a named EEG net via the Hungarian algorithm (:func:tit.tools.map_electrodes.map_electrodes_to_net) and uses the resulting labels (Montage.Mode.FLEX_MAPPED), caching the mapping alongside the run. - Freehand (:func:
resolve_freehand_montage): am2m_{subject}/stim_configs/<name>.jsonfile holds anelectrode_positionsdict keyed by electrode role ("E1+","E1-","E2+","E2-", ...). Only the first four coordinates are used, in["E1+", "E1-", "E2+", "E2-"]order when those keys are present, else sorted-key order for whatever remains -- this is the original GUI's behavior verbatim, not a new convention. mTI (>4 electrodes) freehand configs are not resolvable by this function today; see its docstring.
See Also¶
tit.tools.map_electrodes : Hungarian-algorithm electrode-to-net mapping.
tit.sim.utils.load_montages : Resolves plain montage_list.json entries.
tit.sim.config.Montage : The dataclass every resolver here returns.
short_flex_run_id ¶
Build a stable short id from the subject and flex-search run folder.
Mirrors SimulatorTab._short_flex_run_id -- used only as a display
disambiguator (folder names are not unique across subjects), never as a
lookup key on disk.
Source code in tit/sim/montage_sources.py
flex_montage_name ¶
Build a filesystem-safe unique simulation name for a flex-search run.
Mirrors SimulatorTab._build_flex_montage_name exactly (same
sanitisation and length cap), so simulation output directories named
from a flex-search source stay stable across the PyQt and v3 GUIs.
Source code in tit/sim/montage_sources.py
list_flex_run_options ¶
List resolvable flex-search montage sources for a subject.
Returns one entry per (run, electrode_type) combination that
:func:resolve_flex_montage can turn into a Montage -- every run
has a "mapped" option; a run also gets an "optimized" option
when its electrode_positions.json carries optimized_positions.
Returns¶
list of dict
Each dict has run_name, electrode_type
("mapped"/"optimized"), and run_id (see
:func:short_flex_run_id).
Source code in tit/sim/montage_sources.py
resolve_flex_montage ¶
resolve_flex_montage(pm: PathManager, subject_id: str, run_name: str, electrode_type: str, *, eeg_net: str | None = None, run_id: str | None = None, display_name: str | None = None) -> Montage
Resolve one flex-search run selection into a concrete Montage.
Parameters¶
pm : PathManager
Project path resolver.
subject_id : str
Subject identifier (no sub- prefix).
run_name : str
Flex-search run folder name under flex-search/{subject_id}/.
electrode_type : str
"mapped" (map optimized positions onto eeg_net's nearest
electrodes) or "optimized" (use the raw optimizer XYZ output
directly, no net needed).
eeg_net : str or None, optional
EEG net CSV filename (e.g. "GSN-HydroCel-185.csv"). Required
when electrode_type is "mapped".
run_id : str or None, optional
Precomputed :func:short_flex_run_id; recomputed if omitted.
display_name : str or None, optional
User-facing label for the resulting Montage.display_name.
Defaults to "{run_name} | {run_id} | {electrode_type}".
Returns¶
Montage
mode=FLEX_MAPPED (4 named electrodes) for "mapped", or
mode=FLEX_FREE (4 XYZ coordinates) for "optimized".
Raises¶
ValueError
If electrode_type is unknown, eeg_net is missing for
"mapped", the run folder / electrode_positions.json /
EEG-net CSV cannot be found, or fewer than 4 electrodes are
available (TI requires exactly one pair per channel; only the
first 4 are used for higher electrode counts, matching
SimulatorTab's behavior).
Source code in tit/sim/montage_sources.py
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 | |
list_freehand_configs ¶
list_freehand_configs(pm: PathManager, subject_id: str) -> list[str]
List freehand stim-config names available for a subject.
Returns¶
list of str
Names from each stim_configs/*.json's "name" field (falling
back to the filename stem), sorted by filename.
Source code in tit/sim/montage_sources.py
resolve_freehand_montage ¶
resolve_freehand_montage(pm: PathManager, subject_id: str, name: str) -> Montage
Resolve one freehand stim-config name into a concrete Montage.
Only the first four coordinates from electrode_positions are
used -- ["E1+", "E1-", "E2+", "E2-"] order when present, else the
remaining keys in sorted order -- reproducing
SimulatorTab._build_montage_configs_from_freehand exactly. A
freehand config's "type" field (if any) is not consulted: this
matches today's GUI behavior (2-pair TI only) rather than a documented
contract, and an mTI (>4-electrode) freehand config cannot be resolved
to a usable Montage by this function -- see the module docstring.
Raises¶
ValueError
If the subject has no m2m/stim_configs directory, no config
named name exists, or it has fewer than 4 electrode positions.