Python 倍频程';s fzero()和Scipy';s root()函数不产生相同的结果
我必须找到下面等式的零点: 这是一个状态方程,如果你不知道EoS到底是什么,这并不重要。利用上述方程的根,我计算(除其他外)不同压力和温度下气态物质的压缩因子Z。通过这些解决方案,我可以绘制以压力为横坐标、以Z为纵坐标、以温度为参数的曲线族。Beta、delta、eta和phi是常数,pr和Tr也是常数 在我的头撞到牛顿-拉斐逊方法(该方法适用于其他几种EOS)上失败后,我决定尝试Scipy的Python 倍频程';s fzero()和Scipy';s root()函数不产生相同的结果,python,scipy,octave,Python,Scipy,Octave,我必须找到下面等式的零点: 这是一个状态方程,如果你不知道EoS到底是什么,这并不重要。利用上述方程的根,我计算(除其他外)不同压力和温度下气态物质的压缩因子Z。通过这些解决方案,我可以绘制以压力为横坐标、以Z为纵坐标、以温度为参数的曲线族。Beta、delta、eta和phi是常数,pr和Tr也是常数 在我的头撞到牛顿-拉斐逊方法(该方法适用于其他几种EOS)上失败后,我决定尝试Scipy的root()函数。令我不满的是,我得到了以下图表: 很容易看出,这张锯齿形图表是完全有缺陷的。我应该
root()
函数。令我不满的是,我得到了以下图表:
很容易看出,这张锯齿形图表是完全有缺陷的。我应该换成平滑的曲线。此外,Z通常在0.25和2.0之间。因此,等于(比如)3或以上的Zs是完全不正确的。然而,Z<2的曲线看起来还可以,尽管由于比例的原因,曲线高度压缩
然后我尝试了Octave的fzero()
solver,得到了以下结果:
这正是我应该得到的,因为这些曲线具有正确/预期的形状
我的问题来了。显然,Scipy的root()
和Octave的fzero()
基于与MINPACK相同的混合算法。然而,结果显然不一样。你们知道为什么吗
我绘制了一条由倍频程(横坐标)获得的Zs曲线,与用Scipy获得的Zs曲线对比,得到如下结果:
底部表示直线的点表示y=x
,即在他们给出的解决方案中,倍频程和Scipy一致的点。其他观点完全不一致,不幸的是,它们太多了,不能简单地忽略
从现在起,我可能会一直使用八度音阶,因为它可以工作,但我想继续使用Python
你对此有什么看法?有什么建议吗
PS:这是Python的原始代码。它生成此处显示的第一个图表
import numpy
from scipy.optimize import root
import matplotlib.pyplot as plt
def fx(x, beta, delta, eta, phi, pr_, Tr_):
tmp = phi*x**2
etmp = numpy.exp(-tmp)
f = x*(1.0 + beta*x + delta*x**4 + eta*x**2*(1.0 + tmp)*etmp) - pr_/Tr_
return f
def zsbwr(pr_, Tr_, pc_, Tc_, zc_, w_, MW_, phase=0):
d1 = 0.4912 + 0.6478*w_
d2 = 0.3000 + 0.3619*w_
e1 = 0.0841 + 0.1318*w_ + 0.0018*w_**2
e2 = 0.075 + 0.2408*w_ - 0.014*w_**2
e3 = -0.0065 + 0.1798*w_ - 0.0078*w_**2
f = 0.770
ee = (2.0 - 5.0*zc_)*numpy.exp(f)/(1.0 + f + 3.0*f**2 - 2*f**3)
d = (1.0 - 2.0*zc_ - ee*(1.0 + f - 2.0*f**2)*numpy.exp(-f))/3.0
b = zc_ - 1.0 - d - ee*(1.0 + f)*numpy.exp(-f)
bc = b*zc_
dc = d*zc_**4
ec = ee*zc_**2
phi = f*zc_**2
beta = bc + 0.422*(1.0 - 1.0/Tr_**1.6) + 0.234*w_*(1.0- 1.0/Tr_**3)
delta = dc*(1.0+ d1*(1.0/Tr_ - 1.0) + d2*(1.0/Tr_ - 1.0)**2)
eta = ec + e1*(1.0/Tr_ - 1.0) + e2*(1.0/Tr_ - 1.0)**2 \
+ e3*(1.0/Tr_ - 1.0)**3
if Tr_ > 1:
y0 = pr_/Tr_/(1.0 + beta*pr_/Tr_)
else:
if phase == 0:
y0 = pr_/Tr_/(1.0 + beta*pr_/Tr_)
else:
y0 = 1.0/zc_**(1.0 + (1.0 - Tr_)**(2.0/7.0))
raiz = root(fx,y0,args=(beta, delta, eta, phi, pr_, Tr_),method='hybr',tol=1.0e-06)
return pr_/raiz.x[0]/Tr_
if __name__ == "__main__":
Tc = 304.13
pc = 73.773
omega = 0.22394
zc = 0.2746
MW = 44.01
Tr = numpy.array([0.8, 0.93793103])
pr = numpy.linspace(0.5, 14.5, 25)
zfactor = numpy.zeros((2, 25))
for redT in Tr:
j = numpy.where(Tr == redT)[0][0]
for redp in pr:
indp = numpy.where(pr == redp)[0][0]
zfactor[j][indp] = zsbwr(redp, redT, pc, Tc, zc, omega, MW, 0)
for key, value in enumerate(zfactor):
plt.plot(pr, value, '.-', linewidth=1, color='#ef082a')
plt.figure(1, figsize=(7, 6))
plt.xlabel('$p_R$', fontsize=16)
plt.ylabel('$Z$', fontsize=16)
plt.grid(color='#aaaaaa', linestyle='--', linewidth=1)
plt.show()
现在是八度音阶脚本:
function SoaveBenedictWebbRubin
format long;
nTr = 11;
npr = 43;
ic = 1;
nome = {"CO2"; "N2"; "H2O"; "CH4"; "C2H6"; "C3H8"};
comp = [304.13, 73.773, 0.22394, 0.2746, 44.0100; ...
126.19, 33.958, 0.03700, 0.2894, 28.0134; ...
647.14, 220.640, 0.34430, 0.2294, 18.0153; ...
190.56, 45.992, 0.01100, 0.2863, 16.0430; ...
305.33, 48.718, 0.09930, 0.2776, 30.0700; ...
369.83, 42.477, 0.15240, 0.2769, 44.0970];
Tc = comp(ic,1);
pc = comp(ic,2);
w = comp(ic,3);
zc = comp(ic,4);
MW = comp(ic,5);
Tr = linspace(0.8, 2.8, nTr);
pr = linspace(0.2, 7.2, npr);
figure(1, 'position',[300,150,600,500])
for i=1:size(Tr, 2)
icont = 1;
zval = zeros(1, npr);
for j=1:size(pr, 2)
[Z, phi, density] = SBWR(Tr(i), pr(j), Tc, pc, zc, w, MW, 0);
zval(icont) = Z;
icont = icont + 1;
endfor
plot(pr,zval,'o','markerfacecolor','white','linestyle','-','markersize',3);
hold on;
endfor
str = strcat("Soave-Benedict-Webb-Rubin para","\t",nome(ic));
xlabel("p_r",'fontsize',15);
ylabel("Z",'fontsize',15);
title(str,'fontsize',12);
end
function [Z,phi,density] = SBWR(Tr, pr, Tc, pc, Zc, w, MW, phase)
R = 8.3144E-5; % universal gas constant (bar·m3/(mol·K))
% Definition of parameters
d1 = 0.4912 + 0.6478*w;
d2 = 0.3 + 0.3619*w;
e1 = 0.0841 + 0.1318*w + 0.0018*w**2;
e2 = 0.075 + 0.2408*w - 0.014*w**2;
e3 = -0.0065 + 0.1798*w - 0.0078*w**2;
f = 0.77;
ee = (2.0 - 5.0*Zc)*exp(f)/(1.0 + f + 3.0*f**2 - 2.0*f**3);
d = (1.0 - 2.0*Zc - ee*(1.0 + f - 2.0*f**2)*exp(-f))/3.0;
b = Zc - 1.0 - d - ee*(1.0 + f)*exp(-f);
bc = b*Zc;
dc = d*Zc**4;
ec = ee*Zc**2;
ff = f*Zc**2;
beta = bc + 0.422*(1.0 - 1.0/Tr**1.6) + 0.234*w*(1.0 - 1.0/Tr**3);
delta = dc*(1.0 + d1*(1.0/Tr - 1.0) + d2*(1.0/Tr - 1.0)**2);
eta = ec + e1*(1.0/Tr - 1.0) + e2*(1.0/Tr - 1.0)**2 + e3*(1.0/Tr - 1.0)**3;
if Tr > 1
y0 = pr/Tr/(1.0 + beta*pr/Tr);
else
if phase == 0
y0 = pr/Tr/(1.0 + beta*pr/Tr);
else
y0 = 1.0/Zc**(1.0 + (1.0 - Tr)**(2.0/7.0));
end
end
fun = @(y)y*(1.0 + beta*y + delta*y**4 + eta*y**2*(1.0 + ff*y**2)*exp(-ff*y**2)) - pr/Tr;
options = optimset('TolX',1.0e-06);
yi = fzero(fun,y0,options);
Z = pr/yi/Tr;
density = yi*pc*MW/(1000.0*R*Tc);
phi = exp(Z - 1.0 - log(Z) + beta*yi + 0.25*delta*yi**4 - eta/ff*(exp(-ff*yi**2)*(1.0 + 0.5*ff*yi**2) - 1.0));
end
(请将代码精简为一个最小的示例,该示例仅显示根查找部分和找到不需要的根的参数。)
然后,程序是手动检查方程,以找到所需根的定位间隔并使用它。我通常先使用
brentq
第一件事。您的两个文件不相等,因此很难直接比较底层算法。我在这里附上了一个八度音阶和一个python版本,它们可以一行一行地直接比较,可以并排比较
%%%文件:SoaveBenedictWebbRubin.m:
%无需进口包装
功能SoaveBenedictWebbRubin()
nome={“CO2”;“N2”;“H2O”;“CH4”;“C2H6”;“C3H8”};
comp=[304.13,73.773,0.22394,0.2746,44.0100;
126.19, 33.958, 0.03700, 0.2894, 28.0134;
647.14, 220.640, 0.34430, 0.2294, 18.0153;
190.56, 45.992, 0.01100, 0.2863, 16.0430;
305.33, 48.718, 0.09930, 0.2776, 30.0700;
369.83, 42.477, 0.15240, 0.2769, 44.0970 ];
nTr=11;Tr=linspace(0.8,2.8,nTr);
npr=43;pr=linspace(0.2,7.2,npr);
ic=1;
Tc=补偿(ic,1);
pc=comp(ic,2);
w=成分(ic,3);
zc=补偿(ic,4);
MW=补偿(ic,5);
图(1,‘位置’,[300150600500])
Z值=零(nTr,npr);
对于i=1:nTr
对于j=1:npr
zvalue(i,j)=zSBWR(Tr(i),pr(j),Tc,pc,zc,w,MW,0);
外循环
外循环
等等
对于i=1:nTr
绘图(pr、Z值(i,:)、‘o-’、‘markerfacecolor’、‘white’、‘markersize’、3);
外循环
拖延
xlabel(“p_r”,“fontsize”,15);
ylabel(“Z”,fontsize',15);
标题([“Soave Benedict Webb Rubin para\t”,名称(ic)],“fontsize”,12);
结束函数%main
功能Z=zSBWR(Tr、pr、Tc、pc、Zc、w、MW、相位)
%参数的定义
d1=0.4912+0.6478*w;
d2=0.3+0.3619*w;
e1=0.0841+0.1318*w+0.0018*w**2;
e2=0.075+0.2408*w-0.014*w**2;
e3=-0.0065+0.1798*w-0.0078*w**2;
f=0.77;
ee=(2.0-5.0*Zc)*exp(f)/(1.0+f+3.0*f**2-2.0*f**3);
d=(1.0-2.0*Zc-ee*(1.0+f-2.0*f**2)*exp(-f))/3.0;
b=Zc-1.0-d-ee*(1.0+f)*exp(-f);
bc=b*Zc;
dc=d*Zc**4;
ec=ee*Zc**2;
φ=f*Zc**2;
β=bc+0.422*(1.0-1.0/Tr**1.6)+0.234*w*(1.0-1.0/Tr**3);
delta=dc*(1.0+d1*(1.0/Tr-1.0)+d2*(1.0/Tr-1.0)**2);
eta=ec+e1*(1.0/Tr-1.0)+e2*(1.0/Tr-1.0)**2+e3*(1.0/Tr-1.0)**3;
如果Tr>1
y0=pr/Tr/(1.0+beta*pr/Tr);
其他的
如果相位==0
y0=pr/Tr/(1.0+beta*pr/Tr);
其他的
y0=1.0/Zc**(1.0+(1.0-Tr)**(2.0/7.0));
恩迪夫
恩迪夫
yi=fzero(@(y)fx(y,beta,delta,eta,phi,pr,Tr),y0,optimset('TolX',1.0e-06));
Z=pr/yi/Tr;
结束函数%zSBWR
功能输出=fx(y、β、δ、eta、φ、pr、Tr)
Out=y*(1.0+beta*y+delta*y**4+eta*y**2*(1.0+phi*y**2)*exp(-phi*y**2))-pr/Tr;
端功能
###文件:SoaveBenedictWebbRubin.py
进口纽米;从scipy.optimizeimportroot;将matplotlib.pyplot作为plt导入
def SoavedictWebbrubin():
nome=[“CO2”、“N2”、“H2O”、“CH4”、“C2H6”、“C3H8”]
comp=numpy.数组([[304.13,73.773,0.22394,0.2746,44.0100],
[ 126.19, 33.958, 0.03700, 0.2894, 28.0134 ],
[ 647.14, 220.640, 0.34430, 0.2294, 18.0153 ],
[ 190.56, 45.992, 0.011