51  integer, 
parameter :: &
 
   56  integer, 
parameter :: &
 
   73  subroutine mesh_partition(mesh, namespace, space, lapl_stencil, vsize)
 
   74    type(mesh_t),      
intent(inout)  :: mesh
 
   75    type(namespace_t), 
intent(in)     :: namespace
 
   76    class(space_t),    
intent(in)     :: space
 
   77    type(stencil_t),   
intent(in)     :: lapl_stencil
 
   78    integer,           
intent(in)     :: vsize
 
   84    integer(int64)          :: ivtmp, inb
 
   85    integer              :: ix(space%dim), jx(space%dim)
 
   90    integer(imetis)              :: ne_global
 
   91    integer(imetis)              :: nv_global
 
  101    integer(imetis), 
allocatable :: xadj_global(:)
 
  102    integer(imetis), 
allocatable :: adjncy_global(:)
 
  103    integer(imetis), 
allocatable :: adjncy(:)
 
  104    integer(imetis), 
allocatable :: xadj(:)
 
  106    integer(imetis), 
allocatable :: options(:)
 
  108    integer(imetis)              :: edgecut
 
  110    real(real32),        
allocatable :: tpwgts(:)
 
  113    integer, 
allocatable :: rcounts(:)
 
  114    integer(imetis)      :: tmp
 
  115    integer(imetis), 
allocatable :: rdispls(:)
 
  116    integer(imetis), 
allocatable :: part(:)
 
  117    integer(imetis), 
allocatable :: part_global(:)
 
  118    integer(imetis), 
allocatable :: vtxdist(:)
 
  120    type(stencil_t) :: stencil
 
  121    integer :: stencil_to_use, default_method, method
 
  123    integer, 
parameter   :: STAR = 1, laplacian = 2
 
  124    integer(imetis), 
allocatable :: istart(:)
 
  125    integer, 
allocatable :: lsize(:)
 
  127    integer :: default, ierr
 
  131    if (mesh%np_global == 0) 
then 
  132      message(1) = 
'The mesh is empty and cannot be partitioned.' 
  154    call parse_variable(namespace, 
'MeshPartitionPackage', default, library)
 
  156#if !defined(HAVE_METIS) 
  157    if (library == metis) 
then 
  158      message(1) = 
'METIS was requested, but Octopus was compiled without it.' 
  162#if !defined(HAVE_PARMETIS) 
  164      message(1) = 
'PARMETIS was requested, but Octopus was compiled without it.' 
  184    call parse_variable(namespace, 
'MeshPartitionStencil', star, stencil_to_use)
 
  186    if (stencil_to_use == star) 
then 
  188    else if (stencil_to_use == laplacian) 
then 
  195    if (mesh%np_global > huge(nv_global)) 
then 
  196      message(1) = 
"Error: too many grid points for this version of metis/parmetis." 
  197      message(2) = 
"Please use the 64-bit version." 
  205    npart = mesh%mpi_grp%size
 
  206    ipart = mesh%mpi_grp%rank + 1
 
  208    safe_allocate(istart(1:npart))
 
  209    safe_allocate(lsize(1:npart))
 
  210    safe_allocate(vtxdist(1:npart+1))
 
  212    assert(ivtmp <= huge(0_imetis))
 
  216    safe_allocate(part(1:nv))
 
  222      call mesh%mpi_grp%allgather(nv, 1, mpi_integer, lsize(1), 1, mpi_integer)
 
  224      vtxdist(1:npart) = istart(1:npart)
 
  225      vtxdist(npart+1) = nv_global + 1
 
  229      safe_allocate(xadj(1:nv+1))
 
  230      safe_allocate(adjncy(1:
i4_to_imetis(stencil%size - 1)*nv))
 
  233      do iv = 1, lsize(ipart)
 
  240        do jp = 1, stencil%size
 
  241          if (jp == stencil%center) cycle
 
  245          jx = ix + stencil%points(:, jp)
 
  247          if (all(jx >= mesh%idx%nr(1, :)) .and. all(jx <= mesh%idx%nr(2, :))) 
then 
  251            if (inb /= 0 .and. inb <= nv_global) 
