Id like to thank whoever answers this in advance, as it is probably a stupid question and a waste of time to answer.
The given code takes the electromagnetic forces on a particle and supposedly plots its trajectory, but I cant figure out how to use rk4 with vectors. Feel like my function is set up wrong.
import numpy as np
import matplotlib.pyplot as plt
from numpy.linalg import inv, det, eig
from numpy.random import randn
def rk4(f, x0, dt):
tn = 0
xn = x0
while True:
yield tn,xn
k1 = dt*f(tn,xn)
k2 = dt*f(tn+dt/2,xn+k1/2)
k3 = dt*f(tn+dt/2,xn+k2/2)
k4 = dt*f(tn+dt,xn+k3)
xn = xn + (k1+2*k2+2*k3+k4)/6
tn = tn + dt
#--------------------------------------------------------
def f(t,X):
x,y,z,xv,yv,zv = X
v = [xv,yv,zv]
E = [k*x , k*y , -2*z]
a = (q/m)*(E+np.cross(v,B))
Xdot = np.array([v,a])
return Xdot
q , m , B , k = 1.6e-19, 40, [0,0,1], 10e+4
X0 = np.array([0.001 , 0 , 0.001 , 100 , 0 , 0])
solver = rk4(f,X0,10e-7)
ts = []
Xs = []
for t,X in solver:
ts.append(t)
Xs.append(X[0])
if t > 0.001:
break
#Xs = np.array(Xs)
#plt.figure()
#plt.plot(ts,Xs)
Id really appreciate any tips or hints
I suspect the problem stems from the way iv set up the function, as the code crashes once it tries to run it through rk4.
You can not apply vector arithmetic to simple python lists, thus convert the lists first into numpy arrays. You need to return a flat vector, not a matrix, thus use array concatenation to join the two parts.
def f(t,X):
x,y,z,xv,yv,zv = X
v = np.array([xv,yv,zv]) # or v = X[3:]
E = np.array([k*x , k*y , -2*z]) # or E=k*X[:3]; E[2]=-2*X[2]
a = (q/m)*(E+np.cross(v,B))
Xdot = np.concatenate([v,a])
return Xdot
For the last change see Concatenating two one-dimensional NumPy arrays
Related
I am working on the following code, which solves a system of coupled differential equations. I have been able to solve them, and I plotted one of them. I am curious how to compute and plot the derivative of this graph numerically (I know the derivative is given in the first function, but suppose I didn't have that). I was thinking that I could use a for-loop, but is there a faster way?
import numpy as np
from scipy.integrate import odeint
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt
import math
def hiv(x,t):
kr1 = 1e5
kr2 = 0.1
kr3 = 2e-7
kr4 = 0.5
kr5 = 5
kr6 = 100
h = x[0] # Healthy Cells -- function of time
i= x[1] #Infected Cells -- function of time
v = x[2] # Virus -- function of time
p = kr3 * h * v
dhdt = kr1 - kr2*h - p
didt = p - kr4*i
dvdt = -p -kr5*v + kr6*i
return [dhdt, didt, dvdt]
print(hiv([1e6, 0, 100], 0))
x0 = [1e6, 0, 100] #initial conditions
t = np.linspace(0,15,1000) #time in years
x = odeint(hiv, x0, t) #vector of the functions H(t), I(t), V(t)
h = x[:,0]
i = x[:,1]
v = x[:,2]
plt.semilogy(t,h)
plt.show()
I have been using the SymPy Vector module to do Vector Calculus and related Physics. However, I would like to convert my created vectors to Matrix format. I know that there is a method of Vector.to_matrix(CoordSys), and I got it to work, but I am struggling with creating a 3x3 matrix for eventually finding determinants with.
My current code involves 3 individual vectors: Phidiffu, Phidiffv, and UnitVector. I am trying to insert these into a matrix, and it is sort of working, but I am unable to delete columns, and the method takes a suspiciously large amount of code for something that should be simple. N is the method that I sort of got to work, while m is the method that I could not get to work.
import math as m
import numpy as np
import sympy as sym
from sympy import *
from sympy.vector import *
from sympy.physics.quantum import *
from sympy.physics.vector import *
u, v, Phi = symbols('u v Phi')
Phi = Function('Phi')(u, v)
F = Function('F')(x, y)
N = CoordSys3D('N')
Phi = (2*u*cos(v))*N.i + (2*u*sin(v))*N.j + (u)*N.k
PhiMat = Phi.to_matrix(N)
PhiVec = matrix_to_vector(PhiMat, N)
Phidiffu = Phi.diff(u)
Phidiffv = Phi.diff(v)
UnitVector = N.i + N.j + N.k
UnitVectorMat = UnitVector.to_matrix(N)
PhidiffuMat = Phidiffu.to_matrix(N)
PhidiffvMat = Phidiffv.to_matrix(N)
UnitVectorMat.col_join(PhidiffuMat)
M = Matrix([UnitVectorMat, PhidiffuMat, PhidiffvMat])
#M = Matrix([UnitVectorMat], [PhidiffuMat], [PhidiffvMat])
#M = Matrix(1, 3, [UnitVectorMat, PhidiffuMat, PhidiffvMat])
#M = Matrix(3, 1, [[UnitVectorMat], [PhidiffuMat], [PhidiffvMat]])
N1 = zeros(3)
N2 = N1.col_insert(0, UnitVectorMat)
N3 = N2.col_insert(1, PhidiffuMat)
N4 = N3.col_insert(2, PhidiffvMat)
N5 = N4.col_del(3)
#N6 = N5.col_del(3)
#N7 = N6.col_del(3)
#N7.T
N4
Does anyone know how I may get the code to work?
Best regards, ExactPlace441
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])
I'm trying to compute the following Fourier coefficients
where V_{pot} is a previous def function of this form.
I really don't know what numerical method I can use, however I began with Simpson’s rule of scipy library.
import numpy as np
from scipy.integrate import simps
Nf = 200
IVp = np.zeros(2*Nf)
snn = np.zeros(NP)
def f(k):
for i in range(0,NP):
sn = (i-1)*H
snn[i] = sn
return (1/SF) * np.cos(np.pi*k*sn/SF) * Vpot(sn)
for k in range(0,2*Nf):
Func = f(k)
y1 = np.array(Func,dtype=float)
I = simps(y1,snn)
I had this error:
IndexError: tuple index out of range
Your task can be done via
Nf = 200
s = np.linspace(0, Sf, Nf+1);
V_s = Vpot(s)
I = [ simps(s, np.cos(np.pi*k*s/Sf)*V_s ) / Sf for k in range(0,2*Nf) ]
But really, investigate how to do this via the FFT or related methods.
I'm going through Strogatz's Nonlinear Dynamics and Chaos and I've hit a snag in chapter 2 Exercise 2.8.1. (Educator flag: I've graduated so this isn't for a class, I'm just trying to get back into the numerical solving of differential equations) It's a pretty simple differential equation and I can plot individual solution curves given different initial conditions but I'm trying to use quiver or streamplot to superimpose individual solutions on top of the vector field.
My problem is in understanding how to translate the vector field plots for similar problems in the dy/dx form found here over to the dx/dt form that's primarily tackled in Strogatz's book.
Given that the x vector that's defined in the logistic function is only one dimensional I'm having a hard time reasoning out how express the u and v flows in quiver or streamplot since the problem only seems to have a u flow. It's probably super easy and is being over-thought but any guidance or assistance would be much appreciated!
So far I have the following:
# 2.8.1
# Plot the vector field and some trajectories for xdot = x(1-x) given
# some different initial conditions for the logistic equation with carrying
# capacity K = 1
# dx/dt = x(1-x)
# Imports:
from __future__ import division
from scipy import *
import numpy as np
import pylab
import matplotlib as mp
from matplotlib import pyplot as plt
import sys
import math as mt
def logistic(x,t):
return np.array([x[0]*(1-x[0])])
def RK4(t0 = 0, x0 = np.array([1]), t1 = 5 , dt = 0.01, ng = None):
tsp = np.arange(t0, t1, dt)
Nsize = np.size(tsp)
X = np.empty((Nsize, np.size(x0)))
X[0] = x0
for i in range(1, Nsize):
k1 = ng(X[i-1],tsp[i-1])
k2 = ng(X[i-1] + dt/2*k1, tsp[i-1] + dt/2)
k3 = ng(X[i-1] + dt/2*k2, tsp[i-1] + dt/2)
k4 = ng(X[i-1] + dt*k3, tsp[i-1] + dt)
X[i] = X[i-1] + dt/6*(k1 + 2*k2 + 2*k3 + k4)
return X
def tplot():
t0 = 0
t1 = 10
dt = 0.02
tsp = np.arange(t0,t1,dt)
X = RK4(x0 = np.array([2]), t1 = 10,dt = 0.02, ng = logistic)
Y = RK4(x0 = np.array([0.01]), t1 = 10,dt = 0.02, ng = logistic)
Z = RK4(x0 = np.array([0.5]), t1 = 10,dt = 0.02, ng = logistic)
P = RK4(x0 = np.array([3]), t1 = 10,dt = 0.02, ng = logistic)
Q = RK4(x0 = np.array([0.1]), t1 = 10,dt = 0.02, ng = logistic)
R = RK4(x0 = np.array([1.5]), t1 = 10,dt = 0.02, ng = logistic)
O = RK4(x0 = np.array([1]), t1 = 10,dt = 0.02, ng = logistic)
pylab.figure()
pylab.plot(tsp,X)
pylab.plot(tsp,Y)
pylab.plot(tsp,Z)
pylab.plot(tsp,P)
pylab.plot(tsp,Q)
pylab.plot(tsp,R)
pylab.plot(tsp,O)
pylab.title('Logistic Equation - K=1')
pylab.xlabel('Time')
pylab.ylabel('Xdot')
pylab.show()
print tplot()
image here
To graph a slope from a derivative (like, dx/dt), you can first find dx/dt, and then use a fixed dt to calculate dx. Then, at each (t, x) of interest, plot the little line segment from (t,x) to (t+dt, x+dx).
Here's an example for your equation dx/dt = x(1-x). (The Strogatz picture doesn't have arrowheads so I removed them too.)
import numpy as np
import matplotlib.pyplot as plt
times = np.linspace(0, 10, 20)
x = np.linspace(0 ,2, 20)
T, X = np.meshgrid(times, x) # make a grid that roughly matches the Strogatz grid
dxdt = X*(1-X) # the equation of interest
dt = .5*np.ones(X.shape) # a constant value (.5 is just so segments don't run into each other -- given spacing of times array
dx = dxdt * dt # given dt, now calc dx for the line segment
plt.quiver(T, X, dt, dx, headwidth=0., angles='xy', scale=15.)
plt.show()
wonkybadonk: For the difference in slope of the plotted trajectories and the plotted vector field seem to be due to the fact that your vector field are not steep enough. Make sure that
dx = dxdt*dt; (point by point multiplication, not a dot product)
and that you added "angles='xy'" as a quiver argument. (see tom10 post).