Solve highly non-linear equation for x in Python - python

I am trying to solve the following equation for dB (for simplicity, I stated dB as x in the question title):
All of the other terms in the equation are known. I tried using SymPy to symbolically solve for dB but I kept getting time out errors. I also tried using fminbound from scipy.optimize but the answer for dB is wrong (see below for Python code using the fminbound approach).
Does anyone know of a way to solve the equation for dB using Python?
import numpy as np
from scipy.optimize import fminbound
#------------------------------------------------------------------------------
# parameters
umf = 0.063 # minimum fluidization velocity, m/s
dbed = 0.055 # bed diameter, m
z0 = 0 # position bubbles are generated, m
z = 0.117 # bed vertical position, m
g = 9.81 # gravity, m/s^2
#------------------------------------------------------------------------------
# calculations
m = 3 # multiplier for Umf
u = m*umf # gas superficial velocity, m/s
abed = (np.pi*dbed**2)/4.0 # bed cross-sectional area, m^2
# calculate parameters used in equation
dbmax = 2.59*(g**-0.2)*(abed*(u-umf))**0.4
dbmin = 3.77*(u-umf)**2/g
c1 = 2.56*10**-2*((dbed / g)**0.5/umf)
c2 = (c1**2 + (4*dbmax)/dbed)**0.5
c3 = 0.25*dbed*(c1 + c2)**2
dbeq = 0.25*dbed*(-c1 + (c1**2 + 4*(dbmax/dbed))**0.5 )**2
# general form of equation ... (term1)^power1 * (term2)^power2 = term3
power1 = 1 - c1/c2
power2 = 1 + c1/c2
term3 = np.exp(-0.3*(z - z0)/dbed)
def dB(d):
term1 = (np.sqrt(d) - np.sqrt(dbeq)) / (np.sqrt(dbmin) - np.sqrt(dbeq))
term2 = (np.sqrt(d) + np.sqrt(c3)) / (np.sqrt(dbmin) + np.sqrt(c3))
return term1**power1 * term2**power2 - term3
# solve main equation for dB
dbub = fminbound(dB, 0.01, dbed)
print 'dbub = ', dbub

Here are the four single-dim root-methods:
from scipy.optimize import brentq, brenth, ridder, bisect
for rootMth in [brentq, brenth, ridder, bisect]:
dbub = rootMth(dB, 0.01, dbed)
print 'dbub = ', dbub, '; sanity check (is it a root?):', dB(dbub)
Also the newton-raphson (secant / haley) method:
from scipy.optimize import newton
dbub = newton(dB, dbed)
print 'dbub = ', dbub, '; sanity check (is it a root?):', dB(dbub)
The scipy documentation recommends brentq if you have a bracketing interval.

To solve what's in your title is easy:
In [9]:
import numpy as np
import scipy.optimize as so
In [10]:
def f(x):
return ((x-0.32)**0.8+(x+1.45)**1.1-np.exp(0.8))**2
In [11]:
so.fmin(f, x0=5)
Optimization terminated successfully.
Current function value: 0.000000
Iterations: 20
Function evaluations: 40
Out[11]:
array([ 0.45172119])
In [12]:
f(0.45172119)
Out[12]:
4.7663411535618792e-13
All the other parameters are fixed?

Related

solve_ivp discards imaginary part of complex solution

