2975 lines
113 KiB
C++
2975 lines
113 KiB
C++
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
|
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
|
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
|
//
|
|
// This file is part of the MFEM library. For more information and source code
|
|
// availability visit https://mfem.org.
|
|
//
|
|
// MFEM is free software; you can redistribute it and/or modify it under the
|
|
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
|
// CONTRIBUTING.md for details.
|
|
|
|
#ifndef MFEM_BILININTEG
|
|
#define MFEM_BILININTEG
|
|
|
|
#include "../config/config.hpp"
|
|
#include "nonlininteg.hpp"
|
|
#include "fespace.hpp"
|
|
#include "libceed/ceed.hpp"
|
|
|
|
namespace mfem
|
|
{
|
|
|
|
/// Abstract base class BilinearFormIntegrator
|
|
class BilinearFormIntegrator : public NonlinearFormIntegrator
|
|
{
|
|
protected:
|
|
BilinearFormIntegrator(const IntegrationRule *ir = NULL)
|
|
: NonlinearFormIntegrator(ir) { }
|
|
|
|
public:
|
|
// TODO: add support for other assembly levels (in addition to PA) and their
|
|
// actions.
|
|
|
|
// TODO: for mixed meshes the quadrature rules to be used by methods like
|
|
// AssemblePA() can be given as a QuadratureSpace, e.g. using a new method:
|
|
// SetQuadratureSpace().
|
|
|
|
// TODO: the methods for the various assembly levels make sense even in the
|
|
// base class NonlinearFormIntegrator, except that not all assembly levels
|
|
// make sense for the action of the nonlinear operator (but they all make
|
|
// sense for its Jacobian).
|
|
|
|
using NonlinearFormIntegrator::AssemblePA;
|
|
|
|
/// Method defining partial assembly.
|
|
/** The result of the partial assembly is stored internally so that it can be
|
|
used later in the methods AddMultPA() and AddMultTransposePA(). */
|
|
virtual void AssemblePA(const FiniteElementSpace &fes);
|
|
/** Used with BilinearFormIntegrators that have different spaces. */
|
|
virtual void AssemblePA(const FiniteElementSpace &trial_fes,
|
|
const FiniteElementSpace &test_fes);
|
|
|
|
virtual void AssemblePAInteriorFaces(const FiniteElementSpace &fes);
|
|
|
|
virtual void AssemblePABoundaryFaces(const FiniteElementSpace &fes);
|
|
|
|
/// Assemble diagonal and add it to Vector @a diag.
|
|
virtual void AssembleDiagonalPA(Vector &diag);
|
|
|
|
/// Assemble diagonal of ADA^T (A is this integrator) and add it to @a diag.
|
|
virtual void AssembleDiagonalPA_ADAt(const Vector &D, Vector &diag);
|
|
|
|
/// Method for partially assembled action.
|
|
/** Perform the action of integrator on the input @a x and add the result to
|
|
the output @a y. Both @a x and @a y are E-vectors, i.e. they represent
|
|
the element-wise discontinuous version of the FE space.
|
|
|
|
This method can be called only after the method AssemblePA() has been
|
|
called. */
|
|
virtual void AddMultPA(const Vector &x, Vector &y) const;
|
|
|
|
/// Method for partially assembled transposed action.
|
|
/** Perform the transpose action of integrator on the input @a x and add the
|
|
result to the output @a y. Both @a x and @a y are E-vectors, i.e. they
|
|
represent the element-wise discontinuous version of the FE space.
|
|
|
|
This method can be called only after the method AssemblePA() has been
|
|
called. */
|
|
virtual void AddMultTransposePA(const Vector &x, Vector &y) const;
|
|
|
|
/// Method defining element assembly.
|
|
/** The result of the element assembly is added and stored in the @a emat
|
|
Vector. */
|
|
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
|
|
/** Used with BilinearFormIntegrators that have different spaces. */
|
|
// virtual void AssembleEA(const FiniteElementSpace &trial_fes,
|
|
// const FiniteElementSpace &test_fes,
|
|
// Vector &emat);
|
|
|
|
virtual void AssembleEAInteriorFaces(const FiniteElementSpace &fes,
|
|
Vector &ea_data_int,
|
|
Vector &ea_data_ext);
|
|
|
|
virtual void AssembleEABoundaryFaces(const FiniteElementSpace &fes,
|
|
Vector &ea_data_bdr);
|
|
|
|
/// Given a particular Finite Element computes the element matrix elmat.
|
|
virtual void AssembleElementMatrix(const FiniteElement &el,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
|
|
/** Compute the local matrix representation of a bilinear form
|
|
a(u,v) defined on different trial (given by u) and test
|
|
(given by v) spaces. The rows in the local matrix correspond
|
|
to the test dofs and the columns -- to the trial dofs. */
|
|
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
|
|
const FiniteElement &test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
|
|
virtual void AssembleFaceMatrix(const FiniteElement &el1,
|
|
const FiniteElement &el2,
|
|
FaceElementTransformations &Trans,
|
|
DenseMatrix &elmat);
|
|
|
|
/** Abstract method used for assembling TraceFaceIntegrators in a
|
|
MixedBilinearForm. */
|
|
virtual void AssembleFaceMatrix(const FiniteElement &trial_face_fe,
|
|
const FiniteElement &test_fe1,
|
|
const FiniteElement &test_fe2,
|
|
FaceElementTransformations &Trans,
|
|
DenseMatrix &elmat);
|
|
|
|
/// Perform the local action of the BilinearFormIntegrator
|
|
virtual void AssembleElementVector(const FiniteElement &el,
|
|
ElementTransformation &Tr,
|
|
const Vector &elfun, Vector &elvect);
|
|
|
|
virtual void AssembleElementGrad(const FiniteElement &el,
|
|
ElementTransformation &Tr,
|
|
const Vector &elfun, DenseMatrix &elmat)
|
|
{ AssembleElementMatrix(el, Tr, elmat); }
|
|
|
|
virtual void AssembleFaceGrad(const FiniteElement &el1,
|
|
const FiniteElement &el2,
|
|
FaceElementTransformations &Tr,
|
|
const Vector &elfun, DenseMatrix &elmat)
|
|
{ AssembleFaceMatrix(el1, el2, Tr, elmat); }
|
|
|
|
/** @brief Virtual method required for Zienkiewicz-Zhu type error estimators.
|
|
|
|
The purpose of the method is to compute a local "flux" finite element
|
|
function given a local finite element solution. The "flux" function has
|
|
to be computed in terms of its coefficients (represented by the Vector
|
|
@a flux) which multiply the basis functions defined by the FiniteElement
|
|
@a fluxelem. Typically, the "flux" function will have more than one
|
|
component and consequently @a flux should be store the coefficients of
|
|
all components: first all coefficient for component 0, then all
|
|
coefficients for component 1, etc. What the "flux" function represents
|
|
depends on the specific integrator. For example, in the case of
|
|
DiffusionIntegrator, the flux is the gradient of the solution multiplied
|
|
by the diffusion coefficient.
|
|
|
|
@param[in] el FiniteElement of the solution.
|
|
@param[in] Trans The ElementTransformation describing the physical
|
|
position of the mesh element.
|
|
@param[in] u Solution coefficients representing the expansion of the
|
|
solution function in the basis of @a el.
|
|
@param[in] fluxelem FiniteElement of the "flux".
|
|
@param[out] flux "Flux" coefficients representing the expansion of the
|
|
"flux" function in the basis of @a fluxelem. The size
|
|
of @a flux as a Vector has to be set by this method,
|
|
e.g. using Vector::SetSize().
|
|
@param[in] with_coef If zero (the default value is 1) the implementation
|
|
of the method may choose not to scale the "flux"
|
|
function by any coefficients describing the
|
|
integrator.
|
|
*/
|
|
virtual void ComputeElementFlux(const FiniteElement &el,
|
|
ElementTransformation &Trans,
|
|
Vector &u,
|
|
const FiniteElement &fluxelem,
|
|
Vector &flux, bool with_coef = true) { }
|
|
|
|
/** @brief Virtual method required for Zienkiewicz-Zhu type error estimators.
|
|
|
|
The purpose of this method is to compute a local number that measures the
|
|
energy of a given "flux" function (see ComputeElementFlux() for a
|
|
description of the "flux" function). Typically, the energy of a "flux"
|
|
function should be equal to a_local(u,u), if the "flux" is defined from
|
|
a solution u; here a_local(.,.) denotes the element-local bilinear
|
|
form represented by the integrator.
|
|
|
|
@param[in] fluxelem FiniteElement of the "flux".
|
|
@param[in] Trans The ElementTransformation describing the physical
|
|
position of the mesh element.
|
|
@param[in] flux "Flux" coefficients representing the expansion of the
|
|
"flux" function in the basis of @a fluxelem.
|
|
@param[out] d_energy If not NULL, the given Vector should be set to
|
|
represent directional energy split that can be used
|
|
for anisotropic error estimation.
|
|
@returns The computed energy.
|
|
*/
|
|
virtual double ComputeFluxEnergy(const FiniteElement &fluxelem,
|
|
ElementTransformation &Trans,
|
|
Vector &flux, Vector *d_energy = NULL)
|
|
{ return 0.0; }
|
|
|
|
virtual ~BilinearFormIntegrator() { }
|
|
};
|
|
|
|
/** Wraps a given @a BilinearFormIntegrator and transposes the resulting element
|
|
matrices. See for example ex9, ex9p. */
|
|
class TransposeIntegrator : public BilinearFormIntegrator
|
|
{
|
|
private:
|
|
int own_bfi;
|
|
BilinearFormIntegrator *bfi;
|
|
|
|
DenseMatrix bfi_elmat;
|
|
|
|
public:
|
|
TransposeIntegrator (BilinearFormIntegrator *_bfi, int _own_bfi = 1)
|
|
{ bfi = _bfi; own_bfi = _own_bfi; }
|
|
|
|
virtual void AssembleElementMatrix(const FiniteElement &el,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
|
|
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
|
|
const FiniteElement &test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
|
|
using BilinearFormIntegrator::AssembleFaceMatrix;
|
|
virtual void AssembleFaceMatrix(const FiniteElement &el1,
|
|
const FiniteElement &el2,
|
|
FaceElementTransformations &Trans,
|
|
DenseMatrix &elmat);
|
|
|
|
using BilinearFormIntegrator::AssemblePA;
|
|
|
|
virtual void AssemblePA(const FiniteElementSpace& fes)
|
|
{
|
|
bfi->AssemblePA(fes);
|
|
}
|
|
|
|
virtual void AssemblePAInteriorFaces(const FiniteElementSpace &fes)
|
|
{
|
|
bfi->AssemblePAInteriorFaces(fes);
|
|
}
|
|
|
|
virtual void AssemblePABoundaryFaces(const FiniteElementSpace &fes)
|
|
{
|
|
bfi->AssemblePABoundaryFaces(fes);
|
|
}
|
|
|
|
virtual void AddMultTransposePA(const Vector &x, Vector &y) const
|
|
{
|
|
bfi->AddMultPA(x, y);
|
|
}
|
|
|
|
virtual void AddMultPA(const Vector& x, Vector& y) const
|
|
{
|
|
bfi->AddMultTransposePA(x, y);
|
|
}
|
|
|
|
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
|
|
|
|
virtual void AssembleEAInteriorFaces(const FiniteElementSpace &fes,
|
|
Vector &ea_data_int,
|
|
Vector &ea_data_ext);
|
|
|
|
virtual void AssembleEABoundaryFaces(const FiniteElementSpace &fes,
|
|
Vector &ea_data_bdr);
|
|
|
|
virtual ~TransposeIntegrator() { if (own_bfi) { delete bfi; } }
|
|
};
|
|
|
|
class LumpedIntegrator : public BilinearFormIntegrator
|
|
{
|
|
private:
|
|
int own_bfi;
|
|
BilinearFormIntegrator *bfi;
|
|
|
|
public:
|
|
LumpedIntegrator (BilinearFormIntegrator *_bfi, int _own_bfi = 1)
|
|
{ bfi = _bfi; own_bfi = _own_bfi; }
|
|
|
|
virtual void AssembleElementMatrix(const FiniteElement &el,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
|
|
virtual ~LumpedIntegrator() { if (own_bfi) { delete bfi; } }
|
|
};
|
|
|
|
/// Integrator that inverts the matrix assembled by another integrator.
|
|
class InverseIntegrator : public BilinearFormIntegrator
|
|
{
|
|
private:
|
|
int own_integrator;
|
|
BilinearFormIntegrator *integrator;
|
|
|
|
public:
|
|
InverseIntegrator(BilinearFormIntegrator *integ, int own_integ = 1)
|
|
{ integrator = integ; own_integrator = own_integ; }
|
|
|
|
virtual void AssembleElementMatrix(const FiniteElement &el,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
|
|
virtual ~InverseIntegrator() { if (own_integrator) { delete integrator; } }
|
|
};
|
|
|
|
/// Integrator defining a sum of multiple Integrators.
|
|
class SumIntegrator : public BilinearFormIntegrator
|
|
{
|
|
private:
|
|
int own_integrators;
|
|
DenseMatrix elem_mat;
|
|
Array<BilinearFormIntegrator*> integrators;
|
|
|
|
public:
|
|
SumIntegrator(int own_integs = 1) { own_integrators = own_integs; }
|
|
|
|
void AddIntegrator(BilinearFormIntegrator *integ)
|
|
{ integrators.Append(integ); }
|
|
|
|
virtual void AssembleElementMatrix(const FiniteElement &el,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
|
|
virtual ~SumIntegrator();
|
|
};
|
|
|
|
/** An abstract class for integrating the product of two scalar basis functions
|
|
with an optional scalar coefficient. */
|
|
class MixedScalarIntegrator: public BilinearFormIntegrator
|
|
{
|
|
public:
|
|
|
|
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
|
|
const FiniteElement &test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
|
|
/// Support for use in BilinearForm. Can be used only when appropriate.
|
|
virtual void AssembleElementMatrix(const FiniteElement &fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat)
|
|
{ AssembleElementMatrix2(fe, fe, Trans, elmat); }
|
|
|
|
protected:
|
|
/// This parameter can be set by derived methods to enable single shape
|
|
/// evaluation in case CalcTestShape() and CalcTrialShape() return the same
|
|
/// result if given the same FiniteElement. The default is false.
|
|
bool same_calc_shape;
|
|
|
|
MixedScalarIntegrator() : same_calc_shape(false), Q(NULL) {}
|
|
MixedScalarIntegrator(Coefficient &q) : same_calc_shape(false), Q(&q) {}
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedScalarIntegrator: "
|
|
"Trial and test spaces must both be scalar fields.";
|
|
}
|
|
|
|
inline virtual int GetIntegrationOrder(const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe,
|
|
ElementTransformation &Trans)
|
|
{ return trial_fe.GetOrder() + test_fe.GetOrder() + Trans.OrderW(); }
|
|
|
|
|
|
inline virtual void CalcTestShape(const FiniteElement & test_fe,
|
|
ElementTransformation &Trans,
|
|
Vector & shape)
|
|
{ test_fe.CalcPhysShape(Trans, shape); }
|
|
|
|
inline virtual void CalcTrialShape(const FiniteElement & trial_fe,
|
|
ElementTransformation &Trans,
|
|
Vector & shape)
|
|
{ trial_fe.CalcPhysShape(Trans, shape); }
|
|
|
|
Coefficient *Q;
|
|
|
|
private:
|
|
|
|
#ifndef MFEM_THREAD_SAFE
|
|
Vector test_shape;
|
|
Vector trial_shape;
|
|
#endif
|
|
|
|
};
|
|
|
|
/** An abstract class for integrating the inner product of two vector basis
|
|
functions with an optional scalar, vector, or matrix coefficient. */
|
|
class MixedVectorIntegrator: public BilinearFormIntegrator
|
|
{
|
|
public:
|
|
|
|
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
|
|
const FiniteElement &test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
|
|
/// Support for use in BilinearForm. Can be used only when appropriate.
|
|
virtual void AssembleElementMatrix(const FiniteElement &fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat)
|
|
{ AssembleElementMatrix2(fe, fe, Trans, elmat); }
|
|
|
|
protected:
|
|
/// This parameter can be set by derived methods to enable single shape
|
|
/// evaluation in case CalcTestShape() and CalcTrialShape() return the same
|
|
/// result if given the same FiniteElement. The default is false.
|
|
bool same_calc_shape;
|
|
|
|
MixedVectorIntegrator()
|
|
: same_calc_shape(false), Q(NULL), VQ(NULL), DQ(NULL), MQ(NULL) {}
|
|
MixedVectorIntegrator(Coefficient &q)
|
|
: same_calc_shape(false), Q(&q), VQ(NULL), DQ(NULL), MQ(NULL) {}
|
|
MixedVectorIntegrator(VectorCoefficient &dq, bool diag = true)
|
|
: same_calc_shape(false), Q(NULL), VQ(diag?NULL:&dq), DQ(diag?&dq:NULL),
|
|
MQ(NULL) {}
|
|
MixedVectorIntegrator(MatrixCoefficient &mq)
|
|
: same_calc_shape(false), Q(NULL), VQ(NULL), DQ(NULL), MQ(&mq) {}
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedVectorIntegrator: "
|
|
"Trial and test spaces must both be vector fields";
|
|
}
|
|
|
|
inline virtual int GetIntegrationOrder(const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe,
|
|
ElementTransformation &Trans)
|
|
{ return trial_fe.GetOrder() + test_fe.GetOrder() + Trans.OrderW(); }
|
|
|
|
|
|
inline virtual void CalcTestShape(const FiniteElement & test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ test_fe.CalcVShape(Trans, shape); }
|
|
|
|
inline virtual void CalcTrialShape(const FiniteElement & trial_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ trial_fe.CalcVShape(Trans, shape); }
|
|
|
|
Coefficient *Q;
|
|
VectorCoefficient *VQ;
|
|
VectorCoefficient *DQ;
|
|
MatrixCoefficient *MQ;
|
|
|
|
private:
|
|
|
|
#ifndef MFEM_THREAD_SAFE
|
|
Vector V;
|
|
Vector D;
|
|
DenseMatrix M;
|
|
DenseMatrix test_shape;
|
|
DenseMatrix trial_shape;
|
|
DenseMatrix test_shape_tmp;
|
|
#endif
|
|
|
|
};
|
|
|
|
/** An abstract class for integrating the product of a scalar basis function and
|
|
the inner product of a vector basis function with a vector coefficient. In
|
|
2D the inner product can be replaced with a cross product. */
|
|
class MixedScalarVectorIntegrator: public BilinearFormIntegrator
|
|
{
|
|
public:
|
|
|
|
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
|
|
const FiniteElement &test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
|
|
/// Support for use in BilinearForm. Can be used only when appropriate.
|
|
/** Appropriate use cases are classes derived from
|
|
MixedScalarVectorIntegrator where the trial and test spaces can be the
|
|
same. Examples of such classes are: MixedVectorDivergenceIntegrator,
|
|
MixedScalarWeakDivergenceIntegrator, etc. */
|
|
virtual void AssembleElementMatrix(const FiniteElement &fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat)
|
|
{ AssembleElementMatrix2(fe, fe, Trans, elmat); }
|
|
|
|
protected:
|
|
|
|
MixedScalarVectorIntegrator(VectorCoefficient &vq, bool _transpose = false,
|
|
bool _cross_2d = false)
|
|
: VQ(&vq), transpose(_transpose), cross_2d(_cross_2d) {}
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return ((transpose &&
|
|
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR ) ||
|
|
(!transpose &&
|
|
trial_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR )
|
|
);
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
if ( transpose )
|
|
{
|
|
return "MixedScalarVectorIntegrator: "
|
|
"Trial space must be a vector field "
|
|
"and the test space must be a scalar field";
|
|
}
|
|
else
|
|
{
|
|
return "MixedScalarVectorIntegrator: "
|
|
"Trial space must be a scalar field "
|
|
"and the test space must be a vector field";
|
|
}
|
|
}
|
|
|
|
inline virtual int GetIntegrationOrder(const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe,
|
|
ElementTransformation &Trans)
|
|
{ return trial_fe.GetOrder() + test_fe.GetOrder() + Trans.OrderW(); }
|
|
|
|
|
|
inline virtual void CalcVShape(const FiniteElement & vector_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ vector_fe.CalcVShape(Trans, shape); }
|
|
|
|
inline virtual void CalcShape(const FiniteElement & scalar_fe,
|
|
ElementTransformation &Trans,
|
|
Vector & shape)
|
|
{ scalar_fe.CalcPhysShape(Trans, shape); }
|
|
|
|
VectorCoefficient *VQ;
|
|
bool transpose;
|
|
bool cross_2d; // In 2D use a cross product rather than a dot product
|
|
|
|
private:
|
|
|
|
#ifndef MFEM_THREAD_SAFE
|
|
Vector V;
|
|
DenseMatrix vshape;
|
|
Vector shape;
|
|
Vector vshape_tmp;
|
|
#endif
|
|
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (Q u, v) in either 1D, 2D,
|
|
or 3D and where Q is an optional scalar coefficient, u and v are each in H1
|
|
or L2. */
|
|
class MixedScalarMassIntegrator : public MixedScalarIntegrator
|
|
{
|
|
public:
|
|
MixedScalarMassIntegrator() { same_calc_shape = true; }
|
|
MixedScalarMassIntegrator(Coefficient &q)
|
|
: MixedScalarIntegrator(q) { same_calc_shape = true; }
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (Q u, v) in either 2D, or
|
|
3D and where Q is a vector coefficient, u is in H1 or L2 and v is in H(Curl)
|
|
or H(Div). */
|
|
class MixedVectorProductIntegrator : public MixedScalarVectorIntegrator
|
|
{
|
|
public:
|
|
MixedVectorProductIntegrator(VectorCoefficient &vq)
|
|
: MixedScalarVectorIntegrator(vq) {}
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (Q D u, v) in 1D where Q
|
|
is an optional scalar coefficient, u is in H1, and v is in L2. */
|
|
class MixedScalarDerivativeIntegrator : public MixedScalarIntegrator
|
|
{
|
|
public:
|
|
MixedScalarDerivativeIntegrator() {}
|
|
MixedScalarDerivativeIntegrator(Coefficient &q)
|
|
: MixedScalarIntegrator(q) {}
|
|
|
|
protected:
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetDim() == 1 && test_fe.GetDim() == 1 &&
|
|
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedScalarDerivativeIntegrator: "
|
|
"Trial and test spaces must both be scalar fields in 1D "
|
|
"and the trial space must implement CaldDShape.";
|
|
}
|
|
|
|
inline virtual void CalcTrialShape(const FiniteElement & trial_fe,
|
|
ElementTransformation &Trans,
|
|
Vector & shape)
|
|
{
|
|
DenseMatrix dshape(shape.GetData(), shape.Size(), 1);
|
|
trial_fe.CalcPhysDShape(Trans, dshape);
|
|
}
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := -(Q u, D v) in 1D where Q
|
|
is an optional scalar coefficient, u is in L2, and v is in H1. */
|
|
class MixedScalarWeakDerivativeIntegrator : public MixedScalarIntegrator
|
|
{
|
|
public:
|
|
MixedScalarWeakDerivativeIntegrator() {}
|
|
MixedScalarWeakDerivativeIntegrator(Coefficient &q)
|
|
: MixedScalarIntegrator(q) {}
|
|
|
|
protected:
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetDim() == 1 && test_fe.GetDim() == 1 &&
|
|
trial_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
|
test_fe.GetDerivType() == mfem::FiniteElement::GRAD );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedScalarWeakDerivativeIntegrator: "
|
|
"Trial and test spaces must both be scalar fields in 1D "
|
|
"and the test space must implement CalcDShape with "
|
|
"map type \"VALUE\".";
|
|
}
|
|
|
|
inline virtual void CalcTestShape(const FiniteElement & test_fe,
|
|
ElementTransformation &Trans,
|
|
Vector & shape)
|
|
{
|
|
DenseMatrix dshape(shape.GetData(), shape.Size(), 1);
|
|
test_fe.CalcPhysDShape(Trans, dshape);
|
|
shape *= -1.0;
|
|
}
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (Q div u, v) in either 2D
|
|
or 3D where Q is an optional scalar coefficient, u is in H(Div), and v is a
|
|
scalar field. */
|
|
class MixedScalarDivergenceIntegrator : public MixedScalarIntegrator
|
|
{
|
|
public:
|
|
MixedScalarDivergenceIntegrator() {}
|
|
MixedScalarDivergenceIntegrator(Coefficient &q)
|
|
: MixedScalarIntegrator(q) {}
|
|
|
|
protected:
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetDerivType() == mfem::FiniteElement::DIV &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedScalarDivergenceIntegrator: "
|
|
"Trial must be H(Div) and the test space must be a "
|
|
"scalar field";
|
|
}
|
|
|
|
inline virtual int GetIntegrationOrder(const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe,
|
|
ElementTransformation &Trans)
|
|
{ return trial_fe.GetOrder() + test_fe.GetOrder() + Trans.OrderW() - 1; }
|
|
|
|
inline virtual void CalcTrialShape(const FiniteElement & trial_fe,
|
|
ElementTransformation &Trans,
|
|
Vector & shape)
|
|
{ trial_fe.CalcPhysDivShape(Trans, shape); }
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (V div u, v) in either 2D
|
|
or 3D where V is a vector coefficient, u is in H(Div), and v is a vector
|
|
field. */
|
|
class MixedVectorDivergenceIntegrator : public MixedScalarVectorIntegrator
|
|
{
|
|
public:
|
|
MixedVectorDivergenceIntegrator(VectorCoefficient &vq)
|
|
: MixedScalarVectorIntegrator(vq) {}
|
|
|
|
protected:
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetDerivType() == mfem::FiniteElement::DIV &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedVectorDivergenceIntegrator: "
|
|
"Trial must be H(Div) and the test space must be a "
|
|
"vector field";
|
|
}
|
|
|
|
// Subtract one due to the divergence and add one for the coefficient
|
|
// which is assumed to be at least linear.
|
|
inline virtual int GetIntegrationOrder(const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe,
|
|
ElementTransformation &Trans)
|
|
{ return trial_fe.GetOrder() + test_fe.GetOrder() + Trans.OrderW() - 1 + 1; }
|
|
|
|
inline virtual void CalcShape(const FiniteElement & scalar_fe,
|
|
ElementTransformation &Trans,
|
|
Vector & shape)
|
|
{ scalar_fe.CalcPhysDivShape(Trans, shape); }
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := -(Q u, div v) in either 2D
|
|
or 3D where Q is an optional scalar coefficient, u is in L2 or H1, and v is
|
|
in H(Div). */
|
|
class MixedScalarWeakGradientIntegrator : public MixedScalarIntegrator
|
|
{
|
|
public:
|
|
MixedScalarWeakGradientIntegrator() {}
|
|
MixedScalarWeakGradientIntegrator(Coefficient &q)
|
|
: MixedScalarIntegrator(q) {}
|
|
|
|
protected:
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
|
test_fe.GetDerivType() == mfem::FiniteElement::DIV );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedScalarWeakGradientIntegrator: "
|
|
"Trial space must be a scalar field "
|
|
"and the test space must be H(Div)";
|
|
}
|
|
|
|
inline virtual int GetIntegrationOrder(const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe,
|
|
ElementTransformation &Trans)
|
|
{ return trial_fe.GetOrder() + test_fe.GetOrder() + Trans.OrderW() - 1; }
|
|
|
|
virtual void CalcTestShape(const FiniteElement & test_fe,
|
|
ElementTransformation &Trans,
|
|
Vector & shape)
|
|
{
|
|
test_fe.CalcPhysDivShape(Trans, shape);
|
|
shape *= -1.0;
|
|
}
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (Q curl u, v) in 2D where
|
|
Q is an optional scalar coefficient, u is in H(Curl), and v is in L2 or
|
|
H1. */
|
|
class MixedScalarCurlIntegrator : public MixedScalarIntegrator
|
|
{
|
|
public:
|
|
MixedScalarCurlIntegrator() {}
|
|
MixedScalarCurlIntegrator(Coefficient &q)
|
|
: MixedScalarIntegrator(q) {}
|
|
|
|
protected:
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetDim() == 2 && test_fe.GetDim() == 2 &&
|
|
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedScalarCurlIntegrator: "
|
|
"Trial must be H(Curl) and the test space must be a "
|
|
"scalar field";
|
|
}
|
|
|
|
inline virtual int GetIntegrationOrder(const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe,
|
|
ElementTransformation &Trans)
|
|
{ return trial_fe.GetOrder() + test_fe.GetOrder() + Trans.OrderW() - 1; }
|
|
|
|
inline virtual void CalcTrialShape(const FiniteElement & trial_fe,
|
|
ElementTransformation &Trans,
|
|
Vector & shape)
|
|
{
|
|
DenseMatrix dshape(shape.GetData(), shape.Size(), 1);
|
|
trial_fe.CalcPhysCurlShape(Trans, dshape);
|
|
}
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (Q u, curl v) in 2D where
|
|
Q is an optional scalar coefficient, u is in L2 or H1, and v is in
|
|
H(Curl). */
|
|
class MixedScalarWeakCurlIntegrator : public MixedScalarIntegrator
|
|
{
|
|
public:
|
|
MixedScalarWeakCurlIntegrator() {}
|
|
MixedScalarWeakCurlIntegrator(Coefficient &q)
|
|
: MixedScalarIntegrator(q) {}
|
|
|
|
protected:
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetDim() == 2 && test_fe.GetDim() == 2 &&
|
|
trial_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
|
test_fe.GetDerivType() == mfem::FiniteElement::CURL );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedScalarWeakCurlIntegrator: "
|
|
"Trial space must be a scalar field "
|
|
"and the test space must be H(Curl)";
|
|
}
|
|
|
|
inline virtual void CalcTestShape(const FiniteElement & test_fe,
|
|
ElementTransformation &Trans,
|
|
Vector & shape)
|
|
{
|
|
DenseMatrix dshape(shape.GetData(), shape.Size(), 1);
|
|
test_fe.CalcPhysCurlShape(Trans, dshape);
|
|
}
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (Q u, v) in either 2D or
|
|
3D and where Q is an optional coefficient (of type scalar, matrix, or
|
|
diagonal matrix) u and v are each in H(Curl) or H(Div). */
|
|
class MixedVectorMassIntegrator : public MixedVectorIntegrator
|
|
{
|
|
public:
|
|
MixedVectorMassIntegrator() { same_calc_shape = true; }
|
|
MixedVectorMassIntegrator(Coefficient &q)
|
|
: MixedVectorIntegrator(q) { same_calc_shape = true; }
|
|
MixedVectorMassIntegrator(VectorCoefficient &dq)
|
|
: MixedVectorIntegrator(dq, true) { same_calc_shape = true; }
|
|
MixedVectorMassIntegrator(MatrixCoefficient &mq)
|
|
: MixedVectorIntegrator(mq) { same_calc_shape = true; }
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (V x u, v) in 3D and where
|
|
V is a vector coefficient u and v are each in H(Curl) or H(Div). */
|
|
class MixedCrossProductIntegrator : public MixedVectorIntegrator
|
|
{
|
|
public:
|
|
MixedCrossProductIntegrator(VectorCoefficient &vq)
|
|
: MixedVectorIntegrator(vq, false) { same_calc_shape = true; }
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (V . u, v) in 2D or 3D and
|
|
where V is a vector coefficient u is in H(Curl) or H(Div) and v is in H1 or
|
|
L2. */
|
|
class MixedDotProductIntegrator : public MixedScalarVectorIntegrator
|
|
{
|
|
public:
|
|
MixedDotProductIntegrator(VectorCoefficient &vq)
|
|
: MixedScalarVectorIntegrator(vq, true) {}
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedDotProductIntegrator: "
|
|
"Trial space must be a vector field "
|
|
"and the test space must be a scalar field";
|
|
}
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (-V . u, Div v) in 2D or
|
|
3D and where V is a vector coefficient u is in H(Curl) or H(Div) and v is in
|
|
RT. */
|
|
class MixedWeakGradDotIntegrator : public MixedScalarVectorIntegrator
|
|
{
|
|
public:
|
|
MixedWeakGradDotIntegrator(VectorCoefficient &vq)
|
|
: MixedScalarVectorIntegrator(vq, true) {}
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
|
test_fe.GetDerivType() == mfem::FiniteElement::DIV );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedWeakGradDotIntegrator: "
|
|
"Trial space must be a vector field "
|
|
"and the test space must be a vector field with a divergence";
|
|
}
|
|
|
|
// Subtract one due to the gradient and add one for the coefficient
|
|
// which is assumed to be at least linear.
|
|
inline virtual int GetIntegrationOrder(const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe,
|
|
ElementTransformation &Trans)
|
|
{ return trial_fe.GetOrder() + test_fe.GetOrder() + Trans.OrderW() - 1 + 1; }
|
|
|
|
inline virtual void CalcShape(const FiniteElement & scalar_fe,
|
|
ElementTransformation &Trans,
|
|
Vector & shape)
|
|
{ scalar_fe.CalcPhysDivShape(Trans, shape); shape *= -1.0; }
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (V x u, Grad v) in 3D and
|
|
where V is a vector coefficient u is in H(Curl) or H(Div) and v is in H1. */
|
|
class MixedWeakDivCrossIntegrator : public MixedVectorIntegrator
|
|
{
|
|
public:
|
|
MixedWeakDivCrossIntegrator(VectorCoefficient &vq)
|
|
: MixedVectorIntegrator(vq, false) {}
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetDim() == 3 && test_fe.GetDim() == 3 &&
|
|
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
|
test_fe.GetDerivType() == mfem::FiniteElement::GRAD );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedWeakDivCrossIntegrator: "
|
|
"Trial space must be a vector field in 3D "
|
|
"and the test space must be a scalar field with a gradient";
|
|
}
|
|
|
|
inline virtual void CalcTestShape(const FiniteElement & test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ test_fe.CalcPhysDShape(Trans, shape); shape *= -1.0; }
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (Q Grad u, Grad v) in 3D
|
|
or in 2D and where Q is a scalar or matrix coefficient u and v are both in
|
|
H1. */
|
|
class MixedGradGradIntegrator : public MixedVectorIntegrator
|
|
{
|
|
public:
|
|
MixedGradGradIntegrator() { same_calc_shape = true; }
|
|
MixedGradGradIntegrator(Coefficient &q)
|
|
: MixedVectorIntegrator(q) { same_calc_shape = true; }
|
|
MixedGradGradIntegrator(VectorCoefficient &dq)
|
|
: MixedVectorIntegrator(dq, true) { same_calc_shape = true; }
|
|
MixedGradGradIntegrator(MatrixCoefficient &mq)
|
|
: MixedVectorIntegrator(mq) { same_calc_shape = true; }
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
|
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
|
test_fe.GetDerivType() == mfem::FiniteElement::GRAD );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedGradGradIntegrator: "
|
|
"Trial and test spaces must both be scalar fields "
|
|
"with a gradient operator.";
|
|
}
|
|
|
|
inline virtual int GetIntegrationOrder(const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe,
|
|
ElementTransformation &Trans)
|
|
{
|
|
// Same as DiffusionIntegrator
|
|
return test_fe.Space() == FunctionSpace::Pk ?
|
|
trial_fe.GetOrder() + test_fe.GetOrder() - 2 :
|
|
trial_fe.GetOrder() + test_fe.GetOrder() + test_fe.GetDim() - 1;
|
|
}
|
|
|
|
inline virtual void CalcTrialShape(const FiniteElement & trial_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ trial_fe.CalcPhysDShape(Trans, shape); }
|
|
|
|
inline virtual void CalcTestShape(const FiniteElement & test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ test_fe.CalcPhysDShape(Trans, shape); }
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (V x Grad u, Grad v) in 3D
|
|
or in 2D and where V is a vector coefficient u and v are both in H1. */
|
|
class MixedCrossGradGradIntegrator : public MixedVectorIntegrator
|
|
{
|
|
public:
|
|
MixedCrossGradGradIntegrator(VectorCoefficient &vq)
|
|
: MixedVectorIntegrator(vq, false) { same_calc_shape = true; }
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
|
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
|
test_fe.GetDerivType() == mfem::FiniteElement::GRAD );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedCrossGradGradIntegrator: "
|
|
"Trial and test spaces must both be scalar fields "
|
|
"with a gradient operator.";
|
|
}
|
|
|
|
inline virtual void CalcTrialShape(const FiniteElement & trial_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ trial_fe.CalcPhysDShape(Trans, shape); }
|
|
|
|
inline virtual void CalcTestShape(const FiniteElement & test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ test_fe.CalcPhysDShape(Trans, shape); }
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (Q Curl u, Curl v) in 3D
|
|
and where Q is a scalar or matrix coefficient u and v are both in
|
|
H(Curl). */
|
|
class MixedCurlCurlIntegrator : public MixedVectorIntegrator
|
|
{
|
|
public:
|
|
MixedCurlCurlIntegrator() { same_calc_shape = true; }
|
|
MixedCurlCurlIntegrator(Coefficient &q)
|
|
: MixedVectorIntegrator(q) { same_calc_shape = true; }
|
|
MixedCurlCurlIntegrator(VectorCoefficient &dq)
|
|
: MixedVectorIntegrator(dq, true) { same_calc_shape = true; }
|
|
MixedCurlCurlIntegrator(MatrixCoefficient &mq)
|
|
: MixedVectorIntegrator(mq) { same_calc_shape = true; }
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetDim() == 3 && test_fe.GetDim() == 3 &&
|
|
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
|
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
|
test_fe.GetDerivType() == mfem::FiniteElement::CURL );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedCurlCurlIntegrator"
|
|
"Trial and test spaces must both be vector fields in 3D "
|
|
"with a curl.";
|
|
}
|
|
|
|
inline virtual void CalcTrialShape(const FiniteElement & trial_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ trial_fe.CalcPhysCurlShape(Trans, shape); }
|
|
|
|
inline virtual void CalcTestShape(const FiniteElement & test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ test_fe.CalcPhysCurlShape(Trans, shape); }
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (V x Curl u, Curl v) in 3D
|
|
and where V is a vector coefficient u and v are both in H(Curl). */
|
|
class MixedCrossCurlCurlIntegrator : public MixedVectorIntegrator
|
|
{
|
|
public:
|
|
MixedCrossCurlCurlIntegrator(VectorCoefficient &vq)
|
|
: MixedVectorIntegrator(vq, false) { same_calc_shape = true; }
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetDim() == 3 && test_fe.GetDim() == 3 &&
|
|
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
|
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
|
test_fe.GetDerivType() == mfem::FiniteElement::CURL );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedCrossCurlCurlIntegrator: "
|
|
"Trial and test spaces must both be vector fields in 3D "
|
|
"with a curl.";
|
|
}
|
|
|
|
inline virtual void CalcTrialShape(const FiniteElement & trial_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ trial_fe.CalcPhysCurlShape(Trans, shape); }
|
|
|
|
inline virtual void CalcTestShape(const FiniteElement & test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ test_fe.CalcPhysCurlShape(Trans, shape); }
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (V x Curl u, Grad v) in 3D
|
|
and where V is a vector coefficient u is in H(Curl) and v is in H1. */
|
|
class MixedCrossCurlGradIntegrator : public MixedVectorIntegrator
|
|
{
|
|
public:
|
|
MixedCrossCurlGradIntegrator(VectorCoefficient &vq)
|
|
: MixedVectorIntegrator(vq, false) {}
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetDim() == 3 && test_fe.GetDim() == 3 &&
|
|
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
|
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
|
test_fe.GetDerivType() == mfem::FiniteElement::GRAD );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedCrossCurlGradIntegrator"
|
|
"Trial space must be a vector field in 3D with a curl"
|
|
"and the test space must be a scalar field with a gradient";
|
|
}
|
|
|
|
inline virtual void CalcTrialShape(const FiniteElement & trial_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ trial_fe.CalcPhysCurlShape(Trans, shape); }
|
|
|
|
inline virtual void CalcTestShape(const FiniteElement & test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ test_fe.CalcPhysDShape(Trans, shape); }
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (V x Grad u, Curl v) in 3D
|
|
and where V is a scalar coefficient u is in H1 and v is in H(Curl). */
|
|
class MixedCrossGradCurlIntegrator : public MixedVectorIntegrator
|
|
{
|
|
public:
|
|
MixedCrossGradCurlIntegrator(VectorCoefficient &vq)
|
|
: MixedVectorIntegrator(vq, false) {}
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetDim() == 3 && test_fe.GetDim() == 3 &&
|
|
trial_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
|
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
|
test_fe.GetDerivType() == mfem::FiniteElement::CURL );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedCrossGradCurlIntegrator"
|
|
"Trial space must be a scalar field in 3D with a gradient"
|
|
"and the test space must be a vector field with a curl";
|
|
}
|
|
|
|
inline virtual void CalcTrialShape(const FiniteElement & trial_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ trial_fe.CalcPhysDShape(Trans, shape); }
|
|
|
|
inline virtual void CalcTestShape(const FiniteElement & test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ test_fe.CalcPhysCurlShape(Trans, shape); }
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (V x u, Curl v) in 3D and
|
|
where V is a vector coefficient u is in H(Curl) or H(Div) and v is in
|
|
H(Curl). */
|
|
class MixedWeakCurlCrossIntegrator : public MixedVectorIntegrator
|
|
{
|
|
public:
|
|
MixedWeakCurlCrossIntegrator(VectorCoefficient &vq)
|
|
: MixedVectorIntegrator(vq, false) {}
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetDim() == 3 && test_fe.GetDim() == 3 &&
|
|
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
|
test_fe.GetDerivType() == mfem::FiniteElement::CURL );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedWeakCurlCrossIntegrator: "
|
|
"Trial space must be a vector field in 3D "
|
|
"and the test space must be a vector field with a curl";
|
|
}
|
|
|
|
inline virtual void CalcTestShape(const FiniteElement & test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ test_fe.CalcPhysCurlShape(Trans, shape); }
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (V x u, Curl v) in 2D and
|
|
where V is a vector coefficient u is in H(Curl) or H(Div) and v is in
|
|
H(Curl). */
|
|
class MixedScalarWeakCurlCrossIntegrator : public MixedScalarVectorIntegrator
|
|
{
|
|
public:
|
|
MixedScalarWeakCurlCrossIntegrator(VectorCoefficient &vq)
|
|
: MixedScalarVectorIntegrator(vq, true, true) {}
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetDim() == 2 && test_fe.GetDim() == 2 &&
|
|
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
|
test_fe.GetDerivType() == mfem::FiniteElement::CURL );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedScalarWeakCurlCrossIntegrator: "
|
|
"Trial space must be a vector field in 2D "
|
|
"and the test space must be a vector field with a curl";
|
|
}
|
|
|
|
inline virtual void CalcShape(const FiniteElement & scalar_fe,
|
|
ElementTransformation &Trans,
|
|
Vector & shape)
|
|
{
|
|
DenseMatrix dshape(shape.GetData(), shape.Size(), 1);
|
|
scalar_fe.CalcPhysCurlShape(Trans, dshape);
|
|
}
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (V x Grad u, v) in 3D or
|
|
in 2D and where V is a vector coefficient u is in H1 and v is in H(Curl) or
|
|
H(Div). */
|
|
class MixedCrossGradIntegrator : public MixedVectorIntegrator
|
|
{
|
|
public:
|
|
MixedCrossGradIntegrator(VectorCoefficient &vq)
|
|
: MixedVectorIntegrator(vq, false) {}
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetDim() == 3 && test_fe.GetDim() == 3 &&
|
|
trial_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
|
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedCrossGradIntegrator: "
|
|
"Trial space must be a scalar field with a gradient operator"
|
|
" and the test space must be a vector field both in 3D.";
|
|
}
|
|
|
|
inline virtual void CalcTrialShape(const FiniteElement & trial_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ trial_fe.CalcPhysDShape(Trans, shape); }
|
|
|
|
inline virtual void CalcTestShape(const FiniteElement & test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ test_fe.CalcVShape(Trans, shape); }
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (V x Curl u, v) in 3D and
|
|
where V is a vector coefficient u is in H(Curl) and v is in H(Curl) or
|
|
H(Div). */
|
|
class MixedCrossCurlIntegrator : public MixedVectorIntegrator
|
|
{
|
|
public:
|
|
MixedCrossCurlIntegrator(VectorCoefficient &vq)
|
|
: MixedVectorIntegrator(vq, false) {}
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetDim() == 3 && test_fe.GetDim() == 3 &&
|
|
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
|
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedCrossCurlIntegrator: "
|
|
"Trial space must be a vector field in 3D with a curl "
|
|
"and the test space must be a vector field";
|
|
}
|
|
|
|
inline virtual void CalcTrialShape(const FiniteElement & trial_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ trial_fe.CalcPhysCurlShape(Trans, shape); }
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (V x Curl u, v) in 2D and
|
|
where V is a vector coefficient u is in H(Curl) and v is in H(Curl) or
|
|
H(Div). */
|
|
class MixedScalarCrossCurlIntegrator : public MixedScalarVectorIntegrator
|
|
{
|
|
public:
|
|
MixedScalarCrossCurlIntegrator(VectorCoefficient &vq)
|
|
: MixedScalarVectorIntegrator(vq, false, true) {}
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetDim() == 2 && test_fe.GetDim() == 2 &&
|
|
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
|
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedCrossCurlIntegrator: "
|
|
"Trial space must be a vector field in 2D with a curl "
|
|
"and the test space must be a vector field";
|
|
}
|
|
|
|
inline virtual void CalcShape(const FiniteElement & scalar_fe,
|
|
ElementTransformation &Trans,
|
|
Vector & shape)
|
|
{
|
|
DenseMatrix dshape(shape.GetData(), shape.Size(), 1);
|
|
scalar_fe.CalcPhysCurlShape(Trans, dshape); shape *= -1.0;
|
|
}
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (V x Grad u, v) in 2D and
|
|
where V is a vector coefficient u is in H1 and v is in H1 or L2. */
|
|
class MixedScalarCrossGradIntegrator : public MixedScalarVectorIntegrator
|
|
{
|
|
public:
|
|
MixedScalarCrossGradIntegrator(VectorCoefficient &vq)
|
|
: MixedScalarVectorIntegrator(vq, true, true) {}
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetDim() == 2 && test_fe.GetDim() == 2 &&
|
|
trial_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
|
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedScalarCrossGradIntegrator: "
|
|
"Trial space must be a scalar field in 2D with a gradient "
|
|
"and the test space must be a scalar field";
|
|
}
|
|
|
|
inline virtual void CalcVShape(const FiniteElement & vector_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ vector_fe.CalcPhysDShape(Trans, shape); }
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (V x u, v) in 2D and where
|
|
V is a vector coefficient u is in ND or RT and v is in H1 or L2. */
|
|
class MixedScalarCrossProductIntegrator : public MixedScalarVectorIntegrator
|
|
{
|
|
public:
|
|
MixedScalarCrossProductIntegrator(VectorCoefficient &vq)
|
|
: MixedScalarVectorIntegrator(vq, true, true) {}
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetDim() == 2 && test_fe.GetDim() == 2 &&
|
|
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedScalarCrossProductIntegrator: "
|
|
"Trial space must be a vector field in 2D "
|
|
"and the test space must be a scalar field";
|
|
}
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (V x z u, v) in 2D and
|
|
where V is a vector coefficient u is in H1 or L2 and v is in ND or RT. */
|
|
class MixedScalarWeakCrossProductIntegrator : public MixedScalarVectorIntegrator
|
|
{
|
|
public:
|
|
MixedScalarWeakCrossProductIntegrator(VectorCoefficient &vq)
|
|
: MixedScalarVectorIntegrator(vq, false, true) {}
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetDim() == 2 && test_fe.GetDim() == 2 &&
|
|
trial_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedScalarWeakCrossProductIntegrator: "
|
|
"Trial space must be a scalar field in 2D "
|
|
"and the test space must be a vector field";
|
|
}
|
|
|
|
inline virtual void CalcShape(const FiniteElement & scalar_fe,
|
|
ElementTransformation &Trans,
|
|
Vector & shape)
|
|
{ scalar_fe.CalcPhysShape(Trans, shape); shape *= -1.0; }
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (V . Grad u, v) in 2D or
|
|
3D and where V is a vector coefficient, u is in H1 and v is in H1 or L2. */
|
|
class MixedDirectionalDerivativeIntegrator : public MixedScalarVectorIntegrator
|
|
{
|
|
public:
|
|
MixedDirectionalDerivativeIntegrator(VectorCoefficient &vq)
|
|
: MixedScalarVectorIntegrator(vq, true) {}
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
|
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedDirectionalDerivativeIntegrator: "
|
|
"Trial space must be a scalar field with a gradient "
|
|
"and the test space must be a scalar field";
|
|
}
|
|
|
|
inline virtual void CalcVShape(const FiniteElement & vector_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ vector_fe.CalcPhysDShape(Trans, shape); }
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (-V . Grad u, Div v) in 2D
|
|
or 3D and where V is a vector coefficient, u is in H1 and v is in RT. */
|
|
class MixedGradDivIntegrator : public MixedScalarVectorIntegrator
|
|
{
|
|
public:
|
|
MixedGradDivIntegrator(VectorCoefficient &vq)
|
|
: MixedScalarVectorIntegrator(vq, true) {}
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
|
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
|
test_fe.GetDerivType() == mfem::FiniteElement::DIV );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedGradDivIntegrator: "
|
|
"Trial space must be a scalar field with a gradient"
|
|
"and the test space must be a vector field with a divergence";
|
|
}
|
|
|
|
inline virtual void CalcVShape(const FiniteElement & vector_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ vector_fe.CalcPhysDShape(Trans, shape); shape *= -1.0; }
|
|
|
|
inline virtual void CalcShape(const FiniteElement & scalar_fe,
|
|
ElementTransformation &Trans,
|
|
Vector & shape)
|
|
{ scalar_fe.CalcPhysDivShape(Trans, shape); }
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (-V Div u, Grad v) in 2D
|
|
or 3D and where V is a vector coefficient, u is in RT and v is in H1. */
|
|
class MixedDivGradIntegrator : public MixedScalarVectorIntegrator
|
|
{
|
|
public:
|
|
MixedDivGradIntegrator(VectorCoefficient &vq)
|
|
: MixedScalarVectorIntegrator(vq, false) {}
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
|
trial_fe.GetDerivType() == mfem::FiniteElement::DIV &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
|
test_fe.GetDerivType() == mfem::FiniteElement::GRAD
|
|
);
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedDivGradIntegrator: "
|
|
"Trial space must be a vector field with a divergence"
|
|
"and the test space must be a scalar field with a gradient";
|
|
}
|
|
|
|
inline virtual void CalcVShape(const FiniteElement & vector_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ vector_fe.CalcPhysDShape(Trans, shape); shape *= -1.0; }
|
|
|
|
inline virtual void CalcShape(const FiniteElement & scalar_fe,
|
|
ElementTransformation &Trans,
|
|
Vector & shape)
|
|
{ scalar_fe.CalcPhysDivShape(Trans, shape); }
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (-V u, Grad v) in 2D or 3D
|
|
and where V is a vector coefficient, u is in H1 and v is in H1. */
|
|
class MixedScalarWeakDivergenceIntegrator : public MixedScalarVectorIntegrator
|
|
{
|
|
public:
|
|
MixedScalarWeakDivergenceIntegrator(VectorCoefficient &vq)
|
|
: MixedScalarVectorIntegrator(vq, false) {}
|
|
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
|
|
test_fe.GetDerivType() == mfem::FiniteElement::GRAD );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedScalarWeakDivergenceIntegrator: "
|
|
"Trial space must be a scalar field "
|
|
"and the test space must be a scalar field with a gradient";
|
|
}
|
|
|
|
inline virtual void CalcVShape(const FiniteElement & vector_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{ vector_fe.CalcPhysDShape(Trans, shape); shape *= -1.0; }
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (Q grad u, v) in either 2D
|
|
or 3D and where Q is an optional coefficient (of type scalar, matrix, or
|
|
diagonal matrix) u is in H1 and v is in H(Curl) or H(Div). */
|
|
class MixedVectorGradientIntegrator : public MixedVectorIntegrator
|
|
{
|
|
public:
|
|
MixedVectorGradientIntegrator() {}
|
|
MixedVectorGradientIntegrator(Coefficient &q)
|
|
: MixedVectorIntegrator(q) {}
|
|
MixedVectorGradientIntegrator(VectorCoefficient &dq)
|
|
: MixedVectorIntegrator(dq, true) {}
|
|
MixedVectorGradientIntegrator(MatrixCoefficient &mq)
|
|
: MixedVectorIntegrator(mq) {}
|
|
|
|
protected:
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedVectorGradientIntegrator: "
|
|
"Trial spaces must be H1 and the test space must be a "
|
|
"vector field in 2D or 3D";
|
|
}
|
|
|
|
inline virtual void CalcTrialShape(const FiniteElement & trial_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{
|
|
trial_fe.CalcPhysDShape(Trans, shape);
|
|
}
|
|
|
|
using BilinearFormIntegrator::AssemblePA;
|
|
virtual void AssemblePA(const FiniteElementSpace &trial_fes,
|
|
const FiniteElementSpace &test_fes);
|
|
|
|
virtual void AddMultPA(const Vector&, Vector&) const;
|
|
|
|
private:
|
|
DenseMatrix Jinv;
|
|
|
|
// PA extension
|
|
Vector pa_data;
|
|
const DofToQuad *mapsO; ///< Not owned. DOF-to-quad map, open.
|
|
const DofToQuad *mapsC; ///< Not owned. DOF-to-quad map, closed.
|
|
const GeometricFactors *geom; ///< Not owned
|
|
int dim, ne, dofs1D, quad1D;
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (Q curl u, v) in 3D and
|
|
where Q is an optional coefficient (of type scalar, matrix, or diagonal
|
|
matrix) u is in H(Curl) and v is in H(Div) or H(Curl). */
|
|
class MixedVectorCurlIntegrator : public MixedVectorIntegrator
|
|
{
|
|
public:
|
|
MixedVectorCurlIntegrator() {}
|
|
MixedVectorCurlIntegrator(Coefficient &q)
|
|
: MixedVectorIntegrator(q) {}
|
|
MixedVectorCurlIntegrator(VectorCoefficient &dq)
|
|
: MixedVectorIntegrator(dq, true) {}
|
|
MixedVectorCurlIntegrator(MatrixCoefficient &mq)
|
|
: MixedVectorIntegrator(mq) {}
|
|
|
|
protected:
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetDim() == 3 && test_fe.GetDim() == 3 &&
|
|
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
|
|
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedVectorCurlIntegrator: "
|
|
"Trial space must be H(Curl) and the test space must be a "
|
|
"vector field in 3D";
|
|
}
|
|
|
|
inline virtual void CalcTrialShape(const FiniteElement & trial_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{
|
|
trial_fe.CalcPhysCurlShape(Trans, shape);
|
|
}
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (Q u, curl v) in 3D and
|
|
where Q is an optional coefficient (of type scalar, matrix, or diagonal
|
|
matrix) u is in H(Div) or H(Curl) and v is in H(Curl). */
|
|
class MixedVectorWeakCurlIntegrator : public MixedVectorIntegrator
|
|
{
|
|
public:
|
|
MixedVectorWeakCurlIntegrator() {}
|
|
MixedVectorWeakCurlIntegrator(Coefficient &q)
|
|
: MixedVectorIntegrator(q) {}
|
|
MixedVectorWeakCurlIntegrator(VectorCoefficient &dq)
|
|
: MixedVectorIntegrator(dq, true) {}
|
|
MixedVectorWeakCurlIntegrator(MatrixCoefficient &mq)
|
|
: MixedVectorIntegrator(mq) {}
|
|
|
|
protected:
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetDim() == 3 && test_fe.GetDim() == 3 &&
|
|
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
|
test_fe.GetDerivType() == mfem::FiniteElement::CURL );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedVectorWeakCurlIntegrator: "
|
|
"Trial space must be vector field in 3D and the "
|
|
"test space must be H(Curl)";
|
|
}
|
|
|
|
inline virtual void CalcTestShape(const FiniteElement & test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{
|
|
test_fe.CalcPhysCurlShape(Trans, shape);
|
|
}
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := - (Q u, grad v) in either
|
|
2D or 3D and where Q is an optional coefficient (of type scalar, matrix, or
|
|
diagonal matrix) u is in H(Div) or H(Curl) and v is in H1. */
|
|
class MixedVectorWeakDivergenceIntegrator : public MixedVectorIntegrator
|
|
{
|
|
public:
|
|
MixedVectorWeakDivergenceIntegrator() {}
|
|
MixedVectorWeakDivergenceIntegrator(Coefficient &q)
|
|
: MixedVectorIntegrator(q) {}
|
|
MixedVectorWeakDivergenceIntegrator(VectorCoefficient &dq)
|
|
: MixedVectorIntegrator(dq, true) {}
|
|
MixedVectorWeakDivergenceIntegrator(MatrixCoefficient &mq)
|
|
: MixedVectorIntegrator(mq) {}
|
|
|
|
protected:
|
|
inline virtual bool VerifyFiniteElementTypes(
|
|
const FiniteElement & trial_fe,
|
|
const FiniteElement & test_fe) const
|
|
{
|
|
return (trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
|
|
test_fe.GetDerivType() == mfem::FiniteElement::GRAD );
|
|
}
|
|
|
|
inline virtual const char * FiniteElementTypeFailureMessage() const
|
|
{
|
|
return "MixedVectorWeakDivergenceIntegrator: "
|
|
"Trial space must be vector field and the "
|
|
"test space must be H1";
|
|
}
|
|
|
|
inline virtual void CalcTestShape(const FiniteElement & test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix & shape)
|
|
{
|
|
test_fe.CalcPhysDShape(Trans, shape);
|
|
shape *= -1.0;
|
|
}
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (Q grad u, v) where Q is a
|
|
scalar coefficient, and v is a vector with components v_i in the same space
|
|
as u. */
|
|
class GradientIntegrator : public BilinearFormIntegrator
|
|
{
|
|
protected:
|
|
Coefficient *Q;
|
|
|
|
private:
|
|
Vector shape;
|
|
DenseMatrix dshape;
|
|
DenseMatrix gshape;
|
|
DenseMatrix Jadj;
|
|
DenseMatrix elmat_comp;
|
|
// PA extension
|
|
Vector pa_data;
|
|
const DofToQuad *trial_maps, *test_maps; ///< Not owned
|
|
const GeometricFactors *geom; ///< Not owned
|
|
int dim, ne, nq;
|
|
int trial_dofs1D, test_dofs1D, quad1D;
|
|
|
|
public:
|
|
GradientIntegrator() :
|
|
Q{NULL}, trial_maps{NULL}, test_maps{NULL}, geom{NULL}
|
|
{ }
|
|
GradientIntegrator(Coefficient *_q) :
|
|
Q{_q}, trial_maps{NULL}, test_maps{NULL}, geom{NULL}
|
|
{ }
|
|
GradientIntegrator(Coefficient &q) :
|
|
Q{&q}, trial_maps{NULL}, test_maps{NULL}, geom{NULL}
|
|
{ }
|
|
|
|
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
|
|
const FiniteElement &test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
|
|
using BilinearFormIntegrator::AssemblePA;
|
|
virtual void AssemblePA(const FiniteElementSpace &trial_fes,
|
|
const FiniteElementSpace &test_fes);
|
|
|
|
virtual void AddMultPA(const Vector &x, Vector &y) const;
|
|
virtual void AddMultTransposePA(const Vector &x, Vector &y) const;
|
|
|
|
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
|
|
const FiniteElement &test_fe,
|
|
ElementTransformation &Trans);
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (Q grad u, grad v) where Q
|
|
can be a scalar or a matrix coefficient. */
|
|
class DiffusionIntegrator: public BilinearFormIntegrator
|
|
{
|
|
protected:
|
|
Coefficient *Q;
|
|
MatrixCoefficient *MQ;
|
|
|
|
private:
|
|
Vector vec, pointflux, shape;
|
|
#ifndef MFEM_THREAD_SAFE
|
|
DenseMatrix dshape, dshapedxt, invdfdx, mq;
|
|
DenseMatrix te_dshape, te_dshapedxt;
|
|
#endif
|
|
|
|
// PA extension
|
|
const FiniteElementSpace *fespace;
|
|
const DofToQuad *maps; ///< Not owned
|
|
const GeometricFactors *geom; ///< Not owned
|
|
int dim, ne, dofs1D, quad1D;
|
|
Vector pa_data;
|
|
|
|
#ifdef MFEM_USE_CEED
|
|
// CEED extension
|
|
CeedData* ceedDataPtr;
|
|
#endif
|
|
|
|
public:
|
|
/// Construct a diffusion integrator with coefficient Q = 1
|
|
DiffusionIntegrator()
|
|
{
|
|
Q = NULL;
|
|
MQ = NULL;
|
|
maps = NULL;
|
|
geom = NULL;
|
|
#ifdef MFEM_USE_CEED
|
|
ceedDataPtr = NULL;
|
|
#endif
|
|
}
|
|
|
|
/// Construct a diffusion integrator with a scalar coefficient q
|
|
DiffusionIntegrator(Coefficient &q)
|
|
: Q(&q)
|
|
{
|
|
MQ = NULL;
|
|
maps = NULL;
|
|
geom = NULL;
|
|
#ifdef MFEM_USE_CEED
|
|
ceedDataPtr = NULL;
|
|
#endif
|
|
}
|
|
|
|
/// Construct a diffusion integrator with a matrix coefficient q
|
|
DiffusionIntegrator(MatrixCoefficient &q)
|
|
: MQ(&q)
|
|
{
|
|
Q = NULL;
|
|
maps = NULL;
|
|
geom = NULL;
|
|
#ifdef MFEM_USE_CEED
|
|
ceedDataPtr = NULL;
|
|
#endif
|
|
}
|
|
|
|
virtual ~DiffusionIntegrator()
|
|
{
|
|
#ifdef MFEM_USE_CEED
|
|
delete ceedDataPtr;
|
|
#endif
|
|
}
|
|
|
|
/** Given a particular Finite Element computes the element stiffness matrix
|
|
elmat. */
|
|
virtual void AssembleElementMatrix(const FiniteElement &el,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
/** Given a trial and test Finite Element computes the element stiffness
|
|
matrix elmat. */
|
|
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
|
|
const FiniteElement &test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
|
|
/// Perform the local action of the BilinearFormIntegrator
|
|
virtual void AssembleElementVector(const FiniteElement &el,
|
|
ElementTransformation &Tr,
|
|
const Vector &elfun, Vector &elvect);
|
|
|
|
virtual void ComputeElementFlux(const FiniteElement &el,
|
|
ElementTransformation &Trans,
|
|
Vector &u, const FiniteElement &fluxelem,
|
|
Vector &flux, bool with_coef = true);
|
|
|
|
virtual double ComputeFluxEnergy(const FiniteElement &fluxelem,
|
|
ElementTransformation &Trans,
|
|
Vector &flux, Vector *d_energy = NULL);
|
|
|
|
using BilinearFormIntegrator::AssemblePA;
|
|
|
|
virtual void AssemblePA(const FiniteElementSpace &fes);
|
|
|
|
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
|
|
|
|
virtual void AssembleDiagonalPA(Vector &diag);
|
|
|
|
virtual void AddMultPA(const Vector&, Vector&) const;
|
|
|
|
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
|
|
const FiniteElement &test_fe);
|
|
|
|
void SetupPA(const FiniteElementSpace &fes, const bool force = false);
|
|
};
|
|
|
|
/** Class for local mass matrix assembling a(u,v) := (Q u, v) */
|
|
class MassIntegrator: public BilinearFormIntegrator
|
|
{
|
|
protected:
|
|
#ifndef MFEM_THREAD_SAFE
|
|
Vector shape, te_shape;
|
|
#endif
|
|
Coefficient *Q;
|
|
// PA extension
|
|
const FiniteElementSpace *fespace;
|
|
Vector pa_data;
|
|
const DofToQuad *maps; ///< Not owned
|
|
const GeometricFactors *geom; ///< Not owned
|
|
int dim, ne, nq, dofs1D, quad1D;
|
|
|
|
#ifdef MFEM_USE_CEED
|
|
// CEED extension
|
|
CeedData* ceedDataPtr;
|
|
#endif
|
|
|
|
public:
|
|
MassIntegrator(const IntegrationRule *ir = NULL)
|
|
: BilinearFormIntegrator(ir)
|
|
{
|
|
Q = NULL;
|
|
maps = NULL;
|
|
geom = NULL;
|
|
#ifdef MFEM_USE_CEED
|
|
ceedDataPtr = NULL;
|
|
#endif
|
|
}
|
|
|
|
/// Construct a mass integrator with coefficient q
|
|
MassIntegrator(Coefficient &q, const IntegrationRule *ir = NULL)
|
|
: BilinearFormIntegrator(ir), Q(&q)
|
|
{
|
|
maps = NULL;
|
|
geom = NULL;
|
|
#ifdef MFEM_USE_CEED
|
|
ceedDataPtr = NULL;
|
|
#endif
|
|
}
|
|
|
|
virtual ~MassIntegrator()
|
|
{
|
|
#ifdef MFEM_USE_CEED
|
|
delete ceedDataPtr;
|
|
#endif
|
|
}
|
|
/** Given a particular Finite Element computes the element mass matrix
|
|
elmat. */
|
|
virtual void AssembleElementMatrix(const FiniteElement &el,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
|
|
const FiniteElement &test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
|
|
using BilinearFormIntegrator::AssemblePA;
|
|
|
|
virtual void AssemblePA(const FiniteElementSpace &fes);
|
|
|
|
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
|
|
|
|
virtual void AssembleDiagonalPA(Vector &diag);
|
|
|
|
virtual void AddMultPA(const Vector&, Vector&) const;
|
|
|
|
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
|
|
const FiniteElement &test_fe,
|
|
ElementTransformation &Trans);
|
|
|
|
void SetupPA(const FiniteElementSpace &fes, const bool force = false);
|
|
};
|
|
|
|
/** Mass integrator (u, v) restricted to the boundary of a domain */
|
|
class BoundaryMassIntegrator : public MassIntegrator
|
|
{
|
|
public:
|
|
BoundaryMassIntegrator(Coefficient &q) : MassIntegrator(q) { }
|
|
|
|
using BilinearFormIntegrator::AssembleFaceMatrix;
|
|
|
|
virtual void AssembleFaceMatrix(const FiniteElement &el1,
|
|
const FiniteElement &el2,
|
|
FaceElementTransformations &Trans,
|
|
DenseMatrix &elmat);
|
|
};
|
|
|
|
/// alpha (q . grad u, v)
|
|
class ConvectionIntegrator : public BilinearFormIntegrator
|
|
{
|
|
protected:
|
|
VectorCoefficient *Q;
|
|
double alpha;
|
|
// PA extension
|
|
Vector pa_data;
|
|
const DofToQuad *maps; ///< Not owned
|
|
const GeometricFactors *geom; ///< Not owned
|
|
int dim, ne, nq, dofs1D, quad1D;
|
|
|
|
private:
|
|
#ifndef MFEM_THREAD_SAFE
|
|
DenseMatrix dshape, adjJ, Q_ir;
|
|
Vector shape, vec2, BdFidxT;
|
|
#endif
|
|
|
|
public:
|
|
ConvectionIntegrator(VectorCoefficient &q, double a = 1.0)
|
|
: Q(&q) { alpha = a; }
|
|
virtual void AssembleElementMatrix(const FiniteElement &,
|
|
ElementTransformation &,
|
|
DenseMatrix &);
|
|
|
|
using BilinearFormIntegrator::AssemblePA;
|
|
|
|
virtual void AssemblePA(const FiniteElementSpace&);
|
|
|
|
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
|
|
|
|
virtual void AddMultPA(const Vector&, Vector&) const;
|
|
|
|
static const IntegrationRule &GetRule(const FiniteElement &el,
|
|
ElementTransformation &Trans);
|
|
|
|
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
|
|
const FiniteElement &test_fe,
|
|
ElementTransformation &Trans);
|
|
};
|
|
|
|
/// alpha (q . grad u, v) using the "group" FE discretization
|
|
class GroupConvectionIntegrator : public BilinearFormIntegrator
|
|
{
|
|
protected:
|
|
VectorCoefficient *Q;
|
|
double alpha;
|
|
|
|
private:
|
|
DenseMatrix dshape, adjJ, Q_nodal, grad;
|
|
Vector shape;
|
|
|
|
public:
|
|
GroupConvectionIntegrator(VectorCoefficient &q, double a = 1.0)
|
|
: Q(&q) { alpha = a; }
|
|
virtual void AssembleElementMatrix(const FiniteElement &,
|
|
ElementTransformation &,
|
|
DenseMatrix &);
|
|
};
|
|
|
|
/** Class for integrating the bilinear form a(u,v) := (Q u, v),
|
|
where u=(u1,...,un) and v=(v1,...,vn); ui and vi are defined
|
|
by scalar FE through standard transformation. */
|
|
class VectorMassIntegrator: public BilinearFormIntegrator
|
|
{
|
|
private:
|
|
int vdim;
|
|
Vector shape, te_shape, vec;
|
|
DenseMatrix partelmat;
|
|
DenseMatrix mcoeff;
|
|
int Q_order;
|
|
|
|
protected:
|
|
Coefficient *Q;
|
|
VectorCoefficient *VQ;
|
|
MatrixCoefficient *MQ;
|
|
// PA extension
|
|
Vector pa_data;
|
|
const DofToQuad *maps; ///< Not owned
|
|
const GeometricFactors *geom; ///< Not owned
|
|
int dim, ne, nq, dofs1D, quad1D;
|
|
|
|
public:
|
|
/// Construct an integrator with coefficient 1.0
|
|
VectorMassIntegrator()
|
|
: vdim(-1), Q_order(0), Q(NULL), VQ(NULL), MQ(NULL) { }
|
|
/** Construct an integrator with scalar coefficient q. If possible, save
|
|
memory by using a scalar integrator since the resulting matrix is block
|
|
diagonal with the same diagonal block repeated. */
|
|
VectorMassIntegrator(Coefficient &q, int qo = 0)
|
|
: vdim(-1), Q(&q) { VQ = NULL; MQ = NULL; Q_order = qo; }
|
|
VectorMassIntegrator(Coefficient &q, const IntegrationRule *ir)
|
|
: BilinearFormIntegrator(ir), vdim(-1), Q(&q)
|
|
{ VQ = NULL; MQ = NULL; Q_order = 0; }
|
|
/// Construct an integrator with diagonal coefficient q
|
|
VectorMassIntegrator(VectorCoefficient &q, int qo = 0)
|
|
: vdim(q.GetVDim()), VQ(&q) { Q = NULL; MQ = NULL; Q_order = qo; }
|
|
/// Construct an integrator with matrix coefficient q
|
|
VectorMassIntegrator(MatrixCoefficient &q, int qo = 0)
|
|
: vdim(q.GetVDim()), MQ(&q) { Q = NULL; VQ = NULL; Q_order = qo; }
|
|
|
|
int GetVDim() const { return vdim; }
|
|
void SetVDim(int vdim) { this->vdim = vdim; }
|
|
|
|
virtual void AssembleElementMatrix(const FiniteElement &el,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
|
|
const FiniteElement &test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
using BilinearFormIntegrator::AssemblePA;
|
|
virtual void AssemblePA(const FiniteElementSpace &fes);
|
|
virtual void AssembleDiagonalPA(Vector &diag);
|
|
virtual void AddMultPA(const Vector &x, Vector &y) const;
|
|
};
|
|
|
|
|
|
/** Class for integrating (div u, p) where u is a vector field given by
|
|
VectorFiniteElement through Piola transformation (for RT elements); p is
|
|
scalar function given by FiniteElement through standard transformation.
|
|
Here, u is the trial function and p is the test function.
|
|
|
|
Note: the element matrix returned by AssembleElementMatrix2 does NOT depend
|
|
on the ElementTransformation Trans. */
|
|
class VectorFEDivergenceIntegrator : public BilinearFormIntegrator
|
|
{
|
|
protected:
|
|
Coefficient *Q;
|
|
|
|
using BilinearFormIntegrator::AssemblePA;
|
|
virtual void AssemblePA(const FiniteElementSpace &trial_fes,
|
|
const FiniteElementSpace &test_fes);
|
|
|
|
virtual void AddMultPA(const Vector&, Vector&) const;
|
|
virtual void AddMultTransposePA(const Vector&, Vector&) const;
|
|
|
|
private:
|
|
#ifndef MFEM_THREAD_SAFE
|
|
Vector divshape, shape;
|
|
#endif
|
|
|
|
// PA extension
|
|
Vector pa_data;
|
|
const DofToQuad *mapsO; ///< Not owned. DOF-to-quad map, open.
|
|
const DofToQuad *L2mapsO; ///< Not owned. DOF-to-quad map, open.
|
|
const DofToQuad *mapsC; ///< Not owned. DOF-to-quad map, closed.
|
|
int dim, ne, dofs1D, L2dofs1D, quad1D;
|
|
|
|
public:
|
|
VectorFEDivergenceIntegrator() { Q = NULL; }
|
|
VectorFEDivergenceIntegrator(Coefficient &q) { Q = &q; }
|
|
virtual void AssembleElementMatrix(const FiniteElement &el,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat) { }
|
|
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
|
|
const FiniteElement &test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
|
|
virtual void AssembleDiagonalPA_ADAt(const Vector &D, Vector &diag);
|
|
};
|
|
|
|
|
|
/** Integrator for `(-Q u, grad v)` for Nedelec (`u`) and H1 (`v`) elements.
|
|
This is equivalent to a weak divergence of the Nedelec basis functions. */
|
|
class VectorFEWeakDivergenceIntegrator: public BilinearFormIntegrator
|
|
{
|
|
protected:
|
|
Coefficient *Q;
|
|
|
|
private:
|
|
#ifndef MFEM_THREAD_SAFE
|
|
DenseMatrix dshape;
|
|
DenseMatrix dshapedxt;
|
|
DenseMatrix vshape;
|
|
DenseMatrix invdfdx;
|
|
#endif
|
|
|
|
public:
|
|
VectorFEWeakDivergenceIntegrator() { Q = NULL; }
|
|
VectorFEWeakDivergenceIntegrator(Coefficient &q) { Q = &q; }
|
|
virtual void AssembleElementMatrix(const FiniteElement &el,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat) { }
|
|
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
|
|
const FiniteElement &test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
};
|
|
|
|
/** Integrator for (curl u, v) for Nedelec and RT elements. If the trial and
|
|
test spaces are switched, assembles the form (u, curl v). */
|
|
class VectorFECurlIntegrator: public BilinearFormIntegrator
|
|
{
|
|
protected:
|
|
Coefficient *Q;
|
|
|
|
private:
|
|
#ifndef MFEM_THREAD_SAFE
|
|
DenseMatrix curlshapeTrial;
|
|
DenseMatrix vshapeTest;
|
|
DenseMatrix curlshapeTrial_dFT;
|
|
#endif
|
|
|
|
public:
|
|
VectorFECurlIntegrator() { Q = NULL; }
|
|
VectorFECurlIntegrator(Coefficient &q) { Q = &q; }
|
|
virtual void AssembleElementMatrix(const FiniteElement &el,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat) { }
|
|
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
|
|
const FiniteElement &test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
};
|
|
|
|
/// Class for integrating (Q D_i(u), v); u and v are scalars
|
|
class DerivativeIntegrator : public BilinearFormIntegrator
|
|
{
|
|
protected:
|
|
Coefficient* Q;
|
|
|
|
private:
|
|
int xi;
|
|
DenseMatrix dshape, dshapedxt, invdfdx;
|
|
Vector shape, dshapedxi;
|
|
|
|
public:
|
|
DerivativeIntegrator(Coefficient &q, int i) : Q(&q), xi(i) { }
|
|
virtual void AssembleElementMatrix(const FiniteElement &el,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat)
|
|
{ AssembleElementMatrix2(el,el,Trans,elmat); }
|
|
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
|
|
const FiniteElement &test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
};
|
|
|
|
/// Integrator for (curl u, curl v) for Nedelec elements
|
|
class CurlCurlIntegrator: public BilinearFormIntegrator
|
|
{
|
|
private:
|
|
Vector vec, pointflux;
|
|
#ifndef MFEM_THREAD_SAFE
|
|
DenseMatrix curlshape, curlshape_dFt, M;
|
|
DenseMatrix vshape, projcurl;
|
|
#endif
|
|
|
|
protected:
|
|
Coefficient *Q;
|
|
MatrixCoefficient *MQ;
|
|
|
|
// PA extension
|
|
Vector pa_data;
|
|
const DofToQuad *mapsO; ///< Not owned. DOF-to-quad map, open.
|
|
const DofToQuad *mapsC; ///< Not owned. DOF-to-quad map, closed.
|
|
const GeometricFactors *geom; ///< Not owned
|
|
int dim, ne, nq, dofs1D, quad1D;
|
|
|
|
public:
|
|
CurlCurlIntegrator() { Q = NULL; MQ = NULL; }
|
|
/// Construct a bilinear form integrator for Nedelec elements
|
|
CurlCurlIntegrator(Coefficient &q) : Q(&q) { MQ = NULL; }
|
|
CurlCurlIntegrator(MatrixCoefficient &m) : MQ(&m) { Q = NULL; }
|
|
|
|
/* Given a particular Finite Element, compute the
|
|
element curl-curl matrix elmat */
|
|
virtual void AssembleElementMatrix(const FiniteElement &el,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
|
|
virtual void ComputeElementFlux(const FiniteElement &el,
|
|
ElementTransformation &Trans,
|
|
Vector &u, const FiniteElement &fluxelem,
|
|
Vector &flux, bool with_coef);
|
|
|
|
virtual double ComputeFluxEnergy(const FiniteElement &fluxelem,
|
|
ElementTransformation &Trans,
|
|
Vector &flux, Vector *d_energy = NULL);
|
|
|
|
using BilinearFormIntegrator::AssemblePA;
|
|
virtual void AssemblePA(const FiniteElementSpace &fes);
|
|
virtual void AddMultPA(const Vector &x, Vector &y) const;
|
|
virtual void AssembleDiagonalPA(Vector& diag);
|
|
};
|
|
|
|
/** Integrator for (curl u, curl v) for FE spaces defined by 'dim' copies of a
|
|
scalar FE space. */
|
|
class VectorCurlCurlIntegrator: public BilinearFormIntegrator
|
|
{
|
|
private:
|
|
#ifndef MFEM_THREAD_SAFE
|
|
DenseMatrix dshape_hat, dshape, curlshape, Jadj, grad_hat, grad;
|
|
#endif
|
|
|
|
protected:
|
|
Coefficient *Q;
|
|
|
|
public:
|
|
VectorCurlCurlIntegrator() { Q = NULL; }
|
|
|
|
VectorCurlCurlIntegrator(Coefficient &q) : Q(&q) { }
|
|
|
|
/// Assemble an element matrix
|
|
virtual void AssembleElementMatrix(const FiniteElement &el,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
/// Compute element energy: (1/2) (curl u, curl u)_E
|
|
virtual double GetElementEnergy(const FiniteElement &el,
|
|
ElementTransformation &Tr,
|
|
const Vector &elfun);
|
|
};
|
|
|
|
/** Integrator for (Q u, v), where Q is an optional coefficient (of type scalar,
|
|
vector (diagonal matrix), or matrix), trial function u is in H(Curl) or
|
|
H(Div), and test function v is in H(Curl), H(Div), or v=(v1,...,vn), where
|
|
vi are in H1. */
|
|
class VectorFEMassIntegrator: public BilinearFormIntegrator
|
|
{
|
|
private:
|
|
void Init(Coefficient *q, VectorCoefficient *vq, MatrixCoefficient *mq)
|
|
{ Q = q; VQ = vq; MQ = mq; }
|
|
|
|
#ifndef MFEM_THREAD_SAFE
|
|
Vector shape;
|
|
Vector D;
|
|
DenseMatrix K;
|
|
DenseMatrix partelmat;
|
|
DenseMatrix test_vshape;
|
|
DenseMatrix trial_vshape;
|
|
#endif
|
|
|
|
protected:
|
|
Coefficient *Q;
|
|
VectorCoefficient *VQ;
|
|
MatrixCoefficient *MQ;
|
|
|
|
// PA extension
|
|
Vector pa_data;
|
|
const DofToQuad *mapsO; ///< Not owned. DOF-to-quad map, open.
|
|
const DofToQuad *mapsC; ///< Not owned. DOF-to-quad map, closed.
|
|
const GeometricFactors *geom; ///< Not owned
|
|
int dim, ne, nq, dofs1D, quad1D, fetype;
|
|
|
|
public:
|
|
VectorFEMassIntegrator() { Init(NULL, NULL, NULL); }
|
|
VectorFEMassIntegrator(Coefficient *_q) { Init(_q, NULL, NULL); }
|
|
VectorFEMassIntegrator(Coefficient &q) { Init(&q, NULL, NULL); }
|
|
VectorFEMassIntegrator(VectorCoefficient *_vq) { Init(NULL, _vq, NULL); }
|
|
VectorFEMassIntegrator(VectorCoefficient &vq) { Init(NULL, &vq, NULL); }
|
|
VectorFEMassIntegrator(MatrixCoefficient *_mq) { Init(NULL, NULL, _mq); }
|
|
VectorFEMassIntegrator(MatrixCoefficient &mq) { Init(NULL, NULL, &mq); }
|
|
|
|
virtual void AssembleElementMatrix(const FiniteElement &el,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
|
|
const FiniteElement &test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
|
|
using BilinearFormIntegrator::AssemblePA;
|
|
virtual void AssemblePA(const FiniteElementSpace &fes);
|
|
virtual void AddMultPA(const Vector &x, Vector &y) const;
|
|
virtual void AssembleDiagonalPA(Vector& diag);
|
|
};
|
|
|
|
/** Integrator for (Q div u, p) where u=(v1,...,vn) and all vi are in the same
|
|
scalar FE space; p is also in a (different) scalar FE space. */
|
|
class VectorDivergenceIntegrator : public BilinearFormIntegrator
|
|
{
|
|
protected:
|
|
Coefficient *Q;
|
|
|
|
private:
|
|
Vector shape;
|
|
Vector divshape;
|
|
DenseMatrix dshape;
|
|
DenseMatrix gshape;
|
|
DenseMatrix Jadj;
|
|
// PA extension
|
|
Vector pa_data;
|
|
const DofToQuad *trial_maps, *test_maps; ///< Not owned
|
|
const GeometricFactors *geom; ///< Not owned
|
|
int dim, ne, nq;
|
|
int trial_dofs1D, test_dofs1D, quad1D;
|
|
|
|
public:
|
|
VectorDivergenceIntegrator() :
|
|
Q(NULL), trial_maps(NULL), test_maps(NULL), geom(NULL)
|
|
{ }
|
|
VectorDivergenceIntegrator(Coefficient *_q) :
|
|
Q(_q), trial_maps(NULL), test_maps(NULL), geom(NULL)
|
|
{ }
|
|
VectorDivergenceIntegrator(Coefficient &q) :
|
|
Q(&q), trial_maps(NULL), test_maps(NULL), geom(NULL)
|
|
{ }
|
|
|
|
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
|
|
const FiniteElement &test_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
|
|
using BilinearFormIntegrator::AssemblePA;
|
|
virtual void AssemblePA(const FiniteElementSpace &trial_fes,
|
|
const FiniteElementSpace &test_fes);
|
|
|
|
virtual void AddMultPA(const Vector &x, Vector &y) const;
|
|
virtual void AddMultTransposePA(const Vector &x, Vector &y) const;
|
|
|
|
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
|
|
const FiniteElement &test_fe,
|
|
ElementTransformation &Trans);
|
|
};
|
|
|
|
/// (Q div u, div v) for RT elements
|
|
class DivDivIntegrator: public BilinearFormIntegrator
|
|
{
|
|
protected:
|
|
Coefficient *Q;
|
|
|
|
using BilinearFormIntegrator::AssemblePA;
|
|
virtual void AssemblePA(const FiniteElementSpace &fes);
|
|
virtual void AddMultPA(const Vector &x, Vector &y) const;
|
|
virtual void AssembleDiagonalPA(Vector& diag);
|
|
|
|
private:
|
|
#ifndef MFEM_THREAD_SAFE
|
|
Vector divshape;
|
|
#endif
|
|
|
|
// PA extension
|
|
Vector pa_data;
|
|
const DofToQuad *mapsO; ///< Not owned. DOF-to-quad map, open.
|
|
const DofToQuad *mapsC; ///< Not owned. DOF-to-quad map, closed.
|
|
const GeometricFactors *geom; ///< Not owned
|
|
int dim, ne, dofs1D, quad1D;
|
|
|
|
public:
|
|
DivDivIntegrator() { Q = NULL; }
|
|
DivDivIntegrator(Coefficient &q) : Q(&q) { }
|
|
|
|
virtual void AssembleElementMatrix(const FiniteElement &el,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
};
|
|
|
|
/** Integrator for
|
|
(Q grad u, grad v) = sum_i (Q grad u_i, grad v_i) e_i e_i^T
|
|
for FE spaces defined by 'dim' copies of a scalar FE space. Where e_i
|
|
is the unit vector in the i-th direction. The resulting local element
|
|
matrix is a block-diagonal matrix consisting of 'dim' copies of a scalar
|
|
diffusion matrix in each diagonal block. */
|
|
class VectorDiffusionIntegrator : public BilinearFormIntegrator
|
|
{
|
|
protected:
|
|
Coefficient *Q;
|
|
|
|
// PA extension
|
|
const DofToQuad *maps; ///< Not owned
|
|
const GeometricFactors *geom; ///< Not owned
|
|
int dim, sdim, ne, dofs1D, quad1D;
|
|
Vector pa_data;
|
|
|
|
private:
|
|
DenseMatrix dshape, dshapedxt, pelmat;
|
|
DenseMatrix Jinv, gshape;
|
|
|
|
public:
|
|
VectorDiffusionIntegrator() { Q = NULL; }
|
|
VectorDiffusionIntegrator(Coefficient &q) { Q = &q; }
|
|
|
|
virtual void AssembleElementMatrix(const FiniteElement &el,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
virtual void AssembleElementVector(const FiniteElement &el,
|
|
ElementTransformation &Tr,
|
|
const Vector &elfun, Vector &elvect);
|
|
using BilinearFormIntegrator::AssemblePA;
|
|
virtual void AssemblePA(const FiniteElementSpace &fes);
|
|
virtual void AssembleDiagonalPA(Vector &diag);
|
|
virtual void AddMultPA(const Vector &x, Vector &y) const;
|
|
};
|
|
|
|
/** Integrator for the linear elasticity form:
|
|
a(u,v) = (lambda div(u), div(v)) + (2 mu e(u), e(v)),
|
|
where e(v) = (1/2) (grad(v) + grad(v)^T).
|
|
This is a 'Vector' integrator, i.e. defined for FE spaces
|
|
using multiple copies of a scalar FE space. */
|
|
class ElasticityIntegrator : public BilinearFormIntegrator
|
|
{
|
|
protected:
|
|
double q_lambda, q_mu;
|
|
Coefficient *lambda, *mu;
|
|
|
|
private:
|
|
#ifndef MFEM_THREAD_SAFE
|
|
Vector shape;
|
|
DenseMatrix dshape, gshape, pelmat;
|
|
Vector divshape;
|
|
#endif
|
|
|
|
public:
|
|
ElasticityIntegrator(Coefficient &l, Coefficient &m)
|
|
{ lambda = &l; mu = &m; }
|
|
/** With this constructor lambda = q_l * m and mu = q_m * m;
|
|
if dim * q_l + 2 * q_m = 0 then trace(sigma) = 0. */
|
|
ElasticityIntegrator(Coefficient &m, double q_l, double q_m)
|
|
{ lambda = NULL; mu = &m; q_lambda = q_l; q_mu = q_m; }
|
|
|
|
virtual void AssembleElementMatrix(const FiniteElement &,
|
|
ElementTransformation &,
|
|
DenseMatrix &);
|
|
|
|
/** Compute the stress corresponding to the local displacement @a u and
|
|
interpolate it at the nodes of the given @a fluxelem. Only the symmetric
|
|
part of the stress is stored, so that the size of @a flux is equal to
|
|
the number of DOFs in @a fluxelem times dim*(dim+1)/2. In 2D, the order
|
|
of the stress components is: s_xx, s_yy, s_xy. In 3D, it is: s_xx, s_yy,
|
|
s_zz, s_xy, s_xz, s_yz. In other words, @a flux is the local vector for
|
|
a FE space with dim*(dim+1)/2 vector components, based on the finite
|
|
element @a fluxelem. */
|
|
virtual void ComputeElementFlux(const FiniteElement &el,
|
|
ElementTransformation &Trans,
|
|
Vector &u,
|
|
const FiniteElement &fluxelem,
|
|
Vector &flux, bool with_coef = true);
|
|
|
|
/** Compute the element energy (integral of the strain energy density)
|
|
corresponding to the stress represented by @a flux which is a vector of
|
|
coefficients multiplying the basis functions defined by @a fluxelem. In
|
|
other words, @a flux is the local vector for a FE space with
|
|
dim*(dim+1)/2 vector components, based on the finite element @a fluxelem.
|
|
The number of components, dim*(dim+1)/2 is such that it represents the
|
|
symmetric part of the (symmetric) stress tensor. The order of the
|
|
components is: s_xx, s_yy, s_xy in 2D, and s_xx, s_yy, s_zz, s_xy, s_xz,
|
|
s_yz in 3D. */
|
|
virtual double ComputeFluxEnergy(const FiniteElement &fluxelem,
|
|
ElementTransformation &Trans,
|
|
Vector &flux, Vector *d_energy = NULL);
|
|
};
|
|
|
|
/** Integrator for the DG form:
|
|
alpha < rho_u (u.n) {v},[w] > + beta < rho_u |u.n| [v],[w] >,
|
|
where v and w are the trial and test variables, respectively, and rho/u are
|
|
given scalar/vector coefficients. The vector coefficient, u, is assumed to
|
|
be continuous across the faces and when given the scalar coefficient, rho,
|
|
is assumed to be discontinuous. The integrator uses the upwind value of rho,
|
|
rho_u, which is value from the side into which the vector coefficient, u,
|
|
points. */
|
|
class DGTraceIntegrator : public BilinearFormIntegrator
|
|
{
|
|
protected:
|
|
Coefficient *rho;
|
|
VectorCoefficient *u;
|
|
double alpha, beta;
|
|
// PA extension
|
|
Vector pa_data;
|
|
const DofToQuad *maps; ///< Not owned
|
|
const FaceGeometricFactors *geom; ///< Not owned
|
|
int dim, nf, nq, dofs1D, quad1D;
|
|
|
|
private:
|
|
Vector shape1, shape2;
|
|
|
|
public:
|
|
/// Construct integrator with rho = 1.
|
|
DGTraceIntegrator(VectorCoefficient &_u, double a, double b)
|
|
{ rho = NULL; u = &_u; alpha = a; beta = b; }
|
|
|
|
DGTraceIntegrator(Coefficient &_rho, VectorCoefficient &_u,
|
|
double a, double b)
|
|
{ rho = &_rho; u = &_u; alpha = a; beta = b; }
|
|
|
|
using BilinearFormIntegrator::AssembleFaceMatrix;
|
|
virtual void AssembleFaceMatrix(const FiniteElement &el1,
|
|
const FiniteElement &el2,
|
|
FaceElementTransformations &Trans,
|
|
DenseMatrix &elmat);
|
|
|
|
using BilinearFormIntegrator::AssemblePA;
|
|
|
|
virtual void AssemblePAInteriorFaces(const FiniteElementSpace &fes);
|
|
|
|
virtual void AssemblePABoundaryFaces(const FiniteElementSpace &fes);
|
|
|
|
virtual void AddMultTransposePA(const Vector &x, Vector &y) const;
|
|
|
|
virtual void AddMultPA(const Vector&, Vector&) const;
|
|
|
|
virtual void AssembleEAInteriorFaces(const FiniteElementSpace& fes,
|
|
Vector &ea_data_int,
|
|
Vector &ea_data_ext);
|
|
|
|
virtual void AssembleEABoundaryFaces(const FiniteElementSpace& fes,
|
|
Vector &ea_data_bdr);
|
|
|
|
static const IntegrationRule &GetRule(Geometry::Type geom, int order,
|
|
FaceElementTransformations &T);
|
|
|
|
private:
|
|
void SetupPA(const FiniteElementSpace &fes, FaceType type);
|
|
};
|
|
|
|
/** Integrator for the DG form:
|
|
|
|
- < {(Q grad(u)).n}, [v] > + sigma < [u], {(Q grad(v)).n} >
|
|
+ kappa < {h^{-1} Q} [u], [v] >,
|
|
|
|
where Q is a scalar or matrix diffusion coefficient and u, v are the trial
|
|
and test spaces, respectively. The parameters sigma and kappa determine the
|
|
DG method to be used (when this integrator is added to the "broken"
|
|
DiffusionIntegrator):
|
|
* sigma = -1, kappa >= kappa0: symm. interior penalty (IP or SIPG) method,
|
|
* sigma = +1, kappa > 0: non-symmetric interior penalty (NIPG) method,
|
|
* sigma = +1, kappa = 0: the method of Baumann and Oden. */
|
|
class DGDiffusionIntegrator : public BilinearFormIntegrator
|
|
{
|
|
protected:
|
|
Coefficient *Q;
|
|
MatrixCoefficient *MQ;
|
|
double sigma, kappa;
|
|
|
|
// these are not thread-safe!
|
|
Vector shape1, shape2, dshape1dn, dshape2dn, nor, nh, ni;
|
|
DenseMatrix jmat, dshape1, dshape2, mq, adjJ;
|
|
|
|
public:
|
|
DGDiffusionIntegrator(const double s, const double k)
|
|
: Q(NULL), MQ(NULL), sigma(s), kappa(k) { }
|
|
DGDiffusionIntegrator(Coefficient &q, const double s, const double k)
|
|
: Q(&q), MQ(NULL), sigma(s), kappa(k) { }
|
|
DGDiffusionIntegrator(MatrixCoefficient &q, const double s, const double k)
|
|
: Q(NULL), MQ(&q), sigma(s), kappa(k) { }
|
|
using BilinearFormIntegrator::AssembleFaceMatrix;
|
|
virtual void AssembleFaceMatrix(const FiniteElement &el1,
|
|
const FiniteElement &el2,
|
|
FaceElementTransformations &Trans,
|
|
DenseMatrix &elmat);
|
|
};
|
|
|
|
/** Integrator for the DG elasticity form, for the formulations see:
|
|
- PhD Thesis of Jonas De Basabe, High-Order Finite %Element Methods for
|
|
Seismic Wave Propagation, UT Austin, 2009, p. 23, and references therein
|
|
- Peter Hansbo and Mats G. Larson, Discontinuous Galerkin and the
|
|
Crouzeix-Raviart %Element: Application to Elasticity, PREPRINT 2000-09,
|
|
p.3
|
|
|
|
\f[
|
|
- \left< \{ \tau(u) \}, [v] \right> + \alpha \left< \{ \tau(v) \}, [u]
|
|
\right> + \kappa \left< h^{-1} \{ \lambda + 2 \mu \} [u], [v] \right>
|
|
\f]
|
|
|
|
where \f$ \left<u, v\right> = \int_{F} u \cdot v \f$, and \f$ F \f$ is a
|
|
face which is either a boundary face \f$ F_b \f$ of an element \f$ K \f$ or
|
|
an interior face \f$ F_i \f$ separating elements \f$ K_1 \f$ and \f$ K_2 \f$.
|
|
|
|
In the bilinear form above \f$ \tau(u) \f$ is traction, and it's also
|
|
\f$ \tau(u) = \sigma(u) \cdot \vec{n} \f$, where \f$ \sigma(u) \f$ is
|
|
stress, and \f$ \vec{n} \f$ is the unit normal vector w.r.t. to \f$ F \f$.
|
|
|
|
In other words, we have
|
|
\f[
|
|
- \left< \{ \sigma(u) \cdot \vec{n} \}, [v] \right> + \alpha \left< \{
|
|
\sigma(v) \cdot \vec{n} \}, [u] \right> + \kappa \left< h^{-1} \{
|
|
\lambda + 2 \mu \} [u], [v] \right>
|
|
\f]
|
|
|
|
For isotropic media
|
|
\f[
|
|
\begin{split}
|
|
\sigma(u) &= \lambda \nabla \cdot u I + 2 \mu \varepsilon(u) \\
|
|
&= \lambda \nabla \cdot u I + 2 \mu \frac{1}{2} (\nabla u + \nabla
|
|
u^T) \\
|
|
&= \lambda \nabla \cdot u I + \mu (\nabla u + \nabla u^T)
|
|
\end{split}
|
|
\f]
|
|
|
|
where \f$ I \f$ is identity matrix, \f$ \lambda \f$ and \f$ \mu \f$ are Lame
|
|
coefficients (see ElasticityIntegrator), \f$ u, v \f$ are the trial and test
|
|
functions, respectively.
|
|
|
|
The parameters \f$ \alpha \f$ and \f$ \kappa \f$ determine the DG method to
|
|
use (when this integrator is added to the "broken" ElasticityIntegrator):
|
|
|
|
- IIPG, \f$\alpha = 0\f$,
|
|
C. Dawson, S. Sun, M. Wheeler, Compatible algorithms for coupled flow and
|
|
transport, Comp. Meth. Appl. Mech. Eng., 193(23-26), 2565-2580, 2004.
|
|
|
|
- SIPG, \f$\alpha = -1\f$,
|
|
M. Grote, A. Schneebeli, D. Schotzau, Discontinuous Galerkin Finite
|
|
%Element Method for the Wave Equation, SINUM, 44(6), 2408-2431, 2006.
|
|
|
|
- NIPG, \f$\alpha = 1\f$,
|
|
B. Riviere, M. Wheeler, V. Girault, A Priori Error Estimates for Finite
|
|
%Element Methods Based on Discontinuous Approximation Spaces for Elliptic
|
|
Problems, SINUM, 39(3), 902-931, 2001.
|
|
|
|
This is a '%Vector' integrator, i.e. defined for FE spaces using multiple
|
|
copies of a scalar FE space.
|
|
*/
|
|
class DGElasticityIntegrator : public BilinearFormIntegrator
|
|
{
|
|
public:
|
|
DGElasticityIntegrator(double alpha_, double kappa_)
|
|
: lambda(NULL), mu(NULL), alpha(alpha_), kappa(kappa_) { }
|
|
|
|
DGElasticityIntegrator(Coefficient &lambda_, Coefficient &mu_,
|
|
double alpha_, double kappa_)
|
|
: lambda(&lambda_), mu(&mu_), alpha(alpha_), kappa(kappa_) { }
|
|
|
|
using BilinearFormIntegrator::AssembleFaceMatrix;
|
|
virtual void AssembleFaceMatrix(const FiniteElement &el1,
|
|
const FiniteElement &el2,
|
|
FaceElementTransformations &Trans,
|
|
DenseMatrix &elmat);
|
|
|
|
protected:
|
|
Coefficient *lambda, *mu;
|
|
double alpha, kappa;
|
|
|
|
#ifndef MFEM_THREAD_SAFE
|
|
// values of all scalar basis functions for one component of u (which is a
|
|
// vector) at the integration point in the reference space
|
|
Vector shape1, shape2;
|
|
// values of derivatives of all scalar basis functions for one component
|
|
// of u (which is a vector) at the integration point in the reference space
|
|
DenseMatrix dshape1, dshape2;
|
|
// Adjugate of the Jacobian of the transformation: adjJ = det(J) J^{-1}
|
|
DenseMatrix adjJ;
|
|
// gradient of shape functions in the real (physical, not reference)
|
|
// coordinates, scaled by det(J):
|
|
// dshape_ps(jdof,jm) = sum_{t} adjJ(t,jm)*dshape(jdof,t)
|
|
DenseMatrix dshape1_ps, dshape2_ps;
|
|
Vector nor; // nor = |weight(J_face)| n
|
|
Vector nL1, nL2; // nL1 = (lambda1 * ip.weight / detJ1) nor
|
|
Vector nM1, nM2; // nM1 = (mu1 * ip.weight / detJ1) nor
|
|
Vector dshape1_dnM, dshape2_dnM; // dshape1_dnM = dshape1_ps . nM1
|
|
// 'jmat' corresponds to the term: kappa <h^{-1} {lambda + 2 mu} [u], [v]>
|
|
DenseMatrix jmat;
|
|
#endif
|
|
|
|
static void AssembleBlock(
|
|
const int dim, const int row_ndofs, const int col_ndofs,
|
|
const int row_offset, const int col_offset,
|
|
const double jmatcoef, const Vector &col_nL, const Vector &col_nM,
|
|
const Vector &row_shape, const Vector &col_shape,
|
|
const Vector &col_dshape_dnM, const DenseMatrix &col_dshape,
|
|
DenseMatrix &elmat, DenseMatrix &jmat);
|
|
};
|
|
|
|
/** Integrator for the DPG form: < v, [w] > over all faces (the interface) where
|
|
the trial variable v is defined on the interface and the test variable w is
|
|
defined inside the elements, generally in a DG space. */
|
|
class TraceJumpIntegrator : public BilinearFormIntegrator
|
|
{
|
|
private:
|
|
Vector face_shape, shape1, shape2;
|
|
|
|
public:
|
|
TraceJumpIntegrator() { }
|
|
using BilinearFormIntegrator::AssembleFaceMatrix;
|
|
virtual void AssembleFaceMatrix(const FiniteElement &trial_face_fe,
|
|
const FiniteElement &test_fe1,
|
|
const FiniteElement &test_fe2,
|
|
FaceElementTransformations &Trans,
|
|
DenseMatrix &elmat);
|
|
};
|
|
|
|
/** Integrator for the form: < v, [w.n] > over all faces (the interface) where
|
|
the trial variable v is defined on the interface and the test variable w is
|
|
in an H(div)-conforming space. */
|
|
class NormalTraceJumpIntegrator : public BilinearFormIntegrator
|
|
{
|
|
private:
|
|
Vector face_shape, normal, shape1_n, shape2_n;
|
|
DenseMatrix shape1, shape2;
|
|
|
|
public:
|
|
NormalTraceJumpIntegrator() { }
|
|
using BilinearFormIntegrator::AssembleFaceMatrix;
|
|
virtual void AssembleFaceMatrix(const FiniteElement &trial_face_fe,
|
|
const FiniteElement &test_fe1,
|
|
const FiniteElement &test_fe2,
|
|
FaceElementTransformations &Trans,
|
|
DenseMatrix &elmat);
|
|
};
|
|
|
|
/** Abstract class to serve as a base for local interpolators to be used in the
|
|
DiscreteLinearOperator class. */
|
|
class DiscreteInterpolator : public BilinearFormIntegrator { };
|
|
|
|
|
|
/** Class for constructing the gradient as a DiscreteLinearOperator from an
|
|
H1-conforming space to an H(curl)-conforming space. The range space can be
|
|
vector L2 space as well. */
|
|
class GradientInterpolator : public DiscreteInterpolator
|
|
{
|
|
public:
|
|
virtual void AssembleElementMatrix2(const FiniteElement &h1_fe,
|
|
const FiniteElement &nd_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat)
|
|
{ nd_fe.ProjectGrad(h1_fe, Trans, elmat); }
|
|
};
|
|
|
|
|
|
/** Class for constructing the identity map as a DiscreteLinearOperator. This
|
|
is the discrete embedding matrix when the domain space is a subspace of
|
|
the range space. Otherwise, a dof projection matrix is constructed. */
|
|
class IdentityInterpolator : public DiscreteInterpolator
|
|
{
|
|
public:
|
|
virtual void AssembleElementMatrix2(const FiniteElement &dom_fe,
|
|
const FiniteElement &ran_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat)
|
|
{ ran_fe.Project(dom_fe, Trans, elmat); }
|
|
};
|
|
|
|
|
|
/** Class for constructing the (local) discrete curl matrix which can be used
|
|
as an integrator in a DiscreteLinearOperator object to assemble the global
|
|
discrete curl matrix. */
|
|
class CurlInterpolator : public DiscreteInterpolator
|
|
{
|
|
public:
|
|
virtual void AssembleElementMatrix2(const FiniteElement &dom_fe,
|
|
const FiniteElement &ran_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat)
|
|
{ ran_fe.ProjectCurl(dom_fe, Trans, elmat); }
|
|
};
|
|
|
|
|
|
/** Class for constructing the (local) discrete divergence matrix which can
|
|
be used as an integrator in a DiscreteLinearOperator object to assemble
|
|
the global discrete divergence matrix.
|
|
|
|
Note: Since the dofs in the L2_FECollection are nodal values, the local
|
|
discrete divergence matrix (with an RT-type domain space) will depend on
|
|
the transformation. On the other hand, the local matrix returned by
|
|
VectorFEDivergenceIntegrator is independent of the transformation. */
|
|
class DivergenceInterpolator : public DiscreteInterpolator
|
|
{
|
|
public:
|
|
virtual void AssembleElementMatrix2(const FiniteElement &dom_fe,
|
|
const FiniteElement &ran_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat)
|
|
{ ran_fe.ProjectDiv(dom_fe, Trans, elmat); }
|
|
};
|
|
|
|
|
|
/** A trace face interpolator class for interpolating the normal component of
|
|
the domain space, e.g. vector H1, into the range space, e.g. the trace of
|
|
RT which uses FiniteElement::INTEGRAL map type. */
|
|
class NormalInterpolator : public DiscreteInterpolator
|
|
{
|
|
public:
|
|
virtual void AssembleElementMatrix2(const FiniteElement &dom_fe,
|
|
const FiniteElement &ran_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
};
|
|
|
|
/** Interpolator of a scalar coefficient multiplied by a scalar field onto
|
|
another scalar field. Note that this can produce inaccurate fields unless
|
|
the target is sufficiently high order. */
|
|
class ScalarProductInterpolator : public DiscreteInterpolator
|
|
{
|
|
public:
|
|
ScalarProductInterpolator(Coefficient & sc) : Q(&sc) { }
|
|
|
|
virtual void AssembleElementMatrix2(const FiniteElement &dom_fe,
|
|
const FiniteElement &ran_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
|
|
protected:
|
|
Coefficient *Q;
|
|
};
|
|
|
|
/** Interpolator of a scalar coefficient multiplied by a vector field onto
|
|
another vector field. Note that this can produce inaccurate fields unless
|
|
the target is sufficiently high order. */
|
|
class ScalarVectorProductInterpolator : public DiscreteInterpolator
|
|
{
|
|
public:
|
|
ScalarVectorProductInterpolator(Coefficient & sc)
|
|
: Q(&sc) { }
|
|
|
|
virtual void AssembleElementMatrix2(const FiniteElement &dom_fe,
|
|
const FiniteElement &ran_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
protected:
|
|
Coefficient *Q;
|
|
};
|
|
|
|
/** Interpolator of a vector coefficient multiplied by a scalar field onto
|
|
another vector field. Note that this can produce inaccurate fields unless
|
|
the target is sufficiently high order. */
|
|
class VectorScalarProductInterpolator : public DiscreteInterpolator
|
|
{
|
|
public:
|
|
VectorScalarProductInterpolator(VectorCoefficient & vc)
|
|
: VQ(&vc) { }
|
|
|
|
virtual void AssembleElementMatrix2(const FiniteElement &dom_fe,
|
|
const FiniteElement &ran_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
protected:
|
|
VectorCoefficient *VQ;
|
|
};
|
|
|
|
/** Interpolator of the cross product between a vector coefficient and an
|
|
H(curl)-conforming field onto an H(div)-conforming field. The range space
|
|
can also be vector L2. */
|
|
class VectorCrossProductInterpolator : public DiscreteInterpolator
|
|
{
|
|
public:
|
|
VectorCrossProductInterpolator(VectorCoefficient & vc)
|
|
: VQ(&vc) { }
|
|
|
|
virtual void AssembleElementMatrix2(const FiniteElement &nd_fe,
|
|
const FiniteElement &rt_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
protected:
|
|
VectorCoefficient *VQ;
|
|
};
|
|
|
|
/** Interpolator of the inner product between a vector coefficient and an
|
|
H(div)-conforming field onto an L2-conforming field. The range space can
|
|
also be H1. */
|
|
class VectorInnerProductInterpolator : public DiscreteInterpolator
|
|
{
|
|
public:
|
|
VectorInnerProductInterpolator(VectorCoefficient & vc) : VQ(&vc) { }
|
|
|
|
virtual void AssembleElementMatrix2(const FiniteElement &rt_fe,
|
|
const FiniteElement &l2_fe,
|
|
ElementTransformation &Trans,
|
|
DenseMatrix &elmat);
|
|
protected:
|
|
VectorCoefficient *VQ;
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|