Integration methods#

To perform computation of integrals over elements, the library provides IntegrationMethod class which is an abstract class. Two abstract classes inherit from it : the SingleIM class to deal with single integral and the DoubleIM class to deal with double integral. All the classes have to inherit from these two classes.

Among integration methods, quadrature methods are general and well adapted to regular functions to be integrated. XLiFE++ provides the QuadratureIM class, inherited from SingleIM class, which encapsulates the usual quadrature formulae defined in QuadratureIM class. Besides, the ProductIM class, inherited from doubleIM class, manages a pair of SingleIM objects and may be used to take into double quadrature method (adapted to compute double integral with regular kernel).

In the case of double integrals, the integration method to be used can depend on the distance between two elements. This is the purpose of the IntegrationMethods which collects IntgMeth, which handles an IntegrationMethod object and additional parameters, including a distance criterion and a function part if it is split into a regular and a singular part.

The dependance diagram looks like

../../_images/intgmeth.png

Fig. 157 Inheritance diagram of integration methods (absract class in grey)#

Note that

  • SauterSchwabIM class is dedicated to compute double integrals involving Laplace/Helmholtz kernel in 3d for any kind of finite element

  • DuffyIM class is dedicated to compute double integrals involving Laplace/Helmholtz kernel in 2d for any kind of finite element

  • LenoirSalles2dIM, LenoirSalles3dIM, LenoirSalles2dIR and LenoirSalles3dIR are dedicated to compute double or single integral involving Laplace/Hemholtz kernel and are working only with P0 or P1 Lagrange element.

  • CollinoIM class is dedicated to compute double integrals involving Maxwell kernel in 3d and Raviart-Thomas element of order 0

  • FilonIM class computes 1d oscillatory integrals 0Tf(t)eiat.

The IntegrationMethod class#

The IntegrationMethod class, basis class of all integration methods, manages general information about them:

class IntegrationMethod
{public :
  String name;                  //name for doc purpose
  IntegrationMethodType imType; //method type (see below)
  SingularityType singularType; //singularity supported (_notsingular,_r,_logr,_loglogr)
  real_t singularOrder;         //singularity order
  string_t kerName;             //kernel shortname if adapted to (default is empty)
  bool requireRefElement;       //true if method require reference element (false)
  bool requirePhyElement;       //true if method require physical element (false)
  bool requireNormal;           //true if method involves normal (false)
};

Up to now, the types of integral defined in enumeration are:

enum IntegrationMethodType
{ _undefIM, _quadratureIM,_polynomialIM,_productIM,
  _LenoirSalles2dIM,_LenoirSalles3dIM,_LenoirSalles2dIR,_LenoirSalles3dIR,
  _SauterSchwabIM,_SauterSchwabSymIM,_DuffyIM,_DuffySymIM,
  _HMatrixIM, _CollinoIM, _FilonIM
};

Note

Except the first four types, all the types _xxxIM are aliased xxx, for instance SauterSchwab is an alias of _SauterSchwabIM.

The _HMatrixIM method type is a very particular case because it is used to choose the hierarchical matrix representation (HMatrix class) and compression methods which can be seen in some way as an integration method! See H-matrices.

The SingleIM, DoubleIM inherited from the IntegrationMethod are purely interface classes to real integration methods for single or double integral.

The QuadratureIM class#

The QuadratureIM class is dedicated to integration methods adapted to integrals of regular functions, based on quadrature points and quadrature weights. It is derived from SingleIM class and mainly handles a list of Quadrature objects indexed by ShapeType to deal with multiple quadrature rule in case of domain having more than one shape type. As the quadrature rule are often involved in context of FE computation, the Quadrature class may store shape values:

class QuadratureIM : public SingleIM
{public:
  QuadRule quadRule;         //QuadRule to be used (may be _defaultRule)
  Number degree;             //degree of quadrature (default 3)
  map<ShapeType,Quadrature*> quadratures_; //to store Quadrature obj for different shapes
  map<ShapeType,vector<ShapeValues>*> shapevalues_; //to store shape values
  ...
}

This class offers the setQuadrature and setQuadratures functions that set the Quadrature objects according to the shapes, the quadrature rule and the order provided.

The Quadrature and the QuadratureRule classes#

The quadrature formulae have the following form:

E^f(x^)dx^i=1,qωif(x^i)

where (x^i)i=1,q are quadrature points belonging to reference element E^ and (ωi)i=1,q are quadrature weights.

The Quadrature class manages all information related to quadrature :

class Quadrature
{public:
  GeomRefElement* geomRefElt_p;  //pointer to geometric reference element
  QuadratureRule quadratureRule; //embedded QuadratureRule object
  QuadRule rule;                 //type of quadrature rule
  number_t degree;               //degree of quadrature rule
  bool hasPointsOnBoundary;      //as it reads
  string_t name;                 //name of quadrature formula (for doc purposes)
  static std::vector<Quadrature*> theQuadratureRules; //global list of Quadrature
  ...
}

