首页 > 解决方案 > 当我尝试对简单的化学反应进行敏感性分析时,SALib 返回错误

问题描述

我正在尝试对一个简单的化学反应系统进行敏感性分析。A -> B(反应速率为 k1)和 A1 -> B(k2),B->C (k3),B-> D (k4)。我在我的简单示例中执行了 lmfit 函数,并希望将它与 SALib 包连接起来。

我的尝试

from scipy.integrate import odeint
import numpy as np
from lmfit import minimize, Parameters, report_fit
import matplotlib.pyplot as plt
time = 10
Nt = 10
tt = np.linspace(0,time, Nt)    
from SALib.sample import saltelli
from SALib.analyze import sobol
import numpy as np

def f(xs, t, ps):
    """Test"""
    try:
        k1 = ps['k1'].value
        k2 = ps['k2'].value
        k3 = ps['k3'].value
        k4 = ps['k4'].value
    except:
        k1, k2, k3, k4 = ps

    a, a1, b, c, d = xs
    return [-k1*a,-k2*a1, k1*a + k2*a1, k3*b, k4*b]

def g(t, x0, ps):
    """
    Solution to the ODE x'(t) = f(t,x,k) with initial condition x(0) = x0
    """
    x = odeint(f, x0, t, args=(ps,))
    return x

def residual(ps, ts, data):
    x0 = ps['a'].value, ps['a1'].value, ps['b'].value, ps['c'].value, ps['d'].value
    model = g(ts, x0, ps)
    return (model - data).ravel()

x0 = np.array([1,0.5,0,0,0])

k1, k2, k3, k4 = 1,0.8,0.7,0.2
true_params = np.array((k1,k2,k3,k4))
data = g(tt, x0, true_params)

data += np.abs(np.random.normal(size=data.shape))
lb, ub = 0.2, 0.2

# set parameters incluing bounds
params = Parameters()
params.add('a', value = x0[0] , min=0, max=1.5)
params.add('a1', value = x0[1], min=0, max=2.5)
params.add('b', value = x0[2], min=0, max=1)
params.add('c', value= x0[3] , min=0, max=1)
params.add('d', value= x0[4] , min=0, max=1)
params.add('k1', value=k1, min=k1 - lb, max=k1 + ub)
params.add('k2', value=k2, min=k2 - lb, max=k2 + ub)
params.add('k3', value=k3, min=k3 - lb, max=k3 + ub)
params.add('k4', value=k4, min=k4 - lb, max=k4 + ub)

# fit model and find predicted values
result = minimize(residual, params, args=(tt, data), method='leastsq')
final = data + result.residual.reshape(data.shape)

# plot data and fitted curves
plt.plot(tt, data, 'o')
plt.plot(tt, final, '-', linewidth=2);

# display fitted statistics
report_fit(result)

problem = {
    'num_vars': 4,
    'names': ['k1', 'k2', 'k3', 'k4'],
    'bounds': [[(result.params['k1'].value) - 0.2, (result.params['k1'].value) + 0.2],
               [(result.params['k2'].value) - 0.2, (result.params['k2'].value) + 0.2],
               [(result.params['k3'].value) - 0.2, (result.params['k3'].value) + 0.2],
               [(result.params['k4'].value) - 0.2, (result.params['k4'].value) + 0.2]]
}
param_values = saltelli.sample(problem, 1000, calc_second_order=True)

N = len(param_values) # number of parameter samples
Y = np.zeros(N)
#
for i in range(N):
  Y[i] = g(tt, x0, param_values[i])

Si = sobol.analyze(problem,Y, print_to_console=False)

错误:

  File "code.py", line 94, in <module>
    Y[i] = g(tt,x0,(param_values[i]))

ValueError: setting an array element with a sequence

.

想要得到这个化学反应的不同 k 率的灵敏度。

标签: python

解决方案


我想我解决了。告诉我你的想法!

Y = []
for i in range(N):
    Y.append((g(tt,x0,(param_values[i]))))
a = np.concatenate(Y, axis=None)

Si = sobol.analyze(problem, a, print_to_console=False)

推荐阅读