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