存档求解器回归基线与当前改动
纳管 AMESim 对齐基线、发布锁、回归测试及当前物理门禁调整。 更新日志仅记录已完成成果,并注明当前 HEAD 尚待真实 production 复跑与远端 workflow 验证。
This commit is contained in:
1 parent
53f8601fec
commit
a8c733883c
32 files changed
+47239
-106
No files matched your search
@@ -76,11 +76,12 @@ jobs:
|
|||||||
cache-dependency-path: |
|
cache-dependency-path: |
|
||||||
requirements.txt
|
requirements.txt
|
||||||
constraints/python312-direct.txt
|
constraints/python312-direct.txt
|
||||||
- name: Install reference dependencies
|
constraints/python312-linux-x86_64.lock
|
||||||
|
- name: Install hashed Linux release lock
|
||||||
run: |
|
run: |
|
||||||
python -m pip install \
|
python -m pip install \
|
||||||
-r requirements.txt \
|
--force-reinstall \
|
||||||
-c constraints/python312-direct.txt
|
-r constraints/python312-linux-x86_64.lock
|
||||||
python -m pip check
|
python -m pip check
|
||||||
- name: Run solver foundation tests
|
- name: Run solver foundation tests
|
||||||
env:
|
env:
|
||||||
@@ -89,6 +90,8 @@ jobs:
|
|||||||
python -W error::ResourceWarning -m unittest \
|
python -W error::ResourceWarning -m unittest \
|
||||||
tests.test_dependency_constraints \
|
tests.test_dependency_constraints \
|
||||||
tests.test_benchmark_regression \
|
tests.test_benchmark_regression \
|
||||||
|
tests.test_physical_state_v21 \
|
||||||
|
tests.test_test_mql_ame_contract \
|
||||||
tests.test_test_mql_8_regression \
|
tests.test_test_mql_8_regression \
|
||||||
tests.test_mql_full_branches_regression \
|
tests.test_mql_full_branches_regression \
|
||||||
tests.test_pressure_flow_causal_execution \
|
tests.test_pressure_flow_causal_execution \
|
||||||
@@ -115,18 +118,19 @@ jobs:
|
|||||||
cache-dependency-path: |
|
cache-dependency-path: |
|
||||||
requirements.txt
|
requirements.txt
|
||||||
constraints/python312-direct.txt
|
constraints/python312-direct.txt
|
||||||
- name: Install reference dependencies
|
constraints/python312-linux-x86_64.lock
|
||||||
|
- name: Install hashed Linux release lock
|
||||||
run: |
|
run: |
|
||||||
python -m pip install \
|
python -m pip install \
|
||||||
-r requirements.txt \
|
--force-reinstall \
|
||||||
-c constraints/python312-direct.txt
|
-r constraints/python312-linux-x86_64.lock
|
||||||
python -m pip check
|
python -m pip check
|
||||||
- name: Run 0.81 and 2.10 second historical regression
|
- name: Run 0.81 and 2.10 second historical regression
|
||||||
run: |
|
run: |
|
||||||
mkdir -p artifacts
|
mkdir -p artifacts
|
||||||
python -m app.simulation.benchmark_regression \
|
python -m app.simulation.benchmark_regression \
|
||||||
--manifest tests/baselines/simulation/test_mql_full_branches/manifest.json \
|
--manifest tests/baselines/simulation/test_mql_full_branches/manifest.json \
|
||||||
--lane solver-only \
|
--lane production \
|
||||||
--output artifacts/test-mql-full-branches.json
|
--output artifacts/test-mql-full-branches.json
|
||||||
- if: always()
|
- if: always()
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
@@ -150,11 +154,12 @@ jobs:
|
|||||||
cache-dependency-path: |
|
cache-dependency-path: |
|
||||||
requirements.txt
|
requirements.txt
|
||||||
constraints/python312-direct.txt
|
constraints/python312-direct.txt
|
||||||
- name: Install reference dependencies
|
constraints/python312-linux-x86_64.lock
|
||||||
|
- name: Install hashed Linux release lock
|
||||||
run: |
|
run: |
|
||||||
python -m pip install \
|
python -m pip install \
|
||||||
-r requirements.txt \
|
--force-reinstall \
|
||||||
-c constraints/python312-direct.txt
|
-r constraints/python312-linux-x86_64.lock
|
||||||
python -m pip check
|
python -m pip check
|
||||||
- name: Run bounded progressive main-model regression
|
- name: Run bounded progressive main-model regression
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ ReactFlow 系统建模与 `app.simulation` 仿真后端。
|
|||||||
|
|
||||||
后端统一使用 Python 3.12;仓库根目录的 `.python-version` 记录本轮参考补丁版本
|
后端统一使用 Python 3.12;仓库根目录的 `.python-version` 记录本轮参考补丁版本
|
||||||
`3.12.3`。`requirements.txt` 保留支持范围,
|
`3.12.3`。`requirements.txt` 保留支持范围,
|
||||||
`constraints/python312-direct.txt` 固定应用直接依赖的参考版本。普通开发、性能复测和
|
`constraints/python312-direct.txt` 固定跨平台开发环境的直接依赖参考版本;
|
||||||
CI 应同时使用两者,以避免同一代码在不同时间解析到不同的 NumPy、SciPy 或 Web
|
`constraints/python312-linux-x86_64.lock` 则完整固定发布与 CI 所用的 Linux x86_64
|
||||||
框架版本。
|
wheel、全部传递依赖及其 SHA-256。
|
||||||
|
|
||||||
Windows:
|
Windows:
|
||||||
|
|
||||||
@@ -25,20 +25,21 @@ Linux:
|
|||||||
```bash
|
```bash
|
||||||
python3.12 -m venv .venv
|
python3.12 -m venv .venv
|
||||||
./.venv/bin/python -m pip install \
|
./.venv/bin/python -m pip install \
|
||||||
-r requirements.txt \
|
-r constraints/python312-linux-x86_64.lock
|
||||||
-c constraints/python312-direct.txt
|
|
||||||
./.venv/bin/python -m pip check
|
./.venv/bin/python -m pip check
|
||||||
```
|
```
|
||||||
|
|
||||||
约束文件只固定代码直接导入或启动的 `fastapi`、`lxml`、`numpy`、`pydantic`、
|
Linux 发布锁仅适用于兼容 manylinux_2_28 的 Linux x86_64 和 CPython 3.12。它启用
|
||||||
`scipy` 和 `uvicorn`。`uvicorn[standard]` 的可选传递依赖包含平台差异,因此仍由 pip
|
`--only-binary=:all:` 与 `--require-hashes`,因此不会静默改用源码包或未审计 wheel;
|
||||||
按目标平台解析;这套方案固定求解器和接口层的主要版本,但不是带 wheel 哈希的逐位
|
CI 和正式性能复测必须直接以 `-r` 安装该文件。Windows 或其他平台的开发环境继续
|
||||||
相同发布锁。若要测试 `requirements.txt` 声明的兼容范围,可显式省略 `-c`,但这类
|
使用 `requirements.txt` 加 `constraints/python312-direct.txt`。若要测试
|
||||||
结果不应与受约束环境的性能数据直接比较。
|
`requirements.txt` 声明的兼容范围,可显式省略约束,但这类结果不应与锁定环境的
|
||||||
|
性能数据直接比较。
|
||||||
|
|
||||||
升级参考版本时,应在干净的 Python 3.12 虚拟环境中同时安装范围文件和约束文件,
|
升级参考版本时,应在干净的 Python 3.12 Linux x86_64 虚拟环境中解析范围文件,
|
||||||
运行 `pip check` 与后端测试,再更新约束;不要从单个平台的 `pip freeze` 直接复制
|
仅下载兼容 wheel,逐个记录 wheel 的 SHA-256,再从空环境安装发布锁并运行
|
||||||
所有传递依赖。
|
`pip check`、依赖契约测试与后端测试。不能只复制 `pip freeze`,因为它既不证明
|
||||||
|
依赖来源,也不校验安装产物。
|
||||||
|
|
||||||
前端使用 Vite 8,需要 Node.js `20.19+` 或 `22.12+`。首次启动前安装前端依赖。
|
前端使用 Vite 8,需要 Node.js `20.19+` 或 `22.12+`。首次启动前安装前端依赖。
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,14 @@ from time import monotonic, perf_counter, process_time
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
from app.simulation.physical_state_v21 import (
|
||||||
|
PhysicalStateV21Error,
|
||||||
|
evaluate_physical_state_v21,
|
||||||
|
load_approved_golden as load_physical_state_v21_golden,
|
||||||
|
physical_state_v21_applicable,
|
||||||
|
project_physical_state_v21,
|
||||||
|
)
|
||||||
|
|
||||||
try: # resource is unavailable on native Windows Python.
|
try: # resource is unavailable on native Windows Python.
|
||||||
import resource
|
import resource
|
||||||
except ImportError: # pragma: no cover - Windows regression job
|
except ImportError: # pragma: no cover - Windows regression job
|
||||||
@@ -456,6 +464,50 @@ def load_regression_manifest(path: Path | str) -> dict[str, object]:
|
|||||||
"Authoritative XML byte count does not match manifest source.bytes."
|
"Authoritative XML byte count does not match manifest source.bytes."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
reference_archive = source.get("referenceArchive")
|
||||||
|
reference_archive_path: Path | None = None
|
||||||
|
reference_archive_sha256: str | None = None
|
||||||
|
if reference_archive is not None:
|
||||||
|
if not isinstance(reference_archive, Mapping):
|
||||||
|
raise RegressionManifestError(
|
||||||
|
"Manifest source.referenceArchive must be an object when declared."
|
||||||
|
)
|
||||||
|
archive_path_value = reference_archive.get("path")
|
||||||
|
archive_sha256 = reference_archive.get("sha256")
|
||||||
|
archive_bytes = reference_archive.get("bytes")
|
||||||
|
if (
|
||||||
|
not isinstance(archive_path_value, str)
|
||||||
|
or not archive_path_value
|
||||||
|
or not _valid_sha256(archive_sha256)
|
||||||
|
or not isinstance(archive_bytes, int)
|
||||||
|
or archive_bytes <= 0
|
||||||
|
or reference_archive.get("role") != "authoritativePhysicalBaseline"
|
||||||
|
):
|
||||||
|
raise RegressionManifestError(
|
||||||
|
"Manifest AMESim reference archive identity or role is incomplete."
|
||||||
|
)
|
||||||
|
reference_archive_path = (repository_root / archive_path_value).resolve()
|
||||||
|
if not reference_archive_path.is_relative_to(repository_root):
|
||||||
|
raise RegressionManifestError(
|
||||||
|
"AMESim reference archive must remain inside the repository."
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
archive_payload = reference_archive_path.read_bytes()
|
||||||
|
except OSError as exc:
|
||||||
|
raise RegressionManifestError(
|
||||||
|
f"Could not read AMESim reference archive {reference_archive_path}: {exc}"
|
||||||
|
) from exc
|
||||||
|
if len(archive_payload) != archive_bytes:
|
||||||
|
raise RegressionManifestError(
|
||||||
|
"AMESim reference archive byte count mismatch."
|
||||||
|
)
|
||||||
|
actual_archive_sha256 = _sha256(archive_payload)
|
||||||
|
if actual_archive_sha256 != archive_sha256:
|
||||||
|
raise RegressionManifestError(
|
||||||
|
"AMESim reference archive hash mismatch."
|
||||||
|
)
|
||||||
|
reference_archive_sha256 = str(archive_sha256)
|
||||||
|
|
||||||
companion = source.get("companionProject")
|
companion = source.get("companionProject")
|
||||||
companion_path: Path | None = None
|
companion_path: Path | None = None
|
||||||
if companion is not None:
|
if companion is not None:
|
||||||
@@ -627,6 +679,28 @@ def load_regression_manifest(path: Path | str) -> dict[str, object]:
|
|||||||
correctness = manifest.get("correctness")
|
correctness = manifest.get("correctness")
|
||||||
if not isinstance(correctness, dict):
|
if not isinstance(correctness, dict):
|
||||||
raise RegressionManifestError("Manifest correctness must be an object.")
|
raise RegressionManifestError("Manifest correctness must be an object.")
|
||||||
|
python_golden_role = correctness.get("pythonGoldenRole", "acceptanceGate")
|
||||||
|
if python_golden_role not in {
|
||||||
|
"acceptanceGate",
|
||||||
|
"determinismDiagnosticOnly",
|
||||||
|
}:
|
||||||
|
raise RegressionManifestError(
|
||||||
|
"correctness.pythonGoldenRole must be acceptanceGate or "
|
||||||
|
"determinismDiagnosticOnly."
|
||||||
|
)
|
||||||
|
physical_baseline_authority = correctness.get("physicalBaselineAuthority")
|
||||||
|
compare_amesim_on_every_run = correctness.get(
|
||||||
|
"compareAmesimOnEveryRun", False
|
||||||
|
)
|
||||||
|
if physical_baseline_authority is not None and (
|
||||||
|
physical_baseline_authority != "amesim"
|
||||||
|
or compare_amesim_on_every_run is not True
|
||||||
|
or reference_archive_path is None
|
||||||
|
):
|
||||||
|
raise RegressionManifestError(
|
||||||
|
"AMESim physical authority requires a validated reference archive "
|
||||||
|
"and compareAmesimOnEveryRun=true."
|
||||||
|
)
|
||||||
state_relative_tolerance = _finite_nonnegative(
|
state_relative_tolerance = _finite_nonnegative(
|
||||||
correctness.get("stateRelativeTolerance"),
|
correctness.get("stateRelativeTolerance"),
|
||||||
field="correctness.stateRelativeTolerance",
|
field="correctness.stateRelativeTolerance",
|
||||||
@@ -641,6 +715,9 @@ def load_regression_manifest(path: Path | str) -> dict[str, object]:
|
|||||||
)
|
)
|
||||||
|
|
||||||
loaded_goldens: dict[str, dict[str, dict[str, object]]] = {}
|
loaded_goldens: dict[str, dict[str, dict[str, object]]] = {}
|
||||||
|
loaded_physical_state_v21_goldens: dict[
|
||||||
|
str, dict[str, dict[str, object]]
|
||||||
|
] = {}
|
||||||
for case_id in sequence:
|
for case_id in sequence:
|
||||||
variant = variants[case_id]
|
variant = variants[case_id]
|
||||||
assert isinstance(variant, dict)
|
assert isinstance(variant, dict)
|
||||||
@@ -654,6 +731,14 @@ def load_regression_manifest(path: Path | str) -> dict[str, object]:
|
|||||||
raise RegressionManifestError(
|
raise RegressionManifestError(
|
||||||
f"Variant {case_id!r} has an invalid golden lane reference."
|
f"Variant {case_id!r} has an invalid golden lane reference."
|
||||||
)
|
)
|
||||||
|
if python_golden_role == "determinismDiagnosticOnly" and (
|
||||||
|
reference.get("role") != "pythonDeterminismRegression"
|
||||||
|
or reference.get("affectsPhysicalCorrectness") is not False
|
||||||
|
):
|
||||||
|
raise RegressionManifestError(
|
||||||
|
f"Variant {case_id!r} Python golden must be marked as a "
|
||||||
|
"non-physical determinism regression."
|
||||||
|
)
|
||||||
golden_path_value = reference.get("path")
|
golden_path_value = reference.get("path")
|
||||||
golden_sha256 = reference.get("sha256")
|
golden_sha256 = reference.get("sha256")
|
||||||
if (
|
if (
|
||||||
@@ -704,6 +789,95 @@ def load_regression_manifest(path: Path | str) -> dict[str, object]:
|
|||||||
)
|
)
|
||||||
loaded_goldens.setdefault(case_id, {})[lane_name] = golden
|
loaded_goldens.setdefault(case_id, {})[lane_name] = golden
|
||||||
|
|
||||||
|
raw_physical_state_v21_goldens = variant.get(
|
||||||
|
"physicalStateV21Goldens", {}
|
||||||
|
)
|
||||||
|
if not isinstance(raw_physical_state_v21_goldens, dict):
|
||||||
|
raise RegressionManifestError(
|
||||||
|
f"Variant {case_id!r} physicalStateV21Goldens must be an object "
|
||||||
|
"keyed by lane."
|
||||||
|
)
|
||||||
|
for lane_name, reference in raw_physical_state_v21_goldens.items():
|
||||||
|
if lane_name not in lanes or not isinstance(reference, Mapping):
|
||||||
|
raise RegressionManifestError(
|
||||||
|
f"Variant {case_id!r} has an invalid physical-state-v2.1 "
|
||||||
|
"golden lane reference."
|
||||||
|
)
|
||||||
|
if physical_baseline_authority == "amesim" and (
|
||||||
|
reference.get("role") != "amesimPhysicalBaseline"
|
||||||
|
or reference.get("compareOnEveryRun") is not True
|
||||||
|
):
|
||||||
|
raise RegressionManifestError(
|
||||||
|
f"Variant {case_id!r} physical-state reference must be marked "
|
||||||
|
"as the per-run AMESim physical baseline."
|
||||||
|
)
|
||||||
|
golden_path_value = reference.get("path")
|
||||||
|
golden_sha256 = reference.get("sha256")
|
||||||
|
if (
|
||||||
|
not isinstance(golden_path_value, str)
|
||||||
|
or not golden_path_value
|
||||||
|
or not _valid_sha256(golden_sha256)
|
||||||
|
):
|
||||||
|
raise RegressionManifestError(
|
||||||
|
f"Variant {case_id!r} physical-state-v2.1 golden reference "
|
||||||
|
"is incomplete."
|
||||||
|
)
|
||||||
|
golden_path = (repository_root / golden_path_value).resolve()
|
||||||
|
if not golden_path.is_relative_to(repository_root):
|
||||||
|
raise RegressionManifestError(
|
||||||
|
"Physical-state-v2.1 golden must remain inside the repository."
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
physical_state_golden = load_physical_state_v21_golden(golden_path)
|
||||||
|
except (OSError, PhysicalStateV21Error) as exc:
|
||||||
|
raise RegressionManifestError(
|
||||||
|
f"Could not load physical-state-v2.1 golden {golden_path}: {exc}"
|
||||||
|
) from exc
|
||||||
|
if physical_state_golden.get("_sha256") != golden_sha256:
|
||||||
|
raise RegressionManifestError(
|
||||||
|
f"Variant {case_id!r} physical-state-v2.1 golden hash mismatch."
|
||||||
|
)
|
||||||
|
if (
|
||||||
|
physical_state_golden.get("caseId") != case_id
|
||||||
|
or physical_state_golden.get("lane") != lane_name
|
||||||
|
or physical_state_golden.get("sourceXmlSha256") != expected_sha256
|
||||||
|
):
|
||||||
|
raise RegressionManifestError(
|
||||||
|
f"Variant {case_id!r} physical-state-v2.1 golden identity "
|
||||||
|
"does not match the manifest."
|
||||||
|
)
|
||||||
|
physical_provenance = physical_state_golden.get("provenance")
|
||||||
|
physical_amesim = (
|
||||||
|
physical_provenance.get("amesim")
|
||||||
|
if isinstance(physical_provenance, Mapping)
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
if physical_baseline_authority == "amesim" and (
|
||||||
|
not isinstance(physical_amesim, Mapping)
|
||||||
|
or physical_amesim.get("archiveSha256")
|
||||||
|
!= reference_archive_sha256
|
||||||
|
):
|
||||||
|
raise RegressionManifestError(
|
||||||
|
f"Variant {case_id!r} AMESim baseline provenance does not "
|
||||||
|
"match source.referenceArchive."
|
||||||
|
)
|
||||||
|
expected_times = [float(value) for value in variant["checkpointTimes"]]
|
||||||
|
physical_state_checkpoints = physical_state_golden.get("checkpoints")
|
||||||
|
assert isinstance(physical_state_checkpoints, list)
|
||||||
|
golden_times = [
|
||||||
|
float(checkpoint["requestedTime"])
|
||||||
|
for checkpoint in physical_state_checkpoints
|
||||||
|
if isinstance(checkpoint, Mapping)
|
||||||
|
]
|
||||||
|
if expected_times != golden_times:
|
||||||
|
raise RegressionManifestError(
|
||||||
|
f"Variant {case_id!r} physical-state-v2.1 golden checkpoint "
|
||||||
|
"times differ from manifest."
|
||||||
|
)
|
||||||
|
loaded_physical_state_v21_goldens.setdefault(case_id, {})[
|
||||||
|
lane_name
|
||||||
|
] = physical_state_golden
|
||||||
|
|
||||||
_finite_positive(
|
_finite_positive(
|
||||||
execution.get("predictionSafetyFactor", 1.0),
|
execution.get("predictionSafetyFactor", 1.0),
|
||||||
field="execution.predictionSafetyFactor",
|
field="execution.predictionSafetyFactor",
|
||||||
@@ -720,10 +894,14 @@ def load_regression_manifest(path: Path | str) -> dict[str, object]:
|
|||||||
manifest["_manifestPath"] = str(manifest_path)
|
manifest["_manifestPath"] = str(manifest_path)
|
||||||
manifest["_repositoryRoot"] = str(repository_root)
|
manifest["_repositoryRoot"] = str(repository_root)
|
||||||
manifest["_sourcePath"] = str(source_path)
|
manifest["_sourcePath"] = str(source_path)
|
||||||
|
manifest["_referenceArchivePath"] = (
|
||||||
|
str(reference_archive_path) if reference_archive_path is not None else None
|
||||||
|
)
|
||||||
manifest["_companionPath"] = (
|
manifest["_companionPath"] = (
|
||||||
str(companion_path) if companion_path is not None else None
|
str(companion_path) if companion_path is not None else None
|
||||||
)
|
)
|
||||||
manifest["_goldens"] = loaded_goldens
|
manifest["_goldens"] = loaded_goldens
|
||||||
|
manifest["_physicalStateV21Goldens"] = loaded_physical_state_v21_goldens
|
||||||
return manifest
|
return manifest
|
||||||
|
|
||||||
|
|
||||||
@@ -1105,7 +1283,7 @@ def summarize_simulation_result(
|
|||||||
"eventTrace": event_trace,
|
"eventTrace": event_trace,
|
||||||
"comparisonMode": "numericTolerance",
|
"comparisonMode": "numericTolerance",
|
||||||
}
|
}
|
||||||
return {
|
summary = {
|
||||||
"success": bool(result.get("success")),
|
"success": bool(result.get("success")),
|
||||||
"status": result.get("status"),
|
"status": result.get("status"),
|
||||||
"partial": bool(result.get("partial")),
|
"partial": bool(result.get("partial")),
|
||||||
@@ -1126,6 +1304,13 @@ def summarize_simulation_result(
|
|||||||
"diagnostics": dict(diagnostic_mapping),
|
"diagnostics": dict(diagnostic_mapping),
|
||||||
"eventTrace": event_trace,
|
"eventTrace": event_trace,
|
||||||
}
|
}
|
||||||
|
if physical_state_v21_applicable(result):
|
||||||
|
summary["physicalStateV21"] = project_physical_state_v21(
|
||||||
|
result,
|
||||||
|
checkpoint_times=checkpoint_times,
|
||||||
|
sample_step=sample_step,
|
||||||
|
)
|
||||||
|
return summary
|
||||||
|
|
||||||
|
|
||||||
def _worker_control_listener(cancel_event: threading.Event) -> None:
|
def _worker_control_listener(cancel_event: threading.Event) -> None:
|
||||||
@@ -1666,6 +1851,77 @@ def evaluate_regression_golden(
|
|||||||
return audit
|
return audit
|
||||||
|
|
||||||
|
|
||||||
|
def evaluate_physical_state_v21_golden(
|
||||||
|
summary: Mapping[str, object] | None,
|
||||||
|
golden: Mapping[str, object] | None,
|
||||||
|
) -> dict[str, object]:
|
||||||
|
"""Evaluate the algebraic/discrete v2.1 contract when a manifest pins it."""
|
||||||
|
|
||||||
|
if golden is None:
|
||||||
|
return {
|
||||||
|
"configured": False,
|
||||||
|
"evaluated": False,
|
||||||
|
"passed": None,
|
||||||
|
"issues": [],
|
||||||
|
}
|
||||||
|
provenance = golden.get("provenance")
|
||||||
|
amesim_provenance = (
|
||||||
|
provenance.get("amesim") if isinstance(provenance, Mapping) else None
|
||||||
|
)
|
||||||
|
alignment = golden.get("amesimAlignmentAtGeneration")
|
||||||
|
audit: dict[str, object] = {
|
||||||
|
"configured": True,
|
||||||
|
"evaluated": False,
|
||||||
|
"passed": False,
|
||||||
|
"goldenId": golden.get("id"),
|
||||||
|
"goldenPath": golden.get("_path"),
|
||||||
|
"goldenSha256": golden.get("_sha256"),
|
||||||
|
"amesimArchiveSha256": (
|
||||||
|
amesim_provenance.get("archiveSha256")
|
||||||
|
if isinstance(amesim_provenance, Mapping)
|
||||||
|
else None
|
||||||
|
),
|
||||||
|
"amesimAlignmentAtGenerationPassed": (
|
||||||
|
alignment.get("passed") if isinstance(alignment, Mapping) else None
|
||||||
|
),
|
||||||
|
"issues": [],
|
||||||
|
"metrics": [],
|
||||||
|
}
|
||||||
|
if summary is None:
|
||||||
|
audit["issues"] = ["missingSummaryForPhysicalStateV21Golden"]
|
||||||
|
return audit
|
||||||
|
contract = summary.get("physicalStateV21")
|
||||||
|
if not isinstance(contract, Mapping):
|
||||||
|
audit["issues"] = ["missingPhysicalStateV21Contract"]
|
||||||
|
return audit
|
||||||
|
audit["evaluated"] = True
|
||||||
|
try:
|
||||||
|
evaluation = evaluate_physical_state_v21(contract, golden)
|
||||||
|
except PhysicalStateV21Error as exc:
|
||||||
|
audit["issues"] = ["invalidPhysicalStateV21Contract"]
|
||||||
|
audit["error"] = str(exc)
|
||||||
|
return audit
|
||||||
|
audit.update(evaluation)
|
||||||
|
audit.update(
|
||||||
|
{
|
||||||
|
"configured": True,
|
||||||
|
"evaluated": True,
|
||||||
|
"goldenId": golden.get("id"),
|
||||||
|
"goldenPath": golden.get("_path"),
|
||||||
|
"goldenSha256": golden.get("_sha256"),
|
||||||
|
"amesimArchiveSha256": (
|
||||||
|
amesim_provenance.get("archiveSha256")
|
||||||
|
if isinstance(amesim_provenance, Mapping)
|
||||||
|
else None
|
||||||
|
),
|
||||||
|
"amesimAlignmentAtGenerationPassed": (
|
||||||
|
alignment.get("passed") if isinstance(alignment, Mapping) else None
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return audit
|
||||||
|
|
||||||
|
|
||||||
def _case_correctness_issues(
|
def _case_correctness_issues(
|
||||||
result: Mapping[str, object],
|
result: Mapping[str, object],
|
||||||
*,
|
*,
|
||||||
@@ -1827,8 +2083,20 @@ def _case_correctness_issues(
|
|||||||
if isinstance(golden_evaluation, Mapping):
|
if isinstance(golden_evaluation, Mapping):
|
||||||
raw_golden_issues = golden_evaluation.get("issues")
|
raw_golden_issues = golden_evaluation.get("issues")
|
||||||
if isinstance(raw_golden_issues, list):
|
if isinstance(raw_golden_issues, list):
|
||||||
|
python_golden_role = correctness.get(
|
||||||
|
"pythonGoldenRole", "acceptanceGate"
|
||||||
|
)
|
||||||
|
accepted_issues = (
|
||||||
|
raw_golden_issues
|
||||||
|
if python_golden_role == "acceptanceGate"
|
||||||
|
else [
|
||||||
|
issue
|
||||||
|
for issue in raw_golden_issues
|
||||||
|
if issue in {"missingOutputContract", "outputContractMismatch"}
|
||||||
|
]
|
||||||
|
)
|
||||||
issues.extend(
|
issues.extend(
|
||||||
str(issue) for issue in raw_golden_issues if isinstance(issue, str)
|
str(issue) for issue in accepted_issues if isinstance(issue, str)
|
||||||
)
|
)
|
||||||
return tuple(dict.fromkeys(issues))
|
return tuple(dict.fromkeys(issues))
|
||||||
|
|
||||||
@@ -1912,6 +2180,10 @@ def run_regression_suite(
|
|||||||
assert isinstance(correctness, dict)
|
assert isinstance(correctness, dict)
|
||||||
loaded_goldens = manifest.get("_goldens", {})
|
loaded_goldens = manifest.get("_goldens", {})
|
||||||
assert isinstance(loaded_goldens, dict)
|
assert isinstance(loaded_goldens, dict)
|
||||||
|
loaded_physical_state_v21_goldens = manifest.get(
|
||||||
|
"_physicalStateV21Goldens", {}
|
||||||
|
)
|
||||||
|
assert isinstance(loaded_physical_state_v21_goldens, dict)
|
||||||
|
|
||||||
case_reports: list[dict[str, object]] = []
|
case_reports: list[dict[str, object]] = []
|
||||||
predecessor_completed = True
|
predecessor_completed = True
|
||||||
@@ -1988,6 +2260,45 @@ def run_regression_suite(
|
|||||||
summary if isinstance(summary, Mapping) else None,
|
summary if isinstance(summary, Mapping) else None,
|
||||||
golden if isinstance(golden, Mapping) else None,
|
golden if isinstance(golden, Mapping) else None,
|
||||||
)
|
)
|
||||||
|
golden_evaluation["role"] = correctness.get(
|
||||||
|
"pythonGoldenRole", "acceptanceGate"
|
||||||
|
)
|
||||||
|
golden_evaluation["affectsPhysicalCorrectness"] = (
|
||||||
|
correctness.get("pythonGoldenRole", "acceptanceGate")
|
||||||
|
== "acceptanceGate"
|
||||||
|
)
|
||||||
|
raw_python_golden_issues = golden_evaluation.get("issues")
|
||||||
|
golden_evaluation["acceptanceIssues"] = (
|
||||||
|
list(raw_python_golden_issues)
|
||||||
|
if correctness.get("pythonGoldenRole", "acceptanceGate")
|
||||||
|
== "acceptanceGate"
|
||||||
|
and isinstance(raw_python_golden_issues, list)
|
||||||
|
else [
|
||||||
|
issue
|
||||||
|
for issue in (
|
||||||
|
raw_python_golden_issues
|
||||||
|
if isinstance(raw_python_golden_issues, list)
|
||||||
|
else []
|
||||||
|
)
|
||||||
|
if issue in {"missingOutputContract", "outputContractMismatch"}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
case_physical_state_v21_goldens = loaded_physical_state_v21_goldens.get(
|
||||||
|
case_id, {}
|
||||||
|
)
|
||||||
|
physical_state_v21_golden = (
|
||||||
|
case_physical_state_v21_goldens.get(lane)
|
||||||
|
if isinstance(case_physical_state_v21_goldens, Mapping)
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
physical_state_v21_evaluation = evaluate_physical_state_v21_golden(
|
||||||
|
summary if isinstance(summary, Mapping) else None,
|
||||||
|
(
|
||||||
|
physical_state_v21_golden
|
||||||
|
if isinstance(physical_state_v21_golden, Mapping)
|
||||||
|
else None
|
||||||
|
),
|
||||||
|
)
|
||||||
correctness_issues = (
|
correctness_issues = (
|
||||||
_case_correctness_issues(
|
_case_correctness_issues(
|
||||||
result,
|
result,
|
||||||
@@ -1998,6 +2309,21 @@ def run_regression_suite(
|
|||||||
if solver_completed
|
if solver_completed
|
||||||
else ()
|
else ()
|
||||||
)
|
)
|
||||||
|
if solver_completed:
|
||||||
|
raw_v21_issues = physical_state_v21_evaluation.get("issues")
|
||||||
|
if isinstance(raw_v21_issues, list):
|
||||||
|
correctness_issues = tuple(
|
||||||
|
dict.fromkeys(
|
||||||
|
(
|
||||||
|
*correctness_issues,
|
||||||
|
*(
|
||||||
|
str(issue)
|
||||||
|
for issue in raw_v21_issues
|
||||||
|
if isinstance(issue, str)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
report = {
|
report = {
|
||||||
"caseId": case_id,
|
"caseId": case_id,
|
||||||
"stopTime": stop_time,
|
"stopTime": stop_time,
|
||||||
@@ -2016,6 +2342,7 @@ def run_regression_suite(
|
|||||||
"passed": solver_completed and not correctness_issues,
|
"passed": solver_completed and not correctness_issues,
|
||||||
"issues": list(correctness_issues),
|
"issues": list(correctness_issues),
|
||||||
"regressionGolden": golden_evaluation,
|
"regressionGolden": golden_evaluation,
|
||||||
|
"physicalStateV21Golden": physical_state_v21_evaluation,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if solver_completed and correctness_issues:
|
if solver_completed and correctness_issues:
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -23,6 +23,8 @@ class TestMqlComparisonMetric:
|
|||||||
max_abs_error: float
|
max_abs_error: float
|
||||||
mean_abs_error: float
|
mean_abs_error: float
|
||||||
max_rel_error: float
|
max_rel_error: float
|
||||||
|
undefined_rel_error_count: int
|
||||||
|
near_zero_baseline_count: int
|
||||||
final_abs_error: float
|
final_abs_error: float
|
||||||
|
|
||||||
|
|
||||||
@@ -44,6 +46,10 @@ class TestMqlComparisonResult:
|
|||||||
def max_rel_error(self) -> float:
|
def max_rel_error(self) -> float:
|
||||||
return max((metric.max_rel_error for metric in self.metrics), default=0.0)
|
return max((metric.max_rel_error for metric in self.metrics), default=0.0)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def undefined_rel_error_count(self) -> int:
|
||||||
|
return sum(metric.undefined_rel_error_count for metric in self.metrics)
|
||||||
|
|
||||||
|
|
||||||
class TestMqlComparisonError(ValueError):
|
class TestMqlComparisonError(ValueError):
|
||||||
"""Raised when Python and AMESim series cannot be aligned."""
|
"""Raised when Python and AMESim series cannot be aligned."""
|
||||||
@@ -57,6 +63,16 @@ def compare_test_mql_series(
|
|||||||
data_paths: tuple[str, ...] | list[str] | None = None,
|
data_paths: tuple[str, ...] | list[str] | None = None,
|
||||||
relative_floor: float = 1.0e-12,
|
relative_floor: float = 1.0e-12,
|
||||||
) -> TestMqlComparisonResult:
|
) -> TestMqlComparisonResult:
|
||||||
|
"""Compare current values directly with AMESim simulation values.
|
||||||
|
|
||||||
|
``relative_floor`` only identifies near-zero baselines for reporting. It is
|
||||||
|
never substituted into the relative-error denominator. An exact zero
|
||||||
|
AMESim baseline has undefined relative error and is counted separately;
|
||||||
|
absolute error remains available for judgement.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if relative_floor < 0.0:
|
||||||
|
raise TestMqlComparisonError("relative_floor cannot be negative.")
|
||||||
_validate_time_axis(python_times)
|
_validate_time_axis(python_times)
|
||||||
selected_paths = _select_data_paths(python_series_by_data_path, amesim_results, data_paths)
|
selected_paths = _select_data_paths(python_series_by_data_path, amesim_results, data_paths)
|
||||||
metrics = []
|
metrics = []
|
||||||
@@ -70,11 +86,18 @@ def compare_test_mql_series(
|
|||||||
amesim_values = amesim_results.series(data_path)
|
amesim_values = amesim_results.series(data_path)
|
||||||
abs_errors = []
|
abs_errors = []
|
||||||
rel_errors = []
|
rel_errors = []
|
||||||
|
undefined_rel_error_count = 0
|
||||||
|
near_zero_baseline_count = 0
|
||||||
for time_value, python_value in zip(python_times, python_values):
|
for time_value, python_value in zip(python_times, python_values):
|
||||||
amesim_value = interpolate_series_value(amesim_results.times, amesim_values, time_value)
|
amesim_value = interpolate_series_value(amesim_results.times, amesim_values, time_value)
|
||||||
abs_error = abs(python_value - amesim_value)
|
abs_error = abs(python_value - amesim_value)
|
||||||
abs_errors.append(abs_error)
|
abs_errors.append(abs_error)
|
||||||
rel_errors.append(abs_error / max(abs(amesim_value), relative_floor))
|
if abs(amesim_value) <= relative_floor:
|
||||||
|
near_zero_baseline_count += 1
|
||||||
|
if amesim_value == 0.0:
|
||||||
|
undefined_rel_error_count += 1
|
||||||
|
else:
|
||||||
|
rel_errors.append(abs_error / abs(amesim_value))
|
||||||
final_amesim_value = interpolate_series_value(
|
final_amesim_value = interpolate_series_value(
|
||||||
amesim_results.times,
|
amesim_results.times,
|
||||||
amesim_values,
|
amesim_values,
|
||||||
@@ -87,6 +110,8 @@ def compare_test_mql_series(
|
|||||||
max_abs_error=max(abs_errors, default=0.0),
|
max_abs_error=max(abs_errors, default=0.0),
|
||||||
mean_abs_error=sum(abs_errors) / max(len(abs_errors), 1),
|
mean_abs_error=sum(abs_errors) / max(len(abs_errors), 1),
|
||||||
max_rel_error=max(rel_errors, default=0.0),
|
max_rel_error=max(rel_errors, default=0.0),
|
||||||
|
undefined_rel_error_count=undefined_rel_error_count,
|
||||||
|
near_zero_baseline_count=near_zero_baseline_count,
|
||||||
final_abs_error=abs(python_values[-1] - final_amesim_value),
|
final_abs_error=abs(python_values[-1] - final_amesim_value),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -153,8 +178,19 @@ def write_test_mql_comparison_csv(
|
|||||||
float(time_value),
|
float(time_value),
|
||||||
)
|
)
|
||||||
abs_error = abs(python_value - amesim_value)
|
abs_error = abs(python_value - amesim_value)
|
||||||
rel_error = abs_error / max(abs(amesim_value), 1.0e-12)
|
rel_error = (
|
||||||
row.extend([python_value, amesim_value, abs_error, rel_error])
|
None
|
||||||
|
if amesim_value == 0.0
|
||||||
|
else abs_error / abs(amesim_value)
|
||||||
|
)
|
||||||
|
row.extend(
|
||||||
|
[
|
||||||
|
python_value,
|
||||||
|
amesim_value,
|
||||||
|
abs_error,
|
||||||
|
"" if rel_error is None else rel_error,
|
||||||
|
]
|
||||||
|
)
|
||||||
writer.writerow(row)
|
writer.writerow(row)
|
||||||
|
|
||||||
summary_lines = [
|
summary_lines = [
|
||||||
@@ -163,6 +199,7 @@ def write_test_mql_comparison_csv(
|
|||||||
f"max_abs_error={metric.max_abs_error:.12g}, "
|
f"max_abs_error={metric.max_abs_error:.12g}, "
|
||||||
f"mean_abs_error={metric.mean_abs_error:.12g}, "
|
f"mean_abs_error={metric.mean_abs_error:.12g}, "
|
||||||
f"max_rel_error={metric.max_rel_error:.12%}, "
|
f"max_rel_error={metric.max_rel_error:.12%}, "
|
||||||
|
f"undefined_rel_error_count={metric.undefined_rel_error_count}, "
|
||||||
f"final_abs_error={metric.final_abs_error:.12g}"
|
f"final_abs_error={metric.final_abs_error:.12g}"
|
||||||
)
|
)
|
||||||
for metric in comparison.metrics
|
for metric in comparison.metrics
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# Fully resolved release lock for CPython 3.12 on manylinux_2_28-compatible
|
||||||
|
# Linux x86_64. Resolved and wheel-verified on 2026-08-18.
|
||||||
|
#
|
||||||
|
# Install this file as a requirements file (with -r), not as a constraint
|
||||||
|
# (with -c). Each package is pinned to the wheel selected for the reference
|
||||||
|
# platform, and pip verifies that wheel against its SHA-256 digest.
|
||||||
|
--only-binary=:all:
|
||||||
|
--require-hashes
|
||||||
|
|
||||||
|
annotated-doc==0.0.5 --hash=sha256:117bac03a25ede5df5440e855b32d556049ca169ead221505badf432fed4b101
|
||||||
|
annotated-types==0.8.0 --hash=sha256:f072f4d804ea359e4eaf198b1af7a8b0943881a87f31bb764f8bf219bb9419e0
|
||||||
|
anyio==4.14.2 --hash=sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494
|
||||||
|
click==8.4.2 --hash=sha256:e6f9f66136c816745b9d65817da91d61d957fb16e02e4dcd0552553c5a197b76
|
||||||
|
fastapi==0.141.1 --hash=sha256:bfb91aa2d334c61cb35ba9a116fc123b3d3df31640b801cf57a7a78ec3f603b3
|
||||||
|
h11==0.16.0 --hash=sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86
|
||||||
|
httptools==0.8.0 --hash=sha256:b15fc622b0f869d19207c4089a501d9bcc63ca5e071ffdd2f03f922df882dcb2
|
||||||
|
idna==3.18 --hash=sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2
|
||||||
|
lxml==6.1.1 --hash=sha256:ebe6af670449830d6d9b752c256a983291c766a1365ba5d5460048f9e33a7818
|
||||||
|
numpy==2.5.2 --hash=sha256:3cdec01fa790a186d430433fdd4d4ffb70eed6f0eeb4bf05c8dbe2dce0a9bcb8
|
||||||
|
pydantic==2.13.4 --hash=sha256:45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba
|
||||||
|
pydantic-core==2.46.4 --hash=sha256:926c9541b14b12b1681dca8a0b75feb510b06c6341b70a8e500c2fdcff837cce
|
||||||
|
python-dotenv==1.2.3 --hash=sha256:904552145e8bfed22162c09dab1c2b9b54fefa7b23ba780f4f26ca0316b0f0d9
|
||||||
|
PyYAML==6.0.3 --hash=sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc
|
||||||
|
scipy==1.18.0 --hash=sha256:1f55797419e16e7f30cf88ffb3113ce0467f00cfe3f70d5c281730b21769bfc2
|
||||||
|
starlette==1.6.0 --hash=sha256:a86dd39d14bb45f85a3d18525215a9ef0cfd1f192ac793220e72598c90335f0c
|
||||||
|
typing-extensions==4.16.0 --hash=sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8
|
||||||
|
typing-inspection==0.4.4 --hash=sha256:65b8397ba37ccbce054456aaccddfc91e6e3083c92824df348d96ca832f3f147
|
||||||
|
uvicorn[standard]==0.52.3 --hash=sha256:116af2710dbf47c80f463cd20ee4884b6662f4c9f227d797ddc7279d2fcc2c7c
|
||||||
|
uvloop==0.22.1 --hash=sha256:7b5b1ac819a3f946d3b2ee07f09149578ae76066d70b44df3fa990add49a82e4
|
||||||
|
watchfiles==1.2.0 --hash=sha256:e53a384f76b631c3ae5334ce6a52f0baa3a911eb94a4eac7f160079868b716d5
|
||||||
|
websockets==17.0.1 --hash=sha256:f47b0815af3948ec6a440b3afa02f05b18cc0939549e91b5c677b5d9c2c8472a
|
||||||
+102
-34
@@ -6,8 +6,9 @@
|
|||||||
> 基线模型:`tests/data/test_mql-full-branches-01-04.xml`
|
> 基线模型:`tests/data/test_mql-full-branches-01-04.xml`
|
||||||
> 模型 SHA-256:`2fb95e65f5de0c85a6a17802aef74ea004087323fd00fd8d01acf0184ff71d48`
|
> 模型 SHA-256:`2fb95e65f5de0c85a6a17802aef74ea004087323fd00fd8d01acf0184ff71d48`
|
||||||
> 当前主固化目标:`tests/data/test-mql-8.xml`
|
> 当前主固化目标:`tests/data/test-mql-8.xml`
|
||||||
> 主目标 XML SHA-256:`170463d65d074da01f0f9e9dab730b3815c94c1cc80b5190ec2e3fe623da74d3`
|
> 主目标 XML SHA-256:`0a2d9331df9eb5974daec25a61c1238ba32b1742d933ffc8b16ce316c5627b0b`
|
||||||
> 配套项目 JSON:`tests/data/test-mql-8.json`,SHA-256 `258c50ee4850baa72fb7c2cc24536d0a631fc6a7f1fa6cedb7b6eea7c857cbaa`
|
> 配套项目 JSON:`tests/data/test-mql-8.json`,SHA-256 `b44bf540ccd1c293fe2af2b9b9052b540abf83961ad955a0f6a4ab40fbe0bb18`
|
||||||
|
> AMESim 权威物理基线归档:`AmesimModels/test_mql.ame`,SHA-256 `cbc3aadd4569a49b3a63e5d66d4143ec16126c0f950df73fb637e07673c20fbb`
|
||||||
|
|
||||||
## 1. 使用规则
|
## 1. 使用规则
|
||||||
|
|
||||||
@@ -17,6 +18,9 @@
|
|||||||
- 只有同时完成代码、自动测试、基准复测和本文档更新后,任务才可标记为“已完成”。
|
- 只有同时完成代码、自动测试、基准复测和本文档更新后,任务才可标记为“已完成”。
|
||||||
- 每次性能对比必须记录代码提交、工作树状态、输入哈希、解释器与依赖版本、硬件和运行参数。
|
- 每次性能对比必须记录代码提交、工作树状态、输入哈希、解释器与依赖版本、硬件和运行参数。
|
||||||
- 正确性门槛先于速度收益。若结果越过误差契约,即使运行更快也不能合入默认路径。
|
- 正确性门槛先于速度收益。若结果越过误差契约,即使运行更快也不能合入默认路径。
|
||||||
|
- AMESim 归档中的仿真结果是物理数值正确性的唯一基线;每次正式回归都必须按投影逐项计算并保存当前值、AMESim 基线值、绝对误差和相对误差。
|
||||||
|
- Python exact/state golden 仅用于检测确定性、实现漂移和输出契约变化,不得单独或与本地 physical golden 一起批准物理正确性。
|
||||||
|
- AMESim 基线为 0 时相对误差在数学上未定义,报告写为 `null` 并用绝对误差判定;AMESim 未保存的内部守恒量必须明确标记为不可外部比较,并继续执行独立绝对残差门。
|
||||||
- 容差、模型方程或输出字段发生变化时,必须单独说明;不得将其伪装成纯性能优化。
|
- 容差、模型方程或输出字段发生变化时,必须单独说明;不得将其伪装成纯性能优化。
|
||||||
- 墙钟时间只在同一台机器、相同负载和相同环境下直接比较;跨环境以工作量计数和正确性指标为主。
|
- 墙钟时间只在同一台机器、相同负载和相同环境下直接比较;跨环境以工作量计数和正确性指标为主。
|
||||||
- 每项优化都应保留明确的关闭开关或旧路径,直到新路径经过复杂模型和通用回归验证。
|
- 每项优化都应保留明确的关闭开关或旧路径,直到新路径经过复杂模型和通用回归验证。
|
||||||
@@ -101,17 +105,17 @@
|
|||||||
|
|
||||||
| 项目 | 主目标值 |
|
| 项目 | 主目标值 |
|
||||||
| --- | ---: |
|
| --- | ---: |
|
||||||
| 运行组件 / 连接 | 152 / 174 |
|
| 运行组件 / 连接 | 156 / 178 |
|
||||||
| 动态组件 / 连续状态 | 54 / 124 |
|
| 动态组件 / 连续状态 | 58 / 132 |
|
||||||
| 代数未知量 / 方程 | 760 / 760 |
|
| 代数未知量 / 方程 | 776 / 776 |
|
||||||
| ODE Jacobian 结构 | 3296 nnz / 52 色 |
|
| ODE Jacobian 结构 | 3280 nnz / 52 色 |
|
||||||
| 因果 effort / flow 赋值 | 432 / 328 |
|
| 因果 effort / flow 赋值 | 440 / 336 |
|
||||||
| secondary 代数块 / 未知量 | 12 / 352 |
|
| secondary 代数块 / 未知量 | 12 / 368 |
|
||||||
| 结果变量 | 1,716 |
|
| 结果变量 | 1,784 |
|
||||||
| 原始 `tStop / sampleStep / maxStep` | 0.2 / 0.01 / 0.01 s |
|
| 原始 `tStop / sampleStep / maxStep` | 10 / 0.01 / 0.001 s |
|
||||||
| 信号断点 | 0.04、0.8 s |
|
| 信号断点 | 0.04、0.8 s |
|
||||||
|
|
||||||
本轮参考环境使用仓库 `.venv`:Python 3.12.3、NumPy 2.5.2、SciPy 1.18.0。`.python-version` 与 `constraints/python312-direct.txt` 已固定 Python 和六个直接依赖,README、CI 与依赖契约测试使用同一安装口径;它有意不锁平台相关传递依赖与 wheel 哈希,因此是可审计的参考约束,不是发布级逐位锁。机器可读 manifest 与 runner 分别位于 `tests/baselines/simulation/test_mql_8/manifest.json` 和 `app/simulation/benchmark_regression.py`;默认顺序为 `0.01 smoke → 0.2 → 1 → 5 → 10 s`,每档均有合作取消、硬终止、资源记录与后续档延迟门,且 `sampleStep` 与 `maxStep` 可按 lane 独立覆盖。
|
本轮正式环境使用仓库 `.venv`:Python 3.12.3、NumPy 2.5.2、SciPy 1.18.0。`.python-version` 与 `constraints/python312-direct.txt` 固定跨平台开发参考;`constraints/python312-linux-x86_64.lock` 则固定 Linux x86_64 发布环境的 22 个直接/传递包、wheel SHA-256,并强制 binary-only 与 hash 校验。README、CI 与依赖契约测试使用同一安装口径。机器可读 manifest 与 runner 分别位于 `tests/baselines/simulation/test_mql_8/manifest.json` 和 `app/simulation/benchmark_regression.py`;默认顺序为 `0.01 smoke → 0.2 → 1 → 5 → 10 s`,每档均有合作取消、硬终止、资源记录与后续档延迟门,且 `sampleStep` 与 `maxStep` 可按 lane 独立覆盖。
|
||||||
|
|
||||||
## 3. 总体验收协议
|
## 3. 总体验收协议
|
||||||
|
|
||||||
@@ -146,25 +150,51 @@
|
|||||||
- stream/热流体迭代次数、物性缓存命中率、事件候选与定位次数。
|
- stream/热流体迭代次数、物性缓存命中率、事件候选与定位次数。
|
||||||
- 输出标量数、编码字节数、传输字节数和后处理峰值内存。
|
- 输出标量数、编码字节数、传输字节数和后处理峰值内存。
|
||||||
|
|
||||||
|
### 3.4 P0 最大积分步长路径鲁棒性门
|
||||||
|
|
||||||
|
权威工程场景固定为 `test-mql-8.json` 经浏览器导出并由服务执行的同一系统语义,方法为 BDF。短基线使用
|
||||||
|
`tStop=0.2 s`、`sampleStep=0.01 s`、`maxStep=0.001 s`;长基线只将 `tStop` 延长到
|
||||||
|
`10 s`。`sampleStep` 是输出网格,`maxStep` 是积分步长上限,报告与诊断不得混用两者。
|
||||||
|
|
||||||
|
- **时域延长不变量**:固定模型、容差、方法和 `maxStep` 时,如果较短的 `tStop=T1` 能完成,则
|
||||||
|
`T2>T1` 的运行不得因数值错误在 `T1` 之前提前结束。只比较严格位于 `T1` 之前的公共检查点;
|
||||||
|
短任务终点的 accepted endpoint 与长任务内部插值单独标记,不作位级误判。
|
||||||
|
- **步长细化可解性不变量**:在约定工程区间内,如果较大的 `maxStep` 能完成同一时域,则更小
|
||||||
|
`maxStep` 不得反而出现不可恢复数值失败。更小上限可以更慢;若仅因工作量增加超过预算,必须归类为
|
||||||
|
`budget_limited` 并证明仍持续推进,不能记为 solver failure 或借此选择一个“幸运步长”。
|
||||||
|
- [ ] 首先对账 JSON、浏览器生成的 System XML、服务请求和 worker 最终生效参数;保存输入哈希,禁止用 runner 的内存覆盖掩盖浏览器路径问题。
|
||||||
|
- [ ] 浏览器当前工程验收明确为失败:`0.2 s / 0.001 s` 在 `t≈0.0489 s` 被判定计算超时;离线 production runner 的完成记录只作对照,不能写成浏览器正常完成。必须用同一 JSON 复现并分类为内部慢步、求解器真停滞、后处理/传输或服务假超时。
|
||||||
|
- [ ] 第一阶段在其余参数不变时串行运行 `tStop={0.2,1} s × maxStep={0.001,0.002,0.005,0.01,0.02} s` 的短时二维矩阵;最终签收要求所有单元到达终点,不得出现 NaN/Inf、不可恢复数值错误或无解释回退。定位阶段允许记录有持续进展证据的 `budget_limited`,但它既不算数值失败,也不算通过。
|
||||||
|
- [ ] 短时二维矩阵通过后,再按相同契约依次延长到 `2 s → 5 s → 10 s`;每一档先运行权威 `0.001 s`,再运行代表性的 `0.005/0.02 s`,最后补齐其余步长。每一档先确认同 `maxStep` 公共前缀,再进入下一档,不因较长 `tStop` 改变已覆盖区间的成败结论。
|
||||||
|
- [ ] 跨 `maxStep` 不要求逐位相同;按积分状态、派生量、关键压力/流量、守恒量、事件和离散模式分别验收,近零派生加速度不得使用统一相对误差误判真实积分状态。
|
||||||
|
- [ ] 每个 `0.01 s` 模拟区间记录墙钟、实际 `h_abs`/BDF 阶次、接受/拒绝步、重启、`nfev/njev/nlu`、Jacobian 构建、stream/热流体闭合与恢复轨迹;性能悬崖必须能定位到具体阶段和组件。
|
||||||
|
- [ ] 内部 RHS、Jacobian、stream/热流体闭合或恢复循环仍有活动时,服务持续发送活动心跳,浏览器不得因 60 s 内没有接受步而误判卡死;真正无活动必须有界终止并报告最后阶段、时刻、步长和计数。
|
||||||
|
- [ ] 将终止结果明确分类为 `numerical_failure`、`service_timeout_worker_active`、`active_slow_trial`、`true_stall` 或 `budget_limited`;浏览器超时始终属于工程路径未通过,但在证据不足时不得冒充数值失败。
|
||||||
|
- [ ] 任一会改变数值路径、事件语义、容差或默认求解策略的修复,必须先形成“复现证据 → 首个异常阶段 → 根因假设 → 最小方案 → A/B 判据 → 回退方式”,提交审阅后再实施;每轮只修改一个概念并先复跑原失败单元。
|
||||||
|
- [ ] 在 `0.2/1 s` 短时门通过后,依次取得 `2/5/10 s` 数据;在对本次长跑做任何性能调优前,先完整取得一次 `10 s / 0.001 s` 原始基线,完成后才按时间线选择最小优化并复跑完整阶梯。
|
||||||
|
|
||||||
|
该门的目标不是寻找一个“碰巧能跑”的固定 `maxStep`,也不是要求所有步长得到位级相同轨迹,而是让合理工程区间内的
|
||||||
|
`maxStep` 只影响可解释的误差与成本,不决定仿真能否完成。
|
||||||
|
|
||||||
## 4. 优化任务总览
|
## 4. 优化任务总览
|
||||||
|
|
||||||
优先级定义:`P0` 为基线或正确性前置,`P1` 为主要性能收益,`P2` 为第二阶段,`P3` 为战略性或条件性工作。
|
优先级定义:`P0` 为基线或正确性前置,`P1` 为主要性能收益,`P2` 为第二阶段,`P3` 为战略性或条件性工作。
|
||||||
|
|
||||||
| ID | 优先级 | 任务 | 当前状态 | 难度 | 预期价值 | 主要依赖 |
|
| ID | 优先级 | 任务 | 当前状态 | 难度 | 预期价值 | 主要依赖 |
|
||||||
| --- | --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- | --- |
|
||||||
| OPT-00 | P0 | 固化复现、环境和回归基线 | 部分实现(基础闭环) | 中 | 很高 | 无 |
|
| OPT-00 | P0 | 固化复现、环境和回归基线 | 重新打开(离线基线完成;浏览器路径失败待定位) | 中 | 很高 | 无 |
|
||||||
| OPT-01 | P1 | 完成因果代数内核与坐标消元 | 基本完成(主要矛盾闭环) | 中高 | 中高 | OPT-00 |
|
| OPT-01 | P1 | 完成因果代数内核与坐标消元 | 基本完成(主要矛盾闭环) | 中高 | 中高 | OPT-00 |
|
||||||
| OPT-02 | P1 | 建立扁平数值 IR 和数组执行内核 | 部分实现(参考 IR) | 很高 | 很高 | OPT-01 |
|
| OPT-02 | P1 | 建立扁平数值 IR 和数组执行内核 | 部分实现(参考 IR) | 很高 | 很高 | OPT-01 |
|
||||||
| OPT-03 | P1 | 稀疏 Jacobian 数值层与解析/半解析演进 | 部分实现 | 很高 | 很高 | OPT-00;解析链可与 OPT-02 分阶段 |
|
| OPT-03 | P1 | 稀疏 Jacobian 数值层与解析/半解析演进 | 部分实现 | 很高 | 很高 | OPT-00;解析链可与 OPT-02 分阶段 |
|
||||||
| OPT-04 | P1 | stream 拓扑传播与物性成组复用 | 部分实现 | 中高 | 中高 | OPT-00 |
|
| OPT-04 | P1 | stream 拓扑传播与物性成组复用 | 部分实现 | 中高 | 中高 | OPT-00 |
|
||||||
| OPT-05 | P1 | 状态缩放、分量容差和步长策略 | 部分实现(可恢复试探步) | 中高 | 中高 | OPT-00 |
|
| OPT-05 | P0/P1 | 最大积分步长路径鲁棒性、状态缩放和步长策略 | 进行中(P0 阻断) | 中高 | 很高 | OPT-00 |
|
||||||
| OPT-06 | P2 | 事件检测与 dense output 按需化 | 部分实现 | 中 | 中 | OPT-00 |
|
| OPT-06 | P2 | 事件检测与 dense output 按需化 | 部分实现 | 中 | 中 | OPT-00 |
|
||||||
| OPT-07 | P2 | 输出、后处理和传输内存优化 | 未开始 | 中 | 中高(长仿真) | OPT-00 |
|
| OPT-07 | P2 | 输出、后处理和传输内存优化 | 未开始 | 中 | 中高(长仿真) | OPT-00 |
|
||||||
| OPT-08 | P2 | 进度、取消和服务并发鲁棒性 | 部分实现 | 中 | 中 | OPT-00 |
|
| OPT-08 | P0/P2 | 进度、取消和服务并发鲁棒性 | 进行中(浏览器 `0.0489 s` 失败待定位) | 中 | 很高 | OPT-00、OPT-05 P0 门 |
|
||||||
| OPT-09 | P0/P2 | 建立 10 s 长时验证与模式覆盖 | 进行中 | 中高 | 很高 | OPT-00 |
|
| OPT-09 | P0/P2 | 建立 10 s 长时验证与模式覆盖 | 进行中(权威 `0.001 s` 基线未完成) | 中高 | 很高 | OPT-00、OPT-05 P0 门、OPT-08 服务门 |
|
||||||
| OPT-10 | P3 | 明确高指数 DAE/强非光滑系统边界 | 未开始 | 很高 | 条件性 | OPT-09 |
|
| OPT-10 | P3 | 明确高指数 DAE/强非光滑系统边界 | 未开始 | 很高 | 条件性 | OPT-09 |
|
||||||
|
|
||||||
推荐实施顺序:`OPT-00 → OPT-03/OPT-01 → OPT-04/OPT-05 → OPT-02 → OPT-06/OPT-07/OPT-08 → OPT-09`。其中 OPT-02 与 OPT-03 可先做最小原型,再根据端到端数据调整顺序。
|
当前推荐实施顺序:`OPT-00 浏览器失败复现 → OPT-05/OPT-08 定位并解除 0.2 s 阻断 → 0.2/1 s × 五档 maxStep 短时鲁棒性门 → 2/5/10 s 逐级延长 → OPT-09 首次 10 s / 0.001 s 完整基线 → 基于时间线提案、审阅、单项优化与完整复验`。OPT-01/02/03/04 的既有成果保留,但在该 P0 工程门通过前不以单点性能收益替代鲁棒性验收。
|
||||||
|
|
||||||
## 5. 详细任务
|
## 5. 详细任务
|
||||||
|
|
||||||
@@ -172,42 +202,56 @@
|
|||||||
|
|
||||||
**目标**:先让“是否更快、是否仍正确、是否又卡住”可以稳定复现和自动判断。
|
**目标**:先让“是否更快、是否仍正确、是否又卡住”可以稳定复现和自动判断。
|
||||||
|
|
||||||
**当前状态**:P0 基础设施与新主目标的有界 `0.2 s` 基线已经闭环:权威 XML/JSON、参考依赖约束、仓库内 runner、状态 golden、输出形状契约、三层 CI 和机器可读报告均已建立。完整 OPT-00 仍缺发布级依赖锁、远端 CI 首次实跑、历史 `2.10 s` 三次复测以及更长时域的批准 golden。
|
**当前状态**:重新打开工程端到端复核。2026-08-18 的离线 production runner、发布锁、golden、physical-state-v2.1、历史 `2.10 s` 三次复测和本地自动测试证据继续有效;但浏览器使用权威 JSON、BDF、`tStop=0.2 s`、`sampleStep=0.01 s`、`maxStep=0.001 s` 时当前会在 `t≈0.0489 s` 被判定计算超时,工程验收结果为失败。离线 runner 的完成记录不能替代浏览器结果;同 `maxStep` 的时域延长不变量和减小 `maxStep` 的可解性不变量也尚未验收。
|
||||||
|
|
||||||
**工作项**:
|
**工作项**:
|
||||||
|
|
||||||
- [x] 将新主目标 XML/JSON 放入固定 fixture 路径,并在 manifest/测试中校验双哈希、字节数和配对配置;提交本轮工作时必须一并纳入版本控制。
|
- [x] 将新主目标 XML/JSON 放入固定 fixture 路径,并在 manifest/测试中校验双哈希、字节数和配对配置;提交本轮工作时必须一并纳入版本控制。
|
||||||
- [x] 建立 Python 3.12.3 与六个直接依赖的跨平台参考约束,并在 CI 中校验;发布级传递依赖/wheel 哈希锁仍待后续。
|
- [x] 建立 Python 3.12.3 与六个直接依赖的跨平台参考约束,并建立 Linux x86_64 的 22 个直接/传递包、binary-only wheel SHA-256 发布锁;空 venv 离线安装、`pip check` 与依赖契约均通过。
|
||||||
- [x] 将临时探针整理为仓库内可重复运行的 benchmark,不依赖 `/tmp` 文件。
|
- [x] 将临时探针整理为仓库内可重复运行的 benchmark,不依赖 `/tmp` 文件。
|
||||||
- [x] 添加 `0.81 s` 和仅改 `tStop=2.10 s` 的历史标准运行入口。
|
- [x] 添加 `0.81 s` 和仅改 `tStop=2.10 s` 的历史标准运行入口。
|
||||||
- [x] 添加模型结构快照断言;结构有意变化时显式更新原因。
|
- [x] 添加模型结构快照断言;结构有意变化时显式更新原因。
|
||||||
- [x] 建立 `physical-state-v2` 的首批 state/checkpoint/event 投影,并批准 production `0.2 s` golden。
|
- [x] 建立 `physical-state-v2` 的首批 state/checkpoint/event 投影;其 Python golden 现仅作为 production `0.2 s` 的确定性与实现回归诊断。
|
||||||
- [ ] 将关键压力、流量、守恒量和离散模式加入 `physical-state-v2.1` 数值投影。
|
- [x] 将关键压力、质量流量、三类质量守恒、总储气质量和离散模式加入 `physical-state-v2.1`,绑定 AMESim 单位/符号变换,并在每次运行时以 AMESim reference values 执行物理门。
|
||||||
- [x] 将无数值的完整输出形状契约与物理状态 golden 分开;完整 API 序列化契约若需逐字段稳定性,后续另行定义。
|
- [x] 将无数值的完整输出形状契约与物理状态 golden 分开;完整 API 序列化契约若需逐字段稳定性,后续另行定义。
|
||||||
- [x] 建立短 CI、夜间 `0.81/2.10 s`、定期递进至 `10 s` 的三层 workflow;远端首次执行待提交后确认。
|
- [x] 建立短 CI、夜间 `0.81/2.10 s`、定期递进至 `10 s` 的三层 workflow;远端首次执行待提交后确认。
|
||||||
- [x] 保存带环境、仓库、输入、运行统计和验收结果的机器可读 JSON 报告。
|
- [x] 保存带环境、仓库、输入、运行统计和验收结果的机器可读 JSON 报告。
|
||||||
|
- [ ] 以权威 JSON 经浏览器生成 XML 并走流式 API 的真实路径完成 `0.2 s / 0.001 s`,与 production worker 对账输入哈希、生效参数、事件、物理量和最终结果;定位并消除 `t≈0.0489 s` 的计算超时或假超时。
|
||||||
|
- [ ] 通过第 3.4 节的 `0.2/1 s × 五档 maxStep` P0 短时矩阵与两条不变量;既有 `0.01/0.02/0.05/0.10 s` 历史运行不能替代缺失的 `0.001 s` 工程验收。
|
||||||
|
|
||||||
**验收条件**:
|
**验收条件**:
|
||||||
|
|
||||||
- [ ] 干净环境一条命令可复现;当前参考约束、`pip check`、soft/hard timeout、worker error 与 correctness failure 分类已完成,独立无进度看门狗、服务级故障分类和发布级空环境重建尚未验收。
|
- [x] 干净环境可按发布锁一条安装命令复现:全新空 venv 使用 22 个锁定 wheel 与 SHA-256 完成安装,`pip check`、锁定环境契约和最终 quick workflow 同口径测试通过。
|
||||||
- [ ] 正式环境连续 3 次完成 `2.10 s`,结果满足数值契约且无非预期回退。
|
- [x] 正式 production 环境严格串行 3 次完成 `0.81/2.10 s`;两档检查点、状态、事件、输出契约和除计时外的诊断逐值一致,无非有限值或非预期回退。
|
||||||
- [x] 新主目标 `0.2 s` 性能报告完整记录环境、提交、工作树、输入哈希和统计口径。
|
- [x] 新主目标 `0.2 s` 性能报告完整记录环境、提交、工作树、输入哈希和统计口径。
|
||||||
|
- [ ] 浏览器/服务/worker 三条路径对权威 `0.2 s / 0.001 s` 均能完成且不会发生无证据的 60 s 假停滞;真实无活动仍能有界退出并提供诊断。
|
||||||
|
|
||||||
**前后对比**:
|
**前后对比**:
|
||||||
|
|
||||||
| 指标 | 当前 | 完成后 |
|
| 指标 | 当前 | 完成后 |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| 正式锁定环境 | 无 | Python 3.12.3 + 直接依赖参考约束;发布锁待补 |
|
| 正式锁定环境 | Python 3.12.3 + 22 包 hash lock | 空 venv 安装、`pip check`、依赖契约通过 |
|
||||||
| 复杂模型自动回归 | 部分 | 新主目标 0.01/0.2/1/5/10 递进 + 历史 0.81/2.10 入口 |
|
| 复杂模型自动回归 | 新主目标 0.01/0.2 分层门禁 | 1/5/10 递进入口 + 历史 0.81/2.10 production 入口 |
|
||||||
| 物理解哈希 | 环境相关 v1 | production 0.2 state golden + 独立 output shape contract |
|
| 物理解哈希 | 142 个状态键 × 3 检查点 | Python state golden 作确定性诊断 + output shape + AMESim 当次相对误差物理门 |
|
||||||
| `2.10 s` 连续成功率 | 单次证据 | 待填 |
|
| `2.10 s` 连续成功率 | 3/3 | worker 墙钟 113.497–115.868 s,逐值一致且 0 回退 |
|
||||||
|
|
||||||
|
#### 2026-08-18 / AMESim 权威基线对齐与 OPT-00 收口
|
||||||
|
|
||||||
|
- 状态:部分实现 → 已完成(本地验收)。AME 归档固定 SHA-256 `cbc3aadd...`;XML/JSON 修正后的 SHA-256 分别为 `0a2d9331...`、`b44bf540...`,仿真配置统一为 `0→10 s / sampleStep=0.01 s / maxStep=0.001 s`。
|
||||||
|
- 权威契约:直接解析 AME 的 117 个 COMP 与 40 个建模 LINE,推导出 157 个项目节点、178 条连接、20 类组件和 1092 个参数;单位转 SI、表压转绝压、公式等价、DIRECT/接触/线模型拓扑以及 XML↔JSON 逐 ID/端口均有自动测试。
|
||||||
|
- 权威物理门:production `0.2 s` 每次都把当前 physical-state-v2.1 投影直接与 AMESim reference values 比较并保存相对误差;25 项参与判定,2 个 `t=0.04 s` 跳变流量保留误差但因左右极限语义不参与判定,另有 6 项无 AMESim 数据的内部守恒量单独执行绝对残差门。Python 142 个状态键 × 3 个检查点的 426 值 golden 仅作确定性诊断,不再批准物理正确性。
|
||||||
|
- 历史最终报告:`runs/2026-08-18-production-opt00-approved-replay-0.2.json`,SHA-256 `2e27cd54...`;worker/orchestration 墙钟 `159.607/160.473 s`。其中 Python 值零重放误差是确定性证据;物理结论以该次结果对 AMESim 的最差相对误差 `0.1393485%` 为准,最大质量守恒残差为 `1.82146e-17 kg/s`。
|
||||||
|
- 历史稳定性:production `0.81/2.10 s` 严格串行运行三次,所有 case 通过;`2.10 s` worker 墙钟分别为 `114.075/113.497/115.868 s`,机械事件时刻、检查点、1200 个状态值和除性能计时外的诊断逐值一致。
|
||||||
|
- 环境与自动化:新增 22 包 Linux x86_64 hash lock,并在全新空 venv 完成离线安装和 `pip check`;最终 quick workflow 同口径为 179 项通过(2 项预期跳过),完整后端为 849 项通过(3 项预期跳过)。
|
||||||
|
- 递进边界:由最终 `0.2 s` worker 时间按 `×5×1.5` 外推,`1 s` 为 `1197.053 s`,略低于 1200 s soft budget,因此记录为下一阶段 `eligible`;本次 OPT-00 不启动 1/5/10 s,后续长时递进仍归 OPT-09。
|
||||||
|
- 远端说明:workflow 已使用相同 hash lock 与测试命令;本轮未获授权提交/推送,因此没有声称远端 CI 已运行,提交后的首次托管运行作为运营证据补充。
|
||||||
|
|
||||||
#### 2026-08-17 / `test-mql-8` 固化 runner v2
|
#### 2026-08-17 / `test-mql-8` 固化 runner v2
|
||||||
|
|
||||||
- 状态:进行中 → 部分实现(P0 基础闭环)。新权威 XML/JSON、双哈希、结构快照、参考环境约束、分层 manifest、机器可读报告、批准的 production `0.2 s` golden 和仓库内 runner 已建立;发布级依赖锁、关键代数量投影以及该里程碑时尚未运行的 1/5/10 s 结果仍待后续。
|
- 状态:进行中 → 部分实现(P0 基础闭环)。新权威 XML/JSON、双哈希、结构快照、参考环境约束、分层 manifest、机器可读报告、批准的 production `0.2 s` golden 和仓库内 runner 已建立;发布级依赖锁、关键代数量投影以及该里程碑时尚未运行的 1/5/10 s 结果仍待后续。
|
||||||
- runner 行为:默认严格按 `0.01 smoke → 0.2 → 1 → 5 → 10 s` 递进;smoke 不参与耗时外推。soft deadline 先经 stdin 合作取消,hard deadline 再 terminate/kill;失败、超时、物理验收失败或下一档预测超过预算时,剩余档位统一标记 `deferred`。
|
- runner 行为:默认严格按 `0.01 smoke → 0.2 → 1 → 5 → 10 s` 递进;smoke 不参与耗时外推。soft deadline 先经 stdin 合作取消,hard deadline 再 terminate/kill;失败、超时、物理验收失败或下一档预测超过预算时,剩余档位统一标记 `deferred`。
|
||||||
- 已执行正确性门:完成并到达终点、非空且全有限的输出序列、采样时间严格递增、检查点及状态值、最大缩放残差、预期信号事件及其实际积分分段、机械切换次数/时刻、golden 来源报告与布局哈希、逐状态容差比较和独立 output-shape contract。
|
- 已执行正确性门:完成并到达终点、非空且全有限的输出序列、采样时间严格递增、检查点及状态值、最大缩放残差、预期信号事件及其实际积分分段、机械切换次数/时刻、golden 来源报告与布局哈希、逐状态容差比较和独立 output-shape contract。
|
||||||
- 两条 lane:manifest 中 `solver-only` 在内存把 `sampleStep` 改为 0.02 s,并把 `maxStep` 固定为 0.05 s,用于算法迭代;`production` 的 `sampleStep/maxStep` 均使用权威 XML 源值,当前为 0.01/0.01 s。max-step 矩阵可再显式覆盖单次运行的 `maxStep`;所有覆盖都只发生在内存,不改写 XML。
|
- 两条 lane:该 2026-08-17 里程碑的 manifest 中,`solver-only` 在内存把 `sampleStep` 改为 0.02 s,并把 `maxStep` 固定为 0.05 s,用于算法迭代;当时 SHA `170463d6...` 的 `production` 源值为 `sampleStep/maxStep=0.01/0.01 s`。当前 2026-08-18 权威 AME/XML/JSON 已统一为 `sampleStep/maxStep=0.01/0.001 s`;旧报告仅作历史证据。
|
||||||
- 进程鲁棒性:软取消、硬终止、子进程提前关闭 stdin 的 BrokenPipe 和 stdout/stderr 资源清理均有自动测试。
|
- 进程鲁棒性:软取消、硬终止、子进程提前关闭 stdin 的 BrokenPipe 和 stdout/stderr 资源清理均有自动测试。
|
||||||
- 备份:`backup/general-solver-v1-before-20260817-16a7eb2` 精确指向进入本轮前的 `16a7eb2d6c2f01b23e3bdc7781a6cf6cc3fbe369`。
|
- 备份:`backup/general-solver-v1-before-20260817-16a7eb2` 精确指向进入本轮前的 `16a7eb2d6c2f01b23e3bdc7781a6cf6cc3fbe369`。
|
||||||
- P0 证据:`tests/baselines/simulation/test_mql_8/runs/2026-08-17-production-v2-0.2.json`、`goldens/production-0.2s-v1.json` 与 `runs/2026-08-17-production-v2-extension-decision.json`。
|
- P0 证据:`tests/baselines/simulation/test_mql_8/runs/2026-08-17-production-v2-0.2.json`、`goldens/production-0.2s-v1.json` 与 `runs/2026-08-17-production-v2-extension-decision.json`。
|
||||||
@@ -222,7 +266,7 @@ PYTHONPATH=. .venv/bin/python -m app.simulation.benchmark_regression \
|
|||||||
--output tests/baselines/simulation/test_mql_8/runs/latest-production.json
|
--output tests/baselines/simulation/test_mql_8/runs/latest-production.json
|
||||||
```
|
```
|
||||||
|
|
||||||
正式验收默认使用 `production`,从而执行已批准的 0.2 s 数值 golden;算法迭代若需降低输出成本,可显式改为 `--lane solver-only`。仅重跑首个正式基线档可加 `--case 0.2s`。
|
正式验收默认使用 `production`,从而对 `0.2 s` 当前结果执行 AMESim 权威物理基线比较;Python 数值 golden 同时输出确定性诊断但不作为物理通过依据。算法迭代若需降低输出成本,可显式改为 `--lane solver-only`。仅重跑首个正式基线档可加 `--case 0.2s`。
|
||||||
命令退出码约定:`0` 表示所有选定档完成,`2` 表示依据预算安全暂缓后续档,`1` 表示运行失败或正确性验收失败。显式选择 `1s/5s/10s` 时,runner 仍会自动补齐并先执行所有较短前置档。
|
命令退出码约定:`0` 表示所有选定档完成,`2` 表示依据预算安全暂缓后续档,`1` 表示运行失败或正确性验收失败。显式选择 `1s/5s/10s` 时,runner 仍会自动补齐并先执行所有较短前置档。
|
||||||
|
|
||||||
### OPT-01 完成因果代数内核与坐标消元
|
### OPT-01 完成因果代数内核与坐标消元
|
||||||
@@ -502,11 +546,11 @@ PYTHONPATH=. .venv/bin/python -m app.simulation.benchmark_regression \
|
|||||||
| `2.10 s` 压力闭合 | 57,601 | 待填 |
|
| `2.10 s` 压力闭合 | 57,601 | 待填 |
|
||||||
| 物性调用 / 缓存命中率 | 待测 | 待填 |
|
| 物性调用 / 缓存命中率 | 待测 | 待填 |
|
||||||
|
|
||||||
### OPT-05 状态缩放、分量容差和步长策略
|
### OPT-05 最大积分步长路径鲁棒性、状态缩放和步长策略
|
||||||
|
|
||||||
**目标**:减少量纲差异造成的不必要小步和 Jacobian 重建,同时维持事件与守恒精度。
|
**目标**:首先保证在合理 `maxStep` 工程区间内,步长上限只影响可解释的误差和成本,而不决定仿真能否完成;随后再减少量纲差异造成的不必要小步和 Jacobian 重建,同时维持事件与守恒精度。
|
||||||
|
|
||||||
**当前状态**:模型中不同物理量的量级差异大。历史试验显示机械绝对容差放宽可能带来约 16% 收益,但属于精度策略变化;热流体固定点容差的简单放宽曾使表现变差,不能直接采用。当前已先完成不改变容差契约的可恢复试探步:按积分器实际 `h_abs` 对半退避,并在首次接受后恢复分段步长上限。Generic 显式 opt-in,即使模型无状态事件、断点或取消回调,也会进入支持重建的 stepwise 路径;普通 `integrate_ode` 调用者的默认路径不变。分量 `atol`、缩放和标准/快速配置仍未开始。
|
**当前状态**:P0 阻断、先定位。模型中不同物理量的量级差异大。历史试验显示机械绝对容差放宽可能带来约 16% 收益,但属于精度策略变化;热流体固定点容差的简单放宽曾使表现变差,不能直接采用。当前已先完成不改变容差契约的可恢复试探步:按积分器实际 `h_abs` 对半退避,并在首次接受后恢复分段步长上限。Generic 显式 opt-in,即使模型无状态事件、断点或取消回调,也会进入支持重建的 stepwise 路径;普通 `integrate_ode` 调用者的默认路径不变。权威浏览器场景 `BDF / 0.2 s / sampleStep=0.01 s / maxStep=0.001 s` 当前在 `t≈0.0489 s` 计算超时,已构成工程失败;尚须用同 JSON 的 browser/API/worker A/B 定位其属于数值热点、服务假超时或二者叠加。既有 `2 s` 矩阵没有覆盖 `0.001 s`,也未系统验证时域延长与步长细化不变量,不能替代本次 P0 门。
|
||||||
|
|
||||||
**工作项**:
|
**工作项**:
|
||||||
|
|
||||||
@@ -516,6 +560,12 @@ PYTHONPATH=. .venv/bin/python -m app.simulation.benchmark_regression \
|
|||||||
- [ ] 统计限制步长的状态分量、误差拒步和 Jacobian 重建原因。
|
- [ ] 统计限制步长的状态分量、误差拒步和 Jacobian 重建原因。
|
||||||
- [ ] 对事件前后、接触临界区和稳态区分别评估步长上限策略。
|
- [ ] 对事件前后、接触临界区和稳态区分别评估步长上限策略。
|
||||||
- [ ] 建立严格/标准/快速配置,但默认配置必须有明确精度契约。
|
- [ ] 建立严格/标准/快速配置,但默认配置必须有明确精度契约。
|
||||||
|
- [ ] 用完全相同的 JSON 生成请求,对浏览器流式路径与 production worker 做同参 A/B,逐层核对 requested/effective `tStop/sampleStep/maxStep/method`。
|
||||||
|
- [ ] 围绕 `t=0.04–0.05 s` 按模拟区间记录 BDF 阶次、实际 `h_abs`、接受/拒绝步、重启、Jacobian/RHS/闭合耗时及最坏组件,定位 `0.0489 s` 的首次性能悬崖。
|
||||||
|
- [ ] 在改变算法前提交定位报告与候选方案供审阅,明确证据、影响面、正确性风险、预期计数变化和回退方式;获准后只实施一个概念,并以原失败单元及同一行/列相邻配置做 A/B。
|
||||||
|
- [ ] 审计失败试探的事务恢复、缓存、端口和离散模式,证明失败点不会污染下一条缩步路径。
|
||||||
|
- [ ] 只在证据支持时对事件、接触、流向或闭合边界使用局部步长上限、有界缩步或模式感知策略;禁止靠全程硬编码某个“幸运” `maxStep` 收口。
|
||||||
|
- [ ] 将第 3.4 节的 `0.2/1 s × 五档` 二维矩阵设为每次步长/缩放改动的 P0 回归;短时通过后再按 `2/5/10 s` 逐级验证公共前缀。
|
||||||
- [x] 对可恢复的热流体闭合失败使用积分器实际试探步 `h_abs` 对半回退;最多 16 次且不低于 64 ULP,恢复步仅设置 `first_step`,首次接受后恢复分段 `maxStep` 上限并记录 attempted/next step。
|
- [x] 对可恢复的热流体闭合失败使用积分器实际试探步 `h_abs` 对半回退;最多 16 次且不低于 64 ULP,恢复步仅设置 `first_step`,首次接受后恢复分段 `maxStep` 上限并记录 attempted/next step。
|
||||||
- [x] 为 eventless Generic 显式启用 `recoverable_trial_retries`,使没有状态事件、断点或取消回调的通用模型也能选择 stepwise 恢复;该参数默认关闭,避免改变其他调用者的直接 `solve_ivp` 语义。
|
- [x] 为 eventless Generic 显式启用 `recoverable_trial_retries`,使没有状态事件、断点或取消回调的通用模型也能选择 stepwise 恢复;该参数默认关闭,避免改变其他调用者的直接 `solve_ivp` 语义。
|
||||||
|
|
||||||
@@ -524,6 +574,7 @@ PYTHONPATH=. .venv/bin/python -m app.simulation.benchmark_regression \
|
|||||||
- [ ] 每个配置都有状态、事件、残差和守恒误差界限。
|
- [ ] 每个配置都有状态、事件、残差和守恒误差界限。
|
||||||
- [ ] 标准配置在复杂模型上减少拒步或分解工作,不引入模式遗漏。
|
- [ ] 标准配置在复杂模型上减少拒步或分解工作,不引入模式遗漏。
|
||||||
- [ ] 所有收益报告同时给出误差变化,禁止只报告墙钟。
|
- [ ] 所有收益报告同时给出误差变化,禁止只报告墙钟。
|
||||||
|
- [ ] 满足第 3.4 节 P0 门:短时二维矩阵满足时域延长与步长细化不变量,事件/模式/守恒满足分类契约,任何性能悬崖都有可复现的阶段与组件归因。
|
||||||
|
|
||||||
### OPT-06 事件检测与 dense output 按需化
|
### OPT-06 事件检测与 dense output 按需化
|
||||||
|
|
||||||
@@ -570,7 +621,7 @@ PYTHONPATH=. .venv/bin/python -m app.simulation.benchmark_regression \
|
|||||||
|
|
||||||
**目标**:区分“内部慢步”和“真正无进度”,并让长任务可取消、可限流、不会拖垮服务进程。
|
**目标**:区分“内部慢步”和“真正无进度”,并让长任务可取消、可限流、不会拖垮服务进程。
|
||||||
|
|
||||||
**当前状态**:已有 stream 进度和取消检查;前端无进度阈值约 60 s。历史 2.05 s 附近可见最大间隔约 7.5 s,且中间有接受步与 CPU 活动,因此没有触发真实无进度条件。当前又补充了热流体失败位置、迭代尾部、最差端口及求解器恢复轨迹;`5 s / maxStep=0.05 s` 在 1200 s soft budget 后合作取消并保留 `t=4.2523535 s` 的部分诊断,属于预算终止而非 solver failure。单格 max-step 矩阵不再把“没有跨步长比较对”误判为失败。
|
**当前状态**:P0 服务门进行中。已有 stream 进度和取消检查;前端无接受步进度阈值约 60 s。历史 2.05 s 附近可见最大间隔约 7.5 s,且中间有接受步与 CPU 活动,因此没有触发真实无进度条件。当前又补充了热流体失败位置、迭代尾部、最差端口及求解器恢复轨迹;`5 s / maxStep=0.05 s` 在 1200 s soft budget 后合作取消并保留 `t=4.2523535 s` 的部分诊断,属于预算终止而非 solver failure。单格 max-step 矩阵不再把“没有跨步长比较对”误判为失败。权威 `0.2 s / 0.001 s` 浏览器运行当前在 `t≈0.0489 s` 计算超时,浏览器工程门已经失败;但根因尚未确定,必须追踪前端 60 s 计时器、NDJSON 心跳、API worker 与内部求解活动,不能直接等同于求解器死锁。
|
||||||
|
|
||||||
**工作项**:
|
**工作项**:
|
||||||
|
|
||||||
@@ -580,6 +631,8 @@ PYTHONPATH=. .venv/bin/python -m app.simulation.benchmark_regression \
|
|||||||
- [ ] 限制并发仿真 worker、队列长度和单任务 CPU/内存预算。
|
- [ ] 限制并发仿真 worker、队列长度和单任务 CPU/内存预算。
|
||||||
- [ ] 超时报告最后活动阶段、模拟时刻、步长和关键计数,而非只返回通用错误。
|
- [ ] 超时报告最后活动阶段、模拟时刻、步长和关键计数,而非只返回通用错误。
|
||||||
- [ ] 添加故意慢 RHS、死循环防护、客户端断连和多任务竞争测试。
|
- [ ] 添加故意慢 RHS、死循环防护、客户端断连和多任务竞争测试。
|
||||||
|
- [ ] 将活动心跳从“接受新积分步”扩展到 RHS、Jacobian 构建、stream/热流体闭合和恢复循环;至少携带 phase、wall time、last accepted time、current RHS time、`h_abs`、`nfev` 与闭合迭代。
|
||||||
|
- [ ] 验证客户端流断开、浏览器本地 watchdog 和显式取消的语义不同;客户端误判或断连不得在无用户授权时静默丢失仍健康运行的 worker 结果。
|
||||||
- [x] 热流体失败记录 RHS 时刻、最近迭代尾部、最大增量/尺度/容差、最差端口及带符号差值,并保留求解器逐次恢复的 attempted/next step 与原因。
|
- [x] 热流体失败记录 RHS 时刻、最近迭代尾部、最大增量/尺度/容差、最差端口及带符号差值,并保留求解器逐次恢复的 attempted/next step 与原因。
|
||||||
- [x] 矩阵报告分别记录外层 `soft_timeout` 和 worker 的合作 `cancelled`,避免把预算取消误记为求解器数值失败。
|
- [x] 矩阵报告分别记录外层 `soft_timeout` 和 worker 的合作 `cancelled`,避免把预算取消误记为求解器数值失败。
|
||||||
- [x] 单格 max-step 矩阵将空的跨步长比较集合视为“不适用”而非失败;最终 `2 s / 0.02 s` 单格复验整体通过且 `comparisonFailureCount=0`。
|
- [x] 单格 max-step 矩阵将空的跨步长比较集合视为“不适用”而非失败;最终 `2 s / 0.02 s` 单格复验整体通过且 `comparisonFailureCount=0`。
|
||||||
@@ -589,12 +642,13 @@ PYTHONPATH=. .venv/bin/python -m app.simulation.benchmark_regression \
|
|||||||
- [ ] 正常慢步不会被误判为死锁,真实无活动能在约定时间内终止并给出诊断。
|
- [ ] 正常慢步不会被误判为死锁,真实无活动能在约定时间内终止并给出诊断。
|
||||||
- [ ] 取消请求在每个主要阶段都能在有界时间内生效。
|
- [ ] 取消请求在每个主要阶段都能在有界时间内生效。
|
||||||
- [ ] 并发压力下服务仍能响应健康检查和新请求拒绝/排队逻辑。
|
- [ ] 并发压力下服务仍能响应健康检查和新请求拒绝/排队逻辑。
|
||||||
|
- [ ] 权威 `0.2 s / 0.001 s` 浏览器路径完成且不发生假超时;只要内部活动持续,60 s 无接受步不得触发 `SOLVER_STALLED`,真正无活动仍能按约定上限停止并返回最后阶段与计数。
|
||||||
|
|
||||||
### OPT-09 建立 10 s 长时验证与模式覆盖
|
### OPT-09 建立 10 s 长时验证与模式覆盖
|
||||||
|
|
||||||
**目标**:用实测替代“0.81 s 或 2.10 s 可以外推到 10 s”的假设。
|
**目标**:用权威 JSON 的 `BDF / tStop=10 s / sampleStep=0.01 s / maxStep=0.001 s` 完整实测,替代“短仿真或较大 `maxStep` 可以外推到最终工程场景”的假设。
|
||||||
|
|
||||||
**当前状态**:新主目标的 solver-only `1 s / maxStep=0.05 s` 已完成,worker 墙钟 `182.111 s`。修复前,`tStop=2 s` 与 `tStop=5 s` 在同一 `maxStep=0.05 s` 下具有相同的首次失败时刻和求解统计,均在 `t=1.859512845 s` 耗尽热流体外层 25 次;四档 `maxStep` 的失败时刻集中在 `1.8595–1.8603 s`。这说明远端 `tStop` 不是直接失败原因,它只决定运行是否到达该局部数值困难区。
|
**当前状态**:权威 `0.001 s` 长基线尚未完成。既有 `10 s / maxStep=0.02 s` 只作为算法可行性、恢复机制和历史性能证据,不能签收当前 JSON 的工程基线。此前新主目标的 solver-only `1 s / maxStep=0.05 s` 已完成,worker 墙钟 `182.111 s`。修复前,`tStop=2 s` 与 `tStop=5 s` 在同一 `maxStep=0.05 s` 下具有相同的首次失败时刻和求解统计,均在 `t=1.859512845 s` 耗尽热流体外层 25 次;四档 `maxStep` 的失败时刻集中在 `1.8595–1.8603 s`。这说明远端 `tStop` 不是直接失败原因,它只决定运行是否到达该局部数值困难区。
|
||||||
|
|
||||||
PNL00R stream 语义、单次 RHS 事务回滚和基于实际试探步的恢复完成后,production `2 s` 的 `maxStep=0.01/0.02/0.05/0.10 s` 四个单元均到达 `2.0 s`,`caseFailureCount=0`。矩阵命令整体退出码仍为 1,原因是跨 `maxStep` 的严格状态一致性门未通过,而不是任何单元运行失败:差异集中在事件后的 8 个 MECMAS21 速度和 8 个加速度;在差异最大的一组跨 `maxStep` 终点比较中,绝对差约 `1.01e-6–1.12e-6`。`0.05/0.10 s` 两档则逐位一致。因此当前结论是“2 s 运行失败已解决”,但“跨步长数值等价”尚未签收,不能据此批准长时 golden。
|
PNL00R stream 语义、单次 RHS 事务回滚和基于实际试探步的恢复完成后,production `2 s` 的 `maxStep=0.01/0.02/0.05/0.10 s` 四个单元均到达 `2.0 s`,`caseFailureCount=0`。矩阵命令整体退出码仍为 1,原因是跨 `maxStep` 的严格状态一致性门未通过,而不是任何单元运行失败:差异集中在事件后的 8 个 MECMAS21 速度和 8 个加速度;在差异最大的一组跨 `maxStep` 终点比较中,绝对差约 `1.01e-6–1.12e-6`。`0.05/0.10 s` 两档则逐位一致。因此当前结论是“2 s 运行失败已解决”,但“跨步长数值等价”尚未签收,不能据此批准长时 golden。
|
||||||
|
|
||||||
@@ -633,18 +687,24 @@ PNL00R stream 语义、单次 RHS 事务回滚和基于实际试探步的恢复
|
|||||||
|
|
||||||
**工作项**:
|
**工作项**:
|
||||||
|
|
||||||
|
- [ ] 在 OPT-00 的 `0.2/1 s` 短时二维门通过后,使用同一 JSON 和 `maxStep=0.001 s` 依次延长到 `2/5/10 s`;在任何针对本次长跑的性能调优前先完整运行一次权威 `10 s / 0.001 s` 原始基线。
|
||||||
|
- [ ] 首次长基线不得因总墙钟较长而提前当作性能失败;只有 worker、CPU 和内部活动心跳均停止并满足真停滞条件时才有界终止。若发现致命正确性问题,只做使基线可完成的最小修复,然后从 `t=0` 重新运行。
|
||||||
- [ ] 在正式锁定环境运行未优化基线 `10 s`,设置心跳、资源上限和可恢复日志。
|
- [ ] 在正式锁定环境运行未优化基线 `10 s`,设置心跳、资源上限和可恢复日志。
|
||||||
- [ ] 保存事件、模式、步长、拒步、Jacobian、闭合和内存随模拟时间的时间线。
|
- [ ] 保存事件、模式、步长、拒步、Jacobian、闭合和内存随模拟时间的时间线。
|
||||||
- [ ] 为长跑设置阶段性检查点,支持定位首次偏差而非只比较终点。
|
- [ ] 为长跑设置阶段性检查点,支持定位首次偏差而非只比较终点。
|
||||||
- [ ] 将每项 P1 优化分别加入 `10 s` A/B,不把多个改动混成一个结果。
|
- [ ] 将每项 P1 优化分别加入 `10 s` A/B,不把多个改动混成一个结果。
|
||||||
- [ ] 根据首次基线制定合理的 CI 频率和资源门槛。
|
- [ ] 根据首次基线制定合理的 CI 频率和资源门槛。
|
||||||
- [x] 最终通用接线后的当前工作树完成首次 `10 s / maxStep=0.02 s` 单次运行并保存完整统计;连续 3 次验收仍待后续。
|
- [x] 最终通用接线后的当前工作树完成首次 `10 s / maxStep=0.02 s` 单次运行并保存完整统计;连续 3 次验收仍待后续。
|
||||||
|
- [ ] 首次 `10 s / maxStep=0.001 s` 完整报告生成后,才根据各阶段墙钟与内部计数决定性能优化目标;旧 `0.02 s` 报告不得用于跳过该顺序。
|
||||||
|
|
||||||
**验收条件**:
|
**验收条件**:
|
||||||
|
|
||||||
|
- [ ] 权威 `10 s / 0.001 s` 首次基线到达 `t=10`,输出 `0..10 s` 共 1001 个采样时刻且全部有限;事件、模式、关键状态、压力/流量和守恒量满足契约。
|
||||||
- [ ] 连续 3 次完成 `10 s`,没有无解释回退、NaN/Inf 或资源失控。
|
- [ ] 连续 3 次完成 `10 s`,没有无解释回退、NaN/Inf 或资源失控。
|
||||||
- [ ] 全程模式、事件、关键状态和守恒量满足契约。
|
- [ ] 全程模式、事件、关键状态和守恒量满足契约。
|
||||||
- [ ] 可从日志快速判断任何慢区属于积分、Jacobian、闭合、事件还是输出。
|
- [ ] 可从日志快速判断任何慢区属于积分、Jacobian、闭合、事件还是输出。
|
||||||
|
- [ ] 同一 `maxStep=0.001 s` 下,`0.2/1/2/5/10 s` 的严格公共前缀按分类契约一致;短任务终点单独标记 terminal,不与长任务内部插值作位级误判。
|
||||||
|
- [ ] 最终 `10 s` 至少完成 `maxStep=0.001/0.005/0.02 s` 三个代表档,并逐步补齐 `0.002/0.01 s`;较小步长不得出现较大步长没有的可复现数值失败或更早真停滞。
|
||||||
|
|
||||||
### OPT-10 明确高指数 DAE 和强非光滑系统边界
|
### OPT-10 明确高指数 DAE 和强非光滑系统边界
|
||||||
|
|
||||||
@@ -678,6 +738,12 @@ PNL00R stream 语义、单次 RHS 事务回滚和基于实际试探步的恢复
|
|||||||
| 本文复杂 XML `10 s` | 必测 | 必测 | 必测 | 必测 | 必测 | 必测 |
|
| 本文复杂 XML `10 s` | 必测 | 必测 | 必测 | 必测 | 必测 | 必测 |
|
||||||
| 主目标 `test-mql-8` `0.2 s` | 必测 | 必测 | 必测 | 必测 | 必测 | 必测 |
|
| 主目标 `test-mql-8` `0.2 s` | 必测 | 必测 | 必测 | 必测 | 必测 | 必测 |
|
||||||
| 主目标 `test-mql-8` `1/5/10 s` | 必测 | 必测 | 必测 | 必测 | 必测 | 必测 |
|
| 主目标 `test-mql-8` `1/5/10 s` | 必测 | 必测 | 必测 | 必测 | 必测 | 必测 |
|
||||||
|
| 权威 JSON 浏览器/流式 API `0.2 s / maxStep=0.001 s` | 必测 | 必测 | 必测 | 必测 | 必测(含内部活动心跳) | 可选 |
|
||||||
|
| 权威 worker `0.2/1 s × maxStep={0.001,0.002,0.005,0.01,0.02} s` | 必测 | 必测(分类容差) | 必测 | 必测 | 必测(串行矩阵) | 可选 |
|
||||||
|
| 权威 JSON `10 s / maxStep=0.001 s` | 必测 | 必测 | 必测 | 必测 | 必测(完整时间线) | 必测 |
|
||||||
|
|
||||||
|
2026-08-17 的 `maxStep=0.01/0.02/0.05/0.10 s` 延长结果继续作为恢复机制与历史路径证据,但不替代
|
||||||
|
2026-08-18 权威 `maxStep=0.001 s` 的 browser/API/worker P0 门和 10 s 最终基线。
|
||||||
|
|
||||||
当前相关回归套件包括:
|
当前相关回归套件包括:
|
||||||
|
|
||||||
@@ -728,6 +794,8 @@ PNL00R stream 语义、单次 RHS 事务回滚和基于实际试探步的恢复
|
|||||||
| 2026-08-17 | 同一工作树 | OPT-01/02 因果坐标与参考 IR | `760` 个兼容槽压缩为 `440` 个逻辑坐标;独立 schema v1 参考 IR 覆盖 `112+328` 坐标和 320 个逻辑别名 | kernel on/off、兼容槽、状态导数、结构签名和逐阶段差分通过;审计/验证/回退失败均为 0 | Python 调用 `-36.8%`,RHS 微基准 `-12.9%`,production 0.2 s 单次 `-3.68%` | OPT-01 基本完成;IR 暂不接管默认热路径 |
|
| 2026-08-17 | 同一工作树 | OPT-01/02 因果坐标与参考 IR | `760` 个兼容槽压缩为 `440` 个逻辑坐标;独立 schema v1 参考 IR 覆盖 `112+328` 坐标和 320 个逻辑别名 | kernel on/off、兼容槽、状态导数、结构签名和逐阶段差分通过;审计/验证/回退失败均为 0 | Python 调用 `-36.8%`,RHS 微基准 `-12.9%`,production 0.2 s 单次 `-3.68%` | OPT-01 基本完成;IR 暂不接管默认热路径 |
|
||||||
| 2026-08-17 | 同一工作树 | OPT-00/04/05/08/09 热流体恢复与延长矩阵 | 修正 PNL00R 温度 stream 参考;加入 RHS 事务、类型化闭合失败、基于 `h_abs` 的对半重试和完整诊断 | production 0.2 s golden 通过;2 s 四档 `maxStep` 均完成且 `caseFailureCount=0`,但跨步长严格门因近零机械 `a/v` 差异未过;5 s 的 0.02 s 档完成,0.05 s 档为预算取消而非 solver failure | 2 s worker 墙钟为 324.727/292.035/450.425/448.033 s;5 s 的 0.02 s 档为 696.418 s、0 retry、`18736/1347/4988`,0.05 s 档在 1200 s 预算停止于 4.2523535 s | 原 1.86 s 致命失败已恢复;暂以 0.02 s 作为延长测试首选但不修改正式默认值或批准 golden;10 s 的 0.02 s 档进行中 |
|
| 2026-08-17 | 同一工作树 | OPT-00/04/05/08/09 热流体恢复与延长矩阵 | 修正 PNL00R 温度 stream 参考;加入 RHS 事务、类型化闭合失败、基于 `h_abs` 的对半重试和完整诊断 | production 0.2 s golden 通过;2 s 四档 `maxStep` 均完成且 `caseFailureCount=0`,但跨步长严格门因近零机械 `a/v` 差异未过;5 s 的 0.02 s 档完成,0.05 s 档为预算取消而非 solver failure | 2 s worker 墙钟为 324.727/292.035/450.425/448.033 s;5 s 的 0.02 s 档为 696.418 s、0 retry、`18736/1347/4988`,0.05 s 档在 1200 s 预算停止于 4.2523535 s | 原 1.86 s 致命失败已恢复;暂以 0.02 s 作为延长测试首选但不修改正式默认值或批准 golden;10 s 的 0.02 s 档进行中 |
|
||||||
| 2026-08-17 | 同一工作树;最终通用接线与 10 s repeat | OPT-04/05/08/09 `10 s` 最终收口 | eventless Generic opt-in stepwise recovery;StreamResolver 刷新全部温度参考 override;修复单格矩阵空比较器 | 0.01 s 接线前后逐值一致;两次 0.2 s final candidate 彼此逐值相同且均为旧 golden 398/402,同样 4 个终点派生 MECMAS21 `a` 超差、最大容差比 1.373,未覆盖 golden;最终 2 s 单格通过;真实 SciPy direct/stepwise A/B 等价;完整 unittest 828 项 OK(3 项跳过) | 最终接线后 10 s worker/orchestration 1602.733/1604.152 s,`45455/3075/15282`,接受步 9569、启动 6、事件 2;`t=6.9640458 s` 的 1 次热流体失败经 1 次重试恢复,最大迭代 23、残差 `1.082e-16`,1717 序列/1,722,151 标量全有限;最终 2 s worker 301.782 s | 最终通用接线后的 10 s 已完成;803.622 s 旧报告只作接线前历史证据、不作最终性能;旧 exit 1 仅为空比较器缺陷;旧 golden 保留,连续 3 次 10 s 仍待后续 |
|
| 2026-08-17 | 同一工作树;最终通用接线与 10 s repeat | OPT-04/05/08/09 `10 s` 最终收口 | eventless Generic opt-in stepwise recovery;StreamResolver 刷新全部温度参考 override;修复单格矩阵空比较器 | 0.01 s 接线前后逐值一致;两次 0.2 s final candidate 彼此逐值相同且均为旧 golden 398/402,同样 4 个终点派生 MECMAS21 `a` 超差、最大容差比 1.373,未覆盖 golden;最终 2 s 单格通过;真实 SciPy direct/stepwise A/B 等价;完整 unittest 828 项 OK(3 项跳过) | 最终接线后 10 s worker/orchestration 1602.733/1604.152 s,`45455/3075/15282`,接受步 9569、启动 6、事件 2;`t=6.9640458 s` 的 1 次热流体失败经 1 次重试恢复,最大迭代 23、残差 `1.082e-16`,1717 序列/1,722,151 标量全有限;最终 2 s worker 301.782 s | 最终通用接线后的 10 s 已完成;803.622 s 旧报告只作接线前历史证据、不作最终性能;旧 exit 1 仅为空比较器缺陷;旧 golden 保留,连续 3 次 10 s 仍待后续 |
|
||||||
|
| 2026-08-18 | 工作树基于 `684d287`;AME SHA `cbc3aadd...` | OPT-00 完成 | AME→XML/JSON 权威契约、22 包发布锁、双 golden、最终 replay 与历史 2.10 s 三次复测 | AME 25 项外部评估通过;状态 426/426、物理 33/33 本地重放零误差;quick 179、全量 849 项通过 | 0.2 s worker 159.607 s;2.10 s 三次 113.497–115.868 s | OPT-00 本地验收完成;1 s 预算内 eligible,长时递进转 OPT-09;远端 CI 待提交触发 |
|
||||||
|
| 2026-08-18 | 同一权威 AME/XML/JSON 工作树 | OPT-00/05/08/09 步长鲁棒性重新打开 | 浏览器在 `BDF / 0.2 s / sampleStep=0.01 s / maxStep=0.001 s` 下于 `t≈0.0489 s` 计算超时,当前工程路径判定失败;新增 browser/API/worker 对账、`0.2/1 s × 五档` 短时矩阵、内部活动心跳和权威 10 s 门 | 失败事实已确认,具体根因尚未区分为数值真停滞、内部慢步、后处理/传输或 60 s 服务假超时;离线 OPT-00 证据保留但不足以签收浏览器工程路径 | 暂不使用旧 `0.02 s` 长跑推断 `0.001 s`;先定位并提交方案审阅,短时门通过后再完整取得未经本次性能优化的 `10 s / 0.001 s` 基线 | OPT-00 工程端到端门重新打开;OPT-05 提升为 P0/P1,OPT-08 为 P0 服务门,OPT-09 只认 `0.001 s` 权威长基线 |
|
||||||
|
|
||||||
## 9. 相关文档
|
## 9. 相关文档
|
||||||
|
|
||||||
|
|||||||
@@ -10,3 +10,15 @@
|
|||||||
- 相同 `maxStep=0.02` 的 `2 s` 与 `10 s` 运行在公共严格前缀检查点逐值一致,确认此前约 `1.86 s` 的失败来自不可恢复的试探态闭合处理,而不是远端 `tStop` 直接改变物理方程。
|
- 相同 `maxStep=0.02` 的 `2 s` 与 `10 s` 运行在公共严格前缀检查点逐值一致,确认此前约 `1.86 s` 的失败来自不可恢复的试探态闭合处理,而不是远端 `tStop` 直接改变物理方程。
|
||||||
- 全量后端共运行 `828` 项测试,结果为 OK,其中 `3` 项按条件跳过;差异检查通过且测试后无遗留仿真进程。
|
- 全量后端共运行 `828` 项测试,结果为 OK,其中 `3` 项按条件跳过;差异检查通过且测试后无遗留仿真进程。
|
||||||
- 当前仍有明确限制:跨最大步长严格比较尚未全部通过;最终 `0.2 s` 候选相对旧 golden 为 `398/402`,4 个超差项均是终点派生加速度,旧 golden 未被覆盖;最终 `10 s` 仅完成一次,仍需三次中位数、资源稳定性和新 golden 决策。
|
- 当前仍有明确限制:跨最大步长严格比较尚未全部通过;最终 `0.2 s` 候选相对旧 golden 为 `398/402`,4 个超差项均是终点派生加速度,旧 golden 未被覆盖;最终 `10 s` 仅完成一次,仍需三次中位数、资源稳定性和新 golden 决策。
|
||||||
|
|
||||||
|
## 07:58
|
||||||
|
|
||||||
|
- 以 `AmesimModels/test_mql.ame` 为权威重新核对 `test-mql-8.xml/json`:20 类、157 个项目组件、178 条连接和 1092 个参数一致;唯一确定差异是仿真配置,已按 AME 与其结果网格修正为 `0→10 s`、`sampleStep=0.01 s`、`maxStep=0.001 s`。
|
||||||
|
- 新增 AME 防漂移契约,直接验证归档 SHA/字节、`.sim/.results` 时间轴、单位与表压转换、公式等价、DIRECT/接触/建模线拓扑,以及 XML↔JSON 的逐 ID、参数和端口一致性。
|
||||||
|
- 建立并批准 production `0.2 s` 的通用状态 golden 与 physical-state-v2.1 golden:前者覆盖 142 个状态键、3 个检查点和 426 个值;后者覆盖压力、质量流量、质量守恒、总储气质量和离散模式,并保留 AMESim 外部校准 provenance。
|
||||||
|
- AMESim 外部评估 25 项通过;2 个 `t=0.04 s` 跳变流量因左右极限语义显式不参与外部比较。最差相对误差为 `0.1393485%`,未超过 0.2% 审阅容差;本地物理 golden 33/33 重放误差为 0。
|
||||||
|
- 最终 production replay 的 worker/orchestration 墙钟为 `159.607/160.473 s`,状态与物理门禁均通过;按既定安全公式外推 1 s 为 `1197.053 s`,略低于 1200 s soft budget,记录为后续阶段可运行但本次 OPT-00 未启动。
|
||||||
|
- 历史 production `0.81/2.10 s` 严格串行复测三次并批准两档 golden;三次检查点、状态、事件、输出契约及除计时外诊断逐值一致,无非有限值或非预期回退。
|
||||||
|
- 新增 Linux x86_64 的 22 包 binary-only SHA-256 发布锁;全新空 venv 离线安装、`pip check` 和依赖契约通过,CI 的 quick/historical/main-long 三层任务统一使用该锁。
|
||||||
|
- 最终 quick workflow 同口径 179 项通过(2 项预期跳过),完整后端 849 项通过(3 项预期跳过),`git diff --check` 与残留进程检查进入最终收尾。
|
||||||
|
- OPT-00 已完成当时工作树的本地验收。仍存在的问题:批准报告来自 `684d287` 的脏工作树;后续求解器提交合入后尚未重新运行真实 production 基线和全量回归,远端 workflow 也待提交后首次托管验证。
|
||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
# Supported dependency ranges. Reproducible Python 3.12 installs should also
|
# Supported dependency ranges. Linux CPython 3.12 x86_64 release installs
|
||||||
# apply constraints/python312-direct.txt; see README.md.
|
# should use constraints/python312-linux-x86_64.lock directly; see README.md.
|
||||||
fastapi
|
fastapi
|
||||||
lxml>=5,<7
|
lxml>=5,<7
|
||||||
numpy>=1.26,<3
|
numpy>=1.26,<3
|
||||||
|
|||||||
+952
@@ -0,0 +1,952 @@
|
|||||||
|
{
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"id": "test_mql_8-production-0.2s-physical-state-v2.1",
|
||||||
|
"contractId": "physical-state-v2.1",
|
||||||
|
"caseId": "0.2s",
|
||||||
|
"lane": "production",
|
||||||
|
"sourceXmlSha256": "0a2d9331df9eb5974daec25a61c1238ba32b1742d933ffc8b16ce316c5627b0b",
|
||||||
|
"approval": {
|
||||||
|
"status": "candidate",
|
||||||
|
"generatedAt": "2026-08-18T07:35:03.491746+00:00",
|
||||||
|
"warning": "The correctness gate rejects this file until explicit approval."
|
||||||
|
},
|
||||||
|
"provenance": {
|
||||||
|
"localSourceReport": {
|
||||||
|
"path": "tests/baselines/simulation/test_mql_8/runs/2026-08-18-production-physical-state-v2.1-0.2.json",
|
||||||
|
"bytes": 380076,
|
||||||
|
"sha256": "c647fc7dab6c5cdaea188789dd8e0192d9caf374873afa1f5f5db0da9d69c49b",
|
||||||
|
"generatedAt": "2026-08-18T07:34:00.055573+00:00"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"archivePath": "AmesimModels/test_mql.ame",
|
||||||
|
"archiveBytes": 21708800,
|
||||||
|
"archiveSha256": "cbc3aadd4569a49b3a63e5d66d4143ec16126c0f950df73fb637e07673c20fbb",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"name": "test_mql_.var",
|
||||||
|
"bytes": 95371,
|
||||||
|
"sha256": "175010af62d254b34b1f876ff652feb903fe2ce88bee80d4dc0ef1d31f04067b"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "test_mql_.results",
|
||||||
|
"bytes": 8968576,
|
||||||
|
"sha256": "434a2cdff1322565957934354154425868fa03737558636927cb0f3ec51f1760"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"referencePressurePa": 101300.0,
|
||||||
|
"role": "external calibration reference; not an equality claim"
|
||||||
|
},
|
||||||
|
"amesimStoredMassDataPaths": [
|
||||||
|
"mgas1@pn_c1_8",
|
||||||
|
"mgas1@pn_c1_9",
|
||||||
|
"mgas1@pn_c1_10",
|
||||||
|
"mgas1@pn_c1_11",
|
||||||
|
"mgas1@pn_c1_12",
|
||||||
|
"mgas1@pn_c1_13",
|
||||||
|
"mgas1@pn_c1_14",
|
||||||
|
"mgas1@pn_c1_15",
|
||||||
|
"mgas@pn_general_chamber",
|
||||||
|
"mgas@pn_general_chamber_2",
|
||||||
|
"mgas@pn_general_chamber_4",
|
||||||
|
"mgas@pn_general_chamber_5",
|
||||||
|
"mgas@pneumatic_65",
|
||||||
|
"mgas@pneumatic_66",
|
||||||
|
"mgas@pneumatic_68",
|
||||||
|
"mgas@pneumatic_69",
|
||||||
|
"mgas@pneumatic_70",
|
||||||
|
"mgas@pneumatic_71",
|
||||||
|
"mgas@pneumatic_72",
|
||||||
|
"mgas@pneumatic_73",
|
||||||
|
"mgas@pneumatic_74",
|
||||||
|
"mgas@pneumatic_75",
|
||||||
|
"mgas@pneumatic_76",
|
||||||
|
"mgas@pneumatic_77",
|
||||||
|
"mgas@pneumatic_78",
|
||||||
|
"mgas@pneumatic_79",
|
||||||
|
"mgas@pneumatic_80",
|
||||||
|
"mgas@pneumatic_81",
|
||||||
|
"mgas@pneumatic_82",
|
||||||
|
"mgas@pneumatic_83",
|
||||||
|
"mgas@pneumatic_84",
|
||||||
|
"mgas@pneumatic_85",
|
||||||
|
"mgas@pneumatic_86",
|
||||||
|
"mgas@pneumatic_87",
|
||||||
|
"mgas@pneumatic_88",
|
||||||
|
"mgas@pneumatic_91",
|
||||||
|
"mgas@pneumatic_92",
|
||||||
|
"mgas@pneumatic_93",
|
||||||
|
"mgas@pneumatic_94",
|
||||||
|
"mgas@pneumatic_95",
|
||||||
|
"mgas@pneumatic_96",
|
||||||
|
"mgas@pneumatic_97",
|
||||||
|
"mgas@pneumatic_98",
|
||||||
|
"mgas@pneumatic_99",
|
||||||
|
"mgas@pneumatic_101",
|
||||||
|
"mgas@pneumatic_102",
|
||||||
|
"mgas@pneumatic_103",
|
||||||
|
"mgas@pneumatic_104"
|
||||||
|
],
|
||||||
|
"comparisonPolicy": "Local values are the regression target; transformed AMESim values are retained visibly as an external calibration reference."
|
||||||
|
},
|
||||||
|
"layout": {
|
||||||
|
"projectionKeys": [
|
||||||
|
"pressure.pnch012_8.absolute",
|
||||||
|
"pressure.pnl0001_20.absolute",
|
||||||
|
"massFlow.pnl0001_20.port_1.intoComponent",
|
||||||
|
"massFlow.pnvo001_5.port_2.intoComponent",
|
||||||
|
"conservation.p4node2_8.massBalance",
|
||||||
|
"conservation.pnvo001_5.massBalance",
|
||||||
|
"conservation.pnl0001_20_pnch012_8.connectionMassBalance",
|
||||||
|
"conservation.totalStoredGasMass",
|
||||||
|
"discrete.pnvo001_5.openMode",
|
||||||
|
"discrete.mecmas21_9.endstopMode",
|
||||||
|
"discrete.mecmas21_10.endstopMode"
|
||||||
|
],
|
||||||
|
"projections": [
|
||||||
|
{
|
||||||
|
"key": "pressure.pnch012_8.absolute",
|
||||||
|
"category": "pressure",
|
||||||
|
"unit": "Pa",
|
||||||
|
"python": {
|
||||||
|
"sourceKeys": [
|
||||||
|
"amesim_pnch012_8.p"
|
||||||
|
],
|
||||||
|
"formula": "identity"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"dataPaths": [
|
||||||
|
"press@pn_c1_8"
|
||||||
|
],
|
||||||
|
"sourceUnit": "Pa (gauge)",
|
||||||
|
"targetUnit": "Pa (absolute)",
|
||||||
|
"formula": "target = source + 101300",
|
||||||
|
"scale": 1.0,
|
||||||
|
"offset": 101300.0
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0002,
|
||||||
|
"absolute": 0.001
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "pressure.pnl0001_20.absolute",
|
||||||
|
"category": "pressure",
|
||||||
|
"unit": "Pa",
|
||||||
|
"python": {
|
||||||
|
"sourceKeys": [
|
||||||
|
"amesim_pnl0001_20.p"
|
||||||
|
],
|
||||||
|
"formula": "identity"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"dataPaths": [
|
||||||
|
"p2@pneumatic_69"
|
||||||
|
],
|
||||||
|
"sourceUnit": "Pa (gauge)",
|
||||||
|
"targetUnit": "Pa (absolute)",
|
||||||
|
"formula": "target = source + 101300",
|
||||||
|
"scale": 1.0,
|
||||||
|
"offset": 101300.0
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0002,
|
||||||
|
"absolute": 0.001
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "massFlow.pnl0001_20.port_1.intoComponent",
|
||||||
|
"category": "massFlow",
|
||||||
|
"unit": "kg/s",
|
||||||
|
"python": {
|
||||||
|
"sourceKeys": [
|
||||||
|
"amesim_pnl0001_20.port_1.m_flow"
|
||||||
|
],
|
||||||
|
"formula": "identity"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"dataPaths": [
|
||||||
|
"dm1@pneumatic_69"
|
||||||
|
],
|
||||||
|
"sourceUnit": "g/s (AMESim component orientation)",
|
||||||
|
"targetUnit": "kg/s (positive into generic component)",
|
||||||
|
"formula": "target = -source * 1e-3",
|
||||||
|
"scale": -0.001,
|
||||||
|
"offset": 0.0
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0002,
|
||||||
|
"absolute": 1e-09
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "massFlow.pnvo001_5.port_2.intoComponent",
|
||||||
|
"category": "massFlow",
|
||||||
|
"unit": "kg/s",
|
||||||
|
"python": {
|
||||||
|
"sourceKeys": [
|
||||||
|
"amesim_pnvo001_5.port_2.m_flow"
|
||||||
|
],
|
||||||
|
"formula": "identity"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"dataPaths": [
|
||||||
|
"dm2@pn_morifice_1"
|
||||||
|
],
|
||||||
|
"sourceUnit": "g/s (AMESim component orientation)",
|
||||||
|
"targetUnit": "kg/s (positive into generic component)",
|
||||||
|
"formula": "target = -source * 1e-3",
|
||||||
|
"scale": -0.001,
|
||||||
|
"offset": 0.0
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0002,
|
||||||
|
"absolute": 1e-09
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "conservation.p4node2_8.massBalance",
|
||||||
|
"category": "conservation",
|
||||||
|
"unit": "kg/s",
|
||||||
|
"python": {
|
||||||
|
"sourceKeys": [
|
||||||
|
"amesim_p4node2_8.port_1.m_flow",
|
||||||
|
"amesim_p4node2_8.port_2.m_flow",
|
||||||
|
"amesim_p4node2_8.port_3.m_flow",
|
||||||
|
"amesim_p4node2_8.port_4.m_flow"
|
||||||
|
],
|
||||||
|
"formula": "sum"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"dataPaths": [],
|
||||||
|
"note": "AMESim archive has no complete saved four-port tuple."
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0,
|
||||||
|
"absolute": 1e-09
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "conservation.pnvo001_5.massBalance",
|
||||||
|
"category": "conservation",
|
||||||
|
"unit": "kg/s",
|
||||||
|
"python": {
|
||||||
|
"sourceKeys": [
|
||||||
|
"amesim_pnvo001_5.port_2.m_flow",
|
||||||
|
"amesim_pnvo001_5.port_3.m_flow"
|
||||||
|
],
|
||||||
|
"formula": "sum"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"dataPaths": [
|
||||||
|
"dm2@pn_morifice_1",
|
||||||
|
"dm3@pn_morifice_1"
|
||||||
|
],
|
||||||
|
"sourceUnit": "g/s",
|
||||||
|
"targetUnit": "kg/s",
|
||||||
|
"formula": "target = -(source1 + source2) * 1e-3"
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0,
|
||||||
|
"absolute": 1e-09
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "conservation.pnl0001_20_pnch012_8.connectionMassBalance",
|
||||||
|
"category": "conservation",
|
||||||
|
"unit": "kg/s",
|
||||||
|
"python": {
|
||||||
|
"sourceKeys": [
|
||||||
|
"amesim_pnl0001_20.port_1.m_flow",
|
||||||
|
"amesim_pnch012_8.port_1.m_flow"
|
||||||
|
],
|
||||||
|
"formula": "sum"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"dataPaths": [],
|
||||||
|
"note": "PNCH012 port flow is not saved; local connector contract is authoritative."
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0,
|
||||||
|
"absolute": 1e-09
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "conservation.totalStoredGasMass",
|
||||||
|
"category": "conservation",
|
||||||
|
"unit": "kg",
|
||||||
|
"python": {
|
||||||
|
"sourceKeys": [
|
||||||
|
"amesim_pnch012_10.m",
|
||||||
|
"amesim_pnch012_11.m",
|
||||||
|
"amesim_pnch012_12.m",
|
||||||
|
"amesim_pnch012_13.m",
|
||||||
|
"amesim_pnch012_14.m",
|
||||||
|
"amesim_pnch012_15.m",
|
||||||
|
"amesim_pnch012_8.m",
|
||||||
|
"amesim_pnch012_9.m",
|
||||||
|
"amesim_pnch023_1.m",
|
||||||
|
"amesim_pnch023_2.m",
|
||||||
|
"amesim_pnch023_3.m",
|
||||||
|
"amesim_pnch023_4.m",
|
||||||
|
"amesim_pnl0001_1.m",
|
||||||
|
"amesim_pnl0001_10.m",
|
||||||
|
"amesim_pnl0001_11.m",
|
||||||
|
"amesim_pnl0001_13.m",
|
||||||
|
"amesim_pnl0001_14.m",
|
||||||
|
"amesim_pnl0001_15.m",
|
||||||
|
"amesim_pnl0001_16.m",
|
||||||
|
"amesim_pnl0001_17.m",
|
||||||
|
"amesim_pnl0001_18.m",
|
||||||
|
"amesim_pnl0001_19.m",
|
||||||
|
"amesim_pnl0001_2.m",
|
||||||
|
"amesim_pnl0001_20.m",
|
||||||
|
"amesim_pnl0001_21.m",
|
||||||
|
"amesim_pnl0001_25.m",
|
||||||
|
"amesim_pnl0001_26.m",
|
||||||
|
"amesim_pnl0001_27.m",
|
||||||
|
"amesim_pnl0001_4.m",
|
||||||
|
"amesim_pnl0001_5.m",
|
||||||
|
"amesim_pnl0001_7.m",
|
||||||
|
"amesim_pnl0001_9.m",
|
||||||
|
"amesim_pnl0002_1.m",
|
||||||
|
"amesim_pnl0002_2.m",
|
||||||
|
"amesim_pnl0002_3.m",
|
||||||
|
"amesim_pnl0002_4.m",
|
||||||
|
"amesim_pnl0002_5.m",
|
||||||
|
"amesim_pnl0002_6.m",
|
||||||
|
"amesim_pnl0002_7.m",
|
||||||
|
"amesim_pnl0002_8.m",
|
||||||
|
"amesim_pnl0003_1.m1",
|
||||||
|
"amesim_pnl0003_1.m2",
|
||||||
|
"amesim_pnl0003_2.m1",
|
||||||
|
"amesim_pnl0003_2.m2",
|
||||||
|
"amesim_pnl0003_3.m1",
|
||||||
|
"amesim_pnl0003_3.m2",
|
||||||
|
"amesim_pnl0003_4.m1",
|
||||||
|
"amesim_pnl0003_4.m2",
|
||||||
|
"amesim_pnl0003_5.m1",
|
||||||
|
"amesim_pnl0003_5.m2",
|
||||||
|
"amesim_pnl0003_6.m1",
|
||||||
|
"amesim_pnl0003_6.m2",
|
||||||
|
"amesim_pnl0003_7.m1",
|
||||||
|
"amesim_pnl0003_7.m2",
|
||||||
|
"amesim_pnl0003_8.m1",
|
||||||
|
"amesim_pnl0003_8.m2"
|
||||||
|
],
|
||||||
|
"formula": "sum"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"dataPathSelection": "units == 'g' and signal starts with 'mgas'",
|
||||||
|
"sourceUnit": "g",
|
||||||
|
"targetUnit": "kg",
|
||||||
|
"formula": "target = sum(sources) * 1e-3"
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0002,
|
||||||
|
"absolute": 1e-09
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "discrete.pnvo001_5.openMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"unit": "1",
|
||||||
|
"python": {
|
||||||
|
"sourceKeys": [
|
||||||
|
"amesim_pnvo001_5.xv"
|
||||||
|
],
|
||||||
|
"formula": "1 if opening >= 0.5 else 0"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"dataPaths": [
|
||||||
|
"xv@pn_morifice_1"
|
||||||
|
],
|
||||||
|
"sourceUnit": "1",
|
||||||
|
"targetUnit": "mode code {0,1}",
|
||||||
|
"formula": "1 if source >= 0.5 else 0"
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0,
|
||||||
|
"absolute": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "discrete.mecmas21_9.endstopMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"unit": "1",
|
||||||
|
"python": {
|
||||||
|
"sourceKeys": [
|
||||||
|
"amesim_mecmas21_9.x",
|
||||||
|
"amesim_mecmas21_9.v",
|
||||||
|
"amesim_mecmas21_9.port_1.f",
|
||||||
|
"amesim_mecmas21_9.port_2.f"
|
||||||
|
],
|
||||||
|
"formula": "-1 lower, 0 free, +1 upper using boundary and net-force direction"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"dataPaths": [
|
||||||
|
"x1@mass_friction_endstops_19",
|
||||||
|
"v1@mass_friction_endstops_19"
|
||||||
|
],
|
||||||
|
"lowerBound": -0.72,
|
||||||
|
"upperBound": 0.0,
|
||||||
|
"note": "No saved AMESim endstop code; reference is boundary occupancy."
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0,
|
||||||
|
"absolute": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "discrete.mecmas21_10.endstopMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"unit": "1",
|
||||||
|
"python": {
|
||||||
|
"sourceKeys": [
|
||||||
|
"amesim_mecmas21_10.x",
|
||||||
|
"amesim_mecmas21_10.v",
|
||||||
|
"amesim_mecmas21_10.port_1.f",
|
||||||
|
"amesim_mecmas21_10.port_2.f"
|
||||||
|
],
|
||||||
|
"formula": "-1 lower, 0 free, +1 upper using boundary and net-force direction"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"dataPaths": [
|
||||||
|
"x1@mass_friction_endstops_18",
|
||||||
|
"v1@mass_friction_endstops_18"
|
||||||
|
],
|
||||||
|
"lowerBound": 0.0,
|
||||||
|
"upperBound": 0.37,
|
||||||
|
"note": "No saved AMESim endstop code; reference is boundary occupancy."
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0,
|
||||||
|
"absolute": 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"projectionLayoutSha256": "55cc8f71ea72fd46f71f1ede2587aeb9f6d590bde8e97e881648f88a4a90dca6"
|
||||||
|
},
|
||||||
|
"checkpoints": [
|
||||||
|
{
|
||||||
|
"requestedTime": 0.0,
|
||||||
|
"values": [
|
||||||
|
100000.0,
|
||||||
|
100000.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
5.5668930151375235,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
-1.0
|
||||||
|
],
|
||||||
|
"amesimReferenceValues": [
|
||||||
|
100000.00000000001,
|
||||||
|
100000.00000000001,
|
||||||
|
-0.0,
|
||||||
|
-0.0,
|
||||||
|
null,
|
||||||
|
-0.0,
|
||||||
|
null,
|
||||||
|
5.5668930151375235,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
-1.0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"values": [
|
||||||
|
100153.57210434608,
|
||||||
|
100152.45747547514,
|
||||||
|
6.682314111565264e-06,
|
||||||
|
-0.4978238221497115,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
5.5668930151375235,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
-1.0
|
||||||
|
],
|
||||||
|
"amesimReferenceValues": [
|
||||||
|
100153.61882579065,
|
||||||
|
100152.49205385521,
|
||||||
|
6.672550142634319e-06,
|
||||||
|
-0.4978238226601424,
|
||||||
|
null,
|
||||||
|
-0.0,
|
||||||
|
null,
|
||||||
|
5.566893015142308,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
-1.0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.2,
|
||||||
|
"values": [
|
||||||
|
3620589.728099082,
|
||||||
|
3756379.1344475006,
|
||||||
|
-0.3723610392591412,
|
||||||
|
-0.3962730176377355,
|
||||||
|
1.8214596497756474e-17,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
5.566893015137554,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
-1.0
|
||||||
|
],
|
||||||
|
"amesimReferenceValues": [
|
||||||
|
3625053.2009413484,
|
||||||
|
3760735.7825351665,
|
||||||
|
-0.3728806429214546,
|
||||||
|
-0.3961933197727504,
|
||||||
|
null,
|
||||||
|
-0.0,
|
||||||
|
null,
|
||||||
|
5.566892994134813,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
-1.0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"amesimAlignmentAtGeneration": {
|
||||||
|
"passed": true,
|
||||||
|
"issues": [],
|
||||||
|
"comparedValueCount": 25,
|
||||||
|
"excludedValueCount": 2,
|
||||||
|
"maxToleranceRatio": 0.6967416724836332,
|
||||||
|
"maxToleranceRatioUnbounded": false,
|
||||||
|
"worstValue": {
|
||||||
|
"requestedTime": 0.2,
|
||||||
|
"key": "massFlow.pnl0001_20.port_1.intoComponent",
|
||||||
|
"category": "massFlow",
|
||||||
|
"python": -0.3723610392591412,
|
||||||
|
"amesim": -0.3728806429214546,
|
||||||
|
"absoluteError": 0.0005196036623134059,
|
||||||
|
"relativeError": 0.0013934852135053246,
|
||||||
|
"allowedError": 0.0007457622858429093,
|
||||||
|
"toleranceRatio": 0.6967416724836332,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
"metrics": [
|
||||||
|
{
|
||||||
|
"requestedTime": 0.0,
|
||||||
|
"key": "pressure.pnch012_8.absolute",
|
||||||
|
"category": "pressure",
|
||||||
|
"python": 100000.0,
|
||||||
|
"amesim": 100000.00000000001,
|
||||||
|
"absoluteError": 1.4551915228366852e-11,
|
||||||
|
"relativeError": 1.455191522836685e-16,
|
||||||
|
"allowedError": 200.00100000000003,
|
||||||
|
"toleranceRatio": 7.275921234577252e-14,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.0,
|
||||||
|
"key": "pressure.pnl0001_20.absolute",
|
||||||
|
"category": "pressure",
|
||||||
|
"python": 100000.0,
|
||||||
|
"amesim": 100000.00000000001,
|
||||||
|
"absoluteError": 1.4551915228366852e-11,
|
||||||
|
"relativeError": 1.455191522836685e-16,
|
||||||
|
"allowedError": 200.00100000000003,
|
||||||
|
"toleranceRatio": 7.275921234577252e-14,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.0,
|
||||||
|
"key": "massFlow.pnl0001_20.port_1.intoComponent",
|
||||||
|
"category": "massFlow",
|
||||||
|
"python": 0.0,
|
||||||
|
"amesim": -0.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 1e-09,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.0,
|
||||||
|
"key": "massFlow.pnvo001_5.port_2.intoComponent",
|
||||||
|
"category": "massFlow",
|
||||||
|
"python": 0.0,
|
||||||
|
"amesim": -0.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 1e-09,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.0,
|
||||||
|
"key": "conservation.pnvo001_5.massBalance",
|
||||||
|
"category": "conservation",
|
||||||
|
"python": 0.0,
|
||||||
|
"amesim": -0.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 1e-09,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.0,
|
||||||
|
"key": "conservation.totalStoredGasMass",
|
||||||
|
"category": "conservation",
|
||||||
|
"python": 5.5668930151375235,
|
||||||
|
"amesim": 5.5668930151375235,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 0.011133787030275047,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.0,
|
||||||
|
"key": "discrete.pnvo001_5.openMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"python": 0.0,
|
||||||
|
"amesim": 0.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 0.0,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.0,
|
||||||
|
"key": "discrete.mecmas21_9.endstopMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"python": 1.0,
|
||||||
|
"amesim": 1.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 0.0,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.0,
|
||||||
|
"key": "discrete.mecmas21_10.endstopMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"python": -1.0,
|
||||||
|
"amesim": -1.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 0.0,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"key": "pressure.pnch012_8.absolute",
|
||||||
|
"category": "pressure",
|
||||||
|
"python": 100153.57210434608,
|
||||||
|
"amesim": 100153.61882579065,
|
||||||
|
"absoluteError": 0.04672144456708338,
|
||||||
|
"relativeError": 4.6649781720170954e-07,
|
||||||
|
"allowedError": 200.3082376515813,
|
||||||
|
"toleranceRatio": 0.00023324774415094828,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"key": "pressure.pnl0001_20.absolute",
|
||||||
|
"category": "pressure",
|
||||||
|
"python": 100152.45747547514,
|
||||||
|
"amesim": 100152.49205385521,
|
||||||
|
"absoluteError": 0.03457838007307146,
|
||||||
|
"relativeError": 3.4525731076644157e-07,
|
||||||
|
"allowedError": 200.30598410771043,
|
||||||
|
"toleranceRatio": 0.00017262779355846724,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"key": "massFlow.pnl0001_20.port_1.intoComponent",
|
||||||
|
"category": "massFlow",
|
||||||
|
"python": 6.682314111565264e-06,
|
||||||
|
"amesim": 6.672550142634319e-06,
|
||||||
|
"absoluteError": 9.763968930944316e-09,
|
||||||
|
"relativeError": 0.0014633039426046946,
|
||||||
|
"allowedError": 1.4345100285268639e-08,
|
||||||
|
"toleranceRatio": 0.6806483563569921,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": false,
|
||||||
|
"passed": null,
|
||||||
|
"exclusionReason": "signalDiscontinuityLeftRightLimitSemanticsNotComparableAt0.04s"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"key": "massFlow.pnvo001_5.port_2.intoComponent",
|
||||||
|
"category": "massFlow",
|
||||||
|
"python": -0.4978238221497115,
|
||||||
|
"amesim": -0.4978238226601424,
|
||||||
|
"absoluteError": 5.104309197534462e-10,
|
||||||
|
"relativeError": 1.0253244150228433e-09,
|
||||||
|
"allowedError": 0.0009956486453202849,
|
||||||
|
"toleranceRatio": 5.126616926086898e-07,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": false,
|
||||||
|
"passed": null,
|
||||||
|
"exclusionReason": "signalDiscontinuityLeftRightLimitSemanticsNotComparableAt0.04s"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"key": "conservation.pnvo001_5.massBalance",
|
||||||
|
"category": "conservation",
|
||||||
|
"python": 0.0,
|
||||||
|
"amesim": -0.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 1e-09,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"key": "conservation.totalStoredGasMass",
|
||||||
|
"category": "conservation",
|
||||||
|
"python": 5.5668930151375235,
|
||||||
|
"amesim": 5.566893015142308,
|
||||||
|
"absoluteError": 4.784617146924575e-12,
|
||||||
|
"relativeError": 8.594771147766101e-13,
|
||||||
|
"allowedError": 0.011133787030284616,
|
||||||
|
"toleranceRatio": 4.2973851879060635e-10,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"key": "discrete.pnvo001_5.openMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"python": 1.0,
|
||||||
|
"amesim": 1.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 0.0,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"key": "discrete.mecmas21_9.endstopMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"python": 1.0,
|
||||||
|
"amesim": 1.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 0.0,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"key": "discrete.mecmas21_10.endstopMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"python": -1.0,
|
||||||
|
"amesim": -1.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 0.0,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.2,
|
||||||
|
"key": "pressure.pnch012_8.absolute",
|
||||||
|
"category": "pressure",
|
||||||
|
"python": 3620589.728099082,
|
||||||
|
"amesim": 3625053.2009413484,
|
||||||
|
"absoluteError": 4463.4728422663175,
|
||||||
|
"relativeError": 0.0012312847825536048,
|
||||||
|
"allowedError": 7250.107401882698,
|
||||||
|
"toleranceRatio": 0.6156423063618685,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.2,
|
||||||
|
"key": "pressure.pnl0001_20.absolute",
|
||||||
|
"category": "pressure",
|
||||||
|
"python": 3756379.1344475006,
|
||||||
|
"amesim": 3760735.7825351665,
|
||||||
|
"absoluteError": 4356.648087665904,
|
||||||
|
"relativeError": 0.0011584563073795695,
|
||||||
|
"allowedError": 7521.472565070333,
|
||||||
|
"toleranceRatio": 0.5792280766798443,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.2,
|
||||||
|
"key": "massFlow.pnl0001_20.port_1.intoComponent",
|
||||||
|
"category": "massFlow",
|
||||||
|
"python": -0.3723610392591412,
|
||||||
|
"amesim": -0.3728806429214546,
|
||||||
|
"absoluteError": 0.0005196036623134059,
|
||||||
|
"relativeError": 0.0013934852135053246,
|
||||||
|
"allowedError": 0.0007457622858429093,
|
||||||
|
"toleranceRatio": 0.6967416724836332,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.2,
|
||||||
|
"key": "massFlow.pnvo001_5.port_2.intoComponent",
|
||||||
|
"category": "massFlow",
|
||||||
|
"python": -0.3962730176377355,
|
||||||
|
"amesim": -0.3961933197727504,
|
||||||
|
"absoluteError": 7.969786498507325e-05,
|
||||||
|
"relativeError": 0.00020115903274388008,
|
||||||
|
"allowedError": 0.0007923876395455008,
|
||||||
|
"toleranceRatio": 0.10057938943972738,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.2,
|
||||||
|
"key": "conservation.pnvo001_5.massBalance",
|
||||||
|
"category": "conservation",
|
||||||
|
"python": 0.0,
|
||||||
|
"amesim": -0.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 1e-09,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.2,
|
||||||
|
"key": "conservation.totalStoredGasMass",
|
||||||
|
"category": "conservation",
|
||||||
|
"python": 5.566893015137554,
|
||||||
|
"amesim": 5.566892994134813,
|
||||||
|
"absoluteError": 2.1002740879794146e-08,
|
||||||
|
"relativeError": 3.7727940705744284e-09,
|
||||||
|
"allowedError": 0.011133786988269626,
|
||||||
|
"toleranceRatio": 1.8863968658572583e-06,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.2,
|
||||||
|
"key": "discrete.pnvo001_5.openMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"python": 1.0,
|
||||||
|
"amesim": 1.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 0.0,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.2,
|
||||||
|
"key": "discrete.mecmas21_9.endstopMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"python": 1.0,
|
||||||
|
"amesim": 1.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 0.0,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.2,
|
||||||
|
"key": "discrete.mecmas21_10.endstopMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"python": -1.0,
|
||||||
|
"amesim": -1.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 0.0,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"toleranceProfile": {
|
||||||
|
"id": "amesim-alignment-reviewed-v1",
|
||||||
|
"byCategory": {
|
||||||
|
"pressure": {
|
||||||
|
"relative": 0.002,
|
||||||
|
"absolute": 0.001
|
||||||
|
},
|
||||||
|
"massFlow": {
|
||||||
|
"relative": 0.002,
|
||||||
|
"absolute": 1e-09
|
||||||
|
},
|
||||||
|
"conservation": {
|
||||||
|
"relative": 0.002,
|
||||||
|
"absolute": 1e-09
|
||||||
|
},
|
||||||
|
"discreteMode": {
|
||||||
|
"relative": 0.0,
|
||||||
|
"absolute": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"basis": "0.2% relative envelope for AMESim pressure/flow/inventory alignment; conservation retains a 1e-9 absolute floor and discrete modes are exact.",
|
||||||
|
"exclusions": [
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"category": "massFlow",
|
||||||
|
"reason": "The Python and AMESim samples at the signal discontinuity may represent different left/right limits. Raw errors remain recorded."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"policy": "diagnostic external-reference comparison; local golden is the regression gate"
|
||||||
|
}
|
||||||
|
}
|
||||||
+955
@@ -0,0 +1,955 @@
|
|||||||
|
{
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"id": "test_mql_8-production-0.2s-physical-state-v2.1",
|
||||||
|
"contractId": "physical-state-v2.1",
|
||||||
|
"caseId": "0.2s",
|
||||||
|
"lane": "production",
|
||||||
|
"sourceXmlSha256": "0a2d9331df9eb5974daec25a61c1238ba32b1742d933ffc8b16ce316c5627b0b",
|
||||||
|
"approval": {
|
||||||
|
"status": "approved",
|
||||||
|
"approvedAt": "2026-08-18T07:35:25.264794+00:00",
|
||||||
|
"reviewedBy": "Codex OPT-00 physical-state-v2.1 gate",
|
||||||
|
"note": "Reviewed full 0/0.04/0.2 checkpoints: AMESim external alignment passed the declared 0.2% profile; t=0.04 mass-flow values retain errors but are excluded for explicit left/right-limit ambiguity; local p4node, PNVO, and connection mass-balance residuals pass the strict 1e-9 kg/s gate; discrete modes are exact.",
|
||||||
|
"candidatePath": "tests/baselines/simulation/test_mql_8/goldens/candidates/production-0.2s-physical-state-v2.1-candidate.json",
|
||||||
|
"candidateSha256": "699033337c30e6aed97538e886b81ff897fe2c455860b4ad1ed3293f580fb53a"
|
||||||
|
},
|
||||||
|
"provenance": {
|
||||||
|
"localSourceReport": {
|
||||||
|
"path": "tests/baselines/simulation/test_mql_8/runs/2026-08-18-production-physical-state-v2.1-0.2.json",
|
||||||
|
"bytes": 380076,
|
||||||
|
"sha256": "c647fc7dab6c5cdaea188789dd8e0192d9caf374873afa1f5f5db0da9d69c49b",
|
||||||
|
"generatedAt": "2026-08-18T07:34:00.055573+00:00"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"archivePath": "AmesimModels/test_mql.ame",
|
||||||
|
"archiveBytes": 21708800,
|
||||||
|
"archiveSha256": "cbc3aadd4569a49b3a63e5d66d4143ec16126c0f950df73fb637e07673c20fbb",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"name": "test_mql_.var",
|
||||||
|
"bytes": 95371,
|
||||||
|
"sha256": "175010af62d254b34b1f876ff652feb903fe2ce88bee80d4dc0ef1d31f04067b"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "test_mql_.results",
|
||||||
|
"bytes": 8968576,
|
||||||
|
"sha256": "434a2cdff1322565957934354154425868fa03737558636927cb0f3ec51f1760"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"referencePressurePa": 101300.0,
|
||||||
|
"role": "external calibration reference; not an equality claim"
|
||||||
|
},
|
||||||
|
"amesimStoredMassDataPaths": [
|
||||||
|
"mgas1@pn_c1_8",
|
||||||
|
"mgas1@pn_c1_9",
|
||||||
|
"mgas1@pn_c1_10",
|
||||||
|
"mgas1@pn_c1_11",
|
||||||
|
"mgas1@pn_c1_12",
|
||||||
|
"mgas1@pn_c1_13",
|
||||||
|
"mgas1@pn_c1_14",
|
||||||
|
"mgas1@pn_c1_15",
|
||||||
|
"mgas@pn_general_chamber",
|
||||||
|
"mgas@pn_general_chamber_2",
|
||||||
|
"mgas@pn_general_chamber_4",
|
||||||
|
"mgas@pn_general_chamber_5",
|
||||||
|
"mgas@pneumatic_65",
|
||||||
|
"mgas@pneumatic_66",
|
||||||
|
"mgas@pneumatic_68",
|
||||||
|
"mgas@pneumatic_69",
|
||||||
|
"mgas@pneumatic_70",
|
||||||
|
"mgas@pneumatic_71",
|
||||||
|
"mgas@pneumatic_72",
|
||||||
|
"mgas@pneumatic_73",
|
||||||
|
"mgas@pneumatic_74",
|
||||||
|
"mgas@pneumatic_75",
|
||||||
|
"mgas@pneumatic_76",
|
||||||
|
"mgas@pneumatic_77",
|
||||||
|
"mgas@pneumatic_78",
|
||||||
|
"mgas@pneumatic_79",
|
||||||
|
"mgas@pneumatic_80",
|
||||||
|
"mgas@pneumatic_81",
|
||||||
|
"mgas@pneumatic_82",
|
||||||
|
"mgas@pneumatic_83",
|
||||||
|
"mgas@pneumatic_84",
|
||||||
|
"mgas@pneumatic_85",
|
||||||
|
"mgas@pneumatic_86",
|
||||||
|
"mgas@pneumatic_87",
|
||||||
|
"mgas@pneumatic_88",
|
||||||
|
"mgas@pneumatic_91",
|
||||||
|
"mgas@pneumatic_92",
|
||||||
|
"mgas@pneumatic_93",
|
||||||
|
"mgas@pneumatic_94",
|
||||||
|
"mgas@pneumatic_95",
|
||||||
|
"mgas@pneumatic_96",
|
||||||
|
"mgas@pneumatic_97",
|
||||||
|
"mgas@pneumatic_98",
|
||||||
|
"mgas@pneumatic_99",
|
||||||
|
"mgas@pneumatic_101",
|
||||||
|
"mgas@pneumatic_102",
|
||||||
|
"mgas@pneumatic_103",
|
||||||
|
"mgas@pneumatic_104"
|
||||||
|
],
|
||||||
|
"comparisonPolicy": "Local values are the regression target; transformed AMESim values are retained visibly as an external calibration reference."
|
||||||
|
},
|
||||||
|
"layout": {
|
||||||
|
"projectionKeys": [
|
||||||
|
"pressure.pnch012_8.absolute",
|
||||||
|
"pressure.pnl0001_20.absolute",
|
||||||
|
"massFlow.pnl0001_20.port_1.intoComponent",
|
||||||
|
"massFlow.pnvo001_5.port_2.intoComponent",
|
||||||
|
"conservation.p4node2_8.massBalance",
|
||||||
|
"conservation.pnvo001_5.massBalance",
|
||||||
|
"conservation.pnl0001_20_pnch012_8.connectionMassBalance",
|
||||||
|
"conservation.totalStoredGasMass",
|
||||||
|
"discrete.pnvo001_5.openMode",
|
||||||
|
"discrete.mecmas21_9.endstopMode",
|
||||||
|
"discrete.mecmas21_10.endstopMode"
|
||||||
|
],
|
||||||
|
"projections": [
|
||||||
|
{
|
||||||
|
"key": "pressure.pnch012_8.absolute",
|
||||||
|
"category": "pressure",
|
||||||
|
"unit": "Pa",
|
||||||
|
"python": {
|
||||||
|
"sourceKeys": [
|
||||||
|
"amesim_pnch012_8.p"
|
||||||
|
],
|
||||||
|
"formula": "identity"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"dataPaths": [
|
||||||
|
"press@pn_c1_8"
|
||||||
|
],
|
||||||
|
"sourceUnit": "Pa (gauge)",
|
||||||
|
"targetUnit": "Pa (absolute)",
|
||||||
|
"formula": "target = source + 101300",
|
||||||
|
"scale": 1.0,
|
||||||
|
"offset": 101300.0
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0002,
|
||||||
|
"absolute": 0.001
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "pressure.pnl0001_20.absolute",
|
||||||
|
"category": "pressure",
|
||||||
|
"unit": "Pa",
|
||||||
|
"python": {
|
||||||
|
"sourceKeys": [
|
||||||
|
"amesim_pnl0001_20.p"
|
||||||
|
],
|
||||||
|
"formula": "identity"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"dataPaths": [
|
||||||
|
"p2@pneumatic_69"
|
||||||
|
],
|
||||||
|
"sourceUnit": "Pa (gauge)",
|
||||||
|
"targetUnit": "Pa (absolute)",
|
||||||
|
"formula": "target = source + 101300",
|
||||||
|
"scale": 1.0,
|
||||||
|
"offset": 101300.0
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0002,
|
||||||
|
"absolute": 0.001
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "massFlow.pnl0001_20.port_1.intoComponent",
|
||||||
|
"category": "massFlow",
|
||||||
|
"unit": "kg/s",
|
||||||
|
"python": {
|
||||||
|
"sourceKeys": [
|
||||||
|
"amesim_pnl0001_20.port_1.m_flow"
|
||||||
|
],
|
||||||
|
"formula": "identity"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"dataPaths": [
|
||||||
|
"dm1@pneumatic_69"
|
||||||
|
],
|
||||||
|
"sourceUnit": "g/s (AMESim component orientation)",
|
||||||
|
"targetUnit": "kg/s (positive into generic component)",
|
||||||
|
"formula": "target = -source * 1e-3",
|
||||||
|
"scale": -0.001,
|
||||||
|
"offset": 0.0
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0002,
|
||||||
|
"absolute": 1e-09
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "massFlow.pnvo001_5.port_2.intoComponent",
|
||||||
|
"category": "massFlow",
|
||||||
|
"unit": "kg/s",
|
||||||
|
"python": {
|
||||||
|
"sourceKeys": [
|
||||||
|
"amesim_pnvo001_5.port_2.m_flow"
|
||||||
|
],
|
||||||
|
"formula": "identity"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"dataPaths": [
|
||||||
|
"dm2@pn_morifice_1"
|
||||||
|
],
|
||||||
|
"sourceUnit": "g/s (AMESim component orientation)",
|
||||||
|
"targetUnit": "kg/s (positive into generic component)",
|
||||||
|
"formula": "target = -source * 1e-3",
|
||||||
|
"scale": -0.001,
|
||||||
|
"offset": 0.0
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0002,
|
||||||
|
"absolute": 1e-09
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "conservation.p4node2_8.massBalance",
|
||||||
|
"category": "conservation",
|
||||||
|
"unit": "kg/s",
|
||||||
|
"python": {
|
||||||
|
"sourceKeys": [
|
||||||
|
"amesim_p4node2_8.port_1.m_flow",
|
||||||
|
"amesim_p4node2_8.port_2.m_flow",
|
||||||
|
"amesim_p4node2_8.port_3.m_flow",
|
||||||
|
"amesim_p4node2_8.port_4.m_flow"
|
||||||
|
],
|
||||||
|
"formula": "sum"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"dataPaths": [],
|
||||||
|
"note": "AMESim archive has no complete saved four-port tuple."
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0,
|
||||||
|
"absolute": 1e-09
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "conservation.pnvo001_5.massBalance",
|
||||||
|
"category": "conservation",
|
||||||
|
"unit": "kg/s",
|
||||||
|
"python": {
|
||||||
|
"sourceKeys": [
|
||||||
|
"amesim_pnvo001_5.port_2.m_flow",
|
||||||
|
"amesim_pnvo001_5.port_3.m_flow"
|
||||||
|
],
|
||||||
|
"formula": "sum"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"dataPaths": [
|
||||||
|
"dm2@pn_morifice_1",
|
||||||
|
"dm3@pn_morifice_1"
|
||||||
|
],
|
||||||
|
"sourceUnit": "g/s",
|
||||||
|
"targetUnit": "kg/s",
|
||||||
|
"formula": "target = -(source1 + source2) * 1e-3"
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0,
|
||||||
|
"absolute": 1e-09
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "conservation.pnl0001_20_pnch012_8.connectionMassBalance",
|
||||||
|
"category": "conservation",
|
||||||
|
"unit": "kg/s",
|
||||||
|
"python": {
|
||||||
|
"sourceKeys": [
|
||||||
|
"amesim_pnl0001_20.port_1.m_flow",
|
||||||
|
"amesim_pnch012_8.port_1.m_flow"
|
||||||
|
],
|
||||||
|
"formula": "sum"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"dataPaths": [],
|
||||||
|
"note": "PNCH012 port flow is not saved; local connector contract is authoritative."
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0,
|
||||||
|
"absolute": 1e-09
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "conservation.totalStoredGasMass",
|
||||||
|
"category": "conservation",
|
||||||
|
"unit": "kg",
|
||||||
|
"python": {
|
||||||
|
"sourceKeys": [
|
||||||
|
"amesim_pnch012_10.m",
|
||||||
|
"amesim_pnch012_11.m",
|
||||||
|
"amesim_pnch012_12.m",
|
||||||
|
"amesim_pnch012_13.m",
|
||||||
|
"amesim_pnch012_14.m",
|
||||||
|
"amesim_pnch012_15.m",
|
||||||
|
"amesim_pnch012_8.m",
|
||||||
|
"amesim_pnch012_9.m",
|
||||||
|
"amesim_pnch023_1.m",
|
||||||
|
"amesim_pnch023_2.m",
|
||||||
|
"amesim_pnch023_3.m",
|
||||||
|
"amesim_pnch023_4.m",
|
||||||
|
"amesim_pnl0001_1.m",
|
||||||
|
"amesim_pnl0001_10.m",
|
||||||
|
"amesim_pnl0001_11.m",
|
||||||
|
"amesim_pnl0001_13.m",
|
||||||
|
"amesim_pnl0001_14.m",
|
||||||
|
"amesim_pnl0001_15.m",
|
||||||
|
"amesim_pnl0001_16.m",
|
||||||
|
"amesim_pnl0001_17.m",
|
||||||
|
"amesim_pnl0001_18.m",
|
||||||
|
"amesim_pnl0001_19.m",
|
||||||
|
"amesim_pnl0001_2.m",
|
||||||
|
"amesim_pnl0001_20.m",
|
||||||
|
"amesim_pnl0001_21.m",
|
||||||
|
"amesim_pnl0001_25.m",
|
||||||
|
"amesim_pnl0001_26.m",
|
||||||
|
"amesim_pnl0001_27.m",
|
||||||
|
"amesim_pnl0001_4.m",
|
||||||
|
"amesim_pnl0001_5.m",
|
||||||
|
"amesim_pnl0001_7.m",
|
||||||
|
"amesim_pnl0001_9.m",
|
||||||
|
"amesim_pnl0002_1.m",
|
||||||
|
"amesim_pnl0002_2.m",
|
||||||
|
"amesim_pnl0002_3.m",
|
||||||
|
"amesim_pnl0002_4.m",
|
||||||
|
"amesim_pnl0002_5.m",
|
||||||
|
"amesim_pnl0002_6.m",
|
||||||
|
"amesim_pnl0002_7.m",
|
||||||
|
"amesim_pnl0002_8.m",
|
||||||
|
"amesim_pnl0003_1.m1",
|
||||||
|
"amesim_pnl0003_1.m2",
|
||||||
|
"amesim_pnl0003_2.m1",
|
||||||
|
"amesim_pnl0003_2.m2",
|
||||||
|
"amesim_pnl0003_3.m1",
|
||||||
|
"amesim_pnl0003_3.m2",
|
||||||
|
"amesim_pnl0003_4.m1",
|
||||||
|
"amesim_pnl0003_4.m2",
|
||||||
|
"amesim_pnl0003_5.m1",
|
||||||
|
"amesim_pnl0003_5.m2",
|
||||||
|
"amesim_pnl0003_6.m1",
|
||||||
|
"amesim_pnl0003_6.m2",
|
||||||
|
"amesim_pnl0003_7.m1",
|
||||||
|
"amesim_pnl0003_7.m2",
|
||||||
|
"amesim_pnl0003_8.m1",
|
||||||
|
"amesim_pnl0003_8.m2"
|
||||||
|
],
|
||||||
|
"formula": "sum"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"dataPathSelection": "units == 'g' and signal starts with 'mgas'",
|
||||||
|
"sourceUnit": "g",
|
||||||
|
"targetUnit": "kg",
|
||||||
|
"formula": "target = sum(sources) * 1e-3"
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0002,
|
||||||
|
"absolute": 1e-09
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "discrete.pnvo001_5.openMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"unit": "1",
|
||||||
|
"python": {
|
||||||
|
"sourceKeys": [
|
||||||
|
"amesim_pnvo001_5.xv"
|
||||||
|
],
|
||||||
|
"formula": "1 if opening >= 0.5 else 0"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"dataPaths": [
|
||||||
|
"xv@pn_morifice_1"
|
||||||
|
],
|
||||||
|
"sourceUnit": "1",
|
||||||
|
"targetUnit": "mode code {0,1}",
|
||||||
|
"formula": "1 if source >= 0.5 else 0"
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0,
|
||||||
|
"absolute": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "discrete.mecmas21_9.endstopMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"unit": "1",
|
||||||
|
"python": {
|
||||||
|
"sourceKeys": [
|
||||||
|
"amesim_mecmas21_9.x",
|
||||||
|
"amesim_mecmas21_9.v",
|
||||||
|
"amesim_mecmas21_9.port_1.f",
|
||||||
|
"amesim_mecmas21_9.port_2.f"
|
||||||
|
],
|
||||||
|
"formula": "-1 lower, 0 free, +1 upper using boundary and net-force direction"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"dataPaths": [
|
||||||
|
"x1@mass_friction_endstops_19",
|
||||||
|
"v1@mass_friction_endstops_19"
|
||||||
|
],
|
||||||
|
"lowerBound": -0.72,
|
||||||
|
"upperBound": 0.0,
|
||||||
|
"note": "No saved AMESim endstop code; reference is boundary occupancy."
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0,
|
||||||
|
"absolute": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "discrete.mecmas21_10.endstopMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"unit": "1",
|
||||||
|
"python": {
|
||||||
|
"sourceKeys": [
|
||||||
|
"amesim_mecmas21_10.x",
|
||||||
|
"amesim_mecmas21_10.v",
|
||||||
|
"amesim_mecmas21_10.port_1.f",
|
||||||
|
"amesim_mecmas21_10.port_2.f"
|
||||||
|
],
|
||||||
|
"formula": "-1 lower, 0 free, +1 upper using boundary and net-force direction"
|
||||||
|
},
|
||||||
|
"amesim": {
|
||||||
|
"dataPaths": [
|
||||||
|
"x1@mass_friction_endstops_18",
|
||||||
|
"v1@mass_friction_endstops_18"
|
||||||
|
],
|
||||||
|
"lowerBound": 0.0,
|
||||||
|
"upperBound": 0.37,
|
||||||
|
"note": "No saved AMESim endstop code; reference is boundary occupancy."
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0,
|
||||||
|
"absolute": 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"projectionLayoutSha256": "55cc8f71ea72fd46f71f1ede2587aeb9f6d590bde8e97e881648f88a4a90dca6"
|
||||||
|
},
|
||||||
|
"checkpoints": [
|
||||||
|
{
|
||||||
|
"requestedTime": 0.0,
|
||||||
|
"values": [
|
||||||
|
100000.0,
|
||||||
|
100000.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
5.5668930151375235,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
-1.0
|
||||||
|
],
|
||||||
|
"amesimReferenceValues": [
|
||||||
|
100000.00000000001,
|
||||||
|
100000.00000000001,
|
||||||
|
-0.0,
|
||||||
|
-0.0,
|
||||||
|
null,
|
||||||
|
-0.0,
|
||||||
|
null,
|
||||||
|
5.5668930151375235,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
-1.0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"values": [
|
||||||
|
100153.57210434608,
|
||||||
|
100152.45747547514,
|
||||||
|
6.682314111565264e-06,
|
||||||
|
-0.4978238221497115,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
5.5668930151375235,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
-1.0
|
||||||
|
],
|
||||||
|
"amesimReferenceValues": [
|
||||||
|
100153.61882579065,
|
||||||
|
100152.49205385521,
|
||||||
|
6.672550142634319e-06,
|
||||||
|
-0.4978238226601424,
|
||||||
|
null,
|
||||||
|
-0.0,
|
||||||
|
null,
|
||||||
|
5.566893015142308,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
-1.0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.2,
|
||||||
|
"values": [
|
||||||
|
3620589.728099082,
|
||||||
|
3756379.1344475006,
|
||||||
|
-0.3723610392591412,
|
||||||
|
-0.3962730176377355,
|
||||||
|
1.8214596497756474e-17,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
5.566893015137554,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
-1.0
|
||||||
|
],
|
||||||
|
"amesimReferenceValues": [
|
||||||
|
3625053.2009413484,
|
||||||
|
3760735.7825351665,
|
||||||
|
-0.3728806429214546,
|
||||||
|
-0.3961933197727504,
|
||||||
|
null,
|
||||||
|
-0.0,
|
||||||
|
null,
|
||||||
|
5.566892994134813,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
-1.0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"amesimAlignmentAtGeneration": {
|
||||||
|
"passed": true,
|
||||||
|
"issues": [],
|
||||||
|
"comparedValueCount": 25,
|
||||||
|
"excludedValueCount": 2,
|
||||||
|
"maxToleranceRatio": 0.6967416724836332,
|
||||||
|
"maxToleranceRatioUnbounded": false,
|
||||||
|
"worstValue": {
|
||||||
|
"requestedTime": 0.2,
|
||||||
|
"key": "massFlow.pnl0001_20.port_1.intoComponent",
|
||||||
|
"category": "massFlow",
|
||||||
|
"python": -0.3723610392591412,
|
||||||
|
"amesim": -0.3728806429214546,
|
||||||
|
"absoluteError": 0.0005196036623134059,
|
||||||
|
"relativeError": 0.0013934852135053246,
|
||||||
|
"allowedError": 0.0007457622858429093,
|
||||||
|
"toleranceRatio": 0.6967416724836332,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
"metrics": [
|
||||||
|
{
|
||||||
|
"requestedTime": 0.0,
|
||||||
|
"key": "pressure.pnch012_8.absolute",
|
||||||
|
"category": "pressure",
|
||||||
|
"python": 100000.0,
|
||||||
|
"amesim": 100000.00000000001,
|
||||||
|
"absoluteError": 1.4551915228366852e-11,
|
||||||
|
"relativeError": 1.455191522836685e-16,
|
||||||
|
"allowedError": 200.00100000000003,
|
||||||
|
"toleranceRatio": 7.275921234577252e-14,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.0,
|
||||||
|
"key": "pressure.pnl0001_20.absolute",
|
||||||
|
"category": "pressure",
|
||||||
|
"python": 100000.0,
|
||||||
|
"amesim": 100000.00000000001,
|
||||||
|
"absoluteError": 1.4551915228366852e-11,
|
||||||
|
"relativeError": 1.455191522836685e-16,
|
||||||
|
"allowedError": 200.00100000000003,
|
||||||
|
"toleranceRatio": 7.275921234577252e-14,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.0,
|
||||||
|
"key": "massFlow.pnl0001_20.port_1.intoComponent",
|
||||||
|
"category": "massFlow",
|
||||||
|
"python": 0.0,
|
||||||
|
"amesim": -0.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 1e-09,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.0,
|
||||||
|
"key": "massFlow.pnvo001_5.port_2.intoComponent",
|
||||||
|
"category": "massFlow",
|
||||||
|
"python": 0.0,
|
||||||
|
"amesim": -0.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 1e-09,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.0,
|
||||||
|
"key": "conservation.pnvo001_5.massBalance",
|
||||||
|
"category": "conservation",
|
||||||
|
"python": 0.0,
|
||||||
|
"amesim": -0.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 1e-09,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.0,
|
||||||
|
"key": "conservation.totalStoredGasMass",
|
||||||
|
"category": "conservation",
|
||||||
|
"python": 5.5668930151375235,
|
||||||
|
"amesim": 5.5668930151375235,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 0.011133787030275047,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.0,
|
||||||
|
"key": "discrete.pnvo001_5.openMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"python": 0.0,
|
||||||
|
"amesim": 0.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 0.0,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.0,
|
||||||
|
"key": "discrete.mecmas21_9.endstopMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"python": 1.0,
|
||||||
|
"amesim": 1.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 0.0,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.0,
|
||||||
|
"key": "discrete.mecmas21_10.endstopMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"python": -1.0,
|
||||||
|
"amesim": -1.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 0.0,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"key": "pressure.pnch012_8.absolute",
|
||||||
|
"category": "pressure",
|
||||||
|
"python": 100153.57210434608,
|
||||||
|
"amesim": 100153.61882579065,
|
||||||
|
"absoluteError": 0.04672144456708338,
|
||||||
|
"relativeError": 4.6649781720170954e-07,
|
||||||
|
"allowedError": 200.3082376515813,
|
||||||
|
"toleranceRatio": 0.00023324774415094828,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"key": "pressure.pnl0001_20.absolute",
|
||||||
|
"category": "pressure",
|
||||||
|
"python": 100152.45747547514,
|
||||||
|
"amesim": 100152.49205385521,
|
||||||
|
"absoluteError": 0.03457838007307146,
|
||||||
|
"relativeError": 3.4525731076644157e-07,
|
||||||
|
"allowedError": 200.30598410771043,
|
||||||
|
"toleranceRatio": 0.00017262779355846724,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"key": "massFlow.pnl0001_20.port_1.intoComponent",
|
||||||
|
"category": "massFlow",
|
||||||
|
"python": 6.682314111565264e-06,
|
||||||
|
"amesim": 6.672550142634319e-06,
|
||||||
|
"absoluteError": 9.763968930944316e-09,
|
||||||
|
"relativeError": 0.0014633039426046946,
|
||||||
|
"allowedError": 1.4345100285268639e-08,
|
||||||
|
"toleranceRatio": 0.6806483563569921,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": false,
|
||||||
|
"passed": null,
|
||||||
|
"exclusionReason": "signalDiscontinuityLeftRightLimitSemanticsNotComparableAt0.04s"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"key": "massFlow.pnvo001_5.port_2.intoComponent",
|
||||||
|
"category": "massFlow",
|
||||||
|
"python": -0.4978238221497115,
|
||||||
|
"amesim": -0.4978238226601424,
|
||||||
|
"absoluteError": 5.104309197534462e-10,
|
||||||
|
"relativeError": 1.0253244150228433e-09,
|
||||||
|
"allowedError": 0.0009956486453202849,
|
||||||
|
"toleranceRatio": 5.126616926086898e-07,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": false,
|
||||||
|
"passed": null,
|
||||||
|
"exclusionReason": "signalDiscontinuityLeftRightLimitSemanticsNotComparableAt0.04s"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"key": "conservation.pnvo001_5.massBalance",
|
||||||
|
"category": "conservation",
|
||||||
|
"python": 0.0,
|
||||||
|
"amesim": -0.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 1e-09,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"key": "conservation.totalStoredGasMass",
|
||||||
|
"category": "conservation",
|
||||||
|
"python": 5.5668930151375235,
|
||||||
|
"amesim": 5.566893015142308,
|
||||||
|
"absoluteError": 4.784617146924575e-12,
|
||||||
|
"relativeError": 8.594771147766101e-13,
|
||||||
|
"allowedError": 0.011133787030284616,
|
||||||
|
"toleranceRatio": 4.2973851879060635e-10,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"key": "discrete.pnvo001_5.openMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"python": 1.0,
|
||||||
|
"amesim": 1.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 0.0,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"key": "discrete.mecmas21_9.endstopMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"python": 1.0,
|
||||||
|
"amesim": 1.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 0.0,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"key": "discrete.mecmas21_10.endstopMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"python": -1.0,
|
||||||
|
"amesim": -1.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 0.0,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.2,
|
||||||
|
"key": "pressure.pnch012_8.absolute",
|
||||||
|
"category": "pressure",
|
||||||
|
"python": 3620589.728099082,
|
||||||
|
"amesim": 3625053.2009413484,
|
||||||
|
"absoluteError": 4463.4728422663175,
|
||||||
|
"relativeError": 0.0012312847825536048,
|
||||||
|
"allowedError": 7250.107401882698,
|
||||||
|
"toleranceRatio": 0.6156423063618685,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.2,
|
||||||
|
"key": "pressure.pnl0001_20.absolute",
|
||||||
|
"category": "pressure",
|
||||||
|
"python": 3756379.1344475006,
|
||||||
|
"amesim": 3760735.7825351665,
|
||||||
|
"absoluteError": 4356.648087665904,
|
||||||
|
"relativeError": 0.0011584563073795695,
|
||||||
|
"allowedError": 7521.472565070333,
|
||||||
|
"toleranceRatio": 0.5792280766798443,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.2,
|
||||||
|
"key": "massFlow.pnl0001_20.port_1.intoComponent",
|
||||||
|
"category": "massFlow",
|
||||||
|
"python": -0.3723610392591412,
|
||||||
|
"amesim": -0.3728806429214546,
|
||||||
|
"absoluteError": 0.0005196036623134059,
|
||||||
|
"relativeError": 0.0013934852135053246,
|
||||||
|
"allowedError": 0.0007457622858429093,
|
||||||
|
"toleranceRatio": 0.6967416724836332,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.2,
|
||||||
|
"key": "massFlow.pnvo001_5.port_2.intoComponent",
|
||||||
|
"category": "massFlow",
|
||||||
|
"python": -0.3962730176377355,
|
||||||
|
"amesim": -0.3961933197727504,
|
||||||
|
"absoluteError": 7.969786498507325e-05,
|
||||||
|
"relativeError": 0.00020115903274388008,
|
||||||
|
"allowedError": 0.0007923876395455008,
|
||||||
|
"toleranceRatio": 0.10057938943972738,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.2,
|
||||||
|
"key": "conservation.pnvo001_5.massBalance",
|
||||||
|
"category": "conservation",
|
||||||
|
"python": 0.0,
|
||||||
|
"amesim": -0.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 1e-09,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.2,
|
||||||
|
"key": "conservation.totalStoredGasMass",
|
||||||
|
"category": "conservation",
|
||||||
|
"python": 5.566893015137554,
|
||||||
|
"amesim": 5.566892994134813,
|
||||||
|
"absoluteError": 2.1002740879794146e-08,
|
||||||
|
"relativeError": 3.7727940705744284e-09,
|
||||||
|
"allowedError": 0.011133786988269626,
|
||||||
|
"toleranceRatio": 1.8863968658572583e-06,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.2,
|
||||||
|
"key": "discrete.pnvo001_5.openMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"python": 1.0,
|
||||||
|
"amesim": 1.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 0.0,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.2,
|
||||||
|
"key": "discrete.mecmas21_9.endstopMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"python": 1.0,
|
||||||
|
"amesim": 1.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 0.0,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.2,
|
||||||
|
"key": "discrete.mecmas21_10.endstopMode",
|
||||||
|
"category": "discreteMode",
|
||||||
|
"python": -1.0,
|
||||||
|
"amesim": -1.0,
|
||||||
|
"absoluteError": 0.0,
|
||||||
|
"relativeError": 0.0,
|
||||||
|
"allowedError": 0.0,
|
||||||
|
"toleranceRatio": 0.0,
|
||||||
|
"unboundedToleranceRatio": false,
|
||||||
|
"evaluated": true,
|
||||||
|
"passed": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"toleranceProfile": {
|
||||||
|
"id": "amesim-alignment-reviewed-v1",
|
||||||
|
"byCategory": {
|
||||||
|
"pressure": {
|
||||||
|
"relative": 0.002,
|
||||||
|
"absolute": 0.001
|
||||||
|
},
|
||||||
|
"massFlow": {
|
||||||
|
"relative": 0.002,
|
||||||
|
"absolute": 1e-09
|
||||||
|
},
|
||||||
|
"conservation": {
|
||||||
|
"relative": 0.002,
|
||||||
|
"absolute": 1e-09
|
||||||
|
},
|
||||||
|
"discreteMode": {
|
||||||
|
"relative": 0.0,
|
||||||
|
"absolute": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"basis": "0.2% relative envelope for AMESim pressure/flow/inventory alignment; conservation retains a 1e-9 absolute floor and discrete modes are exact.",
|
||||||
|
"exclusions": [
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"category": "massFlow",
|
||||||
|
"reason": "The Python and AMESim samples at the signal discontinuity may represent different left/right limits. Raw errors remain recorded."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"policy": "diagnostic external-reference comparison; local golden is the regression gate"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,629 @@
|
|||||||
|
{
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"id": "test_mql_8-production-0.2s-physical-state-v2-amesim-aligned",
|
||||||
|
"caseId": "0.2s",
|
||||||
|
"lane": "production",
|
||||||
|
"sourceXmlSha256": "0a2d9331df9eb5974daec25a61c1238ba32b1742d933ffc8b16ce316c5627b0b",
|
||||||
|
"approval": {
|
||||||
|
"status": "approved",
|
||||||
|
"approvedAt": "2026-08-18T07:35:01+00:00",
|
||||||
|
"basis": "AME-aligned source, full physical-state-v2.1 external-reference assessment, finite-series, checkpoint, signal-segment, mechanical-event, residual, audit, no-fallback, and output-shape gates passed in the locked Python 3.12 production environment."
|
||||||
|
},
|
||||||
|
"provenance": {
|
||||||
|
"sourceReport": {
|
||||||
|
"path": "tests/baselines/simulation/test_mql_8/runs/2026-08-18-production-physical-state-v2.1-0.2.json",
|
||||||
|
"sha256": "c647fc7dab6c5cdaea188789dd8e0192d9caf374873afa1f5f5db0da9d69c49b",
|
||||||
|
"generatedAt": "2026-08-18T07:34:00.055573+00:00",
|
||||||
|
"metadataCompatibility": {
|
||||||
|
"status": "current",
|
||||||
|
"differences": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"amesimReference": {
|
||||||
|
"path": "AmesimModels/test_mql.ame",
|
||||||
|
"sha256": "cbc3aadd4569a49b3a63e5d66d4143ec16126c0f950df73fb637e07673c20fbb",
|
||||||
|
"role": "external physical-state-v2.1 calibration reference"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"physicalLayout": {
|
||||||
|
"projectionCategories": [
|
||||||
|
"state"
|
||||||
|
],
|
||||||
|
"stateKeys": [
|
||||||
|
"amesim_mecmas21_1.a",
|
||||||
|
"amesim_mecmas21_1.v",
|
||||||
|
"amesim_mecmas21_1.x",
|
||||||
|
"amesim_mecmas21_10.a",
|
||||||
|
"amesim_mecmas21_10.v",
|
||||||
|
"amesim_mecmas21_10.x",
|
||||||
|
"amesim_mecmas21_2.a",
|
||||||
|
"amesim_mecmas21_2.v",
|
||||||
|
"amesim_mecmas21_2.x",
|
||||||
|
"amesim_mecmas21_3.a",
|
||||||
|
"amesim_mecmas21_3.v",
|
||||||
|
"amesim_mecmas21_3.x",
|
||||||
|
"amesim_mecmas21_4.a",
|
||||||
|
"amesim_mecmas21_4.v",
|
||||||
|
"amesim_mecmas21_4.x",
|
||||||
|
"amesim_mecmas21_5.a",
|
||||||
|
"amesim_mecmas21_5.v",
|
||||||
|
"amesim_mecmas21_5.x",
|
||||||
|
"amesim_mecmas21_6.a",
|
||||||
|
"amesim_mecmas21_6.v",
|
||||||
|
"amesim_mecmas21_6.x",
|
||||||
|
"amesim_mecmas21_7.a",
|
||||||
|
"amesim_mecmas21_7.v",
|
||||||
|
"amesim_mecmas21_7.x",
|
||||||
|
"amesim_mecmas21_8.a",
|
||||||
|
"amesim_mecmas21_8.v",
|
||||||
|
"amesim_mecmas21_8.x",
|
||||||
|
"amesim_mecmas21_9.a",
|
||||||
|
"amesim_mecmas21_9.v",
|
||||||
|
"amesim_mecmas21_9.x",
|
||||||
|
"amesim_pnch012_10.U",
|
||||||
|
"amesim_pnch012_10.m",
|
||||||
|
"amesim_pnch012_11.U",
|
||||||
|
"amesim_pnch012_11.m",
|
||||||
|
"amesim_pnch012_12.U",
|
||||||
|
"amesim_pnch012_12.m",
|
||||||
|
"amesim_pnch012_13.U",
|
||||||
|
"amesim_pnch012_13.m",
|
||||||
|
"amesim_pnch012_14.U",
|
||||||
|
"amesim_pnch012_14.m",
|
||||||
|
"amesim_pnch012_15.U",
|
||||||
|
"amesim_pnch012_15.m",
|
||||||
|
"amesim_pnch012_8.U",
|
||||||
|
"amesim_pnch012_8.m",
|
||||||
|
"amesim_pnch012_9.U",
|
||||||
|
"amesim_pnch012_9.m",
|
||||||
|
"amesim_pnch023_1.U",
|
||||||
|
"amesim_pnch023_1.m",
|
||||||
|
"amesim_pnch023_2.U",
|
||||||
|
"amesim_pnch023_2.m",
|
||||||
|
"amesim_pnch023_3.U",
|
||||||
|
"amesim_pnch023_3.m",
|
||||||
|
"amesim_pnch023_4.U",
|
||||||
|
"amesim_pnch023_4.m",
|
||||||
|
"amesim_pnl0001_1.U",
|
||||||
|
"amesim_pnl0001_1.m",
|
||||||
|
"amesim_pnl0001_10.U",
|
||||||
|
"amesim_pnl0001_10.m",
|
||||||
|
"amesim_pnl0001_11.U",
|
||||||
|
"amesim_pnl0001_11.m",
|
||||||
|
"amesim_pnl0001_13.U",
|
||||||
|
"amesim_pnl0001_13.m",
|
||||||
|
"amesim_pnl0001_14.U",
|
||||||
|
"amesim_pnl0001_14.m",
|
||||||
|
"amesim_pnl0001_15.U",
|
||||||
|
"amesim_pnl0001_15.m",
|
||||||
|
"amesim_pnl0001_16.U",
|
||||||
|
"amesim_pnl0001_16.m",
|
||||||
|
"amesim_pnl0001_17.U",
|
||||||
|
"amesim_pnl0001_17.m",
|
||||||
|
"amesim_pnl0001_18.U",
|
||||||
|
"amesim_pnl0001_18.m",
|
||||||
|
"amesim_pnl0001_19.U",
|
||||||
|
"amesim_pnl0001_19.m",
|
||||||
|
"amesim_pnl0001_2.U",
|
||||||
|
"amesim_pnl0001_2.m",
|
||||||
|
"amesim_pnl0001_20.U",
|
||||||
|
"amesim_pnl0001_20.m",
|
||||||
|
"amesim_pnl0001_21.U",
|
||||||
|
"amesim_pnl0001_21.m",
|
||||||
|
"amesim_pnl0001_25.U",
|
||||||
|
"amesim_pnl0001_25.m",
|
||||||
|
"amesim_pnl0001_26.U",
|
||||||
|
"amesim_pnl0001_26.m",
|
||||||
|
"amesim_pnl0001_27.U",
|
||||||
|
"amesim_pnl0001_27.m",
|
||||||
|
"amesim_pnl0001_4.U",
|
||||||
|
"amesim_pnl0001_4.m",
|
||||||
|
"amesim_pnl0001_5.U",
|
||||||
|
"amesim_pnl0001_5.m",
|
||||||
|
"amesim_pnl0001_7.U",
|
||||||
|
"amesim_pnl0001_7.m",
|
||||||
|
"amesim_pnl0001_9.U",
|
||||||
|
"amesim_pnl0001_9.m",
|
||||||
|
"amesim_pnl0002_1.U",
|
||||||
|
"amesim_pnl0002_1.m",
|
||||||
|
"amesim_pnl0002_2.U",
|
||||||
|
"amesim_pnl0002_2.m",
|
||||||
|
"amesim_pnl0002_3.U",
|
||||||
|
"amesim_pnl0002_3.m",
|
||||||
|
"amesim_pnl0002_4.U",
|
||||||
|
"amesim_pnl0002_4.m",
|
||||||
|
"amesim_pnl0002_5.U",
|
||||||
|
"amesim_pnl0002_5.m",
|
||||||
|
"amesim_pnl0002_6.U",
|
||||||
|
"amesim_pnl0002_6.m",
|
||||||
|
"amesim_pnl0002_7.U",
|
||||||
|
"amesim_pnl0002_7.m",
|
||||||
|
"amesim_pnl0002_8.U",
|
||||||
|
"amesim_pnl0002_8.m",
|
||||||
|
"amesim_pnl0003_1.U1",
|
||||||
|
"amesim_pnl0003_1.U2",
|
||||||
|
"amesim_pnl0003_1.m1",
|
||||||
|
"amesim_pnl0003_1.m2",
|
||||||
|
"amesim_pnl0003_2.U1",
|
||||||
|
"amesim_pnl0003_2.U2",
|
||||||
|
"amesim_pnl0003_2.m1",
|
||||||
|
"amesim_pnl0003_2.m2",
|
||||||
|
"amesim_pnl0003_3.U1",
|
||||||
|
"amesim_pnl0003_3.U2",
|
||||||
|
"amesim_pnl0003_3.m1",
|
||||||
|
"amesim_pnl0003_3.m2",
|
||||||
|
"amesim_pnl0003_4.U1",
|
||||||
|
"amesim_pnl0003_4.U2",
|
||||||
|
"amesim_pnl0003_4.m1",
|
||||||
|
"amesim_pnl0003_4.m2",
|
||||||
|
"amesim_pnl0003_5.U1",
|
||||||
|
"amesim_pnl0003_5.U2",
|
||||||
|
"amesim_pnl0003_5.m1",
|
||||||
|
"amesim_pnl0003_5.m2",
|
||||||
|
"amesim_pnl0003_6.U1",
|
||||||
|
"amesim_pnl0003_6.U2",
|
||||||
|
"amesim_pnl0003_6.m1",
|
||||||
|
"amesim_pnl0003_6.m2",
|
||||||
|
"amesim_pnl0003_7.U1",
|
||||||
|
"amesim_pnl0003_7.U2",
|
||||||
|
"amesim_pnl0003_7.m1",
|
||||||
|
"amesim_pnl0003_7.m2",
|
||||||
|
"amesim_pnl0003_8.U1",
|
||||||
|
"amesim_pnl0003_8.U2",
|
||||||
|
"amesim_pnl0003_8.m1",
|
||||||
|
"amesim_pnl0003_8.m2"
|
||||||
|
],
|
||||||
|
"stateKeyLayoutSha256": "9c5276b19aebf5648aa0175a8b30eeb090ae48a645e00af5efe400679c2a19c0"
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0002,
|
||||||
|
"absolute": 1e-09,
|
||||||
|
"checkpointTimeAbsoluteSeconds": 1e-12
|
||||||
|
},
|
||||||
|
"physicalCheckpoints": [
|
||||||
|
{
|
||||||
|
"requestedTime": 0.0,
|
||||||
|
"values": [
|
||||||
|
-0.8167936695810981,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
-0.8167936695810981,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
-0.8167936695810981,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
-0.8167936695810981,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
-0.8167936695810981,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
-0.8167936695810981,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
-0.8167936695810981,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
-0.8167936695810981,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
-1563.893548405841,
|
||||||
|
0.002462855848963059,
|
||||||
|
-1563.893548405841,
|
||||||
|
0.002462855848963059,
|
||||||
|
-1563.893548405841,
|
||||||
|
0.002462855848963059,
|
||||||
|
-1563.893548405841,
|
||||||
|
0.002462855848963059,
|
||||||
|
-1563.893548405841,
|
||||||
|
0.002462855848963059,
|
||||||
|
-1563.893548405841,
|
||||||
|
0.002462855848963059,
|
||||||
|
-1563.893548405841,
|
||||||
|
0.002462855848963059,
|
||||||
|
-1563.893548405841,
|
||||||
|
0.002462855848963059,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-32.754109884455104,
|
||||||
|
5.158193227968668e-05,
|
||||||
|
-32.754109884455104,
|
||||||
|
5.158193227968668e-05,
|
||||||
|
-32.754109884455104,
|
||||||
|
5.158193227968668e-05,
|
||||||
|
-32.754109884455104,
|
||||||
|
5.158193227968668e-05,
|
||||||
|
-32.754109884455104,
|
||||||
|
5.158193227968668e-05,
|
||||||
|
-32.754109884455104,
|
||||||
|
5.158193227968668e-05,
|
||||||
|
-32.754109884455104,
|
||||||
|
5.158193227968668e-05,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-32.754109884455104,
|
||||||
|
5.158193227968668e-05,
|
||||||
|
-4.814854153014898,
|
||||||
|
7.582544045113939e-06,
|
||||||
|
-4.814854153014898,
|
||||||
|
7.582544045113939e-06,
|
||||||
|
-4.814854153014898,
|
||||||
|
7.582544045113939e-06,
|
||||||
|
-4.814854153014898,
|
||||||
|
7.582544045113939e-06,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-65.50821976891021,
|
||||||
|
0.00010316386455937335,
|
||||||
|
-65.50821976891021,
|
||||||
|
0.00010316386455937335,
|
||||||
|
-65.50821976891021,
|
||||||
|
0.00010316386455937335,
|
||||||
|
-65.50821976891021,
|
||||||
|
0.00010316386455937335,
|
||||||
|
-65.50821976891021,
|
||||||
|
0.00010316386455937335,
|
||||||
|
-65.50821976891021,
|
||||||
|
0.00010316386455937335,
|
||||||
|
-65.50821976891021,
|
||||||
|
0.00010316386455937335,
|
||||||
|
-65.50821976891021,
|
||||||
|
0.00010316386455937335,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"values": [
|
||||||
|
-0.7202663767630412,
|
||||||
|
-0.031313670277005726,
|
||||||
|
-0.0006393262654652846,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
-0.7202445746758257,
|
||||||
|
-0.03131326532214226,
|
||||||
|
-0.0006393222149083683,
|
||||||
|
-0.7202431079507902,
|
||||||
|
-0.031313245044468446,
|
||||||
|
-0.000639322126344006,
|
||||||
|
-0.7202608891564758,
|
||||||
|
-0.03131357572935321,
|
||||||
|
-0.000639325500334864,
|
||||||
|
-0.7203004770720824,
|
||||||
|
-0.03131467563203143,
|
||||||
|
-0.0006393436082476693,
|
||||||
|
-0.7203200385813013,
|
||||||
|
-0.031314937758515383,
|
||||||
|
-0.0006393445984135971,
|
||||||
|
-0.7203210417978083,
|
||||||
|
-0.03131494127751647,
|
||||||
|
-0.0006393443430309219,
|
||||||
|
-0.7203038829240781,
|
||||||
|
-0.031314872463294875,
|
||||||
|
-0.0006393483841598907,
|
||||||
|
0.0,
|
||||||
|
-1.3196376986328492e-22,
|
||||||
|
-2.1367171061617978e-27,
|
||||||
|
-1563.2317229265764,
|
||||||
|
0.0024627103498254554,
|
||||||
|
-1563.2320575702738,
|
||||||
|
0.002462711020582906,
|
||||||
|
-1563.2329311978795,
|
||||||
|
0.002462712553941299,
|
||||||
|
-1563.233271708201,
|
||||||
|
0.0024627131946489966,
|
||||||
|
-1563.2332458437982,
|
||||||
|
0.0024627131438128085,
|
||||||
|
-1563.2328271988004,
|
||||||
|
0.0024627123577517533,
|
||||||
|
-1563.2319625907526,
|
||||||
|
0.0024627108660579895,
|
||||||
|
-1563.2317089857306,
|
||||||
|
0.0024627103184389166,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-32.75534627762145,
|
||||||
|
5.162913025809795e-05,
|
||||||
|
-32.755348137443136,
|
||||||
|
5.1629142243738343e-05,
|
||||||
|
-32.75534804136382,
|
||||||
|
5.162914291472205e-05,
|
||||||
|
-32.7553506164913,
|
||||||
|
5.162913577247215e-05,
|
||||||
|
-32.755345646102356,
|
||||||
|
5.1629112834267025e-05,
|
||||||
|
-32.75534577906393,
|
||||||
|
5.162910342320198e-05,
|
||||||
|
-32.75534577952895,
|
||||||
|
5.162910292904694e-05,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-32.75534579846172,
|
||||||
|
5.1629111455848846e-05,
|
||||||
|
-4.815030419476938,
|
||||||
|
7.589448594417277e-06,
|
||||||
|
-4.815030011609514,
|
||||||
|
7.589450747154388e-06,
|
||||||
|
-4.815030010504332,
|
||||||
|
7.589450673612998e-06,
|
||||||
|
-4.815030207302603,
|
||||||
|
7.589452052046662e-06,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-65.50987529417476,
|
||||||
|
0.00010325724257177476,
|
||||||
|
-65.50922049387084,
|
||||||
|
0.00010325683053111428,
|
||||||
|
-65.50922023152388,
|
||||||
|
0.00010325682249857915,
|
||||||
|
-65.50983596710446,
|
||||||
|
0.00010325719283273935,
|
||||||
|
-65.51060953242626,
|
||||||
|
0.00010325766285951179,
|
||||||
|
-65.51060943575153,
|
||||||
|
0.00010325765252819858,
|
||||||
|
-65.51060962617947,
|
||||||
|
0.0001032576608609912,
|
||||||
|
-65.51061020790279,
|
||||||
|
0.00010325768895577629,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.2,
|
||||||
|
"values": [
|
||||||
|
2.633213298395276e-06,
|
||||||
|
1.1892894705560516e-06,
|
||||||
|
1.5894798508064198e-07,
|
||||||
|
0.0,
|
||||||
|
-2.578751264156614e-22,
|
||||||
|
-4.4071381894537746e-27,
|
||||||
|
2.632795658428222e-06,
|
||||||
|
1.189314089655013e-06,
|
||||||
|
1.589407569517069e-07,
|
||||||
|
2.632610849104822e-06,
|
||||||
|
1.1893270837855721e-06,
|
||||||
|
1.5893755046259315e-07,
|
||||||
|
2.6318631717003883e-06,
|
||||||
|
1.1893767434265974e-06,
|
||||||
|
1.5892477796136446e-07,
|
||||||
|
2.627345675136894e-06,
|
||||||
|
1.1896818589834777e-06,
|
||||||
|
1.588580216987135e-07,
|
||||||
|
2.626597124617547e-06,
|
||||||
|
1.189729910245627e-06,
|
||||||
|
1.5884573170762932e-07,
|
||||||
|
2.626716741360724e-06,
|
||||||
|
1.1897230638966853e-06,
|
||||||
|
1.5884742627218636e-07,
|
||||||
|
2.627662615850568e-06,
|
||||||
|
1.189655709206818e-06,
|
||||||
|
1.588644534572078e-07,
|
||||||
|
0.0,
|
||||||
|
-1.3196897803884347e-20,
|
||||||
|
2.911421882340363e-22,
|
||||||
|
-21722.04652916195,
|
||||||
|
0.06623994849325848,
|
||||||
|
-21723.45572154048,
|
||||||
|
0.06624103226621368,
|
||||||
|
-21805.8029650575,
|
||||||
|
0.06629330102524067,
|
||||||
|
-21807.348632461802,
|
||||||
|
0.06629448766538328,
|
||||||
|
-21807.718245902277,
|
||||||
|
0.06629475455162867,
|
||||||
|
-21841.35926610171,
|
||||||
|
0.06631660356825392,
|
||||||
|
-21724.166913573034,
|
||||||
|
0.06624154605298845,
|
||||||
|
-21722.236505250527,
|
||||||
|
0.06624008714645983,
|
||||||
|
-877966.3231213323,
|
||||||
|
1.2399467552157493,
|
||||||
|
-877966.3231959188,
|
||||||
|
1.2399467558278492,
|
||||||
|
-877963.9668549704,
|
||||||
|
1.2399274199318358,
|
||||||
|
-877963.9667803708,
|
||||||
|
1.2399274193197396,
|
||||||
|
-2232.5019275800073,
|
||||||
|
0.00315798322918964,
|
||||||
|
-2232.4899974231744,
|
||||||
|
0.003157926865311079,
|
||||||
|
-2232.5374050849664,
|
||||||
|
0.003157991047678687,
|
||||||
|
-1390.8326096413955,
|
||||||
|
0.0020292934150847593,
|
||||||
|
-1389.5677102640286,
|
||||||
|
0.0020284826306108832,
|
||||||
|
-1389.567755519397,
|
||||||
|
0.0020284825046839408,
|
||||||
|
-1389.5640026929677,
|
||||||
|
0.002028477899231957,
|
||||||
|
-1384.2773409257754,
|
||||||
|
0.0020250769587299407,
|
||||||
|
-1384.2734539740877,
|
||||||
|
0.002025072398131466,
|
||||||
|
-1384.273453362348,
|
||||||
|
0.002025072497347585,
|
||||||
|
-2232.5493408893735,
|
||||||
|
0.0031580474195833626,
|
||||||
|
-1384.2772469562626,
|
||||||
|
0.0020250771935230094,
|
||||||
|
-225.385588248691,
|
||||||
|
0.00032428657025173376,
|
||||||
|
-225.38393721998736,
|
||||||
|
0.0003242844761714517,
|
||||||
|
-225.38395476780747,
|
||||||
|
0.00032428450098976854,
|
||||||
|
-225.3856398271819,
|
||||||
|
0.0003242866434989134,
|
||||||
|
-2232.549339734738,
|
||||||
|
0.0031580474193159055,
|
||||||
|
-2232.501928009357,
|
||||||
|
0.003157983231060593,
|
||||||
|
-2232.489996268724,
|
||||||
|
0.0031579268650437325,
|
||||||
|
-2232.537405514378,
|
||||||
|
0.0031579910495496645,
|
||||||
|
-152.21172950802372,
|
||||||
|
0.002369452972089371,
|
||||||
|
-233.94138935309604,
|
||||||
|
0.0024219418441874473,
|
||||||
|
-234.03246203501217,
|
||||||
|
0.0024219979480173534,
|
||||||
|
-213.0564611194868,
|
||||||
|
0.002408520518742427,
|
||||||
|
-185.7911471147455,
|
||||||
|
0.0023910044024748737,
|
||||||
|
-185.83507440684312,
|
||||||
|
0.0023910306600708267,
|
||||||
|
-185.52866330836179,
|
||||||
|
0.0023908362272859114,
|
||||||
|
-113.23743631814425,
|
||||||
|
0.0023444176118442837,
|
||||||
|
-665.6994611241944,
|
||||||
|
-664.8834960853846,
|
||||||
|
0.0009422838620001763,
|
||||||
|
0.0009411594503803834,
|
||||||
|
-665.7201688784651,
|
||||||
|
-664.9043863133073,
|
||||||
|
0.0009423119505012294,
|
||||||
|
0.0009411876374833056,
|
||||||
|
-665.6994612846539,
|
||||||
|
-664.8834962525066,
|
||||||
|
0.0009422838626008165,
|
||||||
|
0.0009411594509858708,
|
||||||
|
-665.715814148825,
|
||||||
|
-664.8994727705187,
|
||||||
|
0.0009422941728241457,
|
||||||
|
0.000941169278566084,
|
||||||
|
-665.6951112104504,
|
||||||
|
-664.8785874929312,
|
||||||
|
0.0009422660888104697,
|
||||||
|
0.0009411410960587667,
|
||||||
|
-665.695111741859,
|
||||||
|
-664.8785880272087,
|
||||||
|
0.0009422660891455687,
|
||||||
|
0.0009411410963954202,
|
||||||
|
-665.7158139885557,
|
||||||
|
-664.8994726048427,
|
||||||
|
0.0009422941722236292,
|
||||||
|
0.0009411692779619336,
|
||||||
|
-665.7201683466378,
|
||||||
|
-664.9043857816836,
|
||||||
|
0.0009423119501658692,
|
||||||
|
0.0009411876371485153
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputContract": {
|
||||||
|
"sha256": "ae78c3bc5c60768e1cfc9542267d89922ef10673c5da216f257323c4d94b7499"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,26 +1,55 @@
|
|||||||
{
|
{
|
||||||
"schemaVersion": 1,
|
"schemaVersion": 1,
|
||||||
"id": "test_mql_8-progressive-v3",
|
"id": "test_mql_8-progressive-v3",
|
||||||
"description": "Primary generic-solver regression target for the restored eight-branch 0.005 s-grid authoritative inputs, with a short smoke gate before staged extension.",
|
"description": "Primary generic-solver regression target for the restored eight-branch inputs aligned to the test_mql AMESim archive, with a short smoke gate before staged extension.",
|
||||||
"source": {
|
"source": {
|
||||||
"path": "tests/data/test-mql-8.xml",
|
"path": "tests/data/test-mql-8.xml",
|
||||||
"sha256": "6eb2753a15af66fd8e91c169c4587e66b0ace2164c08c2cb23a67aab5fd09164",
|
"sha256": "0a2d9331df9eb5974daec25a61c1238ba32b1742d933ffc8b16ce316c5627b0b",
|
||||||
"bytes": 104109,
|
"bytes": 104110,
|
||||||
"xmlIsAuthoritative": true,
|
"xmlIsAuthoritative": true,
|
||||||
|
"referenceArchive": {
|
||||||
|
"path": "AmesimModels/test_mql.ame",
|
||||||
|
"sha256": "cbc3aadd4569a49b3a63e5d66d4143ec16126c0f950df73fb637e07673c20fbb",
|
||||||
|
"bytes": 21708800,
|
||||||
|
"role": "authoritativePhysicalBaseline",
|
||||||
|
"resultStartTime": 0.0,
|
||||||
|
"resultStopTime": 10.0,
|
||||||
|
"resultSampleStep": 0.01,
|
||||||
|
"resultPointCount": 1002
|
||||||
|
},
|
||||||
"companionProject": {
|
"companionProject": {
|
||||||
"path": "tests/data/test-mql-8.json",
|
"path": "tests/data/test-mql-8.json",
|
||||||
"sha256": "8d7a263691a9f09f39c92aba19ae1350911dc66b4904e98bae5f20592c5a3fcd",
|
"sha256": "b44bf540ccd1c293fe2af2b9b9052b540abf83961ad955a0f6a4ab40fbe0bb18",
|
||||||
"bytes": 272591,
|
"bytes": 272592,
|
||||||
"executionInput": false
|
"executionInput": false
|
||||||
},
|
},
|
||||||
"simulation": {
|
"simulation": {
|
||||||
"tStart": 0.0,
|
"tStart": 0.0,
|
||||||
"tStop": 5.0,
|
"tStop": 10.0,
|
||||||
"sampleStep": 0.005,
|
"sampleStep": 0.01,
|
||||||
"maxStep": 0.005,
|
"maxStep": 0.001,
|
||||||
"method": "BDF"
|
"method": "BDF"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"acceptanceEvidence": {
|
||||||
|
"production0.2ApprovedReplay": {
|
||||||
|
"path": "tests/baselines/simulation/test_mql_8/runs/2026-08-18-production-opt00-approved-replay-0.2.json",
|
||||||
|
"sha256": "2e27cd54026a2612df88d1903431f3968e03599b2ca6eb83d9b98638cc051502",
|
||||||
|
"bytes": 398198,
|
||||||
|
"workerWallSeconds": 159.60707960650325,
|
||||||
|
"orchestrationWallSeconds": 160.47319143638015,
|
||||||
|
"acceptancePassed": true,
|
||||||
|
"regressionGoldenPassed": true,
|
||||||
|
"physicalStateV21GoldenPassed": true
|
||||||
|
},
|
||||||
|
"extensionDecision": {
|
||||||
|
"path": "tests/baselines/simulation/test_mql_8/runs/2026-08-18-production-opt00-extension-decision.json",
|
||||||
|
"sha256": "7d34aea736863788d9efa72c46910afffd543ddc46eacdf1c6aa9caeab202022",
|
||||||
|
"bytes": 1313,
|
||||||
|
"oneSecondOutcome": "eligible",
|
||||||
|
"extensionWasNotStarted": true
|
||||||
|
}
|
||||||
|
},
|
||||||
"historicalReports": [
|
"historicalReports": [
|
||||||
{
|
{
|
||||||
"path": "tests/baselines/simulation/test_mql_8/runs/2026-08-17-solver-only-v1.json",
|
"path": "tests/baselines/simulation/test_mql_8/runs/2026-08-17-solver-only-v1.json",
|
||||||
@@ -44,7 +73,7 @@
|
|||||||
"sourceXmlSha256": "170463d65d074da01f0f9e9dab730b3815c94c1cc80b5190ec2e3fe623da74d3",
|
"sourceXmlSha256": "170463d65d074da01f0f9e9dab730b3815c94c1cc80b5190ec2e3fe623da74d3",
|
||||||
"status": "historicalOnly",
|
"status": "historicalOnly",
|
||||||
"compatibleWithCurrentSource": false,
|
"compatibleWithCurrentSource": false,
|
||||||
"reason": "This accepted 0.2 s report predates the four restored PNL0001 branches and cannot validate the v3 source."
|
"reason": "This accepted 0.2 s report predates the four restored PNL0001 branches and the AMESim-aligned 10 s simulation settings; it remains historical evidence only."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "tests/baselines/simulation/test_mql_8/runs/2026-08-17-production-v2-extension-decision.json",
|
"path": "tests/baselines/simulation/test_mql_8/runs/2026-08-17-production-v2-extension-decision.json",
|
||||||
@@ -52,7 +81,17 @@
|
|||||||
"sourceXmlSha256": "170463d65d074da01f0f9e9dab730b3815c94c1cc80b5190ec2e3fe623da74d3",
|
"sourceXmlSha256": "170463d65d074da01f0f9e9dab730b3815c94c1cc80b5190ec2e3fe623da74d3",
|
||||||
"status": "historicalOnly",
|
"status": "historicalOnly",
|
||||||
"compatibleWithCurrentSource": false,
|
"compatibleWithCurrentSource": false,
|
||||||
"reason": "This runtime extension decision was derived from the v2 source and is retained only as historical evidence."
|
"reason": "This runtime extension decision was derived from the superseded v2 source and must not control the AMESim-aligned v3 source."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"historicalGoldens": [
|
||||||
|
{
|
||||||
|
"path": "tests/baselines/simulation/test_mql_8/goldens/production-0.2s-v1.json",
|
||||||
|
"sha256": "99fa7b3631a89f59f86551847175f3701a1567d8d0bd10d87545734f17515d72",
|
||||||
|
"sourceXmlSha256": "170463d65d074da01f0f9e9dab730b3815c94c1cc80b5190ec2e3fe623da74d3",
|
||||||
|
"status": "historicalOnly",
|
||||||
|
"compatibleWithCurrentSource": false,
|
||||||
|
"reason": "This Python-state golden predates the four restored PNL0001 branches and the AMESim-aligned simulation settings; it must not approve the current v3 source."
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"structure": {
|
"structure": {
|
||||||
@@ -90,7 +129,7 @@
|
|||||||
"productionEquivalentOutput": false
|
"productionEquivalentOutput": false
|
||||||
},
|
},
|
||||||
"production": {
|
"production": {
|
||||||
"description": "Acceptance lane: changes only tStop and preserves the source 0.005 s output and internal-step grid.",
|
"description": "Acceptance lane: changes only tStop and preserves the AMESim-aligned source 0.01 s output grid and 0.001 s internal-step cap.",
|
||||||
"samplingMode": "source",
|
"samplingMode": "source",
|
||||||
"maxStepMode": "source",
|
"maxStepMode": "source",
|
||||||
"instrumentationMode": "standard",
|
"instrumentationMode": "standard",
|
||||||
@@ -121,7 +160,23 @@
|
|||||||
"expectedSignalEventTimes": [
|
"expectedSignalEventTimes": [
|
||||||
0.04
|
0.04
|
||||||
],
|
],
|
||||||
"expectedMechanicalTransitionTimes": []
|
"expectedMechanicalTransitionTimes": [],
|
||||||
|
"goldens": {
|
||||||
|
"production": {
|
||||||
|
"path": "tests/baselines/simulation/test_mql_8/goldens/production-0.2s-v2.json",
|
||||||
|
"sha256": "7ca8e859d7d2889d6608726eba0faf3441f0f2ad579799c2abdfe571fd49fd0e",
|
||||||
|
"role": "pythonDeterminismRegression",
|
||||||
|
"affectsPhysicalCorrectness": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"physicalStateV21Goldens": {
|
||||||
|
"production": {
|
||||||
|
"path": "tests/baselines/simulation/test_mql_8/goldens/production-0.2s-physical-state-v2.1.json",
|
||||||
|
"sha256": "6f0752afe8c1f7690599c2709a76d9a1342f99f726c6c8593321dc6267e175b2",
|
||||||
|
"role": "amesimPhysicalBaseline",
|
||||||
|
"compareOnEveryRun": true
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"1s": {
|
"1s": {
|
||||||
"stopTime": 1.0,
|
"stopTime": 1.0,
|
||||||
@@ -175,12 +230,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"correctness": {
|
"correctness": {
|
||||||
"status": "partial",
|
"status": "complete",
|
||||||
"maximumScaledResidual": 1e-7,
|
"maximumScaledResidual": 1e-7,
|
||||||
"requireFiniteSeries": true,
|
"requireFiniteSeries": true,
|
||||||
"requireStrictlyIncreasingTimes": true,
|
"requireStrictlyIncreasingTimes": true,
|
||||||
"physicalProjectionCategories": [
|
"physicalProjectionCategories": [
|
||||||
"state"
|
"state",
|
||||||
|
"pressure",
|
||||||
|
"massFlow",
|
||||||
|
"conservation",
|
||||||
|
"discreteMode"
|
||||||
],
|
],
|
||||||
"stateRelativeTolerance": 0.0002,
|
"stateRelativeTolerance": 0.0002,
|
||||||
"stateAbsoluteTolerance": 1e-9,
|
"stateAbsoluteTolerance": 1e-9,
|
||||||
@@ -188,7 +247,10 @@
|
|||||||
"eventTimeAbsoluteToleranceSeconds": 0.00002,
|
"eventTimeAbsoluteToleranceSeconds": 0.00002,
|
||||||
"signalEventTimeAbsoluteToleranceSeconds": 1e-12,
|
"signalEventTimeAbsoluteToleranceSeconds": 1e-12,
|
||||||
"mechanicalTransitionTimesAvailable": true,
|
"mechanicalTransitionTimesAvailable": true,
|
||||||
"note": "The restored v3 source currently enforces structure, finite series, residuals, checkpoints, and events. Its v2 state golden is historical-only; a new reviewed v3 state golden remains pending."
|
"physicalBaselineAuthority": "amesim",
|
||||||
|
"compareAmesimOnEveryRun": true,
|
||||||
|
"pythonGoldenRole": "determinismDiagnosticOnly",
|
||||||
|
"note": "AMESim simulation results are the sole physical baseline and every production run reports current-to-AMESim relative errors. The exact Python-state golden detects determinism and implementation drift only; it cannot approve physical correctness. Longer progressive horizons remain independently staged work."
|
||||||
},
|
},
|
||||||
"execution": {
|
"execution": {
|
||||||
"causalExecutorV2Default": true,
|
"causalExecutorV2Default": true,
|
||||||
|
|||||||
+6393
File diff suppressed because it is too large.
Load diff
+7680
File diff suppressed because it is too large.
Load diff
+40
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"kind": "progressive-extension-decision",
|
||||||
|
"manifestId": "test_mql_8-progressive-v2",
|
||||||
|
"sourceXmlSha256": "0a2d9331df9eb5974daec25a61c1238ba32b1742d933ffc8b16ce316c5627b0b",
|
||||||
|
"sourceReport": "2026-08-18-production-opt00-approved-replay-0.2.json",
|
||||||
|
"sourceReportSha256": "2e27cd54026a2612df88d1903431f3968e03599b2ca6eb83d9b98638cc051502",
|
||||||
|
"lane": "production",
|
||||||
|
"observedCase": {
|
||||||
|
"caseId": "0.2s",
|
||||||
|
"outcome": "completed",
|
||||||
|
"workerWallSeconds": 159.60707960650325,
|
||||||
|
"orchestrationWallSeconds": 160.47319143638015,
|
||||||
|
"acceptancePassed": true,
|
||||||
|
"regressionGoldenPassed": true,
|
||||||
|
"physicalStateV21GoldenPassed": true
|
||||||
|
},
|
||||||
|
"predictionSafetyFactor": 1.5,
|
||||||
|
"decisions": [
|
||||||
|
{
|
||||||
|
"caseId": "1s",
|
||||||
|
"outcome": "eligible",
|
||||||
|
"predictedWallSeconds": 1197.0530970487744,
|
||||||
|
"softTimeoutSeconds": 1200.0,
|
||||||
|
"reason": "predictedWallWithinSoftBudget"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caseId": "5s",
|
||||||
|
"outcome": "notEvaluated",
|
||||||
|
"reason": "predecessorNotRunInOpt00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caseId": "10s",
|
||||||
|
"outcome": "notEvaluated",
|
||||||
|
"reason": "predecessorNotRunInOpt00"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"extensionWasNotStarted": true,
|
||||||
|
"scopeReason": "OPT-00 closes at the approved production 0.2 s gate; longer progressive horizons remain separately staged work."
|
||||||
|
}
|
||||||
+7228
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,631 @@
|
|||||||
|
{
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"id": "test_mql_full_branches-production-0.81s-physical-state-v2",
|
||||||
|
"caseId": "0.81s",
|
||||||
|
"lane": "production",
|
||||||
|
"sourceXmlSha256": "2fb95e65f5de0c85a6a17802aef74ea004087323fd00fd8d01acf0184ff71d48",
|
||||||
|
"approval": {
|
||||||
|
"status": "approved",
|
||||||
|
"approvedAt": "2026-08-18T07:25:28+00:00",
|
||||||
|
"basis": "OPT-00 locked Python 3.12 production repeat 1 passed finite-series, checkpoint, event, residual, audit, and no-fallback gates; repeats 2 and 3 replayed every projected value exactly."
|
||||||
|
},
|
||||||
|
"provenance": {
|
||||||
|
"sourceReport": {
|
||||||
|
"path": "tests/baselines/simulation/test_mql_full_branches/runs/2026-08-18-opt00-historical-repeat-1.json",
|
||||||
|
"sha256": "4659ae850eef4f1541b3172f783b01a1859744a3f0a50030e094c2c25f93e195",
|
||||||
|
"generatedAt": "2026-08-18T07:12:43.593117+00:00",
|
||||||
|
"metadataCompatibility": {
|
||||||
|
"status": "current",
|
||||||
|
"differences": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"physicalLayout": {
|
||||||
|
"projectionCategories": [
|
||||||
|
"state"
|
||||||
|
],
|
||||||
|
"stateKeys": [
|
||||||
|
"branch_boundary_pnl0002_b_chamber.U",
|
||||||
|
"branch_boundary_pnl0002_b_chamber.m",
|
||||||
|
"branch_boundary_pnl0002_branch05_chamber.U",
|
||||||
|
"branch_boundary_pnl0002_branch05_chamber.m",
|
||||||
|
"branch_boundary_pnl00r_branch05_chamber.U",
|
||||||
|
"branch_boundary_pnl00r_branch05_chamber.m",
|
||||||
|
"branch_boundary_pnl00r_chamber.U",
|
||||||
|
"branch_boundary_pnl00r_chamber.m",
|
||||||
|
"mass_friction_endstops_10.a",
|
||||||
|
"mass_friction_endstops_10.v",
|
||||||
|
"mass_friction_endstops_10.x",
|
||||||
|
"mass_friction_endstops_11.a",
|
||||||
|
"mass_friction_endstops_11.v",
|
||||||
|
"mass_friction_endstops_11.x",
|
||||||
|
"mass_friction_endstops_12.a",
|
||||||
|
"mass_friction_endstops_12.v",
|
||||||
|
"mass_friction_endstops_12.x",
|
||||||
|
"mass_friction_endstops_13.a",
|
||||||
|
"mass_friction_endstops_13.v",
|
||||||
|
"mass_friction_endstops_13.x",
|
||||||
|
"mass_friction_endstops_18.a",
|
||||||
|
"mass_friction_endstops_18.v",
|
||||||
|
"mass_friction_endstops_18.x",
|
||||||
|
"mass_friction_endstops_19.a",
|
||||||
|
"mass_friction_endstops_19.v",
|
||||||
|
"mass_friction_endstops_19.x",
|
||||||
|
"pn_c1_10.U",
|
||||||
|
"pn_c1_10.m",
|
||||||
|
"pn_c1_11.U",
|
||||||
|
"pn_c1_11.m",
|
||||||
|
"pn_c1_8.U",
|
||||||
|
"pn_c1_8.m",
|
||||||
|
"pn_c1_9.U",
|
||||||
|
"pn_c1_9.m",
|
||||||
|
"pn_general_chamber.U",
|
||||||
|
"pn_general_chamber.m",
|
||||||
|
"pn_general_chamber_2.U",
|
||||||
|
"pn_general_chamber_2.m",
|
||||||
|
"pneumatic_65.U",
|
||||||
|
"pneumatic_65.m",
|
||||||
|
"pneumatic_66.U",
|
||||||
|
"pneumatic_66.m",
|
||||||
|
"pneumatic_68.U",
|
||||||
|
"pneumatic_68.m",
|
||||||
|
"pneumatic_69.U",
|
||||||
|
"pneumatic_69.m",
|
||||||
|
"pneumatic_75.U1",
|
||||||
|
"pneumatic_75.U2",
|
||||||
|
"pneumatic_75.m1",
|
||||||
|
"pneumatic_75.m2",
|
||||||
|
"pneumatic_76.U1",
|
||||||
|
"pneumatic_76.U2",
|
||||||
|
"pneumatic_76.m1",
|
||||||
|
"pneumatic_76.m2",
|
||||||
|
"pneumatic_80.U",
|
||||||
|
"pneumatic_80.m",
|
||||||
|
"pneumatic_83.U",
|
||||||
|
"pneumatic_83.m",
|
||||||
|
"pneumatic_85.U",
|
||||||
|
"pneumatic_85.m",
|
||||||
|
"pneumatic_86.U",
|
||||||
|
"pneumatic_86.m",
|
||||||
|
"pneumatic_87.U1",
|
||||||
|
"pneumatic_87.U2",
|
||||||
|
"pneumatic_87.m1",
|
||||||
|
"pneumatic_87.m2",
|
||||||
|
"pneumatic_88.U1",
|
||||||
|
"pneumatic_88.U2",
|
||||||
|
"pneumatic_88.m1",
|
||||||
|
"pneumatic_88.m2",
|
||||||
|
"pneumatic_95.U",
|
||||||
|
"pneumatic_95.m",
|
||||||
|
"pneumatic_96.U",
|
||||||
|
"pneumatic_96.m",
|
||||||
|
"pneumatic_97.U",
|
||||||
|
"pneumatic_97.m",
|
||||||
|
"pneumatic_98.U",
|
||||||
|
"pneumatic_98.m",
|
||||||
|
"pneumatic_99.U",
|
||||||
|
"pneumatic_99.m"
|
||||||
|
],
|
||||||
|
"stateKeyLayoutSha256": "65824cf9793e935481c106c9e673bd2034a439c6dc3d74997ae2b8149ced4fbe"
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0002,
|
||||||
|
"absolute": 1e-09,
|
||||||
|
"checkpointTimeAbsoluteSeconds": 1e-12
|
||||||
|
},
|
||||||
|
"physicalCheckpoints": [
|
||||||
|
{
|
||||||
|
"requestedTime": 0.0,
|
||||||
|
"values": [
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-0.8167936695810981,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
-0.8167936695810981,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
-0.8167936695810981,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
-0.8167936695810981,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
-1563.893548405841,
|
||||||
|
0.002462855848963059,
|
||||||
|
-1563.893548405841,
|
||||||
|
0.002462855848963059,
|
||||||
|
-1563.893548405841,
|
||||||
|
0.002462855848963059,
|
||||||
|
-1563.893548405841,
|
||||||
|
0.002462855848963059,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-32.754109884455104,
|
||||||
|
5.158193227968668e-05,
|
||||||
|
-32.754109884455104,
|
||||||
|
5.158193227968668e-05,
|
||||||
|
-32.754109884455104,
|
||||||
|
5.158193227968668e-05,
|
||||||
|
-32.754109884455104,
|
||||||
|
5.158193227968668e-05,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-65.50821976891021,
|
||||||
|
0.00010316386455937335,
|
||||||
|
-65.50821976891021,
|
||||||
|
0.00010316386455937335,
|
||||||
|
-65.50821976891021,
|
||||||
|
0.00010316386455937335,
|
||||||
|
-65.50821976891021,
|
||||||
|
0.00010316386455937335,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-65.50821976891021,
|
||||||
|
0.00010316386455937335,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"values": [
|
||||||
|
-879404.9359576713,
|
||||||
|
1.2522714879032233,
|
||||||
|
-879404.9358312349,
|
||||||
|
1.2522714867708487,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
9.734498453326524e-06,
|
||||||
|
2.2165787255696986e-06,
|
||||||
|
7.615138175359735e-08,
|
||||||
|
6.899700674694032e-06,
|
||||||
|
1.6791980885681643e-06,
|
||||||
|
5.607885010135549e-08,
|
||||||
|
6.900102307554334e-06,
|
||||||
|
1.6791970458948259e-06,
|
||||||
|
5.6078837470433516e-08,
|
||||||
|
9.7344332607463e-06,
|
||||||
|
2.2165785543742696e-06,
|
||||||
|
7.615138012421167e-08,
|
||||||
|
0.0,
|
||||||
|
-1.3786916256412132e-25,
|
||||||
|
-5.521417937686967e-24,
|
||||||
|
0.0,
|
||||||
|
1.7204535623474844e-21,
|
||||||
|
-1.2449238864173693e-21,
|
||||||
|
-3836.4295505841374,
|
||||||
|
0.03971246371985885,
|
||||||
|
-8215.697802972754,
|
||||||
|
0.06449828662707775,
|
||||||
|
-8215.698180211439,
|
||||||
|
0.06449829186881316,
|
||||||
|
-3836.3905996761514,
|
||||||
|
0.03971246529726471,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-2323.937662655075,
|
||||||
|
0.003365680267480819,
|
||||||
|
-1558.6812613835866,
|
||||||
|
0.00229549447954163,
|
||||||
|
-1558.6815406132575,
|
||||||
|
0.0022954946593348505,
|
||||||
|
-2323.9377625288566,
|
||||||
|
0.0033656803769320197,
|
||||||
|
-733.2050606371582,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506629,
|
||||||
|
0.001136356102550663,
|
||||||
|
-3931.718242540372,
|
||||||
|
0.005752354208859085,
|
||||||
|
-3931.719290698283,
|
||||||
|
0.005752354971956523,
|
||||||
|
-7784.908056387039,
|
||||||
|
0.011153351022249161,
|
||||||
|
1704.5017150238582,
|
||||||
|
0.001497027829154341,
|
||||||
|
-733.205060637158,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506629,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-7784.908156509664,
|
||||||
|
0.011153351115632995,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.69,
|
||||||
|
"values": [
|
||||||
|
-860379.0245019491,
|
||||||
|
1.1985497181126685,
|
||||||
|
-860379.0247699278,
|
||||||
|
1.1985497182559621,
|
||||||
|
-874070.5350132573,
|
||||||
|
1.2108685641280736,
|
||||||
|
-874070.5351659104,
|
||||||
|
1.2108685651503308,
|
||||||
|
6.302155088633299e-07,
|
||||||
|
2.0477201022089e-06,
|
||||||
|
1.739862170731644e-06,
|
||||||
|
6.885582115501165e-07,
|
||||||
|
2.072356484372671e-06,
|
||||||
|
1.7151425366011e-06,
|
||||||
|
6.88283471390605e-07,
|
||||||
|
2.0723565171342975e-06,
|
||||||
|
1.7151425037886711e-06,
|
||||||
|
6.301060784608125e-07,
|
||||||
|
2.0477201243571633e-06,
|
||||||
|
1.739862148436311e-06,
|
||||||
|
0.0,
|
||||||
|
2.0520928869397134e-22,
|
||||||
|
4.9098612203217504e-20,
|
||||||
|
0.0,
|
||||||
|
4.7142848729216316e-20,
|
||||||
|
-2.0780593120000206e-21,
|
||||||
|
-95711.13598161584,
|
||||||
|
0.2330223756901088,
|
||||||
|
-99484.30868025024,
|
||||||
|
0.23540556157200768,
|
||||||
|
-99484.30933223445,
|
||||||
|
0.23540556198958848,
|
||||||
|
-95711.12399082902,
|
||||||
|
0.23302236813021637,
|
||||||
|
-874021.6128809263,
|
||||||
|
1.2105342428506563,
|
||||||
|
-874021.6127639221,
|
||||||
|
1.2105342420477019,
|
||||||
|
-4699.544021984157,
|
||||||
|
0.006579168843426967,
|
||||||
|
-4720.142085434138,
|
||||||
|
0.006592090149576305,
|
||||||
|
-4720.142089865395,
|
||||||
|
0.006592090152448902,
|
||||||
|
-4699.544238887633,
|
||||||
|
0.006579168980161733,
|
||||||
|
-720.548977698558,
|
||||||
|
-720.2062838344375,
|
||||||
|
0.000998791691638376,
|
||||||
|
0.00099856697258834,
|
||||||
|
-722.1637803310383,
|
||||||
|
-722.0477500247466,
|
||||||
|
0.0010005181981378461,
|
||||||
|
0.0010004330928084816,
|
||||||
|
-8639.330806039252,
|
||||||
|
0.012679745952732602,
|
||||||
|
-8639.330537692149,
|
||||||
|
0.012679745783851644,
|
||||||
|
-8909.106011748408,
|
||||||
|
0.012849685563490313,
|
||||||
|
1389.1739707221775,
|
||||||
|
0.006354956657485442,
|
||||||
|
-722.1637801799975,
|
||||||
|
-722.0477531282031,
|
||||||
|
0.001000518198664749,
|
||||||
|
0.0010004330953830574,
|
||||||
|
-720.5489778046637,
|
||||||
|
-720.2062839511643,
|
||||||
|
0.0009987916917054815,
|
||||||
|
0.0009985669726623582,
|
||||||
|
-8909.106148651528,
|
||||||
|
0.012849685649995602,
|
||||||
|
-2357.5431522121776,
|
||||||
|
0.00326741144588273,
|
||||||
|
-2355.7331452897465,
|
||||||
|
0.0032646046108505246,
|
||||||
|
-2355.733147442795,
|
||||||
|
0.0032646046116421414,
|
||||||
|
-2357.543151890905,
|
||||||
|
0.0032674114436482805
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.7,
|
||||||
|
"values": [
|
||||||
|
-860379.8819972485,
|
||||||
|
1.1985586239832504,
|
||||||
|
-860379.8822663656,
|
||||||
|
1.1985586241379014,
|
||||||
|
-873989.7214316746,
|
||||||
|
1.210316350104016,
|
||||||
|
-873989.7215632556,
|
||||||
|
1.2103163509793102,
|
||||||
|
-2.1975173149257897e-06,
|
||||||
|
2.02734183270263e-06,
|
||||||
|
1.7602360080939606e-06,
|
||||||
|
-2.245873911306262e-06,
|
||||||
|
2.0517263968615454e-06,
|
||||||
|
1.7357614512099663e-06,
|
||||||
|
-2.2355280816555024e-06,
|
||||||
|
2.051726429425243e-06,
|
||||||
|
1.7357614187243355e-06,
|
||||||
|
-2.1975464187562464e-06,
|
||||||
|
2.0273418547326992e-06,
|
||||||
|
1.7602359860195857e-06,
|
||||||
|
0.0,
|
||||||
|
2.013739831250115e-21,
|
||||||
|
4.909861220321753e-20,
|
||||||
|
0.0,
|
||||||
|
4.665200046136569e-20,
|
||||||
|
-1.9566383001493946e-21,
|
||||||
|
-96560.09354570496,
|
||||||
|
0.2335572995463288,
|
||||||
|
-100288.67701814357,
|
||||||
|
0.23591263994887818,
|
||||||
|
-100288.677678112,
|
||||||
|
0.23591264036701443,
|
||||||
|
-96560.0816929563,
|
||||||
|
0.23355729206770598,
|
||||||
|
-873947.8864856226,
|
||||||
|
1.2100313452817673,
|
||||||
|
-873947.8863858595,
|
||||||
|
1.2100313445985562,
|
||||||
|
-4706.906282326286,
|
||||||
|
0.006583785685946545,
|
||||||
|
-4721.89741006748,
|
||||||
|
0.006593168289865688,
|
||||||
|
-4721.897404439745,
|
||||||
|
0.006593168286323642,
|
||||||
|
-4706.906483656017,
|
||||||
|
0.006583785812787189,
|
||||||
|
-720.6545512340357,
|
||||||
|
-720.3217292925623,
|
||||||
|
0.0009985764249686698,
|
||||||
|
0.0009983591472543481,
|
||||||
|
-722.1508419312411,
|
||||||
|
-722.0421232665894,
|
||||||
|
0.0010001323660439989,
|
||||||
|
0.00100005352811943,
|
||||||
|
-8642.043554742524,
|
||||||
|
0.012681407602717975,
|
||||||
|
-8642.043293601184,
|
||||||
|
0.012681407438297841,
|
||||||
|
-8909.49862797875,
|
||||||
|
0.012849959429845414,
|
||||||
|
1389.0998959067165,
|
||||||
|
0.006354964303801297,
|
||||||
|
-722.1508452424541,
|
||||||
|
-722.0421258113258,
|
||||||
|
0.0010001323686673997,
|
||||||
|
0.001000053530255132,
|
||||||
|
-720.6545510297586,
|
||||||
|
-720.3217293326904,
|
||||||
|
0.0009985764248405691,
|
||||||
|
0.0009983591472800236,
|
||||||
|
-8909.498764806547,
|
||||||
|
0.012849959516004638,
|
||||||
|
-2357.35674156337,
|
||||||
|
0.0032660606424093387,
|
||||||
|
-2355.921025330427,
|
||||||
|
0.0032637130423187337,
|
||||||
|
-2355.921027270413,
|
||||||
|
0.0032637130430599385,
|
||||||
|
-2357.3567413654787,
|
||||||
|
0.003266060640560602
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.8,
|
||||||
|
"values": [
|
||||||
|
-860175.1606710927,
|
||||||
|
1.1970987817186032,
|
||||||
|
-860175.1609442824,
|
||||||
|
1.1970987819042118,
|
||||||
|
-873416.0554547055,
|
||||||
|
1.206445289457375,
|
||||||
|
-873416.0554726648,
|
||||||
|
1.2064452895529436,
|
||||||
|
-1.949198776856065e-06,
|
||||||
|
1.826519161772371e-06,
|
||||||
|
1.9528536810215616e-06,
|
||||||
|
-1.971406163647771e-06,
|
||||||
|
1.848554964674094e-06,
|
||||||
|
1.930697446050263e-06,
|
||||||
|
-1.9711186178028582e-06,
|
||||||
|
1.8485549941949607e-06,
|
||||||
|
1.930697416668372e-06,
|
||||||
|
-1.94919528439641e-06,
|
||||||
|
1.826519181824015e-06,
|
||||||
|
1.9528536610522474e-06,
|
||||||
|
8.892500282325972,
|
||||||
|
2.5187368473853223e-21,
|
||||||
|
4.909861220321753e-20,
|
||||||
|
-16.252500528926326,
|
||||||
|
4.576919129896975e-20,
|
||||||
|
-1.9530653259948938e-21,
|
||||||
|
-104471.75361732666,
|
||||||
|
0.23818832921650948,
|
||||||
|
-107803.92242364622,
|
||||||
|
0.24029497741554184,
|
||||||
|
-107803.92309836508,
|
||||||
|
0.2402949778374652,
|
||||||
|
-104471.7429655161,
|
||||||
|
0.2381883224928943,
|
||||||
|
-873404.5104492744,
|
||||||
|
1.2063684021036665,
|
||||||
|
-873404.5104388825,
|
||||||
|
1.2063684020307441,
|
||||||
|
-4704.300638717692,
|
||||||
|
0.006574703133691949,
|
||||||
|
-4693.326778314112,
|
||||||
|
0.006567696268767441,
|
||||||
|
-4693.326526389924,
|
||||||
|
0.006567696110012524,
|
||||||
|
-4704.3007263131885,
|
||||||
|
0.006574703188787359,
|
||||||
|
-721.1607141734798,
|
||||||
|
-720.9310979144485,
|
||||||
|
0.0009965662267659527,
|
||||||
|
0.0009964191642398892,
|
||||||
|
-721.9230383692676,
|
||||||
|
-721.8772183273541,
|
||||||
|
0.0009972429132872915,
|
||||||
|
0.0009972108290529252,
|
||||||
|
-8703.980749781746,
|
||||||
|
0.012705472199729761,
|
||||||
|
-8703.980555484635,
|
||||||
|
0.01270547207717158,
|
||||||
|
-8967.989302068207,
|
||||||
|
0.012872002894864527,
|
||||||
|
1377.5687495145785,
|
||||||
|
0.006346840211910472,
|
||||||
|
-721.9230326537768,
|
||||||
|
-721.8772199435517,
|
||||||
|
0.0009972429097436842,
|
||||||
|
0.0009972108301285444,
|
||||||
|
-721.1607123097651,
|
||||||
|
-720.9310970023907,
|
||||||
|
0.000996566225592321,
|
||||||
|
0.0009964191636655784,
|
||||||
|
-8967.989425383095,
|
||||||
|
0.0128720029723915,
|
||||||
|
-2356.03147928222,
|
||||||
|
0.0032562562535671563,
|
||||||
|
-2356.668143012874,
|
||||||
|
0.0032561870649935125,
|
||||||
|
-2356.668143725967,
|
||||||
|
0.0032561870653915977,
|
||||||
|
-2356.031477688963,
|
||||||
|
0.0032562562523787346
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.81,
|
||||||
|
"values": [
|
||||||
|
-860055.7816079621,
|
||||||
|
1.1962534043760158,
|
||||||
|
-860055.7818796586,
|
||||||
|
1.1962534045522308,
|
||||||
|
-873367.9088398638,
|
||||||
|
1.206124190328161,
|
||||||
|
-873367.9088547124,
|
||||||
|
1.206124190402843,
|
||||||
|
8.857774649477797,
|
||||||
|
0.08873345197507769,
|
||||||
|
0.00044583262150923715,
|
||||||
|
8.857774480804801,
|
||||||
|
0.08873347304797707,
|
||||||
|
0.0004458106820297355,
|
||||||
|
8.857774445663672,
|
||||||
|
0.08873347304800631,
|
||||||
|
0.0004458106820006473,
|
||||||
|
8.857774661221775,
|
||||||
|
0.08873345197509747,
|
||||||
|
0.00044583262148946694,
|
||||||
|
8.857778206680395,
|
||||||
|
0.08873165793329868,
|
||||||
|
0.00044386167425480166,
|
||||||
|
-16.206598333861397,
|
||||||
|
-0.16235697968747592,
|
||||||
|
-0.0008121695210045893,
|
||||||
|
-105735.3088635258,
|
||||||
|
0.23897151058696434,
|
||||||
|
-109037.397892104,
|
||||||
|
0.24109191168512564,
|
||||||
|
-109037.39857007933,
|
||||||
|
0.2410919121122127,
|
||||||
|
-105735.29829660244,
|
||||||
|
0.23897150391654698,
|
||||||
|
-873350.1784581648,
|
||||||
|
1.206006248314118,
|
||||||
|
-873350.1784501448,
|
||||||
|
1.2060062482571396,
|
||||||
|
-4682.546337026962,
|
||||||
|
0.006553210204193263,
|
||||||
|
-4667.866605288969,
|
||||||
|
0.006543088564608954,
|
||||||
|
-4667.866320678238,
|
||||||
|
0.006543088385317721,
|
||||||
|
-4682.546417371199,
|
||||||
|
0.006553210254794004,
|
||||||
|
-721.1212567696082,
|
||||||
|
-720.9136270898001,
|
||||||
|
0.0009960146033417782,
|
||||||
|
0.0009958781343227421,
|
||||||
|
-721.8635886622386,
|
||||||
|
-721.8407704168852,
|
||||||
|
0.0009969210574287178,
|
||||||
|
0.0009968996150299173,
|
||||||
|
-8724.337750229228,
|
||||||
|
0.012701926255908602,
|
||||||
|
-8724.337567825336,
|
||||||
|
0.012701926140963282,
|
||||||
|
-8998.36421558522,
|
||||||
|
0.012879100492327268,
|
||||||
|
1364.3747046167766,
|
||||||
|
0.00633752606051716,
|
||||||
|
-721.8635847156165,
|
||||||
|
-721.8407700947419,
|
||||||
|
0.000996921054988454,
|
||||||
|
0.0009968996148721218,
|
||||||
|
-721.121255394678,
|
||||||
|
-720.9136259824896,
|
||||||
|
0.0009960146024759352,
|
||||||
|
0.0009958781336253564,
|
||||||
|
-8998.364330621043,
|
||||||
|
0.012879100564768854,
|
||||||
|
-2355.9148119653287,
|
||||||
|
0.0032552690027748852,
|
||||||
|
-2356.531146237746,
|
||||||
|
0.0032546207052266537,
|
||||||
|
-2356.5311468883583,
|
||||||
|
0.0032546207055964556,
|
||||||
|
-2355.914810407958,
|
||||||
|
0.0032552690016484026
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputContract": {
|
||||||
|
"sha256": "e7596daa27144f14d5210c100126fa0c413862ed8a8e4bf525195b2e6070e0f9"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,886 @@
|
|||||||
|
{
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"id": "test_mql_full_branches-production-2.10s-physical-state-v2",
|
||||||
|
"caseId": "2.10s",
|
||||||
|
"lane": "production",
|
||||||
|
"sourceXmlSha256": "2fb95e65f5de0c85a6a17802aef74ea004087323fd00fd8d01acf0184ff71d48",
|
||||||
|
"approval": {
|
||||||
|
"status": "approved",
|
||||||
|
"approvedAt": "2026-08-18T07:25:28+00:00",
|
||||||
|
"basis": "OPT-00 locked Python 3.12 production repeat 1 passed finite-series, checkpoint, event, residual, audit, and no-fallback gates; repeats 2 and 3 replayed every projected value exactly."
|
||||||
|
},
|
||||||
|
"provenance": {
|
||||||
|
"sourceReport": {
|
||||||
|
"path": "tests/baselines/simulation/test_mql_full_branches/runs/2026-08-18-opt00-historical-repeat-1.json",
|
||||||
|
"sha256": "4659ae850eef4f1541b3172f783b01a1859744a3f0a50030e094c2c25f93e195",
|
||||||
|
"generatedAt": "2026-08-18T07:12:43.593117+00:00",
|
||||||
|
"metadataCompatibility": {
|
||||||
|
"status": "current",
|
||||||
|
"differences": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"physicalLayout": {
|
||||||
|
"projectionCategories": [
|
||||||
|
"state"
|
||||||
|
],
|
||||||
|
"stateKeys": [
|
||||||
|
"branch_boundary_pnl0002_b_chamber.U",
|
||||||
|
"branch_boundary_pnl0002_b_chamber.m",
|
||||||
|
"branch_boundary_pnl0002_branch05_chamber.U",
|
||||||
|
"branch_boundary_pnl0002_branch05_chamber.m",
|
||||||
|
"branch_boundary_pnl00r_branch05_chamber.U",
|
||||||
|
"branch_boundary_pnl00r_branch05_chamber.m",
|
||||||
|
"branch_boundary_pnl00r_chamber.U",
|
||||||
|
"branch_boundary_pnl00r_chamber.m",
|
||||||
|
"mass_friction_endstops_10.a",
|
||||||
|
"mass_friction_endstops_10.v",
|
||||||
|
"mass_friction_endstops_10.x",
|
||||||
|
"mass_friction_endstops_11.a",
|
||||||
|
"mass_friction_endstops_11.v",
|
||||||
|
"mass_friction_endstops_11.x",
|
||||||
|
"mass_friction_endstops_12.a",
|
||||||
|
"mass_friction_endstops_12.v",
|
||||||
|
"mass_friction_endstops_12.x",
|
||||||
|
"mass_friction_endstops_13.a",
|
||||||
|
"mass_friction_endstops_13.v",
|
||||||
|
"mass_friction_endstops_13.x",
|
||||||
|
"mass_friction_endstops_18.a",
|
||||||
|
"mass_friction_endstops_18.v",
|
||||||
|
"mass_friction_endstops_18.x",
|
||||||
|
"mass_friction_endstops_19.a",
|
||||||
|
"mass_friction_endstops_19.v",
|
||||||
|
"mass_friction_endstops_19.x",
|
||||||
|
"pn_c1_10.U",
|
||||||
|
"pn_c1_10.m",
|
||||||
|
"pn_c1_11.U",
|
||||||
|
"pn_c1_11.m",
|
||||||
|
"pn_c1_8.U",
|
||||||
|
"pn_c1_8.m",
|
||||||
|
"pn_c1_9.U",
|
||||||
|
"pn_c1_9.m",
|
||||||
|
"pn_general_chamber.U",
|
||||||
|
"pn_general_chamber.m",
|
||||||
|
"pn_general_chamber_2.U",
|
||||||
|
"pn_general_chamber_2.m",
|
||||||
|
"pneumatic_65.U",
|
||||||
|
"pneumatic_65.m",
|
||||||
|
"pneumatic_66.U",
|
||||||
|
"pneumatic_66.m",
|
||||||
|
"pneumatic_68.U",
|
||||||
|
"pneumatic_68.m",
|
||||||
|
"pneumatic_69.U",
|
||||||
|
"pneumatic_69.m",
|
||||||
|
"pneumatic_75.U1",
|
||||||
|
"pneumatic_75.U2",
|
||||||
|
"pneumatic_75.m1",
|
||||||
|
"pneumatic_75.m2",
|
||||||
|
"pneumatic_76.U1",
|
||||||
|
"pneumatic_76.U2",
|
||||||
|
"pneumatic_76.m1",
|
||||||
|
"pneumatic_76.m2",
|
||||||
|
"pneumatic_80.U",
|
||||||
|
"pneumatic_80.m",
|
||||||
|
"pneumatic_83.U",
|
||||||
|
"pneumatic_83.m",
|
||||||
|
"pneumatic_85.U",
|
||||||
|
"pneumatic_85.m",
|
||||||
|
"pneumatic_86.U",
|
||||||
|
"pneumatic_86.m",
|
||||||
|
"pneumatic_87.U1",
|
||||||
|
"pneumatic_87.U2",
|
||||||
|
"pneumatic_87.m1",
|
||||||
|
"pneumatic_87.m2",
|
||||||
|
"pneumatic_88.U1",
|
||||||
|
"pneumatic_88.U2",
|
||||||
|
"pneumatic_88.m1",
|
||||||
|
"pneumatic_88.m2",
|
||||||
|
"pneumatic_95.U",
|
||||||
|
"pneumatic_95.m",
|
||||||
|
"pneumatic_96.U",
|
||||||
|
"pneumatic_96.m",
|
||||||
|
"pneumatic_97.U",
|
||||||
|
"pneumatic_97.m",
|
||||||
|
"pneumatic_98.U",
|
||||||
|
"pneumatic_98.m",
|
||||||
|
"pneumatic_99.U",
|
||||||
|
"pneumatic_99.m"
|
||||||
|
],
|
||||||
|
"stateKeyLayoutSha256": "65824cf9793e935481c106c9e673bd2034a439c6dc3d74997ae2b8149ced4fbe"
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"relative": 0.0002,
|
||||||
|
"absolute": 1e-09,
|
||||||
|
"checkpointTimeAbsoluteSeconds": 1e-12
|
||||||
|
},
|
||||||
|
"physicalCheckpoints": [
|
||||||
|
{
|
||||||
|
"requestedTime": 0.0,
|
||||||
|
"values": [
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-0.8167936695810981,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
-0.8167936695810981,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
-0.8167936695810981,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
-0.8167936695810981,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
-1563.893548405841,
|
||||||
|
0.002462855848963059,
|
||||||
|
-1563.893548405841,
|
||||||
|
0.002462855848963059,
|
||||||
|
-1563.893548405841,
|
||||||
|
0.002462855848963059,
|
||||||
|
-1563.893548405841,
|
||||||
|
0.002462855848963059,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-32.754109884455104,
|
||||||
|
5.158193227968668e-05,
|
||||||
|
-32.754109884455104,
|
||||||
|
5.158193227968668e-05,
|
||||||
|
-32.754109884455104,
|
||||||
|
5.158193227968668e-05,
|
||||||
|
-32.754109884455104,
|
||||||
|
5.158193227968668e-05,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-65.50821976891021,
|
||||||
|
0.00010316386455937335,
|
||||||
|
-65.50821976891021,
|
||||||
|
0.00010316386455937335,
|
||||||
|
-65.50821976891021,
|
||||||
|
0.00010316386455937335,
|
||||||
|
-65.50821976891021,
|
||||||
|
0.00010316386455937335,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-65.50821976891021,
|
||||||
|
0.00010316386455937335,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.04,
|
||||||
|
"values": [
|
||||||
|
-879404.9359576713,
|
||||||
|
1.2522714879032233,
|
||||||
|
-879404.9358312349,
|
||||||
|
1.2522714867708487,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
9.734498453326524e-06,
|
||||||
|
2.2165787255696986e-06,
|
||||||
|
7.615138175359735e-08,
|
||||||
|
6.899700674694032e-06,
|
||||||
|
1.6791980885681643e-06,
|
||||||
|
5.607885010135549e-08,
|
||||||
|
6.900102307554334e-06,
|
||||||
|
1.6791970458948259e-06,
|
||||||
|
5.6078837470433516e-08,
|
||||||
|
9.7344332607463e-06,
|
||||||
|
2.2165785543742696e-06,
|
||||||
|
7.615138012421167e-08,
|
||||||
|
0.0,
|
||||||
|
-1.3786916256412132e-25,
|
||||||
|
-5.521417937686967e-24,
|
||||||
|
0.0,
|
||||||
|
1.7204535623474844e-21,
|
||||||
|
-1.2449238864173693e-21,
|
||||||
|
-3836.4295505841374,
|
||||||
|
0.03971246371985885,
|
||||||
|
-8215.697802972754,
|
||||||
|
0.06449828662707775,
|
||||||
|
-8215.698180211439,
|
||||||
|
0.06449829186881316,
|
||||||
|
-3836.3905996761514,
|
||||||
|
0.03971246529726471,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-886868.3937230138,
|
||||||
|
1.374510850335198,
|
||||||
|
-2323.937662655075,
|
||||||
|
0.003365680267480819,
|
||||||
|
-1558.6812613835866,
|
||||||
|
0.00229549447954163,
|
||||||
|
-1558.6815406132575,
|
||||||
|
0.0022954946593348505,
|
||||||
|
-2323.9377625288566,
|
||||||
|
0.0033656803769320197,
|
||||||
|
-733.2050606371582,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506629,
|
||||||
|
0.001136356102550663,
|
||||||
|
-3931.718242540372,
|
||||||
|
0.005752354208859085,
|
||||||
|
-3931.719290698283,
|
||||||
|
0.005752354971956523,
|
||||||
|
-7784.908056387039,
|
||||||
|
0.011153351022249161,
|
||||||
|
1704.5017150238582,
|
||||||
|
0.001497027829154341,
|
||||||
|
-733.205060637158,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506629,
|
||||||
|
-733.2050606371581,
|
||||||
|
-733.2050606371581,
|
||||||
|
0.0011363561025506627,
|
||||||
|
0.0011363561025506627,
|
||||||
|
-7784.908156509664,
|
||||||
|
0.011153351115632995,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976,
|
||||||
|
-2395.136531414716,
|
||||||
|
0.0037120966016654976
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.69,
|
||||||
|
"values": [
|
||||||
|
-860379.0245019491,
|
||||||
|
1.1985497181126685,
|
||||||
|
-860379.0247699278,
|
||||||
|
1.1985497182559621,
|
||||||
|
-874070.5350132573,
|
||||||
|
1.2108685641280736,
|
||||||
|
-874070.5351659104,
|
||||||
|
1.2108685651503308,
|
||||||
|
6.302155088633299e-07,
|
||||||
|
2.0477201022089e-06,
|
||||||
|
1.739862170731644e-06,
|
||||||
|
6.885582115501165e-07,
|
||||||
|
2.072356484372671e-06,
|
||||||
|
1.7151425366011e-06,
|
||||||
|
6.88283471390605e-07,
|
||||||
|
2.0723565171342975e-06,
|
||||||
|
1.7151425037886711e-06,
|
||||||
|
6.301060784608125e-07,
|
||||||
|
2.0477201243571633e-06,
|
||||||
|
1.739862148436311e-06,
|
||||||
|
0.0,
|
||||||
|
2.0520928869397134e-22,
|
||||||
|
4.9098612203217504e-20,
|
||||||
|
0.0,
|
||||||
|
4.7142848729216316e-20,
|
||||||
|
-2.0780593120000206e-21,
|
||||||
|
-95711.13598161584,
|
||||||
|
0.2330223756901088,
|
||||||
|
-99484.30868025024,
|
||||||
|
0.23540556157200768,
|
||||||
|
-99484.30933223445,
|
||||||
|
0.23540556198958848,
|
||||||
|
-95711.12399082902,
|
||||||
|
0.23302236813021637,
|
||||||
|
-874021.6128809263,
|
||||||
|
1.2105342428506563,
|
||||||
|
-874021.6127639221,
|
||||||
|
1.2105342420477019,
|
||||||
|
-4699.544021984157,
|
||||||
|
0.006579168843426967,
|
||||||
|
-4720.142085434138,
|
||||||
|
0.006592090149576305,
|
||||||
|
-4720.142089865395,
|
||||||
|
0.006592090152448902,
|
||||||
|
-4699.544238887633,
|
||||||
|
0.006579168980161733,
|
||||||
|
-720.548977698558,
|
||||||
|
-720.2062838344375,
|
||||||
|
0.000998791691638376,
|
||||||
|
0.00099856697258834,
|
||||||
|
-722.1637803310383,
|
||||||
|
-722.0477500247466,
|
||||||
|
0.0010005181981378461,
|
||||||
|
0.0010004330928084816,
|
||||||
|
-8639.330806039252,
|
||||||
|
0.012679745952732602,
|
||||||
|
-8639.330537692149,
|
||||||
|
0.012679745783851644,
|
||||||
|
-8909.106011748408,
|
||||||
|
0.012849685563490313,
|
||||||
|
1389.1739707221775,
|
||||||
|
0.006354956657485442,
|
||||||
|
-722.1637801799975,
|
||||||
|
-722.0477531282031,
|
||||||
|
0.001000518198664749,
|
||||||
|
0.0010004330953830574,
|
||||||
|
-720.5489778046637,
|
||||||
|
-720.2062839511643,
|
||||||
|
0.0009987916917054815,
|
||||||
|
0.0009985669726623582,
|
||||||
|
-8909.106148651528,
|
||||||
|
0.012849685649995602,
|
||||||
|
-2357.5431522121776,
|
||||||
|
0.00326741144588273,
|
||||||
|
-2355.7331452897465,
|
||||||
|
0.0032646046108505246,
|
||||||
|
-2355.733147442795,
|
||||||
|
0.0032646046116421414,
|
||||||
|
-2357.543151890905,
|
||||||
|
0.0032674114436482805
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.7,
|
||||||
|
"values": [
|
||||||
|
-860379.8819972485,
|
||||||
|
1.1985586239832504,
|
||||||
|
-860379.8822663656,
|
||||||
|
1.1985586241379014,
|
||||||
|
-873989.7214316746,
|
||||||
|
1.210316350104016,
|
||||||
|
-873989.7215632556,
|
||||||
|
1.2103163509793102,
|
||||||
|
-2.1975173149257897e-06,
|
||||||
|
2.02734183270263e-06,
|
||||||
|
1.7602360080939606e-06,
|
||||||
|
-2.245873911306262e-06,
|
||||||
|
2.0517263968615454e-06,
|
||||||
|
1.7357614512099663e-06,
|
||||||
|
-2.2355280816555024e-06,
|
||||||
|
2.051726429425243e-06,
|
||||||
|
1.7357614187243355e-06,
|
||||||
|
-2.1975464187562464e-06,
|
||||||
|
2.0273418547326992e-06,
|
||||||
|
1.7602359860195857e-06,
|
||||||
|
0.0,
|
||||||
|
2.013739831250115e-21,
|
||||||
|
4.909861220321753e-20,
|
||||||
|
0.0,
|
||||||
|
4.665200046136569e-20,
|
||||||
|
-1.9566383001493946e-21,
|
||||||
|
-96560.09354570496,
|
||||||
|
0.2335572995463288,
|
||||||
|
-100288.67701814357,
|
||||||
|
0.23591263994887818,
|
||||||
|
-100288.677678112,
|
||||||
|
0.23591264036701443,
|
||||||
|
-96560.0816929563,
|
||||||
|
0.23355729206770598,
|
||||||
|
-873947.8864856226,
|
||||||
|
1.2100313452817673,
|
||||||
|
-873947.8863858595,
|
||||||
|
1.2100313445985562,
|
||||||
|
-4706.906282326286,
|
||||||
|
0.006583785685946545,
|
||||||
|
-4721.89741006748,
|
||||||
|
0.006593168289865688,
|
||||||
|
-4721.897404439745,
|
||||||
|
0.006593168286323642,
|
||||||
|
-4706.906483656017,
|
||||||
|
0.006583785812787189,
|
||||||
|
-720.6545512340357,
|
||||||
|
-720.3217292925623,
|
||||||
|
0.0009985764249686698,
|
||||||
|
0.0009983591472543481,
|
||||||
|
-722.1508419312411,
|
||||||
|
-722.0421232665894,
|
||||||
|
0.0010001323660439989,
|
||||||
|
0.00100005352811943,
|
||||||
|
-8642.043554742524,
|
||||||
|
0.012681407602717975,
|
||||||
|
-8642.043293601184,
|
||||||
|
0.012681407438297841,
|
||||||
|
-8909.49862797875,
|
||||||
|
0.012849959429845414,
|
||||||
|
1389.0998959067165,
|
||||||
|
0.006354964303801297,
|
||||||
|
-722.1508452424541,
|
||||||
|
-722.0421258113258,
|
||||||
|
0.0010001323686673997,
|
||||||
|
0.001000053530255132,
|
||||||
|
-720.6545510297586,
|
||||||
|
-720.3217293326904,
|
||||||
|
0.0009985764248405691,
|
||||||
|
0.0009983591472800236,
|
||||||
|
-8909.498764806547,
|
||||||
|
0.012849959516004638,
|
||||||
|
-2357.35674156337,
|
||||||
|
0.0032660606424093387,
|
||||||
|
-2355.921025330427,
|
||||||
|
0.0032637130423187337,
|
||||||
|
-2355.921027270413,
|
||||||
|
0.0032637130430599385,
|
||||||
|
-2357.3567413654787,
|
||||||
|
0.003266060640560602
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 0.8,
|
||||||
|
"values": [
|
||||||
|
-860175.1606710927,
|
||||||
|
1.1970987817186032,
|
||||||
|
-860175.1609442824,
|
||||||
|
1.1970987819042118,
|
||||||
|
-873416.0554547055,
|
||||||
|
1.206445289457375,
|
||||||
|
-873416.0554726648,
|
||||||
|
1.2064452895529436,
|
||||||
|
-1.949198776856065e-06,
|
||||||
|
1.826519161772371e-06,
|
||||||
|
1.9528536810215616e-06,
|
||||||
|
-1.971406163647771e-06,
|
||||||
|
1.848554964674094e-06,
|
||||||
|
1.930697446050263e-06,
|
||||||
|
-1.9711186178028582e-06,
|
||||||
|
1.8485549941949607e-06,
|
||||||
|
1.930697416668372e-06,
|
||||||
|
-1.94919528439641e-06,
|
||||||
|
1.826519181824015e-06,
|
||||||
|
1.9528536610522474e-06,
|
||||||
|
8.892500282325972,
|
||||||
|
2.5187368473853223e-21,
|
||||||
|
4.909861220321753e-20,
|
||||||
|
-16.252500528926326,
|
||||||
|
4.576919129896975e-20,
|
||||||
|
-1.9530653259948938e-21,
|
||||||
|
-104471.75361732666,
|
||||||
|
0.23818832921650948,
|
||||||
|
-107803.92242364622,
|
||||||
|
0.24029497741554184,
|
||||||
|
-107803.92309836508,
|
||||||
|
0.2402949778374652,
|
||||||
|
-104471.7429655161,
|
||||||
|
0.2381883224928943,
|
||||||
|
-873404.5104492744,
|
||||||
|
1.2063684021036665,
|
||||||
|
-873404.5104388825,
|
||||||
|
1.2063684020307441,
|
||||||
|
-4704.300638717692,
|
||||||
|
0.006574703133691949,
|
||||||
|
-4693.326778314112,
|
||||||
|
0.006567696268767441,
|
||||||
|
-4693.326526389924,
|
||||||
|
0.006567696110012524,
|
||||||
|
-4704.3007263131885,
|
||||||
|
0.006574703188787359,
|
||||||
|
-721.1607141734798,
|
||||||
|
-720.9310979144485,
|
||||||
|
0.0009965662267659527,
|
||||||
|
0.0009964191642398892,
|
||||||
|
-721.9230383692676,
|
||||||
|
-721.8772183273541,
|
||||||
|
0.0009972429132872915,
|
||||||
|
0.0009972108290529252,
|
||||||
|
-8703.980749781746,
|
||||||
|
0.012705472199729761,
|
||||||
|
-8703.980555484635,
|
||||||
|
0.01270547207717158,
|
||||||
|
-8967.989302068207,
|
||||||
|
0.012872002894864527,
|
||||||
|
1377.5687495145785,
|
||||||
|
0.006346840211910472,
|
||||||
|
-721.9230326537768,
|
||||||
|
-721.8772199435517,
|
||||||
|
0.0009972429097436842,
|
||||||
|
0.0009972108301285444,
|
||||||
|
-721.1607123097651,
|
||||||
|
-720.9310970023907,
|
||||||
|
0.000996566225592321,
|
||||||
|
0.0009964191636655784,
|
||||||
|
-8967.989425383095,
|
||||||
|
0.0128720029723915,
|
||||||
|
-2356.03147928222,
|
||||||
|
0.0032562562535671563,
|
||||||
|
-2356.668143012874,
|
||||||
|
0.0032561870649935125,
|
||||||
|
-2356.668143725967,
|
||||||
|
0.0032561870653915977,
|
||||||
|
-2356.031477688963,
|
||||||
|
0.0032562562523787346
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 1.0,
|
||||||
|
"values": [
|
||||||
|
-821832.18723991,
|
||||||
|
1.0200651174775017,
|
||||||
|
-821832.18747001,
|
||||||
|
1.0200651176202795,
|
||||||
|
-867004.8037748901,
|
||||||
|
1.1678210257789237,
|
||||||
|
-867004.8037842558,
|
||||||
|
1.1678210258114112,
|
||||||
|
5.337506036671112,
|
||||||
|
1.4692397997585764,
|
||||||
|
0.1599133361094105,
|
||||||
|
5.337515379170655,
|
||||||
|
1.4692397472726986,
|
||||||
|
0.1599133103986336,
|
||||||
|
5.337515143153142,
|
||||||
|
1.4692397472727232,
|
||||||
|
0.15991331039860968,
|
||||||
|
5.337506972429692,
|
||||||
|
1.4692397997585922,
|
||||||
|
0.15991333610939415,
|
||||||
|
5.337478209825592,
|
||||||
|
1.4692396558157577,
|
||||||
|
0.1599111725256627,
|
||||||
|
-9.54931997607691,
|
||||||
|
-2.6696065452676345,
|
||||||
|
-0.2915209059087121,
|
||||||
|
-265725.0471201981,
|
||||||
|
0.37065108819994863,
|
||||||
|
-274733.0912934626,
|
||||||
|
0.38314931696882704,
|
||||||
|
-274733.09196309303,
|
||||||
|
0.38314931740574626,
|
||||||
|
-265725.0371165716,
|
||||||
|
0.3706510817652048,
|
||||||
|
-865080.8367860075,
|
||||||
|
1.1575072978479832,
|
||||||
|
-865080.836781886,
|
||||||
|
1.157507297823738,
|
||||||
|
-3796.0300072134555,
|
||||||
|
0.004795940055001584,
|
||||||
|
-3536.527034352294,
|
||||||
|
0.004541242546837507,
|
||||||
|
-3536.5270264260203,
|
||||||
|
0.004541242541783211,
|
||||||
|
-3796.030006397544,
|
||||||
|
0.004795940054530253,
|
||||||
|
-669.6911044196434,
|
||||||
|
-669.5192067053738,
|
||||||
|
0.000896344956139504,
|
||||||
|
0.0008958075886883069,
|
||||||
|
-706.3131229180824,
|
||||||
|
-705.7453980192186,
|
||||||
|
0.0009508631922671181,
|
||||||
|
0.0009500270072581424,
|
||||||
|
-7576.544518407595,
|
||||||
|
0.009496349448619141,
|
||||||
|
-7576.544516641329,
|
||||||
|
0.009496349447543061,
|
||||||
|
-8495.442747354022,
|
||||||
|
0.010545461510647114,
|
||||||
|
-396.7407438874708,
|
||||||
|
0.004826437204332604,
|
||||||
|
-706.3131229284975,
|
||||||
|
-705.7453980286242,
|
||||||
|
0.0009508631922926857,
|
||||||
|
0.0009500270072830445,
|
||||||
|
-669.6911041651043,
|
||||||
|
-669.5192060345452,
|
||||||
|
0.0008963449559782043,
|
||||||
|
0.0008958075882644087,
|
||||||
|
-8495.442745022583,
|
||||||
|
0.010545461509227754,
|
||||||
|
-2334.4069259408425,
|
||||||
|
0.003123729270270666,
|
||||||
|
-2231.2112738065657,
|
||||||
|
0.002986126319734133,
|
||||||
|
-2231.211273855305,
|
||||||
|
0.0029861263197482296,
|
||||||
|
-2334.4069257629353,
|
||||||
|
0.0031237292700972397
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 2.0,
|
||||||
|
"values": [
|
||||||
|
-772286.4682624673,
|
||||||
|
0.9179360053806332,
|
||||||
|
-772286.4692545742,
|
||||||
|
0.9179360060143595,
|
||||||
|
-803031.5764482999,
|
||||||
|
0.9390697516259071,
|
||||||
|
-803031.5764679932,
|
||||||
|
0.9390697516680178,
|
||||||
|
-5.5966665968298915e-09,
|
||||||
|
6.713197714589101e-08,
|
||||||
|
0.3700023585738787,
|
||||||
|
-4.6964269131422045e-08,
|
||||||
|
8.296314048540649e-08,
|
||||||
|
0.3700023428086111,
|
||||||
|
-2.4841283448040484e-08,
|
||||||
|
8.29631490450475e-08,
|
||||||
|
0.37000234280860256,
|
||||||
|
4.3330946937203405e-08,
|
||||||
|
6.713198290867542e-08,
|
||||||
|
0.3700023585738729,
|
||||||
|
0.0,
|
||||||
|
-1.1654046974175209e-19,
|
||||||
|
0.37,
|
||||||
|
0.0,
|
||||||
|
-3.1507290824741586e-13,
|
||||||
|
-0.72,
|
||||||
|
-437317.9315829484,
|
||||||
|
0.6466111001653223,
|
||||||
|
-453928.6983570724,
|
||||||
|
0.6571847803274807,
|
||||||
|
-453928.69829577766,
|
||||||
|
0.6571847802863814,
|
||||||
|
-437317.92241094704,
|
||||||
|
0.6466110943182897,
|
||||||
|
-802960.6941217952,
|
||||||
|
0.9388828023997754,
|
||||||
|
-802960.694111656,
|
||||||
|
0.938882802373437,
|
||||||
|
-4284.7599403173035,
|
||||||
|
0.005077450257846326,
|
||||||
|
-4343.976212113444,
|
||||||
|
0.005115234066714636,
|
||||||
|
-4343.976212068701,
|
||||||
|
0.0051152340666703175,
|
||||||
|
-4284.7599132929745,
|
||||||
|
0.005077450240619749,
|
||||||
|
-662.1434159057197,
|
||||||
|
-661.7970678665274,
|
||||||
|
0.0007748418062540021,
|
||||||
|
0.0007746177710019782,
|
||||||
|
-663.5584177841083,
|
||||||
|
-663.4278440347166,
|
||||||
|
0.000776034735673773,
|
||||||
|
0.0007759468226959079,
|
||||||
|
-8120.656733496484,
|
||||||
|
0.009869069686396056,
|
||||||
|
-8120.656590103802,
|
||||||
|
0.009869069595030996,
|
||||||
|
-8328.371203371178,
|
||||||
|
0.010001111074316178,
|
||||||
|
-1647.6116574692712,
|
||||||
|
0.005744784430325623,
|
||||||
|
-663.5584178697704,
|
||||||
|
-663.4278441405601,
|
||||||
|
0.0007760347357471679,
|
||||||
|
0.000775946822781371,
|
||||||
|
-662.1434159537747,
|
||||||
|
-661.7970678998525,
|
||||||
|
0.0007748418062849091,
|
||||||
|
0.0007746177710225603,
|
||||||
|
-8328.371132243179,
|
||||||
|
0.010001111028980096,
|
||||||
|
-2168.153541946679,
|
||||||
|
0.002535378014133708,
|
||||||
|
-2164.6176191131335,
|
||||||
|
0.002532440207666662,
|
||||||
|
-2164.6176190758297,
|
||||||
|
0.002532440207628468,
|
||||||
|
-2168.153486402468,
|
||||||
|
0.0025353779787030337
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 2.05,
|
||||||
|
"values": [
|
||||||
|
-772640.2579114933,
|
||||||
|
0.9189711020154747,
|
||||||
|
-772640.2589106868,
|
||||||
|
0.9189711026533357,
|
||||||
|
-802668.8163858769,
|
||||||
|
0.9381125189656889,
|
||||||
|
-802668.8163913072,
|
||||||
|
0.9381125189701648,
|
||||||
|
-1.1839671060442924e-07,
|
||||||
|
6.848947280509e-08,
|
||||||
|
0.37000236198352005,
|
||||||
|
-9.816722013056278e-08,
|
||||||
|
8.350267455159574e-08,
|
||||||
|
0.3700023469893441,
|
||||||
|
-9.857350960373879e-08,
|
||||||
|
8.350268244045684e-08,
|
||||||
|
0.3700023469893362,
|
||||||
|
-9.438255801796913e-08,
|
||||||
|
6.84894782408154e-08,
|
||||||
|
0.3700023619835146,
|
||||||
|
0.0,
|
||||||
|
-1.1644108142482222e-19,
|
||||||
|
0.37,
|
||||||
|
0.0,
|
||||||
|
-3.150728667970711e-13,
|
||||||
|
-0.72,
|
||||||
|
-436877.0913448419,
|
||||||
|
0.6470168220031571,
|
||||||
|
-453182.789784899,
|
||||||
|
0.6574025955544724,
|
||||||
|
-453182.78972087207,
|
||||||
|
0.6574025955125712,
|
||||||
|
-436877.08234619617,
|
||||||
|
0.6470168162690852,
|
||||||
|
-802668.9179584626,
|
||||||
|
0.9381130502939634,
|
||||||
|
-802668.9179569854,
|
||||||
|
0.93811305029142,
|
||||||
|
-4285.669856693608,
|
||||||
|
0.0050823610773067076,
|
||||||
|
-4354.119008990314,
|
||||||
|
0.005125983105252238,
|
||||||
|
-4354.11901311425,
|
||||||
|
0.005125983107881825,
|
||||||
|
-4285.669816785954,
|
||||||
|
0.00508236105187094,
|
||||||
|
-662.3977781264183,
|
||||||
|
-662.0512100662392,
|
||||||
|
0.0007748078072798002,
|
||||||
|
0.0007745870872944216,
|
||||||
|
-663.4643136874881,
|
||||||
|
-663.3368456649802,
|
||||||
|
0.0007754873920209047,
|
||||||
|
0.0007754062014915902,
|
||||||
|
-8144.606717144718,
|
||||||
|
0.009892956807728209,
|
||||||
|
-8144.606576808627,
|
||||||
|
0.009892956718340342,
|
||||||
|
-8356.938599998502,
|
||||||
|
0.010028108806575306,
|
||||||
|
-1651.8254437402938,
|
||||||
|
0.005756202827816742,
|
||||||
|
-663.4643140644157,
|
||||||
|
-663.336846204431,
|
||||||
|
0.0007754873922663931,
|
||||||
|
0.000775406201901327,
|
||||||
|
-662.3977787097264,
|
||||||
|
-662.0512095396308,
|
||||||
|
0.0007748078076617882,
|
||||||
|
0.0007745870869169965,
|
||||||
|
-8356.938530080884,
|
||||||
|
0.010028108762001683,
|
||||||
|
-2167.3598235897343,
|
||||||
|
0.002533287559515925,
|
||||||
|
-2164.9943210453084,
|
||||||
|
0.002531780415394501,
|
||||||
|
-2164.9943209833646,
|
||||||
|
0.002531780415326603,
|
||||||
|
-2167.3597687183774,
|
||||||
|
0.0025332875249184767
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requestedTime": 2.1,
|
||||||
|
"values": [
|
||||||
|
-772729.849215003,
|
||||||
|
0.919232833810773,
|
||||||
|
-772729.8502213629,
|
||||||
|
0.9192328344649761,
|
||||||
|
-802748.5417139007,
|
||||||
|
0.9383229687007891,
|
||||||
|
-802748.5416937041,
|
||||||
|
0.938322968645941,
|
||||||
|
-1.5475961845368147e-07,
|
||||||
|
6.633051283469949e-08,
|
||||||
|
0.3700023653554917,
|
||||||
|
-1.6945006791502238e-07,
|
||||||
|
8.0606090679709e-08,
|
||||||
|
0.3700023510933796,
|
||||||
|
-1.6974110621958972e-07,
|
||||||
|
8.060609824063203e-08,
|
||||||
|
0.3700023510933721,
|
||||||
|
-1.5545636415481566e-07,
|
||||||
|
6.633051807899984e-08,
|
||||||
|
0.37000236535548653,
|
||||||
|
0.0,
|
||||||
|
-1.164558438137342e-19,
|
||||||
|
0.37,
|
||||||
|
0.0,
|
||||||
|
-3.1507286064810157e-13,
|
||||||
|
-0.72,
|
||||||
|
-436285.01209659013,
|
||||||
|
0.646815227151306,
|
||||||
|
-452333.92653835827,
|
||||||
|
0.6570381274463638,
|
||||||
|
-452333.9264734677,
|
||||||
|
0.6570381273931875,
|
||||||
|
-436285.00323808845,
|
||||||
|
0.6468152214977394,
|
||||||
|
-802747.7609731702,
|
||||||
|
0.9383213576466783,
|
||||||
|
-802747.7609716613,
|
||||||
|
0.9383213576459569,
|
||||||
|
-4169.822958852925,
|
||||||
|
0.005009690287404794,
|
||||||
|
-4279.837336800422,
|
||||||
|
0.005079777604819243,
|
||||||
|
-4279.83737473691,
|
||||||
|
0.0050797776289221675,
|
||||||
|
-4169.822929680966,
|
||||||
|
0.005009690268749923,
|
||||||
|
-662.0363168630721,
|
||||||
|
-658.7502160682232,
|
||||||
|
0.0007747218486607169,
|
||||||
|
0.0007726291344808584,
|
||||||
|
-662.5313787250212,
|
||||||
|
-655.702207731343,
|
||||||
|
0.0007750276677438138,
|
||||||
|
0.0007706784944489166,
|
||||||
|
-8148.173203124546,
|
||||||
|
0.00989744668242247,
|
||||||
|
-8148.173078272971,
|
||||||
|
0.009897446602767727,
|
||||||
|
-8360.714796856231,
|
||||||
|
0.010032755342377334,
|
||||||
|
-1652.8900562718827,
|
||||||
|
0.005759128268286419,
|
||||||
|
-662.5313698561031,
|
||||||
|
-655.7022069331298,
|
||||||
|
0.000775027662068701,
|
||||||
|
0.0007706784939136677,
|
||||||
|
-662.0363583491554,
|
||||||
|
-658.7501715937773,
|
||||||
|
0.0007747218750818736,
|
||||||
|
0.0007726291061561864,
|
||||||
|
-8360.714717131163,
|
||||||
|
0.010032755291451692,
|
||||||
|
-2167.569222453132,
|
||||||
|
0.002533854003606723,
|
||||||
|
-2165.094351906718,
|
||||||
|
0.0025322965276950117,
|
||||||
|
-2165.0943434975566,
|
||||||
|
0.0025322965223399637,
|
||||||
|
-2167.569167946825,
|
||||||
|
0.002533853968955365
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputContract": {
|
||||||
|
"sha256": "5ed1efeba81d0f0a47bd1e0513f5503fc507cac8ae8c08f96602f10c1266eb86"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"schemaVersion": 1,
|
"schemaVersion": 1,
|
||||||
"id": "test_mql_full_branches-historical-v1",
|
"id": "test_mql_full_branches-historical-v1",
|
||||||
"description": "Historical slow-region and 2.05 s regression target for the generic solver.",
|
"description": "Historical slow-region and 2.05 s production regression target with three locked-environment repeats and approved state goldens.",
|
||||||
"source": {
|
"source": {
|
||||||
"path": "tests/data/test_mql-full-branches-01-04.xml",
|
"path": "tests/data/test_mql-full-branches-01-04.xml",
|
||||||
"sha256": "2fb95e65f5de0c85a6a17802aef74ea004087323fd00fd8d01acf0184ff71d48",
|
"sha256": "2fb95e65f5de0c85a6a17802aef74ea004087323fd00fd8d01acf0184ff71d48",
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
0.0,
|
0.0,
|
||||||
0.04,
|
0.04,
|
||||||
0.69,
|
0.69,
|
||||||
0.70,
|
0.7,
|
||||||
0.8,
|
0.8,
|
||||||
0.81
|
0.81
|
||||||
],
|
],
|
||||||
@@ -68,7 +68,13 @@
|
|||||||
0.04,
|
0.04,
|
||||||
0.8
|
0.8
|
||||||
],
|
],
|
||||||
"expectedMechanicalTransitionTimes": []
|
"expectedMechanicalTransitionTimes": [],
|
||||||
|
"goldens": {
|
||||||
|
"production": {
|
||||||
|
"path": "tests/baselines/simulation/test_mql_full_branches/goldens/production-0.81s-v1.json",
|
||||||
|
"sha256": "72c4ccf995c7904f80598934bf59fe88cff2f9b85e003396befc4ae3f37a4e53"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"2.10s": {
|
"2.10s": {
|
||||||
"stopTime": 2.1,
|
"stopTime": 2.1,
|
||||||
@@ -78,7 +84,7 @@
|
|||||||
0.0,
|
0.0,
|
||||||
0.04,
|
0.04,
|
||||||
0.69,
|
0.69,
|
||||||
0.70,
|
0.7,
|
||||||
0.8,
|
0.8,
|
||||||
1.0,
|
1.0,
|
||||||
2.0,
|
2.0,
|
||||||
@@ -88,19 +94,35 @@
|
|||||||
"expectedSignalEventTimes": [
|
"expectedSignalEventTimes": [
|
||||||
0.04,
|
0.04,
|
||||||
0.8
|
0.8
|
||||||
]
|
],
|
||||||
|
"expectedMechanicalTransitionTimes": [
|
||||||
|
1.1199696877773673,
|
||||||
|
1.1331667954945566,
|
||||||
|
1.2023983086085228
|
||||||
|
],
|
||||||
|
"goldens": {
|
||||||
|
"production": {
|
||||||
|
"path": "tests/baselines/simulation/test_mql_full_branches/goldens/production-2.10s-v1.json",
|
||||||
|
"sha256": "5fced8349404c9dd1f6284b76af3f1e24ed0933df76fb4b5d2a419b719f64d4c"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"correctness": {
|
"correctness": {
|
||||||
"status": "partial",
|
"status": "complete",
|
||||||
"maximumScaledResidual": 1e-7,
|
"maximumScaledResidual": 1e-07,
|
||||||
"requireFiniteSeries": true,
|
"requireFiniteSeries": true,
|
||||||
"requireStrictlyIncreasingTimes": true,
|
"requireStrictlyIncreasingTimes": true,
|
||||||
"stateRelativeTolerance": 0.0002,
|
"stateRelativeTolerance": 0.0002,
|
||||||
"eventTimeAbsoluteToleranceSeconds": 0.00002,
|
"eventTimeAbsoluteToleranceSeconds": 2e-05,
|
||||||
"signalEventTimeAbsoluteToleranceSeconds": 1e-12,
|
"signalEventTimeAbsoluteToleranceSeconds": 1e-12,
|
||||||
"mechanicalTransitionTimesAvailable": true,
|
"mechanicalTransitionTimesAvailable": true,
|
||||||
"note": "Historical checkpoints are recorded; approved physical-state-v2 golden values remain pending."
|
"note": "OPT-00 production 0.81/2.10 s state, event, output-shape, finite-series, residual, audit, and no-fallback contracts are approved and replayed exactly across three locked-environment runs.",
|
||||||
|
"physicalProjectionCategories": [
|
||||||
|
"state"
|
||||||
|
],
|
||||||
|
"stateAbsoluteTolerance": 1e-09,
|
||||||
|
"checkpointTimeAbsoluteToleranceSeconds": 1e-12
|
||||||
},
|
},
|
||||||
"execution": {
|
"execution": {
|
||||||
"causalExecutorV2Default": true,
|
"causalExecutorV2Default": true,
|
||||||
@@ -116,5 +138,33 @@
|
|||||||
"deferAfterFailureOrTimeout": true,
|
"deferAfterFailureOrTimeout": true,
|
||||||
"deferWhenPredictedWallExceedsSoftTimeout": true,
|
"deferWhenPredictedWallExceedsSoftTimeout": true,
|
||||||
"longTestEnvironmentVariable": "RUN_TEST_MQL_FULL_BRANCHES_LONG_REGRESSION"
|
"longTestEnvironmentVariable": "RUN_TEST_MQL_FULL_BRANCHES_LONG_REGRESSION"
|
||||||
|
},
|
||||||
|
"acceptanceEvidence": {
|
||||||
|
"status": "approved",
|
||||||
|
"lane": "production",
|
||||||
|
"repeatCount": 3,
|
||||||
|
"physicalValuesIdenticalAcrossRepeats": true,
|
||||||
|
"reports": [
|
||||||
|
{
|
||||||
|
"path": "tests/baselines/simulation/test_mql_full_branches/runs/2026-08-18-opt00-historical-repeat-1.json",
|
||||||
|
"sha256": "4659ae850eef4f1541b3172f783b01a1859744a3f0a50030e094c2c25f93e195",
|
||||||
|
"bytes": 314699
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "tests/baselines/simulation/test_mql_full_branches/runs/2026-08-18-opt00-historical-repeat-2.json",
|
||||||
|
"sha256": "99892d0aca554baca7f72ae00412337f6815f62cb7a4349dfe3006db66b4549f",
|
||||||
|
"bytes": 315044
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "tests/baselines/simulation/test_mql_full_branches/runs/2026-08-18-opt00-historical-repeat-3.json",
|
||||||
|
"sha256": "569bf7e576bd56f956f2125921680a570ee16f445f5d3d7cbff16a4f4cc12f85",
|
||||||
|
"bytes": 315606
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"workerWallSeconds2p10": {
|
||||||
|
"minimum": 113.49742291588336,
|
||||||
|
"median": 114.07500359974802,
|
||||||
|
"maximum": 115.86820452474058
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+5925
File diff suppressed because it is too large.
Load diff
+5929
File diff suppressed because it is too large.
Load diff
+5934
File diff suppressed because it is too large.
Load diff
@@ -10196,9 +10196,9 @@
|
|||||||
],
|
],
|
||||||
"simulation": {
|
"simulation": {
|
||||||
"t_start": 0,
|
"t_start": 0,
|
||||||
"t_stop": 5,
|
"t_stop": 10,
|
||||||
"step": 0.005,
|
"step": 0.01,
|
||||||
"max_step": 0.005,
|
"max_step": 0.001,
|
||||||
"method": "BDF"
|
"method": "BDF"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<System name="test-mql-8" schemaVersion="3" unitSystem="SI">
|
<System name="test-mql-8" schemaVersion="3" unitSystem="SI">
|
||||||
<Simulation tStart="0" tStop="5" sampleStep="0.005" maxStep="0.005" method="BDF"/>
|
<Simulation tStart="0" tStop="10" sampleStep="0.01" maxStep="0.001" method="BDF"/>
|
||||||
<Components>
|
<Components>
|
||||||
<Component id="pn_gas_data" type="amesim_helium_medium" modelVersion="0.1.0">
|
<Component id="pn_gas_data" type="amesim_helium_medium" modelVersion="0.1.0">
|
||||||
<Parameter name="gi" value="1"/>
|
<Parameter name="gi" value="1"/>
|
||||||
|
|||||||
@@ -26,6 +26,13 @@ from app.simulation.benchmark_regression import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
PHYSICAL_STATE_V21_REPORT = (
|
||||||
|
DEFAULT_MANIFEST_PATH.parent
|
||||||
|
/ "runs"
|
||||||
|
/ "2026-08-18-production-physical-state-v2.1-0.2.json"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _completed_result(request: RegressionCaseRequest, *, wall_seconds: float = 0.01):
|
def _completed_result(request: RegressionCaseRequest, *, wall_seconds: float = 0.01):
|
||||||
signal_times = (
|
signal_times = (
|
||||||
[0.04, 0.8]
|
[0.04, 0.8]
|
||||||
@@ -125,16 +132,24 @@ class RegressionManifestTests(unittest.TestCase):
|
|||||||
self.assertTrue(manifest["source"]["xmlIsAuthoritative"])
|
self.assertTrue(manifest["source"]["xmlIsAuthoritative"])
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
manifest["source"]["sha256"],
|
manifest["source"]["sha256"],
|
||||||
"6eb2753a15af66fd8e91c169c4587e66b0ace2164c08c2cb23a67aab5fd09164",
|
"0a2d9331df9eb5974daec25a61c1238ba32b1742d933ffc8b16ce316c5627b0b",
|
||||||
)
|
)
|
||||||
self.assertEqual(Path(manifest["_sourcePath"]).name, "test-mql-8.xml")
|
self.assertEqual(Path(manifest["_sourcePath"]).name, "test-mql-8.xml")
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
manifest["source"]["companionProject"]["sha256"],
|
manifest["source"]["companionProject"]["sha256"],
|
||||||
"8d7a263691a9f09f39c92aba19ae1350911dc66b4904e98bae5f20592c5a3fcd",
|
"b44bf540ccd1c293fe2af2b9b9052b540abf83961ad955a0f6a4ab40fbe0bb18",
|
||||||
)
|
)
|
||||||
self.assertFalse(
|
self.assertFalse(
|
||||||
manifest["source"]["companionProject"]["executionInput"]
|
manifest["source"]["companionProject"]["executionInput"]
|
||||||
)
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
manifest["source"]["referenceArchive"]["role"],
|
||||||
|
"authoritativePhysicalBaseline",
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
Path(manifest["_referenceArchivePath"]).name,
|
||||||
|
"test_mql.ame",
|
||||||
|
)
|
||||||
self.assertEqual(manifest["historicalReports"][0]["status"], "historicalOnly")
|
self.assertEqual(manifest["historicalReports"][0]["status"], "historicalOnly")
|
||||||
self.assertFalse(
|
self.assertFalse(
|
||||||
manifest["historicalReports"][0]["compatibleWithCurrentSource"]
|
manifest["historicalReports"][0]["compatibleWithCurrentSource"]
|
||||||
@@ -146,6 +161,86 @@ class RegressionManifestTests(unittest.TestCase):
|
|||||||
self.assertFalse(
|
self.assertFalse(
|
||||||
manifest["historicalReports"][2]["compatibleWithCurrentSource"]
|
manifest["historicalReports"][2]["compatibleWithCurrentSource"]
|
||||||
)
|
)
|
||||||
|
physical_state_golden = manifest["_physicalStateV21Goldens"]["0.2s"][
|
||||||
|
"production"
|
||||||
|
]
|
||||||
|
self.assertEqual(physical_state_golden["approval"]["status"], "approved")
|
||||||
|
self.assertEqual(
|
||||||
|
physical_state_golden["_sha256"],
|
||||||
|
"6f0752afe8c1f7690599c2709a76d9a1342f99f726c6c8593321dc6267e175b2",
|
||||||
|
)
|
||||||
|
self.assertTrue(
|
||||||
|
physical_state_golden["amesimAlignmentAtGeneration"]["passed"]
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
manifest["correctness"]["physicalBaselineAuthority"], "amesim"
|
||||||
|
)
|
||||||
|
self.assertTrue(manifest["correctness"]["compareAmesimOnEveryRun"])
|
||||||
|
self.assertEqual(
|
||||||
|
manifest["correctness"]["pythonGoldenRole"],
|
||||||
|
"determinismDiagnosticOnly",
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
manifest["variants"]["0.2s"]["goldens"]["production"]["role"],
|
||||||
|
"pythonDeterminismRegression",
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
manifest["variants"]["0.2s"]["physicalStateV21Goldens"][
|
||||||
|
"production"
|
||||||
|
]["role"],
|
||||||
|
"amesimPhysicalBaseline",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_manifest_rejects_physical_state_v21_golden_hash_mismatch(self) -> None:
|
||||||
|
manifest = json.loads(DEFAULT_MANIFEST_PATH.read_text(encoding="utf-8"))
|
||||||
|
manifest["variants"]["0.2s"]["physicalStateV21Goldens"]["production"][
|
||||||
|
"sha256"
|
||||||
|
] = "0" * 64
|
||||||
|
with tempfile.TemporaryDirectory(
|
||||||
|
dir=DEFAULT_MANIFEST_PATH.parents[4], prefix=".v21-manifest-test-"
|
||||||
|
) as temporary_directory:
|
||||||
|
manifest_path = Path(temporary_directory) / "manifest.json"
|
||||||
|
manifest_path.write_text(json.dumps(manifest), encoding="utf-8")
|
||||||
|
with self.assertRaisesRegex(
|
||||||
|
RegressionManifestError,
|
||||||
|
"physical-state-v2.1 golden hash mismatch",
|
||||||
|
):
|
||||||
|
load_regression_manifest(manifest_path)
|
||||||
|
|
||||||
|
def test_manifest_rejects_amesim_archive_hash_mismatch(self) -> None:
|
||||||
|
manifest = json.loads(DEFAULT_MANIFEST_PATH.read_text(encoding="utf-8"))
|
||||||
|
manifest["source"]["referenceArchive"]["sha256"] = "0" * 64
|
||||||
|
with tempfile.TemporaryDirectory(
|
||||||
|
dir=DEFAULT_MANIFEST_PATH.parents[4], prefix=".amesim-manifest-test-"
|
||||||
|
) as temporary_directory:
|
||||||
|
manifest_path = Path(temporary_directory) / "manifest.json"
|
||||||
|
manifest_path.write_text(json.dumps(manifest), encoding="utf-8")
|
||||||
|
with self.assertRaisesRegex(
|
||||||
|
RegressionManifestError,
|
||||||
|
"AMESim reference archive hash mismatch",
|
||||||
|
):
|
||||||
|
load_regression_manifest(manifest_path)
|
||||||
|
|
||||||
|
def test_manifest_rejects_amesim_golden_provenance_mismatch(self) -> None:
|
||||||
|
loaded = load_regression_manifest(DEFAULT_MANIFEST_PATH)
|
||||||
|
golden = json.loads(
|
||||||
|
json.dumps(loaded["_physicalStateV21Goldens"]["0.2s"]["production"])
|
||||||
|
)
|
||||||
|
golden["provenance"]["amesim"]["archiveSha256"] = "0" * 64
|
||||||
|
manifest = json.loads(DEFAULT_MANIFEST_PATH.read_text(encoding="utf-8"))
|
||||||
|
with tempfile.TemporaryDirectory(
|
||||||
|
dir=DEFAULT_MANIFEST_PATH.parents[4], prefix=".amesim-provenance-test-"
|
||||||
|
) as temporary_directory:
|
||||||
|
manifest_path = Path(temporary_directory) / "manifest.json"
|
||||||
|
manifest_path.write_text(json.dumps(manifest), encoding="utf-8")
|
||||||
|
with patch(
|
||||||
|
"app.simulation.benchmark_regression.load_physical_state_v21_golden",
|
||||||
|
return_value=golden,
|
||||||
|
), self.assertRaisesRegex(
|
||||||
|
RegressionManifestError,
|
||||||
|
"AMESim baseline provenance",
|
||||||
|
):
|
||||||
|
load_regression_manifest(manifest_path)
|
||||||
|
|
||||||
def test_in_memory_derivative_does_not_change_authoritative_xml(self) -> None:
|
def test_in_memory_derivative_does_not_change_authoritative_xml(self) -> None:
|
||||||
manifest = load_regression_manifest(DEFAULT_MANIFEST_PATH)
|
manifest = load_regression_manifest(DEFAULT_MANIFEST_PATH)
|
||||||
@@ -159,9 +254,9 @@ class RegressionManifestTests(unittest.TestCase):
|
|||||||
max_step=0.005,
|
max_step=0.005,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(source_simulation_config(before)["tStop"], 5.0)
|
self.assertEqual(source_simulation_config(before)["tStop"], 10.0)
|
||||||
self.assertEqual(source_simulation_config(before)["sampleStep"], 0.005)
|
self.assertEqual(source_simulation_config(before)["sampleStep"], 0.01)
|
||||||
self.assertEqual(source_simulation_config(before)["maxStep"], 0.005)
|
self.assertEqual(source_simulation_config(before)["maxStep"], 0.001)
|
||||||
self.assertEqual(source_simulation_config(derived)["tStop"], 1.0)
|
self.assertEqual(source_simulation_config(derived)["tStop"], 1.0)
|
||||||
self.assertEqual(source_simulation_config(derived)["sampleStep"], 0.02)
|
self.assertEqual(source_simulation_config(derived)["sampleStep"], 0.02)
|
||||||
self.assertEqual(source_simulation_config(derived)["maxStep"], 0.005)
|
self.assertEqual(source_simulation_config(derived)["maxStep"], 0.005)
|
||||||
@@ -399,6 +494,145 @@ class BoundedChildProcessTests(unittest.TestCase):
|
|||||||
|
|
||||||
|
|
||||||
class ProgressiveSuiteTests(unittest.TestCase):
|
class ProgressiveSuiteTests(unittest.TestCase):
|
||||||
|
@staticmethod
|
||||||
|
def _physical_state_v21_result_executor():
|
||||||
|
source_report = json.loads(
|
||||||
|
PHYSICAL_STATE_V21_REPORT.read_text(encoding="utf-8")
|
||||||
|
)
|
||||||
|
results = {case["caseId"]: case for case in source_report["cases"]}
|
||||||
|
|
||||||
|
def execute(request: RegressionCaseRequest) -> dict[str, object]:
|
||||||
|
return json.loads(json.dumps(results[request.case_id]))
|
||||||
|
|
||||||
|
return execute
|
||||||
|
|
||||||
|
def test_production_report_replays_through_active_v21_acceptance(self) -> None:
|
||||||
|
report = run_regression_suite(
|
||||||
|
DEFAULT_MANIFEST_PATH,
|
||||||
|
lane="production",
|
||||||
|
case_ids=["0.2s"],
|
||||||
|
case_executor=self._physical_state_v21_result_executor(),
|
||||||
|
)
|
||||||
|
|
||||||
|
case = report["cases"][1]
|
||||||
|
evaluation = case["acceptance"]["physicalStateV21Golden"]
|
||||||
|
self.assertEqual(case["outcome"], "completed")
|
||||||
|
self.assertTrue(case["acceptance"]["passed"])
|
||||||
|
self.assertTrue(evaluation["configured"])
|
||||||
|
self.assertTrue(evaluation["evaluated"])
|
||||||
|
self.assertTrue(evaluation["passed"])
|
||||||
|
self.assertEqual(evaluation["baselineAuthority"], "amesim")
|
||||||
|
self.assertEqual(evaluation["metricCount"], 33)
|
||||||
|
self.assertEqual(evaluation["availableBaselineValueCount"], 27)
|
||||||
|
self.assertEqual(evaluation["unavailableBaselineValueCount"], 6)
|
||||||
|
self.assertEqual(evaluation["comparedValueCount"], 25)
|
||||||
|
self.assertEqual(evaluation["excludedValueCount"], 2)
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
evaluation["maxToleranceRatio"], 0.6967416724836332
|
||||||
|
)
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
evaluation["worstValue"]["relativeError"],
|
||||||
|
0.0013934852135053246,
|
||||||
|
)
|
||||||
|
self.assertTrue(
|
||||||
|
all(
|
||||||
|
"actual" in metric and "amesimBaseline" in metric
|
||||||
|
for metric in evaluation["metrics"]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.assertEqual(evaluation["issues"], [])
|
||||||
|
self.assertTrue(evaluation["amesimAlignmentAtGenerationPassed"])
|
||||||
|
regression = case["acceptance"]["regressionGolden"]
|
||||||
|
self.assertEqual(regression["role"], "determinismDiagnosticOnly")
|
||||||
|
self.assertFalse(regression["affectsPhysicalCorrectness"])
|
||||||
|
|
||||||
|
def test_v21_conservation_drift_fails_runner_acceptance(self) -> None:
|
||||||
|
execute_source = self._physical_state_v21_result_executor()
|
||||||
|
|
||||||
|
def drifted(request: RegressionCaseRequest) -> dict[str, object]:
|
||||||
|
result = execute_source(request)
|
||||||
|
if request.case_id == "0.2s":
|
||||||
|
result["worker"]["summary"]["physicalStateV21"]["checkpoints"][-1][
|
||||||
|
"values"
|
||||||
|
]["conservation.p4node2_8.massBalance"] = 2.0e-9
|
||||||
|
return result
|
||||||
|
|
||||||
|
report = run_regression_suite(
|
||||||
|
DEFAULT_MANIFEST_PATH,
|
||||||
|
lane="production",
|
||||||
|
case_ids=["0.2s"],
|
||||||
|
case_executor=drifted,
|
||||||
|
)
|
||||||
|
|
||||||
|
case = report["cases"][1]
|
||||||
|
evaluation = case["acceptance"]["physicalStateV21Golden"]
|
||||||
|
self.assertEqual(case["outcome"], "correctness_failed")
|
||||||
|
self.assertFalse(case["acceptance"]["passed"])
|
||||||
|
self.assertIn(
|
||||||
|
"physicalStateV21LocalInvariantMismatch",
|
||||||
|
case["acceptance"]["issues"],
|
||||||
|
)
|
||||||
|
self.assertFalse(evaluation["passed"])
|
||||||
|
self.assertEqual(
|
||||||
|
evaluation["localInvariants"]["worstValue"]["key"],
|
||||||
|
"conservation.p4node2_8.massBalance",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_python_state_drift_is_diagnostic_when_amesim_gate_passes(self) -> None:
|
||||||
|
execute_source = self._physical_state_v21_result_executor()
|
||||||
|
|
||||||
|
def drifted(request: RegressionCaseRequest) -> dict[str, object]:
|
||||||
|
result = execute_source(request)
|
||||||
|
if request.case_id == "0.2s":
|
||||||
|
values = result["worker"]["summary"]["physicalContract"][
|
||||||
|
"checkpoints"
|
||||||
|
][-1]["stateValues"]
|
||||||
|
first_key = next(iter(values))
|
||||||
|
values[first_key] += 1.0
|
||||||
|
return result
|
||||||
|
|
||||||
|
report = run_regression_suite(
|
||||||
|
DEFAULT_MANIFEST_PATH,
|
||||||
|
lane="production",
|
||||||
|
case_ids=["0.2s"],
|
||||||
|
case_executor=drifted,
|
||||||
|
)
|
||||||
|
|
||||||
|
case = report["cases"][1]
|
||||||
|
diagnostic = case["acceptance"]["regressionGolden"]
|
||||||
|
self.assertEqual(case["outcome"], "completed")
|
||||||
|
self.assertTrue(case["acceptance"]["passed"])
|
||||||
|
self.assertFalse(diagnostic["passed"])
|
||||||
|
self.assertIn("stateCheckpointGoldenValueMismatch", diagnostic["issues"])
|
||||||
|
self.assertEqual(diagnostic["acceptanceIssues"], [])
|
||||||
|
self.assertTrue(case["acceptance"]["physicalStateV21Golden"]["passed"])
|
||||||
|
|
||||||
|
def test_amesim_baseline_drift_is_the_physical_acceptance_gate(self) -> None:
|
||||||
|
execute_source = self._physical_state_v21_result_executor()
|
||||||
|
|
||||||
|
def drifted(request: RegressionCaseRequest) -> dict[str, object]:
|
||||||
|
result = execute_source(request)
|
||||||
|
if request.case_id == "0.2s":
|
||||||
|
result["worker"]["summary"]["physicalStateV21"]["checkpoints"][-1][
|
||||||
|
"values"
|
||||||
|
]["pressure.pnch012_8.absolute"] += 1.0e6
|
||||||
|
return result
|
||||||
|
|
||||||
|
report = run_regression_suite(
|
||||||
|
DEFAULT_MANIFEST_PATH,
|
||||||
|
lane="production",
|
||||||
|
case_ids=["0.2s"],
|
||||||
|
case_executor=drifted,
|
||||||
|
)
|
||||||
|
|
||||||
|
case = report["cases"][1]
|
||||||
|
evaluation = case["acceptance"]["physicalStateV21Golden"]
|
||||||
|
self.assertEqual(case["outcome"], "correctness_failed")
|
||||||
|
self.assertFalse(case["acceptance"]["passed"])
|
||||||
|
self.assertIn("amesimReferenceToleranceMismatch", case["acceptance"]["issues"])
|
||||||
|
self.assertFalse(evaluation["passed"])
|
||||||
|
self.assertEqual(evaluation["worstValue"]["amesimBaseline"], 3625053.2009413484)
|
||||||
|
|
||||||
def test_requesting_late_case_also_runs_every_predecessor(self) -> None:
|
def test_requesting_late_case_also_runs_every_predecessor(self) -> None:
|
||||||
calls: list[str] = []
|
calls: list[str] = []
|
||||||
|
|
||||||
@@ -585,7 +819,7 @@ class ProgressiveSuiteTests(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
seen,
|
seen,
|
||||||
[("solver-only", 0.02, 0.05), ("production", 0.005, 0.005)],
|
[("solver-only", 0.02, 0.05), ("production", 0.01, 0.001)],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from importlib import metadata
|
from importlib import metadata
|
||||||
import os
|
import os
|
||||||
|
import platform
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
@@ -13,6 +14,11 @@ REQUIREMENTS_PATH = REPOSITORY_ROOT / "requirements.txt"
|
|||||||
CONSTRAINTS_PATH = (
|
CONSTRAINTS_PATH = (
|
||||||
REPOSITORY_ROOT / "constraints" / "python312-direct.txt"
|
REPOSITORY_ROOT / "constraints" / "python312-direct.txt"
|
||||||
)
|
)
|
||||||
|
RELEASE_LOCK_PATH = (
|
||||||
|
REPOSITORY_ROOT
|
||||||
|
/ "constraints"
|
||||||
|
/ "python312-linux-x86_64.lock"
|
||||||
|
)
|
||||||
PYTHON_VERSION_PATH = REPOSITORY_ROOT / ".python-version"
|
PYTHON_VERSION_PATH = REPOSITORY_ROOT / ".python-version"
|
||||||
VERIFY_ENVIRONMENT_VARIABLE = "SYSTEM_SIMULATION_VERIFY_LOCKED_ENV"
|
VERIFY_ENVIRONMENT_VARIABLE = "SYSTEM_SIMULATION_VERIFY_LOCKED_ENV"
|
||||||
|
|
||||||
@@ -24,6 +30,37 @@ REFERENCE_DIRECT_VERSIONS = {
|
|||||||
"scipy": "1.18.0",
|
"scipy": "1.18.0",
|
||||||
"uvicorn": "0.52.3",
|
"uvicorn": "0.52.3",
|
||||||
}
|
}
|
||||||
|
REFERENCE_LOCKED_VERSIONS = {
|
||||||
|
"annotated-doc": "0.0.5",
|
||||||
|
"annotated-types": "0.8.0",
|
||||||
|
"anyio": "4.14.2",
|
||||||
|
"click": "8.4.2",
|
||||||
|
"fastapi": "0.141.1",
|
||||||
|
"h11": "0.16.0",
|
||||||
|
"httptools": "0.8.0",
|
||||||
|
"idna": "3.18",
|
||||||
|
"lxml": "6.1.1",
|
||||||
|
"numpy": "2.5.2",
|
||||||
|
"pydantic": "2.13.4",
|
||||||
|
"pydantic-core": "2.46.4",
|
||||||
|
"python-dotenv": "1.2.3",
|
||||||
|
"pyyaml": "6.0.3",
|
||||||
|
"scipy": "1.18.0",
|
||||||
|
"starlette": "1.6.0",
|
||||||
|
"typing-extensions": "4.16.0",
|
||||||
|
"typing-inspection": "0.4.4",
|
||||||
|
"uvicorn": "0.52.3",
|
||||||
|
"uvloop": "0.22.1",
|
||||||
|
"watchfiles": "1.2.0",
|
||||||
|
"websockets": "17.0.1",
|
||||||
|
}
|
||||||
|
|
||||||
|
LOCK_REQUIREMENT_PATTERN = re.compile(
|
||||||
|
r"(?P<name>[A-Za-z0-9_.-]+)"
|
||||||
|
r"(?:\[(?P<extras>[A-Za-z0-9_,.-]+)\])?"
|
||||||
|
r"==(?P<version>[^\s;]+)\s+"
|
||||||
|
r"--hash=sha256:(?P<digest>[0-9a-f]{64})\Z"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _active_lines(path: Path) -> tuple[str, ...]:
|
def _active_lines(path: Path) -> tuple[str, ...]:
|
||||||
@@ -57,6 +94,33 @@ def _constraint_versions() -> dict[str, str]:
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _release_lock_options() -> tuple[str, ...]:
|
||||||
|
return tuple(
|
||||||
|
line
|
||||||
|
for line in _active_lines(RELEASE_LOCK_PATH)
|
||||||
|
if line.startswith("--")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _release_lock_entries() -> dict[str, tuple[str, str, str | None]]:
|
||||||
|
result: dict[str, tuple[str, str, str | None]] = {}
|
||||||
|
for line in _active_lines(RELEASE_LOCK_PATH):
|
||||||
|
if line.startswith("--"):
|
||||||
|
continue
|
||||||
|
match = LOCK_REQUIREMENT_PATTERN.fullmatch(line)
|
||||||
|
if match is None:
|
||||||
|
raise AssertionError(f"Invalid release-lock entry: {line!r}")
|
||||||
|
normalized = _normalized_name(match.group("name"))
|
||||||
|
if normalized in result:
|
||||||
|
raise AssertionError(f"Duplicate release-lock entry: {normalized}")
|
||||||
|
result[normalized] = (
|
||||||
|
match.group("version"),
|
||||||
|
match.group("digest"),
|
||||||
|
match.group("extras"),
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
class DependencyConstraintContractTests(unittest.TestCase):
|
class DependencyConstraintContractTests(unittest.TestCase):
|
||||||
def test_python_reference_version_is_explicit(self) -> None:
|
def test_python_reference_version_is_explicit(self) -> None:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
@@ -87,18 +151,49 @@ class DependencyConstraintContractTests(unittest.TestCase):
|
|||||||
}.isdisjoint(_constraint_versions())
|
}.isdisjoint(_constraint_versions())
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_linux_release_lock_pins_and_hashes_complete_environment(
|
||||||
|
self,
|
||||||
|
) -> None:
|
||||||
|
self.assertEqual(
|
||||||
|
_release_lock_options(),
|
||||||
|
("--only-binary=:all:", "--require-hashes"),
|
||||||
|
)
|
||||||
|
entries = _release_lock_entries()
|
||||||
|
self.assertEqual(
|
||||||
|
{name: entry[0] for name, entry in entries.items()},
|
||||||
|
REFERENCE_LOCKED_VERSIONS,
|
||||||
|
)
|
||||||
|
self.assertTrue(all(len(entry[1]) == 64 for entry in entries.values()))
|
||||||
|
self.assertEqual(entries["uvicorn"][2], "standard")
|
||||||
|
self.assertTrue(
|
||||||
|
all(
|
||||||
|
entry[2] is None
|
||||||
|
for name, entry in entries.items()
|
||||||
|
if name != "uvicorn"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
{
|
||||||
|
name: REFERENCE_LOCKED_VERSIONS[name]
|
||||||
|
for name in REFERENCE_DIRECT_VERSIONS
|
||||||
|
},
|
||||||
|
REFERENCE_DIRECT_VERSIONS,
|
||||||
|
)
|
||||||
|
|
||||||
@unittest.skipUnless(
|
@unittest.skipUnless(
|
||||||
os.getenv(VERIFY_ENVIRONMENT_VARIABLE, "").strip().lower()
|
os.getenv(VERIFY_ENVIRONMENT_VARIABLE, "").strip().lower()
|
||||||
in {"1", "true", "yes", "on"},
|
in {"1", "true", "yes", "on"},
|
||||||
f"Set {VERIFY_ENVIRONMENT_VARIABLE}=1 to verify installed versions.",
|
f"Set {VERIFY_ENVIRONMENT_VARIABLE}=1 to verify installed versions.",
|
||||||
)
|
)
|
||||||
def test_installed_environment_matches_reference_constraints(self) -> None:
|
def test_installed_environment_matches_linux_release_lock(self) -> None:
|
||||||
self.assertEqual(sys.version_info[:3], (3, 12, 3))
|
self.assertEqual(sys.version_info[:3], (3, 12, 3))
|
||||||
|
self.assertEqual(sys.platform, "linux")
|
||||||
|
self.assertEqual(platform.machine().lower(), "x86_64")
|
||||||
installed = {
|
installed = {
|
||||||
name: metadata.version(name)
|
name: metadata.version(name)
|
||||||
for name in REFERENCE_DIRECT_VERSIONS
|
for name in REFERENCE_LOCKED_VERSIONS
|
||||||
}
|
}
|
||||||
self.assertEqual(installed, REFERENCE_DIRECT_VERSIONS)
|
self.assertEqual(installed, REFERENCE_LOCKED_VERSIONS)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from app.main import compile_system_xml_network
|
from app.main import compile_system_xml_network
|
||||||
from app.simulation.benchmark_regression import (
|
from app.simulation.benchmark_regression import (
|
||||||
|
evaluate_regression_golden,
|
||||||
load_regression_manifest,
|
load_regression_manifest,
|
||||||
run_regression_suite,
|
run_regression_suite,
|
||||||
source_simulation_config,
|
source_simulation_config,
|
||||||
@@ -85,6 +87,60 @@ class MqlFullBranchesStaticRegressionTests(unittest.TestCase):
|
|||||||
expected["hasMechanicalStateEvents"],
|
expected["hasMechanicalStateEvents"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_three_production_repeats_replay_approved_goldens_exactly(self) -> None:
|
||||||
|
repository_root = Path(self.manifest["_repositoryRoot"])
|
||||||
|
evidence = self.manifest["acceptanceEvidence"]
|
||||||
|
self.assertEqual(evidence["status"], "approved")
|
||||||
|
self.assertEqual(evidence["lane"], "production")
|
||||||
|
self.assertEqual(evidence["repeatCount"], 3)
|
||||||
|
self.assertTrue(evidence["physicalValuesIdenticalAcrossRepeats"])
|
||||||
|
|
||||||
|
expected_counts = {"0.81s": 480, "2.10s": 720}
|
||||||
|
stable_signatures: dict[str, object] = {}
|
||||||
|
for report_reference in evidence["reports"]:
|
||||||
|
report_path = repository_root / report_reference["path"]
|
||||||
|
payload = report_path.read_bytes()
|
||||||
|
self.assertEqual(len(payload), report_reference["bytes"])
|
||||||
|
self.assertEqual(
|
||||||
|
hashlib.sha256(payload).hexdigest(),
|
||||||
|
report_reference["sha256"],
|
||||||
|
)
|
||||||
|
report = json.loads(payload)
|
||||||
|
self.assertEqual(report["lane"], "production")
|
||||||
|
self.assertEqual(
|
||||||
|
report["source"]["sha256"], self.manifest["source"]["sha256"]
|
||||||
|
)
|
||||||
|
|
||||||
|
for case_id in self.manifest["sequence"]:
|
||||||
|
case = next(
|
||||||
|
item for item in report["cases"] if item["caseId"] == case_id
|
||||||
|
)
|
||||||
|
self.assertEqual(case["outcome"], "completed")
|
||||||
|
self.assertTrue(case["acceptance"]["passed"])
|
||||||
|
summary = case["worker"]["summary"]
|
||||||
|
golden = self.manifest["_goldens"][case_id]["production"]
|
||||||
|
audit = evaluate_regression_golden(summary, golden)
|
||||||
|
self.assertTrue(audit["passed"], audit)
|
||||||
|
self.assertEqual(
|
||||||
|
audit["comparedValueCount"], expected_counts[case_id]
|
||||||
|
)
|
||||||
|
self.assertEqual(audit["maxAbsoluteError"], 0.0)
|
||||||
|
self.assertEqual(audit["maxToleranceRatio"], 0.0)
|
||||||
|
self.assertEqual(audit["issues"], [])
|
||||||
|
|
||||||
|
diagnostics = dict(summary["diagnostics"])
|
||||||
|
diagnostics.pop("performance", None)
|
||||||
|
signature = {
|
||||||
|
"physicalContract": summary["physicalContract"],
|
||||||
|
"eventTrace": summary["eventTrace"],
|
||||||
|
"outputContract": summary["outputContract"],
|
||||||
|
"diagnosticsWithoutPerformance": diagnostics,
|
||||||
|
}
|
||||||
|
if case_id not in stable_signatures:
|
||||||
|
stable_signatures[case_id] = signature
|
||||||
|
else:
|
||||||
|
self.assertEqual(stable_signatures[case_id], signature)
|
||||||
|
|
||||||
def test_both_horizons_have_the_expected_signal_schedule(self) -> None:
|
def test_both_horizons_have_the_expected_signal_schedule(self) -> None:
|
||||||
assert self.validation.document is not None
|
assert self.validation.document is not None
|
||||||
system = GenericFluidSystem(
|
system = GenericFluidSystem(
|
||||||
@@ -105,9 +161,16 @@ class MqlFullBranchesStaticRegressionTests(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
class MqlFullBranchesLongRegressionTests(unittest.TestCase):
|
class MqlFullBranchesLongRegressionTests(unittest.TestCase):
|
||||||
def test_both_horizons_complete_within_their_safety_budgets(self) -> None:
|
def test_both_horizons_complete_within_their_safety_budgets(self) -> None:
|
||||||
report = run_regression_suite(MANIFEST_PATH, lane="solver-only")
|
report = run_regression_suite(MANIFEST_PATH, lane="production")
|
||||||
outcomes = [case["outcome"] for case in report["cases"]]
|
outcomes = [case["outcome"] for case in report["cases"]]
|
||||||
self.assertEqual(outcomes, ["completed", "completed"], report["cases"])
|
self.assertEqual(outcomes, ["completed", "completed"], report["cases"])
|
||||||
|
self.assertTrue(
|
||||||
|
all(
|
||||||
|
case["acceptance"]["regressionGolden"]["passed"]
|
||||||
|
for case in report["cases"]
|
||||||
|
),
|
||||||
|
report["cases"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -0,0 +1,487 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import copy
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from app.simulation.benchmark_regression import summarize_simulation_result
|
||||||
|
from app.simulation.physical_state_v21 import (
|
||||||
|
PHYSICAL_STATE_V21_ID,
|
||||||
|
PhysicalStateV21Error,
|
||||||
|
approve_candidate_golden,
|
||||||
|
assess_report_against_amesim,
|
||||||
|
build_amesim_reference,
|
||||||
|
build_candidate_golden,
|
||||||
|
compare_contract_to_amesim,
|
||||||
|
evaluate_physical_state_v21,
|
||||||
|
load_approved_golden,
|
||||||
|
project_physical_state_v21,
|
||||||
|
write_candidate_golden,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
AMESIM_ARCHIVE = REPO_ROOT / "AmesimModels" / "test_mql.ame"
|
||||||
|
CANDIDATE_REPORT = (
|
||||||
|
REPO_ROOT
|
||||||
|
/ "tests/baselines/simulation/test_mql_8/runs"
|
||||||
|
/ "2026-08-18-production-amesim-aligned-v1-candidate-0.2.json"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _variable(key: str, quantity: str, unit: str, category: str) -> dict[str, str]:
|
||||||
|
return {"key": key, "quantity": quantity, "unit": unit, "category": category}
|
||||||
|
|
||||||
|
|
||||||
|
def _synthetic_result() -> dict[str, object]:
|
||||||
|
times = [0.0, 0.04, 0.2]
|
||||||
|
variables: list[dict[str, str]] = []
|
||||||
|
series: dict[str, list[float]] = {"time": times}
|
||||||
|
|
||||||
|
def add(
|
||||||
|
key: str,
|
||||||
|
values: list[float],
|
||||||
|
quantity: str,
|
||||||
|
unit: str,
|
||||||
|
category: str,
|
||||||
|
) -> None:
|
||||||
|
variables.append(_variable(key, quantity, unit, category))
|
||||||
|
series[key] = values
|
||||||
|
|
||||||
|
add("amesim_pnch012_8.p", [100_000.0, 200_000.0, 300_000.0], "pressure", "Pa", "thermodynamic")
|
||||||
|
add("amesim_pnl0001_20.p", [100_000.0, 210_000.0, 310_000.0], "pressure", "Pa", "thermodynamic")
|
||||||
|
add("amesim_pnl0001_20.port_1.m_flow", [-0.1, -0.2, -0.3], "mass_flow", "kg/s", "port")
|
||||||
|
add("amesim_pnch012_8.port_1.m_flow", [0.1, 0.2, 0.3], "mass_flow", "kg/s", "port")
|
||||||
|
add("amesim_pnvo001_5.port_2.m_flow", [-0.2, -0.3, -0.4], "mass_flow", "kg/s", "port")
|
||||||
|
add("amesim_pnvo001_5.port_3.m_flow", [0.2, 0.3, 0.4], "mass_flow", "kg/s", "port")
|
||||||
|
for port, values in enumerate(
|
||||||
|
([0.4, 0.5, 0.6], [-0.1, -0.2, -0.3], [-0.2, -0.2, -0.2], [-0.1, -0.1, -0.1]),
|
||||||
|
start=1,
|
||||||
|
):
|
||||||
|
add(f"amesim_p4node2_8.port_{port}.m_flow", list(values), "mass_flow", "kg/s", "port")
|
||||||
|
add("amesim_pnvo001_5.xv", [0.0, 1.0, 1.0], "dimensionless", "", "derived")
|
||||||
|
add("amesim_mecmas21_9.x", [0.0, 0.0, 0.0], "length", "m", "state")
|
||||||
|
add("amesim_mecmas21_9.v", [0.0, 0.0, 0.0], "velocity", "m/s", "state")
|
||||||
|
add("amesim_mecmas21_9.port_1.f", [1.0, 1.0, 1.0], "force", "N", "port")
|
||||||
|
add("amesim_mecmas21_9.port_2.f", [2.0, 2.0, 2.0], "force", "N", "port")
|
||||||
|
add("amesim_mecmas21_10.x", [0.0, 0.0, 0.0], "length", "m", "state")
|
||||||
|
add("amesim_mecmas21_10.v", [0.0, 0.0, 0.0], "velocity", "m/s", "state")
|
||||||
|
add("amesim_mecmas21_10.port_1.f", [-2.0, -2.0, -2.0], "force", "N", "port")
|
||||||
|
add("amesim_mecmas21_10.port_2.f", [-1.0, -1.0, -1.0], "force", "N", "port")
|
||||||
|
add("storage_a.m", [1.0, 2.0, 3.0], "mass", "kg", "state")
|
||||||
|
add("storage_b.m", [4.0, 3.0, 2.0], "mass", "kg", "state")
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"status": "completed",
|
||||||
|
"partial": False,
|
||||||
|
"simulatedUntil": 0.2,
|
||||||
|
"requestedStopTime": 0.2,
|
||||||
|
"variables": variables,
|
||||||
|
"series": series,
|
||||||
|
"final": {key: values[-1] for key, values in series.items() if key != "time"},
|
||||||
|
"diagnostics": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class PhysicalStateProjectionTests(unittest.TestCase):
|
||||||
|
def test_projects_all_categories_with_units_and_strict_balances(self) -> None:
|
||||||
|
contract = project_physical_state_v21(
|
||||||
|
_synthetic_result(), checkpoint_times=(0.0, 0.04, 0.2), sample_step=0.04
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(contract["id"], PHYSICAL_STATE_V21_ID)
|
||||||
|
self.assertEqual(
|
||||||
|
contract["projectionCategories"],
|
||||||
|
["pressure", "massFlow", "conservation", "discreteMode"],
|
||||||
|
)
|
||||||
|
self.assertEqual(len(contract["layout"]["projectionKeys"]), 11)
|
||||||
|
endpoint = contract["checkpoints"][-1]["values"]
|
||||||
|
self.assertEqual(endpoint["conservation.totalStoredGasMass"], 5.0)
|
||||||
|
self.assertAlmostEqual(endpoint["conservation.p4node2_8.massBalance"], 0.0)
|
||||||
|
self.assertAlmostEqual(endpoint["conservation.pnvo001_5.massBalance"], 0.0)
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
endpoint["conservation.pnl0001_20_pnch012_8.connectionMassBalance"], 0.0
|
||||||
|
)
|
||||||
|
self.assertEqual(endpoint["discrete.pnvo001_5.openMode"], 1.0)
|
||||||
|
self.assertEqual(endpoint["discrete.mecmas21_9.endstopMode"], 1.0)
|
||||||
|
self.assertEqual(endpoint["discrete.mecmas21_10.endstopMode"], -1.0)
|
||||||
|
pressure = contract["layout"]["projections"][0]["amesim"]
|
||||||
|
self.assertEqual(pressure["offset"], 101_300.0)
|
||||||
|
flow = contract["layout"]["projections"][2]["amesim"]
|
||||||
|
self.assertEqual(flow["scale"], -1.0e-3)
|
||||||
|
|
||||||
|
def test_fails_closed_on_wrong_source_unit(self) -> None:
|
||||||
|
result = _synthetic_result()
|
||||||
|
next(
|
||||||
|
variable
|
||||||
|
for variable in result["variables"]
|
||||||
|
if variable["key"] == "amesim_pnch012_8.p"
|
||||||
|
)["unit"] = "bar"
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(PhysicalStateV21Error, "Unexpected metadata"):
|
||||||
|
project_physical_state_v21(result, checkpoint_times=(0.2,), sample_step=0.2)
|
||||||
|
|
||||||
|
def test_benchmark_summary_attaches_v21_only_to_matching_result(self) -> None:
|
||||||
|
summary = summarize_simulation_result(
|
||||||
|
_synthetic_result(), checkpoint_times=(0.0, 0.2), sample_step=0.2
|
||||||
|
)
|
||||||
|
self.assertEqual(summary["physicalStateV21"]["id"], PHYSICAL_STATE_V21_ID)
|
||||||
|
|
||||||
|
|
||||||
|
class AmesimReferenceTests(unittest.TestCase):
|
||||||
|
def test_reference_records_archive_hash_units_signs_and_known_endpoint(self) -> None:
|
||||||
|
reference = build_amesim_reference(AMESIM_ARCHIVE, checkpoint_times=(0.2,))
|
||||||
|
values = reference["checkpoints"][0]["values"]
|
||||||
|
|
||||||
|
self.assertAlmostEqual(values["pressure.pnch012_8.absolute"], 3_625_053.2009413484)
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
values["massFlow.pnl0001_20.port_1.intoComponent"],
|
||||||
|
-0.3728806429214546,
|
||||||
|
)
|
||||||
|
self.assertEqual(values["discrete.mecmas21_9.endstopMode"], 1.0)
|
||||||
|
self.assertEqual(values["discrete.mecmas21_10.endstopMode"], -1.0)
|
||||||
|
provenance = reference["provenance"]
|
||||||
|
self.assertEqual(provenance["archivePath"], "AmesimModels/test_mql.ame")
|
||||||
|
self.assertEqual(len(provenance["archiveSha256"]), 64)
|
||||||
|
self.assertEqual(
|
||||||
|
[member["name"] for member in provenance["members"]],
|
||||||
|
["test_mql_.var", "test_mql_.results"],
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_current_candidate_endpoint_passes_explicit_amesim_alignment_profile(self) -> None:
|
||||||
|
assessment = assess_report_against_amesim(
|
||||||
|
CANDIDATE_REPORT, archive_path=AMESIM_ARCHIVE
|
||||||
|
)
|
||||||
|
|
||||||
|
comparison = assessment["comparison"]
|
||||||
|
self.assertEqual(assessment["coverage"], "legacyEndpointOnly")
|
||||||
|
self.assertTrue(comparison["passed"])
|
||||||
|
self.assertEqual(comparison["comparedValueCount"], 9)
|
||||||
|
self.assertEqual(comparison["metricCount"], 11)
|
||||||
|
self.assertEqual(comparison["availableBaselineValueCount"], 9)
|
||||||
|
self.assertEqual(comparison["unavailableBaselineValueCount"], 2)
|
||||||
|
self.assertEqual(len(comparison["metrics"]), 11)
|
||||||
|
self.assertTrue(
|
||||||
|
all(
|
||||||
|
{
|
||||||
|
"requestedTime",
|
||||||
|
"key",
|
||||||
|
"category",
|
||||||
|
"actual",
|
||||||
|
"amesimBaseline",
|
||||||
|
"absoluteError",
|
||||||
|
"relativeError",
|
||||||
|
"evaluated",
|
||||||
|
"passed",
|
||||||
|
}
|
||||||
|
<= set(metric)
|
||||||
|
for metric in comparison["metrics"]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
comparison["worstValue"]["key"],
|
||||||
|
"massFlow.pnl0001_20.port_1.intoComponent",
|
||||||
|
)
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
comparison["worstValue"]["relativeError"],
|
||||||
|
0.0013934852135053246,
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
comparison["toleranceProfile"]["byCategory"]["discreteMode"]["relative"],
|
||||||
|
0.0,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_signal_jump_mass_flows_record_errors_but_are_not_evaluated(self) -> None:
|
||||||
|
contract = project_physical_state_v21(
|
||||||
|
_synthetic_result(), checkpoint_times=(0.0, 0.04, 0.2), sample_step=0.04
|
||||||
|
)
|
||||||
|
reference_checkpoints = []
|
||||||
|
for checkpoint in contract["checkpoints"]:
|
||||||
|
values = dict(checkpoint["values"])
|
||||||
|
values["conservation.p4node2_8.massBalance"] = None
|
||||||
|
values[
|
||||||
|
"conservation.pnl0001_20_pnch012_8.connectionMassBalance"
|
||||||
|
] = None
|
||||||
|
if checkpoint["requestedTime"] == 0.04:
|
||||||
|
values["massFlow.pnl0001_20.port_1.intoComponent"] += 100.0
|
||||||
|
values["massFlow.pnvo001_5.port_2.intoComponent"] -= 100.0
|
||||||
|
reference_checkpoints.append(
|
||||||
|
{"requestedTime": checkpoint["requestedTime"], "values": values}
|
||||||
|
)
|
||||||
|
|
||||||
|
comparison = compare_contract_to_amesim(
|
||||||
|
contract, {"checkpoints": reference_checkpoints}
|
||||||
|
)
|
||||||
|
|
||||||
|
excluded = [
|
||||||
|
metric
|
||||||
|
for metric in comparison["metrics"]
|
||||||
|
if metric["requestedTime"] == 0.04 and metric["category"] == "massFlow"
|
||||||
|
]
|
||||||
|
self.assertTrue(comparison["passed"])
|
||||||
|
self.assertEqual(comparison["metricCount"], 33)
|
||||||
|
self.assertEqual(comparison["availableBaselineValueCount"], 27)
|
||||||
|
self.assertEqual(comparison["unavailableBaselineValueCount"], 6)
|
||||||
|
self.assertEqual(comparison["comparedValueCount"], 25)
|
||||||
|
self.assertEqual(comparison["excludedValueCount"], 2)
|
||||||
|
self.assertEqual(len(comparison["metrics"]), 33)
|
||||||
|
self.assertEqual(len(excluded), 2)
|
||||||
|
self.assertTrue(all(metric["evaluated"] is False for metric in excluded))
|
||||||
|
self.assertTrue(all(metric["passed"] is None for metric in excluded))
|
||||||
|
self.assertTrue(all(metric["absoluteError"] > 99.0 for metric in excluded))
|
||||||
|
self.assertTrue(
|
||||||
|
all("LeftRightLimit" in metric["exclusionReason"] for metric in excluded)
|
||||||
|
)
|
||||||
|
self.assertNotIn(comparison["worstValue"], excluded)
|
||||||
|
|
||||||
|
unavailable = [
|
||||||
|
metric
|
||||||
|
for metric in comparison["metrics"]
|
||||||
|
if metric["amesimBaseline"] is None
|
||||||
|
]
|
||||||
|
self.assertEqual(len(unavailable), 6)
|
||||||
|
self.assertTrue(all(metric["evaluated"] is False for metric in unavailable))
|
||||||
|
self.assertTrue(all(metric["absoluteError"] is None for metric in unavailable))
|
||||||
|
self.assertTrue(all(metric["relativeError"] is None for metric in unavailable))
|
||||||
|
|
||||||
|
def test_relative_error_uses_the_amesim_baseline_denominator(self) -> None:
|
||||||
|
contract = project_physical_state_v21(
|
||||||
|
_synthetic_result(), checkpoint_times=(0.2,), sample_step=0.2
|
||||||
|
)
|
||||||
|
values = dict(contract["checkpoints"][0]["values"])
|
||||||
|
key = "pressure.pnch012_8.absolute"
|
||||||
|
values[key] = 0.5 * values[key]
|
||||||
|
|
||||||
|
comparison = compare_contract_to_amesim(
|
||||||
|
contract,
|
||||||
|
{"checkpoints": [{"requestedTime": 0.2, "values": values}]},
|
||||||
|
)
|
||||||
|
metric = next(item for item in comparison["metrics"] if item["key"] == key)
|
||||||
|
expected = abs(metric["actual"] - metric["amesimBaseline"]) / abs(
|
||||||
|
metric["amesimBaseline"]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertAlmostEqual(metric["relativeError"], expected)
|
||||||
|
self.assertAlmostEqual(metric["relativeErrorPercent"], 100.0 * expected)
|
||||||
|
self.assertTrue(metric["relativeErrorDefined"])
|
||||||
|
|
||||||
|
def test_zero_amesim_baseline_has_undefined_relative_error(self) -> None:
|
||||||
|
contract = project_physical_state_v21(
|
||||||
|
_synthetic_result(), checkpoint_times=(0.2,), sample_step=0.2
|
||||||
|
)
|
||||||
|
values = dict(contract["checkpoints"][0]["values"])
|
||||||
|
key = "massFlow.pnl0001_20.port_1.intoComponent"
|
||||||
|
values[key] = -0.0
|
||||||
|
|
||||||
|
comparison = compare_contract_to_amesim(
|
||||||
|
contract,
|
||||||
|
{"checkpoints": [{"requestedTime": 0.2, "values": values}]},
|
||||||
|
)
|
||||||
|
metric = next(item for item in comparison["metrics"] if item["key"] == key)
|
||||||
|
|
||||||
|
self.assertIsNone(metric["relativeError"])
|
||||||
|
self.assertIsNone(metric["relativeErrorPercent"])
|
||||||
|
self.assertFalse(metric["relativeErrorDefined"])
|
||||||
|
self.assertEqual(metric["relativeErrorReason"], "zeroAmesimBaseline")
|
||||||
|
self.assertEqual(metric["comparisonBasis"], "absoluteNearZero")
|
||||||
|
self.assertEqual(
|
||||||
|
json.loads(json.dumps(comparison, allow_nan=False))["baselineAuthority"],
|
||||||
|
"amesim",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ReviewedGoldenProtocolTests(unittest.TestCase):
|
||||||
|
def _report_and_reference(self):
|
||||||
|
contract = project_physical_state_v21(
|
||||||
|
_synthetic_result(), checkpoint_times=(0.0, 0.04, 0.2), sample_step=0.04
|
||||||
|
)
|
||||||
|
report = {
|
||||||
|
"generatedAt": "2026-08-18T00:00:00+00:00",
|
||||||
|
"source": {"sha256": "a" * 64},
|
||||||
|
"cases": [{
|
||||||
|
"caseId": "0.2s",
|
||||||
|
"lane": "production",
|
||||||
|
"worker": {"summary": {"physicalStateV21": contract}},
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
keys = contract["layout"]["projectionKeys"]
|
||||||
|
reference_checkpoints = []
|
||||||
|
for checkpoint in contract["checkpoints"]:
|
||||||
|
reference_checkpoints.append({
|
||||||
|
"requestedTime": checkpoint["requestedTime"],
|
||||||
|
"values": {key: checkpoint["values"][key] for key in keys},
|
||||||
|
})
|
||||||
|
reference = {
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"provenance": {
|
||||||
|
"archivePath": "AmesimModels/synthetic.ame",
|
||||||
|
"archiveBytes": 2,
|
||||||
|
"archiveSha256": "b" * 64,
|
||||||
|
"members": [
|
||||||
|
{"name": "synthetic.var", "bytes": 1, "sha256": "c" * 64},
|
||||||
|
{
|
||||||
|
"name": "synthetic.results",
|
||||||
|
"bytes": 1,
|
||||||
|
"sha256": "d" * 64,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"storedMassDataPaths": ["mgas@synthetic"],
|
||||||
|
"checkpoints": reference_checkpoints,
|
||||||
|
}
|
||||||
|
return contract, report, reference
|
||||||
|
|
||||||
|
def test_candidate_requires_exact_hash_and_is_approved_to_a_new_file(self) -> None:
|
||||||
|
contract, report, reference = self._report_and_reference()
|
||||||
|
with tempfile.TemporaryDirectory(
|
||||||
|
dir=REPO_ROOT, prefix=".physical-state-v21-test-"
|
||||||
|
) as temporary_directory:
|
||||||
|
root = Path(temporary_directory)
|
||||||
|
report_path = root / "report.json"
|
||||||
|
report_path.write_text(json.dumps(report), encoding="utf-8")
|
||||||
|
candidate_path = root / "candidate.json"
|
||||||
|
approved_path = root / "approved.json"
|
||||||
|
with patch(
|
||||||
|
"app.simulation.physical_state_v21.build_amesim_reference",
|
||||||
|
return_value=reference,
|
||||||
|
):
|
||||||
|
write_candidate_golden(report_path, candidate_path)
|
||||||
|
candidate = json.loads(candidate_path.read_text(encoding="utf-8"))
|
||||||
|
local_report = candidate["provenance"]["localSourceReport"]
|
||||||
|
self.assertFalse(Path(local_report["path"]).is_absolute())
|
||||||
|
self.assertEqual(local_report["bytes"], report_path.stat().st_size)
|
||||||
|
candidate_sha = hashlib.sha256(candidate_path.read_bytes()).hexdigest()
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(PhysicalStateV21Error, "SHA mismatch"):
|
||||||
|
approve_candidate_golden(
|
||||||
|
candidate_path,
|
||||||
|
approved_path,
|
||||||
|
expected_candidate_sha256="0" * 64,
|
||||||
|
reviewed_by="reviewer",
|
||||||
|
note="reviewed",
|
||||||
|
)
|
||||||
|
approve_candidate_golden(
|
||||||
|
candidate_path,
|
||||||
|
approved_path,
|
||||||
|
expected_candidate_sha256=candidate_sha,
|
||||||
|
reviewed_by="reviewer",
|
||||||
|
note="units, signs, and errors reviewed",
|
||||||
|
)
|
||||||
|
golden = load_approved_golden(approved_path)
|
||||||
|
self.assertFalse(Path(golden["approval"]["candidatePath"]).is_absolute())
|
||||||
|
golden["checkpoints"][-1]["values"][0] += 1.0e9
|
||||||
|
self.assertTrue(evaluate_physical_state_v21(contract, golden)["passed"])
|
||||||
|
|
||||||
|
changed = copy.deepcopy(contract)
|
||||||
|
changed["checkpoints"][-1]["values"]["pressure.pnch012_8.absolute"] += 1000.0
|
||||||
|
failure = evaluate_physical_state_v21(changed, golden)
|
||||||
|
self.assertFalse(failure["passed"])
|
||||||
|
self.assertIn("amesimReferenceToleranceMismatch", failure["issues"])
|
||||||
|
|
||||||
|
def test_approval_rejects_failed_or_tampered_alignment(self) -> None:
|
||||||
|
_contract, report, reference = self._report_and_reference()
|
||||||
|
with tempfile.TemporaryDirectory() as temporary_directory:
|
||||||
|
root = Path(temporary_directory)
|
||||||
|
report_path = root / "report.json"
|
||||||
|
report_path.write_text(json.dumps(report), encoding="utf-8")
|
||||||
|
original_path = root / "candidate.json"
|
||||||
|
with patch(
|
||||||
|
"app.simulation.physical_state_v21.build_amesim_reference",
|
||||||
|
return_value=reference,
|
||||||
|
):
|
||||||
|
write_candidate_golden(report_path, original_path)
|
||||||
|
original = json.loads(original_path.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
failed_alignment = copy.deepcopy(original)
|
||||||
|
failed_alignment["amesimAlignmentAtGeneration"]["passed"] = False
|
||||||
|
failed_path = root / "failed-alignment.json"
|
||||||
|
failed_path.write_text(json.dumps(failed_alignment), encoding="utf-8")
|
||||||
|
with self.assertRaisesRegex(
|
||||||
|
PhysicalStateV21Error, "AMESim alignment at generation"
|
||||||
|
):
|
||||||
|
approve_candidate_golden(
|
||||||
|
failed_path,
|
||||||
|
root / "failed-approved.json",
|
||||||
|
expected_candidate_sha256=hashlib.sha256(
|
||||||
|
failed_path.read_bytes()
|
||||||
|
).hexdigest(),
|
||||||
|
reviewed_by="reviewer",
|
||||||
|
note="must not override a failed alignment",
|
||||||
|
)
|
||||||
|
|
||||||
|
failed_metric = copy.deepcopy(original)
|
||||||
|
evaluated_metric = next(
|
||||||
|
metric
|
||||||
|
for metric in failed_metric["amesimAlignmentAtGeneration"]["metrics"]
|
||||||
|
if metric["evaluated"]
|
||||||
|
)
|
||||||
|
evaluated_metric["passed"] = False
|
||||||
|
failed_metric_path = root / "failed-metric.json"
|
||||||
|
failed_metric_path.write_text(json.dumps(failed_metric), encoding="utf-8")
|
||||||
|
with self.assertRaisesRegex(PhysicalStateV21Error, "evaluated metric"):
|
||||||
|
approve_candidate_golden(
|
||||||
|
failed_metric_path,
|
||||||
|
root / "failed-metric-approved.json",
|
||||||
|
expected_candidate_sha256=hashlib.sha256(
|
||||||
|
failed_metric_path.read_bytes()
|
||||||
|
).hexdigest(),
|
||||||
|
reviewed_by="reviewer",
|
||||||
|
note="must not override a failed metric",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_approval_rejects_local_conservation_residual(self) -> None:
|
||||||
|
_contract, report, reference = self._report_and_reference()
|
||||||
|
with tempfile.TemporaryDirectory() as temporary_directory:
|
||||||
|
root = Path(temporary_directory)
|
||||||
|
report_path = root / "report.json"
|
||||||
|
report_path.write_text(json.dumps(report), encoding="utf-8")
|
||||||
|
original_path = root / "candidate.json"
|
||||||
|
with patch(
|
||||||
|
"app.simulation.physical_state_v21.build_amesim_reference",
|
||||||
|
return_value=reference,
|
||||||
|
):
|
||||||
|
write_candidate_golden(report_path, original_path)
|
||||||
|
candidate = json.loads(original_path.read_text(encoding="utf-8"))
|
||||||
|
key = "conservation.p4node2_8.massBalance"
|
||||||
|
value_index = candidate["layout"]["projectionKeys"].index(key)
|
||||||
|
candidate["checkpoints"][1]["values"][value_index] = 2.0e-9
|
||||||
|
tampered_path = root / "conservation-residual.json"
|
||||||
|
tampered_path.write_text(json.dumps(candidate), encoding="utf-8")
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(
|
||||||
|
PhysicalStateV21Error, "local conservation residual"
|
||||||
|
):
|
||||||
|
approve_candidate_golden(
|
||||||
|
tampered_path,
|
||||||
|
root / "residual-approved.json",
|
||||||
|
expected_candidate_sha256=hashlib.sha256(
|
||||||
|
tampered_path.read_bytes()
|
||||||
|
).hexdigest(),
|
||||||
|
reviewed_by="reviewer",
|
||||||
|
note="must not override a local conservation failure",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_candidate_writer_refuses_overwrite_and_unapproved_file_is_rejected(self) -> None:
|
||||||
|
_contract, report, reference = self._report_and_reference()
|
||||||
|
with tempfile.TemporaryDirectory() as temporary_directory:
|
||||||
|
root = Path(temporary_directory)
|
||||||
|
report_path = root / "report.json"
|
||||||
|
report_path.write_text(json.dumps(report), encoding="utf-8")
|
||||||
|
output = root / "candidate.json"
|
||||||
|
with patch(
|
||||||
|
"app.simulation.physical_state_v21.build_amesim_reference",
|
||||||
|
return_value=reference,
|
||||||
|
):
|
||||||
|
write_candidate_golden(report_path, output)
|
||||||
|
with self.assertRaisesRegex(PhysicalStateV21Error, "overwrite"):
|
||||||
|
write_candidate_golden(report_path, output)
|
||||||
|
with self.assertRaisesRegex(PhysicalStateV21Error, "approval.status"):
|
||||||
|
load_approved_golden(output)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
@@ -154,6 +154,26 @@ class TestMql8StaticRegressionTests(unittest.TestCase):
|
|||||||
self.assertEqual(audit["maxAbsoluteError"], 0.0)
|
self.assertEqual(audit["maxAbsoluteError"], 0.0)
|
||||||
self.assertEqual(audit["maxToleranceRatio"], 0.0)
|
self.assertEqual(audit["maxToleranceRatio"], 0.0)
|
||||||
|
|
||||||
|
def test_approved_production_golden_replays_its_source_report(self) -> None:
|
||||||
|
repository_root = Path(self.manifest["_repositoryRoot"])
|
||||||
|
reference = self.manifest["variants"]["0.2s"]["goldens"]["production"]
|
||||||
|
golden = load_regression_golden(
|
||||||
|
repository_root / reference["path"],
|
||||||
|
expected_sha256=reference["sha256"],
|
||||||
|
repository_root=repository_root,
|
||||||
|
)
|
||||||
|
source_report = golden["provenance"]["sourceReport"]
|
||||||
|
report = json.loads(
|
||||||
|
(repository_root / source_report["path"]).read_text(encoding="utf-8")
|
||||||
|
)
|
||||||
|
case = next(item for item in report["cases"] if item["caseId"] == "0.2s")
|
||||||
|
audit = evaluate_regression_golden(case["worker"]["summary"], golden)
|
||||||
|
|
||||||
|
self.assertTrue(audit["passed"], audit)
|
||||||
|
self.assertEqual(audit["comparedValueCount"], 426)
|
||||||
|
self.assertEqual(audit["maxAbsoluteError"], 0.0)
|
||||||
|
self.assertEqual(audit["maxToleranceRatio"], 0.0)
|
||||||
|
|
||||||
def test_historical_v2_extension_decision_remains_auditable(self) -> None:
|
def test_historical_v2_extension_decision_remains_auditable(self) -> None:
|
||||||
repository_root = Path(self.manifest["_repositoryRoot"])
|
repository_root = Path(self.manifest["_repositoryRoot"])
|
||||||
runs = repository_root / "tests/baselines/simulation/test_mql_8/runs"
|
runs = repository_root / "tests/baselines/simulation/test_mql_8/runs"
|
||||||
@@ -202,7 +222,70 @@ class TestMql8StaticRegressionTests(unittest.TestCase):
|
|||||||
self.assertEqual(first_decision["outcome"], "deferred")
|
self.assertEqual(first_decision["outcome"], "deferred")
|
||||||
self.assertTrue(decision["simulationWasNotStartedForDeferredCases"])
|
self.assertTrue(decision["simulationWasNotStartedForDeferredCases"])
|
||||||
|
|
||||||
def test_periodic_main_lane_uses_the_current_production_source(self) -> None:
|
def test_extension_decision_is_bound_to_the_current_report_and_budget(self) -> None:
|
||||||
|
repository_root = Path(self.manifest["_repositoryRoot"])
|
||||||
|
evidence = self.manifest["acceptanceEvidence"]
|
||||||
|
decision_reference = evidence["extensionDecision"]
|
||||||
|
decision_path = repository_root / decision_reference["path"]
|
||||||
|
decision_payload = decision_path.read_bytes()
|
||||||
|
decision = json.loads(decision_payload)
|
||||||
|
report_reference = evidence["production0.2ApprovedReplay"]
|
||||||
|
report_path = repository_root / report_reference["path"]
|
||||||
|
report_payload = report_path.read_bytes()
|
||||||
|
report = json.loads(report_payload)
|
||||||
|
source_case = next(
|
||||||
|
item for item in report["cases"] if item["caseId"] == "0.2s"
|
||||||
|
)
|
||||||
|
first_decision = decision["decisions"][0]
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
decision["sourceXmlSha256"], self.manifest["source"]["sha256"]
|
||||||
|
)
|
||||||
|
self.assertEqual(decision["sourceReport"], report_path.name)
|
||||||
|
self.assertEqual(len(report_payload), report_reference["bytes"])
|
||||||
|
self.assertEqual(
|
||||||
|
hashlib.sha256(report_payload).hexdigest(), report_reference["sha256"]
|
||||||
|
)
|
||||||
|
self.assertEqual(len(decision_payload), decision_reference["bytes"])
|
||||||
|
self.assertEqual(
|
||||||
|
hashlib.sha256(decision_payload).hexdigest(),
|
||||||
|
decision_reference["sha256"],
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
hashlib.sha256(report_payload).hexdigest(),
|
||||||
|
decision["sourceReportSha256"],
|
||||||
|
)
|
||||||
|
self.assertTrue(source_case["acceptance"]["passed"])
|
||||||
|
self.assertEqual(
|
||||||
|
decision["observedCase"]["workerWallSeconds"],
|
||||||
|
source_case["worker"]["wallSeconds"],
|
||||||
|
)
|
||||||
|
expected_prediction = (
|
||||||
|
source_case["worker"]["wallSeconds"]
|
||||||
|
* self.manifest["variants"]["1s"]["stopTime"]
|
||||||
|
/ source_case["stopTime"]
|
||||||
|
* self.manifest["execution"]["predictionSafetyFactor"]
|
||||||
|
)
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
first_decision["predictedWallSeconds"], expected_prediction
|
||||||
|
)
|
||||||
|
self.assertLessEqual(
|
||||||
|
first_decision["predictedWallSeconds"],
|
||||||
|
first_decision["softTimeoutSeconds"],
|
||||||
|
)
|
||||||
|
self.assertEqual(first_decision["outcome"], "eligible")
|
||||||
|
self.assertEqual(first_decision["reason"], "predictedWallWithinSoftBudget")
|
||||||
|
self.assertEqual(
|
||||||
|
[item["outcome"] for item in decision["decisions"]],
|
||||||
|
["eligible", "notEvaluated", "notEvaluated"],
|
||||||
|
)
|
||||||
|
self.assertTrue(decision["extensionWasNotStarted"])
|
||||||
|
self.assertEqual(
|
||||||
|
decision["scopeReason"],
|
||||||
|
"OPT-00 closes at the approved production 0.2 s gate; longer progressive horizons remain separately staged work.",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_periodic_main_lane_exercises_the_approved_production_golden(self) -> None:
|
||||||
workflow = (
|
workflow = (
|
||||||
Path(self.manifest["_repositoryRoot"])
|
Path(self.manifest["_repositoryRoot"])
|
||||||
/ ".github/workflows/solver-regression.yml"
|
/ ".github/workflows/solver-regression.yml"
|
||||||
@@ -210,12 +293,11 @@ class TestMql8StaticRegressionTests(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertIn("default: production", workflow)
|
self.assertIn("default: production", workflow)
|
||||||
self.assertIn("inputs.lane || 'production'", workflow)
|
self.assertIn("inputs.lane || 'production'", workflow)
|
||||||
self.assertNotIn("goldens", self.manifest["variants"]["0.2s"])
|
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(
|
@unittest.skipUnless(
|
||||||
os.getenv(LONG_RUN_ENVIRONMENT, "").strip().lower() in {"1", "true", "yes"},
|
os.getenv(LONG_RUN_ENVIRONMENT, "").strip().lower() in {"1", "true", "yes"},
|
||||||
f"Set {LONG_RUN_ENVIRONMENT}=1 to run bounded 0.005/0.2/1/5/10 s integration.",
|
f"Set {LONG_RUN_ENVIRONMENT}=1 to run bounded 0.01/0.2/1/5/10 s integration.",
|
||||||
)
|
)
|
||||||
class TestMql8ProgressiveLongRegressionTests(unittest.TestCase):
|
class TestMql8ProgressiveLongRegressionTests(unittest.TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -0,0 +1,857 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import ast
|
||||||
|
from collections import Counter
|
||||||
|
from collections.abc import Mapping
|
||||||
|
from dataclasses import dataclass
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import math
|
||||||
|
import operator
|
||||||
|
from pathlib import Path
|
||||||
|
import re
|
||||||
|
import tarfile
|
||||||
|
import unittest
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
from app.simulation.registry import get_component_model_spec
|
||||||
|
from app.simulation.reporting.amesim_results import load_test_mql_amesim_results
|
||||||
|
|
||||||
|
|
||||||
|
REPOSITORY_ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
AME_PATH = REPOSITORY_ROOT / "AmesimModels" / "test_mql.ame"
|
||||||
|
JSON_PATH = REPOSITORY_ROOT / "tests/data/test-mql-8.json"
|
||||||
|
XML_PATH = REPOSITORY_ROOT / "tests/data/test-mql-8.xml"
|
||||||
|
MANIFEST_PATH = (
|
||||||
|
REPOSITORY_ROOT
|
||||||
|
/ "tests/baselines/simulation/test_mql_8/manifest.json"
|
||||||
|
)
|
||||||
|
|
||||||
|
EXPECTED_AME_SHA256 = (
|
||||||
|
"cbc3aadd4569a49b3a63e5d66d4143ec16126c0f950df73fb637e07673c20fbb"
|
||||||
|
)
|
||||||
|
EXPECTED_AME_BYTES = 21_708_800
|
||||||
|
EXPECTED_MODEL_TYPE_COUNT = 20
|
||||||
|
EXPECTED_NODE_COUNT = 157
|
||||||
|
EXPECTED_PARAMETER_COUNT = 1_092
|
||||||
|
EXPECTED_CONNECTION_COUNT = 178
|
||||||
|
EXPECTED_RESULT_POINT_COUNT = 1_002
|
||||||
|
AMESIM_REFERENCE_PRESSURE_PA = 101_300.0
|
||||||
|
|
||||||
|
_BINARY_OPERATORS = {
|
||||||
|
ast.Add: operator.add,
|
||||||
|
ast.Sub: operator.sub,
|
||||||
|
ast.Mult: operator.mul,
|
||||||
|
ast.Div: operator.truediv,
|
||||||
|
ast.Pow: operator.pow,
|
||||||
|
}
|
||||||
|
_UNARY_OPERATORS = {ast.UAdd: operator.pos, ast.USub: operator.neg}
|
||||||
|
|
||||||
|
# Public component names for AMESim state/output values that are promoted to
|
||||||
|
# explicit initial-value parameters. Unlisted names map one-to-one.
|
||||||
|
_SOURCE_FIELD_BY_PARAMETER = {
|
||||||
|
"amesim_mecmas21": {"v0": "v1", "x0": "x1"},
|
||||||
|
"amesim_pnch012": {"p0": "press", "T0": "temp"},
|
||||||
|
"amesim_pnch023": {"p0": "press", "T0": "temp"},
|
||||||
|
"amesim_pnl0001": {"p0": "p2", "T0": "t2"},
|
||||||
|
"amesim_pnl0002": {"p0": "pctr", "T0": "tctr"},
|
||||||
|
"amesim_pnl0003": {
|
||||||
|
"p1_0": "p1",
|
||||||
|
"T1_0": "t1",
|
||||||
|
"p2_0": "p2",
|
||||||
|
"T2_0": "t2",
|
||||||
|
},
|
||||||
|
"amesim_step0": {"initial": "out0", "final": "out1", "time": "t0"},
|
||||||
|
}
|
||||||
|
_FIXED_PUBLIC_DEFAULTS = {
|
||||||
|
"amesim_pnch012": {
|
||||||
|
"vol1": 0.0,
|
||||||
|
"vol2": 0.0,
|
||||||
|
"vol3": 0.0,
|
||||||
|
"vol4": 0.0,
|
||||||
|
"dvol1": 0.0,
|
||||||
|
"dvol2": 0.0,
|
||||||
|
"dvol3": 0.0,
|
||||||
|
"dvol4": 0.0,
|
||||||
|
},
|
||||||
|
"amesim_pnvo001": {"opening0": 1.0},
|
||||||
|
}
|
||||||
|
_GAUGE_PRESSURE_FIELDS = {"press", "p1", "p2", "pctr"}
|
||||||
|
_SOURCE_TO_SI_SCALE = {
|
||||||
|
("mm", "m"): 1.0e-3,
|
||||||
|
("mm**2", "m2"): 1.0e-6,
|
||||||
|
("L", "m3"): 1.0e-3,
|
||||||
|
("N/mm", "N/m"): 1.0e3,
|
||||||
|
("N/(mm/s)", "N/(m/s)"): 1.0e3,
|
||||||
|
}
|
||||||
|
_EQUIVALENT_UNIT_PAIRS = {
|
||||||
|
("", ""),
|
||||||
|
("null", ""),
|
||||||
|
("degree", ""),
|
||||||
|
("J/m**2/K/s", "W/(m2*K)"),
|
||||||
|
("N/m**2", "Pa"),
|
||||||
|
("m**2", "m2"),
|
||||||
|
("N/(m/s)**2", "N/(m/s)^2"),
|
||||||
|
}
|
||||||
|
_SELECTABLE_UNITS_BY_QUANTITY = {
|
||||||
|
"area": {"m2", "cm2", "mm2"},
|
||||||
|
"heat_transfer_coefficient": {"W/(m2*K)"},
|
||||||
|
"pressure": {"Pa", "kPa", "MPa", "bar"},
|
||||||
|
"volume": {"m3", "L", "mL"},
|
||||||
|
"temperature": {"K", "degC"},
|
||||||
|
"length": {"m", "cm", "mm"},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class AmesimValue:
|
||||||
|
expression: str
|
||||||
|
unit: str
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class AmesimContract:
|
||||||
|
simulation_values: tuple[float, ...]
|
||||||
|
node_types: Mapping[str, str]
|
||||||
|
parameters: Mapping[str, Mapping[str, float]]
|
||||||
|
edges: tuple[tuple[str, str], ...]
|
||||||
|
component_count: int
|
||||||
|
modeled_line_count: int
|
||||||
|
direct_line_count: int
|
||||||
|
contact_count: int
|
||||||
|
|
||||||
|
|
||||||
|
def _element_text(body: str, name: str) -> str | None:
|
||||||
|
match = re.search(rf"<{name}>(.*?)</{name}>", body, flags=re.DOTALL)
|
||||||
|
return match.group(1).strip() if match else None
|
||||||
|
|
||||||
|
|
||||||
|
def _required_element_text(body: str, name: str) -> str:
|
||||||
|
value = _element_text(body, name)
|
||||||
|
if value is None:
|
||||||
|
raise AssertionError(f"AME circuit element is missing <{name}>.")
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def _blocks(body: str, name: str) -> list[str]:
|
||||||
|
return re.findall(
|
||||||
|
rf"<{name}>\s*(.*?)\s*</{name}>", body, flags=re.DOTALL
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _evaluate_expression(expression: str, variables: Mapping[str, float]) -> float:
|
||||||
|
parsed = ast.parse(expression.strip().replace("^", "**"), mode="eval")
|
||||||
|
|
||||||
|
def evaluate(node: ast.AST) -> float:
|
||||||
|
if (
|
||||||
|
isinstance(node, ast.Constant)
|
||||||
|
and isinstance(node.value, (int, float))
|
||||||
|
and not isinstance(node.value, bool)
|
||||||
|
):
|
||||||
|
return float(node.value)
|
||||||
|
if isinstance(node, ast.Name):
|
||||||
|
if node.id not in variables:
|
||||||
|
raise ValueError(f"unknown AME expression variable {node.id!r}")
|
||||||
|
return float(variables[node.id])
|
||||||
|
if isinstance(node, ast.BinOp) and type(node.op) in _BINARY_OPERATORS:
|
||||||
|
return float(
|
||||||
|
_BINARY_OPERATORS[type(node.op)](
|
||||||
|
evaluate(node.left), evaluate(node.right)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if isinstance(node, ast.UnaryOp) and type(node.op) in _UNARY_OPERATORS:
|
||||||
|
return float(_UNARY_OPERATORS[type(node.op)](evaluate(node.operand)))
|
||||||
|
raise ValueError(f"unsupported expression node {type(node).__name__}")
|
||||||
|
|
||||||
|
value = evaluate(parsed.body)
|
||||||
|
if not math.isfinite(value):
|
||||||
|
raise ValueError(f"expression is not finite: {expression!r}")
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def _public_model_type(submodel: str) -> str:
|
||||||
|
return (
|
||||||
|
"amesim_helium_medium"
|
||||||
|
if submodel == "PNGD00"
|
||||||
|
else f"amesim_{submodel.lower()}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _value_fields(entity_body: str) -> dict[str, AmesimValue]:
|
||||||
|
fields: dict[str, AmesimValue] = {}
|
||||||
|
for kind in ("RPARAM", "IPARAM", "IVAR", "EVAR"):
|
||||||
|
for field_body in _blocks(entity_body, kind):
|
||||||
|
name = _element_text(field_body, "VARNAME")
|
||||||
|
value = _element_text(field_body, "VALUE")
|
||||||
|
if name is not None and value is not None:
|
||||||
|
fields[name] = AmesimValue(
|
||||||
|
value, _element_text(field_body, "UNITS") or ""
|
||||||
|
)
|
||||||
|
return fields
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_globals(cir_text: str) -> dict[str, float]:
|
||||||
|
remaining = {
|
||||||
|
_required_element_text(body, "GLOB_PARAM_NAME"): _required_element_text(
|
||||||
|
body, "VALUE"
|
||||||
|
)
|
||||||
|
for body in _blocks(cir_text, "GLOBALPARAM")
|
||||||
|
}
|
||||||
|
resolved: dict[str, float] = {}
|
||||||
|
while remaining:
|
||||||
|
progressed = False
|
||||||
|
for name, expression in tuple(remaining.items()):
|
||||||
|
try:
|
||||||
|
resolved[name] = _evaluate_expression(expression, resolved)
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
del remaining[name]
|
||||||
|
progressed = True
|
||||||
|
if not progressed:
|
||||||
|
raise AssertionError(
|
||||||
|
"Unable to resolve AME globals: " + ", ".join(sorted(remaining))
|
||||||
|
)
|
||||||
|
return resolved
|
||||||
|
|
||||||
|
|
||||||
|
def _source_value_in_public_units(
|
||||||
|
source: AmesimValue,
|
||||||
|
*,
|
||||||
|
target_unit: str,
|
||||||
|
source_name: str,
|
||||||
|
globals_: Mapping[str, float],
|
||||||
|
) -> float:
|
||||||
|
value = _evaluate_expression(source.expression, globals_)
|
||||||
|
if source_name in _GAUGE_PRESSURE_FIELDS:
|
||||||
|
if (source.unit, target_unit) != ("Pa", "Pa"):
|
||||||
|
raise AssertionError(
|
||||||
|
f"Unexpected gauge-pressure units for {source_name}: "
|
||||||
|
f"{source.unit!r} -> {target_unit!r}."
|
||||||
|
)
|
||||||
|
return value + AMESIM_REFERENCE_PRESSURE_PA
|
||||||
|
|
||||||
|
pair = (source.unit, target_unit)
|
||||||
|
if pair in _SOURCE_TO_SI_SCALE:
|
||||||
|
return value * _SOURCE_TO_SI_SCALE[pair]
|
||||||
|
if source.unit == target_unit or pair in _EQUIVALENT_UNIT_PAIRS:
|
||||||
|
return value
|
||||||
|
raise AssertionError(
|
||||||
|
f"No AME-to-public conversion for {source_name}: "
|
||||||
|
f"{source.unit!r} -> {target_unit!r}."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _expected_parameters(
|
||||||
|
entity_body: str,
|
||||||
|
model_type: str,
|
||||||
|
globals_: Mapping[str, float],
|
||||||
|
) -> dict[str, float]:
|
||||||
|
spec = get_component_model_spec(model_type)
|
||||||
|
fields = _value_fields(entity_body)
|
||||||
|
expected = {
|
||||||
|
parameter.name: float(parameter.default) for parameter in spec.parameters
|
||||||
|
}
|
||||||
|
source_names = _SOURCE_FIELD_BY_PARAMETER.get(model_type, {})
|
||||||
|
fixed_defaults = _FIXED_PUBLIC_DEFAULTS.get(model_type, {})
|
||||||
|
unbound: list[str] = []
|
||||||
|
for parameter in spec.parameters:
|
||||||
|
source_name = source_names.get(parameter.name, parameter.name)
|
||||||
|
if source_name in fields:
|
||||||
|
expected[parameter.name] = _source_value_in_public_units(
|
||||||
|
fields[source_name],
|
||||||
|
target_unit=parameter.unit,
|
||||||
|
source_name=source_name,
|
||||||
|
globals_=globals_,
|
||||||
|
)
|
||||||
|
elif parameter.name in fixed_defaults:
|
||||||
|
expected[parameter.name] = fixed_defaults[parameter.name]
|
||||||
|
if float(parameter.default) != expected[parameter.name]:
|
||||||
|
raise AssertionError(
|
||||||
|
f"{model_type}.{parameter.name} changed its fixed public "
|
||||||
|
"default without an AME source-field mapping."
|
||||||
|
)
|
||||||
|
elif not (
|
||||||
|
(model_type == "amesim_forc" and parameter.name == "direction")
|
||||||
|
or (
|
||||||
|
model_type == "amesim_helium_medium"
|
||||||
|
and parameter.name == "property_model"
|
||||||
|
)
|
||||||
|
):
|
||||||
|
unbound.append(parameter.name)
|
||||||
|
|
||||||
|
if unbound:
|
||||||
|
raise AssertionError(
|
||||||
|
f"AME parameter mapping is incomplete for {model_type}: "
|
||||||
|
+ ", ".join(unbound)
|
||||||
|
)
|
||||||
|
|
||||||
|
if model_type == "amesim_forc":
|
||||||
|
geometry = _required_element_text(entity_body, "COMP_GEOMETRY")
|
||||||
|
if geometry not in {"2", "8"}:
|
||||||
|
raise AssertionError(f"Unsupported FORC geometry {geometry!r}.")
|
||||||
|
expected["direction"] = 1.0 if geometry == "2" else -1.0
|
||||||
|
|
||||||
|
if model_type == "amesim_helium_medium":
|
||||||
|
codes = tuple(
|
||||||
|
_evaluate_expression(fields[name].expression, globals_)
|
||||||
|
for name in ("fluidType", "eosType", "gasSetting")
|
||||||
|
)
|
||||||
|
if codes != (12.0, 6.0, 1.0):
|
||||||
|
raise AssertionError(
|
||||||
|
"PNGD00 no longer selects helium/Peng-Robinson."
|
||||||
|
)
|
||||||
|
expected["property_model"] = 0.0
|
||||||
|
return expected
|
||||||
|
|
||||||
|
|
||||||
|
def _load_ame_contract(path: Path) -> AmesimContract:
|
||||||
|
with tarfile.open(path) as archive:
|
||||||
|
cir_file = archive.extractfile("test_mql_.cir")
|
||||||
|
sim_file = archive.extractfile("test_mql_.sim")
|
||||||
|
if cir_file is None or sim_file is None:
|
||||||
|
raise AssertionError(
|
||||||
|
"AME archive is missing test_mql_.cir or test_mql_.sim."
|
||||||
|
)
|
||||||
|
cir_text = cir_file.read().decode("latin1")
|
||||||
|
simulation_values = tuple(
|
||||||
|
float(value)
|
||||||
|
for value in sim_file.read().decode("ascii").splitlines()[0].split()
|
||||||
|
)
|
||||||
|
|
||||||
|
globals_ = _resolve_globals(cir_text)
|
||||||
|
component_bodies = _blocks(cir_text, "COMP")
|
||||||
|
line_bodies = _blocks(cir_text, "LINE")
|
||||||
|
node_types: dict[str, str] = {}
|
||||||
|
parameters: dict[str, Mapping[str, float]] = {}
|
||||||
|
for index, body in enumerate(component_bodies):
|
||||||
|
key = f"component:{index}"
|
||||||
|
model_type = _public_model_type(
|
||||||
|
_required_element_text(body, "SUB_NAME")
|
||||||
|
)
|
||||||
|
node_types[key] = model_type
|
||||||
|
parameters[key] = _expected_parameters(body, model_type, globals_)
|
||||||
|
|
||||||
|
# PORT_CONNECT=1 is an AMESim contact; line-backed ports use value 2 and
|
||||||
|
# are reconstructed from LINES_LIST below.
|
||||||
|
directed_contacts: set[
|
||||||
|
tuple[tuple[int, int], tuple[int, int]]
|
||||||
|
] = set()
|
||||||
|
contacts: set[tuple[tuple[int, int], tuple[int, int]]] = set()
|
||||||
|
for component_index, body in enumerate(component_bodies):
|
||||||
|
for port_index, port_body in enumerate(_blocks(body, "COMP_PORT")):
|
||||||
|
if _required_element_text(port_body, "PORT_CONNECT") != "1":
|
||||||
|
continue
|
||||||
|
for connection_body in _blocks(port_body, "CONNECT"):
|
||||||
|
target_index = int(
|
||||||
|
_required_element_text(
|
||||||
|
connection_body, "CONNECT_ENTITY_NUM"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
target_port = int(
|
||||||
|
_required_element_text(
|
||||||
|
connection_body, "CONNECT_ENTITY_PORT"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
endpoint = (component_index, port_index)
|
||||||
|
target = (target_index, target_port)
|
||||||
|
directed_contacts.add((endpoint, target))
|
||||||
|
contacts.add(tuple(sorted((endpoint, target))))
|
||||||
|
|
||||||
|
for endpoint, target in directed_contacts:
|
||||||
|
if (target, endpoint) not in directed_contacts:
|
||||||
|
raise AssertionError(
|
||||||
|
"AME component contact is not reciprocal: "
|
||||||
|
f"{endpoint} -> {target}."
|
||||||
|
)
|
||||||
|
edges = [
|
||||||
|
(f"component:{first[0]}", f"component:{second[0]}")
|
||||||
|
for first, second in contacts
|
||||||
|
]
|
||||||
|
|
||||||
|
direct_line_count = 0
|
||||||
|
modeled_line_count = 0
|
||||||
|
for line_index, body in enumerate(line_bodies):
|
||||||
|
if (
|
||||||
|
_required_element_text(body, "LINE_START_TYPE") != "0"
|
||||||
|
or _required_element_text(body, "LINE_END_TYPE") != "0"
|
||||||
|
):
|
||||||
|
raise AssertionError(
|
||||||
|
"test_mql contains a non-component line endpoint."
|
||||||
|
)
|
||||||
|
start = (
|
||||||
|
"component:"
|
||||||
|
+ _required_element_text(body, "LINE_START_ENTITY")
|
||||||
|
)
|
||||||
|
end = (
|
||||||
|
"component:"
|
||||||
|
+ _required_element_text(body, "LINE_END_ENTITY")
|
||||||
|
)
|
||||||
|
if start not in node_types or end not in node_types:
|
||||||
|
raise AssertionError(
|
||||||
|
f"AME line references an unknown endpoint: {start}, {end}."
|
||||||
|
)
|
||||||
|
submodel = _required_element_text(body, "SUB_NAME")
|
||||||
|
if submodel == "DIRECT":
|
||||||
|
direct_line_count += 1
|
||||||
|
edges.append((start, end))
|
||||||
|
continue
|
||||||
|
|
||||||
|
modeled_line_count += 1
|
||||||
|
key = f"line:{line_index}"
|
||||||
|
model_type = _public_model_type(submodel)
|
||||||
|
node_types[key] = model_type
|
||||||
|
parameters[key] = _expected_parameters(
|
||||||
|
body, model_type, globals_
|
||||||
|
)
|
||||||
|
edges.extend(((start, key), (key, end)))
|
||||||
|
|
||||||
|
return AmesimContract(
|
||||||
|
simulation_values=simulation_values,
|
||||||
|
node_types=node_types,
|
||||||
|
parameters=parameters,
|
||||||
|
edges=tuple(edges),
|
||||||
|
component_count=len(component_bodies),
|
||||||
|
modeled_line_count=modeled_line_count,
|
||||||
|
direct_line_count=direct_line_count,
|
||||||
|
contact_count=len(contacts),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _numeric_project_value(value: object) -> float:
|
||||||
|
if isinstance(value, bool):
|
||||||
|
raise AssertionError(
|
||||||
|
"Boolean is not a valid project parameter value."
|
||||||
|
)
|
||||||
|
if isinstance(value, (int, float)):
|
||||||
|
result = float(value)
|
||||||
|
elif isinstance(value, str):
|
||||||
|
result = _evaluate_expression(value, {})
|
||||||
|
else:
|
||||||
|
raise AssertionError(
|
||||||
|
f"Unsupported project parameter value {value!r}."
|
||||||
|
)
|
||||||
|
if not math.isfinite(result):
|
||||||
|
raise AssertionError(
|
||||||
|
f"Project parameter value is not finite: {value!r}."
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _parameter_fingerprint(
|
||||||
|
values: Mapping[str, object],
|
||||||
|
) -> tuple[tuple[str, str], ...]:
|
||||||
|
# Fifteen significant digits collapse only normal IEEE-754 expression
|
||||||
|
# noise (for example 100000.00000000001 versus 100000).
|
||||||
|
return tuple(
|
||||||
|
sorted(
|
||||||
|
(name, format(_numeric_project_value(value), ".15g"))
|
||||||
|
for name, value in values.items()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _topology_fingerprints(
|
||||||
|
node_types: Mapping[str, str],
|
||||||
|
edges: tuple[tuple[str, str], ...],
|
||||||
|
*,
|
||||||
|
rounds: int = 12,
|
||||||
|
) -> tuple[Counter[str], ...]:
|
||||||
|
adjacency = {node_id: [] for node_id in node_types}
|
||||||
|
for first, second in edges:
|
||||||
|
if first not in adjacency or second not in adjacency:
|
||||||
|
raise AssertionError(
|
||||||
|
f"Unknown topology endpoint: {first}, {second}."
|
||||||
|
)
|
||||||
|
adjacency[first].append(second)
|
||||||
|
adjacency[second].append(first)
|
||||||
|
|
||||||
|
colors = {
|
||||||
|
node_id: hashlib.sha256(model_type.encode()).hexdigest()
|
||||||
|
for node_id, model_type in node_types.items()
|
||||||
|
}
|
||||||
|
fingerprints: list[Counter[str]] = []
|
||||||
|
for _ in range(rounds):
|
||||||
|
colors = {
|
||||||
|
node_id: hashlib.sha256(
|
||||||
|
repr(
|
||||||
|
(
|
||||||
|
node_types[node_id],
|
||||||
|
colors[node_id],
|
||||||
|
sorted(
|
||||||
|
colors[neighbor]
|
||||||
|
for neighbor in adjacency[node_id]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
).encode()
|
||||||
|
).hexdigest()
|
||||||
|
for node_id in node_types
|
||||||
|
}
|
||||||
|
fingerprints.append(Counter(colors.values()))
|
||||||
|
return tuple(fingerprints)
|
||||||
|
|
||||||
|
|
||||||
|
class TestMqlAmeAuthorityContractTests(unittest.TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls) -> None:
|
||||||
|
cls.ame_payload = AME_PATH.read_bytes()
|
||||||
|
cls.ame = _load_ame_contract(AME_PATH)
|
||||||
|
cls.project = json.loads(JSON_PATH.read_text(encoding="utf-8"))
|
||||||
|
cls.xml_root = ET.parse(XML_PATH).getroot()
|
||||||
|
cls.manifest = json.loads(
|
||||||
|
MANIFEST_PATH.read_text(encoding="utf-8")
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_manifest_and_results_bind_the_exact_ame_archive(self) -> None:
|
||||||
|
self.assertEqual(len(self.ame_payload), EXPECTED_AME_BYTES)
|
||||||
|
self.assertEqual(
|
||||||
|
hashlib.sha256(self.ame_payload).hexdigest(),
|
||||||
|
EXPECTED_AME_SHA256,
|
||||||
|
)
|
||||||
|
|
||||||
|
reference = self.manifest["source"]["referenceArchive"]
|
||||||
|
self.assertEqual(
|
||||||
|
reference,
|
||||||
|
{
|
||||||
|
"path": "AmesimModels/test_mql.ame",
|
||||||
|
"sha256": EXPECTED_AME_SHA256,
|
||||||
|
"bytes": EXPECTED_AME_BYTES,
|
||||||
|
"role": "authoritativePhysicalBaseline",
|
||||||
|
"resultStartTime": 0.0,
|
||||||
|
"resultStopTime": 10.0,
|
||||||
|
"resultSampleStep": 0.01,
|
||||||
|
"resultPointCount": EXPECTED_RESULT_POINT_COUNT,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
(REPOSITORY_ROOT / reference["path"]).resolve(),
|
||||||
|
AME_PATH.resolve(),
|
||||||
|
)
|
||||||
|
|
||||||
|
# .sim: start, stop, print interval, ..., maximum integration step.
|
||||||
|
self.assertGreaterEqual(len(self.ame.simulation_values), 6)
|
||||||
|
self.assertEqual(self.ame.simulation_values[0], 0.0)
|
||||||
|
self.assertEqual(self.ame.simulation_values[1], 10.0)
|
||||||
|
self.assertEqual(self.ame.simulation_values[2], 0.01)
|
||||||
|
self.assertEqual(self.ame.simulation_values[5], 0.001)
|
||||||
|
|
||||||
|
results = load_test_mql_amesim_results(AME_PATH)
|
||||||
|
self.assertEqual(
|
||||||
|
len(results.times), EXPECTED_RESULT_POINT_COUNT
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
results.times[0], reference["resultStartTime"]
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
results.times[-1], reference["resultStopTime"]
|
||||||
|
)
|
||||||
|
self.assertTrue(
|
||||||
|
all(
|
||||||
|
left < right
|
||||||
|
for left, right in zip(
|
||||||
|
results.times, results.times[1:]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
step = reference["resultSampleStep"]
|
||||||
|
self.assertTrue(
|
||||||
|
all(
|
||||||
|
math.isclose(
|
||||||
|
time,
|
||||||
|
round(time / step) * step,
|
||||||
|
rel_tol=0.0,
|
||||||
|
abs_tol=1.0e-10,
|
||||||
|
)
|
||||||
|
for time in results.times
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_json_inventory_parameters_and_topology_derive_from_ame(
|
||||||
|
self,
|
||||||
|
) -> None:
|
||||||
|
nodes = self.project["nodes"]
|
||||||
|
edges = self.project["edges"]
|
||||||
|
json_node_types = {
|
||||||
|
node["id"]: node["data"]["modelType"] for node in nodes
|
||||||
|
}
|
||||||
|
json_edges = tuple(
|
||||||
|
(edge["source"], edge["target"]) for edge in edges
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(self.ame.component_count, 117)
|
||||||
|
self.assertEqual(self.ame.modeled_line_count, 40)
|
||||||
|
self.assertEqual(self.ame.direct_line_count, 44)
|
||||||
|
self.assertEqual(self.ame.contact_count, 54)
|
||||||
|
self.assertEqual(
|
||||||
|
len(self.ame.node_types), EXPECTED_NODE_COUNT
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
len(self.ame.edges), EXPECTED_CONNECTION_COUNT
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
len(set(self.ame.node_types.values())),
|
||||||
|
EXPECTED_MODEL_TYPE_COUNT,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(len(nodes), EXPECTED_NODE_COUNT)
|
||||||
|
self.assertEqual(len(edges), EXPECTED_CONNECTION_COUNT)
|
||||||
|
self.assertEqual(
|
||||||
|
len(set(json_node_types.values())),
|
||||||
|
EXPECTED_MODEL_TYPE_COUNT,
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
Counter(self.ame.node_types.values()),
|
||||||
|
Counter(json_node_types.values()),
|
||||||
|
)
|
||||||
|
|
||||||
|
expected_parameter_count = sum(
|
||||||
|
len(values) for values in self.ame.parameters.values()
|
||||||
|
)
|
||||||
|
actual_parameter_count = sum(
|
||||||
|
len(node["data"]["parameters"]) for node in nodes
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
expected_parameter_count, EXPECTED_PARAMETER_COUNT
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
actual_parameter_count, EXPECTED_PARAMETER_COUNT
|
||||||
|
)
|
||||||
|
|
||||||
|
expected_by_type: dict[
|
||||||
|
str, Counter[tuple[tuple[str, str], ...]]
|
||||||
|
] = {}
|
||||||
|
for node_id, model_type in self.ame.node_types.items():
|
||||||
|
expected_by_type.setdefault(model_type, Counter()).update(
|
||||||
|
[
|
||||||
|
_parameter_fingerprint(
|
||||||
|
self.ame.parameters[node_id]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
actual_by_type: dict[
|
||||||
|
str, Counter[tuple[tuple[str, str], ...]]
|
||||||
|
] = {}
|
||||||
|
for node in nodes:
|
||||||
|
model_type = node["data"]["modelType"]
|
||||||
|
actual_by_type.setdefault(model_type, Counter()).update(
|
||||||
|
[
|
||||||
|
_parameter_fingerprint(
|
||||||
|
node["data"]["parameters"]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
self.assertEqual(actual_by_type, expected_by_type)
|
||||||
|
|
||||||
|
expected_edge_types = Counter(
|
||||||
|
tuple(
|
||||||
|
sorted(
|
||||||
|
(
|
||||||
|
self.ame.node_types[first],
|
||||||
|
self.ame.node_types[second],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
for first, second in self.ame.edges
|
||||||
|
)
|
||||||
|
actual_edge_types = Counter(
|
||||||
|
tuple(
|
||||||
|
sorted(
|
||||||
|
(
|
||||||
|
json_node_types[first],
|
||||||
|
json_node_types[second],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
for first, second in json_edges
|
||||||
|
)
|
||||||
|
self.assertEqual(actual_edge_types, expected_edge_types)
|
||||||
|
self.assertEqual(
|
||||||
|
_topology_fingerprints(
|
||||||
|
json_node_types, json_edges
|
||||||
|
),
|
||||||
|
_topology_fingerprints(
|
||||||
|
self.ame.node_types, self.ame.edges
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_json_units_and_component_contracts_are_complete(
|
||||||
|
self,
|
||||||
|
) -> None:
|
||||||
|
for node in self.project["nodes"]:
|
||||||
|
with self.subTest(component=node["id"]):
|
||||||
|
data = node["data"]
|
||||||
|
self.assertEqual(
|
||||||
|
data["componentType"], data["modelType"]
|
||||||
|
)
|
||||||
|
spec = get_component_model_spec(data["modelType"])
|
||||||
|
self.assertEqual(
|
||||||
|
data["modelVersion"], spec.model_version
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
set(data["parameters"]),
|
||||||
|
{
|
||||||
|
parameter.name
|
||||||
|
for parameter in spec.parameters
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
{port["name"] for port in data["ports"]},
|
||||||
|
{port.name for port in spec.ports},
|
||||||
|
)
|
||||||
|
|
||||||
|
units = data.get("parameterUnits", {})
|
||||||
|
self.assertEqual(
|
||||||
|
set(units),
|
||||||
|
{
|
||||||
|
parameter.name
|
||||||
|
for parameter in spec.parameters
|
||||||
|
if parameter.unit
|
||||||
|
},
|
||||||
|
)
|
||||||
|
for parameter in spec.parameters:
|
||||||
|
if not parameter.unit:
|
||||||
|
continue
|
||||||
|
selected = units[parameter.name]
|
||||||
|
allowed = _SELECTABLE_UNITS_BY_QUANTITY.get(
|
||||||
|
parameter.quantity, {parameter.unit}
|
||||||
|
)
|
||||||
|
self.assertIn(selected, allowed, parameter.name)
|
||||||
|
|
||||||
|
def test_json_and_xml_match_by_id_parameter_endpoint_and_time(
|
||||||
|
self,
|
||||||
|
) -> None:
|
||||||
|
xml_components = self.xml_root.findall(
|
||||||
|
"./Components/Component"
|
||||||
|
)
|
||||||
|
xml_connections = self.xml_root.findall(
|
||||||
|
"./Connections/Connection"
|
||||||
|
)
|
||||||
|
xml_component_by_id = {
|
||||||
|
component.attrib["id"]: component
|
||||||
|
for component in xml_components
|
||||||
|
}
|
||||||
|
xml_connection_by_id = {
|
||||||
|
connection.attrib["id"]: connection
|
||||||
|
for connection in xml_connections
|
||||||
|
}
|
||||||
|
json_node_by_id = {
|
||||||
|
node["id"]: node for node in self.project["nodes"]
|
||||||
|
}
|
||||||
|
json_edge_by_id = {
|
||||||
|
edge["id"]: edge for edge in self.project["edges"]
|
||||||
|
}
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
len(xml_component_by_id), len(xml_components)
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
len(xml_connection_by_id), len(xml_connections)
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
set(xml_component_by_id), set(json_node_by_id)
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
set(xml_connection_by_id), set(json_edge_by_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
for node_id, node in json_node_by_id.items():
|
||||||
|
with self.subTest(component=node_id):
|
||||||
|
component = xml_component_by_id[node_id]
|
||||||
|
data = node["data"]
|
||||||
|
self.assertEqual(
|
||||||
|
component.attrib["type"], data["modelType"]
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
component.attrib["modelVersion"],
|
||||||
|
data["modelVersion"],
|
||||||
|
)
|
||||||
|
xml_parameters = {
|
||||||
|
parameter.attrib["name"]: float(
|
||||||
|
parameter.attrib["value"]
|
||||||
|
)
|
||||||
|
for parameter in component.findall("./Parameter")
|
||||||
|
}
|
||||||
|
json_parameters = {
|
||||||
|
name: _numeric_project_value(value)
|
||||||
|
for name, value in data["parameters"].items()
|
||||||
|
}
|
||||||
|
self.assertEqual(
|
||||||
|
set(xml_parameters), set(json_parameters)
|
||||||
|
)
|
||||||
|
for name, value in json_parameters.items():
|
||||||
|
self.assertTrue(
|
||||||
|
math.isclose(
|
||||||
|
xml_parameters[name],
|
||||||
|
value,
|
||||||
|
rel_tol=1.0e-13,
|
||||||
|
abs_tol=1.0e-13,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
f"{node_id}.{name}: "
|
||||||
|
f"XML={xml_parameters[name]!r}, "
|
||||||
|
f"JSON={value!r}"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
for edge_id, edge in json_edge_by_id.items():
|
||||||
|
with self.subTest(connection=edge_id):
|
||||||
|
endpoints = {
|
||||||
|
(
|
||||||
|
endpoint.attrib["component"],
|
||||||
|
endpoint.attrib["port"],
|
||||||
|
)
|
||||||
|
for endpoint in xml_connection_by_id[
|
||||||
|
edge_id
|
||||||
|
].findall("./Endpoint")
|
||||||
|
}
|
||||||
|
self.assertEqual(
|
||||||
|
endpoints,
|
||||||
|
{
|
||||||
|
(
|
||||||
|
edge["source"],
|
||||||
|
edge["sourceHandle"],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
edge["target"],
|
||||||
|
edge["targetHandle"],
|
||||||
|
),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
xml_simulation = self.xml_root.find("./Simulation")
|
||||||
|
self.assertIsNotNone(xml_simulation)
|
||||||
|
assert xml_simulation is not None
|
||||||
|
project_simulation = self.project["simulation"]
|
||||||
|
expected_simulation = {
|
||||||
|
"tStart": float(project_simulation["t_start"]),
|
||||||
|
"tStop": float(project_simulation["t_stop"]),
|
||||||
|
"sampleStep": float(project_simulation["step"]),
|
||||||
|
"maxStep": float(project_simulation["max_step"]),
|
||||||
|
}
|
||||||
|
for name, expected in expected_simulation.items():
|
||||||
|
self.assertEqual(
|
||||||
|
float(xml_simulation.attrib[name]), expected
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
xml_simulation.attrib["method"],
|
||||||
|
project_simulation["method"],
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
project_simulation["t_start"],
|
||||||
|
self.ame.simulation_values[0],
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
project_simulation["t_stop"],
|
||||||
|
self.ame.simulation_values[1],
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
project_simulation["step"],
|
||||||
|
self.ame.simulation_values[2],
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
project_simulation["max_step"],
|
||||||
|
self.ame.simulation_values[5],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
@@ -1,10 +1,14 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import csv
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from app.simulation.reporting.amesim_results import load_test_mql_amesim_results
|
from app.simulation.reporting.amesim_results import (
|
||||||
|
AmesimResults,
|
||||||
|
load_test_mql_amesim_results,
|
||||||
|
)
|
||||||
from app.simulation.reporting.test_mql_comparison import (
|
from app.simulation.reporting.test_mql_comparison import (
|
||||||
DEFAULT_TEST_MQL_ALIGNMENT_PATHS,
|
DEFAULT_TEST_MQL_ALIGNMENT_PATHS,
|
||||||
TestMqlComparisonError,
|
TestMqlComparisonError,
|
||||||
@@ -84,6 +88,46 @@ class TestMqlComparisonTests(unittest.TestCase):
|
|||||||
self.assertAlmostEqual(metric.mean_abs_error, 1.0)
|
self.assertAlmostEqual(metric.mean_abs_error, 1.0)
|
||||||
self.assertGreater(metric.max_rel_error, 0.0)
|
self.assertGreater(metric.max_rel_error, 0.0)
|
||||||
|
|
||||||
|
def test_zero_amesim_baseline_does_not_invent_a_relative_denominator(self) -> None:
|
||||||
|
amesim_results = AmesimResults(
|
||||||
|
times=(0.0, 1.0),
|
||||||
|
variables=(),
|
||||||
|
saved_variable_indices=(),
|
||||||
|
series_by_data_path={"zero@baseline": (0.0, -0.0)},
|
||||||
|
final_values_by_data_path={"zero@baseline": -0.0},
|
||||||
|
)
|
||||||
|
|
||||||
|
comparison = compare_test_mql_series(
|
||||||
|
python_times=(0.0, 1.0),
|
||||||
|
python_series_by_data_path={"zero@baseline": (0.0, 1.0e-6)},
|
||||||
|
amesim_results=amesim_results,
|
||||||
|
data_paths=("zero@baseline",),
|
||||||
|
)
|
||||||
|
metric = comparison.metric("zero@baseline")
|
||||||
|
|
||||||
|
self.assertEqual(metric.max_abs_error, 1.0e-6)
|
||||||
|
self.assertEqual(metric.undefined_rel_error_count, 2)
|
||||||
|
self.assertEqual(metric.near_zero_baseline_count, 2)
|
||||||
|
self.assertEqual(comparison.undefined_rel_error_count, 2)
|
||||||
|
self.assertEqual(metric.max_rel_error, 0.0)
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
|
comparison_path, _summary_path, _comparison = (
|
||||||
|
write_test_mql_comparison_csv(
|
||||||
|
output_dir=Path(temp_dir),
|
||||||
|
python_times=(0.0, 1.0),
|
||||||
|
python_series_by_data_path={
|
||||||
|
"zero@baseline": (0.0, 1.0e-6)
|
||||||
|
},
|
||||||
|
amesim_results=amesim_results,
|
||||||
|
data_paths=("zero@baseline",),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
with comparison_path.open(newline="", encoding="utf-8") as handle:
|
||||||
|
rows = list(csv.reader(handle))
|
||||||
|
self.assertEqual(rows[1][-1], "")
|
||||||
|
self.assertEqual(rows[2][-1], "")
|
||||||
|
|
||||||
def test_missing_data_path_is_rejected(self) -> None:
|
def test_missing_data_path_is_rejected(self) -> None:
|
||||||
with self.assertRaises(TestMqlComparisonError):
|
with self.assertRaises(TestMqlComparisonError):
|
||||||
compare_test_mql_series(
|
compare_test_mql_series(
|
||||||
|
|||||||
Reference in new issue
Block a user