Neko 1.99.6
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
space.f90
Go to the documentation of this file.
1! Copyright (c) 2019-2022, The Neko Authors
2! All rights reserved.
3!
4! Redistribution and use in source and binary forms, with or without
5! modification, are permitted provided that the following conditions
6! are met:
7!
8! * Redistributions of source code must retain the above copyright
9! notice, this list of conditions and the following disclaimer.
10!
11! * Redistributions in binary form must reproduce the above
12! copyright notice, this list of conditions and the following
13! disclaimer in the documentation and/or other materials provided
14! with the distribution.
15!
16! * Neither the name of the authors nor the names of its
17! contributors may be used to endorse or promote products derived
18! from this software without specific prior written permission.
19!
20! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24! COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31! POSSIBILITY OF SUCH DAMAGE.
32!
34module space
36 use num_types, only : rp
37 use speclib, only : zwgll, zwgl, dgll, legendre_poly
40 use matrix, only : matrix_t
41 use utils, only : neko_error
42 use fast3d, only : setup_intp
43 use tensor, only : trsp1
44 use mxm_wrapper, only : mxm
45 use math, only : copy
46 use, intrinsic :: iso_c_binding
47 implicit none
48 private
49
50 integer, public, parameter :: gl = 0, gll = 1, gj = 2
51
64 type, public :: space_t
65 integer :: t
66 integer :: lx
67 integer :: ly
68 integer :: lz
69 integer :: lxy
70 integer :: lyz
71 integer :: lxz
72 integer :: lxyz
73
74 real(kind=rp), allocatable :: zg(:,:)
75
76 real(kind=rp), allocatable :: dr_inv(:)
77 real(kind=rp), allocatable :: ds_inv(:)
78 real(kind=rp), allocatable :: dt_inv(:)
79
80 real(kind=rp), allocatable :: wx(:)
81 real(kind=rp), allocatable :: wy(:)
82 real(kind=rp), allocatable :: wz(:)
83
84 real(kind=rp), allocatable :: w3(:,:,:)
85
87 real(kind=rp), allocatable :: dx(:,:)
89 real(kind=rp), allocatable :: dy(:,:)
91 real(kind=rp), allocatable :: dz(:,:)
92
94 real(kind=rp), allocatable :: dxt(:,:)
96 real(kind=rp), allocatable :: dyt(:,:)
98 real(kind=rp), allocatable :: dzt(:,:)
99
101 real(kind=rp), allocatable :: v(:,:)
102 real(kind=rp), allocatable :: vt(:,:)
103 real(kind=rp), allocatable :: vinv(:,:)
104 real(kind=rp), allocatable :: vinvt(:,:)
106 real(kind=rp), allocatable :: w(:,:)
107
108 !
109 ! Device pointers (if present)
110 !
111 type(c_ptr) :: dr_inv_d = c_null_ptr
112 type(c_ptr) :: ds_inv_d = c_null_ptr
113 type(c_ptr) :: dt_inv_d = c_null_ptr
114 type(c_ptr) :: dxt_d = c_null_ptr
115 type(c_ptr) :: dyt_d = c_null_ptr
116 type(c_ptr) :: dzt_d = c_null_ptr
117 type(c_ptr) :: dx_d = c_null_ptr
118 type(c_ptr) :: dy_d = c_null_ptr
119 type(c_ptr) :: dz_d = c_null_ptr
120 type(c_ptr) :: wx_d = c_null_ptr
121 type(c_ptr) :: wy_d = c_null_ptr
122 type(c_ptr) :: wz_d = c_null_ptr
123 type(c_ptr) :: zg_d = c_null_ptr
124 type(c_ptr) :: w3_d = c_null_ptr
125 type(c_ptr) :: v_d = c_null_ptr
126 type(c_ptr) :: vt_d = c_null_ptr
127 type(c_ptr) :: vinv_d = c_null_ptr
128 type(c_ptr) :: vinvt_d = c_null_ptr
129 type(c_ptr) :: w_d = c_null_ptr
130 contains
131 procedure, pass(s) :: init => space_init
132 procedure, pass(s) :: free => space_free
133
134 end type space_t
135
136 interface operator(.eq.)
137 module procedure space_eq
138 end interface operator(.eq.)
139
140 interface operator(.ne.)
141 module procedure space_ne
142 end interface operator(.ne.)
143
144 public :: operator(.eq.), operator(.ne.)
145
146contains
147
149 subroutine space_init(s, t, lx, ly, lz)
150 class(space_t), intent(inout) :: s
151 integer, intent(in) :: t
152 integer, intent(in) :: lx
153 integer, intent(in) :: ly
154 integer, optional, intent(in) :: lz
155 integer :: ix, iy, iz
156
157 call space_free(s)
158
159 s%lx = lx
160 s%ly = ly
161 s%t = t
162 if (present(lz)) then
163 if (lz .ne. 1) then
164 s%lz = lz
165 if (lx .ne. ly .or. lx .ne. lz) then
166 call neko_error("Unsupported polynomial dimension")
167 end if
168 end if
169 else
170 if (lx .ne. ly) then
171 call neko_error("Unsupported polynomial dimension")
172 end if
173 s%lz = 1
174 end if
175 s%lxy = s%ly*s%lx
176 s%lyz = s%ly*s%lz
177 s%lxz = s%lx*s%lz
178 s%lxyz = s%lx*s%ly*s%lz
179
180 allocate(s%zg(lx, 3))
181
182 allocate(s%wx(s%lx))
183 allocate(s%wy(s%ly))
184 allocate(s%wz(s%lz))
185
186 allocate(s%dr_inv(s%lx))
187 allocate(s%ds_inv(s%ly))
188 allocate(s%dt_inv(s%lz))
189
190 allocate(s%w3(s%lx, s%ly, s%lz))
191
192 allocate(s%dx(s%lx, s%lx))
193 allocate(s%dy(s%ly, s%ly))
194 allocate(s%dz(s%lz, s%lz))
195
196 allocate(s%dxt(s%lx, s%lx))
197 allocate(s%dyt(s%ly, s%ly))
198 allocate(s%dzt(s%lz, s%lz))
199
200 allocate(s%v(s%lx, s%lx))
201 allocate(s%vt(s%lx, s%lx))
202 allocate(s%vinv(s%lx, s%lx))
203 allocate(s%vinvt(s%lx, s%lx))
204 allocate(s%w(s%lx, s%lx))
205
206 ! Call low-level routines to compute nodes and quadrature weights
207 if (t .eq. gll) then
208 call zwgll(s%zg(1,1), s%wx, s%lx)
209 call zwgll(s%zg(1,2), s%wy, s%ly)
210 if (s%lz .gt. 1) then
211 call zwgll(s%zg(1,3), s%wz, s%lz)
212 else
213 s%zg(:,3) = 0d0
214 s%wz = 1d0
215 end if
216 else if (t .eq. gl) then
217 call zwgl(s%zg(1,1), s%wx, s%lx)
218 call zwgl(s%zg(1,2), s%wy, s%ly)
219 if (s%lz .gt. 1) then
220 call zwgl(s%zg(1,3), s%wz, s%lz)
221 else
222 s%zg(:,3) = 0d0
223 s%wz = 1d0
224 end if
225 else
226 call neko_error("Invalid quadrature rule")
227 end if
228
229 do iz = 1, s%lz
230 do iy = 1, s%ly
231 do ix = 1, s%lx
232 s%w3(ix, iy, iz) = s%wx(ix) * s%wy(iy) * s%wz(iz)
233 end do
234 end do
235 end do
237 if (t .eq. gll) then
238 call dgll(s%dx, s%dxt, s%zg(1,1), s%lx, s%lx)
239 call dgll(s%dy, s%dyt, s%zg(1,2), s%ly, s%ly)
240 if (s%lz .gt. 1) then
241 call dgll(s%dz, s%dzt, s%zg(1,3), s%lz, s%lz)
242 else
243 s%dz = 0d0
244 s%dzt = 0d0
245 end if
246 else if (t .eq. gl) then
247 call setup_intp(s%dx, s%dxt, s%zg(1,1), s%zg(1,1), s%lx, s%lx,1)
248 call setup_intp(s%dy, s%dyt, s%zg(1,2), s%zg(1,2), s%ly, s%ly,1)
249 if (s%lz .gt. 1) then
250 call setup_intp(s%dz, s%dzt, s%zg(1,3), s%zg(1,3), s%lz, s%lz, 1)
251 else
252 s%dz = 0d0
253 s%dzt = 0d0
254 end if
255 else
256 call neko_error("Invalid quadrature rule")
257 end if
258
259 call space_compute_dist(s%dr_inv, s%zg(1,1), s%lx)
260 call space_compute_dist(s%ds_inv, s%zg(1,2), s%ly)
261 if (s%lz .gt. 1) then
262 call space_compute_dist(s%dt_inv, s%zg(1,3), s%lz)
263 else
264 s%dt_inv = 0d0
265 end if
267
268 if (neko_bcknd_device .eq. 1) then
269 call device_map(s%dr_inv, s%dr_inv_d, s%lx)
270 call device_map(s%ds_inv, s%ds_inv_d, s%lx)
271 call device_map(s%dt_inv, s%dt_inv_d, s%lx)
272 call device_map(s%wx, s%wx_d, s%lx)
273 call device_map(s%wy, s%wy_d, s%lx)
274 call device_map(s%wz, s%wz_d, s%lx)
275 call device_map(s%dx, s%dx_d, s%lxy)
276 call device_map(s%dy, s%dy_d, s%lxy)
277 call device_map(s%dz, s%dz_d, s%lxy)
278 call device_map(s%dxt, s%dxt_d, s%lxy)
279 call device_map(s%dyt, s%dyt_d, s%lxy)
280 call device_map(s%dzt, s%dzt_d, s%lxy)
281 call device_map(s%w3, s%w3_d, s%lxyz)
282 call device_map(s%v, s%v_d, s%lxy)
283 call device_map(s%vt, s%vt_d, s%lxy)
284 call device_map(s%vinv, s%vinv_d, s%lxy)
285 call device_map(s%vinvt, s%vinvt_d, s%lxy)
286 call device_map(s%w, s%w_d, s%lxy)
287
288 call device_memcpy(s%dr_inv, s%dr_inv_d, s%lx, host_to_device, &
289 sync = .false.)
290 call device_memcpy(s%ds_inv, s%ds_inv_d, s%lx, host_to_device, &
291 sync = .false.)
292 call device_memcpy(s%dt_inv, s%dt_inv_d, s%lx, host_to_device, &
293 sync = .false.)
294 call device_memcpy(s%wx, s%wx_d, s%lx, host_to_device, sync = .false.)
295 call device_memcpy(s%wy, s%wy_d, s%lx, host_to_device, sync = .false.)
296 call device_memcpy(s%wz, s%wz_d, s%lx, host_to_device, sync = .false.)
297 call device_memcpy(s%dx, s%dx_d, s%lxy, host_to_device, sync = .false.)
298 call device_memcpy(s%dy, s%dy_d, s%lxy, host_to_device, sync = .false.)
299 call device_memcpy(s%dz, s%dz_d, s%lxy, host_to_device, sync = .false.)
300 call device_memcpy(s%dxt, s%dxt_d, s%lxy, host_to_device, sync = .false.)
301 call device_memcpy(s%dyt, s%dyt_d, s%lxy, host_to_device, sync = .false.)
302 call device_memcpy(s%dzt, s%dzt_d, s%lxy, host_to_device, sync = .false.)
303 call device_memcpy(s%w3, s%w3_d, s%lxyz, host_to_device, sync = .false.)
304 call device_memcpy(s%v, s%v_d, s%lxy, host_to_device, sync = .false.)
305 call device_memcpy(s%vt, s%vt_d, s%lxy, host_to_device, sync = .false.)
306 call device_memcpy(s%vinv, s%vinv_d, s%lxy, host_to_device, &
307 sync = .false.)
308 call device_memcpy(s%vinvt, s%vinvt_d, s%lxy, host_to_device, &
309 sync = .false.)
310 call device_memcpy(s%w, s%w_d, s%lxy, host_to_device, sync = .false.)
311
312 ix = s%lx * 3
313 call device_map(s%zg, s%zg_d, ix)
314 call device_memcpy(s%zg, s%zg_d, ix, host_to_device, sync = .true.)
315 end if
316
317
318 call device_sync()
319
320 end subroutine space_init
321
323 subroutine space_free(s)
324 class(space_t), intent(inout) :: s
325
326 if (allocated(s%zg)) then
327 if (neko_bcknd_device .eq. 1) call device_unmap(s%zg, s%zg_d)
328 deallocate(s%zg)
329 end if
330
331 if (allocated(s%wx)) then
332 if (neko_bcknd_device .eq. 1) call device_unmap(s%wx, s%wx_d)
333 deallocate(s%wx)
334 end if
335
336 if (allocated(s%wy)) then
337 if (neko_bcknd_device .eq. 1) call device_unmap(s%wy, s%wy_d)
338 deallocate(s%wy)
339 end if
340
341 if (allocated(s%wz)) then
342 if (neko_bcknd_device .eq. 1) call device_unmap(s%wz, s%wz_d)
343 deallocate(s%wz)
344 end if
345
346 if (allocated(s%w3)) then
347 if (neko_bcknd_device .eq. 1) call device_unmap(s%w3, s%w3_d)
348 deallocate(s%w3)
349 end if
350
351 if (allocated(s%dx)) then
352 if (neko_bcknd_device .eq. 1) call device_unmap(s%dx, s%dx_d)
353 deallocate(s%dx)
354 end if
355
356 if (allocated(s%dy)) then
357 if (neko_bcknd_device .eq. 1) call device_unmap(s%dy, s%dy_d)
358 deallocate(s%dy)
359 end if
360
361 if (allocated(s%dz)) then
362 if (neko_bcknd_device .eq. 1) call device_unmap(s%dz, s%dz_d)
363 deallocate(s%dz)
364 end if
365
366 if (allocated(s%dxt)) then
367 if (neko_bcknd_device .eq. 1) call device_unmap(s%dxt, s%dxt_d)
368 deallocate(s%dxt)
369 end if
370
371 if (allocated(s%dyt)) then
372 if (neko_bcknd_device .eq. 1) call device_unmap(s%dyt, s%dyt_d)
373 deallocate(s%dyt)
374 end if
375
376 if (allocated(s%dzt)) then
377 if (neko_bcknd_device .eq. 1) call device_unmap(s%dzt, s%dzt_d)
378 deallocate(s%dzt)
379 end if
380
381 if (allocated(s%dr_inv)) then
382 if (neko_bcknd_device .eq. 1) call device_unmap(s%dr_inv, s%dr_inv_d)
383 deallocate(s%dr_inv)
384 end if
385
386 if (allocated(s%ds_inv)) then
387 if (neko_bcknd_device .eq. 1) call device_unmap(s%ds_inv, s%ds_inv_d)
388 deallocate(s%ds_inv)
389 end if
390
391 if (allocated(s%dt_inv)) then
392 if (neko_bcknd_device .eq. 1) call device_unmap(s%dt_inv, s%dt_inv_d)
393 deallocate(s%dt_inv)
394 end if
395
396 if (allocated(s%v)) then
397 if (neko_bcknd_device .eq. 1) call device_unmap(s%v, s%v_d)
398 deallocate(s%v)
399 end if
400
401 if (allocated(s%vt)) then
402 if (neko_bcknd_device .eq. 1) call device_unmap(s%vt, s%vt_d)
403 deallocate(s%vt)
404 end if
405
406 if (allocated(s%vinv)) then
407 if (neko_bcknd_device .eq. 1) call device_unmap(s%vinv, s%vinv_d)
408 deallocate(s%vinv)
409 end if
410
411 if (allocated(s%vinvt)) then
412 if (neko_bcknd_device .eq. 1) call device_unmap(s%vinvt, s%vinvt_d)
413 deallocate(s%vinvt)
414 end if
415
416 if (allocated(s%w)) then
417 if (neko_bcknd_device .eq. 1) call device_unmap(s%w, s%w_d)
418 deallocate(s%w)
419 end if
420
421 end subroutine space_free
422
425 pure function space_eq(Xh, Yh) result(res)
426 type(space_t), intent(in) :: xh
427 type(space_t), intent(in) :: yh
428 logical :: res
429
430 if ( (xh%lx .eq. yh%lx) .and. &
431 (xh%ly .eq. yh%ly) .and. &
432 (xh%lz .eq. yh%lz) ) then
433 res = .true.
434 else
435 res = .false.
436 end if
437
438 end function space_eq
439
442 pure function space_ne(Xh, Yh) result(res)
443 type(space_t), intent(in) :: xh
444 type(space_t), intent(in) :: yh
445 logical :: res
446
447 if ( (xh%lx .eq. yh%lx) .and. &
448 (xh%ly .eq. yh%ly) .and. &
449 (xh%lz .eq. yh%lz) ) then
450 res = .false.
451 else
452 res = .true.
453 end if
454
455 end function space_ne
456
457 subroutine space_compute_dist(dx, x, lx)
458 integer, intent(in) :: lx
459 real(kind=rp), intent(inout) :: dx(lx), x(lx)
460 integer :: i
461 dx(1) = x(2) - x(1)
462 do i = 2, lx - 1
463 dx(i) = 0.5*(x(i+1) - x(i-1))
464 end do
465 dx(lx) = x(lx) - x(lx-1)
466 do i = 1, lx
467 dx(i) = 1.0_rp / dx(i)
468 end do
469 end subroutine space_compute_dist
470
471
475 type(space_t), intent(inout) :: Xh
476
477 real(kind=rp) :: l(0:xh%lx-1)
478 real(kind=rp) :: delta(xh%lx)
479 integer :: i, kj, j, kk
480 type(matrix_t) :: m
481 logical :: scaled = .false.
482
483 associate(v=> xh%v, vt => xh%vt, &
484 vinv => xh%vinv, vinvt => xh%vinvt, w => xh%w)
485 ! Get the Legendre polynomials for each point
486 ! Then proceed to compose the transform matrix
487 kj = 0
488 do j = 1, xh%lx
489 call legendre_poly(l, xh%zg(j, 1), xh%lx - 1)
490 do kk = 1, xh%lx
491 kj = kj+1
492 v(kj,1) = l(kk-1)
493 end do
494 end do
495
496 ! transpose the matrix
497 call trsp1(v, xh%lx)
498
499 if (scaled) then
500
501 ! Calculate the nominal scaling factors
502 do i = 1, xh%lx
503 delta(i) = 2.0_rp / (2*(i-1)+1)
504 end do
505 ! modify last entry
506 delta(xh%lx) = 2.0_rp / (xh%lx-1)
507
508 ! calculate the inverse to multiply the matrix
509 do i = 1, xh%lx
510 delta(i) = sqrt(1.0_rp / delta(i))
511 end do
512 ! scale the matrix
513 do i = 1, xh%lx
514 do j = 1, xh%lx
515 v(i,j) = v(i,j) * delta(j) ! orthogonal wrt weights
516 end do
517 end do
518
519 ! get the trasposed
520 call copy(vt, v, xh%lx * xh%lx)
521 call trsp1(vt, xh%lx)
522
523 !populate the mass matrix
524 kk = 1
525 do i = 1, xh%lx
526 do j = 1, xh%lx
527 if (i .eq. j) then
528 w(i,j) = xh%wx(kk)
529 kk = kk+1
530 else
531 w(i,j) = 0
532 end if
533 end do
534 end do
535
536 !Get the inverse of the transform matrix
537 call mxm(vt, xh%lx, w, xh%lx, vinv, xh%lx)
538
539 !get the transposed of the inverse
540 call copy(vinvt, vinv, xh%lx * xh%lx)
541 call trsp1(vinvt, xh%lx)
542 else
543 call copy(vt, v, xh%lxy)
544 call trsp1(vt, xh%lx)
545 call m%init(xh%lx, xh%lx)
546 call copy(m%x, v, xh%lxy)
547 call m%inverse_on_host()
548 call copy(vinv, m%x, xh%lxy)
549 call copy(vinvt, vinv, xh%lx * xh%lx)
550 call trsp1(vinvt, xh%lx)
551 call m%free()
552 end if
553 end associate
554
556
557end module space
Map a Fortran array to a device (allocate and associate)
Definition device.F90:83
Copy data between host and device (or device and device)
Definition device.F90:72
Synchronize a device or stream.
Definition device.F90:119
Unmap a Fortran array from a device (deassociate and free)
Definition device.F90:89
Device abstraction, common interface for various accelerators.
Definition device.F90:34
integer, parameter, public host_to_device
Definition device.F90:48
Fast diagonalization methods from NEKTON.
Definition fast3d.f90:61
subroutine, public setup_intp(jh, jht, z_to, z_from, n_to, n_from, derivative)
Compute interpolation weights for points z_to using values at points z_from.
Definition fast3d.f90:246
Definition math.f90:60
subroutine, public copy(a, b, n)
Copy a vector .
Definition math.f90:291
Defines a matrix.
Definition matrix.f90:34
Wrapper for all matrix-matrix product implementations.
subroutine, public mxm(a, n1, b, n2, c, n3)
Compute matrix-matrix product for contiguously packed matrices A,B, and C.
Build configurations.
integer, parameter neko_bcknd_device
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
Defines a function space.
Definition space.f90:34
pure logical function space_ne(xh, yh)
Check if .
Definition space.f90:443
pure logical function space_eq(xh, yh)
Check if .
Definition space.f90:426
integer, parameter, public gll
Definition space.f90:50
subroutine space_compute_dist(dx, x, lx)
Definition space.f90:458
integer, parameter, public gj
Definition space.f90:50
subroutine space_free(s)
Deallocate a space s.
Definition space.f90:324
subroutine space_init(s, t, lx, ly, lz)
Initialize a function space s with given polynomial dimensions.
Definition space.f90:150
integer, parameter, public gl
Definition space.f90:50
subroutine space_generate_transformation_matrices(xh)
Generate spectral tranform matrices.
Definition space.f90:475
LIBRARY ROUTINES FOR SPECTRAL METHODS.
Definition speclib.f90:149
subroutine dgll(d, dt, z, nz, nzd)
Compute the derivative matrix D and its transpose DT associated with the Nth order Lagrangian interpo...
Definition speclib.f90:881
subroutine zwgll(z, w, np)
Generate NP Gauss-Lobatto Legendre points (Z) and weights (W) associated with Jacobi polynomial P(N)(...
Definition speclib.f90:180
subroutine legendre_poly(l, x, n)
Evaluate Legendre polynomials of degrees 0-N at point x and store in array L.
Definition speclib.f90:1004
subroutine zwgl(z, w, np)
Generate NP Gauss Legendre points Z and weights W associated with Jacobi polynomial ....
Definition speclib.f90:165
Tensor operations.
Definition tensor.f90:61
subroutine, public trsp1(a, n)
In-place transpose of a square tensor.
Definition tensor.f90:140
Utilities.
Definition utils.f90:35
The function space for the SEM solution fields.
Definition space.f90:64