Skip to content

utils

tit.opt.flex.utils

ROI configuration and output naming for flex-search.

generate_run_dirname

generate_run_dirname(base_path: str) -> str

Generate a datetime-based directory name for a flex-search run.

Format: YYYYMMDD_HHMMSS. Appends _1, _2, etc. if the folder already exists.

Parameters:

Name Type Description Default
base_path str

Parent directory (e.g. flex-search/) to check for collisions.

required

Returns:

Type Description
str

Directory name string (not full path).

Source code in tit/opt/flex/utils.py
def generate_run_dirname(base_path: str) -> str:
    """Generate a datetime-based directory name for a flex-search run.

    Format: YYYYMMDD_HHMMSS. Appends _1, _2, etc. if the folder already exists.

    Args:
        base_path: Parent directory (e.g. flex-search/) to check for collisions.

    Returns:
        Directory name string (not full path).
    """
    from datetime import datetime

    name = datetime.now().strftime("%Y%m%d_%H%M%S")
    if not os.path.exists(os.path.join(base_path, name)):
        return name
    suffix = 1
    while os.path.exists(os.path.join(base_path, f"{name}_{suffix}")):
        suffix += 1
    return f"{name}_{suffix}"

generate_label

generate_label(config, pareto: bool = False) -> str

Build a human-readable label for a flex-search run.

This label is stored in flex_meta.json for GUI display purposes. It is NOT used for folder naming or machine parsing.

Parameters:

Name Type Description Default
config

FlexConfig instance.

required
pareto bool

True if this is a pareto sweep run.

False

Returns:

Type Description
str

Label string like "mean_maxTI_sphere(-42,-20,55)r10".

Source code in tit/opt/flex/utils.py
def generate_label(config, pareto: bool = False) -> str:
    """Build a human-readable label for a flex-search run.

    This label is stored in flex_meta.json for GUI display purposes.
    It is NOT used for folder naming or machine parsing.

    Args:
        config: FlexConfig instance.
        pareto: True if this is a pareto sweep run.

    Returns:
        Label string like "mean_maxTI_sphere(-42,-20,55)r10".
    """
    postproc_short = {
        "max_TI": "maxTI",
        "dir_TI_normal": "normalTI",
        "dir_TI_tangential": "tangentialTI",
    }
    pp = postproc_short.get(
        (
            config.postproc.value
            if hasattr(config.postproc, "value")
            else str(config.postproc)
        ),
        str(config.postproc),
    )

    goal_str = (
        "pareto"
        if pareto
        else (config.goal.value if hasattr(config.goal, "value") else str(config.goal))
    )

    roi = config.roi
    if isinstance(roi, FlexConfig.SphericalROI):
        x = int(roi.x) if roi.x == int(roi.x) else roi.x
        y = int(roi.y) if roi.y == int(roi.y) else roi.y
        z = int(roi.z) if roi.z == int(roi.z) else roi.z
        r = int(roi.radius) if roi.radius == int(roi.radius) else roi.radius
        roi_str = f"sphere({x},{y},{z})r{r}"
    elif isinstance(roi, FlexConfig.AtlasROI):
        hemi = roi.hemisphere
        atlas = (
            os.path.basename(roi.atlas_path).replace(".annot", "").split(".")[-1]
            if roi.atlas_path
            else "atlas"
        )
        roi_str = f"{hemi}-{atlas}-{roi.label}"
    elif isinstance(roi, FlexConfig.SubcorticalROI):
        atlas = os.path.basename(roi.atlas_path) if roi.atlas_path else "volume"
        for ext in (".nii.gz", ".nii", ".mgz"):
            if atlas.endswith(ext):
                atlas = atlas[: -len(ext)]
                break
        roi_str = f"subcortical-{atlas}-{roi.label}"
    else:
        roi_str = "unknown"

    return f"{goal_str}_{pp}_{roi_str}"

parse_optimization_output

parse_optimization_output(line: str) -> float | None

Extract the optimization function value from a SimNIBS log line.

Handles patterns
  • "Final goal function value: -42.123"
  • "Goal function value.*: -42.123"
  • Table row with max_TI column (scientific notation)

Parameters:

Name Type Description Default
line str

A single line of SimNIBS stdout/stderr.

required

Returns:

Type Description
float | None

The function value as a float, or None if the line does not match.

Source code in tit/opt/flex/utils.py
def parse_optimization_output(line: str) -> float | None:
    """Extract the optimization function value from a SimNIBS log line.

    Handles patterns:
        - "Final goal function value:   -42.123"
        - "Goal function value.*:  -42.123"
        - Table row with max_TI column (scientific notation)

    Args:
        line: A single line of SimNIBS stdout/stderr.

    Returns:
        The function value as a float, or None if the line does not match.
    """
    import re

    # Primary: "Final goal function value: <number>"
    m = re.search(
        r"Final goal function value:\s*([+-]?[\d.eE+-]+)", line, re.IGNORECASE
    )
    if m:
        return float(m.group(1))

    # Secondary: "Goal function value<anything>: <number>"
    m = re.search(r"Goal function value[^:]*:\s*([+-]?[\d.eE+-]+)", line, re.IGNORECASE)
    if m:
        return float(m.group(1))

    # Table row: "|max_TI | 0.025" or "max_TI | 0.025e-03"
    m = re.search(r"\|?\s*max_TI\s+\|\s*([\d.+-]+)(?:e([+-]?\d+))?", line)
    if m:
        base = float(m.group(1))
        exp = int(m.group(2)) if m.group(2) else 0
        val = base * (10**exp)
        if val > 0:
            return val

    return None

configure_roi

configure_roi(opt, config: FlexConfig) -> None

Configure ROI based on the config's ROI specification.

This is the main entry point for ROI configuration that delegates to the appropriate method-specific function.

Parameters:

Name Type Description Default
opt

SimNIBS TesFlexOptimization object.

required
config FlexConfig

Flex-search configuration with ROI spec.

required
Source code in tit/opt/flex/utils.py
def configure_roi(opt, config: FlexConfig) -> None:
    """Configure ROI based on the config's ROI specification.

    This is the main entry point for ROI configuration that delegates to
    the appropriate method-specific function.

    Args:
        opt: SimNIBS ``TesFlexOptimization`` object.
        config: Flex-search configuration with ROI spec.
    """
    if isinstance(config.roi, FlexConfig.SphericalROI):
        _configure_spherical_roi(opt, config)
    elif isinstance(config.roi, FlexConfig.AtlasROI):
        _configure_atlas_roi(opt, config)
    elif isinstance(config.roi, FlexConfig.SubcorticalROI):
        _configure_subcortical_roi(opt, config)
    else:
        raise ValueError(f"Unknown ROI type: {type(config.roi)}")