I have an implicit function to solve:
So I tried root finding functions from scipy.optimize:
- fsolve : RuntimeWarning: The iteration is not making good progress, as
measured by the improvement from the last ten iterations.
- excitingmixing : NoConvergence
-brent: RuntimeWarning: invalid value encountered in double_scalars (but
without a chance to set constraints)
I have to confess that I'm not sure about the correct solver. Could someone please help?
Minimal working example:
from scipy.optimize import fsolve, newton, brent, excitingmixing
import numpy as np
def func_zeta(zeta):
k= 1.2
Re = 5000.
d = 0.03
return (2.51 /Re/np.sqrt(zeta)+k/d/3.71) + 10**(0.5/ np.sqrt(zeta))
zeta = fsolve(func_zeta, 64/Re)
There were problems in your translation of the formula. Shouldn't it rather be the following return statement?
return 2.51 / (Re * np.sqrt(zeta)) + k / (d * 3.71) - 10 ** (-0.5 / np.sqrt(zeta))
But even then we get again a RuntimeWarning. Let's try again and substitute zeta:
from scipy.optimize import fsolve
import numpy as np
def zeta_in_disguise(x):
global k, d, Re
return x + 2 * np.log10(2.51 * x / Re + k / (d * 3.71))
k = 1.2
Re = 5000
d = 0.03
#x = 1 / np.sqrt(zeta)
x = fsolve(zeta_in_disguise, 0)
print(x)
#let's test, if x is really the solution to the equation
print(-2 * np.log10(2.51 * x / Re + k / d / 3.71))
Ah, now it is convergent and produces the following output
-2.06528864
And there we have the problem - there is no solution for your given parameters, at least not, when we only consider float numbers.
Related
Is it possible to solve Cubic equation without using sympy?
Example:
import sympy as sp
xp = 30
num = xp + 4.44
sp.var('x, a, b, c, d')
Sol3 = sp.solve(0.0509 * x ** 3 + 0.0192 * x ** 2 + 3.68 * x - num, x)
The result is:
[6.07118098358257, -3.2241955998463 - 10.0524891203436*I, -3.2241955998463 + 10.0524891203436*I]
But I want to find a way to do it with numpy or without 3 part lib at all
I tried with numpy:
import numpy as np
coeff = [0.0509, 0.0192, 3.68, --4.44]
print(np.roots(coeff))
But the result is :
[ 0.40668245+8.54994773j 0.40668245-8.54994773j -1.19057511+0.j]
In your numpy method you are making two slight mistakes with the final coefficient.
In the SymPy example your last coefficient is - num, this is, according to your code: -num = - (xp + 4.44) = -(30 + 4.44) = -34.44
In your NumPy example yout last coefficient is --4.44, which is 4.44 and does not equal -34.33.
If you edit the NumPy code you will get:
import numpy as np
coeff = [0.0509, 0.0192, 3.68, -34.44]
print(np.roots(coeff))
[-3.2241956 +10.05248912j -3.2241956 -10.05248912j
6.07118098 +0.j ]
The answer are thus the same (note that NumPy uses j to indicate a complex number. SymPy used I)
You could implement the cubic formula
this Youtube video from mathologer could help understand it.
Based on that, the cubic function for ax^3 + bx^2 + cx + d = 0 can be written like this:
def cubic(a,b,c,d):
n = -b**3/27/a**3 + b*c/6/a**2 - d/2/a
s = (n**2 + (c/3/a - b**2/9/a**2)**3)**0.5
r0 = (n-s)**(1/3)+(n+s)**(1/3) - b/3/a
r1 = (n+s)**(1/3)+(n+s)**(1/3) - b/3/a
r2 = (n-s)**(1/3)+(n-s)**(1/3) - b/3/a
return (r0,r1,r2)
The simplified version of the formula only needs to get c and d as parameters (aka p and q) and can be implemented like this:
def cubic(p,q):
n = -q/2
s = (q*q/4+p**3/27)**0.5
r0 = (n-s)**(1/3)+(n+s)**(1/3)
r1 = (n+s)**(1/3)+(n+s)**(1/3)
r2 = (n-s)**(1/3)+(n-s)**(1/3)
return (r0,r1,r2)
print(cubic(-15,-126))
(5.999999999999999, 9.999999999999998, 2.0)
I'll let you mix in complex number operations to properly get all 3 roots
I was trying to obtain the Mathieu characteristic values for a specific problem. I do not have any problem obtaining them, and I have read the documentation from Scipy regarding these functions. The problem is that I know for a fact that the points I am obtaining are not right. My script to obtain the characteristic values I need is below:
import numpy as np
import matplotlib.pyplot as plt
from scipy.special import mathieu_a, mathieu_b, mathieu_cem, mathieu_sem
M = 1.0
g = 1.0
l = 1.0
h = 0.06
U0 = M * g * l
q = 4 * M * l**2 * U0 / h**2
def energy(n, q):
if n % 2 == 0:
return (h**2 / (8 * M * l**2)) * mathieu_a(n, q) + U0
else:
return (h**2 / (8 * M * l**2)) * mathieu_b(n + 1, q) + U0
n_list = np.arange(0, 80, 1)
e_n = [energy(i, q) for i in n_list]
plt.plot(n_list, e_n, '.')
The resulting plot of these values is this one. There is a zone where it appears to be "noise" or a numerical error, and I know that those jumps must not occur. In reality, around x= 40 to x > 40, the points should behave like a staircase of two consecutive points, similar to what can be seen between 70 < x < 80. And the values that x can take for this case are only positive integers.
I saw that the implementation of the Mathieu function has some problems, see here. But this was six years ago! In the answer to this question they use the NAG Library for Python, but it is not exactly open-source.
Is there a way I can still use these functions from Scipy without having this problem? Or is it related to the precision I am using to obtain the Mathieu characteristic value?
I want to do a plot of this equation below:
Problem 1: You see... since my function is a function of ν I have to calculate my integral to each ν in my domain. My question is: what is the best way to do that?
I thought about using scipy to do the integral and a for loop to calculate it several times to each ν, but it seems a very inelegant way to solve my problem. Does someone know a better alternative? Does someone have a different idea?
Problem 2: When I write my code I get some errors, mainly because I think that the exponential has a very small expoent. Do you have any ideas of how should I change it so I can do this plot using Python?
Oh, if you try with a different method, it is supposed to look like this
Here is the code I was working on. I'm coming back to Python now, so maybe there is some errors. The plot I'm getting is very different from the one that this is supposed to look.
from scipy.integrate import quad
from scipy.constants import c, Planck, k, pi
import numpy as np
import matplotlib.pyplot as plt
def luminosity_integral(r, x):
T_est = 4000
R_est = 2.5 * (696.34*1e6)
Temp = ((2/(3*pi))**(1/4)) * T_est * ((R_est/r)**(3/4))
termo1 = ((4 * (pi**2) * Planck * (x**4) ) / (c**2))
termo2 = ((Planck * x) / (k*Temp))
return ((termo1 * r ) / (np.exp(termo2) - 1))
freqs = np.linspace(1e10, 1e16)
y = np.array([])
for i in freqs:
I = quad(luminosity_integral, (6 * 2.5 * (696.34*1e6)), (7e4 * 2.5 * (696.34*1e6)), args = (i))
temp = np.array([I[0]])
y = np.concatenate((y, temp))
plt.loglog(freqs, y)
plt.show()
Reuse the term R_est instead instead of writing its expression 3 times (better if you want to change that parameter).
you used a pi**2 in the constant multiplying the integral (don't affect the shape)
The shape resembles what you put as reference, but not in the suggested range.
You are using the value of T as T_*, are you sure about that?
Try this version of the code
from scipy.integrate import quad
from scipy.constants import c, Planck, k, pi
import numpy as np
import matplotlib.pyplot as plt
R_est = 2.5 * (696.34e6)
def luminosity_integral(r, x):
T_est = 4000
termo1 = ((4 * pi * Planck * (x**4) ) / (c**2))
termo2 = ((Planck * x) / (k*T_est)) * (3*pi/2 * (r/R_est)**3)**0.25
termo3 = np.exp(-termo2)
return ((termo1 * r ) * termo3 / (1 - termo3))
freqs = np.logspace(6, 16)
y = np.zeros_like(freqs)
for i, nu in enumerate(freqs):
y[i] = quad(luminosity_integral, (6* R_est), (7e4 * R_est), args = (nu))[0]
plt.loglog(freqs, y)
plt.ylim([1e6, 1e25])
plt.show()
I have some variables that are uncertain, these are
w_m = u.ufloat(0.1430, 0.0011)
z_rec = u.ufloat(1089.92, 0.25)
theta_srec = u.ufloat(0.0104110, 0.0000031)
r_srec = u.ufloat(144.43, 0.26)
and some constant values
c = 299792.458 # speed of light in [km/s]
N_eff = 3.046
w_r = 2.469 * 10**(-5) * (1 + (7/8)*(4/11)**(4/3) * N_eff)
My problem is I need to solve an integral defined by this functions
def D_zrec(z):
return (c/100) / sqrt(w_m * (1+z)**3 + w_r * (1+z)**4 + (h**2 - w_m - w_r))
This function is evaluated for dz but it also contains an unknown h that we need to find, with corresponding uncertainty. So I need to write a code that finds h.
Here is my full code
from numpy import sqrt, vectorize
from scipy.integrate import quad
import uncertainties as u
from uncertainties.umath import *
from scipy.optimize import fsolve
#### Important Parameters #####
c = 299792.458 # speed of light in [km/s]
N_eff = 3.046
w_r = 2.469 * 10**(-5) * (1 + (7/8)*(4/11)**(4/3) * N_eff)
w_m = u.ufloat(0.1430, 0.0011)
z_rec = u.ufloat(1089.92, 0.25)
theta_srec = u.ufloat(0.0104110, 0.0000031)
r_srec = u.ufloat(144.43, 0.26)
D_zrec_true = r_srec / theta_srec
#u.wrap
def D_zrec_finder(h, w_m, z_rec, D_zrec_true):
def D_zrec(z):
return (c/100) / sqrt(w_m * (1+z)**3 + w_r * (1+z)**4 + (h**2 - w_m - w_r))
result, error = quad(D_zrec, 0, z_rec)
return D_zrec_true - result
def h0_finder(w_m, z_rec, D_zrec_true):
vfunc = vectorize(D_zrec_finder)
sol = fsolve(vfunc, u.ufloat(0.6728, 0.01), args=(w_m, z_rec, D_zrec_true))[0]
return sol
print(h0_finder(w_m, z_rec, D_zrec_true))
So to summarize I have an integral named as D_zrec that is a function of z, but also contains an unknown number h that we need to find by using fsolve.
I have found 3 sites that might be useful for the coder. Please look at them if you want to help
https://kitchingroup.cheme.cmu.edu/blog/2013/03/07/Another-approach-to-error-propagation/
https://kitchingroup.cheme.cmu.edu/blog/2013/07/10/Uncertainty-in-an-integral-equation/
https://kitchingroup.cheme.cmu.edu/blog/2013/01/23/Solving-integral-equations-with-fsolve/
I have looked at them to write my code but no luck.
Thanks for the help
I'm trying to solve the following system: d²i/dt² + R'(i)/L di/dt + 1/LC i(t) = 1/L dE/dt as a set of coupled first order differential equations:
di/dt = k
dk/dt = 1/L dE/dt - R'(i)/L k - 1/LC i(t)
Here is the code I'm using:
import numpy as np
import sympy as sp
import matplotlib.pyplot as plt
from scipy.integrate import odeint
#Define model: x = [i , k]
def RLC(x , t):
i = sp.Symbol('i')
t = sp.Symbol('t')
#Data:
E = sp.ln(t + 1)
dE_dt = E.diff(t)
R1 = 1000 #1 kOhm
R2 = 100 #100 Ohm
R = R1 * i + R2 * i**3
dR_di = R.diff(i)
i = x[0]
k = x[1]
L = 10e-3 #10 mHy
C = 1.56e-6 #1.56 uF
#Model
di_dt = k
dk_dt = 1/L * dE_dt - dR_di/L * k - 1/(L*C) * i
dx_dt = np.array([di_dt , dk_dt])
return dx_dt
#init cond:
x0 = np.array([0 , 0])
#time points:
time = np.linspace(0, 30, 1000)
#solve ODE:
x = odeint(RLC, x0, time)
i = x[: , 0]
However, I get the following error: TypeError: Cannot cast array data from dtype('O') to dtype('float64') according to the rule 'safe'
So, I don't know if sympy and odeint don't work well together. Or maybe is it a problem because I defined t as sp.Symbol?
When you differentiate a function, you get a function back. So you need to evaluate it at a point in order to get a number. To evaluate a sympy expression, you could use .subs() but I prefer .replace() which feels more powerful (at least for me).
You must try and make every single variable have its own name in order to avoid confusion. For example, you replace the float input t with a sympy Symbol from the very beginning, thus losing the value of t. The variables x and i are also repeated in the outer scope which is not good practice if they mean different things.
The following should avoid confusion and hopefully produce something that you were expecting:
import numpy as np
import sympy as sp
import matplotlib.pyplot as plt
from scipy.integrate import odeint
# Define model: x = [i , k]
def RLC(x, t):
# define constants first
i = x[0]
k = x[1]
L = 10e-3 # 10 mHy
C = 1.56e-6 # 1.56 uF
R1 = 1000 # 1 kOhm
R2 = 100 # 100 Ohm
# define symbols (used to find derivatives)
i_symbol = sp.Symbol('i')
t_symbol = sp.Symbol('t')
# Data (differentiate and evaluate)
E = sp.ln(t_symbol + 1)
dE_dt = E.diff(t_symbol).replace(t_symbol, t)
R = R1 * i_symbol + R2 * i_symbol ** 3
dR_di = R.diff(i_symbol).replace(i_symbol, i)
# nothing should contain symbols from here onwards
# variables can however contain sympy expressions
# Model (convert sympy expressions to floats)
di_dt = float(k)
dk_dt = float(1 / L * dE_dt - dR_di / L * k - 1 / (L * C) * i)
dx_dt = np.array([di_dt, dk_dt])
return dx_dt
# init cond:
x0 = np.array([0, 0])
# time points:
time = np.linspace(0, 30, 1000)
# solve ODE:
solution = odeint(RLC, x0, time)
result = solution[:, 0]
print(result)
Just something to note: the value i = x[0] seemed to sit very close to 0 throughout each iteration. This means dR_di stayed basically at 1000 the whole time. I'm not familiar with odeint or your specific ODE, but hopefully this phenomenon is expected and isn't a problem.