7#include "HDF5Interface.h"
9#include <dolfinx/common/IndexMap.h>
10#include <dolfinx/io/cells.h>
11#include <dolfinx/mesh/Mesh.h>
12#include <dolfinx/mesh/Topology.h>
18namespace dolfinx::io::VTKHDF
26void write_mesh(std::string filename,
const mesh::Mesh<U>& mesh);
41void io::VTKHDF::write_mesh(std::string filename,
const mesh::Mesh<U>& mesh)
43 hid_t h5file = io::hdf5::open_file(mesh.comm(), filename,
"w",
true);
46 io::hdf5::add_group(h5file,
"VTKHDF");
48 hid_t vtk_group = H5Gopen(h5file,
"VTKHDF", H5P_DEFAULT);
52 hid_t space_id = H5Screate_simple(1, &dims, NULL);
53 hid_t attr_id = H5Acreate(vtk_group,
"Version", H5T_NATIVE_INT32, space_id,
54 H5P_DEFAULT, H5P_DEFAULT);
55 std::array<std::int32_t, 2>
version = {2, 2};
56 H5Awrite(attr_id, H5T_NATIVE_INT32,
version.data());
61 space_id = H5Screate(H5S_SCALAR);
62 hid_t atype = H5Tcopy(H5T_C_S1);
63 H5Tset_size(atype, 16);
64 H5Tset_strpad(atype, H5T_STR_NULLTERM);
66 = H5Acreate(vtk_group,
"Type", atype, space_id, H5P_DEFAULT, H5P_DEFAULT);
67 H5Awrite(attr_id, atype,
"UnstructuredGrid");
74 auto cell_types = mesh.topology()->entity_types(mesh.topology()->dim());
76 std::vector cell_index_maps
77 = mesh.topology()->index_maps(mesh.topology()->dim());
78 std::vector<std::int32_t> num_cells;
79 std::vector<std::int64_t> num_cells_global;
80 for (
auto im : cell_index_maps)
82 num_cells.push_back(im->size_local());
83 num_cells_global.push_back(im->size_global());
87 auto geom_imap = mesh.geometry().index_map();
88 std::int32_t gdim = mesh.geometry().dim();
89 std::int64_t size_global = geom_imap->size_global();
90 std::vector<std::int64_t> geom_global_shape = {size_global, gdim};
91 auto geom_irange = geom_imap->local_range();
93 io::hdf5::write_dataset(h5file,
"/VTKHDF/Points", mesh.geometry().x().data(),
94 geom_irange, geom_global_shape,
true,
false);
96 io::hdf5::write_dataset(h5file,
"VTKHDF/NumberOfPoints", &size_global, {0, 1},
101 std::vector<std::int64_t> topology_flattened;
102 std::vector<std::int64_t> topology_offsets;
103 std::vector<std::uint8_t> vtkcelltypes;
104 for (
int i = 0; i < cell_index_maps.size(); ++i)
106 auto g_dofmap = mesh.geometry().dofmap(i);
108 std::vector<std::int32_t> local_dm;
109 local_dm.reserve(g_dofmap.extent(1) * num_cells[i]);
111 for (
int j = 0; j < num_cells[i]; ++j)
112 for (
int k = 0; k < g_dofmap.extent(1); ++k)
113 local_dm.push_back(g_dofmap(j, perm[k]));
115 std::vector<std::int64_t> global_dm(local_dm.size());
116 geom_imap->local_to_global(local_dm, global_dm);
118 topology_flattened.insert(topology_flattened.end(), global_dm.begin(),
121 topology_offsets.insert(topology_offsets.end(), g_dofmap.extent(0),
125 vtkcelltypes.end(), cell_index_maps[i]->size_local(),
129 std::partial_sum(topology_offsets.cbegin(), topology_offsets.cend(),
130 topology_offsets.begin());
132 std::vector<int> num_nodes_per_cell;
133 std::vector<std::int64_t> cell_start_pos;
134 std::vector<std::int64_t> cell_stop_pos;
135 for (
int i = 0; i < cell_index_maps.size(); ++i)
137 num_nodes_per_cell.push_back(mesh.geometry().cmaps()[i].dim());
138 auto r = cell_index_maps[i]->local_range();
139 cell_start_pos.push_back(r[0]);
140 cell_stop_pos.push_back(r[1]);
144 std::int64_t offset_start_position
145 = std::accumulate(cell_start_pos.begin(), cell_start_pos.end(), 0);
146 std::int64_t offset_stop_position
147 = std::accumulate(cell_stop_pos.begin(), cell_stop_pos.end(), 0);
150 std::int64_t topology_start
151 = std::inner_product(num_nodes_per_cell.begin(), num_nodes_per_cell.end(),
152 cell_start_pos.begin(), 0);
154 std::for_each(topology_offsets.begin(), topology_offsets.end(),
155 [topology_start](std::int64_t& t) { t += topology_start; });
157 std::int64_t num_all_cells_global
158 = std::accumulate(num_cells_global.begin(), num_cells_global.end(), 0);
159 io::hdf5::write_dataset(h5file,
"/VTKHDF/Offsets", topology_offsets.data(),
160 {offset_start_position + 1, offset_stop_position + 1},
161 {num_all_cells_global + 1},
true,
false);
164 std::int64_t topology_size_global
165 = std::inner_product(num_nodes_per_cell.begin(), num_nodes_per_cell.end(),
166 num_cells_global.begin(), 0);
168 std::int64_t topology_stop = topology_start + topology_flattened.size();
169 io::hdf5::write_dataset(
170 h5file,
"/VTKHDF/Connectivity", topology_flattened.data(),
171 {topology_start, topology_stop}, {topology_size_global},
true,
false);
174 io::hdf5::write_dataset(h5file,
"/VTKHDF/Types", vtkcelltypes.data(),
175 {offset_start_position, offset_stop_position},
176 {num_all_cells_global},
true,
false);
178 io::hdf5::write_dataset(h5file,
"/VTKHDF/NumberOfConnectivityIds",
179 &topology_size_global, {0, 1}, {1},
true,
false);
181 io::hdf5::write_dataset(h5file,
"/VTKHDF/NumberOfCells",
182 &num_all_cells_global, {0, 1}, {1},
true,
false);
184 io::hdf5::close_file(h5file);
188mesh::Mesh<U> io::VTKHDF::read_mesh(MPI_Comm comm, std::string filename)
190 hid_t h5file = io::hdf5::open_file(comm, filename,
"r",
true);
192 std::vector<std::int64_t> shape
193 = io::hdf5::get_dataset_shape(h5file,
"/VTKHDF/Types");
198 hid_t dset_id = io::hdf5::open_dataset(h5file,
"/VTKHDF/Types");
199 std::vector<std::uint8_t> types
200 = io::hdf5::read_dataset<std::uint8_t>(dset_id, local_cell_range,
true);
202 std::vector<std::uint8_t> types_unique(types.begin(), types.end());
204 std::ranges::sort(types_unique);
205 auto [unique_end, range_end] = std::ranges::unique(types_unique);
206 types_unique.erase(unique_end, range_end);
211 std::int32_t count = types_unique.size();
212 std::vector<std::int32_t> recv_count(size);
213 std::vector<std::int32_t> recv_offsets(size + 1, 0);
214 MPI_Allgather(&count, 1, MPI_INT32_T, recv_count.data(), 1, MPI_INT32_T,
216 std::partial_sum(recv_count.begin(), recv_count.end(),
217 recv_offsets.begin() + 1);
218 std::vector<std::uint8_t> recv_types(recv_offsets.back());
219 MPI_Allgatherv(types_unique.data(), count, MPI_UINT8_T, recv_types.data(),
220 recv_count.data(), recv_offsets.data(), MPI_UINT8_T, comm);
222 std::ranges::sort(recv_types);
223 auto [unique_end, range_end] = std::ranges::unique(recv_types);
224 recv_types.erase(unique_end, range_end);
228 std::map<std::uint8_t, mesh::CellType> vtk_to_dolfinx;
229 const std::vector<mesh::CellType> dolfinx_cells
230 = {mesh::CellType::point, mesh::CellType::interval,
231 mesh::CellType::triangle, mesh::CellType::quadrilateral,
232 mesh::CellType::tetrahedron, mesh::CellType::prism,
233 mesh::CellType::pyramid, mesh::CellType::hexahedron};
234 for (
auto dolfinx_type : dolfinx_cells)
242 std::map<std::uint8_t, std::int32_t> type_to_index;
243 std::vector<mesh::CellType> dolfinx_cell_type;
244 for (std::size_t i = 0; i < recv_types.size(); ++i)
246 type_to_index.insert({recv_types[i], i});
247 dolfinx_cell_type.push_back(vtk_to_dolfinx.at(recv_types[i]));
250 dset_id = io::hdf5::open_dataset(h5file,
"/VTKHDF/NumberOfPoints");
251 std::vector<std::int64_t> npoints
252 = io::hdf5::read_dataset<std::int64_t>(dset_id, {0, 1},
true);
254 spdlog::info(
"Mesh with {} points", npoints[0]);
257 std::vector<std::int64_t> x_shape
258 = io::hdf5::get_dataset_shape(h5file,
"/VTKHDF/Points");
259 dset_id = io::hdf5::open_dataset(h5file,
"/VTKHDF/Points");
260 std::vector<U> points_local
261 = io::hdf5::read_dataset<U>(dset_id, local_point_range,
true);
263 dset_id = io::hdf5::open_dataset(h5file,
"/VTKHDF/Offsets");
264 std::vector<std::int64_t> offsets = io::hdf5::read_dataset<std::int64_t>(
265 dset_id, {local_cell_range[0], local_cell_range[1] + 1},
true);
267 dset_id = io::hdf5::open_dataset(h5file,
"/VTKHDF/Connectivity");
268 std::vector<std::int64_t> topology = io::hdf5::read_dataset<std::int64_t>(
269 dset_id, {offsets.front(), offsets.back()},
true);
271 const std::int64_t offset0 = offsets.front();
272 std::for_each(offsets.begin(), offsets.end(),
273 [&offset0](std::int64_t& v) { v -= offset0; });
274 io::hdf5::close_file(h5file);
277 std::vector<std::vector<std::int64_t>> cells_local(recv_types.size());
278 for (std::size_t j = 0; j < types.size(); ++j)
280 std::int32_t type_index = type_to_index.at(types[j]);
284 for (std::size_t k = 0; k < offsets[j + 1] - offsets[j]; ++k)
285 cells_local[type_index].push_back(topology[perm[k] + offsets[j]]);
289 std::vector<fem::CoordinateElement<U>> coordinate_elements;
290 for (
auto& cell : dolfinx_cell_type)
294 std::vector<std::span<const std::int64_t>> cells_span;
295 for (
auto& cells : cells_local)
296 cells_span.push_back(cells);
297 std::array<std::size_t, 2> xs
298 = {(std::size_t)x_shape[0], (std::size_t)x_shape[1]};
299 return create_mesh(comm, comm, cells_span, coordinate_elements, comm,
300 points_local, xs, part);
A Mesh consists of a set of connected and numbered mesh topological entities, and geometry data.
Definition Mesh.h:23
Functions supporting mesh operations.
int size(MPI_Comm comm)
Definition MPI.cpp:72
int rank(MPI_Comm comm)
Return process rank for the communicator.
Definition MPI.cpp:64
constexpr std::array< std::int64_t, 2 > local_range(int rank, std::int64_t N, int size)
Return local range for the calling process, partitioning the global [0, N - 1] range across all ranks...
Definition MPI.h:91
std::int8_t get_vtk_cell_type(mesh::CellType cell, int dim)
Definition cells.cpp:682
std::vector< std::uint16_t > perm_vtk(mesh::CellType type, int num_nodes)
Permutation array to map from VTK to DOLFINx node ordering.
Definition cells.cpp:577
int cell_dim(CellType type)
Return topological dimension of cell type.
Definition cell_types.cpp:134
Mesh< typename std::remove_reference_t< typename U::value_type > > create_mesh(MPI_Comm comm, MPI_Comm commt, std::vector< std::span< const std::int64_t > > cells, const std::vector< fem::CoordinateElement< typename std::remove_reference_t< typename U::value_type > > > &elements, MPI_Comm commg, const U &x, std::array< std::size_t, 2 > xshape, const CellPartitionFunction &partitioner)
Create a distributed mesh::Mesh from mesh data and using the provided graph partitioning function for...
Definition utils.h:803
CellType
Cell type identifier.
Definition cell_types.h:22
CellPartitionFunction create_cell_partitioner(mesh::GhostMode ghost_mode=mesh::GhostMode::none, const graph::partition_fn &partfn=&graph::partition_graph)
Create a function that computes destination rank for mesh cells on this rank by applying the default ...
Definition utils.cpp:85
Top-level namespace.
Definition defines.h:12
std::string version()
Return DOLFINx version string.
Definition defines.cpp:10