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
196
197 if (npe==1) return
199 call get_level_range
200 call amr_morton_order()
201 call load_balance
202 ! rebuild tree connectivity + active-grid list, then refill ghosts (advance assumes filled ghosts)
203 call getigrids
205 call selectgrids
206 call getbc(global_time, 0.d0, ps, iwstart, nwgc)
207 ! after getbc, eos variables of ghost cells are zero for new blocks
208 ! update the additional w state eos variables including ghost cells
209 call prepare_eos_w_fields(ps)
210 end subroutine amr_rebalance
211
212 !> For all grids on all processors, do a check on refinement flags. Make
213 !> sure that neighbors will not differ more than one level of refinement.
214 subroutine proper_nesting
215 use mod_forest
218
219 logical, dimension(:,:), allocatable :: refine2
220 integer :: iigrid, igrid, level, ic^d, inp^d, i^d, my_neighbor_type,ipe
221 logical :: coarsening, pole(ndim), sendbuf(max_blocks)
222 type(tree_node_ptr) :: tree, p_neighbor, my_parent, sibling, my_neighbor, &
223 neighborchild
224
225 if (nbufferx^d/=0|.or.) then
226 allocate(refine2(max_blocks,npe))
227 call mpi_allreduce(refine,refine2,max_blocks*npe,mpi_logical,mpi_lor, &
229 refine=refine2
230 else
231 sendbuf(:)=refine(:,mype)
232 call mpi_allgather(sendbuf,max_blocks,mpi_logical,refine,max_blocks, &
233 mpi_logical,icomm,ierrmpi)
234 end if
235
236 do level=min(levmax,refine_max_level-1),levmin+1,-1
237 tree%node => level_head(level)%node
238 do
239 if (.not.associated(tree%node)) exit
240
241 if (refine(tree%node%igrid,tree%node%ipe)) then
242 ic^d=1+modulo(tree%node%ig^d-1,2);
243 {do inp^db=ic^db-2,ic^db-1\}
244 if (inp^d==0|.and.) cycle
245 p_neighbor%node => tree%node%parent%node
246 {if (inp^d/=0) then
247 p_neighbor%node => p_neighbor%node%neighbor(ic^d,^d)%node
248 if (.not.associated(p_neighbor%node)) cycle
249 end if\}
250 if (p_neighbor%node%leaf) then
251 refine(p_neighbor%node%igrid,p_neighbor%node%ipe)=.true.
252 end if
253 {end do\}
254 end if
255
256 tree%node => tree%node%next%node
257 end do
258 end do
259
260 ! On each processor locally, check if grids set for coarsening are already
261 ! set for refinement.
262
263 do iigrid=1,igridstail; igrid=igrids(iigrid);
264 if (refine(igrid,mype).and.coarsen(igrid,mype)) coarsen(igrid,mype)=.false.
265 end do
266
267 ! For all grids on all processors, do a check on coarse refinement flags
268 sendbuf(:)=coarsen(:,mype)
269 call mpi_allgather(sendbuf,max_blocks,mpi_logical,coarsen,max_blocks, &
270 mpi_logical,icomm,ierrmpi)
271
272 do level=levmax,max(2,levmin),-1
273 tree%node => level_head(level)%node
274 do
275 if (.not.associated(tree%node)) exit
276
277 if (coarsen(tree%node%igrid,tree%node%ipe)) then
278 coarsening=.true.
279 my_parent%node => tree%node%parent%node
280
281 ! are all siblings flagged for coarsen ?
282 check1: {do ic^db=1,2\}
283 sibling%node => my_parent%node%child(ic^d)%node
284 if (sibling%node%leaf) then
285 if (coarsen(sibling%node%igrid,sibling%node%ipe)) cycle
286 end if
288 exit check1
289 {end do\} check1
290
291 ! Make sure that neighbors will not differ more than one level of
292 ! refinement, otherwise unflag all siblings
293 if (coarsening) then
294 check2: {do ic^db=1,2\}
295 sibling%node => my_parent%node%child(ic^d)%node
296 {do i^db=ic^db-2,ic^db-1\}
297 if (i^d==0|.and.) cycle
298 call find_neighbor(my_neighbor,my_neighbor_type, &
299 sibling,i^d,pole)
300 select case (my_neighbor_type)
301 case (neighbor_sibling)
302 if (refine(my_neighbor%node%igrid, &
303 my_neighbor%node%ipe)) then
305 exit check2
306 else
307 cycle
308 end if
309 case (neighbor_fine)
310 neighborchild%node=>my_neighbor%node%child(1^d&)%node
311 if (neighborchild%node%leaf) then
312 if (coarsen(neighborchild%node%igrid, &
313 neighborchild%node%ipe)) then
314 cycle
315 end if
316 end if
318 exit check2
319 end select
320 {end do\}
321 {end do\} check2
322 end if
323
324 end if
325
326 tree%node => tree%node%next%node
327 end do
328 end do
329
330 contains
331
333
334 integer :: ic^D
335 type(tree_node_ptr) :: sibling
336
337 {do ic^db=1,2\}
338 sibling%node => my_parent%node%child(ic^d)%node
339 if (sibling%node%leaf) then
340 coarsen(sibling%node%igrid,sibling%node%ipe)=.false.
341 end if
342 {end do\}
343 coarsening=.false.
344
345 end subroutine unflag_coarsen_siblings
346
347 end subroutine proper_nesting
348
349 !> coarsen sibling blocks into one block
350 subroutine coarsen_grid_siblings(igrid,ipe,child_igrid,child_ipe,active)
352 use mod_coarsen, only: coarsen_grid
355
356 integer, intent(in) :: igrid, ipe
357 integer, dimension(2^D&), intent(in) :: child_igrid, child_ipe
358 logical, intent(in) :: active
359
360 integer :: igridFi, ipeFi, ixCo^L, ixCoG^L, ixCoM^L, ic^D, idir
361
362 if (ipe==mype) call alloc_node(igrid)
363
364 ! New passive cell, coarsen from initial condition:
365 if (.not. active) then
366 if (ipe == mype) then
367 call initial_condition(igrid)
368 {do ic^db=1,2\}
369 igridfi=child_igrid(ic^d)
370 ipefi=child_ipe(ic^d)
371 !if (ipeFi==mype) then
372 ! ! remove solution space of child
373 ! call dealloc_node(igridFi)
374 !end if
375 {end do\}
376 end if
377 return
378 end if
379
380 {do ic^db=1,2\}
381 igridfi=child_igrid(ic^d)
382 ipefi=child_ipe(ic^d)
383
384 if (ipefi==mype) then
385 ^d&dxlevel(^d)=rnode(rpdx^d_,igridfi);
386 if (ipe==mype) then
387 ixcomin^d=ixmlo^d+(ic^d-1)*(ixmhi^d-ixmlo^d+1)/2;
388 ixcomax^d=ixmhi^d+(ic^d-2)*(ixmhi^d-ixmlo^d+1)/2;
389
390 call coarsen_grid(ps(igridfi),ixg^ll,ixm^ll,ps(igrid),ixg^ll,ixco^l)
391 ! remove solution space of child
392 !call dealloc_node(igridFi)
393 else
394 ixcogmin^d=1;
395 ixcogmax^d=ixghi^d/2+nghostcells;
396 ixcom^l=ixcog^l^lsubnghostcells;
397 call coarsen_grid(ps(igridfi),ixg^ll,ixm^ll,psc(igridfi), &
398 ixcog^l,ixcom^l)
399
400 !itag=ipeFi*max_blocks+igridFi
401 itag=ipefi+igridfi
402 isend=isend+1
403 call mpi_isend(psc(igridfi)%w,1,type_coarse_block,ipe,itag, &
404 icomm,sendrequest(isend),ierrmpi)
405 if(stagger_grid) then
406 do idir=1,ndim
407 !itag_stg=(npe+ipeFi+1)*max_blocks+igridFi*(ndir-1+idir)
408 itag_stg=(npe+ipefi+1)+igridfi*(ndir-1+idir)
409 call mpi_isend(psc(igridfi)%ws,1,type_coarse_block_stg(idir,ic^d),ipe,itag_stg, &
410 icomm,sendrequest_stg(isend),ierrmpi)
411 end do
412 end if
413 end if
414 else
415 if (ipe==mype) then
416 !itag=ipeFi*max_blocks+igridFi
417 itag=ipefi+igridfi
418 irecv=irecv+1
419 call mpi_irecv(ps(igrid)%w,1,type_sub_block(ic^d),ipefi,itag, &
420 icomm,recvrequest(irecv),ierrmpi)
421 if(stagger_grid) then
422 do idir=1,ndim
423 !itag_stg=(npe+ipeFi+1)*max_blocks+igridFi*(ndir-1+idir)
424 itag_stg=(npe+ipefi+1)+igridfi*(ndir-1+idir)
425 call mpi_irecv(ps(igrid)%ws,1,type_sub_block_stg(idir,ic^d),ipefi,itag_stg, &
426 icomm,recvrequest_stg(irecv),ierrmpi)
427 end do
428 end if
429 end if
430 end if
431 {end do\}
432
433 end subroutine coarsen_grid_siblings
434
435end 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
Equation of state for AMRVAC, handled through a single eos_container object.
Definition mod_eos.t:30
subroutine, public prepare_eos_w_fields(psx)
Definition mod_eos.t:404
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