完善通用求解器回归与前端交互

- 引入因果坐标内核、热流体恢复和递进长时回归\n- 完善正交连线、线桥、视图保持与结果曲线缩放\n- 补充依赖约束、CI、测试基线和北京时间更新日志
This commit is contained in:
lujingze committed 2026-08-18 06:42:07 +00:00
1 parent 143e8dd309
commit b435daecf2
65 files changed
+172271 -701

No files matched your search

+168 -11
View File
@@ -1,11 +1,13 @@
"""Proof-gated tangent columns for the three-piston reference network.
"""Proof-gated tangent columns for supported piston branch networks.
This module is deliberately narrower than the generic algebraic solver. It
only compiles a tangent provider after proving the state layout, component
types, physical connections, and causal execution plan used by the committed
three-piston XML. A failed proof leaves the ordinary seed-0 numerical
Jacobian in control; a runtime mode boundary requests the same one-build
fallback through :class:`ExactColumnsUnavailable`.
types, physical connections, and causal execution plan used by every selected
piston branch. The legacy three-piston entry point remains available for its
committed fixture, while the topology-driven entry point discovers any number
of branches without depending on component names. A failed proof leaves the
ordinary seed-0 numerical Jacobian in control; a runtime mode boundary requests
the same one-build fallback through :class:`ExactColumnsUnavailable`.
"""
from __future__ import annotations
@@ -57,6 +59,7 @@ class ThreePistonBranch:
chamber: object
pipe: object
contact: object
chamber_connection_port: str
velocity_index: int
position_index: int
@@ -91,7 +94,7 @@ def _failed(reason: str) -> ThreePistonTangentCompilation:
class ThreePistonTangentProvider:
"""Batched six-direction provider compiled for one system instance."""
"""Batched selected-branch provider compiled for one system instance."""
def __init__(
self,
@@ -611,10 +614,17 @@ class ThreePistonTangentProvider:
return out
def compile_three_piston_tangent_provider(
@dataclass(frozen=True)
class _PistonBranchSpec:
names: tuple[str, str, str, str, str]
chamber_connection_port: str
def _compile_named_piston_tangent_provider(
system: "GenericFluidSystem",
branch_specs: Sequence[_PistonBranchSpec],
) -> ThreePistonTangentCompilation:
"""Compile the proof-gated target provider, or return a stable reason."""
"""Compile a named, topology-proven set of supported piston branches."""
solver = system.pressure_flow_solver
if not solver.causal_fast_path_eligible:
@@ -651,7 +661,8 @@ def compile_three_piston_tangent_provider(
"amesim_lstp00a",
)
branches: list[ThreePistonBranch] = []
for names in _TARGET_BRANCH_NAMES:
for branch_spec in branch_specs:
names = branch_spec.names
try:
components = tuple(system.network.components[name] for name in names)
except KeyError:
@@ -671,6 +682,9 @@ def compile_three_piston_tangent_provider(
chamber=chamber,
pipe=pipe,
contact=contact,
chamber_connection_port=(
branch_spec.chamber_connection_port
),
velocity_index=offset,
position_index=offset + 1,
)
@@ -681,7 +695,15 @@ def compile_three_piston_tangent_provider(
required_pairs.update(
{
frozenset((Endpoint(branch.mass.name, "port_1"), Endpoint(branch.piston.name, "port_2"))),
frozenset((Endpoint(branch.piston.name, "port_1"), Endpoint(branch.chamber.name, "port_3"))),
frozenset(
(
Endpoint(branch.piston.name, "port_1"),
Endpoint(
branch.chamber.name,
branch.chamber_connection_port,
),
)
),
frozenset((Endpoint(branch.chamber.name, "port_1"), Endpoint(branch.pipe.name, "port_1"))),
frozenset((Endpoint(branch.piston.name, "port_5"), Endpoint(branch.contact.name, "port_1"))),
}
@@ -790,7 +812,7 @@ def compile_three_piston_tangent_provider(
# Secondary pressure blocks may contain the same causal flow coordinates,
# so membership alone is not evidence of a stream derivative. The direct
# enthalpy reach proof below, plus the runtime dynamic-owner gate, is the
# relevant condition for this target-specific program.
# relevant condition for this proof-gated branch program.
neighbor_by_endpoint: dict[Endpoint, Endpoint] = {}
for connection in system.network.connections:
if connection.kind != "physical":
@@ -848,3 +870,138 @@ def compile_three_piston_tangent_provider(
provider,
reached_assignment_count=len(reached_assignments),
)
def _physical_neighbor_map(
system: "GenericFluidSystem",
) -> dict[Endpoint, Endpoint]:
"""Return the one-to-one physical connector map proved by the network."""
neighbors: dict[Endpoint, Endpoint] = {}
for connection in system.network.connections:
if connection.kind != "physical":
continue
first, second = connection.endpoints
# SimulationNetwork already rejects multiply connected physical ports.
# Retain a defensive gate because this compiler may also be called by
# custom network builders in tests or downstream applications.
if first in neighbors or second in neighbors:
raise ValueError("Physical endpoint has more than one connection.")
neighbors[first] = second
neighbors[second] = first
return neighbors
def _discover_supported_piston_branch_specs(
system: "GenericFluidSystem",
) -> tuple[_PistonBranchSpec, ...] | ThreePistonTangentCompilation:
"""Discover every complete catalog piston branch by type and port topology.
A PNRP17 is the unambiguous root: its mechanical piston-side port must be
driven by a singleton MECMAS21 coordinate, its pneumatic port must feed a
PNCH012 whose first port feeds PNL0001, and its rod-side port must meet an
LSTP00A contact. If even one PNRP17 is only partially supported, reject the
batch with a stable reason instead of silently omitting derivative columns.
"""
try:
neighbors = _physical_neighbor_map(system)
except ValueError:
return _failed("unsupportedPistonBranchTopology:multipleConnection")
components = system.network.components
def model_type(endpoint: Endpoint | None) -> str | None:
if endpoint is None:
return None
return getattr(components[endpoint.component], "MODEL_TYPE", None)
pistons = tuple(
component
for component in components.values()
if getattr(component, "MODEL_TYPE", None) == "amesim_pnrp17"
)
if not pistons:
return _failed("supportedPistonBranchMissing")
specs: list[_PistonBranchSpec] = []
for piston in pistons:
mass_endpoint = neighbors.get(Endpoint(piston.name, "port_2"))
if (
model_type(mass_endpoint) != "amesim_mecmas21"
or mass_endpoint is None
or mass_endpoint.port != "port_1"
):
return _failed("unsupportedPistonBranchTopology:mass")
chamber_endpoint = neighbors.get(Endpoint(piston.name, "port_1"))
if model_type(chamber_endpoint) != "amesim_pnch012":
return _failed("unsupportedPistonBranchTopology:chamber")
assert chamber_endpoint is not None
pipe_endpoint = neighbors.get(
Endpoint(chamber_endpoint.component, "port_1")
)
if (
model_type(pipe_endpoint) != "amesim_pnl0001"
or pipe_endpoint is None
or pipe_endpoint.port != "port_1"
):
return _failed("unsupportedPistonBranchTopology:pipe")
contact_endpoint = neighbors.get(Endpoint(piston.name, "port_5"))
if (
model_type(contact_endpoint) != "amesim_lstp00a"
or contact_endpoint is None
or contact_endpoint.port != "port_1"
):
return _failed("unsupportedPistonBranchTopology:contact")
specs.append(
_PistonBranchSpec(
names=(
mass_endpoint.component,
piston.name,
chamber_endpoint.component,
pipe_endpoint.component,
contact_endpoint.component,
),
chamber_connection_port=chamber_endpoint.port,
)
)
# Port uniqueness already proves unique pistons and masses, but explicitly
# reject a custom multi-port chamber/contact/pipe shared by two roots. The
# tangent propagation assumes one geometry seed per selected state owner.
for role_index in range(5):
if len({spec.names[role_index] for spec in specs}) != len(specs):
return _failed("unsupportedPistonBranchTopology:sharedComponent")
return tuple(specs)
def compile_supported_piston_tangent_provider(
system: "GenericFluidSystem",
) -> ThreePistonTangentCompilation:
"""Compile all name-independent, topology-supported piston branches."""
discovered = _discover_supported_piston_branch_specs(system)
if isinstance(discovered, ThreePistonTangentCompilation):
return discovered
return _compile_named_piston_tangent_provider(system, discovered)
def compile_three_piston_tangent_provider(
system: "GenericFluidSystem",
) -> ThreePistonTangentCompilation:
"""Compile the committed legacy three-piston target by its stable names."""
return _compile_named_piston_tangent_provider(
system,
tuple(
_PistonBranchSpec(
names=names,
chamber_connection_port="port_3",
)
for names in _TARGET_BRANCH_NAMES
),
)