#include "Includes.h" module Solution2VtkHdfModule use SMConstants use SolutionFile use InterpolationMatrices use FileReadingUtilities, only: getFileName #ifdef HAS_HDF5 use iso_c_binding, only: c_char, c_loc, c_ptr use HDF5 #endif implicit none private public Solution2VtkHdf ! ! ======== contains ! ======== ! subroutine Solution2VtkHdf(meshName, solutionName, Nout) use Storage use NodalStorageClass use SharedSpectralBasis use OutputVariables implicit none character(len=*), intent(in) :: meshName character(len=*), intent(in) :: solutionName integer, intent(in) :: Nout(3) #ifdef HAS_HDF5 ! ! --------------- ! Local variables ! --------------- ! type(Mesh_t) :: mesh character(len=LINE_LENGTH) :: meshPltName character(len=LINE_LENGTH) :: solutionFile real(kind=RP), allocatable :: xi(:), eta(:), zeta(:) integer :: Nout__, Nout_(3) integer :: eID, vID, i, j, k character(len=16, kind=c_char), target :: filetype = "UnstructuredGrid" integer(HID_T) :: fid, space, attr, dset integer(HID_T) :: vtkhdf, fdata, pdata integer(HID_T) :: mtype, ftype integer :: error integer :: nPoints integer :: etype integer :: ipt type(c_ptr), target :: ptr integer, target :: vec2(2) character(len=:, kind=c_char), target, allocatable :: title integer, allocatable :: localConnectivities(:) integer, target, allocatable :: connectivities(:) integer, target, allocatable :: offsets(:) integer, target, allocatable :: types(:) real(kind=RP), target, allocatable :: points(:, :) real(kind=RP), target, allocatable :: variable(:) character(len=STRING_CONSTANT_LENGTH), allocatable :: varNames(:) ! ! Read the mesh and solution data ! ------------------------------- call mesh % ReadMesh(meshName) call mesh % ReadSolution(SolutionName) ! Use square domains if (maxval(Nout) > 0) then Nout_ = maxval(Nout) else Nout__ = 1 ! At least two nodes in each direction do eID = 1, mesh % no_of_elements Nout__ = max(Nout__, maxval(mesh % elements(eID) % Nsol)) end do Nout_ = Nout__ end if if (mesh % is2D) Nout_(3) = 0 ! ! Set homogeneous nodes ! --------------------- allocate(xi(0:Nout_(1))) allocate(eta(0:Nout_(2))) allocate(zeta(0:Nout_(3))) xi = [ (-1.0_RP + 2.0_RP * i / Nout_(1), i = 0, Nout_(1)) ] eta = [ (-1.0_RP + 2.0_RP * i / Nout_(2), i = 0, Nout_(2)) ] if (mesh % is2D) then zeta = [ 0.0_RP ] else zeta = [ (-1.0_RP + 2.0_RP * i / Nout_(3), i = 0, Nout_(3)) ] end if ! ! Write each element zone ! ----------------------- do eID = 1, mesh % no_of_elements associate ( e => mesh % elements(eID) ) e % Nout = Nout_ ! ! Construct spectral basis for both mesh and solution ! --------------------------------------------------- call addNewSpectralBasis(spA, e % Nmesh, mesh % nodeType) call addNewSpectralBasis(spA, e % Nsol , mesh % nodeType) ! ! Construct interpolation matrices for the mesh ! --------------------------------------------- call addNewInterpolationMatrix(Tset, e % Nmesh(1), spA(e % Nmesh(1)), e % Nout(1), xi) call addNewInterpolationMatrix(Tset, e % Nmesh(2), spA(e % Nmesh(2)), e % Nout(2), eta) call addNewInterpolationMatrix(Tset, e % Nmesh(3), spA(e % Nmesh(3)), e % Nout(3), zeta) ! ! Construct interpolation matrices for the solution ! ------------------------------------------------- call addNewInterpolationMatrix(Tset, e % Nsol(1), spA(e % Nsol(1)), e % Nout(1), xi) call addNewInterpolationMatrix(Tset, e % Nsol(2), spA(e % Nsol(2)), e % Nout(2), eta) call addNewInterpolationMatrix(Tset, e % Nsol(3), spA(e % Nsol(3)), e % Nout(3), zeta) ! ! Perform interpolation ! --------------------- call ProjectStorageHomogeneousPoints(e, Tset(e % Nout(1), e % Nmesh(1)) % T, & Tset(e % Nout(2), e % Nmesh(2)) % T, & Tset(e % Nout(3), e % Nmesh(3)) % T, & Tset(e % Nout(1), e % Nsol(1)) % T, & Tset(e % Nout(2), e % Nsol(2)) % T, & Tset(e % Nout(3), e % Nsol(3)) % T, & mesh % hasGradients, mesh % isStatistics ) end associate end do ! ! Write the solution file name ! ---------------------------- solutionFile = trim(getFileName(solutionName)) // ".hdf" ! ! Create the file ! --------------- call h5open_f(error) call h5fcreate_f(solutionFile, H5F_ACC_TRUNC_F, fid, error) call h5gcreate_f(fid, "VTKHDF", vtkhdf, error) ! Version vec2 = [1, 0] call h5screate_simple_f(1, [2_HSIZE_T], space, error) call h5acreate_f(vtkhdf, "Version", H5T_STD_I64LE, space, attr, error) call h5awrite_f(attr, H5T_NATIVE_INTEGER, c_loc(vec2), error) call h5aclose_f(attr, error) call h5sclose_f(space, error) ! File type call h5tcopy_f(H5T_FORTRAN_S1, mtype, error) call h5tset_size_f(mtype, len_trim(filetype, kind=8), error) call h5tcopy_f(H5T_C_S1, ftype, error) call h5tset_size_f(ftype, len_trim(filetype, kind=8), error) call h5tset_strpad_f(ftype, H5T_STR_NULLPAD_F, error) call h5screate_f(H5S_SCALAR_F, space, error) call h5acreate_f(vtkhdf, "Type", ftype, space, attr, error) call h5awrite_f(attr, mtype, c_loc(filetype(1:1)), error) call h5aclose_f(attr, error) call h5sclose_f(space, error) call h5tclose_f(mtype, error) call h5tclose_f(ftype, error) ! ! Add the title ! ------------- title = "Generated from " // trim(meshName) // " and " // trim(solutionName) call h5tcopy_f(H5T_STRING, ftype, error) call h5tset_strpad_f(ftype, H5T_STR_NULLPAD_F, error) call h5gcreate_f(vtkhdf, "FieldData", fdata, error) call h5screate_simple_f(1, [1_HSIZE_T], space, error) call h5dcreate_f(fdata, "Title", ftype, space, dset, error) ptr = c_loc(title(1:1)) call h5dwrite_f(dset, ftype, c_loc(ptr), error) call h5dclose_f(dset, error) call h5sclose_f(space, error) call h5gclose_f(fdata, error) call h5tclose_f(ftype, error) ! ! Topology information required by VTKHDF ! --------------------------------------- if (mesh % is2D) then etype = 70 else etype = 72 end if nPoints = mesh % no_of_elements * product(Nout_ + 1) allocate(points(3, nPoints)) allocate(connectivities(nPoints)) allocate(offsets(0:mesh % no_of_elements)) allocate(types(mesh % no_of_elements)) ipt = 0 offsets(0) = 0 localConnectivities = get_connectivities(etype, Nout_) do eID = 1, mesh % no_of_elements associate(e => mesh % elements(eID)) ! Connectivities connectivities(ipt + 1:ipt + product(e % Nout + 1)) = ipt + localConnectivities ! Points do k = 0, e % Nout(3) ; do j = 0, e % Nout(2) ; do i = 0, e % Nout(1) ipt = ipt + 1 points(:, ipt) = e % xOut(:, i, j, k) end do ; end do ; end do ! Offsets offsets(eID) = offsets(eID - 1) + product(e % Nout + 1) ! Element types types(eID) = etype end associate end do ! First, partition related variables call h5screate_simple_f(1, [1_HSIZE_T], space, error) vec2(1) = nPoints call h5dcreate_f(vtkhdf, "NumberOfPoints", H5T_STD_I64LE, space, dset, error) call h5dwrite_f(dset, H5T_NATIVE_INTEGER, c_loc(vec2), error) call h5dclose_f(dset, error) call h5dcreate_f(vtkhdf, "NumberOfConnectivityIds", H5T_STD_I64LE, space, dset, error) call h5dwrite_f(dset, H5T_NATIVE_INTEGER, c_loc(vec2), error) call h5dclose_f(dset, error) vec2(1) = mesh % no_of_elements call h5dcreate_f(vtkhdf, "NumberOfCells", H5T_STD_I64LE, space, dset, error) call h5dwrite_f(dset, H5T_NATIVE_INTEGER, c_loc(vec2), error) call h5dclose_f(dset, error) call h5sclose_f(space, error) ! Now, mesh information call h5screate_simple_f(2, [3_HSIZE_T, int(nPoints, kind=HSIZE_T)], space, error) call h5dcreate_f(vtkhdf, "Points", H5T_IEEE_F64LE, space, dset, error) call h5dwrite_f(dset, H5T_NATIVE_DOUBLE, c_loc(points), error) call h5dclose_f(dset, error) call h5sclose_f(space, error) call h5screate_simple_f(1, [int(nPoints, kind=HSIZE_T)], space, error) call h5dcreate_f(vtkhdf, "Connectivity", H5T_STD_I64LE, space, dset, error) call h5dwrite_f(dset, H5T_NATIVE_INTEGER, c_loc(connectivities), error) call h5dclose_f(dset, error) call h5sclose_f(space, error) call h5screate_simple_f(1, [int(mesh % no_of_elements + 1, kind=HSIZE_T)], space, error) call h5dcreate_f(vtkhdf, "Offsets", H5T_STD_I64LE, space, dset, error) call h5dwrite_f(dset, H5T_NATIVE_INTEGER, c_loc(offsets), error) call h5dclose_f(dset, error) call h5sclose_f(space, error) call h5screate_simple_f(1, [int(mesh % no_of_elements, kind=HSIZE_T)], space, error) call h5dcreate_f(vtkhdf, "Types", H5T_STD_U8LE, space, dset, error) call h5dwrite_f(dset, H5T_NATIVE_INTEGER, c_loc(types), error) call h5dclose_f(dset, error) call h5sclose_f(space, error) deallocate(points) deallocate(connectivities) deallocate(offsets) deallocate(types) ! ! Add the variables ! ----------------- call getOutputVariables() call getOutputVariablesList(varNames) allocate(variable(nPoints)) call h5gcreate_f(vtkhdf, "PointData", pdata, error) call h5screate_simple_f(1, [int(nPoints, kind=HSIZE_T)], space, error) ! Compute output variables do eID = 1, mesh % no_of_elements associate(e => mesh % elements(eID)) allocate(e % outputVars(1:no_of_outputVariables, 0:e % Nout(1), 0:e % Nout(2), 0:e % Nout(3)) ) call ComputeOutputVariables(no_of_outputVariables, outputVariableNames, e % Nout, e, e % outputVars, & mesh % refs, mesh % hasGradients, mesh % isStatistics, mesh % hasSensor) end associate end do ! Serialize and save do vID = 1, size(varNames) ipt = 0 do eID = 1, mesh % no_of_elements associate(e => mesh % elements(eID)) do k = 0, e % Nout(3) ; do j = 0, e % Nout(2) ; do i = 0, e % Nout(1) ipt = ipt + 1 variable(ipt) = e % outputVars(vID, i, j, k) end do ; end do ; end do end associate end do call h5dcreate_f(pdata, trim(varNames(vID)), H5T_IEEE_F64LE, space, dset, error) call h5dwrite_f(dset, H5T_NATIVE_DOUBLE, c_loc(variable), error) call h5dclose_f(dset, error) end do call h5sclose_f(space, error) call h5gclose_f(pdata, error) ! ! Close the file ! -------------- call h5gclose_f(vtkhdf, error) call h5fclose_f(fid, error) call h5close_f(error) #endif end subroutine Solution2VtkHdf subroutine ProjectStorageHomogeneousPoints(e, TxMesh, TyMesh, TzMesh, TxSol, TySol, TzSol, hasGradients, hasStats) use Storage use NodalStorageClass implicit none type(Element_t) :: e real(kind=RP), intent(in) :: TxMesh(0:e % Nout(1), 0:e % Nmesh(1)) real(kind=RP), intent(in) :: TyMesh(0:e % Nout(2), 0:e % Nmesh(2)) real(kind=RP), intent(in) :: TzMesh(0:e % Nout(3), 0:e % Nmesh(3)) real(kind=RP), intent(in) :: TxSol(0:e % Nout(1), 0:e % Nsol(1)) real(kind=RP), intent(in) :: TySol(0:e % Nout(2), 0:e % Nsol(2)) real(kind=RP), intent(in) :: TzSol(0:e % Nout(3), 0:e % Nsol(3)) logical, intent(in) :: hasGradients logical, intent(in) :: hasStats ! ! --------------- ! Local variables ! --------------- ! integer :: i, j, k, l, m, n ! ! Project mesh ! ------------ allocate( e % xOut(1:3, 0:e % Nout(1), 0:e % Nout(2), 0:e % Nout(3)) ) e % xOut = 0.0_RP do n = 0, e % Nmesh(3) ; do m = 0, e % Nmesh(2) ; do l = 0, e % Nmesh(1) do k = 0, e % Nout(3) ; do j = 0, e % Nout(2) ; do i = 0, e % Nout(1) e % xOut(:,i,j,k) = e % xOut(:,i,j,k) + e % x(:,l,m,n) * TxMesh(i,l) * TyMesh(j,m) * TzMesh(k,n) end do ; end do ; end do end do ; end do ; end do ! ! Project the solution ! -------------------- allocate( e % Qout(1:NVARS, 0:e % Nout(1), 0:e % Nout(2), 0:e % Nout(3)) ) e % Qout = 0.0_RP do n = 0, e % Nsol(3) ; do m = 0, e % Nsol(2) ; do l = 0, e % Nsol(1) do k = 0, e % Nout(3) ; do j = 0, e % Nout(2) ; do i = 0, e % Nout(1) e % Qout(:,i,j,k) = e % Qout(:,i,j,k) + e % Q(:,l,m,n) * TxSol(i,l) * TySol(j,m) * TzSol(k,n) end do ; end do ; end do end do ; end do ; end do if ( hasGradients ) then allocate( e % U_xout(1:NGRADVARS, 0:e % Nout(1), 0:e % Nout(2), 0:e % Nout(3))) e % U_xout = 0.0_RP do n = 0, e % Nsol(3) ; do m = 0, e % Nsol(2) ; do l = 0, e % Nsol(1) do k = 0, e % Nout(3) ; do j = 0, e % Nout(2) ; do i = 0, e % Nout(1) e % U_xout(:,i,j,k) = e % U_xout(:,i,j,k) + e % U_x(:,l,m,n) * TxSol(i,l) * TySol(j,m) * TzSol(k,n) end do ; end do ; end do end do ; end do ; end do allocate( e % U_yout(1:NGRADVARS, 0:e % Nout(1), 0:e % Nout(2), 0:e % Nout(3)) ) e % U_yout = 0.0_RP do n = 0, e % Nsol(3) ; do m = 0, e % Nsol(2) ; do l = 0, e % Nsol(1) do k = 0, e % Nout(3) ; do j = 0, e % Nout(2) ; do i = 0, e % Nout(1) e % U_yout(:,i,j,k) = e % U_yout(:,i,j,k) + e % U_y(:,l,m,n) * TxSol(i,l) * TySol(j,m) * TzSol(k,n) end do ; end do ; end do end do ; end do ; end do allocate( e % U_zout(1:NGRADVARS, 0:e % Nout(1), 0:e % Nout(2), 0:e % Nout(3)) ) e % U_zout = 0.0_RP do n = 0, e % Nsol(3) ; do m = 0, e % Nsol(2) ; do l = 0, e % Nsol(1) do k = 0, e % Nout(3) ; do j = 0, e % Nout(2) ; do i = 0, e % Nout(1) e % U_zout(:,i,j,k) = e % U_zout(:,i,j,k) + e % U_z(:,l,m,n) * TxSol(i,l) * TySol(j,m) * TzSol(k,n) end do ; end do ; end do end do ; end do ; end do end if if (hasStats) then allocate( e % statsout(1:NSTAT, 0:e % Nout(1), 0:e % Nout(2), 0:e % Nout(3)) ) e % statsout = 0.0_RP do n = 0, e % Nsol(3) ; do m = 0, e % Nsol(2) ; do l = 0, e % Nsol(1) do k = 0, e % Nout(3) ; do j = 0, e % Nout(2) ; do i = 0, e % Nout(1) e % statsout(:,i,j,k) = e % statsout(:,i,j,k) + e % stats(:,l,m,n) * TxSol(i,l) * TySol(j,m) * TzSol(k,n) end do ; end do ; end do end do ; end do ; end do end if if (hasUt_NS) then allocate( e % ut_NSout(1,0:e % Nout(1), 0:e % Nout(2), 0:e % Nout(3)) ) e % ut_NSout = 0.0_RP do n = 0, e % Nsol(3) ; do m = 0, e % Nsol(2) ; do l = 0, e % Nsol(1) do k = 0, e % Nout(3) ; do j = 0, e % Nout(2) ; do i = 0, e % Nout(1) e % ut_NSout(:,i,j,k) = e % ut_NSout(:,i,j,k) + e % ut_NS(:,l,m,n) * TxSol(i,l) * TySol(j,m) * TzSol(k,n) end do ; end do ; end do end do ; end do ; end do end if if (hasMu_NS) then allocate( e % mu_NSout(1,0:e % Nout(1), 0:e % Nout(2), 0:e % Nout(3)) ) e % mu_NSout = 0.0_RP do n = 0, e % Nsol(3) ; do m = 0, e % Nsol(2) ; do l = 0, e % Nsol(1) do k = 0, e % Nout(3) ; do j = 0, e % Nout(2) ; do i = 0, e % Nout(1) e % mu_NSout(:,i,j,k) = e % mu_NSout(:,i,j,k) + e % mu_NS(:,l,m,n) * TxSol(i,l) * TySol(j,m) * TzSol(k,n) end do ; end do ; end do end do ; end do ; end do end if if (hasWallY) then allocate( e % wallYout(1,0:e % Nout(1), 0:e % Nout(2), 0:e % Nout(3)) ) e % wallYout = 0.0_RP do n = 0, e % Nsol(3) ; do m = 0, e % Nsol(2) ; do l = 0, e % Nsol(1) do k = 0, e % Nout(3) ; do j = 0, e % Nout(2) ; do i = 0, e % Nout(1) e % wallYout(:,i,j,k) = e % wallYout(:,i,j,k) + e % WallY(:,l,m,n) * TxSol(i,l) * TySol(j,m) * TzSol(k,n) end do ; end do ; end do end do ; end do ; end do end if if (hasMu_sgs) then allocate( e % mu_sgsout(1,0:e % Nout(1), 0:e % Nout(2), 0:e % Nout(3)) ) e % mu_sgsout = 0.0_RP do n = 0, e % Nsol(3) ; do m = 0, e % Nsol(2) ; do l = 0, e % Nsol(1) do k = 0, e % Nout(3) ; do j = 0, e % Nout(2) ; do i = 0, e % Nout(1) e % mu_sgsout(:,i,j,k) = e % mu_sgsout(:,i,j,k) + e % mu_sgs(:,l,m,n) * TxSol(i,l) * TySol(j,m) * TzSol(k,n) end do ; end do ; end do end do ; end do ; end do end if end subroutine ProjectStorageHomogeneousPoints function get_connectivities(elemType, Nout) result(conn) implicit none integer, intent(in) :: elemType integer, intent(in) :: Nout(3) integer :: conn(product(Nout + 1)) integer :: i integer :: connectivities(0:Nout(1), 0:Nout(2), 0:Nout(3)) integer, allocatable :: corners(:), edges(:), face(:), faces(:), volume(:) ! Array to vector indexing connectivities = reshape( [(i-1, i = 1, product(Nout + 1))], shape(connectivities) ) ! Quadrangle if (elemType == 70) then corners = [ connectivities(0, 0, 0), & connectivities(Nout(1), 0, 0), & connectivities(Nout(1), Nout(2), 0), & connectivities(0, Nout(2), 0) ] edges = [ connectivities(1:Nout(1)-1, 0, 0), & connectivities(Nout(1), 1:Nout(2)-1, 0), & connectivities(1:Nout(1)-1, Nout(2), 0), & connectivities(0, 1:Nout(2)-1, 0) ] face = pack(connectivities(1:Nout(1)-1, 1:Nout(2)-1, 0), .true.) conn = [ corners, edges, face ] ! Hexahedron else ! elemType == 72 corners = [ connectivities(0, 0, 0), & connectivities(Nout(1), 0, 0), & connectivities(Nout(2), Nout(2), 0), & connectivities(0, Nout(2), 0), & connectivities(0, 0, Nout(3)), & connectivities(Nout(1), 0, Nout(3)), & connectivities(Nout(1), Nout(2), Nout(3)), & connectivities(0, Nout(2), Nout(3)) ] edges = [ connectivities(1:Nout(1)-1, 0, 0), & connectivities(Nout(1), 1:Nout(2)-1, 0), & connectivities(1:Nout(1)-1, Nout(2), 0), & connectivities(0, 1:Nout(2)-1, 0), & connectivities(1:Nout(1)-1, 0, Nout(3)), & connectivities(Nout(1), 1:Nout(2)-1, Nout(3)), & connectivities(1:Nout(1)-1, Nout(2), Nout(3)), & connectivities(0, 1:Nout(2)-1, Nout(3)), & connectivities(0, 0, 1:Nout(3)-1), & connectivities(Nout(1), 0, 1:Nout(3)-1), & connectivities(Nout(1), Nout(2), 1:Nout(3)-1), & connectivities(0, Nout(2), 1:Nout(3)-1) ] faces = [ pack(connectivities(0, 1:Nout(2)-1, 1:Nout(3)-1), .true.), & pack(connectivities(Nout(1), 1:Nout(2)-1, 1:Nout(3)-1), .true.), & pack(connectivities(1:Nout(1)-1, 0, 1:Nout(3)-1), .true.), & pack(connectivities(1:Nout(1)-1, Nout(2), 1:Nout(3)-1), .true.), & pack(connectivities(1:Nout(1)-1, 1:Nout(2)-1, 0), .true.), & pack(connectivities(1:Nout(1)-1, 1:Nout(2)-1, Nout(3)), .true.) ] volume = pack(connectivities(1:Nout(1)-1, 1:Nout(2)-1, 1:Nout(3)-1), .true.) conn = [ corners, edges, faces, volume ] end if end function get_connectivities end module Solution2VtkHdfModule