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 : 10 : #include "DataStructures/DataBox/DataBox.hpp" 11 : #include "DataStructures/DataBox/PrefixHelpers.hpp" 12 : #include "DataStructures/DataBox/Prefixes.hpp" 13 : #include "DataStructures/DataVector.hpp" 14 : #include "DataStructures/Tensor/Slice.hpp" 15 : #include "DataStructures/Tensor/Tensor.hpp" 16 : #include "DataStructures/Variables.hpp" 17 : #include "Domain/Structure/Direction.hpp" 18 : #include "Domain/Structure/IndexToSliceAt.hpp" 19 : #include "Domain/Tags.hpp" 20 : #include "Evolution/Systems/CurvedScalarWave/System.hpp" 21 : #include "Evolution/Systems/CurvedScalarWave/Tags.hpp" 22 : #include "Evolution/Systems/CurvedScalarWave/Worldtube/Inboxes.hpp" 23 : #include "Evolution/Systems/CurvedScalarWave/Worldtube/PunctureField.hpp" 24 : #include "Evolution/Systems/CurvedScalarWave/Worldtube/Tags.hpp" 25 : #include "NumericalAlgorithms/LinearOperators/PartialDerivatives.hpp" 26 : #include "NumericalAlgorithms/Spectral/Mesh.hpp" 27 : #include "Parallel/AlgorithmExecution.hpp" 28 : #include "Parallel/AlgorithmMetafunctions.hpp" 29 : #include "Parallel/GlobalCache.hpp" 30 : #include "Parallel/Invoke.hpp" 31 : #include "PointwiseFunctions/GeneralRelativity/Tags.hpp" 32 : #include "Time/Tags/TimeStepId.hpp" 33 : #include "Utilities/Gsl.hpp" 34 : #include "Utilities/TMPL.hpp" 35 : 36 : namespace CurvedScalarWave::Worldtube::Actions { 37 : 38 : /*! 39 : * \brief Checks if the regular field has been received from the worldtube and 40 : * computes the retarded field for boundary conditions. 41 : * 42 : * \details This action checks whether the coefficients of Taylor Series of the 43 : * regular field have been sent by the worldtube. If so, the series is evaluated 44 : * at the face coordinate in the inertial frame and the puncture field is added 45 : * to it to obtain the retarded field. This is stored in \ref 46 : * Tags::WorldtubeSolution which is used to formulate boundary conditions in 47 : * \ref CurvedScalarWave::BoundaryConditions::Worldtube. 48 : */ 49 1 : struct ReceiveWorldtubeData { 50 0 : static constexpr size_t Dim = 3; 51 0 : using psi_tag = CurvedScalarWave::Tags::Psi; 52 0 : using dt_psi_tag = ::Tags::dt<CurvedScalarWave::Tags::Psi>; 53 : template <typename Frame> 54 0 : using di_psi_tag = 55 : ::Tags::deriv<CurvedScalarWave::Tags::Psi, tmpl::size_t<Dim>, Frame>; 56 0 : using evolved_tags_list = 57 : typename CurvedScalarWave::System<Dim>::variables_tag::tags_list; 58 0 : using simple_tags = tmpl::list<Tags::WorldtubeSolution<Dim>>; 59 0 : using inbox_tags = tmpl::list<Tags::RegularFieldInbox<Dim>>; 60 0 : using tags_to_slice_to_face = 61 : tmpl::list<gr::Tags::Shift<DataVector, Dim>, gr::Tags::Lapse<DataVector>>; 62 : 63 : template <typename DbTagsList, typename... InboxTags, typename Metavariables, 64 : typename ArrayIndex, typename ActionList, 65 : typename ParallelComponent> 66 0 : static Parallel::iterable_action_return_t apply( 67 : db::DataBox<DbTagsList>& box, tuples::TaggedTuple<InboxTags...>& inboxes, 68 : const Parallel::GlobalCache<Metavariables>& /*cache*/, 69 : const ArrayIndex& /*array_index*/, const ActionList /*meta*/, 70 : const ParallelComponent* const /*meta*/) { 71 : const auto& element_id = db::get<domain::Tags::Element<Dim>>(box).id(); 72 : const auto& excision_sphere = db::get<Tags::ExcisionSphere<Dim>>(box); 73 : const auto direction = excision_sphere.abutting_direction(element_id); 74 : if (direction.has_value()) { 75 : const auto& time_step_id = db::get<::Tags::TimeStepId>(box); 76 : auto& inbox = get<Tags::RegularFieldInbox<Dim>>(inboxes); 77 : if (not inbox.count(time_step_id)) { 78 : return {Parallel::AlgorithmExecution::Retry, std::nullopt}; 79 : } 80 : const auto& puncture_field = 81 : db::get<Tags::MaxIterations>(box) > 1 82 : ? db::get<Tags::IteratedPunctureField<Dim>>(box) 83 : : db::get<Tags::PunctureField<Dim>>(box); 84 : ASSERT(puncture_field.has_value(), 85 : "The puncture field should be initialized!"); 86 : 87 : const auto& mesh = db::get<domain::Tags::Mesh<Dim>>(box); 88 : const auto face_mesh = mesh.slice_away(direction->dimension()); 89 : const size_t face_size = face_mesh.number_of_grid_points(); 90 : Variables<tags_to_slice_to_face> vars_on_face(face_size); 91 : tmpl::for_each<tags_to_slice_to_face>( 92 : [&box, &vars_on_face, &mesh, &direction](auto tag_to_slice_v) { 93 : using tag_to_slice = typename decltype(tag_to_slice_v)::type; 94 : data_on_slice(make_not_null(&get<tag_to_slice>(vars_on_face)), 95 : db::get<tag_to_slice>(box), mesh.extents(), 96 : direction.value().dimension(), 97 : index_to_slice_at(mesh.extents(), direction.value())); 98 : }); 99 : auto& received_data = inbox.at(time_step_id); 100 : const auto& centered_face_coords = 101 : db::get<Tags::FaceCoordinates<Dim, Frame::Inertial, true>>(box) 102 : .value(); 103 : 104 : db::mutate<Tags::WorldtubeSolution<Dim>>( 105 : [&received_data, &puncture_field, &vars_on_face, 106 : ¢ered_face_coords, 107 : &expansion_order = db::get<Tags::ExpansionOrder>(box)]( 108 : const gsl::not_null<Variables<evolved_tags_list>*> 109 : worldtube_solution) { 110 : worldtube_solution->initialize( 111 : puncture_field.value().number_of_grid_points()); 112 : 113 : auto& psi = get<psi_tag>(*worldtube_solution); 114 : auto& pi = get<CurvedScalarWave::Tags::Pi>(*worldtube_solution); 115 : auto& phi = 116 : get<CurvedScalarWave::Tags::Phi<Dim>>(*worldtube_solution); 117 : 118 : // the puncture field plus the monopole of the regular field 119 : get(psi) = get(get<psi_tag>(puncture_field.value())) + 120 : get(get<psi_tag>(received_data))[0]; 121 : get(pi) = get(get<dt_psi_tag>(puncture_field.value())) + 122 : get(get<dt_psi_tag>(received_data))[0]; 123 : for (size_t i = 0; i < Dim; ++i) { 124 : phi.get(i) = 125 : get<di_psi_tag<Frame::Inertial>>(puncture_field.value()) 126 : .get(i); 127 : } 128 : if (expansion_order > 0) { 129 : // add on the dipole of the regular field 130 : for (size_t i = 0; i < Dim; ++i) { 131 : get(psi) += get(get<psi_tag>(received_data))[i + 1] * 132 : centered_face_coords.get(i); 133 : get(pi) += get(get<dt_psi_tag>(received_data))[i + 1] * 134 : centered_face_coords.get(i); 135 : phi.get(i) += get(get<psi_tag>(received_data))[i + 1]; 136 : } 137 : } 138 : const auto& shift = 139 : get<gr::Tags::Shift<DataVector, Dim>>(vars_on_face); 140 : const auto& lapse = get<gr::Tags::Lapse<DataVector>>(vars_on_face); 141 : 142 : // convert dt_psi -> pi 143 : get(pi) *= -1.; 144 : get(pi) += get(dot_product(shift, phi)); 145 : get(pi) /= get(lapse); 146 : }, 147 : make_not_null(&box)); 148 : inbox.erase(time_step_id); 149 : } 150 : return {Parallel::AlgorithmExecution::Continue, std::nullopt}; 151 : } 152 : }; 153 : } // namespace CurvedScalarWave::Worldtube::Actions