Python double integral taking too long to compute - python

I am trying to compute the fresnel integral over a grid of coordinates using dblquad. But its taking very long and finally it's not giving any result.
Below is my code. In this code I integrated only over a 10 x 10 grid but I need to integrate at least over a 500 x 500 grid.
import time
st = time.time()
import pylab
import scipy.integrate as inte
import numpy as np
print 'imhere 0'
def sinIntegrand(y,x, X , Y):
a = 0.0001
R = 2e-3
z = 10e-3
Lambda = 0.5e-6
alpha = 0.01
k = np.pi * 2 / Lambda
return np.cos(k * (((x-R)**2)*a + (R-(x**2 + y**2)) * np.tan(np.radians(alpha)) + ((x - X)**2 + (y - Y)**2) / (2 * z)))
print 'im here 1'
def cosIntegrand(y,x,X,Y):
a = 0.0001
R = 2e-3
z = 10e-3
Lambda = 0.5e-6
alpha = 0.01
k = np.pi * 2 / Lambda
return np.sin(k * (((x-R)**2)*a + (R-(x**2 + y**2)) * np.tan(np.radians(alpha)) + ((x - X)**2 + (y - Y)**2) / (2 * z)))
def y1(x,R = 2e-3):
return (R**2 - x**2)**0.5
def y2(x, R = 2e-3):
return -1*(R**2 - x**2)**0.5
points = np.linspace(-1e-3,1e-3,10)
points2 = np.linspace(1e-3,-1e-3,10)
yv,xv = np.meshgrid(points , points2)
#def integrate_on_grid(func, lo, hi,y1,y2):
# """Returns a callable that can be evaluated on a grid."""
# return np.vectorize(lambda n,m: dblquad(func, lo, hi,y1,y2,(n,m))[0])
#
#intensity = abs(integrate_on_grid(sinIntegrand,-1e-3 ,1e-3,y1, y2)(yv,xv))**2 + abs(integrate_on_grid(cosIntegrand,-1e-3 ,1e-3,y1, y2)(yv,xv))**2
Intensity = []
print 'im here2'
for i in points:
row = []
for j in points2:
print 'im here'
intensity = abs(inte.dblquad(sinIntegrand,-1e-3 ,1e-3,y1, y2,(i,j))[0])**2 + abs(inte.dblquad(cosIntegrand,-1e-3 ,1e-3,y1, y2,(i,j))[0])**2
row.append(intensity)
Intensity.append(row)
Intensity = np.asarray(Intensity)
pylab.imshow(Intensity,cmap = 'gray')
pylab.show()
print str(time.time() - st)
I would really appreciate if you could tell any better way of doing this.

Using a scipy.integrate.dblquad to calculate every pixel of your image is going to be slow in any case.
You should try rewriting your mathematical problem so you can use some classical function in scipy.special instead. For instance, scipy.special.fresnel might work, although it is 1D and your problem seems to be in 2D. Otherwise, that there is a relationship between the Fresnel integral and the incomplete Gamma function (scipy.special.gammainc), if that helps.
If none of this work, as a last resort you can spend time optimizing your code and adapting it to Cython. This it will probably give a speed up of a factor of 10 to 100 (see this answer). Though this wouldn't be sufficient to go from a grid 10x10 to a grid 500x500.

Related

Solve integral in an annular domain in Python

I am trying to solve a function in an annular domain that has a change of phase with respect to the angular direction of the annulus.
My attempt to solve it is the following:
import numpy as np
from scipy import integrate
def f(x0, y0):
r = np.sqrt(x0**2 + y0**2)
if r >= rIn and r <= rOut:
theta = np.arctan(y0 / x0)
R = np.sqrt((x - x0)**2 + (y - y0)**2 + z**2)
integrand = (np.exp(-1j * (k*R + theta))) / R
return integrand
else:
return 0
# Test
rIn = 0.5
rOut = 1.5
x = 1
y = 1
z = 1
k = 3.66
I = integrate.dblquad(f, -rOut, rOut, lambda x0: -rOut, lambda x0: rOut)
My problem is that I don't know how to get rid of the division by zero occuring when I evaluate theta.
Any help will be more than appreciated!
Use numpy.arctan2 instead, it will have problems only if both x and y are zero, in which case the angle is undetermined.
Also I see you that your integrand is complex, in this case you will probably have to handle real and imaginary part separately, as done here.

Drawing Poincare Section using Python

