9.2.3. Element Matrizen 1d Fall#

Lagrange Polynome als Basisfunktionen#

Hide code cell content
import numpy as np
import matplotlib.pyplot as plt

from sympy import integrate
from sympy.abc import x

from pandas import DataFrame
from IPython.display import display

def highlight_ortho(s):
    is_ortho = np.abs(s) < 1e-13
    return ['background-color: yellow' if v else '' for v in is_ortho]

Wir benutzen Lagrange Polynome

\[\varphi_j(x) = \prod_{i\not=j}^n \frac{x-x_i}{x_j-x_i}\]

verschiedener Ordnung als FEM Basis Funktionen:

def lagrangePoly(x,j,order):
    xi = np.linspace(0,1,order+1)
    J = np.delete(np.arange(order+1),j)
    return np.prod([(x-xi[i])/(xi[j]-xi[i]) for i in J],axis=0)

Die Polynome sind gegeben durch:

Hide code cell source
maxorder = 4
for order in range(1,maxorder+1):
    print('Order = ',order)
    for i in range(order+1):
        display(lagrangePoly(x,i,order).expand())
Order =  1
\[\displaystyle 1.0 - 1.0 x\]
\[\displaystyle 1.0 x\]
Order =  2
\[\displaystyle 2.0 x^{2} - 3.0 x + 1.0\]
\[\displaystyle - 4.0 x^{2} + 4.0 x\]
\[\displaystyle 2.0 x^{2} - 1.0 x\]
Order =  3
\[\displaystyle - 4.5 x^{3} + 9.0 x^{2} - 5.5 x + 1.0\]
\[\displaystyle 13.5 x^{3} - 22.5 x^{2} + 9.0 x\]
\[\displaystyle - 13.5 x^{3} + 18.0 x^{2} - 4.5 x\]
\[\displaystyle 4.5 x^{3} - 4.5 x^{2} + 1.0 x\]
Order =  4
\[\displaystyle 10.6666666666667 x^{4} - 26.6666666666667 x^{3} + 23.3333333333333 x^{2} - 8.33333333333333 x + 1.0\]
\[\displaystyle - 42.6666666666667 x^{4} + 96.0 x^{3} - 69.3333333333333 x^{2} + 16.0 x\]
\[\displaystyle 64.0 x^{4} - 128.0 x^{3} + 76.0 x^{2} - 12.0 x\]
\[\displaystyle - 42.6666666666667 x^{4} + 74.6666666666667 x^{3} - 37.3333333333333 x^{2} + 5.33333333333333 x\]
\[\displaystyle 10.6666666666667 x^{4} - 16.0 x^{3} + 7.33333333333333 x^{2} - 1.0 x\]
Hide code cell source
xp = np.linspace(0,1,400)
col = ['tab:blue','tab:orange','tab:green','tab:red','tab:purple','tab:brown','tab:pink']
for order in range(1,maxorder+1):
    xi = np.linspace(0,1,order+1)
    for j in range(order+1):
        plt.plot(xp,lagrangePoly(xp,j,order),c=col[j],label=r'$\varphi_'+str(j)+'(x)$')
        plt.plot(xi,lagrangePoly(xi,j,order),'o',c=col[j])
    plt.legend(loc=5)
    plt.grid()
    plt.title('Lagrange Polynome order = '+str(order))
    plt.show()
../_images/26ad0619807bc859274bef06c56bce7f4f5b224065801866ee9a3239e0676817.png ../_images/82d3b7130c684da11385b3c3593716b85de3f81f4b39b7451dff0656c10b0c48.png ../_images/e9e63de024fa273c40a9598821e90c71f067b0388fb48895458c596397517672.png ../_images/d0178945c197ffe92824990c3ddf42efb50953cf7d2c0bcda5f944bd5e20c7ac.png

Für die Steifigkeit-Elementmatrizen

\[A_{i,j} = \int_0^1 \varphi_i'(x) \varphi_j'(x) dx\]

erhalten wir

