Skip to content

paths

tit.paths

BIDS-compliant path management for TI-Toolbox.

Provides a singleton :class:PathManager that resolves all file and directory paths within a BIDS-structured TI-Toolbox project. Paths cover subject anatomical data, SimNIBS derivatives, FreeSurfer outputs, analysis results, and optimization runs.

Public API

PathManager Central path resolver — instantiated as a singleton via :func:get_path_manager. get_path_manager Return (and optionally initialise) the global PathManager singleton. reset_path_manager Destroy the singleton so the next call creates a fresh instance.

Examples

from tit.paths import get_path_manager pm = get_path_manager("/data/project") pm.list_simnibs_subjects() ['001', '002'] pm.m2m("001") '/data/project/derivatives/SimNIBS/sub-001/m2m_001'

See Also

tit.constants : Project-wide constants used for directory/file names.

PathManager

PathManager(project_dir: str | None = None)

BIDS-compliant path resolution for TI-Toolbox projects.

Provides methods to resolve file and directory paths within a BIDS-structured project, including subject anatomical data, SimNIBS derivatives, FreeSurfer outputs, optimization runs, and analysis results.

The project directory can be set explicitly or auto-detected from the PROJECT_DIR / PROJECT_DIR_NAME environment variables (useful inside Docker containers).

Parameters

project_dir : str or None, optional Root directory of the BIDS project. If None, the directory is auto-detected from environment variables on first access.

Attributes

project_dir : str or None Resolved project root, or None if not yet set / detected. project_dir_name : str or None Basename of :attr:project_dir.

See Also

get_path_manager : Obtain the global singleton instance. reset_path_manager : Destroy the singleton for testing or re-init.

Source code in tit/paths.py
def __init__(self, project_dir: str | None = None):
    self._project_dir: str | None = None
    if project_dir:
        self.project_dir = project_dir

project_dir property writable

project_dir: str | None

Project root directory, auto-detected from environment if unset.

project_dir_name property

project_dir_name: str | None

Basename of :attr:project_dir, or the PROJECT_DIR_NAME env var.

derivatives

derivatives() -> str

Path to <project>/derivatives/.

Source code in tit/paths.py
def derivatives(self) -> str:
    """Path to ``<project>/derivatives/``."""
    return os.path.join(self._root(), "derivatives")

sourcedata

sourcedata() -> str

Path to <project>/sourcedata/.

Source code in tit/paths.py
def sourcedata(self) -> str:
    """Path to ``<project>/sourcedata/``."""
    return os.path.join(self._root(), "sourcedata")

simnibs

simnibs() -> str

Path to <project>/derivatives/SimNIBS/.

Source code in tit/paths.py
def simnibs(self) -> str:
    """Path to ``<project>/derivatives/SimNIBS/``."""
    return os.path.join(self._root(), "derivatives", "SimNIBS")

freesurfer

freesurfer() -> str

Path to <project>/derivatives/freesurfer/.

Source code in tit/paths.py
def freesurfer(self) -> str:
    """Path to ``<project>/derivatives/freesurfer/``."""
    return os.path.join(self._root(), "derivatives", "freesurfer")

ti_toolbox

ti_toolbox() -> str

Path to <project>/derivatives/ti-toolbox/.

Source code in tit/paths.py
def ti_toolbox(self) -> str:
    """Path to ``<project>/derivatives/ti-toolbox/``."""
    return os.path.join(self._root(), "derivatives", "ti-toolbox")

config_dir

config_dir() -> str

Path to <project>/code/ti-toolbox/config/.

Source code in tit/paths.py
def config_dir(self) -> str:
    """Path to ``<project>/code/ti-toolbox/config/``."""
    return os.path.join(self._root(), "code", "ti-toolbox", "config")

montage_config

montage_config() -> str

Path to the montage_list.json configuration file.

Source code in tit/paths.py
def montage_config(self) -> str:
    """Path to the ``montage_list.json`` configuration file."""
    return os.path.join(self.config_dir(), "montage_list.json")

project_status

project_status() -> str

Path to the project_status.json file.

Source code in tit/paths.py
def project_status(self) -> str:
    """Path to the ``project_status.json`` file."""
    return os.path.join(self.config_dir(), "project_status.json")

extensions_config

extensions_config() -> str

