Overplott and interpolate in python - python

I'm new in python and i got to do a code with odeint using different values of vs, overplott them and using interpolate find the values were x and y are 0
here is the code.
Hope someone can help me.
import matplotlib.pyplot as plt # Plotting library
import math
from scipy.integrate import odeint # SciPy ODE integration
from numpy import linspace, exp
def Poissons(f, x, vs):
# f is an array of all evolving variables
phi = f[0]
E = f[1]
ne = exp(phi)
vi = math.sqrt(vs**2 - 2*phi)
ni = vs/vi
dphidx= - E
dEdx = ni - ne
return [dphidx, dEdx]
def run(E0, phi0):
vs = 1
y0 = [0.0, 0.001] # Starting location
x = linspace(0.0, 40, 100)
y = odeint(Poissons, y0, x, args = (vs,))
plt.plot(y[:,0], y[:,1])
plt.grid(True) # Add a background grid
plt.xlabel("x")
plt.ylabel("y")
plt.show()
if __name__ == "__main__":
run(0,0)

Related

Second order coupled ODE using ODEINT

I am new to solving coupled ODEs with python, I am wondering if my approach is correct, currently this code outputs a graph that looks nothing like the expected output. These are the equations I am trying to solve:
And here is the code I am using (for the functions f_gr, f_sc_phi and f_gTheta you can just put any constant value)
import Radial as rd
import ScatteringAzimuthal as sa
import PolarComponent as pc
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
#gamma for now set to 1
g_mm = 1
def f(u,t):
#y1 = thetadot :: y2 = phidot :: y3 = cdot
rho, theta, y1, phi, y2, c, y3 = u
p = [y1, (pc.f_gTheta(theta,524.1+rho)/(c*np.cos(phi))-(g_mm*y1)+(2*y1*y2*np.tan(phi))-(2*y3*y1/c)),
y2, ((sa.f_sc_phi(theta,524.1+rho/c))-(g_mm*y2)-(2*y3*y2/c)-(np.sin(phi)*np.cos(phi)*y2**2)),
y3, (rd.f_gr(theta,524.1+rho)-(g_mm*y3)+(c*y2**2)+(c*(y1**2)*(np.cos(phi)**2))), phi]
return p
time = np.linspace(0,10,100)
z2 = odeint(f,[0.1,np.pi/2,0.1,np.pi/2,0.1,0.1,0.1], time)
rhoPl = z2[:,0]
thetaPl = z2[:,1]
phiPl = z2[:,3]
'''
plt.plot(rhoPl,time)
plt.plot(thetaPl,time)
plt.plot(phiPl,time)
plt.show()
'''
x = rhoPl*np.sin(thetaPl)*np.cos(phiPl)
y = rhoPl*np.sin(thetaPl)*np.sin(phiPl)
z = rhoPl*np.cos(thetaPl)
plt.plot(x,time)
plt.plot(y,time)
plt.plot(z,time)
plt.show()
when I change the time from 0.1 to 5 I get an error:
ODEintWarning: Excess work done on this call (perhaps wrong Dfun type). Run with full_output = 1 to get quantitative information.
Any ideas on how to improve this code or if my approach is completely incorrect?
Code for Radial.py
import numpy as np
from scipy.special import spherical_jn
from scipy.special import spherical_yn
import sympy as sp
import matplotlib.pyplot as plt
R_r = 5.6*10**(-5)
l = 720
n_w = 1.326
#k = 524.5/R_r
X_r = 524.5
# R is constant r is changing
def f_gr(theta,x):
f = ((sp.sin(theta))**(2*l-2))*(1+(sp.cos(theta))**2)
b = (spherical_jn(l,n_w*x)*spherical_jn(l,n_w*x,True))+(spherical_yn(l,n_w*x)*spherical_yn(l,n_w*x,True))
c = (spherical_jn(l,n_w*X_r)*spherical_jn(l,n_w*X_r,True))+(spherical_yn(l,n_w*X_r)*spherical_yn(l,n_w*X_r,True))
n = b/c
f = f*n
return f
Code for ScatteringAzimuthal.py
from scipy.special import spherical_jn, spherical_yn
import numpy as np
import matplotlib.pyplot as plt
l = 720
n_w = 1.326
n_p = 1.572
X_r = 524.5
R_r = 5.6*10**(-5)
R_p = 7.5*10**(-7)
k = X_r/R_r
def f_sc_phi(theta,x):
f = (2/3)*(n_w**2)*((X_r**3)/x)*((R_p**3)/(R_r**3))*(((n_p**2)-(n_w**2))/((n_p**2)+(2*(n_w**2))))
g = np.sin(theta)**(2*l-3)
numerator = (l*(1+np.sin(theta))- np.cos(2*theta))\
*((spherical_jn(l,n_w*x)*spherical_jn(l,n_w*x))+(spherical_yn(l,n_w*x)*spherical_yn(l,n_w*x)))
denominator = ((spherical_jn(l,n_w*X_r)*spherical_jn(l,n_w*X_r,True))\
+(spherical_yn(l,n_w*X_r)*spherical_yn(l,n_w*X_r,True)))
m = numerator/denominator
final = f*g*m
return final
And Code for PolarComponent.py
import numpy as np
from scipy.special import spherical_yn, spherical_jn
import matplotlib.pyplot as plt
l = 720
n_w = 1.326
X_r = 524.5 #this value is implemented in the ode file
#define dimensionless polar component
#X_r is radius, x is variable
def f_gTheta(theta,x):
bessel1 = (spherical_jn(l,n_w*x)*spherical_jn(l,n_w*x)) + \
(spherical_yn(l,n_w*x)*spherical_yn(l,n_w*x))
bessel2 = ((spherical_yn(l,n_w*X_r)*spherical_yn(l,n_w*X_r,True)) + \
(spherical_yn(l,n_w*X_r)*spherical_yn(l,n_w*X_r,True)))*n_w*x
bessels = bessel1/bessel2
rest = (np.sin(theta)**(2*l-3))*((l-1)*(1+(np.cos(theta)**2)) \
-((np.sin(theta)**2)*np.cos(theta)))
final = rest*bessels
return final
Here is a link that I really like for simulating second order odes. It has an optamization twist on it because it is fitting the model to match a simulation. It has a couple of examples for odeint and also gekko.

