Python 倍频程';s fzero()和Scipy';s root()函数不产生相同的结果

Python 倍频程';s fzero()和Scipy';s root()函数不产生相同的结果,python,scipy,octave,Python,Scipy,Octave,我必须找到下面等式的零点: 这是一个状态方程,如果你不知道EoS到底是什么,这并不重要。利用上述方程的根,我计算(除其他外)不同压力和温度下气态物质的压缩因子Z。通过这些解决方案,我可以绘制以压力为横坐标、以Z为纵坐标、以温度为参数的曲线族。Beta、delta、eta和phi是常数,pr和Tr也是常数 在我的头撞到牛顿-拉斐逊方法(该方法适用于其他几种EOS)上失败后,我决定尝试Scipy的root()函数。令我不满的是,我得到了以下图表: 很容易看出,这张锯齿形图表是完全有缺陷的。我应该

我必须找到下面等式的零点:

这是一个状态方程,如果你不知道EoS到底是什么,这并不重要。利用上述方程的根,我计算(除其他外)不同压力和温度下气态物质的压缩因子Z。通过这些解决方案,我可以绘制以压力为横坐标、以Z为纵坐标、以温度为参数的曲线族。Beta、delta、eta和phi是常数,pr和Tr也是常数

在我的头撞到牛顿-拉斐逊方法(该方法适用于其他几种EOS)上失败后,我决定尝试Scipy的
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