stackoverflow error in 2d fipy PDE solver in python - python

I am trying to solve a system of three coupled PDEs and two ODEs (coupled) in 2D. The problem tries to solve for a case of a particle moving in a medium. The medium is given by the fields- velocity components vx, vy, and density m and there is one particle moving in this medium with position Rx, Ry.
It runs fine for a while but then throws up errors:
"Fatal Python error: Cannot recover from stack overflow.
Current thread 0x00007fe155915700 (most recent call first):"
Here is the code:
"""
"""
from fipy import (CellVariable, PeriodicGrid2D, Viewer, TransientTerm, DiffusionTerm,
UniformNoiseVariable, LinearLUSolver, numerix,
ImplicitSourceTerm, ExponentialConvectionTerm, VanLeerConvectionTerm,
PowerLawConvectionTerm, Variable)
import sys
import inspect
import matplotlib.pyplot as plt
import numpy as np
import scipy.ndimage
from scipy.optimize import curve_fit
from scipy.signal import correlate
from scipy.stats import kurtosis
from scipy.interpolate import interp1d
numerix.random.seed(2)
def run_simulation(f0, Total_time):
# Define mesh size and number of points
nx = 50
ny = nx
L = 50
dx = L / nx
dy = dx
mesh = PeriodicGrid2D(dx, dy, nx, ny)
# Variables to use
vx = CellVariable(name='vx', mesh=mesh, hasOld=1)
vy = CellVariable(name='vy', mesh=mesh, hasOld=1)
m = CellVariable(name='m', mesh=mesh, hasOld=1)
# Initial condition
m.setValue(UniformNoiseVariable(mesh=mesh, minimum=0.6215, maximum=0.6225))
vx.setValue(UniformNoiseVariable(mesh=mesh, minimum=0, maximum=0.00001))
vy.setValue(UniformNoiseVariable(mesh=mesh, minimum=0, maximum=0.00001))
#particle position
x0=10.0
y0=25.0
# create grids for grad function
xgrid=np.unique(mesh.x.value)+dx/2
ygrid=np.unique(mesh.y.value)+dy/2
# parameters ------------------------------
B=4.0
Gamma=1.0
gamma=1.0
Dm=0.005
C=100.0
## save the initial positions in Rx,Ry
Rx=Variable(value=x0)
Ry=Variable(value=y0)
theta=Variable(value=0.0) # n-hat = cos(theta) x-hat + sin(theta) y-hat
sigma = 1
dt = 0.05
#-----------------------------------------
x_hat = [1.0, 0.0]
y_hat = [0.0, 1.0]
#------------- dirac delta function --------------
# https://stackoverflow.com/questions/58041222/dirac-delta-source-term-in-fipy
def delta_func(x, y, epsilon):
return ((x < epsilon) & (x > -epsilon) & (y < epsilon) & (y > -epsilon)) * \
(1 + numerix.cos(numerix.pi * x / epsilon) * numerix.cos(numerix.pi * y / epsilon)) / 2 / epsilon
############## equations #############
# renormalized parameters by Gamma
# fields : velocity vector, density scalar
# Gamma * v = -B rho(grad(rho)) + f* n-cap* delta(r-R), B>0, f>0, Gamma>0
# dot(rho) + del.(v rho) = 0
# particle
# dot(R) = (f/gamma)*(n-cap) - (C/gamma) * rho(grad(rho)) C>0
# Gamma=gamma=1, B' = B/Gamma, C'=C/gamma, f'=f/Gamma
######################################
eq_m = (TransientTerm(var=m) + ExponentialConvectionTerm(coeff=x_hat * vx + y_hat * vy, var=m) == DiffusionTerm(coeff=Dm, var=m) )
eq_vx = (ImplicitSourceTerm(coeff=1., var=vx) == -(B/Gamma)*m.grad.dot(x_hat)*(m) + (f0/Gamma)*numerix.cos(theta)* delta_func(mesh.x-Rx,mesh.y-Ry,sigma) )
eq_vy = (ImplicitSourceTerm(coeff=1., var=vy) == -(B/Gamma)*m.grad.dot(y_hat)*(m) + (f0/Gamma)*numerix.sin(theta)* delta_func(mesh.x-Rx,mesh.y-Ry,sigma) )
eq = eq_m & eq_vx & eq_vy
viewer = Viewer(vars=(m))
elapsed = 0.0
ms = []
vxs = []
vys = []
xs = []
ys = []
while elapsed < Total_time:
# Old values are used for sweeping when solving nonlinear values
vx.updateOld()
vy.updateOld()
m.updateOld()
print(elapsed, Rx, Ry)
mgrid=np.reshape(m.value,(nx,ny))
# gradient cal, dydx[0][x,y], dydx[1][x,y] -> x derivative, y derivative at x,y
dydx=np.gradient(mgrid,dx,dy,edge_order=2)
# impose periodic boundary on gradient
dydx[0][nx-1,:]=(mgrid[0,:]-mgrid[nx-2,:])/(2.0*dx)
dydx[0][0,:]=(mgrid[1,:]-mgrid[nx-1,:])/(2.0*dx)
dydx[1][:,ny-1]=(mgrid[:,0]-mgrid[:,ny-2])/(2.0*dy)
dydx[1][:,0]=(mgrid[:,1]-mgrid[:,ny-1])/(2.0*dy)
# solve ode
idx = np.argmin(np.abs(xgrid - Rx))
idy = np.argmin(np.abs(ygrid - Ry))
x0=x0+ ((f0/gamma)*np.cos(theta) - C*mgrid[idx,idy]*dydx[0][idx,idy])*dt
y0=y0+ ((f0/gamma)*np.sin(theta) - C*mgrid[idx,idy]*dydx[1][idx,idy])*dt
if(x0>L):
x0=x0-L
if(x0<0):
x0=x0+L
if(y0>L):
y0=y0-L
if(y0<0):
y0=y0+L
Rx.setValue(x0) # element-wise assignment did not work
Ry.setValue(y0)
elapsed += dt
res = 1e5
old_res = res * 2
step = 0
while res > 1e-5 and step < 5 and old_res / res > 1.01:
old_res = res
res = eq.sweep(dt=dt)
step += 1
# The variable values are just numpy arrays so easy to use!
# save velocity & density
vxs.append(vx.value.copy())
vys.append(vy.value.copy())
ms.append(m.value.copy())
viewer.plot()
# save x and y positions
xs.append(mesh.x.value.copy())
ys.append(mesh.y.value.copy())
return ms, vxs, vys, xs, ys
if __name__ == '__main__':
path = 'result/'
Total_time= 50 #40
f0 = 2
ms, vxs, vys, xs, ys = run_simulation(f0,Total_time)
name = 'f0_{:.4f}'.format(f0)
y = np.array([ms, vxs, vys])
xx = np.reshape(xs,(50,50))
yy = np.reshape(ys,(50,50))
vx = np.reshape(vxs[800][:],(50,50))
vy = np.reshape(vys[800][:],(50,50))
print(np.shape(xx), np.shape(xs), np.shape(vx))
#np.save(path + name, y)
plt.imshow(np.reshape(ms[800][:],(50,50)), aspect='auto', interpolation='bicubic', cmap='jet', extent=[0, 50, 50, 0])
plt.colorbar(label='density m')
plt.xlabel(r'$x $')
plt.ylabel(r'$y $')
plt.gcf().savefig(path + 'rho_'+name+'.png', format='png', bbox_inches='tight')
plt.clf()
#---------------------------------------------
plt.imshow(np.reshape(vxs[800][:],(50,50)), aspect='auto', interpolation='bicubic', cmap='jet', extent=[0, 50, 50, 0])
plt.colorbar(label='velocity vx')
plt.xlabel(r'$x $')
plt.ylabel(r'$y $')
plt.gcf().savefig(path + 'vel_'+name+'.png', format='png', bbox_inches='tight')
plt.clf()
#---------------------------------------------
plt.quiver(xx,yy,vx,vy,scale=3)
plt.xlabel(r'$x $')
plt.ylabel(r'$y $')
plt.gcf().savefig(path + 'v_'+name+'.png', format='png', bbox_inches='tight')
plt.clf()
What can cause this error? I am not defining the equation inside the loop (this caused a similar problem before). Thank you in advance for your help.
UPDATE
I changed the function calling for x.mesh as
delta_func(xp,yp,sigma) where xp and yp are xp=Variable(value=mesh.x-Rx) and yp=Variable(value=mesh.y-Ry). Directly calling the x.mesh might have caused the problem according to an answer to my old question. But that did not help, I am still getting the overflow error. Here is the new version of the code:
"""
"""
from fipy import (CellVariable, PeriodicGrid2D, Viewer, TransientTerm, DiffusionTerm,
UniformNoiseVariable, LinearLUSolver, numerix,
ImplicitSourceTerm, ExponentialConvectionTerm, VanLeerConvectionTerm,
PowerLawConvectionTerm, Variable)
import sys
import inspect
import matplotlib.pyplot as plt
import numpy as np
import scipy.ndimage
from scipy.optimize import curve_fit
from scipy.signal import correlate
from scipy.stats import kurtosis
from scipy.interpolate import interp1d
numerix.random.seed(2)
def run_simulation(f0, Total_time):
# Define mesh size and number of points
nx = 50
ny = nx
L = 50
dx = L / nx
dy = dx
mesh = PeriodicGrid2D(dx, dy, nx, ny)
# Variables to use
vx = CellVariable(name='vx', mesh=mesh, hasOld=1)
vy = CellVariable(name='vy', mesh=mesh, hasOld=1)
m = CellVariable(name='m', mesh=mesh, hasOld=1)
# Initial condition
m.setValue(UniformNoiseVariable(mesh=mesh, minimum=0.6215, maximum=0.6225))
vx.setValue(UniformNoiseVariable(mesh=mesh, minimum=0, maximum=0.00001))
vy.setValue(UniformNoiseVariable(mesh=mesh, minimum=0, maximum=0.00001))
#particle position
x0=10.0
y0=25.0
# create grids for grad function
xgrid=np.unique(mesh.x.value)+dx/2
ygrid=np.unique(mesh.y.value)+dy/2
# parameters ------------------------------
B=4.0
Gamma=1.0
gamma=1.0
Dm=0.005
C=100.0
## save the initial positions in Rx,Ry
Rx=Variable(value=x0)
Ry=Variable(value=y0)
theta=Variable(value=0.0) # n-hat = cos(theta) x-hat + sin(theta) y-hat
sigma = 1
dt = 0.05
#-----------------------------------------
xp=Variable(value=mesh.x-Rx)
yp=Variable(value=mesh.y-Ry)
x_hat = [1.0, 0.0]
y_hat = [0.0, 1.0]
#------------- dirac delta function --------------
# https://stackoverflow.com/questions/58041222/dirac-delta-source-term-in-fipy
def delta_func(x, y, epsilon):
return ((x < epsilon) & (x > -epsilon) & (y < epsilon) & (y > -epsilon)) * \
(1 + numerix.cos(numerix.pi * x / epsilon) * numerix.cos(numerix.pi * y / epsilon)) / 2 / epsilon
############## equations #############
# renormalized parameters by Gamma
# fields : velocity vector, density scalar
# Gamma * v = -B rho(grad(rho)) + f* n-cap* delta(r-R), B>0, f>0, Gamma>0
# dot(rho) + del.(v rho) = 0
# particle
# dot(R) = (f/gamma)*(n-cap) - (C/gamma) * rho(grad(rho)) C>0
# Gamma=gamma=1, B' = B/Gamma, C'=C/gamma, f'=f/Gamma
######################################
eq_m = (TransientTerm(var=m) + ExponentialConvectionTerm(coeff=x_hat * vx + y_hat * vy, var=m) == DiffusionTerm(coeff=Dm, var=m) )
eq_vx = (ImplicitSourceTerm(coeff=1., var=vx) == -(B/Gamma)*m.grad.dot(x_hat)*(m) + (f0/Gamma)*numerix.cos(theta)* delta_func(xp,yp,sigma) )
eq_vy = (ImplicitSourceTerm(coeff=1., var=vy) == -(B/Gamma)*m.grad.dot(y_hat)*(m) + (f0/Gamma)*numerix.sin(theta)* delta_func(xp,yp,sigma) )
eq = eq_m & eq_vx & eq_vy
viewer = Viewer(vars=(m))
elapsed = 0.0
ms = []
vxs = []
vys = []
xs = []
ys = []
while elapsed < Total_time:
# Old values are used for sweeping when solving nonlinear values
vx.updateOld()
vy.updateOld()
m.updateOld()
print(elapsed, Rx, Ry)
mgrid=np.reshape(m.value,(nx,ny))
# gradient cal, dydx[0][x,y], dydx[1][x,y] -> x derivative, y derivative at x,y
dydx=np.gradient(mgrid,dx,dy,edge_order=2)
# impose periodic boundary on gradient
dydx[0][nx-1,:]=(mgrid[0,:]-mgrid[nx-2,:])/(2.0*dx)
dydx[0][0,:]=(mgrid[1,:]-mgrid[nx-1,:])/(2.0*dx)
dydx[1][:,ny-1]=(mgrid[:,0]-mgrid[:,ny-2])/(2.0*dy)
dydx[1][:,0]=(mgrid[:,1]-mgrid[:,ny-1])/(2.0*dy)
# solve ode
idx = np.argmin(np.abs(xgrid - Rx))
idy = np.argmin(np.abs(ygrid - Ry))
x0=x0+ ((f0/gamma)*np.cos(theta) - C*mgrid[idx,idy]*dydx[0][idx,idy])*dt
y0=y0+ ((f0/gamma)*np.sin(theta) - C*mgrid[idx,idy]*dydx[1][idx,idy])*dt
if(x0>L):
x0=x0-L
if(x0<0):
x0=x0+L
if(y0>L):
y0=y0-L
if(y0<0):
y0=y0+L
Rx.setValue(x0) # element-wise assignment did not work
Ry.setValue(y0)
elapsed += dt
res = 1e5
old_res = res * 2
step = 0
while res > 1e-5 and step < 5 and old_res / res > 1.01:
old_res = res
res = eq.sweep(dt=dt)
step += 1
# The variable values are just numpy arrays so easy to use!
# save velocity & density
vxs.append(vx.value.copy())
vys.append(vy.value.copy())
ms.append(m.value.copy())
viewer.plot()
# save x and y positions
xs.append(mesh.x.value.copy())
ys.append(mesh.y.value.copy())
return ms, vxs, vys, xs, ys
if __name__ == '__main__':
path = 'result/'
Total_time= 100 #40
f0 = 2
ms, vxs, vys, xs, ys = run_simulation(f0,Total_time)
name = 'f0_{:.4f}'.format(f0)
y = np.array([ms, vxs, vys])
xx = np.reshape(xs,(50,50))
yy = np.reshape(ys,(50,50))
vx = np.reshape(vxs[380][:],(50,50))
vy = np.reshape(vys[380][:],(50,50))
print(np.shape(xx), np.shape(xs), np.shape(vx))
#np.save(path + name, y)
plt.imshow(np.reshape(ms[380][:],(50,50)), aspect='auto', interpolation='bicubic', cmap='jet', extent=[0, 50, 50, 0])
plt.colorbar(label='density m')
plt.xlabel(r'$x $')
plt.ylabel(r'$y $')
plt.gcf().savefig(path + 'rho_'+name+'.png', format='png', bbox_inches='tight')
plt.clf()
#---------------------------------------------
plt.imshow(np.reshape(vxs[380][:],(50,50)), aspect='auto', interpolation='bicubic', cmap='jet', extent=[0, 50, 50, 0])
plt.colorbar(label='velocity vx')
plt.xlabel(r'$x $')
plt.ylabel(r'$y $')
plt.gcf().savefig(path + 'vel_'+name+'.png', format='png', bbox_inches='tight')
plt.clf()
#---------------------------------------------
plt.quiver(xx,yy,vx,vy,scale=3)
plt.xlabel(r'$x $')
plt.ylabel(r'$y $')
plt.gcf().savefig(path + 'v_'+name+'.png', format='png', bbox_inches='tight')
plt.clf()