I am computing a solution to the free basis expansion of the dirac equation for electron-positron pairproduction. For this i need to solve a system of equations that looks like this:
Equation for pairproduction, from Mocken at al.
EDIT: This has been solved by passing y0 as complex type into the solver. As is stated in this issue: https://github.com/scipy/scipy/issues/8453 I would definitely consider this a bug but it seems like it has gone under the rock for at least 4 years
for this i am using SciPy's solve_ivp integrator in the following way:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
from scipy.integrate import solve_ivp
import scipy.constants as constants
#Impulse
px, py = 0 , 0
#physics constants
e = constants.e
m = constants.m_e # electronmass
c = constants.c
hbar = constants.hbar
#relativistic energy
E = np.sqrt(m**2 *c**4 + (px**2+py**2) * c**2) # E_p
#adiabatic parameter
xi = 1
#Parameter of the system
w = 0.840 #frequency in 1/m_e
N = 8 # amount of amplitudes in window
T = 2* np.pi/w
#unit system
c = 1
hbar = 1
m = 1
#strength of electric field
E_0 = xi*m*c*w/e
print(E_0)
#vectorpotential
A = lambda t,F: -E_0/w *np.sin(t)*F
def linearFenster2(t):
conditions = [t <=0, (t/w>=0) and (t/w <= T/2), (t/w >= T/2) and (t/w<=T*(N+1/2)), (t/w>=T*(N+1/2)) and (t/w<=T*(N+1)), t/w>=T*(N+1)]
funcs = [lambda t: 0, lambda t: 1/np.pi *t, lambda t: 1, lambda t: 1-w/np.pi * (t/w-T*(N+1/2)), lambda t: 0]
return np.piecewise(t,conditions,funcs)
#Coefficient functions
nu = lambda t: -1j/hbar *e*A(w*t,linearFenster2(w*t)) *np.exp(2*1j/hbar * E*t) *(px*py*c**2 /(E*(E+m*c**2)) + 1j*(1- c**2 *py**2/(E*(E+m*c**2))))
kappa = lambda t: 1j*e*A(t,linearFenster2(w*t))* c*py/(E * hbar)
#System to solve
def System(t, y, nu, kappa):
df = kappa(t) *y[0] + nu(t) * y[1]
dg = -np.conjugate(nu(t)) * y[0] + np.conjugate(kappa(t))*y[1]
return np.array([df,dg], dtype=np.cdouble)
def solver(tmin, tmax,teval=None,f0=0,g0=1):
'''solves the system.
#tmin: starttime
#tmax: endtime
#f0: starting percentage of already present electrons of positive energy usually 0
#g0: starting percentage of already present electrons of negative energy, usually 1, therefore full vaccuum
'''
y0=[f0,g0]
tspan = np.array([tmin, tmax])
koeff = np.array([nu,kappa])
sol = solve_ivp(System,tspan,y0,t_eval= teval,args=koeff)
return sol
#Plotting of windowfunction
amount = 10**2
t = np.arange(0, T*(N+1), 1/amount)
vlinearFenster2 = np.array([linearFenster2(w*a) for a in t ], dtype = float)
fig3, ax3 = plt.subplots(1,1,figsize=[24,8])
ax3.plot(t,E_0/w * vlinearFenster2)
ax3.plot(t,A(w*t,vlinearFenster2))
ax3.plot(t,-E_0 /w * vlinearFenster2)
ax3.xaxis.set_minor_locator(ticker.AutoMinorLocator())
ax3.set_xlabel("t in s")
ax3.grid(which = 'both')
plt.show()
sol = solver(0, 70,teval = t)
ts= sol.t
f=sol.y[0]
fsquared = 2* np.absolute(f)**2
plt.plot(ts,fsquared)
plt.show()
The plot for the window function looks like this (and is correct)
window function
however the plot for the solution looks like this:
Plot of pairproduction probability
This is not correct based on the papers graphs (and further testing using mathematica instead).
When running the line 'sol = solver(..)' it says:
\numpy\core\_asarray.py:102: ComplexWarning: Casting complex values to real discards the imaginary part
return array(a, dtype, copy=False, order=order)
I simply do not know why solve_ivp discard the imaginary part. Its absolutely necessary.
Can someone enlighten me who knows more or sees the mistake?
According to the documentation, the y0 passed to solve_ivp must be of type complex in order for the integration to be over the complex domain. A robust way of ensuring this is to add the following to your code:
def solver(tmin, tmax,teval=None,f0=0,g0=1):
'''solves the system.
#tmin: starttime
#tmax: endtime
#f0: starting percentage of already present electrons of positive energy usually 0
#g0: starting percentage of already present electrons of negative energy, usually 1, therefore full vaccuum
'''
f0 = complex(f0) # <-- added
g0 = complex(g0) # <-- added
y0=[f0,g0]
tspan = np.array([tmin, tmax])
koeff = np.array([nu,kappa])
sol = solve_ivp(System,tspan,y0,t_eval= teval,args=koeff)
return sol
I tried the above, and it indeed made the warning disappear. However, the result of the integration seems to be the same regardless.