Simulating two coupled dynamical systems in Python

The goal is to plot two identical dynamical systems that are coupled.
We have:
X = [x0,x1,x2]
U = [u0,u1,u2]
And
Xdot = f(X) + alpha*(U-X)
Udot = f(U) + alpha*(X-U)
So I wish to plot the solution to this grand system on one set of axes (i.e in xyz for example) and eventually change the coupling strength to investigate the behaviour.
import matplotlib.pyplot as plt
from scipy.integrate import odeint
from mpl_toolkits.mplot3d import Axes3D
def couple(s,t,a=0.2,beta=0.2,gamma=5.7,alpha=0.03):
[x,u] = s
[u0,u1,u2] = u
[x0,x1,x2] = x
xdot = np.zeros(3)
xdot[0] = -x1-x2
xdot[1] = x0+a*x1
xdot[2] = beta + x2*(x0-gamma)
udot = np.zeros(3)
udot[0] = -u1-u2
udot[1] = u0+a*u1
udot[2] = beta + u2*(u0-gamma)
sdot = np.zeros(2)
sdot[0] = xdot + alpha*(u-x)
sdot[1] = udot + alpha*(x-u)
return sdot
s_init = [0.1,0.1]
t_init=0; t_final = 300; t_step = 0.01
tpoints = np.arange(t_init,t_final,t_step)
a=0.2; beta=0.2; gamma=5.7; alpha=0.03
y = odeint(couple, s_init, tpoints,args=(a,beta,gamma,alpha), hmax = 0.01)
I imagine that something is wrong with s_init since it should be TWO initial condition vectors but when I try that I get that "odeint: y0 should be one-dimensional." On the other hand when I try s_init to be a 6-vector I get "too many values to unpack (expected two)." With the current setup, I am getting the error
File "C:/Users/Python Scripts/dynsys2019work.py", line 88, in couple
[u0,u1,u2] = u
TypeError: cannot unpack non-iterable numpy.float64 object
Cheers
*Edit: Please note this is basically my first time attempting this kind of thing and will be happy to receive further documentation and references.
The ode definition takes in and returns a 1D vector in scipy odeint, and I think some of your confusion is that you actually have 1 system of ODEs with 6 variables. You have just mentally apportioned it into 2 separate ODEs that are coupled.
You can do it like this:
import matplotlib.pyplot as plt
from scipy.integrate import odeint
import numpy as np
def couple(s,t,a=0.2,beta=0.2,gamma=5.7,alpha=0.03):
x0, x1, x2, u0, u1, u2 = s
xdot = np.zeros(3)
xdot[0] = -x1-x2
xdot[1] = x0+a*x1
xdot[2] = beta + x2*(x0-gamma)
udot = np.zeros(3)
udot[0] = -u1-u2
udot[1] = u0+a*u1
udot[2] = beta + u2*(u0-gamma)
return np.ravel([xdot, udot])
s_init = [0.1,0.1, 0.1, 0.1, 0.1, 0.1]
t_init=0; t_final = 300; t_step = 0.01
tpoints = np.arange(t_init,t_final,t_step)
a=0.2; beta=0.2; gamma=5.7; alpha=0.03
y = odeint(couple, s_init, tpoints,args=(a,beta,gamma,alpha), hmax = 0.01)
plt.plot(tpoints,y[:,0])

