def comparison_plot(f, u, Omega, filename='tmp.pdf', plot_title='', ymin=None, ymax=None, u_legend='approximation'): """Compare f(x) and u(x) for x in Omega in a plot.""" x = sm.Symbol('x') print 'f:', f f = sm.lambdify([x], f, modules="numpy") u = sm.lambdify([x], u, modules="numpy") if len(Omega) != 2: raise ValueError('Omega=%s must be an interval (2-list)' % str(Omega)) # When doing symbolics, Omega can easily contain symbolic expressions, # assume .evalf() will work in that case to obtain numerical # expressions, which then must be converted to float before calling # linspace below if not isinstance(Omega[0], (int,float)): Omega[0] = float(Omega[0].evalf()) if not isinstance(Omega[1], (int,float)): Omega[1] = float(Omega[1].evalf()) resolution = 401 # no of points in plot xcoor = linspace(Omega[0], Omega[1], resolution) # Vectorized functions expressions does not work with # lambdify'ed functions without the modules="numpy" exact = f(xcoor) approx = u(xcoor) plot(xcoor, approx, '-') hold('on') plot(xcoor, exact, '-') legend([u_legend, 'exact']) title(plot_title) xlabel('x') if ymin is not None and ymax is not None: axis([xcoor[0], xcoor[-1], ymin, ymax]) savefig(filename)
def non_physical_behavior(I, a, T, dt, theta): """ Given lists/arrays a and dt, and numbers I, dt, and theta, make a two-dimensional contour line B=0.5, where B=1>0.5 means oscillatory (unstable) solution, and B=0<0.5 means monotone solution of u'=-au. """ a = np.asarray(a) dt = np.asarray(dt) # must be arrays B = np.zeros((len(a), len(dt))) # results for i in range(len(a)): for j in range(len(dt)): u, t = solver(I, a[i], T, dt[j], theta) # Does u have the right monotone decay properties? correct_qualitative_behavior = True for n in range(1, len(u)): if u[n] > u[n - 1]: # Not decaying? correct_qualitative_behavior = False break # Jump out of loop B[i, j] = float(correct_qualitative_behavior) a_, dt_ = st.ndgrid(a, dt) # make mesh of a and dt values st.contour(a_, dt_, B, 1) st.grid('on') st.title('theta=%g' % theta) st.xlabel('a') st.ylabel('dt') st.savefig('osc_region_theta_%s.png' % theta) st.savefig('osc_region_theta_%s.eps' % theta)
def plot(self, include_exact=True, plt=None): """ Add solver.u curve to scitools plotting object plt, and include the exact solution if include_exact is True. This plot function can be called several times (if the solver object has computed new solutions). """ if plt is None: import scitools.std as plt plt.plot(self.solver.t, self.solver.u, '--o') plt.hold('on') theta = self.solver.get('theta') theta2name = {0: 'FE', 1: 'BE', 0.5: 'CN'} name = theta2name.get(theta, '') legends = ['numerical %s' % name] if include_exact: t_e = np.linspace(0, self.problem.get('T'), 1001) u_e = self.problem.exact_solution(t_e) plt.plot(t_e, u_e, 'b-') legends.append('exact') plt.legend(legends) plt.xlabel('t') plt.ylabel('u') dt = self.solver.get('dt') plt.title('theta=%g, dt=%g' % (theta, dt)) plt.savefig('%s_%g.png' % (name, dt)) return plt
def demo(): """ Demonstrate difference between Euler-Cromer and the scheme for the corresponding 2nd-order ODE. """ I = 1.2 V = 0.2 m = 4 b = 0.2 s = lambda u: 2 * u F = lambda t: 0 w = np.sqrt(2.0 / 4) # approx freq dt = 0.9 * 2 / w # longest possible time step w = 0.5 P = 2 * pi / w T = 4 * P from vib import solver as solver2 import scitools.std as plt for k in range(4): u2, t2 = solver2(I, V, m, b, s, F, dt, T, "quadratic") u, v, t = solver(I, V, m, b, s, F, dt, T, "quadratic") plt.figure() plt.plot(t, u, "r-", t2, u2, "b-") plt.legend(["Euler-Cromer", "centered scheme"]) plt.title("dt=%.3g" % dt) raw_input() plt.savefig("tmp_%d" % k + ".png") plt.savefig("tmp_%d" % k + ".pdf") dt /= 2
def comparison_plot(u, Omega, u_e=None, filename='tmp.eps', plot_title='', ymin=None, ymax=None): x = sp.Symbol('x') u = sp.lambdify([x], u, modules="numpy") if len(Omega) != 2: raise ValueError('Omega=%s must be an interval (2-list)' % str(Omega)) # When doing symbolics, Omega can easily contain symbolic expressions, # assume .evalf() will work in that case to obtain numerical # expressions, which then must be converted to float before calling # linspace below if not isinstance(Omega[0], (int,float)): Omega[0] = float(Omega[0].evalf()) if not isinstance(Omega[1], (int,float)): Omega[1] = float(Omega[1].evalf()) resolution = 401 # no of points in plot xcoor = linspace(Omega[0], Omega[1], resolution) # Vectorized functions expressions does not work with # lambdify'ed functions without the modules="numpy" approx = u(xcoor) plot(xcoor, approx) legends = ['approximation'] if u_e is not None: exact = u_e(xcoor) hold('on') plot(xcoor, exact) legends = ['exact'] legend(legends) title(plot_title) xlabel('x') if ymin is not None and ymax is not None: axis([xcoor[0], xcoor[-1], ymin, ymax]) savefig(filename)
def run_solvers_and_plot(solvers, rhs, T, dt, title=''): Nt = int(round(T / float(dt))) t_mesh = np.linspace(0, T, Nt + 1) t_fine = np.linspace(0, T, 8 * Nt + 1) # used for very accurate solution legends = [] solver_exact = odespy.RK4(rhs) for solver in solvers: solver.set_initial_condition([rhs.I, 0]) u, t = solver.solve(t_mesh) solver_name = 'CrankNicolson' if solver.__class__.__name__ == \ 'MidpointImplicit' else solver.__class__.__name__ if len(t_mesh) <= 50: plt.plot(t, u[:, 0]) # markers by default else: plt.plot(t, u[:, 0], '-2') # no markers plt.hold('on') legends.append(solver_name) # Compare with RK4 on a much finer mesh solver_exact.set_initial_condition([rhs.I, 0]) u_e, t_e = solver_exact.solve(t_fine) plt.plot(t_e, u_e[:, 0], '-') # avoid markers by spec. line type legends.append('exact (RK4, dt=%g)' % (t_fine[1] - t_fine[0])) plt.legend(legends, loc='upper right') plt.xlabel('t') plt.ylabel('u') plt.title(title) plotfilestem = '_'.join(legends) plt.savefig('tmp_%s.png' % plotfilestem) plt.savefig('tmp_%s.pdf' % plotfilestem)
def demo(): """ Demonstrate difference between Euler-Cromer and the scheme for the corresponding 2nd-order ODE. """ I = 1.2 V = 0.2 m = 4 b = 0.2 s = lambda u: 2 * u F = lambda t: 0 w = np.sqrt(2. / 4) # approx freq dt = 0.9 * 2 / w # longest possible time step w = 0.5 P = 2 * pi / w T = 4 * P from vib import solver as solver2 import scitools.std as plt for k in range(4): u2, t2 = solver2(I, V, m, b, s, F, dt, T, 'quadratic') u, v, t = solver(I, V, m, b, s, F, dt, T, 'quadratic') plt.figure() plt.plot(t, u, 'r-', t2, u2, 'b-') plt.legend(['Euler-Cromer', 'centered scheme']) plt.title('dt=%.3g' % dt) raw_input() plt.savefig('tmp_%d' % k + '.png') plt.savefig('tmp_%d' % k + '.pdf') dt /= 2
def plot(self, include_exact=True, plt=None): """ Add solver.u curve to the plotting object plt, and include the exact solution if include_exact is True. This plot function can be called several times (if the solver object has computed new solutions). """ if plt is None: import scitools.std as plt # can use matplotlib as well plt.plot(self.solver.t, self.solver.u, '--o') plt.hold('on') theta2name = {0: 'FE', 1: 'BE', 0.5: 'CN'} name = theta2name.get(self.solver.theta, '') legends = ['numerical %s' % name] if include_exact: t_e = linspace(0, self.problem.T, 1001) u_e = self.problem.exact_solution(t_e) plt.plot(t_e, u_e, 'b-') legends.append('exact') plt.legend(legends) plt.xlabel('t') plt.ylabel('u') plt.title('theta=%g, dt=%g' % (self.solver.theta, self.solver.dt)) plt.savefig('%s_%g.png' % (name, self.solver.dt)) return plt
def run_solvers_and_plot(solvers, rhs, T, dt, title=''): Nt = int(round(T/float(dt))) t_mesh = np.linspace(0, T, Nt+1) t_fine = np.linspace(0, T, 8*Nt+1) # used for very accurate solution legends = [] solver_exact = odespy.RK4(rhs) for solver in solvers: solver.set_initial_condition([rhs.I, 0]) u, t = solver.solve(t_mesh) solver_name = 'CrankNicolson' if solver.__class__.__name__ == \ 'MidpointImplicit' else solver.__class__.__name__ if len(t_mesh) <= 50: plt.plot(t, u[:,0]) # markers by default else: plt.plot(t, u[:,0], '-2') # no markers plt.hold('on') legends.append(solver_name) # Compare with RK4 on a much finer mesh solver_exact.set_initial_condition([rhs.I, 0]) u_e, t_e = solver_exact.solve(t_fine) plt.plot(t_e, u_e[:,0], '-') # avoid markers by spec. line type legends.append('exact (RK4, dt=%g)' % (t_fine[1]-t_fine[0])) plt.legend(legends, loc='upper right') plt.xlabel('t'); plt.ylabel('u') plt.title(title) plotfilestem = '_'.join(legends) plt.savefig('tmp_%s.png' % plotfilestem) plt.savefig('tmp_%s.pdf' % plotfilestem)
def non_physical_behavior(I, a, T, dt, theta): """ Given lists/arrays a and dt, and numbers I, dt, and theta, make a two-dimensional contour line B=0.5, where B=1>0.5 means oscillatory (unstable) solution, and B=0<0.5 means monotone solution of u'=-au. """ a = np.asarray(a); dt = np.asarray(dt) # must be arrays B = np.zeros((len(a), len(dt))) # results for i in range(len(a)): for j in range(len(dt)): u, t = solver(I, a[i], T, dt[j], theta) # Does u have the right monotone decay properties? correct_qualitative_behavior = True for n in range(1, len(u)): if u[n] > u[n-1]: # Not decaying? correct_qualitative_behavior = False break # Jump out of loop B[i,j] = float(correct_qualitative_behavior) a_, dt_ = st.ndgrid(a, dt) # make mesh of a and dt values st.contour(a_, dt_, B, 1) st.grid('on') st.title('theta=%g' % theta) st.xlabel('a'); st.ylabel('dt') st.savefig('osc_region_theta_%s.png' % theta) st.savefig('osc_region_theta_%s.pdf' % theta)
def visualize(list_of_curves, legends, title='', filename='tmp'): """Plot list of curves: (u, t).""" for u, t in list_of_curves: plt.plot(t, u) plt.hold('on') plt.legend(legends) plt.xlabel('t') plt.ylabel('u') plt.title(title) plt.savefig(filename + '.png') plt.savefig(filename + '.pdf') plt.show()
def visualize(u, t, title='', filename='tmp'): plt.plot(t, u, 'b-') plt.xlabel('t') plt.ylabel('u') dt = t[1] - t[0] plt.title('dt=%g' % dt) umin = 1.2*u.min(); umax = 1.2*u.max() plt.axis([t[0], t[-1], umin, umax]) plt.title(title) plt.savefig(filename + '.png') plt.savefig(filename + '.pdf') plt.show()
def visualize(u, t, title="", filename="tmp"): plt.plot(t, u, "b-") plt.xlabel("t") plt.ylabel("u") dt = t[1] - t[0] plt.title("dt=%g" % dt) umin = 1.2 * u.min() umax = 1.2 * u.max() plt.axis([t[0], t[-1], umin, umax]) plt.title(title) plt.savefig(filename + ".png") plt.savefig(filename + ".pdf") plt.show()
def run_solvers_and_plot(solvers, timesteps_per_period=20, num_periods=1, b=0): w = 2 * np.pi # frequency of undamped free oscillations P = 2 * np.pi / w # duration of one period dt = P / timesteps_per_period Nt = num_periods * timesteps_per_period T = Nt * dt t_mesh = np.linspace(0, T, Nt + 1) t_fine = np.linspace(0, T, 8 * Nt + 1) # used for very accurate solution legends = [] solver_exact = odespy.RK4(f) for solver in solvers: solver.set_initial_condition([solver.users_f.I, 0]) u, t = solver.solve(t_mesh) solver_name = 'CrankNicolson' if solver.__class__.__name__ == \ 'MidpointImplicit' else solver.__class__.__name__ # Make plots (plot last 10 periods????) if num_periods <= 80: plt.figure(1) if len(t_mesh) <= 50: plt.plot(t, u[:, 0]) # markers by default else: plt.plot(t, u[:, 0], '-2') # no markers plt.hold('on') legends.append(solver_name) # Compare with exact solution plotted on a very fine mesh #t_fine = np.linspace(0, T, 10001) #u_e = solver.users_f.exact(t_fine) # Compare with RK4 on a much finer mesh solver_exact.set_initial_condition([solver.users_f.I, 0]) u_e, t_e = solver_exact.solve(t_fine) if num_periods < 80: plt.figure(1) plt.plot(t_e, u_e[:, 0], '-') # avoid markers by spec. line type legends.append('exact (RK4)') plt.legend(legends, loc='upper left') plt.xlabel('t') plt.ylabel('u') plt.title('Time step: %g' % dt) plt.savefig('vib_%d_%d_u.png' % (timesteps_per_period, num_periods)) plt.savefig('vib_%d_%d_u.pdf' % (timesteps_per_period, num_periods)) plt.savefig('vib_%d_%d_u.eps' % (timesteps_per_period, num_periods))
def run_solvers_and_plot(solvers, timesteps_per_period=20, num_periods=1, b=0): w = 2*np.pi # frequency of undamped free oscillations P = 2*np.pi/w # duration of one period dt = P/timesteps_per_period Nt = num_periods*timesteps_per_period T = Nt*dt t_mesh = np.linspace(0, T, Nt+1) t_fine = np.linspace(0, T, 8*Nt+1) # used for very accurate solution legends = [] solver_exact = odespy.RK4(f) for solver in solvers: solver.set_initial_condition([solver.users_f.I, 0]) u, t = solver.solve(t_mesh) solver_name = 'CrankNicolson' if solver.__class__.__name__ == \ 'MidpointImplicit' else solver.__class__.__name__ # Make plots (plot last 10 periods????) if num_periods <= 80: plt.figure(1) if len(t_mesh) <= 50: plt.plot(t, u[:,0]) # markers by default else: plt.plot(t, u[:,0], '-2') # no markers plt.hold('on') legends.append(solver_name) # Compare with exact solution plotted on a very fine mesh #t_fine = np.linspace(0, T, 10001) #u_e = solver.users_f.exact(t_fine) # Compare with RK4 on a much finer mesh solver_exact.set_initial_condition([solver.users_f.I, 0]) u_e, t_e = solver_exact.solve(t_fine) if num_periods < 80: plt.figure(1) plt.plot(t_e, u_e[:,0], '-') # avoid markers by spec. line type legends.append('exact (RK4)') plt.legend(legends, loc='upper left') plt.xlabel('t'); plt.ylabel('u') plt.title('Time step: %g' % dt) plt.savefig('vib_%d_%d_u.png' % (timesteps_per_period, num_periods)) plt.savefig('vib_%d_%d_u.pdf' % (timesteps_per_period, num_periods)) plt.savefig('vib_%d_%d_u.eps' % (timesteps_per_period, num_periods))
def logistic(): problem = Logistic(alpha=0.2, R=1, U0=0.1) T = 40 solver = ForwardEuler(problem) solver.set_initial_condition(problem.U0) t = np.linspace(0, T, 401) # 400 intervals in [0,T] u, t = solver.solve(t) # Note that import * is not legal inside functions so we # have to import each specific function. from scitools.std import plot, hardcopy, xlabel, ylabel, title plot(t, u) xlabel('t'); ylabel('u') title('Logistic growth: alpha=%s, R=%g, dt=%g' \ % (problem.alpha, problem.R, t[1]-t[0])) # Compare with exponential growth #from scitools.std import hold, linspace, exp #te = linspace(0, dt*N, N+1) #ue = 0.1*exp(0.2*te) #hold('on') #plot(te, ue) hardcopy('tmp.eps')
def logistic(): problem = Logistic(alpha=0.2, R=1, U0=0.1) T = 40 method = ForwardEuler(problem) method.set_initial_condition(problem.U0) t = np.linspace(0, T, 401) # 400 intervals in [0,T] u, t = method.solve(t) # Note that import * is not legal inside functions so we # have to import each specific function. from scitools.std import plot, hardcopy, xlabel, ylabel, title plot(t, u) xlabel('t'); ylabel('u') title('Logistic growth: alpha=%s, R=%g, dt=%g' \ % (problem.alpha, problem.R, t[1]-t[0])) # Compare with exponential growth #from scitools.std import hold, linspace, exp #te = linspace(0, dt*N, N+1) #ue = 0.1*exp(0.2*te) #hold('on') #plot(te, ue) hardcopy('tmp.eps')
def logistic(): problem = Logistic(0.2, 1, 0.1) T = 40 dt = 0.1 method = ForwardEuler(problem, dt) method.set_initial_condition(problem.u0, 0) u, t = method.solve(T) # note that import * is not legal inside functions so we # have to import each specific function: from scitools.std import plot, hardcopy, xlabel, ylabel, title plot(t, u) xlabel('t'); ylabel('u') title('Logistic growth: alpha=0.2, dt=%g, %d steps' \ % (dt, len(u)-1)) # compare with exponential growth: #from scitools.std import hold, linspace, exp #te = linspace(0, dt*N, N+1) #ue = 0.1*exp(0.2*te) #hold('on') #plot(te, ue) hardcopy('tmp.eps')
def plot_boundaries(outer_boundary, inner_boundaries=[], marked_points=None): if not isinstance(inner_boundaries, (tuple, list)): inner_boundaries = [inner_boundaries] boundaries = [outer_boundary] boundaries.extend(inner_boundaries) # Find max/min of plotting area plot_area = [ min([b.x.min() for b in boundaries]), max([b.x.max() for b in boundaries]), min([b.y.min() for b in boundaries]), max([b.y.max() for b in boundaries]), ] aspect = (plot_area[3] - plot_area[2]) / (plot_area[1] - plot_area[0]) for b in boundaries: plot(b.x, b.y, daspect=[aspect, 1, 1], daspectratio="manual") hold("on") axis(plot_area) title("Specification of domain with %d boundaries" % len(boundaries)) if marked_points: for pt, name in marked_points: text(pt[0], pt[1], name)
def plot_boundaries(outer_boundary, inner_boundaries=[], marked_points=None): if not isinstance(inner_boundaries, (tuple, list)): inner_boundaries = [inner_boundaries] boundaries = [outer_boundary] boundaries.extend(inner_boundaries) # Find max/min of plotting area plot_area = [ min([b.x.min() for b in boundaries]), max([b.x.max() for b in boundaries]), min([b.y.min() for b in boundaries]), max([b.y.max() for b in boundaries]) ] aspect = (plot_area[3] - plot_area[2]) / (plot_area[1] - plot_area[0]) for b in boundaries: plot(b.x, b.y, daspect=[aspect, 1, 1], daspectratio='manual') hold('on') axis(plot_area) title('Specification of domain with %d boundaries' % len(boundaries)) if marked_points: for pt, name in marked_points: text(pt[0], pt[1], name)
def run(gamma, beta=10, delta=40, scaling=1, animate=False): """Run the scaled model for welding.""" if scaling == 1: v = gamma a = 1 elif scaling == 2: v = 1 a = 1.0/gamma b = 0.5*beta**2 L = 1.0 ymin = 0 # Need gloal to be able change ymax in closure process_u global ymax ymax = 1.2 I = lambda x: 0 f = lambda x, t: delta*np.exp(-b*(x - v*t)**2) import time import scitools.std as plt plot_arrays = [] def process_u(u, x, t, n): global ymax if animate: plt.plot(x, u, 'r-', x, f(x, t[n])/delta, 'b-', axis=[0, L, ymin, ymax], title='t=%f' % t[n], xlabel='x', ylabel='u and f/%g' % delta) if t[n] == 0: time.sleep(1) plot_arrays.append(x) dt = t[1] - t[0] tol = dt/10.0 if abs(t[n] - 0.2) < tol or abs(t[n] - 0.5) < tol: plot_arrays.append((u.copy(), f(x, t[n])/delta)) if u.max() > ymax: ymax = u.max() Nx = 100 D = 10 T = 0.5 u_L = u_R = 0 theta = 1.0 cpu = solver( I, a, f, L, Nx, D, T, theta, u_L, u_R, user_action=process_u) x = plot_arrays[0] plt.figure() for u, f in plot_arrays[1:]: plt.plot(x, u, 'r-', x, f, 'b--', axis=[x[0], x[-1], 0, ymax], xlabel='$x$', ylabel=r'$u, \ f/%g$' % delta) plt.hold('on') plt.legend(['$u,\\ t=0.2$', '$f/%g,\\ t=0.2$' % delta, '$u,\\ t=0.5$', '$f/%g,\\ t=0.5$' % delta]) filename = 'tmp1_gamma%g_s%d' % (gamma, scaling) s = 'diffusion' if scaling == 1 else 'source' plt.title(r'$\beta = %g,\ \gamma = %g,\ $' % (beta, gamma) + 'scaling=%s' % s) plt.savefig(filename + '.pdf'); plt.savefig(filename + '.png') return cpu
def plot(self): filename = 'logistic_' + str(self.problem) + '.pdf' plot(self.t, self.u) title(str(self.problem) + ', dt=%g' % self.dt) savefig(filename) show()
def approximate(f, symbolic=False, d=1, N_e=4, numint=None, Omega=[0, 1], filename='tmp'): if symbolic: if numint == 'Trapezoidal': numint = [[sm.S(-1), sm.S(1)], [sm.S(1), sm.S(1)]] # sympy integers elif numint == 'Simpson': numint = [[sm.S(-1), sm.S(0), sm.S(1)], [ sm.Rational(1, 3), sm.Rational(4, 3), sm.Rational(1, 3) ]] elif numint == 'Midpoint': numint = [[sm.S(0)], [sm.S(2)]] elif numint == 'GaussLegendre2': numint = [[-1 / sm.sqrt(3), 1 / sm.sqrt(3)], [sm.S(1), sm.S(1)]] elif numint == 'GaussLegendre3': numint = [[ -sm.sqrt(sm.Rational(3, 5)), 0, sm.sqrt(sm.Rational(3, 5)) ], [sm.Rational(5, 9), sm.Rational(8, 9), sm.Rational(5, 9)]] elif numint is not None: print 'Numerical rule %s is not supported' % numint numint = None else: if numint == 'Trapezoidal': numint = [[-1, 1], [1, 1]] elif numint == 'Simpson': numint = [[-1, 0, 1], [1. / 3, 4. / 3, 1. / 3]] elif numint == 'Midpoint': numint = [[0], [2]] elif numint == 'GaussLegendre2': numint = [[-1 / sqrt(3), 1 / sqrt(3)], [1, 1]] elif numint == 'GaussLegendre3': numint = [[-sqrt(3. / 5), 0, sqrt(3. / 5)], [5. / 9, 8. / 9, 5. / 9]] elif numint is not None: print 'Numerical rule %s is not supported' % numint numint = None vertices, cells, dof_map = mesh_uniform(N_e, d, Omega, symbolic) # phi is a list where phi[e] holds the basis in cell no e # (this is required by assemble, which can work with # meshes with different types of elements). # len(dof_map[e]) is the number of nodes in cell e, # and the degree of the polynomial is len(dof_map[e])-1 phi = [basis(len(dof_map[e]) - 1) for e in range(N_e)] print 'phi basis (reference element):\n', phi A, b = assemble(vertices, cells, dof_map, phi, f, symbolic=symbolic, numint=numint) print 'cells:', cells print 'vertices:', vertices print 'dof_map:', dof_map print 'A:\n', A print 'b:\n', b #print sm.latex(A, mode='plain') #print sm.latex(b, mode='plain') if symbolic: c = A.LUsolve(b) else: c = np.linalg.solve(A, b) print 'c:\n', c if not symbolic: print 'Plain interpolation/collocation:' x = sm.Symbol('x') f = sm.lambdify([x], f, modules='numpy') try: f_at_vertices = [f(xc) for xc in vertices] print f_at_vertices except Exception as e: print 'could not evaluate f numerically:' print e # else: nodes are symbolic so f(nodes[i]) only makes sense # in the non-symbolic case if not symbolic and filename is not None: title = 'P%d, N_e=%d' % (d, N_e) if numint is None: title += ', exact integration' else: title += ', integration: %s' % numint x_u, u = u_glob(np.asarray(c), vertices, cells, dof_map, resolution_per_element=51) x_f = np.linspace(Omega[0], Omega[1], 10001) # mesh for f plt.plot(x_u, u, '-', x_f, f(x_f), '--') plt.legend(['u', 'f']) plt.title(title) plt.savefig(filename + '.pdf') plt.savefig(filename + '.png') return c
def estimate(truncation_error, T, N_0, m, makeplot=True): """ Compute the truncation error in a problem with one independent variable, using m meshes, and estimate the convergence rate of the truncation error. The user-supplied function truncation_error(dt, N) computes the truncation error on a uniform mesh with N intervals of length dt:: R, t, R_a = truncation_error(dt, N) where R holds the truncation error at points in the array t, and R_a are the corresponding theoretical truncation error values (None if not available). The truncation_error function is run on a series of meshes with 2**i*N_0 intervals, i=0,1,...,m-1. The values of R and R_a are restricted to the coarsest mesh. and based on these data, the convergence rate of R (pointwise) and time-integrated R can be estimated empirically. """ N = [2**i*N_0 for i in range(m)] R_I = np.zeros(m) # time-integrated R values on various meshes R = [None]*m # time series of R restricted to coarsest mesh R_a = [None]*m # time series of R_a restricted to coarsest mesh dt = np.zeros(m) legends_R = []; legends_R_a = [] # all legends of curves for i in range(m): dt[i] = T/float(N[i]) R[i], t, R_a[i] = truncation_error(dt[i], N[i]) R_I[i] = np.sqrt(dt[i]*np.sum(R[i]**2)) if i == 0: t_coarse = t # the coarsest mesh stride = N[i]/N_0 R[i] = R[i][::stride] # restrict to coarsest mesh R_a[i] = R_a[i][::stride] if makeplot: plt.figure(1) plt.plot(t_coarse, R[i], log='y') legends_R.append('N=%d' % N[i]) plt.hold('on') plt.figure(2) plt.plot(t_coarse, R_a[i] - R[i], log='y') plt.hold('on') legends_R_a.append('N=%d' % N[i]) if makeplot: plt.figure(1) plt.xlabel('time') plt.ylabel('pointwise truncation error') plt.legend(legends_R) plt.savefig('R_series.png') plt.savefig('R_series.pdf') plt.figure(2) plt.xlabel('time') plt.ylabel('pointwise error in estimated truncation error') plt.legend(legends_R_a) plt.savefig('R_error.png') plt.savefig('R_error.pdf') # Convergence rates r_R_I = convergence_rates(dt, R_I) print 'R integrated in time; r:', print ' '.join(['%.1f' % r for r in r_R_I]) R = np.array(R) # two-dim. numpy array r_R = [convergence_rates(dt, R[:,n])[-1] for n in range(len(t_coarse))] # Plot convergence rates if makeplot: plt.figure() plt.plot(t_coarse, r_R) plt.xlabel('time') plt.ylabel('r') plt.axis([t_coarse[0], t_coarse[-1], 0, 2.5]) plt.title('Pointwise rate $r$ in truncation error $\sim\Delta t^r$') plt.savefig('R_rate_series.png') plt.savefig('R_rate_series.pdf')
# -*- coding: utf-8 -*- """ Created on Mon Oct 19 21:13:30 2015 @author: antalcides """ from ForwardEuleruni import * from LogisticUni import * problem = Logistic(0.2, 1, 0.1) T = 40 dt = 0.1 method = ForwardEuler(problem, dt) method.set_initial_condition(problem.u0, 0) u, t = method.solve(T) from scitools.std import plot, hardcopy, xlabel, ylabel, title plot(t, u) xlabel('t') ylabel('u') title('Logistic growth: alpha=0.2, dt=%g, %d steps' \ % (dt, len(u)-1))
def approximate(f, symbolic=False, d=1, N_e=4, numint=None, Omega=[0, 1], filename='tmp'): """ Compute the finite element approximation, using Lagrange elements of degree d, to a symbolic expression f (with x as independent variable) on a domain Omega. N_e is the number of elements. symbolic=True implies symbolic expressions in the calculations, while symbolic=False means numerical computing. numint is the name of the numerical integration rule (Trapezoidal, Simpson, GaussLegendre2, GaussLegendre3, GaussLegendre4, etc.). numint=None implies exact integration. """ numint_name = numint # save name if symbolic: if numint == 'Trapezoidal': numint = [[sym.S(-1), sym.S(1)], [sym.S(1), sym.S(1)]] # sympy integers elif numint == 'Simpson': numint = [[sym.S(-1), sym.S(0), sym.S(1)], [sym.Rational(1,3), sym.Rational(4,3), sym.Rational(1,3)]] elif numint == 'Midpoint': numint = [[sym.S(0)], [sym.S(2)]] elif numint == 'GaussLegendre2': numint = [[-1/sym.sqrt(3), 1/sym.sqrt(3)], [sym.S(1), sym.S(1)]] elif numint == 'GaussLegendre3': numint = [[-sym.sqrt(sym.Rational(3,5)), 0, sym.sqrt(sym.Rational(3,5))], [sym.Rational(5,9), sym.Rational(8,9), sym.Rational(5,9)]] elif numint is not None: print 'Numerical rule %s is not supported for symbolic computing' % numint numint = None else: if numint == 'Trapezoidal': numint = [[-1, 1], [1, 1]] elif numint == 'Simpson': numint = [[-1, 0, 1], [1./3, 4./3, 1./3]] elif numint == 'Midpoint': numint = [[0], [2]] elif numint == 'GaussLegendre2': numint = [[-1/sqrt(3), 1/sqrt(3)], [1, 1]] elif numint == 'GaussLegendre3': numint = [[-sqrt(3./5), 0, sqrt(3./5)], [5./9, 8./9, 5./9]] elif numint == 'GaussLegendre4': numint = [[-0.86113631, -0.33998104, 0.33998104, 0.86113631], [ 0.34785485, 0.65214515, 0.65214515, 0.34785485]] elif numint == 'GaussLegendre5': numint = [[-0.90617985, -0.53846931, -0. , 0.53846931, 0.90617985], [ 0.23692689, 0.47862867, 0.56888889, 0.47862867, 0.23692689]] elif numint is not None: print 'Numerical rule %s is not supported for numerical computing' % numint numint = None vertices, cells, dof_map = mesh_uniform(N_e, d, Omega, symbolic) # phi is a list where phi[e] holds the basis in cell no e # (this is required by assemble, which can work with # meshes with different types of elements). # len(dof_map[e]) is the number of nodes in cell e, # and the degree of the polynomial is len(dof_map[e])-1 phi = [basis(len(dof_map[e])-1) for e in range(N_e)] print 'phi basis (reference element):\n', phi A, b = assemble(vertices, cells, dof_map, phi, f, symbolic=symbolic, numint=numint) print 'cells:', cells print 'vertices:', vertices print 'dof_map:', dof_map print 'A:\n', A print 'b:\n', b #print sym.latex(A, mode='plain') #print sym.latex(b, mode='plain') if symbolic: c = A.LUsolve(b) else: c = np.linalg.solve(A, b) print 'c:\n', c if not symbolic: print 'Plain interpolation/collocation:' x = sym.Symbol('x') f = sym.lambdify([x], f, modules='numpy') try: f_at_vertices = [f(xc) for xc in vertices] print f_at_vertices except Exception as e: print 'could not evaluate f numerically:' print e # else: nodes are symbolic so f(nodes[i]) only makes sense # in the non-symbolic case if filename is not None: title = 'P%d, N_e=%d' % (d, N_e) if numint is None: title += ', exact integration' else: title += ', integration: %s' % numint_name x_u, u = u_glob(np.asarray(c), vertices, cells, dof_map, resolution_per_element=51) x_f = np.linspace(Omega[0], Omega[1], 10001) # mesh for f import scitools.std as plt plt.plot(x_u, u, '-', x_f, f(x_f), '--') plt.legend(['u', 'f']) plt.title(title) plt.savefig(filename + '.pdf') plt.savefig(filename + '.png') return c
solvers = [ odespy.RK2(f), odespy.RK3(f), odespy.RK4(f), # BackwardEuler must use Newton solver to converge # (Picard is default and leads to divergence) odespy.BackwardEuler(f, nonlinear_solver='Newton') ] legends = [] for solver in solvers: solver.set_initial_condition(I) u, t = solver.solve(t_mesh) plt.plot(t, u) plt.hold('on') legends.append(solver.__class__.__name__) # Compare with exact solution plotted on a very fine mesh t_fine = np.linspace(0, T, 10001) u_e = I * np.exp(-a * t_fine) plt.plot(t_fine, u_e, '-') # avoid markers by specifying line type legends.append('exact') plt.legend(legends) plt.title('Time step: %g' % dt) plt.savefig('odespy1_dt_%g.png' % dt) plt.savefig('odespy1_dt_%g.pdf' % dt) plt.show()
def approximate(f, d, N_e, numint, Omega=[0, 1], filename='tmp'): """ Compute the finite element approximation, using Lagrange elements of degree d, to a Python functionn f on a domain Omega. N_e is the number of elements. numint is the name of the numerical integration rule (Trapezoidal, Simpson, GaussLegendre2, GaussLegendre3, GaussLegendre4, etc.). numint=None implies exact integration. """ from math import sqrt numint_name = numint # save name if numint == 'Trapezoidal': numint = [[-1, 1], [1, 1]] elif numint == 'Simpson': numint = [[-1, 0, 1], [1. / 3, 4. / 3, 1. / 3]] elif numint == 'Midpoint': numint = [[0], [2]] elif numint == 'GaussLegendre2': numint = [[-1 / sqrt(3), 1 / sqrt(3)], [1, 1]] elif numint == 'GaussLegendre3': numint = [[-sqrt(3. / 5), 0, sqrt(3. / 5)], [5. / 9, 8. / 9, 5. / 9]] elif numint == 'GaussLegendre4': numint = [[-0.86113631, -0.33998104, 0.33998104, 0.86113631], [0.34785485, 0.65214515, 0.65214515, 0.34785485]] elif numint == 'GaussLegendre5': numint = [[-0.90617985, -0.53846931, -0., 0.53846931, 0.90617985], [0.23692689, 0.47862867, 0.56888889, 0.47862867, 0.23692689]] elif numint is not None: print 'Numerical rule %s is not supported '\ 'for numerical computing' % numint sys.exit(1) vertices, cells, dof_map = mesh_uniform(N_e, d, Omega) # phi is a list where phi[e] holds the basis in cell no e # (this is required by assemble, which can work with # meshes with different types of elements). # len(dof_map[e]) is the number of nodes in cell e, # and the degree of the polynomial is len(dof_map[e])-1 phi = [basis(len(dof_map[e]) - 1) for e in range(N_e)] A, b = assemble(vertices, cells, dof_map, phi, f, numint=numint) print 'cells:', cells print 'vertices:', vertices print 'dof_map:', dof_map print 'A:\n', A print 'b:\n', b c = np.linalg.solve(A, b) print 'c:\n', c if filename is not None: title = 'P%d, N_e=%d' % (d, N_e) title += ', integration: %s' % numint_name x_u, u, _ = u_glob(np.asarray(c), vertices, cells, dof_map, resolution_per_element=51) x_f = np.linspace(Omega[0], Omega[1], 10001) # mesh for f import scitools.std as plt plt.plot(x_u, u, '-', x_f, f(x_f), '--') plt.legend(['u', 'f']) plt.title(title) plt.savefig(filename + '.pdf') plt.savefig(filename + '.png') return c
def approximate(f, symbolic=False, d=1, N_e=4, numint=None, Omega=[0, 1], collocation=False, filename='tmp'): """ Compute the finite element approximation, using Lagrange elements of degree d, to a symbolic expression f (with x as independent variable) on a domain Omega. N_e is the number of elements. symbolic=True implies symbolic expressions in the calculations, while symbolic=False means numerical computing. numint is the name of the numerical integration rule (Trapezoidal, Simpson, GaussLegendre2, GaussLegendre3, GaussLegendre4, etc.). numint=None implies exact integration. """ numint_name = numint # save name if symbolic: if numint == 'Trapezoidal': numint = [[sym.S(-1), sym.S(1)], [sym.S(1), sym.S(1)]] # sympy integers elif numint == 'Simpson': numint = [[sym.S(-1), sym.S(0), sym.S(1)], [sym.Rational(1,3), sym.Rational(4,3), sym.Rational(1,3)]] elif numint == 'Midpoint': numint = [[sym.S(0)], [sym.S(2)]] elif numint == 'GaussLegendre2': numint = [[-1/sym.sqrt(3), 1/sym.sqrt(3)], [sym.S(1), sym.S(1)]] elif numint == 'GaussLegendre3': numint = [[-sym.sqrt(sym.Rational(3,5)), 0, sym.sqrt(sym.Rational(3,5))], [sym.Rational(5,9), sym.Rational(8,9), sym.Rational(5,9)]] elif numint is not None: print 'Numerical rule %s is not supported for symbolic computing' % numint numint = None else: if numint == 'Trapezoidal': numint = [[-1, 1], [1, 1]] elif numint == 'Simpson': numint = [[-1, 0, 1], [1./3, 4./3, 1./3]] elif numint == 'Midpoint': numint = [[0], [2]] elif numint == 'GaussLegendre2': numint = [[-1/sqrt(3), 1/sqrt(3)], [1, 1]] elif numint == 'GaussLegendre3': numint = [[-sqrt(3./5), 0, sqrt(3./5)], [5./9, 8./9, 5./9]] elif numint == 'GaussLegendre4': numint = [[-0.86113631, -0.33998104, 0.33998104, 0.86113631], [ 0.34785485, 0.65214515, 0.65214515, 0.34785485]] elif numint == 'GaussLegendre5': numint = [[-0.90617985, -0.53846931, -0. , 0.53846931, 0.90617985], [ 0.23692689, 0.47862867, 0.56888889, 0.47862867, 0.23692689]] elif numint is not None: print 'Numerical rule %s is not supported for numerical computing' % numint numint = None vertices, cells, dof_map = mesh_uniform(N_e, d, Omega, symbolic) # phi is a list where phi[e] holds the basis in cell no e # (this is required by assemble, which can work with # meshes with different types of elements). # len(dof_map[e]) is the number of nodes in cell e, # and the degree of the polynomial is len(dof_map[e])-1 phi = [basis(len(dof_map[e])-1) for e in range(N_e)] A, b = assemble(vertices, cells, dof_map, phi, f, symbolic=symbolic, numint=numint) print 'cells:', cells print 'vertices:', vertices print 'dof_map:', dof_map print 'A:\n', A print 'b:\n', b #print sym.latex(A, mode='plain') #print sym.latex(b, mode='plain') if symbolic: c = A.LUsolve(b) c = np.asarray([c[i,0] for i in range(c.shape[0])]) else: c = np.linalg.solve(A, b) print 'c:\n', c x = sym.Symbol('x') f = sym.lambdify([x], f, modules='numpy') if collocation and not symbolic: print 'Plain interpolation/collocation:' # Should use vertices, but compute all nodes! f_at_vertices = [f(xc) for xc in vertices] print f_at_vertices if filename is not None: title = 'P%d, N_e=%d' % (d, N_e) if numint is None: title += ', exact integration' else: title += ', integration: %s' % numint_name x_u, u, _ = u_glob(c, vertices, cells, dof_map, resolution_per_element=51) x_f = np.linspace(Omega[0], Omega[1], 10001) # mesh for f import scitools.std as plt plt.plot(x_u, u, '-', x_f, f(x_f), '--') plt.legend(['u', 'f']) plt.title(title) plt.savefig(filename + '.pdf') plt.savefig(filename + '.png') return c
def run_solvers_and_plot(solvers, timesteps_per_period=20, num_periods=1, I=1, w=2*np.pi): P = 2*np.pi/w # one period dt = P/timesteps_per_period N = num_periods*timesteps_per_period T = N*dt t_mesh = np.linspace(0, T, N+1) legends = [] for solver in solvers: solver.set(f_kwargs={'w': w}) solver.set_initial_condition([I, 0]) u, t = solver.solve(t_mesh) # Make plots if num_periods <= 80: plt.figure(1) if len(t_mesh) <= 50: plt.plot(t, u[:,0]) # markers by default else: plt.plot(t, u[:,0], '-2') # no markers plt.hold('on') legends.append(solver.__class__.__name__) plt.figure(2) if len(t_mesh) <= 50: plt.plot(u[:,0], u[:,1]) # markers by default else: plt.plot(u[:,0], u[:,1], '-2') # no markers plt.hold('on') if num_periods > 20: minima, maxima = minmax(t, u[:,0]) p = periods(maxima) a = amplitudes(minima, maxima) plt.figure(3) plt.plot(range(len(p)), 2*np.pi/p, '-') plt.hold('on') plt.figure(4) plt.plot(range(len(a)), a, '-') plt.hold('on') # Compare with exact solution plotted on a very fine mesh t_fine = np.linspace(0, T, 10001) u_e = I*np.cos(w*t_fine) v_e = -w*I*np.sin(w*t_fine) if num_periods < 80: plt.figure(1) plt.plot(t_fine, u_e, '-') # avoid markers by spec. line type legends.append('exact') plt.legend(legends, loc='upper left') plt.xlabel('t'); plt.ylabel('u') plt.title('Time step: %g' % dt) plt.savefig('vb_%d_%d_u.png' % (timesteps_per_period, num_periods)) plt.savefig('vb_%d_%d_u.pdf' % (timesteps_per_period, num_periods)) plt.savefig('vb_%d_%d_u.eps' % (timesteps_per_period, num_periods)) plt.figure(2) plt.plot(u_e, v_e, '-') # avoid markers by spec. line type plt.legend(legends, loc='lower right') plt.xlabel('u(t)'); plt.ylabel('v(t)') plt.title('Time step: %g' % dt) plt.savefig('vb_%d_%d_pp.png' % (timesteps_per_period, num_periods)) plt.savefig('vb_%d_%d_pp.pdf' % (timesteps_per_period, num_periods)) plt.savefig('vb_%d_%d_pp.eps' % (timesteps_per_period, num_periods)) del legends[-1] # fig 3 and 4 does not have exact value if num_periods > 20: plt.figure(3) plt.legend(legends, loc='center right') plt.title('Empirically estimated periods') plt.savefig('vb_%d_%d_p.eps' % (timesteps_per_period, num_periods)) plt.savefig('vb_%d_%d_p.png' % (timesteps_per_period, num_periods)) plt.savefig('vb_%d_%d_p.eps' % (timesteps_per_period, num_periods)) plt.figure(4) plt.legend(legends, loc='center right') plt.title('Empirically estimated amplitudes') plt.savefig('vb_%d_%d_a.eps' % (timesteps_per_period, num_periods)) plt.savefig('vb_%d_%d_a.png' % (timesteps_per_period, num_periods)) plt.savefig('vb_%d_%d_a.eps' % (timesteps_per_period, num_periods))
def run(gamma, beta=10, delta=40, scaling=1, animate=False): """Run the scaled model for welding.""" gamma = float(gamma) # avoid integer division if scaling == 'a': v = gamma a = 1 L = 1.0 b = 0.5 * beta**2 elif scaling == 'b': v = 1 a = 1.0 / gamma L = 1.0 b = 0.5 * beta**2 elif scaling == 'c': v = 1 a = beta / gamma L = beta b = 0.5 elif scaling == 'd': # PDE: u_t = gamma**(-1)u_xx + gamma**(-1)*delta*f v = 1 a = 1.0 / gamma L = 1.0 b = 0.5 * beta**2 delta *= 1.0 / gamma ymin = 0 # Need global ymax to be able change ymax in closure process_u global ymax ymax = 1.2 I = lambda x: 0 f = lambda x, t: delta * np.exp(-b * (x - v * t)**2) import time import scitools.std as plt plot_arrays = [] if scaling == 'c': plot_times = [0.2 * beta, 0.5 * beta] else: plot_times = [0.2, 0.5] def process_u(u, x, t, n): """ Animate u, and store arrays in plot_arrays if t coincides with chosen times for plotting (plot_times). """ global ymax if animate: plt.plot(x, u, 'r-', x, f(x, t[n]) / delta, 'b-', axis=[0, L, ymin, ymax], title='t=%f' % t[n], xlabel='x', ylabel='u and f/%g' % delta) if t[n] == 0: time.sleep(1) plot_arrays.append(x) dt = t[1] - t[0] tol = dt / 10.0 if abs(t[n] - plot_times[0]) < tol or \ abs(t[n] - plot_times[1]) < tol: plot_arrays.append((u.copy(), f(x, t[n]) / delta)) if u.max() > ymax: ymax = u.max() Nx = 100 D = 10 if scaling == 'c': T = 0.5 * beta else: T = 0.5 u_L = u_R = 0 theta = 1.0 cpu = solver(I, a, f, L, Nx, D, T, theta, u_L, u_R, user_action=process_u) x = plot_arrays[0] plt.figure() for u, f in plot_arrays[1:]: plt.plot(x, u, 'r-', x, f, 'b--', axis=[x[0], x[-1], 0, ymax], xlabel='$x$', ylabel=r'$u, \ f/%g$' % delta) plt.hold('on') plt.legend([ '$u,\\ t=%g$' % plot_times[0], '$f/%g,\\ t=%g$' % (delta, plot_times[0]), '$u,\\ t=%g$' % plot_times[1], '$f/%g,\\ t=%g$' % (delta, plot_times[1]) ]) filename = 'tmp1_gamma%g_%s' % (gamma, scaling) plt.title(r'$\beta = %g,\ \gamma = %g,\ $' % (beta, gamma) + 'scaling=%s' % scaling) plt.savefig(filename + '.pdf') plt.savefig(filename + '.png') return cpu
dt = float(sys.argv[1]) if len(sys.argv) >= 2 else 0.75 Nt = int(round(T/dt)) t_mesh = np.linspace(0, Nt*dt, Nt+1) solvers = [odespy.RK2(f), odespy.RK3(f), odespy.RK4(f), # BackwardEuler must use Newton solver to converge odespy.BackwardEuler(f, nonlinear_solver='Newton')] legends = [] for solver in solvers: solver.set_initial_condition(I) u, t = solver.solve(t_mesh) plt.plot(t, u) plt.hold('on') legends.append(solver.__class__.__name__) # Compare with exact solution plotted on a very fine mesh t_fine = np.linspace(0, T, 10001) u_e = I*np.exp(-a*t_fine) plt.plot(t_fine, u_e, '-') # avoid markers by specifying line type legends.append('exact') plt.legend(legends) plt.title('Time step: %g' % dt) plt.savefig('odespy1_dt_%g.png' % dt) plt.savefig('odespy1_dt_%g.pdf' % dt) plt.show()
def approximate(f, symbolic=False, d=1, N_e=4, numint=None, Omega=[0, 1], filename='tmp'): if symbolic: if numint == 'Trapezoidal': numint = [[sp.S(-1), sp.S(1)], [sp.S(1), sp.S(1)]] # sympy integers elif numint == 'Simpson': numint = [[sp.S(-1), sp.S(0), sp.S(1)], [sp.Rational(1,3), sp.Rational(4,3), sp.Rational(1,3)]] elif numint == 'Midpoint': numint = [[sp.S(0)], [sp.S(2)]] elif numint == 'GaussLegendre2': numint = [[-1/sp.sqrt(3), 1/sp.sqrt(3)], [sp.S(1), sp.S(1)]] elif numint == 'GaussLegendre3': numint = [[-sp.sqrt(sp.Rational(3,5)), 0, sp.sqrt(sp.Rational(3,5))], [sp.Rational(5,9), sp.Rational(8,9), sp.Rational(5,9)]] elif numint is not None: print 'Numerical rule %s is not supported' % numint numint = None else: if numint == 'Trapezoidal': numint = [[-1, 1], [1, 1]] elif numint == 'Simpson': numint = [[-1, 0, 1], [1./3, 4./3, 1./3]] elif numint == 'Midpoint': numint = [[0], [2]] elif numint == 'GaussLegendre2': numint = [[-1/sqrt(3), 1/sqrt(3)], [1, 1]] elif numint == 'GaussLegendre3': numint = [[-sqrt(3./5), 0, sqrt(3./5)], [5./9, 8./9, 5./9]] elif numint is not None: print 'Numerical rule %s is not supported' % numint numint = None vertices, cells, dof_map = mesh_uniform(N_e, d, Omega, symbolic) # phi is a list where phi[e] holds the basis in cell no e # (this is required by assemble, which can work with # meshes with different types of elements). # len(dof_map[e]) is the number of nodes in cell e, # and the degree of the polynomial is len(dof_map[e])-1 phi = [basis(len(dof_map[e])-1) for e in range(N_e)] print 'phi basis (reference element):\n', phi A, b = assemble(vertices, cells, dof_map, phi, f, symbolic=symbolic, numint=numint) print 'cells:', cells print 'vertices:', vertices print 'dof_map:', dof_map print 'A:\n', A print 'b:\n', b #print sp.latex(A, mode='plain') #print sp.latex(b, mode='plain') if symbolic: c = A.LUsolve(b) else: c = np.linalg.solve(A, b) print 'c:\n', c if not symbolic: print 'Plain interpolation/collocation:' x = sp.Symbol('x') f = sp.lambdify([x], f, modules='numpy') try: f_at_vertices = [f(xc) for xc in vertices] print f_at_vertices except Exception as e: print 'could not evaluate f numerically:' print e # else: nodes are symbolic so f(nodes[i]) only makes sense # in the non-symbolic case if not symbolic and filename is not None: title = 'P%d, N_e=%d' % (d, N_e) if numint is None: title += ', exact integration' else: title += ', integration: %s' % numint x_u, u = u_glob(np.asarray(c), vertices, cells, dof_map, resolution_per_element=51) x_f = np.linspace(Omega[0], Omega[1], 10001) # mesh for f plt.plot(x_u, u, '-', x_f, f(x_f), '--') plt.legend(['u', 'f']) plt.title(title) plt.savefig(filename + '.pdf') plt.savefig(filename + '.png') return c
def approximate(f, d, N_e, numint, Omega=[0,1], filename='tmp'): """ Compute the finite element approximation, using Lagrange elements of degree d, to a Python functionn f on a domain Omega. N_e is the number of elements. numint is the name of the numerical integration rule (Trapezoidal, Simpson, GaussLegendre2, GaussLegendre3, GaussLegendre4, etc.). numint=None implies exact integration. """ from math import sqrt numint_name = numint # save name if numint == 'Trapezoidal': numint = [[-1, 1], [1, 1]] elif numint == 'Simpson': numint = [[-1, 0, 1], [1./3, 4./3, 1./3]] elif numint == 'Midpoint': numint = [[0], [2]] elif numint == 'GaussLegendre2': numint = [[-1/sqrt(3), 1/sqrt(3)], [1, 1]] elif numint == 'GaussLegendre3': numint = [[-sqrt(3./5), 0, sqrt(3./5)], [5./9, 8./9, 5./9]] elif numint == 'GaussLegendre4': numint = [[-0.86113631, -0.33998104, 0.33998104, 0.86113631], [ 0.34785485, 0.65214515, 0.65214515, 0.34785485]] elif numint == 'GaussLegendre5': numint = [[-0.90617985, -0.53846931, -0. , 0.53846931, 0.90617985], [ 0.23692689, 0.47862867, 0.56888889, 0.47862867, 0.23692689]] elif numint is not None: print 'Numerical rule %s is not supported for numerical computing' % numint sys.exit(1) vertices, cells, dof_map = mesh_uniform(N_e, d, Omega) # phi is a list where phi[e] holds the basis in cell no e # (this is required by assemble, which can work with # meshes with different types of elements). # len(dof_map[e]) is the number of nodes in cell e, # and the degree of the polynomial is len(dof_map[e])-1 phi = [basis(len(dof_map[e])-1) for e in range(N_e)] A, b = assemble(vertices, cells, dof_map, phi, f, numint=numint) print 'cells:', cells print 'vertices:', vertices print 'dof_map:', dof_map print 'A:\n', A print 'b:\n', b c = np.linalg.solve(A, b) print 'c:\n', c if filename is not None: title = 'P%d, N_e=%d' % (d, N_e) title += ', integration: %s' % numint_name x_u, u, _ = u_glob(np.asarray(c), vertices, cells, dof_map, resolution_per_element=51) x_f = np.linspace(Omega[0], Omega[1], 10001) # mesh for f import scitools.std as plt plt.plot(x_u, u, '-', x_f, f(x_f), '--') plt.legend(['u', 'f']) plt.title(title) plt.savefig(filename + '.pdf') plt.savefig(filename + '.png') return c
def run(gamma, beta=10, delta=40, scaling=1, animate=False): """Run the scaled model for welding.""" gamma = float(gamma) # avoid integer division if scaling == 'a': v = gamma a = 1 L = 1.0 b = 0.5*beta**2 elif scaling == 'b': v = 1 a = 1.0/gamma L = 1.0 b = 0.5*beta**2 elif scaling == 'c': v = 1 a = beta/gamma L = beta b = 0.5 elif scaling == 'd': # PDE: u_t = gamma**(-1)u_xx + gamma**(-1)*delta*f v = 1 a = 1.0/gamma L = 1.0 b = 0.5*beta**2 delta *= 1.0/gamma ymin = 0 # Need global ymax to be able change ymax in closure process_u global ymax ymax = 1.2 I = lambda x: 0 f = lambda x, t: delta*np.exp(-b*(x - v*t)**2) import time import scitools.std as plt plot_arrays = [] if scaling == 'c': plot_times = [0.2*beta, 0.5*beta] else: plot_times = [0.2, 0.5] def process_u(u, x, t, n): """ Animate u, and store arrays in plot_arrays if t coincides with chosen times for plotting (plot_times). """ global ymax if animate: plt.plot(x, u, 'r-', x, f(x, t[n])/delta, 'b-', axis=[0, L, ymin, ymax], title='t=%f' % t[n], xlabel='x', ylabel='u and f/%g' % delta) if t[n] == 0: time.sleep(1) plot_arrays.append(x) dt = t[1] - t[0] tol = dt/10.0 if abs(t[n] - plot_times[0]) < tol or \ abs(t[n] - plot_times[1]) < tol: plot_arrays.append((u.copy(), f(x, t[n])/delta)) if u.max() > ymax: ymax = u.max() Nx = 100 D = 10 if scaling == 'c': T = 0.5*beta else: T = 0.5 u_L = u_R = 0 theta = 1.0 cpu = solver( I, a, f, L, Nx, D, T, theta, u_L, u_R, user_action=process_u) x = plot_arrays[0] plt.figure() for u, f in plot_arrays[1:]: plt.plot(x, u, 'r-', x, f, 'b--', axis=[x[0], x[-1], 0, ymax], xlabel='$x$', ylabel=r'$u, \ f/%g$' % delta) plt.hold('on') plt.legend(['$u,\\ t=%g$' % plot_times[0], '$f/%g,\\ t=%g$' % (delta, plot_times[0]), '$u,\\ t=%g$' % plot_times[1], '$f/%g,\\ t=%g$' % (delta, plot_times[1])]) filename = 'tmp1_gamma%g_%s' % (gamma, scaling) plt.title(r'$\beta = %g,\ \gamma = %g,\ $' % (beta, gamma) + 'scaling=%s' % scaling) plt.savefig(filename + '.pdf'); plt.savefig(filename + '.png') return cpu
def run_solvers_and_plot(solvers, timesteps_per_period=20, num_periods=1, I=1, w=2*np.pi): P = 2*np.pi/w # duration of one period dt = P/timesteps_per_period Nt = num_periods*timesteps_per_period T = Nt*dt t_mesh = np.linspace(0, T, Nt+1) legends = [] for solver in solvers: solver.set(f_kwargs={'w': w}) solver.set_initial_condition([I, 0]) u, t = solver.solve(t_mesh) # Compute energy dt = t[1] - t[0] E = 0.5*((u[2:,0] - u[:-2,0])/(2*dt))**2 + 0.5*w**2*u[1:-1,0]**2 # Compute error in energy E0 = 0.5*0**2 + 0.5*w**2*I**2 e_E = E - E0 solver_name = 'CrankNicolson' if solver.__class__.__name__ == \ 'MidpointImplicit' else solver.__class__.__name__ print '*** Relative max error in energy for %s [0,%g] with dt=%g: %.3E' % (solver_name, t[-1], dt, np.abs(e_E).max()/E0) # Make plots if num_periods <= 80: plt.figure(1) if len(t_mesh) <= 50: plt.plot(t, u[:,0]) # markers by default else: plt.plot(t, u[:,0], '-2') # no markers plt.hold('on') legends.append(solver.__class__.__name__) plt.figure(2) if len(t_mesh) <= 50: plt.plot(u[:,0], u[:,1]) # markers by default else: plt.plot(u[:,0], u[:,1], '-2') # no markers plt.hold('on') if num_periods > 20: minima, maxima = minmax(t, u[:,0]) p = periods(maxima) a = amplitudes(minima, maxima) plt.figure(3) plt.plot(range(len(p)), 2*np.pi/p, '-') plt.hold('on') plt.figure(4) plt.plot(range(len(a)), a, '-') plt.hold('on') # Compare with exact solution plotted on a very fine mesh t_fine = np.linspace(0, T, 10001) u_e = I*np.cos(w*t_fine) v_e = -w*I*np.sin(w*t_fine) if num_periods < 80: plt.figure(1) plt.plot(t_fine, u_e, '-') # avoid markers by spec. line type legends.append('exact') plt.legend(legends, loc='upper left') plt.xlabel('t'); plt.ylabel('u') plt.title('Time step: %g' % dt) plt.savefig('vib_%d_%d_u.png' % (timesteps_per_period, num_periods)) plt.savefig('vib_%d_%d_u.pdf' % (timesteps_per_period, num_periods)) plt.savefig('vib_%d_%d_u.eps' % (timesteps_per_period, num_periods)) plt.figure(2) plt.plot(u_e, v_e, '-') # avoid markers by spec. line type plt.legend(legends, loc='lower right') plt.xlabel('u(t)'); plt.ylabel('v(t)') plt.title('Time step: %g' % dt) plt.savefig('vib_%d_%d_pp.png' % (timesteps_per_period, num_periods)) plt.savefig('vib_%d_%d_pp.pdf' % (timesteps_per_period, num_periods)) plt.savefig('vib_%d_%d_pp.eps' % (timesteps_per_period, num_periods)) del legends[-1] # fig 3 and 4 does not have exact value if num_periods > 20: plt.figure(3) plt.legend(legends, loc='center right') plt.title('Empirically estimated periods') plt.savefig('vib_%d_%d_p.eps' % (timesteps_per_period, num_periods)) plt.savefig('vib_%d_%d_p.png' % (timesteps_per_period, num_periods)) plt.savefig('vib_%d_%d_p.eps' % (timesteps_per_period, num_periods)) plt.figure(4) plt.legend(legends, loc='center right') plt.title('Empirically estimated amplitudes') plt.savefig('vib_%d_%d_a.eps' % (timesteps_per_period, num_periods)) plt.savefig('vib_%d_%d_a.png' % (timesteps_per_period, num_periods)) plt.savefig('vib_%d_%d_a.eps' % (timesteps_per_period, num_periods))
def run_solvers_and_plot(solvers, timesteps_per_period=20, num_periods=1, I=1, w=2 * np.pi): P = 2 * np.pi / w # one period dt = P / timesteps_per_period N = num_periods * timesteps_per_period T = N * dt t_mesh = np.linspace(0, T, N + 1) legends = [] for solver in solvers: solver.set(f_kwargs={'w': w}) solver.set_initial_condition([I, 0]) u, t = solver.solve(t_mesh) # Make plots if num_periods <= 80: plt.figure(1) if len(t_mesh) <= 50: plt.plot(t, u[:, 0]) # markers by default else: plt.plot(t, u[:, 0], '-2') # no markers plt.hold('on') legends.append(solver.__class__.__name__) plt.figure(2) if len(t_mesh) <= 50: plt.plot(u[:, 0], u[:, 1]) # markers by default else: plt.plot(u[:, 0], u[:, 1], '-2') # no markers plt.hold('on') if num_periods > 20: minima, maxima = minmax(t, u[:, 0]) p = periods(maxima) a = amplitudes(minima, maxima) plt.figure(3) plt.plot(range(len(p)), 2 * np.pi / p, '-') plt.hold('on') plt.figure(4) plt.plot(range(len(a)), a, '-') plt.hold('on') # Compare with exact solution plotted on a very fine mesh t_fine = np.linspace(0, T, 10001) u_e = I * np.cos(w * t_fine) v_e = -w * I * np.sin(w * t_fine) if num_periods < 80: plt.figure(1) plt.plot(t_fine, u_e, '-') # avoid markers by spec. line type legends.append('exact') plt.legend(legends, loc='upper left') plt.xlabel('t') plt.ylabel('u') plt.title('Time step: %g' % dt) plt.savefig('vb_%d_%d_u.png' % (timesteps_per_period, num_periods)) plt.savefig('vb_%d_%d_u.pdf' % (timesteps_per_period, num_periods)) plt.savefig('vb_%d_%d_u.eps' % (timesteps_per_period, num_periods)) plt.figure(2) plt.plot(u_e, v_e, '-') # avoid markers by spec. line type plt.legend(legends, loc='lower right') plt.xlabel('u(t)') plt.ylabel('v(t)') plt.title('Time step: %g' % dt) plt.savefig('vb_%d_%d_pp.png' % (timesteps_per_period, num_periods)) plt.savefig('vb_%d_%d_pp.pdf' % (timesteps_per_period, num_periods)) plt.savefig('vb_%d_%d_pp.eps' % (timesteps_per_period, num_periods)) del legends[-1] # fig 3 and 4 does not have exact value if num_periods > 20: plt.figure(3) plt.legend(legends, loc='center right') plt.title('Empirically estimated periods') plt.savefig('vb_%d_%d_p.eps' % (timesteps_per_period, num_periods)) plt.savefig('vb_%d_%d_p.png' % (timesteps_per_period, num_periods)) plt.savefig('vb_%d_%d_p.eps' % (timesteps_per_period, num_periods)) plt.figure(4) plt.legend(legends, loc='center right') plt.title('Empirically estimated amplitudes') plt.savefig('vb_%d_%d_a.eps' % (timesteps_per_period, num_periods)) plt.savefig('vb_%d_%d_a.png' % (timesteps_per_period, num_periods)) plt.savefig('vb_%d_%d_a.eps' % (timesteps_per_period, num_periods))
def FTCS(): """ Forward time, centered space """ L = 3.0 Nx = 30 bar = np.linspace(0, L, Nx+1) u0 = np.zeros(Nx+1) u1 = np.zeros(Nx+1) # IC is constant u0[0] = 5 u0[-1] = 12 u1[0] = 5 u1[-1] = 12 #u0[10] = 3 k = 0.02364*np.ones(Nx+1) k[int(Nx*0.1):int(Nx)*0.5] = 0.02514 rho = 1.292*np.ones(Nx+1) rho[int(Nx*0.1):int(Nx)*0.5] = 1.204 cp = 1006*np.ones(Nx+1) cp[int(Nx*0.1):int(Nx)*0.5] = 1007 alpha = 1.818*10**(-5)*np.ones(Nx+1) alpha[int(Nx*0.3):int(Nx)*0.5] = 3.243*10**(-5) alpha_max = max(alpha)#max(k) / (min(rho)*min(cp)) r = 0.00001 dx = L / Nx dt = r * dx**2 / alpha_max C = alpha_max*dt/dx**2 Nt = 2000000 t = 0 # constant conductivity """" for i in range(Nt): t += dt u1[1:-1] = u0[1:-1] + C * (u0[2::] - 2*u0[1:-1] + u0[0:-2]) u0 = u1 sci.plot(bar, u1) sci.title('t=%g'%t) """ count = 0 # non constant conductivity for i in range(Nt): count += 1 #for i in range(1, Nx): # u1[i] = u0[i] + dt/dx**2 * (k[i+1]*u0[i+1] - 2*k[i]*u0[i] + k[i-1]*u0[i-1]) / (rho[i]*cp[i]) #u0 = u1 t += dt u1[1:-1] = u0[1:-1] + dt/dx**2 * (k[2::]*u0[2::] - 2*k[1:-1]*u0[1:-1] + k[0:-2]*u0[0:-2] ) / (rho[1:-1]*cp[1:-1]) u0 = u1 if count == 50000: sci.plot(bar, u1) sci.title('t=%g'%t) count = 0
def approximate(f, symbolic=False, d=1, N_e=4, numint=None, Omega=[0, 1], filename="tmp"): if symbolic: if numint == "Trapezoidal": numint = [[sm.S(-1), sm.S(1)], [sm.S(1), sm.S(1)]] # sympy integers elif numint == "Simpson": numint = [[sm.S(-1), sm.S(0), sm.S(1)], [sm.Rational(1, 3), sm.Rational(4, 3), sm.Rational(1, 3)]] elif numint == "Midpoint": numint = [[sm.S(0)], [sm.S(2)]] elif numint == "GaussLegendre2": numint = [[-1 / sm.sqrt(3), 1 / sm.sqrt(3)], [sm.S(1), sm.S(1)]] elif numint == "GaussLegendre3": numint = [ [-sm.sqrt(sm.Rational(3, 5)), 0, sm.sqrt(sm.Rational(3, 5))], [sm.Rational(5, 9), sm.Rational(8, 9), sm.Rational(5, 9)], ] elif numint is not None: print "Numerical rule %s is not supported" % numint numint = None else: if numint == "Trapezoidal": numint = [[-1, 1], [1, 1]] elif numint == "Simpson": numint = [[-1, 0, 1], [1.0 / 3, 4.0 / 3, 1.0 / 3]] elif numint == "Midpoint": numint = [[0], [2]] elif numint == "GaussLegendre2": numint = [[-1 / sqrt(3), 1 / sqrt(3)], [1, 1]] elif numint == "GaussLegendre3": numint = [[-sqrt(3.0 / 5), 0, sqrt(3.0 / 5)], [5.0 / 9, 8.0 / 9, 5.0 / 9]] elif numint is not None: print "Numerical rule %s is not supported" % numint numint = None vertices, cells, dof_map = mesh_uniform(N_e, d, Omega, symbolic) # phi is a list where phi[e] holds the basis in cell no e # (this is required by assemble, which can work with # meshes with different types of elements). # len(dof_map[e]) is the number of nodes in cell e, # and the degree of the polynomial is len(dof_map[e])-1 phi = [basis(len(dof_map[e]) - 1) for e in range(N_e)] print "phi basis (reference element):\n", phi A, b = assemble(vertices, cells, dof_map, phi, f, symbolic=symbolic, numint=numint) print "cells:", cells print "vertices:", vertices print "dof_map:", dof_map print "A:\n", A print "b:\n", b # print sm.latex(A, mode='plain') # print sm.latex(b, mode='plain') if symbolic: c = A.LUsolve(b) else: c = np.linalg.solve(A, b) print "c:\n", c if not symbolic: print "Plain interpolation/collocation:" x = sm.Symbol("x") f = sm.lambdify([x], f, modules="numpy") try: f_at_vertices = [f(xc) for xc in vertices] print f_at_vertices except Exception as e: print "could not evaluate f numerically:" print e # else: nodes are symbolic so f(nodes[i]) only makes sense # in the non-symbolic case if not symbolic and filename is not None: title = "P%d, N_e=%d" % (d, N_e) if numint is None: title += ", exact integration" else: title += ", integration: %s" % numint x_u, u = u_glob(np.asarray(c), vertices, cells, dof_map, resolution_per_element=51) x_f = np.linspace(Omega[0], Omega[1], 10001) # mesh for f plt.plot(x_u, u, "-", x_f, f(x_f), "--") plt.legend(["u", "f"]) plt.title(title) plt.savefig(filename + ".pdf") plt.savefig(filename + ".png") return c
""" As uniform_numbers1.py but the histogram is plotted both as a piecewise constant curve and a piecewise linear curve. The number of bins is read from the command line. """ import sys N = int(sys.argv[1]) nbins = int(sys.argv[2]) import numpy as np np.random.seed(12) # Vectorized generation of random numbers samples = np.random.random(size=N) import scitools.std as st x1, y1 = st.compute_histogram(samples, nbins, piecewise_constant=True) x2, y2 = st.compute_histogram(samples, nbins, piecewise_constant=False) st.plot(x1, y1, 'r', x2, y2, 'b') st.title('%d samples of uniform numbers on (0,1)' % N) st.hardcopy('tmp.eps')
def run(gamma, beta=10, delta=40, scaling=1, animate=False): """Run the scaled model for welding.""" if scaling == 1: v = gamma a = 1 elif scaling == 2: v = 1 a = 1.0 / gamma b = 0.5 * beta**2 L = 1.0 ymin = 0 # Need gloal to be able change ymax in closure process_u global ymax ymax = 1.2 I = lambda x: 0 f = lambda x, t: delta * np.exp(-b * (x - v * t)**2) import time import scitools.std as plt plot_arrays = [] def process_u(u, x, t, n): global ymax if animate: plt.plot(x, u, 'r-', x, f(x, t[n]) / delta, 'b-', axis=[0, L, ymin, ymax], title='t=%f' % t[n], xlabel='x', ylabel='u and f/%g' % delta) if t[n] == 0: time.sleep(1) plot_arrays.append(x) dt = t[1] - t[0] tol = dt / 10.0 if abs(t[n] - 0.2) < tol or abs(t[n] - 0.5) < tol: plot_arrays.append((u.copy(), f(x, t[n]) / delta)) if u.max() > ymax: ymax = u.max() Nx = 100 D = 10 T = 0.5 u_L = u_R = 0 theta = 1.0 cpu = solver(I, a, f, L, Nx, D, T, theta, u_L, u_R, user_action=process_u) x = plot_arrays[0] plt.figure() for u, f in plot_arrays[1:]: plt.plot(x, u, 'r-', x, f, 'b--', axis=[x[0], x[-1], 0, ymax], xlabel='$x$', ylabel=r'$u, \ f/%g$' % delta) plt.hold('on') plt.legend([ '$u,\\ t=0.2$', '$f/%g,\\ t=0.2$' % delta, '$u,\\ t=0.5$', '$f/%g,\\ t=0.5$' % delta ]) filename = 'tmp1_gamma%g_s%d' % (gamma, scaling) s = 'diffusion' if scaling == 1 else 'source' plt.title(r'$\beta = %g,\ \gamma = %g,\ $' % (beta, gamma) + 'scaling=%s' % s) plt.savefig(filename + '.pdf') plt.savefig(filename + '.png') return cpu
def run_solvers_and_plot(solvers, timesteps_per_period=20, num_periods=1, I=1, w=2 * np.pi): P = 2 * np.pi / w # duration of one period dt = P / timesteps_per_period Nt = num_periods * timesteps_per_period T = Nt * dt t_mesh = np.linspace(0, T, Nt + 1) legends = [] for solver in solvers: solver.set(f_kwargs={'w': w}) solver.set_initial_condition([I, 0]) u, t = solver.solve(t_mesh) # Compute energy dt = t[1] - t[0] E = 0.5 * ((u[2:, 0] - u[:-2, 0]) / (2 * dt))**2 + 0.5 * w**2 * u[1:-1, 0]**2 # Compute error in energy E0 = 0.5 * 0**2 + 0.5 * w**2 * I**2 e_E = E - E0 solver_name = 'CrankNicolson' if solver.__class__.__name__ == \ 'MidpointImplicit' else solver.__class__.__name__ print '*** Relative max error in energy for %s [0,%g] with dt=%g: %.3E' % ( solver_name, t[-1], dt, np.abs(e_E).max() / E0) # Make plots if num_periods <= 80: plt.figure(1) if len(t_mesh) <= 50: plt.plot(t, u[:, 0]) # markers by default else: plt.plot(t, u[:, 0], '-2') # no markers plt.hold('on') legends.append(solver_name) plt.figure(2) if len(t_mesh) <= 50: plt.plot(u[:, 0], u[:, 1]) # markers by default else: plt.plot(u[:, 0], u[:, 1], '-2') # no markers plt.hold('on') if num_periods > 20: minima, maxima = minmax(t, u[:, 0]) p = periods(maxima) a = amplitudes(minima, maxima) plt.figure(3) plt.plot(range(len(p)), 2 * np.pi / p, '-') plt.hold('on') plt.figure(4) plt.plot(range(len(a)), a, '-') plt.hold('on') # Compare with exact solution plotted on a very fine mesh t_fine = np.linspace(0, T, 10001) u_e = I * np.cos(w * t_fine) v_e = -w * I * np.sin(w * t_fine) if num_periods < 80: plt.figure(1) plt.plot(t_fine, u_e, '-') # avoid markers by spec. line type legends.append('exact') plt.legend(legends, loc='upper left') plt.xlabel('t') plt.ylabel('u') plt.title('Time step: %g' % dt) plt.savefig('vib_%d_%d_u.png' % (timesteps_per_period, num_periods)) plt.savefig('vib_%d_%d_u.pdf' % (timesteps_per_period, num_periods)) plt.figure(2) plt.plot(u_e, v_e, '-') # avoid markers by spec. line type plt.legend(legends, loc='lower right') plt.xlabel('u(t)') plt.ylabel('v(t)') plt.title('Time step: %g' % dt) plt.savefig('vib_%d_%d_pp.png' % (timesteps_per_period, num_periods)) plt.savefig('vib_%d_%d_pp.pdf' % (timesteps_per_period, num_periods)) del legends[-1] # fig 3 and 4 does not have exact value if num_periods > 20: plt.figure(3) plt.legend(legends, loc='center right') plt.title('Empirically estimated periods') plt.savefig('vib_%d_%d_p.pdf' % (timesteps_per_period, num_periods)) plt.savefig('vib_%d_%d_p.png' % (timesteps_per_period, num_periods)) plt.figure(4) plt.legend(legends, loc='center right') plt.title('Empirically estimated amplitudes') plt.savefig('vib_%d_%d_a.pdf' % (timesteps_per_period, num_periods)) plt.savefig('vib_%d_%d_a.png' % (timesteps_per_period, num_periods))