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