Path to the extensions.json configuration file.

Uses the user-level config directory so that extension preferences persist across projects and container restarts.

Source code in tit/paths.py
def extensions_config(self) -> str:
    """Path to the ``extensions.json`` configuration file.

    Uses the user-level config directory so that extension
    preferences persist across projects and container restarts.
    """
    return os.path.join(self.user_config_dir(), "extensions.json")

user_config_dir staticmethod

user_config_dir() -> str

Path to the user-level config directory.

Returns the directory that persists across projects and container restarts. Inside Docker this is /root/.config/ti-toolbox (mounted from the host by the Electron launcher). Outside Docker the platform-native config directory is used:

  • macOS: ~/.config/ti-toolbox
  • Linux: $XDG_CONFIG_HOME/ti-toolbox (default ~/.config)
  • Windows: %APPDATA%/ti-toolbox

The directory is created if it does not exist.

Returns

str Absolute path to the user config directory.

Source code in tit/paths.py
@staticmethod
def user_config_dir() -> str:
    """Path to the user-level config directory.

    Returns the directory that persists across projects and container
    restarts.  Inside Docker this is ``/root/.config/ti-toolbox``
    (mounted from the host by the Electron launcher).  Outside Docker
    the platform-native config directory is used:

    - **macOS**: ``~/.config/ti-toolbox``
    - **Linux**: ``$XDG_CONFIG_HOME/ti-toolbox`` (default ``~/.config``)
    - **Windows**: ``%APPDATA%/ti-toolbox``

    The directory is created if it does not exist.

    Returns
    -------
    str
        Absolute path to the user config directory.
    """
    import platform as _platform
    import sys as _sys

    # Inside Docker the Electron launcher mounts the host config here.
    docker_path = os.path.join("/root", ".config", "ti-toolbox")
    if os.path.isdir(docker_path):
        return docker_path

    # Outside Docker: platform-native paths
    system = _platform.system()
    if system == "Darwin":
        # Use ~/.config (NOT ~/Library/Application Support which is
        # Electron's userData dir).  Matches env.js getUserConfigDir().
        base = os.path.join(os.path.expanduser("~"), ".config")
    elif system == "Windows":
        base = os.environ.get(
            "APPDATA", os.path.join(os.path.expanduser("~"), "AppData", "Roaming")
        )
    else:  # Linux / other
        base = os.environ.get(
            "XDG_CONFIG_HOME", os.path.join(os.path.expanduser("~"), ".config")
        )

    config_dir = os.path.join(base, "ti-toolbox")
    os.makedirs(config_dir, exist_ok=True)
    return config_dir

reports

reports() -> str

Path to <project>/derivatives/ti-toolbox/reports/.

Source code in tit/paths.py
def reports(self) -> str:
    """Path to ``<project>/derivatives/ti-toolbox/reports/``."""
    return os.path.join(self.ti_toolbox(), "reports")

stats_data

stats_data() -> str

Path to <project>/derivatives/ti-toolbox/stats/data/.

Source code in tit/paths.py
def stats_data(self) -> str:
    """Path to ``<project>/derivatives/ti-toolbox/stats/data/``."""
    return os.path.join(self.ti_toolbox(), "stats", "data")

stats_output

stats_output(analysis_type: str, analysis_name: str) -> str

Path to a specific statistics output directory.

Parameters

analysis_type : str Type of statistical analysis (e.g., "permutation"). analysis_name : str Name of the analysis run.

Returns

str Absolute path to the output directory.

Source code in tit/paths.py
def stats_output(self, analysis_type: str, analysis_name: str) -> str:
    """Path to a specific statistics output directory.

    Parameters
    ----------
    analysis_type : str
        Type of statistical analysis (e.g., ``"permutation"``).
    analysis_name : str
        Name of the analysis run.

    Returns
    -------
    str
        Absolute path to the output directory.
    """
    return os.path.join(self.ti_toolbox(), "stats", analysis_type, analysis_name)

logs_group

logs_group() -> str

Path to group-analysis log directory.

Source code in tit/paths.py
def logs_group(self) -> str:
    """Path to group-analysis log directory."""
    return os.path.join(self.ti_toolbox(), "logs", "group_analysis")

qsiprep

qsiprep() -> str

Path to <project>/derivatives/qsiprep/.

