前端进度条性能优化、仿真结束后后处理优化;后端C代码生成流程优化:先识别来源,再按照已知未知量需求排序,最后局部求解

This commit is contained in:
ljz committed 2026-09-11 11:27:54 +08:00
1 parent 0dcb465d84
commit 91bd9fb252
77 files changed
+11223 -551

No files matched your search

+152
View File
@@ -0,0 +1,152 @@
"""Compile-time variable supply contracts, separate from physical flow direction.
Equation ports may participate in a simultaneous solve. Fixed ports (for example
an Amesim node's reference/branch ports) require complementary local supplies.
These declarations do not add numerical state or Python evaluation callbacks.
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import TYPE_CHECKING, Literal, Mapping
if TYPE_CHECKING:
from .ports import PortDefinition
VARIABLE_LABELS = {
"p": "压力", "T": "温度", "m_flow": "质量流率", "H_flow": "能量流率",
}
@dataclass(frozen=True)
class PortComputation:
inputs: tuple[str, ...] = ()
outputs: tuple[str, ...] = ()
mode: Literal["equation", "fixed"] = "equation"
# Output p/T aliases an input on another port of the same component.
reference_port: str | None = None
def __post_init__(self) -> None:
if self.mode not in {"equation", "fixed"}:
raise ValueError(f"Unknown port computation mode: {self.mode}")
members = (*self.inputs, *self.outputs)
if len(set(members)) != len(members) or set(members) - VARIABLE_LABELS.keys():
raise ValueError("Port computation variables must be unique, supported quantities.")
if self.reference_port and not {"p", "T"}.issubset(self.outputs):
raise ValueError("A reference alias must supply pressure and temperature.")
def as_dict(self) -> dict[str, object]:
return {
"mode": self.mode,
"inputs": list(self.inputs),
"outputs": list(self.outputs),
**({"referencePort": self.reference_port} if self.reference_port else {}),
}
THERMODYNAMIC_SUPPLY = PortComputation(inputs=("m_flow", "H_flow"), outputs=("p", "T"))
FLOW_SUPPLY = PortComputation(inputs=("p", "T"), outputs=("m_flow", "H_flow"))
ZERO_FLOW_SUPPLY = PortComputation(outputs=("m_flow", "H_flow"))
IMPLICIT_PNEUMATIC = PortComputation()
NODE_REFERENCE = PortComputation(inputs=("p", "T"), outputs=("m_flow", "H_flow"), mode="fixed")
NODE_BRANCH = PortComputation(inputs=("m_flow", "H_flow"), outputs=("p", "T"),
mode="fixed", reference_port="port_2")
@dataclass(frozen=True)
class PortSupplyIssue:
code: str
message: str
endpoint: tuple[str, str] | None = None
class PortSupplyError(ValueError):
def __init__(self, issue: PortSupplyIssue):
self.issue = issue
super().__init__(f"{issue.code}: {issue.message}")
def port_supply_issue(first: PortDefinition, second: PortDefinition,
first_label: str | None = None, second_label: str | None = None
) -> PortSupplyIssue | None:
"""Check fixed causality; ordinary equation-to-equation links stay legal."""
if first.kind != second.kind or first.domain != second.domain:
return None # Domain/type checks own their existing, more specific errors.
a, b = first.computation, second.computation
if not any(item and item.mode == "fixed" for item in (a, b)):
return None
for consumer, supplier, consumer_label, supplier_label in (
(a, b, first_label or first.name, second_label or second.name),
(b, a, second_label or second.name, first_label or first.name),
):
if consumer is None:
continue
missing = [name for name in consumer.inputs
if supplier is None or name not in supplier.outputs]
if missing:
quantities = "、".join(VARIABLE_LABELS[name] for name in missing)
return PortSupplyIssue(
"CONNECTION_VARIABLE_SUPPLY_MISSING",
f"{consumer_label} 需要对端提供{quantities},但 {supplier_label} 未提供;"
"请检查参考口与支路口的连接。气体流向反转不会改变这一供需关系。",
)
return None
def reference_supply_issues(
ports: Mapping[tuple[str, str], PortDefinition],
adjacency: Mapping[tuple[str, str], tuple[str, str]],
) -> list[PortSupplyIssue]:
"""Follow declared aliases to reject a reference ring without an origin.
This is a supply check, not a whole-system execution scheduler. Reference
chains are iterative to support deep networks without Python recursion.
"""
issues = []
resolved: dict[str, set[tuple[str, str]]] = {'p': set(), 'T': set()}
for endpoint, port in ports.items():
contract = port.computation
if not contract or contract.mode != "fixed" or not {"p", "T"}.issubset(contract.inputs):
continue
if endpoint not in adjacency:
continue # Existing unconnected-port checks handle incomplete drawings.
for variable in ("p", "T"):
current = endpoint
visited: set[tuple[str, str]] = set()
chain: list[str] = []
while True:
if current in resolved[variable]:
resolved[variable].update(visited)
break
if current in visited:
issues.append(PortSupplyIssue(
"REFERENCE_SUPPLY_CYCLE",
f"{'.'.join(endpoint)} 的{VARIABLE_LABELS[variable]}参考形成循环,"
f"没有实际提供者:{' → '.join(chain)} → {'.'.join(current)}。",
endpoint,
))
break
visited.add(current)
chain.append('.'.join(current))
supplier = adjacency.get(current)
if supplier is None:
issues.append(PortSupplyIssue(
"REFERENCE_SUPPLY_UNCONNECTED",
f"{'.'.join(endpoint)} 的{VARIABLE_LABELS[variable]}参考链在 "
f"{'.'.join(current)} 中断:该参考输入尚未连接。", endpoint,
))
break
supplied = ports.get(supplier)
supply = supplied.computation if supplied else None
if supply is None or variable not in supply.outputs:
# Direct errors are already reported per connection. An
# indirect failure is explained at that failing connection.
break
if supply.reference_port is None:
resolved[variable].update(visited)
break
chain.append('.'.join(supplier))
current = supplier[0], supply.reference_port
if current not in ports:
raise ValueError(f"Invalid reference port declaration: {current}")
return issues