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 <tuple> 9 : #include <utility> 10 : 11 : #include "DataStructures/DataBox/DataBox.hpp" 12 : #include "DataStructures/DataBox/MetavariablesTag.hpp" 13 : #include "DataStructures/DataBox/PrefixHelpers.hpp" 14 : #include "DataStructures/DataBox/Prefixes.hpp" 15 : #include "DataStructures/TaggedTuple.hpp" 16 : #include "DataStructures/Tensor/Tensor.hpp" 17 : #include "DataStructures/Variables.hpp" 18 : #include "Domain/Structure/ElementId.hpp" 19 : #include "Domain/Tags.hpp" 20 : #include "Parallel/AlgorithmExecution.hpp" 21 : #include "Parallel/GlobalCache.hpp" 22 : #include "ParallelAlgorithms/Amr/Protocols/Projector.hpp" 23 : #include "ParallelAlgorithms/Initialization/MutateAssign.hpp" 24 : #include "PointwiseFunctions/AnalyticSolutions/Tags.hpp" 25 : #include "Utilities/CallWithDynamicType.hpp" 26 : #include "Utilities/TMPL.hpp" 27 : 28 : /// \cond 29 : namespace Frame { 30 : struct Inertial; 31 : } // namespace Frame 32 : /// \endcond 33 : 34 0 : namespace elliptic::Actions { 35 : /// @{ 36 : /*! 37 : * \brief Place the analytic solution of the system fields in the DataBox. 38 : * 39 : * The `::Tags::AnalyticSolutions` tag retrieved from the DataBox will hold 40 : * a `std::optional`. The analytic solution is only evaluated and stored in the 41 : * DataBox if the `BackgroundTag` holds a type that inherits from the 42 : * `AnalyticSolutionType`. 43 : * 44 : * Uses: 45 : * - DataBox: 46 : * - `AnalyticSolutionTag` or `BackgroundTag` 47 : * - `domain::Tags::Mesh<Dim>` 48 : * - `Tags::Coordinates<Dim, Frame::Inertial>` 49 : * - `domain::Tags::InverseJacobian<Dim, Frame::ElementLogical, 50 : * Frame::Inertial>` 51 : * 52 : * DataBox: 53 : * - Adds: 54 : * - `::Tags::AnalyticSolutions<AnalyticSolutionFields>` 55 : */ 56 : template <size_t Dim, typename BackgroundTag, typename AnalyticSolutionFields, 57 : typename AnalyticSolutionType> 58 1 : struct InitializeOptionalAnalyticSolution 59 : : tt::ConformsTo<::amr::protocols::Projector> { 60 : private: 61 0 : using analytic_fields_tag = ::Tags::AnalyticSolutions<AnalyticSolutionFields>; 62 : 63 : public: // Iterable action 64 0 : using simple_tags = tmpl::list<analytic_fields_tag>; 65 0 : using compute_tags = tmpl::list<>; 66 0 : using const_global_cache_tags = tmpl::list<BackgroundTag>; 67 : 68 : template <typename DbTagsList, typename... InboxTags, typename Metavariables, 69 : typename ActionList, typename ParallelComponent> 70 0 : static Parallel::iterable_action_return_t apply( 71 : db::DataBox<DbTagsList>& box, 72 : const tuples::TaggedTuple<InboxTags...>& /*inboxes*/, 73 : const Parallel::GlobalCache<Metavariables>& /*cache*/, 74 : const ElementId<Dim>& /*array_index*/, const ActionList /*meta*/, 75 : const ParallelComponent* const /*meta*/) { 76 : db::mutate_apply<InitializeOptionalAnalyticSolution>(make_not_null(&box)); 77 : return {Parallel::AlgorithmExecution::Continue, std::nullopt}; 78 : } 79 : 80 : public: // DataBox mutator, amr::protocols::Projector 81 0 : using return_tags = tmpl::list<analytic_fields_tag>; 82 0 : using argument_tags = 83 : tmpl::list<domain::Tags::Mesh<Dim>, 84 : domain::Tags::Coordinates<Dim, Frame::Inertial>, 85 : domain::Tags::InverseJacobian<Dim, Frame::ElementLogical, 86 : Frame::Inertial>, 87 : BackgroundTag, Parallel::Tags::Metavariables>; 88 : 89 : template <typename Background, typename Metavariables, typename... AmrData> 90 0 : static void apply( 91 : const gsl::not_null<typename analytic_fields_tag::type*> 92 : analytic_solution_fields, 93 : const Mesh<Dim>& mesh, const tnsr::I<DataVector, Dim> inertial_coords, 94 : const InverseJacobian<DataVector, Dim, Frame::ElementLogical, 95 : Frame::Inertial>& inv_jacobian, 96 : const Background& background, const Metavariables& /*meta*/, 97 : const AmrData&... amr_data) { 98 : if constexpr (sizeof...(AmrData) == 1) { 99 : if constexpr (std::is_same_v<AmrData..., 100 : std::pair<Mesh<Dim>, Element<Dim>>>) { 101 : if (((mesh == amr_data.first) and ...)) { 102 : // This element hasn't changed during AMR. Nothing to do. 103 : return; 104 : } 105 : } 106 : } 107 : 108 : const auto analytic_solution = 109 : dynamic_cast<const AnalyticSolutionType*>(&background); 110 : if (analytic_solution != nullptr) { 111 : using factory_classes = typename std::decay_t< 112 : Metavariables>::factory_creation::factory_classes; 113 : *analytic_solution_fields = call_with_dynamic_type< 114 : Variables<AnalyticSolutionFields>, 115 : tmpl::at<factory_classes, AnalyticSolutionType>>( 116 : analytic_solution, 117 : [&inertial_coords, &mesh, &inv_jacobian](const auto* const derived) { 118 : return variables_from_tagged_tuple(derived->variables( 119 : inertial_coords, mesh, inv_jacobian, AnalyticSolutionFields{})); 120 : }); 121 : } else { 122 : *analytic_solution_fields = std::nullopt; 123 : } 124 : } 125 : }; 126 : /// @} 127 : } // namespace elliptic::Actions