Source code for apis

from __future__ import annotations

"""Application API contracts for TDPy.

This module contains the lightweight request, result, and problem-specification
objects used by the top-level application layer.

Design rules
------------
The module intentionally stays dependency-light:

* ``RunRequest`` and ``RunResult`` are the stable envelopes used by the CLI,
  GUI, and ``app.py``.
* Equation-system dataclasses are not duplicated here. The canonical EES-style
  equation specs live in ``equations.spec``.
* Heavy optional backends such as SciPy, GEKKO, CoolProp, and Cantera are not
  imported here.

Runtime notes
-------------
TDPy supports ``"optimize"`` problem inputs in addition to ``"equations"``,
``"nozzle_ideal"``, and ``"thermo_props"``.

CLI and GUI callers may pass runtime overrides through ``RunRequest.opts`` or
``RunRequest.overrides``. Newer code should prefer ``opts``. Application code
should treat both mappings as additive and let ``opts`` take precedence.

Thermodynamic-property backend names are intentionally extensible. Backends may
include CoolProp, Cantera, and native mixture implementations depending on the
installed optional dependencies.
"""

from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Dict, List, Literal, Mapping, Optional, Sequence

__all__ = [
    # runner envelopes
    "UnitSystem",
    "RunRequest",
    "RunResult",
    "ProblemSpec",
    # thermo_props contracts (app-facing)
    "PropsBackend",
    "PropsBasis",
    "ThermoPropsRequest",
    "ThermoPropsResult",
    # equations canonical re-exports (single source of truth)
    "EquationSpec",
    "EquationSystemSpec",
    "VarSpec",
    "ParamSpec",
    "SpecError",
    # back-compat aliases
    "EquationsProblemSpec",
    "EquationsSpecError",
    "VariableSpec",
]


# ---------------------------------------------------------------------
# Core runner request/response
# ---------------------------------------------------------------------

UnitSystem = Literal["SI", "English", "Mixed"]


[docs] @dataclass(frozen=True) class RunRequest: """Top-level run request used by the app, CLI, and GUI. Parameters ---------- in_path: Input file path. TDPy is intentionally file-driven, so this is the only required path. out_path: Optional output file path. When omitted, the application layer chooses a default path. make_plots: Request default plots when the selected solver supports them. unit_system: Unit-system hint. ``"Mixed"`` means individual fields may include explicit units such as ``"300 K"``. prefer_solver: Optional solver preference kept for compatibility with older callers. opts: Preferred runtime override mapping used by newer CLI tooling. overrides: Legacy runtime override mapping kept for compatibility. Notes ----- This module does not apply overrides directly. The application layer decides how to merge and use them. For minimal surprise, application code should merge ``overrides`` first and then ``opts`` so that ``opts`` wins. """ in_path: Path out_path: Optional[Path] = None make_plots: bool = False unit_system: UnitSystem = "SI" prefer_solver: Optional[str] = None # Newer name (used by CLI tooling) opts: Mapping[str, Any] = field(default_factory=dict) # Older name (kept for existing callers) overrides: Mapping[str, Any] = field(default_factory=dict)
[docs] @dataclass(frozen=True) class RunResult: """Standardized result envelope returned by the application layer. Parameters ---------- ok: Whether the pipeline completed successfully. solver: Solver or backend label used for the run. in_path: Resolved input path. out_path: Resolved output path, if output was written. payload: JSON-serializable result payload returned by the solver. plots: Mapping from plot names to generated file paths. warnings: Non-fatal warnings produced during the run. meta: Additional metadata such as backend details, timing, or version tags. """ ok: bool solver: str in_path: Path out_path: Optional[Path] payload: Dict[str, Any] plots: Dict[str, str] = field(default_factory=dict) warnings: List[str] = field(default_factory=list) meta: Dict[str, Any] = field(default_factory=dict)
[docs] @dataclass(frozen=True) class ProblemSpec: """Generic problem specification produced by the design layer. Parameters ---------- problem_type: Extensible problem type string. Common values include ``"nozzle_ideal"``, ``"thermo_props"``, ``"equations"``, and ``"optimize"``. data: Problem-specific input mapping after the top-level ``problem_type`` has been separated. schema_version: Schema version for the generic envelope. """ problem_type: str data: Dict[str, Any] schema_version: str = "1.0"
# --------------------------------------------------------------------- # thermo_props API contracts (app-facing) # --------------------------------------------------------------------- # Keep backend strings lowercase for consistency across the project. # NOTE: The runtime may support additional backends depending on what is installed. PropsBackend = Literal["coolprop", "cantera", "librh2o", "nh3h2o", "auto"] PropsBasis = Literal["mass", "molar"]
[docs] @dataclass(frozen=True) class ThermoPropsRequest: """Request thermodynamic properties from a selected backend. Parameters ---------- fluid: Fluid or working-pair identifier. inputs: Mapping of input property names to values. outputs: Requested output property names. backend: Backend selector such as ``"coolprop"``, ``"cantera"``, or ``"auto"``. basis: Property basis, usually ``"mass"`` or ``"molar"``. units: Optional mapping of property names to unit strings. options: Backend-specific options. Example ------- A typical request may use ``fluid="R134a"``, inputs such as temperature and pressure, and outputs such as enthalpy, entropy, and density. """ fluid: str inputs: Mapping[str, Any] outputs: Sequence[str] backend: PropsBackend = "coolprop" basis: PropsBasis = "mass" units: Mapping[str, str] = field(default_factory=dict) options: Mapping[str, Any] = field(default_factory=dict)
[docs] @dataclass(frozen=True) class ThermoPropsResult: """Result of a thermodynamic-property evaluation.""" fluid: str backend: str basis: str inputs: Dict[str, Any] outputs: Dict[str, Any] units: Dict[str, str] = field(default_factory=dict) warnings: List[str] = field(default_factory=list) meta: Dict[str, Any] = field(default_factory=dict)
# --------------------------------------------------------------------- # equations (canonical contracts live in equations.spec) # --------------------------------------------------------------------- # IMPORTANT: # - Do NOT duplicate equation dataclasses here. # - Re-export the canonical spec types so the rest of the app has ONE truth. # --------------------------------------------------------------------- from equations.spec import ( # noqa: E402 EquationSpec, EquationSystemSpec, ParamSpec, SpecError, VarSpec, ) # Back-compat aliases (older code may import these names from apis) EquationsProblemSpec = EquationSystemSpec EquationsSpecError = SpecError VariableSpec = VarSpec