diff --git a/src/language/modules/CoreModule.cpp b/src/language/modules/CoreModule.cpp
index 14817b1c81af7143279c8e8b842b37bf8db66ce7..85dfdcd94bc57cdff4fb01f1177d186313ebe8db 100644
--- a/src/language/modules/CoreModule.cpp
+++ b/src/language/modules/CoreModule.cpp
@@ -35,11 +35,12 @@
 #include <utils/Messenger.hpp>
 #include <utils/PugsUtils.hpp>
 #include <utils/RandomEngine.hpp>
+
 #include <utils/checkpointing/Checkpoint.hpp>
-#include <utils/checkpointing/CheckpointUtils.hpp>
 #include <utils/checkpointing/ReadOStream.hpp>
 #include <utils/checkpointing/Resume.hpp>
 #include <utils/checkpointing/ResumingManager.hpp>
+#include <utils/checkpointing/WriteOStream.hpp>
 
 #include <random>
 
diff --git a/src/language/modules/MeshModule.cpp b/src/language/modules/MeshModule.cpp
index 7c5ea712adc98d8db8e8622533be1902fe85861e..c76260ce58c75c130e4638054fc394458fedbf63 100644
--- a/src/language/modules/MeshModule.cpp
+++ b/src/language/modules/MeshModule.cpp
@@ -35,7 +35,6 @@
 #include <mesh/SubItemArrayPerItemVariant.hpp>
 #include <mesh/SubItemValuePerItemVariant.hpp>
 #include <utils/Exceptions.hpp>
-#include <utils/checkpointing/CheckpointUtils.hpp>
 
 #include <utils/checkpointing/ReadIBoundaryDescriptor.hpp>
 #include <utils/checkpointing/ReadIInterfaceDescriptor.hpp>
@@ -46,8 +45,15 @@
 #include <utils/checkpointing/ReadMesh.hpp>
 #include <utils/checkpointing/ReadSubItemArrayPerItemVariant.hpp>
 #include <utils/checkpointing/ReadSubItemValuePerItemVariant.hpp>
