Skip to content

mesh2nii

tit.tools.mesh2nii

Mesh-to-NIfTI conversion using the SimNIBS Python API.

Wraps simnibs.transformations so that the simulation pipeline can convert .msh meshes to volumetric NIfTI files without shelling out to bash scripts.

Public API

msh_to_nifti Convert a single mesh to subject-space NIfTI. msh_to_mni Convert a single mesh to MNI-space NIfTI. convert_mesh_dir Batch-convert every .msh file in a directory.

See Also

tit.tools.nifti_to_mesh : Inverse operation (NIfTI to surface mesh). tit.tools.field_extract : Extract tissue sub-meshes before conversion.

msh_to_nifti

msh_to_nifti(mesh_path: str, m2m_dir: str, output_path: str, fields: list[str] | None = None) -> None

Convert a mesh file to subject-space NIfTI.

Parameters

mesh_path : str Path to the .msh file. m2m_dir : str Path to the m2m_{subject} directory (used as reference grid). output_path : str Output file prefix. SimNIBS appends the field name (e.g. prefix_magnE.nii.gz). fields : list[str] | None If given, only these fields are written. Otherwise all fields in the mesh are converted.

Source code in tit/tools/mesh2nii.py
def msh_to_nifti(
    mesh_path: str,
    m2m_dir: str,
    output_path: str,
    fields: list[str] | None = None,
) -> None:
    """Convert a mesh file to subject-space NIfTI.

    Parameters
    ----------
    mesh_path : str
        Path to the ``.msh`` file.
    m2m_dir : str
        Path to the ``m2m_{subject}`` directory (used as reference grid).
    output_path : str
        Output file prefix.  SimNIBS appends the field name
        (e.g. ``prefix_magnE.nii.gz``).
    fields : list[str] | None
        If given, only these fields are written.  Otherwise all fields in the
        mesh are converted.
    """
    mesh = mesh_io.read_msh(mesh_path)
    if fields:
        mesh = _filter_mesh_fields(mesh, fields)
    transformations.interpolate_to_volume(mesh, m2m_dir, output_path)

msh_to_mni

msh_to_mni(mesh_path: str, m2m_dir: str, output_path: str, fields: list[str] | None = None) -> None

Convert a mesh file to MNI-space NIfTI.

Parameters

mesh_path : str Path to the .msh file. m2m_dir : str Path to the m2m_{subject} directory. output_path : str Output file prefix. SimNIBS appends the field name (e.g. prefix_magnE.nii.gz). fields : list[str] | None If given, only these fields are written.

Source code in tit/tools/mesh2nii.py
def msh_to_mni(
    mesh_path: str,
    m2m_dir: str,
    output_path: str,
    fields: list[str] | None = None,
) -> None:
    """Convert a mesh file to MNI-space NIfTI.

    Parameters
    ----------
    mesh_path : str
        Path to the ``.msh`` file.
    m2m_dir : str
        Path to the ``m2m_{subject}`` directory.
    output_path : str
        Output file prefix.  SimNIBS appends the field name
        (e.g. ``prefix_magnE.nii.gz``).
    fields : list[str] | None
        If given, only these fields are written.
    """
    if fields:
        mesh = mesh_io.read_msh(mesh_path)
        mesh = _filter_mesh_fields(mesh, fields)
        mesh_path = _write_temp_mesh(mesh)
    transformations.warp_volume(mesh_path, m2m_dir, output_path)

convert_mesh_dir

convert_mesh_dir(mesh_dir: str, output_dir: str, m2m_dir: str, fields: list[str] | None = None, skip_patterns: list[str] | None = None, max_workers: int | None = None) -> None

Batch-convert every .msh file in mesh_dir to NIfTI.

For each mesh two NIfTI sets are produced:

  • {basename}_subject_{field}.nii.gz – subject space
  • {basename}_MNI_{field}.nii.gz – MNI space

The subject-space and MNI-space conversions are independent (distinct output files, no shared state), so all conversions across every mesh are run concurrently in a process pool. The SimNIBS transforms are single-threaded (OMP_NUM_THREADS is typically 1 in the container), so this yields a substantial wall-clock speedup on multi-core hosts.

Parameters

mesh_dir : str Directory containing .msh files. output_dir : str Where the NIfTI files are written. m2m_dir : str Path to the m2m_{subject} directory. fields : list[str] | None If given, only these fields are converted. skip_patterns : list[str] | None Basenames containing any of these substrings are skipped. Defaults to ["normal"] (surface-only meshes have no volume elements). max_workers : int | None Number of worker processes. Defaults to the TI_NIFTI_WORKERS environment variable, or min(n_tasks, cpu_count, 8). Set to 1 to run serially (e.g. for debugging or memory-constrained hosts).

