i want to plot a 1D Heat Diffusion with implicit PDE. here is the problem Heat Diffusion. here's the PDE equation.
my code is fine but it creates a new figure for each iteration.
import numpy as np
import matplotlib.pyplot as plt
L = 0.05 #length
n = 5 #number of segment
T0 = 20 #initial temperature
T1s = 100 #boundary condition in segment 0
T2s = 25 #boundary condition in segment 5
dx = L/n #delta x
alpha = 0.000014129 #heat coeff
t_final = 9
dt = 3
x = np.linspace(0, L, n+1)
T = np.ones(n+1)*T0 #array of Temperature initial condition
dTdt = np.empty(n+1) #dTdt delta T /delta t
t = np.arange(0, t_final, dt)
for j in range(1,len(t)+1):
for i in range(1, n):
dTdt[i] = alpha*(T[i+1]-2*T[i]+T[i-1])/dx**2 #PDE iterative function for segment i
dTdt[0] = alpha*(T[1]-2*T[0]+T1s)/dx**2
dTdt[n-1] = alpha*(T[n-2]-2*T[n-1]+T2s)/dx**2
T = T + dTdt*dt
T[0]=T1s
T[5]=T2s
plt.figure(1)
plt.plot(x,T)
plt.axis([-0.01, L+0.01, 0, 120])
plt.xlabel('Distance (m)')
plt.ylabel('Temperature (C)')
plt.show()
i've added plt.ion() and plt.pause() but it didnt work. i also tried similar PDE plotting. but didnt work for me either. also is it possible to give each plot a different color and label in the figure?
any suggestion would help !
You can create the figure instance before the loop and add the figures + labels in the loop as follows:
import numpy as np
import matplotlib.pyplot as plt
L = 0.05 #length
n = 5 #number of segment
T0 = 20 #initial temperature
T1s = 100 #boundary condition in segment 0
T2s = 25 #boundary condition in segment 5
dx = L/n #delta x
alpha = 0.000014129 #heat coeff
t_final = 9
dt = 3
x = np.linspace(0, L, n+1)
T = np.ones(n+1)*T0 #array of Temperature initial condition
dTdt = np.empty(n+1) #dTdt delta T /delta t
t = np.arange(0, t_final, dt)
fig, ax = plt.subplots(figsize = (8,6))
for j in range(1,len(t)+1):
for i in range(1, n):
dTdt[i] = alpha*(T[i+1]-2*T[i]+T[i-1])/dx**2 #PDE iterative function for segment i
dTdt[0] = alpha*(T[1]-2*T[0]+T1s)/dx**2
dTdt[n-1] = alpha*(T[n-2]-2*T[n-1]+T2s)/dx**2
T = T + dTdt*dt
T[0]=T1s
T[5]=T2s
ax.plot(x,T,label = 'Iteration' + ' ' + str(j))
ax.legend()
ax.axis([-0.01, L+0.01, 0, 120])
ax.set_xlabel('Distance (m)')
ax.set_ylabel('Temperature (C)');
Related
Trying to plot two separate animations, i.e. in different windows as separate figures. Running this code for me rightly creates two windows, but animates the data on the second figure at the same time. Closing figure 1 results in only the intended data for figure 2 being animated, removing the overlap from the data intended for figure 1. Closing figure 2 results in only the intended data for figure 1 being animated, removing the overlap from the data intended for figure 2.
Minimum code below:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
dx, dv, N, Nb, decp = 2, 1.5, 100, 12, int(1)
Pd = np.zeros([N + 1, 2 * Nb])
Vd = np.zeros([N + 1, 2 * Nb])
Pd[:, 1] = 4
Vd[:, 3] = 2
t = np.zeros(N + 1)
t[0] = 0
for i in range(0, N):
t[i + 1] = (i + 1) * 0.1
Px = []
for i in range(0, (2 * Nb)):
PX = dx * (-Nb + i) / 4
Px.append(PX)
lblx = []
for i in range(0, int((Nb / 2) + 1)):
if i == (Nb / 4):
LBL = r"$\mu_x$"
lblx.append(LBL)
else:
LBL = r"${0}\sigma_x$".format(-(Nb / 4) + i)
lblx.append(LBL)
Pv = []
for i in range(0, (2 * Nb)):
PV = dv * (-Nb + i) / 4
Pv.append(PV)
lblv = []
for i in range(0, int((Nb / 2) + 1)):
if i == (Nb / 4):
LBL = r"$\mu_v$"
lblv.append(LBL)
else:
LBL = r"${0}\sigma_v$".format(-(Nb / 4) + i)
lblv.append(LBL)
fig1 = plt.figure(figsize=(8,6))
def animatex(i):
fig1.clear()
plt.bar(Px, Pd[i, :], width = dx / 4, align = 'edge', color = 'b', \
label = 't = {} seconds'.format(round(t[i], decp)))
s_ticks = np.arange(-3 * dx, (3 + 1) * dx, dx)
plt.xticks(s_ticks, lblx)
plt.ylim(0, np.max(Pd))
plt.xlim(-3 * dx, 3 * dx)
plt.legend()
plt.draw()
anix = FuncAnimation(fig1, animatex, repeat = True, interval = 200, frames = N + 1)
fig2 = plt.figure(figsize=(8,6))
def animatev(i):
fig2.clear()
plt.bar(Pv, Vd[i, :], width = dv / 4, align = 'edge', color = 'b', \
label = 't = {} seconds'.format(round(t[i], decp)))
s_ticks = np.arange(-3 * dv, (3 + 1) * dv, dv)
plt.xticks(s_ticks, lblv)
plt.ylim(0, np.max(Vd))
plt.xlim(-3 * dv, 3 * dv)
plt.legend()
plt.draw()
aniv = FuncAnimation(fig2, animatev, repeat = True, interval = 200, frames = N + 1)
plt.show()
As is probably clear, they are two bar plots, with different vertical and horizontal dimensions. I've seen some solutions for these kinds of problems where the data shares an axis through a shared variable, but here they are not (as can be seen).
For this minimum code, the solution involves having the two bars, one in Pd and the other in Vd, being on their respective intended figures, not both on the second figure.
Let me know if there are any issues with the information here i.e. minimal code requirements not met, more information etc. and I will update.
Ignore any wayward writing style, it is not relevant.
Simplifying your code:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
dx, dv, N, Nb, decp = 2, 1.5, 10, 12, int(1)
Px = np.arange(Nb)
Pd = np.random.randn(N, Nb)
Vd = np.random.randn(N, Nb)
fig1, ax1 = plt.subplots(figsize=(8, 6))
def animatex(i):
ax1.clear()
ax1.bar(Px, Pd[i, :], width=dx / 4, align='edge', color='b')
anix = FuncAnimation(fig1, animatex, repeat=True, interval=200, frames=N)
fig2, ax2 = plt.subplots(figsize=(8, 6))
def animatev(i):
ax2.clear()
ax2.bar(Px, Vd[i, :], width = dv / 4, align='edge', color='b')
aniv = FuncAnimation(fig2, animatev, repeat=True, interval=200, frames=N)
plt.show()
works fine for me. You can add the esthetic/data details back in...
import numpy as np
import matplotlib.pyplot as plot
from IPython.display import HTML
from matplotlib import animation
#setup fig with axis
fig, ax = plot.subplots(figsize=(8,8))
#set axis limits
ax.set(xlim=(-2,2), ylim=(0,600), xlabel="position, metres", ylabel="height, metres", title="falling apple")
#initial params
T = 100.
m = 3
g = 9.81
v0x = 10
H = 553.
#setting calc interval
dt = 0.1
N = int(T/dt)
#arrays
v = np.zeros((N+1 , 2))
x = np.zeros((N+1 , 2))
f = np.zeros((N+1 , 2))
#array start [x ,y] format
v[0] = np.array([0. , H])
x[0] = np.array([v0x , 0.])
# the only force is gravity
f[:] = np.array([0., m * g])
#running the dynamics sim
for n in range(N):
v[n+1] = v[n] + ((f[n]/m) * dt)
x[n+1] = x[n] + (v[n+1] * dt)
#scatter plot
scat_plt = ax.scatter(x[0,0], x[0,1], marker='o', c='#1f77b4', s=200)
## animating
def animate(i):
scat_plt.set_offsets(x[i])
ani = animation.FuncAnimation(fig, func=animate, frames=N)
ani.save('ball.html', writer=animation.HTMLWriter(fps= 1//dt))
plot.close()
ani.save('ball.mp4', fps= 1//dt)
HTML('ball.html')
The out put is just a circle going straight up where as this is supposed to simulate a ball being thrown horizontally off a tower
It would be highly appreciated if someone could suggest any changes to be made to the logic/physics or the code.
Thank you!!
I think you mixed x with v at some point. Also the force should be negative in y. I tried this and it seems to work:
import numpy as np
import matplotlib.pyplot as plot
from IPython.display import HTML
from matplotlib import animation
#setup fig with axis
fig, ax = plot.subplots(figsize=(8,8))
#set axis limits
ax.set(xlim=(-200,200), ylim=(0,600), xlabel="position, metres", ylabel="height, metres", title="falling apple")
#initial params
T = 100.
m = 3
g = 9.81
v0x = 10
H = 553.
#setting calc interval
dt = 0.1
N = int(T/dt)
#arrays
v = np.zeros((N+1 , 2))
x = np.zeros((N+1 , 2))
f = np.zeros((N+1 , 2))
#array start [x ,y] format
x[0] = np.array([0. , H])
v[0] = np.array([v0x , 0.])
# the only force is gravity
f[:] = np.array([0., -m * g])
#running the dynamics sim
for n in range(N):
v[n+1] = v[n] + ((f[n]/m) * dt)
x[n+1] = x[n] + (v[n+1] * dt)
#scatter plot
scat_plt = ax.scatter(x[0,0], x[0,1], marker='o', c='#1f77b4', s=200)
## animating
def animate(i):
scat_plt.set_offsets(x[i])
ani = animation.FuncAnimation(fig, func=animate, frames=N)
ani.save('ball.html', writer=animation.HTMLWriter(fps= 1//dt))
plot.close()
ani.save('ball.gif', fps= 1//dt)
HTML('ball.html')
I'm trying to plot a diagram of Coulomb damping mass-spring model, see image bellow. mi*N is the damping friction force.
Becuase the damping force switches direction depending on the direction of speed vector, we have 2 different equations of motion x(t), I named them x_a(t) and x_b(t). If you look closely on the diagram above, the use of x(t) depends on the period, for the first period which is from 0 to pi/omega_n x_a(t) is used, for the second period which is from pi/omega_n to 2*pi/omega_n we use x_b(t) and so on.
I was thinking to use a piece of code which would go something like
t = i * (pi/omega_n)
for i = 1, 3, 5, 7,...
x_a(t)
for i = 2, 4, 6, 8,...
x_b(t)
But I have no clue how to implement this.
I managed to define the x_a(t) part of the code and plot it with the undampled model, see bellow.
import numpy as np
import matplotlib.pyplot as plt
#constants
k = 2 #(N/m), spring coef
m = 0.04 #(kg), mass
x0 = -0.1 #(m), preload
mi = 0.3 #(), dry dynamic friction coef. ABS-ABS
N = 0.3 #(N), normal contact force
f_tr = mi * N / k #friction force/pring coef - equivalent distance
omega_0 = np.sqrt(k/m)
#time
t = np.linspace(0,5,100)
#undamped model
x_undamp = x0*np.cos(omega_0*t)
dx_undamp = -omega_0*x0*np.sin(omega_0*t)
#damped model
x_damp = (x0+f_tr)*np.cos(omega_0*t)-f_tr
dx_damp = -omega_0*(x0+f_tr)*np.sin(omega_0*t)
#time to x=0
t0 = np.arccos(f_tr/(x0+f_tr))/omega_0
print t0
#plotting
fig, (ax1, ax2) = plt.subplots(1, 2)
fig.suptitle('position on left, velocity on right')
ax1.plot(t, x_undamp,'r', label='x_undamp')
ax1.plot(t, x_damp, 'b', label = 'x_damp')
ax2.plot(t, dx_undamp, 'r', label = 'dx_undamp')
ax2.plot(t, dx_damp, 'b', label = 'dx_damp')
#grids, titles, legends, axis labels
ax1.grid()
ax2.grid()
ax1.set_title('Position vs time')
ax2.set_title('Velocity vs time')
ax1.legend()
ax2.legend()
ax1.set_xlabel('t(s)')
ax1.set_ylabel('x(m)')
ax2.set_xlabel('t(s)')
ax2.set_ylabel('dx(m/s)')
plt.show()
I'm gonna put plot a diagram of Coulomb damping mass-spring model solution here till someone comes with a better one:
from scipy.integrate import odeint
import numpy as np
import matplotlib.pyplot as plt
m = 0.2
k = 2.0
c = 0.1
mus = 0.3
muk = 0.2
g = 9.8
vf = 0.01
v0 = 0.0
t1 = 10
sign = lambda x: np.tanh(100*x)
def Xi(t):
if t < 1 :
return 0
else:
return 1
vXi = np.vectorize(Xi)
def eq(X, t, Xi):
Ff = k * (Xi(t) - X[0])
if np.abs(X[1]) < vf and np.abs(Ff) < mus * m * g :
Ff = k * (Xi(t) - X[0])
else:
Ff = sign(X[1]) * muk * m * g
d2x = (k * (Xi(t) - X[0]) - Ff) / m
return [X[1], d2x]
t = np.linspace(0, t1, 1000)
X0 = [v0, 0]
sol = odeint(func = eq, y0 = X0, t = t, args = (Xi, ), mxstep = 50000, atol = 1e-5)
plt.plot(t, sol[:, 0], 'r-', label = 'Output (x(t))')
plt.plot(t, vXi(t), 'b-', label = 'Input (xi(t))')
plt.ylabel('values')
plt.xlabel('time')
plt.legend(loc='best')
plt.show()
I would like to plot a graph like the one in the following picture:
I wrote the following code that plots a wave graph for each time step.
import matplotlib.pyplot as plt
import numpy as np
def u_0(x):
a = 1.0/np.cosh(2.0*(x+8.0))
b = 1.0/np.cosh((x+1.0))
return 8.0*a*a+2.0*b*b
#spatial grid
N = 100
x = np.linspace(-10,10,N)
#time
Nt = 100
tlist = np.linspace(0.0,2.0,Nt)
#velocity
c = 5.0
count = 0
for t in tlist:
u = u_0(x-c*t)
plt.figure()
plt.plot(x,u)
plt.savefig(str(count))
count = count+1
plt.close()
How can I join these pictures together and get a graph like the one in the picture?
Is there a standard way to do this?
Don't close plot and draw all on one image.
Every plot would need some offset for Y values
u += count # offset
Code
import matplotlib.pyplot as plt
import numpy as np
def u_0(x):
a = 1.0/np.cosh(2.0*(x+8.0))
b = 1.0/np.cosh((x+1.0))
return 8.0*a*a + 2.0*b*b
# spatial grid
N = 100
x = np.linspace(-10, 10, N)
# time
Nt = 100
tlist = np.linspace(0.0, 2.0, Nt)
#velocity
c = 5.0
count = 0
for t in tlist:
u = u_0(x-c*t)
u += count # offset
plt.plot(x, u)
count += 1
plt.savefig("result.png")
Image:
EDIT: Something similar in 3D
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D # need for `projection=`
import numpy as np
def u_0(x):
a = 1.0/np.cosh(2.0*(x+8.0))
b = 1.0/np.cosh((x+1.0))
return 8.0*a*a + 2.0*b*b
#velocity
c = 5.0
#spatial grid
N = 30
x = np.linspace(-10, 10, N)
t = np.linspace(0.0, 2.0, N)
X, T = np.meshgrid(x, t)
Y = u_0(X-c*T)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_wireframe(X, T, Y)
plt.show()
plt.savefig('result.png')
My code has been modified according to many great suggestions from people in this forum. However, I still have some questions about the code.
My code is:
from pylab import *
from numpy import *
N = 100 #lattice points per axis
dt = 1 #time step
dx = 1 #lattice spacing
t = arange(0, 1000000*dt, dt) #time
a = 1 #cofficient
epsilon = 100 #cofficient
M = 1.0 #cofficient
every = 100 #dump an image every
phi_0 = 0.5 #initial mean value of the order parameter
noise = 0.1 #initial amplitude of thermal fluctuations in the order parameter
th = phi_0*ones((N, N)) + noise*(rand(N, N) - 0.5) #initial condition
x, y = meshgrid(fftfreq(int(th.shape[0]), dx), fftfreq(int(th.shape[1]), dx))
k2 = (x*x + y*y) #k is a victor in the Fourier space, k2=x^2+y^2
g = lambda th, a: 4*a*th*(1-th)*(1-2*th) #function g
def update(th, dt, a, k2):
return ifft2((fft2(th)-dt*M*k2*fft2(g(th,a)))/(1+2*epsilon*M*dt*k2**2))
for i in range(size(t)):
print t[i]
if mod(i, every)==0:
imshow(abs(th), vmin=0.0, vmax=1.0)
colorbar()
show()
#savefig('t'+str(i/every).zfill(3)+'.png', dpi=100)
clf()
th=update(th, dt, a, k2)
When I run it, I have to close the figures one by one to see the changes. But I want to demonstrate the changes of the images in one figure. Any good ideas?
Use the "animation" feature of matplotlib, like in
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def update_line(num, data, line):
line.set_data(data[...,:num])
return line,
fig1 = plt.figure()
data = np.random.rand(2, 25)
l, = plt.plot([], [], 'r-')
plt.xlim(0, 1)
plt.ylim(0, 1)
plt.xlabel('x')
plt.title('test')
line_ani = animation.FuncAnimation(fig1, update_line, 25, fargs=(data, l),
interval=50, blit=True)
plt.show()
Tutorial at :
http://matplotlib.org/1.3.1/examples/animation/index.html