My ElementΒΆ
We want to start with a simple linear triangular finite element for the space \(H^1\).
Therefore we can use the ScalarFiniteElement
as a base class:
class MyLinearTrig : public ScalarFiniteElement<2>
{
public:
// constructor
MyLinearTrig ();
virtual ELEMENT_TYPE ElementType() const { return ET_TRIG; }
/*
Calculate the vector of shape functions in the point ip.
ip is given in the reference element.
*/
virtual void CalcShape (const IntegrationPoint & ip,
BareSliceVector<> shape) const;
/*
Calculate the matrix of derivatives of the shape functions in the point ip.
dshape is an 3 by 2 matrix in our case.
*/
virtual void CalcDShape (const IntegrationPoint & ip,
BareSliceMatrix<> dshape) const;
// there are some more functions to bring in ...
using ScalarFiniteElement<2>::CalcShape;
using ScalarFiniteElement<2>::CalcDShape;
};
So we need to define 3 functions: The constructor, CalcShape
and CalcDShape
to compute
the shape functions and their derivatives.
MyLinearTrig :: MyLinearTrig ()
/*
Call constructor for base class:
geometry is ET_TRIG, number of dofs is 3, maximal order is 1
*/
: ScalarFiniteElement<2> (3, 1)
{ ; }
void MyLinearTrig :: CalcShape (const IntegrationPoint & ip,
BareSliceVector<> shape) const
{
// coordinates in reference elements
double x = ip(0);
double y = ip(1);
/*
Vertex coordinates have been defined to be (1,0), (0,1), (0,0)
see ElementTopology::GetVertices(ET_TRIG)
*/
// define shape functions
shape(0) = x;
shape(1) = y;
shape(2) = 1-x-y;
}
void MyLinearTrig :: CalcDShape (const IntegrationPoint & ip,
BareSliceMatrix<> dshape) const
{
// matrix of derivatives:
dshape(0,0) = 1;
dshape(0,1) = 0;
dshape(1,0) = 0;
dshape(1,1) = 1;
dshape(2,0) = -1;
dshape(2,1) = -1;
}
Finally we can export it to Python, as we have done it with the CoefficientFunction. Note that this is not necessary if we just want to build a finite element space with it.
void ExportMyElement(py::module m)
{
using namespace ngfem;
/*
Our Trig is derived
from the classes ScalarFiniteElement<2> -> BaseScalarFiniteElement -> FiniteElement.
Only BaseScalarFiniteElement and FiniteElement are exported to python
(see ngsolve/fem/python_fem.cpp), so we derive from BaseScalarFiniteElement (which derives from
FiniteElement).
If we only want to use it in our FESpace we do not need the Python hierarchy, but it's nice for
debugging :)
*/
py::class_<MyLinearTrig, shared_ptr<MyLinearTrig>, BaseScalarFiniteElement>
(m, "MyLinearTrig", "My new linear Trig")
.def(py::init<>())
;
}
Todo
Explain AutoDiff with second order elements
Next we want to build this finite element into a space, so we can use it.