I am trying to compute the final composition and temperature of a mixture of syn-gas and air. They enter in at 300 K and 600 K respectively. The syn-gas is a mixture of CO and H2 the proportions of which I am varying from 3:1 to 1:3. Later on, this ratio is fixed and additional nitrogen gas is introduced. Lastly, heat loss is accounted for and its effect on temperature/composition is calculated. Focusing on the first part, I am having a hard time balancing the system of non-linear equations. The general equation for the chemical reaction is as follows:
aCO + bH2 + c*(O2 + 79/21 * N2) + dN2 = eCO + fH2 + gO2 + hN2 + jCO2 + kH2O + lNO
From conservation of species:
Carbon: a = e + j
Oxygen: a + 2c = e + 2g + 2*j + k + l
Hydrogen: 2b = 2f + 2*k
Nitrogen: 2*(79/21)c + 2d = 2*h + l
Since there are three compounds, there are three partial pressure equilibrium values called K_p. K_p is a function of temperature and from empirical data is a known constant.
K_p_NO = (X_NO * P) / (sqrt(X_N2*P)*sqrt(X_O2 * P))
K_p_H2O = (X_H2O * P) / (sqrt(P*X_O2)X_H2P)
K_p_CO2 = (X_CO2 * P) / (sqrt(P*X_O2)X_COP)
Where X is the mole fraction. E.G. X_H2O = k/(e+f+g+h+j+k+l)
The variables e,f,g,h,j,k,l are 7 unknowns and there are 7 equations. Variables a, b, c, and d are varied manually and are treated as known values. Using scipy, I implemented fsolve() as shown below:
from scipy.optimize import fsolve # required library
import sympy as sp
import scipy
# known values hard coded for testing
a = 0.25
b = 0.75
c = a + b
d = 0
kp_NO = 0.00051621
kp_H2O = 0.0000000127
kp_CO2 = 0.00000001733
p = 5 # pressure
dec = 10 # decimal point precision
# Solving the system of equations
def equations(vars):
(e, f, g, h, j, k, l) = vars
f1 = e + j - a
f2 = e + 2*g + 2*j + k + l - a - 2*c
f3 = f + k - b
f4 = 2*h + l - 2*d - (2*79/21)*c
f5 = kp_NO - (l/sp.sqrt(c*(79/21)*c))
f6 = kp_H2O - (k/(b*sp.sqrt((c*p)/(e + f + g + h + j + k + l))))
f7 = kp_CO2 - (j/(a*sp.sqrt((c*p)/(e + f + g + h + j + k + l))))
return[f1, f2, f3, f4, f5, f6, f7]
e, f, g, h, j, k, l = scipy.optimize.fsolve(equations, (0.00004, 0.00004, 0.49, 3.76, 0.25, 0.75, 0.01))
# CO, H2, O2, N2, CO2, H2O, NO
print(e, f, g, h, j, k, l)
The results are
0.2499999959640893 0.7499999911270915 0.999499382628763 3.761404150987935 4.0359107126181326e-09 8.872908576472292e-09 0.001001221833654118
Notice that e = 0.24999995 but a = 0.25. It seems that the chemical reaction is progressing little if at all. Why am I getting my inputs back as results? I know something is wrong because in some cases, the chemical coefficients are negative.
Things I've tried:
Triple checked my math/definitions. Used nsolve() from sympy, nonlinsolve() from scipy, other misc. solvers.
I do not see anything wrong in your code, albeit I would have solved it differently.
This question should be moved to Chemistry stackexchange: the Kp values you are using are wrong. The value for water formation at 500K is around 7.65E22 (when pressure is expresed in bar), I am pretty sure that the constant for CO to CO2 is also much higher.
I would have written this as a comment but I do not have enough reputation.
Related
I am interpolating data from the vertices of a quadrilateral to any random point inside the quadrilateral. I implement this by first doing a coordinate transformation which reshapes the quadrilateral to a unit square and then using bilinear interpolation.
Does any of the python libraries already have an implementation to do this?
Bilinear interpolation between the corners of a quadrilateral gives the coordinates
P = (P00 (1-u) + P10 u) (1-v) + (P01 (1-u) + P11 u) v
= P00 + (P10-P00) u + (P01-P00) v + (P11-P10-P01+P00) uv.
This forms a system of two quadratic equations in the unknowns u, v. If P is inside the quadrilateral, u, v ε [0, 1].
If we take the dot and cross products with P11-P10-P01+P0, the system takes the form
A + B u + C v + D uv = 0
a + b u + c v = 0
from which we eliminate v by
c (A + B u) - (C + D u) (a + b u) = -b D u² + (B c - b C - a D) u + (A c - a C) = 0
which is quadratic univariate. Compute the roots and keep the one in the domain. From u you get v.
I am trying to solve a system of non-linear equations. The issue is that my input values are being returned to me as a valid solution. In order for this to happen, some equations have to be ignored. I have tried both sympy.solvers.nsolve() and scipy.optimize.fsolve(). Both give the same answers. I have posted both codes starting with scipy and then sympy. Lastly, I have posted example results.
from scipy.optimize import fsolve # required library
import sympy as sp
import scipy
# known values hard coded for testing
a = 1
b = 3
c = a + b
d = 0
kp_NO = 0.00051621
kp_H2O = 0.0000000127
kp_CO2 = 0.00000001733
p = 5 # pressure
dec = 3 # decimal point precision
# Solving the system of equations
def equations(vars):
(e, f, g, h, j, k, l) = vars
f1 = e + j - a
f2 = e + 2*g + 2*j + k + l - a - 2*c
f3 = f + k - b
f4 = 2*h + l - 2*d - (2*79/21)*c
f5 = kp_NO - (l/(c*(79/21)*c))
f6 = kp_H2O - (k/(b*sp.sqrt((c*p)/(e + f+ g + h + j + k + l))))
f7 = kp_CO2 - (j/(a*sp.sqrt((c*p)/(e + f + g + h + j + k + l))))
return[f1, f2, f3, f4, f5, f6, f7]
e, f, g, h, j, k, l = scipy.optimize.root_scalar(equations, (0, 0, 0, 0, 0, 0, 0))
# CO, H2, O2, N2, CO2, H2O, NO
print(e, f, g, h, j, k, l)
import sympy as sp # required library
import math as m
# known values hard coded for testing
a = 1
b = 3
c = a + b
d = 0
kp_NO = 0.0000000015346
kp_H2O = 1.308*10**-23
kp_CO2 = 9.499*10**-46
p = 5 # pressure
dec = 10 # decimal point precision
# Solving the system of equations
e, f, g, h, j, k, l = sp.symbols('e, f, g, h, j, k, l')
f1 = e + j - a
f2 = e + 2*g + 2*j + k + l - a - 2*c
f3 = f + k - b
f4 = 2*h + l - 2*d - (2*79/21)*c
f5 = kp_NO - (l / (c * (79 / 21) * c))
f6 = kp_H2O - (k / (b * sp.sqrt((c * p) / (e + f + g + h + j + k + l))))
f7 = kp_CO2 - (j / (a * sp.sqrt((c * p) / (e + f + g + h + j + k + l))))
# f5 = m.log(kp_NO, p) + h/2 + g/2 - l
# f6 = m.log(kp_H2O, p) + g/2 + f - k
# f7 = m.log(kp_CO2, p) + e + g/2 - j
results = sp.solvers.nsolve([f1, f2, f3, f4, f5, f6, f7], [e, f, g, h, j, k, l], [0.00004, 0.00004, 0.49, 3.76, 0.25, 0.75, 0.01], manual=True)
e = round(results[0], dec)
f = round(results[1], dec)
g = round(results[2], dec)
h = round(results[3], dec)
j = round(results[4], dec)
k = round(results[5], dec)
l = round(results[6], dec)
# CO, H2, O2, N2, CO2, H2O, NO
print(e, f, g, h, j, k, l)
1.00000000000000 3.00000000000000 3.9999999538 15.0476190014 0.0 0.0 9.24e-8
You will also get no change from the initial guess if each of the equations is within the tolerance of the solver. And with the scaling of your equations, I suspect this is the case. Here is another approach:
Let's work with rationals instead of decimals:
>>> from sympy import nsimplify
>>> eqs = [nsimplify(i, rational=True) for i in [f1, f2, f3, f4, f5, f6, f7]]
>>> v = [e, f, g, h, j, k, l]
All but the last equation is easy to solve for all but g; there is 1 solution:
>>> lpart = solve(eqs[:-1], set(v) - {g}, dict=True)[0]
When radicals are removed from the numerator of the last equation, it yields a cubic for which roots can be found
>>> from sympy import real_roots
>>> from sympy.solvers.solvers import unrad
>>> u, cov = unrad(eqs[-1].subs(lpart).as_numer_denom()[0]); assert cov == []
>>> gsol = list(real_roots(u))
It looks like the first two real roots are solutions of the last equation:
>>> [abs(eqs[-1].simplify().subs(g, i).n()) for i in gsol]
[0.e-145, 0.e-145, 7.84800000000000e-23]
You can check to see if they are also solutions of the others. (The real roots are not compact solutions in terms of radicals.)
You might leave the constants as symbols and repeat the above and only solve the last equation with values when needed -- if needed.
I'm working differentiating in sympy, thanks to this answer I'm almost done, but not quite.
I have the following code in variations:
From the answer
x = IndexedBase('x')
alpha, beta, gamma = symbols('alpha beta gamma', integer=True)
r = sqrt(x[alpha]**2 + x[beta]**2 + x[gamma]**2)
T0 = 1/r
i,j,k,l = symbols('i j k l')
T1 = diff(T0, x[i])
T1.subs(sqrt(x[alpha]**2 + x[beta]**2 + x[gamma]**2), 'r')
Using Vector class
V = CoordSys3D('V')
v = x[alpha]*R.i + x[beta]*R.j + x[gamma]*R.k
r = v.magnitude()
T0 = 1/r
T1 = diff(T0, x[i])
T1.subs(sqrt(x[alpha]**2 + x[beta]**2 + x[gamma]**2), 'r')
Both give the following answer:
However, this has a lot of unwanted delta functions, which only multiply in number after differentiating to higher orders.
Here, alpha beta gamma are just Cartesian components of a vector, and r is its length.
Knowing that, of course, those delta functions can never be simultaneously 1, I want to achieve this result:, where i is some of Cartesian components.
Is this possible?
Thanks!
Managed to do it!
That's the code sample:
x = IndexedBase('x')
alpha, beta, gamma, delta = symbols('alpha beta gamma delta', cls=Idx, range=3)
i = Idx('i', 3)
x_i = x[i]
r = sqrt(Sum(x_i**2, i))
T0 = 1/r
T1 = diff(T0, x[alpha])
T1.simplify().subs(sqrt(Sum(x_i**2, i).doit()), 'r')
Outputs:
-x[alpha]/r**3
I am using sympy and python to solve some equations. I am trying to arrange an equation so that the coefficient in terms of the highest degree is +1. For example the following code produces the output
Km, Kb, L, s, R, J, b = sym.symbols("Km, Kb, L, s, R, J, b")
G1 = Km / (L * s + R)
G2 = 1 / (J * s + b)
Msys = (G1 * G2) / (1 + G1 * G2 * Kb)
Msys = sym.expand(Msys)
Msys = sym.simplify(Msys)
Msys = sym.collect(Msys, s)
print(Msys)
#outputs Km/(J*L*s**2 + Kb*Km + R*b + s*(J*R + L*b))
I need to get rid of coefficients in front of s**2 (ie set to 1). This would normally be done by dividing both the top and bottom by J*L. I found a sympi function called monic that is supposed to do this but it only works on the numerator.
What is the best solution to this problem?
Thanks is advance
This is not an ideal solution because it gets the formula in the form that I need it. Basically I split the formula up into top and bottom, then I multiply by 1 / (J * L) the coefficients in front of the highest degree variable.
Km, Kb, L, R, J, b, Gc, Ain, Amp, Hoi, s = sym.symbols("Km, Kb, L, R, J, b, Gc, Ain, Amp, Hoi, s")
G1 = 1/ (L * s + R)
print(G1)
G2 = 1 / (J * s + b)
print(G2)
Msys = (Km * G1 * G2) / (1 + Km * G1 * G2 * Kb)
Msys = sym.expand(Msys)
Msys = sym.simplify(Msys)
Msys = sym.collect(Msys, s)
g3 = Msys * ((1/(J*L))/(1/(J*L)))
print(g3)
top, bot = Msys.as_numer_denom()
top = top * (1/(J*L))
print(top)
bot = bot * (1/(J*L))
bot = sym.expand(bot)
bot = sym.collect(bot, s)
print(bot)
Msys = top * 1/bot
While this solution worked it is not ideal, because of its complexity. I could probably further develop it and make it into a function I can reuse, but there must be an easier way
I am trying to solve a system of polynomial equations obtained by comparing coefficients of different polynomials.
# Statement of Problem:
# We are attempting to find complex numbers a, b, c, d, e, J, u, v, r, s where
# ((a*x + c)^2)*(x^3 + (3K)*x + 2K) - ((b*x^2 + d*x + e)^2) = a^2*(x - r)^2*(x - s)^3 and
# ((a*x + c)^2)*(x^3 + (3K)*x + 2K)) - ((b*x^2 + d*x + e - 1)^2) = a^2*(x - u)*(x - v)^4
R.<x> = CC['x']
a, b, c, d, e, r, s, u, v, K = var('a, b, c, d, e, r, s, u, v, K')
y2 = x^3 + (3*K)*x + 2*K
q0 = ((a*x + c)^2)*(y2) - ((b*x^2 + d*x + e)^2)
p0 = (a^2)*((x-r)^2)*((x-s)^3)
t = (b^2 - 2*a*c)/a^2
Q0 = q0.expand()
P0 = p0.expand()
P0 = P0.substitute(s = ((t - 2*r)/3))
Relations0 = []
i = 0
while i < 6:
Relations0.append(P0.coefficient(x, n = i) - Q0.coefficient(x, n = i))
i = i+1
q1 = ((a*x + c)^2)*(y2) - ((b*x^2 + d*x + e - 1)^2)
p1 = (a^2)*(x-u)*((x-v)^4)
Q1 = q1.expand()
P1 = p1.expand()
P1 = P1.substitute(u = t - 4*v)
Relations1 = []
i = 0
while i < 6:
Relations1.append(P1.coefficient(x, n = i) - Q1.coefficient(x, n = i))
i = i+1
Relations = Relations0 + Relations1
Telling Sage to solve the system of polynomials using solve(Relations, a,b,c,d,e,r,v,K) seems highly inefficient and has only led to Sage having its memory limit exceeded. Moreover, trying to reduce the number of equations and variables by solving for some of the variables is also inefficient and has not given any fruitful results. Since attempting to find all solutions has proven so difficult, is there any way to extract only a single solution?
Both equations have degree 5, which makes 12 identities. However, the degree 5 identities are identical and always satisfied for both equations. Thus you have effectively 10 or less equations for 10 variables.
Divide by a^2, i.e., replace c, b, d, e by c/a, b/a, d/a, e/a and introduce f=1/a to reduce the degrees of the coefficient equations.
Then the resulting coefficient equations for
(x + c)^2*(x^3 + 3*K*x + 2*K) - (b*x^2 + d*x + e)^2 = (x - r)^2*(x - s)^3;
(x + c)^2*(x^3 + 3*K*x + 2*K) - (b*x^2 + d*x + e - f)^2 = (x - u)*(x - v)^4;
or on http://magma.maths.usyd.edu.au/calc/
A<b, c, d, e, f, r, s, u, v, K> :=PolynomialRing(Rationals(),10,"glex");
P<x> := PolynomialRing(A);
eq1 := (x + c)^2*(x^3 + 3*K*x + 2*K) - (b*x^2 + d*x + e)^2 - (x - r)^2*(x - s)^3;
eq2 := (x + c)^2*(x^3 + 3*K*x + 2*K) - (b*x^2 + d*x + e - f)^2 - (x - u)*(x - v)^4;
I := ideal<A|Coefficients(eq1) cat Coefficients(eq2-eq1)>; I;
giving
Ideal of Polynomial ring of rank 10 over Rational Field
Order: Graded Lexicographical
Variables: b, c, d, e, f, r, s, u, v, K
Basis:
[
r^2*s^3 + 2*c^2*K - e^2,
-3*r^2*s^2 - 2*r*s^3 + 3*c^2*K + 4*c*K - 2*d*e,
3*r^2*s + 6*r*s^2 + s^3 - 2*b*e + 6*c*K - d^2 + 2*K,
-2*b*d + c^2 - r^2 - 6*r*s - 3*s^2 + 3*K,
-b^2 + 2*c + 2*r + 3*s,
-r^2*s^3 + u*v^4 + 2*e*f - f^2,
3*r^2*s^2 + 2*r*s^3 - 4*u*v^3 - v^4 + 2*d*f,
-3*r^2*s - 6*r*s^2 - s^3 + 6*u*v^2 + 4*v^3 + 2*b*f,
r^2 + 6*r*s + 3*s^2 - 4*u*v - 6*v^2,
-2*r - 3*s + u + 4*v
]
have degrees 5,4,3,2,2,5,4,3,2,1 giving an upper bound of 28800 for the number of solutions. As the Groebner basis algorithms that are commonly used have a complexity bound of O(d^(n^2)) for the better algorithms, your runtime will be optimistically be characterized by the number 28800^10 (Bezout bound instead of d^n in (d^n)^n), which is rather large however small the constant. Even removing one variable for the linear equation will not change much in these estimates.
Thus any symbolic solution will take a long time and result in univariate polynomials of rather high degrees as part of any triangular polynomial basis.