PROGRESS  master
prg_graph_mod.F90
Go to the documentation of this file.
1 
3 !
4 !
5 
7 
8  use bml
10  use omp_lib
11 
12  implicit none
13 
14  private !Everything is private by default
15 
16  integer, parameter :: dp = kind(1.0d0)
17 
18  public :: subgraph_t
19  public :: graph_partitioning_t
20  public :: prg_initsubgraph
21  public :: prg_destroysubgraph
25  public :: prg_equalpartition
26  public :: prg_equalgrouppartition
27  public :: prg_filepartition
28  public :: prg_fnormgraph
29  public :: prg_sedacspartition
30  public :: prg_setpartition
31 
34 
36  integer :: part
37 
39  integer :: hsize
40 
42  integer :: lsize
43 
45  integer :: llsize
46 
48  integer, allocatable :: core_halo_index(:)
49 
51  integer, allocatable :: nodeinpart(:)
52 
54  ! real(dp) :: vvx(100)
55 
56  end type subgraph_t
57 
60 
62  character(len=100) :: pname
63 
65  integer :: myrank
66 
68  integer :: totalprocs
69 
71  integer :: totalparts
72 
74  integer :: totalnodes
75 
77  integer :: totalnodes2
78 
80  integer :: globalpartmin
81 
83  integer :: globalpartmax
84 
86  integer :: globalpartextent
87 
89  integer, allocatable :: localpartmin(:)
90 
92  integer, allocatable :: localpartmax(:)
93 
95  integer, allocatable :: localpartextent(:)
96 
98  integer, allocatable :: order(:)
99 
101  integer, allocatable :: reorder(:)
102 
104  integer :: nparts
105 
109  integer :: nx, ny, nz
110 
112  integer, allocatable :: nnodesinpart(:)
113 
115  integer, allocatable :: nnodesinpartall(:)
116 
118  integer :: pp(100)
119 
121  integer :: maxiter
122 
124  real(dp) :: ehomo
125 
127  real(dp) :: elumo
128 
130  real(dp) :: mineval
131 
133  real(dp) :: maxeval
134 
136  real(dp) :: vv(100)
137 
139  type (subgraph_t), allocatable :: sgraph(:)
140 
141  end type graph_partitioning_t
142 
143 contains
144 
149  subroutine prg_initsubgraph(sg, pnum, hsize)
150 
151  type (subgraph_t), intent(inout) :: sg
152  integer, intent(in) :: pnum, hsize
153 
154  sg%part = pnum
155  sg%hsize = hsize
156  sg%lsize = 0
157  sg%llsize = 0
158 
159  allocate(sg%core_halo_index(hsize))
160 
161  end subroutine prg_initsubgraph
162 
165  subroutine prg_destroysubgraph(sg)
166 
167  type (subgraph_t), intent(inout) :: sg
168 
169  if (allocated(sg%core_halo_index)) deallocate(sg%core_halo_index)
170  if (allocated(sg%nodeInPart)) deallocate(sg%nodeInPart)
171 
172  end subroutine prg_destroysubgraph
173 
180  subroutine prg_initgraphpartitioning(gp, pname, np, nnodes, nnodes2)
181 
182  type (graph_partitioning_t), intent(inout) :: gp
183  character(len=*), intent(in) :: pname
184  integer, intent(in) :: np, nnodes, nnodes2
185 
186  integer :: nprocs, avgparts
187  integer :: i, it, last, nleft
188 
189  nprocs = getnranks()
190  gp%myRank = getmyrank()
191 
192  !! Global
193  gp%pname = pname
194  gp%totalProcs = nprocs
195  gp%totalParts = np
196  gp%totalNodes = nnodes
197  gp%totalNodes2 = nnodes2
198 
199  !! Global bounds
200  gp%globalPartMin = 1
201  gp%globalPartMax = np
202  gp%globalPartExtent = gp%globalPartMax - gp%globalPartMin + 1
203 
204  allocate(gp%localPartMin(nprocs))
205  allocate(gp%localPartMax(nprocs))
206  allocate(gp%localPartExtent(nprocs))
207 
208  ! Distribute parts evenly among ranks
209  avgparts = int(gp%totalParts / nprocs)
210  do i = 1, nprocs
211  gp%localPartExtent(i) = avgparts
212  enddo
213 
214  nleft = gp%totalParts - nprocs * avgparts
215  if (nleft .gt. 0) then
216  do i = 1, nleft
217  gp%localPartExtent(i) = gp%localPartExtent(i) + 1
218  enddo
219  endif
220 
221  gp%localPartMin(1) = 1
222  gp%localPartMax(1) = gp%localPartExtent(1)
223  do i = 2, nprocs
224  gp%localPartMin(i) = gp%localPartMax(i-1) + 1
225  gp%localPartMax(i) = gp%localPartMin(i) + gp%localPartExtent(i) - 1
226  enddo
227 
228  gp%nparts = gp%localPartExtent(gp%myRank+1)
229 
230  allocate(gp%nnodesInPart(np))
231  allocate(gp%nnodesInPartAll(np))
232  allocate(gp%sgraph(np))
233 
234  !! For reordering
235  allocate(gp%order(nnodes))
236  allocate(gp%reorder(nnodes))
237 
238  gp%maxIter = 0
239  gp%mineval = 0.0_dp
240  gp%maxeval = 0.0_dp
241 
242  if (printrank() .eq. 1) then
243  write(*,*)
244  write(*,*) "total procs = ", gp%totalProcs
245  write(*,*) "total nodes = ", gp%totalNodes
246  write(*,*) "total nodes2 = ", gp%totalNodes2
247  write(*,*) "total parts = ", gp%totalParts
248  write(*,*) "local parts = ", gp%nparts
249  write(*,*)
250  write(*,*) "globalPartMin = ", gp%globalPartMin, &
251  " globalPartMax = ", gp%globalPartMax, &
252  " globalPartExtent = ", gp%globalPartExtent
253 
254  do i = 1, nprocs
255  write(*,*) "rank = ", i-1, &
256  " localPartMin = ", gp%localPartMin(i), &
257  " localPartMax = ", gp%localPartMax(i), &
258  " localPartExtent = ", gp%localPartExtent(i)
259  enddo
260 
261  write(*,*)
262  endif
263 
264  end subroutine prg_initgraphpartitioning
265 
269 
270  type (graph_partitioning_t), intent(inout) :: gp
271 
272  integer :: i
273 
274  if (allocated(gp%localPartMin))deallocate(gp%localPartMin)
275  if (allocated(gp%localPartMax))deallocate(gp%localPartMax)
276  if (allocated(gp%localPartExtent))deallocate(gp%localPartExtent)
277 
278  if (allocated(gp%order))deallocate(gp%order)
279  if (allocated(gp%reorder))deallocate(gp%reorder)
280 
281  if(allocated(gp%nnodesInPart)) deallocate(gp%nnodesInPart)
282  if(allocated(gp%nnodesInPartAll))deallocate(gp%nnodesInPartAll)
283 
284  if (allocated(gp%sgraph)) then
285  do i = 1, gp%totalParts
286  call prg_destroysubgraph(gp%sgraph(i))
287  enddo
288  deallocate(gp%sgraph)
289  endif
290 
291  end subroutine prg_destroygraphpartitioning
292 
296 
297  type (graph_partitioning_t), intent(in) :: gp
298 
299  integer :: i, j
300 
301  if (gp%myRank .ne. 0) return
302 
303  ! Global data
304  write(*,*) ""
305  write(*,*) ""
306  write(*,*) "Graph partitioning:"
307  write(*,*) ""
308 
309  write(*,*) "name = ", gp%pname
310  write(*,*) "totalProcs = ", gp%totalProcs
311  write(*,*) "totalParts = ", gp%totalParts
312  write(*,*) "totalNodes = ", gp%totalNodes
313  write(*,*) "totalNodes2 = ", gp%totalNodes2
314  write(*,*) ""
315  write(*,*) "globalPartMin = ", gp%globalPartMin, &
316  " globalPartMax = ", gp%globalPartMax, &
317  " globalPartExtent = ", gp%globalPartExtent
318  write(*,*) ""
319 
320  ! Local data
321  write(*,*) "local parts = ", gp%nparts
322  do i = 1, gp%totalProcs
323  write(*,*) "rank = ", i-1, " localPartMin = ", gp%localPartMin(i), &
324  " localPartMax = ", gp%localPartMax(i), &
325  " localPartExtent = ", gp%localPartExtent(i)
326  enddo
327  write(*,*) ""
328 
329  ! SP2 data
330  write(*,*) "Number of iterations = ", gp%maxIter
331  write(*,*) "SP2 sequence = ", (gp%pp(i),i=1,gp%maxIter)
332  write(*,*) "mineval = ", gp%mineval , "maxeval = ", gp%maxeval
333  write(*,*) ""
334 
335  ! For each subgraph
336  do i = 1, gp%nparts
337  write(*,*) "part = ", i, " hsize = ", gp%sgraph(i)%hsize, &
338  " lsize = ", gp%sgraph(i)%lsize, &
339  " llsize = ", gp%sgraph(i)%llsize
340  write(*,*) ""
341  write(*,*) "Number of core nodes in part = ", gp%nnodesInPart(i)
342  write(*,*) "nodeInPart = ", &
343  (gp%sgraph(i)%nodeInPart(j), j=1,gp%nnodesInPart(i))
344  write(*,*) ""
345 
346  write(*,*) "core_halo_index = ", &
347  (gp%sgraph(i)%core_halo_index(j), j=1,gp%sgraph(i)%lsize)
348  write(*,*) ""
349 
350  enddo
351 
352  end subroutine prg_printgraphpartitioning
353 
354 
359  subroutine prg_equalpartition(gp, nodesPerPart, nnodes)
360 
361  type (graph_partitioning_t), intent(inout) :: gp
362  integer, intent(in) :: nodesperpart, nnodes
363 
364  integer :: i, j, it, np, psize
365  character(len=100) :: pname
366 
367  !! Init graph partitioning
368  if (nnodes.le.nodesperpart)then
369  np = 1
370  else
371  np = ceiling(real(nnodes) / real(nodesperpart))
372  endif
373  pname = '("equalParts")'
375  call prg_initgraphpartitioning(gp, pname, np, nnodes, nnodes)
376 
377  ! Assign node ids (mapped to orbitals as rows) to each node in each
378  ! partition
379  !$omp parallel do default(none) private(i) &
380  !$omp private(it,j,psize) &
381  !$omp shared(gp,nnodes,nodesPerPart)
382  do i = 1, gp%totalParts
383  call prg_initsubgraph(gp%sgraph(i), i, nnodes)
384  if ((i * nodesperpart) .le. nnodes) then
385  psize = nodesperpart
386  else
387  psize = nnodes - (nodesperpart * (i-1))
388  endif
389  allocate(gp%sgraph(i)%nodeInPart(psize))
390  do j = 1, psize
391  it = (i-1) * nodesperpart + j-1;
392  gp%sgraph(i)%nodeInPart(j) = it
393  enddo
394  gp%nnodesInPart(i) = psize
395  gp%nnodesInPartAll(i) = psize
396  enddo
397  !$omp end parallel do
398 
399  end subroutine prg_equalpartition
400 
401  function time2milliseconds() result(mls)
402 
403  real(8) :: mls
404  integer :: timevector(8)
405 
406  call date_and_time(values=timevector)
407  mls = timevector(5)*60*60*1000 + timevector(6)*60*1000 + &
408  timevector(7)*1000 + timevector(8)
409 
410  end function time2milliseconds
411 
412 
420  subroutine prg_setpartition(gp,whichParts,nparts,nnodes,verb)
421  implicit none
422  type (graph_partitioning_t), intent(inout) :: gp
423  integer, intent(in) :: nnodes, nparts
424  integer, allocatable, intent(inout) :: whichparts(:)
425  integer, optional, intent(in) :: verb
426  integer :: i, cnt, part, j, it, psize, cut, cutold, ac, nac
427  integer :: mdim, nodesperpart,tobedistributed,sumsizes,rem
428  character(len=100) :: pname
429  logical :: writeout
430 
431  if(present(verb))then
432  if(verb >= 1)then
433  write(*,*)"Setting partitioning in prg_setPartition..."
434  if(verb >= 2) writeout = .true.
435  endif
436  endif
437 
438  pname = '("setPartition")'
440  call prg_initgraphpartitioning(gp, pname, nparts, nnodes, nnodes)
441 
442  !Assign node ids to each node in each part
443  !$omp parallel do default(none) private(i) &
444  !$omp private(cnt,it,j,psize,part) &
445  !$omp shared(gp,nnodes,whichParts)
446  do i = 1, gp%totalParts
447  call prg_initsubgraph(gp%sgraph(i), i, nnodes)
448  psize = int(sum(whichparts, mask=(whichparts==i))/i)
449  allocate(gp%sgraph(i)%nodeInPart(psize))
450  cnt = 0
451  do j = 1,nnodes
452  part = whichparts(j)
453  if(part == i)then
454  cnt = cnt + 1
455  gp%sgraph(i)%nodeInPart(cnt) = j - 1
456  endif
457  enddo
458  gp%nnodesInPart(i) = psize
459  gp%nnodesInPartAll(i) = psize
460  enddo
461  !$omp end parallel do
462 
463 end subroutine prg_setpartition
472  subroutine prg_sedacspartition(gp,coords,whichParts_guess_saved,g_bml,nparts,nnodes,verb)
473  implicit none
474  type (graph_partitioning_t), intent(inout) :: gp
475  integer, intent(in) :: nnodes, nparts
476  integer, allocatable, intent(inout) :: whichparts_guess_saved(:)
477  integer, optional, intent(in) :: verb
478  integer :: i, cnt, part, j, it, psize, cut, cutold, ac, nac
479  integer :: mdim, nodesperpart,tobedistributed,sumsizes,rem
480  integer, allocatable :: whichparts(:)
481  integer, allocatable :: graph(:,:),degs(:)
482  real(kind(1.0)), allocatable :: row(:)
483  real(dp) :: bal,sumdegs, mlsi
484  real(dp), allocatable, intent (in) :: coords(:,:)
485  character(len=100) :: pname
486  type (bml_matrix_t), intent(in) :: g_bml
487  logical :: writeout
488 
489  if(present(verb))then
490  if(verb >= 1)then
491  write(*,*)"Doing SEDACS type of partitioning ..."
492  if(verb >= 2) writeout = .true.
493  endif
494  endif
495 
496  !If there is no guess we will do a "chunk/block" partitioning
497  !This initial pratitioning has all the nodes evenly distributed
498  !if(allocated(whichParts_guess_saved))deallocate(whichParts_guess_saved)
499  if(.not. allocated(whichparts_guess_saved))then
500  nodesperpart = int(nnodes/nparts)
501  rem = nnodes - nodesperpart*nparts
502  tobedistributed = rem
503 
504  pname = '("equalParts")'
506  call prg_initgraphpartitioning(gp, pname, nparts, nnodes, nnodes)
507 
508  sumsizes = 0
509  do i = 1, gp%totalParts
510  call prg_initsubgraph(gp%sgraph(i), i, nnodes)
511  if (sumsizes .le. nnodes - nodesperpart) then
512  psize = nodesperpart + min(tobedistributed,1)
513  tobedistributed = max(tobedistributed - 1,0)
514  else
515  psize = nnodes - sumsizes
516  endif
517  write(*,*)i,psize,sumsizes
518  allocate(gp%sgraph(i)%nodeInPart(psize))
519  do j = 1, psize
520  it = sumsizes + j-1;
521  gp%sgraph(i)%nodeInPart(j) = it
522  enddo
523  sumsizes = sumsizes + psize
524  gp%nnodesInPart(i) = psize
525  gp%nnodesInPartAll(i) = psize
526  enddo
527 
528  call prg_get_parts_indices(gp,nnodes,whichparts)
529  allocate(whichparts_guess_saved(nnodes))
530  else
531  allocate(whichparts(nnodes))
532  whichparts = whichparts_guess_saved
533 
534  endif
535 
536  !Get degrees and build 2D-sedacs-like graph
537  !In this case the degreess are saved in a separate array
538  mdim = bml_get_m(g_bml)
539  allocate(graph(nnodes,mdim))
540  allocate(degs(nnodes))
541  allocate(row(nnodes))
542  row = 0.0
543  degs = 0
544  do i = 1,nnodes
545  call bml_get_row(g_bml,i,row)
546  do j = 1,nnodes
547  if(row(j) .ge. 0.5)then
548  degs(i) = degs(i) + 1
549  graph(i,degs(i)) = j
550  endif
551  enddo
552  enddo
553  deallocate(row)
554 
555  sumdegs = sum(degs)
556  mlsi = time2milliseconds()
557  call prg_get_graphcut(whichparts,degs,graph,cut) !Get the initial cut
558  write(*,*)"Time for initial cut",time2milliseconds() - mlsi
559  if(writeout) write(*,*)"Iter, Cut, RelCut, and Bal",0,cut, cut/sumdegs,bal
560  cutold = cut
561  do i = 1,200
562  mlsi = time2milliseconds()
563  call do_flips_precomp(whichparts,coords,graph,g_bml,degs,nnodes,nparts,bal)
564  write(*,*)"Time for real flip",time2milliseconds() - mlsi
565  mlsi = time2milliseconds()
566  call prg_get_graphcut(whichparts,degs,graph,cut)
567  write(*,*)"Time for real cut",time2milliseconds() - mlsi
568  mlsi = time2milliseconds()
569  call prg_get_balancing(whichparts,nparts,bal)
570  write(*,*)"Time for real bal",time2milliseconds() - mlsi
571  if(writeout) write(*,*)"Iter, Cut, RelCut, and Bal",i,cut, cut/sumdegs,bal
572  if(cut >= cutold)then
573  exit
574  else
575  cutold = cut
576  endif
577  enddo
578 
579  deallocate(graph)
580  deallocate(degs)
581 
582  pname = '("sedacsPartition")'
584  call prg_initgraphpartitioning(gp, pname, nparts, nnodes, nnodes)
585 
586  !Assign node ids to each node in each part
587  !$omp parallel do default(none) private(i) &
588  !$omp private(cnt,it,j,psize,part) &
589  !$omp shared(gp,nnodes,whichParts)
590  do i = 1, gp%totalParts
591  call prg_initsubgraph(gp%sgraph(i), i, nnodes)
592  psize = int(sum(whichparts, mask=(whichparts==i))/i)
593  allocate(gp%sgraph(i)%nodeInPart(psize))
594  cnt = 0
595  do j = 1,nnodes
596  part = whichparts(j)
597  if(part == i)then
598  cnt = cnt + 1
599  gp%sgraph(i)%nodeInPart(cnt) = j - 1
600  endif
601  enddo
602  gp%nnodesInPart(i) = psize
603  gp%nnodesInPartAll(i) = psize
604  enddo
605  !$omp end parallel do
606 
607  whichparts_guess_saved = whichparts
608  deallocate(whichparts)
609 
610  end subroutine prg_sedacspartition
611 
612 
613  !! Do node partition flips with precomputed cuts.
614  !! \brief This function is a special case of do_flips where
615  !! the cuts around a node are precomputed for all possible
616  !! part index that same node could have. This will differ from the do_flips
617  !! since everytime there is a flip, there is no actualization of the cuts. The
618  !! price to pay is the need of more iterations until convergence.
619  !! \param whichPart partition indexing vector.
620  !! \param graph Graph to be partition. graph[i,0] = degree of node i.
621  !! graph[i,j>0] = the node conected to node i.
622  !! \param nnodes Number of nodes.
623  !! \param nparts Number of parts.
624  !! \return whichPartNew New partition indexing verctor.
625  !
626  subroutine do_flips_precomp(whichParts,coords,graph,adj,degs,nnodes,nparts,bal)
627  implicit none
628  integer, allocatable :: cutsI(:,:)
629  integer, intent(in) :: nnodes,nparts
630  integer, allocatable, intent(inout) :: graph(:,:),degs(:)
631  integer, allocatable, intent(inout) :: whichParts(:)
632  real(dp) :: bal
633  real(kind(1.0)), allocatable :: row(:)
634  type(bml_matrix_t) :: adj
635  integer :: i,j,deg,ind,ii,origCut,newCut, sumDeltaCut,ac,nac,newCut1
636  integer :: origCutI,newCutI,origCutJ,newCutJ
637  integer :: partIndexI, partIndexII,partIndexJ,k,cut,cutOld,newPartIndex,inDefect,discon
638  integer, allocatable :: momentI(:),momentsI(:,:),partSizes(:)
639  real(dp), allocatable, intent (in) :: coords(:,:)
640  logical :: disconnected, conditionToFlip,actualize
641 
642 
643  allocate(cutsi(nnodes,nparts))
644  cutsi = 0
645  sumdeltacut = 0
646  ac = 0
647  nac = 0
648  indefect = 0
649 
650  !$omp parallel do default(none) private(i) &
651  !$omp private(ii,deg,partIndexII,ind) &
652  !$omp shared(degs,graph,nnodes,whichParts,cutsI)
653  do i = 1,nnodes
654  deg = degs(i)
655  !Get the max cut a node could have
656  cutsi(i,:) = deg
657  !Lets look at every neighbor
658  do ii = 1,deg
659  ind = graph(i,ii)
660  partindexii = whichparts(ind)
661  !Everytime there is a neighbor in a certain part
662  !it will decrese the cut of I if I would be on that
663  !same part.
664  cutsi(i,partindexii) = cutsi(i,partindexii) - 1
665  enddo
666  enddo
667  !$omp end parallel do
668 
669  !Get sizes
670  allocate(row(nnodes))
671  allocate(partsizes(nparts))
672  partsizes = 0
673 
674  do i = 1,nnodes
675  partindexi = whichparts(i)
676  partsizes(partindexi) = partsizes(partindexi) + 1
677  enddo
678 
679  actualize = .true.
680 
681 ! !$omp parallel do default(none) private(i) &
682 ! !$omp private(row) &
683 ! !$omp private(j,partIndexI,partIndexJ,origCut,origCutI,origCutJ) &
684 ! !$omp private(newPartIndex,newCut,newCutI,newCutJ,ind,newCut1,inDefect) &
685 ! !$omp shared(adj,whichParts,cutsI,graph,partSizes,actualize) &
686 ! !$omp shared(degs,nnodes)
687  do i = 1,nnodes
688  call bml_get_row(adj,i,row)
689  if(cutsi(i,whichparts(i)) > 0)then
690  do j = i+1, nnodes
691  !do j = 1,nnodes
692  !if(row(j) > 0.5)then
693  if((whichparts(i) .ne. whichparts(j)))then
694  !conditionToFlip = .false.
695  !disconnected = .false.
696 
697  !Look at their neighbors and count the cuts
698  partindexi = whichparts(i)
699  partindexj = whichparts(j)
700  origcuti = cutsi(i,partindexi)
701  origcutj = cutsi(j,partindexj)
702 
703  newcuti = cutsi(i,partindexj)
704 
705  if(newcuti < degs(i))then
706  newcutj = cutsi(j,partindexi)
707  if(newcutj < degs(j))then
708 
709  !Now we know the cut when I is in partIndexI and J
710  origcut = origcuti + origcutj
711  newcut = newcuti + newcutj
712 
713  if((newcut <= origcut))then
714 
715  ! !$OMP CRITICAL
716  !ac = ac + 1
717  whichparts(i) = partindexj
718  whichparts(j) = partindexi
719 
720  !Actualizing possible cuts of neighbors of i and j
721  if(actualize)then
722  do ii = 1,degs(i)
723  ind = graph(i,ii)
724  !The neighs of i "if now they are in the "new color
725  !of i", their cut "at that color" will be decreased
726  !by one.
727  cutsi(ind,partindexj) = cutsi(ind,partindexj) - 1
728  cutsi(ind,partindexi) = cutsi(ind,partindexi) + 1
729  enddo
730  do ii = 1,degs(j)
731  ind = graph(j,ii)
732  !Same for the neighs of j
733  cutsi(ind,partindexi) = cutsi(ind,partindexi) - 1
734  cutsi(ind,partindexj) = cutsi(ind,partindexj) + 1
735  enddo
736  endif
737  ! !$OMP END CRITICAL
738  endif
739  endif
740  else
741  !nac = nac + 1
742  endif
743 
744  elseif(whichparts(i) .eq. whichparts(j))then
745  if(row(j) < 0.5)then
746  origcut = 0
747  newcut = 0
748  partindexi = whichparts(i)
749  partindexj = whichparts(j)
750 
751  origcut = cutsi(i,partindexi)
752  origcut = origcut + cutsi(j,partindexj)
753 
754  ! Change color of I
755  indefect = minloc(partsizes,dim=1)
756 
757  newpartindex = indefect
758 
759  newcut = cutsi(i,newpartindex)
760  newcut = newcut + cutsi(j,partindexj)
761 
762  newcut1 = cutsi(i,partindexi)
763  newcut1 = newcut1 + cutsi(j,newpartindex)
764 
765  if(newcut < origcut)then
766  whichparts(i) = newpartindex
767  whichparts(j) = partindexj
768  if(newpartindex .ne.partindexj)then
769  partsizes(newpartindex) = partsizes(newpartindex) + 1
770  partsizes(partindexj) = partsizes(partindexj) - 1
771  endif
772  !sumDeltaCut = newCut - origCut + sumDeltaCut
773  elseif(newcut1 < origcut)then
774  whichparts(i) = partindexi
775  whichparts(j) = newpartindex
776  if(newpartindex .ne. partindexi)then
777  partsizes(newpartindex) = partsizes(newpartindex) + 1
778  partsizes(partindexj) = partsizes(partindexj) - 1
779  endif
780  !sumDeltaCut = newCut1 - origCut + sumDeltaCut
781  else
782  whichparts(i) = partindexi
783  whichparts(j) = partindexj
784  endif
785  endif
786  else
787  cycle
788  endif
789  !endif
790  enddo
791  endif
792  enddo
793 ! !$omp end parallel do
794 
795  deallocate(partsizes)
796  deallocate(cutsi)
797  deallocate(row)
798 
799  end subroutine do_flips_precomp
800 
801 
802 
809  subroutine prg_get_balancing(whichParts,np,bal)
810  implicit none
811  integer, allocatable, intent(in) :: whichParts(:)
812  integer, allocatable :: partsSizes(:)
813  integer :: np, i, nnodes
814  real(dp), intent(out) :: bal
815 
816  allocate(partssizes(np))
817  nnodes = size(whichparts)
818  partssizes = 0
819 
820 ! !$omp parallel do default(none) private(i) &
821 ! !$omp private(nnodes) &
822 ! !$omp shared(whichParts,np) &
823 ! !$omp reduction(+:partsSizes)
824  do i = 1,nnodes
825  !write(*,*)"whichParts",i,nnodes,whichParts(i),np
826  if(whichparts(i) > np)then
827  write(*,*)"!!!ERROR: Part index",whichparts(i),&
828  "is larger than the total number of parts,",np
829  stop
830  endif
831  partssizes(whichparts(i)) = partssizes(whichparts(i)) + 1
832  enddo
833 ! !$omp end parallel do
834 
835  bal = real(maxval(partssizes))/real(minval(partssizes))
836  deallocate(partssizes)
837  end subroutine prg_get_balancing
838 
845  subroutine prg_get_parts_indices(gp,nnodes,whichParts)
846  type (graph_partitioning_t), intent(in) :: gp
847  integer, allocatable,intent(out) :: whichParts(:)
848  integer, intent(in) :: nnodes
849  integer :: i,j,k,kk,partIndex
850 
851  if(.not. allocated(whichparts)) allocate(whichparts(nnodes))
852 
853  partindex = 0
854  whichparts = 0
855 
856  !$omp parallel do default(none) private(i) &
857  !$omp private(k,kk) &
858  !$omp shared(gp,nnodes,whichParts)
859  do i = 1,gp%totalParts !Loop over parts
860  do j = 1,gp%nnodesInPart(i) !Loop over nodes in part
861  k = gp%sgraph(i)%nodeInPart(j)
862  kk = k + 1 !Indexig starts from 0 for all sgraphs (beacuse of historical reasons)
863  whichparts(kk) = i
864  enddo
865  enddo
866  !$omp end parallel do
867 
868  end subroutine prg_get_parts_indices
869 
870 
880  subroutine prg_get_graphcut(whichParts,degs,graph,cut)
881  integer, allocatable, intent(in) :: whichParts(:)
882  integer, intent(out) :: cut
883  integer :: nnodes,i,j,partIndexI,partIndexJ,k,kk
884  integer :: ind
885  integer, allocatable, intent(in) :: graph(:,:),degs(:)
886 
887  cut = 0
888  nnodes = size(whichparts)
889 
890  do i = 1,nnodes
891  !write(*,*)"graph",graph(i,1:degs(i))
892  partindexi = whichparts(i)
893  !Look at the neighbors and check if they are in different part
894  do j = 1,degs(i)
895  ind = graph(i,j)
896  partindexj = whichparts(ind)
897  if(int(partindexi - partindexj) .ne. 0)then
898  cut = cut + 1
899  endif
900  enddo
901  enddo
902  cut = 0.5_dp*cut !Because of the double counting
903 
904  end subroutine prg_get_graphcut
905 
906 
913  subroutine prg_equalgrouppartition(gp, hindex, ngroup, nodesPerPart, nnodes)
914 
915  type (graph_partitioning_t), intent(inout) :: gp
916  integer, intent(in) :: nodesperpart, nnodes, ngroup
917  integer, intent(in) :: hindex(2,ngroup)
918 
919  integer :: i, j, k, ll, np, psize, ind, ptotal
920  character(len=100) :: pname
921 
922  !! Init graph partitioning
923  np = ceiling(real(ngroup) / real(nodesperpart))
924  write(pname, '("equalGroupParts")')
926  call prg_initgraphpartitioning(gp, pname, np, ngroup, nnodes)
927 
928  !! Assign node ids (mapped to orbitals as rows) to each node in each
929  !! partition
930  !$omp parallel do default(none) &
931  !$omp private(i, j, k, ll, ind, psize, ptotal) &
932  !$omp shared(gp, hindex, nnodes, ngroup, nodesPerPart)
933  do i = 1, gp%totalParts
934  call prg_initsubgraph(gp%sgraph(i), i, nnodes)
935 
936  !! Figure out number of groups in part
937  if ((i * nodesperpart) .le. ngroup) then
938  psize = nodesperpart
939  else
940  psize = ngroup - (nodesperpart * (i-1))
941  endif
942 
943  !! Figure out total nodes/rows in part
944  ind = (i-1)*nodesperpart
945  ptotal = 0
946  do j = 1, psize
947  ptotal = ptotal + hindex(2, ind+j) - hindex(1, ind+j) + 1
948  enddo
949  gp%nnodesInPart(i) = ptotal
950  gp%nnodesInPartAll(i) = ptotal
951 
952  !! Enumerate all nodes in part
953  allocate(gp%sgraph(i)%nodeInPart(ptotal))
954  ll = 1
955  do j = 1, psize
956  do k = hindex(1, ind+j), hindex(2, ind+j)
957  gp%sgraph(i)%nodeInPart(ll) = k-1
958  ll = ll + 1
959  enddo
960  enddo
961  enddo
962  !$omp end parallel do
963 
964  ! do i = 1, gp%totalParts
965  ! write(*,*) "part ", i, ": ", gp%nnodesInPart(i), " nodes"
966  ! write(*,*) " ", &
967  ! (gp%sgraph(i)%nodeInPart(ll),ll = 1, gp%nnodesInPart(i))
968  ! enddo
969 
970  end subroutine prg_equalgrouppartition
971 
975  subroutine prg_filepartition(gp, partFile)
976 
977  type (graph_partitioning_t), intent(inout) :: gp
978  character(len=*), intent(in) :: partfile
979 
980  call prg_readpart(gp, partfile)
981 
982  end subroutine prg_filepartition
983 
987  subroutine prg_readpart(gp, partFile)
988 
989  character(len=*), intent(in) :: partFile
990  type (graph_partitioning_t), intent(inout) :: gp
991 
992  integer :: pfile
993  integer :: totalNodes, totalParts
994  integer :: i, j, ip, pnode
995  character(len=100) :: pname
996 
997  pfile = 10
998  open(unit=pfile, status='old', file=partfile)
999 
1000  read(pfile, *) pname
1001  read(pfile, *) totalnodes, totalparts
1002 
1003  call prg_initgraphpartitioning(gp, pname, totalparts, totalnodes, totalnodes)
1004 
1005  !! Read in part sizes
1006  read(pfile, *) (gp%nnodesInPartAll(i), i=1,gp%totalParts)
1007  do i = 1, gp%totalParts
1008  gp%nnodesInPart(i) = gp%nnodesInPartAll(i)
1009  enddo
1010 
1011  !! Read in nodes for each part
1012  do i = 1, gp%totalParts
1013  read(pfile, *) ip
1014  call prg_initsubgraph(gp%sgraph(i), i, totalnodes)
1015  allocate(gp%sgraph(i)%nodeInPart(gp%nnodesInPart(i)))
1016  read(pfile, *) (gp%sgraph(i)%nodeInPart(j),j=1,gp%nnodesInPart(i))
1017  do j = 1, gp%nnodesInPart(i)
1018  gp%sgraph(i)%nodeInPart(j) = gp%sgraph(i)%nodeInPart(j) + 1
1019  enddo
1020  enddo
1021 
1022  close(pfile)
1023 
1024  end subroutine prg_readpart
1025 
1028  subroutine prg_fnormgraph(gp)
1029 
1030  type(graph_partitioning_t), intent(inout) :: gp
1031 
1032  integer :: i, j
1033 #ifdef DO_MPI
1034  real(dp), allocatable :: slocal(:), sglobal(:)
1035 #endif
1036 
1037 #ifdef DO_MPI
1038  ! Sum traces from all parts on all ranks
1039  if (getnranks() .gt. 1) then
1040  allocate(slocal(gp%maxIter))
1041  allocate(sglobal(gp%maxIter))
1042  do i = 1, gp%maxIter
1043  slocal(i) = gp%vv(i)
1044  enddo
1045  call sumrealparallel(slocal, sglobal, gp%maxIter);
1046  do i = 1, gp%maxIter
1047  gp%vv(i) = sglobal(i)
1048  enddo
1049  deallocate(slocal, sglobal)
1050  endif
1051 #endif
1052 
1053  !! Take sqrt for fnorm per iter
1054  do i = 1, gp%maxIter
1055  gp%vv(i) = sqrt(gp%vv(i))
1056  enddo
1057 
1058  if (printrank() .eq. 1) then
1059  write(*,*)
1060  write(*,*) "prg_fnormGraph:"
1061  do i = 1, gp%maxIter
1062  write(*,*) "iter = ", i, " fnorm = ", gp%vv(i)
1063  enddo
1064  endif
1065 
1066  end subroutine prg_fnormgraph
1067 
1068 end module prg_graph_mod
The graph module.
integer, parameter dp
subroutine prg_get_parts_indices(gp, nnodes, whichParts)
Get part indices.
subroutine, public prg_initgraphpartitioning(gp, pname, np, nnodes, nnodes2)
Initialize graph partitioning.
subroutine, public prg_equalpartition(gp, nodesPerPart, nnodes)
Create equal graph partitions, based on number of rows/orbitals.
subroutine, public prg_initsubgraph(sg, pnum, hsize)
Initialize subgraph.
subroutine prg_get_balancing(whichParts, np, bal)
Get balancing.
subroutine, public prg_filepartition(gp, partFile)
Read graph partitions from a file, based on number of rows/orbitals.
subroutine do_flips_precomp(whichParts, coords, graph, adj, degs, nnodes, nparts, bal)
subroutine prg_readpart(gp, partFile)
Read parts (core) from part file.
subroutine, public prg_destroygraphpartitioning(gp)
Destroy graph partitioning.
subroutine, public prg_sedacspartition(gp, coords, whichParts_guess_saved, g_bml, nparts, nnodes, verb)
Create a partitioning based on node flips (as implemented in SEDACS - with several changes)
subroutine prg_get_graphcut(whichParts, degs, graph, cut)
Get graph cut.
subroutine, public prg_destroysubgraph(sg)
Destroy subgraph.
subroutine, public prg_fnormgraph(gp)
Accumulate trace norm across all subgraphs.
subroutine, public prg_equalgrouppartition(gp, hindex, ngroup, nodesPerPart, nnodes)
Create equal group graph partitions, based on number of atoms/groups.
subroutine, public prg_setpartition(gp, whichParts, nparts, nnodes, verb)
Create a partitioning based on an input assignment of atoms to parts.
real(8) function time2milliseconds()
subroutine, public prg_printgraphpartitioning(gp)
Print graph partitioning structure data.
The parallel module.
subroutine, public sumrealparallel(sendBuf, recvBuf, icount)
integer function, public printrank()
integer function, public getnranks()
integer function, public getmyrank()