MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_coarsen_refine.t
Go to the documentation of this file.
1!> Module to coarsen and refine grids for AMR
3 implicit none
4 private
5 !> MPI recv send variables for AMR
6 integer :: itag, irecv, isend
7 integer, dimension(:), allocatable :: recvrequest, sendrequest
8 integer, dimension(:,:), allocatable :: recvstatus, sendstatus
9 !> MPI recv send variables for staggered-variable AMR
10 integer :: itag_stg
11 integer, dimension(:), allocatable :: recvrequest_stg, sendrequest_stg
12 integer, dimension(:,:), allocatable :: recvstatus_stg, sendstatus_stg
13
14 ! Public subroutines
15 public :: amr_coarsen_refine
16 public :: amr_rebalance
17
18contains
19
20 !> coarsen and refine blocks to update AMR grid
22 use mod_forest
26 use mod_amr_fct
33 use mod_refine, only: refine_grids
34
35
37
38 integer :: iigrid, igrid, ipe, igridco, ipeco, level, ic^d
39 integer, dimension(2^D&) :: igridfi, ipefi
40 integer :: n_coarsen, n_refine
41 type(tree_node_ptr) :: tree, sibling
42 logical :: active
43
44 call proper_nesting
45
46 if(stagger_grid) then
47 call store_faces
48 call comm_faces
49 end if
50
51 n_coarsen = count(coarsen(:, :))
52 n_refine = count(refine(:, :))
53
54 ! to save memory: first coarsen then refine
55 irecv=0
56 isend=0
57 allocate(recvstatus(mpi_status_size,max_blocks),recvrequest(max_blocks), &
58 sendstatus(mpi_status_size,max_blocks),sendrequest(max_blocks))
59 recvrequest=mpi_request_null
60 sendrequest=mpi_request_null
61
62 if(stagger_grid) then
63 allocate(recvstatus_stg(mpi_status_size,max_blocks*^nd),recvrequest_stg(max_blocks*^nd), &
64 sendstatus_stg(mpi_status_size,max_blocks*^nd),sendrequest_stg(max_blocks*^nd))
65 recvrequest_stg=mpi_request_null
66 sendrequest_stg=mpi_request_null
67 end if
68
69 do ipe=0,npe-1
70 do igrid=1,max_blocks
71 if (coarsen(igrid,ipe)) then
72 if (.not.associated(igrid_to_node(igrid,ipe)%node)) cycle
73
74 tree%node => igrid_to_node(igrid,ipe)%node%parent%node
75 {do ic^db=1,2\}
76 sibling%node => tree%node%child(ic^d)%node
77 ipefi(ic^d)=sibling%node%ipe
78 igridfi(ic^d)=sibling%node%igrid
79 {end do\}
80
81 ipeco=ipefi(1^d&)
82 igridco=getnode(ipeco)
83
84 call coarsen_tree_leaf(igridco,ipeco,igridfi,ipefi,active)
85
86 call coarsen_grid_siblings(igridco,ipeco,igridfi,ipefi,active)
87
88 ! local coarsening done
89 {do ic^db=1,2\}
90 if (ipefi(ic^d)==ipeco) then
91 call putnode(igridfi(ic^d),ipefi(ic^d))
92 coarsen(igridfi(ic^d),ipefi(ic^d))=.false.
93 end if
94 {end do\}
95 end if
96 end do
97 end do
98
99 if (irecv>0) then
100 call mpi_waitall(irecv,recvrequest,recvstatus,ierrmpi)
101 if(stagger_grid) call mpi_waitall(irecv,recvrequest_stg,recvstatus_stg,ierrmpi)
102 end if
103 if (isend>0) then
104 call mpi_waitall(isend,sendrequest,sendstatus,ierrmpi)
105 if(stagger_grid) call mpi_waitall(isend,sendrequest_stg,sendstatus_stg,ierrmpi)
106 end if
107
108 deallocate(recvstatus,recvrequest,sendstatus,sendrequest)
109 if(stagger_grid) deallocate(recvstatus_stg,recvrequest_stg,sendstatus_stg,sendrequest_stg)
110
111 ! non-local coarsening done
112 do ipe=0,npe-1
113 do igrid=1,max_blocks
114 if (coarsen(igrid,ipe)) then
115 !if (ipe==mype) call dealloc_node(igrid) ! do not deallocate node
116 ! memory preventing fragmentization of system memory as a result
117 ! of frequent allocating and deallocating memory
118
119 ! put the node (igrid number) into unused.
120 call putnode(igrid,ipe)
121 coarsen(igrid,ipe)=.false.
122 end if
123 end do
124 end do
125
126 do ipe=0,npe-1
127 do igrid=1,max_blocks
128 if (refine(igrid,ipe)) then
129
130 {do ic^db=1,2\}
131 igridfi(ic^d)=getnode(ipe)
132 ipefi(ic^d)=ipe
133 {end do\}
134
135 call refine_tree_leaf(igridfi,ipefi,igrid,ipe,active)
136
137 if (ipe==mype) call refine_grids(igridfi,ipefi,igrid,ipe,active)
138
139 ! refinement done
140 call putnode(igrid,ipe)
141 refine(igrid,ipe)=.false.
142 end if
143 end do
144 end do
145
146 ! A crash occurs in later MPI_WAITALL when initial condition comsumes too
147 ! much time to filling new blocks with both gfortran and intel fortran compiler.
148 ! This barrier cure this problem
149 !TODO to find the reason
150 if(.not.time_advance) call mpi_barrier(icomm,ierrmpi)
151
152 if(stagger_grid) call end_comm_faces
153
154 call get_level_range
155
156 ! Update sfc array: igrid and ipe info in space filling curve
157 call amr_morton_order()
158
159 call load_balance
160
161 ! Rebuild tree connectivity
162 call getigrids
163 call build_connectivity
164
165 ! Update the list of active grids
166 call selectgrids
167 ! grid structure now complete again.
168
169 ! since we only filled mesh values, and advance assumes filled
170 ! ghost cells, do boundary filling for the new levels
171 call getbc(global_time,0.d0,ps,iwstart,nwgc)
172
173 if (use_multigrid) call mg_update_refinement(n_coarsen, n_refine)
174
175 if (associated(usr_after_refine)) then
176 call usr_after_refine(n_coarsen, n_refine)
177 end if
178
179 end subroutine amr_coarsen_refine
180
181 !> Cost-weighted rebalance without refine/coarsen. For static/uniform grids (refine_max_level=1)
182 !> amr_coarsen_refine never runs, so the cost-weighted load_balance has no invocation point and the
183 !> partition stays at the initial equal-block (cell-count) split -> photosphere EoS-heavy ranks stall
184 !> the rest. This migrates blocks to equalise the measured per-block cost (block_cost, populated when
185 !> lb_automatic is on) then rebuilds connectivity + ghosts, mirroring the tail of amr_coarsen_refine.
186 subroutine amr_rebalance
187 use mod_forest
190 use mod_amr_fct, only: end_comm_faces
195
196 if (npe==1) return
198 call get_level_range
199 call amr_morton_order()
200 call load_balance
201 ! rebuild tree connectivity + active-grid list, then refill ghosts (advance assumes filled ghosts)
202 call getigrids
204 call selectgrids
205 call getbc(global_time, 0.d0, ps, iwstart, nwgc)
206 end subroutine amr_rebalance
207
208 !> For all grids on all processors, do a check on refinement flags. Make
209 !> sure that neighbors will not differ more than one level of refinement.
210 subroutine proper_nesting
211 use mod_forest
214
215 logical, dimension(:,:), allocatable :: refine2
216 integer :: iigrid, igrid, level, ic^d, inp^d, i^d, my_neighbor_type,ipe
217 logical :: coarsening, pole(ndim), sendbuf(max_blocks)
218 type(tree_node_ptr) :: tree, p_neighbor, my_parent, sibling, my_neighbor, &
219 neighborchild
220
221 if (nbufferx^d/=0|.or.) then
222 allocate(refine2(max_blocks,npe))
223 call mpi_allreduce(refine,refine2,max_blocks*npe,mpi_logical,mpi_lor, &
225 refine=refine2
226 else
227 sendbuf(:)=refine(:,mype)
228 call mpi_allgather(sendbuf,max_blocks,mpi_logical,refine,max_blocks, &
229 mpi_logical,icomm,ierrmpi)
230 end if
231
232 do level=min(levmax,refine_max_level-1),levmin+1,-1
233 tree%node => level_head(level)%node
234 do
235 if (.not.associated(tree%node)) exit
236
237 if (refine(tree%node%igrid,tree%node%ipe)) then
238 ic^d=1+modulo(tree%node%ig^d-1,2);
239 {do inp^db=ic^db-2,ic^db-1\}
240 if (inp^d==0|.and.) cycle
241 p_neighbor%node => tree%node%parent%node
242 {if (inp^d/=0) then
243 p_neighbor%node => p_neighbor%node%neighbor(ic^d,^d)%node
244 if (.not.associated(p_neighbor%node)) cycle
245 end if\}
246 if (p_neighbor%node%leaf) then
247 refine(p_neighbor%node%igrid,p_neighbor%node%ipe)=.true.
248 end if
249 {end do\}
250 end if
251
252 tree%node => tree%node%next%node
253 end do
254 end do
255
256 ! On each processor locally, check if grids set for coarsening are already
257 ! set for refinement.
258
259 do iigrid=1,igridstail; igrid=igrids(iigrid);
260 if (refine(igrid,mype).and.coarsen(igrid,mype)) coarsen(igrid,mype)=.false.
261 end do
262
263 ! For all grids on all processors, do a check on coarse refinement flags
264 sendbuf(:)=coarsen(:,mype)
265 call mpi_allgather(sendbuf,max_blocks,mpi_logical,coarsen,max_blocks, &
266 mpi_logical,icomm,ierrmpi)
267
268 do level=levmax,max(2,levmin),-1
269 tree%node => level_head(level)%node
270 do
271 if (.not.associated(tree%node)) exit
272
273 if (coarsen(tree%node%igrid,tree%node%ipe)) then
274 coarsening=.true.
275 my_parent%node => tree%node%parent%node
276
277 ! are all siblings flagged for coarsen ?
278 check1: {do ic^db=1,2\}
279 sibling%node => my_parent%node%child(ic^d)%node
280 if (sibling%node%leaf) then
281 if (coarsen(sibling%node%igrid,sibling%node%ipe)) cycle
282 end if
284 exit check1
285 {end do\} check1
286
287 ! Make sure that neighbors will not differ more than one level of
288 ! refinement, otherwise unflag all siblings
289 if (coarsening) then
290 check2: {do ic^db=1,2\}
291 sibling%node => my_parent%node%child(ic^d)%node
292 {do i^db=ic^db-2,ic^db-1\}
293 if (i^d==0|.and.) cycle
294 call find_neighbor(my_neighbor,my_neighbor_type, &
295 sibling,i^d,pole)
296 select case (my_neighbor_type)
297 case (neighbor_sibling)
298 if (refine(my_neighbor%node%igrid, &
299 my_neighbor%node%ipe)) then
301 exit check2
302 else
303 cycle
304 end if
305 case (neighbor_fine)
306 neighborchild%node=>my_neighbor%node%child(1^d&)%node
307 if (neighborchild%node%leaf) then
308 if (coarsen(neighborchild%node%igrid, &
309 neighborchild%node%ipe)) then
310 cycle
311 end if
312 end if
314 exit check2
315 end select
316 {end do\}
317 {end do\} check2
318 end if
319
320 end if
321
322 tree%node => tree%node%next%node
323 end do
324 end do
325
326 contains
327
329
330 integer :: ic^D
331 type(tree_node_ptr) :: sibling
332
333 {do ic^db=1,2\}
334 sibling%node => my_parent%node%child(ic^d)%node
335 if (sibling%node%leaf) then
336 coarsen(sibling%node%igrid,sibling%node%ipe)=.false.
337 end if
338 {end do\}
339 coarsening=.false.
340
341 end subroutine unflag_coarsen_siblings
342
343 end subroutine proper_nesting
344
345 !> coarsen sibling blocks into one block
346 subroutine coarsen_grid_siblings(igrid,ipe,child_igrid,child_ipe,active)
348 use mod_coarsen, only: coarsen_grid
351
352 integer, intent(in) :: igrid, ipe
353 integer, dimension(2^D&), intent(in) :: child_igrid, child_ipe
354 logical, intent(in) :: active
355
356 integer :: igridFi, ipeFi, ixCo^L, ixCoG^L, ixCoM^L, ic^D, idir
357
358 if (ipe==mype) call alloc_node(igrid)
359
360 ! New passive cell, coarsen from initial condition:
361 if (.not. active) then
362 if (ipe == mype) then
363 call initial_condition(igrid)
364 {do ic^db=1,2\}
365 igridfi=child_igrid(ic^d)
366 ipefi=child_ipe(ic^d)
367 !if (ipeFi==mype) then
368 ! ! remove solution space of child
369 ! call dealloc_node(igridFi)
370 !end if
371 {end do\}
372 end if
373 return
374 end if
375
376 {do ic^db=1,2\}
377 igridfi=child_igrid(ic^d)
378 ipefi=child_ipe(ic^d)
379
380 if (ipefi==mype) then
381 ^d&dxlevel(^d)=rnode(rpdx^d_,igridfi);
382 if (ipe==mype) then
383 ixcomin^d=ixmlo^d+(ic^d-1)*(ixmhi^d-ixmlo^d+1)/2;
384 ixcomax^d=ixmhi^d+(ic^d-2)*(ixmhi^d-ixmlo^d+1)/2;
385
386 call coarsen_grid(ps(igridfi),ixg^ll,ixm^ll,ps(igrid),ixg^ll,ixco^l)
387 ! remove solution space of child
388 !call dealloc_node(igridFi)
389 else
390 ixcogmin^d=1;
391 ixcogmax^d=ixghi^d/2+nghostcells;
392 ixcom^l=ixcog^l^lsubnghostcells;
393 call coarsen_grid(ps(igridfi),ixg^ll,ixm^ll,psc(igridfi), &
394 ixcog^l,ixcom^l)
395
396 !itag=ipeFi*max_blocks+igridFi
397 itag=ipefi+igridfi
398 isend=isend+1
399 call mpi_isend(psc(igridfi)%w,1,type_coarse_block,ipe,itag, &
400 icomm,sendrequest(isend),ierrmpi)
401 if(stagger_grid) then
402 do idir=1,ndim
403 !itag_stg=(npe+ipeFi+1)*max_blocks+igridFi*(ndir-1+idir)
404 itag_stg=(npe+ipefi+1)+igridfi*(ndir-1+idir)
405 call mpi_isend(psc(igridfi)%ws,1,type_coarse_block_stg(idir,ic^d),ipe,itag_stg, &
406 icomm,sendrequest_stg(isend),ierrmpi)
407 end do
408 end if
409 end if
410 else
411 if (ipe==mype) then
412 !itag=ipeFi*max_blocks+igridFi
413 itag=ipefi+igridfi
414 irecv=irecv+1
415 call mpi_irecv(ps(igrid)%w,1,type_sub_block(ic^d),ipefi,itag, &
416 icomm,recvrequest(irecv),ierrmpi)
417 if(stagger_grid) then
418 do idir=1,ndim
419 !itag_stg=(npe+ipeFi+1)*max_blocks+igridFi*(ndir-1+idir)
420 itag_stg=(npe+ipefi+1)+igridfi*(ndir-1+idir)
421 call mpi_irecv(ps(igrid)%ws,1,type_sub_block_stg(idir,ic^d),ipefi,itag_stg, &
422 icomm,recvrequest_stg(irecv),ierrmpi)
423 end do
424 end if
425 end if
426 end if
427 {end do\}
428
429 end subroutine coarsen_grid_siblings
430
431end module mod_coarsen_refine
subroutine unflag_coarsen_siblings
subroutine, public store_faces
To achive consistency and thus conservation of divergence, when refining a block we take into account...
subroutine, public comm_faces
When refining a coarse block with fine neighbours, it is necessary prolong consistently with the alre...
subroutine, public end_comm_faces
subroutine, public find_neighbor(my_neighbor, my_neighbor_type, tree, id, pole)
find neighors of all blocks
subroutine, public putnode(igrid, ipe)
subroutine, public alloc_node(igrid)
allocate arrays on igrid node
integer function, public getnode(ipe)
Get first available igrid on processor ipe.
Module to coarsen and refine grids for AMR.
subroutine, public amr_rebalance
Cost-weighted rebalance without refine/coarsen. For static/uniform grids (refine_max_level=1) amr_coa...
subroutine, public amr_coarsen_refine
coarsen and refine blocks to update AMR grid
subroutine, public coarsen_grid(sfi, ixfigl, ixfil, sco, ixcogl, ixcol)
coarsen one grid to its coarser representative
Definition mod_coarsen.t:13
Module with basic grid data structures.
Definition mod_forest.t:2
logical, dimension(:,:), allocatable, save refine
Definition mod_forest.t:70
logical, dimension(:,:), allocatable, save coarsen
AMR flags and grids-in-use identifier per processor (igrid,ipe)
Definition mod_forest.t:70
type(tree_node_ptr), dimension(:,:), allocatable, save igrid_to_node
Array to go from an [igrid, ipe] index to a node pointer.
Definition mod_forest.t:32
type(tree_node_ptr), dimension(:), allocatable, save level_head
The head pointer of the linked list per refinement level.
Definition mod_forest.t:35
subroutine, public refine_tree_leaf(child_igrid, child_ipe, igrid, ipe, active)
subroutine, public coarsen_tree_leaf(igrid, ipe, child_igrid, child_ipe, active)
update ghost cells of all blocks including physical boundaries
subroutine getbc(time, qdt, psb, nwstart, nwbc)
do update ghost cells of all blocks including physical boundaries
This module contains definitions of global parameters and variables and some generic functions/subrou...
double precision global_time
The global simulation time.
integer, parameter ndim
Number of spatial dimensions for grid variables.
logical stagger_grid
True for using stagger grid.
integer icomm
The MPI communicator.
integer mype
The rank of the current MPI task.
integer ierrmpi
A global MPI error return code.
double precision, dimension(:), allocatable, parameter d
integer npe
The number of MPI tasks.
integer nbufferx
Number of cells as buffer zone.
integer refine_max_level
Maximal number of AMR levels.
integer max_blocks
The maximum number of grid blocks in a processor.
subroutine, public initial_condition(igrid)
fill in initial condition
subroutine load_balance
reallocate blocks into processors for load balance
Module to couple the octree-mg library to AMRVAC. This file uses the VACPP preprocessor,...
subroutine, public refine_grids(child_igrid, child_ipe, igrid, ipe, active)
refine one block to its children blocks
Definition mod_refine.t:13
subroutine, public selectgrids
subroutine amr_morton_order
Construct Morton-order as a global recursive lexicographic ordering.
Module with all the methods that users can customize in AMRVAC.
procedure(after_refine), pointer usr_after_refine
Pointer to a tree_node.
Definition mod_forest.t:6