then 
  270      if (
debug%info .or. library == metis) 
then 
  272        safe_allocate(rcounts(1:npart))
 
  273        safe_allocate(rdispls(1:npart))
 
  275        safe_allocate(xadj_global(1:nv_global + 1))
 
  277        rcounts(1:npart) = lsize(1:npart)
 
  278        rdispls(1:npart) = vtxdist(1:npart) - 1
 
  279        call mesh%mpi_grp%allgatherv(xadj(2:), lsize(ipart), 
mpi_metis_int, &
 
  282          do iv = 1, lsize(jpart)
 
  283            xadj_global(istart(jpart) + iv) = xadj_global(istart(jpart) + iv) + xadj_global(istart(jpart)) - 1
 
  287        ne_global = xadj_global(nv_global + 1)
 
  288        safe_allocate(adjncy_global(1:ne_global))
 
  290          rdispls(jpart) = xadj_global(vtxdist(jpart)) - 1
 
  291          tmp = xadj_global(vtxdist(jpart+1)) - 1 - rdispls(jpart)
 
  292          assert(tmp < huge(0_int32))
 
  295        assert(xadj(nv+1)-1 < huge(0_int32))
 
  299        safe_deallocate_a(rcounts)
 
  300        safe_deallocate_a(rdispls)
 
  306        message(1) = 
'Info: Adjacency lists of the graph representing the grid' 
  307        message(2) = 
'Info: are stored in debug/mesh_partition/mesh_graph.txt.' 
  308        message(3) = 
'Info: Compatible with METIS programs pmetis and kmetis.' 
  309        message(4) = 
'Info: First line contains number of vertices and edges.' 
  310        message(5) = 
'Info: Edges are not directed and appear twice in the lists.' 
  313          call io_mkdir(
'debug/mesh_partition', namespace)
 
  314          iunit = 
io_open(
'debug/mesh_partition/mesh_graph.txt', namespace, action=
'write')
 
  315          write(iunit, *) nv_global, ne_global/2
 
  317            write(iunit, *) adjncy_global(xadj_global(iv):xadj_global(iv+1) - 1)
 
  321        message(1) = 
"Info: Done writing mesh_graph.txt." 
  327      safe_allocate(tpwgts(1:vsize))
 
  328      tpwgts(1:vsize) = real(1.0, real32)/real(vsize, real32)
 
  330      select case (library)
 
  332        safe_allocate(options(1:40))
 
  342          default_method = 
graph 
  357        call parse_variable(namespace, 
'MeshPartition', default_method, method)
 
  359        safe_allocate(part_global(1:nv_global))
 
  364          message(1) = 
'Info: Using METIS 5 multilevel recursive bisection to partition the mesh.' 
  368            i4_to_imetis(vsize), tpwgts(1), 1.01_4, options(1), edgecut, part_global(1))
 
  372          message(1) = 
'Info: Using METIS 5 multilevel k-way algorithm to partition the mesh.' 
  376            i4_to_imetis(vsize), tpwgts(1), 1.01_4, options(1), edgecut, part_global(1))
 
  380          message(1) = 
'Selected partition method is not available in METIS 5.' 
  384        part(1:nv) = part_global(istart(ipart):istart(ipart) + nv - 1)
 
  386        safe_deallocate_a(options)
 
  387        safe_deallocate_a(part_global)
 
  391        safe_allocate(options(1:3))
 
  394        write(
message(1),
'(a)') 
'Info: Using ParMETIS multilevel k-way algorithm to partition the mesh.' 
  400          1_imetis, 
i4_to_imetis(mesh%mpi_grp%size), tpwgts(1), 1.05_4, &
 
  401          options(1), edgecut, part(1), mesh%mpi_grp%comm%MPI_VAL)
 
  405        safe_deallocate_a(options)
 
  409      safe_deallocate_a(vtxdist)
 
  411      if (
debug%info .or. library == metis) 
then 
  412        safe_deallocate_a(xadj_global)
 
  413        safe_deallocate_a(adjncy_global)
 
  415      safe_deallocate_a(tpwgts)
 
  416      safe_deallocate_a(xadj)
 
  417      safe_deallocate_a(adjncy)
 
  418      safe_deallocate_a(istart)
 
  419      safe_deallocate_a(lsize)
 
  422    assert(all(part(1:nv) > 0))
 
  423    assert(all(part(1:nv) <= vsize))
 
  426    safe_deallocate_a(part)
 
  434      integer, 
intent(in) :: ierr
 
  442        message(1) = 
"Metis: Input error." 
  445        message(1) = 
"Metis: Unable to allocate required memory." 
  448        message(1) = 
"Metis: Some type of error." 
  461    type(
mesh_t), 
intent(inout) :: mesh
 
  462    type(
mesh_t), 
intent(in)    :: parent
 
  464    integer :: np, ip_local
 
  465    integer(int64) :: istart, ip_global
 
  466    integer(int64), 
allocatable :: points(:)
 
  467    integer, 
