MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_ghostcells_update.t
Go to the documentation of this file.
1!> update ghost cells of all blocks including physical boundaries
3
4 implicit none
5
6 ! The number of interleaving sending buffers for ghost cells
7 integer, parameter :: npwbuf=2
8
9 integer :: ixm^l, ixcog^l, ixcom^l, ixcogs^l
10
11 ! index ranges to send (S) to sibling blocks, receive (R) from sibling blocks
12 integer, dimension(-1:1) :: ixs_srl_^l, ixr_srl_^l
13
14 ! index ranges of staggered variables to send (S) to sibling blocks, receive (R) from sibling blocks
15 integer, dimension(^ND,-1:1) :: ixs_srl_stg_^l, ixr_srl_stg_^l
16
17 ! index ranges to send (S) restricted (r) ghost cells to coarser blocks
18 integer, dimension(-1:1) :: ixs_r_^l
19
20 ! index ranges of staggered variables to send (S) restricted (r) ghost cells to coarser blocks
21 integer, dimension(^ND,-1:1) :: ixs_r_stg_^l
22
23 ! index ranges to receive restriced ghost cells from finer blocks
24 integer, dimension(0:3) :: ixr_r_^l
25
26 ! index ranges of staggered variables to receive restriced ghost cells from finer blocks
27 integer, dimension(^ND,0:3) :: ixr_r_stg_^l
28
29 ! send prolongated (p) ghost cells to finer blocks, receive prolongated from coarser blocks
30 integer, dimension(0:3) :: ixs_p_^l, ixr_p_^l
31
32 ! send prolongated (p) staggered ghost cells to finer blocks, receive prolongated from coarser blocks
33 integer, dimension(^ND,0:3) :: ixs_p_stg_^l, ixr_p_stg_^l
34
35 ! number of MPI receive-send pairs, srl: same refinement level; r: restrict; p: prolong
37
38 ! record index position of buffer arrays
40
41 ! count of times of send and receive
43
44 ! count of times of send and receive for cell center ghost cells
45 integer :: isend_c, irecv_c
46
47 ! tag of MPI send and recv
48 integer, private :: itag
49
50 ! total sizes = cell-center normal flux + stagger-grid flux of send and receive
51 integer, dimension(-1:1^D&) :: sizes_srl_send_total, sizes_srl_recv_total
52
53 ! sizes of buffer arrays for center-grid variable for siblings and restrict
54 integer, dimension(:), allocatable :: recvrequest_c_sr, sendrequest_c_sr
55 integer, dimension(:,:), allocatable :: recvstatus_c_sr, sendstatus_c_sr
56
57 ! sizes of buffer arrays for center-grid variable for prolongation
58 integer, dimension(:), allocatable :: recvrequest_c_p, sendrequest_c_p
59 integer, dimension(:,:), allocatable :: recvstatus_c_p, sendstatus_c_p
60
61 ! sizes of buffer arrays for stagger-grid variable
62 integer, dimension(^ND,-1:1^D&) :: sizes_srl_send_stg, sizes_srl_recv_stg
63
64 integer, dimension(:), allocatable :: recvrequest_srl, sendrequest_srl
65 integer, dimension(:,:), allocatable :: recvstatus_srl, sendstatus_srl
66
67 ! buffer arrays for send and receive of siblings, allocate in build_connectivity
68 double precision, dimension(:), allocatable :: recvbuffer_srl, sendbuffer_srl
69
70 integer, dimension(:), allocatable :: recvrequest_r, sendrequest_r
71 integer, dimension(:,:), allocatable :: recvstatus_r, sendstatus_r
72
73 ! buffer arrays for send and receive in restriction
74 double precision, dimension(:), allocatable :: recvbuffer_r, sendbuffer_r
75
76 integer, dimension(:), allocatable :: recvrequest_p, sendrequest_p
77 integer, dimension(:,:), allocatable :: recvstatus_p, sendstatus_p
78
79 ! buffer arrays for send and receive in prolongation
80 double precision, dimension(:), allocatable :: recvbuffer_p, sendbuffer_p
81
82 ! sizes to allocate buffer arrays for send and receive for restriction
83 integer, dimension(-1:1^D&) :: sizes_r_send_total
84 integer, dimension(0:3^D&) :: sizes_r_recv_total
85 integer, dimension(^ND,-1:1^D&) :: sizes_r_send_stg
86 integer, dimension(^ND,0:3^D&) :: sizes_r_recv_stg
87
88 ! sizes to allocate buffer arrays for send and receive for restriction
89 integer, dimension(0:3^D&) :: sizes_p_send_total, sizes_p_recv_total
90 integer, dimension(^ND,0:3^D&) :: sizes_p_send_stg, sizes_p_recv_stg
91
92 ! There are two variants, _f indicates that all flux variables are filled,
93 ! whereas _p means that part of the variables is filled
94 ! Furthermore _r_ stands for restrict, _p_ for prolongation.
95 integer, dimension(-1:1^D&), target :: type_send_srl_f, type_recv_srl_f
96 integer, dimension(-1:1^D&), target :: type_send_r_f
97 integer, dimension( 0:3^D&), target :: type_recv_r_f, type_send_p_f, type_recv_p_f
98 integer, dimension(-1:1^D&), target :: type_send_srl_p1, type_recv_srl_p1
99 integer, dimension(-1:1^D&), target :: type_send_r_p1
100 integer, dimension( 0:3^D&), target :: type_recv_r_p1, type_send_p_p1, type_recv_p_p1
101 integer, dimension(-1:1^D&), target :: type_send_srl_p2, type_recv_srl_p2
102 integer, dimension(-1:1^D&), target :: type_send_r_p2
103 integer, dimension( 0:3^D&), target :: type_recv_r_p2, type_send_p_p2, type_recv_p_p2
104 integer, dimension( :^D&), pointer :: type_send_srl, type_recv_srl, type_send_r
105 integer, dimension( :^D&), pointer :: type_recv_r, type_send_p, type_recv_p
106
107 ! A switch of update physical boundary or not
108 logical, public :: bcphys=.true.
109 ! Special buffer for pole copy
111 double precision, dimension(:^D&,:), allocatable :: w
112 end type wbuffer
113
114 abstract interface
115 subroutine update_eos_bc_sub(ixI^L, ixO^L, w, x)
117 integer, intent(in) :: ixI^L, ixO^L
118 double precision, intent(inout) :: w(ixI^S, nw)
119 double precision, intent(in) :: x(ixI^S, 1:ndim)
120 end subroutine update_eos_bc_sub
121 end interface
122
123 procedure(update_eos_bc_sub), pointer :: update_eos_4_bc => null()
124
125contains
126
127 subroutine init_bc()
129 use mod_physics, only: physics_type
130 use mod_comm_lib, only: mpistop
131
132 integer :: nghostcellsCo, interpolation_order
133 integer :: nx^D, nxCo^D, ixG^L, i^D, idir
134
135 ! Initialise all bc datatype handles to null so get_bc_comm_type can free the previous committed type
136 ! before rebuilding. Without this, every create_bc_mpi_datatype leaks its MPI subarray types; the RT
137 ! sweep rebuilds them each solve -> unbounded virtual-memory growth -> OOM/SIGKILL on long runs.
138 type_send_srl_f=mpi_datatype_null; type_recv_srl_f=mpi_datatype_null
139 type_send_r_f =mpi_datatype_null; type_recv_r_f =mpi_datatype_null
140 type_send_p_f =mpi_datatype_null; type_recv_p_f =mpi_datatype_null
141 type_send_srl_p1=mpi_datatype_null; type_recv_srl_p1=mpi_datatype_null
142 type_send_r_p1 =mpi_datatype_null; type_recv_r_p1 =mpi_datatype_null
143 type_send_p_p1 =mpi_datatype_null; type_recv_p_p1 =mpi_datatype_null
144 type_send_srl_p2=mpi_datatype_null; type_recv_srl_p2=mpi_datatype_null
145 type_send_r_p2 =mpi_datatype_null; type_recv_r_p2 =mpi_datatype_null
146 type_send_p_p2 =mpi_datatype_null; type_recv_p_p2 =mpi_datatype_null
147
148 ixg^l=ixg^ll;
149 ixm^l=ixg^l^lsubnghostcells;
150 ixcogmin^d=1;
151 ixcogmax^d=(ixghi^d-2*nghostcells)/2+2*nghostcells;
152 ixcogsmin^d=0;
153 ixcogsmax^d=ixcogmax^d;
154
155 ixcom^l=ixcog^l^lsubnghostcells;
156
157 nx^d=ixmmax^d-ixmmin^d+1;
158 nxco^d=nx^d/2;
159
160 if(ghost_copy) then
161 interpolation_order=1
162 else
163 interpolation_order=2
164 end if
165 nghostcellsco=int((nghostcells+1)/2)
166
167 if (nghostcellsco+interpolation_order-1>nghostcells) then
168 call mpistop("interpolation order for prolongation in getbc too high")
169 end if
170
171 ! i=-1 means subregion prepared for the neighbor at its minimum side
172 ! i= 1 means subregion prepared for the neighbor at its maximum side
173 {
174 ixs_srl_min^d(-1)=ixmmin^d
175 ixs_srl_min^d( 0)=ixmmin^d
176 ixs_srl_min^d( 1)=ixmmax^d+1-nghostcells
177 ixs_srl_max^d(-1)=ixmmin^d-1+nghostcells
178 ixs_srl_max^d( 0)=ixmmax^d
179 ixs_srl_max^d( 1)=ixmmax^d
180
181 ixr_srl_min^d(-1)=1
182 ixr_srl_min^d( 0)=ixmmin^d
183 ixr_srl_min^d( 1)=ixmmax^d+1
184 ixr_srl_max^d(-1)=nghostcells
185 ixr_srl_max^d( 0)=ixmmax^d
186 ixr_srl_max^d( 1)=ixgmax^d
187
188 ixs_r_min^d(-1)=ixcommin^d
189 ixs_r_min^d( 0)=ixcommin^d
190 ixs_r_min^d( 1)=ixcommax^d+1-nghostcells
191 ixs_r_max^d(-1)=ixcommin^d-1+nghostcells
192 ixs_r_max^d( 0)=ixcommax^d
193 ixs_r_max^d( 1)=ixcommax^d
194
195 ixr_r_min^d(0)=1
196 ixr_r_min^d(1)=ixmmin^d
197 ixr_r_min^d(2)=ixmmin^d+nxco^d
198 ixr_r_min^d(3)=ixmmax^d+1
199 ixr_r_max^d(0)=nghostcells
200 ixr_r_max^d(1)=ixmmin^d-1+nxco^d
201 ixr_r_max^d(2)=ixmmax^d
202 ixr_r_max^d(3)=ixgmax^d
203
204 ixs_p_min^d(0)=ixmmin^d-(interpolation_order-1)
205 ixs_p_min^d(1)=ixmmin^d-(interpolation_order-1)
206 ixs_p_min^d(2)=ixmmin^d+nxco^d-nghostcellsco-(interpolation_order-1)
207 ixs_p_min^d(3)=ixmmax^d+1-nghostcellsco-(interpolation_order-1)
208 ixs_p_max^d(0)=ixmmin^d-1+nghostcellsco+(interpolation_order-1)
209 ixs_p_max^d(1)=ixmmin^d-1+nxco^d+nghostcellsco+(interpolation_order-1)
210 ixs_p_max^d(2)=ixmmax^d+(interpolation_order-1)
211 ixs_p_max^d(3)=ixmmax^d+(interpolation_order-1)
212
213 ixr_p_min^d(0)=ixcommin^d-nghostcellsco-(interpolation_order-1)
214 ixr_p_min^d(1)=ixcommin^d-(interpolation_order-1)
215 ixr_p_min^d(2)=ixcommin^d-nghostcellsco-(interpolation_order-1)
216 ixr_p_min^d(3)=ixcommax^d+1-(interpolation_order-1)
217 ixr_p_max^d(0)=nghostcells+(interpolation_order-1)
218 ixr_p_max^d(1)=ixcommax^d+nghostcellsco+(interpolation_order-1)
219 ixr_p_max^d(2)=ixcommax^d+(interpolation_order-1)
220 ixr_p_max^d(3)=ixcommax^d+nghostcellsco+(interpolation_order-1)
221
222 \}
223
224 if (stagger_grid) then
225 allocate(pole_buf%ws(ixgs^t,nws))
226 ! Staggered (face-allocated) variables
227 do idir=1,ndim
228 { ixs_srl_stg_min^d(idir,-1)=ixmmin^d-kr(idir,^d)
229 ixs_srl_stg_max^d(idir,-1)=ixmmin^d-1+nghostcells
230 ixs_srl_stg_min^d(idir,0) =ixmmin^d-kr(idir,^d)
231 ixs_srl_stg_max^d(idir,0) =ixmmax^d
232 ixs_srl_stg_min^d(idir,1) =ixmmax^d-nghostcells+1-kr(idir,^d)
233 ixs_srl_stg_max^d(idir,1) =ixmmax^d
234
235 ixr_srl_stg_min^d(idir,-1)=1-kr(idir,^d)
236 ixr_srl_stg_max^d(idir,-1)=nghostcells
237 ixr_srl_stg_min^d(idir,0) =ixmmin^d-kr(idir,^d)
238 ixr_srl_stg_max^d(idir,0) =ixmmax^d
239 ixr_srl_stg_min^d(idir,1) =ixmmax^d+1-kr(idir,^d)
240 ixr_srl_stg_max^d(idir,1) =ixgmax^d
241
242 ixs_r_stg_min^d(idir,-1)=ixcommin^d-kr(idir,^d)
243 ixs_r_stg_max^d(idir,-1)=ixcommin^d-1+nghostcells
244 ixs_r_stg_min^d(idir,0) =ixcommin^d-kr(idir,^d)
245 ixs_r_stg_max^d(idir,0) =ixcommax^d
246 ixs_r_stg_min^d(idir,1) =ixcommax^d+1-nghostcells-kr(idir,^d)
247 ixs_r_stg_max^d(idir,1) =ixcommax^d
248
249 ixr_r_stg_min^d(idir,0)=1-kr(idir,^d)
250 ixr_r_stg_max^d(idir,0)=nghostcells
251 ixr_r_stg_min^d(idir,1)=ixmmin^d-kr(idir,^d)
252 ixr_r_stg_max^d(idir,1)=ixmmin^d-1+nxco^d
253 ixr_r_stg_min^d(idir,2)=ixmmin^d+nxco^d-kr(idir,^d)
254 ixr_r_stg_max^d(idir,2)=ixmmax^d
255 ixr_r_stg_min^d(idir,3)=ixmmax^d+1-kr(idir,^d)
256 ixr_r_stg_max^d(idir,3)=ixgmax^d
257 \}
258 {if (idir==^d) then
259 ! Parallel components
260 {
261 ixs_p_stg_min^d(idir,0)=ixmmin^d-1 ! -1 to make redundant
262 ixs_p_stg_max^d(idir,0)=ixmmin^d-1+nghostcellsco
263 ixs_p_stg_min^d(idir,1)=ixmmin^d-1 ! -1 to make redundant
264 ixs_p_stg_max^d(idir,1)=ixmmin^d-1+nxco^d+nghostcellsco
265 ixs_p_stg_min^d(idir,2)=ixmmax^d-nxco^d-nghostcellsco
266 ixs_p_stg_max^d(idir,2)=ixmmax^d
267 ixs_p_stg_min^d(idir,3)=ixmmax^d-nghostcellsco
268 ixs_p_stg_max^d(idir,3)=ixmmax^d
269
270 ixr_p_stg_min^d(idir,0)=ixcommin^d-1-nghostcellsco
271 ixr_p_stg_max^d(idir,0)=ixcommin^d-1
272 ixr_p_stg_min^d(idir,1)=ixcommin^d-1 ! -1 to make redundant
273 ixr_p_stg_max^d(idir,1)=ixcommax^d+nghostcellsco
274 ixr_p_stg_min^d(idir,2)=ixcommin^d-1-nghostcellsco
275 ixr_p_stg_max^d(idir,2)=ixcommax^d
276 ixr_p_stg_min^d(idir,3)=ixcommax^d+1-1 ! -1 to make redundant
277 ixr_p_stg_max^d(idir,3)=ixcommax^d+nghostcellsco
278 \}
279 else
280 {
281 ! Perpendicular component
282 ixs_p_stg_min^d(idir,0)=ixmmin^d
283 ixs_p_stg_max^d(idir,0)=ixmmin^d-1+nghostcellsco+(interpolation_order-1)
284 ixs_p_stg_min^d(idir,1)=ixmmin^d
285 ixs_p_stg_max^d(idir,1)=ixmmin^d-1+nxco^d+nghostcellsco+(interpolation_order-1)
286 ixs_p_stg_min^d(idir,2)=ixmmax^d+1-nxco^d-nghostcellsco-(interpolation_order-1)
287 ixs_p_stg_max^d(idir,2)=ixmmax^d
288 ixs_p_stg_min^d(idir,3)=ixmmax^d+1-nghostcellsco-(interpolation_order-1)
289 ixs_p_stg_max^d(idir,3)=ixmmax^d
290
291 ixr_p_stg_min^d(idir,0)=ixcommin^d-nghostcellsco-(interpolation_order-1)
292 ixr_p_stg_max^d(idir,0)=ixcommin^d-1
293 ixr_p_stg_min^d(idir,1)=ixcommin^d
294 ixr_p_stg_max^d(idir,1)=ixcommax^d+nghostcellsco+(interpolation_order-1)
295 ixr_p_stg_min^d(idir,2)=ixcommin^d-nghostcellsco-(interpolation_order-1)
296 ixr_p_stg_max^d(idir,2)=ixcommax^d
297 ixr_p_stg_min^d(idir,3)=ixcommax^d+1
298 ixr_p_stg_max^d(idir,3)=ixcommax^d+nghostcellsco+(interpolation_order-1)
299 \}
300 end if
301 }
302 end do
303 ! calculate sizes for buffer arrays for siblings
304 {do i^db=-1,1\}
305 ! Staggered (face-allocated) variables
306 do idir=1,ndim
307 sizes_srl_send_stg(idir,i^d)={(ixs_srl_stg_max^d(idir,i^d)-ixs_srl_stg_min^d(idir,i^d)+1)|*}
308 sizes_srl_recv_stg(idir,i^d)={(ixr_srl_stg_max^d(idir,i^d)-ixr_srl_stg_min^d(idir,i^d)+1)|*}
309 sizes_r_send_stg(idir,i^d)={(ixs_r_stg_max^d(idir,i^d)-ixs_r_stg_min^d(idir,i^d)+1)|*}
310 end do
313 sizes_r_send_total(i^d)=sum(sizes_r_send_stg(:,i^d))
314 {end do\}
315
316 {do i^db=0,3\}
317 ! Staggered (face-allocated) variables
318 do idir=1,ndim
319 sizes_r_recv_stg(idir,i^d)={(ixr_r_stg_max^d(idir,i^d)-ixr_r_stg_min^d(idir,i^d)+1)|*}
320 sizes_p_send_stg(idir,i^d)={(ixs_p_stg_max^d(idir,i^d)-ixs_p_stg_min^d(idir,i^d)+1)|*}
321 sizes_p_recv_stg(idir,i^d)={(ixr_p_stg_max^d(idir,i^d)-ixr_p_stg_min^d(idir,i^d)+1)|*}
322 end do
323 sizes_r_recv_total(i^d)=sum(sizes_r_recv_stg(:,i^d))
324 sizes_p_send_total(i^d)=sum(sizes_p_send_stg(:,i^d))
325 sizes_p_recv_total(i^d)=sum(sizes_p_recv_stg(:,i^d))
326 {end do\}
327 end if
328
329 end subroutine init_bc
330
331 subroutine create_bc_mpi_datatype(nwstart,nwbc,nwfull)
333
334 integer, intent(in) :: nwstart, nwbc
335 !> stride of the target state (its last-dim size); defaults to global nw. See get_bc_comm_type.
336 integer, intent(in), optional :: nwfull
337 integer :: i^D, ic^D, inc^D
338 integer :: errh_w, errh_s
339
340 ! get_bc_comm_type frees the previous committed type before rebuilding (else the RT sweep, which
341 ! rebuilds these every solve, leaks MPI subarray types -> unbounded virtual memory -> OOM). Some
342 ! degenerate restrict/prolong handles reject MPI_TYPE_FREE on this MPI, so make the free best-effort:
343 ! set the error handler to return for the rebuild, so a failed free is ignored (that one type leaks,
344 ! minor) while all valid frees succeed; a successful create always overwrites the handle. Restore after.
345 call mpi_comm_get_errhandler(mpi_comm_world, errh_w, ierrmpi)
346 call mpi_comm_get_errhandler(mpi_comm_self, errh_s, ierrmpi)
347 call mpi_comm_set_errhandler(mpi_comm_world, mpi_errors_return, ierrmpi)
348 call mpi_comm_set_errhandler(mpi_comm_self, mpi_errors_return, ierrmpi)
349
350 {do i^db=-1,1\}
351 if(i^d==0|.and.) cycle
352 call get_bc_comm_type(type_send_srl(i^d),ixs_srl_^l(i^d),ixg^ll,nwstart,nwbc,nwfull)
353 call get_bc_comm_type(type_recv_srl(i^d),ixr_srl_^l(i^d),ixg^ll,nwstart,nwbc,nwfull)
354 call get_bc_comm_type(type_send_r(i^d), ixs_r_^l(i^d),ixcog^l,nwstart,nwbc,nwfull)
355 {do ic^db=1+int((1-i^db)/2),2-int((1+i^db)/2)
356 inc^db=2*i^db+ic^db\}
357 call get_bc_comm_type(type_recv_r(inc^d),ixr_r_^l(inc^d), ixg^ll,nwstart,nwbc,nwfull)
358 call get_bc_comm_type(type_send_p(inc^d),ixs_p_^l(inc^d), ixg^ll,nwstart,nwbc,nwfull)
359 call get_bc_comm_type(type_recv_p(inc^d),ixr_p_^l(inc^d),ixcog^l,nwstart,nwbc,nwfull)
360 {end do\}
361 {end do\}
362
363 call mpi_comm_set_errhandler(mpi_comm_world, errh_w, ierrmpi) ! restore fatal handlers
364 call mpi_comm_set_errhandler(mpi_comm_self, errh_s, ierrmpi)
365
366 end subroutine create_bc_mpi_datatype
367
368 subroutine get_bc_comm_type(comm_type,ix^L,ixG^L,nwstart,nwbc,nwfull)
370
371 integer, intent(inout) :: comm_type
372 integer, intent(in) :: ix^L, ixG^L, nwstart, nwbc
373 !> total number of w-variables in the target state's last dimension (its stride). Defaults to the
374 !> global nw (the hydro state). Pass the actual nw of a separate state (e.g. the RT intensity state,
375 !> nw=nisw) so the MPI subarray stride matches that array's layout.
376 integer, intent(in), optional :: nwfull
377
378 integer, dimension(ndim+1) :: fullsize, subsize, start
379
380 ^d&fullsize(^d)=ixgmax^d;
381 fullsize(ndim+1)=nw
382 if(present(nwfull)) fullsize(ndim+1)=nwfull
383 ^d&subsize(^d)=ixmax^d-ixmin^d+1;
384 subsize(ndim+1)=nwbc
385 ^d&start(^d)=ixmin^d-1;
386 start(ndim+1)=nwstart-1
387
388 if(comm_type/=mpi_datatype_null) call mpi_type_free(comm_type,ierrmpi) ! free the previous type (no leak)
389 call mpi_type_create_subarray(ndim+1,fullsize,subsize,start,mpi_order_fortran, &
390 mpi_double_precision,comm_type,ierrmpi)
391 call mpi_type_commit(comm_type,ierrmpi)
392
393 end subroutine get_bc_comm_type
394
395 !> do update ghost cells of all blocks including physical boundaries
396 subroutine getbc(time,qdt,psb,nwstart,nwbc)
398 use mod_physics
400 use mod_coarsen, only: coarsen_grid
402 use mod_comm_lib, only: mpistop
403
404 double precision, intent(in) :: time, qdt
405 type(state), target :: psb(max_blocks)
406 integer, intent(in) :: nwstart ! Fill from nwstart
407 integer, intent(in) :: nwbc ! Number of variables to fill
408
409 double precision :: time_bcin
410 integer :: nwhead, nwtail
411 integer :: iigrid, igrid, isizes, i^D
412 integer :: isend_buf(npwbuf), ipwbuf, nghostcellsco
413 integer :: flushed_send_c, flushed_send_srl, flushed_send_r, flushed_send_p
414 ! index pointer for buffer arrays as a start for a segment
415 integer :: ibuf_start, ibuf_next
416 ! shapes of reshape
417 integer, dimension(1) :: shapes
418 type(wbuffer) :: pwbuf(npwbuf)
419
420 time_bcin=mpi_wtime()
421
422 nwhead=nwstart
423 nwtail=nwstart+nwbc-1
424
425 ! fill internal physical boundary
426 if (internalboundary) then
427 call getintbc(time,qdt,ixg^ll)
428 end if
429
430 ! prepare coarse values to send to coarser neighbors
431 !$OMP PARALLEL DO SCHEDULE(dynamic) PRIVATE(igrid)
432 do iigrid=1,igridstail; igrid=igrids(iigrid);
433 if(any(neighbor_type(:^d&,igrid)==neighbor_coarse)) then
434 call coarsen_grid(psb(igrid),ixg^ll,ixm^l,psc(igrid),ixcog^l,ixcom^l)
435 end if
436 end do
437 !$OMP END PARALLEL DO
438
439 ! default : no singular axis
440 irecv_c=0
441 isend_c=0
442 flushed_send_c=0
443 flushed_send_srl=0
444 flushed_send_r=0
445 flushed_send_p=0
446 isend_buf=0
447 ipwbuf=1
448
449 if(stagger_grid) then
456 irecv_srl=0
457 irecv_r=0
458 irecv_p=0
459 isend_srl=0
460 isend_r=0
461 isend_p=0
462 end if
463
464 !$OMP PARALLEL SECTIONS PRIVATE(iigrid,igrid,i^D)
465 !$OMP SECTION
466 ! MPI receive ghost-cell values from sibling blocks and finer neighbors in different processors
467 do iigrid=1,igridstail; igrid=igrids(iigrid);
468 {do i^db=-1,1\}
469 if (skip_direction([ i^d ])) cycle
470 select case (neighbor_type(i^d,igrid))
471 case (neighbor_sibling)
472 call bc_recv_srl(igrid,i^d)
473 case (neighbor_fine)
474 call bc_recv_restrict(igrid,i^d)
475 end select
476 {end do\}
477 end do
478
479 ! MPI send ghost-cell values to sibling blocks and coarser neighbors in different processors
480 do iigrid=1,igridstail; igrid=igrids(iigrid);
481 {do i^db=-1,1\}
482 if(skip_direction([ i^d ])) cycle
483 select case (neighbor_type(i^d,igrid))
484 case (neighbor_sibling)
485 call bc_send_srl(igrid,i^d)
486 case (neighbor_coarse)
487 call bc_send_restrict(igrid,i^d)
488 end select
489 {end do\}
490 end do
491
493 call waitall_pending(isend_c,flushed_send_c,sendrequest_c_sr,sendstatus_c_sr)
494 if(stagger_grid) then
496 call waitall_pending(nsend_bc_srl,flushed_send_srl,sendrequest_srl,sendstatus_srl)
498 call waitall_pending(nsend_bc_r,flushed_send_r,sendrequest_r,sendstatus_r)
499 end if
500
501 do ipwbuf=1,npwbuf
502 if (isend_buf(ipwbuf)/=0) deallocate(pwbuf(ipwbuf)%w)
503 end do
504 !$OMP SECTION
505 ! fill ghost-cell values of sibling blocks and coarser neighbors in the same processor
506 do iigrid=1,igridstail; igrid=igrids(iigrid);
507 {do i^db=-1,1\}
508 if(skip_direction([ i^d ])) cycle
509 select case (neighbor_type(i^d,igrid))
510 case(neighbor_sibling)
511 call bc_fill_srl(igrid,i^d)
512 case(neighbor_coarse)
513 call bc_fill_restrict(igrid,i^d)
514 end select
515 {end do\}
516 end do
517 !$OMP END PARALLEL SECTIONS
518
519 if(stagger_grid) then
520 ! unpack the received data from sibling blocks and finer neighbors to fill ghost-cell staggered values
523 do iigrid=1,igridstail; igrid=igrids(iigrid);
524 {do i^db=-1,1\}
525 if (skip_direction([ i^d ])) cycle
526 select case (neighbor_type(i^d,igrid))
527 case (neighbor_sibling)
528 call bc_fill_srl_stg(igrid,i^d)
529 case (neighbor_fine)
530 call bc_fill_restrict_stg(igrid,i^d)
531 end select
532 {end do\}
533 end do
534 end if
535
536 irecv_c=0
537 isend_c=0
538 flushed_send_c=0
539 flushed_send_p=0
540 isend_buf=0
541 ipwbuf=1
542
543 !$OMP PARALLEL SECTIONS PRIVATE(iigrid,igrid,i^D)
544 !$OMP SECTION
545 ! MPI receive ghost-cell values from coarser neighbors in different processors
546 do iigrid=1,igridstail; igrid=igrids(iigrid);
547 {do i^db=-1,1\}
548 if (skip_direction([ i^d ])) cycle
549 if (neighbor_type(i^d,igrid)==neighbor_coarse) call bc_recv_prolong(igrid,i^d)
550 {end do\}
551 end do
552 ! MPI send ghost-cell values to finer neighbors in different processors
553 do iigrid=1,igridstail; igrid=igrids(iigrid);
554 {do i^db=-1,1\}
555 if (skip_direction([ i^d ])) cycle
556 if (neighbor_type(i^d,igrid)==neighbor_fine) call bc_send_prolong(igrid,i^d)
557 {end do\}
558 end do
559
561 call waitall_pending(isend_c,flushed_send_c,sendrequest_c_p,sendstatus_c_p)
562
563 if(stagger_grid) then
565 call waitall_pending(nsend_bc_p,flushed_send_p,sendrequest_p,sendstatus_p)
566 end if
567
568 do ipwbuf=1,npwbuf
569 if (isend_buf(ipwbuf)/=0) deallocate(pwbuf(ipwbuf)%w)
570 end do
571
572 !$OMP SECTION
573 ! fill coarse ghost-cell values of finer neighbors in the same processor
574 do iigrid=1,igridstail; igrid=igrids(iigrid);
575 {do i^db=-1,1\}
576 if (skip_direction([ i^d ])) cycle
577 if (neighbor_type(i^d,igrid)==neighbor_fine) call bc_fill_prolong(igrid,i^d)
578 {end do\}
579 end do
580 !$OMP END PARALLEL SECTIONS
581
582 if(stagger_grid) then
583 ! fill coarser representative ghost cells after receipt
585 do iigrid=1,igridstail; igrid=igrids(iigrid);
586 {do i^db=-1,1\}
587 if (skip_direction([ i^d ])) cycle
588 if(neighbor_type(i^d,igrid)==neighbor_coarse) call bc_fill_prolong_stg(igrid,i^d)
589 {end do\}
590 end do
591 end if
592 ! do prolongation on the ghost-cell values based on the received coarse values from coarser neighbors
593 !$OMP PARALLEL DO SCHEDULE(dynamic) PRIVATE(igrid)
594 do iigrid=1,igridstail; igrid=igrids(iigrid);
595 call gc_prolong(igrid)
596 end do
597 !$OMP END PARALLEL DO
598
599 ! fill physical boundary ghost cells after internal ghost-cell values exchange
600 if(bcphys) then
601 if(associated(usr_prepare_boundary)) then
602 call usr_prepare_boundary(time, qdt)
603 endif
604 !$OMP PARALLEL DO SCHEDULE(dynamic) PRIVATE(igrid)
605 do iigrid=1,igridstail; igrid=igrids(iigrid);
606 if(.not.phyboundblock(igrid)) cycle
607 call fill_boundary_after_gc(igrid)
608 end do
609 !$OMP END PARALLEL DO
610 end if
611
612 ! modify normal component of magnetic field to fix divB=0
613 if(bcphys.and.associated(phys_boundary_adjust)) then
614 !$OMP PARALLEL DO SCHEDULE(dynamic) PRIVATE(igrid)
615 do iigrid=1,igridstail; igrid=igrids(iigrid);
616 if(.not.phyboundblock(igrid)) cycle
617 call phys_boundary_adjust(igrid,psb)
618 end do
619 !$OMP END PARALLEL DO
620 end if
621
622 time_bc=time_bc+(mpi_wtime()-time_bcin)
623
624 contains
625
626 subroutine waitall_limited(nrequest,requests,statuses)
627 integer, intent(in) :: nrequest
628 integer, intent(inout) :: requests(:)
629 integer, intent(inout) :: statuses(:,:)
630
631 if (ghostcell_comm_batched) then
632 call waitall_range(1,nrequest,requests,statuses)
633 else
634 call mpi_waitall(nrequest,requests,statuses,ierrmpi)
635 end if
636 end subroutine waitall_limited
637
638 subroutine waitall_range(ifirst,ilast,requests,statuses)
639 integer, intent(in) :: ifirst, ilast
640 integer, intent(inout) :: requests(:)
641 integer, intent(inout) :: statuses(:,:)
642
643 integer :: irequest,nwait
644
645 do irequest=ifirst,ilast,ghostcell_comm_batch_size
646 nwait=min(ghostcell_comm_batch_size,ilast-irequest+1)
647 call mpi_waitall(nwait,requests(irequest:irequest+nwait-1),&
648 statuses(:,irequest:irequest+nwait-1),ierrmpi)
649 end do
650 end subroutine waitall_range
651
652 subroutine waitall_pending(nrequest,nwaited,requests,statuses)
653 integer, intent(in) :: nrequest
654 integer, intent(inout) :: nwaited
655 integer, intent(inout) :: requests(:)
656 integer, intent(inout) :: statuses(:,:)
657
658 if (nrequest>nwaited) then
659 if (ghostcell_comm_batched) then
660 call waitall_range(nwaited+1,nrequest,requests,statuses)
661 else
662 call mpi_waitall(nrequest-nwaited,requests(nwaited+1:nrequest),&
663 statuses(:,nwaited+1:nrequest),ierrmpi)
664 end if
665 nwaited=nrequest
666 end if
667 end subroutine waitall_pending
668
669 subroutine wait_send_batch(nrequest,nwaited,requests,statuses)
670 integer, intent(in) :: nrequest
671 integer, intent(inout) :: nwaited
672 integer, intent(inout) :: requests(:)
673 integer, intent(inout) :: statuses(:,:)
674
675 if (ghostcell_comm_batched .and. &
676 nrequest-nwaited >= ghostcell_comm_batch_size) then
677 call waitall_range(nwaited+1,nrequest,requests,statuses)
678 nwaited=nrequest
679 end if
680 end subroutine wait_send_batch
681
682 logical function skip_direction(dir)
683 integer, intent(in) :: dir(^ND)
684
685 if (all(dir == 0)) then
686 skip_direction = .true.
687 else
688 skip_direction = .false.
689 end if
690 end function skip_direction
691
692 !> Physical boundary conditions
693 subroutine fill_boundary_after_gc(igrid)
694
695 integer, intent(in) :: igrid
696
697 integer :: idims,iside,i^D,k^L,ixB^L,ixO^L
698 logical :: has_eos_bc
699
700 !> Query the hook once: gfortran resolves the symbol as a procedure after the
701 !> first call statement and then rejects associated() on it later in the scope.
702 has_eos_bc = associated(update_eos_4_bc)
703 block=>psb(igrid)
704 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
705 do idims=1,ndim
706 ! to avoid using as yet unknown corner info in more than 1D, we
707 ! fill only interior mesh ranges of the ghost cell ranges at first,
708 ! and progressively enlarge the ranges to include corners later
709 kmin1=0; kmax1=0;
710 {^iftwod
711 kmin2=merge(1, 0, idims .lt. 2 .and. neighbor_type(0,-1,igrid)==1)
712 kmax2=merge(1, 0, idims .lt. 2 .and. neighbor_type(0, 1,igrid)==1)}
713 {^ifthreed
714 kmin2=merge(1, 0, idims .lt. 2 .and. neighbor_type(0,-1,0,igrid)==1)
715 kmax2=merge(1, 0, idims .lt. 2 .and. neighbor_type(0, 1,0,igrid)==1)
716 kmin3=merge(1, 0, idims .lt. 3 .and. neighbor_type(0,0,-1,igrid)==1)
717 kmax3=merge(1, 0, idims .lt. 3 .and. neighbor_type(0,0, 1,igrid)==1)}
718 ixbmin^d=ixglo^d+kmin^d*nghostcells;
719 ixbmax^d=ixghi^d-kmax^d*nghostcells;
720 do iside=1,2
721 i^d=kr(^d,idims)*(2*iside-3);
722 if (aperiodb(idims)) then
723 if (neighbor_type(i^d,igrid) /= neighbor_boundary .and. &
724 .not. psb(igrid)%is_physical_boundary(2*idims-2+iside)) cycle
725 else
726 if (neighbor_type(i^d,igrid) /= neighbor_boundary) cycle
727 end if
728 !> Refresh the EoS-derived ghost fields before extrapolation; the hook
729 !> is set (in amrvac.t) only when the EoS needs it, e.g. LTE.
730 !> ixM (interior) is deliberate: bc_phys extrapolates outward from interior
731 !> values, so it is the interior that must be current here. Ghost cells are
732 !> covered afterwards, for every block, at the end of getbc.
733 if (has_eos_bc) &
734 call update_eos_4_bc(ixg^ll,ixm^ll,psb(igrid)%w,psb(igrid)%x)
735 call bc_phys(iside,idims,time,qdt,psb(igrid),ixg^ll,ixb^l)
736 !> ...and derive them again on the cells bc_phys just wrote. The call above
737 !> refreshes the interior so bc_phys can extrapolate outward from current values;
738 !> it does not touch the ghosts bc_phys produces. Those are never reached by the
739 !> exchange either (physical boundaries have no neighbour to receive from), so
740 !> without this they keep whatever the block held before. ixO is the same ghost
741 !> strip bc_phys derives internally from ixB -- nghostcells deep, this side only.
742 if (has_eos_bc) then
743 select case (idims)
744 {case (^d)
745 if (iside==2) then
746 ixomin^dd=ixbmax^d+1-nghostcells^d%ixOmin^dd=ixbmin^dd;
747 ixomax^dd=ixbmax^dd;
748 else
749 ixomin^dd=ixbmin^dd;
750 ixomax^dd=ixbmin^d-1+nghostcells^d%ixOmax^dd=ixbmax^dd;
751 end if \}
752 end select
753 call update_eos_4_bc(ixg^ll,ixo^l,psb(igrid)%w,psb(igrid)%x)
754 end if
755 end do
756 end do
757
758 end subroutine fill_boundary_after_gc
759
760 !> MPI receive from sibling at same refinement level
761 subroutine bc_recv_srl(igrid,i^D)
762 integer, intent(in) :: igrid,i^D
763
764 integer :: ipe_neighbor
765
766 ipe_neighbor=neighbor(2,i^d,igrid)
767 if (ipe_neighbor/=mype) then
769 itag=(3**^nd+4**^nd)*(igrid-1)+{(i^d+1)*3**(^d-1)+}
770 call mpi_irecv(psb(igrid)%w,1,type_recv_srl(i^d), &
771 ipe_neighbor,itag,icomm,recvrequest_c_sr(irecv_c),ierrmpi)
772 if(stagger_grid) then
774 call mpi_irecv(recvbuffer_srl(ibuf_recv_srl),sizes_srl_recv_total(i^d),mpi_double_precision, &
775 ipe_neighbor,itag,icomm,recvrequest_srl(irecv_srl),ierrmpi)
777 end if
778 end if
779
780 end subroutine bc_recv_srl
781
782 !> MPI receive from fine neighbor
783 subroutine bc_recv_restrict(igrid,i^D)
784 integer, intent(in) :: igrid,i^D
785
786 integer :: ic^D,inc^D,ipe_neighbor
787
788 {do ic^db=1+int((1-i^db)/2),2-int((1+i^db)/2)
789 inc^db=2*i^db+ic^db\}
790 ipe_neighbor=neighbor_child(2,inc^d,igrid)
791 if (ipe_neighbor/=mype) then
793 itag=(3**^nd+4**^nd)*(igrid-1)+3**^nd+{inc^d*4**(^d-1)+}
794 call mpi_irecv(psb(igrid)%w,1,type_recv_r(inc^d), &
795 ipe_neighbor,itag,icomm,recvrequest_c_sr(irecv_c),ierrmpi)
796 if(stagger_grid) then
798 call mpi_irecv(recvbuffer_r(ibuf_recv_r),sizes_r_recv_total(inc^d), &
799 mpi_double_precision,ipe_neighbor,itag, &
800 icomm,recvrequest_r(irecv_r),ierrmpi)
802 end if
803 end if
804 {end do\}
805
806 end subroutine bc_recv_restrict
807
808 !> MPI send to sibling at same refinement level
809 subroutine bc_send_srl(igrid,i^D)
810 integer, intent(in) :: igrid,i^D
811
812 integer :: n_i^D,ipole,idir,ineighbor,ipe_neighbor,ixS^L
813
814 ipe_neighbor=neighbor(2,i^d,igrid)
815 if(ipe_neighbor/=mype) then
816 ineighbor=neighbor(1,i^d,igrid)
817 ipole=neighbor_pole(i^d,igrid)
818 if(ipole==0) then
819 n_i^d=-i^d;
821 itag=(3**^nd+4**^nd)*(ineighbor-1)+{(n_i^d+1)*3**(^d-1)+}
822 call mpi_isend(psb(igrid)%w,1,type_send_srl(i^d), &
823 ipe_neighbor,itag,icomm,sendrequest_c_sr(isend_c),ierrmpi)
824 call wait_send_batch(isend_c,flushed_send_c,sendrequest_c_sr,sendstatus_c_sr)
825 if(stagger_grid) then
826 ibuf_start=ibuf_send_srl
827 do idir=1,ndim
828 ixs^l=ixs_srl_stg_^l(idir,i^d);
829 ibuf_next=ibuf_start+sizes_srl_send_stg(idir,i^d)
830 shapes=(/sizes_srl_send_stg(idir,i^d)/)
831 sendbuffer_srl(ibuf_start:ibuf_next-1)=&
832 reshape(psb(igrid)%ws(ixs^s,idir),shapes)
833 ibuf_start=ibuf_next
834 end do
837 mpi_double_precision, ipe_neighbor,itag,icomm,sendrequest_srl(isend_srl),ierrmpi)
838 call wait_send_batch(isend_srl,flushed_send_srl,sendrequest_srl,sendstatus_srl)
839 ibuf_send_srl=ibuf_next
840 end if
841 else
842 ixs^l=ixs_srl_^l(i^d);
843 select case (ipole)
844 {case (^d)
845 n_i^d=i^d^d%n_i^dd=-i^dd;\}
846 end select
847 if (isend_buf(ipwbuf)/=0) then
848 call mpi_wait(sendrequest_c_sr(isend_buf(ipwbuf)), &
849 sendstatus_c_sr(:,isend_buf(ipwbuf)),ierrmpi)
850 deallocate(pwbuf(ipwbuf)%w)
851 end if
852 allocate(pwbuf(ipwbuf)%w(ixs^s,nwhead:nwtail))
853 call pole_buffer(pwbuf(ipwbuf)%w,ixs^l,ixs^l,psb(igrid)%w,ixg^ll,ixs^l,ipole)
855 isend_buf(ipwbuf)=isend_c
856 itag=(3**^nd+4**^nd)*(ineighbor-1)+{(n_i^d+1)*3**(^d-1)+}
857 isizes={(ixsmax^d-ixsmin^d+1)*}*nwbc
858 call mpi_isend(pwbuf(ipwbuf)%w,isizes,mpi_double_precision, &
859 ipe_neighbor,itag,icomm,sendrequest_c_sr(isend_c),ierrmpi)
860 call wait_send_batch(isend_c,flushed_send_c,sendrequest_c_sr,sendstatus_c_sr)
861 ipwbuf=1+modulo(ipwbuf,npwbuf)
862 if(stagger_grid) then
863 ibuf_start=ibuf_send_srl
864 do idir=1,ndim
865 ixs^l=ixs_srl_stg_^l(idir,i^d);
866 ibuf_next=ibuf_start+sizes_srl_send_stg(idir,i^d)
867 shapes=(/sizes_srl_send_stg(idir,i^d)/)
868 sendbuffer_srl(ibuf_start:ibuf_next-1)=&
869 reshape(psb(igrid)%ws(ixs^s,idir),shapes)
870 ibuf_start=ibuf_next
871 end do
874 mpi_double_precision, ipe_neighbor,itag,icomm,sendrequest_srl(isend_srl),ierrmpi)
875 call wait_send_batch(isend_srl,flushed_send_srl,sendrequest_srl,sendstatus_srl)
876 ibuf_send_srl=ibuf_next
877 end if
878 end if
879 end if
880
881 end subroutine bc_send_srl
882
883 !> MPI send to coarser neighbor's ghost cells
884 subroutine bc_send_restrict(igrid,i^D)
885 integer, intent(in) :: igrid,i^D
886
887 integer :: ic^D,n_inc^D,ipole,idir,ineighbor,ipe_neighbor,ixS^L
888
889 ipe_neighbor=neighbor(2,i^d,igrid)
890 if(ipe_neighbor/=mype) then
891 ic^d=1+modulo(node(pig^d_,igrid)-1,2);
892 if({.not.(i^d==0.or.i^d==2*ic^d-3)|.or.}) return
893 ineighbor=neighbor(1,i^d,igrid)
894 ipole=neighbor_pole(i^d,igrid)
895 if(ipole==0) then
896 n_inc^d=-2*i^d+ic^d;
898 itag=(3**^nd+4**^nd)*(ineighbor-1)+3**^nd+{n_inc^d*4**(^d-1)+}
899 call mpi_isend(psc(igrid)%w,1,type_send_r(i^d), &
900 ipe_neighbor,itag,icomm,sendrequest_c_sr(isend_c),ierrmpi)
901 call wait_send_batch(isend_c,flushed_send_c,sendrequest_c_sr,sendstatus_c_sr)
902 if(stagger_grid) then
903 ibuf_start=ibuf_send_r
904 do idir=1,ndim
905 ixs^l=ixs_r_stg_^l(idir,i^d);
906 ibuf_next=ibuf_start+sizes_r_send_stg(idir,i^d)
907 shapes=(/sizes_r_send_stg(idir,i^d)/)
908 sendbuffer_r(ibuf_start:ibuf_next-1)=&
909 reshape(psc(igrid)%ws(ixs^s,idir),shapes)
910 ibuf_start=ibuf_next
911 end do
913 call mpi_isend(sendbuffer_r(ibuf_send_r),sizes_r_send_total(i^d),&
914 mpi_double_precision,ipe_neighbor,itag, &
915 icomm,sendrequest_r(isend_r),ierrmpi)
916 call wait_send_batch(isend_r,flushed_send_r,sendrequest_r,sendstatus_r)
917 ibuf_send_r=ibuf_next
918 end if
919 else
920 ixs^l=ixs_r_^l(i^d);
921 select case (ipole)
922 {case (^d)
923 n_inc^d=2*i^d+(3-ic^d)^d%n_inc^dd=-2*i^dd+ic^dd;\}
924 end select
925 if(isend_buf(ipwbuf)/=0) then
926 call mpi_wait(sendrequest_c_sr(isend_buf(ipwbuf)), &
927 sendstatus_c_sr(:,isend_buf(ipwbuf)),ierrmpi)
928 deallocate(pwbuf(ipwbuf)%w)
929 end if
930 allocate(pwbuf(ipwbuf)%w(ixs^s,nwhead:nwtail))
931 call pole_buffer(pwbuf(ipwbuf)%w,ixs^l,ixs^l,psc(igrid)%w,ixcog^l,ixs^l,ipole)
933 isend_buf(ipwbuf)=isend_c
934 itag=(3**^nd+4**^nd)*(ineighbor-1)+3**^nd+{n_inc^d*4**(^d-1)+}
935 isizes={(ixsmax^d-ixsmin^d+1)*}*nwbc
936 call mpi_isend(pwbuf(ipwbuf)%w,isizes,mpi_double_precision, &
937 ipe_neighbor,itag,icomm,sendrequest_c_sr(isend_c),ierrmpi)
938 call wait_send_batch(isend_c,flushed_send_c,sendrequest_c_sr,sendstatus_c_sr)
939 ipwbuf=1+modulo(ipwbuf,npwbuf)
940 if(stagger_grid) then
941 ibuf_start=ibuf_send_r
942 do idir=1,ndim
943 ixs^l=ixs_r_stg_^l(idir,i^d);
944 ibuf_next=ibuf_start+sizes_r_send_stg(idir,i^d)
945 shapes=(/sizes_r_send_stg(idir,i^d)/)
946 sendbuffer_r(ibuf_start:ibuf_next-1)=&
947 reshape(psc(igrid)%ws(ixs^s,idir),shapes)
948 ibuf_start=ibuf_next
949 end do
951 call mpi_isend(sendbuffer_r(ibuf_send_r),sizes_r_send_total(i^d),&
952 mpi_double_precision,ipe_neighbor,itag, &
953 icomm,sendrequest_r(isend_r),ierrmpi)
954 call wait_send_batch(isend_r,flushed_send_r,sendrequest_r,sendstatus_r)
955 ibuf_send_r=ibuf_next
956 end if
957 end if
958 end if
959
960 end subroutine bc_send_restrict
961
962 !> fill same-level neighbor's ghost cells in the same processor
963 subroutine bc_fill_srl(igrid,i^D)
964 integer, intent(in) :: igrid,i^D
965
966 integer :: ineighbor,ipe_neighbor,ipole,ixS^L,ixR^L,n_i^D,idir
967
968 ipe_neighbor=neighbor(2,i^d,igrid)
969 if(ipe_neighbor==mype) then
970 ineighbor=neighbor(1,i^d,igrid)
971 ipole=neighbor_pole(i^d,igrid)
972 if(ipole==0) then
973 n_i^d=-i^d;
974 ixs^l=ixs_srl_^l(i^d);
975 ixr^l=ixr_srl_^l(n_i^d);
976 psb(ineighbor)%w(ixr^s,nwhead:nwtail)=&
977 psb(igrid)%w(ixs^s,nwhead:nwtail)
978 if(stagger_grid) then
979 do idir=1,ndim
980 ixs^l=ixs_srl_stg_^l(idir,i^d);
981 ixr^l=ixr_srl_stg_^l(idir,n_i^d);
982 psb(ineighbor)%ws(ixr^s,idir)=psb(igrid)%ws(ixs^s,idir)
983 end do
984 end if
985 else
986 ixs^l=ixs_srl_^l(i^d);
987 select case (ipole)
988 {case (^d)
989 n_i^d=i^d^d%n_i^dd=-i^dd;\}
990 end select
991 ixr^l=ixr_srl_^l(n_i^d);
992 call pole_copy(psb(ineighbor)%w,ixg^ll,ixr^l,psb(igrid)%w,ixg^ll,ixs^l,ipole)
993 if(stagger_grid) then
994 do idir=1,ndim
995 ixs^l=ixs_srl_stg_^l(idir,i^d);
996 ixr^l=ixr_srl_stg_^l(idir,n_i^d);
997 call pole_copy_stg(psb(ineighbor)%ws,ixgs^ll,ixr^l,psb(igrid)%ws,ixgs^ll,ixs^l,idir,ipole)
998 end do
999 end if
1000 end if
1001 end if
1002
1003 end subroutine bc_fill_srl
1004
1005 !> fill coarser neighbor's ghost cells in the same processor
1006 subroutine bc_fill_restrict(igrid,i^D)
1007 integer, intent(in) :: igrid,i^D
1008
1009 integer :: ic^D,n_inc^D,ixS^L,ixR^L,ipe_neighbor,ineighbor,ipole,idir
1010
1011 ipe_neighbor=neighbor(2,i^d,igrid)
1012 if(ipe_neighbor==mype) then
1013 ic^d=1+modulo(node(pig^d_,igrid)-1,2);
1014 if({.not.(i^d==0.or.i^d==2*ic^d-3)|.or.}) return
1015 ineighbor=neighbor(1,i^d,igrid)
1016 ipole=neighbor_pole(i^d,igrid)
1017 if(ipole==0) then
1018 n_inc^d=-2*i^d+ic^d;
1019 ixs^l=ixs_r_^l(i^d);
1020 ixr^l=ixr_r_^l(n_inc^d);
1021 psb(ineighbor)%w(ixr^s,nwhead:nwtail)=&
1022 psc(igrid)%w(ixs^s,nwhead:nwtail)
1023 if(stagger_grid) then
1024 do idir=1,ndim
1025 ixs^l=ixs_r_stg_^l(idir,i^d);
1026 ixr^l=ixr_r_stg_^l(idir,n_inc^d);
1027 psb(ineighbor)%ws(ixr^s,idir)=psc(igrid)%ws(ixs^s,idir)
1028 end do
1029 end if
1030 else
1031 ixs^l=ixs_r_^l(i^d);
1032 select case (ipole)
1033 {case (^d)
1034 n_inc^d=2*i^d+(3-ic^d)^d%n_inc^dd=-2*i^dd+ic^dd;\}
1035 end select
1036 ixr^l=ixr_r_^l(n_inc^d);
1037 call pole_copy(psb(ineighbor)%w,ixg^ll,ixr^l,psc(igrid)%w,ixcog^l,ixs^l,ipole)
1038 if(stagger_grid) then
1039 do idir=1,ndim
1040 ixs^l=ixs_r_stg_^l(idir,i^d);
1041 ixr^l=ixr_r_stg_^l(idir,n_inc^d);
1042 !! Fill ghost cells
1043 call pole_copy_stg(psb(ineighbor)%ws,ixgs^ll,ixr^l,psc(igrid)%ws,ixcogs^l,ixs^l,idir,ipole)
1044 end do
1045 end if
1046 end if
1047 end if
1048
1049 end subroutine bc_fill_restrict
1050
1051 !> fill siblings ghost cells with received data
1052 subroutine bc_fill_srl_stg(igrid,i^D)
1053 integer, intent(in) :: igrid,i^D
1054
1055 integer :: ixS^L,ixR^L,n_i^D,idir,ineighbor,ipe_neighbor,ipole
1056
1057 ipe_neighbor=neighbor(2,i^d,igrid)
1058 if(ipe_neighbor/=mype) then
1059 ineighbor=neighbor(1,i^d,igrid)
1060 ipole=neighbor_pole(i^d,igrid)
1061
1062 !! Now the special treatment of the pole is done here, at the receive step
1063 if (ipole==0) then
1064 ixr^l=ixr_srl_^l(i^d);
1065 !! Unpack the buffer and fill the ghost cells
1066 n_i^d=-i^d;
1067 do idir=1,ndim
1068 ixs^l=ixs_srl_stg_^l(idir,n_i^d);
1069 ixr^l=ixr_srl_stg_^l(idir,i^d);
1070 ibuf_next=ibuf_recv_srl+sizes_srl_recv_stg(idir,i^d)
1071 psb(igrid)%ws(ixr^s,idir)=reshape(source=recvbuffer_srl(ibuf_recv_srl:ibuf_next-1),&
1072 shape=shape(psb(igrid)%ws(ixs^s,idir)))
1073 ibuf_recv_srl=ibuf_next
1074 end do
1075 else ! There is a pole
1076 select case (ipole)
1077 {case (^d)
1078 n_i^d=i^d^d%n_i^dd=-i^dd;\}
1079 end select
1080 pole_buf%ws=zero
1081 do idir=1,ndim
1082 ixr^l=ixr_srl_stg_^l(idir,i^d);
1083 ixs^l=ixs_srl_stg_^l(idir,n_i^d);
1084 ibuf_next=ibuf_recv_srl+sizes_srl_recv_stg(idir,i^d)
1085 pole_buf%ws(ixs^s,idir)=reshape(source=recvbuffer_srl(ibuf_recv_srl:ibuf_next-1),&
1086 shape=shape(psb(igrid)%ws(ixs^s,idir)))
1087 ibuf_recv_srl=ibuf_next
1088 call pole_copy_stg(psb(igrid)%ws,ixgs^ll,ixr^l,pole_buf%ws,ixgs^ll,ixs^l,idir,ipole)
1089 end do
1090 end if
1091 end if
1092
1093 end subroutine bc_fill_srl_stg
1094
1095 !> fill restricted ghost cells after receipt
1096 subroutine bc_fill_restrict_stg(igrid,i^D)
1097 integer, intent(in) :: igrid,i^D
1098
1099 integer :: ipole,ic^D,inc^D,ineighbor,ipe_neighbor,ixS^L,ixR^L,n_i^D,idir
1100
1101 ipole=neighbor_pole(i^d,igrid)
1102 if (ipole==0) then
1103 ! Loop over the children ic^D to and their neighbors inc^D
1104 {do ic^db=1+int((1-i^db)/2),2-int((1+i^db)/2)
1105 inc^db=2*i^db+ic^db\}
1106 ipe_neighbor=neighbor_child(2,inc^d,igrid)
1107 if(ipe_neighbor/=mype) then
1108 ineighbor=neighbor_child(1,inc^d,igrid)
1109 n_i^d=-i^d;
1110 !! Unpack the buffer and fill the ghost cells
1111 do idir=1,ndim
1112 ixr^l=ixr_r_stg_^l(idir,inc^d);
1113 ibuf_next=ibuf_recv_r+sizes_r_recv_stg(idir,inc^d)
1114 psb(igrid)%ws(ixr^s,idir)=reshape(source=recvbuffer_r(ibuf_recv_r:ibuf_next-1),&
1115 shape=shape(psb(igrid)%ws(ixr^s,idir)))
1116 ibuf_recv_r=ibuf_next
1117 end do
1118 end if
1119 {end do\}
1120 else !! There is a pole
1121 {do ic^db=1+int((1-i^db)/2),2-int((1+i^db)/2)
1122 inc^db=2*i^db+ic^db\}
1123 ipe_neighbor=neighbor_child(2,inc^d,igrid)
1124 if(ipe_neighbor/=mype) then
1125 ineighbor=neighbor_child(1,inc^d,igrid)
1126 select case(ipole)
1127 {case (^d)
1128 n_i^d=i^d^d%n_i^dd=-i^dd;\}
1129 end select
1130 ixr^l=ixr_r_^l(inc^d);
1131 !! Unpack the buffer and fill an auxiliary array
1132 pole_buf%ws=zero
1133 do idir=1,ndim
1134 ixs^l=ixs_r_stg_^l(idir,n_i^d);
1135 ixr^l=ixr_r_stg_^l(idir,inc^d);
1136 ibuf_next=ibuf_recv_r+sizes_r_recv_stg(idir,inc^d)
1137 pole_buf%ws(ixr^s,idir)=reshape(source=recvbuffer_r(ibuf_recv_r:ibuf_next-1),&
1138 shape=shape(psb(igrid)%ws(ixr^s,idir)))
1139 call pole_copy_stg(psb(igrid)%ws,ixgs^ll,ixr^l,pole_buf%ws,ixgs^ll,ixr^l,idir,ipole)
1140 ibuf_recv_r=ibuf_next
1141 end do
1142 end if
1143 {end do\}
1144 end if
1145
1146 end subroutine bc_fill_restrict_stg
1147
1148 !> Receive from coarse neighbor
1149 subroutine bc_recv_prolong(igrid,i^D)
1150 integer, intent(in) :: igrid,i^D
1151
1152 integer :: ic^D,ipe_neighbor,inc^D
1153
1154 ic^d=1+modulo(node(pig^d_,igrid)-1,2);
1155 if ({.not.(i^d==0.or.i^d==2*ic^d-3)|.or.}) return
1156
1157 ipe_neighbor=neighbor(2,i^d,igrid)
1158 if (ipe_neighbor/=mype) then
1160 inc^d=ic^d+i^d;
1161 itag=(3**^nd+4**^nd)*(igrid-1)+3**^nd+{inc^d*4**(^d-1)+}
1162 call mpi_irecv(psc(igrid)%w,1,type_recv_p(inc^d), &
1163 ipe_neighbor,itag,icomm,recvrequest_c_p(irecv_c),ierrmpi)
1164 if(stagger_grid) then
1166 call mpi_irecv(recvbuffer_p(ibuf_recv_p),sizes_p_recv_total(inc^d),&
1167 mpi_double_precision,ipe_neighbor,itag,&
1168 icomm,recvrequest_p(irecv_p),ierrmpi)
1170 end if
1171 end if
1172
1173 end subroutine bc_recv_prolong
1174
1175 !> Send to finer neighbor
1176 subroutine bc_send_prolong(igrid,i^D)
1177 integer, intent(in) :: igrid,i^D
1178
1179 integer :: ic^D,inc^D,n_i^D,n_inc^D,ineighbor,ipe_neighbor,ixS^L,ipole,idir
1180
1181 ipole=neighbor_pole(i^d,igrid)
1182
1183 {do ic^db=1+int((1-i^db)/2),2-int((1+i^db)/2)
1184 inc^db=2*i^db+ic^db\}
1185 ipe_neighbor=neighbor_child(2,inc^d,igrid)
1186 if(ipe_neighbor/=mype) then
1187 ineighbor=neighbor_child(1,inc^d,igrid)
1188 if(ipole==0) then
1189 n_i^d=-i^d;
1190 n_inc^d=ic^d+n_i^d;
1192 itag=(3**^nd+4**^nd)*(ineighbor-1)+3**^nd+{n_inc^d*4**(^d-1)+}
1193 call mpi_isend(psb(igrid)%w,1,type_send_p(inc^d), &
1194 ipe_neighbor,itag,icomm,sendrequest_c_p(isend_c),ierrmpi)
1195 call wait_send_batch(isend_c,flushed_send_c,sendrequest_c_p,sendstatus_c_p)
1196 if(stagger_grid) then
1197 ibuf_start=ibuf_send_p
1198 do idir=1,ndim
1199 ixs^l=ixs_p_stg_^l(idir,inc^d);
1200 ibuf_next=ibuf_start+sizes_p_send_stg(idir,inc^d)
1201 shapes=(/sizes_p_send_stg(idir,inc^d)/)
1202 sendbuffer_p(ibuf_start:ibuf_next-1)=&
1203 reshape(psb(igrid)%ws(ixs^s,idir),shapes)
1204 ibuf_start=ibuf_next
1205 end do
1207 call mpi_isend(sendbuffer_p(ibuf_send_p),sizes_p_send_total(inc^d),&
1208 mpi_double_precision,ipe_neighbor,itag, &
1209 icomm,sendrequest_p(isend_p),ierrmpi)
1210 call wait_send_batch(isend_p,flushed_send_p,sendrequest_p,sendstatus_p)
1211 ibuf_send_p=ibuf_next
1212 end if
1213 else
1214 ixs^l=ixs_p_^l(inc^d);
1215 select case (ipole)
1216 {case (^d)
1217 n_inc^d=inc^d^d%n_inc^dd=ic^dd-i^dd;\}
1218 end select
1219 if(isend_buf(ipwbuf)/=0) then
1220 call mpi_wait(sendrequest_c_p(isend_buf(ipwbuf)), &
1221 sendstatus_c_p(:,isend_buf(ipwbuf)),ierrmpi)
1222 deallocate(pwbuf(ipwbuf)%w)
1223 end if
1224 allocate(pwbuf(ipwbuf)%w(ixs^s,nwhead:nwtail))
1225 call pole_buffer(pwbuf(ipwbuf)%w,ixs^l,ixs^l,psb(igrid)%w,ixg^ll,ixs^l,ipole)
1227 isend_buf(ipwbuf)=isend_c
1228 itag=(3**^nd+4**^nd)*(ineighbor-1)+3**^nd+{n_inc^d*4**(^d-1)+}
1229 isizes={(ixsmax^d-ixsmin^d+1)*}*nwbc
1230 call mpi_isend(pwbuf(ipwbuf)%w,isizes,mpi_double_precision, &
1231 ipe_neighbor,itag,icomm,sendrequest_c_p(isend_c),ierrmpi)
1232 call wait_send_batch(isend_c,flushed_send_c,sendrequest_c_p,sendstatus_c_p)
1233 ipwbuf=1+modulo(ipwbuf,npwbuf)
1234 if(stagger_grid) then
1235 ibuf_start=ibuf_send_p
1236 do idir=1,ndim
1237 ixs^l=ixs_p_stg_^l(idir,inc^d);
1238 ibuf_next=ibuf_start+sizes_p_send_stg(idir,inc^d)
1239 shapes=(/sizes_p_send_stg(idir,inc^d)/)
1240 sendbuffer_p(ibuf_start:ibuf_next-1)=&
1241 reshape(psb(igrid)%ws(ixs^s,idir),shapes)
1242 ibuf_start=ibuf_next
1243 end do
1245 call mpi_isend(sendbuffer_p(ibuf_send_p),sizes_p_send_total(inc^d),&
1246 mpi_double_precision,ipe_neighbor,itag, &
1247 icomm,sendrequest_p(isend_p),ierrmpi)
1248 call wait_send_batch(isend_p,flushed_send_p,sendrequest_p,sendstatus_p)
1249 ibuf_send_p=ibuf_next
1250 end if
1251 end if
1252 end if
1253 {end do\}
1254
1255 end subroutine bc_send_prolong
1256
1257 !> Send to finer neighbor
1258 subroutine bc_fill_prolong(igrid,i^D)
1259 integer, intent(in) :: igrid,i^D
1260
1261 integer :: ipe_neighbor,ineighbor,ixS^L,ixR^L,ic^D,inc^D,n_i^D,n_inc^D,ipole,idir
1262
1263 ipole=neighbor_pole(i^d,igrid)
1264
1265 if(ipole==0) then
1266 {do ic^db=1+int((1-i^db)/2),2-int((1+i^db)/2)
1267 inc^db=2*i^db+ic^db\}
1268 ipe_neighbor=neighbor_child(2,inc^d,igrid)
1269 if(ipe_neighbor==mype) then
1270 ixs^l=ixs_p_^l(inc^d);
1271 ineighbor=neighbor_child(1,inc^d,igrid)
1272 n_i^d=-i^d;
1273 n_inc^d=ic^d+n_i^d;
1274 ixr^l=ixr_p_^l(n_inc^d);
1275 psc(ineighbor)%w(ixr^s,nwhead:nwtail) &
1276 =psb(igrid)%w(ixs^s,nwhead:nwtail)
1277 if(stagger_grid) then
1278 do idir=1,ndim
1279 ixs^l=ixs_p_stg_^l(idir,inc^d);
1280 ixr^l=ixr_p_stg_^l(idir,n_inc^d);
1281 psc(ineighbor)%ws(ixr^s,idir)=psb(igrid)%ws(ixs^s,idir)
1282 end do
1283 end if
1284 end if
1285 {end do\}
1286 else
1287 {do ic^db=1+int((1-i^db)/2),2-int((1+i^db)/2)
1288 inc^db=2*i^db+ic^db\}
1289 ipe_neighbor=neighbor_child(2,inc^d,igrid)
1290 if(ipe_neighbor==mype) then
1291 ixs^l=ixs_p_^l(inc^d);
1292 ineighbor=neighbor_child(1,inc^d,igrid)
1293 select case (ipole)
1294 {case (^d)
1295 n_inc^d=inc^d^d%n_inc^dd=ic^dd-i^dd;\}
1296 end select
1297 ixr^l=ixr_p_^l(n_inc^d);
1298 call pole_copy(psc(ineighbor)%w,ixcog^l,ixr^l,psb(igrid)%w,ixg^ll,ixs^l,ipole)
1299 if(stagger_grid) then
1300 do idir=1,ndim
1301 ixs^l=ixs_p_stg_^l(idir,inc^d);
1302 ixr^l=ixr_p_stg_^l(idir,n_inc^d);
1303 call pole_copy_stg(psc(ineighbor)%ws,ixcogs^l,ixr^l,psb(igrid)%ws,ixgs^ll,ixs^l,idir,ipole)
1304 end do
1305 end if
1306 end if
1307 {end do\}
1308 end if
1309 end subroutine bc_fill_prolong
1310
1311 subroutine gc_prolong(igrid)
1312 integer, intent(in) :: igrid
1313
1314 integer :: i^D,idims,iside
1315 logical,dimension(-1:1^D&) :: NeedProlong
1316
1317 needprolong=.false.
1318 {do i^db=-1,1\}
1319 if (skip_direction([ i^d ])) cycle
1320 if (neighbor_type(i^d,igrid)==neighbor_coarse) then
1321 call bc_prolong(igrid,i^d)
1322 needprolong(i^d)=.true.
1323 end if
1324 {end do\}
1325 if(stagger_grid) then
1326 ! Ghost cell prolongation for staggered variables
1327 ! must be done in a specific order.
1328 ! First the first neighbours, which have 2 indices=0 in 3D
1329 ! or one index=0 in 2D
1330 block=>psb(igrid)
1331 do idims=1,ndim
1332 i^d=0;
1333 select case(idims)
1334 {case(^d)
1335 do i^d=-1,1,2
1336 if (needprolong(i^dd)) call bc_prolong_stg(igrid,i^dd,needprolong)
1337 end do
1338 \}
1339 end select
1340 end do
1341 ! Then the second neighbours which have 1 index=0 in 3D
1342 ! (Only in 3D)
1343 {^ifthreed
1344 i1=0;
1345 do i2=-1,1,2
1346 do i3=-1,1,2
1347 if (needprolong(i^d)) call bc_prolong_stg(igrid,i^d,needprolong)
1348 end do
1349 end do
1350 i2=0;
1351 do i3=-1,1,2
1352 do i1=-1,1,2
1353 if (needprolong(i^d)) call bc_prolong_stg(igrid,i^d,needprolong)
1354 end do
1355 end do
1356 i3=0;
1357 do i1=-1,1,2
1358 do i2=-1,1,2
1359 if (needprolong(i^d)) call bc_prolong_stg(igrid,i^d,needprolong)
1360 end do
1361 end do
1362 }
1363 ! Finally, the corners, that have no index=0
1364 {do i^d=-1,1,2\}
1365 if (needprolong(i^d)) call bc_prolong_stg(igrid,i^d,needprolong)
1366 {end do\}
1367 end if
1368 end subroutine gc_prolong
1369
1370 !> fill coarser representative with data from coarser neighbors
1371 subroutine bc_fill_prolong_stg(igrid,i^D)
1372 integer, intent(in) :: igrid,i^D
1373
1374 integer :: ipe_neighbor,ineighbor,ipole,ixR^L,ic^D,inc^D,n_inc^D,idir
1375
1376 ic^d=1+modulo(node(pig^d_,igrid)-1,2);
1377 if ({.not.(i^d==0.or.i^d==2*ic^d-3)|.or.}) return
1378
1379 ipe_neighbor=neighbor(2,i^d,igrid)
1380 if(ipe_neighbor/=mype) then
1381 ineighbor=neighbor(1,i^d,igrid)
1382 ipole=neighbor_pole(i^d,igrid)
1383
1384 if (ipole==0) then !! There is no pole
1385 inc^d=ic^d+i^d;
1386 ixr^l=ixr_p_^l(inc^d);
1387 do idir=1,ndim
1388 ixr^l=ixr_p_stg_^l(idir,inc^d);
1389 ibuf_next=ibuf_recv_p+sizes_p_recv_stg(idir,inc^d)
1390 psc(igrid)%ws(ixr^s,idir)=reshape(source=recvbuffer_p(ibuf_recv_p:ibuf_next-1),&
1391 shape=shape(psc(igrid)%ws(ixr^s,idir)))
1392 ibuf_recv_p=ibuf_next
1393 end do
1394 else !! There is a pole
1395 inc^d=ic^d+i^d;
1396 select case (ipole)
1397 {case (^d)
1398 n_inc^d=2*i^d+(3-ic^d)^d%n_inc^dd=-2*i^dd+ic^dd;\}
1399 end select
1400 !! Unpack the buffer and fill an auxiliary array
1401 pole_buf%ws=zero
1402 do idir=1,ndim
1403 ixr^l=ixr_p_stg_^l(idir,inc^d);
1404 ibuf_next=ibuf_recv_p+sizes_p_recv_stg(idir,inc^d)
1405 pole_buf%ws(ixr^s,idir)=reshape(source=recvbuffer_p(ibuf_recv_p:ibuf_next-1),&
1406 shape=shape(psc(igrid)%ws(ixr^s,idir)))
1407 call pole_copy_stg(psc(igrid)%ws,ixcogs^l,ixr^l,pole_buf%ws,ixgs^ll,ixr^l,idir,ipole)
1408 ibuf_recv_p=ibuf_next
1409 end do
1410 end if
1411 end if
1412
1413 end subroutine bc_fill_prolong_stg
1414
1415 !> do prolongation for fine blocks after receipt data from coarse neighbors
1416 subroutine bc_prolong(igrid,i^D)
1419
1420 double precision :: dxFi^D, dxCo^D, xFimin^D, xComin^D, invdxCo^D
1421 integer :: i^D,igrid
1422 integer :: ixFi^L,ixCo^L,ii^D, idims,iside,ixB^L
1423
1424 ixfi^l=ixr_srl_^l(i^d);
1425 dxfi^d=rnode(rpdx^d_,igrid);
1426 dxco^d=two*dxfi^d;
1427 invdxco^d=1.d0/dxco^d;
1428
1429 ! compute the enlarged grid lower left corner coordinates
1430 ! these are true coordinates for an equidistant grid,
1431 ! but we can temporarily also use them for getting indices
1432 ! in stretched grids
1433 xfimin^d=rnode(rpxmin^d_,igrid)-dble(nghostcells)*dxfi^d;
1434 xcomin^d=rnode(rpxmin^d_,igrid)-dble(nghostcells)*dxco^d;
1435
1436 if(phyboundblock(igrid).and.bcphys) then
1437 block=>psc(igrid)
1438 do idims=1,ndim
1439 ixcomin^d=int((xfimin^d+(dble(ixfimin^d)-half)*dxfi^d-xcomin^d)*invdxco^d)+1-1;
1440 ixcomax^d=int((xfimin^d+(dble(ixfimax^d)-half)*dxfi^d-xcomin^d)*invdxco^d)+1+1;
1441 {^ifthreed
1442 ! avoid using undetermined ghost cells at physical boundary edges
1443 if(idims == 1) then
1444 if(neighbor_type(-1,0,0,igrid)==neighbor_boundary .or. &
1445 neighbor_type(1,0,0,igrid)==neighbor_boundary) then
1446 if(neighbor_type(0,-1,0,igrid)==neighbor_boundary) ixcomin2=ixcommin2
1447 if(neighbor_type(0,0,-1,igrid)==neighbor_boundary) ixcomin3=ixcommin3
1448 if(neighbor_type(0,1,0,igrid)==neighbor_boundary) ixcomax2=ixcommax2
1449 if(neighbor_type(0,0,1,igrid)==neighbor_boundary) ixcomax3=ixcommax3
1450 end if
1451 else if(idims == 2) then
1452 if(neighbor_type(0,-1,0,igrid)==neighbor_boundary .or. &
1453 neighbor_type(0,1,0,igrid)==neighbor_boundary) then
1454 if(neighbor_type(0,0,-1,igrid)==neighbor_boundary) ixcomin3=ixcommin3
1455 if(neighbor_type(0,0,1,igrid)==neighbor_boundary) ixcomax3=ixcommax3
1456 end if
1457 end if
1458 }
1459 do iside=1,2
1460 ii^d=kr(^d,idims)*(2*iside-3);
1461 if(neighbor_type(ii^d,igrid)/=neighbor_boundary) cycle
1462 if(( {(iside==1.and.idims==^d.and.ixcomin^d<ixcogmin^d+nghostcells)|.or.} ) &
1463 .or.( {(iside==2.and.idims==^d.and.ixcomax^d>ixcogmax^d-nghostcells)|.or. })) then
1464 {ixbmin^d=merge(ixcogmin^d,ixcomin^d,idims==^d);}
1465 {ixbmax^d=merge(ixcogmax^d,ixcomax^d,idims==^d);}
1466 call bc_phys(iside,idims,time,0.d0,psc(igrid),ixcog^l,ixb^l)
1467 end if
1468 end do
1469 end do
1470 end if
1471
1472 if(prolongprimitive) then
1473 block=>psc(igrid)
1474 ixcomin^d=int((xfimin^d+(dble(ixfimin^d)-half)*dxfi^d-xcomin^d)*invdxco^d)+1-1;
1475 ixcomax^d=int((xfimin^d+(dble(ixfimax^d)-half)*dxfi^d-xcomin^d)*invdxco^d)+1+1;
1476 call phys_to_primitive(ixcog^l,ixco^l,psc(igrid)%w,psc(igrid)%x)
1477 end if
1478
1479 if(ghost_copy) then
1480 call interpolation_copy(igrid,ixfi^l,dxfi^d,xfimin^d,dxco^d,invdxco^d,xcomin^d)
1481 else
1482 call interpolation_linear(igrid,ixfi^l,dxfi^d,xfimin^d,dxco^d,invdxco^d,xcomin^d)
1483 end if
1484
1485 if(prolongprimitive) then
1486 block=>psc(igrid)
1487 call phys_to_conserved(ixcog^l,ixco^l,psc(igrid)%w,psc(igrid)%x)
1488 end if
1489
1490 end subroutine bc_prolong
1491
1492 subroutine bc_prolong_stg(igrid,i^D,NeedProlong)
1493 use mod_amr_fct
1494 double precision :: dxFi^D,dxCo^D,xFimin^D,xComin^D,invdxCo^D
1495 integer :: igrid,i^D
1496 integer :: ixFi^L,ixCo^L
1497 logical,dimension(-1:1^D&) :: NeedProlong
1498 logical :: fine_^Lin
1499 ! Check what is already at the desired level
1500 fine_^lin=.false.;
1501 {
1502 if(i^d>-1) fine_min^din=(.not.needprolong(i^dd-kr(^d,^dd)).and.neighbor_type(i^dd-kr(^d,^dd),igrid)/=1)
1503 if(i^d<1) fine_max^din=(.not.needprolong(i^dd+kr(^d,^dd)).and.neighbor_type(i^dd+kr(^d,^dd),igrid)/=1)
1504 \}
1505
1506 ixfi^l=ixr_srl_^l(i^d);
1507
1508 dxfi^d=rnode(rpdx^d_,igrid);
1509 dxco^d=two*dxfi^d;
1510 invdxco^d=1.d0/dxco^d;
1511
1512 xfimin^d=rnode(rpxmin^d_,igrid)-dble(nghostcells)*dxfi^d;
1513 xcomin^d=rnode(rpxmin^d_,igrid)-dble(nghostcells)*dxco^d;
1514
1515 ! moved the physical boundary filling here, to only fill the
1516 ! part needed
1517
1518 ixcomin^d=int((xfimin^d+(dble(ixfimin^d)-half)*dxfi^d-xcomin^d)*invdxco^d)+1-1;
1519 ixcomax^d=int((xfimin^d+(dble(ixfimax^d)-half)*dxfi^d-xcomin^d)*invdxco^d)+1+1;
1520
1521 if(prolongprimitive) call phys_to_primitive(ixg^ll,ixfi^l,psb(igrid)%w,psb(igrid)%x)
1522
1523 call prolong_2nd_stg(psc(igrid),psb(igrid),ixco^l,ixfi^l,dxco^d,xcomin^d,dxfi^d,xfimin^d,.true.,fine_^lin)
1524
1525 if(prolongprimitive) call phys_to_conserved(ixg^ll,ixfi^l,psb(igrid)%w,psb(igrid)%x)
1526
1527 ! The current region has already been refined, so it does not need to be prolonged again
1528 needprolong(i^d)=.false.
1529
1530 end subroutine bc_prolong_stg
1531
1532 subroutine interpolation_linear(igrid,ixFi^L,dxFi^D,xFimin^D, &
1533 dxCo^D,invdxCo^D,xComin^D)
1535 integer, intent(in) :: igrid, ixFi^L
1536 double precision, intent(in) :: dxFi^D, xFimin^D,dxCo^D, invdxCo^D, xComin^D
1537
1538 double precision :: xCo^D, xFi^D, eta^D
1539 double precision :: slopeL, slopeR, slopeC, signC, signR
1540 double precision :: slope(1:nw,ndim)
1541 !!double precision :: local_invdxCo^D
1542 double precision :: signedfactorhalf^D
1543 integer :: ixCo^D, jxCo^D, hxCo^D, ixFi^D, ix^D, iw, idims, nwmin,nwmax
1544 !integer :: ixshift^D, icase
1545
1546 !icase=mod(nghostcells,2)
1547
1548 if(prolongprimitive) then
1549 nwmin=1
1550 nwmax=nw
1551 else
1552 nwmin=nwhead
1553 nwmax=nwtail
1554 end if
1555
1556 {do ixfi^db = ixfi^lim^db
1557 ! cell-centered coordinates of fine grid point
1558 ! here we temporarily use an equidistant grid
1559 xfi^db=xfimin^db+(dble(ixfi^db)-half)*dxfi^db
1560
1561 ! indices of coarse cell which contains the fine cell
1562 ! since we computed lower left corner earlier
1563 ! in equidistant fashion: also ok for stretched case
1564 ixco^db=int((xfi^db-xcomin^db)*invdxco^db)+1
1565
1566 ! cell-centered coordinates of coarse grid point
1567 ! here we temporarily use an equidistant grid
1568 xco^db=xcomin^db+(dble(ixco^db)-half)*dxco^db \}
1569
1570 !if(.not.slab) then
1571 ! ^D&local_invdxCo^D=1.d0/psc(igrid)%dx({ixCo^DD},^D)\
1572 !endif
1573
1574 if(slab_uniform) then
1575 ! actual cell-centered coordinates of fine grid point
1576 !!^D&xFi^D=block%x({ixFi^DD},^D)\
1577 ! actual cell-centered coordinates of coarse grid point
1578 !!^D&xCo^D=psc(igrid)%x({ixCo^DD},^D)\
1579 ! normalized distance between fine/coarse cell center
1580 ! in coarse cell: ranges from -0.5 to 0.5 in each direction
1581 ! (origin is coarse cell center)
1582 ! this is essentially +1/4 or -1/4 on cartesian mesh
1583 eta^d=(xfi^d-xco^d)*invdxco^d;
1584 else
1585 !select case(icase)
1586 ! case(0)
1587 !{! here we assume an even number of ghostcells!!!
1588 !ixshift^D=2*(mod(ixFi^D,2)-1)+1
1589 !if(ixshift^D>0.0d0)then
1590 ! ! oneven fine grid points
1591 ! eta^D=-0.5d0*(one-block%dvolume(ixFi^DD) &
1592 ! /sum(block%dvolume(ixFi^D:ixFi^D+1^D%ixFi^DD)))
1593 !else
1594 ! ! even fine grid points
1595 ! eta^D=+0.5d0*(one-block%dvolume(ixFi^DD) &
1596 ! /sum(block%dvolume(ixFi^D-1:ixFi^D^D%ixFi^DD)))
1597 !endif\}
1598 ! case(1)
1599 !{! here we assume an odd number of ghostcells!!!
1600 !ixshift^D=2*(mod(ixFi^D,2)-1)+1
1601 !if(ixshift^D>0.0d0)then
1602 ! ! oneven fine grid points
1603 ! eta^D=+0.5d0*(one-block%dvolume(ixFi^DD) &
1604 ! /sum(block%dvolume(ixFi^D-1:ixFi^D^D%ixFi^DD)))
1605 !else
1606 ! ! even fine grid points
1607 ! eta^D=-0.5d0*(one-block%dvolume(ixFi^DD) &
1608 ! /sum(block%dvolume(ixFi^D:ixFi^D+1^D%ixFi^DD)))
1609 !endif\}
1610 ! case default
1611 ! call mpistop("no such case")
1612 !end select
1613 ! the different cases for even/uneven number of ghost cells
1614 ! are automatically handled using the relative index to ixMlo
1615 ! as well as the pseudo-coordinates xFi and xCo
1616 ! these latter differ from actual cell centers when stretching is used
1617 ix^d=2*int((ixfi^d+ixmlo^d)/2)-ixmlo^d;
1618 {if(xfi^d>xco^d) then
1619 signedfactorhalf^d=0.5d0
1620 else
1621 signedfactorhalf^d=-0.5d0
1622 end if
1623 eta^d=signedfactorhalf^d*(one-psb(igrid)%dvolume(ixfi^dd) &
1624 /sum(psb(igrid)%dvolume(ix^d:ix^d+1^d%ixFi^dd))) \}
1625 !{eta^D=(xFi^D-xCo^D)*invdxCo^D &
1626 ! *two*(one-block%dvolume(ixFi^DD) &
1627 ! /sum(block%dvolume(ix^D:ix^D+1^D%ixFi^DD))) \}
1628 end if
1629
1630 do idims=1,ndim
1631 hxco^d=ixco^d-kr(^d,idims)\
1632 jxco^d=ixco^d+kr(^d,idims)\
1633
1634 do iw=nwmin,nwmax
1635 slopel=psc(igrid)%w(ixco^d,iw)-psc(igrid)%w(hxco^d,iw)
1636 sloper=psc(igrid)%w(jxco^d,iw)-psc(igrid)%w(ixco^d,iw)
1637 slopec=half*(sloper+slopel)
1638
1639 ! get limited slope
1640 signr=sign(one,sloper)
1641 signc=sign(one,slopec)
1642 !select case(prolong_limiter)
1643 !case(1)
1644 ! ! unlimit
1645 ! slope(iw,idims)=slopeC
1646 !case(2)
1647 ! ! minmod
1648 ! slope(iw,idims)=signR*max(zero,min(dabs(slopeR), &
1649 ! signR*slopeL))
1650 !case(3)
1651 ! ! woodward
1652 ! slope(iw,idims)=two*signR*max(zero,min(dabs(slopeR), &
1653 ! signR*slopeL,signR*half*slopeC))
1654 !case(4)
1655 ! ! koren
1656 ! slope(iw,idims)=signR*max(zero,min(two*signR*slopeL, &
1657 ! (dabs(slopeR)+two*slopeL*signR)*third,two*dabs(slopeR)))
1658 !case default
1659 slope(iw,idims)=signc*max(zero,min(dabs(slopec), &
1660 signc*slopel,signc*sloper))
1661 !end select
1662 end do
1663 end do
1664
1665 ! Interpolate from coarse cell using limited slopes
1666 psb(igrid)%w(ixfi^d,nwmin:nwmax)=psc(igrid)%w(ixco^d,nwmin:nwmax)+&
1667 {(slope(nwmin:nwmax,^d)*eta^d)+}
1668
1669 {end do\}
1670
1671 if(prolongprimitive) then
1672 block=>psb(igrid)
1673 call phys_to_conserved(ixg^ll,ixfi^l,psb(igrid)%w,psb(igrid)%x)
1674 end if
1675
1676 end subroutine interpolation_linear
1677
1678 subroutine interpolation_copy(igrid, ixFi^L,dxFi^D,xFimin^D, &
1679 dxCo^D,invdxCo^D,xComin^D)
1681 integer, intent(in) :: igrid, ixFi^L
1682 double precision, intent(in) :: dxFi^D, xFimin^D,dxCo^D, invdxCo^D, xComin^D
1683
1684 double precision :: xFi^D
1685 integer :: ixCo^D, ixFi^D, nwmin,nwmax
1686
1687 if(prolongprimitive) then
1688 nwmin=1
1689 nwmax=nw
1690 else
1691 nwmin=nwhead
1692 nwmax=nwtail
1693 end if
1694
1695 {do ixfi^db = ixfi^lim^db
1696 ! cell-centered coordinates of fine grid point
1697 xfi^db=xfimin^db+(dble(ixfi^db)-half)*dxfi^db
1698
1699 ! indices of coarse cell which contains the fine cell
1700 ! note: this also works for stretched grids
1701 ixco^db=int((xfi^db-xcomin^db)*invdxco^db)+1\}
1702
1703 ! Copy from coarse cell
1704 psb(igrid)%w(ixfi^d,nwmin:nwmax)=psc(igrid)%w(ixco^d,nwmin:nwmax)
1705
1706 {end do\}
1707
1708 if(prolongprimitive) call phys_to_conserved(ixg^ll,ixfi^l,psb(igrid)%w,psb(igrid)%x)
1709
1710 end subroutine interpolation_copy
1711
1712 subroutine pole_copy(wrecv,ixIR^L,ixR^L,wsend,ixIS^L,ixS^L,ipole)
1713
1714 integer, intent(in) :: ixIR^L,ixR^L,ixIS^L,ixS^L,ipole
1715 double precision :: wrecv(ixIR^S,1:nw), wsend(ixIS^S,1:nw)
1716
1717 integer :: iw, iside, iB
1718
1719 select case (ipole)
1720 {case (^d)
1721 iside=int((i^d+3)/2)
1722 ib=2*(^d-1)+iside
1723 do iw=nwhead,nwtail
1724 select case (typeboundary(iw,ib))
1725 case (bc_symm)
1726 wrecv(ixr^s,iw) = wsend(ixsmax^d:ixsmin^d:-1^d%ixS^s,iw)
1727 case (bc_asymm)
1728 wrecv(ixr^s,iw) =-wsend(ixsmax^d:ixsmin^d:-1^d%ixS^s,iw)
1729 case default
1730 call mpistop("Pole boundary condition should be symm or asymm")
1731 end select
1732 end do \}
1733 end select
1734
1735 end subroutine pole_copy
1736
1737 subroutine pole_copy_stg(wrecv,ixIR^L,ixR^L,wsend,ixIS^L,ixS^L,idirs,ipole)
1738
1739 integer, intent(in) :: ixIR^L,ixR^L,ixIS^L,ixS^L,idirs,ipole
1740
1741 double precision :: wrecv(ixIR^S,1:nws), wsend(ixIS^S,1:nws)
1742 integer :: iB, iside
1743
1744 select case (ipole)
1745 {case (^d)
1746 iside=int((i^d+3)/2)
1747 ib=2*(^d-1)+iside
1748 select case (typeboundary(iw_mag(idirs),ib))
1749 case (bc_symm)
1750 wrecv(ixr^s,idirs) = wsend(ixsmax^d:ixsmin^d:-1^d%ixS^s,idirs)
1751 case (bc_asymm)
1752 wrecv(ixr^s,idirs) =-wsend(ixsmax^d:ixsmin^d:-1^d%ixS^s,idirs)
1753 case default
1754 call mpistop("Pole boundary condition should be symm or asymm")
1755 end select
1756 \}
1757 end select
1758
1759 end subroutine pole_copy_stg
1760
1761 subroutine pole_buffer(wrecv,ixIR^L,ixR^L,wsend,ixIS^L,ixS^L,ipole)
1762
1763 integer, intent(in) :: ixIR^L,ixR^L,ixIS^L,ixS^L,ipole
1764 double precision :: wrecv(ixIR^S,nwhead:nwtail), wsend(ixIS^S,1:nw)
1765
1766 integer :: iw, iside, iB
1767
1768 select case (ipole)
1769 {case (^d)
1770 iside=int((i^d+3)/2)
1771 ib=2*(^d-1)+iside
1772 do iw=nwhead,nwtail
1773 select case (typeboundary(iw,ib))
1774 case (bc_symm)
1775 wrecv(ixr^s,iw) = wsend(ixsmax^d:ixsmin^d:-1^d%ixS^s,iw)
1776 case (bc_asymm)
1777 wrecv(ixr^s,iw) =-wsend(ixsmax^d:ixsmin^d:-1^d%ixS^s,iw)
1778 case default
1779 call mpistop("Pole boundary condition should be symm or asymm")
1780 end select
1781 end do \}
1782 end select
1783
1784 end subroutine pole_buffer
1785
1786 end subroutine getbc
1787
1788end module mod_ghostcells_update
subroutine waitall_limited(nrequest, requests, statuses)
subroutine, public prolong_2nd_stg(sco, sfi, ixcolin, ixfilin, dxcod, xcomind, dxfid, xfimind, ghost, fine_lin)
This subroutine performs a 2nd order prolongation for a staggered field F, preserving the divergence ...
Definition mod_amr_fct.t:41
subroutine, public bc_phys(iside, idims, time, qdt, s, ixgl, ixbl)
fill ghost cells at a physical boundary
subroutine, public getintbc(time, qdt, ixgl)
fill inner boundary values
subroutine, public coarsen_grid(sfi, ixfigl, ixfil, sco, ixcogl, ixcol)
coarsen one grid to its coarser representative
Definition mod_coarsen.t:13
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
update ghost cells of all blocks including physical boundaries
integer, dimension(0:3^d &), target type_recv_p_p1
integer, dimension( :^d &), pointer type_recv_r
integer, dimension(-1:1^d &), target type_send_srl_p1
integer, dimension(-1:1^d &) sizes_r_send_total
integer, dimension(^nd, 0:3) l
integer, dimension(-1:1^d &), target type_send_r_p2
integer, dimension(:), allocatable sendrequest_c_p
integer, dimension(^nd,-1:1) ixs_r_stg_
integer, dimension(^nd,-1:1) ixs_srl_stg_
integer, dimension(^nd, 0:3^d &) sizes_p_send_stg
subroutine getbc(time, qdt, psb, nwstart, nwbc)
do update ghost cells of all blocks including physical boundaries
integer, dimension(-1:1^d &) sizes_srl_send_total
integer, dimension(^nd, 0:3) ixr_r_stg_
integer, dimension(:), allocatable sendrequest_r
integer, dimension(:), allocatable recvrequest_r
double precision, dimension(:), allocatable sendbuffer_p
integer, dimension(:,:), allocatable sendstatus_c_p
integer, dimension(^nd,-1:1^d &) sizes_r_send_stg
integer, dimension(0:3) ixs_p_
integer, dimension(0:3) ixr_r_
integer, dimension(0:3^d &), target type_send_p_f
subroutine create_bc_mpi_datatype(nwstart, nwbc, nwfull)
integer, dimension( :^d &), pointer type_send_p
integer, dimension(:,:), allocatable sendstatus_c_sr
integer, dimension(0:3^d &), target type_recv_p_p2
integer, dimension(0:3) ixr_p_
double precision, dimension(:), allocatable recvbuffer_r
integer, dimension( :^d &), pointer type_send_srl
integer, dimension(-1:1^d &), target type_send_r_p1
integer, dimension(:), allocatable recvrequest_c_p
integer, dimension(-1:1^d &), target type_send_srl_p2
integer, dimension(0:3^d &), target type_send_p_p2
integer, dimension(:), allocatable recvrequest_c_sr
integer, dimension(0:3^d &), target type_recv_r_f
integer, dimension(-1:1^d &), target type_recv_srl_f
integer, dimension(:), allocatable sendrequest_c_sr
integer, dimension(-1:1^d &), target type_send_r_f
double precision, dimension(:), allocatable recvbuffer_srl
integer, dimension(:,:), allocatable recvstatus_p
integer, dimension(^nd, 0:3) ixs_p_stg_
integer, dimension(-1:1^d &), target type_send_srl_f
integer, dimension(^nd, 0:3^d &) sizes_p_recv_stg
integer, dimension(0:3^d &), target type_send_p_p1
integer, dimension(^nd,-1:1^d &) sizes_srl_recv_stg
double precision, dimension(:), allocatable recvbuffer_p
integer, dimension(^nd,-1:1) ixr_srl_stg_
integer, dimension(-1:1) ixs_r_
procedure(update_eos_bc_sub), pointer update_eos_4_bc
integer, dimension( :^d &), pointer type_send_r
integer, dimension(-1:1) ixr_srl_
integer, dimension(0:3^d &), target type_recv_r_p1
double precision, dimension(:), allocatable sendbuffer_r
integer, dimension(0:3^d &), target type_recv_r_p2
integer, dimension(0:3^d &) sizes_p_recv_total
subroutine get_bc_comm_type(comm_type, ixl, ixgl, nwstart, nwbc, nwfull)
integer, dimension(:,:), allocatable recvstatus_c_sr
integer, dimension(0:3^d &) sizes_r_recv_total
integer, parameter npwbuf
integer, dimension(:), allocatable sendrequest_p
integer, dimension(^nd, 0:3^d &) sizes_r_recv_stg
integer, dimension(-1:1^d &), target type_recv_srl_p2
double precision, dimension(:), allocatable sendbuffer_srl
integer, dimension(-1:1) ixs_srl_
integer, dimension(:,:), allocatable sendstatus_srl
integer, dimension( :^d &), pointer type_recv_p
integer, dimension(:,:), allocatable recvstatus_srl
integer, dimension(:), allocatable sendrequest_srl
integer, dimension(:,:), allocatable recvstatus_r
integer, dimension(0:3^d &) sizes_p_send_total
integer, dimension(^nd, 0:3) ixr_p_stg_
integer, dimension(-1:1^d &), target type_recv_srl_p1
integer, dimension(:,:), allocatable sendstatus_r
integer, dimension(0:3^d &), target type_recv_p_f
integer, dimension( :^d &), pointer type_recv_srl
integer, dimension(:,:), allocatable sendstatus_p
integer, dimension(-1:1^d &) sizes_srl_recv_total
integer, dimension(:), allocatable recvrequest_p
integer, dimension(:), allocatable recvrequest_srl
integer, dimension(^nd,-1:1^d &) sizes_srl_send_stg
integer, dimension(:,:), allocatable recvstatus_c_p
This module contains definitions of global parameters and variables and some generic functions/subrou...
logical internalboundary
if there is an internal boundary
integer ixghi
Upper index of grid block arrays.
integer, dimension(3, 3) kr
Kronecker delta tensor.
integer, parameter ndim
Number of spatial dimensions for grid variables.
logical stagger_grid
True for using stagger grid.
logical ghost_copy
whether copy values instead of interpolation in ghost cells of finer blocks
integer ierrmpi
A global MPI error return code.
double precision, dimension(:), allocatable, parameter d
integer nghostcells
Number of ghost cells surrounding a grid.
This module defines the procedures of a physics module. It contains function pointers for the various...
Definition mod_physics.t:4
procedure(sub_convert), pointer phys_to_primitive
Definition mod_physics.t:52
procedure(sub_convert), pointer phys_to_prolong
Definition mod_physics.t:55
procedure(sub_convert), pointer phys_to_conserved
Definition mod_physics.t:51
character(len=name_len) physics_type
String describing the physics type of the simulation.
Definition mod_physics.t:47
procedure(sub_convert), pointer phys_from_prolong
Definition mod_physics.t:56
Module with all the methods that users can customize in AMRVAC.
procedure(special_prepare_bc), pointer usr_prepare_boundary