-
-#include <Kokkos_Core.hpp>
+#include <utils/checkpointing/WriteIBoundaryDescriptor.hpp>
+#include <utils/checkpointing/WriteIInterfaceDescriptor.hpp>
+#include <utils/checkpointing/WriteIZoneDescriptor.hpp>
+#include <utils/checkpointing/WriteItemArrayVariant.hpp>
+#include <utils/checkpointing/WriteItemType.hpp>
+#include <utils/checkpointing/WriteItemValueVariant.hpp>
+#include <utils/checkpointing/WriteMesh.hpp>
+#include <utils/checkpointing/WriteSubItemArrayPerItemVariant.hpp>
+#include <utils/checkpointing/WriteSubItemValuePerItemVariant.hpp>
 
 MeshModule::MeshModule()
 {
diff --git a/src/language/modules/SchemeModule.cpp b/src/language/modules/SchemeModule.cpp
index 658642e068ddb1e221d5b319054743921706cea3..f0c1b03df96cf1db239bb300cae2fbf797a17fd5 100644
--- a/src/language/modules/SchemeModule.cpp
+++ b/src/language/modules/SchemeModule.cpp
@@ -53,8 +53,11 @@
 #include <utils/checkpointing/ReadIDiscreteFunctionDescriptor.hpp>
 #include <utils/checkpointing/ReadIQuadratureDescriptor.hpp>
 #include <utils/checkpointing/ReadVariableBCDescriptor.hpp>
-
-#include <utils/checkpointing/CheckpointUtils.hpp>
+#include <utils/checkpointing/WriteDiscreteFunctionVariant.hpp>
+#include <utils/checkpointing/WriteIBoundaryConditionDescriptor.hpp>
+#include <utils/checkpointing/WriteIDiscreteFunctionDescriptor.hpp>
+#include <utils/checkpointing/WriteIQuadratureDescriptor.hpp>
+#include <utils/checkpointing/WriteVariableBCDescriptor.hpp>
 
 #include <memory>
 
diff --git a/src/language/modules/WriterModule.cpp b/src/language/modules/WriterModule.cpp
index e75919ef29d93d0359b56e1ce48df8a6982d8c78..837bc1252d64c5c851ac65561c049b79403ce980 100644
--- a/src/language/modules/WriterModule.cpp
+++ b/src/language/modules/WriterModule.cpp
@@ -18,10 +18,11 @@
 #include <output/NamedItemValueVariant.hpp>
 #include <output/VTKWriter.hpp>
 #include <scheme/DiscreteFunctionVariant.hpp>
-#include <utils/checkpointing/CheckpointUtils.hpp>
 
 #include <utils/checkpointing/ReadINamedDiscreteData.hpp>
 #include <utils/checkpointing/ReadIWriter.hpp>
+#include <utils/checkpointing/WriteINamedDiscreteData.hpp>
+#include <utils/checkpointing/WriteIWriter.hpp>
 
 WriterModule::WriterModule()
 {
diff --git a/src/utils/checkpointing/CMakeLists.txt b/src/utils/checkpointing/CMakeLists.txt
index d16895ad9fcf8a0eca7b174b8c068ae12c2708b1..2c493e227ed375531d8a443a58bcdcf3cf33b82a 100644
--- a/src/utils/checkpointing/CMakeLists.txt
+++ b/src/utils/checkpointing/CMakeLists.txt
@@ -12,7 +12,6 @@ list(APPEND checkpointing_SOURCES
 
 if(PUGS_HAS_HDF5)
   list(APPEND checkpointing_SOURCES
-    CheckpointUtils.cpp
     ReadDiscreteFunctionVariant.cpp
     ReadIBoundaryConditionDescriptor.cpp
     ReadIBoundaryDescriptor.cpp
@@ -31,6 +30,24 @@ if(PUGS_HAS_HDF5)
     ReadSubItemValuePerItemVariant.cpp
     ReadVariableBCDescriptor.cpp
     ResumingData.cpp
+    WriteConnectivity.cpp
+    WriteDiscreteFunctionVariant.cpp
+    WriteIBoundaryConditionDescriptor.cpp
+    WriteIBoundaryDescriptor.cpp
+    WriteIDiscreteFunctionDescriptor.cpp
+    WriteIInterfaceDescriptor.cpp
+    WriteItemArrayVariant.cpp
+    WriteItemType.cpp
+    WriteItemValueVariant.cpp
+    WriteIQuadratureDescriptor.cpp
+    WriteINamedDiscreteData.cpp
+    WriteIWriter.cpp
+    WriteIZoneDescriptor.cpp
+    WriteMesh.cpp
+    WriteOStream.cpp
+    WriteSubItemArrayPerItemVariant.cpp
+    WriteSubItemValuePerItemVariant.cpp
+    WriteVariableBCDescriptor.cpp
   )
 endif(PUGS_HAS_HDF5)
 
diff --git a/src/utils/checkpointing/CheckpointUtils.cpp b/src/utils/checkpointing/CheckpointUtils.cpp
deleted file mode 100644
index e2d6d2b21f3b01c2c8f948e5aede9df0fa0dc4ee..0000000000000000000000000000000000000000
--- a/src/utils/checkpointing/CheckpointUtils.cpp
+++ /dev/null
@@ -1,904 +0,0 @@
-#include <utils/checkpointing/CheckpointUtils.hpp>
-
-#include <analysis/IQuadratureDescriptor.hpp>
-#include <language/modules/MeshModuleTypes.hpp>
-#include <language/modules/SchemeModuleTypes.hpp>
-#include <language/modules/WriterModuleTypes.hpp>
-#include <language/utils/ASTNodeDataTypeTraits.hpp>
-#include <language/utils/DataHandler.hpp>
-#include <language/utils/OFStream.hpp>
-#include <language/utils/OStream.hpp>
-#include <mesh/ItemArrayVariant.hpp>
-#include <mesh/ItemType.hpp>
-#include <mesh/ItemValueVariant.hpp>
-#include <mesh/Mesh.hpp>
-#include <mesh/MeshVariant.hpp>
-#include <mesh/NamedBoundaryDescriptor.hpp>
-#include <mesh/NamedInterfaceDescriptor.hpp>
-#include <mesh/NamedZoneDescriptor.hpp>
-#include <mesh/NumberedBoundaryDescriptor.hpp>
-#include <mesh/NumberedInterfaceDescriptor.hpp>
-#include <mesh/NumberedZoneDescriptor.hpp>
-#include <mesh/SubItemArrayPerItemVariant.hpp>
-#include <mesh/SubItemValuePerItemVariant.hpp>
-#include <output/INamedDiscreteData.hpp>
-#include <output/NamedDiscreteFunction.hpp>
-#include <output/NamedItemArrayVariant.hpp>
-#include <output/NamedItemValueVariant.hpp>
-#include <output/WriterBase.hpp>
-#include <scheme/DiscreteFunctionP0.hpp>
-#include <scheme/DiscreteFunctionP0Vector.hpp>
-#include <scheme/DiscreteFunctionVariant.hpp>
-#include <scheme/IBoundaryConditionDescriptor.hpp>
-#include <scheme/VariableBCDescriptor.hpp>
-#include <utils/checkpointing/DiscreteFunctionTypeHFType.hpp>
-#include <utils/checkpointing/IBoundaryConditionDescriptorHFType.hpp>
-#include <utils/checkpointing/IBoundaryDescriptorHFType.hpp>
-#include <utils/checkpointing/IInterfaceDescriptorHFType.hpp>
-#include <utils/checkpointing/INamedDiscreteDataHFType.hpp>
-#include <utils/checkpointing/IWriterHFType.hpp>
-#include <utils/checkpointing/IZoneDescriptorHFType.hpp>
-#include <utils/checkpointing/ItemTypeHFType.hpp>
-#include <utils/checkpointing/OStreamTypeHFType.hpp>
-#include <utils/checkpointing/QuadratureTypeHFType.hpp>
-#include <utils/checkpointing/RefItemListHFType.hpp>
-
-#include <scheme/AxisBoundaryConditionDescriptor.hpp>
-#include <scheme/DirichletBoundaryConditionDescriptor.hpp>
-#include <scheme/ExternalBoundaryConditionDescriptor.hpp>
-#include <scheme/FixedBoundaryConditionDescriptor.hpp>
-#include <scheme/FourierBoundaryConditionDescriptor.hpp>
-#include <scheme/FreeBoundaryConditionDescriptor.hpp>
-#include <scheme/InflowBoundaryConditionDescriptor.hpp>
-#include <scheme/NeumannBoundaryConditionDescriptor.hpp>
-#include <scheme/OutflowBoundaryConditionDescriptor.hpp>
-#include <scheme/SymmetryBoundaryConditionDescriptor.hpp>
-
-namespace checkpointing
-{
-
-void writeMesh(std::shared_ptr<const MeshVariant> mesh_v, HighFive::File& file, HighFive::Group& checkpoint_group);
-
-template <typename DataType, ItemType item_type, typename ConnectivityPtr>
-void
-write(HighFive::Group& group,
-      const std::string& name,
-      const ItemValue<DataType, item_type, ConnectivityPtr>& item_value)
-{
-  write(group, name, item_value.arrayView());
-}
-
-template <typename DataType, ItemType item_type, typename ConnectivityPtr>
-void
-write(HighFive::Group& group,
-      const std::string& name,
-      const ItemArray<DataType, item_type, ConnectivityPtr>& item_array)
-{
-  write(group, name, item_array.tableView());
-}
-
-template <ItemType item_type, size_t Dimension>
-void
-writeRefItemList(const Connectivity<Dimension>& connectivity, HighFive::Group& connectivity_group)
-{
-  for (size_t i_item_list = 0; i_item_list < connectivity.template numberOfRefItemList<item_type>(); ++i_item_list) {
-    auto ref_item_list = connectivity.template refItemList<item_type>(i_item_list);
-
-    std::ostringstream ref_item_list_group_name;
-    ref_item_list_group_name << "item_ref_list/" << itemName(item_type) << '/' << ref_item_list.refId().tagName();
-    HighFive::Group ref_item_list_group = connectivity_group.createGroup(ref_item_list_group_name.str());
-    ref_item_list_group.createAttribute("tag_name", ref_item_list.refId().tagName());
-    ref_item_list_group.createAttribute("tag_number", ref_item_list.refId().tagNumber());
-    ref_item_list_group.createAttribute("type", ref_item_list.type());
-
-    write(ref_item_list_group, "list", ref_item_list.list());
-  }
-}
-
-template <size_t Dimension>
-void
-writeConnectivity(const Connectivity<Dimension>& connectivity, HighFive::File& file, HighFive::Group& checkpoint_group)
-{
-  std::string connectivity_group_name = "connectivity/" + std::to_string(connectivity.id());
-  if (not checkpoint_group.exist(connectivity_group_name)) {
-    bool linked = false;
-    for (auto group_name : file.listObjectNames()) {
-      const std::string stored_connectivity_group_name = group_name + "/" + connectivity_group_name;
-      if (file.exist(stored_connectivity_group_name)) {
-        HighFive::Group stored_connectivity_group = file.getGroup(stored_connectivity_group_name);
-
-        const std::string type_name = stored_connectivity_group.getAttribute("type").read<std::string>();
-        if (type_name != "dual_connectivity") {
-          checkpoint_group.createHardLink(connectivity_group_name, file.getGroup(stored_connectivity_group_name));
-          linked = true;
-          break;
-        }
-      }
-    }
-
-    if (not linked) {
-      HighFive::Group connectivity_group = checkpoint_group.createGroup(connectivity_group_name);
-
-      connectivity_group.createAttribute("dimension", connectivity.dimension());
-      connectivity_group.createAttribute("id", connectivity.id());
-      connectivity_group.createAttribute("type", std::string{"unstructured"});
-
-      write(connectivity_group, "cell_to_node_matrix_values",
-            connectivity.getMatrix(ItemType::cell, ItemType::node).values());
-      write(connectivity_group, "cell_to_node_matrix_rowsMap",
-            connectivity.getMatrix(ItemType::cell, ItemType::node).rowsMap());
-
-      if constexpr (Dimension > 1) {
-        write(connectivity_group, "cell_to_face_matrix_values",
-              connectivity.getMatrix(ItemType::cell, ItemType::face).values());
-        write(connectivity_group, "cell_to_face_matrix_rowsMap",
-              connectivity.getMatrix(ItemType::cell, ItemType::face).rowsMap());
-
-        write(connectivity_group, "face_to_node_matrix_values",
-              connectivity.getMatrix(ItemType::face, ItemType::node).values());
-        write(connectivity_group, "face_to_node_matrix_rowsMap",
-              connectivity.getMatrix(ItemType::face, ItemType::node).rowsMap());
-
-        write(connectivity_group, "node_to_face_matrix_values",
-              connectivity.getMatrix(ItemType::node, ItemType::face).values());
-        write(connectivity_group, "node_to_face_matrix_rowsMap",
-              connectivity.getMatrix(ItemType::node, ItemType::face).rowsMap());
-
-        write(connectivity_group, "cell_face_is_reversed", connectivity.cellFaceIsReversed().arrayView());
-      }
-
-      if constexpr (Dimension > 2) {
-        write(connectivity_group, "cell_to_edge_matrix_values",
-              connectivity.getMatrix(ItemType::cell, ItemType::edge).values());
-        write(connectivity_group, "cell_to_edge_matrix_rowsMap",
-              connectivity.getMatrix(ItemType::cell, ItemType::edge).rowsMap());
-
-        write(connectivity_group, "face_to_edge_matrix_values",
-              connectivity.getMatrix(ItemType::face, ItemType::edge).values());
-        write(connectivity_group, "face_to_edge_matrix_rowsMap",
-              connectivity.getMatrix(ItemType::face, ItemType::edge).rowsMap());
-
-        write(connectivity_group, "edge_to_node_matrix_values",
-              connectivity.getMatrix(ItemType::edge, ItemType::node).values());
-        write(connectivity_group, "edge_to_node_matrix_rowsMap",
-              connectivity.getMatrix(ItemType::edge, ItemType::node).rowsMap());
-
-        write(connectivity_group, "node_to_edge_matrix_values",
-              connectivity.getMatrix(ItemType::node, ItemType::edge).values());
-        write(connectivity_group, "node_to_edge_matrix_rowsMap",
-              connectivity.getMatrix(ItemType::node, ItemType::edge).rowsMap());
-
-        write(connectivity_group, "face_edge_is_reversed", connectivity.faceEdgeIsReversed().arrayView());
-      }
-
-      write(connectivity_group, "cell_type", connectivity.cellType());
-
-      write(connectivity_group, "cell_numbers", connectivity.cellNumber());
-      write(connectivity_group, "node_numbers", connectivity.nodeNumber());
-
-      write(connectivity_group, "cell_owner", connectivity.cellOwner());
-      write(connectivity_group, "node_owner", connectivity.nodeOwner());
-
-      if constexpr (Dimension > 1) {
-        write(connectivity_group, "face_numbers", connectivity.faceNumber());
-
-        write(connectivity_group, "face_owner", connectivity.faceOwner());
-      }
-      if constexpr (Dimension > 2) {
-        write(connectivity_group, "edge_numbers", connectivity.edgeNumber());
-
-        write(connectivity_group, "edge_owner", connectivity.edgeOwner());
-      }
-
-      writeRefItemList<ItemType::cell>(connectivity, connectivity_group);
-      writeRefItemList<ItemType::face>(connectivity, connectivity_group);
-      writeRefItemList<ItemType::edge>(connectivity, connectivity_group);
-      writeRefItemList<ItemType::node>(connectivity, connectivity_group);
-    }
-  }
-}
-
-void
-writeConnectivity(const IConnectivity& connectivity, HighFive::File& file, HighFive::Group& checkpoint_group)
-{
-  switch (connectivity.dimension()) {
-  case 1: {
-    writeConnectivity(dynamic_cast<const Connectivity<1>&>(connectivity), file, checkpoint_group);
-    break;
-  }
-  case 2: {
-    writeConnectivity(dynamic_cast<const Connectivity<2>&>(connectivity), file, checkpoint_group);
-    break;
-  }
-  case 3: {
-    writeConnectivity(dynamic_cast<const Connectivity<3>&>(connectivity), file, checkpoint_group);
-    break;
-  }
-  default: {
-    throw UnexpectedError("invalid connectivity dimension");
-  }
-  }
-}
-
-void
-writeDiscreteFunctionVariant(HighFive::Group& variable_group,
-                             std::shared_ptr<const DiscreteFunctionVariant> discrete_function_v,
-                             HighFive::File& file,
-                             HighFive::Group& checkpoint_group)
-{
-  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(discrete_function_v)>));
-
-  std::visit(
-    [&](auto&& discrete_function) {
-      auto mesh_v  = discrete_function.meshVariant();
-      using DFType = std::decay_t<decltype(discrete_function)>;
-      variable_group.createAttribute("Vh_type", discrete_function.descriptor().type());
-
-      variable_group.createAttribute("mesh_id", mesh_v->id());
-      writeMesh(mesh_v, file, checkpoint_group);
-      if constexpr (is_discrete_function_P0_v<DFType>) {
-        using data_type = std::decay_t<typename DFType::data_type>;
-        variable_group.createAttribute("data_type", dataTypeName(ast_node_data_type_from<data_type>));
-        write(variable_group, "values", discrete_function.cellValues());
-      } else if constexpr (is_discrete_function_P0_vector_v<DFType>) {
-        using data_type = std::decay_t<typename DFType::data_type>;
-        variable_group.createAttribute("data_type", dataTypeName(ast_node_data_type_from<data_type>));
-        write(variable_group, "values", discrete_function.cellArrays());
-      }
-    },
-    discrete_function_v->discreteFunction());
-}
-
-void
-writeDiscreteFunctionVariant(const std::string& symbol_name,
-                             const EmbeddedData& embedded_data,
-                             HighFive::File& file,
-                             HighFive::Group& checkpoint_group,
-                             HighFive::Group& symbol_table_group)
-{
-  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
-
-  std::shared_ptr<const DiscreteFunctionVariant> discrete_function_p =
-    dynamic_cast<const DataHandler<const DiscreteFunctionVariant>&>(embedded_data.get()).data_ptr();
-
-  writeDiscreteFunctionVariant(variable_group, discrete_function_p, file, checkpoint_group);
-}
-
-void
-writeIBoundaryDescriptor(HighFive::Group& variable_group, const IBoundaryDescriptor& iboundary_descriptor)
-{
-  variable_group.createAttribute("iboundary_descriptor_type", iboundary_descriptor.type());
-
-  switch (iboundary_descriptor.type()) {
-  case IBoundaryDescriptor::Type::named: {
-    const NamedBoundaryDescriptor& named_boundary_descriptor =
-      dynamic_cast<const NamedBoundaryDescriptor&>(iboundary_descriptor);
-    variable_group.createAttribute("name", named_boundary_descriptor.name());
-    break;
-  }
-  case IBoundaryDescriptor::Type::numbered: {
-    const NumberedBoundaryDescriptor& numbered_boundary_descriptor =
-      dynamic_cast<const NumberedBoundaryDescriptor&>(iboundary_descriptor);
-    variable_group.createAttribute("number", numbered_boundary_descriptor.number());
-    break;
-  }
-  }
-}
-
-void
-writeIBoundaryConditionDescriptor(HighFive::Group& variable_group,
-                                  std::shared_ptr<const IBoundaryConditionDescriptor> iboundary_condition_descriptor_p)
-{
-  const IBoundaryConditionDescriptor& iboundary_condition_descriptor = *iboundary_condition_descriptor_p;
-
-  variable_group.createAttribute("type",
-                                 dataTypeName(ast_node_data_type_from<decltype(iboundary_condition_descriptor_p)>));
-  variable_group.createAttribute("iboundary_condition_descriptor_type", iboundary_condition_descriptor.type());
-
-  HighFive::Group boundary_group = variable_group.createGroup("boundary");
-
-  switch (iboundary_condition_descriptor.type()) {
-  case IBoundaryConditionDescriptor::Type::axis: {
-    const AxisBoundaryConditionDescriptor& axis_bc_descriptor =
-      dynamic_cast<const AxisBoundaryConditionDescriptor&>(iboundary_condition_descriptor);
-    writeIBoundaryDescriptor(boundary_group, axis_bc_descriptor.boundaryDescriptor());
-    break;
-  }
-  case IBoundaryConditionDescriptor::Type::dirichlet: {
-    const DirichletBoundaryConditionDescriptor& dirichlet_bc_descriptor =
-      dynamic_cast<const DirichletBoundaryConditionDescriptor&>(iboundary_condition_descriptor);
-    writeIBoundaryDescriptor(boundary_group, dirichlet_bc_descriptor.boundaryDescriptor());
-    variable_group.createAttribute("name", dirichlet_bc_descriptor.name());
-    variable_group.createAttribute("rhs_function_id", dirichlet_bc_descriptor.rhsSymbolId().id());
-    break;
-  }
-  case IBoundaryConditionDescriptor::Type::external: {
-    throw NotImplementedError("checkpoint/resume with sockets");
-
-    break;
-  }
-  case IBoundaryConditionDescriptor::Type::fourier: {
-    const FourierBoundaryConditionDescriptor& fourier_bc_descriptor =
-      dynamic_cast<const FourierBoundaryConditionDescriptor&>(iboundary_condition_descriptor);
-    writeIBoundaryDescriptor(boundary_group, fourier_bc_descriptor.boundaryDescriptor());
-    variable_group.createAttribute("name", fourier_bc_descriptor.name());
-    variable_group.createAttribute("rhs_function_id", fourier_bc_descriptor.rhsSymbolId().id());
-    variable_group.createAttribute("mass_function_id", fourier_bc_descriptor.massSymbolId().id());
-    break;
-  }
-  case IBoundaryConditionDescriptor::Type::fixed: {
-    const FixedBoundaryConditionDescriptor& fixed_bc_descriptor =
-      dynamic_cast<const FixedBoundaryConditionDescriptor&>(iboundary_condition_descriptor);
-    writeIBoundaryDescriptor(boundary_group, fixed_bc_descriptor.boundaryDescriptor());
-    break;
-  }
-  case IBoundaryConditionDescriptor::Type::free: {
-    const FreeBoundaryConditionDescriptor& free_bc_descriptor =
-      dynamic_cast<const FreeBoundaryConditionDescriptor&>(iboundary_condition_descriptor);
-    writeIBoundaryDescriptor(boundary_group, free_bc_descriptor.boundaryDescriptor());
-    break;
-  }
-  case IBoundaryConditionDescriptor::Type::inflow: {
-    const InflowBoundaryConditionDescriptor& inflow_bc_descriptor =
-      dynamic_cast<const InflowBoundaryConditionDescriptor&>(iboundary_condition_descriptor);
-    writeIBoundaryDescriptor(boundary_group, inflow_bc_descriptor.boundaryDescriptor());
-    variable_group.createAttribute("function_id", inflow_bc_descriptor.functionSymbolId().id());
-    break;
-  }
-  case IBoundaryConditionDescriptor::Type::neumann: {
-    const NeumannBoundaryConditionDescriptor& neumann_bc_descriptor =
-      dynamic_cast<const NeumannBoundaryConditionDescriptor&>(iboundary_condition_descriptor);
-    writeIBoundaryDescriptor(boundary_group, neumann_bc_descriptor.boundaryDescriptor());
-    variable_group.createAttribute("name", neumann_bc_descriptor.name());
-    variable_group.createAttribute("rhs_function_id", neumann_bc_descriptor.rhsSymbolId().id());
-    break;
-  }
-  case IBoundaryConditionDescriptor::Type::outflow: {
-    const OutflowBoundaryConditionDescriptor& outflow_bc_descriptor =
-      dynamic_cast<const OutflowBoundaryConditionDescriptor&>(iboundary_condition_descriptor);
-    writeIBoundaryDescriptor(boundary_group, outflow_bc_descriptor.boundaryDescriptor());
-    break;
-  }
-  case IBoundaryConditionDescriptor::Type::symmetry: {
-    const SymmetryBoundaryConditionDescriptor& symmetric_bc_descriptor =
-      dynamic_cast<const SymmetryBoundaryConditionDescriptor&>(iboundary_condition_descriptor);
-    writeIBoundaryDescriptor(boundary_group, symmetric_bc_descriptor.boundaryDescriptor());
-    break;
-  }
-  }
-}
-
-void
-writeIBoundaryConditionDescriptor(const std::string& symbol_name,
-                                  const EmbeddedData& embedded_data,
-                                  HighFive::File&,
-                                  HighFive::Group&,
-                                  HighFive::Group& symbol_table_group)
-{
-  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
-
-  std::shared_ptr<const IBoundaryConditionDescriptor> iboundary_condition_descriptor_p =
-    dynamic_cast<const DataHandler<const IBoundaryConditionDescriptor>&>(embedded_data.get()).data_ptr();
-
-  writeIBoundaryConditionDescriptor(variable_group, iboundary_condition_descriptor_p);
-}
-
-void
-writeIBoundaryDescriptor(const std::string& symbol_name,
-                         const EmbeddedData& embedded_data,
-                         HighFive::File&,
-                         HighFive::Group&,
-                         HighFive::Group& symbol_table_group)
-{
-  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
-
-  std::shared_ptr<const IBoundaryDescriptor> iboundary_descriptor_p =
-    dynamic_cast<const DataHandler<const IBoundaryDescriptor>&>(embedded_data.get()).data_ptr();
-
-  const IBoundaryDescriptor& iboundary_descriptor = *iboundary_descriptor_p;
-
-  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(iboundary_descriptor_p)>));
-
-  writeIBoundaryDescriptor(variable_group, iboundary_descriptor);
-}
-
-void
-writeIDiscreteFunctionDescriptor(const std::string& symbol_name,
-                                 const EmbeddedData& embedded_data,
-                                 HighFive::File&,
-                                 HighFive::Group&,
-                                 HighFive::Group& symbol_table_group)
-{
-  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
-
-  std::shared_ptr<const IDiscreteFunctionDescriptor> idiscrete_function_desriptor_p =
-    dynamic_cast<const DataHandler<const IDiscreteFunctionDescriptor>&>(embedded_data.get()).data_ptr();
-
-  const IDiscreteFunctionDescriptor& idiscrete_function_descriptor = *idiscrete_function_desriptor_p;
-
-  variable_group.createAttribute("type",
-                                 dataTypeName(ast_node_data_type_from<decltype(idiscrete_function_desriptor_p)>));
-  variable_group.createAttribute("discrete_function_type", idiscrete_function_descriptor.type());
-}
-
-void
-writeIInterfaceDescriptor(const std::string& symbol_name,
-                          const EmbeddedData& embedded_data,
-                          HighFive::File&,
-                          HighFive::Group&,
-                          HighFive::Group& symbol_table_group)
-{
-  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
-
-  std::shared_ptr<const IInterfaceDescriptor> iinterface_descriptor_p =
-    dynamic_cast<const DataHandler<const IInterfaceDescriptor>&>(embedded_data.get()).data_ptr();
-
-  const IInterfaceDescriptor& iinterface_descriptor = *iinterface_descriptor_p;
-
-  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(iinterface_descriptor_p)>));
-  variable_group.createAttribute("iinterface_descriptor_type", iinterface_descriptor.type());
-
-  switch (iinterface_descriptor.type()) {
-  case IInterfaceDescriptor::Type::named: {
-    const NamedInterfaceDescriptor& named_interface_descriptor =
-      dynamic_cast<const NamedInterfaceDescriptor&>(iinterface_descriptor);
-    variable_group.createAttribute("name", named_interface_descriptor.name());
-    break;
-  }
-  case IInterfaceDescriptor::Type::numbered: {
-    const NumberedInterfaceDescriptor& numbered_boundary_descriptor =
-      dynamic_cast<const NumberedInterfaceDescriptor&>(iinterface_descriptor);
-    variable_group.createAttribute("number", numbered_boundary_descriptor.number());
-    break;
-  }
-  }
-}
-
-void writeItemArrayVariant(HighFive::Group& variable_group,
-                           std::shared_ptr<const ItemArrayVariant> item_array_variant_v,
-                           HighFive::File& file,
-                           HighFive::Group& checkpoint_group);
-
-void writeItemValueVariant(HighFive::Group& variable_group,
-                           std::shared_ptr<const ItemValueVariant> item_value_variant_v,
-                           HighFive::File& file,
-                           HighFive::Group& checkpoint_group);
-
-void
-writeINamedDiscreteData(const std::string& symbol_name,
-                        const EmbeddedData& embedded_data,
-                        HighFive::File& file,
-                        HighFive::Group& checkpoint_group,
-                        HighFive::Group& symbol_table_group)
-{
-  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
-
-  std::shared_ptr<const INamedDiscreteData> inamed_discrete_data_p =
-    dynamic_cast<const DataHandler<const INamedDiscreteData>&>(embedded_data.get()).data_ptr();
-
-  const INamedDiscreteData& inamed_discrete_data = *inamed_discrete_data_p;
-
-  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(inamed_discrete_data_p)>));
-  variable_group.createAttribute("named_discrete_data_type", inamed_discrete_data.type());
-  variable_group.createAttribute("named_discrete_data_name", inamed_discrete_data.name());
-
-  switch (inamed_discrete_data.type()) {
-  case INamedDiscreteData::Type::discrete_function: {
-    const NamedDiscreteFunction& named_discrete_function =
-      dynamic_cast<const NamedDiscreteFunction&>(inamed_discrete_data);
-
-    HighFive::Group discrete_function_group = variable_group.createGroup("discrete_function_variant");
-    writeDiscreteFunctionVariant(discrete_function_group, named_discrete_function.discreteFunctionVariant(), file,
-                                 checkpoint_group);
-    break;
-  }
-  case INamedDiscreteData::Type::item_array: {
-    const NamedItemArrayVariant& named_item_array_v = dynamic_cast<const NamedItemArrayVariant&>(inamed_discrete_data);
-
-    HighFive::Group item_array_group = variable_group.createGroup("item_array_variant");
-
-    writeItemArrayVariant(item_array_group, named_item_array_v.itemArrayVariant(), file, checkpoint_group);
-    break;
-  }
-  case INamedDiscreteData::Type::item_value: {
-    const NamedItemValueVariant& named_item_value_v = dynamic_cast<const NamedItemValueVariant&>(inamed_discrete_data);
-
-    HighFive::Group item_value_group = variable_group.createGroup("item_value_variant");
-
-    writeItemValueVariant(item_value_group, named_item_value_v.itemValueVariant(), file, checkpoint_group);
-    break;
-  }
-  }
-}
-
-void
-writeIQuadratureDescriptor(const std::string& symbol_name,
-                           const EmbeddedData& embedded_data,
-                           HighFive::File&,
-                           HighFive::Group&,
-                           HighFive::Group& symbol_table_group)
-{
-  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
-
-  std::shared_ptr<const IQuadratureDescriptor> iquadrature_descriptor_p =
-    dynamic_cast<const DataHandler<const IQuadratureDescriptor>&>(embedded_data.get()).data_ptr();
-
-  const IQuadratureDescriptor& iquadrature_descriptor = *iquadrature_descriptor_p;
-
-  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(iquadrature_descriptor_p)>));
-  variable_group.createAttribute("quadrature_type", iquadrature_descriptor.type());
-  variable_group.createAttribute("quadrature_degree", iquadrature_descriptor.degree());
-}
-
-void
-writeItemArrayVariant(HighFive::Group& variable_group,
-                      std::shared_ptr<const ItemArrayVariant> item_array_variant_v,
-                      HighFive::File& file,
-                      HighFive::Group& checkpoint_group)
-{
-  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(item_array_variant_v)>));
-
-  std::visit(
-    [&](auto&& item_array) {
-      using ItemArrayT = std::decay_t<decltype(item_array)>;
-
-      variable_group.createAttribute("item_type", ItemArrayT::item_t);
-      using data_type = std::decay_t<typename ItemArrayT::data_type>;
-      variable_group.createAttribute("data_type", dataTypeName(ast_node_data_type_from<data_type>));
-
-      const IConnectivity& connectivity = *item_array.connectivity_ptr();
-      variable_group.createAttribute("connectivity_id", connectivity.id());
-      writeConnectivity(connectivity, file, checkpoint_group);
-
-      write(variable_group, "arrays", item_array);
-    },
-    item_array_variant_v->itemArray());
-}
-
-void
-writeItemArrayVariant(const std::string& symbol_name,
-                      const EmbeddedData& embedded_data,
-                      HighFive::File& file,
-                      HighFive::Group& checkpoint_group,
-                      HighFive::Group& symbol_table_group)
-{
-  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
-
-  std::shared_ptr<const ItemArrayVariant> item_array_variant_p =
-    dynamic_cast<const DataHandler<const ItemArrayVariant>&>(embedded_data.get()).data_ptr();
-
-  writeItemArrayVariant(variable_group, item_array_variant_p, file, checkpoint_group);
-}
-
-void
-writeItemType(const std::string& symbol_name,
-              const EmbeddedData& embedded_data,
-              HighFive::File&,
-              HighFive::Group&,
-              HighFive::Group& symbol_table_group)
-{
-  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
-
-  std::shared_ptr<const ItemType> item_type_p =
-    dynamic_cast<const DataHandler<const ItemType>&>(embedded_data.get()).data_ptr();
-
-  const ItemType& item_type = *item_type_p;
-
-  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(item_type_p)>));
-  variable_group.createAttribute("item_type", item_type);
-}
-
-void
-writeItemValueVariant(HighFive::Group& variable_group,
-                      std::shared_ptr<const ItemValueVariant> item_value_variant_v,
-                      HighFive::File& file,
-                      HighFive::Group& checkpoint_group)
-{
-  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(item_value_variant_v)>));
-
-  std::visit(
-    [&](auto&& item_value) {
-      using ItemValueT = std::decay_t<decltype(item_value)>;
-
-      variable_group.createAttribute("item_type", ItemValueT::item_t);
-      using data_type = std::decay_t<typename ItemValueT::data_type>;
-      variable_group.createAttribute("data_type", dataTypeName(ast_node_data_type_from<data_type>));
-
-      const IConnectivity& connectivity = *item_value.connectivity_ptr();
-      variable_group.createAttribute("connectivity_id", connectivity.id());
-      writeConnectivity(connectivity, file, checkpoint_group);
-
-      write(variable_group, "values", item_value);
-    },
-    item_value_variant_v->itemValue());
-}
-
-void
-writeItemValueVariant(const std::string& symbol_name,
-                      const EmbeddedData& embedded_data,
-                      HighFive::File& file,
-                      HighFive::Group& checkpoint_group,
-                      HighFive::Group& symbol_table_group)
-{
-  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
-
-  std::shared_ptr<const ItemValueVariant> item_value_variant_p =
-    dynamic_cast<const DataHandler<const ItemValueVariant>&>(embedded_data.get()).data_ptr();
-
-  writeItemValueVariant(variable_group, item_value_variant_p, file, checkpoint_group);
-}
-
-void
-writeIWriter(const std::string& symbol_name,
-             const EmbeddedData& embedded_data,
-             HighFive::File&,
-             HighFive::Group&,
-             HighFive::Group& symbol_table_group)
-{
-  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
-
-  std::shared_ptr<const IWriter> iwriter_p =
-    dynamic_cast<const DataHandler<const IWriter>&>(embedded_data.get()).data_ptr();
-
-  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(iwriter_p)>));
-
-  variable_group.createAttribute("iwriter_type", iwriter_p->type());
-
-  switch (iwriter_p->type()) {
-  case IWriter::Type::gnuplot:
-  case IWriter::Type::gnuplot_1d:
-  case IWriter::Type::vtk: {
-    const WriterBase& writer = dynamic_cast<const WriterBase&>(*iwriter_p);
-
-    variable_group.createAttribute("base_filename", writer.m_base_filename);
-    if (writer.m_signature.has_value()) {
-      variable_group.createAttribute("signature", writer.m_signature.value());
-    }
-    if (writer.m_period_manager.has_value()) {
-      const WriterBase::PeriodManager period_manager = writer.m_period_manager.value();
-      HighFive::Group period_manager_group           = variable_group.createGroup("period_manager");
-
-      period_manager_group.createAttribute("time_period", period_manager.timePeriod());
-      period_manager_group.createAttribute("next_time", period_manager.nextTime());
-      period_manager_group.createAttribute("saved_times", period_manager.getSavedTimes());
-    }
-
-    break;
-  }
-  }
-}
-
-void
-writeSubItemArrayPerItemVariant(HighFive::Group& variable_group,
-                                std::shared_ptr<const SubItemArrayPerItemVariant> sub_item_array_per_item_variant_v,
-                                HighFive::File& file,
-                                HighFive::Group& checkpoint_group)
-{
-  variable_group.createAttribute("type",
-                                 dataTypeName(ast_node_data_type_from<decltype(sub_item_array_per_item_variant_v)>));
-
-  std::visit(
-    [&](auto&& sub_item_array_per_item) {
-      using SubItemArrayPerItemT = std::decay_t<decltype(sub_item_array_per_item)>;
-
-      variable_group.createAttribute("item_type", SubItemArrayPerItemT::item_type);
-      variable_group.createAttribute("sub_item_type", SubItemArrayPerItemT::sub_item_type);
-      using data_type = std::decay_t<typename SubItemArrayPerItemT::data_type>;
-      variable_group.createAttribute("data_type", dataTypeName(ast_node_data_type_from<data_type>));
-
-      const IConnectivity& connectivity = *sub_item_array_per_item.connectivity_ptr();
-      variable_group.createAttribute("connectivity_id", connectivity.id());
-      writeConnectivity(connectivity, file, checkpoint_group);
-
-      write(variable_group, "arrays", sub_item_array_per_item.tableView());
-    },
-    sub_item_array_per_item_variant_v->subItemArrayPerItem());
-}
-
-void
-writeSubItemArrayPerItemVariant(const std::string& symbol_name,
-                                const EmbeddedData& embedded_data,
-                                HighFive::File& file,
-                                HighFive::Group& checkpoint_group,
-                                HighFive::Group& symbol_table_group)
-{
-  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
-
-  std::shared_ptr<const SubItemArrayPerItemVariant> sub_item_array_per_item_variant_p =
-    dynamic_cast<const DataHandler<const SubItemArrayPerItemVariant>&>(embedded_data.get()).data_ptr();
-
-  writeSubItemArrayPerItemVariant(variable_group, sub_item_array_per_item_variant_p, file, checkpoint_group);
-}
-
-void
-writeSubItemValuePerItemVariant(HighFive::Group& variable_group,
-                                std::shared_ptr<const SubItemValuePerItemVariant> sub_item_value_per_item_variant_v,
-                                HighFive::File& file,
-                                HighFive::Group& checkpoint_group)
-{
-  variable_group.createAttribute("type",
-                                 dataTypeName(ast_node_data_type_from<decltype(sub_item_value_per_item_variant_v)>));
-
-  std::visit(
-    [&](auto&& sub_item_value_per_item) {
-      using SubItemValuePerItemT = std::decay_t<decltype(sub_item_value_per_item)>;
-
-      variable_group.createAttribute("item_type", SubItemValuePerItemT::item_type);
-      variable_group.createAttribute("sub_item_type", SubItemValuePerItemT::sub_item_type);
-      using data_type = std::decay_t<typename SubItemValuePerItemT::data_type>;
-      variable_group.createAttribute("data_type", dataTypeName(ast_node_data_type_from<data_type>));
-
-      const IConnectivity& connectivity = *sub_item_value_per_item.connectivity_ptr();
-      variable_group.createAttribute("connectivity_id", connectivity.id());
-      writeConnectivity(connectivity, file, checkpoint_group);
-
-      write(variable_group, "values", sub_item_value_per_item.arrayView());
-    },
-    sub_item_value_per_item_variant_v->subItemValuePerItem());
-}
-
-void
-writeSubItemValuePerItemVariant(const std::string& symbol_name,
-                                const EmbeddedData& embedded_data,
-                                HighFive::File& file,
-                                HighFive::Group& checkpoint_group,
-                                HighFive::Group& symbol_table_group)
-{
-  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
-
-  std::shared_ptr<const SubItemValuePerItemVariant> sub_item_value_per_item_variant_p =
-    dynamic_cast<const DataHandler<const SubItemValuePerItemVariant>&>(embedded_data.get()).data_ptr();
-
-  writeSubItemValuePerItemVariant(variable_group, sub_item_value_per_item_variant_p, file, checkpoint_group);
-}
-
-void
-writeIZoneDescriptor(const std::string& symbol_name,
-                     const EmbeddedData& embedded_data,
-                     HighFive::File&,
-                     HighFive::Group&,
-                     HighFive::Group& symbol_table_group)
-{
-  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
-
-  std::shared_ptr<const IZoneDescriptor> izone_descriptor_p =
-    dynamic_cast<const DataHandler<const IZoneDescriptor>&>(embedded_data.get()).data_ptr();
-
-  const IZoneDescriptor& izone_descriptor = *izone_descriptor_p;
-
-  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(izone_descriptor_p)>));
-  variable_group.createAttribute("izone_descriptor_type", izone_descriptor.type());
-
-  switch (izone_descriptor.type()) {
-  case IZoneDescriptor::Type::named: {
-    const NamedZoneDescriptor& named_zone_descriptor = dynamic_cast<const NamedZoneDescriptor&>(izone_descriptor);
-    variable_group.createAttribute("name", named_zone_descriptor.name());
-    break;
-  }
-  case IZoneDescriptor::Type::numbered: {
-    const NumberedZoneDescriptor& numbered_boundary_descriptor =
-      dynamic_cast<const NumberedZoneDescriptor&>(izone_descriptor);
-    variable_group.createAttribute("number", numbered_boundary_descriptor.number());
-    break;
-  }
-  }
-}
-
-void
-writeMesh(std::shared_ptr<const MeshVariant> mesh_v, HighFive::File& file, HighFive::Group& checkpoint_group)
-{
-  std::string mesh_group_name = "mesh/" + std::to_string(mesh_v->id());
-  if (not checkpoint_group.exist(mesh_group_name)) {
-    bool linked = false;
-    for (auto group_name : file.listObjectNames()) {
-      if (file.exist(group_name + "/" + mesh_group_name)) {
-        checkpoint_group.createHardLink(mesh_group_name, file.getGroup(group_name + "/" + mesh_group_name));
-        linked = true;
-        break;
-      }
-    }
-
-    if (not linked) {
-      HighFive::Group mesh_group = checkpoint_group.createGroup(mesh_group_name);
-      mesh_group.createAttribute("connectivity", mesh_v->connectivity().id());
-      std::visit(
-        [&](auto&& mesh) {
-          using MeshType = mesh_type_t<decltype(mesh)>;
-          if constexpr (is_polygonal_mesh_v<MeshType>) {
-            mesh_group.createAttribute("id", mesh->id());
-            mesh_group.createAttribute("type", std::string{"polygonal"});
-            mesh_group.createAttribute("dimension", mesh->dimension());
-            write(mesh_group, "xr", mesh->xr());
-          } else {
-            throw UnexpectedError("unexpected mesh type");
-          }
-        },
-        mesh_v->variant());
-    }
-  }
-
-  std::visit(
-    [&](auto&& mesh) {
-      using MeshType = mesh_type_t<decltype(mesh)>;
-      if constexpr (is_polygonal_mesh_v<MeshType>) {
-        writeConnectivity(mesh->connectivity(), file, checkpoint_group);
-      }
-    },
-    mesh_v->variant());
-}
-
-void
-writeMesh(const std::string& symbol_name,
-          const EmbeddedData& embedded_data,
-          HighFive::File& file,
-          HighFive::Group& checkpoint_group,
-          HighFive::Group& symbol_table_group)
-{
-  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
-
-  std::shared_ptr<const MeshVariant> mesh_v =
-    dynamic_cast<const DataHandler<const MeshVariant>&>(embedded_data.get()).data_ptr();
-
-  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(mesh_v)>));
-  variable_group.createAttribute("id", mesh_v->id());
-
-  writeMesh(mesh_v, file, checkpoint_group);
-}
-
-void
-writeOStream(const std::string& symbol_name,
-             const EmbeddedData& embedded_data,
-             HighFive::File&,
-             HighFive::Group&,
-             HighFive::Group& symbol_table_group)
-{
-  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
-
-  std::shared_ptr<const OStream> ostream_p =
-    dynamic_cast<const DataHandler<const OStream>&>(embedded_data.get()).data_ptr();
-
-  const OStream& ostream = *ostream_p;
-
-  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(ostream_p)>));
-  variable_group.createAttribute("ostream_type", ostream.type());
-
-  switch (ostream.type()) {
-  case OStream::Type::std_ofstream: {
-    const OFStream& ofstream = dynamic_cast<const OFStream&>(ostream);
-    variable_group.createAttribute("filename", ofstream.filename());
-    break;
-  }
-  case OStream::Type::std_ostream: {
-    throw NotImplementedError("std::ostream checkpoint");
-  }
-  }
-}
-
-void
-writeVariableBCDescriptor(const std::string& symbol_name,
-                          const EmbeddedData& embedded_data,
-                          HighFive::File& file,
-                          HighFive::Group& checkpoint_group,
-                          HighFive::Group& symbol_table_group)
-{
-  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
-
-  std::shared_ptr<const VariableBCDescriptor> variable_bc_descriptor_p =
-    dynamic_cast<const DataHandler<const VariableBCDescriptor>&>(embedded_data.get()).data_ptr();
-
-  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(variable_bc_descriptor_p)>));
-
-  HighFive::Group discrete_function_group = variable_group.createGroup("discrete_function");
-  writeDiscreteFunctionVariant(discrete_function_group, variable_bc_descriptor_p->discreteFunctionVariant(), file,
-                               checkpoint_group);
-
-  const auto bc_descriptor_list            = variable_bc_descriptor_p->bcDescriptorList();
-  HighFive::Group bc_descriptor_list_group = variable_group.createGroup("bc_descriptor_list");
-  for (size_t i_bc_descriptor = 0; i_bc_descriptor < bc_descriptor_list.size(); ++i_bc_descriptor) {
-    HighFive::Group bc_descriptor_group = bc_descriptor_list_group.createGroup(std::to_string(i_bc_descriptor));
-
-    writeIBoundaryConditionDescriptor(bc_descriptor_group, bc_descriptor_list[i_bc_descriptor]);
-  }
-}
-
-}   // namespace checkpointing
diff --git a/src/utils/checkpointing/CheckpointUtils.hpp b/src/utils/checkpointing/CheckpointUtils.hpp
deleted file mode 100644
index 1bef6709c61f633c2beae844215daeb593e4243e..0000000000000000000000000000000000000000
--- a/src/utils/checkpointing/CheckpointUtils.hpp
+++ /dev/null
@@ -1,229 +0,0 @@
-#ifndef CHECKPOINT_UTILS_HPP
-#define CHECKPOINT_UTILS_HPP
-
-#include <utils/HighFivePugsUtils.hpp>
-
-#include <utils/pugs_config.hpp>
-
-#ifdef PUGS_HAS_HDF5
-
-#include <language/utils/SymbolTable.hpp>
-#include <mesh/CellType.hpp>
-#include <mesh/ItemArray.hpp>
-#include <mesh/ItemValue.hpp>
-#include <utils/Messenger.hpp>
-
-namespace checkpointing
-{
-
-template <typename DataType>
-PUGS_INLINE void
-write(HighFive::Group& group, const std::string& name, const Array<DataType>& array)
-{
-  auto get_address = [](auto& x) { return (x.size() > 0) ? &(x[0]) : nullptr; };
-
-  Array<size_t> size_per_rank = parallel::allGather(array.size());
-  size_t global_size          = sum(size_per_rank);
-
-  size_t current_offset = 0;
-  for (size_t i = 0; i < parallel::rank(); ++i) {
-    current_offset += size_per_rank[i];
-  }
-  std::vector<size_t> offset{current_offset, 0ul};
-  std::vector<size_t> count{array.size()};
-
-  using data_type = std::remove_const_t<DataType>;
-  HighFive::DataSetCreateProps properties;
-  properties.add(HighFive::Chunking(std::vector<hsize_t>{std::min(4ul * 1024ul * 1024ul, global_size)}));
-  properties.add(HighFive::Shuffle());
-  properties.add(HighFive::Deflate(3));
-
-  auto xfer_props = HighFive::DataTransferProps{};
-  xfer_props.add(HighFive::UseCollectiveIO{});
-
-  HighFive::DataSet dataset;
-  if constexpr (std::is_same_v<CellType, data_type>) {
-    using base_type = std::underlying_type_t<CellType>;
-    dataset = group.createDataSet<base_type>(name, HighFive::DataSpace{std::vector<size_t>{global_size}}, properties);
-    dataset.select(offset, count)
-      .template write_raw<base_type>(reinterpret_cast<const base_type*>(get_address(array)), xfer_props);
-  } else if constexpr ((std::is_same_v<CellId, data_type>) or (std::is_same_v<FaceId, data_type>) or
-                       (std::is_same_v<EdgeId, data_type>) or (std::is_same_v<NodeId, data_type>)) {
-    using base_type = typename data_type::base_type;
-
-    dataset = group.createDataSet<base_type>(name, HighFive::DataSpace{std::vector<size_t>{global_size}}, properties);
-    dataset.select(offset, count)
-      .template write_raw<base_type>(reinterpret_cast<const base_type*>(get_address(array)), xfer_props);
-  } else {
-    dataset = group.createDataSet<data_type>(name, HighFive::DataSpace{std::vector<size_t>{global_size}}, properties);
-    dataset.select(offset, count).template write_raw<data_type>(get_address(array), xfer_props);
-  }
-
-  std::vector<size_t> size_vector;
-  for (size_t i = 0; i < size_per_rank.size(); ++i) {
-    size_vector.push_back(size_per_rank[i]);
-  }
-
-  dataset.createAttribute("size_per_rank", size_vector);
-}
-
-template <typename DataType>
-PUGS_INLINE void
-write(HighFive::Group& group, const std::string& name, const Table<DataType>& table)
-{
-  const size_t number_of_columns = parallel::allReduceMax(table.numberOfColumns());
-  if ((table.numberOfColumns() != number_of_columns) and (table.numberOfRows() > 0)) {
-    throw UnexpectedError("table must have same number of columns in parallel");
-  }
-
-  auto get_address = [](auto& t) { return (t.numberOfRows() * t.numberOfColumns() > 0) ? &(t(0, 0)) : nullptr; };
-
-  Array<size_t> number_of_rows_per_rank = parallel::allGather(table.numberOfRows());
-  size_t global_size                    = sum(number_of_rows_per_rank) * number_of_columns;
-
-  size_t current_offset = 0;
-  for (size_t i = 0; i < parallel::rank(); ++i) {
-    current_offset += number_of_rows_per_rank[i] * table.numberOfColumns();
-  }
-  std::vector<size_t> offset{current_offset, 0ul};
-  std::vector<size_t> count{table.numberOfRows() * table.numberOfColumns()};
-
-  using data_type = std::remove_const_t<DataType>;
-  HighFive::DataSetCreateProps properties;
-  properties.add(HighFive::Chunking(std::vector<hsize_t>{std::min(4ul * 1024ul * 1024ul, global_size)}));
-  properties.add(HighFive::Shuffle());
-  properties.add(HighFive::Deflate(3));
-
-  auto xfer_props = HighFive::DataTransferProps{};
-  xfer_props.add(HighFive::UseCollectiveIO{});
-
-  HighFive::DataSet dataset =
-    group.createDataSet<data_type>(name, HighFive::DataSpace{std::vector<size_t>{global_size}}, properties);
-  dataset.select(offset, count).template write_raw<data_type>(get_address(table), xfer_props);
-
-  std::vector<size_t> number_of_rows_per_rank_vector;
-  for (size_t i = 0; i < number_of_rows_per_rank.size(); ++i) {
-    number_of_rows_per_rank_vector.push_back(number_of_rows_per_rank[i]);
-  }
-
-  dataset.createAttribute("number_of_rows_per_rank", number_of_rows_per_rank_vector);
-  dataset.createAttribute("number_of_columns", number_of_columns);
-}
-
-template <typename DataType, ItemType item_type, typename ConnectivityPtr>
-void write(HighFive::Group& group,
-           const std::string& name,
-           const ItemValue<DataType, item_type, ConnectivityPtr>& item_value);
-
-template <typename DataType, ItemType item_type, typename ConnectivityPtr>
-void write(HighFive::Group& group,
-           const std::string& name,
-           const ItemArray<DataType, item_type, ConnectivityPtr>& item_array);
-
-void writeDiscreteFunctionVariant(const std::string& symbol_name,
-                                  const EmbeddedData& embedded_data,
-                                  HighFive::File& file,
-                                  HighFive::Group& checkpoint_group,
-                                  HighFive::Group& symbol_table_group);
-
-void writeIBoundaryConditionDescriptor(const std::string& symbol_name,
-                                       const EmbeddedData& embedded_data,
-                                       HighFive::File& file,
-                                       HighFive::Group& checkpoint_group,
-                                       HighFive::Group& symbol_table_group);
-
-void writeIBoundaryDescriptor(const std::string& symbol_name,
-                              const EmbeddedData& embedded_data,
-                              HighFive::File& file,
-                              HighFive::Group& checkpoint_group,
-                              HighFive::Group& symbol_table_group);
-
-void writeIDiscreteFunctionDescriptor(const std::string& symbol_name,
-                                      const EmbeddedData& embedded_data,
-                                      HighFive::File& file,
-                                      HighFive::Group& checkpoint_group,
-                                      HighFive::Group& symbol_table_group);
-
-void writeIInterfaceDescriptor(const std::string& symbol_name,
-                               const EmbeddedData& embedded_data,
-                               HighFive::File& file,
-                               HighFive::Group& checkpoint_group,
-                               HighFive::Group& symbol_table_group);
-
-void writeINamedDiscreteData(const std::string& symbol_name,
-                             const EmbeddedData& embedded_data,
-                             HighFive::File& file,
-                             HighFive::Group& checkpoint_group,
-                             HighFive::Group& symbol_table_group);
-
-void writeIQuadratureDescriptor(const std::string& symbol_name,
-                                const EmbeddedData& embedded_data,
-                                HighFive::File& file,
-                                HighFive::Group& checkpoint_group,
-                                HighFive::Group& symbol_table_group);
-
-void writeItemArrayVariant(const std::string& symbol_name,
-                           const EmbeddedData& embedded_data,
-                           HighFive::File& file,
-                           HighFive::Group& checkpoint_group,
-                           HighFive::Group& symbol_table_group);
-
-void writeItemType(const std::string& symbol_name,
-                   const EmbeddedData& embedded_data,
-                   HighFive::File& file,
-                   HighFive::Group& checkpoint_group,
-                   HighFive::Group& symbol_table_group);
-
-void writeItemValueVariant(const std::string& symbol_name,
-                           const EmbeddedData& embedded_data,
-                           HighFive::File& file,
-                           HighFive::Group& checkpoint_group,
-                           HighFive::Group& symbol_table_group);
-
-void writeIWriter(const std::string& symbol_name,
-                  const EmbeddedData& embedded_data,
-                  HighFive::File& file,
-                  HighFive::Group& checkpoint_group,
-                  HighFive::Group& symbol_table_group);
-
-void writeIZoneDescriptor(const std::string& symbol_name,
-                          const EmbeddedData& embedded_data,
-                          HighFive::File& file,
-                          HighFive::Group& checkpoint_group,
-                          HighFive::Group& symbol_table_group);
-
-void writeMesh(const std::string& symbol_name,
-               const EmbeddedData& embedded_data,
-               HighFive::File& file,
-               HighFive::Group& checkpoint_group,
-               HighFive::Group& symbol_table_group);
-
-void writeOStream(const std::string& symbol_name,
-                  const EmbeddedData& embedded_data,
-                  HighFive::File& file,
-                  HighFive::Group& checkpoint_group,
-                  HighFive::Group& symbol_table_group);
-
-void writeSubItemArrayPerItemVariant(const std::string& symbol_name,
-                                     const EmbeddedData& embedded_data,
-                                     HighFive::File& file,
-                                     HighFive::Group& checkpoint_group,
-                                     HighFive::Group& symbol_table_group);
-
-void writeSubItemValuePerItemVariant(const std::string& symbol_name,
-                                     const EmbeddedData& embedded_data,
-                                     HighFive::File& file,
-                                     HighFive::Group& checkpoint_group,
-                                     HighFive::Group& symbol_table_group);
-
-void writeVariableBCDescriptor(const std::string& symbol_name,
-                               const EmbeddedData& embedded_data,
-                               HighFive::File& file,
-                               HighFive::Group& checkpoint_group,
-                               HighFive::Group& symbol_table_group);
-
-}   // namespace checkpointing
-
-#endif   // PUGS_HAS_HDF5
-
-#endif   // CHECKPOINT_UTILS_HPP
diff --git a/src/utils/checkpointing/DiscreteFunctionTypeHFType.hpp b/src/utils/checkpointing/DiscreteFunctionTypeHFType.hpp
index 55c22f98c4c76330584e46cf50ed1072fa22417d..c9940f248c85a761761e661fa2c068872131b04b 100644
--- a/src/utils/checkpointing/DiscreteFunctionTypeHFType.hpp
+++ b/src/utils/checkpointing/DiscreteFunctionTypeHFType.hpp
@@ -2,7 +2,7 @@
 #define DISCRETE_FUNCTION_TYPE_HF_TYPE_HPP
 
 #include <scheme/DiscreteFunctionType.hpp>
