9.2.2. Zweidimensionaler Fall#
Eine reguläre Triangulierung \(\mathcal{T} = \{T_1, \ldots, T_M\}\) eines Gebiets \(\Omega\) ist die Zerlegung in Dreiecke \(T_i\) so, dass \(\bar{\Omega} = \cup_i T_i\) und \(T_i\cap T_j\) ist
entweder leer
oder hat eine gemeinsame Kante.
In einem erweiterten Sinne kann die Triangulierung aus verschiedenen Elemente bestehen: Dreiecke, Vierecke, (Tetraeder, Hexeder, Prismen, Pyramiden im dreidimensionalen). Die finite Elemente werden typischerweise, wie wir es im eindimensionalen gemacht haben, auf einem Referenzelement definiert. Die einzelnen Elemente der Zerlegung können mit Hilfe einer affinen Transformation und dem Referenzelement beschrieben werden.
Die Koordinaten Transformation im zweidimensionalen erfordert etwas mehr Rechenaufwand.
Ein Dreieck \(T_i\) in allgemeiner Lage mit den Eckpunkten \(P_1(x_1,y_1)\), \(P_2(x_2,y_2)\) und \(P_3(x_3,y_3)\), welche im Gegenuhrzeigersinn fortlaufend numeriert seien, wie dies in Abb. Abb. 9.7 erfolgte, kann mittels der linearen Transformation
bijektiv auf das Einheitsdreieck \(T\) abgebildet werden. Für das Dreieck \(T_i\) gegeben durch die drei Punkte \(\vec{p}_{i,1}, \vec{p}_{i,2}, \vec{p}_{i,3}\) definieren wir die Matrix
Damit können wir die Transformation wie folgt schreiben
bzw. die inverse Transformation
Das Flächenelement \(dx dy\) kann mit der Jacobi-Determinante \(J = \det A_i\) der Transformation durch \(dx\, dy = J\, d\xi\, d\eta\) ersetzt werden. Die Basisfunktion \(\varphi\) auf dem Element \(T_i\) kann (analog zum eindimensionalen Fall) mit Hilfe der Basisfunktion \(\tilde{\varphi}\) auf dem Referenzelement beschrieben werden. Es gilt
analog zu (9.7). Für die Jacobimatrix folgt mit Hilfe der Kettenregel
und damit für den Gradient
Für die Elementsteifigkeitsmatrix folgt somit
mit
und für die Elementmassenmatrix
Beispiel: Betrachten wir Basisfunktionen erster Ordnung
auf dem Einheitsdreieck, gegeben durch die Punkte \((0,0), (1,0), (0,1)\). In dem Fall gilt \(N_e = 2\).
Show code cell content
import numpy as np
from pandas import DataFrame
def highlight_ortho(s):
is_ortho = np.abs(s) < 1e-13
return ['background-color: yellow' if v else '' for v in is_ortho]
import matplotlib.pyplot as plt
from myst_nb import glue
# Basisfunktionen auf dem Referenzelement
def myshape(t, j):
xi, eta = t
if j == 0:
return 1-xi-eta
elif j == 1:
return xi
else:
return eta
# Gradienten der Basisfunktionen auf dem Referenzelement
def Dmyshape(t, j):
if j == 0:
return np.array([-1,-1])
elif j == 1:
return np.array([1,0])
else:
return np.array([0,1])
Die inverse Jacobi-Matrix der Transformation ist gegeben durch
def invDsigma(p1,p2,p3):
return np.linalg.inv(np.array([(p2-p1),(p3-p1)]).T)
Damit können wir für ein beliebiges Dreieck die Elementsteifigkeitsmatrix (9.10) wie folgt berechnen
# Berechnung der C_i Matrix und Jacobi Determinante
def CnJ(p1,p2,p3):
A = np.array([(p2-p1),(p3-p1)]).T
invA = np.linalg.inv(A)
return invA@invA.T, np.linalg.det(A)
# Gebietsintegration über Einheitsdreieck
from scipy.integrate import dblquad
def quadT(f):
return dblquad(f, 0, 1, 0, lambda x: 1-x)[0]
# Integration über Dreieck gegeben durch (1,1), (1.5,-1), (2,1.2)
Ci, Ji = CnJ(np.array([1,1]),np.array([1.5,-1]),np.array([2,1.2]))
Ai = np.array([[ quadT(lambda x,y: Dmyshape([x,y], j)@Ci@Dmyshape([x,y], k)*Ji)
for k in range(3)] for j in range(3)])
Ai = DataFrame(Ai)
Ai.style.\
apply(highlight_ortho).\
set_table_attributes('style="font-size: 12px"')
0 | 1 | 2 | |
---|---|---|---|
0 | 1.211905 | -0.223810 | -0.988095 |
1 | -0.223810 | 0.247619 | -0.023810 |
2 | -0.988095 | -0.023810 | 1.011905 |
Die Matrix \(C_i\) kann analytisch berechnet werden so, womit die Invertierung hinfällig wird. Für \(C_i\cdot J_i^2\) erhalten wir
Show code cell source
from sympy import symbols, Matrix
p1x,p1y, p2x,p2y, p3x,p3y, = symbols('p_1_x,p_1_y,p_2_x,p_2_y,p_3_x,p_3_y')
p1 = np.array([p1x,p1y])
p2 = np.array([p2x,p2y])
p3 = np.array([p3x,p3y])
A=Matrix(np.array([p2-p1,p3-p1]).T).as_immutable()
J = A.det()
invA=A.inverse().simplify()
CJ2=invA@invA.T*J**2
CJ2.simplify()
und damit
mit
Für die Elementmassenmatrix (9.11) folgt
Bi = np.array([[ quadT(lambda x,y: myshape([x,y], j)*myshape([x,y], k)*Ji)
for k in range(3)] for j in range(3)])
Bi = DataFrame(Bi)
Bi.style.\
apply(highlight_ortho).\
set_table_attributes('style="font-size: 12px"')
0 | 1 | 2 | |
---|---|---|---|
0 | 0.175000 | 0.087500 | 0.087500 |
1 | 0.087500 | 0.175000 | 0.087500 |
2 | 0.087500 | 0.087500 | 0.175000 |
Das Assembling des Gesamtsystems erfolgt mit dem Algorithmus Algorithm 9.1 und der Abbildung der Freiheitsgrade \(T\) analog zu (9.8) für den zweidimensionalen Fall
wobei \(N\) im Fall von Elemente erster Ordnung die Anzahl Knoten und \(n\) die Anzahl Elemente (Dreiecke).
Es erweist sich mathematisch wie auch Software technisch als bedeutend effizienter, die Berechnung der System Matrizen über die Triangulierung zu berechnen und die einzelnen Beiträge in der globalen Matrix aufzukummulieren. Diesen Prozess nennt man Assembling.
Allgemein können wir dies in der Form
und
schreiben, wobei \(C_T\) die Verknüpfung zwischen lokalen und globalen Funktionen darstellt.