优化雅可比矩阵计算;端口转发情况下仿真结果传输方式优化
This commit is contained in:
1 parent
3bc4be3c06
commit
aa4951b14e
28 files changed
+8038
-23
No files matched your search
@@ -13,6 +13,7 @@ from .compiler import NativeCapabilityError, NativeProgram, _Groups, _number as
|
||||
from .contracts import SUPPORTED_VERSIONS
|
||||
from .schedule import Computation, EvaluationSchedule, references
|
||||
from .tolerances import state_absolute_tolerance
|
||||
from .jacobian import StateDependencies, expression_inputs
|
||||
|
||||
|
||||
GAS_TYPES = {'amesim_pnch023', 'amesim_pnch012', 'amesim_pnl0001',
|
||||
@@ -149,6 +150,7 @@ def compile_extended_program(network):
|
||||
nstates = max(len(state_keys), 1)
|
||||
if not initial:
|
||||
initial = [0.0]
|
||||
dependencies = StateDependencies(len(state_keys))
|
||||
lines, declarations, breaks = [], [], []
|
||||
assigned = set()
|
||||
def w(c, field):
|
||||
@@ -156,6 +158,7 @@ def compile_extended_program(network):
|
||||
return f'w[{slots[name+"."+field]}]'
|
||||
def put(c, field, expr, dest=None):
|
||||
(lines if dest is None else dest).append(f'{w(c,field)} = {expr};')
|
||||
dependencies.expression(w(c,field), expr)
|
||||
assigned.add((c if isinstance(c,str) else c.name)+'.'+field)
|
||||
def y(c, field):
|
||||
return f'y[{states[c.name,field]}]'
|
||||
@@ -268,7 +271,10 @@ def compile_extended_program(network):
|
||||
if kind=='amesim_pnch012' else
|
||||
c.cvol if kind=='amesim_pnch023' else c.V if kind in ('cylinder','tank') else c.volume)
|
||||
gas_initializers.append(f'if(!native_medium_init({medium(c)},{num(p0)},{num(T0)},{num(initial_volume)},{int(kind in ("cylinder","tank"))},&y[{states[c.name,"m"+suffix]}])) return 0;')
|
||||
lines.append(f'if(!native_medium_gas_context(properties,{medium(c)}, {y(c,"m"+suffix)}, {y(c,"U"+suffix)}, {V}, &{gas})) return 0;')
|
||||
lines.append(f'if(!native_medium_gas_context(gas_properties,{medium(c)}, {y(c,"m"+suffix)}, {y(c,"U"+suffix)}, {V}, &{gas})) return 0;')
|
||||
gas_inputs = expression_inputs(f'{y(c,"m"+suffix)}+{y(c,"U"+suffix)}+({V})')
|
||||
for field in ('p','T','rho','u','h'):
|
||||
dependencies.assign(gas+'.'+field, gas_inputs)
|
||||
for field in ('m', 'U'):
|
||||
put(c, field+suffix, y(c, field+suffix))
|
||||
for field in ('p','T','rho','u','h'):
|
||||
@@ -304,8 +310,11 @@ def compile_extended_program(network):
|
||||
project += [f'projected[{i}]=mass*{num(volume/total)};projected[{i+1}]=energy*{num(volume/total)};']
|
||||
project.append('}')
|
||||
coupled.append((root,offsets,volumes))
|
||||
dependencies.project_states(offsets)
|
||||
dependencies.project_states([i+1 for i in offsets])
|
||||
for root, gas in anchor.items():
|
||||
lines.append(f'p[{pgi[root]}]={gas}.p;')
|
||||
dependencies.assign(f'p[{pgi[root]}]', (gas+'.p',))
|
||||
h_initial = {f'h[{pi[endpoint]}]': gas+'.h' for endpoint,gas in port_gas.items()}
|
||||
|
||||
operations, flow_known, flow_eq = [], set(), []
|
||||
@@ -437,9 +446,12 @@ def compile_extended_program(network):
|
||||
for root,index in pgi.items():
|
||||
labels[f'p[{index}]']='pressure:'+','.join('.'.join(ep) for ep in pneu if groups.find(ep)==root)
|
||||
schedule=EvaluationSchedule(operations,known,labels)
|
||||
for operation in operations:
|
||||
dependencies.computation(operation)
|
||||
for target,expr in h_initial.items():
|
||||
if target not in schedule.producers:
|
||||
lines.append(f'{target}={expr};')
|
||||
dependencies.expression(target, expr)
|
||||
schedule_helpers, scheduled_lines=schedule.emit()
|
||||
lines += scheduled_lines
|
||||
for c in components:
|
||||
@@ -481,7 +493,10 @@ def compile_extended_program(network):
|
||||
if c.use_friction: extra+=f'-{num(c.wind)}*{v}*fabs({v})'
|
||||
feq.append(({w(c,'port_1.f'):1,w(c,'port_2.f'):1,w(ref,'a'):-c.mass},f'-({extra})'))
|
||||
unknownf=[w(c,name+'.f') for c in components for name in mnames(c)]+[w(group[0],'a') for group in mass_groups.values()]
|
||||
lines += linear_schedule(feq,unknownf)
|
||||
# Keep the same elimination/order while registering its structured bindings.
|
||||
for target, expression in linear_assignments(feq, unknownf):
|
||||
lines.append(f'{"double " if target.startswith("b") else ""}{target} = {expression};')
|
||||
dependencies.expression(target, expression)
|
||||
for c in components:
|
||||
for name in mnames(c): assigned.add(c.name+'.'+name+'.f')
|
||||
if c.model_type=='amesim_lmechn1':
|
||||
@@ -491,6 +506,8 @@ def compile_extended_program(network):
|
||||
ref=group[0];vi=states[ref.name,'v'];xi=states[ref.name,'x']
|
||||
limits=[c for c in group if int(c.stoptype) in (1,3)]
|
||||
lines += [f'dy[{vi}]={w(ref,"a")};dy[{xi}]={y(ref,"v")};']
|
||||
dependencies.expression(f'dy[{vi}]', w(ref,'a'))
|
||||
dependencies.expression(f'dy[{xi}]', y(ref,'v'))
|
||||
if limits:
|
||||
lower=max(c.xmin for c in limits);upper=min(c.xmax for c in limits)
|
||||
if lower>upper or ref.x0<lower-1e-12 or ref.x0>upper+1e-12:
|
||||
@@ -502,6 +519,7 @@ def compile_extended_program(network):
|
||||
thresholds.append(max((c.restdvel for c in active if int(c.stoptype)==3),default=0))
|
||||
stops.append((vi,lower,upper,*restitution,*thresholds))
|
||||
lines.append(f'native_stop_motion({y(ref,"x")},{y(ref,"v")},{num(lower)},{num(upper)},&dy[{vi}],&dy[{xi}]);')
|
||||
dependencies.stop_motion(vi, xi)
|
||||
for c in group: put(c,'a',f'dy[{vi}]')
|
||||
|
||||
for c in components:
|
||||
@@ -530,6 +548,8 @@ def compile_extended_program(network):
|
||||
temp=f'.5*({gases[c.name,1]}.T+{gases[c.name,2]}.T)' if half else gas+'.T'
|
||||
heat=f'{num(c.kth*c.exchange_area/(2 if half else 1))}*({num(c.extemp)}-({temp}))'
|
||||
lines += [f'dy[{states[c.name,"m"+suffix]}]={mass};',f'dy[{states[c.name,"U"+suffix]}]={energy}+({heat});']
|
||||
dependencies.expression(f'dy[{states[c.name,"m"+suffix]}]', mass)
|
||||
dependencies.expression(f'dy[{states[c.name,"U"+suffix]}]', f'{energy}+({heat})')
|
||||
if kind.startswith('amesim_pnl'):
|
||||
diag=[]
|
||||
if kind=='amesim_pnl0002':
|
||||
@@ -562,21 +582,26 @@ def compile_extended_program(network):
|
||||
lines.append('{ double mass='+ '+'.join(f'dy[{i}]' for i in offsets)+',energy='+ '+'.join(f'dy[{i+1}]' for i in offsets)+';')
|
||||
for i,volume in zip(offsets,volumes):
|
||||
lines.append(f'dy[{i}]=mass*{num(volume/sum(volumes))};dy[{i+1}]=energy*{num(volume/sum(volumes))};')
|
||||
dependencies.assign(f'dy[{i}]', (f'dy[{j}]' for j in offsets))
|
||||
dependencies.assign(f'dy[{i+1}]', (f'dy[{j+1}]' for j in offsets))
|
||||
lines.append('}')
|
||||
missing=set(slots)-assigned
|
||||
if missing: raise NativeCapabilityError(f'Native output mapping incomplete: {sorted(missing)}')
|
||||
if not state_keys: lines.append('dy[0]=0;')
|
||||
jacobian = dependencies.build()
|
||||
np,ng,nq=max(1,len(pgroups)),max(1,gas_count),max(1,len(pneu))
|
||||
source='\n'.join(['#include "model.h"','#include <math.h>',*declarations,
|
||||
f'const NativeStop model_stops[{max(1,len(stops))}] = {{'+(','.join('{'+str(s[0])+','+','.join(num(v) for v in s[1:])+'}' for s in stops) or '{0,0,0,0,0,0,0}')+'};',
|
||||
'const double model_atol[NSTATES] = {'+','.join(map(state_absolute_tolerance, state_keys or ['dummy']))+'};',
|
||||
'const char *const model_output_keys[NOUTPUTS] = {'+(','.join(json.dumps(v.key,ensure_ascii=True) for v in variables) or '""')+'};',
|
||||
*jacobian.source_lines(),
|
||||
*schedule_helpers,
|
||||
'int model_init(double *y) {',*[f'y[{i}]={num(v)};' for i,v in enumerate(initial)],*gas_initializers,'return 1;}',
|
||||
'int model_eval(double t,const double *y,double *dy,double *w) {',
|
||||
'static int model_eval_internal(double t,const double *y,double *dy,double *w,int canonical) {',
|
||||
f'NativePropertyState property_states[{min(256,max(16,4*gas_count+2*len(components)))}];',
|
||||
'NativePropertyCache property_cache, *properties=&property_cache;',
|
||||
'native_properties_init(properties,property_states,sizeof(property_states)/sizeof(property_states[0]));',
|
||||
'NativePropertyCache *gas_properties=canonical?NULL:properties;(void)gas_properties;',
|
||||
*(['double projected[NSTATES];for(int i=0;i<NSTATES;i++) projected[i]=y[i];',*project,'y=projected;'] if project else []),
|
||||
f'double p[{np}]={{0}},h[{nq}]={{0}},q[{nq}]={{0}};NativeGas g[{ng}];',
|
||||
f'double fb[{max(1,flow_temporary_count)}]={{0}};(void)fb;',
|
||||
@@ -584,6 +609,8 @@ def compile_extended_program(network):
|
||||
'(void)t;(void)y;(void)w;(void)p;(void)h;(void)q;(void)g;',*lines,
|
||||
'for(int i=0;i<NSTATES;i++) if(!isfinite(dy[i])) return 0;',
|
||||
'for(int i=0;i<NOUTPUTS;i++) if(!isfinite(w[i])) return 0;','return 1;}',
|
||||
'int model_eval(double t,const double *y,double *dy,double *w) {return model_eval_internal(t,y,dy,w,0);}',
|
||||
'int model_eval_jacobian(double t,const double *y,double *dy,double *w) {return model_eval_internal(t,y,dy,w,1);}',
|
||||
'double model_next_break(double t,double end) { double result=end;(void)t;',*breaks,'return result;}',''])
|
||||
header=f'''#ifndef GENERATED_NATIVE_MODEL_H
|
||||
#define GENERATED_NATIVE_MODEL_H
|
||||
@@ -594,9 +621,10 @@ def compile_extended_program(network):
|
||||
extern const NativeStop model_stops[{max(1,len(stops))}];
|
||||
extern const double model_atol[NSTATES];
|
||||
extern const char *const model_output_keys[NOUTPUTS];
|
||||
{chr(10).join(jacobian.header_lines(canonical_rhs=True))}
|
||||
int model_init(double *y);
|
||||
int model_eval(double t,const double *y,double *dy,double *w);
|
||||
double model_next_break(double t,double end);
|
||||
#endif
|
||||
'''
|
||||
return NativeProgram(source,header,tuple(state_keys),variables,tuple(sorted({c.model_type for c in components})),schedule.report())
|
||||
return NativeProgram(source,header,tuple(state_keys),variables,tuple(sorted({c.model_type for c in components})),schedule.report(),jacobian.manifest(canonical_rhs=True))
|
||||
Reference in new issue
Block a user