Hide code cell source
for order in range(1,maxorder+1):
    print('order = ',order)
    m = [[integrate(lagrangePoly(x,i,order).diff()*lagrangePoly(x,j,order).diff(),(x,0,1))
                     for i in range(order+1)] for j in range(order+1)]
    df = DataFrame(m)
    display(df.style.\
        apply(highlight_ortho).\
        set_table_attributes('style="font-size: 12px"').\
        format('{:.3f}'))
order =  1
  0 1
0 1.000 -1.000
1 -1.000 1.000
order =  2
  0 1 2
0 2.333 -2.667 0.333
1 -2.667 5.333 -2.667
2 0.333 -2.667 2.333
order =  3
  0 1 2 3
0 3.700 -4.725 1.350 -0.325
1 -4.725 10.800 -7.425 1.350
2 1.350 -7.425 10.800 -4.725
3 -0.325 1.350 -4.725 3.700
order =  4
  0 1 2 3 4
0 5.212 -7.247 3.225 -1.558 0.367
1 -7.247 17.608 -15.035 6.231 -1.558
2 3.225 -15.035 23.619 -15.035 3.225
3 -1.558 6.231 -15.035 17.608 -7.247
4 0.367 -1.558 3.225 -7.247 5.212

Für die Massen-Elementmatrizen

\[M_{i,j} = \int_0^1 \varphi_i(x) \varphi_j(x) dx\]

erhalten wir

Hide code cell source
for order in range(1,maxorder+1):
    print('order = ',order)
    m = [[integrate(lagrangePoly(x,i,order)*lagrangePoly(x,j,order),(x,0,1))
                     for i in range(order+1)] for j in range(order+1)]
    df = DataFrame(m)
    display(df.style.\
        apply(highlight_ortho).\
        set_table_attributes('style="font-size: 12px"').\
        format('{:.3f}'))
order =  1
  0 1
0 0.333 0.167
1 0.167 0.333
order =  2
  0 1 2
0 0.133 0.067 -0.033
1 0.067 0.533 0.067
2 -0.033 0.067 0.133
order =  3
  0 1 2 3
0 0.076 0.059 -0.021 0.011
1 0.059 0.386 -0.048 -0.021
2 -0.021 -0.048 0.386 0.059
3 0.011 -0.021 0.059 0.076
order =  4
  0 1 2 3 4
0 0.051 0.052 -0.031 0.010 -0.005
1 0.052 0.316 -0.068 0.045 0.010
2 -0.031 -0.068 0.330 -0.068 -0.031
3 0.010 0.045 -0.068 0.316 0.052
4 -0.005 0.010 -0.031 0.052 0.051

Hierarchische Basis Polynome#

NGSolve benutzt für die finite Elemente Räume höherer Ordnung immer die Basisfunktionen aus den Räumen niederer Ordnung und erweitert diese entsprechend.

Hide code cell source
from netgen.meshing import Mesh as NGMesh # Vorsicht es gibt Mesh auch in ngsolve!
from netgen.meshing import MeshPoint, Pnt, Element1D, Element0D
from ngsolve import *

m = NGMesh(dim=1)

# Punkte für die Zerlegung auf dem Intervall [0,1]
pnums = []
pnums.append (m.Add (MeshPoint (Pnt(0, 0, 0))))
pnums.append (m.Add (MeshPoint (Pnt(1, 0, 0))))

# Jedes 1D-Element (Teilintervall) kann einem Material zugeordnet
# werden. In unserem Fall gibt es nur ein Material.
idx = m.AddRegion("material", dim=1)
m.Add (Element1D ([pnums[0],pnums[1]], index=idx))

# Linkes und Rechtes Ende sind Randwertpunkte (0D-Elemente)
idx_left = m.AddRegion("left", dim=0)
idx_right = m.AddRegion("right", dim=0)

m.Add (Element0D (pnums[0], index=idx_left))
m.Add (Element0D (pnums[1], index=idx_right))

# Damit haben wir das Mesh definiert
mesh = Mesh(m)

xp = np.linspace(0,1,300)
for order in range(1,maxorder+1):
    V = H1(mesh,order = order, dirichlet='left|right')
    gfu = GridFunction(V)

    for k in range(V.ndof):
        gfu.vec[:] = 0
        gfu.vec[k] = 1
        plt.plot(xp,gfu(mesh(xp)),label=r'$\varphi_'+str(k)+'$')
    plt.legend()
    plt.title('order = '+str(order))
    plt.grid()
    plt.show()
