import numpy as np import matplotlib.pyplot as plt f = lambdify([x], tanh(arg), modules='numpy') # Compute exact f on a fine mesh x_fine = np.linspace(0, 1, 101) f_fine = f(x_fine) for d in 3, 4: for N_e in 1, 2, 4: h = 1.0 / N_e # element length vertices = [i * h for i in range(N_e + 1)] cells = [[e, e + 1] for e in range(N_e)] dof_map = [[d * e + i for i in range(d + 1)] for e in range(N_e)] N_n = d * N_e + 1 # Number of nodes x_nodes = np.linspace(0, 1, N_n) # Node coordinates U = f(x_nodes) # Interpolation method samples node values x, u, _ = u_glob(U, vertices, cells, dof_map, resolution_per_element=51) plt.figure() plt.plot(x, u, '-', x_fine, f_fine, '--', x_nodes, U, 'bo') plt.legend( ['%d P%d elements' % (N_e, d), 'exact', 'interpolation points'], loc='upper left') plt.savefig('tmp_%d_P%d.pdf' % (N_e, d)) plt.savefig('tmp_%d_P%d.png' % (N_e, d)) 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
results[case] = {} for d in d_values: results[case][d] = {'E': [], 'h': [], 'r': []} for N_e in [4, 8, 16, 32, 64, 128]: try: c = approximate( f, symbolic=False, numint='GaussLegendre%d' % (d+1), d=d, N_e=N_e, Omega=Omega, filename='tmp_%s_d%d_e%d' % (case, d, N_e)) except np.linalg.linalg.LinAlgError as e: print str(e) continue vertices, cells, dof_map = mesh_uniform( N_e, d, Omega, symbolic=False) xc, u, _ = u_glob(c, vertices, cells, dof_map, 51) e = f_func(xc) - u # Trapezoidal integration of the L2 error over the # xc/u patches e2 = e**2 L2_error = 0 for i in range(len(xc)-1): L2_error += 0.5*(e2[i+1] + e2[i])*(xc[i+1] - xc[i]) L2_error = np.sqrt(L2_error) h = (Omega[1] - Omega[0])/float(N_e) results[case][d]['E'].append(L2_error) results[case][d]['h'].append(h) # Compute rates h = results[case][d]['h'] E = results[case][d]['E'] for i in range(len(h)-1):
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
results[case] = {} for d in d_values: results[case][d] = {'E': [], 'h': [], 'r': []} for N_e in [4, 8, 16, 32, 64, 128]: try: c = approximate( f, symbolic=False, numint='GaussLegendre%d' % (d+1), d=d, N_e=N_e, Omega=Omega, filename='tmp_%s_d%d_e%d' % (case, d, N_e)) except np.linalg.linalg.LinAlgError as e: print(str(e)) continue vertices, cells, dof_map = mesh_uniform( N_e, d, Omega, symbolic=False) xc, u, _ = u_glob(c, vertices, cells, dof_map, 51) e = f_func(xc) - u # Trapezoidal integration of the L2 error over the # xc/u patches e2 = e**2 L2_error = 0 for i in range(len(xc)-1): L2_error += 0.5*(e2[i+1] + e2[i])*(xc[i+1] - xc[i]) L2_error = np.sqrt(L2_error) h = (Omega[1] - Omega[0])/float(N_e) results[case][d]['E'].append(L2_error) results[case][d]['h'].append(h) # Compute rates h = results[case][d]['h'] E = results[case][d]['E'] for i in range(len(h)-1):
# Interpolation method import numpy as np import matplotlib.pyplot as plt f = lambdify([x], tanh(arg), modules='numpy') # Compute exact f on a fine mesh x_fine = np.linspace(0, 1, 101) f_fine = f(x_fine) for d in 3, 4: for N_e in 1, 2, 4: h = 1.0/N_e # element length vertices = [i*h for i in range(N_e+1)] cells = [[e, e+1] for e in range(N_e)] dof_map = [[d*e + i for i in range(d+1)] for e in range(N_e)] N_n = d*N_e + 1 # Number of nodes x_nodes = np.linspace(0, 1, N_n) # Node coordinates U = f(x_nodes) # Interpolation method samples node values x, u, _ = u_glob(U, vertices, cells, dof_map, resolution_per_element=51) plt.figure() plt.plot(x, u, '-', x_fine, f_fine, '--', x_nodes, U, 'bo') plt.legend(['%d P%d elements' % (N_e, d), 'exact', 'interpolation points'], loc='upper left') plt.savefig('tmp_%d_P%d.pdf' % (N_e, d)) plt.savefig('tmp_%d_P%d.png' % (N_e, d)) plt.show()