Source code in tit/paths.py
def qsiprep(self) -> str:
    """Path to ``<project>/derivatives/qsiprep/``."""
    return os.path.join(self._root(), "derivatives", "qsiprep")

qsirecon

qsirecon() -> str

Path to <project>/derivatives/qsirecon/.

Source code in tit/paths.py
def qsirecon(self) -> str:
    """Path to ``<project>/derivatives/qsirecon/``."""
    return os.path.join(self._root(), "derivatives", "qsirecon")

sub

sub(sid: str) -> str

Path to derivatives/SimNIBS/sub-{sid}/.

Parameters

sid : str Subject identifier (without sub- prefix).

Returns

str Absolute path to the subject's SimNIBS directory.

Source code in tit/paths.py
def sub(self, sid: str) -> str:
    """Path to ``derivatives/SimNIBS/sub-{sid}/``.

    Parameters
    ----------
    sid : str
        Subject identifier (without ``sub-`` prefix).

    Returns
    -------
    str
        Absolute path to the subject's SimNIBS directory.
    """
    return os.path.join(self._root(), "derivatives", "SimNIBS", f"sub-{sid}")

m2m

m2m(sid: str) -> str

Path to the m2m_{sid} head-model directory for sid.

Source code in tit/paths.py
def m2m(self, sid: str) -> str:
    """Path to the ``m2m_{sid}`` head-model directory for *sid*."""
    return os.path.join(self.sub(sid), f"m2m_{sid}")

eeg_positions

eeg_positions(sid: str) -> str

Path to the EEG electrode-position directory for sid.

Source code in tit/paths.py
def eeg_positions(self, sid: str) -> str:
    """Path to the EEG electrode-position directory for *sid*."""
    return os.path.join(self.m2m(sid), "eeg_positions")

rois

rois(sid: str) -> str

Path to the ROI directory for sid.

Source code in tit/paths.py
def rois(self, sid: str) -> str:
    """Path to the ROI directory for *sid*."""
    return os.path.join(self.m2m(sid), "ROIs")

t1

t1(sid: str) -> str

Path to the T1-weighted NIfTI image for sid.

Source code in tit/paths.py
def t1(self, sid: str) -> str:
    """Path to the T1-weighted NIfTI image for *sid*."""
    return os.path.join(self.m2m(sid), "T1.nii.gz")

segmentation

segmentation(sid: str) -> str

Path to the segmentation directory for sid.

Source code in tit/paths.py
def segmentation(self, sid: str) -> str:
    """Path to the segmentation directory for *sid*."""
    return os.path.join(self.m2m(sid), "segmentation")

tissue_labeling

tissue_labeling(sid: str) -> str

Path to the tissue labeling NIfTI for sid.

Source code in tit/paths.py
def tissue_labeling(self, sid: str) -> str:
    """Path to the tissue labeling NIfTI for *sid*."""
    return os.path.join(self.segmentation(sid), "labeling.nii.gz")

leadfields

leadfields(sid: str) -> str

Path to the leadfields directory for sid.

Source code in tit/paths.py
def leadfields(self, sid: str) -> str:
    """Path to the leadfields directory for *sid*."""
    return os.path.join(self.sub(sid), "leadfields")

simulations

simulations(sid: str) -> str

Path to Simulations/ for sid.

Source code in tit/paths.py
def simulations(self, sid: str) -> str:
    """Path to ``Simulations/`` for *sid*."""
    return os.path.join(self.sub(sid), "Simulations")

logs

logs(sid: str) -> str

Path to per-subject log directory for sid.

Source code in tit/paths.py
def logs(self, sid: str) -> str:
    """Path to per-subject log directory for *sid*."""
    return os.path.join(self.ti_toolbox(), "logs", f"sub-{sid}")

tissue_analysis_output

tissue_analysis_output(sid: str) -> str

Path to tissue-analysis output directory for sid.

Source code in tit/paths.py
def tissue_analysis_output(self, sid: str) -> str:
    """Path to tissue-analysis output directory for *sid*."""
    return os.path.join(self.ti_toolbox(), "tissue_analysis", f"sub-{sid}")

bids_subject

bids_subject(sid: str) -> str

Path to <project>/sub-{sid}/ (raw BIDS subject root).