allocatable :: part(:)
 
  477    safe_allocate(points(1:np))
 
  478    safe_allocate(part(1:np))
 
  480      ip_global = istart + ip_local - 1
 
  490    safe_deallocate_a(points)
 
  491    safe_deallocate_a(part)
 
  499    type(
mesh_t),    
intent(in)  :: mesh
 
  500    integer,         
intent(in)  :: vsize
 
  501    integer,         
intent(out) :: ierr
 
  504    character(len=6) :: numstring
 
  516      message(1) = 
"Debug: Writing mesh partition restart." 
  520    write(numstring, 
'(i6.6)') vsize
 
  524      message(1) = 
"Unable to write inner mesh partition to 'inner_partition_"//trim(numstring)//
".obf'" 
  530      message(1) = 
"Debug: Writing mesh partition restart done." 
  541    integer,         
intent(out)   :: ierr
 
  544    character(len=6) :: numstring
 
  545    character(len=MAX_PATH_LEN) :: filename, dir
 
  558      message(1) = 
"Debug: Reading mesh partition restart." 
  564    write(numstring, 
'(i6.6)') mesh%mpi_grp%size
 
  568    filename = 
'inner_partition_'//numstring//
'.obf' 
  570      message(1) = 
"Unable to read inner mesh partition, file '"//trim(filename)//
"' does not exist." 
  576        message(1) = 
"Unable to read inner mesh partition from '"//trim(filename)//
"'." 
  588      message(1) = 
"Debug: Reading mesh partition restart done." 
  598    type(
mesh_t),                
intent(in) :: mesh
 
  599    integer,           
optional, 
intent(in) :: iunit
 
  600    type(
namespace_t), 
optional, 
intent(in) :: namespace
 
  602    integer(int64) :: npoints
 
  604    integer, 
allocatable :: nghost(:), nbound(:), nlocal(:), nneigh(:)
 
  605    integer :: num_ghost, num_bound, num_local, num_neigh
 
  606    real(real64) :: quality
 
  609    logical, 
allocatable :: is_a_neigh(:)
 
  615    npart = mesh%mpi_grp%size
 
  616    npoints = mesh%np_part_global
 
  618    safe_allocate(nghost(1:npart))
 
  619    safe_allocate(nbound(1:npart))
 
  620    safe_allocate(nlocal(1:npart))
 
  621    safe_allocate(nneigh(1:npart))
 
  622    safe_allocate(is_a_neigh(1:npart))
 
  624    ipart = mesh%mpi_grp%rank + 1
 
  627    num_ghost = mesh%pv%np_ghost
 
  628    num_bound = mesh%pv%np_bndry
 
  630    is_a_neigh = mesh%pv%ghost_rcounts > 0
 
  631    num_neigh = count(is_a_neigh(1:npart))
 
  633    safe_deallocate_a(is_a_neigh)
 
  635    call mesh%mpi_grp%gather(num_neigh, 1, mpi_integer, nneigh(1), 1, mpi_integer, 0)
 
  636    call mesh%mpi_grp%gather(num_local, 1, mpi_integer, nlocal(1), 1, mpi_integer, 0)
 
  637    call mesh%mpi_grp%gather(num_ghost, 1, mpi_integer, nghost(1), 1, mpi_integer, 0)
 
  638    call mesh%mpi_grp%gather(num_bound, 1, mpi_integer, nbound(1), 1, mpi_integer, 0)
 
  641    scal = real(npart, real64) /npoints
 
  645    quality = quality + (real(maxval(nlocal), real64) - real(minval(nlocal), real64))**3
 
  646    quality = quality + (sum(real(nghost, real64) **2))
 
  655        'Info: Mesh partition:' 
  659      write(
message(1),
'(a,e16.6)') &
 
  660        '      Partition quality:', quality
 
  665        '                 Neighbours         Ghost points' 
  666      write(
message(2),
'(a,i5,a,i10)') &
 
  667        '      Average  :      ', nint(sum(real(nneigh, real64) )/npart), 
'           ', nint(sum(real(nghost, real64) )/npart)
 
  668      write(
message(3),
'(a,i5,a,i10)') &
 
  669        '      Minimum  :      ', minval(nneigh),    
'           ', minval(nghost)
 
  670      write(
message(4),
'(a,i5,a,i10)') &
 
  671        '      Maximum  :      ', maxval(nneigh),    
