Files
SystemSimulationApp/tests/test_native_friction.py

56 lines
3.4 KiB
Python

"""Native event integration checked against independent Amesim 2404 runs."""
import json
from pathlib import Path
import subprocess
import tempfile
import unittest
import numpy as np
from app.simulation.native_codegen.compiler import compile_native_program
from app.simulation.native_codegen.build import build_native
from app.simulation.native_codegen.result_storage import scan_blocks
from tests.test_native_catalog import Circuit
FIXTURE=Path(__file__).parent/'fixtures/amesim-component-semantics-2404.json'
class NativeFrictionReferenceTests(unittest.TestCase):
def test_amesim_stick_slip_endstops_and_joint_circuits(self):
for case in json.loads(FIXTURE.read_text(encoding='utf-8'))['cases']:
b=Circuit()
for c in case['components']:b.add(c['type'],c['name'],**c['parameters'])
for l,r in case['connections']:b.net.connect(*l,*r)
program=compile_native_program(b.net)
build=build_native(program)
self.addCleanup(build.close)
methods=('BDF','RK45') if case['name'] in ('friction_simple','friction_band') else ('BDF',)
for method in methods:
with self.subTest(case=case['name'],method=method),tempfile.TemporaryDirectory() as tmp:
path=Path(tmp)/'result.json'
state_path=Path(tmp)/'states.bin';output_path=Path(tmp)/'outputs.bin'
subprocess.run([str(build.executable),'--method',method,'--stop','3','--sample-step','.001',
'--max-step','.002','--rtol','1e-9','--timeout','30','--output',str(path),
'--sample-file',str(state_path),'--output-block-file',str(output_path)],
check=True,capture_output=True,timeout=45)
result=json.loads(path.read_text())
self.assertTrue(result['success'],result)
self.assertEqual(result['simulatedUntil'],3)
for blocks, columns in ((state_path,len(program.state_keys)+1),
(output_path,len(program.variables)+1)):
stored=scan_blocks(blocks,expected_columns=columns)
self.assertGreater(stored['blocks'],1)
self.assertEqual(stored['samples'],len(result['series']['time']))
self.assertFalse(stored['incompleteTail'] or stored['corrupt'])
for key,expected in case['series'].items():
actual=np.interp(case['time'],result['series']['time'],result['series'][key])
field=key.split('.')[-1]
atol=1 if field.startswith('p') else .001 if field.startswith('T') else .002 if field in ('a','Ffric','Fmin','Fmax','force') else 3e-6
np.testing.assert_allclose(actual,expected,rtol=0,atol=atol,err_msg=key)
if case['name'].startswith('friction_'):
# Stored mode makes result replay independent of query order.
state=result['finalState']
inputs=[' '.join(map(str,[t,*state])) for t in (2.8,.1,2.8)]
rows=subprocess.run([str(build.executable),'--probe'],input='\n'.join(inputs)+'\n',
text=True,capture_output=True,check=True,timeout=15).stdout.splitlines()
self.assertEqual(json.loads(rows[0]),json.loads(rows[2]))
if __name__=='__main__':unittest.main()