Source code in tit/paths.py
def bids_subject(self, sid: str) -> str:
    """Path to ``<project>/sub-{sid}/`` (raw BIDS subject root)."""
    return os.path.join(self._root(), f"sub-{sid}")

bids_anat

bids_anat(sid: str) -> str

Path to <project>/sub-{sid}/anat/.

Source code in tit/paths.py
def bids_anat(self, sid: str) -> str:
    """Path to ``<project>/sub-{sid}/anat/``."""
    return os.path.join(self.bids_subject(sid), "anat")

bids_dwi

bids_dwi(sid: str) -> str

Path to <project>/sub-{sid}/dwi/.

Source code in tit/paths.py
def bids_dwi(self, sid: str) -> str:
    """Path to ``<project>/sub-{sid}/dwi/``."""
    return os.path.join(self.bids_subject(sid), "dwi")

sourcedata_subject

sourcedata_subject(sid: str) -> str

Path to sourcedata/sub-{sid}/.

Source code in tit/paths.py
def sourcedata_subject(self, sid: str) -> str:
    """Path to ``sourcedata/sub-{sid}/``."""
    return os.path.join(self.sourcedata(), f"sub-{sid}")

freesurfer_subject

freesurfer_subject(sid: str) -> str

Path to derivatives/freesurfer/sub-{sid}/.

Source code in tit/paths.py
def freesurfer_subject(self, sid: str) -> str:
    """Path to ``derivatives/freesurfer/sub-{sid}/``."""
    return os.path.join(self.freesurfer(), f"sub-{sid}")

freesurfer_mri

freesurfer_mri(sid: str) -> str

Path to derivatives/freesurfer/sub-{sid}/mri/.

Source code in tit/paths.py
def freesurfer_mri(self, sid: str) -> str:
    """Path to ``derivatives/freesurfer/sub-{sid}/mri/``."""
    return os.path.join(self.freesurfer_subject(sid), "mri")

qsiprep_subject

qsiprep_subject(sid: str) -> str

Path to derivatives/qsiprep/sub-{sid}/.

Source code in tit/paths.py
def qsiprep_subject(self, sid: str) -> str:
    """Path to ``derivatives/qsiprep/sub-{sid}/``."""
    return os.path.join(self.qsiprep(), f"sub-{sid}")

qsirecon_subject

qsirecon_subject(sid: str) -> str

Path to derivatives/qsirecon/sub-{sid}/.

Source code in tit/paths.py
def qsirecon_subject(self, sid: str) -> str:
    """Path to ``derivatives/qsirecon/sub-{sid}/``."""
    return os.path.join(self.qsirecon(), f"sub-{sid}")
ex_search(sid: str) -> str

Path to exhaustive-search results for sid.

Source code in tit/paths.py
def ex_search(self, sid: str) -> str:
    """Path to exhaustive-search results for *sid*."""
    return os.path.join(self.sub(sid), "ex-search")
flex_search(sid: str) -> str

Path to flex-search results for sid.

Source code in tit/paths.py
def flex_search(self, sid: str) -> str:
    """Path to flex-search results for *sid*."""
    return os.path.join(self.sub(sid), "flex-search")

simulation

simulation(sid: str, sim: str) -> str

Path to a named simulation directory for sid.

Source code in tit/paths.py
def simulation(self, sid: str, sim: str) -> str:
    """Path to a named simulation directory for *sid*."""
    return os.path.join(self.simulations(sid), sim)

ti_mesh

ti_mesh(sid: str, sim: str) -> str

Path to the TI mesh file ({sim}_TI.msh).

Source code in tit/paths.py
def ti_mesh(self, sid: str, sim: str) -> str:
    """Path to the TI mesh file (``{sim}_TI.msh``)."""
    return os.path.join(self.simulation(sid, sim), "TI", "mesh", f"{sim}_TI.msh")

ti_mesh_dir

ti_mesh_dir(sid: str, sim: str) -> str

Path to the TI mesh directory.

Source code in tit/paths.py
def ti_mesh_dir(self, sid: str, sim: str) -> str:
    """Path to the TI mesh directory."""
    return os.path.join(self.simulation(sid, sim), "TI", "mesh")

ti_central_surface

ti_central_surface(sid: str, sim: str) -> str

Path to the TI central cortical surface mesh.