../_images/cb2dacf3120ff7cf0fb7e6245607767b2a42e548fb0524e2a1e72ddf2aef56f1.png ../_images/2b9a2206aeefb3c9f5ace178883700394513f609ccb597ebac854834f13369ff.png ../_images/32fb38201427502e5b95c6d29b9df60d4f82eabaa156974e0ce73a1ef2478f63.png ../_images/d1463121d01fc89aee2d3699241d479c4a6c48df48c8729b4d9c8576f0defd36.png

Für die Steifigkeit-Elementmatrizen

\[A_{i,j} = \int_0^1 \varphi_i'(x) \varphi_j'(x) dx\]

erhalten wir

Hide code cell source
for order in range(1,maxorder+1):
    print('order = ',order)
    V = H1(mesh,order = order, dirichlet='left|right')
    gfu = GridFunction(V)

    phii = GridFunction(V)
    phij = GridFunction(V)

    a = []
    for i in range(V.ndof):
        phii.vec[:]=0
        phii.vec[i]=1
        ai = []
        for j in range(V.ndof):
            phij.vec[:]=0
            phij.vec[j]=1
            ai.append(Integrate(grad(phii)*grad(phij),mesh,order=2*order))
        a.append(ai)

    df = DataFrame(a)
    display(df.style.\
        apply(highlight_ortho).\
        set_table_attributes('style="font-size: 12px"').\
        format('{:.4f}'))
order =  1
  0 1
0 1.0000 -1.0000
1 -1.0000 1.0000
order =  2
  0 1 2
0 1.0000 -1.0000 0.0000
1 -1.0000 1.0000 0.0000
2 0.0000 0.0000 0.0833
order =  3
  0 1 2 3
0 1.0000 -1.0000 0.0000 0.0000
1 -1.0000 1.0000 0.0000 -0.0000
2 0.0000 0.0000 0.0833 0.0000
3 0.0000 -0.0000 0.0000 0.0500
order =  4
  0 1 2 3 4
0 1.0000 -1.0000 0.0000 0.0000 -0.0000
1 -1.0000 1.0000 0.0000 -0.0000 0.0000
2 0.0000 0.0000 0.0833 0.0000 -0.0000
3 0.0000 -0.0000 0.0000 0.0500 0.0000
4 -0.0000 0.0000 -0.0000 0.0000 0.0357

Für die Massen-Elementmatrizen

\[M_{i,j} = \int_0^1 \varphi_i(x) \varphi_j(x) dx\]

erhalten wir

Hide code cell source
for order in range(1,maxorder+1):
    print('order = ',order)
    V = H1(mesh,order = order, dirichlet='left|right')
    gfu = GridFunction(V)

    phii = GridFunction(V)
    phij = GridFunction(V)

    b = []
    for i in range(V.ndof):
        phii.vec[:]=0
        phii.vec[i]=1
        bi = []
        for j in range(V.ndof):
            phij.vec[:]=0
            phij.vec[j]=1
            bi.append(Integrate(phii*phij,mesh,order=2*order))
        b.append(bi)

    df = DataFrame(b)
    display(df.style.\
        apply(highlight_ortho).\
        set_table_attributes('style="font-size: 12px"').\
        format('{:.3f}'))
order =  1
  0 1
0 0.333 0.167
1 0.167 0.333
order =  2
  0 1 2
0 0.333 0.167 -0.042
1 0.167 0.333 -0.042
2 -0.042 -0.042 0.008
order =  3
  0 1 2 3
0 0.333 0.167 -0.042 0.008
1 0.167 0.333 -0.042 -0.008
2 -0.042 -0.042 0.008 -0.000
3 0.008 -0.008 -0.000 0.001
order =  4
  0 1 2 3 4
0 0.333 0.167 -0.042 0.008 0.000
1 0.167 0.333 -0.042 -0.008 0.000
2 -0.042 -0.042 0.008 -0.000 -0.001
3 0.008 -0.008 -0.000 0.001 -0.000
4 0.000 0.000 -0.001 -0.000 0.000