You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用Simulator求解Trambouze反应Pyomo模型时触发TypeError错误

Pyomo模拟Trambouze反应时TypeError错误排查与解决

问题背景

使用Pyomo定义Trambouze反应的PFR模型,调用Simulator并指定scipy包模拟时触发TypeError: 'float' object is not callable错误,相关代码及错误信息如下:

模型定义代码

# kinetic constants
k1 = 0.0001 # mol/dm3*s
k2 = 0.0015 # s-1
k3 = 0.008 # dm3/mol*s

# create pyomo model
def PFR_trambouze(CAo = 0.112, CBo = 0.132, CXo = 0.0783, CYo = 0.0786):
    m = ConcreteModel()

    # define time variable and bounds
    m.t = ContinuousSet(bounds=(0.0, 300.0))
    # define species concentrations
    m.CA = Var(m.t)
    m.CB = Var(m.t)
    m.CX = Var(m.t)
    m.CY = Var(m.t)

    # define differential variables
    m.dCA = DerivativeVar(m.CA)
    m.dCB = DerivativeVar(m.CB)
    m.dCX = DerivativeVar(m.CX)
    m.dCY = DerivativeVar(m.CY)

    # initial conditions
    m.CA[0.0].fix(CAo)
    m.CB[0.0].fix(CBo)
    m.CX[0.0].fix(CXo)
    m.CY[0.0].fix(CYo)

    # differential equations
    @m.Constraint(m.t)
    def ode_A(m, t):
        return m.dCA[t] == - k1 - k2*m.CA[t] - k3*m.CA[t]**2

    @m.Constraint(m.t)
    def ode_B(m, t):
        return m.dCB[t] == k1*m.CA[t]
    
    @m.Constraint(m.t)
    def ode_X(m, t):
        return m.dCX[t] == k1
    
    @m.Constraint(m.t)
    def ode_Y(m, t):
        return m.dCY[t] == k3*m.CA[t]**2
    
    return m

模拟调用代码

sim = Simulator(PFR_trambouze(), package = 'scipy')
tsim, profile = sim.simulate(numpoints= 100)

错误栈信息

TypeError                                 Traceback (most recent call last)
<ipython-input-29-00475f40d0ce> in <cell line: 2>()
      1 sim = Simulator(PFR_trambouze(), package = 'scipy')
----> 2 tsim, profile = sim.simulate(numpoints= 100)

4 frames
/usr/local/lib/python3.10/dist-packages/pyomo/dae/simulator.py in simulate(self, numpoints, tstep, integrator, varying_inputs, initcon, integrator_options)
    921                     "The scipy module is not available. Cannot simulate the model."
    922                 )
---> 923             tsim, profile = self._simulate_with_scipy(
    924                 initcon, tsim, switchpts, varying_inputs, integrator, integrator_options
    925             )

/usr/local/lib/python3.10/dist-packages/pyomo/dae/simulator.py in _simulate_with_scipy(self, initcon, tsim, switchpts, varying_inputs, integrator, integrator_options)
    957                         p.set_value(varying_inputs[v][tsim[i - 1]])
    958 
---> 959             profilestep = scipyint.integrate(tsim[i])
    960             profile = np.vstack([profile, profilestep])
    961             i += 1

/usr/local/lib/python3.10/dist-packages/scipy/integrate/_ode.py in integrate(self, t, step, relax)
    429 
    430         try:
---> 431             self._y, self.t = mth(self.f, self.jac or (lambda: None),
    432                                   self._y, self.t, t,
    433                                   self.f_params, self.jac_params)

/usr/local/lib/python3.10/dist-packages/scipy/integrate/_ode.py in run(self, f, jac, y0, t0, t1, f_params, jac_params)
   1342         args = [f, y0, t0, t1] + self.call_args[:-1] + \
   1343                [jac, self.call_args[-1], f_params, 0, jac_params]
-> 1344         y1, t, istate = self.runner(*args)
   1345         self.istate = istate
   1346         if istate < 0:

/usr/local/lib/python3.10/dist-packages/pyomo/dae/simulator.py in _rhsfun(t, x)
    655 
    656                 for d in derivlist:
---> 657                     residual.append(rhsdict[d]())
    658 
    659                 return residual

TypeError: 'float' object is not callable

错误原因

问题出在全局定义的动力学常数k1、k2、k3被直接当作浮点数写入约束表达式。Pyomo的Simulator在处理ODE时,需要将约束右侧转换为可调用的符号表达式对象;但对于ode_X这类右侧是纯常数(k1)的约束,Pyomo会直接将其计算为浮点数,而非保留可调用的表达式结构。当Simulator尝试调用这个浮点数时,就触发了类型错误。

解决方法

将全局的动力学常数改为Pyomo模型内的Param(参数),让Pyomo将其视为符号化的参数,确保所有约束右侧都是可调用的表达式:

修改后的模型代码:

# create pyomo model
def PFR_trambouze(CAo = 0.112, CBo = 0.132, CXo = 0.0783, CYo = 0.0786):
    m = ConcreteModel()

    # 定义动力学参数(替换全局变量)
    m.k1 = Param(initialize=0.0001, doc='mol/dm3*s')
    m.k2 = Param(initialize=0.0015, doc='s-1')
    m.k3 = Param(initialize=0.008, doc='dm3/mol*s')

    # define time variable and bounds
    m.t = ContinuousSet(bounds=(0.0, 300.0))
    # define species concentrations
    m.CA = Var(m.t)
    m.CB = Var(m.t)
    m.CX = Var(m.t)
    m.CY = Var(m.t)

    # define differential variables
    m.dCA = DerivativeVar(m.CA)
    m.dCB = DerivativeVar(m.CB)
    m.dCX = DerivativeVar(m.CX)
    m.dCY = DerivativeVar(m.CY)

    # initial conditions
    m.CA[0.0].fix(CAo)
    m.CB[0.0].fix(CBo)
    m.CX[0.0].fix(CXo)
    m.CY[0.0].fix(CYo)

    # differential equations(引用模型内的参数m.k1/m.k2/m.k3)
    @m.Constraint(m.t)
    def ode_A(m, t):
        return m.dCA[t] == - m.k1 - m.k2*m.CA[t] - m.k3*m.CA[t]**2

    @m.Constraint(m.t)
    def ode_B(m, t):
        return m.dCB[t] == m.k1*m.CA[t]
    
    @m.Constraint(m.t)
    def ode_X(m, t):
        return m.dCX[t] == m.k1
    
    @m.Constraint(m.t)
    def ode_Y(m, t):
        return m.dCY[t] == m.k3*m.CA[t]**2
    
    return m

修改后,所有约束右侧都是基于Pyomo符号参数的表达式,Simulator可以正确提取并调用这些表达式进行数值积分,不会再触发类型错误。

内容的提问来源于stack exchange,提问作者Mauro Junior

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 19:39:54