Finite elements in two dimensions
Follow 1d case, need local arrays.
Stiffness matrix
\[ k^e_{ab} = \int_{\triangle^e} \text{d}\triangle^e \, \left( \partial_{x} N_a (\mathbf{x}) \partial_{x} N_b(\mathbf{x}) + \partial_{y} N_a(\mathbf{x}) \partial_{y} N_b(\mathbf{x}) \right). \]
Force vector
\[ f^e_b = \int_{\triangle^e} \text{d}\triangle^e \, N_b(\mathbf{x}) S(\mathbf{x}). \]
\[ \begin{aligned} \int_\triangle \mathrm{d} \triangle \phi(x, y) &= \int_{0}^1 \mathrm{d}\xi_2 \int_0^{1-\xi_2} \mathrm{d}\xi_1 \phi(\xi_1, \xi_2) j(\xi_1, \xi_2) \, , \\ j = \det \left[ \frac{\partial \mathbf{x}}{\partial \symbf{\xi}} \right] &= \det \begin{pmatrix} \partial_{\xi_1} x & \partial_{\xi_2} x \\ \partial_{\xi_1} y & \partial_{\xi_2} y \end{pmatrix} \, . \end{aligned} \]
Gauss quadrature on reference triangle:
\[ \begin{split} \int_{0}^1 \mathrm{d}\xi_2 \int_0^{1-\xi_2} \mathrm{d}\xi_1 \psi(\symbf{\xi}) \simeq \tfrac{1}{6} \sum_{j=1}^3 \psi(\mathbf{x}(\symbf{\xi}^{(j)})) \, , \\ \symbf{\xi}^{(1)} = \tfrac{1}{6} \begin{pmatrix} 1 & 1 \end{pmatrix} \, , \quad \symbf{\xi}^{(2)} = \tfrac{1}{6} \begin{pmatrix} 1 & 4 \end{pmatrix} \, , \quad \symbf{\xi}^{(3)} = \tfrac{1}{6} \begin{pmatrix} 4 & 1 \end{pmatrix} \, . \end{split} \]
\[ x = x^e_0 N_0(\symbf{\xi}) + x^e_1 N_1(\symbf{\xi}) + x^e_2 N_2(\symbf{\xi}) \, . \]
Linear basis on reference triangle
\[ \begin{split} N_0 = 1 - \xi_1 - \xi_2, \quad N_1 = \xi_1, \quad N_2 = \xi_2 \\ \implies \qquad \partial_{\xi_1} x = -x^e_0 + x^e_1 \, . \end{split} \]
Now need four things:
nodes (\(\mathtt{i} \to \mathbf{x}\));IEN (\(\mathtt{e} \to \mathtt{i}_0, \mathtt{i}_1, \mathtt{i}_2\));LM linking local/global numbering.Node numbers arbitrary: add all nodes not on Dirichlet boundaries to ID.
\[ \mathtt{LM}(\mathtt{a}, \mathtt{e}) = \mathtt{ID}(\mathtt{IEN}(\mathtt{e}, \mathtt{a})) \, . \]
nodes = np.loadtxt('data/ews_nodes_s5k_lc50k.txt')
IEN = np.loadtxt('data/ews_IEN_s5k_lc50k.txt',
dtype=np.int64)
boundary_nodes = np.loadtxt('data/ews_bdry_s5k_lc50k.txt',
dtype=np.int64)
# Make all boundary points Dirichlet
ID = np.zeros(len(nodes), dtype=np.int64)
n_eq = 0
for i in range(len(nodes[:, 1])):
if i in boundary_nodes:
ID[i] = -1
else:
ID[i] = n_eq
n_eq += 1
N_equations = np.max(ID)+1
N_elements = IEN.shape[0]
N_nodes = nodes.shape[0]
N_dim = nodes.shape[1]
# Location matrix
LM = np.zeros_like(IEN.T)
for e in range(N_elements):
for a in range(3):
LM[a,e] = ID[IEN[e,a]]
# Global stiffness matrix and force vector
K = np.zeros((N_equations, N_equations))
F = np.zeros((N_equations,))
# Loop over elements
for e in range(N_elements):
k_e = stiffness_2d(nodes[IEN[e,:],:])
f_e = force_2d(nodes[IEN[e,:],:], S)
for a in range(3):
A = LM[a, e]
for b in range(3):
B = LM[b, e]
if (A >= 0) and (B >= 0):
K[A, B] += k_e[a, b]
if (A >= 0):
F[A] += f_e[a]
# Solve
Psi_interior = np.linalg.solve(K, F)
Psi_A = np.zeros(N_nodes)
for n in range(N_nodes):
if ID[n] >= 0: # Otherwise Psi should be zero, and we've initialized that already.
Psi_A[n] = Psi_interior[ID[n]]