I would like to plot a function of e and nu, where e is the eccentricity and nu the true anomaly. I am only looking at elliptical orbits so 0<e<1. However, when I try to plot them against each other, I have a shape error:
ValueError: operands could not be broadcast together with shapes (10) (5000)
I know this is because I only want 10 spaces for the eccentricity, but is there a way around this?
import numpy as np
e = np.arange(0, 1, 0.1)
vvals = [[] for i in range(len(e))]
nu = np.linspace(0, 2 * np.pi, 5000)
for i in e:
for j in nu:
i = float(i)
j = float(j)
v = np.sqrt(e ** 2 + 2 * e * np.cos(nu) + 1)
i = int(i)
vvals[i].append(v)
for i in e:
pylab.plot(nu, vvals[i])
pylab.show()
I think this is what you are trying to do:
import numpy as np
e = np.arange(0, 1, 0.1)
vvals = []
nu = np.linspace(0, 2 * np.pi, 5000)
for i in e:
v = np.sqrt(i ** 2 + 2 * i * np.cos(nu) + 1)
vvals.append(v)
for v in vvals:
pylab.plot(nu, v)
pylab.show()
numpy broadcasting is your friend ;)
If you want to get really fancy:
import numpy as np
e = np.arange(0, 1, 0.1).reshape(-1, 1)
nu = np.linspace(0, 2 * np.pi, 5000).reshape(1, -1)
vvals = np.sqrt((e ** 2) * np.ones(nu.shape) + 2 * e * np.cos(nu) + 1)
for v, _e in zip(vvals, e.ravel()):
pylab.plot(nu.ravel(), v, label=str(_e))
pylab.legend()
pylab.show()
Related
I'm trying to use the library multiprocessing, to run the next code:
import matplotlib.pyplot as plt
import numpy as np
from multiprocessing import Pool
def newtalt(fun,x0,err,mit):
xnew = x0.copy()
F, dF = fun(x0)
r = F.copy()
M = dF.copy()
sigma = np.linalg.norm(r)
for k in range(mit):
if sigma < err:
break
d = np.linalg.solve(M, -r)
xnew = xnew + d
r, M = fun(xnew)
sigma = np.linalg.norm(r)
return xnew, k
def fun(x):
f_r = x[0] ** 3 - 3 * x[0] * (x[1] ** 2) - 1
f_i = 3 * (x[0]**2) * x[1] - (x[1] ** 3)
f = np.array([f_r,f_i])
df_rx = 3 * (x[0] ** 2) - 3 * (x[1] ** 2)
df_ry = -6 * x[0] * x[1]
df_ix = 6 * x[0] * x[1]
df_iy = 3 * (x[0] ** 2) - 3 * (x[1] ** 2)
df = np.array([[df_rx,df_ry],[df_ix,df_iy]])
return f, df
if __name__=='__main__':
pool = Pool(processes=10)
err = 1e-5
mit = 300
N = 50
x = np.linspace(-2.5, 2.5, N)
y = np.linspace(-2.5, 2.5, N)
A = np.zeros((N, N))
B = np.zeros([N, N, 4], dtype=int)
for i in range(N):
for j in range(N):
z = np.array([x[i], y[j]])
xsol, it = pool.map(newtonalt,(fun,z,err,mit))
pool.close()
A[i,j] = it
plt.imshow(A,cmap='Set1')
plt.show()
Cleary it doesn't work, 'cause I don't really know how to use multiprocessing properly, and it's even more difficult when the function you use have multiple arguments. I read that isn't good use .pool() inside a for loop, but anyway, as I was saying, I'm really lost with this library.
I am seeking to find a finite difference solution to the 1D Nonlinear PDE
u_t = u_xx + u(u_x)^2
Code:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import math
'''
We explore three different numerical methods for solving the PDE, with solution u(x, t),
u_t = u_xx + u(u_x)^2
for (x, t) in (0, 1) . (0, 1/5)
u(x, 0) = 40 * x^2 * (1 - x) / 3
u(0, t) = u(1, t) = 0
'''
M = 30
dx = 1 / M
r = 0.25
dt = r * dx**2
N = math.floor(0.2 / dt)
x = np.linspace(0, 1, M + 1)
t = np.linspace(0, 0.2, N + 1)
U = np.zeros((M + 1, N + 1)) # Initial array for solution u(x, t)
U[:, 0] = 40 * x**2 * (1 - x) / 3 # Initial condition (: for the whole of that array)
U[0, :] = 0 # Boundary condition at x = 0
U[-1, :] = 0 # Boundary condition at x = 1 (-1 means end of the array)
'''
Explicit Scheme - Simple Forward Difference Scheme
'''
for q in range(0, N - 1):
for p in range(0, M - 1):
b = 1 / (1 - 2 * r)
C = r * U[p, q] * (U[p + 1, q] - U[p, q])**2
U[p, q + 1] = b * (U[p, q] + r * (U[p + 1, q + 1] + U[p - 1, q + 1]) - C)
T, X = np.meshgrid(t, x)
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(T, X, U)
#fig.colorbar(surf, shrink=0.5, aspect=5) # colour bar for reference
ax.set_xlabel('t')
ax.set_ylabel('x')
ax.set_zlabel('u(x, t)')
plt.tight_layout()
plt.savefig('FDExplSol.png', bbox_inches='tight')
plt.show()
The code I use produces the following error:
overflow encountered in double_scalars
C = r * U[p, q] * (U[p + 1, q] - U[p, q])**2
invalid value encountered in double_scalars
U[p, q + 1] = b * (U[p, q] + r * (U[p + 1, q + 1] + U[p - 1, q + 1]) - C)
invalid value encountered in double_scalars
C = r * U[p, q] * (U[p + 1, q] - U[p, q])**2
Z contains NaN values. This may result in rendering artifacts.
surf = ax.plot_surface(T, X, U)
I've looked up these errors and I assume that the square term generates values too small for the dtype. However when I try changing the dtype to account for a larger range of numbers (np.complex128) I get the same error.
The resulting plot obviously has most of its contents missing. So, my question is, what do I do?
Discretisation expression was incorrect.
Should be
for q in range(0, N - 1):
for p in range(0, M - 1):
U[p, q + 1] = r * (U[p + 1, q] - 2 * U[p, q] + U[p - 1, q]) + r * U[p, q] * (U[p + 1, q] - U[p, q])
I am looking for a way to project the intersection point of the graph using a vertical discontinuous line (style '--') on the x-axis and then write the x-coordinate on that axis.
Here's my attempt to find the intersection. For some reason, the point is not exactly on the intersection. It's strange.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
n = 256
k = np.arange(0, 100)
g = 1 - np.exp(-0.5 * k * (k - 1) / n)
plt.plot(g, '-')
plt.hlines(0.5, 0, 100, 'r')
idx = np.argwhere(np.diff(np.sign(g - 0.5)))
plt.plot(k[idx], g[idx], 'o')
plt.show()
As mentioned in the comment by tevemadar you need to find the intersection point by solving for k for g = 0.5 i.e where you've drawn your hline.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
n = 256
k = np.arange(0, 100)
f = 0.5
g = 1 - np.exp(-0.5 * k * (k - 1) / n)
plt.plot(g, '-')
hline_pos = 0.5
plt.hlines(hline_pos, 0, 100, 'r')
# inverse
# np.exp(-0.5 * k * (k - 1) / n) = 1 - g
# -0.5 * k * (k - 1) / n = np.log(1 - g)
# k^2 - k = np.log(1 - g) * (-n/0.5)
solve_for = hline_pos
constant = np.log(1 - solve_for) * (-n/0.5)
ks = np.roots([1, -1, -constant])
ks = np.sort(ks) # sort to get the positive root based on the domain boundaries
plt.scatter(ks[1], hline_pos)
plt.vlines(ks[1], 0, hline_pos, linestyles='--')
plt.show()
I am trying to solve a simple ODE so as to understand the new API of Scipy.
I wrote a routine for Runge Kutta of order 4 to write it and confirmed it with the old API odeint and it matched beautifully. But now that I am trying to get around the solve_ivp, it seems that is not working. What am I getting wrong?
import numpy as np
from matplotlib import pyplot as plt
from scipy.integrate import solve_ivp, odeint
import time
freq = np.arange(1, 10000, 100)
def g(q, t):
return -q ** 3 + np.sin(t)
a = 0
b = 10
npoints = 100
h = (b - a) / npoints
t = np.arange(a, b, h)
output1 = np.zeros(t.shape)
x = 0
for i in range(len(t)):
output1[i] = x
k1 = h * g(x, t[i])
k2 = h * g(x + 0.5 * k1, t[i] + 0.5 * h)
k3 = h * g(x + 0.5 * k2, t[i] + 0.5 * h)
k4 = h * g(x + k3, t[i] + 0.5 * h)
x = x + 1 / 6 * (k1 + 2 * k2 + 2 * k3 + k4)
# ---------------Solving using odeint (old API)---------------#
y1_odeint = odeint(g, 0, t)
#---------------Solving using new API-------------#
y2=solve_ivp(g,(a,b),[0],t_eval=t)
# --------------------Representação gráfica--------------------------#
fig = plt.figure()
ax = fig.add_subplot(121)
ax1=fig.add_subplot(122)
ax.plot(t, output1,label="my own")
ax.plot(t,y1_odeint,label="odeint")
ax.plot(y2.t,np.squeeze(y2.y),label="new API")
ax.legend()
ax.set_title("Output")
ax1.plot(t,output1-np.squeeze(y1_odeint),label="|odeint-my own|")
ax1.legend()
plt.tight_layout()
plt.show()
Take another look at the docstring for solve_ivp. It expects the first argument of g to be t. By default, odeint uses the opposite convention. If you have a recent version of scipy, you can tell odeint that the first argument is t by giving it the argument tfirst=True.
The equation I am working with is
$$
E = M_e + \sum_{n = 1}^N\frac{2}{n}\mathcal{J}_n(ne)\sin(nM_e)
$$
where $\mathcal{J}_n(x)$ is the nth Bessel function of the first kind.
As a test, I plotted the first 6 Bessel functions and everything worked out correctly. When I enter the argument of $n * e$, the plot isn't what I anticipated it to be.
import numpy as np
import pylab as py
import scipy.special as sp
x = np.linspace(0, 15, 500000)
for v in range(0, 6):
py.plot(x, sp.jv(v, x))
py.xlim((0, 15))
py.ylim((-0.5, 1.1))
py.legend(('$\mathcal{J}_0(x)$', '$\mathcal{J}_1(x)$', '$\mathcal{J}_2(x)$',
'$\mathcal{J}_3(x)$', '$\mathcal{J}_4(x)$', '$\mathcal{J}_5(x)$'),
loc = 0)
py.xlabel('$x$')
py.ylabel('$\mathcal{J}_n(x)$')
#py.title('Plots of the first six Bessel Functions')
py.grid(True)
#py.savefig('besseln0to6.eps', format = 'eps')
py.show()
e = 0.99
def E(M):
return (M + sum(2.0 / n * sp.jv(n * e, M) * np.sin(n * M)
for n in range(1, 3, 1)))
M = np.linspace(0, 2 * np.pi, 500000)
fig2 = py.figure()
ax2 = fig2.add_subplot(111, aspect = 'equal')
ax2.plot(E(M), M, 'b')
def E2(M):
return (M + sum(2.0 / n * sp.jv(n * e, M) * np.sin(n * M)
for n in range(1, 11, 1)))
ax2.plot(E2(M), M, 'r')
py.xlim((0, 2 * np.pi))
py.ylim((0, 2 * np.pi))
py.xlabel('Eccentric anomaly, $E$')
py.ylabel('Mean anomaly, $M_e$')
py.show()
The plot is supposed to look like for n = 10
The problem is the use of the Bessel function sp.jv(n * e, M) whereas it should be order, argument. That in turn leads to sp.jv(n , n * e) which generates the correct plot.