Source code for femorph_solver.mapdl_api.cdb

"""Load MAPDL CDB input decks into an femorph-solver :class:`~femorph_solver.Model`.

Thin wrapper around :mod:`mapdl_archive`.  Only the file-format reader
is involved — MAPDL itself is never invoked.
"""

from __future__ import annotations

import re
from pathlib import Path
from typing import TYPE_CHECKING, Any

from femorph_solver._labels import UnitSystem, unit_system_from_mapdl

if TYPE_CHECKING:
    from femorph_solver.model import Model


# ``/UNITS,<token>`` or ``/UNITS,<token>,...`` — whitespace allowed
# around the comma; token is the leading comma-separated field.  CDB
# parsers (including MAPDL itself) only look at the first token.
_UNITS_RE = re.compile(r"^\s*/UNITS\s*,\s*([A-Za-z0-9_]+)", re.IGNORECASE)


def _detect_unit_system(path: str | Path) -> UnitSystem:
    """Scan the CDB for a ``/UNITS,<token>`` command and return its :class:`UnitSystem`.

    Returns :attr:`UnitSystem.UNSPECIFIED` when no ``/UNITS`` command
    appears in the first 8 KiB of the file (the header region).  MAPDL
    decks place ``/UNITS`` near the top; scanning further down would
    just slow this call without improving accuracy.
    """
    try:
        with open(path, encoding="utf-8", errors="ignore") as fh:
            head = fh.read(8192)
    except OSError:  # pragma: no cover - defensive; from_cdb opens again
        return UnitSystem.UNSPECIFIED
    for line in head.splitlines():
        m = _UNITS_RE.match(line)
        if m:
            return unit_system_from_mapdl(m.group(1))
    return UnitSystem.UNSPECIFIED


[docs] def from_cdb(path: str, **kwargs: Any) -> Model: """Load a MAPDL CDB file via :mod:`mapdl_archive`. Requires the ``mapdl`` extra: ``pip install femorph_solver[mapdl]``. The deck's ``/UNITS`` command (if present) is parsed and stamped onto :attr:`Model.unit_system`. Decks without a ``/UNITS`` line get :attr:`UnitSystem.UNSPECIFIED`. """ try: import mapdl_archive except ImportError as exc: # pragma: no cover - import-guard path raise ImportError( "Reading MAPDL CDB decks requires the 'mapdl' extra. " "Install with: pip install femorph_solver[mapdl]" ) from exc from femorph_solver.model import Model archive = mapdl_archive.Archive(path, **kwargs) model = Model.from_grid(archive.grid) model.set_unit_system(_detect_unit_system(path)) return model