高温氦气物性补全;三通四通能量计算bug修正

This commit is contained in:
ljz committed 2026-09-15 17:57:20 +08:00
1 parent 6fc9afe41d
commit 2b07d996cf
133 files changed
+5230 -253310

No files matched your search

+112
View File
@@ -0,0 +1,112 @@
"""Property-domain diagnostics must be nonfatal and independent of trial states."""
from dataclasses import replace
import json
from pathlib import Path
import subprocess
import tempfile
import unittest
from app.simulation.components.amesim.media.mediums import AmesimIdealAirMedium
from app.simulation.config import SolveIVPConfig
from app.simulation.native_codegen.build import build_native, toolchain, _command
from app.simulation.native_codegen.compiler import _compile_storage_anchored_program
from app.simulation.native_codegen.extended import compile_extended_program
from app.simulation.native_codegen.runner import execute_native
from tests.test_native_catalog import Circuit
ROOT = Path(__file__).resolve().parents[1]
class NativePropertyWarningTests(unittest.TestCase):
def run_program(self, program, method='BDF', **kwargs):
build = build_native(program)
self.addCleanup(build.close)
with tempfile.TemporaryDirectory() as directory:
events = []
result = execute_native(build, SolveIVPConfig(t_stop=.01, max_step=.001, method=method),
.001, run_dir=Path(directory), record_samples=False,
warning_callback=events.append, **kwargs)
self.assertTrue(result['success'], result['message'])
self.assertEqual(len(events), len(result['propertyWarnings']))
for warning in result['propertyWarnings']:
self.assertNotIn('component', warning)
self.assertIn('氦气', warning['message'])
self.assertIn('K', warning['message'])
return result
def test_both_generators_boundaries_and_no_viscosity_when_unused(self):
for compiler in (_compile_storage_anchored_program, compile_extended_program):
for T, expected in ((200, []), (1500, []), (1500.01, ['helium-equation-of-state-high']),
(100, ['helium-ideal-caloric-low']),
(20000, ['helium-equation-of-state-high']),
(20000.01, ['helium-equation-of-state-high', 'helium-ideal-caloric-high'])):
with self.subTest(compiler=compiler.__name__, T=T):
b = Circuit(); b.chamber('gas', p0=1e5, T0=T, kth=0)
result = self.run_program(compiler(b.seal()))
self.assertEqual([w['code'] for w in result['propertyWarnings']], expected)
self.assertTrue(all(w['time'] == 0 for w in result['propertyWarnings']))
def test_live_dedup_extrema_and_unchanged_numerical_results(self):
b = Circuit()
b.chamber('gas', p0=1e5, T0=1400, kth=1000, sth=1, extemp=26000)
program = compile_extended_program(b.seal())
disabled = replace(program, header=program.header.replace(
'#define MODEL_PROPERTY_TEMPERATURES 1', '#define MODEL_PROPERTY_TEMPERATURES 0'))
for method in ('RK45', 'BDF'):
with self.subTest(method=method):
enabled_result = self.run_program(program, method)
disabled_result = self.run_program(disabled, method)
warnings = enabled_result['propertyWarnings']
self.assertEqual(len(warnings), 2)
for warning in warnings:
self.assertGreater(warning['time'], 0)
self.assertGreater(warning['extremeTemperature'], warning['temperature'])
self.assertGreaterEqual(warning['extremeTime'], warning['time'])
for key in ('finalState', 'final', 'nfev', 'njev', 'nlu', 'acceptedSteps', 'rejectedSteps'):
self.assertEqual(enabled_result[key], disabled_result[key], key)
def test_pipe_viscosity_and_air_domain_not_invented(self):
for medium, expected in ((None, {'equation-of-state', 'ideal-caloric', 'dynamic-viscosity'}),
(AmesimIdealAirMedium(), set())):
b = Circuit(medium)
left = b.chamber('left', p0=2e5, T0=25000, kth=0)
pipe = b.add('amesim_pnl0001', 'pipe', p0=1e5, T0=25000, kth=0, diam=.001, le=1)
b.connect(left, 'port_1', pipe, 'port_1')
result = self.run_program(compile_extended_program(b.seal()))
self.assertEqual({w['property'] for w in result['propertyWarnings']}, expected)
def test_observer_survives_full_cache_and_ignores_unobserved_trials(self):
source = '#include "%s"\n' % (ROOT/'native/components/modules/properties.c').as_posix() + r'''
#include <stdio.h>
#define CHECK(x) do {if(!(x)){fprintf(stderr,"line %d\n",__LINE__);return 1;}} while(0)
int main(void) {
NativePropertyCache cache;NativePropertyState scratch;
NativePropertyTemperatures report={0};
native_properties_init(&cache,NULL,0);cache.temperatures=&report;
NativePropertyState *s=property_pt(&cache,&helium_medium,1e5,100,&scratch);
property_density(s);property_viscosity(s);local_isentropic(s);
CHECK(report.seen==7 && report.minimum[0]==100 && report.minimum[2]==100);
s=property_pt(&cache,&helium_medium,1e5,25000,&scratch);
property_density(s);property_viscosity(s);local_isentropic(s);
CHECK(report.maximum[0]==25000 && report.maximum[1]==25000 && report.maximum[2]==25000);
/* Ordinary RHS-style calls have no observer and cannot affect reports. */
native_properties_init(&cache,NULL,0);
native_density_context(&cache,&helium_medium,1e5,50000);
CHECK(report.maximum[0]==25000);
NativePropertyTemperatures next={0};cache.temperatures=&next;
native_density_context(&cache,&helium_medium,1e5,300);
CHECK(next.seen==1 && next.minimum[0]==300 && next.maximum[0]==300);
return 0;
}
'''
with tempfile.TemporaryDirectory() as directory:
root = Path(directory); path = root/'test.c'; exe = root/'test.exe'
path.write_text(source)
_command([toolchain()[0], '-std=c11', '-O2', '-Wall', '-Wextra', '-Werror',
'-I', str(ROOT/'native/include'), str(path), '-lm', '-o', str(exe)], log=[])
result = subprocess.run([str(exe)], capture_output=True, text=True, timeout=20)
self.assertEqual(result.returncode, 0, result.stderr)
if __name__ == '__main__':
unittest.main()