SpECTRE Documentation Coverage Report
Current view: top level - ParallelAlgorithms/Events - ObserveFields.hpp Hit Total Coverage
Commit: d07bc7e978f0161d6eb259d687cd7878b5f9f6f0 Lines: 2 25 8.0 %
Date: 2020-09-24 02:51:00
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 <initializer_list>
       8             : #include <pup.h>
       9             : #include <string>
      10             : #include <type_traits>
      11             : #include <unordered_set>
      12             : #include <utility>
      13             : #include <vector>
      14             : 
      15             : #include "DataStructures/DataBox/Prefixes.hpp"
      16             : #include "DataStructures/DataBox/TagName.hpp"
      17             : #include "DataStructures/DataVector.hpp"
      18             : #include "DataStructures/Tensor/TensorData.hpp"
      19             : #include "Domain/Structure/ElementId.hpp"
      20             : #include "Domain/Tags.hpp"
      21             : #include "IO/Observer/ArrayComponentId.hpp"
      22             : #include "IO/Observer/ObservationId.hpp"
      23             : #include "IO/Observer/ObserverComponent.hpp"  // IWYU pragma: keep
      24             : #include "IO/Observer/VolumeActions.hpp"      // IWYU pragma: keep
      25             : #include "Options/Options.hpp"
      26             : #include "Parallel/ArrayIndex.hpp"
      27             : #include "Parallel/CharmPupable.hpp"
      28             : #include "Parallel/GlobalCache.hpp"
      29             : #include "Parallel/Invoke.hpp"
      30             : #include "ParallelAlgorithms/EventsAndTriggers/Event.hpp"
      31             : #include "PointwiseFunctions/AnalyticSolutions/Tags.hpp"
      32             : #include "Utilities/Algorithm.hpp"
      33             : #include "Utilities/Literals.hpp"
      34             : #include "Utilities/MakeString.hpp"
      35             : #include "Utilities/Numeric.hpp"
      36             : #include "Utilities/Registration.hpp"
      37             : #include "Utilities/StdHelpers.hpp"
      38             : #include "Utilities/TMPL.hpp"
      39             : 
      40             : /// \cond
      41             : template <size_t Dim>
      42             : class Mesh;
      43             : namespace Frame {
      44             : struct Inertial;
      45             : }  // namespace Frame
      46             : namespace Tags {
      47             : struct Time;
      48             : }  // namespace Tags
      49             : /// \endcond
      50             : 
      51             : namespace dg {
      52             : namespace Events {
      53             : template <size_t VolumeDim, typename ObservationValueTag, typename Tensors,
      54             :           typename AnalyticSolutionTensors, typename EventRegistrars,
      55             :           typename NonSolutionTensors =
      56             :               tmpl::list_difference<Tensors, AnalyticSolutionTensors>>
      57           0 : class ObserveFields;
      58             : 
      59             : namespace Registrars {
      60             : template <size_t VolumeDim, typename ObservationValueTag, typename Tensors,
      61             :           typename AnalyticSolutionTensors = tmpl::list<>>
      62           0 : struct ObserveFields {
      63             :   template <typename RegistrarList>
      64           0 :   using f = Events::ObserveFields<VolumeDim, ObservationValueTag, Tensors,
      65             :                                   AnalyticSolutionTensors, RegistrarList>;
      66             : };
      67             : }  // namespace Registrars
      68             : 
      69             : template <
      70             :     size_t VolumeDim, typename ObservationValueTag, typename Tensors,
      71             :     typename AnalyticSolutionTensors = tmpl::list<>,
      72             :     typename EventRegistrars = tmpl::list<Registrars::ObserveFields<
      73             :         VolumeDim, ObservationValueTag, Tensors, AnalyticSolutionTensors>>,
      74             :     typename NonSolutionTensors>
      75             : class ObserveFields;  // IWYU pragma: keep
      76             : 
      77             : /*!
      78             :  * \ingroup DiscontinuousGalerkinGroup
      79             :  * \brief %Observe volume tensor fields.
      80             :  *
      81             :  * Writes volume quantities:
      82             :  * - `InertialCoordinates`
      83             :  * - Tensors listed in `Tensors` template parameter
      84             :  * - `Error(*)` = errors in `AnalyticSolutionTensors` =
      85             :  *   \f$\text{value} - \text{analytic solution}\f$
      86             :  */
      87             : template <size_t VolumeDim, typename ObservationValueTag, typename... Tensors,
      88             :           typename... AnalyticSolutionTensors, typename EventRegistrars,
      89             :           typename... NonSolutionTensors>
      90             : class ObserveFields<VolumeDim, ObservationValueTag, tmpl::list<Tensors...>,
      91             :                     tmpl::list<AnalyticSolutionTensors...>, EventRegistrars,
      92             :                     tmpl::list<NonSolutionTensors...>>
      93           1 :     : public Event<EventRegistrars> {
      94             :  private:
      95             :   static_assert(
      96             :       std::is_same_v<
      97             :           tmpl::list_difference<tmpl::list<AnalyticSolutionTensors...>,
      98             :                                 tmpl::list<Tensors...>>,
      99             :           tmpl::list<>>,
     100             :       "All AnalyticSolutionTensors must be listed in Tensors.");
     101           0 :   using coordinates_tag = domain::Tags::Coordinates<VolumeDim, Frame::Inertial>;
     102             : 
     103             :  public:
     104             :   /// The name of the subfile inside the HDF5 file
     105           1 :   struct SubfileName {
     106           0 :     using type = std::string;
     107           0 :     static constexpr Options::String help = {
     108             :         "The name of the subfile inside the HDF5 file without an extension and "
     109             :         "without a preceding '/'."};
     110             :   };
     111             : 
     112             :   /// \cond
     113             :   explicit ObserveFields(CkMigrateMessage* /*unused*/) noexcept {}
     114             :   using PUP::able::register_constructor;
     115             :   WRAPPED_PUPable_decl_template(ObserveFields);  // NOLINT
     116             :   /// \endcond
     117             : 
     118           0 :   struct VariablesToObserve {
     119           0 :     static constexpr Options::String help = "Subset of variables to observe";
     120           0 :     using type = std::vector<std::string>;
     121           0 :     static type default_value() noexcept {
     122             :       return {db::tag_name<Tensors>()...};
     123             :     }
     124           0 :     static size_t lower_bound_on_size() noexcept { return 1; }
     125             :   };
     126             : 
     127           0 :   using options = tmpl::list<SubfileName, VariablesToObserve>;
     128           0 :   static constexpr Options::String help =
     129             :       "Observe volume tensor fields.\n"
     130             :       "\n"
     131             :       "Writes volume quantities:\n"
     132             :       " * InertialCoordinates\n"
     133             :       " * Tensors listed in Tensors template parameter\n"
     134             :       " * Error(*) = errors in AnalyticSolutionTensors\n"
     135             :       "            = value - analytic solution\n"
     136             :       "\n"
     137             :       "Warning: Currently, only one volume observation event can be\n"
     138             :       "triggered at a given time.  Causing multiple events to run at once\n"
     139             :       "will produce unpredictable results.";
     140             : 
     141           0 :   ObserveFields() = default;
     142             : 
     143           0 :   explicit ObserveFields(const std::string& subfile_name,
     144             :                          const std::vector<std::string>& variables_to_observe =
     145             :                              VariablesToObserve::default_value(),
     146             :                          const Options::Context& context = {})
     147             :       : subfile_path_("/" + subfile_name),
     148             :         variables_to_observe_(variables_to_observe.begin(),
     149             :                               variables_to_observe.end()) {
     150             :     using ::operator<<;
     151             :     const std::unordered_set<std::string> valid_tensors{
     152             :         db::tag_name<Tensors>()...};
     153             :     for (const auto& name : variables_to_observe_) {
     154             :       if (valid_tensors.count(name) != 1) {
     155             :         PARSE_ERROR(
     156             :             context,
     157             :             name << " is not an available variable.  Available variables:\n"
     158             :                  << (std::vector<std::string>{db::tag_name<Tensors>()...}));
     159             :       }
     160             :       if (alg::count(variables_to_observe, name) != 1) {
     161             :         PARSE_ERROR(context, name << " specified multiple times");
     162             :       }
     163             :     }
     164             :     variables_to_observe_.insert(coordinates_tag::name());
     165             :   }
     166             : 
     167           0 :   using argument_tags =
     168             :       tmpl::list<ObservationValueTag, domain::Tags::Mesh<VolumeDim>,
     169             :                  coordinates_tag, AnalyticSolutionTensors...,
     170             :                  ::Tags::Analytic<AnalyticSolutionTensors>...,
     171             :                  NonSolutionTensors...>;
     172             : 
     173             :   template <typename Metavariables, typename ParallelComponent>
     174           0 :   void operator()(
     175             :       const typename ObservationValueTag::type& observation_value,
     176             :       const Mesh<VolumeDim>& mesh,
     177             :       const tnsr::I<DataVector, VolumeDim, Frame::Inertial>&
     178             :           inertial_coordinates,
     179             :       const typename AnalyticSolutionTensors::
     180             :           type&... analytic_solution_tensors,
     181             :       const typename ::Tags::Analytic<
     182             :           AnalyticSolutionTensors>::type&... analytic_solutions,
     183             :       const typename NonSolutionTensors::type&... non_solution_tensors,
     184             :       Parallel::GlobalCache<Metavariables>& cache,
     185             :       const ElementId<VolumeDim>& array_index,
     186             :       const ParallelComponent* const /*meta*/) const noexcept {
     187             :     const std::string element_name =
     188             :         MakeString{} << ElementId<VolumeDim>(array_index) << '/';
     189             : 
     190             :     // Remove tensor types, only storing individual components.
     191             :     std::vector<TensorComponent> components;
     192             :     // This is larger than we need if we are only observing some
     193             :     // tensors, but that's not a big deal and calculating the correct
     194             :     // size is nontrivial.
     195             :     components.reserve(alg::accumulate(
     196             :         std::initializer_list<size_t>{
     197             :             inertial_coordinates.size(),
     198             :             2 * AnalyticSolutionTensors::type::size()...,
     199             :             NonSolutionTensors::type::size()...},
     200             :         0_st));
     201             : 
     202             :     const auto record_tensor_components = [ this, &components, &element_name ](
     203             :         const auto tensor_tag_v, const auto& tensor) noexcept {
     204             :       using tensor_tag = tmpl::type_from<decltype(tensor_tag_v)>;
     205             :       if (variables_to_observe_.count(db::tag_name<tensor_tag>()) == 1) {
     206             :         for (size_t i = 0; i < tensor.size(); ++i) {
     207             :           components.emplace_back(element_name + db::tag_name<tensor_tag>() +
     208             :                                       tensor.component_suffix(i),
     209             :                                   tensor[i]);
     210             :         }
     211             :       }
     212             :     };
     213             :     record_tensor_components(tmpl::type_<coordinates_tag>{},
     214             :                              inertial_coordinates);
     215             :     EXPAND_PACK_LEFT_TO_RIGHT(record_tensor_components(
     216             :         tmpl::type_<AnalyticSolutionTensors>{}, analytic_solution_tensors));
     217             :     EXPAND_PACK_LEFT_TO_RIGHT(record_tensor_components(
     218             :         tmpl::type_<NonSolutionTensors>{}, non_solution_tensors));
     219             : 
     220             :     const auto record_errors = [ this, &components, &element_name ](
     221             :         const auto tensor_tag_v, const auto& tensor,
     222             :         const auto& analytic_tensor) noexcept {
     223             :       using tensor_tag = tmpl::type_from<decltype(tensor_tag_v)>;
     224             :       if (variables_to_observe_.count(db::tag_name<tensor_tag>()) == 1) {
     225             :         for (size_t i = 0; i < tensor.size(); ++i) {
     226             :           DataVector error = tensor[i] - analytic_tensor[i];
     227             :           components.emplace_back(element_name + "Error(" +
     228             :                                       db::tag_name<tensor_tag>() + ")" +
     229             :                                       tensor.component_suffix(i),
     230             :                                   std::move(error));
     231             :         }
     232             :       }
     233             :     };
     234             :     EXPAND_PACK_LEFT_TO_RIGHT(
     235             :         record_errors(tmpl::type_<AnalyticSolutionTensors>{},
     236             :                       analytic_solution_tensors, analytic_solutions));
     237             : 
     238             :     (void)(record_errors);  // Silence GCC warning about unused variable
     239             : 
     240             :     // Send data to volume observer
     241             :     auto& local_observer =
     242             :         *Parallel::get_parallel_component<observers::Observer<Metavariables>>(
     243             :              cache)
     244             :              .ckLocalBranch();
     245             :     Parallel::simple_action<observers::Actions::ContributeVolumeData>(
     246             :         local_observer,
     247             :         observers::ObservationId(observation_value, subfile_path_ + ".vol"),
     248             :         subfile_path_,
     249             :         observers::ArrayComponentId(
     250             :             std::add_pointer_t<ParallelComponent>{nullptr},
     251             :             Parallel::ArrayIndex<ElementId<VolumeDim>>(array_index)),
     252             :         std::move(components), mesh.extents(), mesh.basis(),
     253             :         mesh.quadrature());
     254             :   }
     255             : 
     256           0 :   using observation_registration_tags = tmpl::list<>;
     257             :   std::pair<observers::TypeOfObservation, observers::ObservationKey>
     258           0 :   get_observation_type_and_key_for_registration() const noexcept {
     259             :     return {observers::TypeOfObservation::Volume,
     260             :             observers::ObservationKey(subfile_path_ + ".vol")};
     261             :   }
     262             : 
     263             :   // NOLINTNEXTLINE(google-runtime-references)
     264           0 :   void pup(PUP::er& p) noexcept override {
     265             :     Event<EventRegistrars>::pup(p);
     266             :     p | subfile_path_;
     267             :     p | variables_to_observe_;
     268             :   }
     269             : 
     270             :  private:
     271           0 :   std::string subfile_path_;
     272           0 :   std::unordered_set<std::string> variables_to_observe_{};
     273             : };
     274             : 
     275             : /// \cond
     276             : template <size_t VolumeDim, typename ObservationValueTag, typename... Tensors,
     277             :           typename... AnalyticSolutionTensors, typename EventRegistrars,
     278             :           typename... NonSolutionTensors>
     279             : PUP::able::PUP_ID
     280             :     ObserveFields<VolumeDim, ObservationValueTag, tmpl::list<Tensors...>,
     281             :                   tmpl::list<AnalyticSolutionTensors...>, EventRegistrars,
     282             :                   tmpl::list<NonSolutionTensors...>>::my_PUP_ID = 0;  // NOLINT
     283             : /// \endcond
     284             : }  // namespace Events
     285             : }  // namespace dg

Generated by: LCOV version 1.14