SpECTRE Documentation Coverage Report
Current view: top level - IO/H5 - VolumeData.hpp Hit Total Coverage
Commit: 361cb8d8406bb752684a5f31c27320ec444a50e3 Lines: 21 38 55.3 %
Date: 2025-11-09 02:02:04
Legend: Lines: hit not hit

          Line data    Source code
       1           0 : // Distributed under the MIT License.
       2             : // See LICENSE.txt for details.
       3             : 
       4             : #pragma once
       5             : 
       6             : #include <cstddef>
       7             : #include <cstdint>
       8             : #include <optional>
       9             : #include <string>
      10             : #include <tuple>
      11             : #include <utility>
      12             : #include <vector>
      13             : 
      14             : #include "IO/H5/Object.hpp"
      15             : #include "IO/H5/OpenGroup.hpp"
      16             : 
      17             : /// \cond
      18             : class DataVector;
      19             : struct ElementVolumeData;
      20             : template <size_t>
      21             : class Mesh;
      22             : namespace Spectral {
      23             : enum class Basis : uint8_t;
      24             : enum class Quadrature : uint8_t;
      25             : }  // namespace Spectral
      26             : struct TensorComponent;
      27             : /// \endcond
      28             : 
      29             : namespace h5 {
      30             : /*!
      31             :  * \ingroup HDF5Group
      32             :  * \brief A volume data subfile written inside an H5 file.
      33             :  *
      34             :  * The volume data inside the subfile can be of any dimensionality greater than
      35             :  * zero. This means that in a 3D simulation, data on 2-dimensional surfaces are
      36             :  * written as a VolumeData subfile. Data can be written using the
      37             :  * `write_volume_data()` method. An integral observation id is used to keep
      38             :  * track of the observation instance at which the data is written, and
      39             :  * associated with it is a floating point observation value, such as the
      40             :  * simulation time at which the data was written. The observation id will
      41             :  * generally be the result of hashing the temporal identifier used for the
      42             :  * simulation.
      43             :  *
      44             :  * \par Grid names
      45             :  * The data stored in the subfile are the tensor components passed to the
      46             :  * `write_volume_data()` method as a `std::vector<ElementVolumeData>`. Typically
      47             :  * the `GRID_NAME` should be the output of the stream operator of the spatial ID
      48             :  * of the parallel component element sending the data to be observed. For
      49             :  * example, in the case of a dG evolution where the spatial IDs are
      50             :  * `ElementId`s, the grid names would be of the form `[B0,(L2I3,L2I3,L2I3)]`.
      51             :  *
      52             :  * \par Data layout in the H5 file
      53             :  * The data are written contiguously inside of the H5 subfile, in that each
      54             :  * tensor component has a single dataset which holds all of the data from all
      55             :  * elements, e.g. a tensor component `T_xx` which is found on all grids appears
      56             :  * in the path `H5_FILE_NAME/SUBFILE_NAME.vol/OBSERVATION_ID/GRID_NAME/T_xx` and
      57             :  * that is where all of the `T_xx` data from all of the grids resides. Note that
      58             :  * coordinates must be written as tensors in order to visualize the data in
      59             :  * ParaView, Visit, etc.  In order to reconstruct which data came from which
      60             :  * grid, the `get_grid_names()`, and `get_extents()` methods list the grids
      61             :  * and their extents in the order which they and the data were written.
      62             :  * For example, if the first grid has name `GRID_NAME` with extents
      63             :  * `{2, 2, 2}`, it was responsible for contributing the first 2*2*2 = 8 grid
      64             :  * points worth of data in each tensor dataset. Use the
      65             :  * `h5::offset_and_length_for_grid` function to compute the offset into the
      66             :  * contiguous dataset that corresponds to a particular grid.
      67             :  *
      68             :  * \par Domain and FunctionsOfTime
      69             :  * A serialized representation of the domain and the functions of time can be
      70             :  * written into the subfile alongside the tensor data. Reconstructing the domain
      71             :  * (specifically the block maps) is needed for accurate interpolation of the
      72             :  * tensor data to another set of points. The domain is currently stored as a
      73             :  * `std::vector<char>`, and it is up to the calling code to serialize and
      74             :  * deserialize the data, taking into account that files may be written and read
      75             :  * with different versions of the code.
      76             :  *
      77             :  * \warning Currently the topology of the grids is assumed to be tensor products
      78             :  * of lines, i.e. lines, quadrilaterals, and hexahedrons. However, this can be
      79             :  * extended in the future. If support for more topologies is required, please
      80             :  * file an issue.
      81             :  */
      82           1 : class VolumeData : public h5::Object {
      83             :  public:
      84           0 :   static std::string extension() { return ".vol"; }
      85             : 
      86           0 :   VolumeData(bool subfile_exists, detail::OpenGroup&& group, hid_t location,
      87             :              const std::string& name, uint32_t version = 1);
      88             : 
      89           0 :   VolumeData(const VolumeData& /*rhs*/) = delete;
      90           0 :   VolumeData& operator=(const VolumeData& /*rhs*/) = delete;
      91           0 :   VolumeData(VolumeData&& /*rhs*/) = delete;             // NOLINT
      92           0 :   VolumeData& operator=(VolumeData&& /*rhs*/) = delete;  // NOLINT
      93             : 
      94           0 :   ~VolumeData() override = default;
      95             : 
      96             :   /*!
      97             :    * \returns the header of the VolumeData file
      98             :    */
      99           1 :   const std::string& get_header() const { return header_; }
     100             : 
     101             :   /*!
     102             :    * \returns the user-specified version number of the VolumeData file
     103             :    *
     104             :    * \note h5::Version returns a uint32_t, so we return one here too for the
     105             :    * version
     106             :    */
     107           1 :   uint32_t get_version() const { return version_; }
     108             : 
     109             :   /// Insert tensor components at `observation_id` with floating point value
     110             :   /// `observation_value`. Optionally write a serialized representation of the
     111             :   /// domain and the functions of time into the subfile as well.
     112             :   ///
     113             :   /// All `elements` must contain the same tensor components in the same order.
     114           1 :   void write_volume_data(
     115             :       size_t observation_id, double observation_value,
     116             :       const std::vector<ElementVolumeData>& elements,
     117             :       const std::optional<std::vector<char>>& serialized_domain = std::nullopt,
     118             :       const std::optional<std::vector<char>>& serialized_functions_of_time =
     119             :           std::nullopt);
     120             : 
     121             :   /// Overwrites the current connectivity dataset with a new one. This new
     122             :   /// connectivity dataset builds connectivity within each block in the domain
     123             :   /// for each observation id in a list of observation id's
     124             :   template <size_t SpatialDim>
     125           1 :   void extend_connectivity_data(const std::vector<size_t>& observation_ids);
     126             : 
     127           0 :   void write_tensor_component(const size_t observation_id,
     128             :                               const std::string& component_name,
     129             :                               const DataVector& contiguous_tensor_data,
     130             :                               bool overwrite_existing = false);
     131             : 
     132           0 :   void write_tensor_component(const size_t observation_id,
     133             :                               const std::string& component_name,
     134             :                               const std::vector<float>& contiguous_tensor_data,
     135             :                               bool overwrite_existing = false);
     136             : 
     137             :   /// List all the integral observation ids in the subfile
     138             :   ///
     139             :   /// The list of observation IDs is sorted by their observation value, as
     140             :   /// returned by get_observation_value(size_t).
     141           1 :   std::vector<size_t> list_observation_ids() const;
     142             : 
     143             :   /// Get the observation value at the the integral observation id in the
     144             :   /// subfile
     145           1 :   double get_observation_value(size_t observation_id) const;
     146             : 
     147             :   /// Find the observation ID that matches the `observation_value`
     148             :   ///
     149             :   /// \details An epsilon can be specified and the observation id that matches
     150             :   /// within the epsilon of `observation_value` will be returned. If there is
     151             :   /// more than one id that is within the epsilon, an error will occur. If no
     152             :   /// epsilon is specified, this function will do exact comparison.
     153           1 :   size_t find_observation_id(
     154             :       double observation_value,
     155             :       const std::optional<double>& observation_value_epsilon =
     156             :           std::nullopt) const;
     157             : 
     158             :   /// List all the tensor components at observation id `observation_id`
     159           1 :   std::vector<std::string> list_tensor_components(size_t observation_id) const;
     160             : 
     161             :   /// List the names of all the grids at observation id `observation_id`
     162           1 :   std::vector<std::string> get_grid_names(size_t observation_id) const;
     163             : 
     164             :   /// Read a tensor component with name `tensor_component` at observation id
     165             :   /// `observation_id` from all grids in the file
     166           1 :   TensorComponent get_tensor_component(
     167             :       size_t observation_id, const std::string& tensor_component) const;
     168             : 
     169             :   /// Read the extents of all the grids stored in the file at the observation id
     170             :   /// `observation_id`
     171           1 :   std::vector<std::vector<size_t>> get_extents(size_t observation_id) const;
     172             : 
     173             :   /// Retrieve volume data for IDs in
     174             :   /// `[start_observation_value, end_observation_value]`.
     175             :   ///
     176             :   /// Returns a `std::vector` over times, sorted in ascending order of the
     177             :   /// observation value (the time in evolutions). The vector holds a
     178             :   /// `std::tuple` that holds
     179             :   /// 1. the integral observation ID
     180             :   /// 2. the observation value (time in evolutions)
     181             :   /// 3. a vector of `ElementVolumeData` sorted by the elements' name string.
     182             :   ///
     183             :   /// - If `start_observation_value` is `std::nullopt` then return
     184             :   ///   everything from the beginning of the data to `end_observation_value`. If
     185             :   ///   `end_observation_value` is `std::nullopt` then return everything from
     186             :   ///   `start_observation_value` to the end of the data.
     187             :   /// - If `components_to_retrieve` is `std::nullopt` then return all
     188             :   ///   components.
     189           1 :   auto get_data_by_element(std::optional<double> start_observation_value,
     190             :                            std::optional<double> end_observation_value,
     191             :                            const std::optional<std::vector<std::string>>&
     192             :                                components_to_retrieve = std::nullopt) const
     193             :       -> std::vector<
     194             :           std::tuple<size_t, double, std::vector<ElementVolumeData>>>;
     195             : 
     196             :   /// Read the dimensionality of the grids.  Note : This is the dimension of
     197             :   /// the grids as manifolds, not the dimension of the embedding space.  For
     198             :   /// example, the volume data of a sphere is 2-dimensional, even though
     199             :   /// each point has an x, y, and z coordinate.
     200           1 :   size_t get_dimension() const;
     201             : 
     202             :   /// Return the character used as a separator between grids in the subfile.
     203           1 :   static char separator() { return ':'; }
     204             : 
     205             :   /// Return the basis being used for each element along each axis
     206           1 :   std::vector<std::vector<Spectral::Basis>> get_bases(
     207             :       size_t observation_id) const;
     208             : 
     209             :   /// Return the quadrature being used for each element along each axis
     210           1 :   std::vector<std::vector<Spectral::Quadrature>> get_quadratures(
     211             :       size_t observation_id) const;
     212             : 
     213             :   /// Get the serialized domain in the subfile at this observation ID, or
     214             :   /// `std::nullopt` if no domain was written.
     215           1 :   std::optional<std::vector<char>> get_domain(size_t observation_id) const;
     216             : 
     217             :   /// Get the serialized functions of time in the subfile at this observation
     218             :   /// ID, or `std::nullopt` if none were written.
     219           1 :   std::optional<std::vector<char>> get_functions_of_time(
     220             :       size_t observation_id) const;
     221             : 
     222           1 :   const std::string& subfile_path() const override { return path_; }
     223             : 
     224             :  private:
     225           0 :   detail::OpenGroup group_{};
     226           0 :   std::string name_{};
     227           0 :   std::string path_{};
     228           0 :   uint32_t version_{};
     229           0 :   detail::OpenGroup volume_data_group_{};
     230           0 :   std::string header_{};
     231             : };
     232             : 
     233             : /*!
     234             :  * \brief Find the interval within the contiguous dataset stored in
     235             :  * `h5::VolumeData` that holds data for a particular `grid_name`.
     236             :  *
     237             :  * `h5::VolumeData` stores data for all grids that compose the volume
     238             :  * contiguously. This function helps with reconstructing which part of that
     239             :  * contiguous dataset belongs to a particular grid. See the `h5::VolumeData`
     240             :  * documentation for more information on how it stores data.
     241             :  *
     242             :  * To use this function, call `h5::VolumeData::get_grid_names` and
     243             :  * `h5::VolumeData::get_extents` and pass the results for the `all_grid_names`
     244             :  * and `all_extents` arguments, respectively. This means you can retrieve this
     245             :  * information from an `h5::VolumeData` once and use it to call
     246             :  * `offset_and_length_for_grid` multiple times with different `grid_name`s.
     247             :  *
     248             :  * Here is an example for using this function:
     249             :  *
     250             :  * \snippet Test_VolumeData.cpp find_offset
     251             :  *
     252             :  * \see `h5::VolumeData`
     253             :  */
     254           1 : std::pair<size_t, size_t> offset_and_length_for_grid(
     255             :     const std::string& grid_name,
     256             :     const std::vector<std::string>& all_grid_names,
     257             :     const std::vector<std::vector<size_t>>& all_extents);
     258             : 
     259             : template <size_t Dim>
     260           0 : Mesh<Dim> mesh_for_grid(
     261             :     const std::string& grid_name,
     262             :     const std::vector<std::string>& all_grid_names,
     263             :     const std::vector<std::vector<size_t>>& all_extents,
     264             :     const std::vector<std::vector<Spectral::Basis>>& all_bases,
     265             :     const std::vector<std::vector<Spectral::Quadrature>>& all_quadratures);
     266             : 
     267             : }  // namespace h5

Generated by: LCOV version 1.14