'           ', maxval(nghost)
 
  677          '      Nodes in domain-group  ', ipart
 
  678        write(
message(2),
'(a,i10,a,i10)') &
 
  679          '        Neighbours     :', nneigh(ipart), &
 
  680          '        Local points    :', nlocal(ipart)
 
  681        write(
message(3),
'(a,i10,a,i10)') &
 
  682          '        Ghost points   :', nghost(ipart), &
 
  683          '        Boundary points :', nbound(ipart)
 
  691    safe_deallocate_a(nghost)
 
  692    safe_deallocate_a(nbound)
 
  693    safe_deallocate_a(nlocal)
 
  694    safe_deallocate_a(nneigh)
 
  701    type(
mesh_t),      
intent(in)    :: mesh
 
  705    integer(int64)          :: ipg
 
  707    character(len=6)     :: filenum
 
  709    if (.not. 
debug%info) 
return 
  713    call io_mkdir(
'debug/mesh_partition', namespace)
 
  716    write(filenum, 
'(i6.6)') mesh%mpi_grp%rank+1
 
  719    iunit = 
io_open(
'debug/mesh_partition/mesh_partition.'//filenum, &
 
  720      namespace, action=
'write')
 
  728    iunit = 
io_open(
'debug/mesh_partition/mesh_partition_all.'//filenum, &
 
  729      namespace, action=
'write')
 
  730    do ip = 1, mesh%np_part
 
  738      iunit = 
io_open(
'debug/mesh_partition/mesh_partition_boundary', &
 
  739        namespace, action=
'write')
 
  740      do ipg = mesh%np_global+1, mesh%np_part_global
 
subroutine metis_error_code(ierr)
 
type(debug_t), save, public debug
 
real(real64), parameter, public m_zero
 
real(real64), parameter, public m_one
 
This module implements the index, used for the mesh points.
 
subroutine, public io_close(iunit, grp)
 
logical function, public io_file_exists(filename, msg)
Returns true if a file with name 'filename' exists and issues a reminder.
 
subroutine, public io_mkdir(fname, namespace, parents)
 
integer function, public io_open(file, namespace, action, status, form, position, die, recl, grp)
 
This module defines the meshes, which are used in Octopus.
 
subroutine, public mesh_global_index_to_coords(mesh, ipg, ix)
Given a global point index, this function returns the set of integer coordinates of the point.
 
integer(int64) function, public mesh_global_index_from_coords(mesh, ix)
This function returns the true global index of the point for a given vector of integer coordinates.
 
integer(int64) function, public mesh_local2global(mesh, ip)
This function returns the global mesh index for a given local index.
 
real(real64) function, dimension(1:mesh%box%dim), public mesh_x_global(mesh, ipg)
 
integer, parameter hilbert
 
subroutine, public mesh_partition_from_parent(mesh, parent)
create a mesh partition from a given parent mesh
 
subroutine, public mesh_partition_write_info(mesh, iunit, namespace)
 
subroutine, public mesh_partition_messages_debug(mesh, namespace)
 
integer, parameter parmetis
 
subroutine, public mesh_partition(mesh, namespace, space, lapl_stencil, vsize)
This routine converts the mesh given by grid points into a graph.
 
subroutine, public mesh_partition_dump(restart, mesh, vsize, ierr)
 
subroutine, public mesh_partition_load(restart, mesh, ierr)
 
subroutine, public messages_warning(no_lines, all_nodes, namespace)
 
subroutine, public messages_info(no_lines, iunit, verbose_limit, stress, all_nodes, namespace)
 
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
 
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
 
subroutine, public messages_input_error(namespace, var, details, row, column)
 
This module contains interfaces for METIS and PARMETIS routines.
 
integer, parameter metis_ok
Returned normally.
 
integer, parameter metis_option_numbering
 
integer, parameter metis_error_memory
Returned due to insufficient memory.
 
integer, parameter metis_error_input
Returned due to erroneous inputs and/or options.
 
type(mpi_datatype), parameter mpi_metis_int
 
integer, parameter metis_error
Some other errors.
 
logical function mpi_grp_is_root(grp)
 
type(mpi_grp_t), public mpi_world
 
subroutine, public partition_init(partition, np_global, mpi_grp)
initialize the partition table
 
subroutine, public partition_set(partition, part)
 
subroutine, public partition_dump(partition, dir, filename, ierr)
write the partition data
 
subroutine, public partition_end(partition)
 
subroutine, public partition_load(partition, dir, filename, ierr)
read the partition data
 
subroutine, public partition_get_local_size(partition, istart, np_local)
 
character(len=max_path_len) function, public restart_dir(restart)
Returns the name of the directory containing the restart information. The use of this function should...
 
logical pure function, public restart_skip(restart)
Returns true if the restart information should neither be read nor written. This might happen because...
 
This module defines stencils used in Octopus.
 
subroutine, public stencil_end(this)
 
subroutine, public stencil_copy(input, output)
 
This module defines routines, generating operators for a star stencil.
 
subroutine, public stencil_star_get_lapl(this, dim, order)
 
Describes mesh distribution to nodes.