SpECTRE Documentation Coverage Report
Current view: top level - IO/Exporter - SpacetimeInterpolator.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 28.0 % 25 7
Test Date: 2026-10-22 17:29:42
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 <optional>
       8              : #include <shared_mutex>
       9              : #include <string>
      10              : #include <utility>
      11              : #include <variant>
      12              : #include <vector>
      13              : 
      14              : #include "DataStructures/Tensor/TypeAliases.hpp"
      15              : #include "Domain/FunctionsOfTime/FunctionOfTime.hpp"
      16              : #include "IO/Exporter/PointwiseInterpolator.hpp"
      17              : #include "Utilities/Gsl.hpp"
      18              : 
      19              : namespace spectre::Exporter {
      20              : 
      21              : /*!
      22              :  * \brief Interpolates data in volume files in both space and time
      23              :  *
      24              :  * This class reads the volume data at multiple time steps into memory and can
      25              :  * then interpolate it to any number of target points at any time within the
      26              :  * time bounds of the loaded data.
      27              :  *
      28              :  * \details The interpolation is first done in space and then in time. For the
      29              :  * interpolation in space, the PointwiseInterpolator class is used, which does
      30              :  * spectral interpolation within the elements. For the interpolation in time, a
      31              :  * polynomial interpolation with fixed order is used (currently third order,
      32              :  * meaning four time slices are used).
      33              :  *
      34              :  * \par Coordinate frames
      35              :  * The target points are given in the `Frame` specified as template parameter
      36              :  * (defaults to `Frame::Inertial`). However, the interpolation is done in the
      37              :  * grid frame, which is time-independent and therefore best suitable for
      38              :  * interpolation in time. Details of this idea can be found in
      39              :  * \cite Bohn:2016afc .
      40              :  *
      41              :  * \par Thread safety
      42              :  * Loading volume data from H5 files on multiple threads at once is not
      43              :  * generally thread safe, so `load_time_bounds` may only be called on a single
      44              :  * thread. However, once the data is loaded, the `interpolate_to_point` function
      45              :  * is thread safe. This means the volume data can be loaded once in a single
      46              :  * thread and then used by multiple threads to interpolate to different points
      47              :  * in parallel. Also, `load_time_bounds` can be called again to load new data
      48              :  * while other threads are still accessing the old data, as long as they only
      49              :  * request data within both the old and the new time bounds.
      50              :  */
      51              : template <size_t Dim, typename Frame = ::Frame::Inertial>
      52            1 : struct SpacetimeInterpolator {
      53            0 :   SpacetimeInterpolator() = default;
      54            0 :   SpacetimeInterpolator(const SpacetimeInterpolator&) = delete;
      55            0 :   SpacetimeInterpolator& operator=(const SpacetimeInterpolator&) = delete;
      56            0 :   SpacetimeInterpolator(SpacetimeInterpolator&&);
      57            0 :   SpacetimeInterpolator& operator=(SpacetimeInterpolator&&);
      58            0 :   ~SpacetimeInterpolator() = default;
      59              : 
      60              :   /*!
      61              :    * \brief Construct the interpolator without loading any volume data
      62              :    *
      63              :    * \param volume_files_or_glob The list of H5 files, or a glob pattern
      64              :    * \param subfile_name The name of the subfile in the H5 files containing the
      65              :    * volume data
      66              :    * \param tensor_components The tensor components to interpolate. The order of
      67              :    * the components in the vector is the order in which they will be returned.
      68              :    */
      69            1 :   SpacetimeInterpolator(
      70              :       std::variant<std::vector<std::string>, std::string> volume_files_or_glob,
      71              :       std::string subfile_name, std::vector<std::string> tensor_components);
      72              : 
      73              :   /// The maximum time bounds available in the volume data files (taking into
      74              :   /// account the number of ghost slices needed for interpolation). Only time
      75              :   /// bounds in this (inclusive) range can be requested with the
      76              :   /// `load_time_bounds()` function.
      77            1 :   std::array<double, 2> max_time_bounds() const;
      78              : 
      79              :   /*!
      80              :    * \brief Load volume data into memory such that the given time bounds are
      81              :    * covered.
      82              :    *
      83              :    * The given time bounds must be within the `max_time_bounds()` (inclusive).
      84              :    *
      85              :    * Previously loaded volume data slices outside the given time bounds will be
      86              :    * dropped and new ones loaded.
      87              :    *
      88              :    * \par Thread safety
      89              :    * This function is not generally thread safe, as it loads data from H5 files.
      90              :    * It should be called from a single thread only. It is safe to keep calling
      91              :    * interpolation routines from other threads while this function is running,
      92              :    * as long as they are requesting data within both the old and the new time
      93              :    * bounds.
      94              :    */
      95            1 :   void load_time_bounds(std::array<double, 2> time_bounds);
      96              : 
      97              :   /// The time bounds of the loaded data (inclusive). It is an error to call the
      98              :   /// interpolation routines outside these bounds.
      99            1 :   std::array<double, 2> time_bounds() const { return time_bounds_; }
     100              : 
     101              :   /// The number of loaded time slices.
     102            1 :   size_t num_loaded_slices() const { return interpolators_.size(); }
     103              : 
     104              :   /*!
     105              :    * \brief Interpolate to a single point
     106              :    *
     107              :    * This function is thread safe, so the interpolator can be constructed to
     108              :    * load the volume data once and then used by multiple threads to interpolate
     109              :    * to different points in parallel. Note that updating the `block_order` (if
     110              :    * provided) is not thread safe, so each thread should manage a separate
     111              :    * `block_order`.
     112              :    *
     113              :    * \param result the interpolated data at the target point. The vector is over
     114              :    * the number of components. Will be resized automatically.
     115              :    * \param target_point the point to interpolate to.
     116              :    * \param time the time to interpolate to. Must be within the `time_bounds()`.
     117              :    * \param block_order an optional priority order to search for the block
     118              :    * containing the target point. Will be updated when the point is found.
     119              :    * See `block_logical_coordinates_single_point` for more details.
     120              :    */
     121            1 :   void interpolate_to_point(gsl::not_null<std::vector<double>*> result,
     122              :                             const tnsr::I<double, Dim, Frame>& target_point,
     123              :                             double time,
     124              :                             std::optional<gsl::not_null<std::vector<size_t>*>>
     125              :                                 block_order = std::nullopt) const;
     126              : 
     127              :  private:
     128            0 :   std::variant<std::vector<std::string>, std::string> volume_files_or_glob_;
     129            0 :   std::string subfile_name_;
     130            0 :   std::vector<std::string> tensor_components_;
     131            0 :   constexpr static size_t time_interpolation_order_ = 3;  // must be odd
     132            0 :   constexpr static size_t num_ghost_slices_ =
     133              :       (time_interpolation_order_ + 1) / 2 - 1;
     134            0 :   domain::FunctionsOfTimeMap functions_of_time_;
     135              :   // Metadata collected from data files
     136            0 :   std::vector<size_t> all_observation_ids_;
     137            0 :   std::vector<double> all_observation_values_;
     138              :   // State
     139            0 :   std::array<double, 2> time_bounds_{
     140              :       {std::numeric_limits<double>::signaling_NaN(),
     141              :        std::numeric_limits<double>::signaling_NaN()}};
     142              :   // Loaded from data files
     143            0 :   std::vector<PointwiseInterpolator<Dim, ::Frame::Grid>> interpolators_{};
     144              :   // Mutex to protect other threads from accessing the `interpolators_` vector
     145              :   // while it is being modified
     146            0 :   mutable std::shared_mutex interpolators_mutex_;  // NOLINT(spectre-mutable)
     147              : };
     148              : 
     149              : }  // namespace spectre::Exporter
        

Generated by: LCOV version 2.0-1