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, 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
f_func = lambdify([x], f, modules='numpy') Omega = cases[case]['Omega'] 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']
f_func = lambdify([x], f, modules='numpy') Omega = cases[case]['Omega'] 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']