12 integer,
allocatable :: gsq_sfc(:^D&),seq_sfc(:),seq_ig^D(:)
13 integer :: ig^D, ngsq^D, isq, total_number
15 logical,
allocatable :: in_domain(:)
18 ngsq^d=2**ceiling(log(real(
ng^d(1)))/log(2.0));
20 {ngsq^d=max(ngsq^dd) \}
22 total_number={ngsq^d|*}
24 allocate(gsq_sfc(ngsq^d))
26 allocate(seq_sfc(total_number))
28 {
allocate(seq_ig^d(total_number))\}
29 allocate(in_domain(total_number))
34 seq_sfc(gsq_sfc(ig^d))=gsq_sfc(ig^d)
35 {seq_ig^d(gsq_sfc(ig^dd))=ig^d \}
39 if (seq_ig^d(isq)>ng^d(1)|.or.)
then
40 seq_sfc(isq:total_number)=seq_sfc(isq:total_number)-1
41 in_domain(isq)=.false.
45 if(.not.
allocated(iglevel1_sfc))
allocate(iglevel1_sfc(ng^d(1)))
46 if(.not.
allocated(sfc_iglevel1))
allocate(sfc_iglevel1(ndim,nglev1))
48 if(in_domain(isq))
then
49 iglevel1_sfc(seq_ig^d(isq))=seq_sfc(isq)
50 {sfc_iglevel1(^d,seq_sfc(isq))=seq_ig^d(isq) \}
54 deallocate(gsq_sfc,seq_sfc,seq_ig^d,in_domain)
59 use iso_fortran_env,
only : int64
61 integer(kind=8) :: answer, lg^d
62 integer(kind=4),
intent(in) :: ig^d,ndim
72 answer=ior(answer,ior(ishft(iand(lg1,ishft(1_int64,i)),i),&
73 ishft(iand(lg2,ishft(1_int64,i)),i+1)))
76 answer=ior(answer,ior(ishft(iand(lg1,ishft(1_int64,i)),2*i),ior(ishft(&
77 iand(lg2,ishft(1_int64,i)),2*i+1),ishft(iand(lg3,ishft(1_int64,i)),2*i+2))))
90 integer :: ig^D, Morton_no, isfc
99 if (morton_no/=
nleafs)
then
100 call mpistop(
"error in amr_Morton_order: Morton_no/=nleafs")
111 if (tree%node%leaf)
then
112 morton_no=morton_no+1
113 sfc(1,morton_no)=tree%node%igrid
114 sfc(2,morton_no)=tree%node%ipe
115 if (tree%node%active)
then
136 integer :: ipe, blocks_left, procs_left, num_blocks
139 {
#IFDEF EVOLVINGBOUNDARY
153 procs_left =
npe - ipe
154 num_blocks = ceiling(blocks_left / dble(procs_left))
156 blocks_left = blocks_left - num_blocks
160 {
#IFDEF EVOLVINGBOUNDARY
175 integer,
parameter :: wa=3, wp=1
190 integer :: ipe, Morton_no
191 integer :: Mtot, Mstop, Mcurr
193 integer :: nactive(0:npe-1),npassive(0:npe-1)
197 {
#IFDEF EVOLVINGBOUNDARY
211 mstop = (ipe+1)*int(mtot/npe)+min(ipe+1,mod(mtot,npe))
213 mcurr = mcurr + (wa*
sfc(3,morton_no)+wp*(1-
sfc(3,morton_no)))
215 if (
sfc(3,morton_no)==1)
then
216 nactive(ipe) = nactive(ipe) +1
218 npassive(ipe) = npassive(ipe) +1
221 if (mcurr >= mstop)
then
229 xmemory=dble(maxval(npassive+nactive))/&
230 dble(minval(npassive+nactive))
231 xload=dble(maxval(nactive))/&
232 dble(minval(nactive))
240 {
#IFDEF EVOLVINGBOUNDARY
257 integer :: ipe, Morton_no, igrid, ix, nseen, ncut, nmax, nrem
258 integer :: ncut_lo, ncut_hi
259 integer,
save :: last_report = -1
260 double precision :: cost_total, cost_target, cost_mean
261 double precision :: maxcount, mincount, maxcost, meancost
262 double precision,
allocatable :: cost_local(:), cost_cumul(:)
263 integer :: nblocks_per(0:npe-1)
264 logical :: partition_ok
265 logical,
save :: warned_fallback = .false.
268 {
#IFDEF EVOLVINGBOUNDARY
279 allocate(cost_local(
nleafs))
282 if (
sfc(2,morton_no) ==
mype)
then
283 igrid =
sfc(1,morton_no)
294 call mpi_allreduce(mpi_in_place, cost_local,
nleafs, &
304 if (cost_local(morton_no) > 0.0d0)
then
307 + (1.0d0 -
lb_alpha) * cost_local(morton_no)
311 costlist(morton_no) = cost_local(morton_no)
316 deallocate(cost_local)
330 if (cost_total <= 0.0d0 .or. nseen == 0 .or.
nleafs < npe)
then
341 allocate(cost_cumul(0:
nleafs))
342 cost_cumul(0) = 0.0d0
344 cost_cumul(morton_no) = cost_cumul(morton_no-1) +
costlist(morton_no)
355 cost_target = (dble(ipe) + 1.0d0) * cost_total / dble(npe)
358 do while (ncut <
nleafs .and. cost_cumul(ncut) < cost_target)
364 ncut_lo = max(ix + 1,
nleafs - nmax*nrem)
365 ncut_hi = min(ix + nmax,
nleafs - nrem)
366 ncut = min(max(ncut, ncut_lo), ncut_hi)
369 nblocks_per(ipe) = ncut - ix
373 nblocks_per(npe-1) =
nleafs - ix
374 deallocate(cost_cumul)
387 if (.not. partition_ok)
then
388 if (
mype == 0 .and. .not. warned_fallback)
then
389 write(*,*)
'get_Morton_range_costed: partition failed validation at it=',
it
390 write(*,*)
' nleafs=',
nleafs,
' npe=', npe,
' cost_total=', cost_total
391 write(*,*)
' falling back to equal-block partition (warned once)'
392 warned_fallback = .true.
399 maxcount = dble(maxval(nblocks_per))
400 mincount = dble(max(1,minval(nblocks_per)))
406 meancost = cost_total / dble(npe)
407 xload = maxcost / max(meancost, tiny(1.0d0))
411 if (
mype == 0 .and.
it >= last_report + 500)
then
412 write(*,
'(a,i9,a,i6,a,i5,a,i5,a,i5,a,f6.2)') &
413 ' [lb] it=',
it,
' nleafs=',
nleafs, &
414 ' blocks/rank min=', minval(nblocks_per),
' max=', maxval(nblocks_per), &
415 ' cap=', nmax,
' Xload=',
xload
421 {
#IFDEF EVOLVINGBOUNDARY
recursive subroutine get_morton_number(tree)
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
Module with basic grid data structures.
integer, dimension(:), allocatable, save sfc_to_igrid
Go from a Morton number to an igrid index (for a single processor)
integer, dimension(:), allocatable, save sfc_phybound
Space filling curve used for physical boundary blocks.
integer, dimension(:), allocatable, save morton_start
First Morton number per processor.
integer, save nleafs
Number of leaf block.
integer, dimension(:), allocatable, save igrid_to_sfc
Go from a grid index to Morton number (for a single processor)
integer, dimension(:,:), allocatable, save sfc_iglevel1
Space filling curve for level 1 grid. sfc_iglevel1(^D, MN) gives ig^D (the spatial index of the grid)
integer, dimension(:), allocatable, save morton_stop
Last Morton number per processor.
type(tree_node_ptr), dimension(:^d &), allocatable, save tree_root
Pointers to the coarse grid.
integer, dimension(:,:), allocatable, save sfc
Array to go from a Morton number to an igrid and processor index. Sfc(1:3, MN) contains [igrid,...
This module contains definitions of global parameters and variables and some generic functions/subrou...
double precision xload
Stores the memory and load imbalance, used in printlog.
double precision, dimension(:), allocatable costlist
Persistent global per-Morton-leaf EWMA cost, in seconds (block_cost is a wall-clock accumulation)....
double precision, dimension(:), allocatable block_cost
Per-step per-block (per-rank, indexed by igrid) cost accumulator. Reset at start of each advance call...
logical, dimension(:), allocatable costlist_seen
Whether the matching costlist slot has ever carried a measurement. Morton indices created by a refine...
double precision lb_max_block_ratio
Bound on the memory imbalance get_Morton_range_costed may create: no rank may hold more than lb_max_b...
integer it
Number of time steps taken.
integer, parameter ndim
Number of spatial dimensions for grid variables.
integer icomm
The MPI communicator.
integer, dimension(:), allocatable ng
number of grid blocks in domain per dimension, in array over levels
integer mype
The rank of the current MPI task.
integer ierrmpi
A global MPI error return code.
integer npe
The number of MPI tasks.
integer max_blocks
The maximum number of grid blocks in a processor.
double precision lb_alpha
Exponential-moving-average decay for the per-block cost. costlist <- lb_alpha*costlist + (1-lb_alpha)...
subroutine get_morton_range_costed
Cost-weighted SFC partition. Reduces the per-rank block_cost array into a global Morton-indexed cost,...
integer(kind=8) function mortonencode(igd, ndim)
subroutine get_morton_range_active
subroutine get_morton_range
Set the Morton range for each processor.
subroutine amr_morton_order
Construct Morton-order as a global recursive lexicographic ordering.
subroutine level1_morton_order
build Morton space filling curve for level 1 grid