non linear system of differential equations - python

i'm trying to solve the following non linear system of differential equations
but i don't understand where is the problem in the code that i wrote.
The system is non linear with complex coefficients and complex domain.
from pylab import *
from scipy.integrate import ode
#------initial parameters------
c = 3 * 10 ** 8
h = 6.626 / (2 * pi) * 10 ** -34
kb = 1.3806 * 10 ** -23
TT = 0.1
mm = 1.50 * 10 ** -10
wM = 2 * pi * 10 ** 6
gM = 2 * pi * 10 ** 2
ll = 1064 * 10 ** -9
PL = 100 * 10 ** -4
L = 0.025
k = 1.340 * 10 ** 7
D0 = wM
Ns = 2083
wL = 2 * pi * c / ll
wC = D0 + wL
aL = sqrt((2 * k * PL) / (h * wL))
G0 = wC / L * sqrt(h / (mm * wM))
tau = 1 / k
tciclo = 3 * pi / wM
tauP = 0.5 * pi / wM
tauNP = tciclo - tauP
dtau = 1 / (10 * k)
def fun(t, y, wM,gM,G0,k,D0,aL):
return [wM * y[1],
-wM * y[0] - gM * y[1] + G0 * y[2]*y[2].conjugate(),
-(k + 1j * D0) * y[2] + 1j * G0 * y[0] * y[2]+aL]
y0 = [0.0, 0.0, 0.0]
r = ode(f).set_integrator('zvode', method='bdf')
r.set_initial_value(y0, 0).set_f_params(2.0)
tt = []
yy = []
while r.successful() and r.t < tauP:
r.integrate(r.t + dtau)
tt.append(r.t)
yy.append(r.y)
plot(tt, yy)
show()

Always include the error message in your question. If you don't have any errors, include the output that you got, and explain why it is not what you expected.
Having said that... I see at least one problem with your code. fun has the standard t and y arguments, followed by the parameters wM,gM,G0,k,D0,aL. You must specify a value for each of these parameters in the call to set_f_params(). You currently have set_f_params(2.0), but that call needs six arguments to match the extra parameters of fun.
In a comment, #pv. has pointed out a second problem: ode(f) should be ode(fun).

Related

curve fit the function

