Neko 1.99.9
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
53#ifdef HAVE_HDF5
54 use hdf5, only : &
55 hid_t, hsize_t, size_t, &
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=dp), 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 hdf5_session_init()
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)
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=dp), 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%x(idx(1), idx(2), idx(3), idx(4)), dp)
482 y = real(dof%y%x(idx(1), idx(2), idx(3), idx(4)), dp)
483 z = real(dof%z%x(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=dp), 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) = t
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=dp), 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 ! Cleanup before returning
1030
1031 deallocate(name_list)
1032 deallocate(vector_list)
1033
1034 end subroutine vtkhdf_write_pointdata
1035
1036 ! -------------------------------------------------------------------------- !
1037 ! Helper functions and routines
1038
1051 subroutine vtkhdf_build_connectivity(conn, vtk_type, msh, dof, subdivide)
1052 integer, intent(inout) :: conn(:)
1053 integer(kind=1), intent(in) :: vtk_type
1054 type(mesh_t), intent(in) :: msh
1055 type(dofmap_t), intent(in) :: dof
1056 logical, intent(in) :: subdivide
1057 integer :: lx, ly, lz, nelv
1058 integer :: ie, ii, n_pts_per_elem, n_conn_per_elem
1059 integer, allocatable :: node_order(:)
1060
1061 nelv = msh%nelv
1062 lx = dof%Xh%lx
1063 ly = dof%Xh%ly
1064 lz = dof%Xh%lz
1065 n_pts_per_elem = lx * ly * lz
1066
1067 if (subdivide .and. vtk_type .eq. int(12, kind=1)) then
1068 node_order = subdivide_to_hex_ordering(lx, ly, lz)
1069 else if (subdivide .and. vtk_type .eq. int(9, kind=1)) then
1070 node_order = subdivide_to_quad_ordering(lx, ly)
1071 else
1072 node_order = vtk_ordering(vtk_type, lx, ly, lz)
1073 end if
1074
1075 n_conn_per_elem = size(node_order)
1076
1077 do concurrent(ie = 1:nelv, ii = 1:n_conn_per_elem)
1078 block
1079 integer :: idx, base
1080 idx = (ie - 1) * n_conn_per_elem
1081 base = (ie - 1) * n_pts_per_elem
1082 conn(idx + ii) = base + node_order(ii)
1083 end block
1084 end do
1085
1086 deallocate(node_order)
1087
1088 end subroutine vtkhdf_build_connectivity
1089
1102 subroutine vtkhdf_write_numberof(grp, dset_name, value, offset, cnt, &
1103 dcpl, index, xf_id, ierr)
1104 integer(hid_t), intent(in) :: grp, dcpl, xf_id
1105 character(len=*), intent(in) :: dset_name
1106 integer(kind=i8), intent(in) :: value
1107 integer, intent(in):: index
1108 integer(hsize_t), dimension(1), intent(in) :: offset, cnt
1109 integer, intent(out) :: ierr
1110
1111 integer(hid_t) :: dset_id, fspace, mspace
1112 integer(hsize_t), dimension(1) :: dims, maxdims
1113 integer(hid_t) :: H5T_NEKO_INTEGER
1114 logical :: exists
1115
1116 h5t_neko_integer = h5kind_to_type(i8, h5_integer_kind)
1117
1118 call h5lexists_f(grp, dset_name, exists, ierr)
1119 if (exists) then
1120 call h5dopen_f(grp, dset_name, dset_id, ierr)
1121 dims(1) = int(index + 1, hsize_t) * int(pe_size, hsize_t)
1122 call h5dset_extent_f(dset_id, dims, ierr)
1123 else
1124 dims(1) = int(pe_size, hsize_t)
1125 maxdims(1) = h5s_unlimited_f
1126 call h5screate_simple_f(1, dims, fspace, ierr, maxdims)
1127 call h5dcreate_f(grp, dset_name, h5t_neko_integer, &
1128 fspace, dset_id, ierr, dcpl_id = dcpl)
1129 call h5sclose_f(fspace, ierr)
1130 end if
1131
1132 call h5dget_space_f(dset_id, fspace, ierr)
1133 call h5screate_simple_f(1, cnt, mspace, ierr)
1134 call h5sselect_hyperslab_f(fspace, h5s_select_set_f, offset, cnt, ierr)
1135
1136 call h5dwrite_f(dset_id, h5t_neko_integer, value, cnt, ierr, &
1137 file_space_id = fspace, mem_space_id = mspace, xfer_prp = xf_id)
1138
1139 call h5sclose_f(mspace, ierr)
1140 call h5sclose_f(fspace, ierr)
1141 call h5dclose_f(dset_id, ierr)
1142 end subroutine vtkhdf_write_numberof
1143
1151 subroutine vtkhdf_write_i8_at(grp_id, name, value, index)
1152 integer(hid_t), intent(in) :: grp_id
1153 character(len=*), intent(in) :: name
1154 integer(kind=i8), intent(in) :: value
1155 integer, intent(in) :: index
1156
1157 integer :: ierr
1158 integer(hid_t) :: dset_id, dcpl_id, xf_id, filespace, memspace
1159 integer(hsize_t), dimension(1) :: dims, maxdims, count, offset, chunkdims
1160 integer(hid_t) :: H5T_NEKO_INTEGER
1161 logical :: exists
1162
1163 h5t_neko_integer = h5kind_to_type(i8, h5_integer_kind)
1164
1165 ! Create collective transfer property list
1166 call h5pcreate_f(h5p_dataset_xfer_f, xf_id, ierr)
1167 call h5pset_dxpl_mpio_f(xf_id, h5fd_mpio_collective_f, ierr)
1168
1169 call h5lexists_f(grp_id, name, exists, ierr)
1170 if (exists) then
1171 call h5dopen_f(grp_id, name, dset_id, ierr)
1172 call h5dget_space_f(dset_id, filespace, ierr)
1173 call h5sget_simple_extent_dims_f(filespace, dims, maxdims, ierr)
1174 call h5sclose_f(filespace, ierr)
1175
1176 if (int(index, hsize_t) .eq. dims(1)) then
1177 dims(1) = int(index + 1, hsize_t)
1178 call h5dset_extent_f(dset_id, dims, ierr)
1179 else if (int(index, hsize_t) .gt. dims(1)) then
1180 call neko_error("VTKHDF: Values written out of order.")
1181 end if
1182 else
1183 dims = 1_hsize_t
1184 maxdims = h5s_unlimited_f
1185 chunkdims = 1_hsize_t
1186
1187 call h5screate_simple_f(1, dims, filespace, ierr, maxdims)
1188 call h5pcreate_f(h5p_dataset_create_f, dcpl_id, ierr)
1189 call h5pset_chunk_f(dcpl_id, 1, chunkdims, ierr)
1190 call h5dcreate_f(grp_id, name, h5t_neko_integer, &
1191 filespace, dset_id, ierr, dcpl_id = dcpl_id)
1192 call h5sclose_f(filespace, ierr)
1193 call h5pclose_f(dcpl_id, ierr)
1194 end if
1195
1196 count = 1_hsize_t
1197 offset = int(index, hsize_t)
1198
1199 call h5dget_space_f(dset_id, filespace, ierr)
1200 call h5screate_simple_f(1, count, memspace, ierr)
1201 call h5sselect_hyperslab_f(filespace, h5s_select_set_f, offset, count, ierr)
1202 call h5dwrite_f(dset_id, h5t_neko_integer, value, count, ierr, &
1203 file_space_id = filespace, mem_space_id = memspace, xfer_prp = xf_id)
1204
1205 call h5sclose_f(memspace, ierr)
1206 call h5sclose_f(filespace, ierr)
1207 call h5dclose_f(dset_id, ierr)
1208 call h5pclose_f(xf_id, ierr)
1209
1210 end subroutine vtkhdf_write_i8_at
1211
1223 subroutine write_scalar_field(hdf_root, name, x, n_local, &
1224 precision, n_total, offset)
1225 integer, intent(in) :: n_local
1226 integer(hid_t), intent(in) :: hdf_root
1227 character(len=*), intent(in) :: name
1228 real(kind=rp), dimension(n_local), intent(in) :: x
1229 integer, intent(in), optional :: precision
1230 integer, intent(in), optional :: n_total, offset
1231
1232 integer(hsize_t), dimension(1) :: dims, dcount, doffset
1233 integer(hid_t) :: xf_id, dset_id, filespace, memspace, precision_hdf
1234 integer :: i, ierr, precision_local, n_tot, off
1235
1236 ! Setup data sizes, offsets and precision
1237 dcount = int(n_local, hsize_t)
1238
1239 if (present(n_total)) then
1240 dims = int(n_total, hsize_t)
1241 else
1242 call mpi_allreduce(n_local, n_tot, 1, mpi_integer, mpi_sum, neko_comm, &
1243 ierr)
1244 dims = int(n_tot, hsize_t)
1245 end if
1246
1247 if (present(offset)) then
1248 doffset = int(offset, hsize_t)
1249 else
1250 call mpi_exscan(n_local, off, 1, mpi_integer, mpi_sum, neko_comm, &
1251 ierr)
1252 doffset = int(off, hsize_t)
1253 end if
1254
1255 if (present(precision)) then
1256 precision_local = precision
1257 else
1258 precision_local = rp
1259 end if
1260 precision_hdf = h5kind_to_type(precision_local, h5_real_kind)
1261
1262 ! Prepare memory and filespaces
1263 call h5pcreate_f(h5p_dataset_xfer_f, xf_id, ierr)
1264 call h5pset_dxpl_mpio_f(xf_id, h5fd_mpio_collective_f, ierr)
1265
1266 call h5screate_simple_f(1, dims, filespace, ierr)
1267 call h5screate_simple_f(1, dcount, memspace, ierr)
1268 call h5sselect_hyperslab_f(filespace, h5s_select_set_f, &
1269 doffset, dcount, ierr)
1270
1271 call h5dcreate_f(hdf_root, trim(name), precision_hdf, &
1272 filespace, dset_id, ierr)
1273
1274 if (precision_local .eq. rp) then
1275 call h5dwrite_f(dset_id, precision_hdf, x, dcount, ierr, &
1276 file_space_id = filespace, mem_space_id = memspace, &
1277 xfer_prp = xf_id)
1278
1279 else if (precision_local .eq. sp) then
1280 block
1281 real(kind=sp), allocatable :: x_sp(:)
1282
1283 allocate(x_sp(n_local))
1284 do concurrent(i = 1:n_local)
1285 x_sp(i) = real(x(i), sp)
1286 end do
1287
1288 call h5dwrite_f(dset_id, precision_hdf, x_sp, dcount, ierr, &
1289 file_space_id = filespace, mem_space_id = memspace, &
1290 xfer_prp = xf_id)
1291 deallocate(x_sp)
1292 end block
1293
1294 else if (precision_local .eq. dp) then
1295 block
1296 real(kind=dp), allocatable :: x_dp(:)
1297
1298 allocate(x_dp(n_local))
1299 do concurrent(i = 1:n_local)
1300 x_dp(i) = real(x(i), dp)
1301 end do
1302
1303 call h5dwrite_f(dset_id, precision_hdf, x_dp, dcount, ierr, &
1304 file_space_id = filespace, mem_space_id = memspace, &
1305 xfer_prp = xf_id)
1306 deallocate(x_dp)
1307 end block
1308
1309 else if (precision_local .eq. qp) then
1310 block
1311 real(kind=qp), allocatable :: x_qp(:)
1312
1313 allocate(x_qp(n_local))
1314 do concurrent(i = 1:n_local)
1315 x_qp(i) = real(x(i), qp)
1316 end do
1317
1318 call h5dwrite_f(dset_id, precision_hdf, x_qp, dcount, ierr, &
1319 file_space_id = filespace, mem_space_id = memspace, &
1320 xfer_prp = xf_id)
1321 deallocate(x_qp)
1322 end block
1323
1324 else
1325 call neko_error("Unsupported precision in HDF5 write_scalar_field")
1326 end if
1327
1328 call h5sclose_f(filespace, ierr)
1329 call h5sclose_f(memspace, ierr)
1330 call h5dclose_f(dset_id, ierr)
1331 call h5pclose_f(xf_id, ierr)
1332 end subroutine write_scalar_field
1333
1347 subroutine write_vector_field(hdf_root, name, u, v, w, n_local, &
1348 precision, n_total, offset)
1349 integer, intent(in) :: n_local
1350 integer(hid_t), intent(in) :: hdf_root
1351 character(len=*), intent(in) :: name
1352 real(kind=rp), dimension(n_local), intent(in) :: u, v, w
1353 integer, intent(in), optional :: precision
1354 integer, intent(in), optional :: n_total, offset
1355
1356 integer(hsize_t), dimension(2) :: dims, dcount, doffset
1357 integer(hid_t) :: xf_id, dset_id, filespace, memspace, precision_hdf
1358 integer :: i, ierr, precision_local, n_tot, off
1359
1360 ! Setup data sizes, offsets and precision
1361 dcount = [3_hsize_t, int(n_local, hsize_t)]
1362
1363 if (present(n_total)) then
1364 dims = [3_hsize_t, int(n_total, hsize_t)]
1365 else
1366 call mpi_allreduce(n_local, n_tot, 1, mpi_integer, mpi_sum, neko_comm, &
1367 ierr)
1368 dims = [3_hsize_t, int(n_tot, hsize_t)]
1369 end if
1370
1371 if (present(offset)) then
1372 doffset = [0_hsize_t, int(offset, hsize_t)]
1373 else
1374 call mpi_exscan(n_local, off, 1, mpi_integer, mpi_sum, neko_comm, &
1375 ierr)
1376 doffset = [0_hsize_t, int(off, hsize_t)]
1377 end if
1378
1379 if (present(precision)) then
1380 precision_local = precision
1381 else
1382 precision_local = rp
1383 end if
1384 precision_hdf = h5kind_to_type(precision_local, h5_real_kind)
1385
1386 ! Prepare memory and filespaces
1387 call h5pcreate_f(h5p_dataset_xfer_f, xf_id, ierr)
1388 call h5pset_dxpl_mpio_f(xf_id, h5fd_mpio_collective_f, ierr)
1389
1390 call h5screate_simple_f(2, dims, filespace, ierr)
1391 call h5screate_simple_f(2, dcount, memspace, ierr)
1392 call h5sselect_hyperslab_f(filespace, h5s_select_set_f, &
1393 doffset, dcount, ierr)
1394
1395 call h5dcreate_f(hdf_root, trim(name), precision_hdf, filespace, dset_id, &
1396 ierr)
1397
1398 if (precision_local .eq. rp) then
1399 ! Perform direct write for each component seperatly to avoid extra memory
1400 ! allocation
1401 call h5dwrite_f(dset_id, precision_hdf, u, dcount, ierr, &
1402 file_space_id = filespace, mem_space_id = memspace, &
1403 xfer_prp = xf_id)
1404 call h5sselect_hyperslab_f(filespace, h5s_select_set_f, &
1405 [1_hsize_t, doffset(2)], [1_hsize_t, dcount(2)], ierr)
1406 call h5dwrite_f(dset_id, precision_hdf, v, dcount, ierr, &
1407 file_space_id = filespace, mem_space_id = memspace, &
1408 xfer_prp = xf_id)
1409 call h5sselect_hyperslab_f(filespace, h5s_select_set_f, &
1410 [2_hsize_t, doffset(2)], [1_hsize_t, dcount(2)], ierr)
1411 call h5dwrite_f(dset_id, precision_hdf, w, dcount, ierr, &
1412 file_space_id = filespace, mem_space_id = memspace, &
1413 xfer_prp = xf_id)
1414 else if (precision_local .eq. sp) then
1415 block
1416 real(kind=sp), allocatable :: f(:,:)
1417
1418 allocate(f(3, n_local))
1419 do concurrent(i = 1:n_local)
1420 f(1, i) = real(u(i), sp)
1421 f(2, i) = real(v(i), sp)
1422 f(3, i) = real(w(i), sp)
1423 end do
1424
1425 call h5dwrite_f(dset_id, precision_hdf, f, dcount, ierr, &
1426 file_space_id = filespace, mem_space_id = memspace, &
1427 xfer_prp = xf_id)
1428 deallocate(f)
1429 end block
1430
1431 else if (precision_local .eq. dp) then
1432 block
1433 real(kind=dp), allocatable :: f(:,:)
1434
1435 allocate(f(3, n_local))
1436 do concurrent(i = 1:n_local)
1437 f(1, i) = real(u(i), dp)
1438 f(2, i) = real(v(i), dp)
1439 f(3, i) = real(w(i), dp)
1440 end do
1441
1442 call h5dwrite_f(dset_id, precision_hdf, f, dcount, ierr, &
1443 file_space_id = filespace, mem_space_id = memspace, &
1444 xfer_prp = xf_id)
1445 deallocate(f)
1446 end block
1447
1448 else if (precision_local .eq. qp) then
1449 block
1450 real(kind=qp), allocatable :: f(:,:)
1451
1452 allocate(f(3, n_local))
1453 do concurrent(i = 1:n_local)
1454 f(1, i) = real(u(i), qp)
1455 f(2, i) = real(v(i), qp)
1456 f(3, i) = real(w(i), qp)
1457 end do
1458
1459 call h5dwrite_f(dset_id, precision_hdf, f, dcount, ierr, &
1460 file_space_id = filespace, mem_space_id = memspace, &
1461 xfer_prp = xf_id)
1462 deallocate(f)
1463 end block
1464
1465 else
1466 call neko_error("Unsupported precision in HDF5 write_vector_field")
1467 end if
1468
1469 call h5sclose_f(filespace, ierr)
1470 call h5sclose_f(memspace, ierr)
1471 call h5dclose_f(dset_id, ierr)
1472 call h5pclose_f(xf_id, ierr)
1473 end subroutine write_vector_field
1474
1475 ! -------------------------------------------------------------------------- !
1476 ! Reader functions and routines
1477
1479 subroutine vtkhdf_file_read(this, data)
1480 class(vtkhdf_file_t) :: this
1481 class(*), target, intent(inout) :: data
1482 character(len=1024) :: fname
1483 integer(hid_t) :: plist_id, file_id, vtkhdf_grp
1484 integer :: mpi_info, mpi_comm, counter, ierr
1485 type(field_list_t) :: fields
1486 integer :: i
1487
1488 ! Open the file
1489 fname = trim(this%get_base_fname())
1490 counter = this%get_counter() - this%get_start_counter()
1491 if (counter .lt. 0) counter = 0
1492
1493 mpi_info = mpi_info_null%mpi_val
1494 mpi_comm = neko_comm%mpi_val
1495
1496 call hdf5_session_init()
1497 call h5pcreate_f(h5p_file_access_f, plist_id, ierr)
1498 call h5pset_fapl_mpio_f(plist_id, mpi_comm, mpi_info, ierr)
1499
1500 call h5fopen_f(fname, h5f_acc_rdonly_f, file_id, ierr, &
1501 access_prp = plist_id)
1502 if (ierr .ne. 0) then
1503 call neko_error('Error opening VTKHDF file: ' // trim(fname))
1504 end if
1505
1506 call h5gopen_f(file_id, "VTKHDF", vtkhdf_grp, ierr)
1507 if (ierr .ne. 0) then
1508 call h5fclose_f(file_id, ierr)
1509 call h5pclose_f(plist_id, ierr)
1510 call neko_error('VTKHDF group not found in file: ' // trim(fname))
1511 end if
1512
1513 select type (data)
1514 type is (field_t)
1515 call fields%init(1)
1516 ! Specific bindings instead of the assign generic (see
1517 ! vtkhdf_file_write); Fujitsu frt cannot resolve the generic
1518 call fields%assign_to_field(1, data)
1519 type is (field_list_t)
1520 call fields%assign_to_list(data)
1521 class default
1522 call neko_error("Unsupported data type in vtkhdf_file_read")
1523 end select
1524
1525 do i = 1, fields%size()
1526 call vtkhdf_read_field(vtkhdf_grp, fname, counter, fields%get(i))
1527 end do
1528 call fields%copy_from(host_to_device, .true.)
1529
1530 call h5gclose_f(vtkhdf_grp, ierr)
1531 call h5fclose_f(file_id, ierr)
1532 call h5pclose_f(plist_id, ierr)
1533 call hdf5_session_finalize()
1534
1535 call fields%free()
1536
1537 end subroutine vtkhdf_file_read
1538
1548 subroutine vtkhdf_read_field(vtkhdf_grp, fname, counter, fld)
1549 integer(hid_t), intent(in) :: vtkhdf_grp
1550 character(len=*), intent(in) :: fname
1551 integer, intent(in) :: counter
1552 type(field_t), intent(inout) :: fld
1553
1554 character(len=:), allocatable :: field_name
1555 integer :: ierr, local_points, total_points, point_offset, component
1556 integer(hid_t) :: pointdata_grp, dset_id, filespace, memspace, xf_id
1557 integer(hid_t) :: dcpl_id, ext_file_id, ext_plist_id, attr_id
1558 integer(hid_t) :: H5T_NEKO_REAL
1559 integer(hsize_t), dimension(1) :: dcount1, doffset1
1560 integer(hsize_t), dimension(2) :: dcount2, doffset2
1561
1562 integer(size_t) :: vds_count
1563 character(len=128) :: dset_name
1564 character(len=1024) :: vds_src_file, ext_fname, main_path, main_name, main_suffix
1565 logical :: exists, is_vds
1566 real(kind=rp), allocatable :: vec_component(:,:)
1567 integer :: mpi_info, mpi_comm, pct_pos, nsteps
1568 character(len=256) :: error_message
1569
1570 field_name = trim(fld%name)
1571
1572 ! Validate counter against file's NSteps if temporal data exists
1573 call h5lexists_f(vtkhdf_grp, "Steps", exists, ierr)
1574 if (exists) then
1575 call h5aopen_by_name_f(vtkhdf_grp, "Steps", "NSteps", attr_id, ierr)
1576 call h5aread_f(attr_id, h5t_native_integer, nsteps, [1_hsize_t], ierr)
1577 call h5aclose_f(attr_id, ierr)
1578
1579 if (counter .ge. nsteps) then
1580 write(error_message, '(A,I0,A,I0)') &
1581 'VTKHDF read: counter ', counter, ' >= NSteps ', nsteps
1582 call neko_error(trim(error_message))
1583 end if
1584 end if
1585
1586 mpi_info = mpi_info_null%mpi_val
1587 mpi_comm = neko_comm%mpi_val
1588
1589 local_points = fld%dof%size()
1590 total_points = fld%dof%global_size()
1591 point_offset = 0
1592 call mpi_exscan(local_points, point_offset, 1, mpi_integer, &
1593 mpi_sum, neko_comm, ierr)
1594
1595 h5t_neko_real = h5kind_to_type(rp, h5_real_kind)
1596
1597 ! Open PointData group
1598 call h5gopen_f(vtkhdf_grp, "PointData", pointdata_grp, ierr)
1599
1600 ! Determine dataset name with standard mappings
1601 dset_name = trim(field_name)
1602 if (trim(dset_name) .eq. 'p') dset_name = 'Pressure'
1603
1604 component = -1
1605 call h5lexists_f(pointdata_grp, trim(dset_name), exists, ierr)
1606
1607 if (.not. exists) then
1608 if (trim(field_name) .eq. 'u' .or. trim(field_name) .eq. 'v' .or. &
1609 trim(field_name) .eq. 'w') then
1610 call h5lexists_f(pointdata_grp, "Velocity", exists, ierr)
1611 if (exists) then
1612 dset_name = 'Velocity'
1613 select case (trim(field_name))
1614 case ('u')
1615 component = 0
1616 case ('v')
1617 component = 1
1618 case ('w')
1619 component = 2
1620 end select
1621 end if
1622 end if
1623 end if
1624
1625 if (.not. exists) then
1626 call h5gclose_f(pointdata_grp, ierr)
1627 call neko_error('VTKHDF PointData field not found: ' // trim(dset_name))
1628 end if
1629
1630 ! Open the dataset and check if it's a VDS
1631 call h5dopen_f(pointdata_grp, trim(dset_name), dset_id, ierr)
1632 call h5dget_create_plist_f(dset_id, dcpl_id, ierr)
1633 call h5pget_virtual_count_f(dcpl_id, vds_count, ierr)
1634 is_vds = (vds_count .gt. 0_size_t)
1635
1636 if (is_vds) then
1637 call filename_split(fname, main_path, main_name, main_suffix)
1638
1639 ! Query mapping 0 to detect whether this is a printf-style pattern VDS
1640 ! (Neko's own format uses a single mapping with %b as a block counter
1641 ! placeholder) or a multi-mapping VDS where each timestep has its own
1642 ! literal source file.
1643 call h5pget_virtual_filename_f(dcpl_id, 0_size_t, vds_src_file, ierr)
1644 pct_pos = index(vds_src_file, '%b')
1645
1646 if (pct_pos .gt. 0) then
1647 ! Pattern-based VDS: replace %b with the timestep counter.
1648 ! If the stored path is absolute, use it as-is; otherwise prepend the
1649 ! main file's directory so the path is resolved correctly regardless
1650 ! of the process working directory.
1651 if (vds_src_file(1:1) .eq. '/') then
1652 write(ext_fname, '(A,I0,A)') &
1653 vds_src_file(1:pct_pos-1), counter, &
1654 trim(vds_src_file(pct_pos+2:))
1655 else
1656 write(ext_fname, '(A,A,I0,A)') &
1657 trim(main_path), vds_src_file(1:pct_pos-1), counter, &
1658 trim(vds_src_file(pct_pos+2:))
1659 end if
1660 else
1661 ! Multi-mapping VDS: one mapping per timestep. Query the mapping
1662 ! that corresponds directly to the requested counter instead of
1663 ! always using mapping 0, which would silently read the wrong file.
1664 if (int(counter, size_t) .ge. vds_count) then
1665 call h5pclose_f(dcpl_id, ierr)
1666 call h5dclose_f(dset_id, ierr)
1667 call h5gclose_f(pointdata_grp, ierr)
1668 write(error_message, '(A,I0,A,I0)') &
1669 'VTKHDF: VDS counter ', counter, &
1670 ' is out of range, number of mappings: ', int(vds_count)
1671 call neko_error(trim(error_message))
1672 end if
1673 call h5pget_virtual_filename_f(dcpl_id, int(counter, size_t), &
1674 vds_src_file, ierr)
1675 if (vds_src_file(1:1) .eq. '/') then
1676 ext_fname = trim(vds_src_file)
1677 else
1678 write(ext_fname, '(A,A)') trim(main_path), trim(vds_src_file)
1679 end if
1680 end if
1681
1682 call h5pclose_f(dcpl_id, ierr)
1683 call h5dclose_f(dset_id, ierr)
1684 call h5gclose_f(pointdata_grp, ierr)
1685
1686 call h5pcreate_f(h5p_file_access_f, ext_plist_id, ierr)
1687 call h5pset_fapl_mpio_f(ext_plist_id, mpi_comm, mpi_info, ierr)
1688 call h5fopen_f(trim(ext_fname), h5f_acc_rdonly_f, ext_file_id, ierr, &
1689 access_prp = ext_plist_id)
1690
1691 if (ierr .ne. 0) then
1692 call neko_error('VTKHDF: Cannot open VDS source file: ' // &
1693 trim(ext_fname))
1694 end if
1695
1696 ! Open the dataset from the external file
1697 call h5dopen_f(ext_file_id, trim(dset_name), dset_id, ierr)
1698
1699 call h5pclose_f(ext_plist_id, ierr)
1700 else
1701 call h5pclose_f(dcpl_id, ierr)
1702 ext_file_id = -1
1703 end if
1704
1705 ! Now read from the dataset (either original or from external file)
1706 call h5pcreate_f(h5p_dataset_xfer_f, xf_id, ierr)
1707 call h5pset_dxpl_mpio_f(xf_id, h5fd_mpio_collective_f, ierr)
1708 call h5dget_space_f(dset_id, filespace, ierr)
1709
1710 if (trim(dset_name) .eq. 'Velocity' .and. component .ge. 0) then
1711 ! Velocity is stored as (3, n_points), read one component
1712 dcount2 = [1_hsize_t, int(local_points, hsize_t)]
1713 doffset2 = [int(component, hsize_t), int(point_offset, hsize_t)]
1714
1715 call h5screate_simple_f(2, dcount2, memspace, ierr)
1716 call h5sselect_hyperslab_f(filespace, h5s_select_set_f, &
1717 doffset2, dcount2, ierr)
1718
1719 allocate(vec_component(1, local_points))
1720 call h5dread_f(dset_id, h5t_neko_real, vec_component, dcount2, ierr, &
1721 file_space_id = filespace, mem_space_id = memspace, &
1722 xfer_prp = xf_id)
1723 fld%x = reshape(vec_component, shape(fld%x))
1724 deallocate(vec_component)
1725 else
1726 ! Scalar field: 1D array
1727 dcount1 = int(local_points, hsize_t)
1728 doffset1 = int(point_offset, hsize_t)
1729
1730 call h5screate_simple_f(1, dcount1, memspace, ierr)
1731 call h5sselect_hyperslab_f(filespace, h5s_select_set_f, &
1732 doffset1, dcount1, ierr)
1733
1734 call h5dread_f(dset_id, h5t_neko_real, fld%x(1,1,1,1), dcount1, ierr, &
1735 file_space_id = filespace, mem_space_id = memspace, &
1736 xfer_prp = xf_id)
1737 end if
1738
1739 call h5sclose_f(memspace, ierr)
1740 call h5sclose_f(filespace, ierr)
1741 call h5dclose_f(dset_id, ierr)
1742 call h5pclose_f(xf_id, ierr)
1743
1744 if (is_vds) then
1745 call h5fclose_f(ext_file_id, ierr)
1746 else
1747 call h5gclose_f(pointdata_grp, ierr)
1748 end if
1749
1750 end subroutine vtkhdf_read_field
1751
1752#else
1753 ! -------------------------------------------------------------------------- !
1754 ! Dummy functions and subroutines
1755
1757 subroutine vtkhdf_file_write(this, data, t)
1758 class(vtkhdf_file_t), intent(inout) :: this
1759 class(*), target, intent(in) :: data
1760 real(kind=dp), intent(in), optional :: t
1761 call neko_error('Neko needs to be built with HDF5 support')
1762 end subroutine vtkhdf_file_write
1763
1765 subroutine vtkhdf_file_read(this, data)
1766 class(vtkhdf_file_t) :: this
1767 class(*), target, intent(inout) :: data
1768 call neko_error('Neko needs to be built with HDF5 support')
1769 end subroutine vtkhdf_file_read
1770
1771#endif
1772
1773 ! -------------------------------------------------------------------------- !
1774 ! Sub-cell node ordering functions for VTK compatibility
1775
1784 pure function subdivide_to_hex_ordering(lx, ly, lz) result(node_order)
1785 integer, intent(in) :: lx, ly, lz
1786 integer :: node_order(8 * (lx - 1) * (ly - 1) * (lz - 1))
1787 integer :: ii, jj, kk, idx
1788
1789 idx = 0
1790
1791 do ii = 1, lx - 1
1792 do jj = 1, ly - 1
1793 do kk = 1, lz - 1
1794 node_order(idx + 1) = (kk - 1) * lx * ly + (jj - 1) * lx + ii - 1
1795 node_order(idx + 2) = (kk - 1) * lx * ly + (jj - 1) * lx + ii
1796 node_order(idx + 3) = (kk - 1) * lx * ly + jj * lx + ii
1797 node_order(idx + 4) = (kk - 1) * lx * ly + jj * lx + ii - 1
1798 node_order(idx + 5) = kk * lx * ly + (jj - 1) * lx + ii - 1
1799 node_order(idx + 6) = kk * lx * ly + (jj - 1) * lx + ii
1800 node_order(idx + 7) = kk * lx * ly + jj * lx + ii
1801 node_order(idx + 8) = kk * lx * ly + jj * lx + ii - 1
1802 idx = idx + 8
1803 end do
1804 end do
1805 end do
1806
1807 end function subdivide_to_hex_ordering
1808
1816 pure function subdivide_to_quad_ordering(lx, ly) result(node_order)
1817 integer, intent(in) :: lx, ly
1818 integer :: node_order(4 * (lx - 1) * (ly - 1))
1819 integer :: ii, jj, idx
1820
1821 idx = 0
1822
1823 do jj = 1, ly - 1
1824 do ii = 1, lx - 1
1825 node_order(idx + 1) = (jj - 1) * lx + ii - 1
1826 node_order(idx + 2) = (jj - 1) * lx + ii
1827 node_order(idx + 3) = jj * lx + ii
1828 node_order(idx + 4) = jj * lx + ii - 1
1829 idx = idx + 4
1830 end do
1831 end do
1832
1833 end function subdivide_to_quad_ordering
1834
1835end module vtkhdf_file
__inline__ __device__ void nonlinear_index(const int idx, const int lx, int *index)
Definition bc_utils.h:44
double real
Defines format-independent checkpoint registration and restart state.
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
HDF5 session management.
subroutine, public hdf5_session_init
Initialise the global HDF5 session HDF5 does not maintain a global reference count,...
subroutine, public hdf5_session_finalize
Finalize the global HDF5 session.
Logging routines.
Definition log.f90:34
type(log_t), public neko_log
Global log stream.
Definition log.f90:92
Defines a mesh.
Definition mesh.f90:34
integer, parameter, public i8
Definition num_types.f90:7
integer, parameter, public qp
Definition num_types.f90:12
integer, parameter, public dp
Definition num_types.f90:10
integer, parameter, public sp
Definition num_types.f90:8
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:14
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:328
subroutine, public filename_split(fname, path, name, suffix)
Extract file name components.
Definition utils.f90:170
subroutine, public neko_warning(warning_msg)
Reports a warning to standard output.
Definition utils.f90:454
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:213
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...
Collection of live simulation data registered for checkpointing.
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