I must confess that I ran out of patience before getting the stack overflow error, but I was able to identify the problem.
It's a similar (although more subtle) issue to what you reported before. Because theta is declared as a Variable,
x0=x0+ ((f0/gamma)*np.cos(theta) - C*mgrid[idx,idy]*dydx[0][idx,idy])*dt
y0=y0+ ((f0/gamma)*np.sin(theta) - C*mgrid[idx,idy]*dydx[1][idx,idy])*dt
result in longer and longer Variable expressions (and longer and longer step times). I.e., x0 = (((x0_0 + dx0_1) + dx0_2) + dx0_3) + dx0_4 + ...
Changing these to
x0=x0+ (((f0/gamma)*np.cos(theta) - C*mgrid[idx,idy]*dydx[0][idx,idy])*dt).value
y0=y0+ (((f0/gamma)*np.sin(theta) - C*mgrid[idx,idy]*dydx[1][idx,idy])*dt).value
resolves this issue.
Addressing the warning following the question edit
The warning in the comments about "...has been cast to a constant CellVariable" is due to:
xp=Variable(value=mesh.x-Rx)
yp=Variable(value=mesh.y-Ry)
This is definitely not recommended. This takes the MeshVariable objects mesh.x and mesh.y and then throws away the mesh. When the result is later associated with a mesh, e.g., by multiplying by another MeshVariable or using as a SourceTerm, FiPy warns because it looks like it could fit on the mesh, but it's not on a mesh. Just use
xp=mesh.x-Rx
yp=mesh.y-Ry