I was about to plot a Poincare section of the following DE, which is quite meaningful to have a periodic potential function V(x) = - cos(x) in this equation.
After calculating the solution using RK4 with time interval dt = 0.001, the one that python drew was as the following plot.
But according to the textbook(referred to 2E by J.M.T. Thompson and H.B. Stewart), the section would look like as
:
it has so much difference. For my personal opinion, since Poincare section does not appear as what writers draw, there must be some error in my code. However, I actually done for other forced oscillation DE, including Duffing's equation, and obtained the identical one as those in the textbook. So, I was wodering if there are some typos in the equation given by the textbook, or somewhere else. I posted my code, but might be quite messy to understand. So appreicate dealing with it.
import numpy as np
import matplotlib.pylab as plt
import matplotlib as mpl
import sys
import time
state = [1]
def print_percent_done(index, total, state, title='Please wait'):
percent_done2 = (index+1)/total*100
percent_done = round(percent_done2, 1)
print(f'\t⏳{title}: {percent_done}% done', end='\r')
if percent_done2 > 99.9 and state[0]:
print('\t✅'); state = [0]
####
no = 1
####
def multiple(n, q):
m = n; i = 0
while m >= 0:
m -= q
i += 1
return min(abs(n - (i - 1)*q), abs(i*q - n))
# system(2)
#Basic info.
filename = 'sinPotentialWell'
# a = 1
# alpha = 0.01
# w = 4
w0 = .5
n = 1000000
h = .01
t_0 = 0
x_0 = 0.1
y_0 = 0
A = [(t_0, x_0, y_0)]
def f(t, x, y):
return y
def g(t, x, y):
return -0.5*y - np.sin(x) + 1.1*np.sin(0.5*t)
for i in range(n):
t0 = A[i][0]; x0 = A[i][1]; y0 = A[i][2]
k1 = f(t0, x0, y0)
u1 = g(t0, x0, y0)
k2 = f(t0 + h/2, x0 + h*k1/2, y0 + h*u1/2)
u2 = g(t0 + h/2, x0 + h*k1/2, y0 + h*u1/2)
k3 = f(t0 + h/2, x0 + h*k2/2, y0 + h*u2/2)
u3 = g(t0 + h/2, x0 + h*k2/2, y0 + h*u2/2)
k4 = f(t0 + h, x0 + h*k3, y0 + h*u3)
u4 = g(t0 + h, x0 + h*k3, y0 + h*u3)
t = t0 + h
x = x0 + (k1 + 2*k2 + 2*k3 + k4)*h/6
y = y0 + (u1 + 2*u2 + 2*u3 + u4)*h/6
A.append([t, x, y])
if i%1000 == 0: print_percent_done(i, n, state, 'Solving given DE')
#phase diagram
print('showing 3d_(x, y, phi) graph')
PHI=[[]]; X=[[]]; Y=[[]]
PHI_period1 = []; X_period1 = []; Y_period1 = []
for i in range(n):
if w0*A[i][0]%(2*np.pi) < 1 and w0*A[i-1][0]%(2*np.pi) > 6:
PHI.append([]); X.append([]); Y.append([])
PHI_period1.append((w0*A[i][0])%(2*np.pi)); X_period1.append(A[i][1]); Y_period1.append(A[i][2])
phi_period1 = np.array(PHI_period1); x_period1 = np.array(X_period1); y_period1 = np.array(Y_period1)
print('showing Poincare Section at phi=0')
plt.plot(x_period1, y_period1, 'gs', markersize = 2)
plt.plot()
plt.title('phi=0 Poincare Section')
plt.xlabel('x'); plt.ylabel('y')
plt.show()
If you factor out some of the computation blocks, you can make the code more flexible and computations more direct. No need to reconstruct something if you can construct it in the first place. You want to catch the points where w0*t is a multiple of 2*pi, so just construct the time loops so you integrate in chunks of 2*pi/w0 and only remember the interesting points.
num_plot_points = 2000
h = .01
t,x,y = t_0,x_0,y_0
x_section,y_section = [],[]
T = 2*np.pi/w0
for k in range(num_plot_points):
t = 0;
while t < T-1.2*h:
x,y = RK4step(t,x,y,h)
t += h
x,y = RK4step(t,x,y,T-t)
if k%100 == 0: print_percent_done(k, num_plot_points, state, 'Solving given DE')
x_section.append(x); y_section.append(y)
with RK4step just containing the code of the RK4 step.
This will not solve the mystery. The veil gets lifted if you consider that x is the angle theta (of a forced pendulum with friction) on a circle. Thus to get points with the same spacial location it needs to be reduced by multiples of 2*pi. Doing that,
plt.plot([x%(2*np.pi) for x in x_section], y_section, 'gs', markersize = 2)
results in the expected plot