I am trying to curve fit the following equation with parameters d, D, Ar, Tr each of them bounded in some range. The physical constants are: gamma = 26.76E7, n = 6.59E28, Ad = 2.099E-20
The equation is broken into several parts.
#Fitting function
def func(x, d, D, Ar, Tr):
pi = math.pi
#define the variables
w1 = 2 * pi * x
z1 = (2 * w1 * d**2 / D)**0.5
w2 = 2 *w1
z2 = ( 2 * w2 * d**2 / D)**0.5
J1 = (
(1 + 5 * z1 / 8 + z1**2 / 8) /
( 1 + z1 + z1**2 / 2 + z1**3 / 6 + z1**5 / 81 + z1**6 / 648)
)
J2 = (
(1 + 5 * z2 / 8 + z2**2 / 8) /
( 1 + z2 + z2**2 / 2 + z2**3 / 6 + z2**5 / 81 + z2**6 / 648)
)
gamma = 26.76E7 #unit = 1/(T*s)
n = 6.59E28
#define the normalization constant A_d
Ad = (8 / 45) * pi * gamma**4* sc.hbar**2 * (
sc.mu_0 / (4 * pi)
)**2 * n
R1_diff = Ad * (J1 + 4 * J2 ) / (d * D )
R1_rot = Ar * (Tr / (1 + w1**2 * Tr**2) + 4 * Tr / (
1 + w2**2 * Tr**2)
)
R1_IL = R1_diff + R1_rot
return R1_IL
This is the x and y data sets -
#Experimental x and y data points
xData = np.array([
2.00E+07
1.42E+07
1.01E+07
7.16E+06
7.16E+06
5.09E+06
3.61E+06
2.57E+06
1.82E+06
1.29E+06
9.20E+05
6.53E+05
4.63E+05
3.29E+05
2.34E+05
1.66E+05
1.18E+05
8.39E+04
5.96E+04
4.24E+04
3.00E+04])
yData = np.array([
7.89E+00
8.79E+00
9.58E+00
1.02E+01
1.03E+01
1.08E+01
1.13E+01
1.17E+01
1.20E+01
1.23E+01
1.25E+01
1.28E+01
1.29E+01
1.30E+01
1.31E+01
1.31E+01
1.35E+01
1.31E+01
1.33E+01
1.35E+01
1.34E+01])
The range for the parameters are: d = [3.00E-10, 4.00E-10], D = [12.5E-12, 14.00E-12], Ar = [3.00E9, 4.00E9], Tr = [1.00E-10, 2.5E-10]
This is the code that I wrote which is not giving me the correct fit and the right parameter values.
popt, pcov = curve_fit(func, xData, yData, bounds = ([3.00E-10,12.5E-12,2.5E9,1.00E-10],[4.0E-10,14.0E-12,4.00E9,2.00E-10]))
print(popt)
#x values for the fitted function
xFit = np.arange(3.00E+04, 2.00E+07, 10.00)
#Plot the fitted function
plt.loglog(xFit, func(xFit, *popt), 'r') #label='fit params: d=%5.3f, D=%5.3f, Ar=%5.3f, Tr=%5.3f' % tuple(popt))
#Plot experimental data points
plt.loglog(xData, yData, 'bo') #label='experimental-data')
plt.xlabel('f1')
plt.ylabel('R1')
plt.legend()
plt.show()
Anything would be really appreciated. The curve_fit is way off when I run this code.
For information only :
The power function below appears to be well fitted to the data.

Not geting right solution with solve_ivp

I am trying to solve the differential equation using solve_ivp, but I am not getting the right solution. However, I obtained the right solution using ideint. Do I have some problems with the solve_ipv program?
ODEINT program :
# Arhenius Function
def Arhenius(a, T):
dadT = np.exp(lnA)/v * np.exp(- E / (8.3144 * T)) * c * np.abs(a) ** m * np.abs((1 - np.abs(a))) ** n
return dadT
# Initial data
pt = 100000
T0 = 273
Tf = 1500
a0 = 0.0000000001
T = np.linspace(T0, Tf, pt)
a_sol = np.zeros(pt)
dadt = np.zeros(pt)
# ODE solve
a_t = odeint(Arhenius, a0, T)
# For removing errored values and have maximum at 1
search1 = np.where(np.isclose(a_t, 1))
try:
ia_1 = search1[0][0]
a_sol[0,:] = a_t[:,0]
a_sol[0,ia_1+1:pt] = 1
except:
a_sol = a_t[:,0]
# Calculate the new derivative
dadt = np.exp(lnA) * np.exp(- E / (8.3144 * T)) * c * np.abs(a_sol) ** m * np.abs((1 - a_sol)) ** n
PROGRAM with solve_ivp :
# Arhenius Function
def Arhenius(a, T):
dadT = np.exp(lnA) * np.exp(- E / (8.3144 * T)) * c * np.abs(a) ** m * np.abs((1 - np.abs(a))) ** n
return dadT
# Initial data
pt = 100000
T0 = 273
Tf = 1500
a0 = 0.0000000001
T = np.linspace(T0, Tf, pt)
a_sol = np.zeros(pt)
dadt = np.zeros(pt)
# ODE solve
a_t = solve_ivp(Arhenius, t_span = (T0, Tf), y0 = (a0,), t_eval = T, method = 'RK45')
a_sol= a_t.y
# Calculate the new derivative
dadt = np.exp(lnA) * np.exp(- E / (8.3144 * T)) * c * np.abs(a_sol) ** m * np.abs((1 - a_sol)) ** n

