diff --git a/ogstools/meshlib/mesh_series.py b/ogstools/meshlib/mesh_series.py
index 4f5413528553be84f635c779c089d4aa484e0eab..055abca7145ca6b36426a2a41c20c1ae664fa2e6 100644
--- a/ogstools/meshlib/mesh_series.py
+++ b/ogstools/meshlib/mesh_series.py
@@ -7,140 +7,10 @@ import meshio
 import numpy as np
 import pyvista as pv
 import vtuIO
-from meshio.xdmf.time_series import (
-    ReadError,
-    cell_data_from_raw,
-    xdmf_to_numpy_type,
-)
 from scipy.interpolate import LinearNDInterpolator, NearestNDInterpolator
 from tqdm.auto import tqdm
 
-
-class TimeSeriesReader(meshio.xdmf.TimeSeriesReader):
-    def __init__(self, filename):
-        super().__init__(filename)
-
-    def read_data(self, k: int):
-        point_data = {}
-        cell_data_raw = {}
-        other_data = {}
-
-        t = None
-
-        for c in list(self.collection[k]):
-            if c.tag == "Time":
-                t = float(c.attrib["Value"])
-            elif c.tag == "Attribute":
-                name = c.get("Name")
-
-                if len(list(c)) != 1:
-                    raise ReadError()
-                data_item = list(c)[0]
-                data = self._read_data_item(data_item)
-
-                if c.get("Center") == "Node":
-                    point_data[name] = data
-                elif c.get("Center") == "Cell":
-                    cell_data_raw[name] = data
-                elif c.get("Center") == "Other":
-                    other_data[name] = data
-                else:
-                    raise ReadError()
-
-            else:
-                # skip the xi:included mesh
-                continue
-
-        if self.cells is None:
-            raise ReadError()
-        cell_data = cell_data_from_raw(self.cells, cell_data_raw)
-        if t is None:
-            raise ReadError()
-
-        return t, point_data, cell_data, other_data
-
-    def _read_data_item(self, data_item):
-        dims = [int(d) for d in data_item.get("Dimensions").split()]
-
-        # Actually, `NumberType` is XDMF2 and `DataType` XDMF3, but many files out there
-        # use both keys interchangeably.
-        if data_item.get("DataType"):
-            if data_item.get("NumberType"):
-                raise ReadError()
-            data_type = data_item.get("DataType")
-        elif data_item.get("NumberType"):
-            if data_item.get("DataType"):
-                raise ReadError()
-            data_type = data_item.get("NumberType")
-        else:
-            # Default, see
-            # <https://xdmf.org/index.php/XDMF_Model_and_Format#XML_Element_.28Xdmf_ClassName.29_and_Default_XML_Attributes>
-            data_type = "Float"
-
-        try:
-            precision = data_item.attrib["Precision"]
-        except KeyError:
-            precision = "4"
-
-        data_format = data_item.attrib["Format"]
-
-        if data_format == "XML":
-            return np.fromstring(
-                data_item.text,
-                dtype=xdmf_to_numpy_type[(data_type, precision)],
-                sep=" ",
-            ).reshape(dims)
-        if data_format == "Binary":
-            return np.fromfile(
-                data_item.text.strip(),
-                dtype=xdmf_to_numpy_type[(data_type, precision)],
-            ).reshape(dims)
-
-        if data_format != "HDF":
-            msg = f"Unknown XDMF Format '{data_format}'."
-            raise ReadError(msg)
-
-        file_info = data_item.text.strip()
-        file_h5path__selections = file_info.split("|")
-        file_h5path = file_h5path__selections[0]
-        selections = (
-            file_h5path__selections[1]
-            if len(file_h5path__selections) > 1
-            else None
-        )
-        filename, h5path = file_h5path.split(":")
-        if selections:
-            # offsets, slices, current_data_extends, global_data_extends by dimension
-            m = [
-                list(map(int, att.split(" "))) for att in selections.split(":")
-            ]
-            t = np.transpose(m)
-            selection = tuple(
-                slice(start, start + extend, step)
-                for start, step, extend, _ in t
-            )
-        else:
-            selection = ()
-
-        # The HDF5 file path is given with respect to the XDMF (XML) file.
-        dirpath = self.filename.resolve().parent
-        full_hdf5_path = dirpath / filename
-
-        if full_hdf5_path in self.hdf5_files:
-            f = self.hdf5_files[full_hdf5_path]
-        else:
-            import h5py
-
-            f = h5py.File(full_hdf5_path, "r")
-            self.hdf5_files[full_hdf5_path] = f
-
-        if h5path[0] != "/":
-            raise ReadError()
-
-        for key in h5path[1:].split("/"):
-            f = f[key]
-        # `[()]` gives a np.ndarray
-        return f[selection].squeeze()
+from .xdmf_reader import XDMFReader
 
 
 class MeshSeries:
@@ -172,7 +42,7 @@ class MeshSeries:
         if self._data_type == "pvd":
             self._pvd_reader = pv.PVDReader(filepath)
         elif self._data_type == "xdmf":
