Skip to content
Snippets Groups Projects
Select Git revision
  • db6580d492a440bc640748ac56a8c71fcdbc0f83
  • master default protected
  • albertpiwonski-master-patch-57409
  • quadspheres
  • fix_Tmatrix_code_epsr_background
  • albertpiwonski-master-patch-12427
  • cavity
  • c1
8 results

NonLinearEVP.geo

Blame
  • MNeighbour.h 72.29 KiB
    #ifndef _MNEIGHBOUR_H_
    #define _MNEIGHBOUR_H_
    
    // Copyright (C) 2006 S. Guzik, C. Geuzaine, J.-F. Remacle
    //
    // This program is free software; you can redistribute it and/or modify
    // it under the terms of the GNU General Public License as published by
    // the Free Software Foundation; either version 2 of the License, or
    // (at your option) any later version.
    //
    // This program is distributed in the hope that it will be useful,
    // but WITHOUT ANY WARRANTY; without even the implied warranty of
    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    // GNU General Public License for more details.
    //
    // You should have received a copy of the GNU General Public License
    // along with this program; if not, write to the Free Software
    // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
    // USA.
    // 
    // Please report all bugs and problems to <gmsh@geuz.org>.
    
    /*******************************************************************************
     *
     * - The classes in this file construct a database of the elements that share
     *   the lower-dimensional bounding objects (e.g., vertex, edge, or face).
     *   These lower-dimensional objects are referred to in general as polytopes.
     * - Templated traits classes are used extensively to define the characteristics
     *   of the elements and the entities.
     *
     ******************************************************************************/
    
    #include <algorithm>
    #include <iterator>
    #include <vector>
    #include "MElement.h"
    #include "GEdge.h"
    #include "GFace.h"
    #include "GRegion.h"
    #include "MEdgeHash.h"
    #include "MFaceHash.h"
    #include "GmshDefines.h"
    
    // #define HAVE_HASH_MAP
    
    #if defined(HAVE_HASH_MAP)
    #include "HashMap.h"
    #endif
    
    
    /*==============================================================================
     * File scope types
     *============================================================================*/
    
    namespace {
    
    typedef std::list<MElement*> Neighbours;
    typedef Neighbours::const_iterator NeighboursConstIterator;
    typedef Neighbours::iterator NeighboursIterator;
    
    struct Range_t
    {
      int num;
      NeighboursIterator begin;
      Range_t() : num(0) { }
    };
    
    //--Use a hash map for neighbour lookup if possible, otherwise a map will do
    
    #if defined(HAVE_HASH_MAP)
    struct Hash_VertexPtr : public std::unary_function<MVertex*, size_t>
    {
      size_t operator()(const MVertex *const v) const
      {
        return HashFNV1a<sizeof(MVertex*)>::eval(v);
      }
    };
    typedef HASH_MAP<MVertex*, Range_t, Hash_VertexPtr, std::equal_to<MVertex*> >
    VertNRange;
    typedef HASH_MAP<MEdge, Range_t, Hash_Edge, Equal_Edge> EdgeNRange;
    typedef HASH_MAP<MFace, Range_t, Hash_Face, Equal_Face> FaceNRange;
    #else
    typedef std::map<MVertex*, Range_t, std::less<MVertex*> > VertNRange;
    typedef std::map<MEdge, Range_t, Less_Edge> EdgeNRange;
    typedef std::map<MFace, Range_t, Less_Face> FaceNRange;
    #endif
    typedef VertNRange::iterator VertNRangeIterator;
    typedef VertNRange::const_iterator VertNRangeConstIterator;
    typedef EdgeNRange::iterator EdgeNRangeIterator;
    typedef EdgeNRange::const_iterator EdgeNRangeConstIterator;
    typedef FaceNRange::iterator FaceNRangeIterator;
    typedef FaceNRange::const_iterator FaceNRangeConstIterator;
    
    
    /*==============================================================================
     * Traits classes - that just perform compile-time checks for valid argument
     * types
     *============================================================================*/
    
    //--This traits class checks for a pointer and strips it
    
    // NOTE:  If the compiler sent you here, you should be using a pointer.
    template <typename T> struct StripPointer;
    template <typename T> struct StripPointer<T*> { typedef T Type; };
        
    //--This traits class checks for valid types of entities and iterators when the
    //--entity is explicitly specified
    
    // NOTE:  If the compiler sent you here, you're using an invalid entity and/or
    // invalid iterator.  Valid pairs are shown below
    template <typename Ent, typename Iter> struct ValidSpecEntityIterator;
    template <> struct ValidSpecEntityIterator<GEdge, GEdge*>
    { typedef void Type; };
    template <> struct ValidSpecEntityIterator<GEdge, GEntity*>
    { typedef void Type; };
    template <> struct ValidSpecEntityIterator<GFace, GFace*>
    { typedef void Type; };
    template <> struct ValidSpecEntityIterator<GFace, GEntity*>
    { typedef void Type; };
    template <> struct ValidSpecEntityIterator<GRegion, GRegion*>
    { typedef void Type; };
    template <> struct ValidSpecEntityIterator<GRegion, GEntity*>
    { typedef void Type; };
    
    //--This traits class checks for valid types of entities and iterators when the
    //--entity is not specified.  It also strips the pointer.
    
    // NOTE:  If the compiler sent you here, you're using an invalid entity or
    // iterator of entities
    template <typename Iter> struct ValidEntityIterator;
    template <> struct ValidEntityIterator<GEdge*>
    { typedef GEdge Type; };
    template <> struct ValidEntityIterator<GFace*>
    { typedef GFace Type; };
    template <> struct ValidEntityIterator<GRegion*>
    { typedef GRegion Type; };
    
    //--This traits class checks for valid element types
    
    // NOTE:  If the compiler sent you here, you're using an invalid iterator for an
    // element.  What's listed here are NOT the only valid types.  Any iterator with
    // a value type of a pointer to an element should work.
    template <typename Elem_o1> struct ValidElement;
    template <> struct ValidElement<MElement> { typedef void Type; };
    template <> struct ValidElement<MLine> { typedef void Type; };
    template <> struct ValidElement<MTriangle> { typedef void Type; };
    template <> struct ValidElement<MQuadrangle> { typedef void Type; };
    template <> struct ValidElement<MTetrahedron> { typedef void Type; };
    template <> struct ValidElement<MHexahedron> { typedef void Type; };
    template <> struct ValidElement<MPrism> { typedef void Type; };
    template <> struct ValidElement<MPyramid> { typedef void Type; };
    
    
    /*==============================================================================
     * Traits classes - that return information about a type
     *============================================================================*/
    
    //--This traits class gives the first-order base type for a second-order element
    
    template <typename Order2> struct ElemBaseOrder
    { typedef Order2 Order1; };
    template <> struct ElemBaseOrder<MLine3>
    { typedef MLine Order1; };
    template <> struct ElemBaseOrder<MTriangle6>
    { typedef MTriangle Order1; };
    template <> struct ElemBaseOrder<MQuadrangle8>
    { typedef MQuadrangle Order1; };
    template <> struct ElemBaseOrder<MQuadrangle9>
    { typedef MQuadrangle Order1; };
    template <> struct ElemBaseOrder<MTetrahedron10>
    { typedef MTetrahedron Order1; };
    template <> struct ElemBaseOrder<MHexahedron20>
    { typedef MHexahedron Order1; };
    template <> struct ElemBaseOrder<MHexahedron27>
    { typedef MHexahedron Order1; };
    template <> struct ElemBaseOrder<MPrism15>
    { typedef MPrism Order1; };
    template <> struct ElemBaseOrder<MPrism18>
    { typedef MPrism Order1; };
    template <> struct ElemBaseOrder<MPyramid13>
    { typedef MPyramid Order1; };
    template <> struct ElemBaseOrder<MPyramid14>
    { typedef MPyramid Order1; };
    
    //--This traits class describes describes the lower dimensional bounding
    //--polytopes of a first-order element
    
    template <typename Elem> struct ElemTr;
    template <> struct ElemTr<MElement>
    { enum { numVertex = 0, numEdge = 0, numFace = 0 }; };
    template <> struct ElemTr<MLine>
    { enum { numVertex = 2, numEdge = 0, numFace = 0 }; };
    template <> struct ElemTr<MTriangle>
    { enum { numVertex = 3, numEdge = 3, numFace = 0 }; };
    template <> struct ElemTr<MQuadrangle>
    { enum { numVertex = 4, numEdge = 4, numFace = 0 }; };
    template <> struct ElemTr<MTetrahedron>
    { enum { numVertex = 4, numEdge = 6, numFace = 4 }; };
    template <> struct ElemTr<MHexahedron>
    { enum { numVertex = 8, numEdge = 12, numFace = 6 }; };
    template <> struct ElemTr<MPrism>
    { enum { numVertex = 6, numEdge = 9, numFace = 5 }; };
    template <> struct ElemTr<MPyramid>
    { enum { numVertex = 5, numEdge = 8, numFace = 5 }; };
    
    //--This traits class gives the number of element types in entity Ent
    
    template <typename Ent> struct EntTr;
    template <> struct EntTr<GEdge> { enum { numElemTypes = 1 }; };
    template <> struct EntTr<GFace> { enum { numElemTypes = 2 }; };
    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, int N> struct EntElemTr;
    template <> struct EntElemTr<GEdge, 1> {
      typedef MLine Elem;
      typedef std::vector<MLine*>::const_iterator ConstElementIterator;
      typedef std::vector<MLine*>::iterator ElementIterator;
      static ConstElementIterator begin(const GEdge *const edge)
      {
        return edge->lines.begin();
      }
      static ConstElementIterator end(const GEdge *const edge)
      {
        return edge->lines.end();
      }
    };
    template <> struct EntElemTr<GFace, 1> {
      typedef MQuadrangle Elem;
      typedef std::vector<MQuadrangle*>::const_iterator ConstElementIterator;
      typedef std::vector<MQuadrangle*>::iterator ElementIterator;
      static ConstElementIterator begin(const GFace *const face)
      {
        return face->quadrangles.begin();
      }
      static ConstElementIterator end(const GFace *const face)
      {
        return face->quadrangles.end();
      }
    };
    template <> struct EntElemTr<GFace, 2> {
      typedef MTriangle Elem;
      typedef std::vector<MTriangle*>::const_iterator ConstElementIterator;
      typedef std::vector<MTriangle*>::iterator ElementIterator;
      static ConstElementIterator begin(const GFace *const face)
      {
        return face->triangles.begin();
      }
      static ConstElementIterator end(const GFace *const face)
      {
        return face->triangles.end();
      }
    };
    template <> struct EntElemTr<GRegion, 1> {
      typedef MPyramid Elem;
      typedef std::vector<MPyramid*>::const_iterator ConstElementIterator;
      typedef std::vector<MPyramid*>::iterator ElementIterator;
      static ConstElementIterator begin(const GRegion *const region)
      {
        return region->pyramids.begin();
      }
      static ConstElementIterator end(const GRegion *const region)
      {
        return region->pyramids.end();
      }
    };
    template <> struct EntElemTr<GRegion, 2> {
      typedef MPrism Elem;
      typedef std::vector<MPrism*>::const_iterator ConstElementIterator;
      typedef std::vector<MPrism*>::iterator ElementIterator;
      static ConstElementIterator begin(const GRegion *const region)
      {
        return region->prisms.begin();
      }
      static ConstElementIterator end(const GRegion *const region)
      {
        return region->prisms.end();
      }
    };
    template <> struct EntElemTr<GRegion, 3> {
      typedef MHexahedron Elem;
      typedef std::vector<MHexahedron*>::const_iterator ConstElementIterator;
      typedef std::vector<MHexahedron*>::iterator ElementIterator;
      static ConstElementIterator begin(const GRegion *const region)
      {
        return region->hexahedra.begin();
      }
      static ConstElementIterator end(const GRegion *const region)
      {
        return region->hexahedra.end();
      }
    };
    template <> struct EntElemTr<GRegion, 4> {
      typedef MTetrahedron Elem;
      typedef std::vector<MTetrahedron*>::const_iterator ConstElementIterator;
      typedef std::vector<MTetrahedron*>::iterator ElementIterator;
      static ConstElementIterator begin(const GRegion *const region)
      {
        return region->tetrahedra.begin();
      }
      static ConstElementIterator end(const GRegion *const region)
      {
        return region->tetrahedra.end();
      }
    };
    
    //--This is a traits/policy class for the lower-dimension polytopes that bound
    //--an element (i.e., vertex, edge, or face).  It returns the corresponding
    //--range type and extracts from the element the function to get the polytope.
    //--Note that MVertex is a pointer because it exists somewhere whereas MEdge and
    //--MFace are constructed using MVertex's by getEdge() and getFace().
    
    template <typename Polytope> struct PolytopeTr;
    template <> struct PolytopeTr<MVertex*> {
      typedef VertNRange PolytopeNRange;
      typedef VertNRangeConstIterator PNRConstIterator;
      template <typename Elem>
      static MVertex *getPolytope(Elem *const element, const int nPolytope)
      {
        return element->getVertex(nPolytope);
      }
    };
    template <> struct PolytopeTr<MEdge> {
      typedef EdgeNRange PolytopeNRange;
      typedef EdgeNRangeConstIterator PNRConstIterator;
      template <typename Elem>
      static MEdge getPolytope(Elem *const element, const int nPolytope)
      {
        return element->getEdge(nPolytope);
      }
    };
    template <> struct PolytopeTr<MFace> {
      typedef FaceNRange PolytopeNRange;
      typedef FaceNRangeConstIterator PNRConstIterator;
      template <typename Elem>
      static MFace getPolytope(Elem *const element, const int nPolytope)
      {
        return element->getFace(nPolytope);
      }
    };
    
    }  // End of unnamed namespace
    
    
    /*******************************************************************************
     *
     * class: PolytopeIterator
     *
     * Purpose
     * =======
     *
     *   Provides an iterator to iterate through the unique vertices, edges and,
     *   faces defined by the (hash_)maps.  An iterator to the (hash_)map has a
     *   value type of a (key, value) pair.  This iterator makes the container look
     *   like it only contains the bounding polytope.
     *
     * Constructors
     * ============
     *
     *   The class takes one template argument <Polytope> which should be either
     *   MVertex*, MEdge, or MFace.
     *
     *   PolytopeIterator()
     *                     -- default constructor
     *
     *   PolytopeIterator(const BaseIterator &baseIter_in)
     *                     -- the base iterator is the real iterator to the
     *                        (hash_)map
     *
     *   PolytopeIterator(const  PolytopeIterator &iter)
     *                     -- copy
     *
     * Destructor
     * ==========
     *
     *   ~PolytopeIterator -- synthesized
     *
     * Member Functions
     * ================
     *
     *   int num_neighbours()
     *                     -- returns number of elements sharing the polytope
     *
     * Operators
     * =========
     *
     *   Includes typical bidirectional iterator operators {=, ==, !=, *, ->, ++(),
     *   --(), ()++, ()--} with * and -> dereferencing to the polytope.
     *
     * Notes
     * =====
     *
     *   - Only constant iterators are supported.
     *   
     ******************************************************************************/
    
    template<typename Polytope>
    class PolytopeIterator  // Actually only a const_iterator
    {
    
     public:
    
      // The base iterator iterates through the (hash_)maps defining the range of
      // element neighbours for a polytope
      typedef typename PolytopeTr<Polytope>::PNRConstIterator BaseIterator;
      typedef PolytopeIterator Self;
    
      // Standard traits
      typedef std::bidirectional_iterator_tag iterator_category;
      typedef Polytope value_type;
      typedef BaseIterator difference_type;
      typedef const Polytope* pointer;
      typedef const Polytope& reference;
    
    //--Constructors
    
      PolytopeIterator() : baseIter() { }
      PolytopeIterator(const BaseIterator &baseIter_in) : baseIter(baseIter_in) { }
      PolytopeIterator(const PolytopeIterator &iter) : baseIter(iter.baseIter) { }
      PolytopeIterator& operator=(const PolytopeIterator& iter)
      {
        if(&iter != this) baseIter = iter.baseIter;
        return *this;
      }
    
    //--Comparison
    
      bool operator==(const Self& iter) const { return baseIter == iter.baseIter; }
      bool operator!=(const Self& iter) const { return baseIter != iter.baseIter; }
    
    //--Dereference and arrow operator
    
      reference operator*() const { return baseIter->first; }
      pointer operator->() const { return &baseIter->first; }
    
    //--Increment
    
      // Prefix
      Self& operator++()
      {
        ++baseIter;
        return *this;
      }
    
      // Postfix
      Self operator++(int)
      {
        Self tmp = *this;
        ++*this;
        return tmp;
      }
    
    //--Decrement
    
      // Prefix
      Self& operator--()
      {
        --baseIter;
        return *this;
      }
    
      // Postfix
      Self operator--(int)
      {
        Self tmp = *this;
        --*this;
        return tmp;
      }
    
    //--Special
    
      int num_neighbours() { return baseIter->second.num; }
    
     private:
      NeighboursConstIterator begin_neighbours() { return baseIter->second.begin; }
    
    //--Date members
    
      BaseIterator baseIter;
    
    //--Friends
    
      friend class MNeighbour;
    
    };
    
    
    /*******************************************************************************
     *
     * class: MNeighbour
     *
     * Purpose
     * =======
     *
     *   Generates a database for quick lookup of elements sharing a
     *   MVertex*, MEdge, or MFace (referred to in general as polytopes.  I.e., a
     *   geometrical construct bounding the element with a lower dimension than the
     *   element).  The neighbour elements are stored in a list.  Maps or hash maps
     *   provide an index into the list for a given polytope.  In addition to the
     *   element neighbours, this class provides iterators to the unique vertices,
     *   edges, and faces in the database.
     *
     * Iterators
     * =========
     *
     *   Vertex_const_iterator
     *                     -- iterator to sequence of unique vertices
     *   Edge_const_iterator
     *                     -- iterator to sequence of unique edges
     *   Face_const_iterator
     *                     -- iterator to sequence of unique faces
     *
     * Constructors
     * ============
     *
     *   MNeighbour()      -- default constructor does nothing
     *
     * Destructor
     * ==========
     *
     *   ~MNeighbour()     -- synthesized
     *
     * Member Functions
     * ================
     *
     * Iterators
     * ---------
     *
     *   Vertex_const_iterator vertex_begin()
     *                     -- first unique vertex
     *
     *   Vertex_const_iterator vertex_end()
     *                     -- one-past-last unique vertex
     *
     *   Edeg_const_iterator edge_begin()
     *                     -- first unique edge
     *
     *   Edge_const_iterator edge_end()
     *                     -- one-past-last unique edge
     *
     *   Face_const_iterator face_begin()
     *                     -- first unique face
     *
     *   Face_const_iterator face_end()
     *                     -- one-past-last unique face
     *
     * Routines for adding elements
     * ----------------------------
     *
     *   The routines that generate a database of neighbours from container of
     *   entities (add_elements_in_entitie) require knowledge of the specific type
     *   of entity.  In cases where a container contains specific entities, the type
     *   need not be stated.  In cases where the container contains GEntity*, the
     *   user must state the actual entity type.  Extensive compile-time type
     *   checking is employed to make sure the routines are used correctly.
     *
     *   template <typename Ent, typename EntIter>
     *   void add_elements_in_entities(EntIter begin, EntIter end)
     *                     -- adds elements in entities to neighbours database.
     *                        Entity type <Ent> must be explicitly specified.  The
     *                        value type of the iterators must be a pointer to an
     *                        entity.  It is expected, but not required to be a
     *                        pointer to a GEntity.
     *     begin              (I) iterator/pointer to first entity pointer
     *     end                (I) iterator/pointer to one-past-last entity pointer
     *
     *   template <typename Ent, typename EntP>
     *   void add_elements_in_entities(EntP **pEnt, unsigned int n)
     *                     -- adds elements in entities to neighbours database.
     *                        Entity type <Ent> must be explicitly specified.  The
     *                        array element must be a pointer to an element.  It is
     *                        expected, but not required to be a pointer to a
     *                        GEntity.
     *     pEnt               (I) first entity in the array
     *     n                  (I) number of entities in the array
     *
     *   template <typename EntIter>
     *   void add_elements_in_entities(EntIter begin, EntIter end)
     *                     -- adds elements in entities to neighbours database.
     *                        The entity type must not be GEntity.  The value type
     *                        of the iterators must be a pointer to an entity.
     *     begin              (I) iterator/pointer to first entity pointer
     *     end                (I) iterator/pointer to one-past-last entity pointer
     *
     *   template <typename Ent>
     *   void add_elements_in_entities(Ent **pEnt, unsigned int n)
     *                     -- adds elements in entities to neighbours database.
     *                        The entity type must not be GEntity.  The array
     *                        element must be a pointer to an element.
     *     pEnt               (I) first entity in the array
     *     n                  (I) number of entities in the array
     *
     *   template <typename EntPtr>
     *   void add_elements_in_entity(EntPtr entity)
     *                     -- adds elements in a single entity to the neighbours
     *                        database.  The entity type must not be GEntity.  The
     *                        dereferenced quantity must be a pointer to an entity.
     *     entity             (I) pointer to an entity
     *
     *   The routines that generate a database of neighbours from containers of
     *   elements do not require the user to state the specific type of element.
     *   If the container constains a specific element pointer, compiler-time
     *   polymorphism is used.  If the container contains the base pointers
     *   MElement*, run-time switching based on element introspection is used.
     *
     *   template <typename ElemIter>
     *   void add_elements(ElemIter begin, ElemIter end)
     *                     -- adds elements from iterator sequence to the neighbours
     *                        database.
     *     begin              (I) iterator/pointer to first element pointer
     *     end                (I) iterator/pointer to one-past-last element pointer
     *
     *   template <typename Elem>
     *   void add_elements(Elem **pElem, const unsigned int n)
     *                     -- adds elements in an array to the neighbours database.
     *     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
     * ---------------------------------------------
     *
     *   int max_vertex_neighbours()
     *                     -- returns max number of elements sharing a vertex.  This
     *                        is also the max number of elements sharing any
     *                        bounding polytope.
     *
     *   int max_edge_neighbours()
     *                     -- returns max number of elements sharing an edge.
     *
     *   int max_face_neighbours()
     *                     -- returns max number of elements sharing a face.
     *
     *   int vertex_neighbours(Vertex_const_iterator &itVert,
     *                          std::vector<MElement*> &vElem)
     *                     -- return all elements sharing a vertex
     *     itVert             (I) iterator to a unique vertex.  Avoids a find()
     *     vElem              (O) vector with elements loaded via push_back
     *     return             number of neighbour elements
     *
     *   int vertex_neighbours(Vertex_const_iterator &itVert, MElement **pElem)
     *                     -- return all elements sharing a vertex
     *     itVert             (I) iterator to a unique vertex.  Avoids a find()
     *     pElem              (O) array with elements loaded starting at pElem[0]
     *     return             number of neighbour elements
     *
     *   int vertex_neighbours(MVertex *const vertex, std::vector<MElement*> &vElem)
     *                     -- returns all elements sharing a vertex
     *     vertex             (I) pointer to vertex.  It must be found in (hash_)map
     *     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)
     *                     -- 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
     *
     *   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
     *
     *   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]
     *     return             number of neighbour elements
     *
     *   int edge_neighbours(MEdge *const edge, std::vector<MElement*> &vElem)
     *                     -- returns all elements sharing a edge
     *     edge               (I) pointer to edge.  It must be found in (hash_)map
     *     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)
     *                     -- 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
     *
     *   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
     *
     *   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]
     *     return             number of neighbour elements
     *
     *   int face_neighbours(MFace *const face, std::vector<MElement*> &vElem)
     *                     -- returns all elements sharing a face
     *     face               (I) pointer to face.  It must be found in (hash_)map
     *     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)
     *                     -- 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
     *
     *   int vertex_num_neighbours(MVertex *const vertex)
     *                     -- returns the number of elements sharing a vertex
     *
     *   int edge_num_neighbours(const MEdge& edge)
     *                     -- returns the number of elements sharing an edge
     *
     *   int face_num_neighbours(const MFace& face)
     *                     -- returns the number of elements sharing a face
     *
     *   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 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 neighbour to
     *     iPolytope          (I) which polytope to find.  E.g., edge 1
     *     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
     * =======
     *
     *------------------------------------------------------------------------------
    
      // Examples for adding elements from containers (the type of container doesn't
      // matter.
    
      MNeighbour meshNeighbour;
    
      std::list<GEntity*> faceEnt1;  // Assume known to be GFace type
      meshNeighbour.add_elements_in_entities<GFace>(faceEnt1.begin(),
                                                    faceEnt1.end());
    
      std::vector<GFace*> faceEnt2;
      meshNeighbour.add_elements_in_entities(faceEnt2.begin(), faceEnt2.end());
      meshNeighbour.add_elements_in_entity(faceEnt2.begin());
    
      GEntity *faceEnt3[2];  // Assume known to be GFace type
      meshNeighbour.add_elements_in_entities<GFace>(faceEnt3, 2);
    
      GFace *faceEnt4[10];
      meshNeighbour.add_elements_in_entities(faceEnt4, 10);
    
      std::list<MElement*> elem1;
      // Run time introspection.  Elements can be mixed.
      meshNeighbour.add_elements(elem1.begin(), elem1.end());
    
      std::vector<MTriangle*> elem2;
      // Compile time introspection.
      meshNeighbour.add_elements(elem2.begin(), elem2.end());
    
      MElement *elem3[5];
      // Run time introspection.  Elements can be mixed.
      meshNeighbour.add_elements(elem3, 5);
    
      MQuadrangle *elem4[6];
      // Compile time introspection.
      meshNeighbour.add_elements(elem4, 6);
    
     *------------------------------------------------------------------------------
     *
     ******************************************************************************/
    
    class MNeighbour
    {
    
    
    /*==============================================================================
     * Class scope types
     *============================================================================*/
    
     private:
      typedef std::set<MElement*, std::less<MElement*> > ElemSet;
      typedef ElemSet::const_iterator ElemSetConstIterator;
    
    
    /*==============================================================================
     * Iterators
     *============================================================================*/
    
     public:
    
      // Iterators over polytopes
      typedef PolytopeIterator<MVertex*> Vertex_const_iterator;
      typedef PolytopeIterator<MEdge> Edge_const_iterator;
      typedef PolytopeIterator<MFace> Face_const_iterator;
    
      // Begin and end points for these iterators
      Vertex_const_iterator vertex_begin()
      {
        return Vertex_const_iterator(vertNRange.begin()); 
      }
      Vertex_const_iterator vertex_end()
      {
        return Vertex_const_iterator(vertNRange.end()); 
      }
      Edge_const_iterator edge_begin()
      {
        return Edge_const_iterator(edgeNRange.begin()); 
      }
      Edge_const_iterator edge_end()
      {
        return Edge_const_iterator(edgeNRange.end()); 
      }
      Face_const_iterator face_begin()
      {
        return Face_const_iterator(faceNRange.begin()); 
      }
      Face_const_iterator face_end()
      {
        return Face_const_iterator(faceNRange.end()); 
      }
    
    
    /*==============================================================================
     * Template meta-programming classes
     *============================================================================*/
    
     private:
    
      template <typename Elem, typename Polytope, int NP>
      struct FindNeighbours;
      template <typename Ent, int N = EntTr<Ent>::numElemTypes>
      struct FindNeighboursInEntity;
    
    
    /*==============================================================================
     * Public member functions and data
     *============================================================================*/
    
     public:
    
    //--Default constructor.
    
      // The constructor cannot really do anything because the initialization
      // functions (find_neighbours_*) cannot perform template argument deduction.
      MNeighbour() : maxVertNeighbours(0), maxEdgeNeighbours(0),
        maxFaceNeighbours(0) { }
    
    /*--------------------------------------------------------------------*
     * Elements added from entities.
     *--------------------------------------------------------------------*/
    
    //--Compute database of neighbour elements.  The entity pointers may be of a
    //--base or specific type and the call must state the specific type.
    
      template <typename Ent, typename EntIter>
      void add_elements_in_entities(EntIter begin, EntIter end) {
    
        // Check the Ent and EntIter types
        // NOTE:  If the compiler sent you here, you're using an invalid entity as a
        // template parameter and/or and invalid iterator.  See struct
        // ValidEntityIterator above for valid types
        typedef typename ValidSpecEntityIterator<Ent,
          typename EntIter::value_type>::Type Check;
    
        // Find the neighbours of each vertex, edge, and face
        for(EntIter itEnt = begin; itEnt != end; ++itEnt) {
          Ent *entity = static_cast<Ent*>(*itEnt);
          FindNeighboursInEntity<Ent>::eval(entity, vertNRange, edgeNRange,
                                            faceNRange, neighbours);
        }
        maxVertNeighbours = -1;
        maxEdgeNeighbours = -1;
        maxFaceNeighbours = -1;
      }
    
    //--Same as the routine above except the arguments are pointers instead of
    //--iterators.  Hence, value_type does not exist.
    
      template <typename Ent, typename EntP>
      void add_elements_in_entities(EntP **pEnt, unsigned int n) {
    
        // Check the Ent and EntP types
        // NOTE:  If the compiler sent you here, you're using an invalid entity as a
        // template parameter and/or invalid pointers. See struct
        // ValidEntityIterator above for valid types
        typedef typename ValidSpecEntityIterator<Ent, EntP*>::Type Check;
    
        // Find the neighbours of each vertex, edge, and face
        while(n--) {
          Ent *entity = static_cast<Ent*>(*pEnt++);
          FindNeighboursInEntity<Ent>::eval(entity, vertNRange, edgeNRange,
                                            faceNRange, neighbours);
        }
        maxVertNeighbours = -1;
        maxEdgeNeighbours = -1;
        maxFaceNeighbours = -1;
      }
    
    //--Compute database of neighbour elements.  The entity pointers must be of a
    //--specific type (not a base class).  The type of entity is determined from
    //--Iterator::value_type and does not need to be stated.
    
      template <typename EntIter>
      void add_elements_in_entities(EntIter begin, EntIter end) {
    
        // Check the value type in EntIter (it must not be GEntity*)
        // NOTE:  If the compiler sent you here, you're using an invalid entity as a
        // template parameter and/or and invalid iterator for the constructor.  See
        // struct ValidEntityIterator above for valid types
        typedef typename ValidEntityIterator<typename EntIter::value_type>::
          Type Ent;
    
        // Find the neighbours of each vertex, edge, and face
        for(EntIter itEnt = begin; itEnt != end; ++itEnt) {
          FindNeighboursInEntity<Ent>::eval(*itEnt, vertNRange, edgeNRange,
                                            faceNRange, neighbours);
        }
        maxVertNeighbours = -1;
        maxEdgeNeighbours = -1;
        maxFaceNeighbours = -1;
      }
    
    //--Same as the routine above except the arguments are pointers instead of
    //--iterators.  Hence, value_type does not exist.
    
      template <typename Ent>
      void add_elements_in_entities(Ent **pEnt, unsigned int n) {
    
        // Check the type Ent (it must not be GEntity)
        // NOTE:  If the compiler sent you here, you're using an invalid entity as a
        // pointer See struct ValidEntityIterator above for valid types
        typedef typename ValidEntityIterator<Ent*>::Type Check;
    
        // Find the neighbours of each vertex, edge, and face
        while(n--) {
          FindNeighboursInEntity<Ent>::eval(*pEnt++, vertNRange, edgeNRange,
                                            faceNRange, neighbours);
        }
        maxVertNeighbours = -1;
        maxEdgeNeighbours = -1;
        maxFaceNeighbours = -1;
      }
    
    //--Find neighbours from the elements attached to a pointer to a single entity.
    //--The type of entity does not need to be stated.
    
      template <typename EntPtr>
      void add_elements_in_entity(EntPtr entity) {
    
        // Check the type of EntPtr (it must not be GEntity*)
        // NOTE:  If the compiler sent you here, you're using an invalid entity as a
        // pointer See struct ValidEntityIterator above for valid types
        typedef typename ValidEntityIterator<EntPtr>::Type Ent;
    
        // Find the neighbours of each vertex, edge, and face
        FindNeighboursInEntity<Ent>::eval(entity, vertNRange, edgeNRange,
                                          faceNRange, neighbours);
        maxVertNeighbours = -1;
        maxEdgeNeighbours = -1;
        maxFaceNeighbours = -1;
      }
    
    /*--------------------------------------------------------------------*
     * Elements added directly
     *--------------------------------------------------------------------*/
    
    //--Add elements from a container using iterators
    
      template <typename ElemIter>
      void add_elements(ElemIter begin, ElemIter end) {
    
        // Strip the pointer to the element type and convert it to first order
        typedef typename ElemBaseOrder<
          typename StripPointer<
            typename ElemIter::value_type
          >::Type
        >::Order1 Elem_1o;
    
        // Check for a valid type of element
        // NOTE:  If the compiler sent you here, you're using an invalid iterator.
        // The dereferenced object needs to be a pointer to an element.
        typedef typename ValidElement<Elem_1o>::Type Check;
    
        add_elements1<Elem_1o, ElemIter>(begin, end);
      }
    
    //--Add elements from an array of pointers (value_type does not exist)
    
      template <typename Elem>
      void add_elements(Elem **pElem, const unsigned int n) {
    
        // Convert the element type to first order
        typedef typename ElemBaseOrder<Elem>::Order1 Elem_1o;
    
        // Check for a valid type of element
        // NOTE:  If the compiler sent you here, you're using an invalid pointer.
        // The dereferenced object needs to be a pointer to an element.
        typedef typename ValidElement<Elem_1o>::Type Check;
    
        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
    
      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
    
      // From a vertex iterator
      int vertex_neighbours(Vertex_const_iterator &itVert,
                            std::vector<MElement*> &vElem) const
      {
        NeighboursConstIterator itElem = itVert.begin_neighbours();
        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(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
      {
        VertNRangeConstIterator itVert = vertNRange.find(vertex);
        if(itVert == vertNRange.end()) return 0;  // Vertex not found
        NeighboursConstIterator itElem = itVert->second.begin;
        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(int n = itVert->second.num; n--;) *pElem++ = *itElem++;
        return itVert->second.num;
      }
    
    //--Return elements that share an edge
    
      // From an edge iterator
      int edge_neighbours(Edge_const_iterator &itEdge,
                          std::vector<MElement*> &vElem) const 
      {
        NeighboursConstIterator itElem = itEdge.begin_neighbours();
        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(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
      {
        EdgeNRangeConstIterator itEdge = edgeNRange.find(edge);
        if(itEdge == edgeNRange.end()) return 0;  // Edge not found
        NeighboursConstIterator itElem = itEdge->second.begin;
        for(int n = itEdge->second.num; n--;) vElem.push_back(*itElem++);
        return itEdge->second.num;
      }
    
      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(int n = itEdge->second.num; n--;) *pElem++ = *itElem++;
        return itEdge->second.num;
      }
    
    //--Return elements that share a face
    
      // From a face iterator
      int face_neighbours(Face_const_iterator &itFace,
                          std::vector<MElement*> &vElem) const 
      {
        NeighboursConstIterator itElem = itFace.begin_neighbours();
        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(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
      {
        FaceNRangeConstIterator itFace = faceNRange.find(face);
        if(itFace == faceNRange.end()) return 0;  // Face not found
        NeighboursConstIterator itElem = itFace->second.begin;
        for(int n = itFace->second.num; n--;) vElem.push_back(*itElem++);
        return itFace->second.num;
      }
    
      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(int n = itFace->second.num; n--;) *pElem++ = *itElem++;
        return itFace->second.num;
      }
    
    //--Return the number of elements that share a vertex
    
      int vertex_num_neighbours(MVertex *const vertex) const
      {
        VertNRangeConstIterator itVert = vertNRange.find(vertex);
        if(itVert == vertNRange.end()) return 0;  // Vertex not found
        return itVert->second.num;
      }
    
    //--Return the number of elements that share an edge
    
      int edge_num_neighbours(const MEdge& edge) const
      {
        EdgeNRangeConstIterator itEdge = edgeNRange.find(edge);
        if(itEdge == edgeNRange.end()) return 0;  // Edge not found
        return itEdge->second.num;
      }
    
    //--Return the number of elements that share a face
    
      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;
      }
    
    //--Return all the elements connected to a given element (Note: these routines
    //--have specializations - they are defined following the class)
    
      template <typename Elem>
      int all_element_neighbours(Elem *const element, std::vector<MElement*> &vElem,
                                 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) 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 int iPolytope) const
      {
        int num;
        NeighboursConstIterator itElem;
        switch(element->getTypeForMSH()) {
        case MSH_LIN_2:
        case MSH_LIN_3:
          {
            MVertex *vertex = element->getVertex(iPolytope);
            VertNRangeConstIterator itVert = vertNRange.find(vertex);
            if(itVert == vertNRange.end()) return 0;
            num = itVert->second.num;
            itElem = itVert->second.begin;
          }
          break;
        case MSH_TRI_3:
        case MSH_TRI_6:
        case MSH_QUA_4:
        case MSH_QUA_8:
        case MSH_QUA_9:
          {
            MEdge edge = element->getEdge(iPolytope);
            EdgeNRangeConstIterator itEdge = edgeNRange.find(edge);
            if(itEdge == edgeNRange.end()) return 0;
            num = itEdge->second.num;
            itElem = itEdge->second.begin;
          }
          break;
        case MSH_TET_4:
        case MSH_TET_10:
        case MSH_HEX_8:
        case MSH_HEX_20:
        case MSH_HEX_27:
        case MSH_PRI_6:
        case MSH_PRI_15:
        case MSH_PRI_18:
        case MSH_PYR_5:
        case MSH_PYR_13:
        case MSH_PYR_14: {
            MFace face = element->getFace(iPolytope);
            FaceNRangeConstIterator itFace = faceNRange.find(face);
            if(itFace == faceNRange.end()) return 0;
            num = itFace->second.num;
            itElem = itFace->second.begin;
          }
          break;
        }
        if(*itElem != element) return *itElem;
        if(num > 1) {
          ++itElem;
          if(*itElem != element) return  *itElem;
        }
        return 0;
      }
    
    
    /*==============================================================================
     * Private member functions and data
     *============================================================================*/
    
    private:
    
    //--Data members
    
      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 (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)
      {
        // 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_polytope_neighbours<Elem>(*itElem);
        }
        else {
          // We only have an iterator to an MElement* and have to check the type in
          // run-time.
          for(ElemIter itElem = begin; itElem != end; ++itElem) {
            switch((*itElem)->getTypeForMSH()) {
            case MSH_LIN_2:
            case MSH_LIN_3:
              find_polytope_neighbours<MLine>(*itElem);
              break;
            case MSH_TRI_3:
            case MSH_TRI_6:
              find_polytope_neighbours<MTriangle>(*itElem);
              break;
            case MSH_QUA_4:
            case MSH_QUA_8:
            case MSH_QUA_9:
              find_polytope_neighbours<MQuadrangle>(*itElem);
              break;
            case MSH_TET_4:
            case MSH_TET_10:
              find_polytope_neighbours<MTetrahedron>(*itElem);
              break;
            case MSH_HEX_8:
            case MSH_HEX_20:
            case MSH_HEX_27:
              find_polytope_neighbours<MHexahedron>(*itElem);
              break;
            case MSH_PRI_6:
            case MSH_PRI_15:
            case MSH_PRI_18:
              find_polytope_neighbours<MPrism>(*itElem);
              break;
            case MSH_PYR_5:
            case MSH_PYR_13:
            case MSH_PYR_14:
              find_polytope_neighbours<MPyramid>(*itElem);
              break;
            }
          }
        }
        maxVertNeighbours = -1;
        maxEdgeNeighbours = -1;
        maxFaceNeighbours = -1;
      }
    
    //--Find the neighbours sharing each polytope
    
      template <typename Elem>
      void find_polytope_neighbours(MElement *element)
      {
        // Find neighbours for vertices
        FindNeighbours<Elem, MVertex*, ElemTr<Elem>::numVertex>::
          eval(static_cast<Elem*>(element), vertNRange, neighbours);
        // Find neighbours for edges
        FindNeighbours<Elem, MEdge, ElemTr<Elem>::numEdge>::
          eval(static_cast<Elem*>(element), edgeNRange, neighbours);
        // Find neighbours for faces
        FindNeighbours<Elem, MFace, ElemTr<Elem>::numFace>::
          eval(static_cast<Elem*>(element), faceNRange, neighbours);
      }
    
    //--Compute max neighbours
    
      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++);
          }
        }
      }
    
    };
    
    
    /*==============================================================================
     * Template meta-programming classes
     *============================================================================*/
    
    /*--------------------------------------------------------------------
     * This is the main working routine for finding the elements sharing
     * a lower-dimension polytope (i.e, the structures bounding the
     * element: vertex, edge, or face).  It is templated for any type of
     * polytope and uses template meta-programming to unroll the loop over
     * the number of that type of polytope in the element.
     *--------------------------------------------------------------------*/
    
    //--Entry point
    
    template <typename Elem,                // Elem is the type of element
              typename Polytope,            // Polytope is a lower dimensional
                                            // bounding object (MVertex*, MEdge, or
                                            // MFace) of the element.  We want to
                                            // find the elements sharing a given
                                            // Polytope.
              int NP>                       // NP is an index through the number
                                            // of Polytope in the element (e.g.,
                                            // number of vertices)
    struct MNeighbour::FindNeighbours
    {
      typedef typename PolytopeTr<Polytope>::PolytopeNRange PolytopeNRange;
      static void eval(Elem *element, PolytopeNRange &polytopeNRange,
                       Neighbours &neighbours)
      {
        Polytope polytope = PolytopeTr<Polytope>::template
          getPolytope<Elem>(element, NP-1);
        Range_t &range = polytopeNRange[polytope];
        if(range.num == 0) range.begin = neighbours.end();
        range.begin = neighbours.insert(range.begin, element);
        ++range.num;
        FindNeighbours<Elem, Polytope, NP-1>::eval(element, polytopeNRange,
                                                   neighbours);
      }
    };
    
    //--Terminate loop when NP == 1
    
    template <typename Elem, typename Polytope>
    struct MNeighbour::FindNeighbours<Elem, Polytope, 1>
    {
      typedef typename PolytopeTr<Polytope>::PolytopeNRange PolytopeNRange;
      static void eval(Elem *element, PolytopeNRange &polytopeNRange,
                       Neighbours &neighbours)
      {
        Polytope polytope = PolytopeTr<Polytope>::template
          getPolytope<Elem>(element, 0);
        Range_t &range = polytopeNRange[polytope];
        if(range.num == 0) range.begin = neighbours.end();
        range.begin = neighbours.insert(range.begin, element);
        ++range.num;
      }
    };
    
    //--Nothing to do if the dimension of this polytope is equal to or greater than
    //--that of the element (e.g., no faces (2D) in a 2D element).  This is
    //--indicated by NP = 0.
    
    template <typename Elem, typename Polytope>
    struct MNeighbour::FindNeighbours<Elem, Polytope, 0>
    {
      typedef typename PolytopeTr<Polytope>::PolytopeNRange PolytopeNRange;
      static void eval(Elem *element, PolytopeNRange &polytopeNRange,
                       Neighbours &neighbours) { }
    };
    
    /*--------------------------------------------------------------------*
     * This class uses traits to determine the element types in an entity
     * and iterate over them.  A template meta-programming loop is used to
     * iterate over the types of elements.
     *--------------------------------------------------------------------*/
    
    //--Entry point
    
    template <typename Ent, int N>
    struct MNeighbour::FindNeighboursInEntity {
      typedef typename EntElemTr<Ent, N>::Elem Elem;
      static void eval(const Ent *const entity, VertNRange &vertNRange,
                       EdgeNRange &edgeNRange, FaceNRange &faceNRange,
                       Neighbours &neighbours)
      {
        for(typename EntElemTr<Ent, N>::ConstElementIterator itElem =
              EntElemTr<Ent, N>::begin(entity);
            itElem != EntElemTr<Ent, N>::end(entity); ++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);
        }
        FindNeighboursInEntity<Ent, N-1>::eval(entity, vertNRange, edgeNRange,
                                               faceNRange, neighbours);
      }
    };
    
    //--Terminate loop when N = 1
    
    template <typename Ent>
    struct MNeighbour::FindNeighboursInEntity<Ent, 1> {
      typedef typename EntElemTr<Ent, 1>::Elem Elem;
      static void eval(const Ent *const entity, VertNRange &vertNRange,
                       EdgeNRange &edgeNRange, FaceNRange &faceNRange,
                       Neighbours &neighbours)
      {
        for(typename EntElemTr<Ent, 1>::ConstElementIterator itElem =
              EntElemTr<Ent, 1>::begin(entity);
            itElem != EntElemTr<Ent, 1>::end(entity); ++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);
        }
      }
    };
    
    
    /*==============================================================================
     * 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