修复测试模型路径并完善四路八路回归与文档
- 按文件哈希区分当前八路工程和历史 Amesim 基准,修复测试与清单中的旧路径。 - 四路审计从 JSON 按需生成 XML,八路新增只核对模式,并显式使用 UTF-8 与 LF。 - 将缺失高刚度夹具的测试替换为当前八路完整 BDF 运行,明确未恢复原 RK45 专项覆盖。 - 更新前端大型工程测试、历史活动回放入口、数据说明、现行规范和相关报告。 验证:全量后台 374 项通过、1 项条件跳过;前端 11 项通过、历史独立服务用例 1 项跳过;四路八路 AME 审计通过。 环境、缓存和运行产物保持忽略;本次未实施工程 JSON 字段精简。
This commit is contained in:
1 parent
44b6ea74ab
commit
b6c22a54f8
32 files changed
+318
-153
No files matched your search
@@ -1,4 +1,4 @@
|
||||
"""Audit the AME diagram against the corrected XML; emit an aligned browser project.
|
||||
"""Audit the AME diagram against the current browser project; generate XML on demand.
|
||||
|
||||
Run from the repository root with .venv/bin/python. Does not run Amesim or use
|
||||
the stale eight-branch compiled/result cache inside the four-branch archive.
|
||||
@@ -27,9 +27,9 @@ from tests.test_test_mql_ame_contract import (
|
||||
_public_model_type, _expected_parameters, _value_fields,
|
||||
)
|
||||
|
||||
OUT = ROOT / 'test/solver-newton-20260911/mql4'
|
||||
OUT = ROOT / 'test/model-audit/mql4'
|
||||
AME = ROOT / 'tests/data/test_mql_4.ame'
|
||||
XML = ROOT / 'tests/fixtures/amesim/test-mql-4-corrected.xml'
|
||||
XML = OUT / 'aligned-input.xml'
|
||||
REFERENCE = ROOT / 'tests/baselines/simulation/test_mql_4/test-mql-4-amesim-reference.json'
|
||||
PROJECT = ROOT / 'tests/data/test-mql-4-corrected.json'
|
||||
|
||||
@@ -147,9 +147,17 @@ def audit_source():
|
||||
}
|
||||
|
||||
|
||||
def project_xml():
|
||||
# The separately maintained XML fixture was deleted. Use the same input
|
||||
# conversion as the native CLI; the AME remains the independent authority.
|
||||
from app.simulation.native_codegen.input import load_input
|
||||
xml, _ = load_input(PROJECT)
|
||||
return xml
|
||||
|
||||
|
||||
def xml_model(root=None):
|
||||
if root is None:
|
||||
root = ET.parse(XML).getroot()
|
||||
root = ET.fromstring(project_xml())
|
||||
nodes = {item.attrib['id']: {
|
||||
'modelType': item.attrib['type'],
|
||||
'modelVersion': item.attrib['modelVersion'],
|
||||
@@ -257,8 +265,9 @@ def check_project_contract(project, xml_root):
|
||||
|
||||
|
||||
def generate_project(source, source_edges, target, target_edges, xml_root, mapping):
|
||||
layout_source = ROOT / 'tests/fixtures/legacy/test-mql-8.json'
|
||||
layout = json.loads(layout_source.read_text())
|
||||
layout_source = PROJECT
|
||||
layout = json.loads(layout_source.read_text(encoding='utf-8'))
|
||||
layout_sha = sha(layout_source)
|
||||
layout_nodes = {node['id']: node for node in layout['nodes']}
|
||||
reverse_mapping = {value: key for key, value in mapping.items()}
|
||||
nodes = []
|
||||
@@ -331,14 +340,14 @@ def generate_project(source, source_edges, target, target_edges, xml_root, mappi
|
||||
project = {'projectSchemaVersion': 1, 'name': 'test-mql-4-AME-aligned', 'nodes': nodes,
|
||||
'edges': edges, 'simulation': simulation}
|
||||
check_project_contract(project, xml_root)
|
||||
PROJECT.write_text(json.dumps(project, indent=2, ensure_ascii=False) + '\n')
|
||||
PROJECT.write_text(json.dumps(project, indent=2, ensure_ascii=False) + '\n', encoding='utf-8', newline='\n')
|
||||
generated_xml = OUT / 'aligned-input.xml'
|
||||
xml_root.attrib['name'] = project['name']
|
||||
ET.indent(xml_root)
|
||||
ET.ElementTree(xml_root).write(generated_xml, encoding='utf-8', xml_declaration=True)
|
||||
XML.write_bytes(generated_xml.read_bytes())
|
||||
# Check the delivered JSON itself, including every exact endpoint and number.
|
||||
json_nodes = {node['id']: node['data'] for node in json.loads(PROJECT.read_text())['nodes']}
|
||||
json_nodes = {node['id']: node['data'] for node in json.loads(PROJECT.read_text(encoding='utf-8'))['nodes']}
|
||||
for source_id, project_id in mapping.items():
|
||||
assert json_nodes[project_id]['parameters'] == source[source_id]['parameters']
|
||||
expected_edges = {tuple(sorted(((mapping[a], ap), (mapping[b], bp)))) for ((a, ap), (b, bp)) in source_edges}
|
||||
@@ -354,34 +363,44 @@ def generate_project(source, source_edges, target, target_edges, xml_root, mappi
|
||||
'nodeCount': len(nodes), 'edgeCount': len(edges), 'parameterCount': sum(len(n['data']['parameters']) for n in nodes),
|
||||
'allMappedParametersExactlyMatchAme': True, 'allMappedConnectionPortsExactlyMatchAme': True,
|
||||
'parameterChangesFromLegacyXml': parameter_changes, 'connectionPortChangesFromLegacyXml': changed_connections,
|
||||
'layoutMetadataSource': {'path': str(layout_source.relative_to(ROOT)), 'sha256': sha(layout_source)},
|
||||
'layoutMetadataSource': {'path': str(layout_source.relative_to(ROOT)), 'sha256': layout_sha},
|
||||
'simulation': simulation,
|
||||
'simulationSettingsNote': 'AME archive stores historical fixed-step settings. This JSON uses native BDF; rtol is supplied by the backend and is not stored in the project. Initial validation used 1e-7; the backend default was subsequently changed to 1e-8. The earlier official Standard variable-step reference remains tolerance 1e-7. Inspect actual run diagnostics; solver algorithms are not identical.'}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--check', action='store_true', help='Validate delivered JSON/XML only; do not generate or write files.')
|
||||
parser.add_argument('--check', action='store_true', help='Check current JSON parameters and exact connection ports against AME; generate XML in memory, without file writes.')
|
||||
arguments = parser.parse_args()
|
||||
if arguments.check:
|
||||
print(json.dumps(check_project_contract(json.loads(PROJECT.read_text()), ET.parse(XML).getroot()), indent=2))
|
||||
target, target_edges, xml_root = xml_model()
|
||||
result = check_project_contract(json.loads(PROJECT.read_text(encoding='utf-8')), xml_root)
|
||||
source, source_edges, _ = audit_source()
|
||||
mapping = find_mapping(source, source_edges, target, target_edges, ports=True)
|
||||
if mapping is None or len(source) != len(target) or len(source_edges) != len(target_edges):
|
||||
raise ValueError('Current JSON differs from AME in components, parameters or connection ports.')
|
||||
for source_id, target_id in mapping.items():
|
||||
if source[source_id]['parameters'] != target[target_id]['parameters']:
|
||||
raise ValueError(f'{target_id}: parameters do not exactly match AME.')
|
||||
result['ameParametersAndConnectionPortsMatch'] = True
|
||||
result['executionXmlSource'] = str(PROJECT.relative_to(ROOT))
|
||||
print(json.dumps(result, indent=2))
|
||||
return
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
source, source_edges, audit = audit_source()
|
||||
legacy_xml = OUT / 'legacy-corrected-input.xml'
|
||||
if not legacy_xml.exists():
|
||||
legacy_xml.write_bytes(XML.read_bytes())
|
||||
XML.write_bytes(project_xml())
|
||||
(OUT / 'input-before-audit.xml').write_bytes(XML.read_bytes())
|
||||
target, target_edges, xml_root = xml_model()
|
||||
mapping = find_mapping(source, source_edges, target, target_edges)
|
||||
audit['correctedXml'] = {'path': str(XML.relative_to(ROOT)), 'sha256': sha(XML),
|
||||
'parameterAndComponentTopologyIsomorphic': mapping is not None}
|
||||
ref = json.loads(REFERENCE.read_text())
|
||||
ref = json.loads(REFERENCE.read_text(encoding='utf-8'))
|
||||
audit['reference'] = {'path': str(REFERENCE.relative_to(ROOT)), 'sha256': sha(REFERENCE),
|
||||
'source': ref['source'], 'timeCount': len(ref['times']), 'seriesCount': len(ref['series']),
|
||||
'ameHashMatches': ref['originalAmeSha256'] == sha(AME),
|
||||
'xmlHashMatches': ref['xmlSha256'] == sha(XML),
|
||||
'newAmesimRunPerformed': False}
|
||||
(OUT / 'source-model.json').write_text(json.dumps({'nodes': source, 'edges': source_edges}, indent=2, ensure_ascii=False) + '\n')
|
||||
(OUT / 'source-model.json').write_text(json.dumps({'nodes': source, 'edges': source_edges}, indent=2, ensure_ascii=False) + '\n', encoding='utf-8', newline='\n')
|
||||
if not mapping:
|
||||
mapping = find_mapping(source, source_edges, target, target_edges, parameters=False)
|
||||
if mapping:
|
||||
@@ -394,8 +413,8 @@ def main():
|
||||
audit['generatedProject'] = generate_project(source, source_edges, target, target_edges, xml_root, mapping)
|
||||
audit['correctedXml']['scope'] = 'Input XML snapshot before this generation; generatedProject describes the delivered corrected files.'
|
||||
audit_text = json.dumps(audit, indent=2, ensure_ascii=False) + '\n'
|
||||
(OUT / 'model-audit.json').write_text(audit_text)
|
||||
(ROOT / 'tests/model_audit/test-mql-4-audit.json').write_text(audit_text)
|
||||
(OUT / 'model-audit.json').write_text(audit_text, encoding='utf-8', newline='\n')
|
||||
(ROOT / 'tests/model_audit/test-mql-4-audit.json').write_text(audit_text, encoding='utf-8', newline='\n')
|
||||
print(json.dumps({key: value for key, value in audit.items() if key not in {'componentMapping', 'members', 'globals'}}, indent=2))
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user