From fbdc0153a1aab80454c46f47d2c3cecb63b24603 Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Thu, 30 May 2024 08:28:32 +0200
Subject: [PATCH] Continue code cleaning and organization

---
 src/language/modules/CoreModule.cpp           |   3 +-
 src/language/modules/MeshModule.cpp           |  12 +-
 src/language/modules/SchemeModule.cpp         |   7 +-
 src/language/modules/WriterModule.cpp         |   3 +-
 src/utils/checkpointing/CMakeLists.txt        |  19 +-
 src/utils/checkpointing/CheckpointUtils.cpp   | 904 ------------------
 src/utils/checkpointing/CheckpointUtils.hpp   | 229 -----
 .../DiscreteFunctionTypeHFType.hpp            |   2 +-
 .../checkpointing/DualMeshTypeHFType.hpp      |   2 +-
 .../IBoundaryConditionDescriptorHFType.hpp    |   3 +-
 .../IBoundaryDescriptorHFType.hpp             |   3 +-
 .../IInterfaceDescriptorHFType.hpp            |   3 +-
 .../INamedDiscreteDataHFType.hpp              |   3 +-
 src/utils/checkpointing/IWriterHFType.hpp     |   3 +-
 .../checkpointing/IZoneDescriptorHFType.hpp   |   3 +-
 src/utils/checkpointing/ItemTypeHFType.hpp    |   3 +-
 .../LinearSolverOptionsHFType.hpp             |   3 +-
 src/utils/checkpointing/OStreamTypeHFType.hpp |   3 +-
 .../checkpointing/ParallelCheckerHFType.hpp   |   2 +-
 .../checkpointing/QuadratureTypeHFType.hpp    |   3 +-
 src/utils/checkpointing/ReadOStream.cpp       |   1 +
 src/utils/checkpointing/RefItemListHFType.hpp |   3 +-
 src/utils/checkpointing/WriteArray.hpp        |  67 ++
 src/utils/checkpointing/WriteConnectivity.cpp | 154 +++
 src/utils/checkpointing/WriteConnectivity.hpp |  15 +
 .../WriteDiscreteFunctionVariant.cpp          |  60 ++
 .../WriteDiscreteFunctionVariant.hpp          |  24 +
 .../WriteIBoundaryConditionDescriptor.cpp     | 120 +++
 .../WriteIBoundaryConditionDescriptor.hpp     |  23 +
 .../WriteIBoundaryDescriptor.cpp              |  53 +
 .../WriteIBoundaryDescriptor.hpp              |  21 +
 .../WriteIDiscreteFunctionDescriptor.cpp      |  32 +
 .../WriteIDiscreteFunctionDescriptor.hpp      |  19 +
 .../WriteIInterfaceDescriptor.cpp             |  47 +
 .../WriteIInterfaceDescriptor.hpp             |  19 +
 .../checkpointing/WriteINamedDiscreteData.cpp |  66 ++
 .../checkpointing/WriteINamedDiscreteData.hpp |  18 +
 .../WriteIQuadratureDescriptor.cpp            |  30 +
 .../WriteIQuadratureDescriptor.hpp            |  18 +
 src/utils/checkpointing/WriteIWriter.cpp      |  53 +
 src/utils/checkpointing/WriteIWriter.hpp      |  19 +
 .../checkpointing/WriteIZoneDescriptor.cpp    |  46 +
 .../checkpointing/WriteIZoneDescriptor.hpp    |  18 +
 src/utils/checkpointing/WriteItemArray.hpp    |  22 +
 .../checkpointing/WriteItemArrayVariant.cpp   |  56 ++
 .../checkpointing/WriteItemArrayVariant.hpp   |  24 +
 src/utils/checkpointing/WriteItemType.cpp     |  30 +
 src/utils/checkpointing/WriteItemType.hpp     |  18 +
 src/utils/checkpointing/WriteItemValue.hpp    |  22 +
 .../checkpointing/WriteItemValueVariant.cpp   |  56 ++
 .../checkpointing/WriteItemValueVariant.hpp   |  25 +
 src/utils/checkpointing/WriteMesh.cpp         |  75 ++
 src/utils/checkpointing/WriteMesh.hpp         |  22 +
 src/utils/checkpointing/WriteOStream.cpp      |  42 +
 src/utils/checkpointing/WriteOStream.hpp      |  17 +
 .../WriteSubItemArrayPerItemVariant.cpp       |  57 ++
 .../WriteSubItemArrayPerItemVariant.hpp       |  18 +
 .../WriteSubItemValuePerItemVariant.cpp       |  57 ++
 .../WriteSubItemValuePerItemVariant.hpp       |  19 +
 src/utils/checkpointing/WriteTable.hpp        |  57 ++
 .../WriteVariableBCDescriptor.cpp             |  43 +
 .../WriteVariableBCDescriptor.hpp             |  19 +
 62 files changed, 1663 insertions(+), 1155 deletions(-)
 delete mode 100644 src/utils/checkpointing/CheckpointUtils.cpp
 delete mode 100644 src/utils/checkpointing/CheckpointUtils.hpp
 create mode 100644 src/utils/checkpointing/WriteArray.hpp
 create mode 100644 src/utils/checkpointing/WriteConnectivity.cpp
 create mode 100644 src/utils/checkpointing/WriteConnectivity.hpp
 create mode 100644 src/utils/checkpointing/WriteDiscreteFunctionVariant.cpp
 create mode 100644 src/utils/checkpointing/WriteDiscreteFunctionVariant.hpp
 create mode 100644 src/utils/checkpointing/WriteIBoundaryConditionDescriptor.cpp
 create mode 100644 src/utils/checkpointing/WriteIBoundaryConditionDescriptor.hpp
 create mode 100644 src/utils/checkpointing/WriteIBoundaryDescriptor.cpp
 create mode 100644 src/utils/checkpointing/WriteIBoundaryDescriptor.hpp
 create mode 100644 src/utils/checkpointing/WriteIDiscreteFunctionDescriptor.cpp
 create mode 100644 src/utils/checkpointing/WriteIDiscreteFunctionDescriptor.hpp
 create mode 100644 src/utils/checkpointing/WriteIInterfaceDescriptor.cpp
 create mode 100644 src/utils/checkpointing/WriteIInterfaceDescriptor.hpp
 create mode 100644 src/utils/checkpointing/WriteINamedDiscreteData.cpp
 create mode 100644 src/utils/checkpointing/WriteINamedDiscreteData.hpp
 create mode 100644 src/utils/checkpointing/WriteIQuadratureDescriptor.cpp
 create mode 100644 src/utils/checkpointing/WriteIQuadratureDescriptor.hpp
 create mode 100644 src/utils/checkpointing/WriteIWriter.cpp
 create mode 100644 src/utils/checkpointing/WriteIWriter.hpp
 create mode 100644 src/utils/checkpointing/WriteIZoneDescriptor.cpp
 create mode 100644 src/utils/checkpointing/WriteIZoneDescriptor.hpp
 create mode 100644 src/utils/checkpointing/WriteItemArray.hpp
 create mode 100644 src/utils/checkpointing/WriteItemArrayVariant.cpp
 create mode 100644 src/utils/checkpointing/WriteItemArrayVariant.hpp
 create mode 100644 src/utils/checkpointing/WriteItemType.cpp
 create mode 100644 src/utils/checkpointing/WriteItemType.hpp
 create mode 100644 src/utils/checkpointing/WriteItemValue.hpp
 create mode 100644 src/utils/checkpointing/WriteItemValueVariant.cpp
 create mode 100644 src/utils/checkpointing/WriteItemValueVariant.hpp
 create mode 100644 src/utils/checkpointing/WriteMesh.cpp
 create mode 100644 src/utils/checkpointing/WriteMesh.hpp
 create mode 100644 src/utils/checkpointing/WriteOStream.cpp
 create mode 100644 src/utils/checkpointing/WriteOStream.hpp
 create mode 100644 src/utils/checkpointing/WriteSubItemArrayPerItemVariant.cpp
 create mode 100644 src/utils/checkpointing/WriteSubItemArrayPerItemVariant.hpp
 create mode 100644 src/utils/checkpointing/WriteSubItemValuePerItemVariant.cpp
 create mode 100644 src/utils/checkpointing/WriteSubItemValuePerItemVariant.hpp
 create mode 100644 src/utils/checkpointing/WriteTable.hpp
 create mode 100644 src/utils/checkpointing/WriteVariableBCDescriptor.cpp
 create mode 100644 src/utils/checkpointing/WriteVariableBCDescriptor.hpp