How to indicate on a graph where the line started?

I would like to indicate the starting point of the graph - where the line started. This is my code
import numpy as np
from scipy.integrate import odeint
from numpy import sin, cos, pi, array
import matplotlib
from matplotlib import rcParams
import matplotlib.pyplot as plt
from pylab import figure, axes, title, show
import xlsxwriter
def deriv(z, t):
l = 0.3 #unextended length of the spring, in m
m = 1 #mass of the bob, in kg
k = 1 #spring constant, in Nm^-1
g = 9.81 #gravitational acceleration, in ms^-2
x, y, dxdt, dydt = z
dx2dt2 = (l+x)*(dydt)**2 - k/m*x + g*cos(y)
dy2dt2 = (-g*sin(y) - 2*(dxdt)*(dydt))/(l+x)
#equations of motion
return np.array([dxdt, dydt, dx2dt2, dy2dt2])
init = array([0.3, pi/2, 0.0, 2])
#initial conditions (x, y, xdot, ydot)
time = np.linspace(0, 100, 10000)
#time intervals (start, end, number of intervals)
sol = odeint(deriv, init, time)
#solving the equations of motion
x = sol[:,0]
y = sol[:,1]
l = 0.3 #unextended length of the spring, in m
n = (l+x) * sin(y)
u = -(l+x) * cos(y)
#converting x and y to Cartesian coordinates
plt.plot(n,u)
plt.xlabel('$n$ (m)')
plt.ylabel('$u$ (m)')
plt.title('$n$ versus $u$ for 'r'$\theta_0 = \frac{\pi}{2}+0.001$')
plt.show()
which generates this graph:
However, it is unclear where the line actually started (somewhere in the upper right, I think, near where it ended). Is there some way I can add a brightly coloured dot to the starting point not specific just to this graph (i.e. so I can reproduce in on other graphs with different conditions)?
Thank you!
Plotting the first point can be done by adding plt.plot(n[0], u[0], '*') to your code, see below.
Full documentation for the plot function (thanks for the comment mostlyoxygen), to get a better idea of how you can change the colour, size and shape of the dot.
from scipy.integrate import odeint
from numpy import array, linspace, sin, cos, pi, array
from matplotlib import rcParams
import matplotlib.pyplot as plt
def deriv(z, t):
l = 0.3 #unextended length of the spring, in m
m = 1 #mass of the bob, in kg
k = 1 #spring constant, in Nm^-1
g = 9.81 #gravitational acceleration, in ms^-2
x, y, dxdt, dydt = z
dx2dt2 = (l+x)*(dydt)**2 - k/m*x + g*cos(y)
dy2dt2 = (-g*sin(y) - 2*(dxdt)*(dydt))/(l+x)
#equations of motion
return array([dxdt, dydt, dx2dt2, dy2dt2])
init = array([0.3, pi/2, 0.0, 2])
#initial conditions (x, y, xdot, ydot)
time = linspace(0, 100, 10000)
#time intervals (start, end, number of intervals)
sol = odeint(deriv, init, time)
#solving the equations of motion
x = sol[:,0]
y = sol[:,1]
l = 0.3 #unextended length of the spring, in m
n = (l+x) * sin(y)
u = -(l+x) * cos(y)
#converting x and y to Cartesian coordinates
plt.plot(n,u)
plt.plot(n[0], u[0], '*')
plt.xlabel('$n$ (m)')
plt.ylabel('$u$ (m)')
plt.title('$n$ versus $u$ for 'r'$\theta_0 = \frac{\pi}{2}+0.001$')
plt.show()