Related

Deriving Cubic Bezier Curve control points & handles from series of points in Python

I am trying to find the control points and handles of a Cubic Bezier curve from a series of points. My current code is below (credit to Zero Zero on the Python Discord). The Cubic Spline is creating the desired fit, but the handles (in orange) are incorrect. How may I find the handles of this curve?
Thank you!
import numpy as np
import scipy as sp
def fit_curve(points):
# Fit a cubic bezier curve to the points
curve = sp.interpolate.CubicSpline(points[:, 0], points[:, 1], bc_type=((1, 0.0), (1, 0.0)))
# Get 4 control points for the curve
p = np.zeros((4, 2))
p[0, :] = points[0, :]
p[3, :] = points[-1, :]
p[1, :] = points[0, :] + 0.3 * (points[-1, :] - points[0, :])
p[2, :] = points[-1, :] - 0.3 * (points[-1, :] - points[0, :])
return p, curve
ypoints = [0.0, 0.03771681353260319, 0.20421680080883106, 0.49896111463402026, 0.7183501026981503, 0.8481517096346528, 0.9256128196832564, 0.9705404287079152, 0.9933297674379904, 1.0]
xpoints = [x for x in range(len(ypoints))]
points = np.array([xpoints, ypoints]).T
from scipy.interpolate import splprep, splev
tck, u = splprep([xpoints, ypoints], s=0)
#print(tck, u)
xnew, ynew = splev(np.linspace(0, 1, 100), tck)
# Plot the original points and the Bézier curve
import matplotlib.pyplot as plt
#plt.plot(xpoints, ypoints, 'x', xnew, ynew, xpoints, ypoints, 'b')
plt.axis([0, 10, -0.05, 1.05])
plt.legend(['Points', 'Bézier curve', 'True curve'])
plt.title('Bézier curve fitting')
# Get the curve
p, curve = fit_curve(points)
# Plot the points and the curve
plt.plot(points[:, 0], points[:, 1], 'o')
plt.plot(p[:, 0], p[:, 1], 'o')
plt.plot(np.linspace(0, 9, 100), curve(np.linspace(0, 9, 100)))
plt.show()
The answer for my case was a Bezier best fit function that accepts an input of point values, fits the points to a Cubic Spline, and outputs the Bézier handles of the curve by finding their coefficients.
Here is one such script, fitCurves, which can be used like so:
import numpy as np
from fitCurve import fitCurve
import matplotlib.pyplot as plt
y = [0.0,
0.03771681353260319,
0.20421680080883106,
0.49896111463402026,
0.7183501026981503,
0.8481517096346528,
0.9256128196832564,
0.9705404287079152,
0.9933297674379904,
1.0]
x = np.linspace(0, 1, len(y))
pts = np.array([x,y]).T
bezier_handles = fitCurve(points=pts , maxError=20)
x_bez = []
y_bez = []
for bez in bezier_handles:
for pt in bez:
x_bez.append(pt[0])
y_bez.append(pt[1])
plt.plot(pts[:,0], pts[:,1], 'bo-', label='Points')
plt.plot(x_bez[:2], y_bez[:2], 'ro--', label='Handle') # handle 1
plt.plot(x_bez[2:4], y_bez[2:4], 'ro--') # handle 2
plt.legend()
plt.show()
fitCurve.py
from numpy import *
""" Python implementation of
Algorithm for Automatically Fitting Digitized Curves
by Philip J. Schneider
"Graphics Gems", Academic Press, 1990
"""
# evaluates cubic bezier at t, return point
def q(ctrlPoly, t):
return (1.0-t)**3 * ctrlPoly[0] + 3*(1.0-t)**2 * t * ctrlPoly[1] + 3*(1.0-t)* t**2 * ctrlPoly[2] + t**3 * ctrlPoly[3]
# evaluates cubic bezier first derivative at t, return point
def qprime(ctrlPoly, t):
return 3*(1.0-t)**2 * (ctrlPoly[1]-ctrlPoly[0]) + 6*(1.0-t) * t * (ctrlPoly[2]-ctrlPoly[1]) + 3*t**2 * (ctrlPoly[3]-ctrlPoly[2])
# evaluates cubic bezier second derivative at t, return point
def qprimeprime(ctrlPoly, t):
return 6*(1.0-t) * (ctrlPoly[2]-2*ctrlPoly[1]+ctrlPoly[0]) + 6*(t) * (ctrlPoly[3]-2*ctrlPoly[2]+ctrlPoly[1])
# Fit one (ore more) Bezier curves to a set of points
def fitCurve(points, maxError):
leftTangent = normalize(points[1] - points[0])
rightTangent = normalize(points[-2] - points[-1])
return fitCubic(points, leftTangent, rightTangent, maxError)
def fitCubic(points, leftTangent, rightTangent, error):
# Use heuristic if region only has two points in it
if (len(points) == 2):
dist = linalg.norm(points[0] - points[1]) / 3.0
bezCurve = [points[0], points[0] + leftTangent * dist, points[1] + rightTangent * dist, points[1]]
return [bezCurve]
# Parameterize points, and attempt to fit curve
u = chordLengthParameterize(points)
bezCurve = generateBezier(points, u, leftTangent, rightTangent)
# Find max deviation of points to fitted curve
maxError, splitPoint = computeMaxError(points, bezCurve, u)
if maxError < error:
return [bezCurve]
# If error not too large, try some reparameterization and iteration
if maxError < error**2:
for i in range(20):
uPrime = reparameterize(bezCurve, points, u)
bezCurve = generateBezier(points, uPrime, leftTangent, rightTangent)
maxError, splitPoint = computeMaxError(points, bezCurve, uPrime)
if maxError < error:
return [bezCurve]
u = uPrime
# Fitting failed -- split at max error point and fit recursively
beziers = []
centerTangent = normalize(points[splitPoint-1] - points[splitPoint+1])
beziers += fitCubic(points[:splitPoint+1], leftTangent, centerTangent, error)
beziers += fitCubic(points[splitPoint:], -centerTangent, rightTangent, error)
return beziers
def generateBezier(points, parameters, leftTangent, rightTangent):
bezCurve = [points[0], None, None, points[-1]]
# compute the A's
A = zeros((len(parameters), 2, 2))
for i, u in enumerate(parameters):
A[i][0] = leftTangent * 3*(1-u)**2 * u
A[i][1] = rightTangent * 3*(1-u) * u**2
# Create the C and X matrices
C = zeros((2, 2))
X = zeros(2)
for i, (point, u) in enumerate(zip(points, parameters)):
C[0][0] += dot(A[i][0], A[i][0])
C[0][1] += dot(A[i][0], A[i][1])
C[1][0] += dot(A[i][0], A[i][1])
C[1][1] += dot(A[i][1], A[i][1])
tmp = point - q([points[0], points[0], points[-1], points[-1]], u)
X[0] += dot(A[i][0], tmp)
X[1] += dot(A[i][1], tmp)
# Compute the determinants of C and X
det_C0_C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1]
det_C0_X = C[0][0] * X[1] - C[1][0] * X[0]
det_X_C1 = X[0] * C[1][1] - X[1] * C[0][1]
# Finally, derive alpha values
alpha_l = 0.0 if det_C0_C1 == 0 else det_X_C1 / det_C0_C1
alpha_r = 0.0 if det_C0_C1 == 0 else det_C0_X / det_C0_C1
# If alpha negative, use the Wu/Barsky heuristic (see text) */
# (if alpha is 0, you get coincident control points that lead to
# divide by zero in any subsequent NewtonRaphsonRootFind() call. */
segLength = linalg.norm(points[0] - points[-1])
epsilon = 1.0e-6 * segLength
if alpha_l < epsilon or alpha_r < epsilon:
# fall back on standard (probably inaccurate) formula, and subdivide further if needed.
bezCurve[1] = bezCurve[0] + leftTangent * (segLength / 3.0)
bezCurve[2] = bezCurve[3] + rightTangent * (segLength / 3.0)
else:
# First and last control points of the Bezier curve are
# positioned exactly at the first and last data points
# Control points 1 and 2 are positioned an alpha distance out
# on the tangent vectors, left and right, respectively
bezCurve[1] = bezCurve[0] + leftTangent * alpha_l
bezCurve[2] = bezCurve[3] + rightTangent * alpha_r
return bezCurve
def reparameterize(bezier, points, parameters):
return [newtonRaphsonRootFind(bezier, point, u) for point, u in zip(points, parameters)]
def newtonRaphsonRootFind(bez, point, u):
"""
Newton's root finding algorithm calculates f(x)=0 by reiterating
x_n+1 = x_n - f(x_n)/f'(x_n)
We are trying to find curve parameter u for some point p that minimizes
the distance from that point to the curve. Distance point to curve is d=q(u)-p.
At minimum distance the point is perpendicular to the curve.
We are solving
f = q(u)-p * q'(u) = 0
with
f' = q'(u) * q'(u) + q(u)-p * q''(u)
gives
u_n+1 = u_n - |q(u_n)-p * q'(u_n)| / |q'(u_n)**2 + q(u_n)-p * q''(u_n)|
"""
d = q(bez, u)-point
numerator = (d * qprime(bez, u)).sum()
denominator = (qprime(bez, u)**2 + d * qprimeprime(bez, u)).sum()
if denominator == 0.0:
return u
else:
return u - numerator/denominator
def chordLengthParameterize(points):
u = [0.0]
for i in range(1, len(points)):
u.append(u[i-1] + linalg.norm(points[i] - points[i-1]))
for i, _ in enumerate(u):
u[i] = u[i] / u[-1]
return u
def computeMaxError(points, bez, parameters):
maxDist = 0.0
splitPoint = len(points)/2
for i, (point, u) in enumerate(zip(points, parameters)):
dist = linalg.norm(q(bez, u)-point)**2
if dist > maxDist:
maxDist = dist
splitPoint = i
return maxDist, splitPoint
def normalize(v):
return v / linalg.norm(v)

