Integration rules in NGSolve

5.4. Integration rules in NGSolve#

from ngsolve import *
from ngsolve.webgui import Draw

In NGSolve an IntegrationRule for finite element meshes is defined on the respective reference element. E.g. for a triangle TRIG the reference element has the vertices \((0,0),(1,0),(0,1)\),

k = 4

intrule = IntegrationRule(TRIG,k) #returns an integration rule of at least order k
print(intrule)
 locnr = 0: (0.816848, 0.0915762, 0), weight = 0.0549759
 locnr = 1: (0.0915762, 0.816848, 0), weight = 0.0549759
 locnr = 2: (0.0915762, 0.0915762, 0), weight = 0.0549759
 locnr = 3: (0.108103, 0.445948, 0), weight = 0.111691
 locnr = 4: (0.445948, 0.108103, 0), weight = 0.111691
 locnr = 5: (0.445948, 0.445948, 0), weight = 0.111691

An IntegrationRule consists of IntegrationPoints which have a position and a weight:

import matplotlib.pyplot as pl

pl.plot([0,1,0,0],[0,0,1,0])
for ip in intrule:
    print("point: ", ip.point)
    print("weight: ", ip.weight)
    pl.plot(ip.point[0],ip.point[1],'x')
point:  (0.816847572980459, 0.091576213509771, 0.0)
weight:  0.054975871827661
point:  (0.091576213509771, 0.816847572980459, 0.0)
weight:  0.054975871827661
point:  (0.091576213509771, 0.091576213509771, 0.0)
weight:  0.054975871827661
point:  (0.10810301816807, 0.445948490915965, 0.0)
weight:  0.111690794839005
point:  (0.445948490915965, 0.10810301816807, 0.0)
weight:  0.111690794839005
point:  (0.445948490915965, 0.445948490915965, 0.0)
weight:  0.111690794839005
../_images/a98df43b75d74a2615428272be009b4b75fb34633f9781a39084fe9e591323bf.png

We may check the accuracy of the integration rule by using IntegrationRule.Integrate(f) for a lambda function f on the reference element.

intrule = IntegrationRule(TRIG, 5)

for i in range(10):
    intrule_ref = IntegrationRule(TRIG,i+2)
    int_ref = intrule_ref.Integrate(lambda x,y: x**i)
    int_approx = intrule.Integrate(lambda x,y: x**i)
    print("Polynomial of order {}: error =  {}".format(i, abs(int_ref-int_approx)))
Polynomial of order 0: error =  1.942890293094024e-15
Polynomial of order 1: error =  8.326672684688674e-17
Polynomial of order 2: error =  1.249000902703301e-16
Polynomial of order 3: error =  0.0
Polynomial of order 4: error =  0.0
Polynomial of order 5: error =  4.961309141293668e-16
Polynomial of order 6: error =  1.5855372570428017e-15
Polynomial of order 7: error =  2.750544061753263e-06
Polynomial of order 8: error =  4.881966328910969e-06
Polynomial of order 9: error =  7.801460834254426e-07

Integration over a finite element Mesh can be done by supplying the integration rule(s) (if more than one type of element is present in the mesh)

mesh = Mesh(unit_square.GenerateMesh(maxh=0.2))
Draw(mesh)
print(Integrate(sin(6*pi*x)*sin(10*pi*y)*dx(intrules = {TRIG: IntegrationRule(TRIG,0)}),mesh))
-0.024473463317593043

For mesh refinement we should observe convergence:

import numpy as np

mesh = Mesh(unit_square.GenerateMesh(maxh=0.2))

intorders = [0,1,2,3,4]
refinements = 6
errors = np.zeros((refinements,len(intorders)))
hs =     np.ones((refinements,len(intorders)))
for i in range(refinements):
    print("refinement: ", i)
    for j in range(len(intorders)):
        print("order = {}".format(intorders[j]))
        intrules = {TRIG: IntegrationRule(TRIG, intorders[j])}
        integral = abs(Integrate(sin(6*pi*x)*sin(10*pi*y)*dx(intrules = intrules),mesh))
        errors[i,j]=integral
        hs[i,j]=1/2**i
    mesh.Refine()
    