odeint from scipy.integrate in Python giving wrong result?

I am trying to solve the ivp y'=-y-5 * exp(-t) * sin(5 t), y(0)=1, using the following code:
%pylab inline
%matplotlib inline
from scipy.integrate import odeint
def mif(t, y):
return -y-5*exp(-t)*sin(5*t)
tspan = np.arange(0, 3, 0.000001)
y0 = 1.0
y_result = odeint(mif, y0, tspan)
y_result = y_result[:, 0] # convert the returned 2D array to a 1D array
plt.figure()
plt.plot(tspan, y_result)
plt.show()
However, the plot I get is wrong, it does not match what I obtain, say, with Matlab or Mathematica. It is actually different from the following alternative integration:
from scipy.integrate import ode
# initialize the 4th order Runge-Kutta solver
solver = ode(mif).set_integrator('dop853')
# initial value
y0 = 1.0
solver.set_initial_value(y0, 0)
values = 1000
t = np.linspace(0.0001, 3, values)
y = np.zeros(values)
for ii in range(values):
y[ii] = solver.integrate(t[ii])[0] #z[0]=u
which does yield correct result. What am I doing wrong with the odeint?
The function arguments change between ode and odeint. For odeint you need
def mif(y, t):
and for ode
def mif(t, y):
e.g.
%pylab inline
%matplotlib inline
from scipy.integrate import odeint
def mif(t,y):
return y
tspan = np.arange(0, 3, 0.000001)
y0 = 0.0
y_result = odeint(mif, y0, tspan)
plt.figure()
plt.plot(tspan, y_result)
plt.show()
and
from scipy.integrate import ode
def mif(y, t):
return y
# initialize the 4th order Runge-Kutta solver
solver = ode(mif).set_integrator('dop853')
# initial value
y0 = 0.000000
solver.set_initial_value([y0], 0.0)
values = 1000
t = np.linspace(0.0000001, 3, values)
y = np.zeros(values)
for ii in range(values):
y[ii] = solver.integrate(t[ii]) #z[0]=u
plt.figure()
plt.plot(t, y)
plt.show()

Numerical ODE solving in Python