What went wrong with my definition of angle theta and distance in my python code?

I am trying to simulate a particle under the central force $a_c = - k_r r^n \hat r$
however, I am encountering the error that my angle theta would be divided by zero sometimes
theta = np.arctan((r_US[1]-y_0)/(r_US[0]-x_0))
as well as the invalid value error for my definition of my distance
distance = np.sqrt((r_US[0]-x_0) + (r_US[1] - y_0))
what would be a better definition suited for the python code? Thanks for the answers, below is the complete code
%matplotlib inline
import matplotlib.pyplot as plt
plt.rcParams["animation.html"] = 'jshtml'
import matplotlib.animation
import numpy as np
from ipywidgets import interactive
def MotionAnimation4(xstart,ystart,vxstart,vystart, n, k): #4
xMin = 0.
xMax = 5.
yMin = 0.
yMax = 5.
x_0 = 2.5
y_0 = 2.5 #defining the center of the circle
def UpdatedState(r_US, v_US, a_US, Delta_t_US):
distance = np.sqrt((r_US[0]-x_0)**2 + (r_US[1] - y_0)**2) #updating the distance to the center of the circle
theta = np.arctan((r_US[1]-y_0)/(r_US[0]-x_0)) #defining angle relative to the center of the circle
r_US = r_US + v_US * Delta_t_US
a_x = -k * (distance**n) * np.cos(theta)
a_y = -k * (distance**n) * np.sin(theta)
central_acceleration = np.array([[a_x, a_y]]) #defining central acceleration in cartesian coordinate
if r_US[0] > xMax:
r_US[0] = xMax - (r_US[0] - xMax)
v_US[0] = -v_US[0]
if r_US[0] < xMin:
r_US[0] = xMin - (r_US[0] - xMin)
v_US[0] = -v_US[0]
if r_US[1] > yMax:
r_US[1] = yMax - (r_US[1] - yMax)
v_US[1] = -v_US[1]
if r_US[1] < yMin:
r_US[1] = yMin - (r_US[1] - yMin)
v_US[1] = -v_US[1]
a_US = central_acceleration
v_US = v_US + a_US * Delta_t_US
return r_US, v_US, a_US
Delta_t = 0.05
NumFrames = 100
Frames = np.arange(NumFrames)
xStart = xstart
yStart = ystart
vxStart = vxstart
vyStart = vystart
r = np.array([[xStart , yStart]])
v = np.array([[vxStart , vyStart]])
a = np.array([[0, 0]])
for i in Frames:
rnew, vnew, anew = UpdatedState(r[-1], v[-1], a[-1], Delta_t)
r = np.vstack((r,rnew))
v = np.vstack((v,vnew))
a = np.vstack((a, anew))
fig, ax = plt.subplots()
dot, = plt.plot([],[],'-ro')
def InitAniPlot():
ax.axis([xMin,xMax,yMin,yMax])
ax.set_aspect('equal')
return dot,
def UpdatedAniPlot(i):
dot.set_data(r[i,0], r[i,1])
return dot,
ani = matplotlib.animation.FuncAnimation(fig,UpdatedAniPlot, frames = Frames, init_func = InitAniPlot)
return ani
MotionAnimation4(2.5, 4., 1., 1., 2., 2)
p.s how would I apply latex for formulas in this stack exchange?
I replaced
theta = np.arctan((r_US[1]-y_0)/(r_US[0]-x_0))
with
theta = np.arctan2((r_US[1]-y_0), (r_US[0]-x_0))
and the code worked as intended

