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