I'm trying to solve a physical problem with python. The goal is to find the a_n values that minimize the function epsilon (see image):
And the code is:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import quad
from scipy.optimize import minimize
from scipy.misc import derivative
def TryN(x, an, N):
out = 0
for n in range(N+1):
out += an[n]*(1-x)**(N-n+1)*(x+1)**(n+1)
return out
def Bracket(f, g):
dot = lambda x: f(x)*g(x)
return quad(dot, -1, 1)[0]
def Energy(an, N):
phip = lambda x: TryN(x, an, N)
norm = np.sqrt(Bracket(phip, phip))
phip2 = lambda x: derivative(phip, x, n = 2)
energy = Bracket(phip, phip2)
return energy/norm
N = 1
an = [1]*(N+1)
af = minimize(lambda a: Energy(a, N), an, method = 'Powell', tol = 1e-8).x
print(Energy(af, N))
But the result is:
Warning (from warnings module):
File "C:\Users\Abel\AppData\Local\Programs\Python\Python38\lib\site-packages\scipy\optimize\optimize.py", line 2366
if (w - xc) * (xb - w) > 0.0:
RuntimeWarning: overflow encountered in double_scalars
Warning (from warnings module):
File "C:\Users\Abel\AppData\Local\Programs\Python\Python38\lib\site-packages\scipy\optimize\optimize.py", line 2382
elif (w - wlim)*(wlim - xc) >= 0.0:
RuntimeWarning: overflow encountered in double_scalars
Warning (from warnings module):
File "C:\Users\Abel\AppData\Local\Programs\Python\Python38\lib\site-packages\scipy\optimize\optimize.py", line 2361
w = xb - ((xb - xc) * tmp2 - (xb - xa) * tmp1) / denom
RuntimeWarning: overflow encountered in double_scalars
Warning (from warnings module):
File "E:/Sync1/Estudios/Universidad/Grado en Física/3º Grado en Física/Mecanica_Cuantica_II/Practicas/Practica2/P22.py", line 17
dot = lambda x: f(x)*g(x)
RuntimeWarning: overflow encountered in double_scalars
Warning (from warnings module):
File "E:/Sync1/Estudios/Universidad/Grado en Física/3º Grado en Física/Mecanica_Cuantica_II/Practicas/Practica2/P22.py", line 18
return quad(dot, -1, 1)[0]
IntegrationWarning: The occurrence of roundoff error is detected, which prevents
the requested tolerance from being achieved. The error may be
underestimated.
nan
I think that the problem is related with derivative, but I don't find the error. The result of print(Energy(af, N)) should be a positive number and the function phi_p is similar to a sine function, their aproximation depends on N.
The code looks fine. I think that you should try different parameters and methods depending on your problem.
For example, trying with other methods than Powell you will get no warnings (e.g. method="L-BFGS-B"), but the minimized energy becomes negative.
Therefore, since the energy must be a positive number, you can try to use a different method than Powell that allows a constraint.
In your case, lambda a: Energy(a, N) must be greater or equal to zero.
Try to change:
af = minimize(lambda a: Energy(a, N), an, method = 'Powell', tol = 1e-8).x
into:
af = minimize(lambda a: Energy(a, N), an, method = "COBYLA",
tol = 1e-8,constraints={"type": "ineq", "fun": lambda a: Energy(a, N)}).x
Using your code with this change I get
af = [2.54114168e-11, -3.57836680e-10]
Energy(ag, n) = -1.4143692851366237e-09
Using higher N (better approximation for phi), e.g. N = 4:
af = [0.07193712, 1.24003014, 0.38689775, 1.14349888, 0.26623006]
Energy(ag, n) = -4.9576111873203776e-08
If this makes sense, depends on your problem. I suggest you to read through the documentation for minimize and derivative and try different combinations and parameters.
For example, you can try to give a smaller spacing in the derivative to achieve a higher precision.
Related
I have the following function to_minimize which should be equal to the log-likelihood of a dataset for a Weibull distribution, truncated from the left at d.
import numpy as np
from scipy.optimize import minimize
def to_minimize(args, data, d=1):
theta, tau = args
n = len(data)
if tau <= 0 or theta <= 0:
pass
term1 = n * (np.log(tau) - tau * np.log(theta) - (-d / theta) ** tau)
term2 = 0
for x in data:
term2 += (tau - 1) * np.log(x) + (-x / theta) ** tau
return term1 + term2
data = numpy.random.rand(100)
weibull = minimize(lambda args: -to_minimize(args, data),
x0=np.array((1., 1.)), bounds=np.array([(1e-15, 10), (1e-15, 10)]))
As far as I can tell, the only thing that should cause an error of the form
RuntimeWarning: invalid value encountered in double_scalars
should be if tau or theta are 0. But the bounds on those parameters is specifically above 0 so why does my optimization routine crash?
After calling np.seterr(all='raise') and debugging some more, I noticed that I had an error in my calculations. The - in the exponential function has to be applied after the power. Otherwise it will try to take the root of a negative number which won't work for obvious reasons.
I'm trying to simulate in time and space the following system of partial differential equations. I'm using python 3 for that.
Here is a link to the set of equations with their boundary conditions
My ideas was to transform all the equations to the discrete form (forward Euler as the simplest starting point) and then run the code.
Forward Euler implies:
Here lin to image i = 0,...,Nx - mesh for n = 0,1,...,Nt
Here what I have (by the means of numpy)
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
#Define exponents for PDE
m = 0
n = 2
#Define constants for PDE
a = 0.2
b= -0.4
av = 5.0
c = 0.6
d = -0.8
Du = 1
Dv = 20
Dz = 1000
u0 = 0.5
v0 = 0.5
kz = 0.001
L = 10
Nx = 100
T = 5
Nt = 100
x = np.linspace(0, L, Nx+1)
dx = x[1] - x[0]
#print(dx)
#print(dt)
t = np.linspace(0, T, Nt+1)
dt = t[1] - t[0]
if dt<=0.5*dx**2:
print("Ok!")
else:
print("Alert! dt is not smaller than dx^2/2")
u = np.zeros(Nx+1)
v = np.zeros(Nx+1)
z = np.zeros(Nx+1)
u_1 = np.zeros(Nx+1)
v_1 = np.zeros(Nx+1)
z_1 = np.zeros(Nx+1)
# mesh points in space
# mesh points in time
# Set initial condition u(x,0) = I(x)
for i in range(0, Nx+1):
u_1[i] = np.random.random_sample()
v_1[i] = np.random.random_sample()
z_1[i] = np.random.random_sample()
for n in range(0, Nt):
# Compute u at inner mesh points
for i in range(1, Nx):
u[i] = u_1[i] + dt*(a*(u_1[i]-u0) +
b*(v_1[i]-v0)+av*(u_1[i]-u0)**3+(Du/dx**2)*(u_1[i-1] -
2*u_1[i] + u_1[i+1]))*z_1[i]**n
v[i] = v_1[i] + dt*(c*(u_1[i]-u0)+d*(v_1[i]-v0)+(Dv/dx**2)*(v_1[i-1] - 2*v_1[i] + v_1[i+1]))*z_1[i]**n
z[i] = (Dz/dx**2)*((z_1[i-1] - 2*z_1[i] + z_1[i+1]) - kz * z[i])
# Insert boundary conditions u[0]=0; u[Nx]=0
u[0]=0; u[Nx]=1/Dz
v[0]=0; v[Nx]=1
z[0]=0; z[Nx]=1
# Update u_1 before next step
u_1[:]= u
v_1[:]= v
z_1[:]= z
My first problem I'm encountering is different warnings:
/miniconda3/lib/python3.6/site-packages/ipykernel_launcher.py:31: RuntimeWarning: overflow encountered in double_scalars
/miniconda3/lib/python3.6/site-packages/ipykernel_launcher.py:31: RuntimeWarning: invalid value encountered in double_scalars
/miniconda3/lib/python3.6/site-packages/ipykernel_launcher.py:32: RuntimeWarning: invalid value encountered in double_scalars
/miniconda3/lib/python3.6/site-packages/ipykernel_launcher.py:32: RuntimeWarning: overflow encountered in double_scalars
/miniconda3/lib/python3.6/site-packages/ipykernel_launcher.py:33: RuntimeWarning: overflow encountered in double_scalars
/miniconda3/lib/python3.6/site-packages/ipykernel_launcher.py:33: RuntimeWarning: invalid value encountered in double_scalars
My main question is: it possible to solve this set with the forward Euler Method Iam trying at the moment ?
Thank you everyone in advance!
The answer is "yes", but your code needs more work. For example, you will need to work on the algorithm's stability (to avoid it blowing up). Also, the BC does not reflect your system; I think you are looking for zero flux conditions; if so, you are not coding it right. Finally, you can also consider using Fipy, which could make your life easier. Please take a look here https://www.ctcms.nist.gov/fipy/ I also wrote a basic example here http://biological-complexity.blogspot.pe/
I am applying Euler's method to solve a differential equation. This is my code:
def f(x, y):
return ((x**(2))*y)/((x**(4)) + (y**(4)))
di = 0.01
I = 100
x = np.linspace(-I, I, int(I/di) + 1)
w = np.zeros(len(x))
x[0], w[0]
for i in range(1, len(w)):
w[i] = w[i - 1] + f(x[i - 1], w[i - 1])*di
plt.plot(x, w, label='approximation' )
plt.xlabel("x")
plt.ylabel("y")
plt.show()
When I run the code I have this Warning:
"C:\Users\USER\Anaconda3\lib\site-packages\ipykernel__main__.py:3: RuntimeWarning: invalid value encountered in double_scalars app.launch_new_instance()"
I would like to now how to solve it and make it work.
Your code is running into Divide by Zero Error. Try this to convince yourself:
>>> def f(x, y):
... return ((x**(2))*y)/((x**(4))+(y**(4)))
...
>>> I, di = 100, 0.01
>>> x = np.linspace(-I, I, int(I/di) + 1)
>>> w = np.zeros(len(x))
>>> i = len(x)//2 + 1
>>> i
5001
>>> f(x[i-1], w[i-1])
nan
It clearly emerges from the interactive session above that when i takes the value 5001 in the for loop, f(x[i-1], w[i-1]) yields nan. There are several solutions to this issue. For instance, in order to avoid NaN values you could check whether the denominator of the fraction returned by f() is zero prior to perform the division. If it is, you should return a conventional value of your choice (for example 0) instead of the result of the division. The following snippet implements such approach though a conditional expression:
def f(x, y):
return (0 if x==0 and y==0 else float(x**2*y)/(x**4 + y**4))
Alternatively, you could disable run time warnings (but if you do so you need to be aware of the potential risks) by including this code in your script:
import warnings
def f(x, y):
with warnings.catch_warnings():
warnings.simplefilter('ignore')
return ((x**(2))*y)/((x**(4)) + (y**(4)))
The proposed workarounds avoid the RuntimeWarning but don't get your code working as you expect. Indeed, the calculated solution w is a vector in which all the elements are zero. I guess the reason for your code not being working properly is that you missed to assign w[0] an initial value different to 0.
For example, if you simply add this line just before the for loop:
w[0] = 0.5
you get this (apparently meaningful) curve rather than a flat plot.
Hope this helps!
I'm trying to solve a system of ordinary differential equations with Euler's method, but when I try to print velocity I get
RuntimeWarning: overflow encountered in double_scalars
and instead of printing numbers I get nan (not a number). I think the problem might be when defining the acceleration, but I don't know for sure, I would really appreciate if someone could help me.
from numpy import *
from math import pi,exp
d=0.0005*10**-6
a=[]
while d<1.0*10**-6 :
d=d*2
a.append(d)
D=array(a)
def a_particula (D,x, v, t):
cc=((1.00+((2.00*lam)/D))*(1.257+(0.400*exp((-1.10*D)/(2.00*lam)))))
return (g-((densaire*g)/densparticula)-((mu*18.0*v)/(cc*densparticula* (D**2.00))))
def euler (acel,D, x, v, tv, n=15):
nv, xv, vv = tv.size, zeros_like(tv), zeros_like(tv)
xv[0], vv[0] = x, v
for k in range(1, nv):
t, Dt = tv[k-1], (tv[k]-tv[k-1])/float(n)
for i in range(n):
a = acel(D,x, v, t)
t, v = t+Dt, v+a*Dt
x = x+v*Dt
xv[k], vv[k] = x, v
return (xv, vv)
g=(9.80)
densaire= 1.225
lam=0.70*10**-6
densparticula=1000.00
mu=(1.785*10**-5)
tv = linspace(0, 5, 50)
x, v = 0, 0 #initial conditions
for j in range(len(D)):
xx, vv = euler(a_particula, D[j], x, v, tv)
print(D[j],xx,vv)
In future it would be helpful if you included the full warning message in your question - it will contain the line where the problem occurs:
tmp/untitled.py:15: RuntimeWarning: overflow encountered in double_scalars
return (g-((densaire*g)/densparticula)-((mu*18.0*v)/(cc*densparticula* (D**2.00))))
Overflow occurs when the magnitude of a variable exceeds the largest value that can be represented. In this case, double_scalars refers to a 64 bit float, which has a maximum value of:
print(np.finfo(float).max)
# 1.79769313486e+308
So there is a scalar value in the expression:
(g-((densaire*g)/densparticula)-((mu*18.0*v)/(cc*densparticula* (D**2.00))))
that is exceeding ~1.79e308. To find out which one, you can use np.errstate to raise a FloatingPointError when this occurs, then catch it and start the Python debugger:
...
with errstate(over='raise'):
try:
ret = (g-((densaire*g)/densparticula)-((mu*18.0*v)/(cc*densparticula* (D**2.00))))
except FloatingPointError:
import pdb
pdb.set_trace()
return ret
...
From within the debugger you can then check the values of the various parts of this expression. The overflow seems to occur in:
(mu*18.0*v)/(cc*densparticula* (D**2.00))
The first time the warning occurs, (cc*densparticula* (D**2.00) evaluates as 2.3210168586496022e-12, whereas (mu*18.0*v) evaluates as -9.9984582297025182e+299.
Basically you are dividing a very large number by a very small number, and the magnitude of the result is exceeding the maximum value that can be represented. This might be a problem with your math, or it might be that your inputs to the function are not reasonably scaled.
Your system reduces to
dv/dt = a = K - L*v
with K about 10 and L ranging between, at first glance 1e+5 to 1e+10. The actual coefficients used confirm that:
D=1.0000e-09 K= 9.787995 L=1.3843070e+08
D=3.2000e-08 K= 9.787995 L=4.2570244e+06
D=1.0240e-06 K= 9.787995 L=9.0146813e+04
The Euler step for the velocity is
v[j+1]=v[j]+(K-L*v[j])*dt =(1-L*dt)*v[j] + K*dt
For anything resembling the intended friction effect, i.e., the velocity falling to K/L one needs that abs(1-L*dt)<1, and if possible 0<1-L*dt<1, that is, dt < 1/L. Which means here that dt < 1e-10.
To be able to use larger time steps you need to use methods for stiff differential equations, which means implicit methods. The most simple ones are the implicit Euler method, the midpoint method and the trapezoidal method.
Because of the linearity, the midpoint and trapezoidal method amount to the same formula
v[j+1] = v[j] + dt * ( K - L*(v[j]+v[j+1])/2 )
or
v[j+1] = ( (1-L*dt/2)*v[j] + K*dt ) / (1+L*dt/2)
Of course, the most simple method is to just exactly integrate the ODE
(-L*v')/(K-L*v)=-L => K-L*v(t)=C*exp(-L*t), C=K-L*v(0)
v(t)=K/L + exp(-L*t)*(v(0)-K/L)
which integrates to
x(t)=x(0)+K/L*t+(1-exp(-L*t))/L*(v(0)-K/L).
Alternatively it is possible that you made an error in transcribing the physical laws into formulas so that the magnitudes of the constants are all wrong.
I'm trying to back out Black-Scholes implied volatilities from financial options data. If the data contains options for which an implied volatility cannot be found, this will make all the results equal to the initial guess. See the following example
from scipy.optimize import fsolve
import numpy as np
from scipy.stats import norm
S = 1293.77
r = 0.05
K = np.array([1255, 1260, 1265, 1270, 1275])
T = 2./365
price = np.array([38.9, 34.35, 29.7, 25.35, 21.05])
def black_scholes(S, K, r, T, sigma):
d1 = (np.log(S / K) + (r + sigma ** 2 / 2) * T) / (sigma * np.sqrt(T))
d2 = d1 - sigma * np.sqrt(T)
return S * norm.cdf(d1) - K * np.exp(-r * T) * norm.cdf(d2)
volatility = lambda x: black_scholes(S, K, r, T, x) - price
print fsolve(volatility, np.repeat(0.1, len(K)))
gives
RuntimeWarning: The iteration is not making good progress, as measured by the
improvement from the last ten iterations.
warnings.warn(msg, RuntimeWarning)
[ 0.1 0.1 0.1 0.1 0.1]
By doing the same operation with Matlab or Maple I know that no solution can be found for the first option. If I exclude that one, such that
K = np.array([1260, 1265, 1270, 1275])
price = np.array([34.35, 29.7, 25.35, 21.05])
I do get the right result
[ 0.19557092 0.20618568 0.2174149 0.21533821]
Therefore if a solution cannot be found I would expect fsolve to return NaN instead of my initial guess and not mess up the rest of the solutions.
Use the full_output argument to tell fsolve to return more information, and check the value of ier on return. For example,
sol, info, ier, msg = fsolve(volatility, np.repeat(0.1, len(K)), full_output=True)
if ier != 1:
print "ier = %d" % (ier,)
print msg
else:
print "sol =", sol
You said:
...if a solution cannot be found I would expect fsolve to return NaN instead of my initial guess and not mess up the rest of the solutions.
fsolve has no way of knowing that the problem you are solving is actually a collection of decoupled problems. You've given it a single n-dimensional problem. Either it succeeds or it fails to find a solution to that problem.