Nullcline Plot for Nonlinear System of ODEs

I am attempting to plot the nullcline (steady state) curves of the Oregonator model to assert the existence of a limit cycle by applying the Poincare-Bendixson Theorem. I am close, but for some reason the plot that is produced shows two straight lines. I think it has something to do with the plotting stage. Any ideas?
Also any hints for how to construct a quadrilateral to apply the theorem with would be most appreciated.
Code:
import numpy as np
import matplotlib.pyplot as plt
# Dimensionless parameters
eps = 0.04
q = 0.0008
f = 1
# Oregonator model as numpy array
def Sys(Y, t = 0):
return np.array((Y[0] * (1 - Y[0] - ((Y[0] - q) * f * Y[1]) / (Y[0] + q)) / eps, Y[0] - Y[1] ))
# Oregonator model steady states
def g(x,z):
return (x * (1 - x) + ((q - x) * f * z) / (q + x)) / eps
def h(x,z):
return x - z
# Initial lists containing values
x = []
z = []
def sys(iv1, iv2, dt, time):
# initial values:
x.append(iv1)
z.append(iv2)
# Compute and fill lists
for i in range(time):
x.append(x[i] + (g(x[i],z[i])) * dt)
z.append(z[i] + (h(x[i],z[i])) * dt)
return x, z
sys(1, 0.5, 0.01, 30)
# Locate and find equilibrium points
eqp = []
def find_fixed_points(r):
for x in range(r):
for z in range(r):
if ((g(x, z) == 0) and (h(x, z) == 0)):
eqp.append((x,z))
return eqp
# Plot nullclines
plt.plot([0,2],[2,0], 'r-', lw=2, label='x-nullcline')
plt.plot([1,1],[0,2], 'b-', lw=2, label='z-nullcline')
# Plot equilibrium points
for point in eqp:
plt.plot(point[0],point[1],"red", marker = "o", markersize = 10.0)
plt.legend(loc='best')
x = np.linspace(0, 2, 20)
z = np.linspace(0, 2, 20)
X1 , Z1 = np.meshgrid(x, z) # Create a grid
DX1, DZ1 = Sys([X1, Z1]) # Compute reaction rate on the grid
M = (np.hypot(DX1, DZ1)) # Norm reaction rate
M[ M == 0] = 1. # Avoid zero division errors
DX1 /= M # Normalise each arrows
DZ1 /= M
plt.quiver(X1, Z1, DX1, DZ1, M, pivot='mid')
plt.xlabel("x(\u03C4)")
plt.ylabel("z(\u03C4)")
plt.legend()
plt.grid()
plt.show()

