Neko 1.99.7
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=dp) :: depth = 1.0_dp
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, depth)
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
579 subroutine nmsh_file_read_curves(fh, base_offset, ncurves, msh, &
580 extrusion_depth)
581 type(mpi_file), intent(inout) :: fh
582 integer(kind=MPI_OFFSET_KIND), intent(in) :: base_offset
583 integer, intent(in) :: ncurves
584 type(mesh_t), intent(inout) :: msh
585 real(kind=dp), intent(in), optional :: extrusion_depth
586 type(nmsh_curve_el_t), allocatable :: curve_send(:), curve_recv(:)
587 type(linear_dist_t) :: dist
588 type(mpi_status) :: status
589 integer(kind=MPI_OFFSET_KIND) :: mpi_offset
590 integer :: nmsh_curve_size, nlocal, max_recv, n_recv
591 integer :: i, j, ierr, src, dst, step, el_idx, el_idx_glb
592
593 call mpi_type_size(mpi_nmsh_curve, nmsh_curve_size, ierr)
594
595 dist = linear_dist_t(ncurves, pe_rank, pe_size, neko_comm)
596 nlocal = dist%num_local()
597
598 allocate(curve_send(nlocal))
599
600 mpi_offset = base_offset + &
601 int(dist%start_idx(), i8) * int(nmsh_curve_size, i8)
602 call mpi_file_read_at_all(fh, mpi_offset, &
603 curve_send, nlocal, mpi_nmsh_curve, status, ierr)
604
605 if (present(extrusion_depth)) then
606 do i = 1, nlocal
607 curve_send(i)%curve_data(:,5:8) = &
608 curve_send(i)%curve_data(:,1:4)
609 curve_send(i)%type(5:8) = curve_send(i)%type(1:4)
610 do j = 5, 8
611 if (curve_send(i)%type(j) .eq. 4) then
612 curve_send(i)%curve_data(3,j) = extrusion_depth
613 end if
614 end do
615 end do
616 end if
617
618 call mpi_allreduce(nlocal, max_recv, 1, mpi_integer, mpi_max, &
619 neko_comm, ierr)
620 allocate(curve_recv(max_recv))
621
622 do i = 1, nlocal
623 el_idx_glb = curve_send(i)%e
624 if (msh%htel%get(el_idx_glb, el_idx) .eq. 0) then
625 call msh%mark_curve_element(el_idx, &
626 curve_send(i)%curve_data, curve_send(i)%type)
627 end if
628 end do
629
630 do step = 1, pe_size - 1
631 src = modulo(pe_rank - step + pe_size, pe_size)
632 dst = modulo(pe_rank + step, pe_size)
633 call mpi_sendrecv(curve_send, nlocal, mpi_nmsh_curve, dst, 0, &
634 curve_recv, max_recv, mpi_nmsh_curve, src, 0, &
635 neko_comm, status, ierr)
636 call mpi_get_count(status, mpi_nmsh_curve, n_recv, ierr)
637 do i = 1, n_recv
638 el_idx_glb = curve_recv(i)%e
639 if (msh%htel%get(el_idx_glb, el_idx) .eq. 0) then
640 call msh%mark_curve_element(el_idx, &
641 curve_recv(i)%curve_data, curve_recv(i)%type)
642 end if
643 end do
644 end do
645
646 deallocate(curve_send)
647 deallocate(curve_recv)
648
649 end subroutine nmsh_file_read_curves
650
651
653 subroutine nmsh_file_write(this, data, t)
654 class(nmsh_file_t), intent(inout) :: this
655 class(*), target, intent(in) :: data
656 real(kind=rp), intent(in), optional :: t
657 type(nmsh_quad_t), allocatable :: nmsh_quad(:)
658 type(nmsh_hex_t), allocatable :: nmsh_hex(:)
659 type(nmsh_zone_t), allocatable :: nmsh_zone(:)
660 type(nmsh_curve_el_t), allocatable :: nmsh_curve(:)
661 type(mesh_t), pointer :: msh
662 type(mpi_status) :: status
663 type(mpi_file) :: fh
664 integer (kind=MPI_OFFSET_KIND) :: mpi_offset, mpi_el_offset
665 integer :: i, j, ierr, k
666 integer :: nmsh_quad_size, nmsh_hex_size, nmsh_zone_size, nmsh_curve_size
667 integer :: nzones, nzones_glb, nzones_offset
668 integer :: ncurves, ncurves_glb, ncurves_offset
669 integer :: el_idx, el_idx_glb
670 class(element_t), pointer :: ep
671 integer(i4), dimension(8), parameter :: vcyc_to_sym = &
672 [1, 2, 4, 3, 5, 6, 8, 7] ! cyclic to symmetric vertex mapping
673
674 select type (data)
675 type is (mesh_t)
676 msh => data
677 class default
678 call neko_error('Invalid output data')
679 end select
680
681 call mpi_type_size(mpi_nmsh_quad, nmsh_quad_size, ierr)
682 call mpi_type_size(mpi_nmsh_hex, nmsh_hex_size, ierr)
683 call mpi_type_size(mpi_nmsh_zone, nmsh_zone_size, ierr)
684 call mpi_type_size(mpi_nmsh_curve, nmsh_curve_size, ierr)
685
686 call neko_log%message('Writing data as a binary Neko file ' // &
687 this%get_fname())
688
689 call mpi_file_open(neko_comm, trim(this%get_fname()), &
690 mpi_mode_wronly + mpi_mode_create, mpi_info_null, fh, ierr)
691
692 call mpi_file_write_all(fh, msh%glb_nelv, 1, mpi_integer, status, ierr)
693 call mpi_file_write_all(fh, msh%gdim, 1, mpi_integer, status, ierr)
694
695 call msh%reset_periodic_ids()
696
697 if (msh%gdim .eq. 2) then
698 allocate(nmsh_quad(msh%nelv))
699 do i = 1, msh%nelv
700 ep => msh%elements(i)%e
701 nmsh_quad(i)%el_idx = ep%id()
702 do j = 1, 4
703 nmsh_quad(i)%v(j)%v_idx = ep%pts(vcyc_to_sym(j))%p%id()
704 nmsh_quad(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_quad_size, i8)
709 call mpi_file_write_at_all(fh, mpi_offset, &
710 nmsh_quad, msh%nelv, mpi_nmsh_quad, status, ierr)
711 deallocate(nmsh_quad)
712 mpi_el_offset = int(2 * mpi_integer_size, i8) + &
713 int(msh%glb_nelv, i8) * int(nmsh_quad_size, i8)
714 else if (msh%gdim .eq. 3) then
715 allocate(nmsh_hex(msh%nelv))
716 do i = 1, msh%nelv
717 ep => msh%elements(i)%e
718 nmsh_hex(i)%el_idx = ep%id()
719 do j = 1, 8
720 nmsh_hex(i)%v(j)%v_idx = ep%pts(vcyc_to_sym(j))%p%id()
721 nmsh_hex(i)%v(j)%v_xyz = ep%pts(vcyc_to_sym(j))%p%x
722 end do
723 end do
724 mpi_offset = int(2 * mpi_integer_size, i8) + &
725 int(msh%offset_el, i8) * int(nmsh_hex_size, i8)
726 call mpi_file_write_at_all(fh, mpi_offset, &
727 nmsh_hex, min(msh%nelv, max_write_nel), mpi_nmsh_hex, status, ierr)
728 do i = 1, msh%nelv/max_write_nel
729 mpi_offset = int(2 * mpi_integer_size, i8) + &
730 int(msh%offset_el+i*max_write_nel, i8) * int(nmsh_hex_size, i8)
731 call mpi_file_write_at_all(fh, mpi_offset, &
732 nmsh_hex(i*max_write_nel+1), &
733 min(msh%nelv-i*max_write_nel, max_write_nel), &
734 mpi_nmsh_hex, status, ierr)
735 end do
736 deallocate(nmsh_hex)
737 mpi_el_offset = int(2 * mpi_integer_size, i8) + &
738 int(msh%glb_nelv, i8) * int(nmsh_hex_size, i8)
739 else
740 call neko_error('Invalid dimension of mesh')
741 end if
742
743 nzones = msh%periodic%size
744 do i = 1, neko_msh_max_zlbls
745 nzones = nzones + msh%labeled_zones(i)%size
746 end do
747
748 call mpi_allreduce(nzones, nzones_glb, 1, &
749 mpi_integer, mpi_sum, neko_comm, ierr)
750
751 nzones_offset = 0
752 call mpi_exscan(nzones, nzones_offset, 1, &
753 mpi_integer, mpi_sum, neko_comm, ierr)
754
755 mpi_offset = mpi_el_offset
756 call mpi_file_write_at_all(fh, mpi_offset, &
757 nzones_glb, 1, mpi_integer, status, ierr)
758
759 if (nzones_glb .gt. 0) then
760 allocate(nmsh_zone(nzones))
761
762 if (nzones .gt. 0) then
763 nmsh_zone(:)%type = 0
764
765 j = 1
766 do i = 1, msh%periodic%size
767 nmsh_zone(j)%e = msh%elements(msh%periodic%facet_el(i)%x(2))%e%id()
768 nmsh_zone(j)%f = msh%periodic%facet_el(i)%x(1)
769 nmsh_zone(j)%p_e = msh%periodic%p_facet_el(i)%x(2)
770 nmsh_zone(j)%p_f = msh%periodic%p_facet_el(i)%x(1)
771 nmsh_zone(j)%glb_pt_ids = msh%periodic%p_ids(i)%x
772 nmsh_zone(j)%type = 5
773 j = j + 1
774 end do
775
776 do k = 1, neko_msh_max_zlbls
777 do i = 1, msh%labeled_zones(k)%size
778 nmsh_zone(j)%e = &
779 msh%elements(msh%labeled_zones(k)%facet_el(i)%x(2))%e%id()
780 nmsh_zone(j)%f = msh%labeled_zones(k)%facet_el(i)%x(1)
781 nmsh_zone(j)%p_f = k
782 nmsh_zone(j)%type = 7
783 j = j + 1
784 end do
785 end do
786 end if
787
788 mpi_offset = mpi_el_offset + int(mpi_integer_size, i8) + &
789 int(nzones_offset, i8) * int(nmsh_zone_size, i8)
790 call mpi_file_write_at_all(fh, mpi_offset, &
791 nmsh_zone, nzones, mpi_nmsh_zone, status, ierr)
792
793 deallocate(nmsh_zone)
794 end if
795
796 ncurves = msh%curve%size
797
798
799 call mpi_allreduce(ncurves, ncurves_glb, 1, &
800 mpi_integer, mpi_sum, neko_comm, ierr)
801
802 ncurves_offset = 0
803 call mpi_exscan(ncurves, ncurves_offset, 1, &
804 mpi_integer, mpi_sum, neko_comm, ierr)
805
806 mpi_offset = mpi_el_offset + int(mpi_integer_size, i8) + &
807 int(nzones_glb, i8)*int(nmsh_zone_size, i8)
808
809 call mpi_file_write_at_all(fh, mpi_offset, &
810 ncurves_glb, 1, mpi_integer, status, ierr)
811
812 if (ncurves_glb .gt. 0) then
813
814 allocate(nmsh_curve(ncurves))
815
816 do i = 1, ncurves
817 nmsh_curve(i)%type = 0
818 end do
819
820 do i = 1, ncurves
821 nmsh_curve(i)%e = msh%elements(msh%curve%curve_el(i)%el_idx)%e%id()
822 nmsh_curve(i)%curve_data = msh%curve%curve_el(i)%curve_data
823 nmsh_curve(i)%type = msh%curve%curve_el(i)%curve_type
824 end do
825
826 mpi_offset = mpi_el_offset + int(2*mpi_integer_size, i8) + &
827 int(nzones_glb, i8) * int(nmsh_zone_size, i8) + &
828 int(ncurves_offset, i8) * int(nmsh_curve_size, i8)
829
830 call mpi_file_write_at_all(fh, mpi_offset, &
831 nmsh_curve, ncurves, mpi_nmsh_curve, status, ierr)
832 deallocate(nmsh_curve)
833 end if
834
835 call mpi_file_sync(fh, ierr)
836 call mpi_file_close(fh, ierr)
837 call neko_log%message('Done')
838
839 !
840 ! Re-apply periodic facets
841 ! (necessary if the mesh is going to be used after I/O)
842 !
843 do i = 1, msh%periodic%size
844 el_idx_glb = msh%elements(msh%periodic%facet_el(i)%x(2))%e%id()
845 if (msh%htel%get(el_idx_glb, el_idx) .eq. 0) then
846 call msh%apply_periodic_facet(msh%periodic%facet_el(i)%x(1), el_idx, &
847 msh%periodic%p_facet_el(i)%x(1), &
848 msh%periodic%p_facet_el(i)%x(2), msh%periodic%p_ids(i)%x)
849 end if
850 end do
851
852 end subroutine nmsh_file_write
853
854end module nmsh_file
Definition comm.F90:1
integer, public pe_size
MPI size of communicator.
Definition comm.F90:62
integer, public pe_rank
MPI rank.
Definition comm.F90:59
type(mpi_comm), public neko_comm
MPI communicator.
Definition comm.F90:46
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:65
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_read_curves(fh, base_offset, ncurves, msh, extrusion_depth)
Read curve element data in chunks and ring-pass between ranks, avoiding storage of the full curve lis...
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
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