Trouble computing integral with scipy quad

I'm trying to compute the following definite integral:
Integral I want to compute:
where rho_ch is
and
a = 3.66 * 10^(-15) m (in meters)
b = 0.54 * 10^(-15) m
and rho_0 = 1.23 * 10^(-35) C/m^3.
When I compute it, I get something of the order of 10^(-61), but I believe it should be something closer to 1.
I take the upper limit of the integral to 10^(-10) because the integral should have converged by then. My guess is that the problem has do with overflow in the rho_ch function, although I tried a fix for that, but it didn't work.
Does anyone have any idea of what I'm doing wrong?
import numpy as np
from scipy.constants import *
from scipy import integrate
Z_t = 20
a = 1.07*40**(1/3)
b = 0.54
rho_0 = 0.077*e
X_0 = np.array([rho_0, a, b])*10**(-15)
E = 250*10**(6)*e
p_sq = (E/c)**2-(m_e*c)**2
beta_sq = 1-(1/(E/(m_e*c**2))**2)
theta = np.pi/6
def q(theta):
return 2*np.sqrt(p_sq*np.sin(theta/2)**2)
def F_quad(theta, X):
return 4*np.pi*hbar/(Z_t*e*q(theta))*integrate.quad(integrand2, 0, 10**(-10), args=(theta, X))[0]
integrand2 = lambda r, theta, X: r*X[0]/(1+np.exp((r-X[1])/X[2]))*np.sin(q(theta)*r/hbar) if (r-X[1])/X[2] <= 600 else 0

Solving system of nonlinear complex equations in Python

