Neko 1.99.6
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
dofmap.f90
Go to the documentation of this file.
1! Copyright (c) 2020-2026, 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!
35module dofmap
37 use mesh, only : mesh_t
38 use mask, only : mask_t
39 use space, only : space_t, gll
40 use tuple, only : tuple_i4_t, tuple4_i4_t
41 use num_types, only : i4, i8, rp, xp
42 use utils, only : neko_error, neko_warning
43 use fast3d, only : fd_weights_full
44 use tensor, only : tensr3, tnsr2d_el, trsp, addtnsr
49 use element, only : element_t
50 use quad, only : quad_t
51 use hex, only : hex_t
53 use, intrinsic :: iso_c_binding, only : c_ptr, c_null_ptr, c_associated
54 implicit none
55 private
56
57 type, public :: dofmap_t
58 integer(kind=i8), allocatable :: dof(:,:,:,:)
59 logical, allocatable :: shared_dof(:,:,:,:)
60 real(kind=rp), allocatable :: x(:,:,:,:)
61 real(kind=rp), allocatable :: y(:,:,:,:)
62 real(kind=rp), allocatable :: z(:,:,:,:)
63 integer, private :: ntot
64
65 type(mesh_t), pointer :: msh
66 type(mesh_t), allocatable :: msh_subset
67 type(space_t), pointer :: xh
68
69 !
70 ! Device pointers (if present)
71 !
72 type(c_ptr) :: x_d = c_null_ptr
73 type(c_ptr) :: y_d = c_null_ptr
74 type(c_ptr) :: z_d = c_null_ptr
75
76 contains
78 procedure, pass(this) :: init_from_mesh => dofmap_init
79 procedure, pass(this) :: init_from_dof => dofmap_init_and_map
80 generic :: init => init_from_mesh, init_from_dof
82 procedure, pass(this) :: free => dofmap_free
84 procedure, pass(this) :: size => dofmap_size
86 procedure, pass(this) :: subset_by_mask => dofmap_subset_by_mask
88 procedure, pass(this) :: global_size => dofmap_global_size
89 end type dofmap_t
90
91contains
92
96 subroutine dofmap_init(this, msh, Xh)
97 class(dofmap_t) :: this
98 type(mesh_t), target, intent(inout) :: msh
99 type(space_t), target, intent(inout) :: Xh
100
101 if ((msh%gdim .eq. 3 .and. xh%lz .eq. 1) .or. &
102 (msh%gdim .eq. 2 .and. xh%lz .gt. 1)) then
103 call neko_error("Invalid dimension of function space for the given mesh")
104 end if
105
106 call this%free()
107
108 this%msh => msh
109 this%Xh => xh
110
111 this%ntot = xh%lx* xh%ly * xh%lz * msh%nelv
112
113 !
114 ! Assign a unique id for all dofs
115 !
116
117 allocate(this%dof(xh%lx, xh%ly, xh%lz, msh%nelv))
118 allocate(this%shared_dof(xh%lx, xh%ly, xh%lz, msh%nelv))
119
120 this%dof = 0
121 this%shared_dof = .false.
122
124 if (msh%gdim .eq. 3) then
125 call dofmap_number_points(this)
126 call dofmap_number_edges(this)
127 call dofmap_number_faces(this)
128 else
129 call dofmap_number_points(this)
130 call dofmap_number_edges(this)
131 end if
132
133 !
134 ! Generate x,y,z-coordinates for all dofs
135 !
136
137 allocate(this%x(xh%lx, xh%ly, xh%lz, msh%nelv))
138 allocate(this%y(xh%lx, xh%ly, xh%lz, msh%nelv))
139 allocate(this%z(xh%lx, xh%ly, xh%lz, msh%nelv))
140
141 this%x = 0d0
142 this%y = 0d0
143 this%z = 0d0
145
146 call dofmap_generate_xyz(this)
147
148 if (neko_bcknd_device .eq. 1) then
149 call device_map(this%x, this%x_d, this%ntot)
150 call device_map(this%y, this%y_d, this%ntot)
151 call device_map(this%z, this%z_d, this%ntot)
152
153 call device_memcpy(this%x, this%x_d, this%ntot, &
154 host_to_device, sync = .false.)
155 call device_memcpy(this%y, this%y_d, this%ntot, &
156 host_to_device, sync = .false.)
157 call device_memcpy(this%z, this%z_d, this%ntot, &
158 host_to_device, sync = .false.)
159 end if
160
161 end subroutine dofmap_init
162
166 subroutine dofmap_init_and_map(this, dof, Xh)
167 class(dofmap_t) :: this
168 type(dofmap_t), target, intent(inout) :: dof
169 type(space_t), target, intent(inout) :: Xh
170 type(interpolator_t) :: interpolator
171
172 ! Initialize as usual
173 call this%init_from_mesh(dof%msh, xh)
174
175 ! Interpolate if needed
176 if (dof%Xh%lxyz .ne. this%Xh%lxyz) then
177 call interpolator%init(this%Xh, dof%Xh)
178
179 call interpolator%map(this%x, &
180 dof%x, &
181 this%msh%nelv, this%Xh)
182 call interpolator%map(this%y, &
183 dof%y, &
184 this%msh%nelv, this%Xh)
185 call interpolator%map(this%z, &
186 dof%z, &
187 this%msh%nelv, this%Xh)
188
189 call interpolator%free()
190
191 else
192 if (neko_bcknd_device .eq. 1) then
193 call device_copy(this%x_d, dof%x_d, this%ntot)
194 call device_copy(this%y_d, dof%y_d, this%ntot)
195 call device_copy(this%z_d, dof%z_d, this%ntot)
196 else
197 call copy(this%x, dof%x, this%ntot)
198 call copy(this%y, dof%y, this%ntot)
199 call copy(this%z, dof%z, this%ntot)
200 end if
201
202 end if
203
204 end subroutine dofmap_init_and_map
205
207 subroutine dofmap_free(this)
208 class(dofmap_t), intent(inout) :: this
209
210 if (allocated(this%dof)) then
211 deallocate(this%dof)
212 end if
213
214 if (allocated(this%shared_dof)) then
215 deallocate(this%shared_dof)
216 end if
217
218 if (allocated(this%x)) then
219 if (neko_bcknd_device .eq. 1) then
220 call device_unmap(this%x, this%x_d)
221 end if
222 deallocate(this%x)
223 end if
224
225 if (allocated(this%y)) then
226 if (neko_bcknd_device .eq. 1) then
227 call device_unmap(this%y, this%y_d)
228 end if
229 deallocate(this%y)
230 end if
231
232 if (allocated(this%z)) then
233 if (neko_bcknd_device .eq. 1) then
234 call device_unmap(this%z, this%z_d)
235 end if
236 deallocate(this%z)
237 end if
238
239 nullify(this%msh)
240 nullify(this%Xh)
241
242 if (allocated(this%msh_subset)) then
243 call this%msh_subset%free()
244 deallocate(this%msh_subset)
245 end if
246
247 end subroutine dofmap_free
248
250 pure function dofmap_size(this) result(res)
251 class(dofmap_t), intent(in) :: this
252 integer :: res
253 res = this%ntot
254 end function dofmap_size
255
257 pure function dofmap_global_size(this) result(res)
258 class(dofmap_t), intent(in) :: this
259 integer :: res
260 res = this%Xh%lx * this%Xh%ly * this%Xh%lz * this%msh%glb_nelv
261 end function dofmap_global_size
262
264 subroutine dofmap_number_points(this)
265 type(dofmap_t), target :: this
266 integer :: il, jl, ix, iy, iz
267 type(mesh_t), pointer :: msh
268 type(space_t), pointer :: Xh
269
270 msh => this%msh
271 xh => this%Xh
272 do il = 1, msh%nelv
273 do jl = 1, msh%npts
274 ix = mod(jl - 1, 2) * (xh%lx - 1) + 1
275 iy = (mod(jl - 1, 4)/2) * (xh%ly - 1) + 1
276 iz = ((jl - 1)/4) * (xh%lz - 1) + 1
277 this%dof(ix, iy, iz, il) = int(msh%elements(il)%e%pts(jl)%p%id(), i8)
278 this%shared_dof(ix, iy, iz, il) = &
279 msh%is_shared(msh%elements(il)%e%pts(jl)%p)
280 end do
281 end do
282 end subroutine dofmap_number_points
283
285 subroutine dofmap_number_edges(this)
286 type(dofmap_t), target :: this
287 type(mesh_t), pointer :: msh
288 type(space_t), pointer :: Xh
289 integer :: i,j,k
290 integer :: global_id
291 type(tuple_i4_t) :: edge
292 integer(kind=i8) :: num_dofs_edges(3) ! #dofs for each dir (r, s, t)
293 integer(kind=i8) :: edge_id, edge_offset
294 logical :: shared_dof
295
296 msh => this%msh
297 xh => this%Xh
298
299 ! Number of dofs on an edge excluding end-points
300 num_dofs_edges(1) = int(xh%lx - 2, i8)
301 num_dofs_edges(2) = int(xh%ly - 2, i8)
302 num_dofs_edges(3) = int(xh%lz - 2, i8)
303 edge_offset = int(msh%glb_mpts, i8) + int(1, i8)
304
305 !$omp parallel do private(i,j,k,global_id,edge,edge_id,shared_dof)
306 do i = 1, msh%nelv
307
308 select type (ep => msh%elements(i)%e)
309 type is (hex_t)
310 !
311 ! Number edges in r-direction
312 !
313 call ep%edge_id(edge, 1)
314 shared_dof = msh%is_shared(edge)
315 global_id = msh%get_global(edge)
316 edge_id = edge_offset + int((global_id - 1), i8) * num_dofs_edges(1)
317 !Reverse order of tranversal if edge is reversed
318 if (int(edge%x(1), i8) .ne. this%dof(1,1,1,i)) then
319 do concurrent(j = 2:xh%lx - 1)
320 k = xh%lx+1-j
321 this%dof(k, 1, 1, i) = edge_id + (j-2)
322 this%shared_dof(k, 1, 1, i) = shared_dof
323 end do
324 else
325 do concurrent(j = 2:xh%lx - 1)
326 k = j
327 this%dof(k, 1, 1, i) = edge_id + (j-2)
328 this%shared_dof(k, 1, 1, i) = shared_dof
329 end do
330 end if
331
332 call ep%edge_id(edge, 3)
333 shared_dof = msh%is_shared(edge)
334 global_id = msh%get_global(edge)
335 edge_id = edge_offset + int((global_id - 1), i8) * num_dofs_edges(1)
336 if (int(edge%x(1), i8) .ne. this%dof(1, 1, xh%lz, i)) then
337 do concurrent(j = 2:xh%lx - 1)
338 k = xh%lx+1-j
339 this%dof(k, 1, xh%lz, i) = edge_id + (j-2)
340 this%shared_dof(k, 1, xh%lz, i) = shared_dof
341 end do
342 else
343 do concurrent(j = 2:xh%lx - 1)
344 k = j
345 this%dof(k, 1, xh%lz, i) = edge_id + (j-2)
346 this%shared_dof(k, 1, xh%lz, i) = shared_dof
347 end do
348 end if
349
350 call ep%edge_id(edge, 2)
351 shared_dof = msh%is_shared(edge)
352 global_id = msh%get_global(edge)
353 edge_id = edge_offset + int((global_id - 1), i8) * num_dofs_edges(1)
354 if (int(edge%x(1), i8) .ne. this%dof(1, xh%ly, 1, i)) then
355 do concurrent(j = 2:xh%lx - 1)
356 k = xh%lx+1-j
357 this%dof(k, xh%ly, 1, i) = edge_id + (j-2)
358 this%shared_dof(k, xh%ly, 1, i) = shared_dof
359 end do
360 else
361 do concurrent(j = 2:xh%lx - 1)
362 k = j
363 this%dof(k, xh%ly, 1, i) = edge_id + (j-2)
364 this%shared_dof(k, xh%ly, 1, i) = shared_dof
365 end do
366 end if
367
368 call ep%edge_id(edge, 4)
369 shared_dof = msh%is_shared(edge)
370 global_id = msh%get_global(edge)
371 edge_id = edge_offset + int((global_id - 1), i8) * num_dofs_edges(1)
372 if (int(edge%x(1), i8) .ne. this%dof(1, xh%ly, xh%lz, i)) then
373 do concurrent(j = 2:xh%lx - 1)
374 k = xh%lx+1-j
375 this%dof(k, xh%ly, xh%lz, i) = edge_id + (j-2)
376 this%shared_dof(k, xh%ly, xh%lz, i) = shared_dof
377 end do
378 else
379 do concurrent(j = 2:xh%lx - 1)
380 k = j
381 this%dof(k, xh%ly, xh%lz, i) = edge_id + (j-2)
382 this%shared_dof(k, xh%ly, xh%lz, i) = shared_dof
383 end do
384 end if
385
386
387 !
388 ! Number edges in s-direction
389 !
390 call ep%edge_id(edge, 5)
391 shared_dof = msh%is_shared(edge)
392 global_id = msh%get_global(edge)
393 edge_id = edge_offset + int((global_id - 1), i8) * num_dofs_edges(2)
394 if (int(edge%x(1), i8) .ne. this%dof(1,1,1,i)) then
395 do concurrent(j = 2:xh%ly - 1)
396 k = xh%ly+1-j
397 this%dof(1, k, 1, i) = edge_id + (j-2)
398 this%shared_dof(1, k, 1, i) = shared_dof
399 end do
400 else
401 do concurrent(j = 2:xh%ly - 1)
402 k = j
403 this%dof(1, k, 1, i) = edge_id + (j-2)
404 this%shared_dof(1, k, 1, i) = shared_dof
405 end do
406 end if
407
408 call ep%edge_id(edge, 7)
409 shared_dof = msh%is_shared(edge)
410 global_id = msh%get_global(edge)
411 edge_id = edge_offset + int((global_id - 1), i8) * num_dofs_edges(2)
412 if (int(edge%x(1), i8) .ne. this%dof(1, 1, xh%lz, i)) then
413 do concurrent(j = 2:xh%ly - 1)
414 k = xh%ly+1-j
415 this%dof(1, k, xh%lz, i) = edge_id + (j-2)
416 this%shared_dof(1, k, xh%lz, i) = shared_dof
417 end do
418 else
419 do concurrent(j = 2:xh%ly - 1)
420 k = j
421 this%dof(1, k, xh%lz, i) = edge_id + (j-2)
422 this%shared_dof(1, k, xh%lz, i) = shared_dof
423 end do
424 end if
425
426 call ep%edge_id(edge, 6)
427 shared_dof = msh%is_shared(edge)
428 global_id = msh%get_global(edge)
429 edge_id = edge_offset + int((global_id - 1), i8) * num_dofs_edges(2)
430 if (int(edge%x(1), i8) .ne. this%dof(xh%lx, 1, 1, i)) then
431 do concurrent(j = 2:xh%ly - 1)
432 k = xh%ly+1-j
433 this%dof(xh%lx, k, 1, i) = edge_id + (j-2)
434 this%shared_dof(xh%lx, k, 1, i) = shared_dof
435 end do
436 else
437 do concurrent(j = 2:xh%ly - 1)
438 k = j
439 this%dof(xh%lx, k, 1, i) = edge_id + (j-2)
440 this%shared_dof(xh%lx, k, 1, i) = shared_dof
441 end do
442 end if
443
444 call ep%edge_id(edge, 8)
445 shared_dof = msh%is_shared(edge)
446 global_id = msh%get_global(edge)
447 edge_id = edge_offset + int((global_id - 1), i8) * num_dofs_edges(2)
448 if (int(edge%x(1), i8) .ne. this%dof(xh%lx, 1, xh%lz, i)) then
449 do concurrent(j = 2:xh%ly - 1)
450 k = xh%lz+1-j
451 this%dof(xh%lx, k, xh%lz, i) = edge_id + (j-2)
452 this%shared_dof(xh%lx, k, xh%lz, i) = shared_dof
453 end do
454 else
455 do concurrent(j = 2:xh%ly - 1)
456 k = j
457 this%dof(xh%lx, k, xh%lz, i) = edge_id + (j-2)
458 this%shared_dof(xh%lx, k, xh%lz, i) = shared_dof
459 end do
460 end if
461
462 !
463 ! Number edges in t-direction
464 !
465 call ep%edge_id(edge, 9)
466 shared_dof = msh%is_shared(edge)
467 global_id = msh%get_global(edge)
468 edge_id = edge_offset + int((global_id - 1), i8) * num_dofs_edges(3)
469 if (int(edge%x(1), i8) .ne. this%dof(1,1,1,i)) then
470 do concurrent(j = 2:xh%lz - 1)
471 k = xh%lz+1-j
472 this%dof(1, 1, k, i) = edge_id + (j-2)
473 this%shared_dof(1, 1, k, i) = shared_dof
474 end do
475 else
476 do concurrent(j = 2:xh%lz - 1)
477 k = j
478 this%dof(1, 1, k, i) = edge_id + (j-2)
479 this%shared_dof(1, 1, k, i) = shared_dof
480 end do
481 end if
482
483 call ep%edge_id(edge, 10)
484 shared_dof = msh%is_shared(edge)
485 global_id = msh%get_global(edge)
486 edge_id = edge_offset + int((global_id - 1), i8) * num_dofs_edges(3)
487 if (int(edge%x(1), i8) .ne. this%dof(xh%lx,1,1,i)) then
488 do concurrent(j = 2:xh%lz - 1)
489 k = xh%lz+1-j
490 this%dof(xh%lx, 1, k, i) = edge_id + (j-2)
491 this%shared_dof(xh%lx, 1, k, i) = shared_dof
492 end do
493 else
494 do concurrent(j = 2:xh%lz - 1)
495 k = j
496 this%dof(xh%lx, 1, k, i) = edge_id + (j-2)
497 this%shared_dof(xh%lx, 1, k, i) = shared_dof
498 end do
499 end if
500
501 call ep%edge_id(edge, 11)
502 shared_dof = msh%is_shared(edge)
503 global_id = msh%get_global(edge)
504 edge_id = edge_offset + int((global_id - 1), i8) * num_dofs_edges(3)
505 if (int(edge%x(1), i8) .ne. this%dof(1, xh%ly, 1, i)) then
506 do concurrent(j = 2:xh%lz - 1)
507 k = xh%lz+1-j
508 this%dof(1, xh%ly, k, i) = edge_id + (j-2)
509 this%shared_dof(1, xh%ly, k, i) = shared_dof
510 end do
511 else
512 do concurrent(j = 2:xh%lz - 1)
513 k = j
514 this%dof(1, xh%ly, k, i) = edge_id + (j-2)
515 this%shared_dof(1, xh%ly, k, i) = shared_dof
516 end do
517 end if
518
519 call ep%edge_id(edge, 12)
520 shared_dof = msh%is_shared(edge)
521 global_id = msh%get_global(edge)
522 edge_id = edge_offset + int((global_id - 1), i8) * num_dofs_edges(3)
523 if (int(edge%x(1), i8) .ne. this%dof(xh%lx, xh%ly, 1, i)) then
524 do concurrent(j = 2:xh%lz - 1)
525 k = xh%lz+1-j
526 this%dof(xh%lx, xh%ly, k, i) = edge_id + (j-2)
527 this%shared_dof(xh%lx, xh%ly, k, i) = shared_dof
528 end do
529 else
530 do concurrent(j = 2:xh%lz - 1)
531 k = j
532 this%dof(xh%lx, xh%ly, k, i) = edge_id + (j-2)
533 this%shared_dof(xh%lx, xh%ly, k, i) = shared_dof
534 end do
535 end if
536 type is (quad_t)
537 !
538 ! Number edges in r-direction
539 !
540 call ep%facet_id(edge, 3)
541 shared_dof = msh%is_shared(edge)
542 global_id = msh%get_global(edge)
543 edge_id = edge_offset + int((global_id - 1), i8) * num_dofs_edges(1)
544 !Reverse order of tranversal if edge is reversed
545 if (int(edge%x(1), i8) .ne. this%dof(1,1,1,i)) then
546 do concurrent(j = 2:xh%lx - 1)
547 k = xh%lx+1-j
548 this%dof(k, 1, 1, i) = edge_id + (j-2)
549 this%shared_dof(k, 1, 1, i) = shared_dof
550 end do
551 else
552 do concurrent(j = 2:xh%lx - 1)
553 k = j
554 this%dof(k, 1, 1, i) = edge_id + (j-2)
555 this%shared_dof(k, 1, 1, i) = shared_dof
556 end do
557 end if
558
559 call ep%facet_id(edge, 4)
560 shared_dof = msh%is_shared(edge)
561 global_id = msh%get_global(edge)
562 edge_id = edge_offset + int((global_id - 1), i8) * num_dofs_edges(1)
563 if (int(edge%x(1), i8) .ne. this%dof(1, xh%ly, 1, i)) then
564 do concurrent(j = 2:xh%lx - 1)
565 k = xh%lx+1-j
566 this%dof(k, xh%ly, 1, i) = edge_id + (j-2)
567 this%shared_dof(k, xh%ly, 1, i) = shared_dof
568 end do
569 else
570 do concurrent(j = 2:xh%lx - 1)
571 k = j
572 this%dof(k, xh%ly, 1, i) = edge_id + (j-2)
573 this%shared_dof(k, xh%ly, 1, i) = shared_dof
574 end do
575 end if
576
577 !
578 ! Number edges in s-direction
579 !
580 call ep%facet_id(edge, 1)
581 shared_dof = msh%is_shared(edge)
582 global_id = msh%get_global(edge)
583 edge_id = edge_offset + int((global_id - 1), i8) * num_dofs_edges(2)
584 if (int(edge%x(1), i8) .ne. this%dof(1,1,1,i)) then
585 do concurrent(j = 2:xh%ly - 1)
586 k = xh%ly+1-j
587 this%dof(1, k, 1, i) = edge_id + (j-2)
588 this%shared_dof(1, k, 1, i) = shared_dof
589 end do
590 else
591 do concurrent(j = 2:xh%ly - 1)
592 k = j
593 this%dof(1, k, 1, i) = edge_id + (j-2)
594 this%shared_dof(1, k, 1, i) = shared_dof
595 end do
596 end if
597
598 call ep%facet_id(edge, 2)
599 shared_dof = msh%is_shared(edge)
600 global_id = msh%get_global(edge)
601 edge_id = edge_offset + int((global_id - 1), i8) * num_dofs_edges(2)
602 if (int(edge%x(1), i8) .ne. this%dof(xh%lx,1,1,i)) then
603 do concurrent(j = 2:xh%ly - 1)
604 k = xh%ly+1-j
605 this%dof(xh%lx, k, 1, i) = edge_id + (j-2)
606 this%shared_dof(xh%lx, k, 1, i) = shared_dof
607 end do
608 else
609 do concurrent(j = 2:xh%ly - 1)
610 k = j
611 this%dof(xh%lx, k, 1, i) = edge_id + (j-2)
612 this%shared_dof(xh%lx, k, 1, i) = shared_dof
613 end do
614 end if
615 end select
616
617 end do
618 !$omp end parallel do
619 end subroutine dofmap_number_edges
620
622 subroutine dofmap_number_faces(this)
623 type(dofmap_t), target :: this
624 type(mesh_t), pointer :: msh
625 type(space_t), pointer :: Xh
626 integer :: i,j,k
627 integer :: global_id
628 type(tuple4_i4_t) :: face, face_order
629 integer(kind=i8) :: num_dofs_faces(3) ! #dofs for each dir (r, s, t)
630 integer(kind=i8) :: facet_offset, facet_id
631 logical :: shared_dof
632
633 msh => this%msh
634 xh => this%Xh
635
637 facet_offset = int(msh%glb_mpts, i8) + &
638 int(msh%glb_meds, i8) * int(xh%lx-2, i8) + int(1, i8)
639
640 ! Number of dofs on an face excluding end-points
641 num_dofs_faces(1) = int((xh%ly - 2) * (xh%lz - 2), i8)
642 num_dofs_faces(2) = int((xh%lx - 2) * (xh%lz - 2), i8)
643 num_dofs_faces(3) = int((xh%lx - 2) * (xh%ly - 2), i8)
644
645 !$omp parallel do private(i,j,k,global_id,face,face_order,facet_id, shared_dof)
646 do i = 1, msh%nelv
647
648 !
649 ! Number facets in r-direction (s, t)-plane
650 !
651 call msh%elements(i)%e%facet_id(face, 1)
652 call msh%elements(i)%e%facet_order(face_order, 1)
653 shared_dof = msh%is_shared(face)
654 global_id = msh%get_global(face)
655 facet_id = facet_offset + int((global_id - 1), i8) * num_dofs_faces(1)
656 do k = 2, xh%lz - 1
657 do j = 2, xh%ly - 1
658 this%dof(1, j, k, i) = dofmap_facetidx(face_order, face, &
659 facet_id, j, k, xh%lz, xh%ly)
660 this%shared_dof(1, j, k, i) = shared_dof
661 end do
662 end do
663
664 call msh%elements(i)%e%facet_id(face, 2)
665 call msh%elements(i)%e%facet_order(face_order, 2)
666 shared_dof = msh%is_shared(face)
667 global_id = msh%get_global(face)
668 facet_id = facet_offset + int((global_id - 1), i8) * num_dofs_faces(1)
669 do k = 2, xh%lz - 1
670 do j = 2, xh%ly - 1
671 this%dof(xh%lx, j, k, i) = dofmap_facetidx(face_order, face, &
672 facet_id, j, k, xh%lz, xh%ly)
673 this%shared_dof(xh%lx, j, k, i) = shared_dof
674 end do
675 end do
676
677
678 !
679 ! Number facets in s-direction (r, t)-plane
680 !
681 call msh%elements(i)%e%facet_id(face, 3)
682 call msh%elements(i)%e%facet_order(face_order, 3)
683 shared_dof = msh%is_shared(face)
684 global_id = msh%get_global(face)
685 facet_id = facet_offset + int((global_id - 1), i8) * num_dofs_faces(2)
686 do k = 2, xh%lz - 1
687 do j = 2, xh%lx - 1
688 this%dof(j, 1, k, i) = dofmap_facetidx(face_order, face, &
689 facet_id, k, j, xh%lz, xh%lx)
690 this%shared_dof(j, 1, k, i) = shared_dof
691 end do
692 end do
693
694 call msh%elements(i)%e%facet_id(face, 4)
695 call msh%elements(i)%e%facet_order(face_order, 4)
696 shared_dof = msh%is_shared(face)
697 global_id = msh%get_global(face)
698 facet_id = facet_offset + int((global_id - 1), i8) * num_dofs_faces(2)
699 do k = 2, xh%lz - 1
700 do j = 2, xh%lx - 1
701 this%dof(j, xh%ly, k, i) = dofmap_facetidx(face_order, face, &
702 facet_id, k, j, xh%lz, xh%lx)
703 this%shared_dof(j, xh%ly, k, i) = shared_dof
704 end do
705 end do
706
707
708 !
709 ! Number facets in t-direction (r, s)-plane
710 !
711 call msh%elements(i)%e%facet_id(face, 5)
712 call msh%elements(i)%e%facet_order(face_order, 5)
713 shared_dof = msh%is_shared(face)
714 global_id = msh%get_global(face)
715 facet_id = facet_offset + int((global_id - 1), i8) * num_dofs_faces(3)
716 do k = 2, xh%ly - 1
717 do j = 2, xh%lx - 1
718 this%dof(j, k, 1, i) = dofmap_facetidx(face_order, face, &
719 facet_id, k, j, xh%ly, xh%lx)
720 this%shared_dof(j, k, 1, i) = shared_dof
721 end do
722 end do
723
724 call msh%elements(i)%e%facet_id(face, 6)
725 call msh%elements(i)%e%facet_order(face_order, 6)
726 shared_dof = msh%is_shared(face)
727 global_id = msh%get_global(face)
728 facet_id = facet_offset + int((global_id - 1), i8) * num_dofs_faces(3)
729 do k = 2, xh%ly - 1
730 do j = 2, xh%lx - 1
731 this%dof(j, k, xh%lz, i) = dofmap_facetidx(face_order, face, &
732 facet_id, k, j, xh%lz, xh%lx)
733 this%shared_dof(j, k, xh%lz, i) = shared_dof
734 end do
735 end do
736 end do
737 !$omp end parallel do
738
739 end subroutine dofmap_number_faces
740
742 pure function dofmap_facetidx(face_order, face, facet_id, k1, j1, lk1, &
743 lj1) result(facet_idx)
744 type(tuple4_i4_t), intent(in) :: face_order, face
745 integer(kind=i8), intent(in) :: facet_id
746 integer(kind=i8) :: facet_idx
747 integer, intent(in) :: k1, j1, lk1, lj1
748 integer :: k, j, lk, lj
749
750 k = k1 - 2
751 j = j1 - 2
752 lk = lk1 - 2
753 lj = lj1 - 2
754
755 ! Given the indexes k,j for a GLL point on the inner part of the
756 ! face, we assign a unique number to it that depends on the
757 ! corner with the lowest id and its neighbour with the lowest
758 ! id. The id is assigned in this way to be consistent regardless
759 ! of how the faces are rotated or mirrored.
760 !
761 ! 4 -------- 3
762 ! | | k
763 ! |----->| ^
764 ! |----->| |
765 ! |----->| |
766 ! 1 -------- 2 0--->j
767
768
769 if (face_order%x(1) .eq. face%x(1)) then
770 if (face_order%x(2) .lt. face_order%x(4)) then
771 facet_idx = facet_id + j + k*lj
772 else
773 facet_idx = facet_id + j*lk + k
774 end if
775 else if (face_order%x(2) .eq. face%x(1)) then
776 if (face_order%x(3) .lt. face_order%x(1)) then
777 facet_idx = facet_id + lk*(lj-1-j) + k
778 else
779 facet_idx = facet_id + (lj-1-j) + k*lj
780 end if
781 else if (face_order%x(3) .eq. face%x(1)) then
782 if (face_order%x(4) .lt. face_order%x(2)) then
783 facet_idx = facet_id + (lj-1-j) + lj*(lk-1-k)
784 else
785 facet_idx = facet_id + lk*(lj-1-j) + (lk-1-k)
786 end if
787 else if (face_order%x(4) .eq. face%x(1)) then
788 if (face_order%x(1) .lt. face_order%x(3)) then
789 facet_idx = facet_id + lk*j + (lk-1-k)
790 else
791 facet_idx = facet_id + j + lj*(lk-1-k)
792 end if
793 end if
794
795 end function dofmap_facetidx
796
799 subroutine dofmap_generate_xyz(this)
800 type(dofmap_t), target :: this
801 integer :: i, j, el_idx
802 type(mesh_t), pointer :: msh
803 type(space_t), pointer :: Xh
804 real(kind=rp) :: rp_curve_data(5), curve_data_tot(5,12)
805 logical :: midpoint
806 integer :: n_edge, curve_type(12)
807
808 msh => this%msh
809 xh => this%Xh
810
811 if (msh%gdim .eq. 3) then
812 n_edge = 12
813 else
814 n_edge = 4
815 end if
816
817 !$omp parallel do
818 do i = 1, msh%nelv
819 call dofmap_xyzlin(xh, msh, msh%elements(i)%e, this%x(1,1,1,i), &
820 this%y(1,1,1,i), this%z(1,1,1,i))
821 end do
822 !$omp end parallel do
823
824 do i = 1, msh%curve%size
825 midpoint = .false.
826 el_idx = msh%curve%curve_el(i)%el_idx
827 curve_type = msh%curve%curve_el(i)%curve_type
828 curve_data_tot = msh%curve%curve_el(i)%curve_data
829 do j = 1, n_edge
830 if (curve_type(j) .eq. 4) then
831 midpoint = .true.
832 end if
833 end do
834 if (midpoint .and. xh%lx .gt. 2) then
835 call dofmap_xyzquad(xh, msh, msh%elements(el_idx)%e, &
836 this%x(1, 1, 1, el_idx), this%y(1, 1, 1, el_idx), &
837 this%z(1 ,1, 1, el_idx), curve_type, curve_data_tot)
838 end if
839 end do
840 do i = 1, msh%curve%size
841 el_idx = msh%curve%curve_el(i)%el_idx
842 do j = 1, 8
843 if (msh%curve%curve_el(i)%curve_type(j) .eq. 3) then
844 rp_curve_data = msh%curve%curve_el(i)%curve_data(1:5,j)
845 call arc_surface(j, rp_curve_data, &
846 this%x(1, 1, 1, el_idx), &
847 this%y(1, 1, 1, el_idx), &
848 this%z(1, 1, 1, el_idx), &
849 xh, msh%elements(el_idx)%e, msh%gdim)
850 end if
851 end do
852 end do
853 if (associated(msh%apply_deform)) then
854 call msh%apply_deform(this%x, this%y, this%z, xh%lx, xh%ly, xh%lz)
855 end if
856 end subroutine dofmap_generate_xyz
857
866 subroutine dofmap_xyzlin(Xh, msh, element, x, y, z)
867 type(mesh_t), pointer, intent(in) :: msh
868 type(space_t), intent(in) :: Xh
869 class(element_t), intent(in) :: element
870 real(kind=rp), intent(inout) :: x(xh%lx, xh%ly, xh%lz), &
871 y(xh%lx, xh%ly, xh%lz), &
872 z(xh%lx, xh%ly, xh%lz)
873 real(kind=rp) :: xyzb(2,2,2,3), zgml(xh%lx, 3)
874 real(kind=rp) :: jx(xh%lx*2)
875 real(kind=rp) :: jxt(xh%lx*2), jyt(xh%lx*2), jzt(xh%lx*2)
876 real(kind=rp) :: w(4*xh%lx**3), tmp(xh%lx, xh%lx, xh%lx)
877 real(kind=rp), dimension(2), parameter :: zlin = [-1d0, 1d0]
878
879 integer :: j, k
880
881 zgml = 0d0
882 xyzb = 0d0
883
884 w = 0d0
885 call copy(zgml(1,1), xh%zg(1,1), xh%lx)
886 call copy(zgml(1,2), xh%zg(1,2), xh%ly)
887 if (msh%gdim .gt. 2) then
888 call copy(zgml(1,3), xh%zg(1,3), xh%lz)
889 end if
890
891 k = 1
892 do j = 1, xh%lx
893 call fd_weights_full(zgml(j,1), zlin, 1, 0, jxt(k))
894 call fd_weights_full(zgml(j,2), zlin, 1, 0, jyt(k))
895 if (msh%gdim .gt. 2) then
896 call fd_weights_full(zgml(j,3), zlin, 1, 0, jzt(k))
897 end if
898 k = k + 2
899 end do
900 call trsp(jx, xh%lx, jxt, 2)
901
902 if (msh%gdim .eq. 2) then
903 jzt = 1d0
904 end if
905
906 if (msh%gdim .gt. 2) then
907 do concurrent(j = 1:msh%gdim)
908 xyzb(1,1,1,j) = element%pts(1)%p%x(j)
909 xyzb(2,1,1,j) = element%pts(2)%p%x(j)
910 xyzb(1,2,1,j) = element%pts(3)%p%x(j)
911 xyzb(2,2,1,j) = element%pts(4)%p%x(j)
912
913 xyzb(1,1,2,j) = element%pts(5)%p%x(j)
914 xyzb(2,1,2,j) = element%pts(6)%p%x(j)
915 xyzb(1,2,2,j) = element%pts(7)%p%x(j)
916 xyzb(2,2,2,j) = element%pts(8)%p%x(j)
917 end do
918 else
919 do concurrent(j = 1:msh%gdim)
920 xyzb(1,1,1,j) = element%pts(1)%p%x(j)
921 xyzb(2,1,1,j) = element%pts(2)%p%x(j)
922 xyzb(1,2,1,j) = element%pts(3)%p%x(j)
923 xyzb(2,2,1,j) = element%pts(4)%p%x(j)
924 end do
925 end if
926 if (msh%gdim .eq. 3) then
927 call tensr3(tmp, xh%lx, xyzb(1,1,1,1), 2, jx, jyt, jzt, w)
928 call copy(x, tmp, xh%lx*xh%ly*xh%lz)
929 call tensr3(tmp, xh%ly, xyzb(1,1,1,2), 2, jx, jyt, jzt, w)
930 call copy(y, tmp, xh%lx*xh%ly*xh%lz)
931 call tensr3(tmp, xh%lz, xyzb(1,1,1,3), 2, jx, jyt, jzt, w)
932 call copy(z, tmp, xh%lx*xh%ly*xh%lz)
933 else
934 call tnsr2d_el(tmp, xh%lx, xyzb(1,1,1,1), 2, jx, jyt)
935 call copy(x, tmp, xh%lx*xh%ly*xh%lz)
936 call tnsr2d_el(tmp, xh%ly, xyzb(1,1,1,2), 2, jx, jyt)
937 call copy(y, tmp, xh%lx*xh%ly*xh%lz)
938 end if
939 end subroutine dofmap_xyzlin
940
941 !OCL SERIAL
942 subroutine dofmap_xyzquad(Xh, msh, element, x, y, z, curve_type, curve_data)
943 type(mesh_t), pointer, intent(in) :: msh
944 type(space_t), intent(in) :: Xh
945 class(element_t), intent(in) :: element
946 real(kind=rp), dimension(Xh%lx, Xh%ly, Xh%lz), intent(inout) :: x, y, z
947 integer :: curve_type(12), eindx(12)
948 real(kind=rp) :: curve_data(5,12), x3(3,3,3), y3(3,3,3), z3(3,3,3)
949 type(space_t), target :: xh3
950 real(kind=rp), dimension(3), parameter :: zquad = [-1d0, 0d0,1d0]
951 real(kind=rp) :: zg(3)
952 real(kind=rp), dimension(Xh%lx, Xh%lx, Xh%lx) :: tmp
953 real(kind=rp) :: jx(xh%lx*3)
954 real(kind=rp) :: jxt(xh%lx*3), jyt(xh%lx*3), jzt(xh%lx*3)
955 real(kind=rp) :: w(4*xh%lxyz,2)
956 integer :: j, k, n_edges
957 eindx = [2 , 6 , 8 , 4, &
958 20 , 24 , 26 , 22, &
959 10 , 12 , 18 , 16]
960
961 w = 0d0
962 if (msh%gdim .eq. 3) then
963 n_edges = 12
964 call xh3%init(gll, 3, 3, 3)
965 else
966 n_edges = 4
967 call xh3%init(gll, 3, 3)
968 end if
969 call dofmap_xyzlin(xh3, msh, element, x3, y3, z3)
970
971 do k = 1, n_edges
972 if (curve_type(k) .eq. 4) then
973 x3(eindx(k),1,1) = curve_data(1,k)
974 y3(eindx(k),1,1) = curve_data(2,k)
975 z3(eindx(k),1,1) = curve_data(3,k)
976 end if
977 end do
978 zg(1) = -1
979 zg(2) = 0
980 zg(3) = 1
981 if (msh%gdim .eq. 3) then
982 call gh_face_extend_3d(x3, zg, 3, 2, w(1,1), w(1,2)) ! 2 --> edge extend
983 call gh_face_extend_3d(y3, zg, 3, 2, w(1,1), w(1,2))
984 call gh_face_extend_3d(z3, zg, 3, 2, w(1,1), w(1,2))
985 else
986 call neko_warning(' m deformation not supported for 2d yet')
987 call gh_face_extend_2d(x3, zg, 3, 2, w(1,1), w(1,2)) ! 2 --> edge extend
988 call gh_face_extend_2d(y3, zg, 3, 2, w(1,1), w(1,2))
989 end if
990 k = 1
991 do j = 1, xh%lx
992 call fd_weights_full(xh%zg(j,1), zquad, 2, 0, jxt(k))
993 call fd_weights_full(xh%zg(j,2), zquad, 2, 0, jyt(k))
994 if (msh%gdim .gt. 2) then
995 call fd_weights_full(xh%zg(j,3), zquad, 2, 0, jzt(k))
996 end if
997 k = k + 3
998 end do
999 call trsp(jx, xh%lx, jxt, 3)
1000 if (msh%gdim .eq. 3) then
1001 call tensr3(tmp, xh%lx, x3, 3, jx, jyt, jzt, w)
1002 call copy(x, tmp, xh%lx*xh%ly*xh%lz)
1003 call tensr3(tmp, xh%ly, y3, 3, jx, jyt, jzt, w)
1004 call copy(y, tmp, xh%lx*xh%ly*xh%lz)
1005 call tensr3(tmp, xh%lz, z3, 3, jx, jyt, jzt, w)
1006 call copy(z, tmp, xh%lx*xh%ly*xh%lz)
1007 else
1008 call tnsr2d_el(tmp, xh%lx, x3, 3, jx, jyt)
1009 call copy(x, tmp, xh%lx*xh%ly*xh%lz)
1010 call tnsr2d_el(tmp, xh%ly, y3, 3, jx, jyt)
1011 call copy(y, tmp, xh%lx*xh%ly*xh%lz)
1012 end if
1013
1014 call xh3%free()
1015 end subroutine dofmap_xyzquad
1016
1017
1018 !OCL SERIAL
1024 subroutine gh_face_extend_3d(x, zg, n, gh_type, e, v)
1025 integer, intent(in) :: n
1026 real(kind=rp), intent(inout) :: x(n, n, n)
1027 real(kind=rp), intent(in) :: zg(n)
1028 real(kind=rp), intent(inout) :: e(n, n, n)
1029 real(kind=rp), intent(inout) :: v(n, n, n)
1030 integer :: gh_type, ntot, kk, jj, ii, k, j, i
1031 real(kind=xp) :: si, sj, sk, hi, hj, hk
1032
1033 !
1034 ! Build vertex interpolant
1035 !
1036 ntot = n**3
1037 do concurrent(i = 1:ntot)
1038 v(i,1,1) = 0.0_rp
1039 end do
1040
1041 do concurrent(i = 1:n, j = 1:n, k = 1:n, &
1042 ii = 1:n:n-1, jj = 1:n:n-1, kk = 1:n:n-1)
1043 si = 0.5_xp*((n-ii)*(1-zg(i))+(ii-1)*(1+zg(i)))/(n-1)
1044 sj = 0.5_xp*((n-jj)*(1-zg(j))+(jj-1)*(1+zg(j)))/(n-1)
1045 sk = 0.5_xp*((n-kk)*(1-zg(k))+(kk-1)*(1+zg(k)))/(n-1)
1046 v(i,j,k) = v(i,j,k) + si * sj* sk * x(ii, jj, kk)
1047 end do
1048
1049 if (gh_type .eq. 1) then
1050 do concurrent(i = 1:ntot)
1051 x(i,1,1) = v(i,1,1)
1052 end do
1053 return
1054 end if
1055 !
1056 !
1057 ! Extend 12 edges
1058 do concurrent(i = 1:ntot)
1059 e(i,1,1) = 0.0_rp
1060 end do
1061 !
1062 ! x-edges
1063 !
1064 do concurrent(i = 1:n, j = 1:n, k = 1:n, jj = 1:n:n-1, kk = 1:n:n-1)
1065 hj = 0.5_xp*((n-jj)*(1-zg(j))+(jj-1)*(1+zg(j)))/(n-1)
1066 hk = 0.5_xp*((n-kk)*(1-zg(k))+(kk-1)*(1+zg(k)))/(n-1)
1067 e(i,j,k) = e(i,j,k) + hj*hk*(x(i, jj, kk) - v(i, jj, kk))
1068 end do
1069 !
1070 ! y-edges
1071 !
1072 do concurrent(i = 1:n, j = 1:n, k = 1:n, ii = 1:n:n-1, kk = 1:n:n-1)
1073 hi = 0.5_xp*((n-ii)*(1-zg(i))+(ii-1)*(1+zg(i)))/(n-1)
1074 hk = 0.5_xp*((n-kk)*(1-zg(k))+(kk-1)*(1+zg(k)))/(n-1)
1075 e(i,j,k) = e(i,j,k) + hi*hk*(x(ii, j, kk) - v(ii, j, kk))
1076 end do
1077 !
1078 ! z-edges
1079 !
1080 do concurrent(i = 1:n, j = 1:n, k = 1:n, ii = 1:n:n-1, jj = 1:n:n-1)
1081 hi = 0.5_xp*((n-ii)*(1-zg(i))+(ii-1)*(1+zg(i)))/(n-1)
1082 hj = 0.5_xp*((n-jj)*(1-zg(j))+(jj-1)*(1+zg(j)))/(n-1)
1083 e(i,j,k) = e(i,j,k) + hi*hj*(x(ii, jj, k) - v(ii, jj, k))
1084 end do
1085
1086 do concurrent(i = 1:ntot)
1087 e(i,1,1) = e(i,1,1) + v(i,1,1)
1088 end do
1089
1090 if (gh_type .eq. 2) then
1091 do concurrent(i = 1:ntot)
1092 x(i,1,1) = e(i,1,1)
1093 end do
1094 return
1095 end if
1096 !
1097 ! Extend faces
1098 !
1099 do concurrent(i = 1:ntot)
1100 v(i,1,1) = 0.0_rp
1101 end do
1102 !
1103 ! x-edges
1104 !
1105 do concurrent(i = 1:n, j = 1:n, k = 1:n, ii = 1:n:n-1)
1106 hi = 0.5_xp*((n-ii)*(1-zg(i))+(ii-1)*(1+zg(i)))/(n-1)
1107 v(i,j,k) = v(i,j,k) + hi*(x(ii,j,k)-e(ii,j,k))
1108 end do
1109
1110 !
1111 ! y-edges
1112 !
1113 do concurrent(i = 1:n, j = 1:n, k = 1:n, jj = 1:n:n-1)
1114 hj = 0.5_xp*((n-jj)*(1-zg(j))+(jj-1)*(1+zg(j)))/(n-1)
1115 v(i,j,k) = v(i,j,k) + hj*(x(i, jj, k) - e(i, jj, k))
1116 end do
1117
1118 !
1119 ! z-edges
1120 !
1121 do concurrent(i = 1:n, j = 1:n, k = 1:n, kk = 1:n:n-1)
1122 hk = 0.5_xp*((n-kk)*(1-zg(k))+(kk-1)*(1+zg(k)))/(n-1)
1123 v(i,j,k) = v(i,j,k) + hk*(x(i, j, kk) - e(i, j, kk))
1124 end do
1125
1126 do concurrent(i = 1:ntot)
1127 v(i,1,1) = v(i,1,1) + e(i,1,1)
1128 x(i,1,1) = v(i,1,1)
1129 end do
1130
1131 end subroutine gh_face_extend_3d
1132
1133 !OCL SERIAL
1137 subroutine gh_face_extend_2d(x, zg, n, gh_type, e, v)
1138 integer, intent(in) :: n
1139 real(kind=rp), intent(inout) :: x(n, n)
1140 real(kind=rp), intent(in) :: zg(n)
1141 real(kind=rp), intent(inout) :: e(n, n)
1142 real(kind=rp), intent(inout) :: v(n, n)
1143 integer, intent(in) :: gh_type
1144 integer :: i,j , jj, ii, ntot
1145 real(kind=rp) :: si, sj, hi, hj
1146
1147 !Build vertex interpolant
1148
1149 ntot = n*n
1150 call rzero(v, ntot)
1151 do jj = 1, n, n-1
1152 do ii = 1, n, n-1
1153 do j = 1, n
1154 do i = 1, n
1155 si = 0.5_xp*((n-ii)*(1-zg(i))+(ii-1)*(1+zg(i)))/(n-1)
1156 sj = 0.5_xp*((n-jj)*(1-zg(j))+(jj-1)*(1+zg(j)))/(n-1)
1157 v(i,j) = v(i,j) + si*sj*x(ii, jj)
1158 end do
1159 end do
1160 end do
1161 end do
1162 if (gh_type .eq. 1) then
1163 call copy(x, v, ntot)
1164 return
1165 end if
1166
1167 !Extend 4 edges
1168 call rzero(e, ntot)
1169
1170 !x-edges
1171
1172 do jj = 1, n, n-1
1173 do j = 1, n
1174 do i = 1, n
1175 hj = 0.5_xp*((n-jj)*(1-zg(j))+(jj-1)*(1+zg(j)))/(n-1)
1176 e(i,j) = e(i,j) + hj*(x(i, jj) - v(i, jj))
1177 end do
1178 end do
1179 end do
1180
1181 !y-edges
1182
1183 do ii = 1, n, n-1
1184 do j = 1, n
1185 do i = 1, n
1186 hi = 0.5_xp*((n-ii)*(1-zg(i))+(ii-1)*(1+zg(i)))/(n-1)
1187 e(i,j) = e(i,j) + hi*(x(ii,j)-v(ii,j))
1188 end do
1189 end do
1190 end do
1191
1192 call add3(x, e, v, ntot)
1193
1194 end subroutine gh_face_extend_2d
1195
1196
1197
1198 subroutine arc_surface(isid, curve_data, x, y, z, Xh, element, gdim)
1199 integer, intent(in) :: isid, gdim
1200 type(space_t), intent(in) :: Xh
1201 class(element_t) :: element
1202 real(kind=rp), dimension(5), intent(in) :: curve_data
1203 real(kind=rp), dimension(Xh%lx, Xh%ly, Xh%lz), intent(inout) :: x, y, z
1204 real(kind=rp) :: pt1x, pt1y, pt2x, pt2y, pt12x, pt12y
1205 real(kind=rp) :: radius, dtheta, r, xys
1206 real(kind=rp) :: theta0, xcenn, ycenn, h(xh%lx, 3, 2)
1207 real(kind=rp) :: xcrved(xh%lx), ycrved(xh%lx), xs, ys
1208 integer :: isid1, ixt, iyt, izt, ix, itmp
1209 ! Cyclic to symmetric face mapping
1210 integer(i4), dimension(6), parameter :: fcyc_to_sym = [3, 2, 4, 1, 5, 6]
1211 ! Cyclic to symmetric edge mapping
1212 integer(i4), dimension(12), parameter :: ecyc_to_sym = [1, 6, 2, 5, 3, 8, &
1213 4, 7, 9, 10, 12, 11]
1214 ! Symmetric edge to vertex mapping
1215 integer, parameter, dimension(2, 12) :: edge_nodes = reshape([1, 2, 3, 4, &
1216 5, 6, 7, 8, 1, 3, 2, 4, 5, 7, 6, 8, 1, 5, 2, 6, 3, 7, 4, 8], &
1217 [2,12])
1218 ! copy from hex as this has private attribute there
1219
1220 ! this subroutine is a mess of symmetric and cyclic edge/face numberring and
1221 ! cannot be cleaned without changing an input format (isid seems to be
1222 ! a cyclic edge number)
1223 ! following according to cyclic edge numbering and orientation
1224 itmp = ecyc_to_sym(isid)
1225 select case (isid)
1226 case (1:2,5:6)
1227 pt1x = element%pts(edge_nodes(1, itmp))%p%x(1)
1228 pt1y = element%pts(edge_nodes(1, itmp))%p%x(2)
1229 pt2x = element%pts(edge_nodes(2, itmp))%p%x(1)
1230 pt2y = element%pts(edge_nodes(2, itmp))%p%x(2)
1231 case (3:4,7:8)
1232 pt1x = element%pts(edge_nodes(2, itmp))%p%x(1)
1233 pt1y = element%pts(edge_nodes(2, itmp))%p%x(2)
1234 pt2x = element%pts(edge_nodes(1, itmp))%p%x(1)
1235 pt2y = element%pts(edge_nodes(1, itmp))%p%x(2)
1236 end select
1237 ! find slope of perpendicular
1238 radius = curve_data(1)
1239 xs = pt2y-pt1y
1240 ys = pt1x-pt2x
1241 ! make length radius
1242 xys = sqrt(xs**2 + ys**2)
1243 ! sanity check
1244 if (abs(2.0 * radius) <= xys * 1.00001) &
1245 & call neko_error('Radius to small for arced element surface')
1246 ! find center
1247 dtheta = abs(asin(0.5_xp*xys/radius))
1248 pt12x = (pt1x + pt2x)/2.0
1249 pt12y = (pt1y + pt2y)/2.0
1250 xcenn = pt12x - xs/xys * radius*cos(dtheta)
1251 ycenn = pt12y - ys/xys * radius*cos(dtheta)
1252 theta0 = atan2((pt12y-ycenn), (pt12x-xcenn))
1253 ! compute perturbation of geometry
1254 isid1 = mod(isid+4-1, 4)+1
1255 call compute_h(h, xh%zg, gdim, xh%lx)
1256 if (radius < 0.0) dtheta = -dtheta
1257 do ix = 1, xh%lx
1258 ixt = ix
1259 if (isid1 .gt. 2) ixt = xh%lx+1-ix
1260 r = xh%zg(ix,1)
1261 xcrved(ixt) = xcenn + abs(radius) * cos(theta0 + r*dtheta) &
1262 - ( h(ix,1,1)*pt1x + h(ix,1,2)*pt2x )
1263 ycrved(ixt) = ycenn + abs(radius) * sin(theta0 + r*dtheta) &
1264 - ( h(ix,1,1)*pt1y + h(ix,1,2)*pt2y )
1265 end do
1266 ! points all set, add perturbation to current mesh.
1267 ! LEGACY WARNING
1268 ! I dont want to dive in this again, Martin Karp 2/3 - 2021
1269 isid1 = fcyc_to_sym(isid1)
1270 izt = (isid-1)/4+1
1271 iyt = isid1-2
1272 ixt = isid1
1273 if (isid1 .le. 2) then
1274 call addtnsr(x, h(1, 1, ixt), xcrved, h(1, 3, izt), &
1275 xh%lx, xh%ly, xh%lz)
1276 call addtnsr(y, h(1, 1, ixt), ycrved, h(1, 3, izt), &
1277 xh%lx, xh%ly, xh%lz)
1278 else
1279 call addtnsr(x, xcrved, h(1, 2, iyt), h(1, 3, izt), &
1280 xh%lx, xh%ly, xh%lz)
1281 call addtnsr(y, ycrved, h(1, 2, iyt), h(1, 3, izt), &
1282 xh%lx, xh%ly, xh%lz)
1283 end if
1284 end subroutine arc_surface
1285
1286 !OCL SERIAL
1287 subroutine compute_h(h, zgml, gdim, lx)
1288 integer, intent(in) :: lx, gdim
1289 real(kind=rp), intent(inout) :: h(lx, 3, 2)
1290 real(kind=rp), intent(in) :: zgml(lx, 3)
1291 integer :: ix, iy, iz
1292
1293 do ix = 1, lx
1294 h(ix,1,1) = (1.0_rp - zgml(ix, 1)) * 0.5_rp
1295 h(ix,1,2) = (1.0_rp + zgml(ix, 1)) * 0.5_rp
1296 end do
1297
1298 do iy = 1, lx
1299 h(iy,2,1) = (1.0_rp - zgml(iy, 2)) * 0.5_rp
1300 h(iy,2,2) = (1.0_rp + zgml(iy, 2)) * 0.5_rp
1301 end do
1302
1303 if (gdim .eq. 3) then
1304 do iz = 1, lx
1305 h(iz,3,1) = (1.0_rp - zgml(iz, 3)) * 0.5_rp
1306 h(iz,3,2) = (1.0_rp + zgml(iz, 3)) * 0.5_rp
1307 end do
1308 else
1309 call rone(h(1,3,1), lx)
1310 call rone(h(1,3,2), lx)
1311 end if
1312
1313 end subroutine compute_h
1314
1319 subroutine dofmap_subset_by_mask(this, other, mask)
1320 class(dofmap_t), intent(inout) :: this
1321 class(dofmap_t), intent(inout) :: other
1322 type(mask_t), intent(in) :: mask
1323 integer :: i
1324
1325 ! Initialize the mesh subset_mesh in this
1326 ! Deallocate any previously allocated mesh subset
1327 if (allocated(this%msh_subset)) then
1328 call this%msh_subset%free()
1329 deallocate(this%msh_subset)
1330 end if
1331
1332 allocate(this%msh_subset)
1333 call this%msh%subset_by_mask(this%msh_subset, mask, &
1334 this%Xh%lx, this%Xh%ly, this%Xh%lz)
1335
1336 ! Initialize the other dofmap
1337 call other%init(this%msh_subset, this%Xh)
1338
1339 ! Overwrite dofmap in case it has been updated and
1340 ! the mesh has not.
1341 if (neko_bcknd_device .eq. 1) then
1342 call device_masked_gather_copy_aligned(other%x_d, &
1343 this%x_d, mask%get_d(), &
1344 this%size(), mask%size())
1345 call device_masked_gather_copy_aligned(other%y_d, &
1346 this%y_d, mask%get_d(), &
1347 this%size(), mask%size())
1348 call device_masked_gather_copy_aligned(other%z_d, &
1349 this%z_d, mask%get_d(), &
1350 this%size(), mask%size())
1351
1352 ! Sync with host
1353 call device_memcpy(other%x, other%x_d, other%ntot, &
1354 device_to_host, sync = .false.)
1355 call device_memcpy(other%y, other%y_d, other%ntot, &
1356 device_to_host, sync = .false.)
1357 call device_memcpy(other%z, other%z_d, other%ntot, &
1358 device_to_host, sync = .true.)
1359
1360 else
1361 call masked_gather_copy(other%x, this%x, mask%get(), &
1362 this%size(), mask%size())
1363 call masked_gather_copy(other%y, this%y, mask%get(), &
1364 this%size(), mask%size())
1365 call masked_gather_copy(other%z, this%z, mask%get(), &
1366 this%size(), mask%size())
1367 end if
1368
1369 end subroutine dofmap_subset_by_mask
1370
1371end module dofmap
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
Unmap a Fortran array from a device (deassociate and free)
Definition device.F90:89
subroutine, public device_copy(a_d, b_d, n, strm)
Copy a vector .
subroutine, public device_masked_gather_copy_aligned(a_d, b_d, mask_d, n, n_mask, strm)
Gather a masked vector .
Device abstraction, common interface for various accelerators.
Definition device.F90:34
integer, parameter, public host_to_device
Definition device.F90:48
integer, parameter, public device_to_host
Definition device.F90:48
Defines a mapping of the degrees of freedom.
Definition dofmap.f90:35
pure integer function dofmap_global_size(this)
Return the global number of dofs in the dofmap, lx*ly*lz*glb_nelv.
Definition dofmap.f90:258
subroutine gh_face_extend_2d(x, zg, n, gh_type, e, v)
Extend 2D faces into interior via gordon hall gh_type: 1 - vertex only 2 - vertex and faces.
Definition dofmap.f90:1138
subroutine dofmap_init_and_map(this, dof, xh)
Constructor.
Definition dofmap.f90:167
subroutine dofmap_generate_xyz(this)
Generate x,y,z-coordinates for all dofs.
Definition dofmap.f90:800
subroutine arc_surface(isid, curve_data, x, y, z, xh, element, gdim)
Definition dofmap.f90:1199
subroutine compute_h(h, zgml, gdim, lx)
Definition dofmap.f90:1288
subroutine dofmap_subset_by_mask(this, other, mask)
Generate/Initialize a new dofmap object based on a mask.
Definition dofmap.f90:1320
subroutine dofmap_xyzlin(xh, msh, element, x, y, z)
Generate the x, y, z coordinates of the dofs in a signle element, assuming linear element edges.
Definition dofmap.f90:867
subroutine dofmap_free(this)
Destructor.
Definition dofmap.f90:208
subroutine dofmap_number_edges(this)
Assing numbers to dofs on edges.
Definition dofmap.f90:286
subroutine dofmap_init(this, msh, xh)
Constructor.
Definition dofmap.f90:97
subroutine dofmap_number_points(this)
Assign numbers to each dofs on points.
Definition dofmap.f90:265
pure integer function dofmap_size(this)
Return the local number of dofs in the dofmap, lx*ly*lz*nelv.
Definition dofmap.f90:251
subroutine dofmap_xyzquad(xh, msh, element, x, y, z, curve_type, curve_data)
Definition dofmap.f90:943
subroutine dofmap_number_faces(this)
Assign numbers to dofs on faces.
Definition dofmap.f90:623
subroutine gh_face_extend_3d(x, zg, n, gh_type, e, v)
Extend faces into interior via gordon hall gh_type: 1 - vertex only 2 - vertex and edges 3 - vertex,...
Definition dofmap.f90:1025
pure integer(kind=i8) function dofmap_facetidx(face_order, face, facet_id, k1, j1, lk1, lj1)
Get idx for GLL point on face depending on face ordering k and j.
Definition dofmap.f90:744
Fast diagonalization methods from NEKTON.
Definition fast3d.f90:61
subroutine, public fd_weights_full(xi, x, n, m, c)
Compute finite-difference stencil weights for evaluating derivatives up to order at a point.
Definition fast3d.f90:106
Defines a hexahedron element.
Definition hex.f90:34
Routines to interpolate between different spaces.
Object for handling masks in Neko.
Definition mask.f90:34
Definition math.f90:60
subroutine, public rone(a, n)
Set all elements to one.
Definition math.f90:277
subroutine, public masked_gather_copy(a, b, mask, n, n_mask)
Gather a masked vector to reduced contigous vector .
Definition math.f90:420
subroutine, public add3(a, b, c, n)
Vector addition .
Definition math.f90:915
subroutine, public copy(a, b, n)
Copy a vector .
Definition math.f90:291
subroutine, public rzero(a, n)
Zero a real vector.
Definition math.f90:235
Defines a mesh.
Definition mesh.f90:34
Build configurations.
integer, parameter neko_bcknd_device
integer, parameter, public i8
Definition num_types.f90:7
integer, parameter, public i4
Definition num_types.f90:6
integer, parameter, public xp
Definition num_types.f90:14
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
Defines a quadrilateral element.
Definition quad.f90:34
Defines a function space.
Definition space.f90:34
integer, parameter, public gll
Definition space.f90:50
Tensor operations.
Definition tensor.f90:61
subroutine, public addtnsr(s, h1, h2, h3, nx, ny, nz)
Maps and adds to S a tensor product form of the three functions H1,H2,H3. This is a single element ro...
Definition tensor.f90:280
subroutine, public trsp(a, lda, b, ldb)
Transpose of a rectangular tensor .
Definition tensor.f90:124
subroutine, public tensr3(v, nv, u, nu, a, bt, ct, w)
Tensor product .
Definition tensor.f90:94
subroutine, public tnsr2d_el(v, nv, u, nu, a, bt)
Computes .
Definition tensor.f90:157
Implements a n-tuple.
Definition tuple.f90:41
Utilities.
Definition utils.f90:35
subroutine, public neko_warning(warning_msg)
Reports a warning to standard output.
Definition utils.f90:398
Base type for an element.
Definition element.f90:44
Hexahedron element.
Definition hex.f90:63
Interpolation between two space::space_t.
Type for consistently handling masks in Neko. This type encapsulates the mask array and its associate...
Definition mask.f90:51
Quadrilateral element.
Definition quad.f90:58
The function space for the SEM solution fields.
Definition space.f90:64
Integer based 4-tuple.
Definition tuple.f90:76
Integer based 2-tuple.
Definition tuple.f90:58