Find maxima for a negative parabolic equation

I have the following negative quadratic equation
-0.03402645959398278x^{2}+156.003469x-178794.025
I want to know if there is a straight way (using numpy/scipy libraries or any other) to get the value of x when the slope of the derivative is zero (the maxima). I'm aware I could:
change the sign of the equation and apply the scipy.optimize.minima method or
using the derivative of the equation so I can get the value when the slope is zero
For instance:
from scipy.optimize import minimize
quad_eq = np.poly1d([-0.03402645959398278, 156.003469, -178794.025])
############SCIPY####################
neg_quad_eq = np.poly1d(np.negative(quad_eq))
fit = minimize(neg_quad_eq, x0=15)
slope_zero_neg = fit.x[0]
maxima = np.polyval(quad_eq, slope_zero_neg)
print(maxima)
##################numpy######################
import numpy as np
first_dev = np.polyder(quad_eq)
slope_zero = first_dev.r
maxima = np.polyval(quad_eq, slope_zero)
print(maxima)
Is there any straight way to get the same result?
print(maxima)
You don't need all that code... The first derivative of a x^2 + b x + c is 2a x + b, so solving 2a x + b = 0 for x yields x = -b / (2a) that is actually the maximum you are searching for
import numpy as np
import matplotlib.pyplot as plt
def func(x, a=-0.03402645959398278, b=156.003469, c=-178794.025):
result = a * x**2 + b * x + c
return result
def func_max(a=-0.03402645959398278, b=156.003469, c=-178794.025):
maximum_x = -b / (2 * a)
maximum_y = a * maximum_x**2 + b * maximum_x + c
return maximum_x, maximum_y
x = np.linspace(-50000, 50000, 100)
y = func(x)
mx, my = func_max()
print('maximum:', mx, my)
maximum: 2292.384674478263 15.955750522436574
and verify
plt.plot(x, y)
plt.axvline(mx, color='r')
plt.axhline(my, color='r')

Cannot get RK4 to solve for position of orbiting body in Python

