metis_mod.F90       coverage:  0.00 %func     0.00 %block


     1) #ifdef HAVE_CONFIG_H
     2) #include "config.h"
     3) #endif
     4) 
     5) module metis_mod
     6)   use kinds, only : iulog
     7)   use parallel_mod, only : abortmp
     8)   implicit none
     9)   private 
    10)   integer, parameter :: VertexWeight = 1000
    11)   integer, parameter :: EdgeWeight = 1000
    12) 
    13)   public  :: genmetispart
    14)   private :: PartitionGraph
    15)   private :: CreateMeshGraph
    16)   private :: PrintMeshGraph
    17)   private :: genLocal2Global
    18)   private :: sort
    19) contains 
    20) 
    21)   subroutine genmetispart(GridEdge, GridVertex)
    22)     use gridgraph_mod, only : GridVertex_t, GridEdge_t, freegraph, createsubgridgraph, printgridvertex
    23)     use kinds, only : int_kind
    24)     use parallel_mod , only : iam, FrameWeight, PartitionForNodes
    25)     use dimensions_mod , only : nmpi_per_node, npart, nnodes, nelem
    26)     use control_mod, only:  partmethod
    27)     use params_mod, only : wrecursive
    28)     
    29)     implicit none
    30) 
    31)     type (GridVertex_t), intent(inout) :: GridVertex(:)
    32)     type (GridEdge_t),   intent(inout) :: GridEdge(:)
    33) 
    34)     integer , target, allocatable :: xadj(:),adjncy(:)    ! Adjacency structure for METIS
    35)     integer , target, allocatable :: vwgt(:),adjwgt(:)    ! Weights for the adj struct for METIS
    36) 
    37)     integer , target, allocatable :: xadj_nl(:),adjncy_nl(:)
    38)     integer , target, allocatable :: vwgt_nl(:),adjwgt_nl(:)
    39) 
    40)     type (GridVertex_t), allocatable   :: SubVertex(:)
    41) 
    42)     real(kind=4), allocatable   :: tpwgts(:)
    43)     real(kind=4)                :: tmp
    44) 
    45)     integer(kind=int_kind), allocatable          :: part(:)
    46)     integer, allocatable          :: part_nl(:),local2global_nl(:)
    47)     integer, allocatable          :: part_fl(:),local2global_fl(:)
    48) 
    49) 
    50)     integer, allocatable          :: cnt(:),newnum(:),oldnum(:)
    51) 
    52)     integer                       :: nelem_edge,numflag,edgecut,wgtflag
    53)     integer                       :: head_part,tail_part
    54)     integer                       :: options(5)
    55)     integer                       :: i,j,ii,ig,in,ip,if
    56)     integer                       :: nelem_nl,nelem_fl,newPartition
    57)     integer                       :: partitionmethod,numpartitions
    58)     integer                       :: nodes_per_frame
    59)     logical , parameter           :: Debug = .true.
    60)     real (kind=4)                 :: dummy(1) 
    61)     nelem_edge = SIZE(GridEdge) 
    62) 
    63)     print *, "nelem = ", nelem
    64)     print *, "nelem_edge = ", nelem_edge
    65)     allocate(tpwgts(npart))
    66)     allocate(part(nelem))
    67)     allocate(xadj(nelem+1))
    68)     allocate(vwgt(nelem))
    69)     allocate(adjncy(nelem_edge))
    70)     allocate(adjwgt(nelem_edge))
    71) 
    72)     if(Debug) write(iulog,*)'genmetispart: point #1'
    73)     ! =============================================
    74)     !   Generate Graph for METIS
    75)     ! =============================================
    76)     !DBG  call PrintGridVertex(GridVertex)
    77)     call CreateMeshGraph(GridVertex,xadj,adjncy,adjwgt)
    78)     ! Add weights to all the vertices
    79)     vwgt(:)=VertexWeight
    80)     if(Debug) write(iulog,*)'genmetispart: point #2'
    81) 
    82)     ! ====================================================
    83)     ! Some cruff from the Weighted partitioning 
    84)     ! experimentation... Remove soon 
    85)     ! ====================================================
    86)     do i=1,npart
    87)        tpwgts(i) = i
    88)     enddo
    89)     tmp = SUM(tpwgts)
    90)     tpwgts = tpwgts/tmp
    91)     if(Debug) write(iulog,*)'genmetispart: point #3'
    92) 
    93)     !================================================
    94)     !  Setup some options for the METIS partitioning
    95)     !================================================
    96)     options(1) = 0     ! Use Default METIS options
    97)     !  wgtflag    = 1     ! Weights on the Edges only
    98)     wgtflag    = 3     ! Weights on the edges and vertices
    99)     numflag    = 1     ! Use Fortran based numbering
   100) 
   101)     if(npart > 1) then 
   102) 
   103)        if (PartitionForNodes) then 
   104)           numPartitions   = nnodes
   105)           PartitionMethod = partmethod 
   106)        else
   107)           numPartitions   = npart
   108)           PartitionMethod = partmethod 
   109)        endif
   110)        !===========================================
   111)        !  Generate the METIS partitioning
   112)        !===========================================
   113)        if(iam .eq. 1) write(6,100) nelem,PartitionMethod,numPartitions
   114)        if(Debug) write(iulog,*)'genmetispart: point #4'
   115)        if (PartitionMethod==WRECURSIVE) then
   116)           call PartitionGraph(PartitionMethod,nelem,xadj,adjncy, &
   117)                vwgt,adjwgt,wgtflag,numflag, &
   118)                numPartitions,FrameWeight,options,edgecut,part)
   119)        else
   120)           ! FrameWeight has not been allocated in this case, so replace
   121)           ! with dummy argument: 
   122)           call PartitionGraph(PartitionMethod,nelem,xadj,adjncy, &
   123)                vwgt,adjwgt,wgtflag,numflag, &
   124)                numPartitions,dummy,options,edgecut,part)
   125)        endif
   126)        if(Debug) write(iulog,*)'genmetispart: point #5'
   127)        ! ===============================
   128)        !  Do not partitiion for nodes 
   129)        ! ===============================
   130)        !     PartitionForNodes=.FALSE.
   131)        if(PartitionForNodes)  then 
   132)           ! =========================================
   133)           ! Partition the graph on each compute node 
   134)           ! =========================================
   135)           if(nmpi_per_node .ne. 1 ) then 
   136) 
   137)              do ip = 1,nelem
   138)                 part(ip) = nmpi_per_node*(part(ip)-1) + 1
   139)              enddo
   140) 
   141)              if(Debug) write(iulog,*)'genmetispart: point #14'
   142) 
   143)              ! ====================
   144)              ! Loop over each node 
   145)              ! ====================
   146)              do in = 1,nnodes
   147) 
   148)                 newPartition = nmpi_per_node*(in -1) + 1
   149)                 nelem_nl = COUNT(part .eq. newPartition)
   150) 
   151)                 ! ===================================================
   152)                 ! Allocate all the memory for node level partitioning 
   153)                 ! ===================================================
   154) 
   155)                 allocate(local2global_nl(nelem_nl))
   156)                 allocate(part_nl(nelem_nl))
   157) 
   158)                 if(Debug) write(iulog,*)'genmetispart: point #15'
   159)                 allocate(xadj_nl(nelem_nl+1))
   160)                 allocate(vwgt_nl(nelem_nl))
   161)                 allocate(adjncy_nl(8*nelem_nl))
   162)                 allocate(adjwgt_nl(8*nelem_nl))
   163)                 adjncy_nl(:) = 0
   164)                 adjwgt_nl(:) = 0
   165)                 part_nl(:)   = 0
   166) 
   167)                 if(Debug) write(iulog,*)'genmetispart: point #16'
   168)                 !Add vertex weights to the subgraphs
   169)                 vwgt_nl(:) = VertexWeight
   170)                 allocate(SubVertex(nelem_nl))
   171) 
   172)                 ! =====================================
   173)                 !   Setup the index translation arrays
   174)                 ! =====================================
   175)                 call genLocal2Global(local2global_nl,part,newPartition)
   176) 
   177)                 if(Debug) write(iulog,*)'genmetispart: point #17'
   178)                 ! ======================================================
   179)                 ! Create a set of the Vertices that represent a subgraph 
   180)                 ! ======================================================
   181)                 if(Debug) write(iulog,*)'genmetispart: local2global_nl',local2global_nl
   182)                 if(Debug) call PrintGridVertex(GridVertex)
   183)                 call CreateSubGridGraph(GridVertex,SubVertex,local2global_nl)
   184)                 !JMD call CheckGridNeighbors(SubVertex)
   185)                 if(Debug) call PrintGridVertex(SubVertex)
   186)                 if(Debug) write(iulog,*)'genmetispart: point #18'
   187) 
   188)                 ! ==============================
   189)                 !  Convert grep to Metis format
   190)                 ! ==============================
   191)                 call CreateMeshGraph(SubVertex,xadj_nl,adjncy_nl,adjwgt_nl)
   192) 
   193)                 !debug     call PrintMetisgraph(xadj_nl,adjncy_nl,adjwgt_nl)
   194)                 ! =======================
   195)                 ! Partition the subgraph 
   196)                 ! =======================
   197)                 if(iam .eq. 1) write(6,100) nelem_nl,partmethod,nmpi_per_node
   198)                 call PartitionGraph(partmethod,nelem_nl,xadj_nl,adjncy_nl, &
   199)                      vwgt_nl,adjwgt_nl,wgtflag,numflag, &
   200)                      nmpi_per_node,tpwgts,options,edgecut,part_nl)
   201)                 if(Debug) write(iulog,*)'genmetispart: point #19'
   202) 
   203)                 ! ========================================================= 
   204)                 ! Apply the node partitioning the the overall partitioning 
   205)                 ! ========================================================= 
   206)                 do i=1,nelem_nl
   207)                    ig = local2global_nl(i)
   208)                    part(ig) = part(ig) + (part_nl(i)-1)
   209)                 enddo
   210) 
   211)                 ! ======================================
   212)                 ! Free up the temporaries that were used
   213)                 ! ======================================
   214)                 deallocate(local2global_nl)
   215)                 deallocate(part_nl)
   216)                 deallocate(xadj_nl)
   217)                 deallocate(vwgt_nl)
   218)                 deallocate(adjncy_nl)
   219)                 deallocate(adjwgt_nl)
   220) 
   221) 
   222)                 if(Debug) write(iulog,*)'genmetispart: point #20'
   223)                 call FreeGraph(SubVertex)
   224)                 deallocate(SubVertex)
   225)                 if(Debug) write(iulog,*)'genmetispart: point #21'
   226) 
   227)              enddo
   228) 
   229) 
   230)           endif  ! if node based partitioning 
   231) 
   232)        endif   ! if multilevel 
   233) 
   234)     else   ! else no partitioning needed
   235)        !======================================================================
   236)        ! It appears that Metis will set part(:) = 2 if nnodes == 1, 
   237)        ! which messes stuff up, so set it myself
   238)        !======================================================================
   239)        part(:)=1 
   240)     endif
   241) 
   242)     if(Debug) write(iulog,*)'genmetispart: point #22'
   243)     ! ===========================================
   244)     !  Add the partitioning information into the 
   245)     !    Grid Vertex and Grid Edge structures
   246)     ! ===========================================
   247) 
   248)     GridVertex(:)%processor_number = part
   249)     if(Debug) write(iulog,*)'genmetispart: point #23'
   250)     !=================================================
   251)     !  Output the partitioning information 
   252)     !=================================================
   253) #if 0
   254) 
   255)     write(iulog,*)'Metis Parititioning: '
   256)     write(iulog,*)part
   257) 
   258)     write(iulog,*)'Metis Parititioning: '
   259)     do k=1,nelem
   260)        write(iulog,*) k,part(k)
   261)     enddo
   262)     call abortmp(' at the end of genmetispart')
   263) 
   264)     if(OutputFiles) then
   265)        do k=1,nelem
   266)           write(10,*) GridVertex(k)%processor_number
   267)        end do
   268)        close(10)
   269)     end if
   270) #endif
   271) 
   272) 100 format("genmetispart:  Partitioning ",i4," elements, using method: ",i2," into ",i4," pieces")
   273) 
   274)   end subroutine genmetispart
   275) 
   276)   subroutine NewPartitionNumber(newnum,oldnum,cnt)
   277) 
   278)     implicit none
   279) 
   280)     integer, intent(in)           :: oldnum(:)
   281)     integer, intent(in)           :: cnt(:)
   282)     integer, intent(out)          :: newnum(:)
   283) 
   284)     integer                       :: i,n
   285) 
   286)     n = SIZE(cnt)
   287) 
   288)     newnum(1) = oldnum(1)
   289)     do i=2,n
   290)        newnum(i) = newnum(i-1) + cnt(i-1)
   291)     enddo
   292) 
   293)   end subroutine NewPartitionNumber
   294) 
   295)   subroutine genLocal2Global(local2Global,part,newP)
   296) 
   297)     implicit none 
   298) 
   299)     integer,intent(inout)      :: local2Global(:)
   300)     integer,intent(in)         :: part(:)
   301)     integer,intent(in)         :: newP
   302) 
   303)     integer                    :: i,ii,nelem
   304) 
   305)     nelem = SIZE(part)
   306)     ii = 1
   307)     do i=1,nelem
   308)        if( part(i) .eq. newP) then 
   309)           local2global(ii) = i
   310)           ii = ii + 1
   311)        endif
   312)     enddo
   313) 
   314)   end subroutine genLocal2Global
   315) 
   316)   subroutine PartitionGraph(partmethod,nelem,xadj,adjncy,vwgt,adjwgt, &
   317)        wgtflag,numflag,npart,tpwgts,options,edgecut,part)
   318) 
   319)     implicit none
   320) 
   321)     integer                               :: partmethod,nelem
   322)     integer                               :: xadj(:),adjncy(:)
   323)     integer                               :: vwgt(:),adjwgt(:)
   324)     integer                               :: wgtflag,numflag,edgecut
   325)     real(kind=4)                          :: tpwgts(:)
   326)     integer                               :: options(5)
   327)     integer                               :: npart
   328)     integer                               :: part(:)
   329) 
   330) 
   331) #ifdef _USEMETIS
   332) 
   333)     if (partmethod .eq. KWAY) then 
   334)        call metis_partgraphkway(nelem,xadj,adjncy, &
   335)             vwgt,adjwgt,wgtflag,numflag,npart,options,edgecut,part)
   336)     else if (partmethod .eq. RECURSIVE) then  
   337)        call METIS_PartGraphRecursive(nelem,xadj,adjncy, &
   338)             vwgt,adjwgt,wgtflag,numflag,npart,options,edgecut,part)
   339)     else if (partmethod .eq. WRECURSIVE) then  
   340)        call METIS_WPartGraphRecursive(nelem,xadj,adjncy, &
   341)             vwgt,adjwgt,wgtflag,numflag,npart,tpwgts,options,edgecut,part)
   342)     else if (partmethod .eq. VOLUME) then  
   343)        call METIS_PartGraphVKway(nelem,xadj,adjncy, &
   344)             vwgt,adjwgt,wgtflag,numflag,npart,options,edgecut,part)
   345)     endif
   346) #endif
   347) 
   348)   end subroutine PartitionGraph
   349) 
   350)   subroutine CreateMeshGraph(GridVertex,xadj,adjncy,adjwgt)
   351)     use gridgraph_mod, only : GridVertex_t, num_neighbors
   352)     use kinds, only : real_kind, int_kind
   353)     type (GridVertex_t), intent(in) :: GridVertex(:)
   354)     integer,intent(out)           :: xadj(:),adjncy(:),adjwgt(:)
   355) 
   356)     integer                         :: i,j,k,ii,jj
   357)     integer                         :: degree,nelem
   358)     !integer(kind=int_kind),allocatable  :: neigh_list(:),sort_indices(:)
   359)     !real(kind=REAL_KIND),allocatable    :: neigh_wgt(:)
   360)     integer(kind=int_kind) :: neigh_list(num_neighbors), &
   361)                               sort_indices(num_neighbors)
   362)     real(kind=REAL_KIND) :: neigh_wgt(num_neighbors)
   363)     integer                         :: max_neigh
   364) 
   365)     integer :: start, cnt
   366) 
   367)     nelem = SIZE(GridVertex)
   368) 
   369)     degree = 0
   370)     ii     = 1
   371) 
   372)     max_neigh = num_neighbors
   373) 
   374)     do i=1,nelem
   375)        print *, "i = ", i
   376)        xadj(i)      = ii
   377)        degree = 0
   378)        neigh_list=0
   379) 
   380) 
   381)        do j=1,num_neighbors
   382)           cnt = GridVertex(i)%nbrs_ptr(j+1) -  GridVertex(i)%nbrs_ptr(j) 
   383)           start =  GridVertex(i)%nbrs_ptr(j) 
   384)           print *, "j,cnt,start = ", j, cnt, start
   385)           do k=0, cnt-1
   386)              print *, "k,wgt = ", k, GridVertex(i)%nbrs_wgt(start+k)
   387)              if(GridVertex(i)%nbrs_wgt(start+k) .gt. 0) then 
   388)                 degree = degree + 1
   389)                 !adjncy(ii+degree-1)   = GridVertex(i)%nbrs(start+k)
   390)                 neigh_list(degree)    = GridVertex(i)%nbrs(start+k)
   391)                 !adjwgt(ii+degree-1)   = GridVertex(i)%nbrs_wgt(start+k)*EdgeWeight
   392)                 neigh_wgt(degree)     = GridVertex(i)%nbrs_wgt(start+k)*EdgeWeight
   393)              endif
   394)           enddo
   395)        enddo
   396)        if (degree > max_neigh) call abortmp( "number of neighbors found exceeds expected max")
   397) 
   398)        call sort(degree,neigh_list,sort_indices)
   399)        !degree       = COUNT(GridVertex(i)%nbrs_wgt(:) .gt. 0) 
   400)        ! Copy the sorted adjncy list in
   401)        do j=1,degree
   402)           adjncy(ii+j-1) = neigh_list(sort_indices(j))
   403)           adjwgt(ii+j-1) = neigh_wgt(sort_indices(j))
   404)        enddo
   405)        print *, "degree = ", degree
   406)        !print *, "wgts = ", GridVertex(i)%nbrs_wgt(:) 
   407)        ii           = ii + degree
   408)     enddo
   409)     xadj(nelem+1)     = ii
   410)     !open(unit=11, file="csr.txt")
   411)     !write(11,*) xadj
   412)     !write(11,*) adjncy
   413)     !write(11,*) adjwgt
   414)     !close(11)
   415) 
   416)   end subroutine CreateMeshGraph
   417) 
   418)   subroutine sort(n,list,index)
   419)     use kinds, only : int_kind
   420)     implicit none
   421)     integer, intent(in) :: n
   422)     integer(kind=int_kind), intent(in) :: list(n)
   423)     integer(kind=int_kind), intent(inout) :: index(n)
   424) 
   425)     ! Local variables
   426)     integer :: i,iloc,nct,ii,lmax,lmin
   427)     logical :: msk(n)
   428)     logical,parameter  :: Debug =.FALSE.
   429) 
   430)     msk=.TRUE.
   431)     if(Debug) write(iulog,*)'sort: point #1'
   432)     nct=0
   433)     do i=1,n
   434)        if(list(i) .eq. 0) then 
   435)           msk(i)=.FALSE.
   436)        else
   437)           nct = nct + 1
   438)        endif
   439)     enddo
   440)     if(Debug) write(iulog,*)'sort: point #2   list: ',list
   441)     if(Debug) write(iulog,*)'sort: point #2.1 msk: ',msk
   442) 
   443)     lmax=maxval(list)
   444)     do i=1,nct
   445)        if(Debug) write(iulog,*)'sort: point #3'
   446) 
   447)        !     pgf90 Rel 3.1-4i:  minloc() with mask is buggy   
   448)        !     iloc = minloc(list,dim=1,mask=msk)
   449)        lmin=lmax
   450)        iloc=-1      
   451)        do ii=1,n
   452)           if (msk(ii) .and. list(ii)<= lmin) iloc=ii
   453)        enddo
   454)        if (iloc==-1) call abortmp( "sort() error")
   455) 
   456)        index(i)=iloc
   457)        if(Debug) write(iulog,*)'sort: point #4'
   458)        msk(iloc)=.FALSE.
   459)        if(Debug) write(iulog,*)'sort: point #5'
   460)        if(Debug) write(iulog,*)'sort: i, msk',i,msk
   461)     enddo
   462)     if(Debug) write(iulog,*)'sort: point #6'
   463)     !DBG   write(iulog,*)'sort: list is:',list
   464)     !DBG   write(iulog,*)'sort: index is:',index
   465)     !DBG   stop
   466) 
   467)   end subroutine sort
   468)   !------------------------------------------------------------------------
   469)   subroutine PrintMeshGraph(xadj,adjncy,adjwgt)
   470)     integer, intent(in)       :: xadj(:),adjncy(:),adjwgt(:)
   471)     integer  :: nelem,nadj,i,j
   472) 
   473)     nelem = SIZE(xadj)
   474) 
   475)     do i=1,nelem
   476)        write(iulog,*)'xadj(i):= ',xadj(i)
   477)     enddo
   478)     nadj = xadj(nelem)
   479)     do j=1,nadj-1
   480)        write(iulog,*)'{adjncy(i),adjwgt(i)}:=',adjncy(j),adjwgt(j)
   481)     enddo
   482) 
   483)   end subroutine PrintMeshGraph
   484)   !------------------------------------------------------------------------
   485) end module metis_mod

generated by
Intel(R) C++/Fortran Compiler code-coverage tool
Web-Page Owner: Nobody