where

  • geomRefElt_p refers to the geometry (segment, triangle, …) bearing the quadrature.

  • quadratureRule refers to a QuadratureRule object which handles the points and weights of quadrature and the functions to build them.

  • rule refers to a QuadRule which is an enumeration of all types of quadrature supported:

     enum QuadRule
     {
      _defaultRule = 0, _GaussLegendreRule, _symmetricalGaussRule, _GaussLobattoRule,
      _nodalRule, _miscRule,_GrundmannMollerRule, _doubleQuadrature,
      _evenGaussLegendreRule, _evenGaussLobattoRule
    };
    
  • degree_ is either the degree of the quadrature rule or the degree of the polynomial interpolation in case of nodal quadrature rules.

  • the static vector theQuadratures collects all the pointers to Quadrature object in order to have only one instance of a Quadrature object.

The practical “construction” of a Quadrature object is done by the external function findQuadrature which first, searches in the static vector theQuadratures the quadrature defined by a shape, a quadrature rule and a degree. If it is not found, a new Quadrature object is created on the heap. In any case a pointer to the Quadrature object is returned.

This class offers also the bestQuadrule function that returns the “best” quadrature rule regarding the shape and the degree.

The QuadratureRule class stores the quadrature points and quadrature weights and provides member functions to load them :

class QuadratureRule
{
  std::vector<Real> coords_;    // point coordinates of quadrature rule
  std::vector<Real> weights_;   // weights of quadrature rule
  Dimen dim_;                   // dimension of points
  ...
}

The main task of this class is to load quadrature points and weights. Thus, there are a lot of member functions to load these values. Some of them have a general purpose (for instance to build quadrature rules from tensor or conical products of 1D rules) and others are specific to one quadrature rule.

Here is a simple example of how to use quadrature objects :

Quadrature* q=findQuadrature(_triangle,_GaussLegendreRule, 3);
Real S=0, x,y;
Number k=0;
for(Number i =0;i<q->quadratureRule.size();i++,k+=2)
{
  x=q->quadratureRule.coords()[k];
  y=q->quadratureRule.coords()[k+1];
  S+=q->quadratureRule.weights()[i]*std::sin(x*y);
}
std::cout<<"S="<<S;