-#include <utils/checkpointing/CheckpointUtils.hpp>
+#include <utils/HighFivePugsUtils.hpp>
 
 HighFive::EnumType<DiscreteFunctionType> PUGS_INLINE
 create_enum_discrete_function_type()
diff --git a/src/utils/checkpointing/DualMeshTypeHFType.hpp b/src/utils/checkpointing/DualMeshTypeHFType.hpp
index 14010b647f13aa978446ccf9723fd7e79b232cd4..ef742b231763d53e66c9a57bfb9765c16fa6eb54 100644
--- a/src/utils/checkpointing/DualMeshTypeHFType.hpp
+++ b/src/utils/checkpointing/DualMeshTypeHFType.hpp
@@ -2,7 +2,7 @@
 #define DUAL_MESH_TYPE_HF_TYPE_HPP
 
 #include <mesh/DualConnectivityManager.hpp>
-#include <utils/checkpointing/CheckpointUtils.hpp>
+#include <utils/HighFivePugsUtils.hpp>
 
 HighFive::EnumType<DualMeshType> PUGS_INLINE
 create_enum_DualMeshType_type()
diff --git a/src/utils/checkpointing/IBoundaryConditionDescriptorHFType.hpp b/src/utils/checkpointing/IBoundaryConditionDescriptorHFType.hpp
index fb58b6d56557f34ab25d589f69d5de0444f4c242..4a7632af5b933710d6ddf1356c7b83aa3562442a 100644
--- a/src/utils/checkpointing/IBoundaryConditionDescriptorHFType.hpp
+++ b/src/utils/checkpointing/IBoundaryConditionDescriptorHFType.hpp
@@ -2,7 +2,8 @@
 #define I_BOUNDARY_CONDITION_DESCRIPTOR_HF_TYPE_HPP
 
 #include <scheme/IBoundaryConditionDescriptor.hpp>
