Neko 1.99.3
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
nmsh_file.f90
Go to the documentation of this file.
1! Copyright (c) 2019-2021, 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!
36 use comm, only : neko_comm, pe_rank, pe_size
37 use num_types, only : rp, dp, i4, i8
38 use mesh, only : mesh_t, neko_msh_max_zlbls
39 use utils, only : neko_error
40 use point, only : point_t
41 use tuple, only : tuple4_i4_t
43 use element, only : element_t
44 use datadist, only : linear_dist_t
47 use mpi_f08, only : mpi_wtime, mpi_status, mpi_file, mpi_offset_kind, &
48 mpi_mode_wronly, mpi_mode_create, mpi_mode_rdonly, mpi_info_null, &
49 mpi_file_open, mpi_file_close, mpi_file_read_all, mpi_file_write_all, &
50 mpi_file_write_at_all, mpi_file_read_at_all, mpi_integer, mpi_sum, &
51 mpi_max, mpi_exscan, mpi_barrier, mpi_type_size, mpi_allreduce, &
52 mpi_file_sync, mpi_sendrecv, mpi_get_count
53 use logger, only : neko_log, log_size
54 implicit none
55
56 private
59 integer, parameter :: max_write_nel = 8000000
61 type, public, extends(generic_file_t) :: nmsh_file_t
62 contains
63 procedure :: read => nmsh_file_read
64 procedure :: write => nmsh_file_write
65 end type nmsh_file_t
66
67contains
68
70 subroutine nmsh_file_read(this, data)
71 class(nmsh_file_t) :: this
72 class(*), target, intent(inout) :: data
73 type(nmsh_hex_t), allocatable :: nmsh_hex(:)
74 type(nmsh_quad_t), allocatable :: nmsh_quad(:)
75 type(mesh_t), pointer :: msh
76 type(mpi_status) :: status
77 type(mpi_file) :: fh
78 integer (kind=MPI_OFFSET_KIND) :: mpi_offset, mpi_el_offset
79 integer :: i, j, ierr, element_offset
80 integer :: nmsh_quad_size, nmsh_hex_size, nmsh_zone_size
81 integer :: nelv, gdim, nzones, ncurves
82 type(point_t), target :: p(8)
83 type(linear_dist_t) :: dist
84 character(len=LOG_SIZE) :: log_buf
85 real(kind=rp) :: t_start, t_end
86
87 call this%check_exists()
88
89 select type (data)
90 type is (mesh_t)
91 msh => data
92 class default
93 call neko_error('Invalid output data')
94 end select
95
96
97 call neko_log%section("Mesh")
98 call neko_log%message('Reading a binary Neko file ' // this%get_fname())
99
100 call mpi_type_size(mpi_nmsh_hex, nmsh_hex_size, ierr)
101 call mpi_type_size(mpi_nmsh_quad, nmsh_quad_size, ierr)
102 call mpi_type_size(mpi_nmsh_zone, nmsh_zone_size, ierr)
103
104 call mpi_file_open(neko_comm, trim(this%get_fname()), &
105 mpi_mode_rdonly, mpi_info_null, fh, ierr)
106
107 if (ierr > 0) then
108 call neko_error('Could not open the mesh file ' // this%get_fname() // &
109 'for reading!')
110 end if
111 call mpi_file_read_all(fh, nelv, 1, mpi_integer, status, ierr)
112 call mpi_file_read_all(fh, gdim, 1, mpi_integer, status, ierr)
113
114 write(log_buf,1) gdim, nelv
1151 format('gdim = ', i1, ', nelements = ', i9)
116 call neko_log%message(log_buf)
117
118 if (gdim .eq. 2) then
119 call mpi_file_close(fh, ierr)
120 call nmsh_file_read_2d(this, msh)
121 else
122
123 dist = linear_dist_t(nelv, pe_rank, pe_size, neko_comm)
124 nelv = dist%num_local()
125 element_offset = dist%start_idx()
126
127 call msh%init(gdim, nelv)
128
129 call neko_log%message('Reading elements')
130
131 if (msh%gdim .eq. 2) then
132 allocate(nmsh_quad(msh%nelv))
133 mpi_offset = int(2 * mpi_integer_size, i8) + &
134 int(element_offset, i8) * int(nmsh_quad_size, i8)
135 call mpi_file_read_at_all(fh, mpi_offset, &
136 nmsh_quad, msh%nelv, mpi_nmsh_quad, status, ierr)
137 do i = 1, nelv
138 do j = 1, 4
139 call p(j)%init(nmsh_quad(i)%v(j)%v_xyz, nmsh_quad(i)%v(j)%v_idx)
140 end do
141 ! swap vertices to keep symmetric vertex numbering in neko
142 call msh%add_element(i, nmsh_quad(i)%el_idx, &
143 p(1), p(2), p(4), p(3))
144 end do
145 deallocate(nmsh_quad)
146 mpi_el_offset = int(2 * mpi_integer_size, i8) + &
147 int(dist%num_global(), i8) * int(nmsh_quad_size, i8)
148 else if (msh%gdim .eq. 3) then
149 allocate(nmsh_hex(msh%nelv))
150 mpi_offset = int(2 * mpi_integer_size, i8) + &
151 int(element_offset, i8) * int(nmsh_hex_size, i8)
152 call mpi_file_read_at_all(fh, mpi_offset, &
153 nmsh_hex, msh%nelv, mpi_nmsh_hex, status, ierr)
154 do i = 1, nelv
155 do j = 1, 8
156 call p(j)%init(nmsh_hex(i)%v(j)%v_xyz, nmsh_hex(i)%v(j)%v_idx)
157 end do
158 ! swap vertices to keep symmetric vertex numbering in neko
159 call msh%add_element(i, nmsh_hex(i)%el_idx, &
160 p(1), p(2), p(4), p(3), p(5), p(6), p(8), p(7))
161 end do
162 deallocate(nmsh_hex)
163 mpi_el_offset = int(2 * mpi_integer_size, i8) + &
164 int(dist%num_global(), i8) * int(nmsh_hex_size, i8)
165 else
166 if (pe_rank .eq. 0) call neko_error('Invalid dimension of mesh')
167 end if
168 call neko_log%message('Reading BC/zone data')
169
170 mpi_offset = mpi_el_offset
171 call mpi_file_read_at_all(fh, mpi_offset, &
172 nzones, 1, mpi_integer, status, ierr)
173 if (nzones .gt. 0) then
174 mpi_offset = mpi_el_offset + int(mpi_integer_size, i8)
175 call nmsh_file_read_zones(fh, mpi_offset, nzones, msh)
176 end if
177 call neko_log%message('Reading deformation data')
178
179 mpi_offset = mpi_el_offset + int(mpi_integer_size, i8) + &
180 int(nzones, i8)*int(nmsh_zone_size, i8)
181 call mpi_file_read_at_all(fh, mpi_offset, &
182 ncurves, 1, mpi_integer, status, ierr)
183
184 if (ncurves .gt. 0) then
185 mpi_offset = mpi_el_offset + int(2 * mpi_integer_size, i8) + &
186 int(nzones, i8)*int(nmsh_zone_size, i8)
187 call nmsh_file_read_curves(fh, mpi_offset, ncurves, msh)
188 end if
189
190 call mpi_file_close(fh, ierr)
191 call neko_log%message('Mesh read, setting up connectivity')
192
193 t_start = mpi_wtime()
194 call msh%finalize()
195 call mpi_barrier(neko_comm, ierr)
196 t_end = mpi_wtime()
197 write(log_buf, '(A)') 'Done setting up mesh and connectivity'
198 call neko_log%message(log_buf)
199 write(log_buf, '(A,F9.6)') &
200 'Mesh and connectivity setup (excluding read) time (s): ', &
201 t_end - t_start
202 call neko_log%message(log_buf)
203
204 call neko_log%end_section()
205 end if
206
207 end subroutine nmsh_file_read
208
210 subroutine nmsh_file_read_2d(this, msh)
211 class(nmsh_file_t) :: this
212 type(mesh_t), pointer, intent(inout) :: msh
213 type(nmsh_hex_t), allocatable :: nmsh_hex(:)
214 type(nmsh_quad_t), allocatable :: nmsh_quad(:)
215 type(mpi_status) :: status
216 type(mpi_file) :: fh
217 integer (kind=MPI_OFFSET_KIND) :: mpi_offset, mpi_el_offset
218 integer :: i, j, ierr, element_offset, id
219 integer :: nmsh_quad_size, nmsh_hex_size, nmsh_zone_size
220 integer :: nelv, gdim, nzones, ncurves
221 integer :: el_idx
222 type(point_t) :: p(8)
223 type(linear_dist_t) :: dist
224 character(len=LOG_SIZE) :: log_buf
225 real(kind=rp) :: depth = 1d0
226 real(kind=dp) :: coord(3)
227 type(tuple4_i4_t) :: glb_pt_ids
228
229
230 call mpi_type_size(mpi_nmsh_hex, nmsh_hex_size, ierr)
231 call mpi_type_size(mpi_nmsh_quad, nmsh_quad_size, ierr)
232 call mpi_type_size(mpi_nmsh_zone, nmsh_zone_size, ierr)
233
234 call mpi_file_open(neko_comm, trim(this%get_fname()), &
235 mpi_mode_rdonly, mpi_info_null, fh, ierr)
236 call mpi_file_read_all(fh, nelv, 1, mpi_integer, status, ierr)
237 call mpi_file_read_all(fh, gdim, 1, mpi_integer, status, ierr)
238
239 write(log_buf,2) gdim
2402 format('gdim = ', i1, ', no full 2d support, creating thin slab')
241 call neko_log%message(log_buf)
242 gdim = 3
243
244 dist = linear_dist_t(nelv, pe_rank, pe_size, neko_comm)
245 nelv = dist%num_local()
246 element_offset = dist%start_idx()
247
248 call msh%init(gdim, nelv)
249
250 allocate(nmsh_quad(msh%nelv))
251 mpi_offset = int(2 * mpi_integer_size, i8) + &
252 int(element_offset, i8) * int(nmsh_quad_size, i8)
253 call mpi_file_read_at_all(fh, mpi_offset, &
254 nmsh_quad, msh%nelv, mpi_nmsh_quad, status, ierr)
255 do i = 1, nelv
256 do j = 1, 4
257 coord = nmsh_quad(i)%v(j)%v_xyz
258 coord(3) = 0_rp
259 call p(j)%init(coord, nmsh_quad(i)%v(j)%v_idx)
260 end do
261 do j = 1, 4
262 coord = nmsh_quad(i)%v(j)%v_xyz
263 coord(3) = depth
264 id = nmsh_quad(i)%v(j)%v_idx+msh%glb_nelv*8
265 call p(j+4)%init(coord, id)
266 end do
267 ! swap vertices to keep symmetric vertex numbering in neko
268 call msh%add_element(i, nmsh_quad(i)%el_idx, &
269 p(1), p(2), p(4), p(3), p(5), p(6), p(8), p(7))
270 end do
271 deallocate(nmsh_quad)
272 mpi_el_offset = int(2 * mpi_integer_size, i8) + &
273 int(dist%num_global(), i8) * int(nmsh_quad_size, i8)
274
275 mpi_offset = mpi_el_offset
276 call mpi_file_read_at_all(fh, mpi_offset, &
277 nzones, 1, mpi_integer, status, ierr)
278 if (nzones .gt. 0) then
279 mpi_offset = mpi_el_offset + int(mpi_integer_size, i8)
280 call nmsh_file_read_zones_2d(fh, mpi_offset, nzones, msh)
281
282 !Do the same for extruded 3d points
283 do el_idx = 1, nelv
284 call msh%elements(el_idx)%e%facet_order(glb_pt_ids,5)
285 call msh%mark_periodic_facet(6, el_idx, &
286 5, el_idx, glb_pt_ids%x)
287 call msh%elements(el_idx)%e%facet_order(glb_pt_ids,5)
288 call msh%mark_periodic_facet(5, el_idx, &
289 6, el_idx, glb_pt_ids%x)
290 end do
291 do el_idx = 1, nelv
292 call msh%elements(el_idx)%e%facet_order(glb_pt_ids,5)
293 call msh%apply_periodic_facet(6, el_idx, &
294 5, el_idx, glb_pt_ids%x)
295 call msh%elements(el_idx)%e%facet_order(glb_pt_ids,5)
296 call msh%apply_periodic_facet(5, el_idx, &
297 6, el_idx, glb_pt_ids%x)
298 end do
299 end if
300
301 mpi_offset = mpi_el_offset + &
302 int(mpi_integer_size, i8) + int(nzones, i8)*int(nmsh_zone_size, i8)
303 call mpi_file_read_at_all(fh, mpi_offset, &
304 ncurves, 1, mpi_integer, status, ierr)
305
306 if (ncurves .gt. 0) then
307 mpi_offset = mpi_el_offset + &
308 int(2*mpi_integer_size, i8) + &
309 int(nzones, i8)*int(nmsh_zone_size, i8)
310 call nmsh_file_read_curves(fh, mpi_offset, ncurves, msh)
311 end if
312
313 call mpi_file_close(fh, ierr)
314
315 call msh%finalize()
316
317 call neko_log%end_section()
318
319 end subroutine nmsh_file_read_2d
320
326 subroutine nmsh_file_read_zones(fh, base_offset, nzones, msh)
327 type(mpi_file), intent(inout) :: fh
328 integer(kind=MPI_OFFSET_KIND), intent(in) :: base_offset
329 integer, intent(in) :: nzones
330 type(mesh_t), intent(inout) :: msh
331 type(nmsh_zone_t), allocatable :: zone_send(:), zone_recv(:)
332 type(linear_dist_t) :: dist
333 type(mpi_status) :: status
334 integer(kind=MPI_OFFSET_KIND) :: mpi_offset
335 integer :: nmsh_zone_size, nlocal, max_recv, n_recv
336 integer :: i, ierr, src, dst, step, el_idx, el_idx_glb
337
338 call mpi_type_size(mpi_nmsh_zone, nmsh_zone_size, ierr)
339
340 dist = linear_dist_t(nzones, pe_rank, pe_size, neko_comm)
341 nlocal = dist%num_local()
342
343 allocate(zone_send(nlocal))
344
345 mpi_offset = base_offset + &
346 int(dist%start_idx(), i8) * int(nmsh_zone_size, i8)
347 call mpi_file_read_at_all(fh, mpi_offset, &
348 zone_send, nlocal, mpi_nmsh_zone, status, ierr)
349
350 call mpi_allreduce(nlocal, max_recv, 1, mpi_integer, mpi_max, &
351 neko_comm, ierr)
352 allocate(zone_recv(max_recv))
353
354 ! Mark pass: process local chunk
355 do i = 1, nlocal
356 el_idx_glb = zone_send(i)%e
357 if (msh%htel%get(el_idx_glb, el_idx) .eq. 0) then
358 select case (zone_send(i)%type)
359 case (5)
360 call msh%mark_periodic_facet(zone_send(i)%f, el_idx, &
361 zone_send(i)%p_f, zone_send(i)%p_e, &
362 zone_send(i)%glb_pt_ids)
363 case (7)
364 call msh%mark_labeled_facet(zone_send(i)%f, el_idx, &
365 zone_send(i)%p_f)
366 end select
367 end if
368 end do
369
370 ! Mark pass: ring-shift through all other ranks
371 do step = 1, pe_size - 1
372 src = modulo(pe_rank - step + pe_size, pe_size)
373 dst = modulo(pe_rank + step, pe_size)
374 call mpi_sendrecv(zone_send, nlocal, mpi_nmsh_zone, dst, 0, &
375 zone_recv, max_recv, mpi_nmsh_zone, src, 0, &
376 neko_comm, status, ierr)
377 call mpi_get_count(status, mpi_nmsh_zone, n_recv, ierr)
378 do i = 1, n_recv
379 el_idx_glb = zone_recv(i)%e
380 if (msh%htel%get(el_idx_glb, el_idx) .eq. 0) then
381 select case (zone_recv(i)%type)
382 case (5)
383 call msh%mark_periodic_facet(zone_recv(i)%f, el_idx, &
384 zone_recv(i)%p_f, zone_recv(i)%p_e, &
385 zone_recv(i)%glb_pt_ids)
386 case (7)
387 call msh%mark_labeled_facet(zone_recv(i)%f, el_idx, &
388 zone_recv(i)%p_f)
389 end select
390 end if
391 end do
392 end do
393
394 ! Apply pass (periodic only): process local chunk first
395 do i = 1, nlocal
396 el_idx_glb = zone_send(i)%e
397 if (msh%htel%get(el_idx_glb, el_idx) .eq. 0) then
398 if (zone_send(i)%type .eq. 5) then
399 call msh%apply_periodic_facet(zone_send(i)%f, el_idx, &
400 zone_send(i)%p_f, zone_send(i)%p_e, &
401 zone_send(i)%glb_pt_ids)
402 end if
403 end if
404 end do
405
406 ! Apply pass: ring-shift through all other ranks
407 do step = 1, pe_size - 1
408 src = modulo(pe_rank - step + pe_size, pe_size)
409 dst = modulo(pe_rank + step, pe_size)
410 call mpi_sendrecv(zone_send, nlocal, mpi_nmsh_zone, dst, 1, &
411 zone_recv, max_recv, mpi_nmsh_zone, src, 1, &
412 neko_comm, status, ierr)
413 call mpi_get_count(status, mpi_nmsh_zone, n_recv, ierr)
414 do i = 1, n_recv
415 el_idx_glb = zone_recv(i)%e
416 if (msh%htel%get(el_idx_glb, el_idx) .eq. 0) then
417 if (zone_recv(i)%type .eq. 5) then
418 call msh%apply_periodic_facet(zone_recv(i)%f, el_idx, &
419 zone_recv(i)%p_f, zone_recv(i)%p_e, &
420 zone_recv(i)%glb_pt_ids)
421 end if
422 end if
423 end do
424 end do
425
426 deallocate(zone_send)
427 deallocate(zone_recv)
428
429 end subroutine nmsh_file_read_zones
430
434 pure subroutine nmsh_file_extrude_periodic_ids(f, glb_pt_ids, glb_nelv, ids)
435 integer, intent(in) :: f
436 integer, intent(in) :: glb_pt_ids(4)
437 integer, intent(in) :: glb_nelv
438 integer, intent(out) :: ids(4)
439 integer :: pt(4)
440
441 pt(1) = glb_pt_ids(1)
442 pt(2) = glb_pt_ids(2)
443 pt(3) = glb_pt_ids(1) + glb_nelv * 8
444 pt(4) = glb_pt_ids(2) + glb_nelv * 8
445
446 if (f .eq. 1 .or. f .eq. 2) then
447 ids(1) = pt(1)
448 ids(2) = pt(3)
449 ids(3) = pt(4)
450 ids(4) = pt(2)
451 else
452 ids(1) = pt(1)
453 ids(2) = pt(2)
454 ids(3) = pt(4)
455 ids(4) = pt(3)
456 end if
457 end subroutine nmsh_file_extrude_periodic_ids
458
463 subroutine nmsh_file_read_zones_2d(fh, base_offset, nzones, msh)
464 type(mpi_file), intent(inout) :: fh
465 integer(kind=MPI_OFFSET_KIND), intent(in) :: base_offset
466 integer, intent(in) :: nzones
467 type(mesh_t), intent(inout) :: msh
468 type(nmsh_zone_t), allocatable :: zone_send(:), zone_recv(:)
469 type(linear_dist_t) :: dist
470 type(mpi_status) :: status
471 integer(kind=MPI_OFFSET_KIND) :: mpi_offset
472 integer :: nmsh_zone_size, nlocal, max_recv, n_recv
473 integer :: i, ierr, src, dst, step, el_idx, el_idx_glb
474 integer :: ids(4)
475
476 call mpi_type_size(mpi_nmsh_zone, nmsh_zone_size, ierr)
477
478 dist = linear_dist_t(nzones, pe_rank, pe_size, neko_comm)
479 nlocal = dist%num_local()
480
481 allocate(zone_send(nlocal))
482
483 mpi_offset = base_offset + &
484 int(dist%start_idx(), i8) * int(nmsh_zone_size, i8)
485 call mpi_file_read_at_all(fh, mpi_offset, &
486 zone_send, nlocal, mpi_nmsh_zone, status, ierr)
487
488 call mpi_allreduce(nlocal, max_recv, 1, mpi_integer, mpi_max, &
489 neko_comm, ierr)
490 allocate(zone_recv(max_recv))
491
492 ! Mark pass: process local chunk. We recompute the extruded ids on
493 ! demand rather than storing them back into zone_send, so the buffer
494 ! we ring-shift always carries the original on-disk values.
495 do i = 1, nlocal
496 el_idx_glb = zone_send(i)%e
497 if (msh%htel%get(el_idx_glb, el_idx) .eq. 0) then
498 select case (zone_send(i)%type)
499 case (5)
500 call nmsh_file_extrude_periodic_ids(zone_send(i)%f, &
501 zone_send(i)%glb_pt_ids, msh%glb_nelv, ids)
502 call msh%mark_periodic_facet(zone_send(i)%f, el_idx, &
503 zone_send(i)%p_f, zone_send(i)%p_e, ids)
504 case (7)
505 call msh%mark_labeled_facet(zone_send(i)%f, el_idx, &
506 zone_send(i)%p_f)
507 end select
508 end if
509 end do
510
511 ! Mark pass: ring-shift through all other ranks
512 do step = 1, pe_size - 1
513 src = modulo(pe_rank - step + pe_size, pe_size)
514 dst = modulo(pe_rank + step, pe_size)
515 call mpi_sendrecv(zone_send, nlocal, mpi_nmsh_zone, dst, 0, &
516 zone_recv, max_recv, mpi_nmsh_zone, src, 0, &
517 neko_comm, status, ierr)
518 call mpi_get_count(status, mpi_nmsh_zone, n_recv, ierr)
519 do i = 1, n_recv
520 el_idx_glb = zone_recv(i)%e
521 if (msh%htel%get(el_idx_glb, el_idx) .eq. 0) then
522 select case (zone_recv(i)%type)
523 case (5)
524 call nmsh_file_extrude_periodic_ids(zone_recv(i)%f, &
525 zone_recv(i)%glb_pt_ids, msh%glb_nelv, ids)
526 call msh%mark_periodic_facet(zone_recv(i)%f, el_idx, &
527 zone_recv(i)%p_f, zone_recv(i)%p_e, ids)
528 case (7)
529 call msh%mark_labeled_facet(zone_recv(i)%f, el_idx, &
530 zone_recv(i)%p_f)
531 end select
532 end if
533 end do
534 end do
535
536 ! Apply pass (periodic only): local chunk
537 do i = 1, nlocal
538 el_idx_glb = zone_send(i)%e
539 if (msh%htel%get(el_idx_glb, el_idx) .eq. 0) then
540 if (zone_send(i)%type .eq. 5) then
541 call nmsh_file_extrude_periodic_ids(zone_send(i)%f, &
542 zone_send(i)%glb_pt_ids, msh%glb_nelv, ids)
543 call msh%apply_periodic_facet(zone_send(i)%f, el_idx, &
544 zone_send(i)%p_f, zone_send(i)%p_e, ids)
545 end if
546 end if
547 end do
548
549 ! Apply pass: ring-shift through all other ranks
550 do step = 1, pe_size - 1
551 src = modulo(pe_rank - step + pe_size, pe_size)
552 dst = modulo(pe_rank + step, pe_size)
553 call mpi_sendrecv(zone_send, nlocal, mpi_nmsh_zone, dst, 1, &
554 zone_recv, max_recv, mpi_nmsh_zone, src, 1, &
555 neko_comm, status, ierr)
556 call mpi_get_count(status, mpi_nmsh_zone, n_recv, ierr)
557 do i = 1, n_recv
558 el_idx_glb = zone_recv(i)%e
559 if (msh%htel%get(el_idx_glb, el_idx) .eq. 0) then
560 if (zone_recv(i)%type .eq. 5) then
561 call nmsh_file_extrude_periodic_ids(zone_recv(i)%f, &
562 zone_recv(i)%glb_pt_ids, msh%glb_nelv, ids)
563 call msh%apply_periodic_facet(zone_recv(i)%f, el_idx, &
564 zone_recv(i)%p_f, zone_recv(i)%p_e, ids)
565 end if
566 end if
567 end do
568 end do
569
570 deallocate(zone_send)
571 deallocate(zone_recv)
572
573 end subroutine nmsh_file_read_zones_2d
574
577 subroutine nmsh_file_read_curves(fh, base_offset, ncurves, msh)
578 type(mpi_file), intent(inout) :: fh
579 integer(kind=MPI_OFFSET_KIND), intent(in) :: base_offset
580 integer, intent(in) :: ncurves
581 type(mesh_t), intent(inout) :: msh
582 type(nmsh_curve_el_t), allocatable :: curve_send(:), curve_recv(:)
583 type(linear_dist_t) :: dist
584 type(mpi_status) :: status
585 integer(kind=MPI_OFFSET_KIND) :: mpi_offset
586 integer :: nmsh_curve_size, nlocal, max_recv, n_recv
587 integer :: i, ierr, src, dst, step, el_idx, el_idx_glb
588
589 call mpi_type_size(mpi_nmsh_curve, nmsh_curve_size, ierr)
590
591 dist = linear_dist_t(ncurves, pe_rank, pe_size, neko_comm)
592 nlocal = dist%num_local()
593
594 allocate(curve_send(nlocal))
595
596 mpi_offset = base_offset + &
597 int(dist%start_idx(), i8) * int(nmsh_curve_size, i8)
598 call mpi_file_read_at_all(fh, mpi_offset, &
599 curve_send, nlocal, mpi_nmsh_curve, status, ierr)
600
601 call mpi_allreduce(nlocal, max_recv, 1, mpi_integer, mpi_max, &
602 neko_comm, ierr)
603 allocate(curve_recv(max_recv))
604
605 do i = 1, nlocal
606 el_idx_glb = curve_send(i)%e
607 if (msh%htel%get(el_idx_glb, el_idx) .eq. 0) then
608 call msh%mark_curve_element(el_idx, &
609 curve_send(i)%curve_data, curve_send(i)%type)
610 end if
611 end do
612
613 do step = 1, pe_size - 1
614 src = modulo(pe_rank - step + pe_size, pe_size)
615 dst = modulo(pe_rank + step, pe_size)
616 call mpi_sendrecv(curve_send, nlocal, mpi_nmsh_curve, dst, 0, &
617 curve_recv, max_recv, mpi_nmsh_curve, src, 0, &
618 neko_comm, status, ierr)
619 call mpi_get_count(status, mpi_nmsh_curve, n_recv, ierr)
620 do i = 1, n_recv
621 el_idx_glb = curve_recv(i)%e
622 if (msh%htel%get(el_idx_glb, el_idx) .eq. 0) then
623 call msh%mark_curve_element(el_idx, &
624 curve_recv(i)%curve_data, curve_recv(i)%type)
625 end if
626 end do
627 end do
628
629 deallocate(curve_send)
630 deallocate(curve_recv)
631
632 end subroutine nmsh_file_read_curves
633
634
636 subroutine nmsh_file_write(this, data, t)
637 class(nmsh_file_t), intent(inout) :: this
638 class(*), target, intent(in) :: data
639 real(kind=rp), intent(in), optional :: t
640 type(nmsh_quad_t), allocatable :: nmsh_quad(:)
641 type(nmsh_hex_t), allocatable :: nmsh_hex(:)
642 type(nmsh_zone_t), allocatable :: nmsh_zone(:)
643 type(nmsh_curve_el_t), allocatable :: nmsh_curve(:)
644 type(mesh_t), pointer :: msh
645 type(mpi_status) :: status
646 type(mpi_file) :: fh
647 integer (kind=MPI_OFFSET_KIND) :: mpi_offset, mpi_el_offset
648 integer :: i, j, ierr, k
649 integer :: nmsh_quad_size, nmsh_hex_size, nmsh_zone_size, nmsh_curve_size
650 integer :: nzones, nzones_glb, nzones_offset
651 integer :: ncurves, ncurves_glb, ncurves_offset
652 integer :: el_idx, el_idx_glb
653 class(element_t), pointer :: ep
654 integer(i4), dimension(8), parameter :: vcyc_to_sym = &
655 [1, 2, 4, 3, 5, 6, 8, 7] ! cyclic to symmetric vertex mapping
656
657 select type (data)
658 type is (mesh_t)
659 msh => data
660 class default
661 call neko_error('Invalid output data')
662 end select
663
664 call mpi_type_size(mpi_nmsh_quad, nmsh_quad_size, ierr)
665 call mpi_type_size(mpi_nmsh_hex, nmsh_hex_size, ierr)
666 call mpi_type_size(mpi_nmsh_zone, nmsh_zone_size, ierr)
667 call mpi_type_size(mpi_nmsh_curve, nmsh_curve_size, ierr)
668
669 call neko_log%message('Writing data as a binary Neko file ' // &
670 this%get_fname())
671
672 call mpi_file_open(neko_comm, trim(this%get_fname()), &
673 mpi_mode_wronly + mpi_mode_create, mpi_info_null, fh, ierr)
674
675 call mpi_file_write_all(fh, msh%glb_nelv, 1, mpi_integer, status, ierr)
676 call mpi_file_write_all(fh, msh%gdim, 1, mpi_integer, status, ierr)
677
678 call msh%reset_periodic_ids()
679
680 if (msh%gdim .eq. 2) then
681 allocate(nmsh_quad(msh%nelv))
682 do i = 1, msh%nelv
683 ep => msh%elements(i)%e
684 nmsh_quad(i)%el_idx = ep%id()
685 do j = 1, 4
686 nmsh_quad(i)%v(j)%v_idx = ep%pts(vcyc_to_sym(j))%p%id()
687 nmsh_quad(i)%v(j)%v_xyz = ep%pts(vcyc_to_sym(j))%p%x
688 end do
689 end do
690 mpi_offset = int(2 * mpi_integer_size, i8) + &
691 int(msh%offset_el, i8) * int(nmsh_quad_size, i8)
692 call mpi_file_write_at_all(fh, mpi_offset, &
693 nmsh_quad, msh%nelv, mpi_nmsh_quad, status, ierr)
694 deallocate(nmsh_quad)
695 mpi_el_offset = int(2 * mpi_integer_size, i8) + &
696 int(msh%glb_nelv, i8) * int(nmsh_quad_size, i8)
697 else if (msh%gdim .eq. 3) then
698 allocate(nmsh_hex(msh%nelv))
699 do i = 1, msh%nelv
700 ep => msh%elements(i)%e
701 nmsh_hex(i)%el_idx = ep%id()
702 do j = 1, 8
703 nmsh_hex(i)%v(j)%v_idx = ep%pts(vcyc_to_sym(j))%p%id()
704 nmsh_hex(i)%v(j)%v_xyz = ep%pts(vcyc_to_sym(j))%p%x
705 end do
706 end do
707 mpi_offset = int(2 * mpi_integer_size, i8) + &
708 int(msh%offset_el, i8) * int(nmsh_hex_size, i8)
709 call mpi_file_write_at_all(fh, mpi_offset, &
710 nmsh_hex, min(msh%nelv, max_write_nel), mpi_nmsh_hex, status, ierr)
711 do i = 1, msh%nelv/max_write_nel
712 mpi_offset = int(2 * mpi_integer_size, i8) + &
713 int(msh%offset_el+i*max_write_nel, i8) * int(nmsh_hex_size, i8)
714 call mpi_file_write_at_all(fh, mpi_offset, &
715 nmsh_hex(i*max_write_nel+1), &
716 min(msh%nelv-i*max_write_nel, max_write_nel), &
717 mpi_nmsh_hex, status, ierr)
718 end do
719 deallocate(nmsh_hex)
720 mpi_el_offset = int(2 * mpi_integer_size, i8) + &
721 int(msh%glb_nelv, i8) * int(nmsh_hex_size, i8)
722 else
723 call neko_error('Invalid dimension of mesh')
724 end if
725
726 nzones = msh%periodic%size
727 do i = 1, neko_msh_max_zlbls
728 nzones = nzones + msh%labeled_zones(i)%size
729 end do
730
731 call mpi_allreduce(nzones, nzones_glb, 1, &
732 mpi_integer, mpi_sum, neko_comm, ierr)
733
734 nzones_offset = 0
735 call mpi_exscan(nzones, nzones_offset, 1, &
736 mpi_integer, mpi_sum, neko_comm, ierr)
737
738 mpi_offset = mpi_el_offset
739 call mpi_file_write_at_all(fh, mpi_offset, &
740 nzones_glb, 1, mpi_integer, status, ierr)
741
742 if (nzones_glb .gt. 0) then
743 allocate(nmsh_zone(nzones))
744
745 if (nzones .gt. 0) then
746 nmsh_zone(:)%type = 0
747
748 j = 1
749 do i = 1, msh%periodic%size
750 nmsh_zone(j)%e = msh%elements(msh%periodic%facet_el(i)%x(2))%e%id()
751 nmsh_zone(j)%f = msh%periodic%facet_el(i)%x(1)
752 nmsh_zone(j)%p_e = msh%periodic%p_facet_el(i)%x(2)
753 nmsh_zone(j)%p_f = msh%periodic%p_facet_el(i)%x(1)
754 nmsh_zone(j)%glb_pt_ids = msh%periodic%p_ids(i)%x
755 nmsh_zone(j)%type = 5
756 j = j + 1
757 end do
758
759 do k = 1, neko_msh_max_zlbls
760 do i = 1, msh%labeled_zones(k)%size
761 nmsh_zone(j)%e = &
762 msh%elements(msh%labeled_zones(k)%facet_el(i)%x(2))%e%id()
763 nmsh_zone(j)%f = msh%labeled_zones(k)%facet_el(i)%x(1)
764 nmsh_zone(j)%p_f = k
765 nmsh_zone(j)%type = 7
766 j = j + 1
767 end do
768 end do
769 end if
770
771 mpi_offset = mpi_el_offset + int(mpi_integer_size, i8) + &
772 int(nzones_offset, i8) * int(nmsh_zone_size, i8)
773 call mpi_file_write_at_all(fh, mpi_offset, &
774 nmsh_zone, nzones, mpi_nmsh_zone, status, ierr)
775
776 deallocate(nmsh_zone)
777 end if
778
779 ncurves = msh%curve%size
780
781
782 call mpi_allreduce(ncurves, ncurves_glb, 1, &
783 mpi_integer, mpi_sum, neko_comm, ierr)
784
785 ncurves_offset = 0
786 call mpi_exscan(ncurves, ncurves_offset, 1, &
787 mpi_integer, mpi_sum, neko_comm, ierr)
788
789 mpi_offset = mpi_el_offset + int(mpi_integer_size, i8) + &
790 int(nzones_glb, i8)*int(nmsh_zone_size, i8)
791
792 call mpi_file_write_at_all(fh, mpi_offset, &
793 ncurves_glb, 1, mpi_integer, status, ierr)
794
795 if (ncurves_glb .gt. 0) then
796
797 allocate(nmsh_curve(ncurves))
798
799 do i = 1, ncurves
800 nmsh_curve(i)%type = 0
801 end do
802
803 do i = 1, ncurves
804 nmsh_curve(i)%e = msh%elements(msh%curve%curve_el(i)%el_idx)%e%id()
805 nmsh_curve(i)%curve_data = msh%curve%curve_el(i)%curve_data
806 nmsh_curve(i)%type = msh%curve%curve_el(i)%curve_type
807 end do
808
809 mpi_offset = mpi_el_offset + int(2*mpi_integer_size, i8) + &
810 int(nzones_glb, i8) * int(nmsh_zone_size, i8) + &
811 int(ncurves_offset, i8) * int(nmsh_curve_size, i8)
812
813 call mpi_file_write_at_all(fh, mpi_offset, &
814 nmsh_curve, ncurves, mpi_nmsh_curve, status, ierr)
815 deallocate(nmsh_curve)
816 end if
817
818 call mpi_file_sync(fh, ierr)
819 call mpi_file_close(fh, ierr)
820 call neko_log%message('Done')
821
822 !
823 ! Re-apply periodic facets
824 ! (necessary if the mesh is going to be used after I/O)
825 !
826 do i = 1, msh%periodic%size
827 el_idx_glb = msh%elements(msh%periodic%facet_el(i)%x(2))%e%id()
828 if (msh%htel%get(el_idx_glb, el_idx) .eq. 0) then
829 call msh%apply_periodic_facet(msh%periodic%facet_el(i)%x(1), el_idx, &
830 msh%periodic%p_facet_el(i)%x(1), &
831 msh%periodic%p_facet_el(i)%x(2), msh%periodic%p_ids(i)%x)
832 end if
833 end do
834
835 end subroutine nmsh_file_write
836
837end module nmsh_file
Definition comm.F90:1
integer, public pe_size
MPI size of communicator.
Definition comm.F90:60
integer, public pe_rank
MPI rank.
Definition comm.F90:57
type(mpi_comm), public neko_comm
MPI communicator.
Definition comm.F90:44
Defines practical data distributions.
Definition datadist.f90:34
Logging routines.
Definition log.f90:34
type(log_t), public neko_log
Global log stream.
Definition log.f90:80
integer, parameter, public log_size
Definition log.f90:46
Defines a mesh.
Definition mesh.f90:34
integer, parameter, public neko_msh_max_zlbls
Max num. zone labels.
Definition mesh.f90:64
MPI derived types.
Definition mpi_types.f90:34
type(mpi_datatype), public mpi_nmsh_hex
MPI derived type for 3D Neko nmsh data.
Definition mpi_types.f90:47
type(mpi_datatype), public mpi_nmsh_quad
MPI derived type for 2D Neko nmsh data.
Definition mpi_types.f90:48
type(mpi_datatype), public mpi_nmsh_curve
MPI derived type for Neko nmsh curved elements.
Definition mpi_types.f90:50
integer, public mpi_integer_size
Size of MPI type integer.
Definition mpi_types.f90:68
type(mpi_datatype), public mpi_nmsh_zone
MPI derived type for Neko nmsh zone data.
Definition mpi_types.f90:49
Neko binary mesh data.
Definition nmsh_file.f90:34
pure subroutine nmsh_file_extrude_periodic_ids(f, glb_pt_ids, glb_nelv, ids)
Compute the extruded periodic point ids for the 2D thin-slab path. Pure function of the zone fields; ...
subroutine nmsh_file_write(this, data, t)
Write a mesh from to a binary Neko nmsh file.
subroutine nmsh_file_read(this, data)
Load a mesh from a binary Neko nmsh file.
Definition nmsh_file.f90:71
subroutine nmsh_file_read_curves(fh, base_offset, ncurves, msh)
Read curve element data in chunks and ring-pass between ranks, avoiding storage of the full curve lis...
integer, parameter max_write_nel
Specifices the maximum number of elements any rank is allowed to write (for nmsh)....
Definition nmsh_file.f90:59
subroutine nmsh_file_read_2d(this, msh)
Load a mesh from a binary Neko nmsh file.
subroutine nmsh_file_read_zones(fh, base_offset, nzones, msh)
Read zone data in chunks and ring-pass between ranks, avoiding storage of the full zone list on every...
subroutine nmsh_file_read_zones_2d(fh, base_offset, nzones, msh)
Read zone data in chunks and ring-pass between ranks for the 2D thin-slab path. Two ring traversals a...
Neko binary mesh format.
Definition nmsh.f90:2
integer, parameter, public i8
Definition num_types.f90:7
integer, parameter, public i4
Definition num_types.f90:6
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
Implements a n-tuple.
Definition tuple.f90:41
Utilities.
Definition utils.f90:35
Load-balanced linear distribution .
Definition datadist.f90:50
Base type for an element.
Definition element.f90:44
A generic file handler.
Neko curve data.
Definition nmsh.f90:39
Neko hex element data.
Definition nmsh.f90:24
Neko quad element data.
Definition nmsh.f90:19
Neko zone data.
Definition nmsh.f90:29
Interface for Neko nmsh files.
Definition nmsh_file.f90:61
A point in with coordinates .
Definition point.f90:43
Integer based 4-tuple.
Definition tuple.f90:76