Optimizing function parameters

I explain briefly what the attached program code should do. We give a number of passes before runs = 100. and we give I = 10.
For example we set the area_factor = 1. Then the function HH_model(I,area_factor) does the following:
run 100 times with this I and this area_factor and return the number of times the barrier 60 is broken -- this is checked in the if max(v[:]-v_Rest) > 60 query.
Now I want to do the following: Determine that area_factor so that the number of count matches observations as well as possible.
For example, I know from measurements
HH_model(2*I,area_factor) = 70
HH_model(I,area_factor)=50
HH_model(0.5*I,area_factor) = 30
...
how can I find the area_factor for a given I, so that the difference to the observations becomes minimal.
import matplotlib.pyplot as py
import numpy as np
import scipy.optimize as optimize
# HH parameters
v_Rest = -65 # in mV
gNa = 120 # in mS/cm^2
gK = 36 # in mS/cm^2
gL = 0.3 # in mS/cm^2
vNa = 115 # in mV
vK = -12 # in mV
vL = 10.6 # in mV
#Number of runs
runs = 30
c = 1 # in uF/cm^2
#performing bisection-procedure
ROOT = True
def HH_model(I,area_factor):
count = 0
t_end = 10 # in ms
delay = 1 # in ms
duration = 0.3 # in ms
dt = 0.01 # in ms
I = I
area_factor = area_factor
#geometry
d = 2 # diameter in um
r = d/2 # Radius in um
l = 10 # Length of the compartment in um
A = (2 * np.pi * r * l * 1e-8)*area_factor # surface [cm^2]
C = c * A # uF
for j in range(0,runs):
# Introduction of equations and channels
def alphaM(v): return 12 * ((2.5 - 0.1 * (v)) / (np.exp(2.5 - 0.1 * (v)) - 1))
def betaM(v): return 12 * (4 * np.exp(-(v) / 18))
def betaH(v): return 12 * (1 / (np.exp(3 - 0.1 * (v)) + 1))
def alphaH(v): return 12 * (0.07 * np.exp(-(v) / 20))
def alphaN(v): return 12 * ((1 - 0.1 * (v)) / (10 * (np.exp(1 - 0.1 * (v)) - 1)))
def betaN(v): return 12 * (0.125 * np.exp(-(v) / 80))
# compute the timesteps
t_steps= t_end/dt+1
# Compute the initial values
v0 = 0
m0 = alphaM(v0)/(alphaM(v0)+betaM(v0))
h0 = alphaH(v0)/(alphaH(v0)+betaH(v0))
n0 = alphaN(v0)/(alphaN(v0)+betaN(v0))
# Allocate memory for v, m, h, n
v = np.zeros((int(t_steps), 1))
m = np.zeros((int(t_steps), 1))
h = np.zeros((int(t_steps), 1))
n = np.zeros((int(t_steps), 1))
# Set Initial values
v[:, 0] = v0
m[:, 0] = m0
h[:, 0] = h0
n[:, 0] = n0
### Noise component
knoise= 0.003 #uA/(mS)^1/2
### --------- Step3: SOLVE
for i in range(0, int(t_steps)-1, 1):
# Get current states
vT = v[i]
mT = m[i]
hT = h[i]
nT = n[i]
# Stimulus current
IStim = 0
if delay / dt <= i <= (delay + duration) / dt:
IStim = I * A # in uA
else:
IStim = 0
# Compute change of m, h and n
m[i + 1] = (mT + dt * alphaM(vT)) / (1 + dt * (alphaM(vT) + betaM(vT)))
h[i + 1] = (hT + dt * alphaH(vT)) / (1 + dt * (alphaH(vT) + betaH(vT)))
n[i + 1] = (nT + dt * alphaN(vT)) / (1 + dt * (alphaN(vT) + betaN(vT)))
# Ionic currents
iNa = gNa * m[i + 1] ** 3. * h[i + 1] * (vT - vNa)
iK = gK * n[i + 1] ** 4. * (vT - vK)
iL = gL * (vT-vL)
Inoise = (np.random.normal(0, 1) * knoise * np.sqrt(gNa * A))
IIon = ((iNa + iK + iL) * A) + Inoise #
# Compute change of voltage
v[i + 1] = vT + ((-IIon + IStim) / C) * dt # in ((uA / cm ^ 2) / (uF / cm ^ 2)) * ms == mV
# adjust the voltage to the resting potential
v = v + v_Rest
# test if there was a spike
if max(v[:]-v_Rest) > 60:
count += 1
return count
Ich habe folgendes versucht:
I = 30
xdata = np.array([0.92*I,I,1.05*I])
ydata = np.array([28,100,110])
y0=np.array([1,1,1])
def g(y,xdata,ydata):
return ydata - HH_model(xdata,y)
fit = optimize.leastsq(g, y0, args=(xdata, ydata))
File "", line
126, in HH_model
v[i + 1] = vT + ((-IIon + IStim) / C) * dt
ValueError: could not broadcast input array from shape (3) into shape
(1)
how can I get around this and make the input in the correct format?
The result of your line 126 is a three dimensional array with three times the same value. This size-3 array does not fit into an element of v, which has size-1 elements as you initialized them this way.
Therefore, you could add a [0]:
v[i + 1] = (vT + ((-IIon + IStim) / C) * dt)[0]
Furthermore, I think you do not need to allocate memory. You could for example use numpy.append in line 126.

