I was tasked of to plot a possible trajectory knowing the derivative of a function : X' = 0.05X *(1-X/100) using the eulor method. So i came up with the following
import numpy as np
import matplotlib.pyplot as plt
##defining derivative
def changevector(X):
dX = 0.05*X *(1-(X/100))
return dX
#defining initial values
timestep = 0.001
itera = 1000
x = np.zeros(itera+1)
passedtime = np.zeros(itera+1)
x[0] = 100
#stepping trough time
for i in range(itera):
x[i+1] = x[i] + timestep*changevector(x[i])
passedtime[i] = i * timestep
fig1 = plt.figure(figsize=(5,4))
ax = fig1.add_axes(([0.1, 0.1, 0.9, 0.9]))
plt.plot(passedtime, x)
plt.show()
This would give me a flat line instead of a trajectory and I cant figure out why or how to fix it. Thank you in advance
Related
I am trying to solve the following nonlinear system of differential equation with the explicit Euler method:
x' = f1(x,y),
y' = f2(x,y)
And I know the fact that the curve corresponding to the solution must connect (x_{initial},y_{initial}) to (0,1) in the x-y plane, but the obtained curve stops prematurely at around (0.17,0.98). I tried to vary the parameters but again I can't push that value any further towards (0,1). First, I thought my equations becomes stiff towards the end point; now it doesn't seem to be the case when I read about the stiff ODEs. What might be the problem?
The code I wrote in python is:
import math
import numpy as np
import matplotlib.pyplot as plt
q=1
#my f1 and f2 functions:
def l(lna,x,y,m,n,xi,yi):
return n *m**(-1)*(np.divide((yi**2)*(np.float64(1)-np.power(x,2)-np.power(y,2))*np.exp(3*(lna-lnai)),(y**2)*(1-xi**2-yi**2)))**(-1/n)
def f1 (x,y,l):
return -3*x + l*np.sqrt(3/2)* y**2+ 3/2 *x*(2*(x**2)+q*(1-x**2-y**2))
def f2 (x,y,l):
return -l*np.sqrt(3/2) *y*x + 3/2 *y*(2*x**2+q*(1-x**2-y**2))
#my code for the explicit Euler:
def e_E(xa,xb,dlna,m,n,xi,yi):
N = int(round((lnaf-lnai)/dlna))
lna = np.linspace(0, N*dlna, N+1)
x = np.empty(N+1)
y = np.empty(N+1)
x[0],y[0] = xi,yi
for i in range(N):
sd = l(lna[i],x[i],y[i],m,n,xi,yi)
x[i+1] = x[i] + dlna * f1(x[i],y[i],sd)
y[i+1] = y[i] + dlna * f2(x[i],y[i],sd)
return x,y,lna
#range for the independent variable (in my case it is lna)
lnai = np.float64(0)
lnaf = np.float64(15)
#step size
dlna = np.float64(1e-3)
#initial conditions
yi = np.float64(1e-5)
xi = 0
x1,y1,lna1 = e_E(lnai, lnaf, dlna, np.float64(0.1), np.float64(2), xi, yi)
plt.plot(x1,y1,'b',label = ('x1'))
plt.legend()
plt.grid()
plt.ylabel('y')
plt.xlabel('x')
plt.show()
My solution in the x-y plane:
Full/correct solution:
I'm transitioning my code from using scipy's odeint to scipy's solve_ivp. When using odeint I would use a while loop as follows:
while solver.successful() :
solver.integrate(t_final, step=True)
# do other operations
This method allowed me to store values that depended on the solutions after each timestep.
I'm now switching to using solve_ivp but not sure how to accomplish this functionality with the solve_ivp solver. Has anyone accomplished this functionality with solve_ivp?
Thanks!
I think i know what your trying to ask. I had a program that used solve_ivp to integrate between each time step individually, then used the values to calculate the values for the next iteration. (i.e. heat transfer coefficients, transport coefficients etc.) I used two nested for loops. The inner for loop calculates or completes the operations you need to at each step. Then save each value in a list or array and then the inner loop should terminate. The outer loop should only be used to feed time values and possibly reload necessary constants.
For example:
for i in range(start_value, end_value, time_step):
start_time = i
end_time = i + time_step
# load initial values and used most recent values
for j in range(0, 1, 1):
answer = solve_ivp(function,(start_time,end_time), [initial_values])
# Save new values at the end of a list storing all calculated values
Say you have a system such as
d(Y1)/dt = a1*Y2 + Y1
d(Y2)/dt = a2*Y1 + Y2
and you want to solve it from t = 0, 10. With a 0.1 time step. Where a1 and a2 are values calculated or determined elsewhere. This code would work.
from scipy.integrate import solve_ivp
import sympy as sp
import numpy as np
import math
import matplotlib.pyplot as plt
def a1(n):
return 1E-10*math.exp(n)
def a2(n):
return 2E-10*math.exp(n)
def rhs(t,y, *args):
a1, a2 = args
return [a1*y[1] + y[0],a2*y[0] + y[1]]
Y1 = [0.02]
Y2 = [0.01]
A1 = []
A2 = []
endtime = 10
time_step = 0.1
times = np.linspace(0,endtime, int(endtime/time_step)+1)
tsymb = sp.symbols('t')
ysymb = sp.symbols('y')
for i in range(0,endtime,1):
for j in range(0,int(1/time_step),1):
tstart = i + j*time_step
tend = i + j*time_step + time_step
A1.append(a1(tstart/100))
A2.append(a2(tstart/100))
Y0 = [Y1[-1],Y2[-1]]
args = [A1[-1],A2[-1]]
answer = solve_ivp(lambda tsymb, ysymb : rhs(tsymb,ysymb, *args), (tstart,tend), Y0)
Y1.append(answer.y[0][-1])
Y2.append(answer.y[1][-1])
fig = plt.figure()
plt1 = plt.plot(times,Y1, label = "Y1")
plt2 = plt.plot(times,Y2, label = "Y2")
plt.xlabel('Time')
plt.ylabel('Y Values')
plt.legend()
plt.grid()
plt.show()
I have plotted a 'tear drop' shaped cylinder in matplotlib. To obtain the tear drop shape I plotted a normal cylinder from theta = 0 to theta = pi and an ellipse from theta = pi to theta = 2pi. However I am now trying to 'spin' the cylinder around it's axis which here is given conveniently by the z-axis.
I tried using the rotation matrix for rotating around the z-axis which Wikipedia gives as:
However when I try to rotate through -pi/3 radians, the cylinder becomes very disfigured.
Is there anyway to prevent this from happening?
Here is my code:
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from math import sin, cos, pi
import math
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
theta = np.linspace(0,2*pi, 1200)
Z = np.linspace(0,5,1000+600)
Z,theta = np.meshgrid(Z, theta)
X = []
Y = []
R = 0.003
#calculate the x and y values
for i in theta:
cnt = 0
tempX = []
tempY = []
for j in i:
#circle
if(i[0]<=pi):
tempX.append(R*cos(j))
tempY.append(R*sin(j))
cnt+=1
#ellipse
else:
tempX.append(R*cos(j))
tempY.append(0.006*sin(j))
X.append(tempX)
Y.append(tempY)
X1 = np.array(X)
Y1 = np.array(Y)
#rotate around the Z axis
a = -pi/3
for i in range(len(X)):
X1[i] = cos(a)*X1[i]-sin(a)*Y1[i]
Y1[i] = sin(a)*X1[i]+cos(a)*Y1[i]
#plot
ax.plot_surface(X1,Y1,Z,linewidth = 0, shade = True, alpha = 0.3)
ax.set_xlim(-0.01,0.01)
ax.set_ylim(-0.01, 0.01)
azimuth = 173
elevation = 52
ax.view_init(elevation, azimuth)
plt.show()
Your rotating is flawed: To calculate Y1[i] you need the old value of X1[i], but you already updated it. You can try something like
X1[i], Y1[i] = cos(a)*X1[i]-sin(a)*Y1[i], sin(a)*X1[i]+cos(a)*Y1[i]
if you want to make the matrix multiplication a bit more obvious (and fix the bug) you could also do the following (please doublecheck that the matrix is correct and that the multiplication is in the right order, I did not test this):
rotation_matrix = np.array([[cos(a), -sin(a)], [sin(a), cos(a)]])
x, y = zip(*[(x,y) # rotation_matrix for x,y in zip(x,y)])
the # is new in 3.5 and for numpy array it's defined to be the matrix multiplication. If you are on a version below 3.5 you can use np.dot.
The zip(*...) is necessary to get a pair of lists instead of a list of pairs. See also this answer
could you please help me with finding points of intersection in graphic
import numpy as np
import matplotlib.pyplot as plt
#interact
def foo(count=(1,10,1), t=slider(100,1000,100,default=100)):
plt.cla()
dt = 1/t
x = np.arange(1, step=dt)
xl = np.arange(1, step=.000001)
W = np.zeros(t, np.dtype(float))
#Iteration Logarithm
l = np.sqrt(2*xl*ln(ln(1/xl)))
plt.plot(xl, l,'r--')
plt.plot(xl, -l,'r--')
mu, sig = 0, 1
for ITER in range(1, count+1): #count of W[i] in plot
for i in range(1, len(W)):
W[i] = W[i-1] + np.random.normal(mu, sig) * np.sqrt(dt) #Wiener process
plt.plot(x,W)
plt.xlabel('t',fontsize=26)
plt.ylabel('W(t)',fontsize=26)
plt.grid(True)
#interact
def _dee(deep=slider(0.0001, .4, 0.001, default=.2)): #scale
plt.xlim(0, deep)
plt.ylim(-.5, .5)
plt.show()
I use https://cloud.sagemath.com
Can't realize, how to find points of graphic cross each other.
Thanks.
Although I'm not familiar with sage, getting intersection points given two sampled function should be easy - just calculate the difference between them, and there will be an intersection every time the sign changes.
step=0.1
x= np.arange(-5,5, step=step)
f1 = x**2 - 4
f2 = -x**2 + 4
dif= f2-f1
dif_sign= dif/np.abs(dif) #just the sign of the function
dif_sign_dif= np.diff(dif_sign) #places where the sign changes
change_idxs= np.where(dif_sign_dif!=0)[0] #indexes where the sign changes
print -5+change_idxs*step
output:
[-2. 2.]
Since you are adding brownian motion, you'll get "false positives" once in while, though.
I want to create a simple animation of how bad the Forward Time Central Space (FTCS) solves the flux conservation equation for a Gaussian velocity distribution ("Physics... yeah!"). I have written a small animation based on this tutorial. I have attached the code below. I'm satisfied with it (given that I don't really know anything about matplotlib's animation package), but I cannot get the animation to be slow enough so that I can actually see something.
This boils down to me not understanding how to set the parameters in the animation.FuncAnimation in the last line of the code. Could anybody explain, help?
import math
import numpy as np
import scipy as sci
import matplotlib.pyplot as plt
from matplotlib import animation
#generate velocity distribution
sigma = 1.
xZero = 0.
N = 101
x = np.linspace(-10,10,N)
uZero = 1. / math.sqrt(2 * math.pi * (sigma**2)) * np.exp(-0.5*((x - xZero)/(2*sigma))**2)
v = 1
xStep = x[2]-x[1]
tStep = 0.1
alpha = v * tStep/xStep * 0.5
#include boundary conditions
u = np.hstack((0.,uZero,0.))
uNext = np.zeros(N + 2)
#solve with forward time central space and store each outer loop in data
#so it can be used in the animation
data = []
data.append(u[1:-1])
for n in range(0,100):
for i in range(1,N+1):
uNext[i] = -alpha * u[i+1] + u[i] + alpha*u[i-1]
u = uNext
data.append(u[1:-1])
data = np.array(data)
#launch up the animation
fig = plt.figure()
ax = plt.axes(xlim=(-10,10),ylim=(-1,1))
line, = ax.plot([],[],lw=2)
def init():
line.set_data([],[])
return line,
#get the data for animation from the data array
def animate(i):
y = data[i]
line.set_data(x,y)
return line,
#the actual animation
anim = animation.FuncAnimation(fig,animate,init_func=init,frames=200,interval=2000,blit=True)
plt.show()
Explore your data variable first. If i run your code, only data[0] and data[1] are different, from data[1] onwards all data (thus frames) are the same.
np.allclose(data[1], data[100])
True