Buckets:
| from scitools.std import plot, savefig, hold, axis, legend | |
| import numpy as np | |
| import sympy as sym | |
| def mesh(N_e, d, Omega=[0,1]): | |
| """ | |
| Return a 1D finite element mesh on Omega with N_e elements of | |
| the polynomial degree d. The nodes are uniformly spaced. | |
| Return nodes (coordinates) and elements (connectivity) lists. | |
| """ | |
| nodes = np.linspace(Omega[0], Omega[1], N_e*d + 1).tolist() | |
| elements = [[e*d + i for i in range(d+1)] \ | |
| for e in range(N_e)] | |
| return nodes, elements | |
| def mesh_symbolic(N_e, d, Omega=[0,1]): | |
| """ | |
| Return a 1D finite element mesh on Omega with N_e elements of | |
| the polynomial degree d. The nodes are uniformly spaced. | |
| Return nodes (coordinates) and elements (connectivity) | |
| lists, using symbols for the coordinates (rational expressions | |
| with h as the uniform element length). | |
| """ | |
| h = sym.Symbol('h') # element length | |
| dx = h*sym.Rational(1, d) # node spacing | |
| nodes = [Omega[0] + i*dx for i in range(N_e*d + 1)] | |
| elements = [[e*d + i for i in range(d+1)] \ | |
| for e in range(N_e)] | |
| return nodes, elements | |
| def mesh2(N_e, d, Omega=[0,1]): | |
| """ | |
| Return a 1D finite element mesh on Omega with N_e elements of | |
| the polynomial degree d. The nodes are uniformly spaced. | |
| Return vertices (vertices), local vertex to global | |
| vertex mapping (cells), and local to global degree of freedom | |
| mapping (dof_map). | |
| """ | |
| vertices = np.linspace(Omega[0], Omega[1], N_e + 1).tolist() | |
| doc_map = [[e*d + i for i in range(d+1)] for e in range(N_e)] | |
| cells = [[e, e+1] for e in range(N_e)] | |
| return vertices, cells, dof_map | |
| # Not yet used | |
| from Lagrange import Lagrange_polynomial, Lagrange_polynomials | |
| def phi_r(r, X, d): | |
| """ | |
| Return local basis function phi_r at local point X in | |
| a 1D element with d+1 nodes. | |
| """ | |
| if isinstance(X, sym.Symbol): | |
| # Use sym.Rational and integers for nodes | |
| # (to maximize nice-looking output) | |
| h = sym.Rational(1, d) | |
| nodes = [2*i*h - 1 for i in range(d+1)] | |
| else: | |
| # X is numeric: use floats for nodes | |
| nodes = np.linspace(-1, 1, d+1) | |
| return Lagrange_polynomial(X, r, nodes) | |
| def phi_r(r, X, d, point_distribution='uniform'): | |
| """ | |
| Return local basis function phi_r at local point X in | |
| a 1D element with d+1 nodes. | |
| point_distribution can be 'uniform' or 'Chebyshev'. | |
| """ | |
| if point_distribution == 'uniform': | |
| if isinstance(X, sym.Symbol): | |
| # Use sym.Rational and integers for nodes | |
| # (to maximize nice-looking output) | |
| h = sym.Rational(1, d) | |
| nodes = [2*i*h - 1 for i in range(d+1)] | |
| else: | |
| # X is numeric: use floats for nodes | |
| nodes = np.linspace(-1, 1, d+1) | |
| elif point_distribution == 'Chebyshev': | |
| nodes = Chebyshev_nodes(-1, 1, d) | |
| return Lagrange_polynomial(X, r, nodes) | |
| def basis(d=1): | |
| """Return the finite element basis in 1D of degree d.""" | |
| X = sym.Symbol('X') | |
| phi = [phi_r(r, X, d) for r in range(d+1)] | |
| return phi | |
| def affine_mapping(X, Omega_e): | |
| x_L, x_R = Omega_e | |
| return 0.5*(x_L + x_R) + 0.5*(x_R - x_L)*X | |
| def locate_element_scalar(x, elements, nodes): | |
| """Return number of element containing point x. Scalar version.""" | |
| for e, local_nodes in enumerate(elements): | |
| if nodes[local_nodes[0]] <= x <= nodes[local_nodes[-1]]: | |
| return e | |
| def locate_element_vectorized(x, elements, nodes): | |
| """Return number of element containing point x. Vectorized version.""" | |
| elements = np.asarray(elements) | |
| print elements[:,-1] | |
| element_right_boundaries = nodes[elements[:,-1]] | |
| return searchsorted(element_right_boundaries, x) | |
| # vectorized version for locating elements: numpy.searchsorted | |
| #http://www.astropython.org/snippet/2010/11/Interpolation-without-SciPy | |
| def phi_glob(i, elements, nodes, resolution_per_element=41): | |
| """ | |
| Compute (x, y) coordinates of the curve y = phi_i(x), | |
| where i is a global node number (used for plotting, e.g.). | |
| Method: Run through each element and compute the pieces | |
| of phi_i(x) on this element in the reference coordinate | |
| system. Adding up the patches yields the complete phi_i(x). | |
| """ | |
| x_patches = [] | |
| phi_patches = [] | |
| for e in range(len(elements)): | |
| Omega_e = (nodes[elements[e][0]], nodes[elements[e][-1]]) | |
| local_nodes = elements[e] | |
| d = len(local_nodes) - 1 | |
| X = np.linspace(-1, 1, resolution_per_element) | |
| if i in local_nodes: | |
| r = local_nodes.index(i) | |
| phi = phi_r(r, X, d) | |
| phi_patches.append(phi) | |
| x = affine_mapping(X, Omega_e) | |
| x_patches.append(x) | |
| else: | |
| # i is not a node in the element, phi_i(x)=0 | |
| x_patches.append(Omega_e) | |
| phi_patches.append([0, 0]) | |
| x = np.concatenate(x_patches) | |
| phi = np.concatenate(phi_patches) | |
| return x, phi | |
| def u_glob(U, elements, nodes, resolution_per_element=51): | |
| """ | |
| Compute (x, y) coordinates of a curve y = u(x), where u is a | |
| finite element function: u(x) = sum_i of U_i*phi_i(x). | |
| Method: Run through each element and compute cordinates | |
| over the element. | |
| """ | |
| x_patches = [] | |
| u_patches = [] | |
| for e in range(len(elements)): | |
| Omega_e = (nodes[elements[e][0]], nodes[elements[e][-1]]) | |
| local_nodes = elements[e] | |
| d = len(local_nodes) - 1 | |
| X = np.linspace(-1, 1, resolution_per_element) | |
| x = affine_mapping(X, Omega_e) | |
| x_patches.append(x) | |
| u_element = 0 | |
| for r in range(len(local_nodes)): | |
| i = local_nodes[r] # global node number | |
| u_element += U[i]*phi_r(r, X, d) | |
| u_patches.append(u_element) | |
| x = np.concatenate(x_patches) | |
| u = np.concatenate(u_patches) | |
| return x, u | |
| def element_matrix(phi, Omega_e, symbolic=True): | |
| n = len(phi) | |
| A_e = sym.zeros((n, n)) | |
| X = sym.Symbol('X') | |
| if symbolic: | |
| h = sym.Symbol('h') | |
| else: | |
| h = Omega_e[1] - Omega_e[0] | |
| detJ = h/2 # dx/dX | |
| for r in range(n): | |
| for s in range(r, n): | |
| A_e[r,s] = sym.integrate(phi[r]*phi[s]*detJ, (X, -1, 1)) | |
| A_e[s,r] = A_e[r,s] | |
| return A_e | |
| def element_vector(f, phi, Omega_e, symbolic=True): | |
| n = len(phi) | |
| b_e = sym.zeros((n, 1)) | |
| # Make f a function of X (via f.subs to avoid real numbers from lambdify) | |
| X = sym.Symbol('X') | |
| if symbolic: | |
| h = sym.Symbol('h') | |
| else: | |
| h = Omega_e[1] - Omega_e[0] | |
| x = (Omega_e[0] + Omega_e[1])/2 + h/2*X # mapping | |
| f = f.subs('x', x) # or subs(sym.Symbol('x'), x)? | |
| detJ = h/2 # dx/dX | |
| for r in range(n): | |
| I = sym.integrate(f*phi[r]*detJ, (X, -1, 1)) | |
| if isinstance(I, sym.Integral): | |
| print 'numerical integration of', f*phi[r]*detJ | |
| # Ensure h is numerical | |
| h = Omega_e[1] - Omega_e[0] | |
| detJ = h/2 | |
| integrand = sym.lambdify([X], f*phi[r]*detJ) | |
| I = sym.mpmath.quad(integrand, [-1, 1]) | |
| b_e[r] = I | |
| return b_e | |
| def assemble(nodes, elements, phi, f, symbolic=True): | |
| N_n, N_e = len(nodes), len(elements) | |
| A = sym.zeros((N_n, N_n)) | |
| b = sym.zeros((N_n, 1)) | |
| for e in range(N_e): | |
| Omega_e = [nodes[elements[e][0]], nodes[elements[e][-1]]] | |
| A_e = element_matrix(phi, Omega_e, symbolic) | |
| b_e = element_vector(f, phi, Omega_e, symbolic) | |
| #print 'element', e | |
| #print b_e | |
| for r in range(len(elements[e])): | |
| for s in range(len(elements[e])): | |
| A[elements[e][r],elements[e][s]] += A_e[r,s] | |
| b[elements[e][r]] += b_e[r] | |
| return A, b | |
| def approximate(f, symbolic=False, d=1, N_e=4, | |
| Omega=[0, 1], filename='tmp.eps'): | |
| phi = basis(d) | |
| print 'phi basis (reference element):\n', phi | |
| # Exemplify element matrix and vector | |
| Omega_e = [0.1, 0.2] | |
| A_e = element_matrix(phi, Omega_e=Omega_e, | |
| symbolic=symbolic, numint=numint) | |
| if symbolic: | |
| h = sym.Symbol('h') | |
| Omega_e=[1*h, 2*h] | |
| b_e = element_vector(f, phi, Omega_e=Omega_e, | |
| symbolic=symbolic, numint=numint) | |
| print 'Element matrix:\n', A_e | |
| print 'Element vector:\n', b_e | |
| if symbolic: | |
| nodes, elements = mesh_symbolic(N_e, d, Omega) | |
| else: | |
| nodes, elements = mesh(N_e, d, Omega) | |
| 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') | |
| c = A.LUsolve(b) | |
| print 'c:\n', c | |
| print 'Plain interpolation:' | |
| 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: | |
| xf = np.linspace(Omega[0], Omega[1], 10001) | |
| U = np.asarray(c) | |
| xu, u = u_glob(U, elements, nodes) | |
| from scitools.std import plot | |
| plot(xu, u, 'r-', | |
| xf, f(xf), 'b-', | |
| legend=('u', 'f'), | |
| savefig=filename) | |
| # Extended versions with numerical integration (Midpoint, Trap., Simpson) | |
| # (note that these functions overwrite those above!) | |
| def element_matrix(phi, Omega_e, symbolic=True, numint=None): | |
| n = len(phi) | |
| A_e = sym.zeros((n, n)) | |
| X = sym.Symbol('X') | |
| if symbolic: | |
| h = sym.Symbol('h') | |
| else: | |
| h = Omega_e[1] - Omega_e[0] | |
| detJ = h/2 # dx/dX | |
| if numint is None: | |
| for r in range(n): | |
| for s in range(r, n): | |
| A_e[r,s] = sym.integrate(phi[r]*phi[s]*detJ, (X, -1, 1)) | |
| A_e[s,r] = A_e[r,s] | |
| else: | |
| #phi = [sym.lambdify([X], phi[r]) for r in range(n)] | |
| # Do instead a phi_rj = phi[r].subs(X, Xj) to avoid real numbers | |
| for r in range(n): | |
| for s in range(r, n): | |
| for j in range(len(numint[0])): | |
| Xj, wj = numint[0][j], numint[1][j] | |
| phi_rj = phi[r].subs(X, Xj) | |
| phi_sj = phi[s].subs(X, Xj) | |
| A_e[r,s] += phi_rj*phi_sj*detJ*wj | |
| A_e[s,r] = A_e[r,s] | |
| return A_e | |
| def element_vector(f, phi, Omega_e, symbolic=True, numint=None): | |
| n = len(phi) | |
| b_e = sym.zeros((n, 1)) | |
| # Make f a function of X (via f.subs to avoid real numbers from lambdify) | |
| X = sym.Symbol('X') | |
| if symbolic: | |
| h = sym.Symbol('h') | |
| else: | |
| h = Omega_e[1] - Omega_e[0] | |
| x = (Omega_e[0] + Omega_e[1])/2 + h/2*X # mapping | |
| f = f.subs('x', x) | |
| detJ = h/2 | |
| if numint is None: | |
| for r in range(n): | |
| I = sym.integrate(f*phi[r]*detJ, (X, -1, 1)) | |
| if isinstance(I, sym.Integral): | |
| print 'numerical integration of', f*phi[r]*detJ | |
| # Ensure h is numerical | |
| h = Omega_e[1] - Omega_e[0] | |
| detJ = h/2 | |
| integrand = sym.lambdify([X], f*phi[r]*detJ) | |
| I = sym.mpmath.quad(integrand, [-1, 1]) | |
| b_e[r] = I | |
| else: | |
| #phi = [sym.lambdify([X], phi[r]) for r in range(n)] | |
| # f contains h from the mapping, substitute X with Xj | |
| # instead of f = sym.lambdify([X], f) | |
| for r in range(n): | |
| for j in range(len(numint[0])): | |
| Xj, wj = numint[0][j], numint[1][j] | |
| fj = f.subs(X, Xj) | |
| phi_rj = phi[r].subs(X, Xj) | |
| b_e[r] += fj*phi_rj*detJ*wj | |
| return b_e | |
| def assemble(nodes, elements, phi, f, symbolic=True, numint=None): | |
| N_n, N_e = len(nodes), len(elements) | |
| A = sym.zeros((N_n, N_n)) | |
| b = sym.zeros((N_n, 1)) | |
| for e in range(N_e): | |
| Omega_e = [nodes[elements[e][0]], nodes[elements[e][-1]]] | |
| A_e = element_matrix(phi, Omega_e, symbolic, numint) | |
| b_e = element_vector(f, phi, Omega_e, symbolic, numint) | |
| #print 'element', e | |
| #print b_e | |
| for r in range(len(elements[e])): | |
| for s in range(len(elements[e])): | |
| A[elements[e][r],elements[e][s]] += A_e[r,s] | |
| b[elements[e][r]] += b_e[r] | |
| return A, b | |
| def approximate(f, symbolic=False, d=1, N_e=4, numint=None, | |
| Omega=[0, 1], filename='tmp.eps'): | |
| if symbolic: | |
| if numint == 'Trapezoidal': | |
| numint = [[sym.S(-1), sym.S(1)], [sym.S(1), sym.S(1)]] # sumpy 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)]] | |
| else: | |
| 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]] | |
| else: | |
| numint = None | |
| phi = basis(d) | |
| print 'phi basis (reference element):\n', phi | |
| integration_msg = """ | |
| Symbolic integration failed, and then numerical integration | |
| encountered an undefined symbol (because of the symbolic expressions): | |
| %s""" | |
| # Exemplify element matrix and vector | |
| Omega_e = [0.1, 0.2] | |
| A_e = element_matrix(phi, Omega_e=Omega_e, | |
| symbolic=symbolic, numint=numint) | |
| if symbolic: | |
| h = sym.Symbol('h') | |
| Omega_e=[1*h, 2*h] | |
| try: | |
| b_e = element_vector(f, phi, Omega_e=Omega_e, | |
| symbolic=symbolic, numint=numint) | |
| except NameError as e: | |
| raise NameError(integration_msg % e) | |
| print 'Element matrix:\n', A_e | |
| print 'Element vector:\n', b_e | |
| if symbolic: | |
| try: | |
| nodes, elements = mesh_symbolic(N_e, d, Omega) | |
| except NameError as e: | |
| raise NameError(integration_msg % e) | |
| else: | |
| nodes, elements = mesh(N_e, d, Omega) | |
| A, b = assemble(nodes, elements, phi, f, | |
| symbolic=symbolic, numint=numint) | |
| 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') | |
| c = A.LUsolve(b) | |
| print 'c:\n', c | |
| print 'Plain interpolation:' | |
| 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) | |
| xu, u = u_glob(U, elements, nodes) | |
| from scitools.std import plot | |
| plot(xu, u, 'r-', | |
| xf, f(xf), 'b-', | |
| legend=('u', 'f'), | |
| savefig=filename) | |
| if __name__ == '__main__': | |
| import sys | |
| if len(sys.argv) < 2: | |
| print """Usage %s function arg1 arg2 arg3 ...""" % sys.argv[0] | |
| sys.exit(0) | |
| cmd = '%s(%s)' % (sys.argv[1], ', '.join(sys.argv[2:])) | |
| print cmd | |
| x = sym.Symbol('x') # needed in eval when expression f contains x | |
| eval(cmd) | |
Xet Storage Details
- Size:
- 15.4 kB
- Xet hash:
- 1a81d770dd00aa9e754cf18737f3822cdea279b2e3ff833602a22874a8428b9e
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.