Neko 1.1.0
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
vtkhdf_file.F90
Go to the documentation of this file.
1! Copyright (c) 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!
35 use num_types, only : rp, sp, dp, qp, i8
37 use checkpoint, only : chkp_t
40 use mesh, only : mesh_t
41 use field, only : field_t
42 use field_list, only : field_list_t
44 use dofmap, only : dofmap_t
45 use logger, only : neko_log
46 use comm, only : pe_rank, pe_size, neko_comm
48 use mpi_f08, only : mpi_info_null, mpi_allreduce, mpi_allgather, &
49 mpi_in_place, mpi_integer, mpi_sum, mpi_max, mpi_comm_size, mpi_exscan, &
50 mpi_barrier, mpi_bcast, mpi_logical
51 use vtk, only : vtk_ordering
52#ifdef HAVE_HDF5
53 use hdf5, only : &
54 hid_t, hsize_t, size_t, &
55 h5open_f, h5close_f, &
56 h5fcreate_f, h5fopen_f, h5fclose_f, h5fflush_f, h5fget_obj_count_f, &
57 h5f_obj_all_f, h5f_scope_global_f, &
58 h5gcreate_f, h5gopen_f, h5gclose_f, &
59 h5acreate_f, h5aopen_f, h5awrite_f, h5aread_f, h5aclose_f, h5aexists_f, &
60 h5aopen_by_name_f, &
61 h5dcreate_f, h5dopen_f, h5dwrite_f, h5dread_f, h5dclose_f, &
62 h5dget_create_plist_f, &
63 h5tcopy_f, h5tclose_f, h5tset_strpad_f, h5tset_size_f, &
64 h5screate_f, h5screate_simple_f, h5sclose_f, &
65 h5sselect_hyperslab_f, h5sselect_all_f, h5sget_simple_extent_dims_f, &
66 h5dget_space_f, h5dset_extent_f, &
67 h5pcreate_f, h5pclose_f, h5pset_fapl_mpio_f, h5pset_dxpl_mpio_f, &
68 h5pget_virtual_count_f, h5pget_virtual_filename_f, &
69 h5lexists_f, h5ldelete_f, &
70 h5p_file_access_f, h5p_dataset_xfer_f, h5p_dataset_create_f, &
71 h5f_acc_trunc_f, h5f_acc_rdwr_f, h5f_acc_rdonly_f, h5pset_chunk_f, &
72 h5t_std_u8le, h5t_native_integer, h5t_fortran_s1, h5t_str_nullterm_f, &
73 h5kind_to_type, h5_real_kind, h5_integer_kind, h5pset_virtual_f, &
74 h5s_scalar_f, h5s_select_set_f, h5fd_mpio_collective_f, h5p_default_f, &
75 h5s_unlimited_f
76#endif
77 implicit none
78 private
79
81 type, public, extends(generic_file_t) :: vtkhdf_file_t
82 logical :: amr_enabled = .false.
83 logical :: subdivide = .false.
84 logical :: enable_vds = .false.
85 integer :: precision = -1
86 contains
87 procedure :: get_vtkhdf_fname => vtkhdf_file_get_fname
88 procedure :: read => vtkhdf_file_read
89 procedure :: write => vtkhdf_file_write
90 procedure :: set_overwrite => vtkhdf_file_set_overwrite
91 procedure :: enable_amr => vtkhdf_file_enable_amr
92 procedure :: set_precision => vtkhdf_file_set_precision
93 procedure :: set_subdivide => vtkhdf_file_set_subdivide
94 end type vtkhdf_file_t
95
96 integer, dimension(2), parameter :: vtkhdf_version = [2, 6]
97
98contains
99
100 ! -------------------------------------------------------------------------- !
101 ! Well defined subroutines
102
104 subroutine vtkhdf_file_set_overwrite(this, overwrite)
105 class(vtkhdf_file_t), intent(inout) :: this
106 logical, intent(in) :: overwrite
107 this%overwrite = overwrite
108 end subroutine vtkhdf_file_set_overwrite
109
111 subroutine vtkhdf_file_enable_amr(this)
112 class(vtkhdf_file_t), intent(inout) :: this
113 this%amr_enabled = .false.
114 end subroutine vtkhdf_file_enable_amr
115
117 subroutine vtkhdf_file_set_precision(this, precision)
118 class(vtkhdf_file_t), intent(inout) :: this
119 integer, intent(in) :: precision
120 this%precision = precision
121 end subroutine vtkhdf_file_set_precision
122
124 function vtkhdf_file_get_fname(this) result(base_fname)
125 class(vtkhdf_file_t), intent(in) :: this
126 character(len=1024) :: base_fname
127 character(len=1024) :: fname
128 character(len=1024) :: path, name, suffix
129
130 fname = trim(this%get_base_fname())
131 call filename_split(fname, path, name, suffix)
132
133 write(base_fname, '(A,A,"_",I0,A)') &
134 trim(path), trim(name), this%get_start_counter(), trim(suffix)
135
136 end function vtkhdf_file_get_fname
137
143 subroutine vtkhdf_file_set_subdivide(this, subdivide)
144 class(vtkhdf_file_t), intent(inout) :: this
145 logical, intent(in) :: subdivide
146 this%subdivide = subdivide
147 end subroutine vtkhdf_file_set_subdivide
148
149#ifdef HAVE_HDF5
150 ! -------------------------------------------------------------------------- !
151 ! HDF5 Required subroutines
152
155 subroutine vtkhdf_file_write(this, data, t)
156 class(vtkhdf_file_t), intent(inout) :: this
157 class(*), target, intent(in) :: data
158 real(kind=rp), intent(in), optional :: t
159 type(mesh_t), pointer :: msh
160 type(dofmap_t), pointer :: dof
161 type(field_list_t) :: fields
162 integer :: ierr, mpi_info, mpi_comm, i, n_fields
163 integer(hid_t) :: plist_id, file_id, attr_id, vtkhdf_grp
164 integer(hid_t) :: filespace, H5T_NEKO_STRING
165 integer(hsize_t), dimension(1) :: vdims
166 integer(size_t) :: type_len
167 integer :: lx, ly, lz
168 integer :: local_points, local_cells, local_conn
169 integer :: total_points, total_cells, total_conn
170 integer :: point_offset
171 integer :: max_local_points
172 integer, allocatable :: part_points(:), part_cells(:), part_conns(:)
173 character(len=1024) :: fname
174 character(len=16) :: type_str
175 logical :: exists
176 integer :: counter
177
178 ! Determine mesh and field data
179 select type(data)
180 type is (field_t)
181 msh => data%msh
182 dof => data%dof
183 n_fields = 1
184 call fields%init(1)
185 ! Call the specific bindings; resolving the assign generic here
186 ! requires matching a TARGET actual to a POINTER, INTENT(IN) dummy
187 ! (F2008), which the Fujitsu compiler rejects
188 call fields%assign_to_field(1, data)
189 type is (field_list_t)
190 msh => data%msh(1)
191 dof => data%dof(1)
192 call fields%assign_to_list(data)
193 class default
194 call neko_error('Invalid data type for vtkhdf_file_write')
195 end select
196
197 ! Check conditions to ensure the input data is supported.
198 if (.not. associated(msh)) then
199 call neko_error('Mesh must be associated for vtkhdf_file_write')
200 end if
201 if (dof%Xh%lx .lt. 2 .or. dof%Xh%ly .lt. 2) then
202 call neko_error('VTKHDF linear output requires lx, ly >= 2')
203 end if
204 if (msh%gdim .eq. 3 .and. dof%Xh%lz .lt. 2) then
205 call neko_error('VTKHDF linear output requires lz >= 2 in 3D')
206 end if
207 if (msh%gdim .lt. 2 .or. msh%gdim .gt. 3) then
208 call neko_error('VTKHDF output only supports 2D and 3D meshes')
209 end if
210
211 ! Ensure precision is set and are valid.
212 if (this%precision .gt. rp) then
213 this%precision = rp
214 call neko_warning('Requested precision is higher than working precision')
215 else if (this%precision .eq. -1) then
216 this%precision = rp
217 end if
218
219 call this%increment_counter()
220 fname = trim(this%get_vtkhdf_fname())
221 counter = this%get_counter() - this%get_start_counter()
222
223 mpi_info = mpi_info_null%mpi_val
224 mpi_comm = neko_comm%mpi_val
225
226 call h5open_f(ierr)
227 call h5pcreate_f(h5p_file_access_f, plist_id, ierr)
228 call h5pset_fapl_mpio_f(plist_id, mpi_comm, mpi_info, ierr)
229
230 if (counter .eq. 0) then
231 ! First write: always create a fresh file to avoid stale data
232 call h5fcreate_f(fname, h5f_acc_trunc_f, &
233 file_id, ierr, access_prp = plist_id)
234 else
235 call h5fopen_f(fname, h5f_acc_rdwr_f, file_id, ierr, &
236 access_prp = plist_id)
237 end if
238
239 ! Create/open VTKHDF root group with vtkhdf_version and type attributes
240 call h5lexists_f(file_id, "VTKHDF", exists, ierr)
241 if (exists) then
242 call h5gopen_f(file_id, "VTKHDF", vtkhdf_grp, ierr)
243 else
244 call h5gcreate_f(file_id, "VTKHDF", vtkhdf_grp, ierr)
245
246 ! Write Version attribute
247 vdims = 2_hsize_t
248 call h5screate_simple_f(1, vdims, filespace, ierr)
249 call h5acreate_f(vtkhdf_grp, "Version", h5t_native_integer, filespace, &
250 attr_id, ierr)
251 call h5awrite_f(attr_id, h5t_native_integer, vtkhdf_version, vdims, ierr)
252 call h5aclose_f(attr_id, ierr)
253 call h5sclose_f(filespace, ierr)
254
255 ! Write Type attribute "UnstructuredGrid" as a fixed-length string
256 type_str = "UnstructuredGrid"
257 type_len = int(len_trim(type_str), kind=size_t)
258 vdims = 1_hsize_t
259 call h5screate_f(h5s_scalar_f, filespace, ierr)
260
261 call h5tcopy_f(h5t_fortran_s1, h5t_neko_string, ierr)
262 call h5tset_size_f(h5t_neko_string, type_len, ierr)
263 call h5tset_strpad_f(h5t_neko_string, h5t_str_nullterm_f, ierr)
264
265 call h5acreate_f(vtkhdf_grp, "Type", h5t_neko_string, filespace, &
266 attr_id, ierr)
267 call h5awrite_f(attr_id, h5t_neko_string, [type_str], vdims, ierr)
268 call h5aclose_f(attr_id, ierr)
269
270 call h5tclose_f(h5t_neko_string, ierr)
271 call h5sclose_f(filespace, ierr)
272 end if
273
274 if (present(t)) then
275 call vtkhdf_write_steps(vtkhdf_grp, counter, t)
276 end if
277
278 if (associated(msh)) then
279 call vtkhdf_write_mesh(vtkhdf_grp, dof, msh, &
280 this%amr_enabled, counter, this%subdivide, t)
281 end if
282
283 ! Write field data in PointData group
284 if (fields%size() .gt. 0) then
285 call vtkhdf_write_pointdata(vtkhdf_grp, fields, this%precision, &
286 counter, fname, t)
287 end if
288
289 call h5gclose_f(vtkhdf_grp, ierr)
290 call h5pclose_f(plist_id, ierr)
291
292 ! A leaked id defers the real (weak) close indefinitely, so the
293 ! metadata cache would never reach disk; flush explicitly and warn
294 ! if anything besides the file itself is still open.
295 block
296 integer(size_t) :: obj_count
297 character(len=80) :: wrn_buf
298 call h5fget_obj_count_f(file_id, h5f_obj_all_f, obj_count, ierr)
299 if (obj_count .gt. 1_size_t .and. pe_rank .eq. 0) then
300 write(wrn_buf, '(A,I0,A)') 'VTKHDF: ', obj_count - 1, &
301 ' HDF5 id(s) still open at file close'
302 call neko_warning(trim(wrn_buf))
303 end if
304 end block
305 call h5fflush_f(file_id, h5f_scope_global_f, ierr)
306 call h5fclose_f(file_id, ierr)
307 call h5close_f(ierr)
308
309 call fields%free()
310
311 end subroutine vtkhdf_file_write
312
313 ! -------------------------------------------------------------------------- !
314 ! Internal helper subroutines for VTKHDF writing
315
325 subroutine vtkhdf_write_mesh(vtkhdf_grp, dof, msh, amr, counter, subdivide, t)
326 type(dofmap_t), intent(in) :: dof
327 type(mesh_t), intent(in) :: msh
328 integer(hid_t), intent(in) :: vtkhdf_grp
329 logical, intent(in) :: amr
330 integer, intent(in) :: counter
331 logical, intent(in) :: subdivide
332 real(kind=rp), intent(in), optional :: t
333
334 integer(kind=1) :: VTK_cell_type
335 integer :: ierr, i, ii, jj, kk, el, local_idx
336 integer :: lx, ly, lz, npts_per_cell, nodes_per_cell, cells_per_element
337 integer :: local_points, local_cells, local_conn
338 integer :: total_points, total_cells, total_conn
339 integer :: point_offset, max_local_points
340 integer :: total_offsets, cell_offset, conn_offset, offsets_offset
341 integer :: max_local_cells, max_local_conn
342 integer(hid_t) :: xf_id, dset_id, dcpl_id, grp_id, attr_id
343 integer(hid_t) :: filespace, memspace, H5T_NEKO_DOUBLE
344 integer(hsize_t), dimension(1) :: dcount, vdims, maxdims, doffset, chunkdims
345 integer(hsize_t), dimension(2) :: dcount2, vdims2, maxdims2, doffset2
346 integer(kind=i8) :: i8_value
347 logical :: exists
348 integer, dimension(3) :: component_sizes
349 integer, dimension(3) :: component_offsets
350 integer, dimension(3) :: component_max_sizes
351
352 lx = dof%Xh%lx
353 ly = dof%Xh%ly
354 lz = dof%Xh%lz
355
356 if (subdivide .and. msh%gdim .eq. 3) then
357 vtk_cell_type = int(12, kind=1) ! VTK_HEXAHEDRON
358 cells_per_element = (lx - 1) * (ly - 1) * (lz - 1)
359 nodes_per_cell = 8
360 else if (subdivide .and. msh%gdim .eq. 2) then
361 vtk_cell_type = int(9, kind=1) ! VTK_QUAD
362 cells_per_element = (lx - 1) * (ly - 1)
363 nodes_per_cell = 4
364 else if (msh%gdim .eq. 3) then
365 vtk_cell_type = int(72, kind=1) ! VTK_LAGRANGE_HEXAHEDRON
366 cells_per_element = 1
367 nodes_per_cell = lx * ly * lz
368 else if (msh%gdim .eq. 2) then
369 vtk_cell_type = int(70, kind=1) ! VTK_LAGRANGE_QUADRILATERAL
370 cells_per_element = 1
371 nodes_per_cell = lx * ly
372 end if
373
374 ! --- Build the number of cells and the connectivity
375 local_points = dof%size()
376 local_cells = msh%nelv * cells_per_element
377 local_conn = local_cells * nodes_per_cell
378
379 total_points = dof%global_size()
380 total_cells = msh%glb_nelv * cells_per_element
381 total_conn = total_cells * nodes_per_cell
382
383 component_sizes = [local_points, local_cells, local_conn]
384 component_offsets = 0
385 component_max_sizes = 0
386
387 call mpi_exscan(component_sizes, component_offsets, 3, mpi_integer, &
388 mpi_sum, neko_comm, ierr)
389 call mpi_allreduce(component_sizes, component_max_sizes, 3, mpi_integer, &
390 mpi_max, neko_comm, ierr)
391
392 point_offset = component_offsets(1)
393 cell_offset = component_offsets(2)
394 conn_offset = component_offsets(3)
395 max_local_points = component_max_sizes(1)
396 max_local_cells = component_max_sizes(2)
397 max_local_conn = component_max_sizes(3)
398
399 offsets_offset = cell_offset + pe_rank
400 total_offsets = total_cells + pe_size
401
402 ! Create collective transfer property list
403 call h5pcreate_f(h5p_dataset_xfer_f, xf_id, ierr)
404 call h5pset_dxpl_mpio_f(xf_id, h5fd_mpio_collective_f, ierr)
405
406 ! --- NumberOfPoints, NumberOfCells, NumberOfConnectivityIds ---
407 ! These datasets must accumulate nPieces entries per timestep,
408 ! giving a total size of nSteps * nPieces. VTK's reader computes
409 ! numberOfPieces = dims[0] / nSteps, so missing entries cause
410 ! garbage reads.
411 block
412 integer(hsize_t), dimension(1) :: nof_dims, nof_maxdims
413 integer(hsize_t), dimension(1) :: nof_count, nof_offset, nof_chunk
414 integer(hid_t) :: nof_filespace, nof_memspace, nof_dcpl
415 integer(kind=i8) :: nof_values(3)
416
417 nof_count(1) = 1_hsize_t
418 nof_offset(1) = int(counter, hsize_t) * int(pe_size, hsize_t) &
419 + int(pe_rank, hsize_t)
420 nof_chunk(1) = max(1_hsize_t, int(pe_size, hsize_t))
421 nof_values = [int(local_points, kind=i8), int(local_cells, kind=i8), &
422 int(local_conn, kind=i8)]
423
424 call h5pcreate_f(h5p_dataset_create_f, nof_dcpl, ierr)
425 call h5pset_chunk_f(nof_dcpl, 1, nof_chunk, ierr)
426
427 call vtkhdf_write_numberof(vtkhdf_grp, "NumberOfPoints", &
428 nof_values(1), nof_offset, nof_count, nof_dcpl, &
429 counter, xf_id, ierr)
430 call vtkhdf_write_numberof(vtkhdf_grp, "NumberOfCells", &
431 nof_values(2), nof_offset, nof_count, nof_dcpl, &
432 counter, xf_id, ierr)
433 call vtkhdf_write_numberof(vtkhdf_grp, "NumberOfConnectivityIds", &
434 nof_values(3), nof_offset, nof_count, nof_dcpl, &
435 counter, xf_id, ierr)
436
437 call h5pclose_f(nof_dcpl, ierr)
438 end block
439
440 ! --- Points dataset (global coordinates) ---
441 call h5lexists_f(vtkhdf_grp, "Points", exists, ierr)
442 if (.not. exists) then
443
444 vdims2 = [3_hsize_t, int(total_points, hsize_t)]
445 maxdims2 = [3_hsize_t, h5s_unlimited_f]
446 chunkdims(1) = int(max(1, min(max_local_points, total_points)), hsize_t)
447 dcount2 = [3_hsize_t, int(local_points, hsize_t)]
448 doffset2 = [0_hsize_t, int(point_offset, hsize_t)]
449 h5t_neko_double = h5kind_to_type(dp, h5_real_kind)
450
451 call h5pcreate_f(h5p_dataset_create_f, dcpl_id, ierr)
452 call h5screate_simple_f(2, dcount2, memspace, ierr)
453 call h5screate_simple_f(2, vdims2, filespace, ierr, maxdims2)
454
455 call h5pset_chunk_f(dcpl_id, 2, [3_hsize_t, chunkdims(1)], ierr)
456 call h5dcreate_f(vtkhdf_grp, "Points", h5t_neko_double, &
457 filespace, dset_id, ierr, dcpl_id = dcpl_id)
458 call h5sselect_hyperslab_f(filespace, h5s_select_set_f, &
459 doffset2, dcount2, ierr)
460
461 block
462 real(kind=dp), allocatable :: coords(:,:)
463
464 allocate(coords(3, local_points))
465 do concurrent(local_idx = 1:local_points)
466 block
467 integer :: idx(4)
468 real(kind=dp) :: x, y, z
469 idx = nonlinear_index(local_idx, lx, ly, lz)
470
471 x = real(dof%x(idx(1), idx(2), idx(3), idx(4)), dp)
472 y = real(dof%y(idx(1), idx(2), idx(3), idx(4)), dp)
473 z = real(dof%z(idx(1), idx(2), idx(3), idx(4)), dp)
474
475 coords(1, local_idx) = x
476 coords(2, local_idx) = y
477 coords(3, local_idx) = z
478 end block
479 end do
480 call h5dwrite_f(dset_id, h5t_neko_double, coords, dcount2, ierr, &
481 file_space_id = filespace, mem_space_id = memspace, &
482 xfer_prp = xf_id)
483 deallocate(coords)
484 end block
485
486 call h5dclose_f(dset_id, ierr)
487 call h5sclose_f(filespace, ierr)
488 call h5sclose_f(memspace, ierr)
489 call h5pclose_f(dcpl_id, ierr)
490 end if
491
492 ! --- Connectivity dataset ---
493 call h5lexists_f(vtkhdf_grp, "Connectivity", exists, ierr)
494 if (exists) call h5ldelete_f(vtkhdf_grp, "Connectivity", ierr)
495
496 vdims = int(total_conn, hsize_t)
497 maxdims = h5s_unlimited_f
498 chunkdims = int(max(1, min(max_local_conn, total_conn)), hsize_t)
499 dcount = int(local_conn, hsize_t)
500 doffset = int(conn_offset, hsize_t)
501
502 call h5pcreate_f(h5p_dataset_create_f, dcpl_id, ierr)
503 call h5screate_simple_f(1, dcount, memspace, ierr)
504 call h5screate_simple_f(1, vdims, filespace, ierr, maxdims)
505
506 call h5pset_chunk_f(dcpl_id, 1, chunkdims, ierr)
507 call h5dcreate_f(vtkhdf_grp, "Connectivity", h5t_native_integer, &
508 filespace, dset_id, ierr, dcpl_id = dcpl_id)
509 call h5sselect_hyperslab_f(filespace, h5s_select_set_f, &
510 doffset, dcount, ierr)
511
512 block
513 integer, allocatable :: connectivity(:)
514
515 allocate(connectivity(local_conn))
516 call vtkhdf_build_connectivity(connectivity, vtk_cell_type, msh, dof, &
517 subdivide)
518 call h5dwrite_f(dset_id, h5t_native_integer, connectivity, dcount, &
519 ierr, file_space_id = filespace, mem_space_id = memspace, &
520 xfer_prp = xf_id)
521 deallocate(connectivity)
522 end block
523
524 call h5dclose_f(dset_id, ierr)
525 call h5sclose_f(filespace, ierr)
526 call h5sclose_f(memspace, ierr)
527 call h5pclose_f(dcpl_id, ierr)
528
529 ! --- Offsets dataset ---
530 call h5lexists_f(vtkhdf_grp, "Offsets", exists, ierr)
531 if (exists) call h5ldelete_f(vtkhdf_grp, "Offsets", ierr)
532
533 vdims = int(total_offsets, hsize_t)
534 maxdims = h5s_unlimited_f
535 chunkdims = int(max(1, min(max_local_cells + 1, total_offsets)), hsize_t)
536 dcount = int(local_cells + 1, hsize_t)
537 doffset = int(offsets_offset, hsize_t)
538
539 call h5pcreate_f(h5p_dataset_create_f, dcpl_id, ierr)
540 call h5screate_simple_f(1, dcount, memspace, ierr)
541 call h5screate_simple_f(1, vdims, filespace, ierr, maxdims)
542
543 call h5pset_chunk_f(dcpl_id, 1, chunkdims, ierr)
544 call h5dcreate_f(vtkhdf_grp, "Offsets", h5t_native_integer, &
545 filespace, dset_id, ierr, dcpl_id = dcpl_id)
546 call h5sselect_hyperslab_f(filespace, h5s_select_set_f, &
547 doffset, dcount, ierr)
548
549 block
550 integer, allocatable :: offsets(:)
551
552 allocate(offsets(local_cells + 1))
553 do concurrent(i = 1:local_cells)
554 offsets(i) = (i - 1) * nodes_per_cell
555 end do
556 offsets(local_cells + 1) = local_conn
557 call h5dwrite_f(dset_id, h5t_native_integer, offsets, dcount, ierr, &
558 file_space_id = filespace, mem_space_id = memspace, xfer_prp = xf_id)
559 deallocate(offsets)
560 end block
561
562 call h5dclose_f(dset_id, ierr)
563 call h5sclose_f(filespace, ierr)
564 call h5sclose_f(memspace, ierr)
565 call h5pclose_f(dcpl_id, ierr)
566
567 ! --- Types dataset (VTK cell types) ---
568 call h5lexists_f(vtkhdf_grp, "Types", exists, ierr)
569 if (exists) call h5ldelete_f(vtkhdf_grp, "Types", ierr)
570
571 vdims = int(total_cells, hsize_t)
572 maxdims = h5s_unlimited_f
573 chunkdims = int(max(1, min(max_local_cells, total_cells)), hsize_t)
574 dcount = int(local_cells, hsize_t)
575 doffset = int(cell_offset, hsize_t)
576
577 call h5pcreate_f(h5p_dataset_create_f, dcpl_id, ierr)
578 call h5screate_simple_f(1, dcount, memspace, ierr)
579 call h5screate_simple_f(1, vdims, filespace, ierr, maxdims)
580
581 call h5pset_chunk_f(dcpl_id, 1, chunkdims, ierr)
582 call h5dcreate_f(vtkhdf_grp, "Types", h5t_std_u8le, &
583 filespace, dset_id, ierr, dcpl_id = dcpl_id)
584 call h5sselect_hyperslab_f(filespace, h5s_select_set_f, &
585 doffset, dcount, ierr)
586
587 block
588 integer(kind=1), allocatable :: cell_types(:)
589 allocate(cell_types(local_cells), source=vtk_cell_type)
590 call h5dwrite_f(dset_id, h5t_std_u8le, cell_types, dcount, ierr, &
591 file_space_id = filespace, mem_space_id = memspace, xfer_prp = xf_id)
592 deallocate(cell_types)
593 end block
594
595 call h5dclose_f(dset_id, ierr)
596 call h5sclose_f(filespace, ierr)
597 call h5sclose_f(memspace, ierr)
598 call h5pclose_f(dcpl_id, ierr)
599
600 if (present(t)) then
601 ! Open Steps group
602 call h5gopen_f(vtkhdf_grp, "Steps", grp_id, ierr)
603
604 ! --- NumberOfParts ---
605 call vtkhdf_write_i8_at(grp_id, "NumberOfParts", int(pe_size, kind=i8), &
606 counter)
607
608 ! --- PartOffsets ---
609 i8_value = 0_i8
610 if (amr) then
611 i8_value = int(counter - 1, kind=i8) * int(pe_size, kind=i8)
612 call vtkhdf_write_i8_at(grp_id, "PartOffsets", i8_value, counter)
613
614 i8_value = int(counter - 1, kind=i8) * int(total_points, kind=i8)
615 call vtkhdf_write_i8_at(grp_id, "PointOffsets", i8_value, counter)
616
617 i8_value = int(counter - 1, kind=i8) * int(total_cells, kind=i8)
618 call vtkhdf_write_i8_at(grp_id, "CellOffsets", i8_value, counter)
619
620 i8_value = int(counter - 1, kind=i8) * int(total_conn, kind=i8)
621 call vtkhdf_write_i8_at(grp_id, "ConnectivityIdOffsets", i8_value, &
622 counter)
623
624 else
625 i8_value = 0_i8
626 call vtkhdf_write_i8_at(grp_id, "PartOffsets", i8_value, counter)
627 call vtkhdf_write_i8_at(grp_id, "PointOffsets", i8_value, counter)
628 call vtkhdf_write_i8_at(grp_id, "CellOffsets", i8_value, counter)
629 call vtkhdf_write_i8_at(grp_id, "ConnectivityIdOffsets", i8_value, &
630 counter)
631 end if
632
633 call h5gclose_f(grp_id, ierr)
634 end if
635
636 call h5pclose_f(xf_id, ierr)
637
638 end subroutine vtkhdf_write_mesh
639
646 subroutine vtkhdf_write_steps(vtkhdf_grp, counter, t)
647 integer(hid_t), intent(in) :: vtkhdf_grp
648 integer, intent(in) :: counter
649 real(kind=rp), intent(in) :: t
650
651 integer(hid_t) :: xf_id, H5T_NEKO_DOUBLE
652 integer :: ierr
653 integer(hid_t) :: grp_id, dset_id, dcpl_id, filespace, memspace, attr_id
654 integer(hsize_t), dimension(1) :: step_dims, step_maxdims
655 integer(hsize_t), dimension(1) :: step_count, step_offset, chunkdims, ddim
656 real(kind=dp), dimension(1) :: time_value
657 integer(kind=i8) :: i8_value
658 logical :: exists, attr_exists
659
660 ! Create collective transfer property list
661 call h5pcreate_f(h5p_dataset_xfer_f, xf_id, ierr)
662 call h5pset_dxpl_mpio_f(xf_id, h5fd_mpio_collective_f, ierr)
663 h5t_neko_double = h5kind_to_type(dp, h5_real_kind)
664
665 ! Create or open Steps group
666 call h5lexists_f(vtkhdf_grp, "Steps", exists, ierr)
667 if (exists) then
668 call h5gopen_f(vtkhdf_grp, "Steps", grp_id, ierr)
669 else
670 call h5gcreate_f(vtkhdf_grp, "Steps", grp_id, ierr)
671 end if
672
673 ! --- Values dataset (time values, real type) ---
674 call h5lexists_f(grp_id, "Values", exists, ierr)
675 if (exists) then
676 call h5dopen_f(grp_id, "Values", dset_id, ierr)
677 call h5dget_space_f(dset_id, filespace, ierr)
678 call h5sget_simple_extent_dims_f(filespace, step_dims, step_maxdims, &
679 ierr)
680 call h5sclose_f(filespace, ierr)
681
682 ! We have not written this timestep yet, expand the array
683 if (step_dims(1) .eq. int(counter, hsize_t)) then
684 step_dims(1) = int(counter + 1, hsize_t)
685 call h5dset_extent_f(dset_id, step_dims, ierr)
686 else if (step_dims(1) .lt. int(counter, hsize_t)) then
687 call neko_error("VTKHDF: Time steps written out of order.")
688 end if
689 else
690 step_dims(1) = 1_hsize_t
691 step_maxdims(1) = h5s_unlimited_f
692 chunkdims(1) = 1_hsize_t
693
694 call h5screate_simple_f(1, step_dims, filespace, ierr, step_maxdims)
695 call h5pcreate_f(h5p_dataset_create_f, dcpl_id, ierr)
696 call h5pset_chunk_f(dcpl_id, 1, chunkdims, ierr)
697 call h5dcreate_f(grp_id, "Values", h5t_neko_double, &
698 filespace, dset_id, ierr, dcpl_id = dcpl_id)
699 call h5sclose_f(filespace, ierr)
700 call h5pclose_f(dcpl_id, ierr)
701 end if
702
703 step_count(1) = 1_hsize_t
704 step_offset(1) = int(counter, hsize_t)
705
706 call h5dget_space_f(dset_id, filespace, ierr)
707 call h5screate_simple_f(1, step_count, memspace, ierr)
708 call h5sselect_hyperslab_f(filespace, h5s_select_set_f, &
709 step_offset, step_count, ierr)
710
711 time_value(1) = real(t, kind=dp)
712 call h5dwrite_f(dset_id, h5t_neko_double, time_value, step_count, ierr, &
713 file_space_id = filespace, mem_space_id = memspace, xfer_prp = xf_id)
714
715 call h5sclose_f(memspace, ierr)
716 call h5sclose_f(filespace, ierr)
717 call h5dclose_f(dset_id, ierr)
718
719 ! --- NSteps attribute ---
720 ddim(1) = 1_hsize_t
721 call h5aexists_f(grp_id, "NSteps", attr_exists, ierr)
722 if (attr_exists) then
723 call h5aopen_f(grp_id, "NSteps", attr_id, ierr)
724 else
725 call h5screate_f(h5s_scalar_f, filespace, ierr)
726 call h5acreate_f(grp_id, "NSteps", h5t_native_integer, filespace, &
727 attr_id, ierr, h5p_default_f, h5p_default_f)
728 call h5sclose_f(filespace, ierr)
729 end if
730
731 call h5awrite_f(attr_id, h5t_native_integer, counter + 1, ddim, ierr)
732
733 call h5aclose_f(attr_id, ierr)
734 call h5gclose_f(grp_id, ierr)
735 call h5pclose_f(xf_id, ierr)
736
737 end subroutine vtkhdf_write_steps
738
753 subroutine vtkhdf_write_pointdata(vtkhdf_grp, fields, precision, counter, &
754 fname, t)
755 integer(hid_t), intent(in) :: vtkhdf_grp
756 type(field_list_t), intent(inout) :: fields
757 integer, intent(in) :: precision
758 integer, intent(in) :: counter
759 character(len=*), intent(in) :: fname
760 real(kind=rp), intent(in), optional :: t
761
762 integer(kind=i8) :: time_offset
763 integer :: local_points, point_offset, total_points
764 integer(hid_t) :: precision_hdf
765 integer :: ierr, i, j
766 integer :: n_fields
767 integer(hid_t) :: pointdata_grp, grp_id, step_grp_id
768 integer(hid_t) :: dset_id, dcpl_id, filespace
769 integer(hsize_t), dimension(1) :: pd_dims1, pd_maxdims1
770 integer(hsize_t), dimension(2) :: pd_dims2, pd_maxdims2
771 type(field_t), pointer :: u, v, w
772 character(len=128) :: field_name
773 logical :: exists, is_vector
774
775 ! VDS and per-timestep external file variables
776 character(len=1024) :: ext_fname, ext_path, src_pattern
777 character(len=1024) :: main_path, main_name, main_suffix
778 integer(hid_t) :: ext_file_id, ext_plist_id, vds_src_space
779 integer(hid_t) :: write_target, attr_id, H5T_NEKO_STRING
780 integer :: mpi_info, mpi_comm
781
782 ! Collected field info for VDS phase
783 integer :: fields_written
784 character(len=128), allocatable :: name_list(:)
785 logical, allocatable :: vector_list(:)
786
787 mpi_info = mpi_info_null%mpi_val
788 mpi_comm = neko_comm%mpi_val
789
790 n_fields = fields%size()
791
792 ! Compute local/global point counts and MPI offsets
793 local_points = fields%item_size(1)
794 total_points = fields%items(1)%ptr%dof%global_size()
795 point_offset = 0
796 call mpi_exscan(local_points, point_offset, 1, mpi_integer, &
797 mpi_sum, neko_comm, ierr)
798
799 ! Sync all the fields
800 do i = 1, n_fields
801 if (associated(fields%items(i)%ptr)) then
802 call fields%items(i)%ptr%copy_from(device_to_host, sync = i .eq. n_fields)
803 end if
804 end do
805
806 fields_written = 0
807 allocate(name_list(n_fields))
808 allocate(vector_list(n_fields))
809
810 ! Create PointData group if missing
811 call h5lexists_f(vtkhdf_grp, "PointData", exists, ierr)
812 if (.not. exists) then
813 call h5gcreate_f(vtkhdf_grp, "PointData", pointdata_grp, ierr)
814 call h5gclose_f(pointdata_grp, ierr)
815 end if
816
817 ! ------------------------------------------------------------------------ !
818 ! Construct the target where data is written
819
820 if (present(t)) then
821
822 ! Derive base path from main filename for external files
823 call filename_split(fname, main_path, main_name, main_suffix)
824 write(ext_path, '(A,A,".data/")') trim(main_path), trim(main_name)
825 write(ext_fname, '(A,I0,".h5")') trim(ext_path), counter
826 write(src_pattern, '(A,".data/%b.h5")') trim(main_name)
827
828 if (pe_rank .eq. 0) then
829 call mkdir(trim(ext_path))
830 end if
831 call mpi_barrier(neko_comm, ierr)
832
833 call h5pcreate_f(h5p_file_access_f, ext_plist_id, ierr)
834 call h5pset_fapl_mpio_f(ext_plist_id, mpi_comm, mpi_info, ierr)
835 call h5fcreate_f(trim(ext_fname), h5f_acc_trunc_f, write_target, ierr, &
836 access_prp = ext_plist_id)
837 call h5pclose_f(ext_plist_id, ierr)
838
839 else
840 ! Non-temporal: write directly into the main file's PointData group
841 call h5gopen_f(vtkhdf_grp, "PointData", write_target, ierr)
842 end if
843
844 ! ------------------------------------------------------------------------ !
845 ! Write field data
846
847 do i = 1, n_fields
848 field_name = fields%name(i)
849 if (field_name .eq. 'p') field_name = 'Pressure'
850
851 ! Determine if this is a velocity component to group as a vector
852 is_vector = .false.
853 if (field_name .eq. 'u' .or. field_name .eq. 'v' .or. &
854 field_name .eq. 'w') then
855 u => null()
856 v => null()
857 w => null()
858 do j = 1, n_fields
859 select case (trim(fields%name(j)))
860 case ('u')
861 u => fields%get(j)
862 case ('v')
863 v => fields%get(j)
864 case ('w')
865 w => fields%get(j)
866 end select
867 end do
868
869 if (associated(u) .and. associated(v) .and. associated(w)) then
870 is_vector = .true.
871 field_name = 'Velocity'
872 end if
873 end if
874
875 ! Skip duplicate fields (e.g. fluid_rho added by both fluid output
876 ! and field_writer when sharing the same output file)
877 exists = .false.
878 do j = 1, fields_written
879 if (trim(name_list(j)) .eq. trim(field_name)) then
880 exists = .true.
881 exit
882 end if
883 end do
884
885 ! Skip duplicate fields
886 if (exists) cycle
887
888 ! Track unique field names for VDS phase
889 fields_written = fields_written + 1
890 name_list(fields_written) = field_name
891 vector_list(fields_written) = is_vector
892
893 ! Write field data to the target
894 if (is_vector) then
895 call write_vector_field(write_target, field_name, u%x, v%x, w%x, &
896 local_points, precision, total_points, point_offset)
897 else
898 call write_scalar_field(write_target, field_name, fields%x(i), &
899 local_points, precision, total_points, point_offset)
900 end if
901 end do
902
903 ! Close write target
904 if (present(t)) then
905 call h5fclose_f(write_target, ierr)
906 else
907 call h5gclose_f(write_target, ierr)
908 end if
909
910 ! ------------------------------------------------------------------------ !
911 ! Manage temporal datasets through VDS
912
913 if (present(t)) then
914
915 ! Temporal: set up per-timestep external file as write target
916 call h5gopen_f(vtkhdf_grp, "Steps", step_grp_id, ierr)
917 time_offset = int(counter, kind=i8) * int(total_points, kind=i8)
918
919 ! Write PointDataOffsets under Steps for each unique field
920 call h5lexists_f(step_grp_id, "PointDataOffsets", exists, ierr)
921 if (exists) then
922 call h5gopen_f(step_grp_id, "PointDataOffsets", grp_id, ierr)
923 else
924 call h5gcreate_f(step_grp_id, "PointDataOffsets", grp_id, ierr)
925 end if
926 do i = 1, fields_written
927 call vtkhdf_write_i8_at(grp_id, trim(name_list(i)), &
928 time_offset, counter)
929 end do
930 call h5gclose_f(grp_id, ierr)
931 call h5gclose_f(step_grp_id, ierr)
932
933 ! ===== Create or extend VDS in main file =====
934 call h5gopen_f(vtkhdf_grp, "PointData", pointdata_grp, ierr)
935
936 do i = 1, fields_written
937 field_name = name_list(i)
938 is_vector = vector_list(i)
939
940 if (counter .eq. 0) then
941 ! First write: create VDS with pattern-based mapping
942 call h5pcreate_f(h5p_dataset_create_f, dcpl_id, ierr)
943 precision_hdf = h5kind_to_type(precision, h5_real_kind)
944
945 if (is_vector) then
946 pd_dims2 = [3_hsize_t, int(total_points, hsize_t)]
947 call h5screate_simple_f(2, pd_dims2, vds_src_space, ierr)
948 call h5sselect_all_f(vds_src_space, ierr)
949
950 pd_maxdims2 = [3_hsize_t, h5s_unlimited_f]
951 call h5screate_simple_f(2, pd_dims2, filespace, ierr, &
952 pd_maxdims2)
953
954 call h5sselect_hyperslab_f(filespace, h5s_select_set_f, &
955 [0_hsize_t, 0_hsize_t], &
956 [1_hsize_t, h5s_unlimited_f], &
957 ierr, &
958 stride = [3_hsize_t, int(total_points, hsize_t)], &
959 block = [3_hsize_t, int(total_points, hsize_t)])
960
961 call h5pset_virtual_f(dcpl_id, filespace, trim(src_pattern), &
962 trim(field_name), vds_src_space, ierr)
963 call h5sclose_f(vds_src_space, ierr)
964
965 call h5dcreate_f(pointdata_grp, trim(field_name), &
966 precision_hdf, filespace, dset_id, ierr, &
967 dcpl_id = dcpl_id)
968 call h5sclose_f(filespace, ierr)
969 else
970 pd_dims1 = int(total_points, hsize_t)
971 call h5screate_simple_f(1, pd_dims1, vds_src_space, ierr)
972 call h5sselect_all_f(vds_src_space, ierr)
973
974 pd_maxdims1(1) = h5s_unlimited_f
975 call h5screate_simple_f(1, pd_dims1, filespace, ierr, &
976 pd_maxdims1)
977
978 call h5sselect_hyperslab_f(filespace, h5s_select_set_f, &
979 [0_hsize_t], &
980 [h5s_unlimited_f], &
981 ierr, &
982 stride = [int(total_points, hsize_t)], &
983 block = [int(total_points, hsize_t)])
984
985 call h5pset_virtual_f(dcpl_id, filespace, trim(src_pattern), &
986 trim(field_name), vds_src_space, ierr)
987 call h5sclose_f(vds_src_space, ierr)
988
989 call h5dcreate_f(pointdata_grp, trim(field_name), &
990 precision_hdf, filespace, dset_id, ierr, &
991 dcpl_id = dcpl_id)
992 call h5sclose_f(filespace, ierr)
993 end if
994
995 call h5pclose_f(dcpl_id, ierr)
996 call h5dclose_f(dset_id, ierr)
997
998 else
999 ! Subsequent write: extend VDS to include new timestep
1000 call h5dopen_f(pointdata_grp, trim(field_name), dset_id, ierr)
1001
1002 if (is_vector) then
1003 pd_dims2 = [3_hsize_t, &
1004 int(counter + 1, hsize_t) * int(total_points, hsize_t)]
1005 call h5dset_extent_f(dset_id, pd_dims2, ierr)
1006 else
1007 pd_dims1 = int(counter + 1, hsize_t) * int(total_points, hsize_t)
1008 call h5dset_extent_f(dset_id, pd_dims1, ierr)
1009 end if
1010
1011 call h5dclose_f(dset_id, ierr)
1012 end if
1013 end do
1014
1015 call h5gclose_f(pointdata_grp, ierr)
1016 end if
1017
1018 ! ------------------------------------------------------------------------ !
1019 ! Add attributes to the PointData
1020
1021 do i = 1, fields_written
1022 field_name = name_list(i)
1023 is_vector = vector_list(i)
1024 pd_dims1 = 1_hsize_t
1025
1026 call h5gopen_f(vtkhdf_grp, "PointData", pointdata_grp, ierr)
1027 call h5dopen_f(pointdata_grp, trim(field_name), dset_id, ierr)
1028
1029 call h5aexists_f(dset_id, "Attribute", exists, ierr)
1030 if (exists) then
1031 call h5dclose_f(dset_id, ierr)
1032 call h5gclose_f(pointdata_grp, ierr)
1033 cycle
1034 end if
1035
1036 ! Write the attribute what this PointData represents
1037 call h5screate_f(h5s_scalar_f, filespace, ierr)
1038
1039 call h5tcopy_f(h5t_fortran_s1, h5t_neko_string, ierr)
1040 call h5tset_size_f(h5t_neko_string, int(6, size_t), ierr)
1041 call h5tset_strpad_f(h5t_neko_string, h5t_str_nullterm_f, ierr)
1042
1043 call h5acreate_f(dset_id, "Attribute", h5t_neko_string, filespace, &
1044 attr_id, ierr)
1045 if (is_vector) then
1046 call h5awrite_f(attr_id, h5t_neko_string, ["Vector"], pd_dims1, ierr)
1047 else
1048 call h5awrite_f(attr_id, h5t_neko_string, ["Scalar"], pd_dims1, ierr)
1049 end if
1050
1051 call h5aclose_f(attr_id, ierr)
1052 call h5tclose_f(h5t_neko_string, ierr)
1053 call h5sclose_f(filespace, ierr)
1054 call h5dclose_f(dset_id, ierr)
1055 call h5gclose_f(pointdata_grp, ierr)
1056
1057 end do
1058
1059 ! ------------------------------------------------------------------------ !
1060 ! Cleanup before returning
1061
1062 deallocate(name_list)
1063 deallocate(vector_list)
1064
1065 end subroutine vtkhdf_write_pointdata
1066
1067 ! -------------------------------------------------------------------------- !
1068 ! Helper functions and routines
1069
1082 subroutine vtkhdf_build_connectivity(conn, vtk_type, msh, dof, subdivide)
1083 integer, intent(inout) :: conn(:)
1084 integer(kind=1), intent(in) :: vtk_type
1085 type(mesh_t), intent(in) :: msh
1086 type(dofmap_t), intent(in) :: dof
1087 logical, intent(in) :: subdivide
1088 integer :: lx, ly, lz, nelv
1089 integer :: ie, ii, n_pts_per_elem, n_conn_per_elem
1090 integer, allocatable :: node_order(:)
1091
1092 nelv = msh%nelv
1093 lx = dof%Xh%lx
1094 ly = dof%Xh%ly
1095 lz = dof%Xh%lz
1096 n_pts_per_elem = lx * ly * lz
1097
1098 if (subdivide .and. vtk_type .eq. int(12, kind=1)) then
1099 node_order = subdivide_to_hex_ordering(lx, ly, lz)
1100 else if (subdivide .and. vtk_type .eq. int(9, kind=1)) then
1101 node_order = subdivide_to_quad_ordering(lx, ly)
1102 else
1103 node_order = vtk_ordering(vtk_type, lx, ly, lz)
1104 end if
1105
1106 n_conn_per_elem = size(node_order)
1107
1108 do concurrent(ie = 1:nelv, ii = 1:n_conn_per_elem)
1109 block
1110 integer :: idx, base
1111 idx = (ie - 1) * n_conn_per_elem
1112 base = (ie - 1) * n_pts_per_elem
1113 conn(idx + ii) = base + node_order(ii)
1114 end block
1115 end do
1116
1117 deallocate(node_order)
1118
1119 end subroutine vtkhdf_build_connectivity
1120
1133 subroutine vtkhdf_write_numberof(grp, dset_name, value, offset, cnt, &
1134 dcpl, index, xf_id, ierr)
1135 integer(hid_t), intent(in) :: grp, dcpl, xf_id
1136 character(len=*), intent(in) :: dset_name
1137 integer(kind=i8), intent(in) :: value
1138 integer, intent(in):: index
1139 integer(hsize_t), dimension(1), intent(in) :: offset, cnt
1140 integer, intent(out) :: ierr
1141
1142 integer(hid_t) :: dset_id, fspace, mspace
1143 integer(hsize_t), dimension(1) :: dims, maxdims
1144 integer(hid_t) :: H5T_NEKO_INTEGER
1145 logical :: exists
1146
1147 h5t_neko_integer = h5kind_to_type(i8, h5_integer_kind)
1148
1149 call h5lexists_f(grp, dset_name, exists, ierr)
1150 if (exists) then
1151 call h5dopen_f(grp, dset_name, dset_id, ierr)
1152 dims(1) = int(index + 1, hsize_t) * int(pe_size, hsize_t)
1153 call h5dset_extent_f(dset_id, dims, ierr)
1154 else
1155 dims(1) = int(pe_size, hsize_t)
1156 maxdims(1) = h5s_unlimited_f
1157 call h5screate_simple_f(1, dims, fspace, ierr, maxdims)
1158 call h5dcreate_f(grp, dset_name, h5t_neko_integer, &
1159 fspace, dset_id, ierr, dcpl_id = dcpl)
1160 call h5sclose_f(fspace, ierr)
1161 end if
1162
1163 call h5dget_space_f(dset_id, fspace, ierr)
1164 call h5screate_simple_f(1, cnt, mspace, ierr)
1165 call h5sselect_hyperslab_f(fspace, h5s_select_set_f, offset, cnt, ierr)
1166
1167 call h5dwrite_f(dset_id, h5t_neko_integer, value, cnt, ierr, &
1168 file_space_id = fspace, mem_space_id = mspace, xfer_prp = xf_id)
1169
1170 call h5sclose_f(mspace, ierr)
1171 call h5sclose_f(fspace, ierr)
1172 call h5dclose_f(dset_id, ierr)
1173 end subroutine vtkhdf_write_numberof
1174
1182 subroutine vtkhdf_write_i8_at(grp_id, name, value, index)
1183 integer(hid_t), intent(in) :: grp_id
1184 character(len=*), intent(in) :: name
1185 integer(kind=i8), intent(in) :: value
1186 integer, intent(in) :: index
1187
1188 integer :: ierr
1189 integer(hid_t) :: dset_id, dcpl_id, xf_id, filespace, memspace
1190 integer(hsize_t), dimension(1) :: dims, maxdims, count, offset, chunkdims
1191 integer(hid_t) :: H5T_NEKO_INTEGER
1192 logical :: exists
1193
1194 h5t_neko_integer = h5kind_to_type(i8, h5_integer_kind)
1195
1196 ! Create collective transfer property list
1197 call h5pcreate_f(h5p_dataset_xfer_f, xf_id, ierr)
1198 call h5pset_dxpl_mpio_f(xf_id, h5fd_mpio_collective_f, ierr)
1199
1200 call h5lexists_f(grp_id, name, exists, ierr)
1201 if (exists) then
1202 call h5dopen_f(grp_id, name, dset_id, ierr)
1203 call h5dget_space_f(dset_id, filespace, ierr)
1204 call h5sget_simple_extent_dims_f(filespace, dims, maxdims, ierr)
1205 call h5sclose_f(filespace, ierr)
1206
1207 if (int(index, hsize_t) .eq. dims(1)) then
1208 dims(1) = int(index + 1, hsize_t)
1209 call h5dset_extent_f(dset_id, dims, ierr)
1210 else if (int(index, hsize_t) .gt. dims(1)) then
1211 call neko_error("VTKHDF: Values written out of order.")
1212 end if
1213 else
1214 dims = 1_hsize_t
1215 maxdims = h5s_unlimited_f
1216 chunkdims = 1_hsize_t
1217
1218 call h5screate_simple_f(1, dims, filespace, ierr, maxdims)
1219 call h5pcreate_f(h5p_dataset_create_f, dcpl_id, ierr)
1220 call h5pset_chunk_f(dcpl_id, 1, chunkdims, ierr)
1221 call h5dcreate_f(grp_id, name, h5t_neko_integer, &
1222 filespace, dset_id, ierr, dcpl_id = dcpl_id)
1223 call h5sclose_f(filespace, ierr)
1224 call h5pclose_f(dcpl_id, ierr)
1225 end if
1226
1227 count = 1_hsize_t
1228 offset = int(index, hsize_t)
1229
1230 call h5dget_space_f(dset_id, filespace, ierr)
1231 call h5screate_simple_f(1, count, memspace, ierr)
1232 call h5sselect_hyperslab_f(filespace, h5s_select_set_f, offset, count, ierr)
1233 call h5dwrite_f(dset_id, h5t_neko_integer, value, count, ierr, &
1234 file_space_id = filespace, mem_space_id = memspace, xfer_prp = xf_id)
1235
1236 call h5sclose_f(memspace, ierr)
1237 call h5sclose_f(filespace, ierr)
1238 call h5dclose_f(dset_id, ierr)
1239 call h5pclose_f(xf_id, ierr)
1240
1241 end subroutine vtkhdf_write_i8_at
1242
1254 subroutine write_scalar_field(hdf_root, name, x, n_local, &
1255 precision, n_total, offset)
1256 integer, intent(in) :: n_local
1257 integer(hid_t), intent(in) :: hdf_root
1258 character(len=*), intent(in) :: name
1259 real(kind=rp), dimension(n_local), intent(in) :: x
1260 integer, intent(in), optional :: precision
1261 integer, intent(in), optional :: n_total, offset
1262
1263 integer(hsize_t), dimension(1) :: dims, dcount, doffset
1264 integer(hid_t) :: xf_id, dset_id, filespace, memspace, precision_hdf
1265 integer :: i, ierr, precision_local, n_tot, off
1266
1267 ! Setup data sizes, offsets and precision
1268 dcount = int(n_local, hsize_t)
1269
1270 if (present(n_total)) then
1271 dims = int(n_total, hsize_t)
1272 else
1273 call mpi_allreduce(n_local, n_tot, 1, mpi_integer, mpi_sum, neko_comm, &
1274 ierr)
1275 dims = int(n_tot, hsize_t)
1276 end if
1277
1278 if (present(offset)) then
1279 doffset = int(offset, hsize_t)
1280 else
1281 call mpi_exscan(n_local, off, 1, mpi_integer, mpi_sum, neko_comm, &
1282 ierr)
1283 doffset = int(off, hsize_t)
1284 end if
1285
1286 if (present(precision)) then
1287 precision_local = precision
1288 else
1289 precision_local = rp
1290 end if
1291 precision_hdf = h5kind_to_type(precision_local, h5_real_kind)
1292
1293 ! Prepare memory and filespaces
1294 call h5pcreate_f(h5p_dataset_xfer_f, xf_id, ierr)
1295 call h5pset_dxpl_mpio_f(xf_id, h5fd_mpio_collective_f, ierr)
1296
1297 call h5screate_simple_f(1, dims, filespace, ierr)
1298 call h5screate_simple_f(1, dcount, memspace, ierr)
1299 call h5sselect_hyperslab_f(filespace, h5s_select_set_f, &
1300 doffset, dcount, ierr)
1301
1302 call h5dcreate_f(hdf_root, trim(name), precision_hdf, &
1303 filespace, dset_id, ierr)
1304
1305 if (precision_local .eq. rp) then
1306 call h5dwrite_f(dset_id, precision_hdf, x, dcount, ierr, &
1307 file_space_id = filespace, mem_space_id = memspace, &
1308 xfer_prp = xf_id)
1309
1310 else if (precision_local .eq. sp) then
1311 block
1312 real(kind=sp), allocatable :: x_sp(:)
1313
1314 allocate(x_sp(n_local))
1315 do concurrent(i = 1:n_local)
1316 x_sp(i) = real(x(i), sp)
1317 end do
1318
1319 call h5dwrite_f(dset_id, precision_hdf, x_sp, dcount, ierr, &
1320 file_space_id = filespace, mem_space_id = memspace, &
1321 xfer_prp = xf_id)
1322 deallocate(x_sp)
1323 end block
1324
1325 else if (precision_local .eq. dp) then
1326 block
1327 real(kind=dp), allocatable :: x_dp(:)
1328
1329 allocate(x_dp(n_local))
1330 do concurrent(i = 1:n_local)
1331 x_dp(i) = real(x(i), dp)
1332 end do
1333
1334 call h5dwrite_f(dset_id, precision_hdf, x_dp, dcount, ierr, &
1335 file_space_id = filespace, mem_space_id = memspace, &
1336 xfer_prp = xf_id)
1337 deallocate(x_dp)
1338 end block
1339
1340 else if (precision_local .eq. qp) then
1341 block
1342 real(kind=qp), allocatable :: x_qp(:)
1343
1344 allocate(x_qp(n_local))
1345 do concurrent(i = 1:n_local)
1346 x_qp(i) = real(x(i), qp)
1347 end do
1348
1349 call h5dwrite_f(dset_id, precision_hdf, x_qp, dcount, ierr, &
1350 file_space_id = filespace, mem_space_id = memspace, &
1351 xfer_prp = xf_id)
1352 deallocate(x_qp)
1353 end block
1354
1355 else
1356 call neko_error("Unsupported precision in HDF5 write_scalar_field")
1357 end if
1358
1359 call h5sclose_f(filespace, ierr)
1360 call h5sclose_f(memspace, ierr)
1361 call h5dclose_f(dset_id, ierr)
1362 call h5pclose_f(xf_id, ierr)
1363 end subroutine write_scalar_field
1364
1378 subroutine write_vector_field(hdf_root, name, u, v, w, n_local, &
1379 precision, n_total, offset)
1380 integer, intent(in) :: n_local
1381 integer(hid_t), intent(in) :: hdf_root
1382 character(len=*), intent(in) :: name
1383 real(kind=rp), dimension(n_local), intent(in) :: u, v, w
1384 integer, intent(in), optional :: precision
1385 integer, intent(in), optional :: n_total, offset
1386
1387 integer(hsize_t), dimension(2) :: dims, dcount, doffset
1388 integer(hid_t) :: xf_id, dset_id, filespace, memspace, precision_hdf
1389 integer :: i, ierr, precision_local, n_tot, off
1390
1391 ! Setup data sizes, offsets and precision
1392 dcount = [3_hsize_t, int(n_local, hsize_t)]
1393
1394 if (present(n_total)) then
1395 dims = [3_hsize_t, int(n_total, hsize_t)]
1396 else
1397 call mpi_allreduce(n_local, n_tot, 1, mpi_integer, mpi_sum, neko_comm, &
1398 ierr)
1399 dims = [3_hsize_t, int(n_tot, hsize_t)]
1400 end if
1401
1402 if (present(offset)) then
1403 doffset = [0_hsize_t, int(offset, hsize_t)]
1404 else
1405 call mpi_exscan(n_local, off, 1, mpi_integer, mpi_sum, neko_comm, &
1406 ierr)
1407 doffset = [0_hsize_t, int(off, hsize_t)]
1408 end if
1409
1410 if (present(precision)) then
1411 precision_local = precision
1412 else
1413 precision_local = rp
1414 end if
1415 precision_hdf = h5kind_to_type(precision_local, h5_real_kind)
1416
1417 ! Prepare memory and filespaces
1418 call h5pcreate_f(h5p_dataset_xfer_f, xf_id, ierr)
1419 call h5pset_dxpl_mpio_f(xf_id, h5fd_mpio_collective_f, ierr)
1420
1421 call h5screate_simple_f(2, dims, filespace, ierr)
1422 call h5screate_simple_f(2, dcount, memspace, ierr)
1423 call h5sselect_hyperslab_f(filespace, h5s_select_set_f, &
1424 doffset, dcount, ierr)
1425
1426 call h5dcreate_f(hdf_root, trim(name), precision_hdf, filespace, dset_id, &
1427 ierr)
1428
1429 if (precision_local .eq. sp) then
1430 block
1431 real(kind=sp), allocatable :: f(:,:)
1432
1433 allocate(f(3, n_local))
1434 do concurrent(i = 1:n_local)
1435 f(1, i) = real(u(i), sp)
1436 f(2, i) = real(v(i), sp)
1437 f(3, i) = real(w(i), sp)
1438 end do
1439
1440 call h5dwrite_f(dset_id, precision_hdf, f, dcount, ierr, &
1441 file_space_id = filespace, mem_space_id = memspace, &
1442 xfer_prp = xf_id)
1443 deallocate(f)
1444 end block
1445
1446 else if (precision_local .eq. dp) then
1447 block
1448 real(kind=dp), allocatable :: f(:,:)
1449
1450 allocate(f(3, n_local))
1451 do concurrent(i = 1:n_local)
1452 f(1, i) = real(u(i), dp)
1453 f(2, i) = real(v(i), dp)
1454 f(3, i) = real(w(i), dp)
1455 end do
1456
1457 call h5dwrite_f(dset_id, precision_hdf, f, dcount, ierr, &
1458 file_space_id = filespace, mem_space_id = memspace, &
1459 xfer_prp = xf_id)
1460 deallocate(f)
1461 end block
1462
1463 else if (precision_local .eq. qp) then
1464 block
1465 real(kind=qp), allocatable :: f(:,:)
1466
1467 allocate(f(3, n_local))
1468 do concurrent(i = 1:n_local)
1469 f(1, i) = real(u(i), qp)
1470 f(2, i) = real(v(i), qp)
1471 f(3, i) = real(w(i), qp)
1472 end do
1473
1474 call h5dwrite_f(dset_id, precision_hdf, f, dcount, ierr, &
1475 file_space_id = filespace, mem_space_id = memspace, &
1476 xfer_prp = xf_id)
1477 deallocate(f)
1478 end block
1479
1480 else
1481 call neko_error("Unsupported precision in HDF5 write_vector_field")
1482 end if
1483
1484 call h5sclose_f(filespace, ierr)
1485 call h5sclose_f(memspace, ierr)
1486 call h5dclose_f(dset_id, ierr)
1487 call h5pclose_f(xf_id, ierr)
1488 end subroutine write_vector_field
1489
1490 ! -------------------------------------------------------------------------- !
1491 ! Reader functions and routines
1492
1494 subroutine vtkhdf_file_read(this, data)
1495 class(vtkhdf_file_t) :: this
1496 class(*), target, intent(inout) :: data
1497 character(len=1024) :: fname
1498 integer(hid_t) :: plist_id, file_id, vtkhdf_grp
1499 integer :: mpi_info, mpi_comm, counter, ierr
1500 type(field_list_t) :: fields
1501 integer :: i
1502
1503 ! Open the file
1504 fname = trim(this%get_base_fname())
1505 counter = this%get_counter() - this%get_start_counter()
1506 if (counter .lt. 0) counter = 0
1507
1508 mpi_info = mpi_info_null%mpi_val
1509 mpi_comm = neko_comm%mpi_val
1510
1511 call h5open_f(ierr)
1512 call h5pcreate_f(h5p_file_access_f, plist_id, ierr)
1513 call h5pset_fapl_mpio_f(plist_id, mpi_comm, mpi_info, ierr)
1514
1515 call h5fopen_f(fname, h5f_acc_rdonly_f, file_id, ierr, &
1516 access_prp = plist_id)
1517 if (ierr .ne. 0) then
1518 call neko_error('Error opening VTKHDF file: ' // trim(fname))
1519 end if
1520
1521 call h5gopen_f(file_id, "VTKHDF", vtkhdf_grp, ierr)
1522 if (ierr .ne. 0) then
1523 call h5fclose_f(file_id, ierr)
1524 call h5pclose_f(plist_id, ierr)
1525 call neko_error('VTKHDF group not found in file: ' // trim(fname))
1526 end if
1527
1528 select type (data)
1529 type is (field_t)
1530 call fields%init(1)
1531 ! Specific bindings instead of the assign generic (see
1532 ! vtkhdf_file_write); Fujitsu frt cannot resolve the generic
1533 call fields%assign_to_field(1, data)
1534 type is (field_list_t)
1535 call fields%assign_to_list(data)
1536 class default
1537 call neko_error("Unsupported data type in vtkhdf_file_read")
1538 end select
1539
1540 do i = 1, fields%size()
1541 call vtkhdf_read_field(vtkhdf_grp, fname, counter, fields%get(i))
1542 end do
1543 call fields%copy_from(host_to_device, .true.)
1544
1545 call h5gclose_f(vtkhdf_grp, ierr)
1546 call h5fclose_f(file_id, ierr)
1547 call h5pclose_f(plist_id, ierr)
1548 call h5close_f(ierr)
1549
1550 call fields%free()
1551
1552 end subroutine vtkhdf_file_read
1553
1563 subroutine vtkhdf_read_field(vtkhdf_grp, fname, counter, fld)
1564 integer(hid_t), intent(in) :: vtkhdf_grp
1565 character(len=*), intent(in) :: fname
1566 integer, intent(in) :: counter
1567 type(field_t), intent(inout) :: fld
1568
1569 character(len=:), allocatable :: field_name
1570 integer :: ierr, local_points, total_points, point_offset, component
1571 integer(hid_t) :: pointdata_grp, dset_id, filespace, memspace, xf_id
1572 integer(hid_t) :: dcpl_id, ext_file_id, ext_plist_id, attr_id
1573 integer(hid_t) :: H5T_NEKO_REAL
1574 integer(hsize_t), dimension(1) :: dcount1, doffset1
1575 integer(hsize_t), dimension(2) :: dcount2, doffset2
1576
1577 integer(size_t) :: vds_count
1578 character(len=128) :: dset_name
1579 character(len=1024) :: vds_src_file, ext_fname, main_path, main_name, main_suffix
1580 logical :: exists, is_vds
1581 real(kind=rp), allocatable :: vec_component(:,:)
1582 integer :: mpi_info, mpi_comm, pct_pos, nsteps
1583 character(len=256) :: error_message
1584
1585 field_name = trim(fld%name)
1586
1587 ! Validate counter against file's NSteps if temporal data exists
1588 call h5lexists_f(vtkhdf_grp, "Steps", exists, ierr)
1589 if (exists) then
1590 call h5aopen_by_name_f(vtkhdf_grp, "Steps", "NSteps", attr_id, ierr)
1591 call h5aread_f(attr_id, h5t_native_integer, nsteps, [1_hsize_t], ierr)
1592 call h5aclose_f(attr_id, ierr)
1593
1594 if (counter .ge. nsteps) then
1595 write(error_message, '(A,I0,A,I0)') &
1596 'VTKHDF read: counter ', counter, ' >= NSteps ', nsteps
1597 call neko_error(trim(error_message))
1598 end if
1599 end if
1600
1601 mpi_info = mpi_info_null%mpi_val
1602 mpi_comm = neko_comm%mpi_val
1603
1604 local_points = fld%dof%size()
1605 total_points = fld%dof%global_size()
1606 point_offset = 0
1607 call mpi_exscan(local_points, point_offset, 1, mpi_integer, &
1608 mpi_sum, neko_comm, ierr)
1609
1610 h5t_neko_real = h5kind_to_type(rp, h5_real_kind)
1611
1612 ! Open PointData group
1613 call h5gopen_f(vtkhdf_grp, "PointData", pointdata_grp, ierr)
1614
1615 ! Determine dataset name with standard mappings
1616 dset_name = trim(field_name)
1617 if (trim(dset_name) .eq. 'p') dset_name = 'Pressure'
1618
1619 component = -1
1620 call h5lexists_f(pointdata_grp, trim(dset_name), exists, ierr)
1621
1622 if (.not. exists) then
1623 if (trim(field_name) .eq. 'u' .or. trim(field_name) .eq. 'v' .or. &
1624 trim(field_name) .eq. 'w') then
1625 call h5lexists_f(pointdata_grp, "Velocity", exists, ierr)
1626 if (exists) then
1627 dset_name = 'Velocity'
1628 select case (trim(field_name))
1629 case ('u')
1630 component = 0
1631 case ('v')
1632 component = 1
1633 case ('w')
1634 component = 2
1635 end select
1636 end if
1637 end if
1638 end if
1639
1640 if (.not. exists) then
1641 call h5gclose_f(pointdata_grp, ierr)
1642 call neko_error('VTKHDF PointData field not found: ' // trim(dset_name))
1643 end if
1644
1645 ! Open the dataset and check if it's a VDS
1646 call h5dopen_f(pointdata_grp, trim(dset_name), dset_id, ierr)
1647 call h5dget_create_plist_f(dset_id, dcpl_id, ierr)
1648 call h5pget_virtual_count_f(dcpl_id, vds_count, ierr)
1649 is_vds = (vds_count .gt. 0_size_t)
1650
1651 if (is_vds) then
1652 call filename_split(fname, main_path, main_name, main_suffix)
1653
1654 ! Query mapping 0 to detect whether this is a printf-style pattern VDS
1655 ! (Neko's own format uses a single mapping with %b as a block counter
1656 ! placeholder) or a multi-mapping VDS where each timestep has its own
1657 ! literal source file.
1658 call h5pget_virtual_filename_f(dcpl_id, 0_size_t, vds_src_file, ierr)
1659 pct_pos = index(vds_src_file, '%b')
1660
1661 if (pct_pos .gt. 0) then
1662 ! Pattern-based VDS: replace %b with the timestep counter.
1663 ! If the stored path is absolute, use it as-is; otherwise prepend the
1664 ! main file's directory so the path is resolved correctly regardless
1665 ! of the process working directory.
1666 if (vds_src_file(1:1) .eq. '/') then
1667 write(ext_fname, '(A,I0,A)') &
1668 vds_src_file(1:pct_pos-1), counter, &
1669 trim(vds_src_file(pct_pos+2:))
1670 else
1671 write(ext_fname, '(A,A,I0,A)') &
1672 trim(main_path), vds_src_file(1:pct_pos-1), counter, &
1673 trim(vds_src_file(pct_pos+2:))
1674 end if
1675 else
1676 ! Multi-mapping VDS: one mapping per timestep. Query the mapping
1677 ! that corresponds directly to the requested counter instead of
1678 ! always using mapping 0, which would silently read the wrong file.
1679 if (int(counter, size_t) .ge. vds_count) then
1680 call h5pclose_f(dcpl_id, ierr)
1681 call h5dclose_f(dset_id, ierr)
1682 call h5gclose_f(pointdata_grp, ierr)
1683 write(error_message, '(A,I0,A,I0)') &
1684 'VTKHDF: VDS counter ', counter, &
1685 ' is out of range, number of mappings: ', int(vds_count)
1686 call neko_error(trim(error_message))
1687 end if
1688 call h5pget_virtual_filename_f(dcpl_id, int(counter, size_t), &
1689 vds_src_file, ierr)
1690 if (vds_src_file(1:1) .eq. '/') then
1691 ext_fname = trim(vds_src_file)
1692 else
1693 write(ext_fname, '(A,A)') trim(main_path), trim(vds_src_file)
1694 end if
1695 end if
1696
1697 call h5pclose_f(dcpl_id, ierr)
1698 call h5dclose_f(dset_id, ierr)
1699 call h5gclose_f(pointdata_grp, ierr)
1700
1701 call h5pcreate_f(h5p_file_access_f, ext_plist_id, ierr)
1702 call h5pset_fapl_mpio_f(ext_plist_id, mpi_comm, mpi_info, ierr)
1703 call h5fopen_f(trim(ext_fname), h5f_acc_rdonly_f, ext_file_id, ierr, &
1704 access_prp = ext_plist_id)
1705
1706 if (ierr .ne. 0) then
1707 call neko_error('VTKHDF: Cannot open VDS source file: ' // &
1708 trim(ext_fname))
1709 end if
1710
1711 ! Open the dataset from the external file
1712 call h5dopen_f(ext_file_id, trim(dset_name), dset_id, ierr)
1713
1714 call h5pclose_f(ext_plist_id, ierr)
1715 else
1716 call h5pclose_f(dcpl_id, ierr)
1717 ext_file_id = -1
1718 end if
1719
1720 ! Now read from the dataset (either original or from external file)
1721 call h5pcreate_f(h5p_dataset_xfer_f, xf_id, ierr)
1722 call h5pset_dxpl_mpio_f(xf_id, h5fd_mpio_collective_f, ierr)
1723 call h5dget_space_f(dset_id, filespace, ierr)
1724
1725 if (trim(dset_name) .eq. 'Velocity' .and. component .ge. 0) then
1726 ! Velocity is stored as (3, n_points), read one component
1727 dcount2 = [1_hsize_t, int(local_points, hsize_t)]
1728 doffset2 = [int(component, hsize_t), int(point_offset, hsize_t)]
1729
1730 call h5screate_simple_f(2, dcount2, memspace, ierr)
1731 call h5sselect_hyperslab_f(filespace, h5s_select_set_f, &
1732 doffset2, dcount2, ierr)
1733
1734 allocate(vec_component(1, local_points))
1735 call h5dread_f(dset_id, h5t_neko_real, vec_component, dcount2, ierr, &
1736 file_space_id = filespace, mem_space_id = memspace, &
1737 xfer_prp = xf_id)
1738 fld%x = reshape(vec_component, shape(fld%x))
1739 deallocate(vec_component)
1740 else
1741 ! Scalar field: 1D array
1742 dcount1 = int(local_points, hsize_t)
1743 doffset1 = int(point_offset, hsize_t)
1744
1745 call h5screate_simple_f(1, dcount1, memspace, ierr)
1746 call h5sselect_hyperslab_f(filespace, h5s_select_set_f, &
1747 doffset1, dcount1, ierr)
1748
1749 call h5dread_f(dset_id, h5t_neko_real, fld%x(1,1,1,1), dcount1, ierr, &
1750 file_space_id = filespace, mem_space_id = memspace, &
1751 xfer_prp = xf_id)
1752 end if
1753
1754 call h5sclose_f(memspace, ierr)
1755 call h5sclose_f(filespace, ierr)
1756 call h5dclose_f(dset_id, ierr)
1757 call h5pclose_f(xf_id, ierr)
1758
1759 if (is_vds) then
1760 call h5fclose_f(ext_file_id, ierr)
1761 else
1762 call h5gclose_f(pointdata_grp, ierr)
1763 end if
1764
1765 end subroutine vtkhdf_read_field
1766
1767#else
1768 ! -------------------------------------------------------------------------- !
1769 ! Dummy functions and subroutines
1770
1772 subroutine vtkhdf_file_write(this, data, t)
1773 class(vtkhdf_file_t), intent(inout) :: this
1774 class(*), target, intent(in) :: data
1775 real(kind=rp), intent(in), optional :: t
1776 call neko_error('Neko needs to be built with HDF5 support')
1777 end subroutine vtkhdf_file_write
1778
1780 subroutine vtkhdf_file_read(this, data)
1781 class(vtkhdf_file_t) :: this
1782 class(*), target, intent(inout) :: data
1783 call neko_error('Neko needs to be built with HDF5 support')
1784 end subroutine vtkhdf_file_read
1785
1786#endif
1787
1788 ! -------------------------------------------------------------------------- !
1789 ! Sub-cell node ordering functions for VTK compatibility
1790
1799 pure function subdivide_to_hex_ordering(lx, ly, lz) result(node_order)
1800 integer, intent(in) :: lx, ly, lz
1801 integer :: node_order(8 * (lx - 1) * (ly - 1) * (lz - 1))
1802 integer :: ii, jj, kk, idx
1803
1804 idx = 0
1805
1806 do ii = 1, lx - 1
1807 do jj = 1, ly - 1
1808 do kk = 1, lz - 1
1809 node_order(idx + 1) = (kk - 1) * lx * ly + (jj - 1) * lx + ii - 1
1810 node_order(idx + 2) = (kk - 1) * lx * ly + (jj - 1) * lx + ii
1811 node_order(idx + 3) = (kk - 1) * lx * ly + jj * lx + ii
1812 node_order(idx + 4) = (kk - 1) * lx * ly + jj * lx + ii - 1
1813 node_order(idx + 5) = kk * lx * ly + (jj - 1) * lx + ii - 1
1814 node_order(idx + 6) = kk * lx * ly + (jj - 1) * lx + ii
1815 node_order(idx + 7) = kk * lx * ly + jj * lx + ii
1816 node_order(idx + 8) = kk * lx * ly + jj * lx + ii - 1
1817 idx = idx + 8
1818 end do
1819 end do
1820 end do
1821
1822 end function subdivide_to_hex_ordering
1823
1831 pure function subdivide_to_quad_ordering(lx, ly) result(node_order)
1832 integer, intent(in) :: lx, ly
1833 integer :: node_order(4 * (lx - 1) * (ly - 1))
1834 integer :: ii, jj, idx
1835
1836 idx = 0
1837
1838 do jj = 1, ly - 1
1839 do ii = 1, lx - 1
1840 node_order(idx + 1) = (jj - 1) * lx + ii - 1
1841 node_order(idx + 2) = (jj - 1) * lx + ii
1842 node_order(idx + 3) = jj * lx + ii
1843 node_order(idx + 4) = jj * lx + ii - 1
1844 idx = idx + 4
1845 end do
1846 end do
1847
1848 end function subdivide_to_quad_ordering
1849
1850end module vtkhdf_file
__inline__ __device__ void nonlinear_index(const int idx, const int lx, int *index)
Definition bc_utils.h:44
double real
Defines a checkpoint.
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
Device abstraction, common interface for various accelerators.
Definition device.F90:34
integer, parameter, public host_to_device
Definition device.F90:48
integer, parameter, public device_to_host
Definition device.F90:48
Defines a mapping of the degrees of freedom.
Definition dofmap.f90:35
Contains the field_serties_t type.
Defines a field.
Definition field.f90:34
Logging routines.
Definition log.f90:34
type(log_t), public neko_log
Global log stream.
Definition log.f90:80
Defines a mesh.
Definition mesh.f90:34
integer, parameter, public i8
Definition num_types.f90:7
integer, parameter, public qp
Definition num_types.f90:10
integer, parameter, public dp
Definition num_types.f90:9
integer, parameter, public sp
Definition num_types.f90:8
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
Utilities.
Definition utils.f90:35
pure integer function, public linear_index(i, j, k, l, lx, ly, lz)
Compute the address of a (i,j,k,l) array with sizes (1:lx, 1:ly, 1:lz, :)
Definition utils.f90:289
subroutine, public filename_split(fname, path, name, suffix)
Extract file name components.
Definition utils.f90:131
subroutine, public neko_warning(warning_msg)
Reports a warning to standard output.
Definition utils.f90:398
recursive subroutine, public mkdir(path, mode)
Recursively create a directory and all parent directories if they do not exist. This should be safer ...
Definition utils.f90:174
VTK Module containing utilities for VTK file handling.
Definition vtk.f90:42
integer function, dimension(:), allocatable, public vtk_ordering(cell_type, lx, ly, lz)
Get the VTK node ordering for a given cell type. For Lagrange cells, returns an array mapping VTK nod...
Definition vtk.f90:60
VTKHDF file format.
subroutine vtkhdf_file_set_overwrite(this, overwrite)
Set the overwrite flag for HDF5 files.
subroutine vtkhdf_file_enable_amr(this)
Enable support for Adaptive Mesh Refinement.
subroutine vtkhdf_file_set_precision(this, precision)
Set the precision for VTKHDF output (single or double)
subroutine vtkhdf_file_write(this, data, t)
Write data in HDF5 format (no HDF5 support)
pure integer function, dimension(8 *(lx - 1) *(ly - 1) *(lz - 1)) subdivide_to_hex_ordering(lx, ly, lz)
Build linear hexahedron sub-cell node ordering for a spectral element. Returns an array of 0-based te...
integer, dimension(2), parameter vtkhdf_version
subroutine vtkhdf_file_set_subdivide(this, subdivide)
Enable or disable subdivision of spectral elements into linear sub-cells. When subdivision is enabled...
subroutine vtkhdf_file_read(this, data)
Read data in HDF5 format (no HDF5 support)
character(len=1024) function vtkhdf_file_get_fname(this)
Return the file name with the start counter.
pure integer function, dimension(4 *(lx - 1) *(ly - 1)) subdivide_to_quad_ordering(lx, ly)
Build linear quadrilateral sub-cell node ordering for a spectral element. Returns an array of 0-based...
field_list_t, To be able to group fields together
A wrapper for a pointer to a field_series_t.
Stores a series (sequence) of fields, logically connected to a base field, and arranged according to ...
A generic file handler.
Interface for HDF5 files.
#define max(a, b)
Definition tensor.cu:40