Up to now, there exist quadrature formulae for unit segment ]0,1[, for unit triangle, for unit quadrangle (square), for unit tetrahedron, for unit hexahedron (cube) for unit prism and for unit pyramid. The following tables give the list of available quadrature formulae :

General rules

Gauss-Legendre

Gauss-Lobatto

Grundmann-Muller

symmetrical Gauss

segment

any odd degree

any odd degree

quadrangle

any odd degree

any odd degree

any odd degree up to 21

triangle

any odd degree

any odd degree

degree up to 10

hexahedron

any odd degree

any odd degree

odd degree up to 11

tetrahedron

any odd degree -

any odd degree

degree up to 10

prism

degree up to 10

pyramid

any odd degree

any odd degree

degree up to 10

Particular rules

nodal

miscellaneous

segment

P1 to P4

quadrangle

Q1 to Q4

triangle

P1 to P3

Hammer-Stroud 1 to 6

hexahedron

Q1 to Q4

tetrahedron

P1, P3

Stroud 1 to 5

prism

P1

centroid 1, tensor product 1,3,5

pyramid

P1

centroid 1, Stroud 7

More precisely, the rules that are implemented :

  • 1D rules

    • Gauss-Legendre rule, degree 2n+1, n points

    • Gauss-Lobatto rule, degree 2n1, n points

    • Gauss-Lobatto rule, degree 2n1, n points

    • trapezoidal rule, degree 1, 2 points

    • Simpson rule, degree 3, 3 points

    • Simpson 3 8 rule, degree 3, 4 points

    • Booleb rule, degree 5, 5 points

    • Wedge rule, degree 5, 6 points

  • Rules over the unit simplex (less quadrature points BUT with negative weights)

    • TN Grundmann-Moller rule, degree 2n+1, Cn+d+1n points

  • Rules over the unit triangle {x>0,y>0,x+y<1}

    • T2P2 MidEdge rule

    • T2P2 Hammer-Stroud rule

    • T2P3 Albrecht-Collatz rule, degree 3, 6 points, Stroud (p.314)

    • T2P3 Stroud rule, degree 3, 7 points, Stroud (p.308)

    • T2P5 Radon-Hammer-Marlowe-Stroud rule, degree 6, 7 points, Stroud (p.314)

    • T2P6 Hammer rule, degree 6, 12 points, G.Dhatt, G.Touzot (p.298)

    • Gauss-Legendre (conical product), any order

    • symmetrical Gauss up to degree 10

  • Rules over the unit quadrangle [0,1]×[0,1]

    • nodal degree 1 to 4 (1D nodal, tensor product)

    • Gauss-Legendre (tensor product), any order

    • Gauss-Lobatto (tensor product), any order

  • Rules over the unit tetrahedron {x>0,y>0,z>0,x+y+z<1}

    • T3P2 Hammer-Stroud rule, degree 2, 4 points, Stroud (p.307)

    • T3P3 Stroud rule, degree 3, 8 points, Stroud (p.308)

    • T3P5 Stroud rule, degree 5, 15 points, Stroud (p.315)

    • Gauss-Legendre (conical product), any order

    • symmetrical Gauss up to degree 10

  • Rules over the unit hexahedron [0,1]×[0,1]×[0,1]

    • nodal degree 1 to 4 (1D nodal, tensor product)

    • Gauss-Legendre (tensor product), any order

    • Gauss-Lobatto (tensor product), any order

    • symmetrical Gauss up to degree 11

  • Rules over the unit prism {0<x,y<1,x+y<1,0<z<1}

    • P1 nodal rule

    • tensor product of 2-points Gauss-Legendre rule on [0,1] and Stroud 7 points formula on the unit triangle (degree 3)

    • tensor product of 3-points Gauss-Legendre rule on [0,1] and Radon-Hammmer-Marlowe-Stroud 7 points formula on the unit triangle (degree 5)

    • Gauss-Legendre (tensor product), any order

    • Gauss-Lobatto (tensor product), any order

    • symmetrical Gauss up to degree 10

  • Rules over the unit pyramid {0<x,y<1z,0<z<1}

    • P1 nodal rule

    • symmetrical Gauss up to degree 10

  • Rules built from lower dimension rules

    • tensor product of quadrature rules (quadrangle and hexahedron)

    • conical product of quadrature rules (triangle and pyramid)

    • rule built from 1D nodal rule which are quadrangle nodal rule

    • rule built from 1D nodal rule which are hexahedron nodal rule

References :

  • A.H. Stroud, Approximate calculation of multiple integrals, Prentice Hall, 1971.

  • G.Dhatt & G Touzot, The finite element method displayed, John Wiley & Sons, Chichester, 1984

    1. Grundmann & H.M. Moller, Invariant Integration Formulas for the N-Simplex by Combinatorial Methods, SIAM Journal on Numerical Analysis, Vol 15, No 2, Apr. 1978, pages 282-290.

  • F.D. Witherden & P.E. Vincent, On the identification of symmetric quadrature rules for finite element methods, Computers & Mathematics with Applications, Volume 69, Issue 10, May 2015, Pages 1232-1241.

To choose quadrature rules, the class provides the static function bestQuadRule returning the ‘best’ quadrature rule for a given shape S and a given polynomial degree d.

static QuadRule bestQuadRule(ShapeType, Number);

Best rule has to be understood as the rule on shape S with the minimum of quadrature points integrating exactly polynomials of degree d.

The following table gives the current best rules :

shape

degree

quadrature rule

number of points

segment

1

Gauss-Legendre 1

1

segment

2,3

Gauss-Legendre 3

2

segment

4,5

Gauss-Legendre 5

3

segment

2n1

Gauss-Legendre 2n1

n

shape

degree

quadrature rule

number of points

quadrangle

1

Gauss-Legendre 1

1

quadrangle

2,3

Gauss-Legendre 3

4

quadrangle

4,5

symmetrical Gauss 5

8

quadrangle

6,7

symmetrical Gauss 7

12

quadrangle

7,9

symmetrical Gauss 9

20

quadrangle

10,11

symmetrical Gauss 11

28

quadrangle

12,13

symmetrical Gauss 13

37

quadrangle

14,15

symmetrical Gauss 15

48

quadrangle

16,17

symmetrical Gauss 17

60

quadrangle

18,19

symmetrical Gauss 19

72

quadrangle

20,21

symmetrical Gauss 21

85

quadrangle

2n1>21

Gauss-Legendre 2n1

n2

shape

degree

quadrature rule

number of points

triangle

1

centroid rule (misc, 1)

1

triangle

2

P2 Hammer-Stroud (misc, 2)

2

triangle

3

Grundmann-Moller 3

3

triangle

4

symmetrical Gauss 4

6

triangle

5

symmetrical Gauss 5

7

triangle

6

symmetrical Gauss 6

12

triangle

7

symmetrical Gauss 7

15

triangle

8

symmetrical Gauss 8

16

triangle

9

symmetrical Gauss 9

19

triangle

10

symmetrical Gauss 10

25

triangle

11

symmetrical Gauss 11

28

triangle

12

symmetrical Gauss 12

33

triangle

13

symmetrical Gauss 13

37

triangle

14

symmetrical Gauss 14

42

triangle

15

symmetrical Gauss 15

49

triangle

16

symmetrical Gauss 16

55

triangle

17

symmetrical Gauss 17

60

triangle

18

symmetrical Gauss 18

67

triangle

19

symmetrical Gauss 19

73

triangle

20

symmetrical Gauss 20

79

triangle

2n1>20

Gauss-Legendre 2n1

?

shape

degree

quadrature rule

number of points

hexahedron

1

Gauss-Legendre 1

1

hexahedron

2,3

symmetrical Gauss 3

6

hexahedron

4,5

symmetrical Gauss 5

14

hexahedron

6,7

symmetrical Gauss 7

34

hexahedron

8,9

symmetrical Gauss 9

58

hexahedron

10,11

symmetrical Gauss 11

90

hexahedron

2n112

Gauss-Legendre 2n1

n3

shape

degree

quadrature rule

number of points

tetrahedron

1

centroid rule (misc, 1)

1

tetrahedron

2

P2 Hammer-Stroud (misc, 2)

4

tetrahedron

3

Grundmann-Moller 3

5

tetrahedron

4,5

symmetrical Gauss 5

14

tetrahedron

6

symmetrical Gauss 6

24

tetrahedron

7

symmetrical Gauss 7

35

tetrahedron

8

symmetrical Gauss 8

46

tetrahedron

9

symmetrical Gauss 9

59

tetrahedron

10

symmetrical Gauss 10

81

tetrahedron

2n111

Grundmann-Moller 2n1

?

shape

degree

quadrature rule

number of points

prism

1

centroid rule (misc, 1)

1

prism

2

symmetrical Gauss 2

5

prism

3

symmetrical Gauss 3

8

prism

4

symmetrical Gauss 4

11

prism

5

symmetrical Gauss 5

16

prism

6

symmetrical Gauss 6

28

prism

7

symmetrical Gauss 7

35

prism

8

symmetrical Gauss 8

46

prism

9

symmetrical Gauss 9

60

prism

10

symmetrical Gauss 10

85

shape

degree

quadrature rule

number of points

pyramid

1

centroid rule (misc, 1)

1

pyramid

2

symmetrical Gauss 2

5

pyramid

3

symmetrical Gauss 3

6

pyramid

4

symmetrical Gauss 4

10

pyramid

5

symmetrical Gauss 5

15

pyramid

6

symmetrical Gauss 6

24

pyramid

7

symmetrical Gauss 7

31

pyramid

8

symmetrical Gauss 8

47

pyramid

9

symmetrical Gauss 9

62

pyramid

10

symmetrical Gauss 10

83

How to add a new quadrature formula ?#

To add a new quadrature formula, say myRule on a unit element, say geomelt:

  • first, add myRule to QuadRule enumeration type

  • next, add in QuadratureRule class the member function defining the quadrature points and weights, e.g QuadratureRule::myQuadRule.

  • finally, modify the geomeltQuadrature function by adding in the right case statement the properties of the new quadrature formula. For instance, in the case of a new quadrature formula on the triangle:

Quadrature* triangleQuadrature(QuadRule rule, number_t numb)
{...
 switch(appliedRule)
 {case _nodalRule           : ...; break;
  case _GaussLegendreRule   : ...; break;
  case _GrundmannMollerRule : ...; break;
  case _symmetricalGaussRule: ...; break;
  case _miscRule            : ...; break;
  case _myRule :
    q=findQuadrature(_triangle, _myRule, numb, false); //find if already loaded
    if(q==nullptr) // create new Quadrature
    {
      q=new Quadrature(_triangle,_myRule,numb,"my rule",false);
      q->quadratureRule.myQuadRule(numb); //set points and weights
    }
    break;
  default: badDegreeRule(numb,"miscellaneous rule",_triangle); break;
 }
 ...
 return q;
}

Attention

When the QuadRule enumeration is modified, the dictionaries and may be, the Quadrature::bestQuadRule static function must be updated.

The ProductIM class#

In order to represent a product of integration method over a product of geometric domain (double integrals), the ProductIM class carries two SingleIM pointers:

class ProductIM : public DoubleIM
{
 protected :
  SingleIM* im_x;     //integration method along x
  SingleIM* im_y;     //integration method along y
}

ProductIM objects are used to calculate double integrals involving kernels which are regular on the integration domain.

Integration methods for singular kernels#

To deal with single or double integral involving a kernel with a singularity on the integration domain, say

E1E2p1(x)K(x,y)p2(y)dydx

XLiFE++ provides some additional classes:

  • DuffyIM (segments) and SauterSchwabIM (triangle) well adapted to Laplace/Helmholtz kernel and any regular functions p1, p2

  • LenoirSalles2dIM (segments) and LenoirSalles3dIM (triangles) well adapted to Laplace kernel with p1, p2 constant or linear functions

  • CollinoIM (triangles) designed to Maxwell 3d BEM integrals using Raviart-Thomas elements (affine).

  • LenoirSalles2dIR (segments) and LenoirSalles3dIR (triangles) well adapted to calculate integral representation invoving Laplace kernel with p1, p2 constant or linear functions

DuffyIM class#

This class deals with double integral over segments (S1×S2) involving 2d kernel K with log|xy| singularity.

For adjacent elements (sharing only one vertex) a Duffy transform is used (segments [S1,S2] and [T1,T2] with T1=S1):

φ : (η;ν)[0,1]×[0,1](S1+η(S2S1);T1+ην(T2T1))[S1,S2]×[T1,T2]

For self influence (S1=S2) two methods are proposed:

  • one based on a splitting of the unit square ]0,1[×]0,1[ in ny decreasing rectangles

    ]0,1[×]12k,12k1[, k=1,n1 and ]0,1[×]0,12n1[.
  • one based on diagonal splitting and using a tp transform in order to concentrate the quadrature points in the neighbor of the diagonal x=y (for more details see the separate documentation emph{quadrature_self_influence_2D}). This is the default one with p=5.

class DuffyIM : public DoubleIM
{
 public:
 Quadrature* quadSelfX, *quadSelfY;//quadratures on segment [0,1] for self influence
 Quadrature* quadAdjtX, *quadAdjtY;//quadratures on segment [0,1] for adjacent elements
 Number ordSelfX, ordSelfY;    //order of quadratures for self influence
 Number ordAdjtX, ordAdjtY;    //order of quadratures for adjacent elements
 Number selfOrd;               //order of t^p transform or number of number of layers(def=5)
 bool useSelfTrans;              //use improved method for self influence (def=true)

 DuffyIM(IntegrationMethodType);         //default constructor
 DuffyIM(Number oX=6, Number oY=6);  //full constructor
 DuffyIM(QuadRule qsX, Number osX, QuadRule qsY, Number osY, QuadRule qaX, Number oaX, QuadRule qaY, Number oaY, Number so=5, bool ust=true);
 DuffyIM(const Quadrature&);             //full constructor from a quadrature
}

The class provides computation functions regarding geometrical configuration of segments:

template<typename K>
 void computeIE(...) const;
 void SelfInfluences(...) const;
 void SelfInfluencesTP(...) const;
 void AdjacentSegments(...) const;
 void k4(...) const;
 void k5(...) const;

The computation precision is very sensitive to the order of quadrature used in y direction. When using the first method to compute the self influence coefficients, to get very accurate results in the case of P2 mesh, very high order quadrature must be involved, for instance

DuffyIM dufim(_GaussLegendreRule,60,_GaussLegendreRule,60, _GaussLegendreRule,60,_GaussLegendreRule,60,5,false);

which lead to 300 quadrature points in each direction for self-influence coefficients!

Using the second method improves drastically the efficiency of the computation :

DuffyIM dufim(_GaussLegendreRule,30,_GaussLegendreRule,30, _GaussLegendreRule,50,_GaussLegendreRule,50,5,true);

The following picture shows the convergence rates of th BEM (single layer) in case of the diffraction (k=1.35) of a plane wave on a disk (radius 1). It can be noted that with a very low quadrature (red curve) the convergence rate is not captured at all, with a very high quadrature using the first method (cyan curve) the convergence rate becomes hard to capture when refining the mesh and finally the second method (black curve) allows to well capture the convergence rate with a reasonable number of quadrature points.

finiteElements (png)

SauterSchwabIM class#

This class deals with double integral over triangles involving 3d kernel K with |xy|1 singularity, say

T1T2p1(x)K(x,y)p2(y)dydx
class SauterSchwabIM : public DoubleIM
{
 public:
  Quadrature* quadSelf;    //quadrature for self influence
  Quadrature* quadEdge;    //quadrature for elements adjacent by edge
  Quadrature* quadVertex;  //quadrature for elements adjacent by vertex
  Number ordSelf;        //order of quadrature for self influence
  Number ordEdge;        //order of quadrature for edge adjacence
  Number ordVertex;      //order of quadrature for vertex adjacence

  SauterSchwabIM(Number =3); //basic constructor (order 3)
  SauterSchwabIM(Quadrature&); //full constructor from quadrature object
}

LenoirSalles2dIM and LenoirSalles3dIM classes#

The LenoirSalles2dIM class can compute analytically

12πS1S2p1(x)log|xy|p2(y)dydx   (singlelayer)
12πS1S2p1(x)(xy).ny|xy|2p2(y)dydx   (double layer)

where p1 and p2 are either the P0 or P1 shape functions on segments S1 and S2 and the LenoirSalles3dIM class computes analytically

14πT1T2p1(x)1|xy|p2(y)dydx   (single layer)
14πT1T2p1(x)(xy).ny|xy|3p2(y)dydx   (double layer)

where p1 and p2 are the P0 shape functions (say 1) on triangles T1 and T2.

These two classes have no member data and only one basic constructor.

LenoirSalles2dIR and LenoirSalles3dIR classes#

The LenoirSalles2dIR class can compute analytically

12πSlog|xy|p(y)dydx   (single layer)
12πS(xy).ny|xy|2p(y)dydx   (double layer)

where p is either the P0 or P1 shape functions on segment S and the LenoirSalles3dIR class that computes analytically

14πT1|xy|p(y)dydx   (single layer)
14πTS(xy).ny|xy|3p(y)dydx   (double layer)

where p is the P0 or P1 shape functions on triangle T.

These two classes have no member data and only one basic constructor.

All the previous classes provides, a clone method, access to the list of quadratures if there are ones and an interface to the computation functions:

virtual LenoirSalles2dIM* clone() const;  //covariant
virtual std::list<Quadrature*> quadratures() const; //list of quadratures
template<typename K>
void computeIE(const Element* S, const Element* T, AdjacenceInfo& adj, const KernelOperatorOnUnknowns& kuv, Matrix<K>& res, IEcomputationParameters& iep, Vector<K>& vopu, Vector<K>& vopv, Vector<K>& vopk) const;

CollinoIM class#

The CollinoIM class is a wrapper to an integration method developed by F. Collino to deal with some integrals involved in 3D Maxwell BEM when using Raviart-Thomas elements of order 1 (triangle). More precisely, it can compute the integrals:

ΓΓ(kH(k;x,y)wj(y).wi(x)1kH(k;x,y)divwj(y)divwi(x))

and

ΓΓ(yH(k;x,y)×wj(y)).wi(x),

where (wi)i=1,n denote the Raviart-Thomas shape functions and H(k;x,y) the Green function of the Helmholtz equation (wave number k) in the 3D free space. The class looks like

enum ComputeIntgFlag {_computeI1=1, _computeI2,_computeBoth};

class CollinoIM : public DoubleIM
{
 private:
  myquad_t* quads_;
public:
 Number ordSNear; //default 12
 Number ordTNear; //default 64
 Number ordTFar;  //default 3
 Real eta;        //default 3.
 ComputeIntgFlag computeFlag;

 CollinoIM();
 CollinoIM(ComputeIntgFlag cf, Number otf, Number otn, Number osn, Real e);
 CollinoIM(const CollinoIM&);
 ~CollinoIM();
 virtual CollinoIM* clone() const;
 CollinoIM& operator=(const CollinoIM&);

 virtual std::list<Quadrature*> quadratures() const;
 virtual void print(std::ostream& os) const;
 template<typename K>
 void computeIE(const Element*, const Element*, AdjacenceInfo&, const KernelOperatorOnUnknowns&, Matrix<K>&, IEcomputationParameters&,Vector<K>&,Vector<K>&,Vector<K>&) const;
}

quads_ is a pointer to a quadrature structure provided by the Collino package, ordSNear, ordTNear, ordTFar are order of quadrature rules used, eta is a relative distance used to separate far and near triangle interactions and computeFlag allows to choose the integrals that have to be computed. computeIE is the main computation function calling the real computation function (ElemTools_weakstrong_c) provided by the Collino package (see files {itshape Collino.hpp} and Collino.cpp).

The IntegrationMethods class#

The IntegrationMethods class collects some IntgMeth objects that handle an integration method pointer with some additional parameters:

class IntgMeth
{
  public:
   const IntegrationMethod* intgMeth;
   FunctionPart functionPart; //_allFunction, _regularPart, _singularPart
  Real bound;              //bound value
}

The bound value may be used to select an integration method regarding a criterion. For instance, in BEM computation the criterion is the relative distance between the centroids of elements. Besides, using functionPart member, different integration method may be called on different part of the kernel, see Kernel class. This class has only some constructors and print stuff:

IntgMeth(const IntegrationMethod& im, FunctionPart fp=_allFunction, Real b=0);
IntgMeth(const IntgMeth&);
~IntgMeth();
IntgMeth& operator=(const IntgMeth&);
void print(std::ostream&) const;
void print(PrintStream&) const;
friend ostream& operator<<(ostream&, const IntgMeth&)

For safe multi-threading behavior, copy constructor and assign operator do a full copy of IntegrationMethod object.

The IntegrationMethods class is simply a vector of IntMeth object:

class IntegrationMethods
{
 public:
  vector<IntgMeth> intgMethods;
  typedef vector<IntgMeth>::const_iterator const_iterator;
  typedef vector<IntgMeth>::iterator iterator;
 ...
}

This class provides many constructors depending on the number of integration methods given (up to 3 at this time), to some shortcuts :

IntegrationMethods() {};
IntegrationMethods(const IntegrationMethod&,FunctionPart=_allFunction,Real=0);
...
void add(const IntegrationMethod&, FunctionPart=_allFunction,Real=0);
void push_back(const IntgMeth&);

To handle more than 3 integration methods, use the add member function.

Besides, the class offers some accessors and print stuff:

const IntgMeth& operator[](Number) cons ;
vector<IntgMeth>::const_iterator begin() const;
vector<IntgMeth>::const_iterator end() const;
vector<IntgMeth>::iterator begin();
vector<IntgMeth>::iterator end();
bool empty() const {return intgMethods.empty();}
void print(ostream&) const;
void print(PrintStream&) const;
friend ostream& operator<<(ostream&, const IntegrationMethods&);

In BEM computation, the following relative distance between two elements (Ei, Ej) is used:

dr(Ei,Ej)=||CiCj||max(diamEi,diamEj)whereCiisthecentroidofEi.

So defining for instance

IntegrationMethods ims(SauterSchwabIM(4), 0., symmetrical_Gauss, 5, 1., symmetrical_Gauss, 3);

the BEM computation algorithm will perform on function (all part):

Sauter-Schwab with quadrature of order 4 on segment

if dr(Ei,Ej)=0

Symmetrical gauss quadrature of order 5 on triangle

if 0<dr(Ei,Ej)1

Symmetrical gauss quadrature of order 3 on triangle

if dr(Ei,Ej)>1

Standard integration method#

Classic 1d integration methods#

For various integration purpose, XLiFE++ provides the uniform rectangle, trapeze and Simpson method (h=ban):

rectangle:abf(t)dthi=0,n1f(a+ih)trapeze:abf(t)dth2(f(a)+4i=1,n/2f(a+(2i1)h)+2i=1,n/21f(a+2ih)+f(b))  (n even)Simpson:abf(t)dth3(f(a)+2i=1,n1f(a+ih)+f(b))

with f a real or complex function. The rectangle method integrates exactly P0 polynomials, the trapeze method integrates exactly P1 polynomials whereas the Simpson method integrates exactly P3 polynomials. They respectively approximate the integral with order 1, 2 and 3.

For each of them, four template functions (with names rectangle, trapz, simpson) are provided according to the user gives the values of f on a uniform set of points, the function f or a function f with some parameters (e.g. trapeze method):

template<typename T, typename Iterator>
T trapz(Number n, Real h, Iterator itb, T& intg);
template<typename T>
T trapz(const std::vector<T>& f, Real h);
T trapz(T(*f)(Real), Real a, Real b, Number n);
T trapz(T(*f)(Real, Parameters&), Parameters& pars, Real a, Real b, Number n);

XLiFE++ provides also an adaptive trapeze method using the improved trapeze method (0.25(ba)(f(a)+2f((a+b)/2)+f(b))) to get an estimator. The user has to give its function (with parameters if required), the integral bounds a tolerance factor (106 if not given):

template<typename T>
T adaptiveTrapz(T(*f)(Real), Real a, Real b, Real eps=1E-6);
T adaptiveTrapz(T(*f)(Real,Parameters&), Parameters& pars, Real a, Real b, Real eps=1E-6)

Hint

Because at the first step, the adaptive method uses 5 points uniformly distributed, the result may be surprising if unfortunately the function takes the same value at these points!

Discrete Fast Fourier Transform (FFT)#

XLiFE++ provides the standard 1D discrete fast Fourier transform with 2n values:

gk=j=0,n1fje2iπjkn.

FFT and inverse FFT are computed using some functions addressing iterators on a collection of real or complex values:

template<class Iterator>
void  fft(Iterator ita, Iterator itb, Number log2n);
void ifft(Iterator ita, Iterator itb, Number log2n);

Computations from real or complex vectors is also available, but the results are always some complex vectors:

template<typename T>
vector<Complex>&  fft(vector<T>& f, vector<Complex>& g);
vector<Complex>& ifft(vector<T>& f, vector<Complex>& g);

The following example shows how to use them:

Number ln=6, n=64;
Vector<Complex> f(n),g(n),f2(n);
for(Number i=0; i<n; i++) f[i]=std::sin(2*i*pi_/(n-1));
fft(f.begin(),g.begin(),ln);
ifft(g.begin(),f2.begin(),ln); //f2 should be very close to f
// or
fft(f,g); ifft(g,f2);

Integration methods for oscillatory integrals#

Up to now, only one method is provided to compute 1D oscillatory integrals based on the Filon’s method. The Filon’s method XLiFE++ proposes is designed to compute an approximation of the following oscillatory integral:

I(x)=0Tf(t)eixt

where f is a slowly varying function with real or complex values (template type).

Considering a uniform grid tn=ndt, n=0,N and an interpolation space on this grid, say vect (wn)n=0,N where wn are polynomial on each segment [tn1,tn]; the Filon’s method consists in interpolating the function f:

f(t)=n=1,Nanwn(t).

Substituting f by its interpolation in integral and collecting terms in a particular way, the integral I(x) is thus approximated as follows:

IN(x)=dtj=1,pCj(x)n=1,Nf(tnj)expixtn1+dt2j=1,pCj(x)n=1,Nf(tnj)expixtn1

where Cj(x) and Cj are coefficients of the form :math:` int_0^1 tau_j(s) exp^{-i,x,s,dt}ds` with τj some shape functions on the segment [0,1] ant tnj the support of the jth DoF on the segment [tn1,tn]. The second sum in IN appears only when using Hermite interpolation; for Lagrange interpolation, Cj(x)=0.

If the values f(tnj)n=0,N and f(tnj)n=0,N (if Hermite interpolation) are pre-computed, the computation of IN(x) for many values of x may be very efficient!

The FilonIMT is a template class, FilonIM being its complex specialization:

template <typename T = Complex>
class FilonIMT : public SingleIM
{
 typedef T(*funT)(Real);  // T function pointer alias
 protected:
  Number ord_;        //interpolation order of (0,1 or 2)
  Real tf_;           //upper bound of integral (lower bound is 0)
  Real dt_;           //grid step if uniform
  Number ns_;         //number of segments
  Vector<T> fn_;        //values of f (and df if required) on the grid
  Vector<Real> tn_;   //grid points
  ...
}

ord_ corresponds to the interpolation used : 0 for Lagrange P0, 1 for Lagrange P1 and 2 for Hermite P3. The values f(tnj)n=0,N and f(tnj)n=0,N are collected (only one copy) in the same vector with the following storage:

  • Lagrange P0 : f(dt/2)f(3dt/2),f((N1/2)dt) (N values)

  • Lagrange P1 : f(0)f(dt),f(Ndt) (N+1 values)

  • Hermite P3 : f(0)f(0)f(dt)f(dt),f(Ndt)f(Ndt) (2(N+1) values)

The FilonIMT class provides several constructors that pre-compute the values of f and f from user’s functions of the real variable with real or complex values. More precisely, the following types are available:

Real f(Real t) {...}
Complex f(Real t) {...}
Real f(Real t, Parameters& pars) {...}
Complex f(Real t, Parameters& pars) {...}

It is also possible to construct a FilonIMT object passing the values of f at uniformly distributed points on:math:` [0,t_f]`. In that case, Filon of order 1 is selected. So the class looks like

typedef T(*funT)(Real);
typedef T(*funTP)(Real, Parameters& pa);
FilonIMT();
FilonIMT(Number o,Number N,Real tf,funT f);
FilonIMT(Number o,Number N,Real tf,funT f,funT df);
FilonIMT(Number o,Number N,Real tf,funTP f,Parameters& pars);
FilonIMT(Number o,Number N,Real tf,funTP f,funTP df, Parameters& pars);
FilonIMT(const Vector<T>& vf, Real tf);
void init(Number N,funT f,funT df);
void init(Number N,funTP f,funTP df,Parameters& pars);
Number size() const {return tn_.size();}     //grid size
template <typename S>
Complex coef(const S& x, Number j) const;  //Filon's coefficients
Complex compute(const S& x) const;           //compute I(x)
Complex operator()(const S& x) const         //compute I(x)
virtual void print(std::ostream& os) const;    //print FilonIMT on stream

This class is quite easy to use, for instance to compute the integral

I(x)=010eteixt

by the P1-Filon method:

Complex f(Real x) {return Complex(std::exp(-x),0.);}
...
FilonIM fim(1, 100, 10, f);
Complex y = fim(0.5);
// or in a more compact syntax if only one evaluation
Complex y = FilonIM(1, 100, 10, f) (0.5);

To invoke Hermite P3 Filon method, define also the derivative of f:

Complex f(Real x)  {return Complex(exp(-x),0.);}
Complex df(Real x) {return Complex(-exp(-x),0.);}
...
FilonIM fim(2, 100, 10, f, df);
Complex y = fim(0.5);

Hint

The P0 Filon method is of order 1, the P1 Filon is of order 2 while the Hermite P3 Filon is of order 4. The Hermite P3 Filon is less stable than the Lagrange Filon methods!

Filonconvergence (png)

See also

  • library= finiteElements,

  • header= Quadrature.hpp QuadratureRule.hpp IntegrationMethod.hpp,

  • implementation= Quadrature.cpp QuadratureRule.cpp IntegrationMethod.cpp,

  • test= test_Quadtrature.cpp,

  • header dep= config.h, utils.h, LagrangeQuadrangle.hpp, LagrangeHexahedron.hpp, mathsResources.h.