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
258 double precision :: cost_total, cost_target, cost_cum
259 double precision :: maxcount, mincount, maxcost, meancost
260 double precision,
allocatable :: cost_local(:)
261 integer :: nblocks_per(0:npe-1)
264 {
#IFDEF EVOLVINGBOUNDARY
274 allocate(cost_local(
nleafs))
277 if (
sfc(2,morton_no) ==
mype)
then
278 igrid =
sfc(1,morton_no)
289 call mpi_allreduce(mpi_in_place, cost_local,
nleafs, &
299 if (cost_local(morton_no) > 0.0d0)
then
301 + (1.0d0 -
lb_alpha) * cost_local(morton_no)
304 deallocate(cost_local)
307 if (cost_total <= 0.0d0)
then
321 cost_cum = cost_cum +
costlist(morton_no)
322 cost_target = (dble(ipe) + 1.0d0) * cost_total / dble(npe)
323 nblocks_per(ipe) = nblocks_per(ipe) + 1
324 if (cost_cum >= cost_target .and. ipe < npe-1)
then
333 maxcount = dble(maxval(nblocks_per))
334 mincount = dble(max(1,minval(nblocks_per)))
340 meancost = cost_total / dble(npe)
341 xload = maxcost / max(meancost, tiny(1.0d0))
345 {
#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. Sized to max_blocks*npe (the upper bound on nleafs); onl...
double precision, dimension(:), allocatable block_cost
Per-step per-block (per-rank, indexed by igrid) cost accumulator. Reset at start of each advance call...
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