Source code in tit/paths.py
def ti_central_surface(self, sid: str, sim: str) -> str:
    """Path to the TI central cortical surface mesh."""
    return os.path.join(
        self.simulation(sid, sim), "TI", "mesh", "surfaces", f"{sim}_TI_central.msh"
    )

mti_mesh_dir

mti_mesh_dir(sid: str, sim: str) -> str

Path to the mTI mesh directory.

Source code in tit/paths.py
def mti_mesh_dir(self, sid: str, sim: str) -> str:
    """Path to the mTI mesh directory."""
    return os.path.join(self.simulation(sid, sim), "mTI", "mesh")

analysis_dir

analysis_dir(sid: str, sim: str, space: str) -> str

Path to the analysis directory for a given analysis space.

Parameters

sid : str Subject identifier. sim : str Simulation name. space : str Analysis space — "mesh" or "voxel".

Returns

str Absolute path to Analyses/Mesh/ or Analyses/Voxel/.

Source code in tit/paths.py
def analysis_dir(self, sid: str, sim: str, space: str) -> str:
    """Path to the analysis directory for a given analysis space.

    Parameters
    ----------
    sid : str
        Subject identifier.
    sim : str
        Simulation name.
    space : str
        Analysis space — ``"mesh"`` or ``"voxel"``.

    Returns
    -------
    str
        Absolute path to ``Analyses/Mesh/`` or ``Analyses/Voxel/``.
    """
    folder = "Mesh" if space.lower() == "mesh" else "Voxel"
    return os.path.join(self.simulation(sid, sim), "Analyses", folder)

sourcedata_dicom

sourcedata_dicom(sid: str, modality: str) -> str

Path to DICOM source data for sid and modality.

Source code in tit/paths.py
def sourcedata_dicom(self, sid: str, modality: str) -> str:
    """Path to DICOM source data for *sid* and *modality*."""
    return os.path.join(self.sourcedata_subject(sid), modality, "dicom")

ex_search_run

ex_search_run(sid: str, run: str) -> str

Path to a specific exhaustive-search run directory.

Source code in tit/paths.py
def ex_search_run(self, sid: str, run: str) -> str:
    """Path to a specific exhaustive-search run directory."""
    return os.path.join(self.ex_search(sid), run)

flex_search_run

flex_search_run(sid: str, name: str) -> str

Path to a specific flex-search run directory.

Source code in tit/paths.py
def flex_search_run(self, sid: str, name: str) -> str:
    """Path to a specific flex-search run directory."""
    return os.path.join(self.flex_search(sid), name)

flex_electrode_positions

flex_electrode_positions(sid: str, name: str) -> str

Path to electrode_positions.json for a flex-search run.

Source code in tit/paths.py
def flex_electrode_positions(self, sid: str, name: str) -> str:
    """Path to ``electrode_positions.json`` for a flex-search run."""
    return os.path.join(self.flex_search_run(sid, name), "electrode_positions.json")

flex_manifest

flex_manifest(sid: str, name: str) -> str

Path to flex_meta.json for a flex-search run.

Source code in tit/paths.py
def flex_manifest(self, sid: str, name: str) -> str:
    """Path to ``flex_meta.json`` for a flex-search run."""
    return os.path.join(self.flex_search_run(sid, name), "flex_meta.json")

ensure

ensure(path: str) -> str

Create a directory (with parents) if it does not exist.

Parameters

path : str Directory path to create.

Returns

str The same path, for convenient chaining.

Source code in tit/paths.py
def ensure(self, path: str) -> str:
    """Create a directory (with parents) if it does not exist.

    Parameters
    ----------
    path : str
        Directory path to create.

    Returns
    -------
    str
        The same *path*, for convenient chaining.
    """
    os.makedirs(path, exist_ok=True)
    return path

list_simnibs_subjects

list_simnibs_subjects() -> list[str]

List subject IDs that have a SimNIBS head-model (m2m) folder.

Returns

list of str Naturally sorted subject identifiers (without the sub- prefix). Returns an empty list if the SimNIBS directory does not exist.

