Source code for neofoam.framework.model.runtime

# SPDX-License-Identifier: GPL-3.0-or-later
# SPDX-FileCopyrightText: 2025 NeoFOAM authors

"""
ModelRuntime — one instantiation of a ModelSpec with its own loaded config.

Created by ModelSpec.instantiate(). Never shared between solver runs.
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Any, TYPE_CHECKING

if TYPE_CHECKING:
    from .spec import ModelSpec
    from neofoam.framework.initialization import ConfigContext, InitStep
    from neofoam.framework.operations import Operation


[docs] @dataclass class ModelRuntime: """ One instantiation of a ModelSpec with its own loaded config. Owns per-instance state (config, name). All stage execution delegates to the spec, passing config explicitly so state never leaks between runs. """ spec: "ModelSpec" name: str # unique: "<spec.name>_<instance_id>" config: Any # loaded config — updated during RESOLVE
[docs] def run_resolve(self, ctx: "ConfigContext") -> None: """Call spec's resolve func; store the returned updated config.""" if self.spec._resolve_func is not None: result = self.spec._resolve_func(self.config, ctx) if result is not None: self.config = result
[docs] def run_build(self) -> list["InitStep"]: """Call spec's build func with this instance's config (if it accepts args).""" import inspect if self.spec._build_func is None: return [] sig = inspect.signature(self.spec._build_func) if len(sig.parameters) > 0: return self.spec._build_func(self.config) # type: ignore[no-any-return] return self.spec._build_func() # type: ignore[no-any-return]
@property def operations(self) -> list["Operation"]: """Build operations with this runtime as the self binding.""" return self.spec._build_operations_for(self) @property def configs(self) -> list[Any]: """ Return BaseConfig instances held by this runtime. Used by ``LoadResult.configs`` to collect configs for validation. Handles both a single config and a SimpleNamespace of multiple configs. """ from neofoam.io import BaseConfig from types import SimpleNamespace result = [] if isinstance(self.config, BaseConfig): result.append(self.config) elif isinstance(self.config, SimpleNamespace): for val in vars(self.config).values(): if isinstance(val, BaseConfig): result.append(val) return result