Approximation spaces#
The Space and SpaceInfo classes#
The Space class manages different kind of spaces using inherited classes: finite element space (FeSpace), spectral space (SpSpace), subspace (SubSpace) and product space (ProdSpace). To avoid the user to deal explicitly with this space hierarchy, we use the following design pattern: Space class has a pointer to a Space as attribute, which contains either its own address or the address of a child. In a sense, the Space class is not an abstract class but has the behavior of an abstract one. When an end user declares a Space object, he induces the construction of a child Space.
The dependency diagram looks like
With this pattern, an end user instantiates only Space object, never the child spaces.
As a consequence, it requires a little more memory because member attributes are duplicated. In order to limit this effect, the common characteristics of a space are collected in the SpaceInfo class:
class SpaceInfo
{
public :
String name_; // name of space
Domain * domain_p; // geometric domain supporting the space
SobolevType spaceConforming_; // conforming space (L2, H1, Hdiv, Hcurl, H2, Hinf)
dimen_t dimFun_; // number of components of the basis functions
Dimen dimCom; // number of components of the unknowns
SpaceType spaceType_; // space type (FESpace, SPSpace, SubSpace, ProductSpace)
SpaceInfo(){};
SpaceInfo(const String &,SobolevType,Domain *,dimen_t , SpaceType)
};
The general characteristics of a space are the geometric domain supporting the basis functions,
the space conformity which “tells” the regularity of the basis functions and the dimension
of the basis functions. The space conformity property is a way to distinguish discontinuous
finite element approximation from continuous one. The space conformity is given by the SobolevType enumeration declared in the textit{config.hpp} header file:
enum SobolevType
{
_L2=0, L2=_L2,
_H1, H1=_H1,
_Hdiv, Hdiv=_Hdiv,
_Hcurl, Hcurl=_Hcurl, _Hrot=_Hcurl, Hrot=_Hrot,
_H2, H2=_H2,
_Hinf, Hinf=_Hinf
};
To be user-friendly, several names are available for the same space.
The parent class Space has only two pointers and a static vector managing the list
of all defined spaces:
class Space
{
protected:
Space* space_p; //!< pointer to the "true" space
SpaceInfo* spaceInfo_p; //!< pointer to the space information structure
public:
mutable bool global; //!< declare space as global, if true forbid deletion of pointer space_p
static std::vector<Space*> theSpaces; //!< unique list of defined spaces
As far as the space type is concerned, the Space class provides several constructors for child spaces:
//! constructor of spectral space from explicit spectral basis
Space(const SpectralBasis& spb, const string_t& na);
//! constructor from domain and Interpolation (FeSpace)
Space(const GeomDomain& dom, const Interpolation& in, const string_t& na, bool opt = true);
//! constructor from GeomDomain and Space (SubSpace)
Space(const GeomDomain& dom, Space& sp, const string_t& na = "");
//! constructor from GeomDomain, dofIds list and Space (SubSpace)
Space(const GeomDomain& dom, const std::vector<number_t>& dofids, Space& sp, const string_t& na = "");
//! constructor from dofIds list and Space (SubSpace)
Space(const std::vector<number_t>& dofids, Space& sp, const string_t& na = "");
//! real constructor of analytic functions spectral space
void buildSpFun(const GeomDomain& dom, const Function& f, number_t nbFun, dimen_t dimFun, const string_t& na);
//! actual subspace constructor
SubSpace* createSubSpace(const GeomDomain& dom, Space&sp, const string_t& na);
//! create subspaces of current space from a list of subdomains
void createSubSpaces(const std::vector<const GeomDomain*>& doms, std::vector<Space*>& subspaces);
//! build subspaces from a list of subdomains and the largest subspace
Space* buildSubspaces(const std::vector<const GeomDomain*>& doms, std::vector<Space*>& subspaces);
These constructors work as follows (ChildSpace denotes any inherited space class):
ChildSpace* csp_p=new ChildSpace(...); // create the ChildSpace
space_p=static_cast<Space *>(csp_p); // cast ChildSpace* to Space*
spaceInfo_p=csp_p->spaceInfo_p; // copy the SpaceInfo pointer
theSpaces.push_back(this); // store space in list of spaces
Note that it is the child constructors that set all the attributes (general ones and specific ones).
The key-value system#
Most of the Space constructors use a key-value system, so there are Space constructors taking from 1 to 13 inputs of type Parameter. See
Keys for spaces for the full list of available keys and their description.
These constructors transfer the building work to the following routines:
void buildSpace(const std::vector<Parameter>& ps);
This routine works in the same way as the internal constructors described in the previous subsection.
Space member functions#
The Space class provides some accessors, some being virtual:
string_t name() const; //space name
SobolevType conformingSpace() const; //space conformity
const GeomDomain* domain(); //related domain
dimen_t dimDomain() const; //dimension of related domain
dimen_t dimPoint() const ; //dimension of points
dimen_t dimFun() const; //dimension of basis functions
SpaceType typeOfSpace() const; //type of space
SpaceType typeOfSubSpace() const; //type of sub-space
virtual bool isSpectral() const; //true if spectral space
virtual bool isFE() const; //true if FE space or FeSubspace
const Space* space() const; //pointer to true space object
virtual number_t dimSpace() const; //space dimension
virtual number_t nbDofs()const; //number of DOFs
virtual const FeSpace* feSpace() const; //pointer to child fespace
virtual FeSpace* feSpace(); //pointer to child fespace
virtual const FeSubSpace* feSubSpace() const;//pointer to child fesubspace
virtual const SpSpace* spSpace() const; //pointer to child fesubspace
virtual const SubSpace* subSpace() const; //pointer to child subspace
virtual SubSpace* subSpace(); //pointer to child subspace
virtual const Space* rootSpace() const; //pointer to root space
virtual Space* rootSpace(); //pointer to root space
virtual ValueType valueType() const; //value type of basis function
virtual StrucType strucType() const; //structure type of basis function
virtual bool include(const Space*) const; //inclusion test
virtual bool extensionRequired() const; //rue if space has no trace space
To understand how works the non abstract/abstract class paradigm, here is the implementation
of the access function feSpace
FeSpace* Space::feSpace() const
{
if (space_p!=this) return space_p->feSpace(); //call the true feSpace
error("is_not_fespace",name());
return 0;
}
FeSpace* FeSpace::feSpace() const {return *this;}
The test space_p!=this means that the current space is a user space (it has a child), the feSpace function is called by its child. By polymorphic behavior, if space_p is a FeSpace the feSpace is called else feSpace is again called, but with space_p=this and an error is thrown because the current space is not a FeSpace.
As you will see in section ref{s.dof}, the DOF number is relative to the parent space. To get the global number of a DOF or the DOF itself and to manage DOFs, Space provides the following functions:
virtual number_t DoFId(number_t) const; // n-th DOF id of space
virtual std::vector<number_t> DoFIds() const; // DoF ids on space
virtual const Dof& DoF(number_t) const; // n-th DOF (n=1,...)
virtual std::pair<number_t, number_t> renumberDofs(); // optimize DOFs numbering
virtual void shiftDofs(number_t n); // shift DOFs numbering from n (SpSpace)
When space is a FE space or a FE subspace, tools to access to finite element information are provided:
virtual const Interpolation* interpolation() const;
virtual number_t nbOfElements() const;
virtual const Element* element_p(number_t k) const:
virtual const Element* element_p(GeomElement* gelt) const;
virtual number_t numElement(GeomElement* gelt) const;
virtual vector<number_t> elementDofs(number_t k) const;
virtual vector<number_t> elementParentDofs(number_t k) const;
virtual const set<RefElement*>& refElements() const;
virtual void buildgelt2elt() const;
virtual const vector<FeDof>& feDofs() const;
virtual const Point& feDofCoords(number_t k) const;
virtual void buildDoFid2rank() const; // built on fly
virtual const map<number_t, number_t>& DoFid2rank() const; // built on fly
virtual Dof& locateDof(const Point&) const;
Finally, the Space provides some printing facilities:
void printSpaceInfo(std::ostream &) const;
virtual void print(std::ostream &) const;
friend std::ostream& operator<<(std::ostream&,const Space &);
Some functions managing subspaces (comparison, merging) are also available:
bool compareSpaceUsingSize(const Space*, const Space*);
vector<number_t> renumber(const Space*, const Space*);
Space& subSpace(Space&, const GeomDomain&);
inline Space& operator |(Space&, const GeomDomain&);
Space* mergeSubspaces(Space*&, Space*&, bool newSubspaces=false);
Space* mergeSubspaces(std::vector<Space*>&, bool newSubspaces=false);
Space* unionOf(std::vector<Space*>&);
vector<Point> DoFCoords(Space&, const GeomDomain&);
Linked to the Space class, the class{DoF} class stores characteristics of degree
of freedom. Degree of freedom is like a key index of components of element of space. Generally,
it handles a numeric index and carries some additional information. From class{DoF} class
inherit the classes class{FeDoF} and class{SpDoF} (see section DOF).
displayInfos{library=space, header=Space.hpp, implementation=Space.cpp, test=test_Space.cpp, header dep={config.h, geometry.h, DoF.hpp}}
Now, let’s take a look at the child space classes.
The FeSpace class#
A finite elements space is defined from a finite set of functions given by an interpolation method on a mesh.
The inherited FeSpace class is defined as follows:
class FeSpace : public Space
{
protected :
const Interpolation* interpolation_p; // pointer to finite element interpolation
bool optimizedNumbering_; // true if DOF numbering is bandwidth optimized
public:
vector<Element> elements; //list of finite elements
vector<FeDof> DoFs; //list of global degrees of freedom
set<RefElement *> refElts; //set of RefElement pointers involved
mutable map<GeomElement*, number_t> gelt2elt; // map GeomElement->element number
mutable map<number_t, number_t> DoFid2rank_; // map DOF iD->rank in DOFs vector
static Number lastEltIndex; // to manage a unique index for elements
};
Besides the two fundamental lists of elements and DOFs, two useful maps gelt2elt and DoFid2rank may be constructed on the fly. The first map is built when some interpolation operations are handled and the second one when some FE subspaces are involved. The set refElts collects the types of FE elements involved in the space, generally only one type.
This class provides one constructor, using two member functions:
FeSpace(const Domain&, const Interpolation&, Dimen, const String&, bool opt=true, bool withLocateData=true);
void buildElements(); // construct the list of elements
void buildFeDofs(); // construct the list of FeDofs
void buildgelt2elt() const; // construct the map gelt2elt
void buildDoFid2rank() const; // construct the map DoFid2rank
void buildBCRTSpace(); // construction of BuffaChristiansen-RT space
The buildElements member functions create the list of elements (Element objects) from the list of geometric elements belonging to the domain supporting the space. The cmd{buildFeDofs} function is the most important one. It constructs from reference DOFs the list of global DOFs using a general algorithm based on the class{DofKey} class that indexes DOF regarding its localization in the mesh:
class DofKey
{
public:
DofLocalization where;
number_t v1, v2; // used for vertex, edge, element DOFs
std::vector<number_t> vs; // used for face DOFs
number_t locIndex;
friend bool operator<(const DofKey& k1, const DofKey& k2);
};
Using this indexing, the algorithm building the DOFs set works as follows:
To ensure the right matching between shared DOFs on edge or face, this algorithm uses the cmd{sideDofsMap} and cmd{sideOfSideDofsMap} member functions of finite element classes. These functions relate DOF numbering to one edge/face to another edge/face.\
The FeSpace class provides also some specific accessors and properties:
virtual Number nbDofs() const; //number of DOFs (a DOF may be a vector DOF)
Dimen dimElements() const; //return the dimension of FE elements
number_t nbOfElements() const; //number of elements
const Interpolation* interpolation() const; //return pointer to interpolation
virtual Space* rootSpace(); //root space pointer
virtual number_t dimSpace()const; //the space dimension
virtual number_t nbDofs()const; //number of DOFs (may be a vector DOF)
virtual number_t DoFId(number_t n) const; //the DOF id of n-th space DOF
virtual vector<number_t> DoFIds() const; //the DOF ids on space
virtual const Dof& DoF(number_t n) const; //n-th FeDof as Dof (n=1,\ldots)
virtual const FeDof& feDoF(number_t n) const //n-th FeDof (n=1,\ldots)
virtual const std::vector<FeDof>& feDofs() const; //DoFs vector
dimen_t dimElements() const; //the dimension of FE elements
const Interpolation* interpolation() const; //pointer to interpolation
const set<RefElement*>& refElements() const; //set of pointer to RefElement
number_t maxDegree() const; //max degree of shape functions involved
virtual bool include(const Space*) const; //true if space is included in current space
virtual ValueType valueType() const; //value type of basis function
virtual StrucType strucType() const; //structure type of basis function
virtual bool isSpectral() const; //true if spectral space
virtual bool isFE() const; //true if FE space or FeSubspace
virtual bool extensionRequired() const; //true if space has no trace space
The FeSpace class has functions related to renumbering:
Graph graphOfDofs(); //create DOF connection graph
const Element* element_p(Number k) const; //k-th (k>=0) element (pointer)
vector<Number> elementDofs(Number k) const; //DoFs ranks (local numbering) of k-th (>=0) element
vector<Number> elementParentDofs(Number k) const; //DoFs ranks (parent numbering, same as local) of k-th (>=0) element
const map<number_t, number_t>& DoFid2rank() const; //map DOF to rank, built on fly
void shiftDofs(number_t); //shift DOFs numbering from n (see SpSpace)
and functions related to interpolation operations:
vector<number_t> DoFsOn(const GeomDomain&) const; //set of DOF numbers of DOFs
Dof& locateDof(const Point &) const; //DoF nearest a given point
template <typename T, typename K>
T& interpolate(const Vector<K>&, const Point&, T&, DiffOpType =_id) const; //interpolation value at P
The SpSpace class#
A spectral space is defined by a finite set of functions given by analytic expression or by
interpolated form. These global basis functions defined over a geometric domain are collected
in the SpectralBasis class declared in the SpectralBasis.hpp header file
(see the section SpectralBasis). The inherited SpSpace class is defined as follows:
class SpSpace : public Space
{
protected :
SpectralBasis* spectralBasis_; //! object function encapsulating the spectral functions
//either defined in an analytical form or by interpolated functions (TermVector)
public :
std::vector<SpDof> DoFs; //! list of global degrees of freedom
};
This class provides one constructor, a destructor, several accessors and a printing function:
SpSpace(const String&, Domain&, number_t, dimen_t, SpectralBasis*);
~SpSpace();
SpectralBasis* spectralBasis() const;
virtual Number nbDofs() const; //!< number of DOFs (a DOF may be a vector DOF)
The SubSpace and FeSubSpace classes#
A subspace is part of a space. Its DOFs are a subset of the parent DOFs. The inherited SubSpace class is defined as follows:
class SubSpace : public Space
{
protected :
Space* parent_p; //!< the parent space
std::vector<Number> DoFNumbers_; //!< global numbers of D.o.Fs in parent D.o.Fs numbering
};
This class provides two constructor, a destructor, and several specific accessors about the DoFNumbers_ attribute or about the type of subspace:
SubSpace() //!< default constructor
SubSpace(const Domain&, Space&, const String& na = ""); //!< constructor specifying geom domain, parent space and name
~SubSpace(); //! destructor
std::vector<Number>& DoFNumbers() //!< access to DoFNumbers list
const std::vector<Number>& DoFNumbers() const //!< access to DoFNumbers list (const)
std::vector<Number> DoFRootNumbers() const; //!< access to DoFNumbers list in root space numbering
Number DoFRootNumber(Number k) const; //!< access to DOF number in root space numbering
virtual Number nbDofs() const //! number of DOFs (a DOF may be a vector DOF)
virtual bool isFeSubspace();
virtual const FeSubSpace* fesubspace() const;
It also provides functions for numbering management:
void createNumbering(); //!< create numbering of subspace DOFs
void DoFsOfFeSubspace(); //!< build DOFs numbering of Fe SubSpace
void DoFsOfSpSubspace(); //!< build DOFs numbering of Sp SubSpace
void DoFsOfSubSubspace(); //!< build DOFs numbering of Subspace of SubSpace
The FeSubSpace class concerns subspaces of finite element spaces. It is defined as follows:
class FeSubSpace : public SubSpace
{
public :
std::vector<Element*> elements; //!< list of finite elements (or subelements)
std::vector<std::vector<Number> > DoFRanks; //!< numbering of D.o.Fs of domain elements in domain D.o.Fs
};
This class provides one constructor, a destructor, and several specific functions, also provided by the FeSpace class:
FeSubSpace(const Domain&, Space&, const String& na = ""); //!< constructor specifying geom domain, parent space and name
~FeSubSpace(); //!< destructor
Number nbOfElements() const; //!< number of elements
const Element* element_p(Number k) const; //!< access to k-th (k>=0) element (pointer)
std::vector<Number> elementDofs(Number k) const; //!< access to DOFs ranks (local numbering) of k-th (>=0) element
std::vector<Number> elementParentDofs(Number k) const; //!< access to DOFs ranks (parent numbering) of k-th (>=0) element
The ProdSpace class#
The ProdSpace class manages product of spaces using a vector of space pointers:
class ProdSpace : public Space
{
protected :
std::vector<Space*> spaces_;
public :
virtual Number dimSpace()const;
virtual Number nbDoFs() const;
virtual const Space* rootSpace() const
{return static_cast<const Space*>(this);}
virtual Space* rootSpace()
{return static_cast<Space*>(this);}
virtual Number DoFId(Number n) const
{error("no_DoF_numbering", name());
return 0;}
};
It is currently not used.
The Spaces class#
Spaces is an alias of PCollection<Space> class that manages a collection of Space objects, in fact a std::vector<Space*>. Be cautious when using it because the Space pointers are shared; in particular when using temporary instance of Space! It is the reason why the PCollectionItem<Space> class is overloaded to protect pointer in assign syntax sp(i)=Space(...):
template<> class PCollectionItem<Space>
{public:
typename std::vector<Space*>::iterator itp;
PCollectionItem(typename std::vector<Space*>::iterator it) : itp(it){}
Space& operator = (const Space& sp); //protected assignment
operator Space&(){return **itp;} //autocast PCollectionItem->Space&
};
Main usages of this class are the following:
Space V1(omega,_P1,"V1"), V2(omega,_P2,"V2"), V3(omega,_P3,"V3");
Spaces Vs2(V1,V2);
Spaces Vs3(V1,V2,V3);
Spaces Vs4; Vs4<<V1<<V2<<V3<<V1;
Spaces Vs5(5);
for(Number i=1;i<=5;i++)
Vs5(i)=Space(omega,interpolation(Lagrange,_standard,i,H1),"V_"+tostring(i));
Tip
As XLiFE++ is compiled with minimal standard higher to C++11, the following syntax is also working:
Spaces vs={V1,V2,V3};
Collection of spaces can also be set by the following functions from one or several domains and one or several interpolations:
Spaces spaces(const Domains&,const Interpolations&,bool=true);
Spaces spaces(const Domains&,const Interpolation&,bool=true);
Spaces spaces(const GeomDomain&,const Interpolations&,bool=true);