Source code in tit/paths.py
def list_simnibs_subjects(self) -> list[str]:
    """List subject IDs that have a SimNIBS head-model (m2m) folder.

    Returns
    -------
    list of str
        Naturally sorted subject identifiers (without the ``sub-`` prefix).
        Returns an empty list if the SimNIBS directory does not exist.
    """
    simnibs_dir = self.simnibs() if self.project_dir else None
    if not simnibs_dir or not os.path.isdir(simnibs_dir):
        return []

    subjects = []
    for item in os.listdir(simnibs_dir):
        if not item.startswith(const.PREFIX_SUBJECT):
            continue
        sid = item.replace(const.PREFIX_SUBJECT, "", 1)
        if os.path.isdir(self.m2m(sid)):
            subjects.append(sid)

    subjects.sort(
        key=lambda x: [
            int(c) if c.isdigit() else c.lower() for c in re.split("([0-9]+)", x)
        ]
    )
    return subjects

list_simulations

list_simulations(sid: str) -> list[str]

List simulation folder names for a subject.

Parameters

sid : str Subject identifier.

Returns

list of str Alphabetically sorted simulation directory names. Returns an empty list if the Simulations/ directory does not exist.

Source code in tit/paths.py
def list_simulations(self, sid: str) -> list[str]:
    """List simulation folder names for a subject.

    Parameters
    ----------
    sid : str
        Subject identifier.

    Returns
    -------
    list of str
        Alphabetically sorted simulation directory names.  Returns an
        empty list if the ``Simulations/`` directory does not exist.
    """
    sim_root = self.simulations(sid)

    try:
        simulations: list[str] = []
        with os.scandir(sim_root) as it:
            for entry in it:
                if entry.is_dir() and not entry.name.startswith("."):
                    simulations.append(entry.name)
        simulations.sort()
        return simulations
    except OSError:
        return []

list_eeg_caps

list_eeg_caps(sid: str) -> list[str]

List EEG cap CSV filenames for a subject.

Parameters

sid : str Subject identifier.

Returns

list of str Sorted CSV filenames found in the eeg_positions/ directory.

Source code in tit/paths.py
def list_eeg_caps(self, sid: str) -> list[str]:
    """List EEG cap CSV filenames for a subject.

    Parameters
    ----------
    sid : str
        Subject identifier.

    Returns
    -------
    list of str
        Sorted CSV filenames found in the ``eeg_positions/`` directory.
    """
    eeg_pos_dir = self.eeg_positions(sid) if self.project_dir else None
    if not eeg_pos_dir or not os.path.isdir(eeg_pos_dir):
        return []

    caps = [
        f
        for f in os.listdir(eeg_pos_dir)
        if f.endswith(const.EXT_CSV) and not f.startswith(".")
    ]
    caps.sort()
    return caps

list_flex_search_runs

list_flex_search_runs(sid: str) -> list[str]

List flex-search run directories containing result metadata.

Only directories that contain flex_meta.json or electrode_positions.json are included.

Parameters

sid : str Subject identifier.

Returns

list of str Sorted run directory names.

Source code in tit/paths.py
def list_flex_search_runs(self, sid: str) -> list[str]:
    """List flex-search run directories containing result metadata.

    Only directories that contain ``flex_meta.json`` or
    ``electrode_positions.json`` are included.

    Parameters
    ----------
    sid : str
        Subject identifier.

    Returns
    -------
    list of str
        Sorted run directory names.
    """
    root = self.flex_search(sid) if self.project_dir else None
    if not root or not os.path.isdir(root):
        return []

    try:
        out: list[str] = []
        with os.scandir(root) as it:
            for entry in it:
                if not entry.is_dir() or entry.name.startswith("."):
                    continue
                if os.path.isfile(
                    os.path.join(entry.path, "flex_meta.json")
                ) or os.path.isfile(
                    os.path.join(entry.path, "electrode_positions.json")
                ):
                    out.append(entry.name)
        out.sort()
        return out
    except OSError:
        return []

spherical_analysis_name staticmethod

spherical_analysis_name(x: float, y: float, z: float, radius: float, coordinate_space: str) -> str

Build a canonical folder name for a spherical ROI analysis.

Parameters

x, y, z : float Centre coordinates of the sphere (mm). radius : float Sphere radius (mm). coordinate_space : str "MNI" or "subject".

Returns

str Folder name, e.g. "sphere_x0.00_y0.00_z0.00_r5.0_MNI".