refinement:  0
order = 0
order = 1
order = 2
order = 3
order = 4
refinement:  1
order = 0
order = 1
order = 2
order = 3
order = 4
refinement:  2
order = 0
order = 1
order = 2
order = 3
order = 4
refinement:  3
order = 0
order = 1
order = 2
order = 3
order = 4
refinement:  4
order = 0
order = 1
order = 2
order = 3
order = 4
refinement:  5
order = 0
order = 1
order = 2
order = 3
order = 4
pl.loglog(hs,errors);
../_images/06bc915444bae01174c41f7113f522a4bbd50b5e914d842b215eda5e053ea863.png

For mixed meshes we also need an integration rule for quads:

from netgen.occ import *
geo = OCCGeometry(Rectangle(1,1).Face()-MoveTo(0.3,0.3).Rectangle(0.2,0.2).Face(),dim=2)

mesh = Mesh(geo.GenerateMesh(maxh=0.3,quad_dominated=True))
Draw(mesh)

intorders = [0,1,2]
refinements = 7
errors = np.zeros((refinements,len(intorders)))
hs =     np.ones((refinements,len(intorders)))

intrules_ref = {TRIG: IntegrationRule(TRIG, 20), QUAD:IntegrationRule(QUAD,20)}
integral_ref = Integrate(sin(x)*sin(y)*dx(intrules = intrules_ref),mesh)
for i in range(refinements):
    print("refinement: ", i)
    for j in range(len(intorders)):
        print("order = {}".format(intorders[j]))
        intrules = {TRIG: IntegrationRule(TRIG, intorders[j]),QUAD: IntegrationRule(QUAD, intorders[j])}
        integral = Integrate(sin(x)*sin(y)*dx(intrules = intrules),mesh)
        errors[i,j] = abs(integral-integral_ref)
        hs[i,j]=1/2**i
    mesh.Refine()
refinement:  0
order = 0
order = 1
order = 2
refinement:  1
order = 0
order = 1
order = 2
refinement:  2
order = 0
order = 1
order = 2
refinement:  3
order = 0
order = 1
order = 2
refinement:  4
order = 0
order = 1
order = 2
refinement:  5
order = 0
order = 1
order = 2
refinement:  6
order = 0
order = 1
order = 2
pl.loglog(hs,errors);
../_images/47cb7a51634c62543a400ba30961e2312ae7bb9e9bd517566b07ad0e46d56b92.png

One may also create an own integration rule:

my_intrule_trig = IntegrationRule([(0,0),(1,0),(0,1)],[1/6,1/6,1/6])
my_intrule_quad = IntegrationRule([(0,0),(1,0),(0,1),(1,1)],[1/4,1/4,1/4,1/4])
geo = OCCGeometry(Rectangle(1,1).Face()-MoveTo(0.3,0.3).Rectangle(0.2,0.2).Face(),dim=2)

mesh = Mesh(geo.GenerateMesh(maxh=0.3,quad_dominated=True))
Draw(mesh)

intrules_ref = {TRIG: IntegrationRule(TRIG, 20), QUAD:IntegrationRule(QUAD,20)}
integral_ref = Integrate(sin(x)*sin(y)*dx(intrules = intrules_ref),mesh)
refinements = 6
errors = []
hs = []
for i in range(refinements):
        intrules = {TRIG: my_intrule_trig,QUAD: my_intrule_quad}
        integral = Integrate(sin(x)*sin(y)*dx(intrules = intrules),mesh)
        errors.append(abs(integral-integral_ref))
        hs.append(1/2**i)
        mesh.Refine()
pl.loglog(hs,errors);
pl.loglog(hs,[h**2 for h in hs]);
../_images/19adf1143b920e503dcd10894bd25145365954ea05a3693664f3ea490f66e66b.png