Praktikum zur Vorlesung Numerik partieller Differentialgleichungen I
Mario Ohlberger, Felix Schindler
Dazu müssen auf Ihrem Rechner die Befehle python3
und virtualenv
verfügbar sein. Das können Sie überprüfen, indem Sie ein Terminal starten (unter Ubuntu: Super/Windows Taste, terminal eingeben, Return) und die folgenden Befehle eingeben:
python3 --version
virtualenv --version
Beide Befehle sollten Ihnen die jeweilige Version des Programms anzeigen (und keine Fehlermeldung). Zur Einrichtung gehen Sie folgendermaßen vor:
HOME
Verzeichnis wechseln und einen Projekt-Ordner anlegencd # ins HOME Verzeichnis wechseln
pwd # Ort des aktuellen Verzeichnises anzeigen
ls -lh # Inhalt des aktuellen Verzeichnisses anzeigen
mkdir NPDGL1 # ein neues Verzeichnis erstellen
cd NPDGL1 # in dieses Verzeichnis wechseln
pwd
ls -lh
virtualenv --python=python3 python_umgebung_NPDGL1
ls -lh
source python_umgebung_NPDGL1/bin/activate
pip install --upgrade pip
pip install pymor[full]
pip install notebook
du -sh python_umgebung_NPDGL1
Dabei installiert pip install pymor[full]
das neueste Release von pyMOR
(momentan 0.5.2
). Mehr dazu finden Sie auf https://pymor.org (gehen Sie dort auf View on Github
und wählen anstelle von branch: master
links oben Tags: 0.5.2
aus, um die entsprechende README.md anzuzeigen).
mkdir notebooks
cd ~/NPDGL1
source python_umgebung_NPDGL1/bin/activate
jupyter-notebook --notebook-dir=notebooks
Laden Sie sich von der Homepage der Vorlesung blatt_00.ipynb herunter und speichern Sie dieses im Verzeichnis NPDGL1/notebooks/
als blatt_00.ipynb
.
Starten Sie den Notebook server (siehe ii) und führen Sie blatt_00.ipynb
aus.
Ab jetzt können Sie direkt im jeweiligen Übungsblatt arbeiten, fügen Sie dazu einfach direkt nach der Aufgabenstellung mit +
(oben links) eine neue Code Zelle hinzu. Eine Code Zelle können Sie mit STRG + Return
ausführen. Hilfe zu einem Typ Foo
oder einer Objekt foo
können Sie mit Foo?
oder foo?
erhalten.
# führen Sie in einem Notebook immer die folgenden Befehle als erstes aus
%matplotlib notebook
import numpy as np
from pymor.basic import *
Ab jetzt ist die numpy Bibliothek unter np
verfügbar und alles aus pymor.basic
direkt verfügbar.
Wir betrachten ein vereinfachtes stationäres Diffusionsproblem. Sei dazu
gegeben. Gesucht ist die Lösung $u: \Omega \to \mathbb{R}$, sodass
$$\begin{align} -\nabla\cdot( A \nabla u ) &= f &&\text{in } \Omega\\ u &= 0 &&\text{auf } \partial \Omega, \end{align}$$(im schwachen Sinne, siehe Kapitel 1) erfüllt ist.
docs.pymor.org/
nach einer Klasse, die das Gebiet $$\Omega = [0, 1]^2$$ mit Dirichlet-Randwerten modellieren kann und legen Sie ein entsprechendes Objekt mit Namen omega
an. Nutzen Sie dazu auch die Möglichkeit des jupyter Notebooks, sich zu einem beliebigen Objekt mit Hilfe des ?
-postfix die Dokumentation anzeigen zu lassen (z.B. np.array?
).# => API Dokumentation http://docs.pymor.org/en/0.5.2/index.html#api-documentation
# => Modul "domaindescriptions": http://docs.pymor.org/en/0.5.2/generated/pymor.domaindescriptions.html
# => Klasse RectDomain, diese ist Dank des * imports direkt verfügbar
# => Hilfe zu RectDomain anzeigen lassen: RectDomain?
# => enthält schon Dirichlet Randwerttyp überall
omega = RectDomain(([0, 0], [1, 1]))
Suchen Sie nach einer Möglichkeit ein konformes Dreiecksgitter $\mathcal{T}_h$ als Partitionierung des Gebiets $\Omega$ mit 16 Dreiecken zu erstellen, und geben Sie folgende Informationen aus:
d
des Gittersd
Entitäten, Punkte) im Gitterfor
-SchleifeVergleichen Sie die Positionen der Knoten mit der Dokumentation.
# => API Dokumentation, Modul grid, Klasse TriaGrid
# => Hilfe anzeigen lassen: TriaGrid?
grid = TriaGrid(num_intervals=(2, 2), domain=omega.domain)
print(grid)
print()
print('grid lives in a {}-dimensional space'.format(grid.dim))
print('grid has {} simplices'.format(grid.size(0)))
print('grid has {} edges'.format(grid.size(1)))
print('grid has {} vertices'.format(grid.size(2)))
vertices = grid.centers(grid.dim)
print()
print(type(vertices))
print(vertices.shape)
print()
print('vertices:')
counter = 0
for vertex in vertices:
print('vertex {} has position {}'.format(counter, vertex))
counter += 1
Sei $f: \Omega \to \mathbb{R}$ gegeben durch $f(x_0, x_1) := x_0 \cdot x_1$.
f
, die die Auswertung von $f$ and einem Punkt $x$ modelliert und werten Sie die Funktion f
für jeden Knotenpunkt des Gitters einzeln mit Hilfe einer for
-Schleife aus.def f(x):
return x[0]*x[1]
for x in vertices:
print('f({}) = {}'.format(x, f(x)))
f
an jedem Knotenpunkt des feineren Gitters auszuwerten.fine_grid = TriaGrid(num_intervals=(1024, 1024), domain=omega.domain)
print(fine_grid)
import time
tic = time.time()
values = f(fine_grid.centers(grid.dim))
toc = time.time() - tic
print()
print('evaluating non-vectorized function took {}s'.format(toc))
f
an allen Knotenpunkten des groben Gitters gleichzeitig auszuwerten. Warum funktioniert das nicht?# => an allen Punkten gleichzeitig auswerten
values = f(vertices)
print(values)
print(len(vertices))
print(len(values))
# Warum kommt das raus?
# Beim Aufruf f(vertices) passiert
vertices[0]*vertices[1]
# also eine elementweise Multiplikation des 0ten und 1ten Knotens
f
, welche die elementweisen Operationen des numpy.ndarray
ausnutzt und werten Sie diese Variante für alle Knotenpunkte des feineren Gitters gleichzeitig aus und messen Sie die benötigte Zeit.# Gegeben eine Menge von Punkten als Matrix
print(vertices)
print(vertices.shape)
# extrahiere 0te und 1te Komponente für alle Punkte gleichzeitig
x_0s = vertices[..., 0] # 0te Spalte
x_1s = vertices[..., 1] # 1te Spalte
print()
print(type(x_0s))
print(x_0s)
print(x_1s)
# Das ganze kompakt in einer Funktion
def f(x):
return x[..., 0]*x[..., 1]
# Kann an einem Punkt ausgewertet werden ...
print(f(vertices[0]))
# ... oder an allen Punkten gleichzeitig
print(f(vertices))
tic = time.time()
values = f(fine_grid.centers(grid.dim))
toc = time.time() - tic
print('took {}s'.format(toc))
ExpressionFunction
, um $f$ zu modellieren, werten Sie diese an allen Knotenpunkten des feinen Gitters aus und messen Sie die benötigte Zeit.f = ExpressionFunction('x[..., 0]*x[..., 1]', dim_domain=2, shape_range=())
tic = time.time()
values = f.evaluate(fine_grid.centers(grid.dim))
toc = time.time() - tic
print('took {}s'.format(toc))
Modellieren Sie das vereinfachte Diffusionsproblem mit
mit Hilfe eines analytischen Problems in pyMOR.
#ConstantFunction?
A = ConstantFunction(1, 2)
f = ConstantFunction(value=1, dim_domain=2)
StationaryProblem
vertraut und legen Sie ein problem
an, welches die gewünschten Datenfunktionen enthält.#StationaryProblem?
problem = StationaryProblem(
domain=omega,
diffusion=ConstantFunction(1, 2),
rhs=ConstantFunction(1, 2),
)
result = discretize_stationary_cg(problem)
type(result)
print()
for rr in result:
print(rr)
print()
disc, _ = discretize_stationary_cg(problem)
u_h
des vereinfachten Diffusionsproblems mit Hilfe der Diskretisierung. Machen Sie sich dazu mit der Dokumentation von StationaryDiscretization
vertraut oder finden Sie die entsprechende Funktion interaktiv (um die Methoden eines Objektes foo
anzuzeigen, schreiben Sie foo.
und drücken Sie Tab
).u_h = disc.solve()
disc.visualize(u_h)
Berechnen Sie Approximationen u_h
für verschieden Gitterweiten h = 1/2, 1/4, 1/16, 1/64
, indem Sie das diameter
Argument der Funktion discretize_stationary_cg
nutzen.
set_log_levels({'pymor': 'WARN'})
set_log_levels({'pymor': 'WARN'})
def discretize_and_visualize(h):
disc, _ = discretize_stationary_cg(problem, diameter=h)
print(disc.solution_space)
u_h = disc.solve()
disc.visualize(u_h)
for h in (1/2, 1/4, 1/16, 1/64):
print('h = {}'.format(h))
discretize_and_visualize(h)
print()