Neko 1.99.5
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
mesh.f90
Go to the documentation of this file.
1! Copyright (c) 2018-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!
34module mesh
35 use num_types, only : rp, dp, i8
36 use point, only : point_t
37 use element, only : element_t
38 use hex, only : hex_t, neko_hex_neds, neko_hex_nfcs, &
42 use mask, only : mask_t
44 use tuple, only : tuple_i4_t, tuple4_i4_t
47 use datadist, only : linear_dist_t
48 use distdata, only : distdata_t
49 use comm, only : pe_size, pe_rank, neko_comm
51 use math, only : abscmp, sort
53 use mpi_f08, only : mpi_integer, mpi_max, mpi_sum, mpi_in_place, &
54 mpi_allreduce, mpi_exscan, mpi_request, mpi_status, mpi_wait, &
55 mpi_issend, mpi_irecv, mpi_status_ignore, mpi_integer8, &
56 mpi_get_count
57 use uset, only : uset_i8_t
58 use curve, only : curve_t
59 use logger, only : log_size
60 use, intrinsic :: iso_fortran_env, only: error_unit
61 implicit none
62 private
63
65 integer, public, parameter :: neko_msh_max_zlbls = 20
67 integer, public, parameter :: neko_msh_max_zlbl_len = 40
68
69 type, private :: mesh_element_t
70 class(element_t), allocatable :: e
71 end type mesh_element_t
72
73 type, public :: mesh_t
74 integer :: nelv
75 integer :: npts
76 integer :: gdim
77 integer :: mpts
78 integer :: mfcs
79 integer :: meds
80
81 integer :: glb_nelv
82 integer :: glb_mpts
83 integer :: glb_mfcs
84 integer :: glb_meds
85
86 integer :: offset_el
87 integer :: max_pts_id
88
89 type(point_t), allocatable :: points(:)
90 type(mesh_element_t), allocatable :: elements(:)
91 logical, allocatable :: dfrmd_el(:)
92
93 type(htable_i4_t) :: htp
94 type(htable_i4t4_t) :: htf
95 type(htable_i4t2_t) :: hte
96 type(htable_i4_t) :: htel
97
98
99 integer, allocatable :: facet_neigh(:,:)
100
104 class(htable_t), allocatable :: facet_map
105 type(stack_i4_t), allocatable :: point_neigh(:)
106
107 type(distdata_t) :: ddata
108 logical, allocatable :: neigh(:)
109 integer, allocatable :: neigh_order(:)
110
111 integer(2), allocatable :: facet_type(:,:)
112
113 type(facet_zone_t), allocatable :: labeled_zones(:)
114 type(facet_zone_periodic_t) :: periodic
115 type(curve_t) :: curve
116
117 logical :: lconn = .false.
118 logical :: ldist = .false.
119 logical :: lnumr = .false.
120 logical :: lgenc = .true.
121
122 logical :: is_submesh = .false.
123
126 procedure(mesh_deform), pass(msh), pointer :: apply_deform => null()
127 contains
128 procedure, private, pass(this) :: init_nelv => mesh_init_nelv
129 procedure, private, pass(this) :: init_dist => mesh_init_dist
130 procedure, private, pass(this) :: add_quad => mesh_add_quad
131 procedure, private, pass(this) :: add_hex => mesh_add_hex
132 procedure, private, pass(this) :: add_edge => mesh_add_edge
133 procedure, private, pass(this) :: add_face => mesh_add_face
134 procedure, private, pass(this) :: add_point => mesh_add_point
135 procedure, private, pass(this) :: get_local_point => mesh_get_local_point
136 procedure, private, pass(this) :: get_local_edge => mesh_get_local_edge
137 procedure, private, pass(this) :: get_local_facet => mesh_get_local_facet
138 procedure, private, pass(this) :: get_global_edge => mesh_get_global_edge
139 procedure, private, pass(this) :: get_global_facet => mesh_get_global_facet
140 procedure, private, pass(this) :: is_shared_point => mesh_is_shared_point
141 procedure, private, pass(this) :: is_shared_edge => mesh_is_shared_edge
142 procedure, private, pass(this) :: is_shared_facet => mesh_is_shared_facet
143 procedure, pass(this) :: free => mesh_free
144 procedure, pass(this) :: finalize => mesh_finalize
145 procedure, pass(this) :: mark_periodic_facet => mesh_mark_periodic_facet
146 procedure, pass(this) :: mark_labeled_facet => mesh_mark_labeled_facet
147 procedure, pass(this) :: mark_curve_element => mesh_mark_curve_element
148 procedure, pass(this) :: apply_periodic_facet => mesh_apply_periodic_facet
149 procedure, pass(this) :: all_deformed => mesh_all_deformed
150 procedure, pass(this) :: get_facet_ids => mesh_get_facet_ids
151 procedure, pass(this) :: reset_periodic_ids => mesh_reset_periodic_ids
152 procedure, pass(this) :: create_periodic_ids => mesh_create_periodic_ids
153 procedure, pass(this) :: generate_conn => mesh_generate_conn
154 procedure, pass(this) :: have_point_glb_idx => mesh_have_point_glb_idx
155 procedure, pass(this) :: subset_by_mask => mesh_subset_by_mask
156
158 procedure, pass(this) :: check_right_handedness => &
161 generic :: init => init_nelv, init_dist
163 generic :: add_element => add_quad, add_hex
166 generic :: get_local => get_local_point, get_local_edge, get_local_facet
169 generic :: get_global => get_global_edge, get_global_facet
171 generic :: is_shared => is_shared_point, is_shared_edge, is_shared_facet
172 end type mesh_t
173
174 abstract interface
175 subroutine mesh_deform(msh, x, y, z, lx, ly, lz)
176 import mesh_t
177 import rp
178 class(mesh_t) :: msh
179 integer, intent(in) :: lx, ly, lz
180 real(kind=rp), intent(inout) :: x(lx, ly, lz, msh%nelv)
181 real(kind=rp), intent(inout) :: y(lx, ly, lz, msh%nelv)
182 real(kind=rp), intent(inout) :: z(lx, ly, lz, msh%nelv)
183 end subroutine mesh_deform
184 end interface
185
187
188
189contains
190
192 subroutine mesh_init_nelv(this, gdim, nelv)
193 class(mesh_t), intent(inout) :: this
194 integer, intent(in) :: gdim
195 integer, intent(in) :: nelv
196 integer :: ierr
197 character(len=LOG_SIZE) :: log_buf
198
199 call this%free()
200
201 this%nelv = nelv
202 this%gdim = gdim
203
204 if (this%nelv < 1) then
205 write(log_buf, '(A,I0,A)') 'MPI rank ', pe_rank, ' has zero elements'
206 call neko_warning(log_buf)
207 end if
208
209 call mpi_allreduce(this%nelv, this%glb_nelv, 1, &
210 mpi_integer, mpi_sum, neko_comm, ierr)
211
212 this%offset_el = 0
213 call mpi_exscan(this%nelv, this%offset_el, 1, &
214 mpi_integer, mpi_sum, neko_comm, ierr)
215
216 call mesh_init_common(this)
217
218 end subroutine mesh_init_nelv
219
221 subroutine mesh_init_dist(this, gdim, dist)
222 class(mesh_t), intent(inout) :: this
223 integer, intent(in) :: gdim
224 type(linear_dist_t), intent(in) :: dist
225 character(len=LOG_SIZE) :: log_buf
226
227 call this%free()
228
229 this%nelv = dist%num_local()
230 if (this%nelv < 1) then
231 write(log_buf, '(A,I0,A)') 'MPI rank ', pe_rank, ' has zero elements'
232 call neko_warning(log_buf)
233 end if
234 this%glb_nelv = dist%num_global()
235 this%offset_el = dist%start_idx()
236 this%gdim = gdim
237
238 call mesh_init_common(this)
239
240 end subroutine mesh_init_dist
241
242 subroutine mesh_init_common(this)
243 type(mesh_t), intent(inout) :: this
244 integer :: i
245 type(tuple_i4_t) :: facet_data
246
247 this%max_pts_id = 0
248
249 allocate(this%elements(this%nelv))
250 allocate(this%dfrmd_el(this%nelv))
251 if (this%gdim .eq. 3) then
252 do i = 1, this%nelv
253 allocate(hex_t::this%elements(i)%e)
254 end do
255 this%npts = neko_hex_npts
257 if (this%lgenc) then
258 allocate(htable_i4t4_t::this%facet_map)
259 select type (fmp => this%facet_map)
260 type is(htable_i4t4_t)
261 call fmp%init(this%nelv, facet_data)
262 end select
263
264 allocate(this%facet_neigh(neko_hex_nfcs, this%nelv))
265
266 call this%htf%init(this%nelv * neko_hex_nfcs, i)
267 call this%hte%init(this%nelv * neko_hex_neds, i)
268 end if
269 else if (this%gdim .eq. 2) then
270 do i = 1, this%nelv
271 allocate(quad_t::this%elements(i)%e)
272 end do
273 this%npts = neko_quad_npts
274 if (this%lgenc) then
275 allocate(htable_i4t2_t::this%facet_map)
276 select type (fmp => this%facet_map)
277 type is(htable_i4t2_t)
278 call fmp%init(this%nelv, facet_data)
279 end select
280
281 allocate(this%facet_neigh(neko_quad_neds, this%nelv))
282
283 call this%hte%init(this%nelv * neko_quad_neds, i)
284 end if
285 else
286 call neko_error("Invalid dimension")
287 end if
288
290 allocate(this%points(this%npts*this%nelv))
291
294 if (this%lgenc) then
295 ! Temporary workaround to avoid long vacations with Cray Fortran
296 if (allocated(this%point_neigh)) then
297 deallocate(this%point_neigh)
298 end if
299 allocate(this%point_neigh(this%gdim*this%npts*this%nelv))
300 do i = 1, this%gdim*this%npts*this%nelv
301 call this%point_neigh(i)%init(size=4)
302 end do
303 end if
304
305 allocate(this%facet_type(2 * this%gdim, this%nelv))
306 this%facet_type = 0
307
308 call this%htp%init(this%npts*this%nelv, i)
309 call this%htel%init(this%nelv, i)
310
311 call this%periodic%init(this%nelv)
312
313 allocate(this%labeled_zones(neko_msh_max_zlbls))
314 do i = 1, neko_msh_max_zlbls
315 call this%labeled_zones(i)%init(this%nelv)
316 end do
317
318 call this%curve%init(this%nelv)
319
320 call this%ddata%init()
321
322 allocate(this%neigh(0:pe_size-1))
323 this%neigh = .false.
324
325 this%mpts = 0
326 this%mfcs = 0
327 this%meds = 0
328
329 end subroutine mesh_init_common
330
332 subroutine mesh_free(this)
333 class(mesh_t), intent(inout) :: this
334 integer :: i
335
336 call this%htp%free()
337 call this%htf%free()
338 call this%hte%free()
339 call this%htel%free()
340 call this%ddata%free()
341 call this%curve%free()
342
343 if (allocated(this%dfrmd_el)) then
344 deallocate(this%dfrmd_el)
345 end if
346
347 if (allocated(this%elements)) then
348 do i = 1, this%nelv
349 call this%elements(i)%e%free()
350 deallocate(this%elements(i)%e)
351 end do
352 deallocate(this%elements)
353 end if
354
355 if (allocated(this%facet_map)) then
356 select type (fmp => this%facet_map)
357 type is(htable_i4t2_t)
358 call fmp%free()
359 type is(htable_i4t4_t)
360 call fmp%free()
361 end select
362 deallocate(this%facet_map)
363 end if
364
365 if (allocated(this%facet_neigh)) then
366 deallocate(this%facet_neigh)
367 end if
368
369 if (allocated(this%point_neigh)) then
370 do i = 1, this%gdim * this%npts * this%nelv
371 call this%point_neigh(i)%free()
372 end do
373 ! This causes Cray Fortran to take a long vacation
374 !deallocate(this%point_neigh)
375 end if
376
377 if (allocated(this%facet_type)) then
378 deallocate(this%facet_type)
379 end if
380 if (allocated(this%labeled_zones)) then
381 do i = 1, neko_msh_max_zlbls
382 call this%labeled_zones(i)%free()
383 end do
384 deallocate(this%labeled_zones)
385 end if
386
387 if (allocated(this%neigh)) then
388 deallocate(this%neigh)
389 end if
390
391 if (allocated(this%neigh_order)) then
392 deallocate(this%neigh_order)
393 end if
394
395 if (allocated(this%points)) then
396 deallocate(this%points)
397 end if
398
399 call this%periodic%free()
400 this%lconn = .false.
401 this%lnumr = .false.
402 this%ldist = .false.
403 this%lgenc = .true.
404
405 end subroutine mesh_free
406
407 subroutine mesh_finalize(this)
408 class(mesh_t), target, intent(inout) :: this
409 integer :: i
410
411 call mesh_generate_flags(this)
412 call mesh_generate_conn(this)
413
414 call this%periodic%finalize()
415 do i = 1, neko_msh_max_zlbls
416 call this%labeled_zones(i)%finalize()
417 end do
418 call this%curve%finalize()
419
420 ! Due to a bug, right handedness check disabled for the time being.
421 !call this%check_right_handedness()
422
423 end subroutine mesh_finalize
424
425 subroutine mesh_generate_flags(this)
426 type(mesh_t), intent(inout) :: this
427 real(kind=dp) :: u(3), v(3), w(3), temp
428 integer :: e
429
430 do e = 1, this%nelv
431 if (this%gdim .eq. 2) then
432 this%dfrmd_el(e) = .false.
433 u = this%elements(e)%e%pts(2)%p%x - this%elements(e)%e%pts(1)%p%x
434 v = this%elements(e)%e%pts(3)%p%x - this%elements(e)%e%pts(1)%p%x
435 temp = u(1)*v(1) + u(2)*v(2)
436 if(.not. abscmp(temp, 0d0)) this%dfrmd_el(e) = .true.
437 else
438 this%dfrmd_el(e) = .false.
439 u = this%elements(e)%e%pts(2)%p%x - this%elements(e)%e%pts(1)%p%x
440 v = this%elements(e)%e%pts(3)%p%x - this%elements(e)%e%pts(1)%p%x
441 w = this%elements(e)%e%pts(5)%p%x - this%elements(e)%e%pts(1)%p%x
442 temp = u(1)*v(1) + u(2)*v(2) + u(3)*v(3)
443 if(.not. abscmp(temp, 0d0)) this%dfrmd_el(e) = .true.
444 temp = u(1)*w(1) + u(2)*w(2) + u(3)*w(3)
445 if(.not. abscmp(temp, 0d0)) this%dfrmd_el(e) = .true.
446 u = this%elements(e)%e%pts(7)%p%x - this%elements(e)%e%pts(8)%p%x
447 v = this%elements(e)%e%pts(6)%p%x - this%elements(e)%e%pts(8)%p%x
448 w = this%elements(e)%e%pts(4)%p%x - this%elements(e)%e%pts(8)%p%x
449 temp = u(1)*v(1) + u(2)*v(2) + u(3)*v(3)
450 if(.not. abscmp(temp, 0d0)) this%dfrmd_el(e) = .true.
451 temp = u(1)*w(1) + u(2)*w(2) + u(3)*w(3)
452 if(.not. abscmp(temp, 0d0)) this%dfrmd_el(e) = .true.
453 end if
454 end do
455 end subroutine mesh_generate_flags
456
458 subroutine mesh_all_deformed(this)
459 class(mesh_t), intent(inout) :: this
460 this%dfrmd_el = .true.
461 end subroutine mesh_all_deformed
462
464 subroutine mesh_generate_conn(this)
465 class(mesh_t), target, intent(inout) :: this
466 type(tuple_i4_t) :: edge
467 type(tuple4_i4_t) :: face, face_comp
468 type(tuple_i4_t) :: facet_data
469 type(stack_i4_t) :: neigh_order
470 class(element_t), pointer :: ep
471 type(tuple_i4_t) :: e
472 type(tuple4_i4_t) :: f
473 integer :: p_local_idx
474 integer :: el, id
475 integer :: i, j, k, ierr, el_glb_idx, n_sides, n_nodes, src, dst
476
477 if (this%lconn) return
478
479 if (.not. this%lgenc) return
480
481 !If we generate connectivity, we do that here.
482 do el = 1, this%nelv
483 ep => this%elements(el)%e
484 select type(ep)
485 type is (hex_t)
486 do i = 1, neko_hex_npts
487 !Only for getting the id
488 call this%add_point(ep%pts(i)%p, id)
489 p_local_idx = this%get_local(this%points(id))
490 !should stack have inout on what we push? would be neat with in
491 id = ep%id()
492 call this%point_neigh(p_local_idx)%push(id)
493 end do
494 do i = 1, neko_hex_nfcs
495 call ep%facet_id(f, i)
496 call this%add_face(f)
497 end do
498
499 do i = 1, neko_hex_neds
500 call ep%edge_id(e, i)
501 call this%add_edge(e)
502 end do
503 type is (quad_t)
504 do i = 1, neko_quad_npts
505 !Only for getting the id
506 call this%add_point(ep%pts(i)%p, id)
507 p_local_idx = this%get_local(this%points(id))
508 !should stack have inout on what we push? would be neat with in
509 id = ep%id()
510 call this%point_neigh(p_local_idx)%push(id)
511 end do
512
513 do i = 1, neko_quad_neds
514 call ep%facet_id(e, i)
515 call this%add_edge(e)
516 end do
517 end select
518 end do
519
520
521 if (this%gdim .eq. 2) then
522 n_sides = 4
523 n_nodes = 2
524 else
525 n_sides = 6
526 n_nodes = 4
527 end if
528
529 ! Compute global number of unique points
530 call mpi_allreduce(this%max_pts_id, this%glb_mpts, 1, &
531 mpi_integer, mpi_max, neko_comm, ierr)
532
533 !
534 ! Find all (local) boundaries
535 !
536
540 select type (fmp => this%facet_map)
541 type is(htable_i4t2_t)
542 do k = 1, 2
543 do i = 1, this%nelv
544 el_glb_idx = i + this%offset_el
545 do j = 1, n_sides
546 call this%elements(i)%e%facet_id(edge, j)
547
548 ! Assume that all facets are on the exterior
549 facet_data%x = [0, 0]
550
551 !check it this face has shown up earlier
552 if (fmp%get(edge, facet_data) .eq. 0) then
553 !if element is already recognized on face
554 if (facet_data%x(1) .eq. el_glb_idx ) then
555 this%facet_neigh(j, i) = facet_data%x(2)
556 else if( facet_data%x(2) .eq. el_glb_idx) then
557 this%facet_neigh(j, i) = facet_data%x(1)
558 !if this is the second element, arrange so low id is first
559 else if(facet_data%x(1) .gt. el_glb_idx) then
560 facet_data%x(2) = facet_data%x(1)
561 facet_data%x(1) = el_glb_idx
562 this%facet_neigh(j, i) = facet_data%x(2)
563 call fmp%set(edge, facet_data)
564 else if(facet_data%x(1) .lt. el_glb_idx) then
565 facet_data%x(2) = el_glb_idx
566 this%facet_neigh(j, i) = facet_data%x(1)
567 call fmp%set(edge, facet_data)
568 end if
569 else
570 facet_data%x(1) = el_glb_idx
571 this%facet_neigh(j, i) = facet_data%x(2)
572 call fmp%set(edge, facet_data)
573 end if
574 end do
575 end do
576 end do
577 type is(htable_i4t4_t)
578
579 do k = 1, 2
580 do i = 1, this%nelv
581 el_glb_idx = i + this%offset_el
582 do j = 1, n_sides
583 call this%elements(i)%e%facet_id(face, j)
584
585 facet_data%x = (/ 0, 0/)
586
587 !check it this face has shown up earlier
588 if (fmp%get(face, facet_data) .eq. 0) then
589 !if element is already recognized on face
590 if (facet_data%x(1) .eq. el_glb_idx ) then
591 this%facet_neigh(j, i) = facet_data%x(2)
592 call this%elements(i)%e%facet_id(face_comp, &
593 j + (2*mod(j, 2) - 1))
594 if (face_comp .eq. face) then
595 facet_data%x(2) = el_glb_idx
596 this%facet_neigh(j, i) = facet_data%x(1)
597 call fmp%set(face, facet_data)
598 end if
599 else if( facet_data%x(2) .eq. el_glb_idx) then
600 this%facet_neigh(j, i) = facet_data%x(1)
601 !if this is the second element, arrange so low id is first
602 else if(facet_data%x(1) .gt. el_glb_idx) then
603 facet_data%x(2) = facet_data%x(1)
604 facet_data%x(1) = el_glb_idx
605 this%facet_neigh(j, i) = facet_data%x(2)
606 call fmp%set(face, facet_data)
607 else if(facet_data%x(1) .lt. el_glb_idx) then
608 facet_data%x(2) = el_glb_idx
609 this%facet_neigh(j, i) = facet_data%x(1)
610 call fmp%set(face, facet_data)
611 end if
612 else
613 facet_data%x(1) = el_glb_idx
614 this%facet_neigh(j, i) = 0
615 call fmp%set(face, facet_data)
616 end if
617 end do
618 end do
619 end do
620 class default
621 call neko_error('Invalid facet map')
622 end select
623
624
625 !
626 ! Find all external (between PEs) boundaries
627 !
628 if (pe_size .gt. 1) then
629
631
632 !
633 ! Generate neighbour exchange order
634 !
635 call neigh_order%init(pe_size)
636
637 do i = 1, pe_size - 1
638 src = modulo(pe_rank - i + pe_size, pe_size)
639 dst = modulo(pe_rank + i, pe_size)
640 if (this%neigh(src) .or. this%neigh(dst)) then
641 j = i ! adhere to standards...
642 call neigh_order%push(j)
643 end if
644 end do
645
646 allocate(this%neigh_order(neigh_order%size()))
647 select type(order => neigh_order%data)
648 type is (integer)
649 do i = 1, neigh_order%size()
650 this%neigh_order(i) = order(i)
651 end do
652 end select
653 call neigh_order%free()
654
656 else
657 allocate(this%neigh_order(1))
658 this%neigh_order = 1
659 end if
660
661 !
662 ! Find all internal/extenral edge connections
663 ! (Note it needs to be called after external point connections has
664 ! been established)
665 !
666 if (this%gdim .eq. 3) then
667 call mesh_generate_edge_conn(this)
668 end if
669
670
672
673 this%lconn = .true.
674
675 end subroutine mesh_generate_conn
676
679 type(mesh_t), intent(inout) :: this
680 type(tuple_i4_t) :: edge, edge2
681 type(tuple4_i4_t) :: face, face2
682 type(tuple_i4_t) :: facet_data
683 type(stack_i4_t) :: buffer
684 type(mpi_status) :: status
685 type(mpi_request) :: send_req, recv_req
686 integer, allocatable :: recv_buffer(:)
687 integer :: i, j, k, el_glb_idx, n_sides, n_nodes, facet, element, l
688 integer :: max_recv, ierr, src, dst, n_recv, recv_side, neigh_el
689
690
691 if (this%gdim .eq. 2) then
692 n_sides = 4
693 n_nodes = 2
694 else
695 n_sides = 6
696 n_nodes = 4
697 end if
698
699 call buffer%init()
700
701 ! Build send buffers containing
702 ! [el_glb_idx, side number, facet_id (global ids of points)]
703 do i = 1, this%nelv
704 el_glb_idx = i + this%offset_el
705 do j = 1, n_sides
706 facet = j ! Adhere to standards...
707 if (this%facet_neigh(j, i) .eq. 0) then
708 if (n_nodes .eq. 2) then
709 call this%elements(i)%e%facet_id(edge, j)
710 call buffer%push(el_glb_idx)
711 call buffer%push(facet)
712 do k = 1, n_nodes
713 call buffer%push(edge%x(k))
714 end do
715 else
716 call this%elements(i)%e%facet_id(face, j)
717 call buffer%push(el_glb_idx)
718 call buffer%push(facet)
719 do k = 1, n_nodes
720 call buffer%push(face%x(k))
721 end do
722 end if
723 end if
724 end do
725 end do
726
727
728 call mpi_allreduce(buffer%size(), max_recv, 1, &
729 mpi_integer, mpi_max, neko_comm, ierr)
730
731 allocate(recv_buffer(max_recv))
732
733 do i = 1, size(this%neigh_order)
734 src = modulo(pe_rank - this%neigh_order(i) + pe_size, pe_size)
735 dst = modulo(pe_rank + this%neigh_order(i), pe_size)
736
737 if (this%neigh(src)) then
738 call mpi_irecv(recv_buffer, max_recv, mpi_integer, &
739 src, 0, neko_comm, recv_req, ierr)
740 end if
741
742 if (this%neigh(dst)) then
743 ! Synchronous send so the buffer is never eager-buffered as an
744 ! unexpected message, which exhausts the MPI internal buffer pool
745 ! (SIGBUS) under flat MPI at high rank counts. Deadlock-safe: the
746 ! matching recv is pre-posted at the top of the peer's iteration.
747 call mpi_issend(buffer%array(), buffer%size(), mpi_integer, &
748 dst, 0, neko_comm, send_req, ierr)
749 end if
750
751 if (this%neigh(src)) then
752 call mpi_wait(recv_req, status, ierr)
753 call mpi_get_count(status, mpi_integer, n_recv, ierr)
754
755 select type (fmp => this%facet_map)
756 type is(htable_i4t2_t)
757 do j = 1, n_recv, n_nodes + 2
758 neigh_el = recv_buffer(j)
759 recv_side = recv_buffer(j+1)
760
761 edge = (/ recv_buffer(j+2), recv_buffer(j+3) /)
762
763 facet_data = (/ 0, 0 /)
764 !Check if the face is present on this PE
765 if (fmp%get(edge, facet_data) .eq. 0) then
766 element = facet_data%x(1) - this%offset_el
767 !Check which side is connected
768 do l = 1, n_sides
769 call this%elements(element)%e%facet_id(edge2, l)
770 if(edge2 .eq. edge) then
771 facet = l
772 exit
773 end if
774 end do
775 this%facet_neigh(facet, element) = -neigh_el
776 facet_data%x(2) = -neigh_el
777
778 ! Update facet map
779 call fmp%set(edge, facet_data)
780
781 call this%ddata%set_shared_el_facet(element, facet)
782
783 if (this%hte%get(edge, facet) .eq. 0) then
784 call this%ddata%set_shared_facet(facet)
785 else
786 call neko_error("Invalid shared edge")
787 end if
788
789 end if
790
791 end do
792 type is(htable_i4t4_t)
793 do j = 1, n_recv, n_nodes + 2
794 neigh_el = recv_buffer(j)
795 recv_side = recv_buffer(j+1)
796
797 face%x = (/ recv_buffer(j+2), recv_buffer(j+3), &
798 recv_buffer(j+4), recv_buffer(j+5) /)
799
800
801 facet_data%x = (/ 0, 0 /)
802
803 !Check if the face is present on this PE
804 if (fmp%get(face, facet_data) .eq. 0) then
805 ! Determine opposite side and update neighbor
806 element = facet_data%x(1) - this%offset_el
807 do l = 1, 6
808 call this%elements(element)%e%facet_id(face2, l)
809 if(face2 .eq. face) then
810 facet = l
811 exit
812 end if
813 end do
814 this%facet_neigh(facet, element) = -neigh_el
815 facet_data%x(2) = -neigh_el
816
817 ! Update facet map
818 call fmp%set(face, facet_data)
819
820 call this%ddata%set_shared_el_facet(element, facet)
821
822 if (this%htf%get(face, facet) .eq. 0) then
823 call this%ddata%set_shared_facet(facet)
824 else
825 call neko_error("Invalid shared face")
826 end if
827
828
829 end if
830
831 end do
832 end select
833 end if
834
835 if (this%neigh(dst)) then
836 call mpi_wait(send_req, mpi_status_ignore, ierr)
837 end if
838
839 end do
840
841
842 deallocate(recv_buffer)
843
844 call buffer%free()
845
847
857 type(mesh_t), intent(inout) :: this
858 type(stack_i8_t) :: cr_buf
859 integer(i8), allocatable :: buf(:), body(:)
860 integer(i8), pointer :: cr_data(:)
861 integer, allocatable :: gkey(:), gperm(:), rpos(:)
862 integer, contiguous, pointer :: neighs(:)
863 integer :: i, j, k, n, p, owner, num_neigh, nrec, rlen
864 integer :: pt_glb_idx, pt_loc_idx, src_rank, neigh_el, rk, rp
865
866 !
867 ! Phase 1: route every local point's element list to its canonical owner.
868 ! record payload = [glb_idx, origin, elems...]
869 !
870 call cr_buf%init(this%mpts * 4)
871 allocate(body(8))
872 do i = 1, this%mpts
873 pt_glb_idx = this%points(i)%id() ! Adhere to standards...
874 num_neigh = this%point_neigh(i)%size()
875 if (2 + num_neigh .gt. size(body)) then
876 deallocate(body)
877 allocate(body(2 + num_neigh))
878 end if
879 body(1) = int(pt_glb_idx, i8) ! glb_idx
880 body(2) = int(pe_rank, i8) ! origin
881 neighs => this%point_neigh(i)%array()
882 do j = 1, num_neigh
883 body(2 + j) = int(neighs(j), i8) ! element ids
884 end do
885 owner = modulo(pt_glb_idx, pe_size)
886 call crystal_router_pack(cr_buf, owner, body(1:2 + num_neigh))
887 end do
888 deallocate(body)
889
890 n = cr_buf%size()
891 allocate(buf(max(n, 1)))
892 if (n .gt. 0) then
893 cr_data => cr_buf%array()
894 buf(1:n) = cr_data(1:n)
895 end if
896 call cr_buf%free()
897
898 call crystal_router_transfer(buf, n)
899
900 !
901 ! Phase 2: at the owner, group received records by glb_idx and reflect,
902 ! to each holder, the element lists of every *other* holder.
903 ! reply = [dest=holder, len=2+num_neigh, glb_idx, src_rank, elems...]
904 !
905 ! Index the received records and sort their keys (glb_idx) so equal keys
906 ! form contiguous runs; per-point holder counts are small, so the
907 ! all-pairs reflection within a run is cheap.
908 nrec = 0
909 p = 1
910 do while (p .le. n)
911 nrec = nrec + 1
912 p = p + 2 + int(buf(p + 1))
913 end do
914
915 allocate(gkey(max(nrec, 1)), gperm(max(nrec, 1)), rpos(max(nrec, 1)))
916 nrec = 0
917 p = 1
918 do while (p .le. n)
919 nrec = nrec + 1
920 rpos(nrec) = p ! record start offset in buf
921 gkey(nrec) = int(buf(p + 2)) ! glb_idx
922 p = p + 2 + int(buf(p + 1))
923 end do
924 if (nrec .gt. 0) call sort(gkey, gperm, nrec)
925
926 call cr_buf%init(max(n, 1))
927 i = 1
928 do while (i .le. nrec)
929 ! [i, j) is the run of records sharing the same glb_idx
930 j = i
931 do while (j .le. nrec)
932 if (gkey(j) .ne. gkey(i)) exit
933 j = j + 1
934 end do
935 ! All-pairs reflection within the run (skip singletons = unshared):
936 ! send source holder p's record body (glb_idx, origin, elems) to
937 ! recipient holder k, addressed to k's origin rank.
938 if (j - i .gt. 1) then
939 do k = i, j - 1 ! recipient holder
940 rk = rpos(gperm(k))
941 do p = i, j - 1 ! source holder
942 if (p .eq. k) cycle
943 rp = rpos(gperm(p))
944 call crystal_router_pack(cr_buf, int(buf(rk + 3)), &
945 buf(rp + 2 : rp + 1 + int(buf(rp + 1))))
946 end do
947 end do
948 end if
949 i = j
950 end do
951 deallocate(gkey, gperm, rpos)
952
953 n = cr_buf%size()
954 if (allocated(buf)) deallocate(buf)
955 allocate(buf(max(n, 1)))
956 if (n .gt. 0) then
957 cr_data => cr_buf%array()
958 buf(1:n) = cr_data(1:n)
959 end if
960 call cr_buf%free()
961
962 call crystal_router_transfer(buf, n)
963
964 !
965 ! Phase 3: finalise locally. Each reply names a remote holder of one of our
966 ! points; mark it as a neighbour and absorb its (remote) element list.
967 !
968 p = 1
969 do while (p .le. n)
970 rlen = int(buf(p + 1))
971 pt_glb_idx = int(buf(p + 2))
972 src_rank = int(buf(p + 3))
973 pt_loc_idx = this%have_point_glb_idx(pt_glb_idx)
974 if (pt_loc_idx .gt. 0) then
975 this%neigh(src_rank) = .true.
976 call this%ddata%set_shared_point(pt_loc_idx)
977 do k = 1, rlen - 2
978 neigh_el = -int(buf(p + 3 + k))
979 call this%point_neigh(pt_loc_idx)%push(neigh_el)
980 end do
981 end if
982 p = p + 2 + rlen
983 end do
984
985 if (allocated(buf)) deallocate(buf)
986
988
992 subroutine mesh_generate_edge_conn(this)
993 type(mesh_t), target, intent(inout) :: this
994 type(htable_iter_i4t2_t) :: it
995 type(tuple_i4_t), pointer :: edge
996 type(uset_i8_t), target :: edge_idx, ghost, owner
997 type(stack_i8_t), target :: send_buff
998 type(htable_i8_t) :: glb_to_loc
999 type(mpi_status) :: status
1000 type(mpi_request) :: send_req, recv_req
1001 integer, contiguous, pointer :: p1(:), p2(:), ns_id(:)
1002 integer :: i, j, id, ierr, num_edge_glb, edge_offset, num_edge_loc
1003 integer :: k, l , shared_offset, glb_nshared, n_glb_id
1004 integer(kind=i8) :: C, glb_max, glb_id
1005 integer(kind=i8), pointer :: glb_ptr
1006 integer(kind=i8), allocatable :: recv_buff(:)
1007 logical :: shared_edge
1008 type(stack_i4_t), target :: non_shared_edges
1009 integer :: max_recv, src, dst, n_recv
1010
1011
1013 allocate(this%ddata%local_to_global_edge(this%meds))
1014
1015 call edge_idx%init(this%hte%num_entries())
1016 call send_buff%init(this%hte%num_entries())
1017 call owner%init(this%hte%num_entries())
1018
1019 call glb_to_loc%init(32, i)
1020
1021 !
1022 ! Determine/ constants used to generate unique global edge numbers
1023 ! for shared edges
1024 !
1025 c = int(this%glb_nelv, i8) * int(neko_hex_neds, i8)
1026
1027 num_edge_glb = 2* this%meds
1028 call mpi_allreduce(mpi_in_place, num_edge_glb, 1, &
1029 mpi_integer, mpi_sum, neko_comm, ierr)
1030
1031 glb_max = int(num_edge_glb, i8)
1032
1033 call non_shared_edges%init(this%hte%num_entries())
1034
1035 call it%init(this%hte)
1036 do while(it%next())
1037 edge => it%key()
1038 call it%data(id)
1039
1040 k = this%have_point_glb_idx(edge%x(1))
1041 l = this%have_point_glb_idx(edge%x(2))
1042 p1 => this%point_neigh(k)%array()
1043 p2 => this%point_neigh(l)%array()
1044
1045 shared_edge = .false.
1046
1047 ! Find edge neighbor from point neighbors
1048 do i = 1, this%point_neigh(k)%size()
1049 do j = 1, this%point_neigh(l)%size()
1050 if ((p1(i) .eq. p2(j)) .and. &
1051 (p1(i) .lt. 0) .and. (p2(j) .lt. 0)) then
1052 call this%ddata%set_shared_edge(id)
1053 shared_edge = .true.
1054 end if
1055 end do
1056 end do
1057
1058 ! Generate a unique id for the shared edge as,
1059 ! ((e1 * C) + e2 )) + glb_max if e1 > e2
1060 ! ((e2 * C) + e1 )) + glb_max if e2 > e1
1061 if (shared_edge) then
1062 glb_id = ((int(edge%x(1), i8)) + int(edge%x(2), i8)*c) + glb_max
1063 call glb_to_loc%set(glb_id, id)
1064 call edge_idx%add(glb_id)
1065 call owner%add(glb_id) ! Always assume the PE is the owner
1066 call send_buff%push(glb_id)
1067 else
1068 call non_shared_edges%push(id)
1069 end if
1070 end do
1071
1072 ! Determine start offset for global numbering of locally owned edges
1073 edge_offset = 0
1074 num_edge_loc = non_shared_edges%size()
1075 call mpi_exscan(num_edge_loc, edge_offset, 1, &
1076 mpi_integer, mpi_sum, neko_comm, ierr)
1077 edge_offset = edge_offset + 1
1078
1079 ! Construct global numbering of locally owned edges
1080 ns_id => non_shared_edges%array()
1081 do i = 1, non_shared_edges%size()
1082 call this%ddata%set_local_to_global_edge(ns_id(i), edge_offset)
1083 edge_offset = edge_offset + 1
1084 end do
1085 nullify(ns_id)
1086
1087 !
1088 ! Renumber shared edges into integer range
1089 !
1090
1091 call mpi_allreduce(send_buff%size(), max_recv, 1, &
1092 mpi_integer, mpi_max, neko_comm, ierr)
1093
1094 call ghost%init(send_buff%size())
1095
1096 allocate(recv_buff(max_recv))
1097
1098 do i = 1, size(this%neigh_order)
1099 src = modulo(pe_rank - this%neigh_order(i) + pe_size, pe_size)
1100 dst = modulo(pe_rank + this%neigh_order(i), pe_size)
1101
1102 if (this%neigh(src)) then
1103 call mpi_irecv(recv_buff, max_recv, mpi_integer8, &
1104 src, 0, neko_comm, recv_req, ierr)
1105 end if
1106
1107 if (this%neigh(dst)) then
1108 ! We should use the %array() procedure, which works great for
1109 ! GNU, Intel and NEC, but it breaks horribly on Cray when using
1110 ! certain data types
1111 select type(sbarray=>send_buff%data)
1112 type is (integer(i8))
1113 ! Synchronous send to avoid eager-buffering the key list as an
1114 ! unexpected message (FJMPI buffer-pool exhaustion / SIGBUS under
1115 ! flat MPI); matching recv is pre-posted by the peer.
1116 call mpi_issend(sbarray, send_buff%size(), mpi_integer8, &
1117 dst, 0, neko_comm, send_req, ierr)
1118 end select
1119 end if
1120
1121 if (this%neigh(src)) then
1122 call mpi_wait(recv_req, status, ierr)
1123 call mpi_get_count(status, mpi_integer8, n_recv, ierr)
1124
1125 do j = 1, n_recv
1126 if ((edge_idx%element(recv_buff(j))) .and. (src .lt. pe_rank)) then
1127 call ghost%add(recv_buff(j))
1128 call owner%remove(recv_buff(j))
1129 end if
1130 end do
1131 end if
1132
1133 if (this%neigh(dst)) then
1134 call mpi_wait(send_req, mpi_status_ignore, ierr)
1135 end if
1136 end do
1137
1138
1139 ! Determine start offset for global numbering of shared edges
1140 glb_nshared = num_edge_loc
1141 call mpi_allreduce(mpi_in_place, glb_nshared, 1, &
1142 mpi_integer, mpi_sum, neko_comm, ierr)
1143
1144 shared_offset = 0
1145 call mpi_exscan(owner%size(), shared_offset, 1, &
1146 mpi_integer, mpi_sum, neko_comm, ierr)
1147 shared_offset = shared_offset + glb_nshared + 1
1148
1149 ! Renumber locally owned set of shared edges
1150 call send_buff%clear()
1151 call owner%iter_init()
1152 do while (owner%iter_next())
1153 glb_ptr => owner%iter_value()
1154 if (glb_to_loc%get(glb_ptr, id) .eq. 0) then
1155 call this%ddata%set_local_to_global_edge(id, shared_offset)
1156
1157 ! Add new number to send data as [old_glb_id new_glb_id] for each edge
1158 call send_buff%push(glb_ptr) ! Old glb_id integer*8
1159 glb_id = int(shared_offset, i8) ! Waste some space here...
1160 call send_buff%push(glb_id) ! New glb_id integer*4
1161
1162 shared_offset = shared_offset + 1
1163 else
1164 call neko_error('Invalid edge id')
1165 end if
1166 end do
1167 nullify(glb_ptr)
1168
1169 ! Determine total number of unique edges in the mesh
1170 ! (This can probably be done in a clever way...)
1171 this%glb_meds = shared_offset -1
1172 call mpi_allreduce(mpi_in_place, this%glb_meds, 1, &
1173 mpi_integer, mpi_max, neko_comm, ierr)
1174
1175 !
1176 ! Update ghosted edges with new global id
1177 !
1178
1179 call mpi_allreduce(send_buff%size(), max_recv, 1, &
1180 mpi_integer, mpi_max, neko_comm, ierr)
1181
1182 deallocate(recv_buff)
1183 allocate(recv_buff(max_recv))
1184
1185
1186 do i = 1, size(this%neigh_order)
1187 src = modulo(pe_rank - this%neigh_order(i) + pe_size, pe_size)
1188 dst = modulo(pe_rank + this%neigh_order(i), pe_size)
1189
1190 if (this%neigh(src)) then
1191 call mpi_irecv(recv_buff, max_recv, mpi_integer8, &
1192 src, 0, neko_comm, recv_req, ierr)
1193 end if
1194
1195 if (this%neigh(dst)) then
1196 ! We should use the %array() procedure, which works great for
1197 ! GNU, Intel and NEC, but it breaks horribly on Cray when using
1198 ! certain data types
1199 select type(sbarray=>send_buff%data)
1200 type is (integer(i8))
1201 ! Synchronous send to avoid eager-buffering the key list as an
1202 ! unexpected message (FJMPI buffer-pool exhaustion / SIGBUS under
1203 ! flat MPI); matching recv is pre-posted by the peer.
1204 call mpi_issend(sbarray, send_buff%size(), mpi_integer8, &
1205 dst, 0, neko_comm, send_req, ierr)
1206 end select
1207 end if
1208
1209 if (this%neigh(src)) then
1210 call mpi_wait(recv_req, status, ierr)
1211 call mpi_get_count(status, mpi_integer8, n_recv, ierr)
1212
1213 do j = 1, n_recv, 2
1214 if (ghost%element(recv_buff(j))) then
1215 if (glb_to_loc%get(recv_buff(j), id) .eq. 0) then
1216 n_glb_id = int(recv_buff(j + 1 ), 4)
1217 call this%ddata%set_local_to_global_edge(id, n_glb_id)
1218 else
1219 call neko_error('Invalid edge id')
1220 end if
1221 end if
1222 end do
1223 end if
1224
1225 if (this%neigh(dst)) then
1226 call mpi_wait(send_req, mpi_status_ignore, ierr)
1227 end if
1228 end do
1229
1230 deallocate(recv_buff)
1231 call glb_to_loc%free()
1232 call send_buff%free()
1233 call edge_idx%free()
1234 call non_shared_edges%free()
1235 call ghost%free()
1236 call owner%free()
1237
1238 end subroutine mesh_generate_edge_conn
1239
1242 type(mesh_t), target, intent(inout) :: this
1243 type(htable_iter_i4t4_t), target :: face_it
1244 type(htable_iter_i4t2_t), target :: edge_it
1245 type(tuple4_i4_t), pointer :: face, fd(:)
1246 type(tuple_i4_t), pointer :: edge, ed(:)
1247 type(tuple_i4_t) :: facet_data
1248 type(tuple4_i4_t) :: recv_face
1249 type(tuple_i4_t) :: recv_edge
1250 type(stack_i4t4_t) :: face_owner
1251 type(htable_i4t4_t) :: face_ghost
1252 type(stack_i4t2_t) :: edge_owner
1253 type(htable_i4t2_t) :: edge_ghost
1254 type(stack_i4_t) :: send_buff
1255 type(mpi_status) :: status
1256 type(mpi_request) :: send_req, recv_req
1257 integer, allocatable :: recv_buff(:)
1258 integer :: non_shared_facets, shared_facets, facet_offset
1259 integer :: id, glb_nshared, shared_offset, owned_facets
1260 integer :: i, j, ierr, max_recv, src, dst, n_recv
1261
1262 shared_facets = this%ddata%shared_facet%size()
1263
1265 if (this%gdim .eq. 2) then
1266 allocate(this%ddata%local_to_global_facet(this%meds))
1267 call edge_owner%init(this%meds)
1268 call edge_ghost%init(64, i)
1269 non_shared_facets = this%hte%num_entries() - shared_facets
1270 else
1271 allocate(this%ddata%local_to_global_facet(this%mfcs))
1272 call face_owner%init(this%mfcs)
1273 call face_ghost%init(64, i)
1274 non_shared_facets = this%htf%num_entries() - shared_facets
1275 end if
1276
1278
1279 facet_offset = 0
1280 call mpi_exscan(non_shared_facets, facet_offset, 1, &
1281 mpi_integer, mpi_sum, neko_comm, ierr)
1282 facet_offset = facet_offset + 1
1283
1284 ! Determine ownership of shared facets
1285 if (this%gdim .eq. 2) then
1286 call edge_it%init(this%hte)
1287 do while (edge_it%next())
1288 call edge_it%data(id)
1289 edge => edge_it%key()
1290 if (.not. this%ddata%shared_facet%element(id)) then
1291 call this%ddata%set_local_to_global_facet(id, facet_offset)
1292 facet_offset = facet_offset + 1
1293 else
1294 select type(fmp => this%facet_map)
1295 type is(htable_i4t2_t)
1296 if (fmp%get(edge, facet_data) .eq. 0) then
1297 if (facet_data%x(2) .lt. 0) then
1298 if (abs(facet_data%x(2)) .lt. (this%offset_el + 1)) then
1299 call edge_ghost%set(edge, id)
1300 else
1301 call edge_owner%push(edge)
1302 end if
1303 else
1304 call neko_error("Invalid edge neigh.")
1305 end if
1306 end if
1307 end select
1308 end if
1309 end do
1310 owned_facets = edge_owner%size()
1311 else
1312 call face_it%init(this%htf)
1313 do while (face_it%next())
1314 call face_it%data(id)
1315 face => face_it%key()
1316 if (.not. this%ddata%shared_facet%element(id)) then
1317 call this%ddata%set_local_to_global_facet(id, facet_offset)
1318 facet_offset = facet_offset + 1
1319 else
1320 select type(fmp => this%facet_map)
1321 type is(htable_i4t4_t)
1322 if (fmp%get(face, facet_data) .eq. 0) then
1323 if (facet_data%x(2) .lt. 0) then
1324 if (abs(facet_data%x(2)) .lt. (this%offset_el + 1)) then
1325 call face_ghost%set(face, id)
1326 else
1327 call face_owner%push(face)
1328 end if
1329 else
1330 call neko_error("Invalid face neigh.")
1331 end if
1332 end if
1333 end select
1334 end if
1335 end do
1336 owned_facets = face_owner%size()
1337 end if
1338
1339 ! Determine start offset for global numbering of shared facets
1340 glb_nshared = non_shared_facets
1341 call mpi_allreduce(mpi_in_place, glb_nshared, 1, &
1342 mpi_integer, mpi_sum, neko_comm, ierr)
1343
1344 shared_offset = 0
1345 call mpi_exscan(owned_facets, shared_offset, 1, &
1346 mpi_integer, mpi_sum, neko_comm, ierr)
1347 shared_offset = shared_offset + glb_nshared + 1
1348
1349 if (this%gdim .eq. 2) then
1350
1351 if (owned_facets .gt. 32) then
1352 call send_buff%init(owned_facets)
1353 else
1354 call send_buff%init()
1355 end if
1356
1357 ed => edge_owner%array()
1358 do i = 1, edge_owner%size()
1359 if (this%hte%get(ed(i), id) .eq. 0) then
1360 call this%ddata%set_local_to_global_facet(id, shared_offset)
1361
1362 ! Add new number to send buffer
1363 ! [edge id1 ... edge idn new_glb_id]
1364 do j = 1, 2
1365 call send_buff%push(ed(i)%x(j))
1366 end do
1367 call send_buff%push(shared_offset)
1368
1369 shared_offset = shared_offset + 1
1370 end if
1371 end do
1372
1373 else
1374
1375 if (owned_facets .gt. 32) then
1376 call send_buff%init(owned_facets)
1377 else
1378 call send_buff%init()
1379 end if
1380
1381 fd => face_owner%array()
1382 do i = 1, face_owner%size()
1383 if (this%htf%get(fd(i), id) .eq. 0) then
1384 call this%ddata%set_local_to_global_facet(id, shared_offset)
1385
1386 ! Add new number to send buffer
1387 ! [face id1 ... face idn new_glb_id]
1388 do j = 1, 4
1389 call send_buff%push(fd(i)%x(j))
1390 end do
1391 call send_buff%push(shared_offset)
1392
1393 shared_offset = shared_offset + 1
1394 end if
1395 end do
1396 nullify(fd)
1397
1398 end if
1399
1400 ! Determine total number of unique facets in the mesh
1401 ! (This can probably be done in a clever way...)
1402 this%glb_mfcs = shared_offset - 1
1403 call mpi_allreduce(mpi_in_place, this%glb_mfcs, 1, &
1404 mpi_integer, mpi_max, neko_comm, ierr)
1405
1406 !
1407 ! Update ghosted facets with new global id
1408 !
1409
1410 call mpi_allreduce(send_buff%size(), max_recv, 1, &
1411 mpi_integer, mpi_max, neko_comm, ierr)
1412
1413 allocate(recv_buff(max_recv))
1414
1416 do i = 1, size(this%neigh_order)
1417 src = modulo(pe_rank - this%neigh_order(i) + pe_size, pe_size)
1418 dst = modulo(pe_rank + this%neigh_order(i), pe_size)
1419
1420 if (this%neigh(src)) then
1421 call mpi_irecv(recv_buff, max_recv, mpi_integer, &
1422 src, 0, neko_comm, recv_req, ierr)
1423 end if
1424
1425 if (this%neigh(dst)) then
1426 ! Synchronous send to avoid eager-buffered unexpected messages
1427 ! (FJMPI buffer-pool exhaustion / SIGBUS under flat MPI); the
1428 ! matching recv is pre-posted at the top of the peer's iteration.
1429 call mpi_issend(send_buff%array(), send_buff%size(), mpi_integer, &
1430 dst, 0, neko_comm, send_req, ierr)
1431 end if
1432
1433 if (this%neigh(src)) then
1434 call mpi_wait(recv_req, status, ierr)
1435 call mpi_get_count(status, mpi_integer, n_recv, ierr)
1436
1437 if (this%gdim .eq. 2) then
1438 do j = 1, n_recv, 3
1439
1440 recv_edge = (/recv_buff(j), recv_buff(j+1)/)
1441
1442 ! Check if the PE has the shared edge
1443 if (edge_ghost%get(recv_edge, id) .eq. 0) then
1444 call this%ddata%set_local_to_global_facet(id, recv_buff(j+2))
1445 end if
1446 end do
1447 else
1448 do j = 1, n_recv, 5
1449
1450 recv_face = (/recv_buff(j), recv_buff(j+1), &
1451 recv_buff(j+2), recv_buff(j+3) /)
1452
1453 ! Check if the PE has the shared face
1454 if (face_ghost%get(recv_face, id) .eq. 0) then
1455 call this%ddata%set_local_to_global_facet(id, recv_buff(j+4))
1456 end if
1457 end do
1458 end if
1459 end if
1460
1461 if (this%neigh(dst)) then
1462 call mpi_wait(send_req, mpi_status_ignore, ierr)
1463 end if
1464
1465 end do
1466
1467 if (this%gdim .eq. 2) then
1468 call edge_owner%free()
1469 call edge_ghost%free()
1470 else
1471 call face_owner%free()
1472 call face_ghost%free()
1473 end if
1474
1475 call send_buff%free()
1476 deallocate(recv_buff)
1477
1478 end subroutine mesh_generate_facet_numbering
1479
1480
1482 subroutine mesh_add_quad(this, el, el_glb, p1, p2, p3, p4)
1483 class(mesh_t), target, intent(inout) :: this
1484 integer, value :: el, el_glb
1485 type(point_t), target, intent(inout) :: p1, p2, p3, p4
1486 integer :: p(4)
1487 type(tuple_i4_t) :: e
1488
1489 ! Connectivity invalidated if a new element is added
1490 this%lconn = .false.
1491
1492 ! Numbering invalidated if a new element is added
1493 this%lnumr = .false.
1494
1495 call this%add_point(p1, p(1))
1496 call this%add_point(p2, p(2))
1497 call this%add_point(p3, p(3))
1498 call this%add_point(p4, p(4))
1499
1500 select type (ep => this%elements(el)%e)
1501 type is (quad_t)
1502 call ep%init(el_glb, &
1503 this%points(p(1)), this%points(p(2)), &
1504 this%points(p(3)), this%points(p(4)))
1505
1506
1507 class default
1508 call neko_error('Invalid element type')
1509 end select
1510
1511 end subroutine mesh_add_quad
1512
1514 subroutine mesh_add_hex(this, el, el_glb, p1, p2, p3, p4, p5, p6, p7, p8)
1515 class(mesh_t), target, intent(inout) :: this
1516 integer, value :: el, el_glb
1517 type(point_t), target, intent(inout) :: p1, p2, p3, p4, p5, p6, p7, p8
1518 integer :: p(8)
1519 type(tuple4_i4_t) :: f
1520 type(tuple_i4_t) :: e
1521
1522 ! Connectivity invalidated if a new element is added
1523 this%lconn = .false.
1524
1525 ! Numbering invalidated if a new element is added
1526 this%lnumr = .false.
1527
1528 call this%add_point(p1, p(1))
1529 call this%add_point(p2, p(2))
1530 call this%add_point(p3, p(3))
1531 call this%add_point(p4, p(4))
1532 call this%add_point(p5, p(5))
1533 call this%add_point(p6, p(6))
1534 call this%add_point(p7, p(7))
1535 call this%add_point(p8, p(8))
1536
1537 ! Global to local mapping
1538 call this%htel%set(el_glb, el)
1539
1540 select type (ep => this%elements(el)%e)
1541 type is (hex_t)
1542 call ep%init(el_glb, &
1543 this%points(p(1)), this%points(p(2)), &
1544 this%points(p(3)), this%points(p(4)), &
1545 this%points(p(5)), this%points(p(6)), &
1546 this%points(p(7)), this%points(p(8)))
1547 class default
1548 call neko_error('Invalid element type')
1549 end select
1550
1551 end subroutine mesh_add_hex
1552
1554 subroutine mesh_add_point(this, p, idx)
1555 class(mesh_t), intent(inout) :: this
1556 type(point_t), intent(inout) :: p
1557 integer, intent(inout) :: idx
1558 integer :: tmp
1559
1560 tmp = p%id()
1561
1562 this%max_pts_id = max(this%max_pts_id, tmp)
1563
1564 if (tmp .le. 0) then
1565 call neko_error("Invalid point id")
1566 end if
1567
1568 if (this%htp%get(tmp, idx) .gt. 0) then
1569 this%mpts = this%mpts + 1
1570 call this%htp%set(tmp, this%mpts)
1571 this%points(this%mpts) = p
1572 idx = this%mpts
1573 end if
1574
1575 end subroutine mesh_add_point
1576
1578 subroutine mesh_add_face(this, f)
1579 class(mesh_t), intent(inout) :: this
1580 type(tuple4_i4_t), intent(inout) :: f
1581 integer :: idx
1582
1583 if (this%htf%get(f, idx) .gt. 0) then
1584 this%mfcs = this%mfcs + 1
1585 call this%htf%set(f, this%mfcs)
1586 end if
1587
1588 end subroutine mesh_add_face
1589
1591 subroutine mesh_add_edge(this, e)
1592 class(mesh_t), intent(inout) :: this
1593 type(tuple_i4_t), intent(inout) :: e
1594 integer :: idx
1595
1596 if (this%hte%get(e, idx) .gt. 0) then
1597 this%meds = this%meds + 1
1598 call this%hte%set(e, this%meds)
1599 end if
1600
1601 end subroutine mesh_add_edge
1602
1604 subroutine mesh_mark_curve_element(this, e, curve_data, curve_type)
1605 class(mesh_t), intent(inout) :: this
1606 integer, intent(in) :: e
1607 real(kind=dp), dimension(5,12), intent(in) :: curve_data
1608 integer, dimension(12), intent(in) :: curve_type
1609
1610 if (e .gt. this%nelv) then
1611 call neko_error('Invalid element index')
1612 end if
1613 if ((this%gdim .eq. 2 .and. sum(curve_type(5:8)) .gt. 0) ) then
1614 call neko_error('Invalid curve element')
1615 end if
1616 call this%curve%add_element(e, curve_data, curve_type)
1617
1618 end subroutine mesh_mark_curve_element
1619
1621 subroutine mesh_mark_labeled_facet(this, f, e, label)
1622 class(mesh_t), intent(inout) :: this
1623 integer, intent(in) :: f
1624 integer, intent(in) :: e
1625 integer, intent(in) :: label
1626
1627 if (e .gt. this%nelv) then
1628 call neko_error('Invalid element index')
1629 end if
1630
1631 if ((this%gdim .eq. 2 .and. f .gt. 4) .or. &
1632 (this%gdim .eq. 3 .and. f .gt. 6)) then
1633 call neko_error('Invalid facet index')
1634 end if
1635 call this%labeled_zones(label)%add_facet(f, e)
1636 this%facet_type(f,e) = -label
1637
1638 end subroutine mesh_mark_labeled_facet
1639
1641 subroutine mesh_mark_periodic_facet(this, f, e, pf, pe, pids)
1642 class(mesh_t), intent(inout) :: this
1643 integer, intent(in) :: f
1644 integer, intent(in) :: e
1645 integer, intent(in) :: pf
1646 integer, intent(in) :: pe
1647 integer, intent(inout) :: pids(4)
1648 integer, dimension(4) :: org_ids
1649
1650 call this%get_facet_ids(f, e, org_ids)
1651 call this%periodic%add_periodic_facet(f, e, pf, pe, pids, org_ids)
1652 end subroutine mesh_mark_periodic_facet
1653
1655 subroutine mesh_get_facet_ids(this, f, e, pids)
1656 class(mesh_t), intent(inout) :: this
1657 integer, intent(in) :: f
1658 integer, intent(in) :: e
1659 integer, intent(inout) :: pids(4)
1660 type(point_t), pointer :: pi
1661 type(tuple4_i4_t) :: t
1662 type(tuple_i4_t) :: t2
1663
1664 select type(ele => this%elements(e)%e)
1665 type is(hex_t)
1666 call ele%facet_order(t,f)
1667 pids = t%x
1668 type is(quad_t)
1669 call ele%facet_order(t2,f)
1670 pids(1) = t2%x(1)
1671 pids(2) = t2%x(2)
1672 pids(3) = 0
1673 pids(4) = 0
1674 end select
1675 end subroutine mesh_get_facet_ids
1676
1679 class(mesh_t), intent(inout) :: this
1680 integer :: i,j
1681 integer :: f
1682 integer :: e
1683 integer :: pf
1684 integer :: pe
1685 integer :: org_ids(4), pids(4)
1686 type(point_t), pointer :: pi
1687 integer, dimension(4, 6) :: face_nodes = reshape([ &
1688 1,5,7,3, &
1689 2,6,8,4, &
1690 1,2,6,5, &
1691 3,4,8,7, &
1692 1,2,4,3, &
1693 5,6,8,7],&
1694 [4,6])
1695 integer, dimension(2, 4) :: edge_nodes = reshape([ &
1696 1,3, &
1697 2,4, &
1698 1,2, &
1699 3,4],&
1700 [2,4])
1701
1702 do i = 1, this%periodic%size
1703 e = this%periodic%facet_el(i)%x(2)
1704 f = this%periodic%facet_el(i)%x(1)
1705 pe = this%periodic%p_facet_el(i)%x(2)
1706 pf = this%periodic%p_facet_el(i)%x(1)
1707 pids = this%periodic%p_ids(i)%x
1708 call this%get_facet_ids(f, e, pids)
1709 this%periodic%p_ids(i)%x = pids
1710 end do
1711 do i = 1, this%periodic%size
1712 e = this%periodic%facet_el(i)%x(2)
1713 f = this%periodic%facet_el(i)%x(1)
1714 org_ids = this%periodic%org_ids(i)%x
1715 select type(ele => this%elements(e)%e)
1716 type is(hex_t)
1717 do j = 1, 4
1718 pi => ele%pts(face_nodes(j,f))%p
1719 call pi%set_id(org_ids(j))
1720 end do
1721 type is(quad_t)
1722 do j = 1, 2
1723 pi => ele%pts(edge_nodes(j,f))%p
1724 call pi%set_id(org_ids(j))
1725 end do
1726 end select
1727 end do
1728 end subroutine mesh_reset_periodic_ids
1729
1731 subroutine mesh_create_periodic_ids(this, f, e, pf, pe)
1732 class(mesh_t), intent(inout) :: this
1733 integer, intent(in) :: f
1734 integer, intent(in) :: e
1735 integer, intent(in) :: pf
1736 integer, intent(in) :: pe
1737 type(point_t), pointer :: pi, pj
1738 real(kind=dp) :: l(3)
1739 integer :: i, j, id, p_local_idx, match
1740 type(tuple4_i4_t) :: ft
1741 type(tuple_i4_t) :: et
1742 integer :: envvar_len
1743 character(len=255) :: tol_str
1744 real(kind=dp) :: tol
1745 integer, dimension(4, 6) :: face_nodes = reshape([&
1746 1,5,7,3,&
1747 2,6,8,4,&
1748 1,2,6,5,&
1749 3,4,8,7,&
1750 1,2,4,3,&
1751 5,6,8,7],&
1752 [4,6])
1753 integer, dimension(2, 4) :: edge_nodes = reshape([&
1754 1,3,&
1755 2,4,&
1756 1,2,&
1757 3,4 ],&
1758 [2,4])
1759
1760 call get_environment_variable("NEKO_PERIODIC_TOL", tol_str, envvar_len)
1761 if (envvar_len .gt. 0) then
1762 read(tol_str(1:envvar_len), *) tol
1763 else
1764 tol = 1d-7
1765 end if
1766
1767 select type(ele => this%elements(e)%e)
1768 type is(hex_t)
1769 select type(elp => this%elements(pe)%e)
1770 type is(hex_t)
1771 l = 0d0
1772 do i = 1, 4
1773 l = l + ele%pts(face_nodes(i,f))%p%x(1:3) - &
1774 elp%pts(face_nodes(i,pf))%p%x(1:3)
1775 end do
1776 l = l/4
1777 do i = 1, 4
1778 pi => ele%pts(face_nodes(i,f))%p
1779 match = 0
1780 do j = 1, 4
1781 pj => elp%pts(face_nodes(j,pf))%p
1782 if (norm2(pi%x(1:3) - pj%x(1:3) - l) .lt. tol) then
1783 id = min(pi%id(), pj%id())
1784 call pi%set_id(id)
1785 call pj%set_id(id)
1786 p_local_idx = this%get_local(this%points(id))
1787 match = match + 1
1788 end if
1789 end do
1790 if ( match .gt. 1) then
1791 call neko_error('Multiple matches when creating periodic ids')
1792 else if (match .eq. 0) then
1793 call neko_error('Cannot find matching periodic point')
1794 end if
1795 end do
1796 end select
1797 type is(quad_t)
1798 select type(elp => this%elements(pe)%e)
1799 type is(quad_t)
1800 l = 0d0
1801 do i = 1, 2
1802 l = l + ele%pts(edge_nodes(i,f))%p%x(1:3) - &
1803 elp%pts(edge_nodes(i,pf))%p%x(1:3)
1804 end do
1805 l = l/2
1806 do i = 1, 2
1807 pi => ele%pts(edge_nodes(i,f))%p
1808 do j = 1, 2
1809 pj => elp%pts(edge_nodes(j,pf))%p
1810 !whatabout thie tolerance?
1811 if (norm2(pi%x(1:3) - pj%x(1:3) - l) .lt. tol) then
1812 id = min(pi%id(), pj%id())
1813 call pi%set_id(id)
1814 call pj%set_id(id)
1815 p_local_idx = this%get_local(this%points(id))
1816 end if
1817 end do
1818 end do
1819 end select
1820 end select
1821 end subroutine mesh_create_periodic_ids
1822
1825 subroutine mesh_apply_periodic_facet(this, f, e, pf, pe, pids)
1826 class(mesh_t), intent(inout) :: this
1827 integer, intent(in) :: f
1828 integer, intent(in) :: e
1829 integer, intent(in) :: pf
1830 integer, intent(in) :: pe
1831 integer, intent(inout) :: pids(4)
1832 type(point_t), pointer :: pi
1833 integer :: i, id, p_local_idx
1834 type(tuple4_i4_t) :: ft
1835 type(tuple_i4_t) :: et
1836 integer, dimension(4, 6) :: face_nodes = reshape([&
1837 1,5,7,3,&
1838 2,6,8,4,&
1839 1,2,6,5,&
1840 3,4,8,7,&
1841 1,2,4,3,&
1842 5,6,8,7],&
1843 [4,6])
1844 select type(ele => this%elements(e)%e)
1845 type is(hex_t)
1846 do i = 1, 4
1847 pi => ele%pts(face_nodes(i,f))%p
1848 call pi%set_id(pids(i))
1849 call this%add_point(pi, id)
1850 p_local_idx = this%get_local(this%points(id))
1851 end do
1852 end select
1853
1854 end subroutine mesh_apply_periodic_facet
1855
1857 function mesh_get_local_point(this, p) result(local_id)
1858 class(mesh_t), intent(inout) :: this
1859 type(point_t), intent(inout) :: p
1860 integer :: local_id
1861 integer :: tmp
1862
1864 tmp = p%id()
1865
1866 if (this%htp%get(tmp, local_id) .gt. 0) then
1867 call neko_error('Invalid global id (local point)')
1868 end if
1869
1870 end function mesh_get_local_point
1871
1874 function mesh_get_local_edge(this, e) result(local_id)
1875 class(mesh_t), intent(inout) :: this
1876 type(tuple_i4_t), intent(inout) :: e
1877 integer :: local_id
1878
1879 if (this%hte%get(e, local_id) .gt. 0) then
1880 call neko_error('Invalid global id (local edge)')
1881 end if
1882
1883 end function mesh_get_local_edge
1884
1886 function mesh_get_local_facet(this, f) result(local_id)
1887 class(mesh_t), intent(inout) :: this
1888 type(tuple4_i4_t), intent(inout) :: f
1889 integer :: local_id
1890
1891 if (this%htf%get(f, local_id) .gt. 0) then
1892 call neko_error('Invalid global id (local facet)')
1893 end if
1894
1895 end function mesh_get_local_facet
1896
1898 function mesh_get_global_edge(this, e) result(global_id)
1899 class(mesh_t), intent(inout) :: this
1900 type(tuple_i4_t), intent(inout) :: e
1901 integer :: global_id
1902
1903 global_id = this%get_local(e)
1904
1905 if (this%gdim .eq. 2) then
1906 if (pe_size .gt. 1) then
1907 global_id = this%ddata%local_to_global_facet(global_id)
1908 end if
1909 else
1910 if (pe_size .gt. 1) then
1911 global_id = this%ddata%local_to_global_edge(global_id)
1912 end if
1913 end if
1914
1915 end function mesh_get_global_edge
1916
1918 function mesh_get_global_facet(this, f) result(global_id)
1919 class(mesh_t), intent(inout) :: this
1920 type(tuple4_i4_t), intent(inout) :: f
1921 integer :: global_id
1922
1923 global_id = this%get_local_facet(f)
1924
1925 if (pe_size .gt. 1) then
1926 global_id = this%ddata%local_to_global_facet(global_id)
1927 end if
1928
1929 end function mesh_get_global_facet
1930
1931
1935 function mesh_have_point_glb_idx(this, index) result(local_id)
1936 class(mesh_t), intent(inout) :: this
1937 integer, intent(inout) :: index
1938 integer :: local_id
1939
1940 if (this%htp%get(index, local_id) .eq. 1) then
1941 local_id = -1
1942 end if
1943
1944 end function mesh_have_point_glb_idx
1945
1946
1948 function mesh_is_shared_point(this, p) result(shared)
1949 class(mesh_t), intent(inout) :: this
1950 type(point_t), intent(inout) :: p
1951 integer :: local_index
1952 logical shared
1953
1954 local_index = this%get_local(p)
1955 shared = this%ddata%shared_point%element(local_index)
1956
1957 end function mesh_is_shared_point
1958
1959
1962 function mesh_is_shared_edge(this, e) result(shared)
1963 class(mesh_t), intent(inout) :: this
1964 type(tuple_i4_t), intent(inout) :: e
1965 integer :: local_index
1966 logical shared
1967 local_index = this%get_local(e)
1968 if (this%gdim .eq. 2) then
1969 shared = this%ddata%shared_facet%element(local_index)
1970 else
1971 shared = this%ddata%shared_edge%element(local_index)
1972 end if
1973 end function mesh_is_shared_edge
1974
1976 function mesh_is_shared_facet(this, f) result(shared)
1977 class(mesh_t), intent(inout) :: this
1978 type(tuple4_i4_t), intent(inout) :: f
1979 integer :: local_index
1980 logical shared
1981
1982 local_index = this%get_local(f)
1983 shared = this%ddata%shared_facet%element(local_index)
1984
1985 end function mesh_is_shared_facet
1986
1990 class(mesh_t), intent(inout) :: this
1991 integer :: i
1992 real(kind=rp) :: v(8)
1993 type(point_t) :: centroid
1994 logical :: fail
1995
1996 fail = .false.
1997
1998 if (this%gdim .eq. 3) then
1999 do i = 1, this%nelv
2001 this%elements(i)%e%pts(2)%p%x, &
2002 this%elements(i)%e%pts(3)%p%x, &
2003 this%elements(i)%e%pts(5)%p%x, &
2004 this%elements(i)%e%pts(1)%p%x &
2005 )
2006
2008 this%elements(i)%e%pts(4)%p%x, &
2009 this%elements(i)%e%pts(1)%p%x, &
2010 this%elements(i)%e%pts(6)%p%x, &
2011 this%elements(i)%e%pts(2)%p%x &
2012 )
2013
2015 this%elements(i)%e%pts(1)%p%x, &
2016 this%elements(i)%e%pts(4)%p%x, &
2017 this%elements(i)%e%pts(7)%p%x, &
2018 this%elements(i)%e%pts(3)%p%x &
2019 )
2020
2022 this%elements(i)%e%pts(3)%p%x, &
2023 this%elements(i)%e%pts(2)%p%x, &
2024 this%elements(i)%e%pts(8)%p%x, &
2025 this%elements(i)%e%pts(4)%p%x &
2026 )
2027
2029 this%elements(i)%e%pts(6)%p%x, &
2030 this%elements(i)%e%pts(7)%p%x, &
2031 this%elements(i)%e%pts(1)%p%x, &
2032 this%elements(i)%e%pts(5)%p%x &
2033 )
2034
2036 this%elements(i)%e%pts(8)%p%x, &
2037 this%elements(i)%e%pts(5)%p%x, &
2038 this%elements(i)%e%pts(2)%p%x, &
2039 this%elements(i)%e%pts(6)%p%x &
2040 )
2041
2043 this%elements(i)%e%pts(5)%p%x, &
2044 this%elements(i)%e%pts(8)%p%x, &
2045 this%elements(i)%e%pts(3)%p%x, &
2046 this%elements(i)%e%pts(7)%p%x &
2047 )
2048
2050 this%elements(i)%e%pts(7)%p%x, &
2051 this%elements(i)%e%pts(6)%p%x, &
2052 this%elements(i)%e%pts(4)%p%x, &
2053 this%elements(i)%e%pts(8)%p%x &
2054 )
2055
2056 if (v(1) .le. 0.0_rp .or. &
2057 v(2) .le. 0.0_rp .or. &
2058 v(3) .le. 0.0_rp .or. &
2059 v(4) .le. 0.0_rp .or. &
2060 v(5) .le. 0.0_rp .or. &
2061 v(6) .le. 0.0_rp .or. &
2062 v(7) .le. 0.0_rp .or. &
2063 v(8) .le. 0.0_rp ) then
2064
2065 centroid = this%elements(i)%e%centroid()
2066
2067 write(error_unit, '(A, A, I0, A, 3G12.5)') "*** ERROR ***: ", &
2068 "Wrong orientation of mesh element ", i, &
2069 " with centroid ", centroid%x
2070
2071 fail = .true.
2072 end if
2073 end do
2074 end if
2075
2076 if (fail) then
2077 call neko_error("Some mesh elements are not right-handed")
2078 end if
2079 end subroutine mesh_check_right_handedness
2080
2089 function parallelepiped_signed_volume(p1, p2, p3, origin) result(v)
2090 real(kind=dp), dimension(3), intent(in) :: p1, p2, p3, origin
2091 real(kind=dp) :: v
2092 real(kind=dp) :: vp1(3), vp2(3), vp3(3), cross(3)
2093
2094 vp1 = p1 - origin
2095 vp2 = p2 - origin
2096 vp3 = p3 - origin
2097
2098 cross(1) = vp1(2)*vp2(3) - vp2(3)*vp1(2)
2099 cross(2) = vp1(3)*vp2(1) - vp1(1)*vp2(3)
2100 cross(3) = vp1(1)*vp2(2) - vp1(2)*vp2(1)
2101
2102 v = cross(1)*vp3(1) + cross(2)*vp3(2) + cross(3)*vp3(3)
2103
2104 end function parallelepiped_signed_volume
2105
2115 subroutine mesh_subset_by_mask(this, other, mask, lx, ly, lz)
2116 class(mesh_t), intent(in) :: this
2117 class(mesh_t), intent(inout) :: other
2118 type(mask_t), intent(in) :: mask
2119 integer, intent(in) :: lx, ly, lz
2120 integer :: i, j, k, nelv, lxyz, gdim, e_m, nidx(4), nelv_c, el_c, el, i_m
2121 type(point_t) :: p(8)
2122 integer :: p_id = 1
2123
2124 call other%free()
2125 lxyz = lx * ly * lz
2126
2127 ! Initialize
2128 nelv = mask%size()/lxyz
2129 call other%init(this%gdim, nelv)
2130
2131 ! Assign the elements
2132 if (other%gdim .eq. 2) then
2133 call neko_error("Subset mesh not implemented for 2d")
2134 else if (other%gdim .eq. 3) then
2135 do el = 1, nelv
2136 i_m = 1 + lxyz * (el - 1)
2137 nidx = nonlinear_index(mask%get(i_m), lx, ly, lz)
2138 e_m = nidx(4) ! Actual element from the original mesh
2139 ! Retrieve the points form the other mesh.
2140 ! No need to shift points, since original
2141 ! mesh has done it.
2142 ! Had to use a new point id to avoid issues at
2143 ! periodic boundaries
2144 ! But this means that all points might be incorrectly
2145 ! marked as unique.
2146 do j = 1, 8
2147 call p(j)%init(this%elements(e_m)%e%pts(j)%p%x, p_id)
2148 p_id = p_id + 1
2149 end do
2150
2151 call other%add_element(el, el + other%offset_el, &
2152 p(1), p(2), p(3), p(4), &
2153 p(5), p(6), p(7), p(8))
2154 end do
2155 else
2156 if (pe_rank .eq. 0) call neko_error('Invalid dimension of mesh')
2157 end if
2158
2159 ! Skip searching for boundaries.
2160
2161 ! Update the curvature
2162 nelv_c = this%curve%size
2163 if (nelv_c .gt. 0) then
2164 el_c = 1
2165 el = 1
2166 ! 2 pointer scan
2167 do while (el .le. nelv .and. el_c .le. nelv_c)
2168
2169 i_m = 1 + lxyz * (el - 1)
2170 nidx = nonlinear_index(mask%get(i_m), lx, ly, lz)
2171 e_m = nidx(4)
2172
2173 if (e_m .lt. this%curve%curve_el(el_c)%el_idx) then
2174 el = el + 1
2175
2176 else if (e_m .gt. this%curve%curve_el(el_c)%el_idx) then
2177 el_c = el_c + 1
2178
2179 else
2180 call other%mark_curve_element(el, &
2181 this%curve%curve_el(el_c)%curve_data, &
2182 this%curve%curve_el(el_c)%curve_type)
2183 el = el + 1
2184 el_c = el_c + 1
2185 end if
2186
2187 end do
2188 end if
2189
2190 ! Finalize
2191 call other%finalize()
2192
2193 other%is_submesh = .true.
2194
2195 end subroutine mesh_subset_by_mask
2196
2197end module mesh
__inline__ __device__ void nonlinear_index(const int idx, const int lx, int *index)
Definition bc_utils.h:44
Generic buffer that is extended with buffers of varying rank.
Definition buffer.F90:34
Definition comm.F90:1
integer, public pe_size
MPI size of communicator.
Definition comm.F90:61
integer, public pe_rank
MPI rank.
Definition comm.F90:58
type(mpi_comm), public neko_comm
MPI communicator.
Definition comm.F90:45
Crystal router: scalable all-to-some personalized exchange.
subroutine, public crystal_router_transfer(buf, n)
Route packed records to their destination ranks.
subroutine, public crystal_router_pack(out, dest, body)
Append one record to a packed crystal-router buffer.
Defines a domain as a subset of facets in a mesh.
Definition curve.f90:2
Defines practical data distributions.
Definition datadist.f90:34
Distributed mesh data.
Definition distdata.f90:34
Defines a zone as a subset of facets in a mesh.
Defines a hexahedron element.
Definition hex.f90:34
integer, parameter, public neko_hex_npts
Number of points.
Definition hex.f90:42
integer, parameter, public neko_hex_nfcs
Number of faces.
Definition hex.f90:43
integer, parameter, public neko_hex_neds
Number of edges.
Definition hex.f90:44
Implements a hash table ADT.
Definition htable.f90:52
Logging routines.
Definition log.f90:34
integer, parameter, public log_size
Definition log.f90:46
Object for handling masks in Neko.
Definition mask.f90:34
Definition math.f90:60
Defines a mesh.
Definition mesh.f90:34
subroutine mesh_generate_flags(this)
Definition mesh.f90:426
subroutine mesh_generate_facet_numbering(this)
Generate a unique facet numbering.
Definition mesh.f90:1242
subroutine mesh_init_dist(this, gdim, dist)
Initialise a mesh this based on a distribution dist.
Definition mesh.f90:222
logical function mesh_is_shared_point(this, p)
Check if a point is shared.
Definition mesh.f90:1949
integer, parameter, public neko_msh_max_zlbls
Max num. zone labels.
Definition mesh.f90:65
subroutine mesh_add_face(this, f)
Add a unique face represented as a 4-tuple to the mesh.
Definition mesh.f90:1579
integer function mesh_get_global_edge(this, e)
Return the global id of an edge e.
Definition mesh.f90:1899
subroutine mesh_generate_edge_conn(this)
Generate element-element connectivity via edges both between internal and between PEs.
Definition mesh.f90:993
subroutine mesh_add_edge(this, e)
Add a unique edge represented as a 2-tuple to the mesh.
Definition mesh.f90:1592
subroutine mesh_add_point(this, p, idx)
Add a unique point to the mesh.
Definition mesh.f90:1555
subroutine mesh_free(this)
Deallocate a mesh this.
Definition mesh.f90:333
subroutine mesh_mark_labeled_facet(this, f, e, label)
Mark facet f in element e with label.
Definition mesh.f90:1622
subroutine mesh_add_quad(this, el, el_glb, p1, p2, p3, p4)
Add a quadrilateral element to the mesh this.
Definition mesh.f90:1483
real(kind=dp) function, public parallelepiped_signed_volume(p1, p2, p3, origin)
Compute a signed volume of a parallelepiped formed by three vectors, in turn defined via three points...
Definition mesh.f90:2090
integer, parameter, public neko_msh_max_zlbl_len
Max length of a zone label.
Definition mesh.f90:67
subroutine mesh_mark_periodic_facet(this, f, e, pf, pe, pids)
Mark facet f in element e as periodic with (pf, pe)
Definition mesh.f90:1642
integer function mesh_get_local_edge(this, e)
Return the local id of an edge e.
Definition mesh.f90:1875
subroutine mesh_all_deformed(this)
Set all elements as if they are deformed.
Definition mesh.f90:459
logical function mesh_is_shared_edge(this, e)
Check if an edge is shared.
Definition mesh.f90:1963
subroutine mesh_init_common(this)
Definition mesh.f90:243
subroutine mesh_get_facet_ids(this, f, e, pids)
Get original ids of periodic points.
Definition mesh.f90:1656
subroutine mesh_create_periodic_ids(this, f, e, pf, pe)
Creates common ids for matching periodic points.
Definition mesh.f90:1732
subroutine mesh_reset_periodic_ids(this)
Reset ids of periodic points to their original ids.
Definition mesh.f90:1679
subroutine mesh_init_nelv(this, gdim, nelv)
Initialise a mesh this with nelv elements.
Definition mesh.f90:193
logical function mesh_is_shared_facet(this, f)
Check if a facet is shared.
Definition mesh.f90:1977
integer function mesh_get_global_facet(this, f)
Return the local id of a face f.
Definition mesh.f90:1919
integer function mesh_have_point_glb_idx(this, index)
Check if the mesh has a point given its global index.
Definition mesh.f90:1936
subroutine mesh_generate_external_point_conn(this)
Generate element-element connectivity via points between PEs.
Definition mesh.f90:857
subroutine mesh_apply_periodic_facet(this, f, e, pf, pe, pids)
Replaces the periodic point's id with a common id for matching periodic points.
Definition mesh.f90:1826
subroutine mesh_finalize(this)
Definition mesh.f90:408
subroutine mesh_generate_external_facet_conn(this)
Generate element-element connectivity via facets between PEs.
Definition mesh.f90:679
subroutine mesh_mark_curve_element(this, e, curve_data, curve_type)
Mark element e as a curve element.
Definition mesh.f90:1605
subroutine mesh_check_right_handedness(this)
Check the correct orientation of the rst coordindates.
Definition mesh.f90:1990
subroutine mesh_generate_conn(this)
Generate element-to-element connectivity.
Definition mesh.f90:465
subroutine mesh_add_hex(this, el, el_glb, p1, p2, p3, p4, p5, p6, p7, p8)
Add a hexahedral element to the mesh this.
Definition mesh.f90:1515
integer function mesh_get_local_facet(this, f)
Return the local id of a face f.
Definition mesh.f90:1887
integer function mesh_get_local_point(this, p)
Return the local id of a point p.
Definition mesh.f90:1858
subroutine mesh_subset_by_mask(this, other, mask, lx, ly, lz)
Create a subset of the mesh this in other based on the provided mask.
Definition mesh.f90:2116
integer, parameter, public i8
Definition num_types.f90:7
integer, parameter, public dp
Definition num_types.f90:9
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
Implements a point.
Definition point.f90:35
Defines a quadrilateral element.
Definition quad.f90:34
integer, parameter, public neko_quad_neds
Number of edges.
Definition quad.f90:43
integer, parameter, public neko_quad_npts
Number of points.
Definition quad.f90:42
Implements a dynamic stack ADT.
Definition stack.f90:49
Implements a n-tuple.
Definition tuple.f90:41
Implements an unordered set ADT.
Definition uset.f90:39
Utilities.
Definition utils.f90:35
subroutine, public neko_warning(warning_msg)
Reports a warning to standard output.
Definition utils.f90:398
Load-balanced linear distribution .
Definition datadist.f90:50
Base type for an element.
Definition element.f90:44
Hexahedron element.
Definition hex.f90:63
Integer based hash table.
Definition htable.f90:102
Integer 2-tuple based hash table.
Definition htable.f90:142
Integer 4-tuple based hash table.
Definition htable.f90:152
Integer*8 based hash table.
Definition htable.f90:112
Iterator for an integer based 2-tuple hash table.
Definition htable.f90:222
Iterator for an integer based 4-tuple hash table.
Definition htable.f90:231
Base type for a hash table.
Definition htable.f90:73
Type for consistently handling masks in Neko. This type encapsulates the mask array and its associate...
Definition mask.f90:51
A point in with coordinates .
Definition point.f90:43
Quadrilateral element.
Definition quad.f90:58
Integer based stack.
Definition stack.f90:77
Integer 2-tuple based stack.
Definition stack.f90:98
Integer 4-tuple based stack.
Definition stack.f90:105
Integer*8 based stack.
Definition stack.f90:84
Integer based 4-tuple.
Definition tuple.f90:76
Integer based 2-tuple.
Definition tuple.f90:58
Integer*8 based unordered set.
Definition uset.f90:78
#define max(a, b)
Definition tensor.cu:40