Dymos/OpenMDAO仿真高压瓶排液时Vb参数无效报错求助
Dymos高压瓶排液仿真报错修复方案
核心报错根因
报错提示找不到pressure_rate.Vb输入,是因为你在BottleModelODE组组件中通过promotes_inputs将pressure_rate子系统的Vb、p等输入提升到了ODE组的顶层命名空间,此时这些输入的访问路径不再带子系统前缀,直接以变量名存在于ODE组层级,原代码中写的带前缀的target路径自然无法匹配到对应输入。
全量修复点
- 修正状态、参数的target路径:所有被promote到组顶层的变量,target直接写变量名即可,不需要带
pressure_rate./volume_flow_rate.前缀;同时rate_source也直接写提升后的输出名(如p_dot、Vl_dot)即可。 - 删除
BottleModelODE中多余的connect语句:p、Vl_dot已经被提升到组顶层,两个子系统的同名输入会自动连接到同一个组级变量,手动重复连接会触发OpenMDAO重复连接报错。 - 修复
VolumeFlowRate类的重复定义问题:类中写了两个setup方法,第二个会覆盖第一个,导致num_nodes配置失效、所有输入未设置向量化形状。删除冗余setup,将num_nodes读取、输入shape配置(所有输入shape设为(nn,),和PressureRate保持一致)合并到同一个setup方法中。 - 修正拼写错误:后续
set_val时把phase名expulsion错写为explusion(字母l、s顺序颠倒),会导致赋值路径不存在。 - 修复语法错误:
bottle_params字典中pinit键名前缺失双引号,会触发Python语法报错;同时字典中缺失deltap键值,后续赋值会触发键不存在错误。 - 修正单位不匹配问题:状态
p定义单位为bar,但初始值、出口压力等参数传入的都是Pa单位的数值,量级差1e5,直接仿真会得到完全错误的结果,统一将压力相关单位设为Pa即可。 - 修正物理公式错误:
PressureRate中压力变化率公式符号反了——定义流出流量为正的情况下,液体流出导致液位降低、气相体积膨胀,瓶内压力应该下降,公式需要补负号;另外流量计算时要对压差做非负截断,避免瓶内压力低于出口压力时根号内出现负数,导致仿真出现NaN。 - 修正数值错误:调用
trajectory时传入的环境压力误写为100*10*3(结果为10kPa),和定义的100kPa环境压力不符,改为100*10**3。 - 移除不必要的优化配置:你使用
solve_segments='forward'做正向积分仿真,没有将终止时间设为设计变量,不需要配置SLSQP驱动和时间目标,直接调用prob.run_model()即可运行仿真,多余的优化配置反而可能引入未知错误。
修复后的关键代码片段
修复后的VolumeFlowRate组件
class VolumeFlowRate(om.ExplicitComponent): def initialize(self): self.options.declare('num_nodes', types=int) def setup(self): nn = self.options['num_nodes'] # 所有输入配置向量化shape self.add_input('p', shape=(nn,), desc='Pressure inside the nox_bottle', units='Pa') self.add_input('pout', shape=(nn,), desc='Pressure outside the nox_bottle', units='Pa') self.add_input('deltap', shape=(nn,), desc='Nox bottle pressure losses', units='Pa') self.add_input('rhol', shape=(nn,), desc='Liquid density', units='kg/m**3') self.add_input('Aout', shape=(nn,), desc='Output nox_bottle area', units='m**2') self.add_output('Vl_dot', shape=(nn,), desc='Volume flow rate', units='m**3/s') self.declare_partials(of='*', wrt='*', method='fd') def compute(self, inputs, outputs): p = inputs['p'] pout = inputs['pout'] deltap = inputs['deltap'] rhol = inputs['rhol'] Aout = inputs['Aout'] # 压差做非负截断,避免根号出负数 dp = np.maximum(p - pout - deltap, 0) outputs['Vl_dot'] = Aout*np.sqrt(2/rhol*dp)
修复后的PressureRate组件compute方法
def compute(self, inputs, outputs): p = inputs['p'] Vb = inputs['Vb'] Vl = inputs['Vl'] Vl_dot = inputs['Vl_dot'] gamma = inputs['gamma'] # 补负号,流出为正时压力下降 outputs['p_dot'] = - gamma * p/(Vb - Vl) * Vl_dot
修复后的BottleModelODE组
class BottleModelODE(om.Group): def initialize(self): self.options.declare('num_nodes', types=int) def setup(self): nn = self.options['num_nodes'] self.add_subsystem('pressure_rate', subsys=PressureRate(num_nodes=nn), promotes_inputs=['p', "Vb", "Vl", "Vl_dot", "gamma"], promotes_outputs=['p_dot']) self.add_subsystem('volume_flow_rate', subsys=VolumeFlowRate(num_nodes=nn), promotes_inputs=['p', "pout", 'deltap', 'rhol', "Aout"], promotes_outputs=['Vl_dot']) # 删除冗余connect语句,promote后变量自动连通
修复后的相配置
phase.add_state('p', units='Pa', rate_source='p_dot', targets=['p'], fix_initial=True, fix_final=False, lower=pamb) phase.add_state('Vl', units='m**3', rate_source='Vl_dot', targets=['Vl'], fix_initial=True, fix_final=False, lower=0) phase.add_parameter('Vb', targets=['Vb'], units='m**3') phase.add_parameter('gamma', targets=['gamma']) phase.add_parameter('rhol', targets=['rhol'], units='kg/m**3') phase.add_parameter('Aout', targets=['Aout'], units='m**2') phase.add_parameter('pout', targets=['pout'], units="Pa") phase.add_parameter('deltap', targets=['deltap'], units="Pa")
修复后的问题配置与赋值
def launch_compt(): pamb = 100*10**3 # 补全参数字典,修正语法错误 bottle_params = { "Vb": 5*10**-3, "gamma": 1.4, "Aout": 3*10**-2, "rhol": 1000, "pout": pamb, "pinit": 300*10**3, "Vl": 1*10**-3, "deltap": 0 } prob = om.Problem(model=om.Group()) # 移除不必要的优化驱动,正向仿真直接用默认驱动即可 traj, phase = trajectory(pamb=pamb) prob.model.add_subsystem("traj", traj) prob.setup() # 修正phase名拼写错误 prob.set_val('traj.expulsion.t_initial', 0.0) prob.set_val('traj.expulsion.t_duration', 200.0) prob.set_val('traj.expulsion.states:p', bottle_params["pinit"]) prob.set_val('traj.expulsion.states:Vl', bottle_params["Vl"]) prob.set_val('traj.expulsion.parameters:Vb', bottle_params["Vb"]) prob.set_val('traj.expulsion.parameters:gamma', bottle_params["gamma"]) prob.set_val('traj.expulsion.parameters:rhol', bottle_params["rhol"]) prob.set_val('traj.expulsion.parameters:Aout', bottle_params["Aout"]) prob.set_val('traj.expulsion.parameters:pout', bottle_params["pout"]) prob.set_val('traj.expulsion.parameters:deltap', bottle_params["deltap"]) # 正向仿真直接调用run_model prob.run_model()
内容的提问来源于stack exchange,提问作者Quentin Tiefaine
相关产品推荐
相关产品推荐

