Ubungsblatt P1 - (IGPM) | RWTH Aachen

Werbung
Rheinisch Westfälische Technische Hochschule
Institut für Geometrie und Praktische Mathematik
Numerische Analysis IV — SS 2007
Prof. Dr. Sebastian Noelle — Dipl. Math. Jörg Grande
Übungsblatt P1
Abgabe bis Dienstag, 22.5., 11:45,
in den Einwurfkasten
vor Raum 149, Hauptgebäude
Programmieraufgabe 1 (Massenmatrix)
Triangulierungen von Gebieten und Verfahren zur Diskretisierung von Operatoren sind Grundbestandteile aller
Finite-Elemente-Programme. Ziel der vorliegenden Aufgabe ist es eine gegebene Triangulierung einzulesen,
die Massenmatrix der stetigen, stückweise linearen Finiten Elemente aufzustellen und diese Matrix in einem
weiterverwendbaren Format zu speichern.
Die Triangulierung eines beschränkten, polygonalen Gebietes Ω ⊂ R2 , das auf einer Seite seines Randes
liegt, ist in einer Datei folgender Form gegeben:
• Kommentare beginnen mit #“ am Anfang einer Zeile und enden am Zeilenende. Sie dürfen an jeder Stelle
”
in der Datei stehen.
• Das Schlüsselwort Vertices“ steht in einer eigenen Zeile.
”
• Es folgen, zeilenweise, die Ecken der Triangulierung als Paare reeller Zahlen (x- und y-Koordinate). Sie
sind mit mindestens 10stelliger Genauigkeit gegeben. Eckpunkt vi befindet sich in Zeile i nach Vertices“,
”
i = 1, 2, 3, . . . , m. Dabei werden Kommentarzeilen nicht mitgezählt.
• Das Schlüsselwort Triangles“ steht in einer eigenen Zeile.
”
• Es folgen, zeilenweise, die Dreiecke der Triangulierung als Tripel natürlicher Zahlen (Indizes der Eckpunkte
aus der Liste Vertices“). Die n Dreiecke sind ebenfalls durch Ihre Zeilennummer nach Triangles“ implizit
”
”
von 1 an numeriert. Wieder werden Kommentarzeilen nicht mitgezählt.
• Das Ende der Dreiecksliste ist entweder das Dateiende oder das Schlüsselwort EndTriangles“ in einer
”
eigenen Zeile.
• Innerhalb der Zeilen sind Leerzeichen und Tabulatoren zu Beginn und am Ende erlaubt; sie trennen auch
die einzelnen Zahlen der Paare bzw. Tripel.
Sie dürfen annehmen, daß die Triangulierung konsistent ist und mindestens ein Dreieck enthält. Entwerfen Sie
eine möglichst einfache Datenstruktur Grid, um diese Listen in Ihrem Programm zu repräsentieren. Es bietet
sich zum Beispiel an, std::vector von geeigneten Strukturen in Grid zu verwenden. Eine Beispieldatei könnte
so aussehen:
# Das Referenzdreieck
Vertices
0.0 0.0
1.0 0.0
# Es folgt e_2:
0.0 1.0
Triangles
1 2 3
EndTriangles
Was hier steht, wird ist unspezifiziert und wird ignoriert.
Schreiben Sie die Funktion MaxNumEdgesOfVertex (...) , die die maximale Zahl von Kanten liefert, die sich in
einem Eckpunkt der Triangulierung treffen. Diese Funktion ist beim Aufstellen der Massenmatrix hilfreich. Eine
effiziente Verfahrensweise besteht darin, zu jedem Eckpunkt ein (zunächst leeres) std::set<size_t> S anzulegen. Anschließend besucht man jedes Dreieck und trägt für jeden Eckpunkt seine beiden Nachbar-Eckpunkte
in S ein. Die gesuchte Zahl ist dann max{ |S| } + 1.
Die Massenmatrix
ist die Diskretisierung des L2 (Ω)-Skalarproduktes,
(φi , φj )L2 (Ω) = (J(ei ), J(ej ))L2 (Ω) =: hM ei , ej i,
i, j = 1, 2, . . . m.
Dabei ist h·, ·i das Euklidische Skalarprodukt des Rm . J : Rm → M10 ist die Basisdarstellung der stetigen,
1
stückweise linearen Finiten Elemente bezüglich der nodalen Basis (φi )m
i=1 .
Die Einträge der Matrix lassen sich effizient berechnen, indem man die Liste der Dreiecke T einmal durchgeht.
Man summiert dabei den Beitrag des Integrals über T zu den Matrixeinträgen der Basisfunktionen, die zu den
Ecken von T gehören. Dies funktioniert wegen2
Z
X
(φi , φj )L2 (Ω) =
φi φj dx dy.
{T |vi ,vj sind Ecken von T }
T
Die Integrale können mit der Quadraturformel aus Aufgabe 1 c.) exakt bestimmt werden, da der Integrand auf
1
, so wird die Auswertung der Integranden
jedem Dreieck quadratisch ist. Wählt man a = 0, b = 83 und c = 24
besonders einfach, denn in den Ecken des Dreiecks ist der Integrand nur 0 oder 1 und im Schwerpunkt tritt stets
derselbe Wert auf (welcher?). Denken Sie daran, das Integral über das Referenzdreieck auf das Integral über T
zu transformieren: Es muß |T |/|Tref | als Vorfaktor berücksichtigt werden.
Als Datenstruktur für die Massenmatrix soll Jagged Diagonal Storage verwendet werden. Denn obwohl
M ∈ Rm×m ist, sind maximal c = MaxNumEdgesOfVertex (...) Einträge in jeder Zeile von Null verschieden.
Diese Dünnbesetztheit ist bei großen Gittern essentiell. Im JDS-Format nutzt man dies aus, indem man die von
Null verschiedenen Einträge der Matrix in jeder Zeile nach links zusammenschiebt.
Die von Null verschiedenen Matrixeinträge werden in einem std::valarray<double> coeff der Länge m × c
gespeichert. Die Einträge der Zeile i = 1, . . . , m stehen in [coeff[(i − 1) ∗ m], . . . ,coeff[i ∗ m]), wobei nichtverwendete Speicherstellen auf 0 gesetzt werden. Beachten Sie, daß Indizes in C und C++ bei 0 beginnen.
Um die richtige Spalte rekonstruieren zu können, wird in einem std::valarray<size_t> col der Länge m × c
der um eins verminderte Spaltenindex gespeichert, der zu dem entsprechenden Eintrag in coeff gehört. Nicht
verwendete Speicherstellen erhalten m als Spaltenindex. Beispielsweise wird die Matrix


