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