I'm trying to solve a problem with 8 unknowns and 8 complex equations. I've tried to use fsolve but I get the error message:
error: Result from function call is not a proper array of floats.
From what I've now read fsolve doesn't support complex equations and hence my questions, how would I solve systems of complex non-linear equations in Python?
PS: I've seen the suggestion to split my problem up into imaginary and real part and use fsolve on those separately but that is too cumbersome.
This is the relevant snippet of my code:
A=1
def equations(p):
B,C,D,F,G,H,I,J = p
return (
A+B-C-D,
1j*k0*(A-B) -1j*k1*(C-D),
B*exp(1j*k1*a1) + D*exp(-1j*k1*a1) - F*exp(1j*k0*a1) - G*exp(-1j*k0*a1),
1j*k1* ( C*exp(1j*k1*a1) - D*exp(-1j*k1*a1) ) - 1j*k0*( F*exp(1j*k0*a1) - G*exp(-1j*k0*a1) ),
F*exp(1j*k0*a1L) + G*exp(-1j*k0*a1L) - H*exp(-k2*a1L) - I*exp(k2*a1L),
1j*k0*( F*exp(1j*k0*a1L) - G*exp(-1j*k0*a1L) )- k2*( -H*exp(-k2*a1L) + I*exp(k2*a1L) ),
H*exp(-k2*a12L) + I*exp(k2*a12L) - J*exp(1j*k0*a12L),
k2*( -H*exp(-k2*a12L) + I*exp(k2*a12L) ) - 1j*k0*J*exp(1j*k0*a12L)
)
B, C, D, F, G, H, I, J = fsolve(equations, (-1,-1,-1,-1,-1,-1,-1,-1))
Algorithm in which the code below was written
algorithm for Newton’s Method for Systems
# Author : Carlos Eduardo da Silva Lima
# Theme : Newton’s Method for Systems (real or complex)
# Language: Python
# IDE : Google Colab
# Data : 18/11/2022
######################################################################
# This Part contains the imports of packages needed for this project #
######################################################################
import numpy as np
import matplotlib.pyplot as plt
from numpy.linalg import inv, norm, multi_dot
from scipy.optimize import fsolve
######################
# Enter problem data #
######################
x0 = np.array([1.0+0.0j, 1.0+0.0j, 1.0+0.0j]) # Initial guess for the possible root of the set of nonlinear equations entered in F(x)
TOL = 1e-49 # Stipulated minimum tolerance
N = 10 # Number of required maximum iterations
############################
# Newton-Raphson algorithm #
############################
def newtonRapshonSistem(F,J,x0,TOL,N):
x = x0 # First kick
k = 1
while(k<=N):
# Ccalculation of the product between the inverse of the Jacobian matrix (J(x)^(-1)) and the vector F(x) (T a transpose)
y = -((inv(J(x)))#(F(x).T))
x += (y.T)
# absolute value norm
erro_abs = np.linalg.norm(np.abs(y))
if erro_abs<TOL:
break
k += 1
# Exit #
print(f"Number of iterations: {k}")
print(f"Absolute error: {erro_abs}\n")
print("\nSolução\n")
for l in range(0,np.size(x),1):
print(f"x[{l}] = {x[l]:.4}\n")
# print(f'x[{l}] = {np.real(x[l]):.4} + {np.imag(x[l]):.4}j')
return x
#################
# Function F(x) #
#################
def F(x):
# definition of variables (Arrays)
x1,x2,x3 = x
# definition of the set of nonlinear equations
f1 = x1+x2-10000
f2 = x1*np.exp(-1j*x3*5) + x2*np.exp(1j*x3*5) - 12000
f3 = x1*np.exp(-1j*x3*10) + x2*np.exp(1j*x3*10) - 8000
return np.array([f1, f2, f3], dtype=np.complex128)
############
# Jacobian #
############
def J(x):
# definition of variables (Arrays)
x1,x2,x3 = x
# Jacobean matrix elements
df1_dx1 = 1
df1_dx2 = 1
df1_dx3 = 0
df2_dx1 = np.exp(-1j*x3*5)
df2_dx2 = np.exp(1j*x3*5)
df2_dx3 = x1*(-1j*5)*np.exp(-1j*x3*5)+x2*(1j*5)*np.exp(1j*x3*5)
df3_dx1 = np.exp(-1j*x3*10)
df3_dx2 = np.exp(1j*x3*10)
df3_dx3 = x1*(-1j*10)*np.exp(-1j*x3*10) + x2*(1j*10)*np.exp(1j*x3*10)
matriz_jacobiana = np.array([
[df1_dx1, df1_dx2, df1_dx3],
[df2_dx1, df2_dx2, df2_dx3],
[df3_dx1, df3_dx2, df3_dx3]], dtype=np.complex128)
return matriz_jacobiana
# Calculate the roots
s = newtonRapshonSistem(F,J,x0,TOL,N)
# Application of the result obtained in x in F.
F(s)
Finally! If you don't agree, or if you find any errors, please let me know. In the most I hope to help you and the community the community. Up until :-).

fmin_slsqp returns initial guess finding the minimum of cubic spline

I am trying to find the minimum of a natural cubic spline. I have written the following code to find the natural cubic spline. (I have been given test data and have confirmed this method is correct.) Now I can not figure out how to find the minimum of this function.
This is the data
xdata = np.linspace(0.25, 2, 8)
ydata = 10**(-12) * np.array([1,2,1,2,3,1,1,2])
This is the function
import scipy as sp
import numpy as np
import math
from numpy.linalg import inv
from scipy.optimize import fmin_slsqp
from scipy.optimize import minimize, rosen, rosen_der
def phi(x, xd,yd):
n = len(xd)
h = np.array(xd[1:n] - xd[0:n-1])
f = np.divide(yd[1:n] - yd[0:(n-1)],h)
q = [0]*(n-2)
for i in range(n-2):
q[i] = 3*(f[i+1] - f[i])
A = np.zeros(((n-2),(n-2)))
#define A for j=0
A[0,0] = 2*(h[0] + h[1])
A[0,1] = h[1]
#define A for j = n-2
A[-1,-2] = h[-2]
A[-1,-1] = 2*(h[-2] + h[-1])
#define A for in the middle
for j in range(1,(n-3)):
A[j,j-1] = h[j]
A[j,j] = 2*(h[j] + h[j+1])
A[j,j+1] = h[j+1]
Ainv = inv(A)
B = Ainv.dot(q)
b = (n)*[0]
b[1:(n-1)] = B
# now we find a, b, c and d
a = [0]*(n-1)
c = [0]*(n-1)
d = [0]*(n-1)
s = [0]*(n-1)
for r in range(n-1):
a[r] = 1/(3*h[r]) * (b[r + 1] - b[r])
c[r] = f[r] - h[r]*((2*b[r] + b[r+1])/3)
d[r] = yd[r]
#solution 1 start
for m in range(n-1):
if xd[m] <= x <= xd[m+1]:
s = a[m]*(x - xd[m])**3 + b[m]*(x-xd[m])**2 + c[m]*(x-xd[m]) + d[m]
return(s)
#solution 1 end
I want to find the minimum on the domain of my xdata, so a fmin didn't work as you can not define bounds there. I tried both fmin_slsqp and minimize. They are not compatible with the phi function I wrote so I rewrote phi(x, xd,yd) and added an extra variable such that phi is phi(x, xd,yd, m). M indicates in which subfunction of the spline we are calculating a solution (from x_m to x_m+1). In the code we replaced #solution 1 by the following
# solution 2 start
return(a[m]*(x - xd[m])**3 + b[m]*(x-xd[m])**2 + c[m]*(x-xd[m]) + d[m])
# solution 2 end
To find the minimum in a domain x_m to x_(m+1) we use the following code: (we use an instance where m=0, so x from 0.25 to 0.5. The initial guess is 0.3)
fmin_slsqp(phi, x0 = 0.3, bounds=([(0.25,0.5)]), args=(xdata, ydata, 0))
What I would then do (I know it's crude), is iterate this with a for loop to find the minimum on all subdomains and then take the overall minimum. However, the function fmin_slsqp constantly returns the initial guess as the minimum. So there is something wrong, which I do not know how to fix. If you could help me this would be greatly appreciated. Thanks for reading this far.
When I plot your function phi and the data you feed in, I see that its range is of the order of 1e-12. However, fmin_slsqp is unable to handle that level of precision and fails to find any change in your objective.
The solution I propose is scaling the return of your objective by the same order of precision like so:
return(s*1e12)
Then you get good results.
>>> sol = fmin_slsqp(phi, x0=0.3, bounds=([(0.25, 0.5)]), args=(xdata, ydata))
>>> print(sol)
Optimization terminated successfully. (Exit mode 0)
Current function value: 1.0
Iterations: 2
Function evaluations: 6
Gradient evaluations: 2
[ 0.25]

Finding the roots of an equation numerically returns the initial guess

I am trying to find the root of a cubic equation using fsolve. This is my code:
from scipy import *
from scipy.optimize import fsolve
import matplotlib.pyplot as plt
import numpy as np
#These are all parameters
g = 5.61
gamma = 6.45
kappa = 6.45
J = 6.45
rs = 10.0
m = 5.0*10**(-11)
wm = 2*3.14*23.4
r2 = np.linspace(0, 0.02, 1000)
deltaW = 0
A = 1j*g**2*(kappa + 1j*deltaW)*r2*r2/(m*wm**2)
B = J**2 + (1j*deltaW - gamma)*(1j*deltaW + kappa)
C = A + B
D = abs(C)*r2 - J*np.sqrt(2*kappa)*rs
def func(x):
D = abs(C)*r2 - J*np.sqrt(2*kappa)*rs
return D
x0 = fsolve(func, 0.0)
print x0
plt.plot(r2, D)
plt.show()
I can see from the plot that there is at least one r2 that makes D zero. However, the return value x0 I get from fsolve is always the guess value I set.
Can anyone tell me why this is happening and how to fix it?
You are passing to fsolve a function that isn't a function at all: it doesn't do anything with the inputs x. Yet, fsolve needs that, because it will test a series of values and each time check the return value from the function call with that test value. In your case, func(x) never changes, so fsolve stops with an error message of
The iteration is not making good progress, as measured by the improvement from the last ten iterations.
You could see that message if you would add full_output=True in the call to fsolve.
To solve it, define your function like this:
def func(x):
A = 1j*g**2*(kappa + 1j*deltaW)*x*x/(m*wm**2)
B = J**2 + (1j*deltaW - gamma)*(1j*deltaW + kappa)
C = A + B
D = abs(C)*x - J*np.sqrt(2*kappa)*rs
return D

Categories