download
raw
9.77 kB
import numpy as np
import sympy as sym
import sys
def mesh_uniform(N_e, d, Omega=[0,1], symbolic=False):
"""
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.
If symbolic is True, the nodes are expressed as rational
sympy expressions with the symbol h as element length.
"""
if symbolic:
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)]
else:
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
from Lagrange import Lagrange_polynomial, Chebyshev_nodes, Lagrange_polynomials
def basis(d, point_distribution='uniform', symbolic=False):
"""
Return all local basis function phi as functions of the
local point X in a 1D element with d+1 nodes.
If symbolic=True, return symbolic expressions, else
return Python functions of X.
point_distribution can be 'uniform' or 'Chebyshev'.
"""
X = sym.symbols('X')
if d == 0:
phi_sym = [1]
else:
if point_distribution == 'uniform':
if symbolic:
h = sym.Rational(1, d) # node spacing
nodes = [2*i*h - 1 for i in range(d+1)]
else:
nodes = np.linspace(-1, 1, d+1)
elif point_distribution == 'Chebyshev':
# Just numeric nodes
nodes = Chebyshev_nodes(-1, 1, d)
phi_sym = [Lagrange_polynomial(X, r, nodes)
for r in range(d+1)]
# Transform to Python functions
phi_num = [sym.lambdify([X], phi_sym[r], modules='numpy')
for r in range(d+1)]
return phi_sym if symbolic else phi_num
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 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).
(The solution of the linear system is in U.)
Method: Run through each element and compute curve coordinates
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
phi = basis(d)
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](X)
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 floats 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):
if symbolic:
I = sym.integrate(f*phi[r]*detJ, (X, -1, 1))
if not symbolic or 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 exemplify_element_matrix_vector(f, d, symbolic=True):
phi = basis(d)
print 'phi basis (reference element):\n', phi
Omega_e = [0.1, 0.2]
A_e = element_matrix(phi, Omega_e=Omega_e, symbolic=symbolic)
if symbolic:
h = sym.Symbol('h')
Omega_e=[1*h, 2*h]
b_e = element_vector(f, phi, Omega_e=Omega_e,
symbolic=symbolic)
print 'Element matrix:\n', A_e
print 'Element vector:\n', b_e
def assemble(nodes, elements, phi, f, symbolic=True):
N_n, N_e = len(nodes), len(elements)
if symbolic:
A = sym.zeros((N_n, N_n))
b = sym.zeros((N_n, 1)) # note: (N_n, 1) matrix
else:
A = np.zeros((N_n, N_n))
b = np.zeros(N_n)
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)
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'):
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 phi_glob(i, elements, nodes, resolution_per_element=41,
derivative=0):
"""
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)
if derivative == 0:
phi = phi_r(r, X, d)
elif derivative == 1:
phi = dphi_r(r, X, d)
if phi is None:
return None, None
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 phi_r(r, X, d):
"""
Return local basis function phi_r at local point X in
a 1D element with d+1 nodes.
"""
if d == 0:
return np.ones_like(X)
nodes = np.linspace(-1, 1, d+1)
return Lagrange_polynomial(X, r, nodes)
def dphi_r(r, X, d, point_distribution='uniform'):
"""
Return the derivative of local basis function phi_r at
local point X in a 1D element with d+1 nodes.
point_distribution can be 'uniform' or 'Chebyshev'.
"""
# Strange function....
if isinstance(X, np.ndarray):
z = np.zeros(len(X))
if d == 0:
return 0 + z
elif d == 1:
if r == 0:
return -0.5 + z
elif r == 1:
return 0.5 + z
elif d == 2:
if r == 0:
return X - 0.5
elif r == 1:
return -2*X
elif r == 2:
return X + 0.5
else:
print 'dphi_r only supports d=0,1,2, not %d' % d
return None
if __name__ == '__main__':
pass

Xet Storage Details

Size:
9.77 kB
·
Xet hash:
b20e55bd29c52b2b63a4f8feb040b70404d1ed108e812917988cecd809384dfe

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.