download
raw
10.2 kB
import numpy as np
import matplotlib.pyplot as plt
def solver(I, w, dt, T):
"""
Solve u'' + w**2*u = 0 for t in (0,T], u(0)=I and u'(0)=0,
by a central finite difference method with time step dt.
"""
dt = float(dt)
Nt = int(round(T/dt))
u = np.zeros(Nt+1)
t = np.linspace(0, Nt*dt, Nt+1)
u[0] = I
u[1] = u[0] - 0.5*dt**2*w**2*u[0]
for n in range(1, Nt):
u[n+1] = 2*u[n] - u[n-1] - dt**2*w**2*u[n]
return u, t
def u_exact(t, I, w):
return I*np.cos(w*t)
def visualize(u, t, I, w):
plt.plot(t, u, 'r--o')
t_fine = np.linspace(0, t[-1], 1001) # very fine mesh for u_e
u_e = u_exact(t_fine, I, w)
plt.hold('on')
plt.plot(t_fine, u_e, 'b-')
plt.legend(['numerical', 'exact'], loc='upper left')
plt.xlabel('t')
plt.ylabel('u')
dt = t[1] - t[0]
plt.title('dt=%g' % dt)
umin = 1.2*u.min(); umax = -umin
plt.axis([t[0], t[-1], umin, umax])
plt.savefig('tmp1.png'); plt.savefig('tmp1.pdf')
def test_three_steps():
from math import pi
I = 1; w = 2*pi; dt = 0.1; T = 1
u_by_hand = np.array([1.000000000000000,
0.802607911978213,
0.288358920740053])
u, t = solver(I, w, dt, T)
diff = np.abs(u_by_hand - u[:3]).max()
tol = 1E-14
assert diff < tol
def convergence_rates(m, solver_function, num_periods=8):
"""
Return m-1 empirical estimates of the convergence rate
based on m simulations, where the time step is halved
for each simulation.
solver_function(I, w, dt, T) solves each problem, where T
is based on simulation for num_periods periods.
"""
from math import pi
w = 0.35; I = 0.3 # just chosen values
P = 2*pi/w # period
dt = P/30 # 30 time step per period 2*pi/w
T = P*num_periods
dt_values = []
E_values = []
for i in range(m):
u, t = solver_function(I, w, dt, T)
u_e = u_exact(t, I, w)
E = np.sqrt(dt*np.sum((u_e-u)**2))
dt_values.append(dt)
E_values.append(E)
dt = dt/2
r = [np.log(E_values[i-1]/E_values[i])/
np.log(dt_values[i-1]/dt_values[i])
for i in range(1, m, 1)]
return r
def test_convergence_rates():
r = convergence_rates(m=5, solver_function=solver, num_periods=8)
# Accept rate to 1 decimal place
tol = 0.1
assert abs(r[-1] - 2.0) < tol
def main(solver_function=solver):
import argparse
from math import pi
parser = argparse.ArgumentParser()
parser.add_argument('--I', type=float, default=1.0)
parser.add_argument('--w', type=float, default=2*pi)
parser.add_argument('--dt', type=float, default=0.05)
parser.add_argument('--num_periods', type=int, default=5)
parser.add_argument('--savefig', action='store_true')
# Hack to allow --SCITOOLS options (read when importing scitools.std)
parser.add_argument('--SCITOOLS_easyviz_backend', default='matplotlib')
a = parser.parse_args()
I, w, dt, num_periods, savefig = \
a.I, a.w, a.dt, a.num_periods, a.savefig
P = 2*pi/w # one period
T = P*num_periods
u, t = solver_function(I, w, dt, T)
if num_periods <= 10:
visualize(u, t, I, w)
else:
visualize_front(u, t, I, w, savefig)
#visualize_front_ascii(u, t, I, w)
#plot_empirical_freq_and_amplitude(u, t, I, w)
plt.show()
def plot_empirical_freq_and_amplitude(u, t, I, w):
"""
Find the empirical angular frequency and amplitude of
simulations in u and t. u and t can be arrays or (in
the case of multiple simulations) multiple arrays.
One plot is made for the amplitude and one for the angular
frequency (just called frequency in the legends).
"""
from vib_empirical_analysis import minmax, periods, amplitudes
from math import pi
if not isinstance(u, (list,tuple)):
u = [u]
t = [t]
legends1 = []
legends2 = []
for i in range(len(u)):
minima, maxima = minmax(t[i], u[i])
p = periods(maxima)
a = amplitudes(minima, maxima)
plt.figure(1)
plt.plot(range(len(p)), 2*pi/p)
legends1.append('frequency, case%d' % (i+1))
plt.hold('on')
plt.figure(2)
plt.plot(range(len(a)), a)
plt.hold('on')
legends2.append('amplitude, case%d' % (i+1))
plt.figure(1)
plt.plot(range(len(p)), [w]*len(p), 'k--')
legends1.append('exact frequency')
plt.legend(legends1, loc='lower left')
plt.axis([0, len(a)-1, 0.8*w, 1.2*w])
plt.savefig('tmp1.png'); plt.savefig('tmp1.pdf')
plt.figure(2)
plt.plot(range(len(a)), [I]*len(a), 'k--')
legends2.append('exact amplitude')
plt.legend(legends2, loc='lower left')
plt.axis([0, len(a)-1, 0.8*I, 1.2*I])
plt.savefig('tmp2.png'); plt.savefig('tmp2.pdf')
plt.show()
def visualize_front(u, t, I, w, savefig=False, skip_frames=1):
"""
Visualize u and the exact solution vs t, using a
moving plot window and continuous drawing of the
curves as they evolve in time.
Makes it easy to plot very long time series.
Plots are saved to files if savefig is True.
Only each skip_frames-th plot is saved (e.g., if
skip_frame=10, only each 10th plot is saved to file;
this is convenient if plot files corresponding to
different time steps are to be compared).
"""
import scitools.std as st
from scitools.MovingPlotWindow import MovingPlotWindow
from math import pi
# Remove all old plot files tmp_*.png
import glob, os
for filename in glob.glob('tmp_*.png'):
os.remove(filename)
P = 2*pi/w # one period
umin = 1.2*u.min(); umax = -umin
dt = t[1] - t[0]
plot_manager = MovingPlotWindow(
window_width=8*P,
dt=dt,
yaxis=[umin, umax],
mode='continuous drawing')
frame_counter = 0
for n in range(1,len(u)):
if plot_manager.plot(n):
s = plot_manager.first_index_in_plot
st.plot(t[s:n+1], u[s:n+1], 'r-1',
t[s:n+1], I*cos(w*t)[s:n+1], 'b-1',
title='t=%6.3f' % t[n],
axis=plot_manager.axis(),
show=not savefig) # drop window if savefig
if savefig and n % skip_frames == 0:
filename = 'tmp_%04d.png' % frame_counter
st.savefig(filename)
print 'making plot file', filename, 'at t=%g' % t[n]
frame_counter += 1
plot_manager.update(n)
def visualize_front_ascii(u, t, I, w, fps=10):
"""
Plot u and the exact solution vs t line by line in a
terminal window (only using ascii characters).
Makes it easy to plot very long time series.
"""
from scitools.avplotter import Plotter
import time
from math import pi
P = 2*pi/w
umin = 1.2*u.min(); umax = -umin
p = Plotter(ymin=umin, ymax=umax, width=60, symbols='+o')
for n in range(len(u)):
print p.plot(t[n], u[n], I*cos(w*t[n])), \
'%.1f' % (t[n]/P)
time.sleep(1/float(fps))
def bokeh_plot(u, t, legends, I, w, t_range, filename):
"""
Make plots for u vs t using the Bokeh library.
u and t are lists (several experiments can be compared).
legens contain legend strings for the various u,t pairs.
"""
if not isinstance(u, (list,tuple)):
u = [u] # wrap in list
if not isinstance(t, (list,tuple)):
t = [t] # wrap in list
if not isinstance(legends, (list,tuple)):
legends = [legends] # wrap in list
import bokeh.plotting as plt
plt.output_file(filename, mode='cdn', title='Comparison')
# Assume that all t arrays have the same range
t_fine = np.linspace(0, t[0][-1], 1001) # fine mesh for u_e
tools = 'pan,wheel_zoom,box_zoom,reset,'\
'save,box_select,lasso_select'
u_range = [-1.2*I, 1.2*I]
font_size = '8pt'
p = [] # list of plot objects
# Make the first figure
p_ = plt.figure(
width=300, plot_height=250, title=legends[0],
x_axis_label='t', y_axis_label='u',
x_range=t_range, y_range=u_range, tools=tools,
title_text_font_size=font_size)
p_.xaxis.axis_label_text_font_size=font_size
p_.yaxis.axis_label_text_font_size=font_size
p_.line(t[0], u[0], line_color='blue')
# Add exact solution
u_e = u_exact(t_fine, I, w)
p_.line(t_fine, u_e, line_color='red', line_dash='4 4')
p.append(p_)
# Make the rest of the figures and attach their axes to
# the first figure's axes
for i in range(1, len(t)):
p_ = plt.figure(
width=300, plot_height=250, title=legends[i],
x_axis_label='t', y_axis_label='u',
x_range=p[0].x_range, y_range=p[0].y_range, tools=tools,
title_text_font_size=font_size)
p_.xaxis.axis_label_text_font_size = font_size
p_.yaxis.axis_label_text_font_size = font_size
p_.line(t[i], u[i], line_color='blue')
p_.line(t_fine, u_e, line_color='red', line_dash='4 4')
p.append(p_)
# Arrange all plots in a grid with 3 plots per row
grid = [[]]
for i, p_ in enumerate(p):
grid[-1].append(p_)
if (i+1) % 3 == 0:
# New row
grid.append([])
plot = plt.gridplot(grid, toolbar_location='left')
plt.save(plot)
plt.show(plot)
def demo_bokeh():
"""Solve a scaled ODE u'' + u = 0."""
from math import pi
w = 1.0 # Scaled problem (frequency)
P = 2*np.pi/w # Period
num_steps_per_period = [5, 10, 20, 40, 80]
T = 40*P # Simulation time: 40 periods
u = [] # List of numerical solutions
t = [] # List of corresponding meshes
legends = []
for n in num_steps_per_period:
dt = P/n
u_, t_ = solver(I=1, w=w, dt=dt, T=T)
u.append(u_)
t.append(t_)
legends.append('# time steps per period: %d' % n)
bokeh_plot(u, t, legends, I=1, w=w, t_range=[0, 4*P],
filename='tmp.html')
if __name__ == '__main__':
#main()
demo_bokeh()
raw_input()

Xet Storage Details

Size:
10.2 kB
·
Xet hash:
408ad015ce7ab197a483fe623369f1fbaed9eea597c63f7495a3904e808a608e

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.