Source code in tit/paths.py
@staticmethod
def spherical_analysis_name(
    x: float, y: float, z: float, radius: float, coordinate_space: str
) -> str:
    """Build a canonical folder name for a spherical ROI analysis.

    Parameters
    ----------
    x, y, z : float
        Centre coordinates of the sphere (mm).
    radius : float
        Sphere radius (mm).
    coordinate_space : str
        ``"MNI"`` or ``"subject"``.

    Returns
    -------
    str
        Folder name, e.g. ``"sphere_x0.00_y0.00_z0.00_r5.0_MNI"``.
    """
    coord_space_suffix = (
        "_MNI" if str(coordinate_space).upper() == "MNI" else "_subject"
    )
    return f"sphere_x{x:.2f}_y{y:.2f}_z{z:.2f}_r{float(radius)}{coord_space_suffix}"

cortical_analysis_name classmethod

cortical_analysis_name(*, whole_head: bool, region: str | None, atlas_name: str | None = None, atlas_path: str | None = None) -> str

Build a canonical folder name for a cortical/atlas analysis.

Parameters

whole_head : bool If True, the analysis covers the whole head (no region filter). region : str or None Atlas region label(s). Multiple regions are +-separated. atlas_name : str or None, optional Human-readable atlas name. atlas_path : str or None, optional Filesystem path to the atlas file (used as fallback for naming).

Returns

str Folder name, e.g. "cortical_precentral_DK40" or "whole_head_DK40".

Raises

ValueError If whole_head is False and region is empty or None.

Source code in tit/paths.py
@classmethod
def cortical_analysis_name(
    cls,
    *,
    whole_head: bool,
    region: str | None,
    atlas_name: str | None = None,
    atlas_path: str | None = None,
) -> str:
    """Build a canonical folder name for a cortical/atlas analysis.

    Parameters
    ----------
    whole_head : bool
        If *True*, the analysis covers the whole head (no region filter).
    region : str or None
        Atlas region label(s).  Multiple regions are ``+``-separated.
    atlas_name : str or None, optional
        Human-readable atlas name.
    atlas_path : str or None, optional
        Filesystem path to the atlas file (used as fallback for naming).

    Returns
    -------
    str
        Folder name, e.g. ``"cortical_precentral_DK40"`` or
        ``"whole_head_DK40"``.

    Raises
    ------
    ValueError
        If *whole_head* is *False* and *region* is empty or *None*.
    """
    atlas_clean = cls._atlas_name_clean(atlas_name or atlas_path or "unknown_atlas")
    if whole_head:
        return f"whole_head_{atlas_clean}"
    region_val = str(region or "").strip()
    if not region_val:
        raise ValueError(
            "region is required for cortical analysis unless whole_head=True"
        )
    if "+" in region_val:
        n = len(region_val.split("+"))
        h = hashlib.md5(region_val.encode()).hexdigest()[:8]
        return f"cortical_{n}regions_{atlas_clean}_{h}"
    return f"cortical_{region_val}_{atlas_clean}"

analysis_output_dir

analysis_output_dir(*, sid: str, sim: str, space: str, analysis_type: str, coordinates=None, radius=None, coordinate_space: str = 'subject', whole_head: bool = False, region: str | None = None, atlas_name: str | None = None, atlas_path: str | None = None) -> str

Return the analysis output directory path (does not create it).

Delegates to :meth:spherical_analysis_name or :meth:cortical_analysis_name depending on analysis_type.

Parameters

sid : str Subject identifier. sim : str Simulation name. space : str Analysis space ("mesh" or "voxel"). analysis_type : str "spherical" or "cortical". coordinates : sequence of float or None, optional (x, y, z) centre for spherical analysis. radius : float or None, optional Sphere radius in mm (required when analysis_type is "spherical"). coordinate_space : str, optional "MNI" or "subject". Default is "subject". whole_head : bool, optional Whether cortical analysis covers the whole head. region : str or None, optional Atlas region label(s) for cortical analysis. atlas_name : str or None, optional Atlas name for cortical analysis. atlas_path : str or None, optional Atlas file path for cortical analysis.

Returns

str Absolute path to the analysis output directory.

Raises

ValueError If required parameters for the chosen analysis_type are missing or invalid.

See Also

spherical_analysis_name : Naming convention for spherical ROIs. cortical_analysis_name : Naming convention for cortical/atlas ROIs.