I am trying to solve for the position of a body orbiting a much more massive body, using the idealization that the much more massive body doesn't move. I am trying to solve for the position in cartesian coordinates using 4th order Runge-Kutta in python.
Here is my code:
dt = .1
t = np.arange(0,10,dt)
vx = np.zeros(len(t))
vy = np.zeros(len(t))
x = np.zeros(len(t))
y = np.zeros(len(t))
vx[0] = 10 #initial x velocity
vy[0] = 10 #initial y velocity
x[0] = 10 #initial x position
y[0] = 0 #initial y position
M = 20
def fx(x,y,t): #x acceleration
return -G*M*x/((x**2+y**2)**(3/2))
def fy(x,y,t): #y acceleration
return -G*M*y/((x**2+y**2)**(3/2))
def rkx(x,y,t,dt): #runge-kutta for x
kx1 = dt * fx(x,y,t)
mx1 = dt * x
kx2 = dt * fx(x + .5*kx1, y + .5*kx1, t + .5*dt)
mx2 = dt * (x + kx1/2)
kx3 = dt * fx(x + .5*kx2, y + .5*kx2, t + .5*dt)
mx3 = dt * (x + kx2/2)
kx4 = dt * fx(x + kx3, y + x3, t + dt)
mx4 = dt * (x + kx3)
return (kx1 + 2*kx2 + 2*kx3 + kx4)/6
return (mx1 + 2*mx2 + 2*mx3 + mx4)/6
def rky(x,y,t,dt): #runge-kutta for y
ky1 = dt * fy(x,y,t)
my1 = dt * y
ky2 = dt * fy(x + .5*ky1, y + .5*ky1, t + .5*dt)
my2 = dt * (y + ky1/2)
ky3 = dt * fy(x + .5*ky2, y + .5*ky2, t + .5*dt)
my3 = dt * (y + ky2/2)
ky4 = dt * fy(x + ky3, y + ky3, t + dt)
my4 = dt * (y + ky3)
return (ky1 + 2*ky2 + 2*ky3 + ky4)/6
return (my1 + 2*my2 + 2*my3 + my4)/6
for n in range(1,len(t)): #solve using RK4 functions
vx[n] = vx[n-1] + fx(x[n-1],y[n-1],t[n-1])*dt
vy[n] = vy[n-1] + fy(x[n-1],y[n-1],t[n-1])*dt
x[n] = x[n-1] + vx[n-1]*dt
y[n] = y[n-1] + vy[n-1]*dt
Originally, no matter which way I tweaked the code, I was getting an error on my for loop, either "object of type 'float' has no len()" (I didn't understand what float python could be referring to), or "setting an array element with a sequence" (I also didn't understand what sequence it meant). I've managed to get rid of the errors, but my results are just wrong. I get vx and vy arrays of 10s, an x array of integers from 10. to 109., and a y array of integers from 0. to 99.
I suspect there are issues with fx(x,y,t) and fy(x,y,t) or with the way I have coded the runge-kutta functions to go with fx and fy, because I've used the same runge-kutta code for other functions and it works fine.
I greatly appreciate any help in figuring out why my code isn't working. Thank you.
Physics
The Newton law gives you a second order ODE u''=F(u) with u=[x,y]. Using v=[x',y'] you get the first order system
u' = v
v' = F(u)
which is 4-dimensional and has to be solved using a 4 dimensional state. The only reduction available is to use the Kepler laws which allow to reduce the system to a scalar order one ODE for the angle. But that is not the task here.
But to get the scales correct, for a circular orbit of radius R with angular velocity w one gets the identity w^2*R^3=G*M which implies that the speed along the orbit is w*R=sqrt(G*M/R) and period T=2*pi*sqrt(R^3/(G*M)). With the data given, R ~ 10, w ~ 1, thus G*M ~ 1000 for a close-to-circular orbit, so with M=20 this would require G between 50 and 200, with an orbital period of about 2*pi ~ 6. The time span of 10 could represent one half to about 2 or 3 orbits.
Euler method
You correctly implemented the Euler method to calculate values in the last loop of your code. That it may look un-physical can be because the Euler method continuously increases the orbit, as it moves to the outside of convex trajectories following the tangent. In your implementation this outward spiral can be seen for G=100.
This can be reduced in effect by choosing a smaller step size, such as dt=0.001.
You should select the integration time to be a good part of a full orbit to get a presentable result, with above parameters you get about 2 loops, which is good.
RK4 implementation
You made several errors. Somehow you lost the velocities, the position updates should be based on the velocities.
Then you should have halted at fx(x + .5*kx1, y + .5*kx1, t + .5*dt) to reconsider your approach as that is inconsistent with any naming convention. The consistent, correct variant is
fx(x + .5*kx1, y + .5*ky1, t + .5*dt)
which shows that you can not decouple the integration of a coupled system, as you need the y updates alongside the x updates. Further, the function values are the accelerations, thus update the velocities. The position updates use the velocities of the current state. Thus the step should start as
kx1 = dt * fx(x,y,t) # vx update
mx1 = dt * vx # x update
ky1 = dt * fy(x,y,t) # vy update
my1 = dt * vy # y update
kx2 = dt * fx(x + 0.5*mx1, y + 0.5*my1, t + 0.5*dt)
mx2 = dt * (vx + 0.5*kx1)
ky2 = dt * fy(x + 0.5*mx1, y + 0.5*my1, t + 0.5*dt)
my2 = dt * (vy + 0.5*ky1)
etc.
However, as you see, this already starts to become unwieldy. Assemble the state into a vector and use a vector valued function for the system equations
M, G = 20, 100
def orbitsys(u):
x,y,vx,vy = u
r = np.hypot(x,y)
f = G*M/r**3
return np.array([vx, vy, -f*x, -f*y]);
Then you can use a cook-book implementation of the Euler or Runge-Kutta step
def Eulerstep(f,u,dt): return u+dt*f(u)
def RK4step(f,u,dt):
k1 = dt*f(u)
k2 = dt*f(u+0.5*k1)
k3 = dt*f(u+0.5*k2)
k4 = dt*f(u+k3)
return u + (k1+2*k2+2*k3+k4)/6
and combine them into an integration loop
def Eulerintegrate(f, y0, tspan):
y = np.zeros([len(tspan),len(y0)])
y[0,:]=y0
for k in range(1, len(tspan)):
y[k,:] = Eulerstep(f, y[k-1], tspan[k]-tspan[k-1])
return y
def RK4integrate(f, y0, tspan):
y = np.zeros([len(tspan),len(y0)])
y[0,:]=y0
for k in range(1, len(tspan)):
y[k,:] = RK4step(f, y[k-1], tspan[k]-tspan[k-1])
return y
and invoke them with your given problem
dt = .1
t = np.arange(0,10,dt)
y0 = np.array([10, 0.0, 10, 10])
sol_euler = Eulerintegrate(orbitsys, y0, t)
x,y,vx,vy = sol_euler.T
plt.plot(x,y)
sol_RK4 = RK4integrate(orbitsys, y0, t)
x,y,vx,vy = sol_RK4.T
plt.plot(x,y)
You are not using rkx, rky functions anywhere!
There are two return at the end of function definition you should use
return [(kx1 + 2*kx2 + 2*kx3 + kx4)/6, (mx1 + 2*mx2 + 2*mx3 + mx4)/6] (as pointed out by #eapetcho). Also, your implementation of Runge-Kutta is not clear to me.
You have dv/dt so you solve for v and then update r accordingly.
for n in range(1,len(t)): #solve using RK4 functions
vx[n] = vx[n-1] + rkx(vx[n-1],vy[n-1],t[n-1])*dt
vy[n] = vy[n-1] + rky(vx[n-1],vy[n-1],t[n-1])*dt
x[n] = x[n-1] + vx[n-1]*dt
y[n] = y[n-1] + vy[n-1]*dt
Here is my version of the code
import numpy as np
#constants
G=1
M=1
h=0.1
#initiating variables
rt = np.arange(0,10,h)
vx = np.zeros(len(rt))
vy = np.zeros(len(rt))
rx = np.zeros(len(rt))
ry = np.zeros(len(rt))
#initial conditions
vx[0] = 10 #initial x velocity
vy[0] = 10 #initial y velocity
rx[0] = 10 #initial x position
ry[0] = 0 #initial y position
def fx(x,y): #x acceleration
return -G*M*x/((x**2+y**2)**(3/2))
def fy(x,y): #y acceleration
return -G*M*y/((x**2+y**2)**(3/2))
def rk4(xj, yj):
k0 = h*fx(xj, yj)
l0 = h*fx(xj, yj)
k1 = h*fx(xj + 0.5*k0 , yj + 0.5*l0)
l1 = h*fy(xj + 0.5*k0 , yj + 0.5*l0)
k2 = h*fx(xj + 0.5*k1 , yj + 0.5*l1)
l2 = h*fy(xj + 0.5*k1 , yj + 0.5*l1)
k3 = h*fx(xj + k2, yj + l2)
l3 = h*fy(xj + k2, yj + l2)
xj1 = xj + (1/6)*(k0 + 2*k1 + 2*k2 + k3)
yj1 = yj + (1/6)*(l0 + 2*l1 + 2*l2 + l3)
return (xj1, yj1)
for t in range(1,len(rt)):
nv = rk4(vx[t-1],vy[t-1])
[vx[t],vy[t]] = nv
rx[t] = rx[t-1] + vx[t-1]*h
ry[t] = ry[t-1] + vy[t-1]*h
I suspect there are issues with fx(x,y,t) and fy(x,y,t)
This is the case, I just checked my code for fx=3 and fy=y and I got a nice trajectory.
Here is the ry vs rx plot:

how can I do a maximum likelihood regression using scipy.optimize.minimize

How can I do a maximum likelihood regression using scipy.optimize.minimize? I specifically want to use the minimize function here, because I have a complex model and need to add some constraints. I am currently trying a simple example using the following:
from scipy.optimize import minimize
def lik(parameters):
m = parameters[0]
b = parameters[1]
sigma = parameters[2]
for i in np.arange(0, len(x)):
y_exp = m * x + b
L = sum(np.log(sigma) + 0.5 * np.log(2 * np.pi) + (y - y_exp) ** 2 / (2 * sigma ** 2))
return L
x = [1,2,3,4,5]
y = [2,3,4,5,6]
lik_model = minimize(lik, np.array([1,1,1]), method='L-BFGS-B', options={'disp': True})
When I run this, convergence fails. Does anyone know what is wrong with my code?
The message I get running this is 'ABNORMAL_TERMINATION_IN_LNSRCH'. I am using the same algorithm that I have working using optim in R.
Thank you Aleksander. You were correct that my likelihood function was wrong, not the code. Using a formula I found on wikipedia I adjusted the code to:
import numpy as np
from scipy.optimize import minimize
def lik(parameters):
m = parameters[0]
b = parameters[1]
sigma = parameters[2]
for i in np.arange(0, len(x)):
y_exp = m * x + b
L = (len(x)/2 * np.log(2 * np.pi) + len(x)/2 * np.log(sigma ** 2) + 1 /
(2 * sigma ** 2) * sum((y - y_exp) ** 2))
return L
x = np.array([1,2,3,4,5])
y = np.array([2,5,8,11,14])
lik_model = minimize(lik, np.array([1,1,1]), method='L-BFGS-B')
plt.scatter(x,y)
plt.plot(x, lik_model['x'][0] * x + lik_model['x'][1])
plt.show()
Now it seems to be working.
Thanks for the help!

Categories