'Solving system of linear equations with different orders of magnitude
I am trying to solve a system of two non-linear equations to obtain the value of one of the unknowns. The system of equations is:
p_sis=K*e^((-T/3)/(R_tot * C_tot))
p_dia=K*e^(-T/(R_tot * C_tot))
Data: p_sis = 22931.447 ; p_dia = 11865.691 ; T = 1.15384 ; R_tot = 9785025352
I have solved the system of equations through Wolfram Alpha and by hand and the results are the same:
K = 31865
C_tot = 1.18974*10^-10
I only need the value of C_tot. I would like to solve this system of equations automatically through Python. However, after having applied several possible methods, none of them have provided the correct answer (even when changing the initial guess values and using values very close to the actual solution).
Here are the different sets of code I have used:
METHOD #1: through scipy.optimize.fsolve
import numpy as np
from scipy.optimize import fsolve #
p_sis = 22931.447
p_dia = 11865.691
T = 1.15384
R_tot = 9785025352
def myFunction(z):
x = z[0] # = K
y = z[1] # = C_tot
F = np.empty((2))
F[0] = p_sis-x * np.exp((-T/3)/(R_tot * y))
F[1] = p_dia-x * np.exp((-T)/(R_tot * y))
return F
zGuess = np.array([30000,0.0000001])
z = fsolve(myFunction,zGuess)
print(z)
RESULT: [3.18787051e+04 4.14184981e-08].
METHOD #2: through simpy
from sympy import *
import numpy as np
import mpmath
p_sis = 22931.447
p_dia = 11865.691
T = 1.15384
R_tot = 9785025352
mpmath.mp.dps=40
x = Symbol('x') # = K
y = Symbol('y') # = C_tot
aaa= nsolve([p_sis - x * 2.71828**(((-T / 3) / (R_tot * y))), p_dia - x * 2.71828**(((-T) / (R_tot * y)))], [x, y], [30000, 0.000000001])
print(aaa)
RESULT: Could not find root within the given tolerance.
METHOD #3: Least Squares Method with Levenberg-Marquardt (scipy.optimize.root)
import numpy as np
import sympy
import pandas as pd
from scipy.optimize import fsolve, root
def func(x):
return [p_sis - x[0] * np.exp(((-T / 3) / (R_tot * x[1]))), p_dia - x[0] * np.exp(((-T) / (R_tot * x[1])))]
def jac(x):
return np.array([[-np.exp(-T/(3*R_tot*x[1])),
-(T*x[0]*np.exp(-T/(3*R_tot*x[1])))/(3*R_tot*x[1]**2)],
[-np.exp(-T/(R_tot*x[1])),
-(T*x[0]*np.exp(-T/(R_tot*x[1])))/(R_tot*x[1]**2)]])
initialGuess = np.array([30000, 1e-10])
results = root(func, initialGuess, method='lm', jac=jac, tol=(1e-90), options={'maxiter': 5000000})
print(results)
RESULT: [2.89750393e+07, 8.07125772e-10].
METHOD #4: Newton's Method
from sympy import *
import numpy as np
p_sis = 22931.447
p_dia = 11865.691
T = 1.15384
R_tot = 9785025352
def Newton_system(F, J, x, eps):
from numpy import pi, exp
F_value = F(x)
F_norm = np.linalg.norm(F_value, ord=2) # l2 norm of vector
iteration_counter = 0
while abs(F_norm) > eps and iteration_counter < 100:
delta = np.linalg.solve(J(x), -F_value)
x = x + delta
F_value = F(x)
F_norm = np.linalg.norm(F_value, ord=2)
iteration_counter += 1
# Here, either a solution is found, or too many iterations
if abs(F_norm) > eps:
iteration_counter = -1
return x, iteration_counter
def test_Newton_system1():
from numpy import pi, exp
def F(x):
return np.array(
[p_sis - x[0] * exp(((-T / 3) / (R_tot * x[1]))),
p_dia - x[0] * exp(((-T) / (R_tot * x[1])))])
def J(x):
return np.array(
[[-exp(-T/(3*R_tot*x[1])), -(T*x[0]*exp(((-T / 3) / (R_tot * x[1]))))/(3*R_tot*x[1]**2)],
[-exp(-T/(R_tot*x[1])), -(T*x[0]*exp(((-T) / (R_tot * x[1]))))/(R_tot*x[1]**2)]])
expected = np.array([10000, 0.000001])
tol = 1e-16
x, n = Newton_system(F, J, x=np.array([0.02, 0.2]), eps=0.00000001)
print(n, x)
error_norm = np.linalg.norm(expected - x, ord=2)
assert error_norm < tol, 'norm of error =%g' % error_norm
print( 'norm of error =%g' % error_norm)
aaaaa=test_Newton_system1()
print(aaaaa)
RESULT: Singular matrix (did not reach a solution).
METHOD #5: Eq from sympy
from sympy import symbols, Eq, solve
import numpy as np
p_sis = 22931.447
p_dia = 11865.691
T = 1.15384
R_tot = 9785025352
x, y = symbols("x y") # x = K ; y = C_tot ; e = approx 2.71828
equation_1 = Eq((p_sis - x * 2.71828**((-T/3)/(R_tot * y))), 0)
equation_2 = Eq((p_dia - x * 2.71828**((-T)/(R_tot * y))), 0)
print("Equation 1:", equation_1)
print("Equation 2:", equation_2)
solution = solve((equation_1, equation_2), (x, y))
print("Solution:", solution)
RESULT: computes forever and does not return a solution.
I have even conjoined the two equations into one and tried to solve it to obtain only C_tot:
p_sis*e^((T/3)/(R_tot * C_tot)) = p_dia*e^((T)/(R_tot * C_tot))
The code looks like this:
from math import exp
import scipy.optimize
p_sis = 22931.447
p_dia = 11865.691
T = 1.15384
R_tot = 9785025352
def fun(y): # y = C_tot
z = p_dia*exp((T)/(R_tot * y)) - p_sis*exp((T/3)/(R_tot * y))
return z
z = scipy.optimize.fsolve(fun,10e-6, maxfev=1000)
print (z)
RESULT: The iteration is not making good progress, as measured by the improvement from the last ten iterations (solution equal to initial guess of 10e-6).
I suspect that the fact that K and C_tot have very different magnitudes, the program has trouble converging to the solution. Increasing the number of decimal places didn't really impact the performance.
How could I solve this issue? The fact that all the used methods did not reach the final solution makes me wonder if I made any mistakes in the definition of the problem.
Thank you in advance for all the help.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