Source code in tit/paths.py
def analysis_output_dir(
    self,
    *,
    sid: str,
    sim: str,
    space: str,
    analysis_type: str,
    coordinates=None,
    radius=None,
    coordinate_space: str = "subject",
    whole_head: bool = False,
    region: str | None = None,
    atlas_name: str | None = None,
    atlas_path: str | None = None,
) -> str:
    """Return the analysis output directory path (does not create it).

    Delegates to :meth:`spherical_analysis_name` or
    :meth:`cortical_analysis_name` depending on *analysis_type*.

    Parameters
    ----------
    sid : str
        Subject identifier.
    sim : str
        Simulation name.
    space : str
        Analysis space (``"mesh"`` or ``"voxel"``).
    analysis_type : str
        ``"spherical"`` or ``"cortical"``.
    coordinates : sequence of float or None, optional
        ``(x, y, z)`` centre for spherical analysis.
    radius : float or None, optional
        Sphere radius in mm (required when *analysis_type* is
        ``"spherical"``).
    coordinate_space : str, optional
        ``"MNI"`` or ``"subject"``.  Default is ``"subject"``.
    whole_head : bool, optional
        Whether cortical analysis covers the whole head.
    region : str or None, optional
        Atlas region label(s) for cortical analysis.
    atlas_name : str or None, optional
        Atlas name for cortical analysis.
    atlas_path : str or None, optional
        Atlas file path for cortical analysis.

    Returns
    -------
    str
        Absolute path to the analysis output directory.

    Raises
    ------
    ValueError
        If required parameters for the chosen *analysis_type* are
        missing or invalid.

    See Also
    --------
    spherical_analysis_name : Naming convention for spherical ROIs.
    cortical_analysis_name : Naming convention for cortical/atlas ROIs.
    """
    base = self.analysis_dir(sid, sim, space)
    at = str(analysis_type).lower()
    if at == "spherical":
        if not coordinates or len(coordinates) != 3 or radius is None:
            raise ValueError(
                "coordinates(3) and radius required for spherical analysis"
            )
        name = self.spherical_analysis_name(
            float(coordinates[0]),
            float(coordinates[1]),
            float(coordinates[2]),
            float(radius),
            coordinate_space,
        )
    else:
        name = self.cortical_analysis_name(
            whole_head=bool(whole_head),
            region=region,
            atlas_name=atlas_name,
            atlas_path=atlas_path,
        )
    return os.path.join(base, name)

get_path_manager

get_path_manager(project_dir: str | None = None) -> PathManager

Return the global :class:PathManager singleton.

Creates a new instance on the first call. If project_dir is provided, the singleton's :attr:~PathManager.project_dir is (re)set.

Parameters

project_dir : str or None, optional Project root directory. When None, the existing value (or environment auto-detection) is used.

Returns

PathManager The shared singleton instance.

See Also

reset_path_manager : Destroy the singleton for testing or re-init.

Source code in tit/paths.py
def get_path_manager(project_dir: str | None = None) -> PathManager:
    """Return the global :class:`PathManager` singleton.

    Creates a new instance on the first call.  If *project_dir* is provided,
    the singleton's :attr:`~PathManager.project_dir` is (re)set.

    Parameters
    ----------
    project_dir : str or None, optional
        Project root directory.  When *None*, the existing value (or
        environment auto-detection) is used.

    Returns
    -------
    PathManager
        The shared singleton instance.

    See Also
    --------
    reset_path_manager : Destroy the singleton for testing or re-init.
    """
    global _path_manager_instance
    if _path_manager_instance is None:
        _path_manager_instance = PathManager()
    if project_dir is not None:
        _path_manager_instance.project_dir = project_dir
    return _path_manager_instance

reset_path_manager

reset_path_manager() -> None

Destroy the singleton so the next call creates a fresh instance.

Primarily used in test fixtures to prevent cross-test contamination.

See Also

get_path_manager : Obtain the singleton instance.

Source code in tit/paths.py
def reset_path_manager() -> None:
    """Destroy the singleton so the next call creates a fresh instance.

    Primarily used in test fixtures to prevent cross-test contamination.

    See Also
    --------
    get_path_manager : Obtain the singleton instance.
    """
    global _path_manager_instance
    _path_manager_instance = None