Praktikum zu Vorlesung Modellreduktion parametrisierter Systeme
Mario Ohlberger, Felix Schindler
Aktivieren Sie die virtuelle Umgebung zum Praktikum und starten Sie den Notebook server. Zur Erinnerung:
Terminal starten (super
-Taste/Windows
-Taste, terminal
eingeben, Enter
)
ins Projektverzeichnis wechseln
cd ~/vorlesung_modellreduktion
die virtuelle Umgebung aktivieren
source python_umgebung_praktikum_modellreduktion/bin/activate
Notebook server starten
jupyter-notebook --notebook-dir=notebooks
grid_interpolations
in grid_visualization
um.Erstellen Sie ein neues Python 3
notebook und benennen Sie es in interpolations
um.
Importieren Sie numpy
und pymor.basic
und machen Sie matplotlib
für das Notebook nutzbar.
%matplotlib notebook
import numpy as np
from pymor.basic import *
Schreiben Sie eine Python Funktion visualize_fv(v_h, grid, title)
, die für eine diskrete Funktion vh= v_h
(gegeben als VectorArray
der Länge 1), Gitter Th= grid
und Titel title
, die Funktion vh∈V0h visualisiert, wobei wie in [Blatt 00]
V0h:={v∈L2(Ω)|v|K∈P0(K)∀K∈Th}
den Raum der stückweise konstanten Funktionen bzgl. des Gitters (Finite Volumen Raum) bezeichnet (Pp(ω) ist dabei der Raum der Polynome vom Grad kleiner gleich p∈N über einem Gebiet ω⊂Rd).
PatchVisualizer
anzulegen und dessen visualize
Methode zu nuzten.v_h
die richtige Länge und Dimension hat.from pymor.gui.visualizers import PatchVisualizer
def visualize_fv(v_h, grid, title):
fv_visualizer = PatchVisualizer(grid, bounding_box=grid.bounding_box, codim=0)
fv_visualizer.visualize(v_h, d=None, legend=title)
Schreiben Sie eine Python Funktion visualize_grid(grid)
, die ein gegebenes Gitter Th= grid
visualisiert.
grid
zu erhalten, einen entsprechenden fv_space
als NumpyVectorSpace
anzulegen, die Funktion vh als Element von V0h mit Hilfe von fv_space
zu erhalten.visualize_fv
Funktion.def visualize_grid(grid):
vertices = grid.centers(grid.dim)
fv_space = NumpyVectorSpace(dim=grid.size(0), id_='FV')
v_h = fv_space.from_data(np.arange(fv_space.dim))
visualize_fv(v_h, grid, 'element indices of a TriaGrid with {} elements'.format(grid.size(0)))
Testen Sie Ihre Funktionen, indem Sie ein Dreicksgitter Th mit 12 Intervallen des Gebiets Ω=[0,1]2 visualisieren.
visualize_grid
Funktion auf.omega = RectDomain(([0, 0], [1, 1]))
grid = TriaGrid(num_intervals=(1, 1), domain=omega.domain)
visualize_grid(grid)
Zur Visualisierung einer Funktion f:Ω→R auf einem gegebenen Gitter Th von Ω⊂Rd, d=1,2,3, benötigen wir eine geeignete Approximation fh. Für stetige Funktionen f∈C0 bietet sich dazu die Lagrange-Interpolation an. Sei dazu
S1h:={v∈C0(Ω)|v|K∈P1(K)∀K∈Th}⊂C0(Ω)der Raum der stetigen und stückweisen linearen Funktionen bezüglich des Gitters.
Sei Tdh die Menge aller Knotenpunkte des Gitters (Entitäten mit Kodimension d) und I:=|Tdh|∈N die Anzahl der Knotenpunkte. Dann ist eine Basis von S1h gegeben durch
{φ0,…,φI−1}wobei die Hütchenfunktion φi zu einem Knotenpunkt νi∈Tdh eindeutig definiert ist durch
φi(νj):=δi,j:={1,falls i=j,0,sonst(diese Basis wird Lagrange-Basis genannt).
Damit ist jede Funktion vh∈S1h eindeutig definiert durch die Angabe ihrer Werte in den Knotenpunkten des Gitters, denn aus der Basisdarstellung
vh(x)=I−1∑i=0vh_iφi(x)und der Definition der Basis folgt, dass vh_i=vh(νi).
Wir können also S1h isomorph mit RI identifizieren und jede Funktion vh∈S1h mit ihrem DoF Vektor (Degree of Freedom: Freiheitsgrad) vh_∈RI, wobei vh_i:=vh(νi) für alle 0≤i<I.
Um für eine beliebige Funktion f:Ω→R eine Approximation in S1h zu erhalten, betrachten wir die Lagrange-Interpolation
ΠS1h:C0(Ω)→S1h,f↦ΠS1h[f],die eindeutig definiert ist durch die Angabe ihrer Werte in den Knotenpunkten,
ΠS1h[f](νi):=f(νi) für 0≤i<I.Als Approximation von f erhalten wir also fh∈S1h als fh:=ΠS1h[f] und den dazugehörigen DoF Vektor fh_∈RI durch
fh_i:=f(νi), für alle 0≤1<I.Bemerkung: Die Lagrange-Interpolation ist eine Projektion, denn (ΠS1h∘ΠS1h)[vh]=ΠS1h[vh] für alle vh∈S1h.
Schreiben Sie eine Python Funktion interpolate_lagrange_p1(f, grid)
, die für eine gegebene Funktion f= f
und Gitter Th= grid
die Lagrange-Interpolierte fh:=ΠS1h[f] als geeignetes VectorArray
zurück gibt.
NumpyVectorSpace
entsprechender Dimension, mit der Kennung CG
(continuous Galerkin) und legen Sie ein entsprechendes Objekt cg_space
an.f
an allen Knotenpunkten des Gitters aus, um fh_ zu erhalten.cg_space
nutzen.def interpolate_lagrange_p1(f, grid):
cg_space = NumpyVectorSpace(dim=grid.size(grid.dim), id_='CG')
vertices = grid.centers(grid.dim)
f_h = f.evaluate(vertices)
return cg_space.from_data(f_h)
Testen Sie Ihre interpolate_lagrange_p1
Funktion, indem Sie die wie in [Blatt 00, Aufgabe 1] gegebene Funktion f:Ω→R, f(x0,x1):=x0⋅x1 auf Ω=[0,1]2 interpolieren.
ExpressionFunktion
.interpolate_lagrange_p1
mit dieser Funktion und dem Gitter aus Aufgabe 1 auf und geben Sie die Länge und Dimension des resultierenden VectorArray
s, sowie die Anzahl der Knotenpunkte des Gitters aus.f = ExpressionFunction('x[..., 0]*x[..., 1]', dim_domain=2, shape_range=())
f_h = interpolate_lagrange_p1(f, grid)
print(len(f_h))
print(f_h.dim)
print(grid.size(grid.dim))
Schreiben Sie eine Funktion visualize_lagrange_p1(v_h, grid, title)
, die für eine diskrete Funtion vh= v_h
(gegeben als VectorArray
der Länge 1), Gitter Th= grid
und Titel title
, die Funktion vh∈S1h visualisiert.
v_h
die richtige Länge und Dimension hat.cg_visualizer
vom Typ PatchVisualizer, achten Sie auf die korrekte Kodimension!visualize
Methode, geben Sie mit legend=
einen Titel an, setzen Sie bei Bedarf d=None
.def visualize_lagrange_p1(v_h, grid, title):
assert len(v_h) == 1
assert v_h.dim == grid.size(grid.dim)
cg_visualizer = PatchVisualizer(grid, bounding_box=grid.bounding_box, codim=2)
cg_visualizer.visualize(v_h, d=None, legend=title)
Testen Sie Ihre visualize_lagrange_p1
Funktion, indem Sie die Funktion f für verschiede Gitter interpolieren und visualisieren, messen Sie dabei jeweils die Zeit für
Testen Sie mindestens folgende Gitter:
import time
t = time.time()
grid = TriaGrid(num_intervals=(1, 1), domain=omega.domain)
print('creating simplex grid with {} elements took {}s'.format(grid.size(0), time.time() - t))
t = time.time()
f_h = interpolate_lagrange_p1(f, grid)
print('interpolation took {}s'.format(time.time() - t))
t = time.time()
visualize_lagrange_p1(f_h, grid, 'TriaGrid with {} elements'.format(grid.size(0)))
print('visualization took {}s'.format(time.time() - t))
t = time.time()
grid = TriaGrid(num_intervals=(512, 512), domain=omega.domain)
print('creating simplex grid with {} elements took {}s'.format(grid.size(0), time.time() - t))
t = time.time()
f_h = interpolate_lagrange_p1(f, grid)
print('interpolation took {}s'.format(time.time() - t))
t = time.time()
visualize_lagrange_p1(f_h, grid, 'TriaGrid with {} elements'.format(grid.size(0)))
print('visualization took {}s'.format(time.time() - t))
t = time.time()
grid = RectGrid(num_intervals=(2, 2), domain=omega.domain)
print('creating cubic grid with {} elements took {}s'.format(grid.size(0), time.time() - t))
t = time.time()
f_h = interpolate_lagrange_p1(f, grid)
print('interpolation took {}s'.format(time.time() - t))
t = time.time()
visualize_lagrange_p1(f_h, grid, 'RectGrid with {} elements'.format(grid.size(0)))
print('visualization took {}s'.format(time.time() - t))
t = time.time()
grid = RectGrid(num_intervals=(1024, 1024), domain=omega.domain)
print('creating cubic grid with {} elements took {}s'.format(grid.size(0), time.time() - t))
t = time.time()
f_h = interpolate_lagrange_p1(f, grid)
print('interpolation took {}s'.format(time.time() - t))
t = time.time()
visualize_lagrange_p1(f_h, grid, 'RectGrid with {} elements'.format(grid.size(0)))
print('visualization took {}s'.format(time.time() - t))
Für allgemeine (unstetige Funktionen) f:Ω→R bietet sich außerdem die Approximation (und Visualisierung) als Finite Volumen Funktion an, die wir schon zur Visualisierung des Gitters genutzt haben. Sei Th ein Gitter mit I:=|Th|∈N Elementen (Entitäten der Kodimension 0). Eine Basis des Finite Volumen Raumes V0h ist durch
{χK0,…,χKI−1}gegeben, wobei
χKi:={1,für x∈Ki0,sonstdie Indikatorfunktion bezüglich des Gitterelementes Ki∈Th sei, für 0≤i<I. Da jede Funktion vh∈V0h stückweise konstant bezüglich des Gitters Th ist (vergleiche die Definition von V0h oben), ist Sie eindeutig durch die Angabe eines Wertes vh_i∈R auf jedem Gitterelement Ki∈Th gegeben, was aus der Basisdarstellung
vh(x):=I−1∑i=0vh_iχKi(x)und der Definition der Basis und V0h folgt.
Um für eine beliebige Funktion f∈L2(Ω) eine Approximation in V0h zu erhalten, betrachten wir die Finite Volumen-Iterpolation
ΠV0h:L2(Ω)→V0h,f↦ΠV0h[f],die eindeutig definiert ist durch die Angabe ihrer Werte auf den Gitterelementen als Mittelwert der Funktion f,
ΠV0h[f]|Ki:=|Ki|−1∫Kif(x)dx für 0≤i<I.Als Approximation von f erhalten wir also fh∈V0h als fh:=ΠV0h[f] und den dazugehörigen DoF Vektor fh_∈RI durch
fh_i:=|Ki|−1∫Kif(x)dx für 0≤i<I.Bemerkung: Die Finite Volumen-Interpolation ist eine Projektion (genauer gesagt eine L2-Projektion), denn (ΠV0h∘ΠV0h)[vh]=ΠV0h[vh] für alle vh∈V0h.
Schreiben Sie eine Python Funktion interpolate_fv(f, grid)
, die für eine gegebene Funktion f= f
und Gitter Th= grid
die Finite Volumen-Interpolierte fh:=ΠV0h[f] als geeignetes VectorArray
zurück gibt.
NumpyVectorSpace
entsprechender Dimension, mit der Kennung FV
und legen Sie ein entsprechendes Objekt fv_space
an.fv_space
nutzen.def interpolate_fv(f, grid):
fv_space = NumpyVectorSpace(dim=grid.size(0), id_='FV')
centers = grid.centers(0)
f_h = f.evaluate(centers)
return fv_space.from_data(f_h)
interpolate_fv
Funktion, indem Sie die Funktionauf Ω=[0,1]2 interpolieren.
ExpressionFunktion
.interpolate_fv
mit dieser Funktion und dem groben Dreiecksgitter auf und geben Sie die Länge und Dimension des resultierenden VectorArray
s, sowie die Anzahl der Elements des Gitters aus.grid = TriaGrid(domain=omega.domain, num_intervals=(2, 2))
f = ExpressionFunction('(0.25 <= x[..., 0]) * (x[..., 0] <= 0.5) * (0.25 <= x[..., 1]) * (x[..., 1] <= 0.5) * 1.', dim_domain=2, shape_range=())
f_h = interpolate_fv(f, grid)
print(len(f_h))
print(f_h.dim)
print(grid.size(0))
Testen Sie Ihre interpolate_fv
und visualize_fv
Funktion von oben, indem Sie die Funktion f für verschiede Gitter interpolieren und visualisieren, testen Sie mindestens folgende Gitter:
grid = TriaGrid(num_intervals=(2, 2), domain=omega.domain)
f_h = interpolate_fv(f, grid)
visualize_fv(f_h, grid, 'TriaGrid with {} elements'.format(grid.size(0)))
grid = TriaGrid(num_intervals=(3, 3), domain=omega.domain)
f_h = interpolate_fv(f, grid)
visualize_fv(f_h, grid, 'TriaGrid with {} elements'.format(grid.size(0)))
grid = TriaGrid(num_intervals=(4, 4), domain=omega.domain)
f_h = interpolate_fv(f, grid)
visualize_fv(f_h, grid, 'TriaGrid with {} elements'.format(grid.size(0)))
grid = RectGrid(num_intervals=(2, 2), domain=omega.domain)
f_h = interpolate_fv(f, grid)
visualize_fv(f_h, grid, 'RectGrid with {} elements'.format(grid.size(0)))
grid = RectGrid(num_intervals=(3, 3), domain=omega.domain)
f_h = interpolate_fv(f, grid)
visualize_fv(f_h, grid, 'RectGrid with {} elements'.format(grid.size(0)))
grid = RectGrid(num_intervals=(4, 4), domain=omega.domain)
f_h = interpolate_fv(f, grid)
visualize_fv(f_h, grid, 'RectGrid with {} elements'.format(grid.size(0)))