-#include <utils/checkpointing/CheckpointUtils.hpp>
+#include <utils/HighFivePugsUtils.hpp>
+#include <utils/PugsMacros.hpp>
 
 HighFive::EnumType<IBoundaryConditionDescriptor::Type> PUGS_INLINE
 create_enum_i_boundary_condition_descriptor_type()
diff --git a/src/utils/checkpointing/IBoundaryDescriptorHFType.hpp b/src/utils/checkpointing/IBoundaryDescriptorHFType.hpp
index cc68000de638f530dea39ae6c90ce3e13767f36d..495ace8acdd5fc10180827f3c63420157981556c 100644
--- a/src/utils/checkpointing/IBoundaryDescriptorHFType.hpp
+++ b/src/utils/checkpointing/IBoundaryDescriptorHFType.hpp
@@ -2,7 +2,8 @@
 #define I_BOUNDARY_DESCRIPTOR_HF_TYPE_HPP
 
 #include <mesh/IBoundaryDescriptor.hpp>
-#include <utils/checkpointing/CheckpointUtils.hpp>
+#include <utils/HighFivePugsUtils.hpp>
+#include <utils/PugsMacros.hpp>
 
 HighFive::EnumType<IBoundaryDescriptor::Type> PUGS_INLINE
 create_enum_i_boundary_descriptor_type()
diff --git a/src/utils/checkpointing/IInterfaceDescriptorHFType.hpp b/src/utils/checkpointing/IInterfaceDescriptorHFType.hpp
index 5e4231ad3ae999a5ac262a47e17fd51e6fcdccc5..9f170b0e769b03f3c92679b5b0928af1e5a6267a 100644
--- a/src/utils/checkpointing/IInterfaceDescriptorHFType.hpp
+++ b/src/utils/checkpointing/IInterfaceDescriptorHFType.hpp
@@ -2,7 +2,8 @@
 #define I_INTERFACE_DESCRIPTOR_HF_TYPE_HPP
 
 #include <mesh/IInterfaceDescriptor.hpp>
-#include <utils/checkpointing/CheckpointUtils.hpp>
+#include <utils/HighFivePugsUtils.hpp>
+#include <utils/PugsMacros.hpp>
 
 HighFive::EnumType<IInterfaceDescriptor::Type> PUGS_INLINE
 create_enum_i_interface_descriptor_type()
diff --git a/src/utils/checkpointing/INamedDiscreteDataHFType.hpp b/src/utils/checkpointing/INamedDiscreteDataHFType.hpp
index a1bb006a9502db74bc218fec154d38ef9e647540..0f35ccceca6541f13ec81d2c269ba596618d4195 100644
--- a/src/utils/checkpointing/INamedDiscreteDataHFType.hpp
+++ b/src/utils/checkpointing/INamedDiscreteDataHFType.hpp
@@ -2,7 +2,8 @@
 #define I_NAMED_DISCRETE_DATA_HF_HPP
 
 #include <output/INamedDiscreteData.hpp>
-#include <utils/checkpointing/CheckpointUtils.hpp>
+#include <utils/HighFivePugsUtils.hpp>
+#include <utils/PugsMacros.hpp>
 
 HighFive::EnumType<INamedDiscreteData::Type> PUGS_INLINE
 create_enum_i_named_discrete_data_type()
diff --git a/src/utils/checkpointing/IWriterHFType.hpp b/src/utils/checkpointing/IWriterHFType.hpp
index 7b6659bdccc8a1c58366a1e1ba5ad4b50c2806c9..124cb2ee53f6bf477361cd381e98af366e626231 100644
--- a/src/utils/checkpointing/IWriterHFType.hpp
+++ b/src/utils/checkpointing/IWriterHFType.hpp
@@ -2,7 +2,8 @@
 #define I_WRITER_HF_TYPE_HPP
 
 #include <output/IWriter.hpp>
-#include <utils/checkpointing/CheckpointUtils.hpp>
+#include <utils/HighFivePugsUtils.hpp>
+#include <utils/PugsMacros.hpp>
 
 HighFive::EnumType<IWriter::Type> PUGS_INLINE
 create_enum_i_writer_type()
diff --git a/src/utils/checkpointing/IZoneDescriptorHFType.hpp b/src/utils/checkpointing/IZoneDescriptorHFType.hpp
index d1986624f3616329d882846e866b596d32fc1db5..ffed7f4d02620b3aae3117cee945537a4164d952 100644
--- a/src/utils/checkpointing/IZoneDescriptorHFType.hpp
+++ b/src/utils/checkpointing/IZoneDescriptorHFType.hpp
@@ -2,7 +2,8 @@
 #define I_ZONE_DESCRIPTOR_HF_TYPE_HPP
 
 #include <mesh/IZoneDescriptor.hpp>
-#include <utils/checkpointing/CheckpointUtils.hpp>
+#include <utils/HighFivePugsUtils.hpp>
+#include <utils/PugsMacros.hpp>
 
 HighFive::EnumType<IZoneDescriptor::Type> PUGS_INLINE
 create_enum_i_zone_descriptor_type()
diff --git a/src/utils/checkpointing/ItemTypeHFType.hpp b/src/utils/checkpointing/ItemTypeHFType.hpp
index 714091e0c73ff55c42a5c59ee24a469495977c67..2b7db0ee4061ee6a9695023ecce893710ba99f82 100644
--- a/src/utils/checkpointing/ItemTypeHFType.hpp
+++ b/src/utils/checkpointing/ItemTypeHFType.hpp
@@ -2,7 +2,8 @@
 #define ITEM_TYPE_HF_TYPE_HPP
 
 #include <mesh/ItemType.hpp>
-#include <utils/checkpointing/CheckpointUtils.hpp>
+#include <utils/HighFivePugsUtils.hpp>
+#include <utils/PugsMacros.hpp>
 
 HighFive::EnumType<ItemType> PUGS_INLINE
 create_enum_item_type()
diff --git a/src/utils/checkpointing/LinearSolverOptionsHFType.hpp b/src/utils/checkpointing/LinearSolverOptionsHFType.hpp
index 127fdddc0dfa292d1228d12bf3cd6d7ca39ce4e3..94f88fc60088c297479af36975d533d1c94bdd71 100644
--- a/src/utils/checkpointing/LinearSolverOptionsHFType.hpp
+++ b/src/utils/checkpointing/LinearSolverOptionsHFType.hpp
@@ -2,7 +2,8 @@
 #define LINEAR_SOLVER_OPTIONS_HF_TYPE_HPP
 
 #include <algebra/LinearSolverOptions.hpp>
-#include <utils/checkpointing/CheckpointUtils.hpp>
+#include <utils/HighFivePugsUtils.hpp>
+#include <utils/PugsMacros.hpp>
 
 HighFive::EnumType<LSLibrary> PUGS_INLINE
 create_enum_LSOptions_library_type()
diff --git a/src/utils/checkpointing/OStreamTypeHFType.hpp b/src/utils/checkpointing/OStreamTypeHFType.hpp
index 1c003d18b6312b78a90bb03124a0f9f267221da9..71ced52e7ed58d28f0e8fccd687a8534447b7ce5 100644
--- a/src/utils/checkpointing/OStreamTypeHFType.hpp
+++ b/src/utils/checkpointing/OStreamTypeHFType.hpp
@@ -2,7 +2,8 @@
 #define OSTREAM_TYPE_HF_TYPE_HPP
 
 #include <language/utils/OStream.hpp>
-#include <utils/checkpointing/CheckpointUtils.hpp>
+#include <utils/HighFivePugsUtils.hpp>
+#include <utils/PugsMacros.hpp>
 
 HighFive::EnumType<OStream::Type> PUGS_INLINE
 create_enum_ostream_type()
diff --git a/src/utils/checkpointing/ParallelCheckerHFType.hpp b/src/utils/checkpointing/ParallelCheckerHFType.hpp
index 27cd6412ba1641964c5019275c8032a455860cd1..288326d60ccba261fc586d920b1b5f2c67895133 100644
--- a/src/utils/checkpointing/ParallelCheckerHFType.hpp
+++ b/src/utils/checkpointing/ParallelCheckerHFType.hpp
@@ -2,7 +2,7 @@
 #define PARALLEL_CHECKER_HF_TYPE_HPP
 
 #include <dev/ParallelChecker.hpp>
-#include <utils/checkpointing/CheckpointUtils.hpp>
+#include <utils/HighFivePugsUtils.hpp>
 
 HighFive::EnumType<ParallelChecker::Mode> PUGS_INLINE
 create_enum_ParallelChecker_mode()
diff --git a/src/utils/checkpointing/QuadratureTypeHFType.hpp b/src/utils/checkpointing/QuadratureTypeHFType.hpp
index 3c73f7c72909876eae5f285fdab006ee2a59b111..bba68e822a74237a9e540a5bb5fd3c65714c3976 100644
--- a/src/utils/checkpointing/QuadratureTypeHFType.hpp
+++ b/src/utils/checkpointing/QuadratureTypeHFType.hpp
@@ -2,7 +2,8 @@
 #define QUADRATURE_TYPE_HF_TYPE_HPP
 
 #include <analysis/QuadratureType.hpp>
-#include <utils/checkpointing/CheckpointUtils.hpp>
+#include <utils/HighFivePugsUtils.hpp>
+#include <utils/PugsMacros.hpp>
 
 HighFive::EnumType<QuadratureType> PUGS_INLINE
 create_enum_quadrature_descriptor_type()
diff --git a/src/utils/checkpointing/ReadOStream.cpp b/src/utils/checkpointing/ReadOStream.cpp
index c01491c4613567a047e2a1d4823ce0b301e80fea..d1c597064a60b9af67db0ae5a49e839914089598 100644
--- a/src/utils/checkpointing/ReadOStream.cpp
+++ b/src/utils/checkpointing/ReadOStream.cpp
@@ -3,6 +3,7 @@
 #include <language/utils/DataHandler.hpp>
 #include <language/utils/EmbeddedData.hpp>
 #include <language/utils/OFStream.hpp>
+#include <utils/Exceptions.hpp>
 #include <utils/checkpointing/OStreamTypeHFType.hpp>
 
 namespace checkpointing
diff --git a/src/utils/checkpointing/RefItemListHFType.hpp b/src/utils/checkpointing/RefItemListHFType.hpp
index 4491d4f52b4fd49f8e0d1cef2c88b1e0325f44ee..f9912a61856ed0e52ed6c153f8d9135c63bcaf75 100644
--- a/src/utils/checkpointing/RefItemListHFType.hpp
+++ b/src/utils/checkpointing/RefItemListHFType.hpp
@@ -2,7 +2,8 @@
 #define REF_ITEM_LIST_HF_TYPE_HPP
 
 #include <mesh/RefItemList.hpp>
-#include <utils/checkpointing/CheckpointUtils.hpp>
+#include <utils/HighFivePugsUtils.hpp>
+#include <utils/PugsMacros.hpp>
 
 HighFive::EnumType<RefItemListBase::Type> PUGS_INLINE
 create_enum_ref_item_list_type()
