'issue with scipy.optimize.root returing non-zero errors
The code below is a simplified version of a set of non-linear equations I am trying to solve using scipy.optimize.root. The if statements associated with variables e_eqn3 and e_eqn4 in function system_err try to prevent the solver from heading off into non-physical solution space. Everything seems to work fine for x12t >= 0.26 in the main program, but at lower values, I get back my initial guess, as the following output shows:
x12t = 0.25
q12 p12
Initial: 19.00 1695.00
Final: 19.00 1695.00
Exited successfully: True
x12t = 0.26
q12 p12
Initial: 19.00 1695.00
Final: 21.62 2187.55
Exited successfully: True
I checked this using EXCEL and I get a sensible solution for x12t = 0.25. I also checked the values being returned by system_err for x12t < 0.25 and an example of the final values before successful convergence is [1000000.0, 0.0, 1.378, 0.0, 0.0], which I thought meant that the overall error was still too high. Would appreciate any comments about either what I am doing wrong or a possible fix. Thanks in advance!
import math
import scipy.optimize
import numpy as np
# Calculate the system error
def system_err(x, pres, psgp, ptgp, x12t, x11t, x11s):
# Unpack the unknowns
p11 = x[0]
p12 = x[1]
q11 = x[2]
q12 = x[3]
r = x[4]
# Define constants
a = 1.5152
b = 1.7576
c = 1.3433
beta = 0.0129
C11 = 0.010
C12 = 0.018
n11 = 0.595
n12 = 0.533
# Define the error associated with the constituent equations
if p12 > pres:
e_eqn3 = 1.0E06
else:
e_eqn3 = q12 - C12 * ((pres ** 2 - p12 ** 2) ** n12)
if p11 > pres:
e_eqn4 = 1.0E06
else:
e_eqn4 = q11 - C11 * ((pres ** 2 - p11 ** 2) ** n11)
e_eqn5 = q12 - c * x12t * p12 * math.sqrt(beta * ( (ptgp / p12) ** a - (ptgp / p12) ** b) )
e_eqn6 = r * q11 - c * x11t * p11 * math.sqrt(beta * ( (ptgp / p11) ** a - (ptgp / p11) ** b) )
e_eqn7 = (1.0 - r) * q11 - c * x11s * p11 * math.sqrt(beta * ( (psgp / p11) ** a - (psgp / p11) ** b) )
# Return the errors
err = [e_eqn3, e_eqn4, e_eqn5, e_eqn6, e_eqn7]
return err
# MAIN program
if __name__ == "__main__":
# Initialise
psgp = 1000.0 # plant 1 pressure (psia)
ptgp = 1200.0 # plant 2 pressure (psia)
pres = 2190.0 # inlet pressure (psia)
x11s = 0.0 # FCV 1 setting
x11t = 0.0 # FCV 2 setting
# Vary FCV 3 setting
for x12t in np.arange(0.20, 0.301, 0.01):
# Initial guess for solution
p11 = pres
p12 = (ptgp + pres) / 2.0
q11 = 0.0
q12 = 50.0
r = 0.0
x0 = [p11, p12, q11, q12, r]
print("\nx12t = %4.2f" % x12t)
print(" q12 p12")
print("Initial: %5.2f %7.2f" % (q12, p12) )
# Solve system
sol = scipy.optimize.root(system_err, x0, args=(pres, psgp, ptgp, x12t, x11t, x11s))
# Unpack the solution
p11 = sol.x[0]
p12 = sol.x[1]
q11 = sol.x[2]
q12 = sol.x[3]
r = sol.x[4]
print("Final: %5.2f %7.2f" % (q12, p12))
print("Exited successfully: %s" % sol.success)
Solution 1:[1]
Thought a bit harder about the physics of the problem and when eg p12 > pres then the flow direction reverses. This leads to raising a negative number to a fractional power which the original fix tried to prevent. Changed the code to represent the flow reversal explicitly
if p12 > pres:
e_eqn3 = q12 + C12 * ((p12 ** 2 - pres ** 2) ** n12)
else:
e_eqn3 = q12 - C12 * ((pres ** 2 - p12 ** 2) ** n12)
and the issue seems to have gone away.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | PetGriffin |
