/** \file * \brief implement universally usable, unique partitioning of entities (vertex, edge, face, element) * in a Dune grid; it is a general problem in parallel calculation to assign entities in a unique * way to processors; thus, we need a unique criterion; here, we will use the rule that an entity * is always assigned to the process with the lowest rank. * * * In particular, it is the objective to provide this functionality in a unique way so that it can * be used in a wide range of an application's needs: e.g., it can be used to assign faces, * situated on the inter processor boundary, in a unique way, i.e. the face is always assigned to * the process with the lower rank. A concrete application of this mechanism is the implementation * of the transparent integral boundary condition to remove redundant triangular faces of the * fictitious boundary surface. Indeed, the implementation of the UniqueEntityPartition class has * been motivated by this need. However, its usage is much wider. It will also be the underlying * infrastructure to calculate global, consecutive, zero-starting indices for grid entities over all * the processes over which the grid is partitioned. * * * \author Benedikt Oswald, Patrick Leidenberger * * \warning None * * \attention * * \bug * * \todo */ #ifndef ENTITY_PARTITONING_HH #define ENTITY_PARTITONING_HH /** \brief Include standard header files. */ #include <vector> #include <iostream> #include <fstream> #include <map> #include <utility> #include <dune/common/version.hh> /** Include base class functionality for the communication interface */ #include <dune/grid/common/datahandleif.hh> /*********************************************************************************************/ /* calculate unique partitioning for all entities of a given codim in a given GridView, */ /* assuming they all have the same geometry, i.e. codim, type */ /*********************************************************************************************/ template<class GridView, int CODIM> class UniqueEntityPartition { private: /* A DataHandle class to cacluate the minimum of a std::vector which is accompanied by an index set */ template<class IS, class V> // mapper type and vector type class MinimumExchange : public Dune::CommDataHandleIF<MinimumExchange<IS,V>,typename V::value_type> { public: //! export type of data for message buffer typedef typename V::value_type DataType; //! returns true if data for this codim should be communicated bool contains (int dim, int codim) const { return(codim==CODIM); } //! returns true if size per entity of given dim and codim is a constant bool fixedsize (int dim, int codim) const { return(true); } /*! how many objects of type DataType have to be sent for a given entity * * Note: Only the sender side needs to know this size. */ template<class EntityType> size_t size (EntityType& e) const { return(1); } /*! pack data from user to message buffer */ template<class MessageBuffer, class EntityType> void gather (MessageBuffer& buff, const EntityType& e) const { buff.write(v_[indexset_.index(e)]); } /*! unpack data from message buffer to user n is the number of objects sent by the sender */ template<class MessageBuffer, class EntityType> void scatter (MessageBuffer& buff, const EntityType& e, size_t n) { DataType x; buff.read(x); if (x>=0) // other is -1 means, he does not want it { v_[indexset_.index(e)] = std::min(x,v_[indexset_.index(e)]); } } //! constructor MinimumExchange (const IS& indexset, V& v) : indexset_(indexset), v_(v) { ; } private: const IS& indexset_; V& v_; }; public: /** declare often uses types */ typedef typename GridView::Traits::template Codim<CODIM>::Iterator Iterator; typedef typename GridView::Traits::template Codim<CODIM>::Entity Entity; /*! \brief Constructor needs to know the grid function space */ UniqueEntityPartition (const GridView& gridview) : gridview_(gridview), assignment_(gridview.size(CODIM)), rank_(gridview_.comm().rank()) { /** extract types from the GridView data type */ typedef typename GridView::IndexSet IndexSet; // assign own rank to entities that I might have for(auto it = gridview_.template begin<0>();it!=gridview_.template end<0>(); ++it) #if DUNE_VERSION_NEWER(DUNE_GRID,2,4) for (int i=0; i<it->subEntities(CODIM); i++) #else for (int i=0; i<it->template count<CODIM>(); i++) #endif { assignment_[gridview_.indexSet().template subIndex(*it,i,CODIM)] = ( (it->template subEntity<CODIM>(i)->partitionType()==Dune::InteriorEntity) || (it->template subEntity<CODIM>(i)->partitionType()==Dune::BorderEntity) ) ? rank_ // set to own rank : - 1; // it is a ghost entity, I will not possibly own it. } /** exchange entity index through communication */ MinimumExchange<IndexSet,std::vector<int> > dh(gridview_.indexSet(),assignment_); gridview_.communicate(dh,Dune::All_All_Interface,Dune::ForwardCommunication); /* convert vector of minimum ranks to assignment vector */ for (size_t i=0; i<assignment_.size(); i++) assignment_[i] = (assignment_[i] == rank_) ? 1 : 0; } /** answer question if entity belongs to me, to this process */ bool owner(size_t i) { return assignment_[i]; } size_t numOwners() const { return std::accumulate(assignment_.begin(), assignment_.end(), 0); } /** answer question if entity belongs to me, to this process */ bool owner(const Entity& entity) { return(assignment_[gridview_.indexSet().template index(entity)]); } private: /** declare private data members */ const GridView& gridview_; std::vector<int> assignment_; int rank_; }; #endif /** ENTITY_PARTITONING_HH */