SpECTRE Documentation Coverage Report
Current view: top level - PointwiseFunctions/AnalyticSolutions - Tags.hpp Hit Total Coverage
Commit: aabde07399ba7837e5db64eedfd0a21f31f96922 Lines: 10 34 29.4 %
Date: 2024-04-26 02:38:13
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 <optional>
       7             : 
       8             : #include "DataStructures/DataBox/PrefixHelpers.hpp"
       9             : #include "DataStructures/DataBox/SubitemTag.hpp"
      10             : #include "DataStructures/DataBox/Subitems.hpp"
      11             : #include "DataStructures/DataBox/Tag.hpp"
      12             : #include "DataStructures/Variables.hpp"
      13             : #include "Options/String.hpp"
      14             : #include "PointwiseFunctions/AnalyticData/Tags.hpp"
      15             : #include "PointwiseFunctions/AnalyticSolutions/AnalyticSolution.hpp"
      16             : #include "Utilities/PrettyType.hpp"
      17             : #include "Utilities/Serialization/Serialize.hpp"
      18             : #include "Utilities/TMPL.hpp"
      19             : 
      20             : namespace OptionTags {
      21             : /// \ingroup OptionGroupsGroup
      22             : /// Holds the `OptionTags::AnalyticSolution` option in the input file
      23           1 : struct AnalyticSolutionGroup {
      24           0 :   static std::string name() { return "AnalyticSolution"; }
      25           0 :   static constexpr Options::String help =
      26             :       "Analytic solution used for the initial data and errors";
      27             : };
      28             : 
      29             : /// \ingroup OptionTagsGroup
      30             : /// The analytic solution, with the type of the analytic solution set as the
      31             : /// template parameter
      32             : template <typename SolutionType>
      33           1 : struct AnalyticSolution {
      34           0 :   static std::string name() { return pretty_type::name<SolutionType>(); }
      35           0 :   static constexpr Options::String help = "Options for the analytic solution";
      36           0 :   using type = SolutionType;
      37           0 :   using group = AnalyticSolutionGroup;
      38             : };
      39             : }  // namespace OptionTags
      40             : 
      41             : namespace Tags {
      42             : /// Can be used to retrieve the analytic solution from the cache without having
      43             : /// to know the template parameters of AnalyticSolution.
      44           1 : struct AnalyticSolutionBase : AnalyticSolutionOrData {};
      45             : 
      46             : /// \ingroup OptionTagsGroup
      47             : /// The analytic solution, with the type of the analytic solution set as the
      48             : /// template parameter
      49             : template <typename SolutionType>
      50           1 : struct AnalyticSolution : AnalyticSolutionBase, db::SimpleTag {
      51           0 :   using type = SolutionType;
      52           0 :   using option_tags = tmpl::list<::OptionTags::AnalyticSolution<SolutionType>>;
      53             : 
      54           0 :   static constexpr bool pass_metavariables = false;
      55           0 :   static SolutionType create_from_options(
      56             :       const SolutionType& analytic_solution) {
      57             :     return deserialize<type>(serialize<type>(analytic_solution).data());
      58             :   }
      59             : };
      60             : 
      61             : /// \ingroup DataBoxTagsGroup
      62             : /// \brief Prefix indicating the analytic solution value for a quantity
      63             : ///
      64             : /// \snippet AnalyticSolutions/Test_Tags.cpp analytic_name
      65             : template <typename Tag>
      66           1 : struct Analytic : db::PrefixTag, db::SimpleTag {
      67           0 :   using type = std::optional<typename Tag::type>;
      68           0 :   using tag = Tag;
      69             : };
      70             : 
      71             : /// Base tag for the analytic solution tensors.
      72             : ///
      73             : /// \see ::Tags::AnalyticSolutions
      74           1 : struct AnalyticSolutionsBase : db::BaseTag {};
      75             : 
      76             : namespace detail {
      77             : template <typename Tag>
      78             : struct AnalyticImpl : db::PrefixTag, db::SimpleTag {
      79             :   using type = typename Tag::type;
      80             :   using tag = Tag;
      81             : };
      82             : }  // namespace detail
      83             : 
      84             : /*!
      85             :  * \brief The analytic solution of the `FieldTags`.
      86             :  *
      87             :  * The `std::optional` is a `nullopt` if there is no analytic solution.
      88             :  *
      89             :  * The individual `FieldTags` are added as `Tags::Analytic<Tag>` which holds a
      90             :  * `std::optional<Tensor>`.
      91             :  */
      92             : template <typename FieldTags>
      93           1 : struct AnalyticSolutions : ::Tags::AnalyticSolutionsBase, db::SimpleTag {
      94           0 :   using field_tags = FieldTags;
      95           0 :   using type = std::optional<
      96             :       ::Variables<db::wrap_tags_in<detail::AnalyticImpl, FieldTags>>>;
      97             : };
      98             : 
      99             : namespace detail {
     100             : // Check if the argument is a `::Tags::AnalyticSolutions` template, or derived
     101             : // from it
     102             : template <typename FieldTags>
     103             : constexpr std::true_type is_analytic_solutions(
     104             :     ::Tags::AnalyticSolutions<FieldTags>&&) {
     105             :   return {};
     106             : }
     107             : 
     108             : constexpr std::false_type is_analytic_solutions(...) { return {}; }
     109             : 
     110             : template <typename Tag>
     111             : static constexpr bool is_analytic_solutions_v =
     112             :     decltype(is_analytic_solutions(std::declval<Tag>()))::value;
     113             : }  // namespace detail
     114             : 
     115             : /*!
     116             :  * \brief The error of the `Tag` defined as `numerical - analytic`.
     117             :  *
     118             :  * The `std::optional` is a `nullopt` if no error was able to be computed, e.g.
     119             :  * if there is no analytic solution to compare to.
     120             :  */
     121             : template <typename Tag>
     122           1 : struct Error : db::PrefixTag, db::SimpleTag {
     123           0 :   using type = std::optional<typename Tag::type>;
     124           0 :   using tag = Tag;
     125             : };
     126             : 
     127             : namespace detail {
     128             : template <typename Tag>
     129             : struct ErrorImpl : db::PrefixTag, db::SimpleTag {
     130             :   using type = typename Tag::type;
     131             :   using tag = Tag;
     132             : };
     133             : }  // namespace detail
     134             : 
     135             : /*!
     136             :  * \brief The error of the `FieldTags`, defined as `numerical - analytic`.
     137             :  *
     138             :  * The `std::optional` is a `nullopt` if no error was able to be computed, e.g.
     139             :  * if there is no analytic solution to compare to.
     140             :  *
     141             :  * The individual `FieldTags` are added as `Tags::Error<Tag>` which holds a
     142             :  * `std::optional<Tensor>`.
     143             :  */
     144             : template <typename FieldTags>
     145           1 : struct Errors : db::SimpleTag {
     146           0 :   using field_tags = FieldTags;
     147           0 :   using type = std::optional<
     148             :       ::Variables<db::wrap_tags_in<detail::ErrorImpl, FieldTags>>>;
     149             : };
     150             : 
     151             : /// \cond
     152             : template <typename FieldTagsList>
     153             : struct ErrorsCompute;
     154             : /// \endcond
     155             : 
     156             : /*!
     157             :  * \brief Compute tag for computing the error from the `Tags::Analytic` of the
     158             :  * `FieldTags`.
     159             :  *
     160             :  * The error is defined as `numerical - analytic`.
     161             :  *
     162             :  * We use individual `Tensor`s rather than `Variables` of the `FieldTags`
     163             :  * because not all `FieldTags` are always stored in the same `Variables`.
     164             :  * For example, in the Generalized Harmonic-GRMHD combined system, the analytic
     165             :  * variables for the GH system are part of the `evolved_variables_tag` while the
     166             :  * GRMHD analytic variables are part of the `primitive_variables_tag`. A similar
     167             :  * issue arises in some elliptic systems. The main drawback of having to use the
     168             :  * tensor-by-tensor implementation instead of a `Variables` implementation is
     169             :  * the added loop complexity. However, this is offset by the reduced code
     170             :  * duplication and flexibility.
     171             :  */
     172             : template <typename... FieldTags>
     173           1 : struct ErrorsCompute<tmpl::list<FieldTags...>>
     174             :     : Errors<tmpl::list<FieldTags...>>, db::ComputeTag {
     175           0 :   using field_tags = tmpl::list<FieldTags...>;
     176           0 :   using base = Errors<tmpl::list<FieldTags...>>;
     177           0 :   using return_type = typename base::type;
     178           0 :   using argument_tags =
     179             :       tmpl::list<FieldTags..., ::Tags::Analytic<FieldTags>...>;
     180           0 :   static void function(
     181             :       const gsl::not_null<return_type*> errors,
     182             :       const typename FieldTags::type&... vars,
     183             :       const typename ::Tags::Analytic<FieldTags>::type&... analytic_vars) {
     184             :     if (const auto& first_analytic_var = get_first_argument(analytic_vars...);
     185             :         first_analytic_var.has_value()) {
     186             :       // Construct a Variables of the size of the DataVector of the first
     187             :       // analytic_vars tensor.
     188             :       *errors = typename return_type::value_type{
     189             :           first_analytic_var.value()[0].size()};
     190             :       const auto compute_error = [](const auto error_ptr, const auto& var,
     191             :                                     const auto& analytic_var) {
     192             :         for (size_t tensor_index = 0; tensor_index < var.size();
     193             :              ++tensor_index) {
     194             :           (*error_ptr)[tensor_index] =
     195             :               var[tensor_index] - analytic_var[tensor_index];
     196             :         }
     197             :       };
     198             :       EXPAND_PACK_LEFT_TO_RIGHT(compute_error(
     199             :           make_not_null(
     200             :               &get<::Tags::detail::ErrorImpl<FieldTags>>(errors->value())),
     201             :           vars, analytic_vars.value()));
     202             :     } else {
     203             :       *errors = std::nullopt;
     204             :     }
     205             :   }
     206             : };
     207             : 
     208             : namespace detail {
     209             : // Check if the argument is a `::Tags::Errors` template, or derived
     210             : // from it
     211             : template <typename FieldTags>
     212             : constexpr std::true_type is_errors(::Tags::Errors<FieldTags>&&) {
     213             :   return {};
     214             : }
     215             : 
     216             : constexpr std::false_type is_errors(...) { return {}; }
     217             : 
     218             : template <typename Tag>
     219             : static constexpr bool is_errors_v =
     220             :     decltype(is_errors(std::declval<Tag>()))::value;
     221             : }  // namespace detail
     222             : }  // namespace Tags
     223             : 
     224             : /// \cond
     225             : namespace Tags {
     226             : template <typename Tag, typename ParentTag>
     227             : struct Subitem<Tag, ParentTag,
     228             :                Requires<detail::is_analytic_solutions_v<ParentTag>>>
     229             :     : Tag, db::ComputeTag {
     230             :   using field_tags = typename ParentTag::field_tags;
     231             :   using base = Tag;
     232             :   using parent_tag = AnalyticSolutions<field_tags>;
     233             :   using argument_tags = tmpl::list<parent_tag>;
     234             :   static void function(const gsl::not_null<typename base::type*> result,
     235             :                        const typename parent_tag::type& vars) {
     236             :     if (vars.has_value()) {
     237             :       result->reset();
     238             :       *result = typename base::type::value_type{};
     239             :       const auto& tensor =
     240             :           get<typename detail::AnalyticImpl<typename Tag::tag>>(*vars);
     241             :       const size_t num_components = tensor.size();
     242             :       for (size_t storage_index = 0; storage_index < num_components;
     243             :            ++storage_index) {
     244             :         (**result)[storage_index].set_data_ref(
     245             :             make_not_null(&const_cast<DataVector&>(tensor[storage_index])));
     246             :       }
     247             :     } else {
     248             :       *result = std::nullopt;
     249             :     }
     250             :   }
     251             : };
     252             : 
     253             : template <typename Tag, typename ParentTag>
     254             : struct Subitem<Tag, ParentTag, Requires<detail::is_errors_v<ParentTag>>>
     255             :     : Tag, db::ComputeTag {
     256             :   using field_tags = typename ParentTag::field_tags;
     257             :   using base = Tag;
     258             :   using parent_tag = Errors<field_tags>;
     259             :   using argument_tags = tmpl::list<parent_tag>;
     260             :   static void function(const gsl::not_null<typename base::type*> result,
     261             :                        const typename parent_tag::type& vars) {
     262             :     if (vars.has_value()) {
     263             :       result->reset();
     264             :       *result = typename base::type::value_type{};
     265             :       const auto& tensor =
     266             :           get<typename detail::ErrorImpl<typename Tag::tag>>(*vars);
     267             :       const size_t num_components = tensor.size();
     268             :       for (size_t storage_index = 0; storage_index < num_components;
     269             :            ++storage_index) {
     270             :         (**result)[storage_index].set_data_ref(
     271             :             make_not_null(&const_cast<DataVector&>(tensor[storage_index])));
     272             :       }
     273             :     } else {
     274             :       *result = std::nullopt;
     275             :     }
     276             :   }
     277             : };
     278             : }  // namespace Tags
     279             : 
     280             : namespace db {
     281             : template <typename Tag>
     282             : struct Subitems<Tag, Requires<Tags::detail::is_analytic_solutions_v<Tag>>> {
     283             :   using field_tags = typename Tag::field_tags;
     284             :   using type = db::wrap_tags_in<::Tags::Analytic, field_tags>;
     285             : 
     286             :   template <typename Subtag>
     287             :   static void create_item(
     288             :       const gsl::not_null<typename Tag::type*> parent_value,
     289             :       const gsl::not_null<typename Subtag::type*> sub_value) {
     290             :     if (parent_value->has_value()) {
     291             :       auto& tensor = get<::Tags::detail::AnalyticImpl<typename Subtag::tag>>(
     292             :           parent_value->value());
     293             :       sub_value->emplace();
     294             :       // Only update the Tensor if the Variables has changed its allocation
     295             :       if constexpr (not is_any_spin_weighted_v<
     296             :                         typename Subtag::tag::type::type>) {
     297             :         if (tensor.begin()->data() != sub_value->value().begin()->data()) {
     298             :           for (auto tensor_component = tensor.begin(),
     299             :                     sub_var_it = sub_value->value().begin();
     300             :                tensor_component != tensor.end();
     301             :                ++tensor_component, ++sub_var_it) {
     302             :             sub_var_it->set_data_ref(make_not_null(&*tensor_component));
     303             :           }
     304             :         }
     305             :       } else {
     306             :         if (tensor.begin()->data().data() !=
     307             :             sub_value->value().begin()->data().data()) {
     308             :           for (auto tensor_component = tensor.begin(),
     309             :                     sub_var_it = sub_value->value().begin();
     310             :                tensor_component != tensor.end();
     311             :                ++tensor_component, ++sub_var_it) {
     312             :             sub_var_it->set_data_ref(make_not_null(&*tensor_component));
     313             :           }
     314             :         }
     315             :       }
     316             :     } else {
     317             :       *sub_value = std::nullopt;
     318             :     }
     319             :   }
     320             : };
     321             : 
     322             : template <typename Tag>
     323             : struct Subitems<Tag, Requires<Tags::detail::is_errors_v<Tag>>> {
     324             :   using field_tags = typename Tag::field_tags;
     325             :   using type = db::wrap_tags_in<::Tags::Error, field_tags>;
     326             : 
     327             :   template <typename Subtag>
     328             :   static void create_item(
     329             :       const gsl::not_null<typename Tag::type*> parent_value,
     330             :       const gsl::not_null<typename Subtag::type*> sub_value) {
     331             :     if (parent_value->has_value()) {
     332             :       auto& tensor = get<::Tags::detail::ErrorImpl<typename Subtag::tag>>(
     333             :           parent_value->value());
     334             :       *sub_value = std::decay_t<decltype(tensor)>{};
     335             :       // Only update the Tensor if the Variables has changed its allocation
     336             :       if constexpr (not is_any_spin_weighted_v<
     337             :                         typename Subtag::tag::type::type>) {
     338             :         if (tensor.begin()->data() != sub_value->value().begin()->data()) {
     339             :           for (auto tensor_component = tensor.begin(),
     340             :                     sub_var_it = sub_value->value().begin();
     341             :                tensor_component != tensor.end();
     342             :                ++tensor_component, ++sub_var_it) {
     343             :             sub_var_it->set_data_ref(make_not_null(&*tensor_component));
     344             :           }
     345             :         }
     346             :       } else {
     347             :         if (tensor.begin()->data().data() !=
     348             :             sub_value->value().begin()->data().data()) {
     349             :           for (auto tensor_component = tensor.begin(),
     350             :                     sub_var_it = sub_value->value().begin();
     351             :                tensor_component != tensor.end();
     352             :                ++tensor_component, ++sub_var_it) {
     353             :             sub_var_it->set_data_ref(make_not_null(&*tensor_component));
     354             :           }
     355             :         }
     356             :       }
     357             :     } else {
     358             :       *sub_value = std::nullopt;
     359             :     }
     360             :   }
     361             : };
     362             : }  // namespace db
     363             : /// \endcond

Generated by: LCOV version 1.14