diff --git a/src/utils/checkpointing/WriteArray.hpp b/src/utils/checkpointing/WriteArray.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..1902378d43a5cf8fce7d5dffcf4c0a0bd9be0dd4
--- /dev/null
+++ b/src/utils/checkpointing/WriteArray.hpp
@@ -0,0 +1,67 @@
+#ifndef WRITE_ARRAY_HPP
+#define WRITE_ARRAY_HPP
+
+#include <utils/HighFivePugsUtils.hpp>
+
+#include <mesh/CellType.hpp>
+#include <mesh/ItemId.hpp>
+#include <utils/Array.hpp>
+#include <utils/Messenger.hpp>
+
+namespace checkpointing
+{
+
+template <typename DataType>
+PUGS_INLINE void
+write(HighFive::Group& group, const std::string& name, const Array<DataType>& array)
+{
+  auto get_address = [](auto& x) { return (x.size() > 0) ? &(x[0]) : nullptr; };
+
+  Array<size_t> size_per_rank = parallel::allGather(array.size());
+  size_t global_size          = sum(size_per_rank);
+
+  size_t current_offset = 0;
+  for (size_t i = 0; i < parallel::rank(); ++i) {
+    current_offset += size_per_rank[i];
+  }
+  std::vector<size_t> offset{current_offset, 0ul};
+  std::vector<size_t> count{array.size()};
+
+  using data_type = std::remove_const_t<DataType>;
+  HighFive::DataSetCreateProps properties;
+  properties.add(HighFive::Chunking(std::vector<hsize_t>{std::min(4ul * 1024ul * 1024ul, global_size)}));
+  properties.add(HighFive::Shuffle());
+  properties.add(HighFive::Deflate(3));
+
+  auto xfer_props = HighFive::DataTransferProps{};
+  xfer_props.add(HighFive::UseCollectiveIO{});
+
+  HighFive::DataSet dataset;
+  if constexpr (std::is_same_v<CellType, data_type>) {
+    using base_type = std::underlying_type_t<CellType>;
+    dataset = group.createDataSet<base_type>(name, HighFive::DataSpace{std::vector<size_t>{global_size}}, properties);
+    dataset.select(offset, count)
+      .template write_raw<base_type>(reinterpret_cast<const base_type*>(get_address(array)), xfer_props);
+  } else if constexpr ((std::is_same_v<CellId, data_type>) or (std::is_same_v<FaceId, data_type>) or
+                       (std::is_same_v<EdgeId, data_type>) or (std::is_same_v<NodeId, data_type>)) {
+    using base_type = typename data_type::base_type;
+
+    dataset = group.createDataSet<base_type>(name, HighFive::DataSpace{std::vector<size_t>{global_size}}, properties);
+    dataset.select(offset, count)
+      .template write_raw<base_type>(reinterpret_cast<const base_type*>(get_address(array)), xfer_props);
+  } else {
+    dataset = group.createDataSet<data_type>(name, HighFive::DataSpace{std::vector<size_t>{global_size}}, properties);
+    dataset.select(offset, count).template write_raw<data_type>(get_address(array), xfer_props);
+  }
+
+  std::vector<size_t> size_vector;
+  for (size_t i = 0; i < size_per_rank.size(); ++i) {
+    size_vector.push_back(size_per_rank[i]);
+  }
+
+  dataset.createAttribute("size_per_rank", size_vector);
+}
+
+}   // namespace checkpointing
+
+#endif   // WRITE_ARRAY_HPP
diff --git a/src/utils/checkpointing/WriteConnectivity.cpp b/src/utils/checkpointing/WriteConnectivity.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7bed7f83f33b8fbe323a7513bf4455a77b5924c7
--- /dev/null
+++ b/src/utils/checkpointing/WriteConnectivity.cpp
@@ -0,0 +1,154 @@
+#include <utils/checkpointing/WriteConnectivity.hpp>
+
+#include <mesh/Connectivity.hpp>
+#include <utils/checkpointing/RefItemListHFType.hpp>
+#include <utils/checkpointing/WriteArray.hpp>
+#include <utils/checkpointing/WriteItemValue.hpp>
+
+namespace checkpointing
+{
+
+template <ItemType item_type, size_t Dimension>
+void
+writeRefItemList(const Connectivity<Dimension>& connectivity, HighFive::Group& connectivity_group)
+{
+  for (size_t i_item_list = 0; i_item_list < connectivity.template numberOfRefItemList<item_type>(); ++i_item_list) {
+    auto ref_item_list = connectivity.template refItemList<item_type>(i_item_list);
+
+    std::ostringstream ref_item_list_group_name;
+    ref_item_list_group_name << "item_ref_list/" << itemName(item_type) << '/' << ref_item_list.refId().tagName();
+    HighFive::Group ref_item_list_group = connectivity_group.createGroup(ref_item_list_group_name.str());
+    ref_item_list_group.createAttribute("tag_name", ref_item_list.refId().tagName());
+    ref_item_list_group.createAttribute("tag_number", ref_item_list.refId().tagNumber());
+    ref_item_list_group.createAttribute("type", ref_item_list.type());
+
+    write(ref_item_list_group, "list", ref_item_list.list());
+  }
+}
+
+template <size_t Dimension>
+void
+writeConnectivity(const Connectivity<Dimension>& connectivity, HighFive::File& file, HighFive::Group& checkpoint_group)
+{
+  std::string connectivity_group_name = "connectivity/" + std::to_string(connectivity.id());
+  if (not checkpoint_group.exist(connectivity_group_name)) {
+    bool linked = false;
+    for (auto group_name : file.listObjectNames()) {
+      const std::string stored_connectivity_group_name = group_name + "/" + connectivity_group_name;
+      if (file.exist(stored_connectivity_group_name)) {
+        HighFive::Group stored_connectivity_group = file.getGroup(stored_connectivity_group_name);
+
+        const std::string type_name = stored_connectivity_group.getAttribute("type").read<std::string>();
+        if (type_name != "dual_connectivity") {
+          checkpoint_group.createHardLink(connectivity_group_name, file.getGroup(stored_connectivity_group_name));
+          linked = true;
+          break;
+        }
+      }
+    }
+
+    if (not linked) {
+      HighFive::Group connectivity_group = checkpoint_group.createGroup(connectivity_group_name);
+
+      connectivity_group.createAttribute("dimension", connectivity.dimension());
+      connectivity_group.createAttribute("id", connectivity.id());
+      connectivity_group.createAttribute("type", std::string{"unstructured"});
+
+      write(connectivity_group, "cell_to_node_matrix_values",
+            connectivity.getMatrix(ItemType::cell, ItemType::node).values());
+      write(connectivity_group, "cell_to_node_matrix_rowsMap",
+            connectivity.getMatrix(ItemType::cell, ItemType::node).rowsMap());
+
+      if constexpr (Dimension > 1) {
+        write(connectivity_group, "cell_to_face_matrix_values",
+              connectivity.getMatrix(ItemType::cell, ItemType::face).values());
+        write(connectivity_group, "cell_to_face_matrix_rowsMap",
+              connectivity.getMatrix(ItemType::cell, ItemType::face).rowsMap());
+
+        write(connectivity_group, "face_to_node_matrix_values",
+              connectivity.getMatrix(ItemType::face, ItemType::node).values());
+        write(connectivity_group, "face_to_node_matrix_rowsMap",
+              connectivity.getMatrix(ItemType::face, ItemType::node).rowsMap());
+
+        write(connectivity_group, "node_to_face_matrix_values",
+              connectivity.getMatrix(ItemType::node, ItemType::face).values());
+        write(connectivity_group, "node_to_face_matrix_rowsMap",
+              connectivity.getMatrix(ItemType::node, ItemType::face).rowsMap());
+
+        write(connectivity_group, "cell_face_is_reversed", connectivity.cellFaceIsReversed().arrayView());
+      }
+
+      if constexpr (Dimension > 2) {
+        write(connectivity_group, "cell_to_edge_matrix_values",
+              connectivity.getMatrix(ItemType::cell, ItemType::edge).values());
+        write(connectivity_group, "cell_to_edge_matrix_rowsMap",
+              connectivity.getMatrix(ItemType::cell, ItemType::edge).rowsMap());
+
+        write(connectivity_group, "face_to_edge_matrix_values",
+              connectivity.getMatrix(ItemType::face, ItemType::edge).values());
+        write(connectivity_group, "face_to_edge_matrix_rowsMap",
+              connectivity.getMatrix(ItemType::face, ItemType::edge).rowsMap());
+
+        write(connectivity_group, "edge_to_node_matrix_values",
+              connectivity.getMatrix(ItemType::edge, ItemType::node).values());
+        write(connectivity_group, "edge_to_node_matrix_rowsMap",
+              connectivity.getMatrix(ItemType::edge, ItemType::node).rowsMap());
+
+        write(connectivity_group, "node_to_edge_matrix_values",
+              connectivity.getMatrix(ItemType::node, ItemType::edge).values());
+        write(connectivity_group, "node_to_edge_matrix_rowsMap",
+              connectivity.getMatrix(ItemType::node, ItemType::edge).rowsMap());
+
+        write(connectivity_group, "face_edge_is_reversed", connectivity.faceEdgeIsReversed().arrayView());
+      }
+
+      write(connectivity_group, "cell_type", connectivity.cellType());
+
+      write(connectivity_group, "cell_numbers", connectivity.cellNumber());
+      write(connectivity_group, "node_numbers", connectivity.nodeNumber());
+
+      write(connectivity_group, "cell_owner", connectivity.cellOwner());
+      write(connectivity_group, "node_owner", connectivity.nodeOwner());
+
+      if constexpr (Dimension > 1) {
+        write(connectivity_group, "face_numbers", connectivity.faceNumber());
+
+        write(connectivity_group, "face_owner", connectivity.faceOwner());
+      }
+      if constexpr (Dimension > 2) {
+        write(connectivity_group, "edge_numbers", connectivity.edgeNumber());
+
+        write(connectivity_group, "edge_owner", connectivity.edgeOwner());
+      }
+
+      writeRefItemList<ItemType::cell>(connectivity, connectivity_group);
+      writeRefItemList<ItemType::face>(connectivity, connectivity_group);
+      writeRefItemList<ItemType::edge>(connectivity, connectivity_group);
+      writeRefItemList<ItemType::node>(connectivity, connectivity_group);
+    }
+  }
+}
+
+void
+writeConnectivity(const IConnectivity& connectivity, HighFive::File& file, HighFive::Group& checkpoint_group)
+{
+  switch (connectivity.dimension()) {
+  case 1: {
+    writeConnectivity(dynamic_cast<const Connectivity<1>&>(connectivity), file, checkpoint_group);
+    break;
+  }
+  case 2: {
+    writeConnectivity(dynamic_cast<const Connectivity<2>&>(connectivity), file, checkpoint_group);
+    break;
+  }
+  case 3: {
+    writeConnectivity(dynamic_cast<const Connectivity<3>&>(connectivity), file, checkpoint_group);
+    break;
+  }
+  default: {
+    throw UnexpectedError("invalid connectivity dimension");
+  }
+  }
+}
+
+}   // namespace checkpointing
diff --git a/src/utils/checkpointing/WriteConnectivity.hpp b/src/utils/checkpointing/WriteConnectivity.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..8e3fb4334b7af81691929da12d5f3e28b8cc01c6
--- /dev/null
+++ b/src/utils/checkpointing/WriteConnectivity.hpp
@@ -0,0 +1,15 @@
+#ifndef WRITE_CONNECTIVITY_HPP
+#define WRITE_CONNECTIVITY_HPP
+
+#include <utils/HighFivePugsUtils.hpp>
+
+class IConnectivity;
+
+namespace checkpointing
+{
+
+void writeConnectivity(const IConnectivity& connectivity, HighFive::File& file, HighFive::Group& checkpoint_group);
+
+}   // namespace checkpointing
+
+#endif   // WRITE_CONNECTIVITY_HPP
diff --git a/src/utils/checkpointing/WriteDiscreteFunctionVariant.cpp b/src/utils/checkpointing/WriteDiscreteFunctionVariant.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ddedb95cbad205b8b2f415104730f105d74bc630
--- /dev/null
+++ b/src/utils/checkpointing/WriteDiscreteFunctionVariant.cpp
@@ -0,0 +1,60 @@
+#include <utils/checkpointing/WriteDiscreteFunctionVariant.hpp>
+
+#include <language/modules/SchemeModuleTypes.hpp>
+#include <language/utils/ASTNodeDataTypeTraits.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <scheme/DiscreteFunctionVariant.hpp>
+#include <utils/checkpointing/DiscreteFunctionTypeHFType.hpp>
+#include <utils/checkpointing/WriteIDiscreteFunctionDescriptor.hpp>
+#include <utils/checkpointing/WriteItemArray.hpp>
+#include <utils/checkpointing/WriteItemValue.hpp>
+#include <utils/checkpointing/WriteMesh.hpp>
+
+namespace checkpointing
+{
+
+void
+writeDiscreteFunctionVariant(HighFive::Group& variable_group,
+                             std::shared_ptr<const DiscreteFunctionVariant> discrete_function_v,
+                             HighFive::File& file,
+                             HighFive::Group& checkpoint_group)
+{
+  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(discrete_function_v)>));
+
+  std::visit(
+    [&](auto&& discrete_function) {
+      auto mesh_v  = discrete_function.meshVariant();
+      using DFType = std::decay_t<decltype(discrete_function)>;
+      variable_group.createAttribute("Vh_type", discrete_function.descriptor().type());
+
+      variable_group.createAttribute("mesh_id", mesh_v->id());
+      writeMesh(mesh_v, file, checkpoint_group);
+      if constexpr (is_discrete_function_P0_v<DFType>) {
+        using data_type = std::decay_t<typename DFType::data_type>;
+        variable_group.createAttribute("data_type", dataTypeName(ast_node_data_type_from<data_type>));
+        write(variable_group, "values", discrete_function.cellValues());
+      } else if constexpr (is_discrete_function_P0_vector_v<DFType>) {
+        using data_type = std::decay_t<typename DFType::data_type>;
+        variable_group.createAttribute("data_type", dataTypeName(ast_node_data_type_from<data_type>));
+        write(variable_group, "values", discrete_function.cellArrays());
+      }
+    },
+    discrete_function_v->discreteFunction());
+}
+
+void
+writeDiscreteFunctionVariant(const std::string& symbol_name,
+                             const EmbeddedData& embedded_data,
+                             HighFive::File& file,
+                             HighFive::Group& checkpoint_group,
+                             HighFive::Group& symbol_table_group)
+{
+  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
+
+  std::shared_ptr<const DiscreteFunctionVariant> discrete_function_p =
+    dynamic_cast<const DataHandler<const DiscreteFunctionVariant>&>(embedded_data.get()).data_ptr();
+
+  writeDiscreteFunctionVariant(variable_group, discrete_function_p, file, checkpoint_group);
+}
+
+}   // namespace checkpointing
diff --git a/src/utils/checkpointing/WriteDiscreteFunctionVariant.hpp b/src/utils/checkpointing/WriteDiscreteFunctionVariant.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..981d6ea5a2adc0756dcf8003b382a67a543f636e
--- /dev/null
+++ b/src/utils/checkpointing/WriteDiscreteFunctionVariant.hpp
@@ -0,0 +1,24 @@
+#ifndef WRITE_DISCRETE_FUNCTION_VARIANT_HPP
+#define WRITE_DISCRETE_FUNCTION_VARIANT_HPP
+
+#include <utils/HighFivePugsUtils.hpp>
+
+class DiscreteFunctionVariant;
+class EmbeddedData;
+
+namespace checkpointing
+{
+
+void writeDiscreteFunctionVariant(HighFive::Group& variable_group,
+                                  std::shared_ptr<const DiscreteFunctionVariant> discrete_function_v,
+                                  HighFive::File& file,
+                                  HighFive::Group& checkpoint_group);
+
+void writeDiscreteFunctionVariant(const std::string& symbol_name,
+                                  const EmbeddedData& embedded_data,
+                                  HighFive::File& file,
+                                  HighFive::Group& checkpoint_group,
+                                  HighFive::Group& symbol_table_group);
+}   // namespace checkpointing
+
+#endif   // WRITE_DISCRETE_FUNCTION_VARIANT_HPP
diff --git a/src/utils/checkpointing/WriteIBoundaryConditionDescriptor.cpp b/src/utils/checkpointing/WriteIBoundaryConditionDescriptor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ad99b31934b88bdff44e6f4780c1bd334fe875b0
--- /dev/null
+++ b/src/utils/checkpointing/WriteIBoundaryConditionDescriptor.cpp
@@ -0,0 +1,120 @@
+#include <utils/checkpointing/WriteIBoundaryConditionDescriptor.hpp>
+
+#include <language/modules/SchemeModuleTypes.hpp>
+#include <language/utils/ASTNodeDataTypeTraits.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <scheme/AxisBoundaryConditionDescriptor.hpp>
+#include <scheme/DirichletBoundaryConditionDescriptor.hpp>
+#include <scheme/FixedBoundaryConditionDescriptor.hpp>
+#include <scheme/FourierBoundaryConditionDescriptor.hpp>
+#include <scheme/FreeBoundaryConditionDescriptor.hpp>
+#include <scheme/InflowBoundaryConditionDescriptor.hpp>
+#include <scheme/NeumannBoundaryConditionDescriptor.hpp>
+#include <scheme/OutflowBoundaryConditionDescriptor.hpp>
+#include <scheme/SymmetryBoundaryConditionDescriptor.hpp>
+#include <utils/Exceptions.hpp>
+#include <utils/checkpointing/IBoundaryConditionDescriptorHFType.hpp>
+#include <utils/checkpointing/WriteIBoundaryDescriptor.hpp>
+
+namespace checkpointing
+{
+
+void
+writeIBoundaryConditionDescriptor(HighFive::Group& variable_group,
+                                  std::shared_ptr<const IBoundaryConditionDescriptor> iboundary_condition_descriptor_p)
+{
+  const IBoundaryConditionDescriptor& iboundary_condition_descriptor = *iboundary_condition_descriptor_p;
+
+  variable_group.createAttribute("type",
+                                 dataTypeName(ast_node_data_type_from<decltype(iboundary_condition_descriptor_p)>));
+  variable_group.createAttribute("iboundary_condition_descriptor_type", iboundary_condition_descriptor.type());
+
+  HighFive::Group boundary_group = variable_group.createGroup("boundary");
+
+  switch (iboundary_condition_descriptor.type()) {
+  case IBoundaryConditionDescriptor::Type::axis: {
+    const AxisBoundaryConditionDescriptor& axis_bc_descriptor =
+      dynamic_cast<const AxisBoundaryConditionDescriptor&>(iboundary_condition_descriptor);
+    writeIBoundaryDescriptor(boundary_group, axis_bc_descriptor.boundaryDescriptor());
+    break;
+  }
+  case IBoundaryConditionDescriptor::Type::dirichlet: {
+    const DirichletBoundaryConditionDescriptor& dirichlet_bc_descriptor =
+      dynamic_cast<const DirichletBoundaryConditionDescriptor&>(iboundary_condition_descriptor);
+    writeIBoundaryDescriptor(boundary_group, dirichlet_bc_descriptor.boundaryDescriptor());
+    variable_group.createAttribute("name", dirichlet_bc_descriptor.name());
+    variable_group.createAttribute("rhs_function_id", dirichlet_bc_descriptor.rhsSymbolId().id());
+    break;
+  }
+  case IBoundaryConditionDescriptor::Type::external: {
+    throw NotImplementedError("checkpoint/resume with sockets");
+
+    break;
+  }
+  case IBoundaryConditionDescriptor::Type::fourier: {
+    const FourierBoundaryConditionDescriptor& fourier_bc_descriptor =
+      dynamic_cast<const FourierBoundaryConditionDescriptor&>(iboundary_condition_descriptor);
+    writeIBoundaryDescriptor(boundary_group, fourier_bc_descriptor.boundaryDescriptor());
+    variable_group.createAttribute("name", fourier_bc_descriptor.name());
+    variable_group.createAttribute("rhs_function_id", fourier_bc_descriptor.rhsSymbolId().id());
+    variable_group.createAttribute("mass_function_id", fourier_bc_descriptor.massSymbolId().id());
+    break;
+  }
+  case IBoundaryConditionDescriptor::Type::fixed: {
+    const FixedBoundaryConditionDescriptor& fixed_bc_descriptor =
+      dynamic_cast<const FixedBoundaryConditionDescriptor&>(iboundary_condition_descriptor);
+    writeIBoundaryDescriptor(boundary_group, fixed_bc_descriptor.boundaryDescriptor());
+    break;
+  }
+  case IBoundaryConditionDescriptor::Type::free: {
+    const FreeBoundaryConditionDescriptor& free_bc_descriptor =
+      dynamic_cast<const FreeBoundaryConditionDescriptor&>(iboundary_condition_descriptor);
+    writeIBoundaryDescriptor(boundary_group, free_bc_descriptor.boundaryDescriptor());
+    break;
+  }
+  case IBoundaryConditionDescriptor::Type::inflow: {
+    const InflowBoundaryConditionDescriptor& inflow_bc_descriptor =
+      dynamic_cast<const InflowBoundaryConditionDescriptor&>(iboundary_condition_descriptor);
+    writeIBoundaryDescriptor(boundary_group, inflow_bc_descriptor.boundaryDescriptor());
+    variable_group.createAttribute("function_id", inflow_bc_descriptor.functionSymbolId().id());
+    break;
+  }
+  case IBoundaryConditionDescriptor::Type::neumann: {
+    const NeumannBoundaryConditionDescriptor& neumann_bc_descriptor =
+      dynamic_cast<const NeumannBoundaryConditionDescriptor&>(iboundary_condition_descriptor);
+    writeIBoundaryDescriptor(boundary_group, neumann_bc_descriptor.boundaryDescriptor());
+    variable_group.createAttribute("name", neumann_bc_descriptor.name());
+    variable_group.createAttribute("rhs_function_id", neumann_bc_descriptor.rhsSymbolId().id());
+    break;
+  }
+  case IBoundaryConditionDescriptor::Type::outflow: {
+    const OutflowBoundaryConditionDescriptor& outflow_bc_descriptor =
+      dynamic_cast<const OutflowBoundaryConditionDescriptor&>(iboundary_condition_descriptor);
+    writeIBoundaryDescriptor(boundary_group, outflow_bc_descriptor.boundaryDescriptor());
+    break;
+  }
+  case IBoundaryConditionDescriptor::Type::symmetry: {
+    const SymmetryBoundaryConditionDescriptor& symmetric_bc_descriptor =
+      dynamic_cast<const SymmetryBoundaryConditionDescriptor&>(iboundary_condition_descriptor);
+    writeIBoundaryDescriptor(boundary_group, symmetric_bc_descriptor.boundaryDescriptor());
+    break;
+  }
+  }
+}
+
+void
+writeIBoundaryConditionDescriptor(const std::string& symbol_name,
+                                  const EmbeddedData& embedded_data,
+                                  HighFive::File&,
+                                  HighFive::Group&,
+                                  HighFive::Group& symbol_table_group)
+{
+  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
+
+  std::shared_ptr<const IBoundaryConditionDescriptor> iboundary_condition_descriptor_p =
+    dynamic_cast<const DataHandler<const IBoundaryConditionDescriptor>&>(embedded_data.get()).data_ptr();
+
+  writeIBoundaryConditionDescriptor(variable_group, iboundary_condition_descriptor_p);
+}
+
+}   // namespace checkpointing
diff --git a/src/utils/checkpointing/WriteIBoundaryConditionDescriptor.hpp b/src/utils/checkpointing/WriteIBoundaryConditionDescriptor.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..1cfc07416f4f7d59509d91997bc02c41857e4cd2
--- /dev/null
+++ b/src/utils/checkpointing/WriteIBoundaryConditionDescriptor.hpp
@@ -0,0 +1,23 @@
+#ifndef WRITE_IBOUNDARY_CONDITION_DESCRIPTOR_HPP
+#define WRITE_IBOUNDARY_CONDITION_DESCRIPTOR_HPP
+
+#include <language/utils/EmbeddedData.hpp>
+#include <scheme/IBoundaryConditionDescriptor.hpp>
+#include <utils/HighFivePugsUtils.hpp>
+
+namespace checkpointing
+{
+
+void writeIBoundaryConditionDescriptor(
+  HighFive::Group& variable_group,
+  std::shared_ptr<const IBoundaryConditionDescriptor> iboundary_condition_descriptor_p);
+
+void writeIBoundaryConditionDescriptor(const std::string& symbol_name,
+                                       const EmbeddedData& embedded_data,
+                                       HighFive::File&,
+                                       HighFive::Group&,
+                                       HighFive::Group& symbol_table_group);
+
+}   // namespace checkpointing
+
+#endif   // WRITE_IBOUNDARY_CONDITION_DESCRIPTOR_HPP
diff --git a/src/utils/checkpointing/WriteIBoundaryDescriptor.cpp b/src/utils/checkpointing/WriteIBoundaryDescriptor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fee719592bcb72c7a9bb48a801d0afe001b1b116
--- /dev/null
+++ b/src/utils/checkpointing/WriteIBoundaryDescriptor.cpp
@@ -0,0 +1,53 @@
+#include <utils/checkpointing/WriteIBoundaryDescriptor.hpp>
+
+#include <language/modules/MeshModuleTypes.hpp>
+#include <language/utils/ASTNodeDataTypeTraits.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <mesh/NamedBoundaryDescriptor.hpp>
+#include <mesh/NumberedBoundaryDescriptor.hpp>
+#include <utils/checkpointing/IBoundaryDescriptorHFType.hpp>
+
+namespace checkpointing
+{
+
+void
+writeIBoundaryDescriptor(HighFive::Group& variable_group, const IBoundaryDescriptor& iboundary_descriptor)
+{
+  variable_group.createAttribute("iboundary_descriptor_type", iboundary_descriptor.type());
+
+  switch (iboundary_descriptor.type()) {
+  case IBoundaryDescriptor::Type::named: {
+    const NamedBoundaryDescriptor& named_boundary_descriptor =
+      dynamic_cast<const NamedBoundaryDescriptor&>(iboundary_descriptor);
+    variable_group.createAttribute("name", named_boundary_descriptor.name());
+    break;
+  }
+  case IBoundaryDescriptor::Type::numbered: {
+    const NumberedBoundaryDescriptor& numbered_boundary_descriptor =
+      dynamic_cast<const NumberedBoundaryDescriptor&>(iboundary_descriptor);
+    variable_group.createAttribute("number", numbered_boundary_descriptor.number());
+    break;
+  }
+  }
+}
+
+void
+writeIBoundaryDescriptor(const std::string& symbol_name,
+                         const EmbeddedData& embedded_data,
+                         HighFive::File&,
+                         HighFive::Group&,
+                         HighFive::Group& symbol_table_group)
+{
+  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
+
+  std::shared_ptr<const IBoundaryDescriptor> iboundary_descriptor_p =
+    dynamic_cast<const DataHandler<const IBoundaryDescriptor>&>(embedded_data.get()).data_ptr();
+
+  const IBoundaryDescriptor& iboundary_descriptor = *iboundary_descriptor_p;
+
+  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(iboundary_descriptor_p)>));
+
+  writeIBoundaryDescriptor(variable_group, iboundary_descriptor);
+}
+
+}   // namespace checkpointing
diff --git a/src/utils/checkpointing/WriteIBoundaryDescriptor.hpp b/src/utils/checkpointing/WriteIBoundaryDescriptor.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..4dce7298d9d846aa14ff1f3cd57b5e176a1d71a1
--- /dev/null
+++ b/src/utils/checkpointing/WriteIBoundaryDescriptor.hpp
@@ -0,0 +1,21 @@
+#ifndef WRITE_IBOUNDARY_DESCRIPTOR_HPP
+#define WRITE_IBOUNDARY_DESCRIPTOR_HPP
+
+#include <language/utils/EmbeddedData.hpp>
+#include <mesh/IBoundaryDescriptor.hpp>
+#include <utils/HighFivePugsUtils.hpp>
+
+namespace checkpointing
+{
+
+void writeIBoundaryDescriptor(HighFive::Group& variable_group, const IBoundaryDescriptor& iboundary_descriptor);
+
+void writeIBoundaryDescriptor(const std::string& symbol_name,
+                              const EmbeddedData& embedded_data,
+                              HighFive::File&,
+                              HighFive::Group&,
+                              HighFive::Group& symbol_table_group);
+
+}   // namespace checkpointing
+
+#endif   // WRITE_IBOUNDARY_DESCRIPTOR_HPP
diff --git a/src/utils/checkpointing/WriteIDiscreteFunctionDescriptor.cpp b/src/utils/checkpointing/WriteIDiscreteFunctionDescriptor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6633854b28befc0efbfc0adaf8f41e3f318de06f
--- /dev/null
+++ b/src/utils/checkpointing/WriteIDiscreteFunctionDescriptor.cpp
@@ -0,0 +1,32 @@
+#include <utils/checkpointing/WriteIDiscreteFunctionDescriptor.hpp>
+
+#include <language/modules/SchemeModuleTypes.hpp>
+#include <language/utils/ASTNodeDataTypeTraits.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <language/utils/EmbeddedData.hpp>
+#include <scheme/IDiscreteFunctionDescriptor.hpp>
+#include <utils/checkpointing/DiscreteFunctionTypeHFType.hpp>
+
+namespace checkpointing
+{
+
+void
+writeIDiscreteFunctionDescriptor(const std::string& symbol_name,
+                                 const EmbeddedData& embedded_data,
+                                 HighFive::File&,
+                                 HighFive::Group&,
+                                 HighFive::Group& symbol_table_group)
+{
+  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
+
+  std::shared_ptr<const IDiscreteFunctionDescriptor> idiscrete_function_desriptor_p =
+    dynamic_cast<const DataHandler<const IDiscreteFunctionDescriptor>&>(embedded_data.get()).data_ptr();
+
+  const IDiscreteFunctionDescriptor& idiscrete_function_descriptor = *idiscrete_function_desriptor_p;
+
+  variable_group.createAttribute("type",
+                                 dataTypeName(ast_node_data_type_from<decltype(idiscrete_function_desriptor_p)>));
+  variable_group.createAttribute("discrete_function_type", idiscrete_function_descriptor.type());
+}
+
+}   // namespace checkpointing
diff --git a/src/utils/checkpointing/WriteIDiscreteFunctionDescriptor.hpp b/src/utils/checkpointing/WriteIDiscreteFunctionDescriptor.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..89e1b33016abd8da16596cd1e86f0aee9a45194a
--- /dev/null
+++ b/src/utils/checkpointing/WriteIDiscreteFunctionDescriptor.hpp
@@ -0,0 +1,19 @@
+#ifndef WRITE_IDISCRETE_FUNCTION_DESCRIPTOR_HPP
+#define WRITE_IDISCRETE_FUNCTION_DESCRIPTOR_HPP
+
+#include <utils/HighFivePugsUtils.hpp>
+
+class EmbeddedData;
+
+namespace checkpointing
+{
+
+void writeIDiscreteFunctionDescriptor(const std::string& symbol_name,
+                                      const EmbeddedData& embedded_data,
+                                      HighFive::File&,
+                                      HighFive::Group&,
+                                      HighFive::Group& symbol_table_group);
+
+}   // namespace checkpointing
+
+#endif   // WRITE_IDISCRETE_FUNCTION_DESCRIPTOR_HPP
diff --git a/src/utils/checkpointing/WriteIInterfaceDescriptor.cpp b/src/utils/checkpointing/WriteIInterfaceDescriptor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e3b34dd5790562d0085a34c83acb1e6a15976cc8
--- /dev/null
+++ b/src/utils/checkpointing/WriteIInterfaceDescriptor.cpp
@@ -0,0 +1,47 @@
+#include <utils/checkpointing/WriteIInterfaceDescriptor.hpp>
+
+#include <language/modules/MeshModuleTypes.hpp>
+#include <language/utils/ASTNodeDataTypeTraits.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <language/utils/EmbeddedData.hpp>
+#include <mesh/NamedInterfaceDescriptor.hpp>
+#include <mesh/NumberedInterfaceDescriptor.hpp>
+#include <utils/checkpointing/IInterfaceDescriptorHFType.hpp>
+
+namespace checkpointing
+{
+
+void
+writeIInterfaceDescriptor(const std::string& symbol_name,
+                          const EmbeddedData& embedded_data,
+                          HighFive::File&,
+                          HighFive::Group&,
+                          HighFive::Group& symbol_table_group)
+{
+  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
+
+  std::shared_ptr<const IInterfaceDescriptor> iinterface_descriptor_p =
+    dynamic_cast<const DataHandler<const IInterfaceDescriptor>&>(embedded_data.get()).data_ptr();
+
+  const IInterfaceDescriptor& iinterface_descriptor = *iinterface_descriptor_p;
+
+  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(iinterface_descriptor_p)>));
+  variable_group.createAttribute("iinterface_descriptor_type", iinterface_descriptor.type());
+
+  switch (iinterface_descriptor.type()) {
+  case IInterfaceDescriptor::Type::named: {
+    const NamedInterfaceDescriptor& named_interface_descriptor =
+      dynamic_cast<const NamedInterfaceDescriptor&>(iinterface_descriptor);
+    variable_group.createAttribute("name", named_interface_descriptor.name());
+    break;
+  }
+  case IInterfaceDescriptor::Type::numbered: {
+    const NumberedInterfaceDescriptor& numbered_boundary_descriptor =
+      dynamic_cast<const NumberedInterfaceDescriptor&>(iinterface_descriptor);
+    variable_group.createAttribute("number", numbered_boundary_descriptor.number());
+    break;
+  }
+  }
+}
+
+}   // namespace checkpointing
diff --git a/src/utils/checkpointing/WriteIInterfaceDescriptor.hpp b/src/utils/checkpointing/WriteIInterfaceDescriptor.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..98a4e37abfe6535956347685d8212aabb4d0923e
--- /dev/null
+++ b/src/utils/checkpointing/WriteIInterfaceDescriptor.hpp
@@ -0,0 +1,19 @@
+#ifndef WRITE_IINTERFACE_DESCRIPTOR_HPP
+#define WRITE_IINTERFACE_DESCRIPTOR_HPP
+
+#include <utils/HighFivePugsUtils.hpp>
+
+class EmbeddedData;
+
+namespace checkpointing
+{
+
+void writeIInterfaceDescriptor(const std::string& symbol_name,
+                               const EmbeddedData& embedded_data,
+                               HighFive::File&,
+                               HighFive::Group&,
+                               HighFive::Group& symbol_table_group);
+
+}   // namespace checkpointing
+
+#endif   // WRITE_IINTERFACE_DESCRIPTOR_HPP
diff --git a/src/utils/checkpointing/WriteINamedDiscreteData.cpp b/src/utils/checkpointing/WriteINamedDiscreteData.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a1ed691091d18c568f5560119b1f8fb35ed93de5
--- /dev/null
+++ b/src/utils/checkpointing/WriteINamedDiscreteData.cpp
@@ -0,0 +1,66 @@
+#include <utils/checkpointing/WriteINamedDiscreteData.hpp>
+
+#include <language/modules/WriterModuleTypes.hpp>
+#include <language/utils/ASTNodeDataTypeTraits.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <language/utils/EmbeddedData.hpp>
+#include <output/INamedDiscreteData.hpp>
+#include <output/NamedDiscreteFunction.hpp>
+#include <output/NamedItemArrayVariant.hpp>
+#include <output/NamedItemValueVariant.hpp>
+#include <utils/checkpointing/INamedDiscreteDataHFType.hpp>
+#include <utils/checkpointing/WriteDiscreteFunctionVariant.hpp>
+#include <utils/checkpointing/WriteItemArrayVariant.hpp>
+#include <utils/checkpointing/WriteItemValueVariant.hpp>
+
+namespace checkpointing
+{
+
+void
+writeINamedDiscreteData(const std::string& symbol_name,
+                        const EmbeddedData& embedded_data,
+                        HighFive::File& file,
+                        HighFive::Group& checkpoint_group,
+                        HighFive::Group& symbol_table_group)
+{
+  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
+
+  std::shared_ptr<const INamedDiscreteData> inamed_discrete_data_p =
+    dynamic_cast<const DataHandler<const INamedDiscreteData>&>(embedded_data.get()).data_ptr();
+
+  const INamedDiscreteData& inamed_discrete_data = *inamed_discrete_data_p;
+
+  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(inamed_discrete_data_p)>));
+  variable_group.createAttribute("named_discrete_data_type", inamed_discrete_data.type());
+  variable_group.createAttribute("named_discrete_data_name", inamed_discrete_data.name());
+
+  switch (inamed_discrete_data.type()) {
+  case INamedDiscreteData::Type::discrete_function: {
+    const NamedDiscreteFunction& named_discrete_function =
+      dynamic_cast<const NamedDiscreteFunction&>(inamed_discrete_data);
+
+    HighFive::Group discrete_function_group = variable_group.createGroup("discrete_function_variant");
+    writeDiscreteFunctionVariant(discrete_function_group, named_discrete_function.discreteFunctionVariant(), file,
+                                 checkpoint_group);
+    break;
+  }
+  case INamedDiscreteData::Type::item_array: {
+    const NamedItemArrayVariant& named_item_array_v = dynamic_cast<const NamedItemArrayVariant&>(inamed_discrete_data);
+
+    HighFive::Group item_array_group = variable_group.createGroup("item_array_variant");
+
+    writeItemArrayVariant(item_array_group, named_item_array_v.itemArrayVariant(), file, checkpoint_group);
+    break;
+  }
+  case INamedDiscreteData::Type::item_value: {
+    const NamedItemValueVariant& named_item_value_v = dynamic_cast<const NamedItemValueVariant&>(inamed_discrete_data);
+
+    HighFive::Group item_value_group = variable_group.createGroup("item_value_variant");
+
+    writeItemValueVariant(item_value_group, named_item_value_v.itemValueVariant(), file, checkpoint_group);
+    break;
+  }
+  }
+}
+
+}   // namespace checkpointing
diff --git a/src/utils/checkpointing/WriteINamedDiscreteData.hpp b/src/utils/checkpointing/WriteINamedDiscreteData.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..076e1318dc0596e1ed57af9abb57e3946cc3e5c8
--- /dev/null
+++ b/src/utils/checkpointing/WriteINamedDiscreteData.hpp
@@ -0,0 +1,18 @@
+#ifndef WRITE_INAMED_DISCRETE_DATA_HPP
+#define WRITE_INAMED_DISCRETE_DATA_HPP
+
+#include <utils/HighFivePugsUtils.hpp>
+
+class EmbeddedData;
+
+namespace checkpointing
+{
+
+void writeINamedDiscreteData(const std::string& symbol_name,
+                             const EmbeddedData& embedded_data,
+                             HighFive::File& file,
+                             HighFive::Group& checkpoint_group,
+                             HighFive::Group& symbol_table_group);
+}   // namespace checkpointing
+
+#endif   // WRITE_INAMED_DISCRETE_DATA_HPP
diff --git a/src/utils/checkpointing/WriteIQuadratureDescriptor.cpp b/src/utils/checkpointing/WriteIQuadratureDescriptor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ed0b2cb2dc31677689a8e9c7c07fa8e4d62c768c
--- /dev/null
+++ b/src/utils/checkpointing/WriteIQuadratureDescriptor.cpp
@@ -0,0 +1,30 @@
+#include <utils/checkpointing/WriteIQuadratureDescriptor.hpp>
+
+#include <analysis/IQuadratureDescriptor.hpp>
+#include <language/modules/SchemeModuleTypes.hpp>
+#include <language/utils/ASTNodeDataType.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <utils/checkpointing/QuadratureTypeHFType.hpp>
+
+namespace checkpointing
+{
+void
+writeIQuadratureDescriptor(const std::string& symbol_name,
+                           const EmbeddedData& embedded_data,
+                           HighFive::File&,
+                           HighFive::Group&,
+                           HighFive::Group& symbol_table_group)
+{
+  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
+
+  std::shared_ptr<const IQuadratureDescriptor> iquadrature_descriptor_p =
+    dynamic_cast<const DataHandler<const IQuadratureDescriptor>&>(embedded_data.get()).data_ptr();
+
+  const IQuadratureDescriptor& iquadrature_descriptor = *iquadrature_descriptor_p;
+
+  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(iquadrature_descriptor_p)>));
+  variable_group.createAttribute("quadrature_type", iquadrature_descriptor.type());
+  variable_group.createAttribute("quadrature_degree", iquadrature_descriptor.degree());
+}
+
+}   // namespace checkpointing
diff --git a/src/utils/checkpointing/WriteIQuadratureDescriptor.hpp b/src/utils/checkpointing/WriteIQuadratureDescriptor.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..52439403bc169013f5e24bcee246a76a916f0bde
--- /dev/null
+++ b/src/utils/checkpointing/WriteIQuadratureDescriptor.hpp
@@ -0,0 +1,18 @@
+#ifndef WRITE_IQUADRATURE_DESCRIPTOR_HPP
+#define WRITE_IQUADRATURE_DESCRIPTOR_HPP
+
+#include <language/utils/EmbeddedData.hpp>
+#include <utils/HighFivePugsUtils.hpp>
+
+namespace checkpointing
+{
+
+void writeIQuadratureDescriptor(const std::string& symbol_name,
+                                const EmbeddedData& embedded_data,
+                                HighFive::File&,
+                                HighFive::Group&,
+                                HighFive::Group& symbol_table_group);
+
+}   // namespace checkpointing
+
+#endif   // WRITE_IQUADRATURE_DESCRIPTOR_HPP
diff --git a/src/utils/checkpointing/WriteIWriter.cpp b/src/utils/checkpointing/WriteIWriter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f05c8e77c424856561ee9d579392390bd384650b
--- /dev/null
+++ b/src/utils/checkpointing/WriteIWriter.cpp
@@ -0,0 +1,53 @@
+#include <utils/checkpointing/WriteIWriter.hpp>
+
+#include <language/modules/WriterModuleTypes.hpp>
+#include <language/utils/ASTNodeDataTypeTraits.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <language/utils/EmbeddedData.hpp>
+#include <output/WriterBase.hpp>
+#include <utils/checkpointing/IWriterHFType.hpp>
+
+namespace checkpointing
+{
+
+void
+writeIWriter(const std::string& symbol_name,
+             const EmbeddedData& embedded_data,
+             HighFive::File&,
+             HighFive::Group&,
+             HighFive::Group& symbol_table_group)
+{
+  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
+
+  std::shared_ptr<const IWriter> iwriter_p =
+    dynamic_cast<const DataHandler<const IWriter>&>(embedded_data.get()).data_ptr();
+
+  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(iwriter_p)>));
+
+  variable_group.createAttribute("iwriter_type", iwriter_p->type());
+
+  switch (iwriter_p->type()) {
+  case IWriter::Type::gnuplot:
+  case IWriter::Type::gnuplot_1d:
+  case IWriter::Type::vtk: {
+    const WriterBase& writer = dynamic_cast<const WriterBase&>(*iwriter_p);
+
+    variable_group.createAttribute("base_filename", writer.m_base_filename);
+    if (writer.m_signature.has_value()) {
+      variable_group.createAttribute("signature", writer.m_signature.value());
+    }
+    if (writer.m_period_manager.has_value()) {
+      const WriterBase::PeriodManager period_manager = writer.m_period_manager.value();
+      HighFive::Group period_manager_group           = variable_group.createGroup("period_manager");
+
+      period_manager_group.createAttribute("time_period", period_manager.timePeriod());
+      period_manager_group.createAttribute("next_time", period_manager.nextTime());
+      period_manager_group.createAttribute("saved_times", period_manager.getSavedTimes());
+    }
+
+    break;
+  }
+  }
+}
+
+}   // namespace checkpointing
diff --git a/src/utils/checkpointing/WriteIWriter.hpp b/src/utils/checkpointing/WriteIWriter.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..309ed5cb18b9dcbd8f4bc23a5b0ce0d4fcc9e02c
--- /dev/null
+++ b/src/utils/checkpointing/WriteIWriter.hpp
@@ -0,0 +1,19 @@
+#ifndef WRITE_IWRITER_HPP
+#define WRITE_IWRITER_HPP
+
+#include <utils/HighFivePugsUtils.hpp>
+
+class EmbeddedData;
+
+namespace checkpointing
+{
+
+void writeIWriter(const std::string& symbol_name,
+                  const EmbeddedData& embedded_data,
+                  HighFive::File&,
+                  HighFive::Group&,
+                  HighFive::Group& symbol_table_group);
+
+}
+
+#endif   // WRITE_IWRITER_HPP
diff --git a/src/utils/checkpointing/WriteIZoneDescriptor.cpp b/src/utils/checkpointing/WriteIZoneDescriptor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..32851b6a282a799c4e50105f03e49373324050f2
--- /dev/null
+++ b/src/utils/checkpointing/WriteIZoneDescriptor.cpp
@@ -0,0 +1,46 @@
+#include <utils/checkpointing/WriteIZoneDescriptor.hpp>
+
+#include <language/modules/MeshModuleTypes.hpp>
+#include <language/utils/ASTNodeDataTypeTraits.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <language/utils/EmbeddedData.hpp>
+#include <mesh/NamedZoneDescriptor.hpp>
+#include <mesh/NumberedZoneDescriptor.hpp>
+#include <utils/checkpointing/IZoneDescriptorHFType.hpp>
+
+namespace checkpointing
+{
+
+void
+writeIZoneDescriptor(const std::string& symbol_name,
+                     const EmbeddedData& embedded_data,
+                     HighFive::File&,
+                     HighFive::Group&,
+                     HighFive::Group& symbol_table_group)
+{
+  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
+
+  std::shared_ptr<const IZoneDescriptor> izone_descriptor_p =
+    dynamic_cast<const DataHandler<const IZoneDescriptor>&>(embedded_data.get()).data_ptr();
+
+  const IZoneDescriptor& izone_descriptor = *izone_descriptor_p;
+
+  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(izone_descriptor_p)>));
+  variable_group.createAttribute("izone_descriptor_type", izone_descriptor.type());
+
+  switch (izone_descriptor.type()) {
+  case IZoneDescriptor::Type::named: {
+    const NamedZoneDescriptor& named_zone_descriptor = dynamic_cast<const NamedZoneDescriptor&>(izone_descriptor);
+    variable_group.createAttribute("name", named_zone_descriptor.name());
+    break;
+  }
+  case IZoneDescriptor::Type::numbered: {
+    const NumberedZoneDescriptor& numbered_boundary_descriptor =
+      dynamic_cast<const NumberedZoneDescriptor&>(izone_descriptor);
+    variable_group.createAttribute("number", numbered_boundary_descriptor.number());
+    break;
+  }
+  }
+}
+
+}   // namespace checkpointing
diff --git a/src/utils/checkpointing/WriteIZoneDescriptor.hpp b/src/utils/checkpointing/WriteIZoneDescriptor.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..c4de384c8aaf72848172286b4ce7f609ae67be8e
--- /dev/null
+++ b/src/utils/checkpointing/WriteIZoneDescriptor.hpp
@@ -0,0 +1,18 @@
+#ifndef WRITE_IZONE_DESCRIPTOR_HPP
+#define WRITE_IZONE_DESCRIPTOR_HPP
+
+#include <utils/HighFivePugsUtils.hpp>
+class EmbeddedData;
+
+namespace checkpointing
+{
+
+void writeIZoneDescriptor(const std::string& symbol_name,
+                          const EmbeddedData& embedded_data,
+                          HighFive::File&,
+                          HighFive::Group&,
+                          HighFive::Group& symbol_table_group);
+
+}   // namespace checkpointing
+
+#endif   // WRITE_IZONE_DESCRIPTOR_HPP
diff --git a/src/utils/checkpointing/WriteItemArray.hpp b/src/utils/checkpointing/WriteItemArray.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..1bc52b16b78f5f9c0df801e971e1ddb1ef355607
--- /dev/null
+++ b/src/utils/checkpointing/WriteItemArray.hpp
@@ -0,0 +1,22 @@
+#ifndef WRITE_ITEM_ARRAY_HPP
+#define WRITE_ITEM_ARRAY_HPP
+
+#include <mesh/ItemArray.hpp>
+#include <utils/HighFivePugsUtils.hpp>
+#include <utils/checkpointing/WriteTable.hpp>
+
+namespace checkpointing
+{
+
+template <typename DataType, ItemType item_type, typename ConnectivityPtr>
+void
+write(HighFive::Group& group,
+      const std::string& name,
+      const ItemArray<DataType, item_type, ConnectivityPtr>& item_array)
+{
+  write(group, name, item_array.tableView());
+}
+
+}   // namespace checkpointing
+
+#endif   // WRITE_ITEM_ARRAY_HPP
diff --git a/src/utils/checkpointing/WriteItemArrayVariant.cpp b/src/utils/checkpointing/WriteItemArrayVariant.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..df950cf1eb3b8f904ab66bae217af5ec264c8a26
--- /dev/null
+++ b/src/utils/checkpointing/WriteItemArrayVariant.cpp
@@ -0,0 +1,56 @@
+#include <utils/checkpointing/WriteItemArrayVariant.hpp>
+
+#include <language/modules/MeshModuleTypes.hpp>
+#include <language/utils/ASTNodeDataTypeTraits.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <language/utils/EmbeddedData.hpp>
+#include <mesh/ItemArrayVariant.hpp>
+#include <scheme/VariableBCDescriptor.hpp>
+#include <utils/checkpointing/ItemTypeHFType.hpp>
+#include <utils/checkpointing/WriteConnectivity.hpp>
+#include <utils/checkpointing/WriteItemArray.hpp>
+
+namespace checkpointing
+{
+
+void
+writeItemArrayVariant(HighFive::Group& variable_group,
+                      std::shared_ptr<const ItemArrayVariant> item_array_variant_v,
+                      HighFive::File& file,
+                      HighFive::Group& checkpoint_group)
+{
+  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(item_array_variant_v)>));
+
+  std::visit(
+    [&](auto&& item_array) {
+      using ItemArrayT = std::decay_t<decltype(item_array)>;
+
+      variable_group.createAttribute("item_type", ItemArrayT::item_t);
+      using data_type = std::decay_t<typename ItemArrayT::data_type>;
+      variable_group.createAttribute("data_type", dataTypeName(ast_node_data_type_from<data_type>));
+
+      const IConnectivity& connectivity = *item_array.connectivity_ptr();
+      variable_group.createAttribute("connectivity_id", connectivity.id());
+      writeConnectivity(connectivity, file, checkpoint_group);
+
+      write(variable_group, "arrays", item_array);
+    },
+    item_array_variant_v->itemArray());
+}
+
+void
+writeItemArrayVariant(const std::string& symbol_name,
+                      const EmbeddedData& embedded_data,
+                      HighFive::File& file,
+                      HighFive::Group& checkpoint_group,
+                      HighFive::Group& symbol_table_group)
+{
+  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
+
+  std::shared_ptr<const ItemArrayVariant> item_array_variant_p =
+    dynamic_cast<const DataHandler<const ItemArrayVariant>&>(embedded_data.get()).data_ptr();
+
+  writeItemArrayVariant(variable_group, item_array_variant_p, file, checkpoint_group);
+}
+
+}   // namespace checkpointing
diff --git a/src/utils/checkpointing/WriteItemArrayVariant.hpp b/src/utils/checkpointing/WriteItemArrayVariant.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..ddd9c2e70d74cff0f11b160c999cdc82016ab131
--- /dev/null
+++ b/src/utils/checkpointing/WriteItemArrayVariant.hpp
@@ -0,0 +1,24 @@
+#ifndef WRITE_ITEM_ARRAY_VARIANT_HPP
+#define WRITE_ITEM_ARRAY_VARIANT_HPP
+
+#include <utils/HighFivePugsUtils.hpp>
+
+class EmbeddedData;
+class ItemArrayVariant;
+
+namespace checkpointing
+{
+
+void writeItemArrayVariant(HighFive::Group& variable_group,
+                           std::shared_ptr<const ItemArrayVariant> item_array_variant_v,
+                           HighFive::File& file,
+                           HighFive::Group& checkpoint_group);
+
+void writeItemArrayVariant(const std::string& symbol_name,
+                           const EmbeddedData& embedded_data,
+                           HighFive::File& file,
+                           HighFive::Group& checkpoint_group,
+                           HighFive::Group& symbol_table_group);
+}   // namespace checkpointing
+
+#endif   // WRITE_ITEM_ARRAY_VARIANT_HPP
diff --git a/src/utils/checkpointing/WriteItemType.cpp b/src/utils/checkpointing/WriteItemType.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8eff5445bd17912cd58b85da202e81c008f76704
--- /dev/null
+++ b/src/utils/checkpointing/WriteItemType.cpp
@@ -0,0 +1,30 @@
+#include <utils/checkpointing/WriteItemType.hpp>
+
+#include <language/modules/MeshModuleTypes.hpp>
+#include <language/utils/ASTNodeDataTypeTraits.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <mesh/ItemType.hpp>
+#include <utils/checkpointing/ItemTypeHFType.hpp>
+
+namespace checkpointing
+{
+
+void
+writeItemType(const std::string& symbol_name,
+              const EmbeddedData& embedded_data,
+              HighFive::File&,
+              HighFive::Group&,
+              HighFive::Group& symbol_table_group)
+{
+  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
+
+  std::shared_ptr<const ItemType> item_type_p =
+    dynamic_cast<const DataHandler<const ItemType>&>(embedded_data.get()).data_ptr();
+
+  const ItemType& item_type = *item_type_p;
+
+  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(item_type_p)>));
+  variable_group.createAttribute("item_type", item_type);
+}
+
+}   // namespace checkpointing
diff --git a/src/utils/checkpointing/WriteItemType.hpp b/src/utils/checkpointing/WriteItemType.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..b06abb59fd7316d4af97f27063e597af4bc3ddcc
--- /dev/null
+++ b/src/utils/checkpointing/WriteItemType.hpp
@@ -0,0 +1,18 @@
+#ifndef WRITE_ITEM_TYPE_HPP
+#define WRITE_ITEM_TYPE_HPP
+
+#include <language/utils/EmbeddedData.hpp>
+#include <utils/HighFivePugsUtils.hpp>
+
+namespace checkpointing
+{
+
+void writeItemType(const std::string& symbol_name,
+                   const EmbeddedData& embedded_data,
+                   HighFive::File&,
+                   HighFive::Group&,
+                   HighFive::Group& symbol_table_group);
+
+}   // namespace checkpointing
+
+#endif   // WRITE_ITEM_TYPE_HPP
diff --git a/src/utils/checkpointing/WriteItemValue.hpp b/src/utils/checkpointing/WriteItemValue.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..bc6739b84fc25c50e3f8c7aeb67e585759d8a824
--- /dev/null
+++ b/src/utils/checkpointing/WriteItemValue.hpp
@@ -0,0 +1,22 @@
+#ifndef WRITE_ITEM_VALUE_HPP
+#define WRITE_ITEM_VALUE_HPP
+
+#include <mesh/ItemValue.hpp>
+#include <utils/HighFivePugsUtils.hpp>
+#include <utils/checkpointing/WriteArray.hpp>
+
+namespace checkpointing
+{
+
+template <typename DataType, ItemType item_type, typename ConnectivityPtr>
+void
+write(HighFive::Group& group,
+      const std::string& name,
+      const ItemValue<DataType, item_type, ConnectivityPtr>& item_value)
+{
+  write(group, name, item_value.arrayView());
+}
+
+}   // namespace checkpointing
+
+#endif   // WRITE_ITEM_VALUE_HPP
diff --git a/src/utils/checkpointing/WriteItemValueVariant.cpp b/src/utils/checkpointing/WriteItemValueVariant.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..47246049d84dce9b586c35908805fe344c27efd3
--- /dev/null
+++ b/src/utils/checkpointing/WriteItemValueVariant.cpp
@@ -0,0 +1,56 @@
+#include <utils/checkpointing/WriteItemValueVariant.hpp>
+
+#include <language/modules/MeshModuleTypes.hpp>
+#include <language/utils/ASTNodeDataTypeTraits.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <language/utils/EmbeddedData.hpp>
+#include <mesh/ItemValueVariant.hpp>
+#include <scheme/VariableBCDescriptor.hpp>
+#include <utils/checkpointing/ItemTypeHFType.hpp>
+#include <utils/checkpointing/WriteConnectivity.hpp>
+#include <utils/checkpointing/WriteItemValue.hpp>
+
+namespace checkpointing
+{
+
+void
+writeItemValueVariant(HighFive::Group& variable_group,
+                      std::shared_ptr<const ItemValueVariant> item_value_variant_v,
+                      HighFive::File& file,
+                      HighFive::Group& checkpoint_group)
+{
+  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(item_value_variant_v)>));
+
+  std::visit(
+    [&](auto&& item_value) {
+      using ItemValueT = std::decay_t<decltype(item_value)>;
+
+      variable_group.createAttribute("item_type", ItemValueT::item_t);
+      using data_type = std::decay_t<typename ItemValueT::data_type>;
+      variable_group.createAttribute("data_type", dataTypeName(ast_node_data_type_from<data_type>));
+
+      const IConnectivity& connectivity = *item_value.connectivity_ptr();
+      variable_group.createAttribute("connectivity_id", connectivity.id());
+      writeConnectivity(connectivity, file, checkpoint_group);
+
+      write(variable_group, "values", item_value);
+    },
+    item_value_variant_v->itemValue());
+}
+
+void
+writeItemValueVariant(const std::string& symbol_name,
+                      const EmbeddedData& embedded_data,
+                      HighFive::File& file,
+                      HighFive::Group& checkpoint_group,
+                      HighFive::Group& symbol_table_group)
+{
+  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
+
+  std::shared_ptr<const ItemValueVariant> item_value_variant_p =
+    dynamic_cast<const DataHandler<const ItemValueVariant>&>(embedded_data.get()).data_ptr();
+
+  writeItemValueVariant(variable_group, item_value_variant_p, file, checkpoint_group);
+}
+
+}   // namespace checkpointing
diff --git a/src/utils/checkpointing/WriteItemValueVariant.hpp b/src/utils/checkpointing/WriteItemValueVariant.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..55157df238f069f0e571bff064e08a10a28076bc
--- /dev/null
+++ b/src/utils/checkpointing/WriteItemValueVariant.hpp
@@ -0,0 +1,25 @@
+#ifndef WRITE_ITEM_VALUE_VARIANT_HPP
+#define WRITE_ITEM_VALUE_VARIANT_HPP
+
+#include <utils/HighFivePugsUtils.hpp>
+
+class EmbeddedData;
+class ItemValueVariant;
+
+namespace checkpointing
+{
+
+void writeItemValueVariant(HighFive::Group& variable_group,
+                           std::shared_ptr<const ItemValueVariant> item_value_variant_v,
+                           HighFive::File& file,
+                           HighFive::Group& checkpoint_group);
+
+void writeItemValueVariant(const std::string& symbol_name,
+                           const EmbeddedData& embedded_data,
+                           HighFive::File& file,
+                           HighFive::Group& checkpoint_group,
+                           HighFive::Group& symbol_table_group);
+
+}   // namespace checkpointing
+
+#endif   // WRITE_ITEM_VALUE_VARIANT_HPP
diff --git a/src/utils/checkpointing/WriteMesh.cpp b/src/utils/checkpointing/WriteMesh.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..09212cebe092e884deb7cff6d7bfb48968fb5c11
--- /dev/null
+++ b/src/utils/checkpointing/WriteMesh.cpp
@@ -0,0 +1,75 @@
+#include <utils/checkpointing/WriteMesh.hpp>
+
+#include <language/modules/MeshModuleTypes.hpp>
+#include <language/utils/ASTNodeDataTypeTraits.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <mesh/Mesh.hpp>
+#include <mesh/MeshVariant.hpp>
+#include <utils/checkpointing/WriteConnectivity.hpp>
+#include <utils/checkpointing/WriteItemValue.hpp>
+
+namespace checkpointing
+{
+
+void
+writeMesh(std::shared_ptr<const MeshVariant> mesh_v, HighFive::File& file, HighFive::Group& checkpoint_group)
+{
+  std::string mesh_group_name = "mesh/" + std::to_string(mesh_v->id());
+  if (not checkpoint_group.exist(mesh_group_name)) {
+    bool linked = false;
+    for (auto group_name : file.listObjectNames()) {
+      if (file.exist(group_name + "/" + mesh_group_name)) {
+        checkpoint_group.createHardLink(mesh_group_name, file.getGroup(group_name + "/" + mesh_group_name));
+        linked = true;
+        break;
+      }
+    }
+
+    if (not linked) {
+      HighFive::Group mesh_group = checkpoint_group.createGroup(mesh_group_name);
+      mesh_group.createAttribute("connectivity", mesh_v->connectivity().id());
+      std::visit(
+        [&](auto&& mesh) {
+          using MeshType = mesh_type_t<decltype(mesh)>;
+          if constexpr (is_polygonal_mesh_v<MeshType>) {
+            mesh_group.createAttribute("id", mesh->id());
+            mesh_group.createAttribute("type", std::string{"polygonal"});
+            mesh_group.createAttribute("dimension", mesh->dimension());
+            write(mesh_group, "xr", mesh->xr());
+          } else {
+            throw UnexpectedError("unexpected mesh type");
+          }
+        },
+        mesh_v->variant());
+    }
+  }
+
+  std::visit(
+    [&](auto&& mesh) {
+      using MeshType = mesh_type_t<decltype(mesh)>;
+      if constexpr (is_polygonal_mesh_v<MeshType>) {
+        writeConnectivity(mesh->connectivity(), file, checkpoint_group);
+      }
+    },
+    mesh_v->variant());
+}
+
+void
+writeMesh(const std::string& symbol_name,
+          const EmbeddedData& embedded_data,
+          HighFive::File& file,
+          HighFive::Group& checkpoint_group,
+          HighFive::Group& symbol_table_group)
+{
+  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
+
+  std::shared_ptr<const MeshVariant> mesh_v =
+    dynamic_cast<const DataHandler<const MeshVariant>&>(embedded_data.get()).data_ptr();
+
+  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(mesh_v)>));
+  variable_group.createAttribute("id", mesh_v->id());
+
+  writeMesh(mesh_v, file, checkpoint_group);
+}
+
+}   // namespace checkpointing
diff --git a/src/utils/checkpointing/WriteMesh.hpp b/src/utils/checkpointing/WriteMesh.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..07ce40ad29e97545a31d99732a3074b227855f63
--- /dev/null
+++ b/src/utils/checkpointing/WriteMesh.hpp
@@ -0,0 +1,22 @@
+#ifndef WRITE_MESH_HPP
+#define WRITE_MESH_HPP
+
+#include <language/utils/EmbeddedData.hpp>
+#include <utils/HighFivePugsUtils.hpp>
+
+class MeshVariant;
+
+namespace checkpointing
+{
+
+void writeMesh(std::shared_ptr<const MeshVariant> mesh_v, HighFive::File& file, HighFive::Group& checkpoint_group);
+
+void writeMesh(const std::string& symbol_name,
+               const EmbeddedData& embedded_data,
+               HighFive::File& file,
+               HighFive::Group& checkpoint_group,
+               HighFive::Group& symbol_table_group);
+
+}   // namespace checkpointing
+
+#endif   // WRITE_MESH_HPP
diff --git a/src/utils/checkpointing/WriteOStream.cpp b/src/utils/checkpointing/WriteOStream.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..51201f5987abca1689123d52833efe5520691f4a
--- /dev/null
+++ b/src/utils/checkpointing/WriteOStream.cpp
@@ -0,0 +1,42 @@
+#include <utils/checkpointing/WriteOStream.hpp>
+
+#include <language/utils/ASTNodeDataTypeTraits.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <language/utils/OFStream.hpp>
+#include <language/utils/OStream.hpp>
+#include <utils/Exceptions.hpp>
+#include <utils/checkpointing/OStreamTypeHFType.hpp>
+
+namespace checkpointing
+{
+
+void
+writeOStream(const std::string& symbol_name,
+             const EmbeddedData& embedded_data,
+             HighFive::File&,
+             HighFive::Group&,
+             HighFive::Group& symbol_table_group)
+{
+  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
+
+  std::shared_ptr<const OStream> ostream_p =
+    dynamic_cast<const DataHandler<const OStream>&>(embedded_data.get()).data_ptr();
+
+  const OStream& ostream = *ostream_p;
+
+  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(ostream_p)>));
+  variable_group.createAttribute("ostream_type", ostream.type());
+
+  switch (ostream.type()) {
+  case OStream::Type::std_ofstream: {
+    const OFStream& ofstream = dynamic_cast<const OFStream&>(ostream);
+    variable_group.createAttribute("filename", ofstream.filename());
+    break;
+  }
+  case OStream::Type::std_ostream: {
+    throw NotImplementedError("std::ostream checkpoint");
+  }
+  }
+}
+
+}   // namespace checkpointing
diff --git a/src/utils/checkpointing/WriteOStream.hpp b/src/utils/checkpointing/WriteOStream.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..14616a50ce10cdf21b4de2f313807ac162ef5950
--- /dev/null
+++ b/src/utils/checkpointing/WriteOStream.hpp
@@ -0,0 +1,17 @@
+#ifndef WRITE_OSTREAM_HPP
+#define WRITE_OSTREAM_HPP
+
+#include <language/utils/EmbeddedData.hpp>
+#include <utils/HighFivePugsUtils.hpp>
+
+namespace checkpointing
+{
+
+void writeOStream(const std::string& symbol_name,
+                  const EmbeddedData& embedded_data,
+                  HighFive::File&,
+                  HighFive::Group&,
+                  HighFive::Group& symbol_table_group);
+}   // namespace checkpointing
+
+#endif   // WRITE_OSTREAM_HPP
diff --git a/src/utils/checkpointing/WriteSubItemArrayPerItemVariant.cpp b/src/utils/checkpointing/WriteSubItemArrayPerItemVariant.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d71838fb6dd57550cadbb5452d69a8b7c9009f0b
--- /dev/null
+++ b/src/utils/checkpointing/WriteSubItemArrayPerItemVariant.cpp
@@ -0,0 +1,57 @@
+#include <utils/checkpointing/WriteSubItemArrayPerItemVariant.hpp>
+
+#include <language/modules/MeshModuleTypes.hpp>
+#include <language/utils/ASTNodeDataTypeTraits.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <language/utils/EmbeddedData.hpp>
+#include <mesh/SubItemArrayPerItemVariant.hpp>
+#include <utils/checkpointing/ItemTypeHFType.hpp>
+#include <utils/checkpointing/WriteConnectivity.hpp>
+#include <utils/checkpointing/WriteTable.hpp>
+
+namespace checkpointing
+{
+
+void
+writeSubItemArrayPerItemVariant(HighFive::Group& variable_group,
+                                std::shared_ptr<const SubItemArrayPerItemVariant> sub_item_array_per_item_variant_v,
+                                HighFive::File& file,
+                                HighFive::Group& checkpoint_group)
+{
+  variable_group.createAttribute("type",
+                                 dataTypeName(ast_node_data_type_from<decltype(sub_item_array_per_item_variant_v)>));
+
+  std::visit(
+    [&](auto&& sub_item_array_per_item) {
+      using SubItemArrayPerItemT = std::decay_t<decltype(sub_item_array_per_item)>;
+
+      variable_group.createAttribute("item_type", SubItemArrayPerItemT::item_type);
+      variable_group.createAttribute("sub_item_type", SubItemArrayPerItemT::sub_item_type);
+      using data_type = std::decay_t<typename SubItemArrayPerItemT::data_type>;
+      variable_group.createAttribute("data_type", dataTypeName(ast_node_data_type_from<data_type>));
+
+      const IConnectivity& connectivity = *sub_item_array_per_item.connectivity_ptr();
+      variable_group.createAttribute("connectivity_id", connectivity.id());
+      writeConnectivity(connectivity, file, checkpoint_group);
+
+      write(variable_group, "arrays", sub_item_array_per_item.tableView());
+    },
+    sub_item_array_per_item_variant_v->subItemArrayPerItem());
+}
+
+void
+writeSubItemArrayPerItemVariant(const std::string& symbol_name,
+                                const EmbeddedData& embedded_data,
+                                HighFive::File& file,
+                                HighFive::Group& checkpoint_group,
+                                HighFive::Group& symbol_table_group)
+{
+  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
+
+  std::shared_ptr<const SubItemArrayPerItemVariant> sub_item_array_per_item_variant_p =
+    dynamic_cast<const DataHandler<const SubItemArrayPerItemVariant>&>(embedded_data.get()).data_ptr();
+
+  writeSubItemArrayPerItemVariant(variable_group, sub_item_array_per_item_variant_p, file, checkpoint_group);
+}
+
+}   // namespace checkpointing
diff --git a/src/utils/checkpointing/WriteSubItemArrayPerItemVariant.hpp b/src/utils/checkpointing/WriteSubItemArrayPerItemVariant.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..8e03a4d925c9e29bb13e791792e0b5d48200bb7d
--- /dev/null
+++ b/src/utils/checkpointing/WriteSubItemArrayPerItemVariant.hpp
@@ -0,0 +1,18 @@
+#ifndef WRITE_SUB_ITEM_ARRAY_PER_ITEM_VARIANT_HPP
+#define WRITE_SUB_ITEM_ARRAY_PER_ITEM_VARIANT_HPP
+
+#include <utils/HighFivePugsUtils.hpp>
+
+class EmbeddedData;
+
+namespace checkpointing
+{
+
+void writeSubItemArrayPerItemVariant(const std::string& symbol_name,
+                                     const EmbeddedData& embedded_data,
+                                     HighFive::File& file,
+                                     HighFive::Group& checkpoint_group,
+                                     HighFive::Group& symbol_table_group);
+}   // namespace checkpointing
+
+#endif   // WRITE_SUB_ITEM_ARRAY_PER_ITEM_VARIANT_HPP
diff --git a/src/utils/checkpointing/WriteSubItemValuePerItemVariant.cpp b/src/utils/checkpointing/WriteSubItemValuePerItemVariant.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dfc7d49df769c8d9eec4aa5f31a04ad0b09fcc0f
--- /dev/null
+++ b/src/utils/checkpointing/WriteSubItemValuePerItemVariant.cpp
@@ -0,0 +1,57 @@
+#include <utils/checkpointing/WriteSubItemValuePerItemVariant.hpp>
+
+#include <language/modules/MeshModuleTypes.hpp>
+#include <language/utils/ASTNodeDataTypeTraits.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <language/utils/EmbeddedData.hpp>
+#include <mesh/SubItemValuePerItemVariant.hpp>
+#include <utils/checkpointing/ItemTypeHFType.hpp>
+#include <utils/checkpointing/WriteArray.hpp>
+#include <utils/checkpointing/WriteConnectivity.hpp>
+
+namespace checkpointing
+{
+
+void
+writeSubItemValuePerItemVariant(HighFive::Group& variable_group,
+                                std::shared_ptr<const SubItemValuePerItemVariant> sub_item_value_per_item_variant_v,
+                                HighFive::File& file,
+                                HighFive::Group& checkpoint_group)
+{
+  variable_group.createAttribute("type",
+                                 dataTypeName(ast_node_data_type_from<decltype(sub_item_value_per_item_variant_v)>));
+
+  std::visit(
+    [&](auto&& sub_item_value_per_item) {
+      using SubItemValuePerItemT = std::decay_t<decltype(sub_item_value_per_item)>;
+
+      variable_group.createAttribute("item_type", SubItemValuePerItemT::item_type);
+      variable_group.createAttribute("sub_item_type", SubItemValuePerItemT::sub_item_type);
+      using data_type = std::decay_t<typename SubItemValuePerItemT::data_type>;
+      variable_group.createAttribute("data_type", dataTypeName(ast_node_data_type_from<data_type>));
+
+      const IConnectivity& connectivity = *sub_item_value_per_item.connectivity_ptr();
+      variable_group.createAttribute("connectivity_id", connectivity.id());
+      writeConnectivity(connectivity, file, checkpoint_group);
+
+      write(variable_group, "values", sub_item_value_per_item.arrayView());
+    },
+    sub_item_value_per_item_variant_v->subItemValuePerItem());
+}
+
+void
+writeSubItemValuePerItemVariant(const std::string& symbol_name,
+                                const EmbeddedData& embedded_data,
+                                HighFive::File& file,
+                                HighFive::Group& checkpoint_group,
+                                HighFive::Group& symbol_table_group)
+{
+  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
+
+  std::shared_ptr<const SubItemValuePerItemVariant> sub_item_value_per_item_variant_p =
+    dynamic_cast<const DataHandler<const SubItemValuePerItemVariant>&>(embedded_data.get()).data_ptr();
+
+  writeSubItemValuePerItemVariant(variable_group, sub_item_value_per_item_variant_p, file, checkpoint_group);
+}
+
+}   // namespace checkpointing
diff --git a/src/utils/checkpointing/WriteSubItemValuePerItemVariant.hpp b/src/utils/checkpointing/WriteSubItemValuePerItemVariant.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..e1842cad5852b7d2ba0be9a9d5593641893af7c1
--- /dev/null
+++ b/src/utils/checkpointing/WriteSubItemValuePerItemVariant.hpp
@@ -0,0 +1,19 @@
+#ifndef WRITE_SUB_ITEM_VALUE_PER_ITEM_VARIANT_HPP
+#define WRITE_SUB_ITEM_VALUE_PER_ITEM_VARIANT_HPP
+
+#include <utils/HighFivePugsUtils.hpp>
+
+class EmbeddedData;
+
+namespace checkpointing
+{
+
+void writeSubItemValuePerItemVariant(const std::string& symbol_name,
+                                     const EmbeddedData& embedded_data,
+                                     HighFive::File& file,
+                                     HighFive::Group& checkpoint_group,
+                                     HighFive::Group& symbol_table_group);
+
+}   // namespace checkpointing
+
+#endif   // WRITE_SUB_ITEM_VALUE_PER_ITEM_VARIANT_HPP
diff --git a/src/utils/checkpointing/WriteTable.hpp b/src/utils/checkpointing/WriteTable.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..fb11b5f962b1a7199850bd0bdd3f1206da428683
--- /dev/null
+++ b/src/utils/checkpointing/WriteTable.hpp
@@ -0,0 +1,57 @@
+#ifndef WRITE_TABLE_HPP
+#define WRITE_TABLE_HPP
+
+#include <utils/HighFivePugsUtils.hpp>
+
+#include <utils/Messenger.hpp>
+#include <utils/Table.hpp>
+
+namespace checkpointing
+{
+
+template <typename DataType>
+PUGS_INLINE void
+write(HighFive::Group& group, const std::string& name, const Table<DataType>& table)
+{
+  const size_t number_of_columns = parallel::allReduceMax(table.numberOfColumns());
+  if ((table.numberOfColumns() != number_of_columns) and (table.numberOfRows() > 0)) {
+    throw UnexpectedError("table must have same number of columns in parallel");
+  }
+
+  auto get_address = [](auto& t) { return (t.numberOfRows() * t.numberOfColumns() > 0) ? &(t(0, 0)) : nullptr; };
+
+  Array<size_t> number_of_rows_per_rank = parallel::allGather(table.numberOfRows());
+  size_t global_size                    = sum(number_of_rows_per_rank) * number_of_columns;
+
+  size_t current_offset = 0;
+  for (size_t i = 0; i < parallel::rank(); ++i) {
+    current_offset += number_of_rows_per_rank[i] * table.numberOfColumns();
+  }
+  std::vector<size_t> offset{current_offset, 0ul};
+  std::vector<size_t> count{table.numberOfRows() * table.numberOfColumns()};
+
+  using data_type = std::remove_const_t<DataType>;
+  HighFive::DataSetCreateProps properties;
+  properties.add(HighFive::Chunking(std::vector<hsize_t>{std::min(4ul * 1024ul * 1024ul, global_size)}));
+  properties.add(HighFive::Shuffle());
+  properties.add(HighFive::Deflate(3));
+
+  auto xfer_props = HighFive::DataTransferProps{};
+  xfer_props.add(HighFive::UseCollectiveIO{});
+
+  HighFive::DataSet dataset =
+    group.createDataSet<data_type>(name, HighFive::DataSpace{std::vector<size_t>{global_size}}, properties);
+  dataset.select(offset, count).template write_raw<data_type>(get_address(table), xfer_props);
+
+  std::vector<size_t> number_of_rows_per_rank_vector;
+  for (size_t i = 0; i < number_of_rows_per_rank.size(); ++i) {
+    number_of_rows_per_rank_vector.push_back(number_of_rows_per_rank[i]);
+  }
+
+  dataset.createAttribute("number_of_rows_per_rank", number_of_rows_per_rank_vector);
+  dataset.createAttribute("number_of_columns", number_of_columns);
+}
+
+}   // namespace checkpointing
+
+#endif   // WRITE_TABLE_HPP
diff --git a/src/utils/checkpointing/WriteVariableBCDescriptor.cpp b/src/utils/checkpointing/WriteVariableBCDescriptor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7d4432e80052546bf35ecaca6313bac5d504d580
--- /dev/null
+++ b/src/utils/checkpointing/WriteVariableBCDescriptor.cpp
@@ -0,0 +1,43 @@
+#include <utils/checkpointing/WriteVariableBCDescriptor.hpp>
+
+#include <language/modules/SchemeModuleTypes.hpp>
+#include <language/utils/ASTNodeDataTypeTraits.hpp>
+#include <language/utils/DataHandler.hpp>
+#include <scheme/DiscreteFunctionVariant.hpp>
+#include <scheme/VariableBCDescriptor.hpp>
+#include <utils/checkpointing/DiscreteFunctionTypeHFType.hpp>
+#include <utils/checkpointing/IBoundaryConditionDescriptorHFType.hpp>
+#include <utils/checkpointing/WriteDiscreteFunctionVariant.hpp>
+#include <utils/checkpointing/WriteIBoundaryConditionDescriptor.hpp>
+
+namespace checkpointing
+{
+
+void
+writeVariableBCDescriptor(const std::string& symbol_name,
+                          const EmbeddedData& embedded_data,
+                          HighFive::File& file,
+                          HighFive::Group& checkpoint_group,
+                          HighFive::Group& symbol_table_group)
+{
+  HighFive::Group variable_group = symbol_table_group.createGroup("embedded/" + symbol_name);
+
+  std::shared_ptr<const VariableBCDescriptor> variable_bc_descriptor_p =
+    dynamic_cast<const DataHandler<const VariableBCDescriptor>&>(embedded_data.get()).data_ptr();
+
+  variable_group.createAttribute("type", dataTypeName(ast_node_data_type_from<decltype(variable_bc_descriptor_p)>));
+
+  HighFive::Group discrete_function_group = variable_group.createGroup("discrete_function");
+  writeDiscreteFunctionVariant(discrete_function_group, variable_bc_descriptor_p->discreteFunctionVariant(), file,
+                               checkpoint_group);
+
+  const auto bc_descriptor_list            = variable_bc_descriptor_p->bcDescriptorList();
+  HighFive::Group bc_descriptor_list_group = variable_group.createGroup("bc_descriptor_list");
+  for (size_t i_bc_descriptor = 0; i_bc_descriptor < bc_descriptor_list.size(); ++i_bc_descriptor) {
+    HighFive::Group bc_descriptor_group = bc_descriptor_list_group.createGroup(std::to_string(i_bc_descriptor));
+
+    writeIBoundaryConditionDescriptor(bc_descriptor_group, bc_descriptor_list[i_bc_descriptor]);
+  }
+}
+
+}   // namespace checkpointing
diff --git a/src/utils/checkpointing/WriteVariableBCDescriptor.hpp b/src/utils/checkpointing/WriteVariableBCDescriptor.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..ab82a6f7498cb1053a0fb92faad784a63e233c34
--- /dev/null
+++ b/src/utils/checkpointing/WriteVariableBCDescriptor.hpp
@@ -0,0 +1,19 @@
+#ifndef WRITE_VARIABLE_BC_DESCRIPTOR_HPP
+#define WRITE_VARIABLE_BC_DESCRIPTOR_HPP
+
+#include <utils/HighFivePugsUtils.hpp>
+
+class EmbeddedData;
+
+namespace checkpointing
+{
+
+void writeVariableBCDescriptor(const std::string& symbol_name,
+                               const EmbeddedData& embedded_data,
+                               HighFive::File& file,
+                               HighFive::Group& checkpoint_group,
+                               HighFive::Group& symbol_table_group);
+
+}
+
+#endif   // WRITE_VARIABLE_BC_DESCRIPTOR_HPP