// ============================================================================ // == == // == AMDiS - Adaptive multidimensional simulations == // == == // ============================================================================ // == == // == TU Dresden == // == == // == Institut für Wissenschaftliches Rechnen == // == Zellescher Weg 12-14 == // == 01069 Dresden == // == germany == // == == // ============================================================================ // == == // == https://gforge.zih.tu-dresden.de/projects/amdis/ == // == == // ============================================================================ /** \file Element.h */ #ifndef AMDIS_ELEMENT_H #define AMDIS_ELEMENT_H #include "Global.h" #include "RefinementManager.h" #include "Serializable.h" #include "ElementData.h" #include "LeafData.h" #include "AMDiS_fwd.h" namespace AMDiS { template class FixVec; #define AMDIS_UNDEFINED 5 /** \ingroup Triangulation * \brief * Base class for Line, Triangle, Tetrahedron * * Elements in AMDiS are always simplices (a simplex is a Line in 1d, a * Triangle in 2d and a Tetrahedron in 3d). * We restrict ourselves here to simplicial meshes, for several reasons: * -# A simplex is one of the most simple geometric types and complex domains * may be approximated by a set of simplices quite easily. * -# Simplicial meshes allow local refinement without the need of * nonconforming meshes (hanging nodes), parametric elements, or mixture of * element types (which is the case for quadrilateral meshes). * -# Polynomials of any degree are easily represented on a simplex using * local (barycentric) coordinates. * * A Line element and its refinement: * * * * A Triangle element and its refinement: * * * * A Tetrahedron element and its refinements: * * */ class Element : public Serializable { private: /// private standard constructor because an Element must know his Mesh Element() {} public: /// constructs an Element which belongs to Mesh Element(Mesh *); /// copy constructor Element(const Element& old); /// destructor virtual ~Element(); /// void deleteElementDOFs(); /** \brief * Clone this Element and return a reference to it. Because also the DOFs * are cloned, \ref Mesh::serializedDOfs must be used. */ Element* cloneWithDOFs(); /** \name getting methods * \{ */ /// Returns \ref child[0] inline Element* getFirstChild() const { return child[0]; } /// Returns \ref child[1] inline Element* getSecondChild() const { return child[1]; } /// Returns \ref child[i], i=0,1 inline Element* getChild(int i) const { TEST_EXIT_DBG(i==0 || i==1)("i must be 0 or 1\n"); return child[i]; } /** \brief * Returns true if Element is a leaf element (\ref child[0] == NULL), returns * false otherwise. */ inline const bool isLeaf() const { return (child[0] == NULL); } /// Returns \ref dof[i][j] which is the j-th DOF of the i-th node of Element. const DegreeOfFreedom getDOF(int i, int j) const { return dof[i][j]; } /// Returns \ref dof[i] which is a pointer to the DOFs of the i-th node. const DegreeOfFreedom* getDOF(int i) const { return dof[i]; } /// Returns a pointer to the DOFs of this Element const DegreeOfFreedom** getDOF() const { return const_cast(dof); } /// Returns \ref mesh of Element inline Mesh* getMesh() const { return mesh; } /** \brief * Returns \ref elementData's error estimation, if Element is a leaf element * and has leaf data. */ inline double getEstimation(int row) const { if (isLeaf()) { TEST_EXIT_DBG(elementData)("leaf element without leaf data\n"); ElementData *ld = elementData->getElementData(ESTIMATABLE); TEST_EXIT_DBG(ld)("leaf data not estimatable!\n"); return dynamic_cast(ld)->getErrorEstimate(row); } return 0.0; } /** \brief * Returns Element's coarsening error estimation, if Element is a leaf * element and if it has leaf data and if this leaf data are coarsenable. */ inline double getCoarseningEstimation(int row) { if (isLeaf()) { TEST_EXIT_DBG(elementData)("leaf element without leaf data\n"); ElementData *ld = elementData->getElementData(COARSENABLE); TEST_EXIT_DBG(ld)("element data not coarsenable!\n"); return dynamic_cast(ld)->getCoarseningErrorEstimate(row); } return 0.0; } /// Returns region of element if defined, -1 else. int getRegion() const; /// Returns local vertex number of the j-th vertex of the i-th edge virtual int getVertexOfEdge(int i, int j) const = 0; /** \brief * Returns local vertex number of the vertexIndex-th vertex of the * positionIndex-th part of type position (vertex, edge, face) */ virtual int getVertexOfPosition(GeoIndex position, int positionIndex, int vertexIndex) const = 0; /// virtual int getPositionOfVertex(int side, int vertex) const = 0; /// virtual int getEdgeOfFace(int face, int edge) const = 0; /// Returns the number of parts of type i in this element virtual int getGeo(GeoIndex i) const = 0; /// Returns Element's \ref mark inline const signed char getMark() const { return mark; } /// Returns \ref newCoord[i] inline double getNewCoord(int i) const { TEST_EXIT_DBG(newCoord)("newCoord = NULL\n"); return (*newCoord)[i]; } /// Returns Element's \ref index inline int getIndex() const { return index; } /// Returns \ref newCoord inline WorldVector* getNewCoord() const { return newCoord; } /** \} */ /** \name setting methods * \{ */ /// Sets \ref child[0] virtual void setFirstChild(Element *aChild) { child[0] = aChild; } /// Sets \ref child[1] virtual void setSecondChild(Element *aChild) { child[1] = aChild; } /// Sets \ref elementData of Element void setElementData(ElementData* ed) { elementData = ed; } /** \brief * Sets \ref newCoord of Element. Needed by refinement, if Element has a * boundary edge on a curved boundary. */ inline void setNewCoord(WorldVector* coord) { newCoord = coord; } /// Sets \ref mesh. inline void setMesh(Mesh *m) { mesh = m; } /// Sets the pointer to the DOFs of the i-th node of Element DegreeOfFreedom* setDOF(int pos, DegreeOfFreedom* p) { dof[pos] = p; return dof[pos]; } /** \brief * Checks whether Element is a leaf element and whether it has leaf data. * If the checks don't fail, leaf data's error estimation is set to est. */ inline void setEstimation(double est, int row) { if (isLeaf()) { TEST_EXIT_DBG(elementData)("leaf element without leaf data\n"); ElementData *ld = elementData->getElementData(ESTIMATABLE); TEST_EXIT_DBG(ld)("leaf data not estimatable\n"); dynamic_cast(ld)-> setErrorEstimate(row, est); } else { ERROR_EXIT("setEstimation only for leaf elements!\n"); } } /** \brief * Sets Element's coarsening error estimation, if Element is a leaf element * and if it has leaf data and if this leaf data are coarsenable. */ inline void setCoarseningEstimation(double est, int row) { if (isLeaf()) { TEST_EXIT_DBG(elementData)("leaf element without leaf data\n"); ElementData *ld = elementData->getElementData(COARSENABLE); TEST_EXIT_DBG(ld)("leaf data not coarsenable\n"); dynamic_cast(ld)-> setCoarseningErrorEstimate(row, est); } else { ERROR_EXIT("setEstimation only for leaf elements!\n"); } } /// Sets Elements \ref mark = mark + 1; inline void incrementMark() { mark++; } /// Sets Elements \ref mark = mark - 1; inline void decrementMark() { if (0 < mark) mark--; } /// Sets Element's \ref mark inline void setMark(signed char m) { mark = m; } /** \} */ /** \name pure virtual methods * \{ */ /** \brief * orient the vertices of edges/faces. * Used by Estimator for the jumps => same quadrature nodes from both sides! */ virtual const FixVec& sortFaceIndices(int face, FixVec *vec) const = 0; /// Returns a copy of itself. Needed by Mesh to create Elements by a prototype. virtual Element *clone() = 0; /** \brief * Returns which side of child[childnr] corresponds to side sidenr of this * Element. If the child has no corresponding side, the return value is negative. * isBisected is true after the function call, if the side of the child is only * a part of element's side, false otherwise. */ virtual int getSideOfChild(int childnr, int sidenr, int elType = 0) const = 0; /** \brief * Returns which vertex of elements parent corresponds to the vertexnr of * the element, if the element is the childnr-th child of the parent. * If the vertex is the ner vertex at the refinement edge, -1 is returned. */ virtual int getVertexOfParent(int childnr, int vertexnr, int elType = 0) const = 0; /// Returns whether Element is a Line virtual bool isLine() const = 0; /// Returns whether Element is a Triangle virtual bool isTriangle() const = 0; /// Returns whether Element is a Tetrahedron virtual bool isTetrahedron() const = 0; /// Returns whether Element has sideElem as one of its sides. virtual bool hasSide(Element *sideElem) const = 0; /** \brief * Returns for a given element type number the element type number of the children. * For 1d and 2d this is always 0, because element type number are used in the * 3d case only. */ virtual int getChildType(int elType) const = 0; /** \brief * Traverses an edge/face of a given element (this includes also all children of * the element having the same edge/face). All vertex dofs alonge this edge/face * are assembled and put together to a list. * * \param[in] feSpace FE space which is used to get the dofs. * \param[in] ith Defines the edge/face on which all the vertex dofs * are assembled. * \param[in] geoPos Must be either EDGE or FACE. Defines whether an * edge or a face (only in 3d) should be traversed. * \param[out] dofs List of dofs, where the result is stored. * \param[in] parentVertices If true, also the two vertices of the parent * element are put into the result list. */ virtual void getVertexDofs(FiniteElemSpace* feSpace, BoundaryObject bound, DofContainer& dofs, bool parentVertices = false) const = 0; /** \brief * Traverses an edge/face of a given element (this includes also all children of * the element having the same edge/face). All non vertex dofs alonge this edge/face * are assembled and put together to a list. * * \param[in] feSpace FE space which is used to get the dofs. * \param[in] ith Defines the edge/face on which all the non vertex * dofs are assembled. * \param[in] geoPos Must be either EDGE or FACE. Defines whether an * edge or a face (only in 3d) should be traversed. * \param[out] dofs All dofs are put to this dof list. */ virtual void getNonVertexDofs(FiniteElemSpace* feSpace, BoundaryObject bound, DofContainer& dofs) const = 0; /** \} */ // ===== other public methods ================================================= /// assignment operator Element& operator=(const Element& el); /** \brief * Checks whether the face with vertices dof[0],..,dof[DIM-1] is * part of mel's boundary. returns the opposite vertex if true, -1 else */ int oppVertex(FixVec pdof) const; /// Refines Element's leaf data inline void refineElementData(Element* child1, Element* child2, int elType = 0) { if (elementData) { bool remove = elementData->refineElementData(this, child1, child2, elType); if (remove) { ElementData *tmp = elementData->getDecorated(); delete elementData; elementData = tmp; } } } /// Coarsens Element's leaf data inline void coarsenElementData(Element* child1, Element* child2, int elType = 0) { ElementData *childData; childData = child1->getElementData(); if (childData) { childData->coarsenElementData(this, child1, child2, elType); delete childData; child1->setElementData(NULL); } childData = child2->getElementData(); if (childData) { childData->coarsenElementData(this, child2, child1, elType); delete childData; child2->setElementData(NULL); } } /// Returns pointer to \ref elementData inline ElementData* getElementData() const { return elementData; } /// inline ElementData* getElementData(int typeID) const { if (elementData) return elementData->getElementData(typeID); return NULL; } /// Deletes the \ref elementData with a specific typeID. bool deleteElementData(int typeID); /** \brief * Returns whether element is refined at side side * el1, el2 are the corresponding children. * (not neccessarly the direct children!) * elementTyp is the type of this element (comes from ElInfo) */ bool isRefinedAtSide(int side, Element *el1, Element *el2, unsigned char elementTyp = 255); /// Returns whether Element's \ref newCoord is set inline bool isNewCoordSet() const { return (newCoord != NULL); } /// Frees memory for \ref newCoord void eraseNewCoord(); /// Serialize the element to a file. void serialize(std::ostream &out); /// Deserialize an element from a file. void deserialize(std::istream &in); /// int calcMemoryUsage(); protected: /// Sets Element's \ref dof pointer. Used by friend class Mesh. void setDOFPtrs(); /// Sets Element's \ref index. Used by friend class Mesh. inline void setIndex(int i) { index = i; } /// Used by friend class Mesh while dofCompress void newDOFFct1(const DOFAdmin*); /// Used by friend class Mesh while dofCompress void newDOFFct2(const DOFAdmin*); protected: /** \brief * Pointers to the two children of interior elements of the tree. Pointers * to NULL for leaf elements. */ Element *child[2]; /** \brief * Vector of pointers to DOFs. These pointers must be available for elements * vertices (for the geometric description of the mesh). There my be pointers * for the edges, for faces and for the center of an element. They are * ordered the following way: The first N_VERTICES entries correspond to the * DOFs at the vertices of the element. The next ones are those at the edges, * if present, then those at the faces, if present, and then those at the * barycenter, if present. */ DegreeOfFreedom **dof; /** \brief * Unique global index of the element. these indices are not strictly ordered * and may be larger than the number of elements in the binary tree (the list * of indices may have holes after coarsening). */ int index; /** \brief * Marker for refinement and coarsening. if mark is positive for a leaf * element, this element is refined mark times. if mark is negative for * a leaf element, this element is coarsened -mark times. */ signed char mark; /** \brief * If the element has a boundary edge on a curved boundary, this is a pointer * to the coordinates of the new vertex that is created due to the refinement * of the element, otherwise it is a NULL pointer. Thus coordinate * information can be also produced by the traversal routines in the case of * curved boundary. */ WorldVector *newCoord; /// Pointer to the Mesh this element belongs to Mesh* mesh; /// Pointer to Element's leaf data ElementData* elementData; /** \brief * This map is used for deletion of all DOFs of all elements of a mesh. Once * a DOF-vector (all DOFS at a node, edge, etc.) is deleted, its address is * added to this map to note not to delete it a second time. */ static std::map deletedDOFs; friend class Mesh; }; } #endif // AMDIS_ELEMENT_H