METISPartitioning.f90 Source File


Source Code

   subroutine GetMETISElementsPartition(mesh, no_of_domains, elementsDomain, nodesDomain, useWeights)
!
!     *********************************************************************
!        This subroutine performs the mesh partitioning using METIS
!     *********************************************************************
!        
      use HexMeshClass
      use SMConstants
      implicit none
      type(HexMesh), intent(in)              :: mesh
      integer,       intent(in)              :: no_of_domains
      integer,       intent(out)             :: elementsDomain(mesh % no_of_elements)
      integer,       intent(out)             :: nodesDomain(size(mesh % nodes))
      logical,       intent(in)              :: useWeights
!
!     ---------------
!     Local Variables
!     ---------------
!
      integer                :: i
      integer                :: ielem
      integer                :: ne                    ! # elements
      integer                :: nn                    ! # nodes
      integer                :: nvertex               ! # vertices per element
      integer, allocatable   :: eptr(:)               ! index in eind --> eptr(ne+1)
      integer, allocatable   :: eind(:)               ! vertices of each element   --> eind(nvertex*ne)
      integer, pointer       :: vwgt(:) => null()     ! vertices weights
      integer, pointer       :: vsize(:) => null()    !
      integer, parameter     :: ncommon = 4           ! common faces for dual nesh (4 for hexahedrals)
      real(kind=RP), pointer :: tpwgt(:) => null()    ! partitions' weights --> tpwgt(no_of_domains)
      integer, pointer       :: opts(:) => null()     ! metis options
      integer, parameter     :: metis_noptions = 39   ! number of metis options
      integer                :: objval                ! objective calculated value
      integer, parameter     :: MIN_EDGE_CUT = -1     ! option to minimize edge-cut
      integer, parameter     :: MIN_COMM_VOL = 1      ! option to minimize the communication volume
      integer, allocatable, target   :: weights(:)
#ifdef _HAS_METIS_
!
!     **************
!     Initialization    
!     **************
!
      ne = mesh % no_of_elements
      nn = size(mesh % nodes)
      nvertex = 8

      allocate(eptr(ne+1))
      allocate(eind(nvertex*ne))
!
!     Gather each element nodes: they are stored using C indexes (starting on 0)
!     -------------------------
      i = 1
      do ielem=1,ne
!
!        Save each element nodes
!        -----------------------
         eind(i:i+nvertex-1) = mesh % elements(ielem) % nodeIDs - 1
!
!        Save each element ID
!        --------------------
         eptr(ielem) = i - 1
         i = i + nvertex
      end do
!
!     Termination: set the last element position in the N+1 entry
!     -----------
      eptr(ne+1) = i - 1
!
!     *****************
!     Set METIS options
!     *****************
!
      allocate(opts(0:metis_noptions))
      call METIS_SetDefaultOptions(opts)
!
!     First option chooses the method: edge-cut / communication volume      
!     -------------------------------
      opts(1) = MIN_EDGE_CUT
!
!     Disable verbosity
!     -----------------
      opts(5) = 0
!
!     *******************************
!     Calculate weights based on NDOF
!     *******************************
!
      if (useWeights) then
          allocate(weights(ne))
          do ielem=1,ne
              weights(ielem) = product(mesh % elements(ielem) % Nxyz + 1)
          end do
          ! weights(ne+1) = product(mesh % elements(ielem) % Nxyz + 1)
          ! eptr(ne+1) = i - 1
          if (maxval(weights) .ne. minval(weights)) then
              vwgt => weights
          endif
      end if 
!     **********************
!     Perform the partitions
!     **********************
!
      call METIS_PartMeshDual(ne, nn,  eptr, eind,  vwgt, vsize, ncommon, no_of_domains, tpwgt,  opts,  objval, elementsDomain, nodesDomain)
!
!     Recover FORTRAN displacements by adding 1
!     -----------------------------------------
      elementsDomain = elementsDomain + 1
      nodesDomain = nodesDomain + 1
!
!     ****
!     Free
!     ****
!
      deallocate(eptr)
      deallocate(eind)
#endif
   end subroutine GetMETISElementsPartition