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 approximate(f, symbolic=False, d=1, N_e=4, Omega=[0, 1], filename='tmp'): phi = basis(d) print 'phi basis (reference element):\n', phi nodes, elements = mesh_uniform(N_e, d, Omega, symbolic) A, b = assemble(nodes, elements, phi, f, symbolic=symbolic) print 'nodes:', nodes print 'elements:', elements 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 print 'Plain interpolation/collocation:' x = sp.Symbol('x') f = sp.lambdify([x], f, modules='numpy') try: f_at_nodes = [f(xc) for xc in nodes] except NameError as e: raise NameError('numpy does not support special function:\n%s' % e) print f_at_nodes if not symbolic and filename is not None: xf = np.linspace(Omega[0], Omega[1], 10001) U = np.asarray(c) xu, u = u_glob(U, elements, nodes) plt.plot(xu, u, '-', xf, f(xf), '--') plt.legend(['u', 'f']) plt.savefig(filename + '.pdf') plt.savefig(filename + '.png')
def run_solvers_and_check_amplitudes(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) file_name = 'Amplitudes' # initialize filename for plot for solver in solvers: solver.set(f_kwargs={'w': w}) solver.set_initial_condition([0, I]) u, t = solver.solve(t_mesh) solver_name = \ 'CrankNicolson' if solver.__class__.__name__ == \ 'MidpointImplicit' else solver.__class__.__name__ file_name = file_name + '_' + solver_name minima, maxima = minmax(t, u[:, 0]) a = amplitudes(minima, maxima) plt.plot(range(len(a)), a, '-', label=solver_name) plt.hold('on') plt.xlabel('Number of periods') plt.ylabel('Amplitude (absolute value)') plt.legend(loc='upper left') plt.savefig(file_name + '.png') plt.savefig(file_name + '.pdf') plt.show()
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_check_amplitudes(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) file_name = 'Amplitudes' # initialize filename for plot for solver in solvers: solver.set(f_kwargs={'w': w}) solver.set_initial_condition([0, I]) u, t = solver.solve(t_mesh) solver_name = \ 'CrankNicolson' if solver.__class__.__name__ == \ 'MidpointImplicit' else solver.__class__.__name__ file_name = file_name + '_' + solver_name minima, maxima = minmax(t, u[:,0]) a = amplitudes(minima, maxima) plt.plot(range(len(a)), a, '-', label=solver_name) plt.hold('on') plt.xlabel('Number of periods') plt.ylabel('Amplitude (absolute value)') plt.legend(loc='upper left') plt.savefig(file_name + '.png') plt.savefig(file_name + '.pdf') plt.show()
def u_P1(): """ Plot P1 basis functions and a resulting u to illustrate what it means to use finite elements. """ import matplotlib.pyplot as plt x = [0, 1.5, 2.5, 3.5, 4] phi = [np.zeros(len(x)) for i in range(len(x)-2)] for i in range(len(phi)): phi[i][i+1] = 1 #u = 5*x*np.exp(-0.25*x**2)*(4-x) u = [0, 8, 5, 4, 0] for i in range(len(phi)): plt.plot(x, phi[i], 'r-') #, label=r'$\varphi_%d$' % i) plt.text(x[i+1], 1.2, r'$\varphi_%d$' % i) plt.plot(x, u, 'b-', label='$u$') plt.legend(loc='upper left') plt.axis([0, x[-1], 0, 9]) plt.savefig('u_example_P1.png') plt.savefig('u_example_P1.pdf') # Mark elements for xi in x[1:-1]: plt.plot([xi, xi], [0, 9], 'm--') # Mark nodes #plt.plot(x, np.zeros(len(x)), 'ro', markersize=4) plt.savefig('u_example_P1_welms.png') plt.savefig('u_example_P1_welms.pdf') plt.show()
def u_P1(): """ Plot P1 basis functions and a resulting u to illustrate what it means to use finite elements. """ import matplotlib.pyplot as plt x = [0, 1.5, 2.5, 3.5, 4] phi = [np.zeros(len(x)) for i in range(len(x)-2)] for i in range(len(phi)): phi[i][i+1] = 1 #u = 5*x*np.exp(-0.25*x**2)*(4-x) u = [0, 8, 5, 4, 0] for i in range(len(phi)): plt.plot(x, phi[i], 'r-') #, label=r'$\varphi_%d$' % i) plt.text(x[i+1], 1.2, r'$\varphi_%d$' % i) plt.plot(x, u, 'b-', label='$u$') plt.legend(loc='upper left') plt.axis([0, x[-1], 0, 9]) plt.savefig('tmp_u_P1.png') plt.savefig('tmp_u_P1.pdf') # Mark elements for xi in x[1:-1]: plt.plot([xi, xi], [0, 9], 'm--') # Mark nodes #plt.plot(x, np.zeros(len(x)), 'ro', markersize=4) plt.savefig('tmp_u_P1_welms.png') plt.savefig('tmp_u_P1_welms.pdf') plt.show()
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 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 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 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 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 comparison_plot(f, u, Omega, filename='tmp.pdf'): x = sm.Symbol('x') f = sm.lambdify([x], f, modules="numpy") u = sm.lambdify([x], u, modules="numpy") resolution = 401 # no of points in plot xcoor = linspace(Omega[0], Omega[1], resolution) exact = f(xcoor) approx = u(xcoor) plot(xcoor, approx) hold('on') plot(xcoor, exact) legend(['approximation', 'exact']) savefig(filename)
def plot_empirical_freq_and_amplitude(u, t): minima, maxima = minmax(t, u) p = periods(maxima) a = amplitudes(minima, maxima) plt.figure() from math import pi w = 2 * pi / p plt.plot(range(len(p)), w, 'r-') plt.hold('on') plt.plot(range(len(a)), a, 'b-') ymax = 1.1 * max(w.max(), a.max()) ymin = 0.9 * min(w.min(), a.min()) plt.axis([0, max(len(p), len(a)), ymin, ymax]) plt.legend(['estimated frequency', 'estimated amplitude'], loc='upper right') return len(maxima)
def plot_empirical_freq_and_amplitude(u, t): minima, maxima = minmax(t, u) p = periods(maxima) a = amplitudes(minima, maxima) plt.figure() from math import pi w = 2*pi/p plt.plot(range(len(p)), w, 'r-') plt.hold('on') plt.plot(range(len(a)), a, 'b-') ymax = 1.1*max(w.max(), a.max()) ymin = 0.9*min(w.min(), a.min()) plt.axis([0, max(len(p), len(a)), ymin, ymax]) plt.legend(['estimated frequency', 'estimated amplitude'], loc='upper right') return len(maxima)
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 approximate(f, symbolic=False, d=1, N_e=4, Omega=[0, 1], filename='tmp'): phi = basis(d) print 'phi basis (reference element):\n', phi nodes, elements = mesh_uniform(N_e, d, Omega, symbolic) A, b = assemble(nodes, elements, phi, f, symbolic=symbolic) print 'nodes:', nodes print 'elements:', elements 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 = [c[i,0] for i in range(c.shape[0])] else: c = np.linalg.solve(A, b) print 'c:\n', c print 'Plain interpolation/collocation:' x = sym.Symbol('x') f = sym.lambdify([x], f, modules='numpy') try: f_at_nodes = [f(xc) for xc in nodes] except NameError as e: raise NameError('numpy does not support special function:\n%s' % e) print f_at_nodes if not symbolic and filename is not None: xf = np.linspace(Omega[0], Omega[1], 10001) U = np.asarray(c) # c is a plain array xu, u = u_glob(U, elements, nodes) import scitools.std as plt #import matplotlib.pyplot as plt plt.plot(xu, u, '-', xf, f(xf), '--') plt.legend(['u', 'f']) plt.savefig(filename + '.pdf') plt.savefig(filename + '.png') return c
def approximate(f, symbolic=False, d=1, N_e=4, Omega=[0, 1], filename="tmp"): phi = basis(d) print "phi basis (reference element):\n", phi nodes, elements = mesh_uniform(N_e, d, Omega, symbolic) A, b = assemble(nodes, elements, phi, f, symbolic=symbolic) print "nodes:", nodes print "elements:", elements 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 = [c[i, 0] for i in range(c.shape[0])] else: c = np.linalg.solve(A, b) print "c:\n", c print "Plain interpolation/collocation:" x = sym.Symbol("x") f = sym.lambdify([x], f, modules="numpy") try: f_at_nodes = [f(xc) for xc in nodes] except NameError as e: raise NameError("numpy does not support special function:\n%s" % e) print f_at_nodes if not symbolic and filename is not None: xf = np.linspace(Omega[0], Omega[1], 10001) U = np.asarray(c) # c is a plain array xu, u = u_glob(U, elements, nodes) import scitools.std as plt # import matplotlib.pyplot as plt plt.plot(xu, u, "-", xf, f(xf), "--") plt.legend(["u", "f"]) plt.savefig(filename + ".pdf") plt.savefig(filename + ".png") return c
def run_solver_and_plot(solver, 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) solver.set(f_kwargs={'w': w}) solver.set_initial_condition([0, I]) u, t = solver.solve(t_mesh) from vib_undamped import solver u2, t2 = solver(I, w, dt, T) plt.plot(t, u[:,1], 'r-', t2, u2, 'b-') plt.legend(['Euler-Cromer', '2nd-order ODE']) plt.xlabel('t'); plt.ylabel('u') plt.savefig('tmp1.png'); plt.savefig('tmp1.pdf')
def u_sines(): """ Plot sine basis functions and a resulting u to illustrate what it means to use global basis functions. """ import matplotlib.pyplot as plt x = np.linspace(0, 4, 1001) psi0 = np.sin(2*np.pi/4*x) psi1 = np.sin(2*np.pi*x) psi2 = np.sin(2*np.pi*4*x) u = 4*psi0 - 0.5*psi1 - 0*psi2 plt.plot(x, psi0, 'r-', label=r"$\psi_0$") plt.plot(x, psi1, 'g-', label=r"$\psi_1$") #plt.plot(x, psi2, label=r"$\psi_2$") plt.plot(x, u, 'b-', label=r"u") plt.legend() plt.savefig('tmp_u_sines.pdf') plt.savefig('tmp_u_sines.png') plt.show()
def fe_basis_function_figure(d, target_elm=[1], N_e=3, derivative=0, filename='tmp.pdf', labels=False): """ Draw all basis functions (or their derivative), of degree d, associated with element target_elm (may be list of elements). Add a mesh with N_e elements. """ nodes, elements = mesh_uniform(N_e, d) """ x = 1.1 print locate_element_vectorized(x, elements, nodes) print locate_element_scalar(x, elements, nodes) x = 0.1, 0.4, 0.8 print locate_element_vectorized(x, elements, nodes) """ if isinstance(target_elm, int): target_elm = [target_elm] # wrap in list # Draw the basis functions for element 1 phi_drawn = [] # list of already drawn phi functions ymin = ymax = 0 for e in target_elm: for i in elements[e]: if not i in phi_drawn: x, y = phi_glob(i, elements, nodes, derivative=derivative) if x is None and y is None: return # abort ymax = max(ymax, max(y)) ymin = min(ymin, min(y)) plt.plot(x, y, '-') plt.hold('on') if labels: if plt.backend == 'gnuplot': if derivative == 0: plt.legend(r'basis func. %d' % i) else: plt.legend(r'derivative of basis func. %d' % i) elif plt.backend == 'matplotlib': if derivative == 0: plt.legend(r'\varphi_%d' % i) else: plt.legend(r"\varphi_%d'(x)" % i) phi_drawn.append(i) plt.axis([nodes[0], nodes[-1], ymin - 0.1, ymax + 0.1]) plot_fe_mesh(nodes, elements, element_marker=[ymin - 0.1, ymax + 0.1]) plt.hold('off') plt.savefig(filename)
def u_sines(): """ Plot sine basis functions and a resulting u to illustrate what it means to use global basis functions. """ import matplotlib.pyplot as plt x = np.linspace(0, 4, 1001) psi0 = np.sin(2*np.pi/4*x) psi1 = np.sin(2*np.pi*x) psi2 = np.sin(2*np.pi*4*x) #u = 4*psi0 - 0.5*psi1 - 0*psi2 u = 4*psi0 - 0.5*psi1 plt.plot(x, psi0, 'r-', label=r"$\psi_0$") plt.plot(x, psi1, 'g-', label=r"$\psi_1$") #plt.plot(x, psi2, label=r"$\psi_2$") plt.plot(x, u, 'b-', label=r"$u=4\psi_0 - \frac{1}{2}\psi_1$") plt.legend() plt.savefig('u_example_sin.pdf') plt.savefig('u_example_sin.png') plt.show()
def fe_basis_function_figure(d, target_elm=[1], n_e=3, derivative=0, filename='tmp.pdf', labels=False): """ Draw all basis functions (or their derivative), of degree d, associated with element target_elm (may be list of elements). Add a mesh with n_e elements. """ nodes, elements = mesh_uniform(n_e, d) """ x = 1.1 print locate_element_vectorized(x, elements, nodes) print locate_element_scalar(x, elements, nodes) x = 0.1, 0.4, 0.8 print locate_element_vectorized(x, elements, nodes) """ if isinstance(target_elm, int): target_elm = [target_elm] # wrap in list # Draw the basis functions for element 1 phi_drawn = [] # list of already drawn phi functions ymin = ymax = 0 for e in target_elm: for i in elements[e]: if not i in phi_drawn: x, y = phi_glob(i, elements, nodes, derivative=derivative) if x is None and y is None: return # abort ymax = max(ymax, max(y)) ymin = min(ymin, min(y)) plt.plot(x, y, '-') plt.hold('on') if labels: if plt.backend == 'gnuplot': if derivative == 0: plt.legend(r'basis function no. %d' % i) else: plt.legend(r'derivative of basis function no. %d' % i) elif plt.backend == 'matplotlib': if derivative == 0: plt.legend(r'\varphi_%d' % i) else: plt.legend(r"\varphi_%d'(x)" % i) phi_drawn.append(i) plt.axis([nodes[0], nodes[-1], ymin-0.1, ymax+0.1]) plot_fe_mesh(nodes, elements, element_marker=[ymin-0.1, ymax+0.1]) plt.hold('off') plt.savefig(filename)
def run_solver_and_plot(solver, 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) solver.set(f_kwargs={'w': w}) solver.set_initial_condition([0, I]) u, t = solver.solve(t_mesh) from vib_undamped import solver u2, t2 = solver(I, w, dt, T) plt.plot(t, u[:, 1], 'r-', t2, u2, 'b-') plt.legend(['Euler-Cromer', '2nd-order ODE']) plt.xlabel('t') plt.ylabel('u') plt.savefig('tmp1.png') plt.savefig('tmp1.pdf')
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, 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 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 f(u, t): return -a * u def exact_solution(t): return I * np.exp(-a * t) I = 1 a = 2 T = 5 tol = float(sys.argv[1]) solver = odespy.DormandPrince(f, atol=tol, rtol=0.1 * tol) N = 1 # just one step - let the scheme find its intermediate points t_mesh = np.linspace(0, T, N + 1) t_fine = np.linspace(0, T, 10001) solver.set_initial_condition(I) u, t = solver.solve(t_mesh) # u and t will only consist of [I, u^N] and [0,T] # solver.u_all and solver.t_all contains all computed points plt.plot(solver.t_all, solver.u_all, 'ko') plt.hold('on') plt.plot(t_fine, exact_solution(t_fine), 'b-') plt.legend(['tol=%.0E' % tol, 'exact']) plt.savefig('tmp_odespy_adaptive.png') plt.show()
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')
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 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 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))
t_mesh = np.linspace(0, T, Nt + 1) t_fine = np.linspace(0, T, 10001) solver.set_initial_condition(u0) u, t = solver.solve(t_mesh) # u and t will only consist of [I, u^Nt] and [0,T], i.e. 2 values # each, while solver.u_all and solver.t_all contain all computed # points. solver.u_all is a list with arrays, one array (with 2 # values) for each point in time. u_adaptive = np.array(solver.u_all) # For comparison, we solve also with simple FDM method import sys, os sys.path.insert(0, os.path.join(os.pardir, 'src-vib')) from vib_undamped import solver as simple_solver Nt_simple = len(solver.t_all) dt = float(T) / Nt_simple u_simple, t_simple = simple_solver(I, w, dt, T) # Compare in plot: adaptive, constant dt, exact plt.plot(solver.t_all, u_adaptive[:, 0], 'k-') plt.hold('on') plt.plot(t_simple, u_simple, 'r--') plt.plot(t_fine, u_exact(t_fine), 'b-') plt.legend(['tol=%.0E' % tol, 'u simple', 'exact']) plt.savefig('tmp_odespy_adaptive.png') plt.savefig('tmp_odespy_adaptive.pdf') plt.show() raw_input()
T = num_periods * P t = np.linspace(0, T, time_steps_per_period * num_periods + 1) import odespy def f(u, t, alpha): # Note the sequence of unknowns: v, u (v=du/dt) v, u = u return [-alpha * np.sign(v) - u, v] solver = odespy.RK4(f, f_args=[alpha]) solver.set_initial_condition([beta, 1]) # sequence must match f uv, t = solver.solve(t) u = uv[:, 1] # recall sequence in f: v, u v = uv[:, 0] return u, t if __name__ == '__main__': alpha_values = [0, 0.05, 0.1] for alpha in alpha_values: u, t = simulate(alpha, 0, 6, 60) plt.plot(t, u) plt.hold('on') plt.legend([r'$\alpha=%g$' % alpha for alpha in alpha_values]) plt.xlabel(r'$\bar t$') plt.ylabel(r'$\bar u$') plt.savefig('tmp.png') plt.savefig('tmp.pdf') plt.show() raw_input() # for scitools' matplotlib engine
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
T = num_periods * P t = np.linspace(0, T, time_steps_per_period * num_periods + 1) import odespy def f(u, t, alpha): # Note the sequence of unknowns: v, u (v=du/dt) v, u = u return [-alpha * np.sign(v) - u, v] solver = odespy.RK4(f, f_args=[alpha]) solver.set_initial_condition([beta, 1]) # sequence must match f uv, t = solver.solve(t) u = uv[:, 1] # recall sequence in f: v, u v = uv[:, 0] return u, t if __name__ == "__main__": alpha_values = [0, 0.05, 0.1] for alpha in alpha_values: u, t = simulate(alpha, 0, 6, 60) plt.plot(t, u) plt.hold("on") plt.legend([r"$\alpha=%g$" % alpha for alpha in alpha_values]) plt.xlabel(r"$\bar t$") plt.ylabel(r"$\bar u$") plt.savefig("tmp.png") plt.savefig("tmp.pdf") plt.show() raw_input() # for scitools' matplotlib engine
import sys #import matplotlib.pyplot as plt import scitools.std as plt def f(u, t): return -a*u def u_exact(t): return I*np.exp(-a*t) I = 1; a = 2; T = 5 tol = float(sys.argv[1]) solver = odespy.DormandPrince(f, atol=tol, rtol=0.1*tol) Nt = 1 # just one step - let the scheme find its intermediate points t_mesh = np.linspace(0, T, Nt+1) t_fine = np.linspace(0, T, 10001) solver.set_initial_condition(I) u, t = solver.solve(t_mesh) # u and t will only consist of [I, u^Nt] and [0,T] # solver.u_all and solver.t_all contains all computed points plt.plot(solver.t_all, solver.u_all, 'ko') plt.hold('on') plt.plot(t_fine, u_exact(t_fine), 'b-') plt.legend(['tol=%.0E' % tol, 'exact']) plt.savefig('tmp_odespy_adaptive.png') 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 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
solver.set_initial_condition(u0) u, t = solver.solve(t_mesh) # u and t will only consist of [I, u^Nt] and [0,T], i.e. 2 values # each, while solver.u_all and solver.t_all contain all computed # points. solver.u_all is a list with arrays, one array (with 2 # values) for each point in time. u_adaptive = np.array(solver.u_all) # For comparison, we solve also with simple FDM method Nt_simple = len(solver.t_all) # get no of time steps from ad. meth. t_simple = np.linspace(0, T, Nt_simple+1) # create equal steps dt = t_simple[1] - t_simple[0] # constant time step u_simple = np.zeros(Nt_simple+1) u_simple[0] = I u_simple[1] = u_simple[0] - 0.5*dt**2*w**2*u_simple[0] for n in range(1, Nt_simple): u_simple[n+1] = 2*u_simple[n] - u_simple[n-1] - \ dt**2*w**2*u_simple[n] plt.plot(solver.t_all, u_adaptive[:,0], 'k-') plt.hold('on') plt.plot(t_simple, u_simple, 'r--') plt.plot(t_fine, u_exact(t_fine), 'b-') plt.legend(['tol=%.0E' % tol, 'u simple', 'exact']) plt.savefig('tmp_odespy_adaptive.png') plt.savefig('tmp_odespy_adaptive.pdf') plt.show()
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))
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'): """ 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
import scitools.std as plt import sys import numpy as np import matplotlib.pyplot as plt x, y = np.loadtxt('volt.txt', delimiter=',', unpack=True) plt.figure(1) plt.plot(x, y, '*', linewidth=1) # avoid markers by spec. line type #plt.xlim([0.0, 10]) #plt.ylim([0.0, 2]) plt.legend(['Force-- Tip'], loc='upper right', prop={"family": "Times New Roman"}) plt.xlabel('Sampled time') plt.ylabel('$Force /m$') plt.savefig('volt1v.png') plt.savefig('volt1v.pdf') plt.hold(True)
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
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))
import odespy def f(u, t, Theta): # Note the sequence of unknowns: omega, theta # omega = d(theta)/dt, angular velocity omega, theta = u return [-Theta**(-1) * np.sin(Theta * theta), omega] solver = odespy.RK4(f, f_args=[Theta]) solver.set_initial_condition([0, 1]) # sequence must match f u, t = solver.solve(t) theta = u[:, 1] # recall sequence in f: omega, theta return theta, t if __name__ == '__main__': Theta_values_degrees = [1, 20, 45, 60] for Theta_degrees in Theta_values_degrees: Theta = Theta_degrees * np.pi / 180 theta, t = simulate(Theta, 6, 60) plt.plot(t, theta) plt.hold('on') plt.legend([r'$\Theta=%g$' % Theta for Theta in Theta_values_degrees], loc='lower left') plt.xlabel(r'$\bar t$') plt.ylabel(r'$\bar\theta$') plt.savefig('tmp.png') plt.savefig('tmp.pdf') plt.show() raw_input()
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 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 # 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))