1 0 2 0 0
3 4 0 5 0 



M =
0 6 7 0 8 
0 0 9 10 0 
0 0 0 11 12
so repräsentiert:
1 2
3 4
coeff = 6 7
9 10
11 12
0
5
8 ,
0
0
0
0
col = 1
2
3
2
1
2
3
4
5
3
4
5
5
Fassen Sie die Felder und eventuelle Hilfsfunktionen in einer Datenstruktur Matrix zusammen und schreiben
Sie den Operator *, der die Matrix-Vektor-Multiplikation ausführt:
std::valarray<double> operator* (const Matrix& M, const std::valarray<double>& x)
Zur Ausgabe der Matrix M soll ein einfaches Datenformat verwendet werden, das unter anderem in Matlab
importiert werden kann:
• Zeile 1 enthält die Dimension der Matrix in folgender Gestalt: % mxm q. Dabei ist q die Anzahl der von
Null verschiedenen Einträge von M .
• Für jeden von Null verschiedenen Eintrag Mi,j der Matrix folgt eine Zeile der Form i j: Mi,j“ (ohne
”
Anführungszeichen). Der Matrixeintrag soll mit mindestens 10 signifikanten Stellen ausgegeben werden.
Als Anwendung Ihres Finite-Elemente-Codes können Sie die Fläche der zur Verfügung gestellten Triangulierungen berechnen und ausgeben. Stellen Sie dazu die Funktion f ≡ 1 in der nodalen Basis dar, und verwenden
Sie |Ω| = (f, f )L2 (Ω) .
1 Zur Erinnerung: Die nodale Basis besteht aus genau den Funktionen in M1 , die in einem Eckpunkt den Wert 1 und in allen
0
anderen den Wert 0 annehmen.
2 Veranschaulichen Sie sich supp(φ φ ).
i j
Testen und dokumentieren Sie Ihre Komponenten einzeln und im Zusammenspiel. Stellen Sie zum Beispiel
die Massenmatrix auf dem Referenzelement manuell auf, und vergleichen Sie das Ergebnis mit Ihrem Programm.
Überprüfen Sie ob Ihr M symmetrisch ist und ob der berechnete Flaecheninhalt bei einfachen Beispielen stimmt,
etc.
(10 Punkte)
Abgabe der Programmieraufgabe
Lösen Sie die Aufgabe in C++, C oder Fortran. (Wenn Sie nicht C++ verwenden, müssen Sie evtl. auf andere
als die oben beschriebenen Datentypen zurückgreifen.)
Werfen Sie bis zum Abgabetermin einen mit Matrikelnummer und Name versehenen Ausdruck Ihres Programms
in den Einwurfkasten vor Raum 149 im Hauptgebäude.
Legen Sie eine elektronische Version Ihrer Lösung auf einer CD oder 3.500 -Diskette bei, die ebenfalls mit
Matrikelnummer und Name beschriftet ist, oder schicken Sie sie als Email mit dem Betreff [NAIV] P1 an
[email protected].
Gebiete
Das Referenzdreieck:
1
0.9
0.8
0.7
0.6
0.5
0.4
0.3
0.2
0.1
0
0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1
Die Programmieraufgabe:
0.8
0.6
0.4
0.2
0
−0.2
−0.4
−0.6
−0.8
−1.5
−1
−0.5
0
0.5
1
Der Pacman:
1
0.8
0.6
0.4
0.2
0
−0.2
−0.4
−0.6
−0.8
−1
−0.8
−0.6
−0.4
−0.2
0
0.2
0.4
0.6
0.8
Herunterladen