Skip to content
Snippets Groups Projects
globalindex.hh 13.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • /** \file
    *
    *  \brief Implement the functionality that provides a globally unique index for
    *         all kinds of entities of a Dune grid. Such functionality is relevant
    *         for a number of cases:
    *         e.g. to map a degree of freedom associated wit an entity to its
    *         location in a global matrix or global vector; e.g. to associate data
    *         with entities in an adaptive mesh refinement scheme.
    *
    *  Nota bene: the functionality to provide a globally unique index for an entity, over all
    *             processes in a distributed memory parallel compute environment is at present
    *  not available in the Dune framework; therefore, we implement such functionality in a class
    *  that is templatized by the GridView Type and the codimension of the entity for which the
    *  globaly unique index shall be computed.
    *
    *  Method: (1) we use the UniqueEntityPartition class that reports if a specific entity belongs
    *              to a specific process;
    *
    *          (2) we compute the number of entities that are owned by the specific process;
    *
    *          (3) we communicate the index of entities that are owned by the process to processes
    *              that also contain these entities but do not own them, so that on a non-owner process
    *              we have information on the index of the entity that it got from the owner-process;
    *
    *  Thus, we can access the same element in a global, distributed matrix that is managed
    *  by all processes; a typical case would be using matrix and vector routines from the PETSc
    *  or trilinos parallel linear algebra packages for distributed memory parallel computers.
    *
    *  Copyright by Benedikt Oswald and Patrick Leidenberger, 2002-2010. All rights reserved.
    *
    *  \author    Benedikt Oswald, Patrick Leidenberger
    *
    *  \warning   None
    *
    *  \attention globally unique indices are ONLY provided for entities of the
    *             InteriorBorder_Partition type, NOT for the Ghost_Partition type !!!
    */
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
    #ifndef GLOBALUNIQUEINDEX_HH_
    #define GLOBALUNIQUEINDEX_HH_
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
    /** \brief Include standard header files. */
    #include <vector>
    #include <iostream>
    #include <fstream>
    #include <map>
    #include <utility>
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
    /** include base class functionality for the communication interface */
    #include <dune/grid/common/datahandleif.hh>
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
    // Include proprietary header files.
    #include "uniqueentitypartition.hh"
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
    #include <dune/common/version.hh>
    
    
    /** include parallel capability */
    #if HAVE_MPI
      #include <dune/common/parallel/mpihelper.hh>
    #endif
    
    /*********************************************************************************************/
    /* calculate globally unique index over all processes in a Dune grid that is distributed     */
    /* over all the processes in a distributed memory parallel environment, 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 GlobalUniqueIndex
    {
    private:
      /** define data types */
      typedef typename GridView::Grid Grid;
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
      typedef typename GridView::Grid::GlobalIdSet GlobalIdSet;
      typedef typename GridView::Grid::GlobalIdSet::IdType IdType;
    
      typedef typename GridView::Traits::template Codim<0>::Iterator Iterator;
    
      typedef typename GridView::Traits::template Codim<CODIM>::Entity Entity;
    
    #if HAVE_MPI
      /** define data type related to collective communication */
      typedef typename Dune::template CollectiveCommunication<MPI_Comm> CollectiveCommunication;
    #else
      typedef typename Grid::CollectiveCommunication CollectiveCommunication;
    #endif
    
    
    Oliver Sander's avatar
    Oliver Sander committed
      typedef std::map<IdType,int> MapId2Index;
    
      typedef std::map<int,int>    IndexMap;
    
      typedef UniqueEntityPartition<GridView,CODIM> UniqueEntityPartitionType;
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
    private:
      /* A DataHandle class to communicate the global index from the
       * owning to the non-owning entity; the class is based on the MinimumExchange
       * class in the parallelsolver.hh header file.
       */
      template<class GlobalIdSet, class IdType, class Map, typename ValueType>
      class IndexExchange           :       public Dune::CommDataHandleIF<IndexExchange<GlobalIdSet,IdType,Map,ValueType>,ValueType>
      {
      public:
        //! returns true if data for this codim should be communicated
        bool contains (int dim, int codim) const
        {
          return(codim==CODIM);
        }
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
        //! returns true if size per entity of given dim and codim is a constant
        bool fixedsize (int dim, int codim) const
        {
          return(true);
        }
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
        /*! 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);
        }
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
        /*! pack data from user to message buffer */
        template<class MessageBuffer, class EntityType>
        void gather (MessageBuffer& buff, const EntityType& e) const
        {
          IdType id=globalidset_.id(e);
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
          buff.write((*mapid2entity_.find(id)).second);
        }
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
        /*! unpack data from message buffer to user
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
          n is the number of objects sent by the sender
        */
        template<class MessageBuffer, class EntityType>
        void scatter (MessageBuffer& buff, const EntityType& entity, size_t n)
        {
          ValueType x;
          buff.read(x);
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
          /** only if the incoming index is a valid one,
    	  i.e. if it is greater than zero, will it be
    	  inserted as the global index; it is made
    	  sure in the upper class, i.e. GlobalUniqueIndex,
    	  that non-owning processes use -1 to mark an entity
    	  that they do not own.
          */
          if(x >= 0)
    	{
    	  IdType id = globalidset_.id(entity);
    	  mapid2entity_.erase(id);
    	  mapid2entity_.insert(std::make_pair(id,x));
    
    	  const int lindex = indexSet_.index(entity);
    	  localGlobalMap_[lindex] = x;
    	  globalLocalMap_[x]      = lindex;
    	}
        }
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
        //! constructor
        IndexExchange (const GlobalIdSet& globalidset, Map& mapid2entity, int &rank,
    		   const typename GridView::IndexSet& localIndexSet, IndexMap& localGlobal, IndexMap& globalLocal)
          : globalidset_(globalidset),
    	mapid2entity_(mapid2entity),
    	rank_(rank),
    	indexSet_(localIndexSet),
    	localGlobalMap_(localGlobal),
    	globalLocalMap_(globalLocal)
        {
        }
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
      private:
        const GlobalIdSet& globalidset_;
        Map& mapid2entity_;
        int& rank_;
    
        const typename GridView::IndexSet& indexSet_;
        IndexMap& localGlobalMap_;
        IndexMap& globalLocalMap_;
      };
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
    public:
      /**********************************************************************************************************************/
      /* \brief class constructor - when the class is instantiated by passing a const reference to a GridView object,       */
      /*                      we calculate the complete set of global unique indices so that we can then                    */
      /*  later query the global index, by directly passing the entity in question: then the respective global              */
      /*  index is returned.                                                                                                */
      /**********************************************************************************************************************/
      GlobalUniqueIndex(const GridView& gridview)
        :       gridview_(gridview),
    
    Oliver Sander's avatar
    Oliver Sander committed
    	    uniqueEntityPartition_(gridview)
    
    Oliver Sander's avatar
    Oliver Sander committed
        int rank = gridview.comm().rank();
        int size = gridview.comm().size();
    
    
        nLocalEntity_=0;
        nGlobalEntity_=0;
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
        nLocalEntity_ = uniqueEntityPartition_.numOwners();
    
        /** compute the global, non-redundant number of entities, i.e. the number of entities in the set
         *  without double, aka. redundant entities, on the interprocessor boundary via global reduce. */
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
        const CollectiveCommunication& collective = gridview_.comm();
        nGlobalEntity_ = collective.template sum<int>(nLocalEntity_);
    
        /** communicate the number of locally owned entities to all other processes so that the respective offset
         *  can be calculated on the respective processor; we use the Dune mpi collective communication facility
         *  for this; first, we gather the number of locally owned entities on the root process and, second, we
         *  broadcast the array to all processes where the respective offset can be calculated. */
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
    Oliver Sander's avatar
    Oliver Sander committed
        std::vector<int> offset(size);
        std::fill(offset.begin(), offset.end(), 0);
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
        /** gather number of locally owned entities on root process */
    
    Oliver Sander's avatar
    Oliver Sander committed
        collective.template gather<int>(&nLocalEntity_,offset.data(),1,0);
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
        /** broadcast the array containing the number of locally owned entities to all processes */
    
    Oliver Sander's avatar
    Oliver Sander committed
        collective.template broadcast<int>(offset.data(),size,0);
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
    Oliver Sander's avatar
    Oliver Sander committed
        indexOffset_.resize(size,0);
    
    
        for(unsigned int ii=0; ii<indexOffset_.size(); ++ii)
    	for(unsigned int jj=0; jj < ii; ++jj)
    	    indexOffset_[ii] += offset[jj];
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
        /** compute globally unique index over all processes; the idea of the algorithm is as follows: if
         *  an entity is owned by the process, it is assigned an index that is the addition of the offset
         *  specific for this process and a consecutively incremented counter; if the entity is not owned
         *  by the process, it is assigned -1, which signals that this specific entity will get its global
         *  unique index through communication afterwards;
         *
         *  thus, the calculation of the globally unique index is divided into 2 stages:
         *
         *  (1) we calculate the global index independently;
         *
         *  (2) we achieve parallel adjustment by communicating the index
         *      from the owning entity to the non-owning entity.
         *
         */
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
        /** 1st stage of global index calculation: calculate global index for owned entities */
    
    Oliver Sander's avatar
    Oliver Sander committed
         /** intialize map that stores an entity's global index via it's globally unique id as key */
        MapId2Index globalIndex;
    
    
        const typename GridView::IndexSet& indexSet = gridview.indexSet();
    
        const GlobalIdSet &globalIdSet=gridview_.grid().globalIdSet();  /** retrieve globally unique Id set */
    
    Oliver Sander's avatar
    Oliver Sander committed
        int myoffset=indexOffset_[rank];
    
    
        int globalcontrib=0;    /** initialize contribution for the global index */
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
        std::vector<bool> firstTime(gridview_.size(CODIM));
        std::fill(firstTime.begin(), firstTime.end(), true);
    
        for(Iterator iter = gridview_.template begin<0>();iter!=gridview_.template end<0>(); ++iter)
        {
    
    #if DUNE_VERSION_NEWER(DUNE_GRID,2,4)
          for (size_t i=0; i<iter->subEntities(CODIM); i++)
    #else
    
          for (size_t i=0; i<iter->template count<CODIM>(); i++)
    
            IdType id=globalIdSet.subId(*iter,i,CODIM);                 /** retrieve the entity's id */
    
            int idx = gridview_.indexSet().subIndex(*iter,i,CODIM);
    
            if (! firstTime[idx] )
              continue;
    
            firstTime[idx] = false;
    
            if(uniqueEntityPartition_.owner(idx) == true)  /** if the entity is owned by the process, go ahead with computing the global index */
            {
              const int gindex = myoffset + globalcontrib;    /** compute global index */
              globalIndex.insert(std::make_pair(id,gindex)); /** insert pair (key, value) into the map */
    
              const int lindex = idx;
              localGlobalMap_[lindex] = gindex;
              globalLocalMap_[gindex] = lindex;
    
              globalcontrib++;                                /** increment contribution to global index */
            }
            else /** if entity is not owned, insert -1 to signal not yet calculated global index */
            {
              globalIndex.insert(std::make_pair(id,-1));
            }
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
        /** 2nd stage of global index calculation: communicate global index for non-owned entities */
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
        // Create the data handle and communicate.
    
    Oliver Sander's avatar
    Oliver Sander committed
        IndexExchange<GlobalIdSet,IdType,MapId2Index,int> dataHandle(globalIdSet,globalIndex,rank,indexSet,localGlobalMap_,globalLocalMap_);
    
        gridview_.communicate(dataHandle, Dune::All_All_Interface, Dune::ForwardCommunication);
      }
    
      /** \brief Given a local index, retrieve its index globally unique over all processes. */
      int globalIndex(const int& localIndex) const {
        return localGlobalMap_.find(localIndex)->second;
      }
    
      int localIndex(const int& globalIndex) const {
        return globalLocalMap_.find(globalIndex)->second;
      }
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
      int globalIndex(const typename GridView::template Codim<CODIM>::Entity& entity) const
      {
        return localGlobalMap_.find(gridview_.indexSet().index(entity))->second;
      }
    
      int localIndex(const typename GridView::template Codim<CODIM>::Entity& entity) const {
        return gridview_.indexSet().index(entity);
      }
    
    
      inline unsigned int nGlobalEntity() const
      {
        return(nGlobalEntity_);
      }
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
      inline unsigned int nOwnedLocalEntity() const
      {
        return(nLocalEntity_);
      }
    
      const GridView& getGridView() const {
        return gridview_;
      }
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
    protected:
      /** store data members */
      const GridView gridview_;                                                       /** store a const reference to a gridview */
      UniqueEntityPartitionType uniqueEntityPartition_;
      int nLocalEntity_;                                                      /** store number of entities that are owned by the local */
      int nGlobalEntity_;                                             /** store global number of entities, i.e. number of entities without rendundant entities on interprocessor boundaries */
      std::vector<int> indexOffset_;                          /** store offset of entity index on every process */
    
      IndexMap localGlobalMap_;
      IndexMap globalLocalMap_;
    };
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    
    #endif /* GLOBALUNIQUEINDEX_HH_ */