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