Praktikum zur Vorlesung Numerik partieller Differentialgleichungen I
Mario Ohlberger, Felix Schindler
~/NPDGL1/notebooks/blatt_02.ipynb
.numpy
und pymor.basic
und machen Sie matplotlib
für das Notebook nutzbar.%matplotlib notebook
import numpy as np
from pymor.basic import *
Als Partitionierung eines zusammenhängenden beschränkten Gebietes $\Omega \subset \mathbb{R}$ (also eines Intervals $(a, b)$ für $a < b$) betrachten wir ein äquidistantes Gitter $\mathcal{T}_h := \{ T_0, \dots, T_{I - 1}\}$
Das Gitter ist also
Für ein zusammenhängendes beschränktes Gebiet $T \subset \mathbb{R}$ sei $\mathbb{P}_k(T)$ der Raum der Polynome über $T$ vom Grad höchstens $k \in \mathbb{N}_0$.
Zu einem gegebenen Gitter $\mathcal{T}_h$ betrachten wir den Raum der stetigen stückweise linearen Funktionen bezüglich des Gitters:
$$S_h^1 := \big\{ u \in C^0(\Omega) \;\big|\; u|_T \in \mathbb{P}_1(T) \big\}$$Jede Funktion $u_h \in S_h^1$ ist dabei eindeutig definiert durch ihre Werte in den Knotenpunkten des Gitters. Wir können also der Funktion $u_h$ ihren Vektor an Freiheitsgeraden (DoF Vektor, von degree of freedom) $\underline{u_h} \in \mathbb{R}^{I + 1}$ zuordnen, sodass $(\underline{u_h})_i = u_h(x_i)$ für $0 \leq i \leq I$. Es besteht also die folgende Isomorphie:
$$\begin{align*}S_h^1 &\cong \mathbb{R}^{I + 1}\\ u_h&\leftrightarrow \underline{u_h}\end{align*}$$Da wir beliebige Funktionen $f \in C^0(\Omega)$ nicht fehlerfrei handhaben können (zum Beispiel Integrieren oder visualisieren) betrachten wir geeignete Approximationen $f_h \in S_h^1$. Dazu definieren wir den zu $S_h^1$ passenden Interpolationsoperator
$$\begin{align*}\Pi_{S_h^1}; C^0(\Omega) &\to S_h^1,\\f&\mapsto \Pi_{S_h^1}[f] =: f_h,\end{align*}$$wobei $f_h$ eindeutig bestimmt ist durch die Auswertung von $f$ an den Knotenpunkten des Gitters:
$$\begin{align*}f_h(x_i) = f(x_i)&&\text{für } 0 \leq i \leq I\end{align*}$$Implementieren Sie den Interpolationsoperator $\Pi_{S_h^1}$ als Python Funktion und testen Sie Ihr Program für $\Omega = (0, 2\pi)$, $I = 4$ und $f(x) = sin(x)$!
Hinweis: Sie können der Einfachheit halber for
-Schleifen verwenden!
Schreiben Sie eine Python Funktion f_h = interpolate(grid, f)
, die für ein gegebenes pyMOR Gitter in einer Raumdimension, grid
$ = \mathcal{T}_h$, und eine gegebene pyMOR Funktion, f
$ = f$, den DoF-Vektor der Interpolierten, f_h
$ = \underline{f_h}$, als Numpy-Array entsprechender länge zurück gibt.
vertices
ab.f
and allen Knotenpunkten aus (siehe Dokumentation von FunctionInterface) und speichern Sie die Werte in values
.values
zurück.Ein äquidistantes Gitter in einer Raumdimension wird in pyMOR durch die Klasse OnedGrid
modelliert.
grid
an,ExpressionFunction
modelliert.
Legen Sie ein entsprechendes Objekt mit Namen f
an.Berechnen Sie die Interpolation von $f$ auf dem Gitter $\mathcal{T}_h$ mittels Ihrer interpolate
Funktion.
f_h
ab.f_h
aus.f_h
aus.for
-Schleife die Koordinaten aller Knotenpunkte des Gitters zusammen mit den Werten von $f$ aus (Hinweis: Nutzen Sie zip
).Schreiben Sie eine Python Funktion visualize(grid, f_h, name='')
, welche die Interpolation einer Funktion über einem Gitter mit Hilfe von matplotlib
visualisiert und testen Sie Ihr Program für $\Omega = (0, 2\pi)$, $f(x) = sin(x)$ und Gitter mit $I = 2^2, 2^3, 2^4, 2^5$ Elementen!
from matplotlib import pyplot as plt
unter dem Namen plt
verfügbar und machen Sie sich mit plt.plot
und plt.legend
vertraut.Schreiben Sie die Funktion visualize
, welche eine Funktion visualisiert.
plt.figure()
eine neue (leere) Grafik.f_h
mit der Anzahl der Knotenpunkte des Gitters überein stimmt.plot
Funktion aus dem plt
Modul, um die Werte von f_h
an den Knotenpunktes des Gitters zu visualisieren und linear zu interpolieren, und den Namen der Funktion zu übergeben.legend
Funktion aus dem plt
Modul, um die Legende anzeigen zu lassen.Erweitern Sie Ihre Funktion, sodass Sie mehrere Interpolierte gleichzeitig visualisieren können.
Erstellen Sie vor Ihrer Funktion folgendermaßen eine Farbskala:
colors = list(plt.get_cmap('tab20c').colors)
colors.reverse()
plt.figure()
einmalig eine neue (leere) Grafik.grid
, f_h
und name
, ob es sich um eine Python Liste handelt (Hinweis: nutzen Sie dafür isinstance
), und wandeln Sie es gegebenenfalls in eine Liste der Länge der 1 um.zip
) und gehen Sie wie oben vor, um jede Interpolierte bezüglich ihres Gitters zu visualisieren.
Geben Sie in Ihrer Funktion zusätzlich beim Aufruf von plot
mit Hilfe von color=colors.pop()
jeder visualisierung eine andere Farbe.legend()
auf, um die Legend anzeigen zu lassen.for
-Schleife mit den entsprechenden Gittern, Interpolierten und Namen (welche die Anzahl der Gitterelemente enthalten).Wir betrachten das vereinfachte Diffusionsproblems aus Blatt 00 in einer Raumdimension mit $A = 1$ (Poisson Problem), gesucht ist also $u \in C^2(\Omega)$, sodass
$$\begin{align*}\partial_{xx} u(x) &= f(x) &&\text{für } x \in \Omega\\ u(x) &= g_\text{D}(x) &&\text{für } x \in \partial\Omega.\end{align*}$$Zur Diskretisierung mit dem Verfahren der Finiten Differenzen für ein gegebenes äquidistantes Gitter $\mathcal{T}_h$ gehen wir folgendermaßen vor:
Wir betrachten den Differentialoperator $\partial_{xx}:C^2(\Omega) \to C^0(\Omega)$, $u \mapsto \partial_{xx}u$. Gesucht ist eine Approximation, welche für Funktionen in $S_h^1$ wohldefiniert ist: $\partial_{h,h}: S_h^1 \to S_h^1$.
Betrachten Sie dazu für eine Funktion $u \in C^\infty(\Omega)$ die Taylor-Entwicklung von $u$ um einen Gitterpunkt $x_i$, ausgewertet an einem beliebigen Punkt $y \in \Omega$:
$$u_(y) = u(x_i) + u'(x_i) \cdot (y - x_i) + \tfrac{1}{2} u''(x_i)\cdot(y - x_i)^2 + \mathcal{O}\big((y - x_i)^3\big)$$
Nutzen Sie diese Entwicklung, ausgewertet an den benachbarten Gitterpunkten $x_{i - 1}$ und $x_{i + 1}$, um einen Differenzenquotionten als Approximation von $u''(x_i)$ der Güte $\mathcal{O}(h)$ herzuleiten (Hinweis: nuzten Sie die Gitterweite $h$, um die Darstellung zu vereinfachen).
Leiten Sie eine Approximationen obiger Differentialgleichung für die approximative Lösung $u_h \in S_h^1$ her.
Leiten Sie mit Hilfe dieser $I + 1$ Gleichungen ein Gleichungssystem der Form
$$\underline{b_h} \cdot \underline{u_h} = \underline{f_h}$$
für den DoF-Vektor der approximativen Lösung $u_h \in S_h^1$ her, indem Sie
bestimmen.
for
-Schleifen und/oder Ihrer interpolate
Funktion.np
verfügbar).u_h = discretize_elliptic_1d_fd(grid, f, g_D)
zusammen und testen Sie Ihr Programm für $\Omega = (0, 1)$, $f = 1$ und $g_\text{D} = 0$ und für Gitter mit $2^2, 2^3, 2^4, 2^5$ Elementen (dabei soll g_D
ein Python Tuple mit zwei Werten sein, also in diesem Beispiel g_D = (0, 0)
).
Visualisieren Sie die Lösungen mit Hilfe der visualize
Funktion aus Aufgabe 2.Testen Sie Ihr Programm für $\Omega = (0, 1)$ und ein Gitter mit $2^7$ Elementen und die folgenden Fälle, visualisieren Sie die Lösungen.
$f = 1$, $g_D(x) = \begin{cases}0,&x = 0\\1, &x = 1\end{cases}$
$g_D = 0$, $f(x) = \begin{cases}1, &x \in [0.2, 0.4]\\0, &\text{sonst}\end{cases}$