-            self._xdmf_reader = TimeSeriesReader(filepath)
+            self._xdmf_reader = XDMFReader(filepath)
             self._read_xdmf(0)  # necessary to initialize hdf5_files
             meshes = self.hdf5["meshes"]
             self.hdf5_bulk_name = list(meshes.keys())[
diff --git a/ogstools/meshlib/xdmf_reader.py b/ogstools/meshlib/xdmf_reader.py
new file mode 100644
index 0000000000000000000000000000000000000000..6f1b49b5797a73bc50b140484ae44eac20611adb
--- /dev/null
+++ b/ogstools/meshlib/xdmf_reader.py
@@ -0,0 +1,151 @@
+"""
+This file provides an override to meshios XDMF Reader since it misses a feature
+to handle hyperslabs (there are two ways to handle hyperslab:
+the common documented `here <https://www.xdmf.org/index.php/XDMF_Model_and_Format#HyperSlab>`_
+and the way paraview supports it (documentation missing).
+
+Example::
+
+    2D_single_fracture_HT.h5:/meshes/2D_single_fracture/temperature|0 0:1 1:1 190:97 190
+
+
+to be read like::
+
+    | start : stride : count : end
+
+"""
+
+import meshio
+import numpy as np
+from meshio.xdmf.time_series import (
+    ReadError,
+    cell_data_from_raw,
+    xdmf_to_numpy_type,
+)
+
+
+class XDMFReader(meshio.xdmf.TimeSeriesReader):
+    def __init__(self, filename):
+        super().__init__(filename)
+
+    def read_data(self, k: int):
+        point_data = {}
+        cell_data_raw = {}
+        other_data = {}
+
+        t = None
+
+        for c in list(self.collection[k]):
+            if c.tag == "Time":
+                t = float(c.attrib["Value"])
+            elif c.tag == "Attribute":
+                name = c.get("Name")
+
+                if len(list(c)) != 1:
+                    raise ReadError()
+                data_item = list(c)[0]
+                data = self._read_data_item(data_item)
+
+                if c.get("Center") == "Node":
+                    point_data[name] = data
+                elif c.get("Center") == "Cell":
+                    cell_data_raw[name] = data
+                elif c.get("Center") == "Other":
+                    other_data[name] = data
+                else:
+                    raise ReadError()
+
+            else:
+                # skip the xi:included mesh
+                continue
+
+        if self.cells is None:
+            raise ReadError()
+        cell_data = cell_data_from_raw(self.cells, cell_data_raw)
+        if t is None:
+            raise ReadError()
+
+        return t, point_data, cell_data, other_data
+
+    def _read_data_item(self, data_item):
+        dims = [int(d) for d in data_item.get("Dimensions").split()]
+
+        # Actually, `NumberType` is XDMF2 and `DataType` XDMF3, but many files out there
+        # use both keys interchangeably.
+        if data_item.get("DataType"):
+            if data_item.get("NumberType"):
+                raise ReadError()
+            data_type = data_item.get("DataType")
+        elif data_item.get("NumberType"):
+            if data_item.get("DataType"):
+                raise ReadError()
+            data_type = data_item.get("NumberType")
+        else:
+            # Default, see
+            # <https://xdmf.org/index.php/XDMF_Model_and_Format#XML_Element_.28Xdmf_ClassName.29_and_Default_XML_Attributes>
+            data_type = "Float"
+
+        try:
+            precision = data_item.attrib["Precision"]
+        except KeyError:
+            precision = "4"
+
+        data_format = data_item.attrib["Format"]
+
+        if data_format == "XML":
+            return np.fromstring(
+                data_item.text,
+                dtype=xdmf_to_numpy_type[(data_type, precision)],
+                sep=" ",
+            ).reshape(dims)
+        if data_format == "Binary":
+            return np.fromfile(
+                data_item.text.strip(),
+                dtype=xdmf_to_numpy_type[(data_type, precision)],
+            ).reshape(dims)
+
+        if data_format != "HDF":
+            msg = f"Unknown XDMF Format '{data_format}'."
+            raise ReadError(msg)
+
+        file_info = data_item.text.strip()
+        file_h5path__selections = file_info.split("|")
+        file_h5path = file_h5path__selections[0]
+        selections = (
+            file_h5path__selections[1]
+            if len(file_h5path__selections) > 1
+            else None
+        )
+        filename, h5path = file_h5path.split(":")
+        if selections:
+            # offsets, slices, current_data_extends, global_data_extends by dimension
+            m = [
+                list(map(int, att.split(" "))) for att in selections.split(":")
+            ]
+            t = np.transpose(m)
+            selection = tuple(
+                slice(start, start + extend, step)
+                for start, step, extend, _ in t
+            )
+        else:
+            selection = ()
+
+        # The HDF5 file path is given with respect to the XDMF (XML) file.
+        dirpath = self.filename.resolve().parent
+        full_hdf5_path = dirpath / filename
+
+        if full_hdf5_path in self.hdf5_files:
+            f = self.hdf5_files[full_hdf5_path]
+        else:
+            import h5py
+
+            f = h5py.File(full_hdf5_path, "r")
+            self.hdf5_files[full_hdf5_path] = f
+
+        if h5path[0] != "/":
+            raise ReadError()
+
+        for key in h5path[1:].split("/"):
+            f = f[key]
+        # `[()]` gives a np.ndarray
+        return f[selection].squeeze()