Offset for SciPy.optimize least squares is not correct

I have a script which generates a noisy curve composed of 3 different sine curves. Using LombScargle I find the periods which are dominant because of these curves and detrend the original curve.
This involves phase folding, using SciPy optimize to fit a sine curve and then extrapolating the fitted curve out of phase space and onto the original multi-sine-wave-curve, and then subtracting this fit to detrend the data.
I iterate this process so that eventually when the signal on the LombScargle is less than 3 times some pre-generated noise height, the iteration stops. (equivalent to signal-to-noise ratio becoming too small).
But after the 1st iteration the phase of the fitted curve is way off! I can't see why this happens though. Can anyone help?
import matplotlib.pyplot as plt
import numpy as np
import math
from scipy.optimize import leastsq
from astropy.stats import LombScargle
t = np.linspace(15,30,1000)
y = 5 * np.sin(2*np.pi * 1./2. * (t + 1)) + 30
y1 = 11 * np.sin(2*np.pi * 1./3. * (t + 1))
y4 = 2 * np.sin(2*np.pi * 1./7. * (t + 1))
sampl = np.random.uniform(low = 0, high = 2.5, size = len(t))
y2 = y+y1+y4+sampl
y2 = y2/np.nanmedian(y2)
freq = np.linspace(1./150.,1./0.5,10000)
power2 = LombScargle(t,sampl).power(freq)
for _ in range(5):
plt.figure()
plt.subplot(221)
plt.plot(t,y2,'-')
plt.grid()
power = LombScargle(t,y2).power(freq)
p = 1./freq[np.argmax(power)]
plt.title(p)
plt.subplot(222)
plt.plot(1./freq,power)
plt.grid()
# print p
if np.max(power) <= np.max(power2)*3:
print 'done'
break
else:
foldtimes = (t - t[0])/p
FoldTimes = foldtimes % 1
p_0 = np.min(FoldTimes)
dp = 0.01
its = math.ceil((np.max(FoldTimes)-p_0)/dp)
n = np.linspace(0,its,its+1)
binned_flux = []
binned_phase = []
for i in range(len(n)):
indices = np.where(((p_0 + (n[i]*dp)) <= FoldTimes) & (FoldTimes <= (p_0 + (n[i]*dp)+dp)))[0]
if len(indices)>1:
binned_flux.append( np.nanmedian(y2[indices])) ##continuously adds the averaged fluxes to list
binned_phase.append (np.mean(FoldTimes[indices])) #same for hjs averages
binned_flux = np.array(binned_flux)
binned_phase = np.array(binned_phase)
plt.subplot(223)
plt.grid()
plt.plot(binned_phase,binned_flux,'.',linestyle='None')
plt.ylabel('Relative Flux')
plt.xlabel('Phase')
guess_mean = np.mean(y2)
guess_A = (np.max(y2) - np.min(y2))/2.
guess_phase = 0
optimize_func = lambda x: ((x[0] * np.sin(2*np.pi*(np.sort(binned_phase) + x[1]))) + x[2]) - binned_flux
est_A, est_phase, est_mean = leastsq(optimize_func, [guess_A,guess_phase,guess_mean])[0]
print est_phase
fit = (est_A*np.sin(2*np.pi*(1./p)*(t+ (est_phase*p)))) + est_mean
fit_p = (est_A*np.sin(2*np.pi*(1.)*(np.sort(binned_phase)+(est_phase)))) + est_mean
plt.plot(binned_phase,fit_p)
plt.subplot(224)
plt.plot(t,y2,'-')
plt.plot(t,fit)
plt.grid()
y2 = (y2 - fit) + est_mean #rewrites the original curve minus the fit

