#!/usr/bin/python3
# -*- coding: utf-8 -*-
'''Pychemqt, Chemical Engineering Process simulator
Copyright (C) 2009-2023, Juan José Gómez Romera <jjgomera@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Module for implement physics correlation:
* Constants don't available in scipy.constants
* Particle solid distributions
* Other
* root3poly
* Cunninghan factor
* :func:`Collision_Neufeld`: Neufeld Collision integral
'''
from math import exp, sin, cos, acos
from scipy.constants import R, calorie, liter, atm, Btu, lb
from lib.utilities import refDoc
__doi__ = {
1:
{"autor": "Neufeld, P.D., Janzen, A.R., Aziz, R.A.",
"title": "Empirical Equations to Calculate 16 of the Transport "
"Collision Integrals Ω for the Lennard-Jones Potential",
"ref": "J. Chem. Phys. 57(3) (1972) 1100-1102",
"doi": "10.1063/1.1678363"},
2:
{"autor": "",
"title": "",
"ref": "",
"doi": ""},
}
# Constants don't availables in scipy.constants
R_cal = R/calorie
R_atml = R/liter/atm
R_Btu = R/Btu*lb*1000*5/9
factor_acentrico_octano = 0.398
# Particle solids distribution
# Ref Hoffmann,Gas Cyclones and Swirl Tubes, pag 63
[docs]
def normal(media, varianza):
from scipy.stats import norm
return norm(media, varianza)
[docs]
def lognormal(media, varianza):
from scipy.stats import lognorm
return lognorm(media, varianza)
[docs]
def weibull(escala, start, forma):
from scipy.stats import weibull_min
return weibull_min(escala, start, forma)
# Mathematical special functions
[docs]
def cubicCardano(a, b, c, d):
"""
Implementation of Cardano formula to find all roots in a cubic equation
faster than with scipy.roots
.. math::
ax^3 + bx^2 + cx + d = 0
Algorithms referenced at http://www.1728.org/cubic2.htm
Parameters
----------
a : float
Third grade coefficient, [-]
b : float
Second grade coefficient, [-]
c : float
First grade coefficient, [-]
d : float
Zero grade coefficient, [-]
Returns
-------
root : list
Solution list, [-]
Examples
--------
# (x+2)^3
>>> "%i %i %i" % (cubicCardano(1, 6, 12, 8))
'2 2 2'
# (x-2)^3
>>> "%i %i %i" % (cubicCardano(1, -6, 12, -8))
'-2 -2 -2'
>>> "%.1f %.1f %.1f" % (cubicCardano(2, -4, -22, 24))
'-3.0 1.0 4.0'
>>> "{:.4f} {:.4f} {:.4f}".format(*cubicCardano(3, -10, 14, 27))
'-1.0000 2.1667+2.0750j 2.1667-2.0750j'
"""
f = ((3*c/a) - (b**2/a**2))/3
g = ((2*b**3/a**3) - (9*b*c/a**2) + (27*d/a))/27
h = g**2/4 + f**3/27
if f == 0 and g == 0 and h == 0:
# All 3 roots are real and equal
x1 = abs((d/a))**(1/3) * (1, -1)[d/a < 0]
return x1, x1, x1
elif h <= 0:
# All 3 roots are real
i = (g**2/4 - h)**0.5
j = i**(1/3)
k = acos(-g/(2*i))
L = -j
M = cos(k/3)
N = 3**0.5*sin(k/3)
P = -b/(3*a)
x1 = 2*j*cos(k/3) - b/(3*a)
x2 = L*(M+N) + P
x3 = L*(M-N) + P
return tuple(sorted((x1, x2, x3)))
elif h > 0:
# One real root and two conjugate complex roots
R = -g/2 + h**0.5
S = abs(R)**(1/3) * (1, -1)[R < 0]
T = -g/2 - h**0.5
U = abs(T)**(1/3) * (1, -1)[T < 0]
x1 = S + U - b/(3*a)
x2 = complex(-(S+U)/2 - b/(3*a) + 1j*(S-U)*3**0.5/2)
x3 = complex(-(S+U)/2 - b/(3*a) - 1j*(S-U)*3**0.5/2)
# Complex root converted from numpy.complex type to let a exception
# sort typeerror detect complex values in
return x1, x2, x3
# Other
[docs]
def Cunningham(l, Kn, method=0):
"""Cunningham slip correction factor for air
l: Mean free path
kn: Knudsen dimensionless number
method: reference procedure
0 - Jennings (1987)
1 - Allen & Raabe (1982)
2 - Fuchs (1964)
3 - Davies (1945)
"""
if method == 3:
C = 1+Kn*(1.257+0.4*exp(-1.1/Kn))
elif method == 2:
C = 1+Kn*(1.246+0.418*exp(-0.867/Kn))
elif method == 1:
C = 1+Kn*(1.155+0.471*exp(-0.596/Kn))
else:
C = 1+Kn*(1.252+0.399*exp(-1.1/Kn))
return C
[docs]
@refDoc(__doi__, [1])
def Collision_Neufeld(T, l=2, s=2, simple=False):
r"""Calculate the collision integral using the Neufeld correlation
.. math::
\varOmega^{(l,s)}=A/T^{B}+C/\exp\left(DT\right)+E/\exp\left(FT\right)+
G/\exp\left(HT\right)+RT^{B}\sin\left(ST^{w}-P\right)
A,B,C,D,E,F,G,H,R,S,W,P are constants for each collison order
Parameters
----------
T : float
Reduced temperature, [-]
l: int, optional
Collision integral first term order, default 2
s : int, optional
Collision integral second term order, default 2
simple : boolean, optional
Calculate a short formulation without the last sin term
Returns
-------
omega : float
Transport collision integral, [-]
"""
# Table I
dat = {
(1, 1): (1.06036, 0.15610, 0.19300, 0.47635, 1.03587, 1.52996, 1.76474,
3.89411, 0, 0, 0, 0),
(1, 2): (1.00220, 0.15530, 0.16105, 0.72751, 0.86125, 2.06848, 1.95162,
4.84492, 0, 0, 0, 0),
(1, 3): (0.96573, 0.15611, 0.44067, 1.52420, 2.38981, 5.08063, 0, 0,
-5.373, 19.2866, -1.30775, 6.58711),
(1, 4): (0.93447, 0.15578, 0.39478, 1.85761, 2.45988, 6.15727, 0, 0,
4.246, 12.9880, -1.36399, 3.33290),
(1, 5): (0.90972, 0.15565, 0.35967, 2.18528, 2.45169, 7.17936, 0, 0,
-3.814, 9.38191, 0.14025, 9.93802),
(1, 6): (0.88928, 0.15562, 0.33305, 2.51303, 2.36298, 8.11690, 0, 0,
-4.649, 9.86928, 0.12851, 9.82414),
(1, 7): (0.87208, 0.15568, 0.36583, 3.01399, 2.70659, 9.92310, 0, 0,
-4.902, 10.2274, 0.12306, 9.97712),
(2, 2): (1.16145, 0.14874, 0.52487, 0.77320, 2.16178, 2.43787, 0, 0,
-6.435, 18.0323, -0.76830, 7.27371),
(2, 3): (1.11521, 0.14796, 0.44844, 0.99548, 2.30009, 3.06031, 0, 0,
4.565, 38.5868, -0.69403, 2.56375),
(2, 4): (1.08228, 0.14807, 0.47128, 1.31596, 2.42738, 3.90018, 0, 0,
-5.623, 3.08449, 0.28271, 3.22871),
(2, 5): (1.05581, 0.14822, 0.51203, 1.67007, 2.57317, 4.85939, 0, 0,
-7.120, 4.71210, 0.21730, 4.73530),
(2, 6): (1.03358, 0.14834, 0.53928, 2.01942, 2.72350, 5.84817, 0, 0,
-8.576, 7.66012, 0.15493, 7.60110),
(3, 3): (1.05567, 0.14980, 0.30887, 0.86437, 1.35766, 2.44123, 1.29030,
5.55734, 2.339, 57.7757, -1.08980, 6.94750),
(3, 4): (1.02621, 0.15050, 0.55381, 1.40070, 2.06176, 4.26234, 0, 0,
5.227, 11.3331, -0.82090, 3.87185),
(3, 5): (0.99958, 0.15029, 0.50441, 1.64304, 2.06947, 4.87712, 0, 0,
-5.184, 3.45031, 0.26821, 3.73348),
(4, 4): (1.12007, 0.14578, 0.53347, 1.11986, 2.28803, 3.27567, 0, 0,
7.427, 21.0480, -0.28759, 6.69149)}
A, B, C, D, E, F, G, H, R_, S, W, P = dat[(l, s)]
# Eq 2
omega = A/T**B + C/exp(D*T) + E/exp(F*T) + G/exp(H*T)
if not simple:
omega += R_*1e-4*T**B*sin(S*T**W-P)
return omega
if __name__ == "__main__":
# from pylab import arange, plot, grid, show
# x = arange(0, 2.5, 0.01)
# y = weibull(0.5, 0, 1.).cdf(x)
# z = weibull(1, 0, 1).pdf(x)
# w = weibull(1.5, 0, 1).pdf(x)
# v = weibull(5, 0, 1).pdf(x)
# plot(x, y)
# plot(x, z)
# plot(x, w)
# plot(x, v)
# grid(True)
# show()
import time
from pprint import pprint
from scipy import roots
args = [1, -1.0, 0.14358582833553338, -0.004243577526503186]
# # args = [1, -1, 0.6269002858464162, -0.07953977078483085]
inicio=time.time()
pprint(roots(args))
fin=time.time()
print("scipy.roots:", (fin-inicio)*1000., "ms")
inicio=time.time()
pprint(cubicCardano(*args))
fin=time.time()
print("alg.roots:", (fin-inicio)*1000., "ms")