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
404
405 double precision, intent(in) :: time, qdt
406 type(state), target :: psb(max_blocks)
407 integer, intent(in) :: nwstart ! Fill from nwstart
408 integer, intent(in) :: nwbc ! Number of variables to fill
409
410 double precision :: tbc(3)
411 integer :: nwhead, nwtail
412 integer :: iigrid, igrid, isizes, i^D
413 integer :: isend_buf(npwbuf), ipwbuf, nghostcellsco
414 integer :: flushed_send_c, flushed_send_srl, flushed_send_r, flushed_send_p
415 ! index pointer for buffer arrays as a start for a segment
416 integer :: ibuf_start, ibuf_next
417 ! shapes of reshape
418 integer, dimension(1) :: shapes
419 type(wbuffer) :: pwbuf(npwbuf)
420
421 call timer_open(tbc)
422
423 nwhead=nwstart
424 nwtail=nwstart+nwbc-1
425
426 ! fill internal physical boundary
427 if (internalboundary) then
428 call getintbc(time,qdt,ixg^ll)
429 end if
430
431 ! prepare coarse values to send to coarser neighbors
432 !$OMP PARALLEL DO SCHEDULE(dynamic) PRIVATE(igrid)
433 do iigrid=1,igridstail; igrid=igrids(iigrid);
434 if(any(neighbor_type(:^d&,igrid)==neighbor_coarse)) then
435 call coarsen_grid(psb(igrid),ixg^ll,ixm^l,psc(igrid),ixcog^l,ixcom^l)
436 end if
437 end do
438 !$OMP END PARALLEL DO
439
440 ! default : no singular axis
441 irecv_c=0
442 isend_c=0
443 flushed_send_c=0
444 flushed_send_srl=0
445 flushed_send_r=0
446 flushed_send_p=0
447 isend_buf=0
448 ipwbuf=1
449
450 if(stagger_grid) then
457 irecv_srl=0
458 irecv_r=0
459 irecv_p=0
460 isend_srl=0
461 isend_r=0
462 isend_p=0
463 end if
464
465 !$OMP PARALLEL SECTIONS PRIVATE(iigrid,igrid,i^D)
466 !$OMP SECTION
467 ! MPI receive ghost-cell values from sibling blocks and finer neighbors in different processors
468 do iigrid=1,igridstail; igrid=igrids(iigrid);
469 {do i^db=-1,1\}
470 if (skip_direction([ i^d ])) cycle
471 select case (neighbor_type(i^d,igrid))
472 case (neighbor_sibling)
473 call bc_recv_srl(igrid,i^d)
474 case (neighbor_fine)
475 call bc_recv_restrict(igrid,i^d)
476 end select
477 {end do\}
478 end do
479
480 ! MPI send ghost-cell values to sibling blocks and coarser neighbors in different processors
481 do iigrid=1,igridstail; igrid=igrids(iigrid);
482 {do i^db=-1,1\}
483 if(skip_direction([ i^d ])) cycle
484 select case (neighbor_type(i^d,igrid))
485 case (neighbor_sibling)
486 call bc_send_srl(igrid,i^d)
487 case (neighbor_coarse)
488 call bc_send_restrict(igrid,i^d)
489 end select
490 {end do\}
491 end do
492
494 call waitall_pending(isend_c,flushed_send_c,sendrequest_c_sr,sendstatus_c_sr)
495 if(stagger_grid) then
497 call waitall_pending(nsend_bc_srl,flushed_send_srl,sendrequest_srl,sendstatus_srl)
499 call waitall_pending(nsend_bc_r,flushed_send_r,sendrequest_r,sendstatus_r)
500 end if
501
502 do ipwbuf=1,npwbuf
503 if (isend_buf(ipwbuf)/=0) deallocate(pwbuf(ipwbuf)%w)
504 end do
505 !$OMP SECTION
506 ! fill ghost-cell values of sibling blocks and coarser neighbors in the same processor
507 do iigrid=1,igridstail; igrid=igrids(iigrid);
508 {do i^db=-1,1\}
509 if(skip_direction([ i^d ])) cycle
510 select case (neighbor_type(i^d,igrid))
511 case(neighbor_sibling)
512 call bc_fill_srl(igrid,i^d)
513 case(neighbor_coarse)
514 call bc_fill_restrict(igrid,i^d)
515 end select
516 {end do\}
517 end do
518 !$OMP END PARALLEL SECTIONS
519
520 if(stagger_grid) then
521 ! unpack the received data from sibling blocks and finer neighbors to fill ghost-cell staggered values
524 do iigrid=1,igridstail; igrid=igrids(iigrid);
525 {do i^db=-1,1\}
526 if (skip_direction([ i^d ])) cycle
527 select case (neighbor_type(i^d,igrid))
528 case (neighbor_sibling)
529 call bc_fill_srl_stg(igrid,i^d)
530 case (neighbor_fine)
531 call bc_fill_restrict_stg(igrid,i^d)
532 end select
533 {end do\}
534 end do
535 end if
536
537 irecv_c=0
538 isend_c=0
539 flushed_send_c=0
540 flushed_send_p=0
541 isend_buf=0
542 ipwbuf=1
543
544 !$OMP PARALLEL SECTIONS PRIVATE(iigrid,igrid,i^D)
545 !$OMP SECTION
546 ! MPI receive ghost-cell values from coarser neighbors in different processors
547 do iigrid=1,igridstail; igrid=igrids(iigrid);
548 {do i^db=-1,1\}
549 if (skip_direction([ i^d ])) cycle
550 if (neighbor_type(i^d,igrid)==neighbor_coarse) call bc_recv_prolong(igrid,i^d)
551 {end do\}
552 end do
553 ! MPI send ghost-cell values to finer neighbors in different processors
554 do iigrid=1,igridstail; igrid=igrids(iigrid);
555 {do i^db=-1,1\}
556 if (skip_direction([ i^d ])) cycle
557 if (neighbor_type(i^d,igrid)==neighbor_fine) call bc_send_prolong(igrid,i^d)
558 {end do\}
559 end do
560
562 call waitall_pending(isend_c,flushed_send_c,sendrequest_c_p,sendstatus_c_p)
563
564 if(stagger_grid) then
566 call waitall_pending(nsend_bc_p,flushed_send_p,sendrequest_p,sendstatus_p)
567 end if
568
569 do ipwbuf=1,npwbuf
570 if (isend_buf(ipwbuf)/=0) deallocate(pwbuf(ipwbuf)%w)
571 end do
572
573 !$OMP SECTION
574 ! fill coarse ghost-cell values of finer neighbors in the same processor
575 do iigrid=1,igridstail; igrid=igrids(iigrid);
576 {do i^db=-1,1\}
577 if (skip_direction([ i^d ])) cycle
578 if (neighbor_type(i^d,igrid)==neighbor_fine) call bc_fill_prolong(igrid,i^d)
579 {end do\}
580 end do
581 !$OMP END PARALLEL SECTIONS
582
583 if(stagger_grid) then
584 ! fill coarser representative ghost cells after receipt
586 do iigrid=1,igridstail; igrid=igrids(iigrid);
587 {do i^db=-1,1\}
588 if (skip_direction([ i^d ])) cycle
589 if(neighbor_type(i^d,igrid)==neighbor_coarse) call bc_fill_prolong_stg(igrid,i^d)
590 {end do\}
591 end do
592 end if
593 ! do prolongation on the ghost-cell values based on the received coarse values from coarser neighbors
594 !$OMP PARALLEL DO SCHEDULE(dynamic) PRIVATE(igrid)
595 do iigrid=1,igridstail; igrid=igrids(iigrid);
596 call gc_prolong(igrid)
597 end do
598 !$OMP END PARALLEL DO
599
600 ! fill physical boundary ghost cells after internal ghost-cell values exchange
601 if(bcphys) then
602 if(associated(usr_prepare_boundary)) then
603 call usr_prepare_boundary(time, qdt)
604 endif
605 !$OMP PARALLEL DO SCHEDULE(dynamic) PRIVATE(igrid)
606 do iigrid=1,igridstail; igrid=igrids(iigrid);
607 if(.not.phyboundblock(igrid)) cycle
608 call fill_boundary_after_gc(igrid)
609 end do
610 !$OMP END PARALLEL DO
611 end if
612
613 ! modify normal component of magnetic field to fix divB=0
614 if(bcphys.and.associated(phys_boundary_adjust)) then
615 !$OMP PARALLEL DO SCHEDULE(dynamic) PRIVATE(igrid)
616 do iigrid=1,igridstail; igrid=igrids(iigrid);
617 if(.not.phyboundblock(igrid)) cycle
618 call phys_boundary_adjust(igrid,psb)
619 end do
620 !$OMP END PARALLEL DO
621 end if
622
623 ! EoS work in the boundary conditions and level-jump conversions is counted under the EoS
624 time_bc=time_bc+timer_close(tbc)
625
626 contains
627
628 subroutine waitall_limited(nrequest,requests,statuses)
629 integer, intent(in) :: nrequest
630 integer, intent(inout) :: requests(:)
631 integer, intent(inout) :: statuses(:,:)
632
633 if (ghostcell_comm_batched) then
634 call waitall_range(1,nrequest,requests,statuses)
635 else
636 call mpi_waitall(nrequest,requests,statuses,ierrmpi)
637 end if
638 end subroutine waitall_limited
639
640 subroutine waitall_range(ifirst,ilast,requests,statuses)
641 integer, intent(in) :: ifirst, ilast
642 integer, intent(inout) :: requests(:)
643 integer, intent(inout) :: statuses(:,:)
644
645 integer :: irequest,nwait
646
647 do irequest=ifirst,ilast,ghostcell_comm_batch_size
648 nwait=min(ghostcell_comm_batch_size,ilast-irequest+1)
649 call mpi_waitall(nwait,requests(irequest:irequest+nwait-1),&
650 statuses(:,irequest:irequest+nwait-1),ierrmpi)
651 end do
652 end subroutine waitall_range
653
654 subroutine waitall_pending(nrequest,nwaited,requests,statuses)
655 integer, intent(in) :: nrequest
656 integer, intent(inout) :: nwaited
657 integer, intent(inout) :: requests(:)
658 integer, intent(inout) :: statuses(:,:)
659
660 if (nrequest>nwaited) then
661 if (ghostcell_comm_batched) then
662 call waitall_range(nwaited+1,nrequest,requests,statuses)
663 else
664 call mpi_waitall(nrequest-nwaited,requests(nwaited+1:nrequest),&
665 statuses(:,nwaited+1:nrequest),ierrmpi)
666 end if
667 nwaited=nrequest
668 end if
669 end subroutine waitall_pending
670
671 subroutine wait_send_batch(nrequest,nwaited,requests,statuses)
672 integer, intent(in) :: nrequest
673 integer, intent(inout) :: nwaited
674 integer, intent(inout) :: requests(:)
675 integer, intent(inout) :: statuses(:,:)
676
677 if (ghostcell_comm_batched .and. &
678 nrequest-nwaited >= ghostcell_comm_batch_size) then
679 call waitall_range(nwaited+1,nrequest,requests,statuses)
680 nwaited=nrequest
681 end if
682 end subroutine wait_send_batch
683
684 logical function skip_direction(dir)
685 integer, intent(in) :: dir(^ND)
686
687 if (all(dir == 0)) then
688 skip_direction = .true.
689 else
690 skip_direction = .false.
691 end if
692 end function skip_direction
693
694 !> Physical boundary conditions
695 subroutine fill_boundary_after_gc(igrid)
696
697 integer, intent(in) :: igrid
698
699 integer :: idims,iside,i^D,k^L,ixB^L,ixO^L
700 logical :: has_eos_bc
701
702 !> Query the hook once: gfortran resolves the symbol as a procedure after the
703 !> first call statement and then rejects associated() on it later in the scope.
704 has_eos_bc = associated(update_eos_4_bc)
705 block=>psb(igrid)
706 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
707 do idims=1,ndim
708 ! to avoid using as yet unknown corner info in more than 1D, we
709 ! fill only interior mesh ranges of the ghost cell ranges at first,
710 ! and progressively enlarge the ranges to include corners later
711 kmin1=0; kmax1=0;
712 {^iftwod
713 kmin2=merge(1, 0, idims .lt. 2 .and. neighbor_type(0,-1,igrid)==1)
714 kmax2=merge(1, 0, idims .lt. 2 .and. neighbor_type(0, 1,igrid)==1)}
715 {^ifthreed
716 kmin2=merge(1, 0, idims .lt. 2 .and. neighbor_type(0,-1,0,igrid)==1)
717 kmax2=merge(1, 0, idims .lt. 2 .and. neighbor_type(0, 1,0,igrid)==1)
718 kmin3=merge(1, 0, idims .lt. 3 .and. neighbor_type(0,0,-1,igrid)==1)
719 kmax3=merge(1, 0, idims .lt. 3 .and. neighbor_type(0,0, 1,igrid)==1)}
720 ixbmin^d=ixglo^d+kmin^d*nghostcells;
721 ixbmax^d=ixghi^d-kmax^d*nghostcells;
722 do iside=1,2
723 i^d=kr(^d,idims)*(2*iside-3);
724 if (aperiodb(idims)) then
725 if (neighbor_type(i^d,igrid) /= neighbor_boundary .and. &
726 .not. psb(igrid)%is_physical_boundary(2*idims-2+iside)) cycle
727 else
728 if (neighbor_type(i^d,igrid) /= neighbor_boundary) cycle
729 end if
730 !> Refresh the EoS-derived ghost fields before extrapolation; the hook
731 !> is set (in amrvac.t) only when the EoS needs it, e.g. LTE.
732 !> ixM (interior) is deliberate: bc_phys extrapolates outward from interior
733 !> values, so it is the interior that must be current here. Ghost cells are
734 !> covered afterwards, for every block, at the end of getbc.
735 if (has_eos_bc) &
736 call update_eos_4_bc(ixg^ll,ixm^ll,psb(igrid)%w,psb(igrid)%x)
737 call bc_phys(iside,idims,time,qdt,psb(igrid),ixg^ll,ixb^l)
738 !> ...and derive them again on the cells bc_phys just wrote. The call above
739 !> refreshes the interior so bc_phys can extrapolate outward from current values;
740 !> it does not touch the ghosts bc_phys produces. Those are never reached by the
741 !> exchange either (physical boundaries have no neighbour to receive from), so
742 !> without this they keep whatever the block held before. ixO is the same ghost
743 !> strip bc_phys derives internally from ixB -- nghostcells deep, this side only.
744 if (has_eos_bc) then
745 select case (idims)
746 {case (^d)
747 if (iside==2) then
748 ixomin^dd=ixbmax^d+1-nghostcells^d%ixOmin^dd=ixbmin^dd;
749 ixomax^dd=ixbmax^dd;
750 else
751 ixomin^dd=ixbmin^dd;
752 ixomax^dd=ixbmin^d-1+nghostcells^d%ixOmax^dd=ixbmax^dd;
753 end if \}
754 end select
755 call update_eos_4_bc(ixg^ll,ixo^l,psb(igrid)%w,psb(igrid)%x)
756 end if
757 end do
758 end do
759
760 end subroutine fill_boundary_after_gc
761
762 !> MPI receive from sibling at same refinement level
763 subroutine bc_recv_srl(igrid,i^D)
764 integer, intent(in) :: igrid,i^D
765
766 integer :: ipe_neighbor
767
768 ipe_neighbor=neighbor(2,i^d,igrid)
769 if (ipe_neighbor/=mype) then
771 itag=(3**^nd+4**^nd)*(igrid-1)+{(i^d+1)*3**(^d-1)+}
772 call mpi_irecv(psb(igrid)%w,1,type_recv_srl(i^d), &
773 ipe_neighbor,itag,icomm,recvrequest_c_sr(irecv_c),ierrmpi)
774 if(stagger_grid) then
776 call mpi_irecv(recvbuffer_srl(ibuf_recv_srl),sizes_srl_recv_total(i^d),mpi_double_precision, &
777 ipe_neighbor,itag,icomm,recvrequest_srl(irecv_srl),ierrmpi)
779 end if
780 end if
781
782 end subroutine bc_recv_srl
783
784 !> MPI receive from fine neighbor
785 subroutine bc_recv_restrict(igrid,i^D)
786 integer, intent(in) :: igrid,i^D
787
788 integer :: ic^D,inc^D,ipe_neighbor
789
790 {do ic^db=1+int((1-i^db)/2),2-int((1+i^db)/2)
791 inc^db=2*i^db+ic^db\}
792 ipe_neighbor=neighbor_child(2,inc^d,igrid)
793 if (ipe_neighbor/=mype) then
795 itag=(3**^nd+4**^nd)*(igrid-1)+3**^nd+{inc^d*4**(^d-1)+}
796 call mpi_irecv(psb(igrid)%w,1,type_recv_r(inc^d), &
797 ipe_neighbor,itag,icomm,recvrequest_c_sr(irecv_c),ierrmpi)
798 if(stagger_grid) then
800 call mpi_irecv(recvbuffer_r(ibuf_recv_r),sizes_r_recv_total(inc^d), &
801 mpi_double_precision,ipe_neighbor,itag, &
802 icomm,recvrequest_r(irecv_r),ierrmpi)
804 end if
805 end if
806 {end do\}
807
808 end subroutine bc_recv_restrict
809
810 !> MPI send to sibling at same refinement level
811 subroutine bc_send_srl(igrid,i^D)
812 integer, intent(in) :: igrid,i^D
813
814 integer :: n_i^D,ipole,idir,ineighbor,ipe_neighbor,ixS^L
815
816 ipe_neighbor=neighbor(2,i^d,igrid)
817 if(ipe_neighbor/=mype) then
818 ineighbor=neighbor(1,i^d,igrid)
819 ipole=neighbor_pole(i^d,igrid)
820 if(ipole==0) then
821 n_i^d=-i^d;
823 itag=(3**^nd+4**^nd)*(ineighbor-1)+{(n_i^d+1)*3**(^d-1)+}
824 call mpi_isend(psb(igrid)%w,1,type_send_srl(i^d), &
825 ipe_neighbor,itag,icomm,sendrequest_c_sr(isend_c),ierrmpi)
826 call wait_send_batch(isend_c,flushed_send_c,sendrequest_c_sr,sendstatus_c_sr)
827 if(stagger_grid) then
828 ibuf_start=ibuf_send_srl
829 do idir=1,ndim
830 ixs^l=ixs_srl_stg_^l(idir,i^d);
831 ibuf_next=ibuf_start+sizes_srl_send_stg(idir,i^d)
832 shapes=(/sizes_srl_send_stg(idir,i^d)/)
833 sendbuffer_srl(ibuf_start:ibuf_next-1)=&
834 reshape(psb(igrid)%ws(ixs^s,idir),shapes)
835 ibuf_start=ibuf_next
836 end do
839 mpi_double_precision, ipe_neighbor,itag,icomm,sendrequest_srl(isend_srl),ierrmpi)
840 call wait_send_batch(isend_srl,flushed_send_srl,sendrequest_srl,sendstatus_srl)
841 ibuf_send_srl=ibuf_next
842 end if
843 else
844 ixs^l=ixs_srl_^l(i^d);
845 select case (ipole)
846 {case (^d)
847 n_i^d=i^d^d%n_i^dd=-i^dd;\}
848 end select
849 if (isend_buf(ipwbuf)/=0) then
850 call mpi_wait(sendrequest_c_sr(isend_buf(ipwbuf)), &
851 sendstatus_c_sr(:,isend_buf(ipwbuf)),ierrmpi)
852 deallocate(pwbuf(ipwbuf)%w)
853 end if
854 allocate(pwbuf(ipwbuf)%w(ixs^s,nwhead:nwtail))
855 call pole_buffer(pwbuf(ipwbuf)%w,ixs^l,ixs^l,psb(igrid)%w,ixg^ll,ixs^l,ipole)
857 isend_buf(ipwbuf)=isend_c
858 itag=(3**^nd+4**^nd)*(ineighbor-1)+{(n_i^d+1)*3**(^d-1)+}
859 isizes={(ixsmax^d-ixsmin^d+1)*}*nwbc
860 call mpi_isend(pwbuf(ipwbuf)%w,isizes,mpi_double_precision, &
861 ipe_neighbor,itag,icomm,sendrequest_c_sr(isend_c),ierrmpi)
862 call wait_send_batch(isend_c,flushed_send_c,sendrequest_c_sr,sendstatus_c_sr)
863 ipwbuf=1+modulo(ipwbuf,npwbuf)
864 if(stagger_grid) then
865 ibuf_start=ibuf_send_srl
866 do idir=1,ndim
867 ixs^l=ixs_srl_stg_^l(idir,i^d);
868 ibuf_next=ibuf_start+sizes_srl_send_stg(idir,i^d)
869 shapes=(/sizes_srl_send_stg(idir,i^d)/)
870 sendbuffer_srl(ibuf_start:ibuf_next-1)=&
871 reshape(psb(igrid)%ws(ixs^s,idir),shapes)
872 ibuf_start=ibuf_next
873 end do
876 mpi_double_precision, ipe_neighbor,itag,icomm,sendrequest_srl(isend_srl),ierrmpi)
877 call wait_send_batch(isend_srl,flushed_send_srl,sendrequest_srl,sendstatus_srl)
878 ibuf_send_srl=ibuf_next
879 end if
880 end if
881 end if
882
883 end subroutine bc_send_srl
884
885 !> MPI send to coarser neighbor's ghost cells
886 subroutine bc_send_restrict(igrid,i^D)
887 integer, intent(in) :: igrid,i^D
888
889 integer :: ic^D,n_inc^D,ipole,idir,ineighbor,ipe_neighbor,ixS^L
890
891 ipe_neighbor=neighbor(2,i^d,igrid)
892 if(ipe_neighbor/=mype) then
893 ic^d=1+modulo(node(pig^d_,igrid)-1,2);
894 if({.not.(i^d==0.or.i^d==2*ic^d-3)|.or.}) return
895 ineighbor=neighbor(1,i^d,igrid)
896 ipole=neighbor_pole(i^d,igrid)
897 if(ipole==0) then
898 n_inc^d=-2*i^d+ic^d;
900 itag=(3**^nd+4**^nd)*(ineighbor-1)+3**^nd+{n_inc^d*4**(^d-1)+}
901 call mpi_isend(psc(igrid)%w,1,type_send_r(i^d), &
902 ipe_neighbor,itag,icomm,sendrequest_c_sr(isend_c),ierrmpi)
903 call wait_send_batch(isend_c,flushed_send_c,sendrequest_c_sr,sendstatus_c_sr)
904 if(stagger_grid) then
905 ibuf_start=ibuf_send_r
906 do idir=1,ndim
907 ixs^l=ixs_r_stg_^l(idir,i^d);
908 ibuf_next=ibuf_start+sizes_r_send_stg(idir,i^d)
909 shapes=(/sizes_r_send_stg(idir,i^d)/)
910 sendbuffer_r(ibuf_start:ibuf_next-1)=&
911 reshape(psc(igrid)%ws(ixs^s,idir),shapes)
912 ibuf_start=ibuf_next
913 end do
915 call mpi_isend(sendbuffer_r(ibuf_send_r),sizes_r_send_total(i^d),&
916 mpi_double_precision,ipe_neighbor,itag, &
917 icomm,sendrequest_r(isend_r),ierrmpi)
918 call wait_send_batch(isend_r,flushed_send_r,sendrequest_r,sendstatus_r)
919 ibuf_send_r=ibuf_next
920 end if
921 else
922 ixs^l=ixs_r_^l(i^d);
923 select case (ipole)
924 {case (^d)
925 n_inc^d=2*i^d+(3-ic^d)^d%n_inc^dd=-2*i^dd+ic^dd;\}
926 end select
927 if(isend_buf(ipwbuf)/=0) then
928 call mpi_wait(sendrequest_c_sr(isend_buf(ipwbuf)), &
929 sendstatus_c_sr(:,isend_buf(ipwbuf)),ierrmpi)
930 deallocate(pwbuf(ipwbuf)%w)
931 end if
932 allocate(pwbuf(ipwbuf)%w(ixs^s,nwhead:nwtail))
933 call pole_buffer(pwbuf(ipwbuf)%w,ixs^l,ixs^l,psc(igrid)%w,ixcog^l,ixs^l,ipole)
935 isend_buf(ipwbuf)=isend_c
936 itag=(3**^nd+4**^nd)*(ineighbor-1)+3**^nd+{n_inc^d*4**(^d-1)+}
937 isizes={(ixsmax^d-ixsmin^d+1)*}*nwbc
938 call mpi_isend(pwbuf(ipwbuf)%w,isizes,mpi_double_precision, &
939 ipe_neighbor,itag,icomm,sendrequest_c_sr(isend_c),ierrmpi)
940 call wait_send_batch(isend_c,flushed_send_c,sendrequest_c_sr,sendstatus_c_sr)
941 ipwbuf=1+modulo(ipwbuf,npwbuf)
942 if(stagger_grid) then
943 ibuf_start=ibuf_send_r
944 do idir=1,ndim
945 ixs^l=ixs_r_stg_^l(idir,i^d);
946 ibuf_next=ibuf_start+sizes_r_send_stg(idir,i^d)
947 shapes=(/sizes_r_send_stg(idir,i^d)/)
948 sendbuffer_r(ibuf_start:ibuf_next-1)=&
949 reshape(psc(igrid)%ws(ixs^s,idir),shapes)
950 ibuf_start=ibuf_next
951 end do
953 call mpi_isend(sendbuffer_r(ibuf_send_r),sizes_r_send_total(i^d),&
954 mpi_double_precision,ipe_neighbor,itag, &
955 icomm,sendrequest_r(isend_r),ierrmpi)
956 call wait_send_batch(isend_r,flushed_send_r,sendrequest_r,sendstatus_r)
957 ibuf_send_r=ibuf_next
958 end if
959 end if
960 end if
961
962 end subroutine bc_send_restrict
963
964 !> fill same-level neighbor's ghost cells in the same processor
965 subroutine bc_fill_srl(igrid,i^D)
966 integer, intent(in) :: igrid,i^D
967
968 integer :: ineighbor,ipe_neighbor,ipole,ixS^L,ixR^L,n_i^D,idir
969
970 ipe_neighbor=neighbor(2,i^d,igrid)
971 if(ipe_neighbor==mype) then
972 ineighbor=neighbor(1,i^d,igrid)
973 ipole=neighbor_pole(i^d,igrid)
974 if(ipole==0) then
975 n_i^d=-i^d;
976 ixs^l=ixs_srl_^l(i^d);
977 ixr^l=ixr_srl_^l(n_i^d);
978 psb(ineighbor)%w(ixr^s,nwhead:nwtail)=&
979 psb(igrid)%w(ixs^s,nwhead:nwtail)
980 if(stagger_grid) then
981 do idir=1,ndim
982 ixs^l=ixs_srl_stg_^l(idir,i^d);
983 ixr^l=ixr_srl_stg_^l(idir,n_i^d);
984 psb(ineighbor)%ws(ixr^s,idir)=psb(igrid)%ws(ixs^s,idir)
985 end do
986 end if
987 else
988 ixs^l=ixs_srl_^l(i^d);
989 select case (ipole)
990 {case (^d)
991 n_i^d=i^d^d%n_i^dd=-i^dd;\}
992 end select
993 ixr^l=ixr_srl_^l(n_i^d);
994 call pole_copy(psb(ineighbor)%w,ixg^ll,ixr^l,psb(igrid)%w,ixg^ll,ixs^l,ipole)
995 if(stagger_grid) then
996 do idir=1,ndim
997 ixs^l=ixs_srl_stg_^l(idir,i^d);
998 ixr^l=ixr_srl_stg_^l(idir,n_i^d);
999 call pole_copy_stg(psb(ineighbor)%ws,ixgs^ll,ixr^l,psb(igrid)%ws,ixgs^ll,ixs^l,idir,ipole)
1000 end do
1001 end if
1002 end if
1003 end if
1004
1005 end subroutine bc_fill_srl
1006
1007 !> fill coarser neighbor's ghost cells in the same processor
1008 subroutine bc_fill_restrict(igrid,i^D)
1009 integer, intent(in) :: igrid,i^D
1010
1011 integer :: ic^D,n_inc^D,ixS^L,ixR^L,ipe_neighbor,ineighbor,ipole,idir
1012
1013 ipe_neighbor=neighbor(2,i^d,igrid)
1014 if(ipe_neighbor==mype) then
1015 ic^d=1+modulo(node(pig^d_,igrid)-1,2);
1016 if({.not.(i^d==0.or.i^d==2*ic^d-3)|.or.}) return
1017 ineighbor=neighbor(1,i^d,igrid)
1018 ipole=neighbor_pole(i^d,igrid)
1019 if(ipole==0) then
1020 n_inc^d=-2*i^d+ic^d;
1021 ixs^l=ixs_r_^l(i^d);
1022 ixr^l=ixr_r_^l(n_inc^d);
1023 psb(ineighbor)%w(ixr^s,nwhead:nwtail)=&
1024 psc(igrid)%w(ixs^s,nwhead:nwtail)
1025 if(stagger_grid) then
1026 do idir=1,ndim
1027 ixs^l=ixs_r_stg_^l(idir,i^d);
1028 ixr^l=ixr_r_stg_^l(idir,n_inc^d);
1029 psb(ineighbor)%ws(ixr^s,idir)=psc(igrid)%ws(ixs^s,idir)
1030 end do
1031 end if
1032 else
1033 ixs^l=ixs_r_^l(i^d);
1034 select case (ipole)
1035 {case (^d)
1036 n_inc^d=2*i^d+(3-ic^d)^d%n_inc^dd=-2*i^dd+ic^dd;\}
1037 end select
1038 ixr^l=ixr_r_^l(n_inc^d);
1039 call pole_copy(psb(ineighbor)%w,ixg^ll,ixr^l,psc(igrid)%w,ixcog^l,ixs^l,ipole)
1040 if(stagger_grid) then
1041 do idir=1,ndim
1042 ixs^l=ixs_r_stg_^l(idir,i^d);
1043 ixr^l=ixr_r_stg_^l(idir,n_inc^d);
1044 !! Fill ghost cells
1045 call pole_copy_stg(psb(ineighbor)%ws,ixgs^ll,ixr^l,psc(igrid)%ws,ixcogs^l,ixs^l,idir,ipole)
1046 end do
1047 end if
1048 end if
1049 end if
1050
1051 end subroutine bc_fill_restrict
1052
1053 !> fill siblings ghost cells with received data
1054 subroutine bc_fill_srl_stg(igrid,i^D)
1055 integer, intent(in) :: igrid,i^D
1056
1057 integer :: ixS^L,ixR^L,n_i^D,idir,ineighbor,ipe_neighbor,ipole
1058
1059 ipe_neighbor=neighbor(2,i^d,igrid)
1060 if(ipe_neighbor/=mype) then
1061 ineighbor=neighbor(1,i^d,igrid)
1062 ipole=neighbor_pole(i^d,igrid)
1063
1064 !! Now the special treatment of the pole is done here, at the receive step
1065 if (ipole==0) then
1066 ixr^l=ixr_srl_^l(i^d);
1067 !! Unpack the buffer and fill the ghost cells
1068 n_i^d=-i^d;
1069 do idir=1,ndim
1070 ixs^l=ixs_srl_stg_^l(idir,n_i^d);
1071 ixr^l=ixr_srl_stg_^l(idir,i^d);
1072 ibuf_next=ibuf_recv_srl+sizes_srl_recv_stg(idir,i^d)
1073 psb(igrid)%ws(ixr^s,idir)=reshape(source=recvbuffer_srl(ibuf_recv_srl:ibuf_next-1),&
1074 shape=shape(psb(igrid)%ws(ixs^s,idir)))
1075 ibuf_recv_srl=ibuf_next
1076 end do
1077 else ! There is a pole
1078 select case (ipole)
1079 {case (^d)
1080 n_i^d=i^d^d%n_i^dd=-i^dd;\}
1081 end select
1082 pole_buf%ws=zero
1083 do idir=1,ndim
1084 ixr^l=ixr_srl_stg_^l(idir,i^d);
1085 ixs^l=ixs_srl_stg_^l(idir,n_i^d);
1086 ibuf_next=ibuf_recv_srl+sizes_srl_recv_stg(idir,i^d)
1087 pole_buf%ws(ixs^s,idir)=reshape(source=recvbuffer_srl(ibuf_recv_srl:ibuf_next-1),&
1088 shape=shape(psb(igrid)%ws(ixs^s,idir)))
1089 ibuf_recv_srl=ibuf_next
1090 call pole_copy_stg(psb(igrid)%ws,ixgs^ll,ixr^l,pole_buf%ws,ixgs^ll,ixs^l,idir,ipole)
1091 end do
1092 end if
1093 end if
1094
1095 end subroutine bc_fill_srl_stg
1096
1097 !> fill restricted ghost cells after receipt
1098 subroutine bc_fill_restrict_stg(igrid,i^D)
1099 integer, intent(in) :: igrid,i^D
1100
1101 integer :: ipole,ic^D,inc^D,ineighbor,ipe_neighbor,ixS^L,ixR^L,n_i^D,idir
1102
1103 ipole=neighbor_pole(i^d,igrid)
1104 if (ipole==0) then
1105 ! Loop over the children ic^D to and their neighbors inc^D
1106 {do ic^db=1+int((1-i^db)/2),2-int((1+i^db)/2)
1107 inc^db=2*i^db+ic^db\}
1108 ipe_neighbor=neighbor_child(2,inc^d,igrid)
1109 if(ipe_neighbor/=mype) then
1110 ineighbor=neighbor_child(1,inc^d,igrid)
1111 n_i^d=-i^d;
1112 !! Unpack the buffer and fill the ghost cells
1113 do idir=1,ndim
1114 ixr^l=ixr_r_stg_^l(idir,inc^d);
1115 ibuf_next=ibuf_recv_r+sizes_r_recv_stg(idir,inc^d)
1116 psb(igrid)%ws(ixr^s,idir)=reshape(source=recvbuffer_r(ibuf_recv_r:ibuf_next-1),&
1117 shape=shape(psb(igrid)%ws(ixr^s,idir)))
1118 ibuf_recv_r=ibuf_next
1119 end do
1120 end if
1121 {end do\}
1122 else !! There is a pole
1123 {do ic^db=1+int((1-i^db)/2),2-int((1+i^db)/2)
1124 inc^db=2*i^db+ic^db\}
1125 ipe_neighbor=neighbor_child(2,inc^d,igrid)
1126 if(ipe_neighbor/=mype) then
1127 ineighbor=neighbor_child(1,inc^d,igrid)
1128 select case(ipole)
1129 {case (^d)
1130 n_i^d=i^d^d%n_i^dd=-i^dd;\}
1131 end select
1132 ixr^l=ixr_r_^l(inc^d);
1133 !! Unpack the buffer and fill an auxiliary array
1134 pole_buf%ws=zero
1135 do idir=1,ndim
1136 ixs^l=ixs_r_stg_^l(idir,n_i^d);
1137 ixr^l=ixr_r_stg_^l(idir,inc^d);
1138 ibuf_next=ibuf_recv_r+sizes_r_recv_stg(idir,inc^d)
1139 pole_buf%ws(ixr^s,idir)=reshape(source=recvbuffer_r(ibuf_recv_r:ibuf_next-1),&
1140 shape=shape(psb(igrid)%ws(ixr^s,idir)))
1141 call pole_copy_stg(psb(igrid)%ws,ixgs^ll,ixr^l,pole_buf%ws,ixgs^ll,ixr^l,idir,ipole)
1142 ibuf_recv_r=ibuf_next
1143 end do
1144 end if
1145 {end do\}
1146 end if
1147
1148 end subroutine bc_fill_restrict_stg
1149
1150 !> Receive from coarse neighbor
1151 subroutine bc_recv_prolong(igrid,i^D)
1152 integer, intent(in) :: igrid,i^D
1153
1154 integer :: ic^D,ipe_neighbor,inc^D
1155
1156 ic^d=1+modulo(node(pig^d_,igrid)-1,2);
1157 if ({.not.(i^d==0.or.i^d==2*ic^d-3)|.or.}) return
1158
1159 ipe_neighbor=neighbor(2,i^d,igrid)
1160 if (ipe_neighbor/=mype) then
1162 inc^d=ic^d+i^d;
1163 itag=(3**^nd+4**^nd)*(igrid-1)+3**^nd+{inc^d*4**(^d-1)+}
1164 call mpi_irecv(psc(igrid)%w,1,type_recv_p(inc^d), &
1165 ipe_neighbor,itag,icomm,recvrequest_c_p(irecv_c),ierrmpi)
1166 if(stagger_grid) then
1168 call mpi_irecv(recvbuffer_p(ibuf_recv_p),sizes_p_recv_total(inc^d),&
1169 mpi_double_precision,ipe_neighbor,itag,&
1170 icomm,recvrequest_p(irecv_p),ierrmpi)
1172 end if
1173 end if
1174
1175 end subroutine bc_recv_prolong
1176
1177 !> Send to finer neighbor
1178 subroutine bc_send_prolong(igrid,i^D)
1179 integer, intent(in) :: igrid,i^D
1180
1181 integer :: ic^D,inc^D,n_i^D,n_inc^D,ineighbor,ipe_neighbor,ixS^L,ipole,idir
1182
1183 ipole=neighbor_pole(i^d,igrid)
1184
1185 {do ic^db=1+int((1-i^db)/2),2-int((1+i^db)/2)
1186 inc^db=2*i^db+ic^db\}
1187 ipe_neighbor=neighbor_child(2,inc^d,igrid)
1188 if(ipe_neighbor/=mype) then
1189 ineighbor=neighbor_child(1,inc^d,igrid)
1190 if(ipole==0) then
1191 n_i^d=-i^d;
1192 n_inc^d=ic^d+n_i^d;
1194 itag=(3**^nd+4**^nd)*(ineighbor-1)+3**^nd+{n_inc^d*4**(^d-1)+}
1195 call mpi_isend(psb(igrid)%w,1,type_send_p(inc^d), &
1196 ipe_neighbor,itag,icomm,sendrequest_c_p(isend_c),ierrmpi)
1197 call wait_send_batch(isend_c,flushed_send_c,sendrequest_c_p,sendstatus_c_p)
1198 if(stagger_grid) then
1199 ibuf_start=ibuf_send_p
1200 do idir=1,ndim
1201 ixs^l=ixs_p_stg_^l(idir,inc^d);
1202 ibuf_next=ibuf_start+sizes_p_send_stg(idir,inc^d)
1203 shapes=(/sizes_p_send_stg(idir,inc^d)/)
1204 sendbuffer_p(ibuf_start:ibuf_next-1)=&
1205 reshape(psb(igrid)%ws(ixs^s,idir),shapes)
1206 ibuf_start=ibuf_next
1207 end do
1209 call mpi_isend(sendbuffer_p(ibuf_send_p),sizes_p_send_total(inc^d),&
1210 mpi_double_precision,ipe_neighbor,itag, &
1211 icomm,sendrequest_p(isend_p),ierrmpi)
1212 call wait_send_batch(isend_p,flushed_send_p,sendrequest_p,sendstatus_p)
1213 ibuf_send_p=ibuf_next
1214 end if
1215 else
1216 ixs^l=ixs_p_^l(inc^d);
1217 select case (ipole)
1218 {case (^d)
1219 n_inc^d=inc^d^d%n_inc^dd=ic^dd-i^dd;\}
1220 end select
1221 if(isend_buf(ipwbuf)/=0) then
1222 call mpi_wait(sendrequest_c_p(isend_buf(ipwbuf)), &
1223 sendstatus_c_p(:,isend_buf(ipwbuf)),ierrmpi)
1224 deallocate(pwbuf(ipwbuf)%w)
1225 end if
1226 allocate(pwbuf(ipwbuf)%w(ixs^s,nwhead:nwtail))
1227 call pole_buffer(pwbuf(ipwbuf)%w,ixs^l,ixs^l,psb(igrid)%w,ixg^ll,ixs^l,ipole)
1229 isend_buf(ipwbuf)=isend_c
1230 itag=(3**^nd+4**^nd)*(ineighbor-1)+3**^nd+{n_inc^d*4**(^d-1)+}
1231 isizes={(ixsmax^d-ixsmin^d+1)*}*nwbc
1232 call mpi_isend(pwbuf(ipwbuf)%w,isizes,mpi_double_precision, &
1233 ipe_neighbor,itag,icomm,sendrequest_c_p(isend_c),ierrmpi)
1234 call wait_send_batch(isend_c,flushed_send_c,sendrequest_c_p,sendstatus_c_p)
1235 ipwbuf=1+modulo(ipwbuf,npwbuf)
1236 if(stagger_grid) then
1237 ibuf_start=ibuf_send_p
1238 do idir=1,ndim
1239 ixs^l=ixs_p_stg_^l(idir,inc^d);
1240 ibuf_next=ibuf_start+sizes_p_send_stg(idir,inc^d)
1241 shapes=(/sizes_p_send_stg(idir,inc^d)/)
1242 sendbuffer_p(ibuf_start:ibuf_next-1)=&
1243 reshape(psb(igrid)%ws(ixs^s,idir),shapes)
1244 ibuf_start=ibuf_next
1245 end do
1247 call mpi_isend(sendbuffer_p(ibuf_send_p),sizes_p_send_total(inc^d),&
1248 mpi_double_precision,ipe_neighbor,itag, &
1249 icomm,sendrequest_p(isend_p),ierrmpi)
1250 call wait_send_batch(isend_p,flushed_send_p,sendrequest_p,sendstatus_p)
1251 ibuf_send_p=ibuf_next
1252 end if
1253 end if
1254 end if
1255 {end do\}
1256
1257 end subroutine bc_send_prolong
1258
1259 !> Send to finer neighbor
1260 subroutine bc_fill_prolong(igrid,i^D)
1261 integer, intent(in) :: igrid,i^D
1262
1263 integer :: ipe_neighbor,ineighbor,ixS^L,ixR^L,ic^D,inc^D,n_i^D,n_inc^D,ipole,idir
1264
1265 ipole=neighbor_pole(i^d,igrid)
1266
1267 if(ipole==0) then
1268 {do ic^db=1+int((1-i^db)/2),2-int((1+i^db)/2)
1269 inc^db=2*i^db+ic^db\}
1270 ipe_neighbor=neighbor_child(2,inc^d,igrid)
1271 if(ipe_neighbor==mype) then
1272 ixs^l=ixs_p_^l(inc^d);
1273 ineighbor=neighbor_child(1,inc^d,igrid)
1274 n_i^d=-i^d;
1275 n_inc^d=ic^d+n_i^d;
1276 ixr^l=ixr_p_^l(n_inc^d);
1277 psc(ineighbor)%w(ixr^s,nwhead:nwtail) &
1278 =psb(igrid)%w(ixs^s,nwhead:nwtail)
1279 if(stagger_grid) then
1280 do idir=1,ndim
1281 ixs^l=ixs_p_stg_^l(idir,inc^d);
1282 ixr^l=ixr_p_stg_^l(idir,n_inc^d);
1283 psc(ineighbor)%ws(ixr^s,idir)=psb(igrid)%ws(ixs^s,idir)
1284 end do
1285 end if
1286 end if
1287 {end do\}
1288 else
1289 {do ic^db=1+int((1-i^db)/2),2-int((1+i^db)/2)
1290 inc^db=2*i^db+ic^db\}
1291 ipe_neighbor=neighbor_child(2,inc^d,igrid)
1292 if(ipe_neighbor==mype) then
1293 ixs^l=ixs_p_^l(inc^d);
1294 ineighbor=neighbor_child(1,inc^d,igrid)
1295 select case (ipole)
1296 {case (^d)
1297 n_inc^d=inc^d^d%n_inc^dd=ic^dd-i^dd;\}
1298 end select
1299 ixr^l=ixr_p_^l(n_inc^d);
1300 call pole_copy(psc(ineighbor)%w,ixcog^l,ixr^l,psb(igrid)%w,ixg^ll,ixs^l,ipole)
1301 if(stagger_grid) then
1302 do idir=1,ndim
1303 ixs^l=ixs_p_stg_^l(idir,inc^d);
1304 ixr^l=ixr_p_stg_^l(idir,n_inc^d);
1305 call pole_copy_stg(psc(ineighbor)%ws,ixcogs^l,ixr^l,psb(igrid)%ws,ixgs^ll,ixs^l,idir,ipole)
1306 end do
1307 end if
1308 end if
1309 {end do\}
1310 end if
1311 end subroutine bc_fill_prolong
1312
1313 subroutine gc_prolong(igrid)
1314 integer, intent(in) :: igrid
1315
1316 integer :: i^D,idims,iside
1317 logical,dimension(-1:1^D&) :: NeedProlong
1318
1319 needprolong=.false.
1320 {do i^db=-1,1\}
1321 if (skip_direction([ i^d ])) cycle
1322 if (neighbor_type(i^d,igrid)==neighbor_coarse) then
1323 call bc_prolong(igrid,i^d)
1324 needprolong(i^d)=.true.
1325 end if
1326 {end do\}
1327 if(stagger_grid) then
1328 ! Ghost cell prolongation for staggered variables
1329 ! must be done in a specific order.
1330 ! First the first neighbours, which have 2 indices=0 in 3D
1331 ! or one index=0 in 2D
1332 block=>psb(igrid)
1333 do idims=1,ndim
1334 i^d=0;
1335 select case(idims)
1336 {case(^d)
1337 do i^d=-1,1,2
1338 if (needprolong(i^dd)) call bc_prolong_stg(igrid,i^dd,needprolong)
1339 end do
1340 \}
1341 end select
1342 end do
1343 ! Then the second neighbours which have 1 index=0 in 3D
1344 ! (Only in 3D)
1345 {^ifthreed
1346 i1=0;
1347 do i2=-1,1,2
1348 do i3=-1,1,2
1349 if (needprolong(i^d)) call bc_prolong_stg(igrid,i^d,needprolong)
1350 end do
1351 end do
1352 i2=0;
1353 do i3=-1,1,2
1354 do i1=-1,1,2
1355 if (needprolong(i^d)) call bc_prolong_stg(igrid,i^d,needprolong)
1356 end do
1357 end do
1358 i3=0;
1359 do i1=-1,1,2
1360 do i2=-1,1,2
1361 if (needprolong(i^d)) call bc_prolong_stg(igrid,i^d,needprolong)
1362 end do
1363 end do
1364 }
1365 ! Finally, the corners, that have no index=0
1366 {do i^d=-1,1,2\}
1367 if (needprolong(i^d)) call bc_prolong_stg(igrid,i^d,needprolong)
1368 {end do\}
1369 end if
1370 end subroutine gc_prolong
1371
1372 !> fill coarser representative with data from coarser neighbors
1373 subroutine bc_fill_prolong_stg(igrid,i^D)
1374 integer, intent(in) :: igrid,i^D
1375
1376 integer :: ipe_neighbor,ineighbor,ipole,ixR^L,ic^D,inc^D,n_inc^D,idir
1377
1378 ic^d=1+modulo(node(pig^d_,igrid)-1,2);
1379 if ({.not.(i^d==0.or.i^d==2*ic^d-3)|.or.}) return
1380
1381 ipe_neighbor=neighbor(2,i^d,igrid)
1382 if(ipe_neighbor/=mype) then
1383 ineighbor=neighbor(1,i^d,igrid)
1384 ipole=neighbor_pole(i^d,igrid)
1385
1386 if (ipole==0) then !! There is no pole
1387 inc^d=ic^d+i^d;
1388 ixr^l=ixr_p_^l(inc^d);
1389 do idir=1,ndim
1390 ixr^l=ixr_p_stg_^l(idir,inc^d);
1391 ibuf_next=ibuf_recv_p+sizes_p_recv_stg(idir,inc^d)
1392 psc(igrid)%ws(ixr^s,idir)=reshape(source=recvbuffer_p(ibuf_recv_p:ibuf_next-1),&
1393 shape=shape(psc(igrid)%ws(ixr^s,idir)))
1394 ibuf_recv_p=ibuf_next
1395 end do
1396 else !! There is a pole
1397 inc^d=ic^d+i^d;
1398 select case (ipole)
1399 {case (^d)
1400 n_inc^d=2*i^d+(3-ic^d)^d%n_inc^dd=-2*i^dd+ic^dd;\}
1401 end select
1402 !! Unpack the buffer and fill an auxiliary array
1403 pole_buf%ws=zero
1404 do idir=1,ndim
1405 ixr^l=ixr_p_stg_^l(idir,inc^d);
1406 ibuf_next=ibuf_recv_p+sizes_p_recv_stg(idir,inc^d)
1407 pole_buf%ws(ixr^s,idir)=reshape(source=recvbuffer_p(ibuf_recv_p:ibuf_next-1),&
1408 shape=shape(psc(igrid)%ws(ixr^s,idir)))
1409 call pole_copy_stg(psc(igrid)%ws,ixcogs^l,ixr^l,pole_buf%ws,ixgs^ll,ixr^l,idir,ipole)
1410 ibuf_recv_p=ibuf_next
1411 end do
1412 end if
1413 end if
1414
1415 end subroutine bc_fill_prolong_stg
1416
1417 !> do prolongation for fine blocks after receipt data from coarse neighbors
1418 subroutine bc_prolong(igrid,i^D)
1421
1422 double precision :: dxFi^D, dxCo^D, xFimin^D, xComin^D, invdxCo^D
1423 integer :: i^D,igrid
1424 integer :: ixFi^L,ixCo^L,ii^D, idims,iside,ixB^L
1425
1426 ixfi^l=ixr_srl_^l(i^d);
1427 dxfi^d=rnode(rpdx^d_,igrid);
1428 dxco^d=two*dxfi^d;
1429 invdxco^d=1.d0/dxco^d;
1430
1431 ! compute the enlarged grid lower left corner coordinates
1432 ! these are true coordinates for an equidistant grid,
1433 ! but we can temporarily also use them for getting indices
1434 ! in stretched grids
1435 xfimin^d=rnode(rpxmin^d_,igrid)-dble(nghostcells)*dxfi^d;
1436 xcomin^d=rnode(rpxmin^d_,igrid)-dble(nghostcells)*dxco^d;
1437
1438 if(phyboundblock(igrid).and.bcphys) then
1439 block=>psc(igrid)
1440 do idims=1,ndim
1441 ixcomin^d=int((xfimin^d+(dble(ixfimin^d)-half)*dxfi^d-xcomin^d)*invdxco^d)+1-1;
1442 ixcomax^d=int((xfimin^d+(dble(ixfimax^d)-half)*dxfi^d-xcomin^d)*invdxco^d)+1+1;
1443 {^ifthreed
1444 ! avoid using undetermined ghost cells at physical boundary edges
1445 if(idims == 1) then
1446 if(neighbor_type(-1,0,0,igrid)==neighbor_boundary .or. &
1447 neighbor_type(1,0,0,igrid)==neighbor_boundary) then
1448 if(neighbor_type(0,-1,0,igrid)==neighbor_boundary) ixcomin2=ixcommin2
1449 if(neighbor_type(0,0,-1,igrid)==neighbor_boundary) ixcomin3=ixcommin3
1450 if(neighbor_type(0,1,0,igrid)==neighbor_boundary) ixcomax2=ixcommax2
1451 if(neighbor_type(0,0,1,igrid)==neighbor_boundary) ixcomax3=ixcommax3
1452 end if
1453 else if(idims == 2) then
1454 if(neighbor_type(0,-1,0,igrid)==neighbor_boundary .or. &
1455 neighbor_type(0,1,0,igrid)==neighbor_boundary) then
1456 if(neighbor_type(0,0,-1,igrid)==neighbor_boundary) ixcomin3=ixcommin3
1457 if(neighbor_type(0,0,1,igrid)==neighbor_boundary) ixcomax3=ixcommax3
1458 end if
1459 end if
1460 }
1461 do iside=1,2
1462 ii^d=kr(^d,idims)*(2*iside-3);
1463 if(neighbor_type(ii^d,igrid)/=neighbor_boundary) cycle
1464 if(( {(iside==1.and.idims==^d.and.ixcomin^d<ixcogmin^d+nghostcells)|.or.} ) &
1465 .or.( {(iside==2.and.idims==^d.and.ixcomax^d>ixcogmax^d-nghostcells)|.or. })) then
1466 {ixbmin^d=merge(ixcogmin^d,ixcomin^d,idims==^d);}
1467 {ixbmax^d=merge(ixcogmax^d,ixcomax^d,idims==^d);}
1468 call bc_phys(iside,idims,time,0.d0,psc(igrid),ixcog^l,ixb^l)
1469 end if
1470 end do
1471 end do
1472 end if
1473
1474 if(prolongprimitive) then
1475 block=>psc(igrid)
1476 ixcomin^d=int((xfimin^d+(dble(ixfimin^d)-half)*dxfi^d-xcomin^d)*invdxco^d)+1-1;
1477 ixcomax^d=int((xfimin^d+(dble(ixfimax^d)-half)*dxfi^d-xcomin^d)*invdxco^d)+1+1;
1478 call phys_to_primitive(ixcog^l,ixco^l,psc(igrid)%w,psc(igrid)%x)
1479 end if
1480
1481 if(ghost_copy) then
1482 call interpolation_copy(igrid,ixfi^l,dxfi^d,xfimin^d,dxco^d,invdxco^d,xcomin^d)
1483 else
1484 call interpolation_linear(igrid,ixfi^l,dxfi^d,xfimin^d,dxco^d,invdxco^d,xcomin^d)
1485 end if
1486
1487 if(prolongprimitive) then
1488 block=>psc(igrid)
1489 call phys_to_conserved(ixcog^l,ixco^l,psc(igrid)%w,psc(igrid)%x)
1490 end if
1491
1492 end subroutine bc_prolong
1493
1494 subroutine bc_prolong_stg(igrid,i^D,NeedProlong)
1495 use mod_amr_fct
1496 double precision :: dxFi^D,dxCo^D,xFimin^D,xComin^D,invdxCo^D
1497 integer :: igrid,i^D
1498 integer :: ixFi^L,ixCo^L
1499 logical,dimension(-1:1^D&) :: NeedProlong
1500 logical :: fine_^Lin
1501 ! Check what is already at the desired level
1502 fine_^lin=.false.;
1503 {
1504 if(i^d>-1) fine_min^din=(.not.needprolong(i^dd-kr(^d,^dd)).and.neighbor_type(i^dd-kr(^d,^dd),igrid)/=1)
1505 if(i^d<1) fine_max^din=(.not.needprolong(i^dd+kr(^d,^dd)).and.neighbor_type(i^dd+kr(^d,^dd),igrid)/=1)
1506 \}
1507
1508 ixfi^l=ixr_srl_^l(i^d);
1509
1510 dxfi^d=rnode(rpdx^d_,igrid);
1511 dxco^d=two*dxfi^d;
1512 invdxco^d=1.d0/dxco^d;
1513
1514 xfimin^d=rnode(rpxmin^d_,igrid)-dble(nghostcells)*dxfi^d;
1515 xcomin^d=rnode(rpxmin^d_,igrid)-dble(nghostcells)*dxco^d;
1516
1517 ! moved the physical boundary filling here, to only fill the
1518 ! part needed
1519
1520 ixcomin^d=int((xfimin^d+(dble(ixfimin^d)-half)*dxfi^d-xcomin^d)*invdxco^d)+1-1;
1521 ixcomax^d=int((xfimin^d+(dble(ixfimax^d)-half)*dxfi^d-xcomin^d)*invdxco^d)+1+1;
1522
1523 if(prolongprimitive) call phys_to_primitive(ixg^ll,ixfi^l,psb(igrid)%w,psb(igrid)%x)
1524
1525 call prolong_2nd_stg(psc(igrid),psb(igrid),ixco^l,ixfi^l,dxco^d,xcomin^d,dxfi^d,xfimin^d,.true.,fine_^lin)
1526
1527 if(prolongprimitive) call phys_to_conserved(ixg^ll,ixfi^l,psb(igrid)%w,psb(igrid)%x)
1528
1529 ! The current region has already been refined, so it does not need to be prolonged again
1530 needprolong(i^d)=.false.
1531
1532 end subroutine bc_prolong_stg
1533
1534 subroutine interpolation_linear(igrid,ixFi^L,dxFi^D,xFimin^D, &
1535 dxCo^D,invdxCo^D,xComin^D)
1537 integer, intent(in) :: igrid, ixFi^L
1538 double precision, intent(in) :: dxFi^D, xFimin^D,dxCo^D, invdxCo^D, xComin^D
1539
1540 double precision :: xCo^D, xFi^D, eta^D
1541 double precision :: slopeL, slopeR, slopeC, signC, signR
1542 double precision :: slope(1:nw,ndim)
1543 !!double precision :: local_invdxCo^D
1544 double precision :: signedfactorhalf^D
1545 integer :: ixCo^D, jxCo^D, hxCo^D, ixFi^D, ix^D, iw, idims, nwmin,nwmax
1546 !integer :: ixshift^D, icase
1547
1548 !icase=mod(nghostcells,2)
1549
1550 if(prolongprimitive) then
1551 nwmin=1
1552 nwmax=nw
1553 else
1554 nwmin=nwhead
1555 nwmax=nwtail
1556 end if
1557
1558 {do ixfi^db = ixfi^lim^db
1559 ! cell-centered coordinates of fine grid point
1560 ! here we temporarily use an equidistant grid
1561 xfi^db=xfimin^db+(dble(ixfi^db)-half)*dxfi^db
1562
1563 ! indices of coarse cell which contains the fine cell
1564 ! since we computed lower left corner earlier
1565 ! in equidistant fashion: also ok for stretched case
1566 ixco^db=int((xfi^db-xcomin^db)*invdxco^db)+1
1567
1568 ! cell-centered coordinates of coarse grid point
1569 ! here we temporarily use an equidistant grid
1570 xco^db=xcomin^db+(dble(ixco^db)-half)*dxco^db \}
1571
1572 !if(.not.slab) then
1573 ! ^D&local_invdxCo^D=1.d0/psc(igrid)%dx({ixCo^DD},^D)\
1574 !endif
1575
1576 if(slab_uniform) then
1577 ! actual cell-centered coordinates of fine grid point
1578 !!^D&xFi^D=block%x({ixFi^DD},^D)\
1579 ! actual cell-centered coordinates of coarse grid point
1580 !!^D&xCo^D=psc(igrid)%x({ixCo^DD},^D)\
1581 ! normalized distance between fine/coarse cell center
1582 ! in coarse cell: ranges from -0.5 to 0.5 in each direction
1583 ! (origin is coarse cell center)
1584 ! this is essentially +1/4 or -1/4 on cartesian mesh
1585 eta^d=(xfi^d-xco^d)*invdxco^d;
1586 else
1587 !select case(icase)
1588 ! case(0)
1589 !{! here we assume an even number of ghostcells!!!
1590 !ixshift^D=2*(mod(ixFi^D,2)-1)+1
1591 !if(ixshift^D>0.0d0)then
1592 ! ! oneven fine grid points
1593 ! eta^D=-0.5d0*(one-block%dvolume(ixFi^DD) &
1594 ! /sum(block%dvolume(ixFi^D:ixFi^D+1^D%ixFi^DD)))
1595 !else
1596 ! ! even fine grid points
1597 ! eta^D=+0.5d0*(one-block%dvolume(ixFi^DD) &
1598 ! /sum(block%dvolume(ixFi^D-1:ixFi^D^D%ixFi^DD)))
1599 !endif\}
1600 ! case(1)
1601 !{! here we assume an odd number of ghostcells!!!
1602 !ixshift^D=2*(mod(ixFi^D,2)-1)+1
1603 !if(ixshift^D>0.0d0)then
1604 ! ! oneven fine grid points
1605 ! eta^D=+0.5d0*(one-block%dvolume(ixFi^DD) &
1606 ! /sum(block%dvolume(ixFi^D-1:ixFi^D^D%ixFi^DD)))
1607 !else
1608 ! ! even fine grid points
1609 ! eta^D=-0.5d0*(one-block%dvolume(ixFi^DD) &
1610 ! /sum(block%dvolume(ixFi^D:ixFi^D+1^D%ixFi^DD)))
1611 !endif\}
1612 ! case default
1613 ! call mpistop("no such case")
1614 !end select
1615 ! the different cases for even/uneven number of ghost cells
1616 ! are automatically handled using the relative index to ixMlo
1617 ! as well as the pseudo-coordinates xFi and xCo
1618 ! these latter differ from actual cell centers when stretching is used
1619 ix^d=2*int((ixfi^d+ixmlo^d)/2)-ixmlo^d;
1620 {if(xfi^d>xco^d) then
1621 signedfactorhalf^d=0.5d0
1622 else
1623 signedfactorhalf^d=-0.5d0
1624 end if
1625 eta^d=signedfactorhalf^d*(one-psb(igrid)%dvolume(ixfi^dd) &
1626 /sum(psb(igrid)%dvolume(ix^d:ix^d+1^d%ixFi^dd))) \}
1627 !{eta^D=(xFi^D-xCo^D)*invdxCo^D &
1628 ! *two*(one-block%dvolume(ixFi^DD) &
1629 ! /sum(block%dvolume(ix^D:ix^D+1^D%ixFi^DD))) \}
1630 end if
1631
1632 do idims=1,ndim
1633 hxco^d=ixco^d-kr(^d,idims)\
1634 jxco^d=ixco^d+kr(^d,idims)\
1635
1636 do iw=nwmin,nwmax
1637 slopel=psc(igrid)%w(ixco^d,iw)-psc(igrid)%w(hxco^d,iw)
1638 sloper=psc(igrid)%w(jxco^d,iw)-psc(igrid)%w(ixco^d,iw)
1639 slopec=half*(sloper+slopel)
1640
1641 ! get limited slope
1642 signr=sign(one,sloper)
1643 signc=sign(one,slopec)
1644 !select case(prolong_limiter)
1645 !case(1)
1646 ! ! unlimit
1647 ! slope(iw,idims)=slopeC
1648 !case(2)
1649 ! ! minmod
1650 ! slope(iw,idims)=signR*max(zero,min(dabs(slopeR), &
1651 ! signR*slopeL))
1652 !case(3)
1653 ! ! woodward
1654 ! slope(iw,idims)=two*signR*max(zero,min(dabs(slopeR), &
1655 ! signR*slopeL,signR*half*slopeC))
1656 !case(4)
1657 ! ! koren
1658 ! slope(iw,idims)=signR*max(zero,min(two*signR*slopeL, &
1659 ! (dabs(slopeR)+two*slopeL*signR)*third,two*dabs(slopeR)))
1660 !case default
1661 slope(iw,idims)=signc*max(zero,min(dabs(slopec), &
1662 signc*slopel,signc*sloper))
1663 !end select
1664 end do
1665 end do
1666
1667 ! Interpolate from coarse cell using limited slopes
1668 psb(igrid)%w(ixfi^d,nwmin:nwmax)=psc(igrid)%w(ixco^d,nwmin:nwmax)+&
1669 {(slope(nwmin:nwmax,^d)*eta^d)+}
1670
1671 {end do\}
1672
1673 if(prolongprimitive) then
1674 block=>psb(igrid)
1675 call phys_to_conserved(ixg^ll,ixfi^l,psb(igrid)%w,psb(igrid)%x)
1676 end if
1677
1678 end subroutine interpolation_linear
1679
1680 subroutine interpolation_copy(igrid, ixFi^L,dxFi^D,xFimin^D, &
1681 dxCo^D,invdxCo^D,xComin^D)
1683 integer, intent(in) :: igrid, ixFi^L
1684 double precision, intent(in) :: dxFi^D, xFimin^D,dxCo^D, invdxCo^D, xComin^D
1685
1686 double precision :: xFi^D
1687 integer :: ixCo^D, ixFi^D, nwmin,nwmax
1688
1689 if(prolongprimitive) then
1690 nwmin=1
1691 nwmax=nw
1692 else
1693 nwmin=nwhead
1694 nwmax=nwtail
1695 end if
1696
1697 {do ixfi^db = ixfi^lim^db
1698 ! cell-centered coordinates of fine grid point
1699 xfi^db=xfimin^db+(dble(ixfi^db)-half)*dxfi^db
1700
1701 ! indices of coarse cell which contains the fine cell
1702 ! note: this also works for stretched grids
1703 ixco^db=int((xfi^db-xcomin^db)*invdxco^db)+1\}
1704
1705 ! Copy from coarse cell
1706 psb(igrid)%w(ixfi^d,nwmin:nwmax)=psc(igrid)%w(ixco^d,nwmin:nwmax)
1707
1708 {end do\}
1709
1710 if(prolongprimitive) call phys_to_conserved(ixg^ll,ixfi^l,psb(igrid)%w,psb(igrid)%x)
1711
1712 end subroutine interpolation_copy
1713
1714 subroutine pole_copy(wrecv,ixIR^L,ixR^L,wsend,ixIS^L,ixS^L,ipole)
1715
1716 integer, intent(in) :: ixIR^L,ixR^L,ixIS^L,ixS^L,ipole
1717 double precision :: wrecv(ixIR^S,1:nw), wsend(ixIS^S,1:nw)
1718
1719 integer :: iw, iside, iB
1720
1721 select case (ipole)
1722 {case (^d)
1723 iside=int((i^d+3)/2)
1724 ib=2*(^d-1)+iside
1725 do iw=nwhead,nwtail
1726 select case (typeboundary(iw,ib))
1727 case (bc_symm)
1728 wrecv(ixr^s,iw) = wsend(ixsmax^d:ixsmin^d:-1^d%ixS^s,iw)
1729 case (bc_asymm)
1730 wrecv(ixr^s,iw) =-wsend(ixsmax^d:ixsmin^d:-1^d%ixS^s,iw)
1731 case default
1732 call mpistop("Pole boundary condition should be symm or asymm")
1733 end select
1734 end do \}
1735 end select
1736
1737 end subroutine pole_copy
1738
1739 subroutine pole_copy_stg(wrecv,ixIR^L,ixR^L,wsend,ixIS^L,ixS^L,idirs,ipole)
1740
1741 integer, intent(in) :: ixIR^L,ixR^L,ixIS^L,ixS^L,idirs,ipole
1742
1743 double precision :: wrecv(ixIR^S,1:nws), wsend(ixIS^S,1:nws)
1744 integer :: iB, iside
1745
1746 select case (ipole)
1747 {case (^d)
1748 iside=int((i^d+3)/2)
1749 ib=2*(^d-1)+iside
1750 select case (typeboundary(iw_mag(idirs),ib))
1751 case (bc_symm)
1752 wrecv(ixr^s,idirs) = wsend(ixsmax^d:ixsmin^d:-1^d%ixS^s,idirs)
1753 case (bc_asymm)
1754 wrecv(ixr^s,idirs) =-wsend(ixsmax^d:ixsmin^d:-1^d%ixS^s,idirs)
1755 case default
1756 call mpistop("Pole boundary condition should be symm or asymm")
1757 end select
1758 \}
1759 end select
1760
1761 end subroutine pole_copy_stg
1762
1763 subroutine pole_buffer(wrecv,ixIR^L,ixR^L,wsend,ixIS^L,ixS^L,ipole)
1764
1765 integer, intent(in) :: ixIR^L,ixR^L,ixIS^L,ixS^L,ipole
1766 double precision :: wrecv(ixIR^S,nwhead:nwtail), wsend(ixIS^S,1:nw)
1767
1768 integer :: iw, iside, iB
1769
1770 select case (ipole)
1771 {case (^d)
1772 iside=int((i^d+3)/2)
1773 ib=2*(^d-1)+iside
1774 do iw=nwhead,nwtail
1775 select case (typeboundary(iw,ib))
1776 case (bc_symm)
1777 wrecv(ixr^s,iw) = wsend(ixsmax^d:ixsmin^d:-1^d%ixS^s,iw)
1778 case (bc_asymm)
1779 wrecv(ixr^s,iw) =-wsend(ixsmax^d:ixsmin^d:-1^d%ixS^s,iw)
1780 case default
1781 call mpistop("Pole boundary condition should be symm or asymm")
1782 end select
1783 end do \}
1784 end select
1785
1786 end subroutine pole_buffer
1787
1788 end subroutine getbc
1789
1790end 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
subroutine timer_open(t0)
Open a timing window, whose length leaves out the EoS and ghost-cell time spent inside it,...
Definition mod_timing.t:66
double precision function timer_close(t0)
Wall time since timer_open, less the EoS and ghost-cell time spent in between.
Definition mod_timing.t:73
Module with all the methods that users can customize in AMRVAC.
procedure(special_prepare_bc), pointer usr_prepare_boundary