Octave's fzero() and Scipy's root() functions not producing the same result

I have to find the zero of the following equation:
This is an equation of state, and it doesn't matter a whole lot if you don't know exactly what an EoS is. With the root of the above equation I compute (among other things) the compressibility factors of a gaseous substance, Z, for different pressures and temperatures. With those solutions I can plot families of curves having pressures as abscissas, Zs as ordinates and temperatures as parameters. Beta, delta, eta and phi are constants, as well as pr and Tr.
After banging my head unsuccessfully against the Newton-Raphson method (which works fine with several other EoSs) I decided to try Scipy's root() function. To my discontent, I obtained this chart:
As one can easily perceive, this saw-toothed chart is totally flawed. I should've gotten smooth curves instead. Also, Z typically ranges between 0.25 and 2.0. Thus, Zs equal to, say, 3 or above are completely off the mark. Yet the curves with Z < 2 look OK, although highly compressed because of the scale.
Then I tried Octave's fzero() solver, and got this:
Which is exactly what I should've gotten, as those are curves with the correct/expected shape!
Here comes my question. Apparently Scipy's root() and Octave's fzero() are based on the same algorithm hybrid from MINPACK. Still, the results clearly aren't the same. Do any of you know why?
I plotted a curve of the Zs obtained by Octave (abscissas) against the ones obtained with Scipy and got this:
The points at the bottom hinting a straight line represent y = x, i.e., the points for which Octave and Scipy agreed in the solutions they presented. The other points are in total disagreement and, unfortunately, they're too many to be simply ignored.
I might always use Octave from now on since it works, but I want to keep using Python.
What's your take on this? Any suggestion?
PS: Here's the original Python code. It produces the first chart shown here.
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()
And now the Octave script:
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
First things first. Your two files weren't equivalent, therefore a direct comparison of the underlying algorithms was difficult. I attach here an octave and a python version that are directly comparable line-for-line that can be compared side-by-side.
%%% File: SoaveBenedictWebbRubin.m:
% No package imports necessary
function 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 = comp(ic, 1);
pc = comp(ic, 2);
w = comp(ic, 3);
zc = comp(ic, 4);
MW = comp(ic, 5);
figure(1, 'position',[300,150,600,500])
zvalues = zeros( nTr, npr );
for i = 1 : nTr
for j = 1 : npr
zvalues(i,j) = zSBWR( Tr(i), pr(j), Tc, pc, zc, w, MW, 0 );
endfor
endfor
hold on
for i = 1 : nTr
plot( pr, zvalues(i,:), 'o-', 'markerfacecolor', 'white', 'markersize', 3);
endfor
hold off
xlabel( "p_r", 'fontsize', 15 );
ylabel( "Z" , 'fontsize', 15 );
title( ["Soave-Benedict-Webb-Rubin para\t", nome(ic)], 'fontsize', 12 );
endfunction % main
function Z = zSBWR( Tr, pr, Tc, pc, Zc, w, MW, phase )
% 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;
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) );
endif
endif
yi = fzero( #(y) fx(y, beta, delta, eta, phi, pr, Tr), y0, optimset( 'TolX', 1.0e-06 ) );
Z = pr / yi / Tr;
endfunction % zSBWR
function Out = fx( y, beta, delta, eta, phi, 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;
endfunction
### File: SoaveBenedictWebbRubin.py
import numpy; from scipy.optimize import root; import matplotlib.pyplot as plt
def SoaveBenedictWebbRubin():
nome = ["CO2", "N2", "H2O", "CH4", "C2H6", "C3H8"]
comp = numpy.array( [ [ 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 = numpy.linspace( 0.8, 2.8, nTr )
npr = 43; pr = numpy.linspace( 0.2, 7.2, npr )
ic = 0
Tc = comp[ic, 0]
pc = comp[ic, 1]
w = comp[ic, 2]
zc = comp[ic, 3]
MW = comp[ic, 4]
plt.figure(1, figsize=(7, 6))
zvalues = numpy.zeros( (nTr, npr) )
for i in range( nTr ):
for j in range( npr ):
zvalues[i,j] = zsbwr( Tr[i], pr[j], pc, Tc, zc, w, MW, 0)
# endfor
# endfor
for i in range(nTr):
plt.plot(pr, zvalues[i, :], 'o-', markerfacecolor='white', markersize=3 )
plt.xlabel( '$p_r$', fontsize = 15 )
plt.ylabel( '$Z$' , fontsize = 15 )
plt.title( "Soave-Benedict-Webb-Rubin para\t" + nome[ic], fontsize = 12 );
plt.show()
# end function main
def zsbwr( Tr, pr, pc, Tc, zc, w, MW, phase=0):
# Definition of parameters
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))
# endif
# endif
yi = root( fx, y0, args = (beta, delta, eta, phi, pr, Tr), method = 'hybr', tol = 1.0e-06 ).x
return pr / yi / Tr
# endfunction zsbwr
def fx(y, beta, delta, eta, phi, pr, Tr):
return y*(1.0 + beta*y + delta*y**4 + eta*y**2*(1.0 + phi*y**2)*numpy.exp(-phi*y**2)) - pr/Tr
# endfunction fx
if __name__ == "__main__": SoaveBenedictWebbRubin()
This confirms that the outputs from the two systems do in fact differ partly due to the outputs of the underlying algorithms used, rather than because the programs weren't the effectively the same. However, the comparison is not as bad now:
As for "the algorithms are the same", they are not. Octave typically hides more technical implementation details in the source code, so this is always worth checking. In particular, in file fzero.m, right after the docstring, it mentions the following:
This is essentially the ACM "Algorithm 748: Enclosing Zeros of Continuous Functions" due to Alefeld, Potra and Shi, ACM Transactions on Mathematical Software, Vol. 21, No. 3, September 1995.
Although the workflow should be the same, the structure of the algorithm has been transformed non-trivially; instead of the authors' approach of sequentially calling building blocks subprograms we implement here a FSM version using one interior point determination and one bracketing per iteration, thus reducing the number of temporary variables and simplifying the algorithm structure. Further, this approach reduces the need for external functions and error handling. The algorithm has also been slightly modified.
Whereas according to help(root):
Notes
This section describes the available solvers that can be selected by the 'method' parameter. The default method is hybr.
Method hybr uses a modification of the Powell hybrid method as
implemented in MINPACK [1].
References
[1] More, Jorge J., Burton S. Garbow, and Kenneth E. Hillstrom. 1980. User Guide for MINPACK-1.
I tried a couple of the alternatives mentioned in help(root). The df-sane one seems to be optimised for 'scalar' values (i.e. like 'fzero'). Indeed, while not as good as octave's implementation, this does give a slightly 'saner' (pun intended) result:
Having said all that, the hybrid method doesn't dump any warnings, but if you use some of the other alternatives, many of them will inform you that you have a lot of effective divisions by zero, nans, and infs, in places were you shouldn't, which is presumably why you get such weird results. So, perhaps it's not that octave's algorithm is "better" per se, but that it handles "division by zero" instances in this problem slightly more gracefully.
I don't know the exact nature of your problem, but it may be that the algorithms on python's side simply expect you to feed it well-conditioned problems instead. Perhaps some of your computations in zsbwr() result in division by zero occasions or unrealistic zeros etc, which you could detect and treat as special cases?
(Please trim the code to a minimum example which only show the root-finding part and parameters where it finds an unwanted root.)
Then the procedure is to manually inspect the equation to find the localization interval for the root you want and use it. I typically use brentq.

TypeError: bad operand type for unary -: 'tuple'

Here in my code i want to compute the variation of Q with respect to the variation of l and d but I am getting an error of TypeError: bad operand type for unary -: 'tuple' how to fix this issue
import numpy as np
import matplotlib.pyplot as plt
def plot_with_variating_D ():
l = np.arange(1, 1.5, 0.01)
d = np.arange(0.005, 0.015, 0.0002)
zero=np.zeros(50)
one=np.ones(50)
Eb1 = 3543.75
A1 = 1
A2 = np.pi * (d / 2)
A3 = np.pi
F11 = 0
F21 = 2 * (np.arctan(0.5 / l) * (180 / np.pi)) / 360
F12 = (d * np.pi * F21)
F12p = (((4 / l ** 2) + 4) ** 0.5 - 2) * (l / 2)
F13 = F12p - F12
F14 = 1 - F12 - F13
F23 = 0.5
F24 = 1 - F21 - F23
F34 = F14 / np.pi
rho = 0.7
k = 0.04
pr = 0.7
cp = 1005
myu = 2.4 * 10 ** -5
alpha = 5.68 * 10 ** -5
beta = 1 / 500
Ra = (rho * 9.81 * beta * (500 - 293) * l) / (myu * alpha)
Nu = 0.68 + (0.67 * Ra ** 0.25) / (1 + (0.429 / pr) ** (9 / 16)) ** (4 / 9)
h = Nu * k
J1 = 3543.75 + 0.42 * h * (500 - 295)
a = np.array([[F12,F13, zero], [A2*F23,-(A2*F23+F13,zero)], [-(4*A2+F12+A2*F23),A2*F23,4*A2]])
b = np.array([7*(J1-Eb1)/3 +F12*J1+F13*J1,-F13*J1,-F12*J1])
x = np.linalg.solve(np.moveaxis(a, -1, 0), np.moveaxis(b,-1,0))
x = x.T
J2 = -x[0]
J3 = x[1]
Eb2 = -x[2]
qrad = (Eb2 - J2)*(0.8 * A2) / 0.2
print(Eb2)
return qrad
plot_with_variating_D()
The following line causes it:
a = np.array([[F12,F13, zero], [A2*F23,-(A2*F23+F13,zero)], [-(4*A2+F12+A2*F23),A2*F23,4*A2]])
More specifically: [A2*F23,-(A2*F23+F13,zero)] is invalid.
I'm guessing you meant [A2*F23,-(A2*F23+F13),zero]

Categories

Resources