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 <type_traits>
9 :
10 : #include "DataStructures/DataBox/PrefixHelpers.hpp"
11 : #include "DataStructures/DataBox/Tag.hpp"
12 : #include "DataStructures/Tensor/Tensor.hpp"
13 : #include "DataStructures/Variables.hpp"
14 : #include "DataStructures/VariablesTag.hpp"
15 : #include "Domain/Tags.hpp"
16 : #include "ParallelAlgorithms/Events/Tags.hpp"
17 : #include "PointwiseFunctions/AnalyticSolutions/AnalyticSolution.hpp"
18 : #include "PointwiseFunctions/AnalyticSolutions/Tags.hpp"
19 : #include "PointwiseFunctions/InitialDataUtilities/InitialData.hpp"
20 : #include "PointwiseFunctions/InitialDataUtilities/Tags/InitialData.hpp"
21 : #include "Utilities/CallWithDynamicType.hpp"
22 : #include "Utilities/Gsl.hpp"
23 : #include "Utilities/TMPL.hpp"
24 :
25 : /// \cond
26 : namespace Tags {
27 : struct Time;
28 : } // namespace Tags
29 : /// \endcond
30 :
31 : namespace evolution::Tags {
32 : /*!
33 : * \brief Computes the analytic solution and adds `::Tags::Analytic` of the
34 : * `std::optional<Tensor>`s to the DataBox.
35 : *
36 : * \note If `InitialDataList` is not an empty `tmpl::list`, then
37 : * `evolution::initial_data::Tags::InitialData` is retrieved and downcast to the
38 : * initial data for computing the errors.
39 : */
40 : template <size_t Dim, typename AnalyticFieldsTagList, bool UsingDgSubcell,
41 : typename InitialDataList = tmpl::list<>>
42 1 : struct AnalyticSolutionsCompute
43 : : ::Tags::AnalyticSolutions<AnalyticFieldsTagList>,
44 : db::ComputeTag {
45 0 : using field_tags = AnalyticFieldsTagList;
46 0 : using base = ::Tags::AnalyticSolutions<AnalyticFieldsTagList>;
47 0 : using return_type = typename base::type;
48 0 : using argument_tags =
49 : tmpl::list<evolution::initial_data::Tags::InitialData,
50 : tmpl::conditional_t<
51 : UsingDgSubcell,
52 : Events::Tags::ObserverCoordinates<Dim, Frame::Inertial>,
53 : domain::Tags::Coordinates<Dim, Frame::Inertial>>,
54 : ::Tags::Time>;
55 :
56 0 : static void function(
57 : const gsl::not_null<return_type*> analytic_solution,
58 : const evolution::initial_data::InitialData& initial_data,
59 : const tnsr::I<DataVector, Dim, Frame::Inertial>& inertial_coords,
60 : const double time) {
61 : // Unwrap wrapper types (e.g. WithNoise) to reach the underlying analytic
62 : // solution for error computation.
63 : call_with_dynamic_type<void, InitialDataList>(
64 : &initial_data.unwrap(), [&analytic_solution, &inertial_coords,
65 : time](const auto* const data_or_solution) {
66 : function(analytic_solution, *data_or_solution, inertial_coords, time);
67 : });
68 : }
69 :
70 : private:
71 : template <typename AnalyticSolution>
72 0 : static void function(
73 : const gsl::not_null<return_type*> analytic_solution,
74 : const AnalyticSolution& analytic_solution_computer,
75 : const tnsr::I<DataVector, Dim, Frame::Inertial>& inertial_coords,
76 : const double time) {
77 : if constexpr (::is_analytic_solution_v<AnalyticSolution>) {
78 : *analytic_solution =
79 : variables_from_tagged_tuple(analytic_solution_computer.variables(
80 : inertial_coords, time, AnalyticFieldsTagList{}));
81 : } else {
82 : (void)analytic_solution_computer;
83 : (void)inertial_coords;
84 : (void)time;
85 : *analytic_solution = std::nullopt;
86 : }
87 : }
88 : };
89 : } // namespace evolution::Tags
|