Python: heat density plot in a disk

My goal is to make a density heat map plot of sphere in 2D. The plotting code below the line works when I use rectangular domains. However, I am trying to use the code for a circular domain. The radius of sphere is 1. The code I have so far is:
from pylab import *
import numpy as np
from matplotlib.colors import LightSource
from numpy.polynomial.legendre import leggauss, legval
xi = 0.0
xf = 1.0
numx = 500
yi = 0.0
yf = 1.0
numy = 500
def f(x):
if 0 <= x <= 1:
return 100
if -1 <= x <= 0:
return 0
deg = 1000
xx, w = leggauss(deg)
L = np.polynomial.legendre.legval(xx, np.identity(deg))
integral = (L * (f(x) * w)[None,:]).sum(axis = 1)
c = (np.arange(1, 500) + 0.5) * integral[1:500]
def r(x, y):
return np.sqrt(x ** 2 + y ** 2)
theta = np.arctan2(y, x)
x, y = np.linspace(0, 1, 500000)
def T(x, y):
return (sum(r(x, y) ** l * c[:,None] *
np.polynomial.legendre.legval(xx, identity(deg)) for l in range(1, 500)))
T(x, y) should equal the sum of c the coefficients times the radius as a function of x and y to the l power times the legendre polynomial where the argument is of the legendre polynomial is cos(theta).
In python: integrating a piecewise function, I learned how to use the Legendre polynomials in a summation but that method is slightly different, and for the plotting, I need a function T(x, y).
This is the plotting code.
densityinterpolation = 'bilinear'
densitycolormap = cm.jet
densityshadedflag = False
densitybarflag = True
gridflag = True
plotfilename = 'laplacesphere.eps'
x = arange(xi, xf, (xf - xi) / (numx - 1))
y = arange(yi, yf, (yf - yi) / (numy - 1))
X, Y = meshgrid(x, y)
z = T(X, Y)
if densityshadedflag:
ls = LightSource(azdeg = 120, altdeg = 65)
rgb = ls.shade(z, densitycolormap)
im = imshow(rgb, extent = [xi, xf, yi, yf], cmap = densitycolormap)
else:
im = imshow(z, extent = [xi, xf, yi, yf], cmap = densitycolormap)
im.set_interpolation(densityinterpolation)
if densitybarflag:
colorbar(im)
grid(gridflag)
show()
I made the plot in Mathematica for reference of what my end goal is
If you set the values outside of the disk domain (or whichever domain you want) to float('nan'), those points will be ignored when plotting (leaving them in white color).

Categories

Resources