From 55485a0598d9f8a666a24b5f9f15bf5ca71ab9e4 Mon Sep 17 00:00:00 2001 From: Stefen Guzik <guzik2@llnl.gov> Date: Mon, 6 Nov 2006 07:07:00 +0000 Subject: [PATCH] - max*Neighbours only computed when requested - routines added for finding all or some of an elements neighbours - many miscellaneous changes and some reorganization --- Geo/MNeighbour.h | 695 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 595 insertions(+), 100 deletions(-) diff --git a/Geo/MNeighbour.h b/Geo/MNeighbour.h index a657127a01..c12f99d26a 100644 --- a/Geo/MNeighbour.h +++ b/Geo/MNeighbour.h @@ -28,7 +28,7 @@ * - Templated traits classes are used extensively to define the characteristics * of the elements and the entities. * - * ****************************************************************************/ + ******************************************************************************/ #include <algorithm> #include <iterator> @@ -50,13 +50,15 @@ * File scope types *============================================================================*/ +namespace { + typedef std::list<MElement*> Neighbours; typedef Neighbours::const_iterator NeighboursConstIterator; typedef Neighbours::iterator NeighboursIterator; struct Range_t { - unsigned int num; + int num; NeighboursIterator begin; Range_t() : num(0) { } }; @@ -209,7 +211,7 @@ template <> struct EntTr<GRegion> { enum { numElemTypes = 4 }; }; //--This traits class gives iterator types and begin and end iterators for //--element type number N in entity Ent. -template <typename Ent, unsigned int N> struct EntElemTr; +template <typename Ent, int N> struct EntElemTr; template <> struct EntElemTr<GEdge, 1> { typedef MLine Elem; typedef std::vector<MLine*>::const_iterator ConstElementIterator; @@ -313,8 +315,7 @@ template <> struct PolytopeTr<MVertex*> { typedef VertNRange PolytopeNRange; typedef VertNRangeConstIterator PNRConstIterator; template <typename Elem> - static MVertex *getPolytope(Elem *const element, - const unsigned int nPolytope) + static MVertex *getPolytope(Elem *const element, const int nPolytope) { return element->getVertex(nPolytope); } @@ -323,8 +324,7 @@ template <> struct PolytopeTr<MEdge> { typedef EdgeNRange PolytopeNRange; typedef EdgeNRangeConstIterator PNRConstIterator; template <typename Elem> - static MEdge getPolytope(Elem *const element, - const unsigned int nPolytope) + static MEdge getPolytope(Elem *const element, const int nPolytope) { return element->getEdge(nPolytope); } @@ -333,13 +333,14 @@ template <> struct PolytopeTr<MFace> { typedef FaceNRange PolytopeNRange; typedef FaceNRangeConstIterator PNRConstIterator; template <typename Elem> - static MFace getPolytope(Elem *const element, - const unsigned int nPolytope) + static MFace getPolytope(Elem *const element, const int nPolytope) { return element->getFace(nPolytope); } }; +} // End of unnamed namespace + /******************************************************************************* * @@ -377,7 +378,7 @@ template <> struct PolytopeTr<MFace> { * Member Functions * ================ * - * unsigned int num_neighbours() + * int num_neighbours() * -- returns number of elements sharing the polytope * * Operators @@ -468,7 +469,7 @@ class PolytopeIterator // Actually only a const_iterator //--Special - unsigned int num_neighbours() { return baseIter->second.num; } + int num_neighbours() { return baseIter->second.num; } private: NeighboursConstIterator begin_neighbours() { return baseIter->second.begin; } @@ -615,19 +616,24 @@ class PolytopeIterator // Actually only a const_iterator * pElem (I) first element in the array * n (I) number of elements in the array * + * void clear() -- clears the neighbours database. Use this before + * constructing a new database of element neighbours. + * Otherwise, new elements are added to the existing + * database. + * * Routines for querying the neighbours database * --------------------------------------------- * - * unsigned int max_vertex_neighbours() + * int max_vertex_neighbours() * -- returns max number of elements sharing a vertex. This * is also the max number of elements sharing any * bounding polytope. * - * unsigned int max_edge_neighbours() - * -- returns max number of elements sharing an edge + * int max_edge_neighbours() + * -- returns max number of elements sharing an edge. * - * unsigned int max_face_neighbours() - * -- returns max number of elements sharing a face + * int max_face_neighbours() + * -- returns max number of elements sharing a face. * * int vertex_neighbours(Vertex_const_iterator &itVert, * std::vector<MElement*> &vElem) @@ -648,20 +654,20 @@ class PolytopeIterator // Actually only a const_iterator * vElem (O) vector with elements loaded via push_back * return number of neighbour elements. 0 if vertex not found * - * int vertex_neighbours(MVertex *const vertex, MElement **pElem) + * int vertex_neighbours(MVertex *const vertex, MElement **pElem) * -- returns all elements sharing a vertex * vertex (I) pointer to vertex. It must be found in (hash_)map * pElem (O) array with elements loaded starting at pElem[0] * return number of neighbour elements. 0 if vertex not found * - * void edge_neighbours(Edge_const_iterator &itEdge, + * int edge_neighbours(Edge_const_iterator &itEdge, * std::vector<MElement*> &vElem) * -- return all elements sharing a edge * itEdge (I) iterator to a unique edge. Avoids a find() * vElem (O) vector with elements loaded via push_back * return number of neighbour elements * - * void edge_neighbours(Edge_const_iterator &itEdge, MElement **pElem) + * int edge_neighbours(Edge_const_iterator &itEdge, MElement **pElem) * -- return all elements sharing a edge * itEdge (I) iterator to a unique edge. Avoids a find() * pElem (O) array with elements loaded starting at pElem[0] @@ -673,20 +679,20 @@ class PolytopeIterator // Actually only a const_iterator * vElem (O) vector with elements loaded via push_back * return number of neighbour elements. 0 if edge not found * - * int edge_neighbours(MEdge *const edge, MElement **pElem) + * int edge_neighbours(MEdge *const edge, MElement **pElem) * -- returns all elements sharing a edge * edge (I) pointer to edge. It must be found in (hash_)map * pElem (O) array with elements loaded starting at pElem[0] * return number of neighbour elements. 0 if edge not found * - * void face_neighbours(Face_const_iterator &itFace, + * int face_neighbours(Face_const_iterator &itFace, * std::vector<MElement*> &vElem) * -- return all elements sharing a face * itFace (I) iterator to a unique face. Avoids a find() * vElem (O) vector with elements loaded via push_back * return number of neighbour elements * - * void face_neighbours(Face_const_iterator &itFace, MElement **pElem) + * int face_neighbours(Face_const_iterator &itFace, MElement **pElem) * -- return all elements sharing a face * itFace (I) iterator to a unique face. Avoids a find() * pElem (O) array with elements loaded starting at pElem[0] @@ -698,35 +704,160 @@ class PolytopeIterator // Actually only a const_iterator * vElem (O) vector with elements loaded via push_back * return number of neighbour elements. 0 if face not found * - * int face_neighbours(MFace *const face, MElement **pElem) + * int face_neighbours(MFace *const face, MElement **pElem) * -- returns all elements sharing a face * face (I) pointer to face. It must be found in (hash_)map * pElem (O) array with elements loaded starting at pElem[0] * return number of neighbour elements. 0 if face not found * - * unsigned int vertex_num_neighbours(MVertex *const vertex) const + * int vertex_num_neighbours(MVertex *const vertex) * -- returns the number of elements sharing a vertex * - * unsigned int edge_num_neighbours(const MEdge& edge) const + * int edge_num_neighbours(const MEdge& edge) * -- returns the number of elements sharing an edge * - * unsigned int edge_num_neighbours(const MFace& face) const + * int face_num_neighbours(const MFace& face) * -- returns the number of elements sharing a face * - * void clear() -- clears the neighbours database. Use this before - * constructing a new database of element neighbours. - * Otherwise, new elements are added to the existing - * database. + * template <typename Elem> + * int all_element_neighbours(Elem *const element, + * std::vector<MElement*> &vElem, + * const bool exclusive = true) + * -- find all the elements connected to the given element + * element (I) element to find neighbours to + * vElem (O) vector with elements loaded via push_back + * exclusive (I) T - exclude the given element in vElem + * F - include the given element in vElem + * return number of elements added to vElem + * + * template <typename Elem> + * int all_element_neighbours(Elem *const element, MElement **pElem + * const bool exclusive = true) + * -- find all the elements connected to the given element + * element (I) element to find neighbours to + * pElem (O) array with elements loaded starting at pElem[0] + * exclusive (I) T - exclude the given element in vElem + * F - include the given element in vElem + * return number of elements added to pElem + * + * template <typename Elem> + * int all_element_edge_neighbours(Elem *const element, + * std::vector<MElement*> &vElem, + * const bool exclusive = true) + * -- find all the elements connected to the edges of a + * given element + * element (I) element to find neighbours to + * vElem (O) vector with elements loaded via push_back + * exclusive (I) T - exclude the given element in vElem + * F - include the given element in vElem + * return number of elements added to vElem + * + * template <typename Elem> + * int all_element_edge_neighbours(Elem *const element, MElement **pElem + * const bool exclusive = true) + * -- find all the elements connected to the edges of a + * given element + * element (I) element to find neighbours to + * pElem (O) array with elements loaded starting at pElem[0] + * exclusive (I) T - exclude the given element in vElem + * F - include the given element in vElem + * return number of elements added to pElem + * + * template <typename Elem> + * int all_element_face_neighbours(Elem *const element, + * std::vector<MElement*> &vElem, + * const bool exclusive = true) + * -- find all the elements connected to the faces of a + * given element + * element (I) element to find neighbours to + * vElem (O) vector with elements loaded via push_back + * exclusive (I) T - exclude the given element in vElem + * F - include the given element in vElem + * return number of elements added to vElem + * + * template <typename Elem> + * int all_element_face_neighbours(Elem *const element, MElement **pElem + * const bool exclusive = true) + * -- find all the elements connected to the faces of a + * given element + * element (I) element to find neighbours to + * pElem (O) array with elements loaded starting at pElem[0] + * exclusive (I) T - exclude the given element in vElem + * F - include the given element in vElem + * return number of elements added to pElem + * + * int element_vertex_neighbours(const MElement *const element, + * MVertex *const vertex, + * std::vector<MElement*> &vElem) + * -- find all the elements connected to a vertex of a given + * element. This is the same as routine + * vertex_neighbours except that the given element is + * excluded from the result. + * element (I) element to exclude + * vertex (I) vertex to find element neighbours to + * vElem (O) vector with elements loaded via push_back + * return number of elements added to vElem + * + * int element_vertex_neighbours(const MElement *const element, + * MVertex *const vertex, MElement **pElem) + * -- find all the elements connected to a vertex of a given + * element. This is the same as routine + * vertex_neighbours except that the given element is + * excluded from the result. + * element (I) element to exclude + * vertex (I) vertex to find element neighbours to + * pElem (O) array with elements loaded starting at pElem[0] + * return number of elements added to pElem + * + * int element_edge_neighbours(const MElement *const element, + * const MEdge &edge, + * std::vector<MElement*> &vElem) + * -- find all the elements connected to an edge of a given + * element. This is the same as routine + * edge_neighbours except that the given element is + * excluded from the result. + * element (I) element to exclude + * edge (I) edge to find element neighbours to + * vElem (O) vector with elements loaded via push_back + * return number of elements added to vElem + * + * int element_edge_neighbours(const MElement *const element, + * const MEdge &edge, MElement **pElem) + * -- find all the elements connected to an edge of a given + * element. This is the same as routine + * edge_neighbours except that the given element is + * excluded from the result. + * element (I) element to exclude + * edge (I) edge to find element neighbours to + * pElem (O) array with elements loaded starting at pElem[0] + * return number of elements added to pElem + * + * MElement *element_face_neighbour(const MElement *const element, + * const MFace &face) + * -- find the element connected to the face of a given + * element. Routine element_neighbour could also be + * used. + * element (I) element to find neighbour to + * face (I) face to find element neighbour across + * return the neighbour element or 0 if none found * * MElement *element_neighbour(MElement *const element, - * const unsigned int iPolytope) const + * const int iPolytope) * -- find the neighbour element across the d-1 bounding * polytope. E.g., for a triangle, find an element * across an edge. - * element (I) element to find + * element (I) element to find neighbour to * iPolytope (I) which polytope to find. E.g., edge 1 - * return the neighbour element or 0 if polytope not found - * in neighbours database. + * return the neighbour element or 0 if none found + * + * Notes + * ===== + * + * - Many of the query routines that have an element argument are specialized. + * If a specific element pointer is given, static (compile-time) + * polymorphism is used. If a base element pointer is given, dynamic + * (run-time) polymorphism is used. This is mostly experimental and may not + * have any tangible benefit. * * Example * ======= @@ -776,6 +907,15 @@ class MNeighbour { +/*============================================================================== + * Class scope types + *============================================================================*/ + + private: + typedef std::set<MElement*, std::less<MElement*> > ElemSet; + typedef ElemSet::const_iterator ElemSetConstIterator; + + /*============================================================================== * Iterators *============================================================================*/ @@ -820,14 +960,14 @@ class MNeighbour private: - template <typename Elem, typename Polytope, unsigned int NP> + template <typename Elem, typename Polytope, int NP> struct FindNeighbours; - template <typename Ent, unsigned int N = EntTr<Ent>::numElemTypes> + template <typename Ent, int N = EntTr<Ent>::numElemTypes> struct FindNeighboursInEntity; /*============================================================================== - * Member functions and data + * Public member functions and data *============================================================================*/ public: @@ -862,7 +1002,9 @@ class MNeighbour FindNeighboursInEntity<Ent>::eval(entity, vertNRange, edgeNRange, faceNRange, neighbours); } - maxNeighbours(); + maxVertNeighbours = -1; + maxEdgeNeighbours = -1; + maxFaceNeighbours = -1; } //--Same as the routine above except the arguments are pointers instead of @@ -883,7 +1025,9 @@ class MNeighbour FindNeighboursInEntity<Ent>::eval(entity, vertNRange, edgeNRange, faceNRange, neighbours); } - maxNeighbours(); + maxVertNeighbours = -1; + maxEdgeNeighbours = -1; + maxFaceNeighbours = -1; } //--Compute database of neighbour elements. The entity pointers must be of a @@ -905,7 +1049,9 @@ class MNeighbour FindNeighboursInEntity<Ent>::eval(*itEnt, vertNRange, edgeNRange, faceNRange, neighbours); } - maxNeighbours(); + maxVertNeighbours = -1; + maxEdgeNeighbours = -1; + maxFaceNeighbours = -1; } //--Same as the routine above except the arguments are pointers instead of @@ -924,7 +1070,9 @@ class MNeighbour FindNeighboursInEntity<Ent>::eval(*pEnt++, vertNRange, edgeNRange, faceNRange, neighbours); } - maxNeighbours(); + maxVertNeighbours = -1; + maxEdgeNeighbours = -1; + maxFaceNeighbours = -1; } //--Find neighbours from the elements attached to a pointer to a single entity. @@ -941,7 +1089,9 @@ class MNeighbour // Find the neighbours of each vertex, edge, and face FindNeighboursInEntity<Ent>::eval(entity, vertNRange, edgeNRange, faceNRange, neighbours); - maxNeighbours(); + maxVertNeighbours = -1; + maxEdgeNeighbours = -1; + maxFaceNeighbours = -1; } /*--------------------------------------------------------------------* @@ -984,15 +1134,42 @@ class MNeighbour add_elements1<Elem_1o, Elem**>(pElem, pElem+n); } +/*--------------------------------------------------------------------* + * Reset the database + *--------------------------------------------------------------------*/ + + void clear() + { + vertNRange.clear(); + edgeNRange.clear(); + faceNRange.clear(); + neighbours.clear(); + maxVertNeighbours = 0; + maxEdgeNeighbours = 0; + maxFaceNeighbours = 0; + } + /*--------------------------------------------------------------------* * Query the database *--------------------------------------------------------------------*/ //--Get the max number of elements sharing a vertex, edge, or face - unsigned int max_vertex_neighbours() const { return maxVertNeighbours; } - unsigned int max_edge_neighbours() const { return maxEdgeNeighbours; } - unsigned int max_face_neighbours() const { return maxFaceNeighbours; } + int max_vertex_neighbours() + { + if ( maxVertNeighbours < 0 ) compute_max_vert_neighbours(); + return maxVertNeighbours; + } + int max_edge_neighbours() + { + if ( maxEdgeNeighbours < 0 ) compute_max_edge_neighbours(); + return maxEdgeNeighbours; + } + int max_face_neighbours() + { + if ( maxFaceNeighbours < 0 ) compute_max_face_neighbours(); + return maxFaceNeighbours; + } //--Return elements that share a vertex @@ -1001,17 +1178,17 @@ class MNeighbour std::vector<MElement*> &vElem) const { NeighboursConstIterator itElem = itVert.begin_neighbours(); - for(unsigned int n = itVert.num_neighbours(); n--;) - vElem.push_back(*itElem++); + for(int n = itVert.num_neighbours(); n--;) vElem.push_back(*itElem++); return itVert.num_neighbours(); } + int vertex_neighbours(Vertex_const_iterator &itVert, MElement **pElem) const { NeighboursConstIterator itElem = itVert.begin_neighbours(); - for(unsigned int n = itVert.num_neighbours(); n--;) - *pElem++ = *itElem++; + for(int n = itVert.num_neighbours(); n--;) *pElem++ = *itElem++; return itVert.num_neighbours(); } + // From a vertex int vertex_neighbours(MVertex *const vertex, std::vector<MElement*> &vElem) const @@ -1019,15 +1196,16 @@ class MNeighbour VertNRangeConstIterator itVert = vertNRange.find(vertex); if(itVert == vertNRange.end()) return 0; // Vertex not found NeighboursConstIterator itElem = itVert->second.begin; - for(unsigned int n = itVert->second.num; n--;) vElem.push_back(*itElem++); + for(int n = itVert->second.num; n--;) vElem.push_back(*itElem++); return itVert->second.num; } + int vertex_neighbours(MVertex *const vertex, MElement **pElem) const { VertNRangeConstIterator itVert = vertNRange.find(vertex); if(itVert == vertNRange.end()) return 0; // Vertex not found NeighboursConstIterator itElem = itVert->second.begin; - for(unsigned int n = itVert->second.num; n--;) *pElem++ = *itElem++; + for(int n = itVert->second.num; n--;) *pElem++ = *itElem++; return itVert->second.num; } @@ -1038,32 +1216,35 @@ class MNeighbour std::vector<MElement*> &vElem) const { NeighboursConstIterator itElem = itEdge.begin_neighbours(); - for(unsigned int n = itEdge.num_neighbours(); n--;) + for(int n = itEdge.num_neighbours(); n--;) vElem.push_back(*itElem++); return itEdge.num_neighbours(); } + int edge_neighbours(Edge_const_iterator &itEdge, MElement **pElem) const { NeighboursConstIterator itElem = itEdge.begin_neighbours(); - for(unsigned int n = itEdge.num_neighbours(); n--;) + for(int n = itEdge.num_neighbours(); n--;) *pElem++ = *itElem++; return itEdge.num_neighbours(); } + // From an edge - int edge_neighbours(const MEdge& edge, std::vector<MElement*> &vElem) const + int edge_neighbours(const MEdge &edge, std::vector<MElement*> &vElem) const { EdgeNRangeConstIterator itEdge = edgeNRange.find(edge); if(itEdge == edgeNRange.end()) return 0; // Edge not found NeighboursConstIterator itElem = itEdge->second.begin; - for(unsigned int n = itEdge->second.num; n--;) vElem.push_back(*itElem++); + for(int n = itEdge->second.num; n--;) vElem.push_back(*itElem++); return itEdge->second.num; } - int edge_neighbours(const MEdge& edge, MElement **pElem) const + + int edge_neighbours(const MEdge &edge, MElement **pElem) const { EdgeNRangeConstIterator itEdge = edgeNRange.find(edge); if(itEdge == edgeNRange.end()) return 0; // Edge not found NeighboursConstIterator itElem = itEdge->second.begin; - for(unsigned int n = itEdge->second.num; n--;) *pElem++ = *itElem++; + for(int n = itEdge->second.num; n--;) *pElem++ = *itElem++; return itEdge->second.num; } @@ -1074,38 +1255,41 @@ class MNeighbour std::vector<MElement*> &vElem) const { NeighboursConstIterator itElem = itFace.begin_neighbours(); - for(unsigned int n = itFace.num_neighbours(); n--;) + for(int n = itFace.num_neighbours(); n--;) vElem.push_back(*itElem++); return itFace.num_neighbours(); } + int face_neighbours(Face_const_iterator &itFace, MElement **pElem) const { NeighboursConstIterator itElem = itFace.begin_neighbours(); - for(unsigned int n = itFace.num_neighbours(); n--;) + for(int n = itFace.num_neighbours(); n--;) *pElem++ = *itElem++; return itFace.num_neighbours(); } + // From a face - int face_neighbours(const MFace& face, std::vector<MElement*> &vElem) const + int face_neighbours(const MFace &face, std::vector<MElement*> &vElem) const { FaceNRangeConstIterator itFace = faceNRange.find(face); if(itFace == faceNRange.end()) return 0; // Face not found NeighboursConstIterator itElem = itFace->second.begin; - for(unsigned int n = itFace->second.num; n--;) vElem.push_back(*itElem++); + for(int n = itFace->second.num; n--;) vElem.push_back(*itElem++); return itFace->second.num; } - int face_neighbours(const MFace& face, MElement **pElem) const + + int face_neighbours(const MFace &face, MElement **pElem) const { FaceNRangeConstIterator itFace = faceNRange.find(face); if(itFace == faceNRange.end()) return 0; // Face not found NeighboursConstIterator itElem = itFace->second.begin; - for(unsigned int n = itFace->second.num; n--;) *pElem++ = *itElem++; + for(int n = itFace->second.num; n--;) *pElem++ = *itElem++; return itFace->second.num; } //--Return the number of elements that share a vertex - unsigned int vertex_num_neighbours(MVertex *const vertex) const + int vertex_num_neighbours(MVertex *const vertex) const { VertNRangeConstIterator itVert = vertNRange.find(vertex); if(itVert == vertNRange.end()) return 0; // Vertex not found @@ -1114,7 +1298,7 @@ class MNeighbour //--Return the number of elements that share an edge - unsigned int edge_num_neighbours(const MEdge& edge) const + int edge_num_neighbours(const MEdge& edge) const { EdgeNRangeConstIterator itEdge = edgeNRange.find(edge); if(itEdge == edgeNRange.end()) return 0; // Edge not found @@ -1123,32 +1307,216 @@ class MNeighbour //--Return the number of elements that share a face - unsigned int face_num_neighbours(const MFace& face) const + int face_num_neighbours(const MFace& face) const { FaceNRangeConstIterator itFace = faceNRange.find(face); if(itFace == faceNRange.end()) return 0; // Face not found return itFace->second.num; } -//--Clear the containers +//--Return all the elements connected to a given element (Note: these routines +//--have specializations - they are defined following the class) - void clear() + template <typename Elem> + int all_element_neighbours(Elem *const element, std::vector<MElement*> &vElem, + const bool exclusive = true) { - vertNRange.clear(); - edgeNRange.clear(); - faceNRange.clear(); - neighbours.clear(); - maxVertNeighbours = 0; - maxEdgeNeighbours = 0; - maxFaceNeighbours = 0; + typedef typename ElemBaseOrder<Elem>::Order1 Elem_1o; + element_neighbours1<Elem, MVertex*>(static_cast<Elem_1o*>(element), + vertNRange, ElemTr<Elem_1o>::numVertex); + if(exclusive) elemSet.erase(element); + const ElemSetConstIterator itElemEnd = elemSet.end(); + for(ElemSetConstIterator itElem = elemSet.begin(); itElem != itElemEnd; + ++itElem) vElem.push_back(*itElem); + const int nElem = elemSet.size(); + elemSet.clear(); + return nElem; + } + + template <typename Elem> + int all_element_neighbours(Elem *const element, MElement **pElem, + const bool exclusive = true) + { + typedef typename ElemBaseOrder<Elem>::Order1 Elem_1o; + element_neighbours1<Elem, MVertex*>(static_cast<Elem_1o*>(element), + vertNRange, ElemTr<Elem_1o>::numVertex); + if(exclusive) elemSet.erase(element); + const ElemSetConstIterator itElemEnd = elemSet.end(); + for(ElemSetConstIterator itElem = elemSet.begin(); itElem != itElemEnd; + ++itElem) *pElem++ = *itElem; + const int nElem = elemSet.size(); + elemSet.clear(); + return nElem; + } + +//--Return all the elements connected to the edges of a given element (Note: +//--these routines have specializations - they are defined following the class) + + template <typename Elem> + int all_element_edge_neighbours(Elem *const element, + std::vector<MElement*> &vElem, + const bool exclusive = true) + { + typedef typename ElemBaseOrder<Elem>::Order1 Elem_1o; + element_neighbours1<Elem, MEdge>(static_cast<Elem_1o*>(element), + edgeNRange, ElemTr<Elem_1o>::numEdge); + if(exclusive) elemSet.erase(element); + const ElemSetConstIterator itElemEnd = elemSet.end(); + for(ElemSetConstIterator itElem = elemSet.begin(); itElem != itElemEnd; + ++itElem) vElem.push_back(*itElem); + const int nElem = elemSet.size(); + elemSet.clear(); + return nElem; + } + + template <typename Elem> + int all_element_edge_neighbours(Elem *const element, MElement **pElem, + const bool exclusive = true) + { + typedef typename ElemBaseOrder<Elem>::Order1 Elem_1o; + element_neighbours1<Elem, MEdge>(static_cast<Elem_1o*>(element), + edgeNRange, ElemTr<Elem_1o>::numEdge); + if(exclusive) elemSet.erase(element); + const ElemSetConstIterator itElemEnd = elemSet.end(); + for(ElemSetConstIterator itElem = elemSet.begin(); itElem != itElemEnd; + ++itElem) *pElem++ = *itElem; + const int nElem = elemSet.size(); + elemSet.clear(); + return nElem; + } + +//--Return all the elements connected to the faces of a given element (Note: +//--these routines have specializations - they are defined following the class) + + template <typename Elem> + int all_element_face_neighbours(Elem *const element, + std::vector<MElement*> &vElem, + const bool exclusive = true) + { + typedef typename ElemBaseOrder<Elem>::Order1 Elem_1o; + element_neighbours1<Elem, MFace>(static_cast<Elem_1o*>(element), + faceNRange, ElemTr<Elem_1o>::numFace); + if(exclusive) elemSet.erase(element); + const ElemSetConstIterator itElemEnd = elemSet.end(); + for(ElemSetConstIterator itElem = elemSet.begin(); itElem != itElemEnd; + ++itElem) vElem.push_back(*itElem); + const int nElem = elemSet.size(); + elemSet.clear(); + return nElem; + } + + template <typename Elem> + int all_element_face_neighbours(Elem *const element, MElement **pElem, + const bool exclusive = true) + { + typedef typename ElemBaseOrder<Elem>::Order1 Elem_1o; + element_neighbours1<Elem, MFace>(static_cast<Elem_1o*>(element), + faceNRange, ElemTr<Elem_1o>::numFace); + if(exclusive) elemSet.erase(element); + const ElemSetConstIterator itElemEnd = elemSet.end(); + for(ElemSetConstIterator itElem = elemSet.begin(); itElem != itElemEnd; + ++itElem) *pElem++ = *itElem; + const int nElem = elemSet.size(); + elemSet.clear(); + return nElem; + } + +//--Return elements connected to a specific vertex of a given element (Note: +//--these routines are the same as vertex_neighbours() except that the given +//--element is excluded) + + int element_vertex_neighbours(const MElement *const element, + MVertex *const vertex, + std::vector<MElement*> &vElem) const + { + VertNRangeConstIterator itVert = vertNRange.find(vertex); + if(itVert == vertNRange.end()) return 0; // Vertex not found + NeighboursConstIterator itElem = itVert->second.begin; + int n = itVert->second.num; + while(*itElem != element) { + vElem.push_back(*itElem++); + --n; + } + ++itElem; + for(--n; n--;) vElem.push_back(*itElem++); + return itVert->second.num - 1; + } + + int element_vertex_neighbours(const MElement *const element, + MVertex *const vertex, MElement **pElem) const + { + VertNRangeConstIterator itVert = vertNRange.find(vertex); + if(itVert == vertNRange.end()) return 0; // Vertex not found + NeighboursConstIterator itElem = itVert->second.begin; + int n = itVert->second.num; + while(*itElem != element) { + *pElem++ = *itElem++; + --n; + } + ++itElem; + for(--n; n--;) *pElem++ = *itElem++; + return itVert->second.num - 1; + } + +//--Return elements connected to a specific edge of a given element (Note: these +//--routines are the same as edge_neighbours except that the given element is +//--excluded) + + int element_edge_neighbours(const MElement *const element, const MEdge &edge, + std::vector<MElement*> &vElem) const + { + EdgeNRangeConstIterator itEdge = edgeNRange.find(edge); + if(itEdge == edgeNRange.end()) return 0; // Edge not found + NeighboursConstIterator itElem = itEdge->second.begin; + int n = itEdge->second.num; + while(*itElem != element) { + vElem.push_back(*itElem++); + --n; + } + ++itElem; + for(--n; n--;) vElem.push_back(*itElem++); + return itEdge->second.num - 1; + } + + int element_edge_neighbours(const MElement *const element, const MEdge &edge, + MElement **pElem) const + { + EdgeNRangeConstIterator itEdge = edgeNRange.find(edge); + if(itEdge == edgeNRange.end()) return 0; // Edge not found + NeighboursConstIterator itElem = itEdge->second.begin; + int n = itEdge->second.num; + while(*itElem != element) { + *pElem++ = *itElem++; + --n; + } + ++itElem; + for(--n; n--;) *pElem++ = *itElem++; + return itEdge->second.num - 1; + } + +//--Return the element connected to a specific face of a given element (Note: +//--this routine is similar to element_neighbour except less general) + + MElement *element_face_neighbour(const MElement *const element, + const MFace &face) const + { + FaceNRangeConstIterator itFace = faceNRange.find(face); + if(itFace == faceNRange.end()) return 0; // Face not found + NeighboursConstIterator itElem = itFace->second.begin; + if(*itElem != element) return *itElem; + if(itFace->second.num > 1) { + ++itElem; + if(*itElem != element) return *itElem; + } + return 0; } //--Return the element neighbour across a d-1 polytope MElement *element_neighbour(MElement *const element, - const unsigned int iPolytope) const + const int iPolytope) const { - unsigned int num; + int num; NeighboursConstIterator itElem; switch(element->getTypeForMSH()) { case MSH_LIN_2: @@ -1201,19 +1569,27 @@ class MNeighbour return 0; } + +/*============================================================================== + * Private member functions and data + *============================================================================*/ + private: //--Data members - VertNRange vertNRange; - EdgeNRange edgeNRange; - FaceNRange faceNRange; - Neighbours neighbours; - unsigned int maxVertNeighbours; - unsigned int maxEdgeNeighbours; - unsigned int maxFaceNeighbours; + VertNRange vertNRange; // Map of Vert. to indexes in neighbours + EdgeNRange edgeNRange; // Map of edge to indexes in neighbours + FaceNRange faceNRange; // Map of face to indexes in neighbours + Neighbours neighbours; // List of element neighbours + ElemSet elemSet; // Buffer for finding unique elements + int maxVertNeighbours; + int maxEdgeNeighbours; + int maxFaceNeighbours; -//--Working routine to determine the neighbours from elements +//--Working routine to determine the neighbours from elements (Note: Ideally +//--this class would use a specialization for MElement but partial +//--specialization is not currently permitted for member functions) template <typename Elem, typename ElemIter> void add_elements1(ElemIter begin, ElemIter end) @@ -1221,17 +1597,8 @@ private: // Test if the type of element is known if(ElemTr<Elem>::numVertex) { // 0 only for MElement // Find the neighbours of each vertex, edge, and face - for(ElemIter itElem = begin; itElem != end; ++itElem) { - // Find neighbours for vertices - FindNeighbours<Elem, MVertex*, ElemTr<Elem>::numVertex>:: - eval(*itElem, vertNRange, neighbours); - // Find neighbours for edges - FindNeighbours<Elem, MEdge, ElemTr<Elem>::numEdge>:: - eval(*itElem, edgeNRange, neighbours); - // Find neighbours for faces - FindNeighbours<Elem, MFace, ElemTr<Elem>::numFace>:: - eval(*itElem, faceNRange, neighbours); - } + for(ElemIter itElem = begin; itElem != end; ++itElem) + find_polytope_neighbours<Elem>(*itElem); } else { // We only have an iterator to an MElement* and have to check the type in @@ -1273,7 +1640,9 @@ private: } } } - maxNeighbours(); + maxVertNeighbours = -1; + maxEdgeNeighbours = -1; + maxFaceNeighbours = -1; } //--Find the neighbours sharing each polytope @@ -1294,22 +1663,47 @@ private: //--Compute max neighbours - void maxNeighbours() + void compute_max_vert_neighbours() { maxVertNeighbours = 0; for(VertNRangeConstIterator itVert = vertNRange.begin(); itVert != vertNRange.end(); ++itVert) maxVertNeighbours = std::max(maxVertNeighbours, itVert->second.num); + } + void compute_max_edge_neighbours() + { maxEdgeNeighbours = 0; for(EdgeNRangeConstIterator itEdge = edgeNRange.begin(); itEdge != edgeNRange.end(); ++itEdge) maxEdgeNeighbours = std::max(maxEdgeNeighbours, itEdge->second.num); + } + void compute_max_face_neighbours() + { maxFaceNeighbours = 0; for(FaceNRangeConstIterator itFace = faceNRange.begin(); itFace != faceNRange.end(); ++itFace) maxFaceNeighbours = std::max(maxFaceNeighbours, itFace->second.num); } +//--Work routine for finding all the element neighbours + + template <typename Elem, typename Polytope> + void element_neighbours1(Elem *const element, + typename PolytopeTr<Polytope>::PolytopeNRange + &polytopeNRange, const int nVPE) + { + for(int iVPE = 0; iVPE != nVPE; ++iVPE) { + Polytope polytope = PolytopeTr<Polytope>::getPolytope(element, iVPE); + typename PolytopeTr<Polytope>::PNRConstIterator itPoly = + polytopeNRange.find(polytope); + if(itPoly != polytopeNRange.end()) { + NeighboursConstIterator itElem = itPoly->second.begin; + for(int n = itPoly->second.num; n--;) + elemSet.insert(*itElem++); + } + } + } + }; @@ -1333,7 +1727,7 @@ template <typename Elem, // Elem is the type of element // MFace) of the element. We want to // find the elements sharing a given // Polytope. - unsigned int NP> // NP is an index through the number + int NP> // NP is an index through the number // of Polytope in the element (e.g., // number of vertices) struct MNeighbour::FindNeighbours @@ -1391,7 +1785,7 @@ struct MNeighbour::FindNeighbours<Elem, Polytope, 0> //--Entry point -template <typename Ent, unsigned int N> +template <typename Ent, int N> struct MNeighbour::FindNeighboursInEntity { typedef typename EntElemTr<Ent, N>::Elem Elem; static void eval(const Ent *const entity, VertNRange &vertNRange, @@ -1441,4 +1835,105 @@ struct MNeighbour::FindNeighboursInEntity<Ent, 1> { } }; + +/*============================================================================== + * Specializations for base elements - dynamic polymorphism + *============================================================================*/ + +//--Return all the elements connected to a given element + +template <> +inline int MNeighbour::all_element_neighbours<MElement> +(MElement *const element, std::vector<MElement*> &vElem, const bool exclusive) +{ + element_neighbours1<MElement, MVertex*>(element, vertNRange, + element->getNumPrimaryVertices()); + if(exclusive) elemSet.erase(element); + const ElemSetConstIterator itElemEnd = elemSet.end(); + for(ElemSetConstIterator itElem = elemSet.begin(); itElem != itElemEnd; + ++itElem) vElem.push_back(*itElem); + const int nElem = elemSet.size(); + elemSet.clear(); + return nElem; +} + +template <> +inline int MNeighbour::all_element_neighbours<MElement> +(MElement *const element, MElement **pElem, const bool exclusive) +{ + element_neighbours1<MElement, MVertex*>(element, vertNRange, + element->getNumPrimaryVertices()); + if(exclusive) elemSet.erase(element); + const ElemSetConstIterator itElemEnd = elemSet.end(); + for(ElemSetConstIterator itElem = elemSet.begin(); itElem != itElemEnd; + ++itElem) *pElem++ = *itElem; + const int nElem = elemSet.size(); + elemSet.clear(); + return nElem; +} + +//--Return all the elements connected to the edges of a given element + +template <> +inline int MNeighbour::all_element_edge_neighbours<MElement> +(MElement *const element, std::vector<MElement*> &vElem, const bool exclusive) +{ + element_neighbours1<MElement, MEdge>(element, edgeNRange, + element->getNumEdges()); + if(exclusive) elemSet.erase(element); + const ElemSetConstIterator itElemEnd = elemSet.end(); + for(ElemSetConstIterator itElem = elemSet.begin(); itElem != itElemEnd; + ++itElem) vElem.push_back(*itElem); + const int nElem = elemSet.size(); + elemSet.clear(); + return nElem; +} + +template <> +inline int MNeighbour::all_element_edge_neighbours<MElement> +(MElement *const element, MElement **pElem, const bool exclusive) +{ + element_neighbours1<MElement, MEdge>(element, edgeNRange, + element->getNumEdges()); + if(exclusive) elemSet.erase(element); + const ElemSetConstIterator itElemEnd = elemSet.end(); + for(ElemSetConstIterator itElem = elemSet.begin(); itElem != itElemEnd; + ++itElem) *pElem++ = *itElem; + const int nElem = elemSet.size(); + elemSet.clear(); + return nElem; +} + +//--Return all the elements connected to the faces of a given element + +template <> +inline int MNeighbour::all_element_face_neighbours<MElement> +(MElement *const element, std::vector<MElement*> &vElem, const bool exclusive) +{ + element_neighbours1<MElement, MFace>(element, faceNRange, + element->getNumFaces()); + if(exclusive) elemSet.erase(element); + const ElemSetConstIterator itElemEnd = elemSet.end(); + for(ElemSetConstIterator itElem = elemSet.begin(); itElem != itElemEnd; + ++itElem) vElem.push_back(*itElem); + const int nElem = elemSet.size(); + elemSet.clear(); + return nElem; +} + +template <> +inline int MNeighbour::all_element_face_neighbours<MElement> +(MElement *const element, MElement **pElem, const bool exclusive) +{ + element_neighbours1<MElement, MFace>(element, faceNRange, + element->getNumFaces()); + if(exclusive) elemSet.erase(element); + const ElemSetConstIterator itElemEnd = elemSet.end(); + for(ElemSetConstIterator itElem = elemSet.begin(); itElem != itElemEnd; + ++itElem) *pElem++ = *itElem; + const int nElem = elemSet.size(); + elemSet.clear(); + return nElem; +} + #endif -- GitLab