How do I numerically solve an ODE in Python?
Consider
\ddot{u}(\phi) = -u + \sqrt{u}
with the following conditions
u(0) = 1.49907
and
\dot{u}(0) = 0
with the constraint
0 <= \phi <= 7\pi.
Then finally, I want to produce a parametric plot where the x and y coordinates are generated as a function of u.
The problem is, I need to run odeint twice since this is a second order differential equation.
I tried having it run again after the first time but it comes back with a Jacobian error. There must be a way to run it twice all at once.
Here is the error:
odepack.error: The function and its Jacobian must be callable functions
which the code below generates. The line in question is the sol = odeint.
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
from numpy import linspace
def f(u, t):
return -u + np.sqrt(u)
times = linspace(0.0001, 7 * np.pi, 1000)
y0 = 1.49907
yprime0 = 0
yvals = odeint(f, yprime0, times)
sol = odeint(yvals, y0, times)
x = 1 / sol * np.cos(times)
y = 1 / sol * np.sin(times)
plot(x,y)
plt.show()
Edit
I am trying to construct the plot on page 9
Classical Mechanics Taylor
Here is the plot with Mathematica
In[27]:= sol =
NDSolve[{y''[t] == -y[t] + Sqrt[y[t]], y[0] == 1/.66707928,
y'[0] == 0}, y, {t, 0, 10*\[Pi]}];
In[28]:= ysol = y[t] /. sol[[1]];
In[30]:= ParametricPlot[{1/ysol*Cos[t], 1/ysol*Sin[t]}, {t, 0,
7 \[Pi]}, PlotRange -> {{-2, 2}, {-2.5, 2.5}}]
import scipy.integrate as integrate
import matplotlib.pyplot as plt
import numpy as np
pi = np.pi
sqrt = np.sqrt
cos = np.cos
sin = np.sin
def deriv_z(z, phi):
u, udot = z
return [udot, -u + sqrt(u)]
phi = np.linspace(0, 7.0*pi, 2000)
zinit = [1.49907, 0]
z = integrate.odeint(deriv_z, zinit, phi)
u, udot = z.T
# plt.plot(phi, u)
fig, ax = plt.subplots()
ax.plot(1/u*cos(phi), 1/u*sin(phi))
ax.set_aspect('equal')
plt.grid(True)
plt.show()
The code from your other question is really close to what you want. Two changes are needed:
You were solving a different ODE (because you changed two signs inside function deriv)
The y component of your desired plot comes from the solution values, not from the values of the first derivative of the solution, so you need to replace u[:,0] (function values) for u[:, 1] (derivatives).
This is the end result:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
def deriv(u, t):
return np.array([u[1], -u[0] + np.sqrt(u[0])])
time = np.arange(0.01, 7 * np.pi, 0.0001)
uinit = np.array([1.49907, 0])
u = odeint(deriv, uinit, time)
x = 1 / u[:, 0] * np.cos(time)
y = 1 / u[:, 0] * np.sin(time)
plt.plot(x, y)
plt.show()
However, I suggest that you use the code from unutbu's answer because it's self documenting (u, udot = z) and uses np.linspace instead of np.arange. Then, run this to get your desired figure:
x = 1 / u * np.cos(phi)
y = 1 / u * np.sin(phi)
plt.plot(x, y)
plt.show()
You can use scipy.integrate.ode. To solve dy/dt = f(t,y), with initial condition y(t0)=y0, at time=t1 with 4th order Runge-Kutta you could do something like this:
from scipy.integrate import ode
solver = ode(f).set_integrator('dopri5')
solver.set_initial_value(y0, t0)
dt = 0.1
while t < t1:
y = solver.integrate(t+dt)
t += dt
Edit: You have to get your derivative to first order to use numerical integration. This you can achieve by setting e.g. z1=u and z2=du/dt, after which you have dz1/dt = z2 and dz2/dt = d^2u/dt^2. Substitute these into your original equation, and simply iterate over the vector dZ/dt, which is first order.
Edit 2: Here's an example code for the whole thing:
import numpy as np
import matplotlib.pyplot as plt
from numpy import sqrt, pi, sin, cos
from scipy.integrate import ode
# use z = [z1, z2] = [u, u']
# and then f = z' = [u', u''] = [z2, -z1+sqrt(z1)]
def f(phi, z):
return [z[1], -z[0]+sqrt(z[0])]
# initialize the 4th order Runge-Kutta solver
solver = ode(f).set_integrator('dopri5')
# initial value
z0 = [1.49907, 0.]
solver.set_initial_value(z0)
values = 1000
phi = np.linspace(0.0001, 7.*pi, values)
u = np.zeros(values)
for ii in range(values):
u[ii] = solver.integrate(phi[ii])[0] #z[0]=u
x = 1. / u * cos(phi)
y = 1. / u * sin(phi)
plt.figure()
plt.plot(x,y)
plt.grid()
plt.show()
scipy.integrate() does ODE integration. Is that what you are looking for?

Categories

Resources