diff --git a/src/language/modules/CoreModule.cpp b/src/language/modules/CoreModule.cpp
index 14817b1c8..85dfdcd94 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 7c5ea712a..c76260ce5 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 658642e06..f0c1b03df 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 e75919ef2..837bc1252 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 d16895ad9..2c493e227 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 e2d6d2b21..000000000
--- 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 1bef6709c..000000000
--- 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 55c22f98c..c9940f248 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 14010b647..ef742b231 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 fb58b6d56..4a7632af5 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 cc68000de..495ace8ac 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 5e4231ad3..9f170b0e7 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 a1bb006a9..0f35cccec 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 7b6659bdc..124cb2ee5 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 d1986624f..ffed7f4d0 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 714091e0c..2b7db0ee4 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 127fdddc0..94f88fc60 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 1c003d18b..71ced52e7 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 27cd6412b..288326d60 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 3c73f7c72..bba68e822 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 c01491c46..d1c597064 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 4491d4f52..f9912a618 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 000000000..1902378d4
--- /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 000000000..7bed7f83f
--- /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 000000000..8e3fb4334
--- /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 000000000..ddedb95cb
--- /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 000000000..981d6ea5a
--- /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 000000000..ad99b3193
--- /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 000000000..1cfc07416
--- /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 000000000..fee719592
--- /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 000000000..4dce7298d
--- /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 000000000..6633854b2
--- /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 000000000..89e1b3301
--- /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 000000000..e3b34dd57
--- /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 000000000..98a4e37ab
--- /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 000000000..a1ed69109
--- /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 000000000..076e1318d
--- /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 000000000..ed0b2cb2d
--- /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 000000000..52439403b
--- /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 000000000..f05c8e77c
--- /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 000000000..309ed5cb1
--- /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 000000000..32851b6a2
--- /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 000000000..c4de384c8
--- /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 000000000..1bc52b16b
--- /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 000000000..df950cf1e
--- /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 000000000..ddd9c2e70
--- /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 000000000..8eff5445b
--- /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 000000000..b06abb59f
--- /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 000000000..bc6739b84
--- /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 000000000..47246049d
--- /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 000000000..55157df23
--- /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 000000000..09212cebe
--- /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 000000000..07ce40ad2
--- /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 000000000..51201f598
--- /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 000000000..14616a50c
--- /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 000000000..d71838fb6
--- /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 000000000..8e03a4d92
--- /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 000000000..dfc7d49df
--- /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 000000000..e1842cad5
--- /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 000000000..fb11b5f96
--- /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 000000000..7d4432e80
--- /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 000000000..ab82a6f74
--- /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
-- 
GitLab