See Also

convert_mesh_dirs : Convert several directories in a single pool.

Source code in tit/tools/mesh2nii.py
def convert_mesh_dir(
    mesh_dir: str,
    output_dir: str,
    m2m_dir: str,
    fields: list[str] | None = None,
    skip_patterns: list[str] | None = None,
    max_workers: int | None = None,
) -> None:
    """Batch-convert every ``.msh`` file in *mesh_dir* to NIfTI.

    For each mesh two NIfTI sets are produced:

    * ``{basename}_subject_{field}.nii.gz``  – subject space
    * ``{basename}_MNI_{field}.nii.gz``      – MNI space

    The subject-space and MNI-space conversions are independent (distinct
    output files, no shared state), so all conversions across every mesh
    are run concurrently in a process pool.  The SimNIBS transforms are
    single-threaded (``OMP_NUM_THREADS`` is typically 1 in the container),
    so this yields a substantial wall-clock speedup on multi-core hosts.

    Parameters
    ----------
    mesh_dir : str
        Directory containing ``.msh`` files.
    output_dir : str
        Where the NIfTI files are written.
    m2m_dir : str
        Path to the ``m2m_{subject}`` directory.
    fields : list[str] | None
        If given, only these fields are converted.
    skip_patterns : list[str] | None
        Basenames containing any of these substrings are skipped.
        Defaults to ``["normal"]`` (surface-only meshes have no volume
        elements).
    max_workers : int | None
        Number of worker processes.  Defaults to the ``TI_NIFTI_WORKERS``
        environment variable, or ``min(n_tasks, cpu_count, 8)``.  Set to
        ``1`` to run serially (e.g. for debugging or memory-constrained
        hosts).

    See Also
    --------
    convert_mesh_dirs : Convert several directories in a single pool.
    """
    tasks, temp_paths = _collect_tasks(mesh_dir, output_dir, fields, skip_patterns)
    if not tasks:
        logger.warning("No .msh files to convert in %s", mesh_dir)
        return

    _run_tasks(tasks, m2m_dir, temp_paths, max_workers)
    logger.info("NIfTI conversion complete: %s", output_dir)

convert_mesh_dirs

convert_mesh_dirs(specs: list[dict], m2m_dir: str, max_workers: int | None = None) -> None

Convert several mesh directories to NIfTI in a single process pool.

Equivalent to calling :func:convert_mesh_dir once per directory, but every conversion task from every directory is submitted to one shared pool. This overlaps directories that would otherwise run one after the other (e.g. the TI-mesh and HF-mesh directories in the simulation pipeline) and avoids nesting process pools.

Parameters

specs : list[dict] One dict per directory with keys mesh_dir and output_dir (required) and optional fields / skip_patterns (same meaning as in :func:convert_mesh_dir). m2m_dir : str Path to the m2m_{subject} directory. max_workers : int | None Number of worker processes. See :func:convert_mesh_dir.

See Also

convert_mesh_dir : Convert a single directory.

Source code in tit/tools/mesh2nii.py
def convert_mesh_dirs(
    specs: list[dict],
    m2m_dir: str,
    max_workers: int | None = None,
) -> None:
    """Convert several mesh directories to NIfTI in a single process pool.

    Equivalent to calling :func:`convert_mesh_dir` once per directory, but
    every conversion task from every directory is submitted to *one* shared
    pool.  This overlaps directories that would otherwise run one after the
    other (e.g. the TI-mesh and HF-mesh directories in the simulation
    pipeline) and avoids nesting process pools.

    Parameters
    ----------
    specs : list[dict]
        One dict per directory with keys ``mesh_dir`` and ``output_dir``
        (required) and optional ``fields`` / ``skip_patterns`` (same meaning
        as in :func:`convert_mesh_dir`).
    m2m_dir : str
        Path to the ``m2m_{subject}`` directory.
    max_workers : int | None
        Number of worker processes.  See :func:`convert_mesh_dir`.

    See Also
    --------
    convert_mesh_dir : Convert a single directory.
    """
    all_tasks: list[tuple] = []
    all_temp: list[str] = []
    for spec in specs:
        tasks, temp_paths = _collect_tasks(
            spec["mesh_dir"],
            spec["output_dir"],
            spec.get("fields"),
            spec.get("skip_patterns"),
        )
        all_tasks.extend(tasks)
        all_temp.extend(temp_paths)

    if not all_tasks:
        logger.warning("No .msh files to convert in any of %d directories", len(specs))
        return

    _run_tasks(all_tasks, m2m_dir, all_temp, max_workers)
    for spec in specs:
        logger.info("NIfTI conversion complete: %s", spec["output_dir"])