SpECTRE Documentation Coverage Report
Current view: top level - IO/External - InterpolateFromSpec.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 50.0 % 2 1
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 <Exporter.hpp>  // The SpEC Exporter
       7              : #include <cstddef>
       8              : #include <memory>
       9              : #include <utility>
      10              : #include <vector>
      11              : 
      12              : #include "DataStructures/TaggedTuple.hpp"
      13              : #include "DataStructures/Tensor/Tensor.hpp"
      14              : #include "Utilities/ContainerHelpers.hpp"
      15              : #include "Utilities/ErrorHandling/Assert.hpp"
      16              : #include "Utilities/SetNumberOfGridPoints.hpp"
      17              : #include "Utilities/TMPL.hpp"
      18              : 
      19              : namespace io {
      20              : 
      21              : /*!
      22              :  * \brief Interpolate numerical SpEC initial data to arbitrary points
      23              :  *
      24              :  * \tparam Tags List of tags to load. The tags must correspond exactly to the
      25              :  * list of variables that the `spec_exporter` was configured with. This function
      26              :  * does not support interpolating only a subset of the variables. This is a
      27              :  * limitation of the `spec::Exporter`.
      28              :  * \tparam DataType `double` or `DataVector`.
      29              :  * \tparam CoordFrame The frame of the coordinates `x`. These coordinates are
      30              :  * always assumed to be in SpEC's "grid" frame.
      31              :  *
      32              :  * \param spec_exporter Has the numerical data already loaded. It must be
      33              :  * configured with the same number of variables that were passed as `Tags`, and
      34              :  * in the same order.
      35              :  * \param x Interpolate to these coordinates. They are assumed to be in SpEC's
      36              :  * "grid" frame.
      37              :  * \param which_interpolator Index of the interpolator. See `spec::Exporter`
      38              :  * documentation for details.
      39              :  */
      40              : template <typename Tags, typename DataType, typename CoordFrame>
      41            1 : tuples::tagged_tuple_from_typelist<Tags> interpolate_from_spec(
      42              :     const gsl::not_null<spec::Exporter*> spec_exporter,
      43              :     const tnsr::I<DataType, 3, CoordFrame>& x,
      44              :     const size_t which_interpolator) {
      45              :   // The `spec::Exporter` doesn't currently expose its `vars_to_interpolate`.
      46              :   // Once it does, we can assert the number of variables here.
      47              :   // const auto& dataset_names = spec_exporter.vars_to_interpolate();
      48              :   // ASSERT(tmpl::size<Tags>::value == dataset_names.size(),
      49              :   //        "Mismatch between number of tags and dataset names. The SpEC
      50              :   //        exporter " "was configured with " +
      51              :   //            std::to_string(dataset_names.size()) +
      52              :   //            " variables to interpolate, but requested " +
      53              :   //            std::to_string(tmpl::size<Tags>::value) + " tags.");
      54              :   // Transform coordinates into SpEC's expected format. SpEC expects grid
      55              :   // coordinates. We assume that the grid coordinates coincide with inertial
      56              :   // coordinates for the initial data.
      57              :   const size_t num_points = get_size(get<0>(x));
      58              :   std::vector<std::vector<double>> spec_grid_coords(num_points);
      59              :   for (size_t i = 0; i < num_points; ++i) {
      60              :     spec_grid_coords[i] = std::vector<double>{get_element(get<0>(x), i),
      61              :                                               get_element(get<1>(x), i),
      62              :                                               get_element(get<2>(x), i)};
      63              :   }
      64              :   // Allocate memory for the interpolation and point into it
      65              :   tuples::tagged_tuple_from_typelist<Tags> interpolation_buffer{};
      66              :   std::vector<std::vector<double*>> buffer_pointers(tmpl::size<Tags>::value);
      67              :   size_t var_i = 0;
      68              :   tmpl::for_each<Tags>([&interpolation_buffer, &buffer_pointers, &num_points,
      69              :                         &var_i](const auto tag_v) {
      70              :     using tag = tmpl::type_from<std::decay_t<decltype(tag_v)>>;
      71              :     auto& tensor = get<tag>(interpolation_buffer);
      72              :     set_number_of_grid_points(make_not_null(&tensor), num_points);
      73              :     const size_t num_components = tensor.size();
      74              :     buffer_pointers[var_i].resize(num_components);
      75              :     // The SpEC exporter supports tensors up to symmetric rank 2, which are
      76              :     // ordered xx, yx, zx, yy, zy, zz. Because this is also the order in
      77              :     // which we store components in the Tensor class, we don't have to do
      78              :     // anything special here.
      79              :     // WARNING: If the Tensor storage order changes for some reason, this
      80              :     // code needs to be updated.
      81              :     for (size_t component_i = 0; component_i < num_components; ++component_i) {
      82              : #ifdef SPECTRE_DEBUG
      83              :       const auto component_name =
      84              :           tensor.component_name(tensor.get_tensor_index(component_i));
      85              :       if constexpr (std::decay_t<decltype(tensor)>::rank() == 1) {
      86              :         const std::array<std::string, 3> spec_component_order{{"x", "y", "z"}};
      87              :         ASSERT(component_name == gsl::at(spec_component_order, component_i),
      88              :                "Unexpected Tensor component order. Expected "
      89              :                    << spec_component_order);
      90              :       } else if constexpr (std::decay_t<decltype(tensor)>::rank() == 2 and
      91              :                            std::decay_t<decltype(tensor)>::size() == 6) {
      92              :         const std::array<std::string, 6> spec_component_order{
      93              :             {"xx", "yx", "zx", "yy", "zy", "zz"}};
      94              :         ASSERT(component_name == gsl::at(spec_component_order, component_i),
      95              :                "Unexpected Tensor component order. Expected "
      96              :                    << spec_component_order);
      97              :       } else if constexpr (std::decay_t<decltype(tensor)>::rank() > 0) {
      98              :         ASSERT(
      99              :             false,
     100              :             "Unsupported Tensor type for SpEC import. Only scalars, "
     101              :             "vectors, and symmetric rank-2 tensors are currently supported.");
     102              :       }
     103              : #endif
     104              :       auto& component = tensor[component_i];
     105              :       auto& component_pointer = buffer_pointers[var_i][component_i];
     106              :       if constexpr (std::is_same_v<DataType, double>) {
     107              :         component_pointer = &component;
     108              :       } else {
     109              :         component_pointer = component.data();
     110              :       }
     111              :     }
     112              :     ++var_i;
     113              :   });
     114              :   // Interpolate!
     115              :   spec_exporter->interpolate(buffer_pointers, spec_grid_coords,
     116              :                              which_interpolator);
     117              :   return interpolation_buffer;
     118              : }
     119              : 
     120              : }  // namespace io
        

Generated by: LCOV version 2.0-1