41 use mpi_f08,
only : mpi_allreduce, mpi_allgather, mpi_integer, &
55 logical :: periodic_enabled = .false.
56 logical :: rotational_periodic_enabled = .false.
57 integer :: n_periodic_dirs = 0
58 real(kind=
rp) :: periodic_shift_x1 = 0.0_rp
59 real(kind=
rp) :: periodic_shift_y1 = 0.0_rp
60 real(kind=
rp) :: periodic_shift_z1 = 0.0_rp
61 real(kind=
rp) :: periodic_shift_x2 = 0.0_rp
62 real(kind=
rp) :: periodic_shift_y2 = 0.0_rp
63 real(kind=
rp) :: periodic_shift_z2 = 0.0_rp
64 real(kind=
rp) :: periodic_shift_x3 = 0.0_rp
65 real(kind=
rp) :: periodic_shift_y3 = 0.0_rp
66 real(kind=
rp) :: periodic_shift_z3 = 0.0_rp
67 real(kind=
rp) :: periodic_dir_x1 = 0.0_rp
68 real(kind=
rp) :: periodic_dir_y1 = 0.0_rp
69 real(kind=
rp) :: periodic_dir_z1 = 0.0_rp
70 real(kind=
rp) :: periodic_dir_x2 = 0.0_rp
71 real(kind=
rp) :: periodic_dir_y2 = 0.0_rp
72 real(kind=
rp) :: periodic_dir_z2 = 0.0_rp
73 real(kind=
rp) :: periodic_dir_x3 = 0.0_rp
74 real(kind=
rp) :: periodic_dir_y3 = 0.0_rp
75 real(kind=
rp) :: periodic_dir_z3 = 0.0_rp
76 real(kind=
rp) :: periodic_min1 = 0.0_rp
77 real(kind=
rp) :: periodic_min2 = 0.0_rp
78 real(kind=
rp) :: periodic_min3 = 0.0_rp
79 real(kind=
rp) :: periodic_max1 = 0.0_rp
80 real(kind=
rp) :: periodic_max2 = 0.0_rp
81 real(kind=
rp) :: periodic_max3 = 0.0_rp
82 real(kind=
rp) :: periodic_len1 = 0.0_rp
83 real(kind=
rp) :: periodic_len2 = 0.0_rp
84 real(kind=
rp) :: periodic_len3 = 0.0_rp
85 real(kind=
rp) :: rotational_theta_min = 0.0_rp
86 real(kind=
rp) :: rotational_theta_max = 0.0_rp
87 real(kind=
rp) :: rotational_theta_len = 0.0_rp
93 procedure,
private, pass(this) :: init_rotational => &
95 procedure,
private, pass(this) :: init_translational => &
114 type(
mesh_t),
intent(in),
target :: msh
116 type(
coef_t),
intent(in) :: coef
120 if (msh%periodic%size .eq. 0)
return
122 call this%init_rotational(msh, dm_xh, coef)
123 if (this%rotational_periodic_enabled)
return
125 call this%init_translational(msh)
133 subroutine lpt_periodic_bc_wrap(this, x, y, z, n, u, v, w, u_lag, v_lag, &
134 w_lag, u_laglag, v_laglag, w_laglag, acc_xlag, acc_ylag, acc_zlag, &
135 acc_xlaglag, acc_ylaglag, acc_zlaglag)
137 type(
vector_t),
intent(inout) :: x, y, z
138 integer,
intent(in) :: n
139 type(
vector_t),
intent(inout),
optional :: u, v, w
140 type(
vector_t),
intent(inout),
optional :: u_lag, v_lag, w_lag
141 type(
vector_t),
intent(inout),
optional :: u_laglag, v_laglag, w_laglag
142 type(
vector_t),
intent(inout),
optional :: acc_xlag, acc_ylag, acc_zlag
143 type(
vector_t),
intent(inout),
optional :: acc_xlaglag
144 type(
vector_t),
intent(inout),
optional :: acc_ylaglag
145 type(
vector_t),
intent(inout),
optional :: acc_zlaglag
148 if (.not. this%periodic_enabled .and. &
149 .not. this%rotational_periodic_enabled)
return
152 if (this%rotational_periodic_enabled)
then
154 this%rotational_theta_min, this%rotational_theta_max, &
155 this%rotational_theta_len, u, v, w, u_lag, v_lag, w_lag, &
156 u_laglag, v_laglag, w_laglag, acc_xlag, acc_ylag, acc_zlag, &
157 acc_xlaglag, acc_ylaglag, acc_zlaglag)
160 this%n_periodic_dirs, this%periodic_dir_x1, &
161 this%periodic_dir_y1, this%periodic_dir_z1, &
162 this%periodic_dir_x2, this%periodic_dir_y2, &
163 this%periodic_dir_z2, this%periodic_dir_x3, &
164 this%periodic_dir_y3, this%periodic_dir_z3, &
165 this%periodic_min1, this%periodic_min2, this%periodic_min3, &
166 this%periodic_max1, this%periodic_max2, this%periodic_max3, &
167 this%periodic_shift_x1, this%periodic_shift_y1, &
168 this%periodic_shift_z1, this%periodic_shift_x2, &
169 this%periodic_shift_y2, this%periodic_shift_z2, &
170 this%periodic_shift_x3, this%periodic_shift_y3, &
171 this%periodic_shift_z3, this%periodic_len1, &
172 this%periodic_len2, this%periodic_len3)
175 w_lag, u_laglag, v_laglag, w_laglag, acc_xlag, acc_ylag, &
176 acc_zlag, acc_xlaglag, acc_ylaglag, acc_zlaglag)
180 if (this%rotational_periodic_enabled)
then
182 this%rotational_theta_min, this%rotational_theta_max, &
183 this%rotational_theta_len, u, v, w, u_lag, v_lag, w_lag, &
184 u_laglag, v_laglag, w_laglag, acc_xlag, acc_ylag, acc_zlag, &
185 acc_xlaglag, acc_ylaglag, acc_zlaglag)
190 this%periodic_enabled, this%n_periodic_dirs, this%periodic_dir_x1, &
191 this%periodic_dir_y1, this%periodic_dir_z1, this%periodic_dir_x2, &
192 this%periodic_dir_y2, this%periodic_dir_z2, this%periodic_dir_x3, &
193 this%periodic_dir_y3, this%periodic_dir_z3, this%periodic_min1, &
194 this%periodic_min2, this%periodic_min3, this%periodic_max1, &
195 this%periodic_max2, this%periodic_max3, this%periodic_shift_x1, &
196 this%periodic_shift_y1, this%periodic_shift_z1, &
197 this%periodic_shift_x2, this%periodic_shift_y2, &
198 this%periodic_shift_z2, this%periodic_shift_x3, &
199 this%periodic_shift_y3, this%periodic_shift_z3, &
200 this%periodic_len1, this%periodic_len2, this%periodic_len3)
205 v_lag, w_lag, u_laglag, v_laglag, w_laglag, acc_xlag, acc_ylag, &
206 acc_zlag, acc_xlaglag, acc_ylaglag, acc_zlaglag)
207 type(
vector_t),
intent(inout) :: x, y, z
208 type(
vector_t),
intent(inout),
optional :: u, v, w
209 type(
vector_t),
intent(inout),
optional :: u_lag, v_lag, w_lag
210 type(
vector_t),
intent(inout),
optional :: u_laglag, v_laglag, w_laglag
211 type(
vector_t),
intent(inout),
optional :: acc_xlag, acc_ylag, acc_zlag
212 type(
vector_t),
intent(inout),
optional :: acc_xlaglag
213 type(
vector_t),
intent(inout),
optional :: acc_ylaglag
214 type(
vector_t),
intent(inout),
optional :: acc_zlaglag
225 if (
present(u_laglag))
call u_laglag%copy_from(
device_to_host, .false.)
226 if (
present(v_laglag))
call v_laglag%copy_from(
device_to_host, .false.)
227 if (
present(w_laglag))
call w_laglag%copy_from(
device_to_host, .false.)
228 if (
present(acc_xlag))
call acc_xlag%copy_from(
device_to_host, .false.)
229 if (
present(acc_ylag))
call acc_ylag%copy_from(
device_to_host, .false.)
230 if (
present(acc_zlag))
call acc_zlag%copy_from(
device_to_host, .false.)
231 if (
present(acc_xlaglag))
then
234 if (
present(acc_ylaglag))
then
237 if (
present(acc_zlaglag))
then
247 this%periodic_enabled = .false.
248 this%rotational_periodic_enabled = .false.
249 this%n_periodic_dirs = 0
251 this%rotational_theta_min = 0.0_rp
252 this%rotational_theta_max = 0.0_rp
253 this%rotational_theta_len = 0.0_rp
262 type(
mesh_t),
intent(in) :: msh
264 type(
coef_t),
intent(in) :: coef
265 real(kind=
rp) :: theta_min
266 real(kind=
rp) :: theta_max
270 if (.not. coef%cyclic .or. msh%gdim .lt. 2)
return
273 if (msh%nelv .gt. 0)
then
274 theta_min = minval(modulo(atan2(dm_xh%y, dm_xh%x) + &
275 2.0_rp * pi, 2.0_rp * pi))
276 theta_max = maxval(modulo(atan2(dm_xh%y, dm_xh%x) + &
277 2.0_rp * pi, 2.0_rp * pi))
279 theta_min = huge(0.0_rp)
280 theta_max = -huge(0.0_rp)
283 call mpi_allreduce(theta_min, this%rotational_theta_min, 1, &
285 call mpi_allreduce(theta_max, this%rotational_theta_max, 1, &
288 this%rotational_theta_len = this%rotational_theta_max - &
289 this%rotational_theta_min
290 this%rotational_periodic_enabled = &
298 type(
mesh_t),
intent(in) :: msh
307 integer,
allocatable :: counts(:)
308 integer,
allocatable :: padded_meta(:)
309 integer,
allocatable :: gathered_meta(:)
310 integer,
allocatable :: global_meta(:)
311 real(kind=
rp),
allocatable :: padded_center(:)
312 real(kind=
rp),
allocatable :: gathered_center(:)
313 real(kind=
rp),
allocatable :: global_center(:)
314 real(kind=
rp) :: src_center(3)
315 real(kind=
rp) :: tgt_center(3)
316 real(kind=
rp) :: shift(3)
317 real(kind=
rp) :: proj_src
318 real(kind=
rp) :: proj_tgt
319 real(kind=
rp) :: dir(3)
321 if (msh%periodic%size .eq. 0)
return
323 n_local = msh%periodic%size
325 call mpi_allgather(n_local, 1, mpi_integer, counts, 1, mpi_integer, &
327 n_global = sum(counts)
328 max_local =
max(1, maxval(counts))
330 allocate(padded_meta(2 * max_local))
331 allocate(padded_center(3 * max_local))
333 padded_center = 0.0_rp
339 padded_meta(2 * (i - 1) + 1) = msh%periodic%facet_el(i)%x(1)
340 padded_meta(2 * (i - 1) + 2) = msh%elements( &
341 msh%periodic%facet_el(i)%x(2))%e%id()
342 padded_center(3 * (i - 1) + 1:3 * i) = src_center
346 allocate(gathered_meta(2 * max_local *
pe_size))
347 allocate(gathered_center(3 * max_local *
pe_size))
348 call mpi_allgather(padded_meta, 2 * max_local, mpi_integer, gathered_meta, &
349 2 * max_local, mpi_integer,
neko_comm, ierr)
354 allocate(global_meta(2 * n_global))
355 allocate(global_center(3 * n_global))
358 if (counts(i) .gt. 0)
then
359 global_meta(2 * idx + 1:2 * (idx + counts(i))) = &
360 gathered_meta(2 * max_local * (i - 1) + 1: &
361 2 * max_local * (i - 1) + 2 * counts(i))
362 global_center(3 * idx + 1:3 * (idx + counts(i))) = &
363 gathered_center(3 * max_local * (i - 1) + 1: &
364 3 * max_local * (i - 1) + 3 * counts(i))
365 idx = idx + counts(i)
371 do i = 1, msh%periodic%size
378 if (global_meta(2 * (j - 1) + 1) .eq. msh%periodic%p_facet_el(i)%x(1)&
379 .and. global_meta(2 * (j - 1) + 2) .eq. &
380 msh%periodic%p_facet_el(i)%x(2))
then
385 if (match_idx .eq. 0) cycle
388 tgt_center = global_center(3 * (match_idx - 1) + 1:3 * match_idx)
389 shift = tgt_center - src_center
395 proj_src = dot_product(src_center, dir)
396 proj_tgt = dot_product(tgt_center, dir)
400 do j = 1, this%n_periodic_dirs
401 if (abs(dot_product(dir, &
403 1.0_rp - 1.0e-6_rp)
then
409 if (idx .ne. 0) cycle
413 if (this%n_periodic_dirs .ge. 3) cycle
414 idx = this%n_periodic_dirs + 1
415 this%n_periodic_dirs = idx
417 min(proj_src, proj_tgt),
max(proj_src, proj_tgt), shift, &
421 deallocate(global_center)
422 deallocate(global_meta)
423 deallocate(gathered_center)
424 deallocate(gathered_meta)
425 deallocate(padded_center)
426 deallocate(padded_meta)
429 this%periodic_enabled = this%n_periodic_dirs .gt. 0
438 type(
mesh_t),
intent(in) :: msh
439 integer,
intent(in) :: el
440 integer,
intent(in) :: facet
441 real(kind=
rp),
intent(out) :: pts(3, 4)
442 integer,
dimension(4, 6) :: face_nodes = reshape([ &
449 integer,
dimension(2, 4) :: edge_nodes = reshape([ &
457 if (msh%gdim .eq. 3)
then
459 pts(:, i) =
real(msh%elements(el)%e%pts(face_nodes(i, facet))%p%x,
rp)
463 pts(:, i) =
real(msh%elements(el)%e%pts(edge_nodes(i, facet))%p%x,
rp)
473 type(
mesh_t),
intent(in) :: msh
474 integer,
intent(in) :: i_periodic
475 real(kind=
rp),
intent(out) :: pt(3)
477 real(kind=
rp) :: pts(3, 4)
479 npts = merge(4, 2, msh%gdim .eq. 3)
481 msh%periodic%facet_el(i_periodic)%x(1), pts)
482 pt = sum(pts(:, 1:npts), dim = 2) /
real(npts,
rp)
488 real(kind=
rp),
intent(inout) :: v(3)
489 real(kind=
rp) :: vnorm
499 this%periodic_shift_x1 = 0.0_rp
500 this%periodic_shift_y1 = 0.0_rp
501 this%periodic_shift_z1 = 0.0_rp
502 this%periodic_shift_x2 = 0.0_rp
503 this%periodic_shift_y2 = 0.0_rp
504 this%periodic_shift_z2 = 0.0_rp
505 this%periodic_shift_x3 = 0.0_rp
506 this%periodic_shift_y3 = 0.0_rp
507 this%periodic_shift_z3 = 0.0_rp
508 this%periodic_dir_x1 = 0.0_rp
509 this%periodic_dir_y1 = 0.0_rp
510 this%periodic_dir_z1 = 0.0_rp
511 this%periodic_dir_x2 = 0.0_rp
512 this%periodic_dir_y2 = 0.0_rp
513 this%periodic_dir_z2 = 0.0_rp
514 this%periodic_dir_x3 = 0.0_rp
515 this%periodic_dir_y3 = 0.0_rp
516 this%periodic_dir_z3 = 0.0_rp
517 this%periodic_min1 = 0.0_rp
518 this%periodic_min2 = 0.0_rp
519 this%periodic_min3 = 0.0_rp
520 this%periodic_max1 = 0.0_rp
521 this%periodic_max2 = 0.0_rp
522 this%periodic_max3 = 0.0_rp
523 this%periodic_len1 = 0.0_rp
524 this%periodic_len2 = 0.0_rp
525 this%periodic_len3 = 0.0_rp
530 integer,
intent(in) :: idx
531 real(kind=
rp) :: dir(3)
535 dir = [this%periodic_dir_x1, this%periodic_dir_y1, &
536 this%periodic_dir_z1]
538 dir = [this%periodic_dir_x2, this%periodic_dir_y2, &
539 this%periodic_dir_z2]
541 dir = [this%periodic_dir_x3, this%periodic_dir_y3, &
542 this%periodic_dir_z3]
556 periodic_max, shift, periodic_len)
558 integer,
intent(in) :: idx
559 real(kind=
rp),
intent(in) :: dir(3)
560 real(kind=
rp),
intent(in) :: periodic_min
561 real(kind=
rp),
intent(in) :: periodic_max
562 real(kind=
rp),
intent(in) :: shift(3)
563 real(kind=
rp),
intent(in) :: periodic_len
567 this%periodic_dir_x1 = dir(1)
568 this%periodic_dir_y1 = dir(2)
569 this%periodic_dir_z1 = dir(3)
570 this%periodic_min1 = periodic_min
571 this%periodic_max1 = periodic_max
572 this%periodic_shift_x1 = shift(1)
573 this%periodic_shift_y1 = shift(2)
574 this%periodic_shift_z1 = shift(3)
575 this%periodic_len1 = periodic_len
577 this%periodic_dir_x2 = dir(1)
578 this%periodic_dir_y2 = dir(2)
579 this%periodic_dir_z2 = dir(3)
580 this%periodic_min2 = periodic_min
581 this%periodic_max2 = periodic_max
582 this%periodic_shift_x2 = shift(1)
583 this%periodic_shift_y2 = shift(2)
584 this%periodic_shift_z2 = shift(3)
585 this%periodic_len2 = periodic_len
587 this%periodic_dir_x3 = dir(1)
588 this%periodic_dir_y3 = dir(2)
589 this%periodic_dir_z3 = dir(3)
590 this%periodic_min3 = periodic_min
591 this%periodic_max3 = periodic_max
592 this%periodic_shift_x3 = shift(1)
593 this%periodic_shift_y3 = shift(2)
594 this%periodic_shift_z3 = shift(3)
595 this%periodic_len3 = periodic_len
Synchronize a device or stream.
type(mpi_datatype), public mpi_real_precision
MPI type for working precision of REAL types.
integer, public pe_size
MPI size of communicator.
type(mpi_comm), public neko_comm
MPI communicator.
Device abstraction, common interface for various accelerators.
integer, parameter, public device_to_host
Defines a mapping of the degrees of freedom.
CPU kernels for LPT periodic boundary-condition wrapping.
subroutine, public lpt_periodic_bc_wrap_translational_cpu(x, y, z, n, periodic_enabled, n_periodic_dirs, periodic_dir_x1, periodic_dir_y1, periodic_dir_z1, periodic_dir_x2, periodic_dir_y2, periodic_dir_z2, periodic_dir_x3, periodic_dir_y3, periodic_dir_z3, periodic_min1, periodic_min2, periodic_min3, periodic_max1, periodic_max2, periodic_max3, periodic_shift_x1, periodic_shift_y1, periodic_shift_z1, periodic_shift_x2, periodic_shift_y2, periodic_shift_z2, periodic_shift_x3, periodic_shift_y3, periodic_shift_z3, periodic_len1, periodic_len2, periodic_len3)
Wrap particle coordinates through translational periodic directions.
real(kind=rp), parameter lpt_periodic_tol
subroutine, public lpt_periodic_bc_wrap_rotational_cpu(x, y, z, n, theta_min, theta_max, theta_len, u, v, w, u_lag, v_lag, w_lag, u_laglag, v_laglag, w_laglag, acc_xlag, acc_ylag, acc_zlag, acc_xlaglag, acc_ylaglag, acc_zlaglag)
Wrap particles through a rotational periodic sector on the CPU.
Device dispatch for LPT periodic boundary-condition wrapping.
subroutine, public lpt_periodic_bc_wrap_rotational_device(x, y, z, n, theta_min, theta_max, theta_len, u, v, w, u_lag, v_lag, w_lag, u_laglag, v_laglag, w_laglag, acc_xlag, acc_ylag, acc_zlag, acc_xlaglag, acc_ylaglag, acc_zlaglag, strm)
Launch device kernel for rotational periodic wrapping.
subroutine, public lpt_periodic_bc_wrap_translational_device(x, y, z, n, n_periodic_dirs, periodic_dir_x1, periodic_dir_y1, periodic_dir_z1, periodic_dir_x2, periodic_dir_y2, periodic_dir_z2, periodic_dir_x3, periodic_dir_y3, periodic_dir_z3, periodic_min1, periodic_min2, periodic_min3, periodic_max1, periodic_max2, periodic_max3, periodic_shift_x1, periodic_shift_y1, periodic_shift_z1, periodic_shift_x2, periodic_shift_y2, periodic_shift_z2, periodic_shift_x3, periodic_shift_y3, periodic_shift_z3, periodic_len1, periodic_len2, periodic_len3, strm)
Launch device kernel for translational periodic wrapping.
Periodic and cyclic boundary-condition support for LPT.
subroutine lpt_periodic_bc_wrap(this, x, y, z, n, u, v, w, u_lag, v_lag, w_lag, u_laglag, v_laglag, w_laglag, acc_xlag, acc_ylag, acc_zlag, acc_xlaglag, acc_ylaglag, acc_zlaglag)
Wrap particle positions and optional vector histories across boundaries.
subroutine lpt_periodic_bc_init_translational(this, msh)
Detect unique translational periodic directions from facet pairs.
subroutine lpt_periodic_bc_set_translational(this, idx, dir, periodic_min, periodic_max, shift, periodic_len)
Store one translational periodic wrapping direction.
subroutine lpt_periodic_bc_reset(this)
Reset all periodic wrapping flags, directions, and extents.
subroutine lpt_periodic_bc_sync_from_device(x, y, z, u, v, w, u_lag, v_lag, w_lag, u_laglag, v_laglag, w_laglag, acc_xlag, acc_ylag, acc_zlag, acc_xlaglag, acc_ylaglag, acc_zlaglag)
Copy wrapped particle coordinates and optional histories back to host.
subroutine lpt_get_periodic_center(msh, i_periodic, pt)
Compute the geometric center of a periodic source facet.
subroutine lpt_get_facet_points(msh, el, facet, pts)
Gather the corner points of a mesh facet.
subroutine lpt_periodic_bc_init_rotational(this, msh, dm_xh, coef)
Detect and initialise rotational periodic wrapping.
pure real(kind=rp) function, dimension(3) lpt_periodic_bc_get_dir(this, idx)
subroutine lpt_periodic_bc_free(this)
Free periodic-boundary wrapping metadata.
subroutine lpt_normalize(v)
Normalise a 3-vector when its norm is above LPT periodic tolerance.
subroutine lpt_periodic_bc_init(this, msh, dm_xh, coef)
Initialise rotational or translational periodic wrapping from the mesh.
subroutine lpt_periodic_bc_clear_translational(this)
Clear translational periodic direction, extent, and shift storage.
integer, parameter neko_bcknd_device
integer, parameter, public rp
Global precision used in computations.
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...