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 "Utilities/Gsl.hpp" 33 : #include "Utilities/TMPL.hpp" 34 : 35 : /// \cond 36 : namespace Tags { 37 : struct TimeStepId; 38 : } // namespace Tags 39 : /// \endcond 40 : 41 0 : namespace CurvedScalarWave::Worldtube::Actions { 42 : 43 : /*! 44 : * \brief Checks if the regular field has been received from the worldtube and 45 : * computes the retarded field for boundary conditions. 46 : * 47 : * \details This action checks whether values for the regular field have been 48 : * send by the worldtube. If so, the spatial derivative is converted from the 49 : * grid to inertial frame and the puncture field is added to it to obtain the 50 : * retarded field. This is stored in \ref Tags::WorldtubeSolution which is used 51 : * to formulate boundary conditions in 52 : * \ref CurvedScalarWave::BoundaryConditions::Worldtube. 53 : */ 54 1 : struct ReceiveWorldtubeData { 55 0 : static constexpr size_t Dim = 3; 56 0 : using psi_tag = CurvedScalarWave::Tags::Psi; 57 0 : using dt_psi_tag = ::Tags::dt<CurvedScalarWave::Tags::Psi>; 58 : template <typename Frame> 59 0 : using di_psi_tag = 60 : ::Tags::deriv<CurvedScalarWave::Tags::Psi, tmpl::size_t<Dim>, Frame>; 61 0 : using received_tags = 62 : tmpl::list<psi_tag, dt_psi_tag, di_psi_tag<Frame::Grid>>; 63 0 : using evolved_tags_list = 64 : typename CurvedScalarWave::System<Dim>::variables_tag::tags_list; 65 0 : using simple_tags = tmpl::list<Tags::WorldtubeSolution<Dim>>; 66 0 : using inbox_tags = tmpl::list<Tags::RegularFieldInbox<Dim>>; 67 0 : using tags_to_slice_to_face = tmpl::list< 68 : domain::Tags::InverseJacobian<Dim, Frame::Grid, Frame::Inertial>, 69 : gr::Tags::Shift<DataVector, Dim>, gr::Tags::Lapse<DataVector>>; 70 : 71 : template <typename DbTagsList, typename... InboxTags, typename Metavariables, 72 : typename ArrayIndex, typename ActionList, 73 : typename ParallelComponent> 74 0 : static Parallel::iterable_action_return_t apply( 75 : db::DataBox<DbTagsList>& box, tuples::TaggedTuple<InboxTags...>& inboxes, 76 : const Parallel::GlobalCache<Metavariables>& /*cache*/, 77 : const ArrayIndex& /*array_index*/, const ActionList /*meta*/, 78 : const ParallelComponent* const /*meta*/) { 79 : const auto& puncture_field = db::get<Tags::PunctureField<Dim>>(box); 80 : if (puncture_field.has_value()) { 81 : const auto& time_step_id = db::get<::Tags::TimeStepId>(box); 82 : auto& inbox = get<Tags::RegularFieldInbox<Dim>>(inboxes); 83 : if (not inbox.count(time_step_id)) { 84 : return {Parallel::AlgorithmExecution::Retry, std::nullopt}; 85 : } 86 : const auto& element_id = db::get<domain::Tags::Element<Dim>>(box).id(); 87 : const auto& excision_sphere = db::get<Tags::ExcisionSphere<Dim>>(box); 88 : const auto direction = excision_sphere.abutting_direction(element_id); 89 : ASSERT(direction.has_value(), "This element should abut the worldtube!"); 90 : 91 : const auto& mesh = db::get<domain::Tags::Mesh<Dim>>(box); 92 : const auto face_mesh = mesh.slice_away(direction->dimension()); 93 : const size_t face_size = face_mesh.number_of_grid_points(); 94 : Variables<tags_to_slice_to_face> vars_on_face(face_size); 95 : tmpl::for_each<tags_to_slice_to_face>( 96 : [&box, &vars_on_face, &mesh, &direction](auto tag_to_slice_v) { 97 : using tag_to_slice = typename decltype(tag_to_slice_v)::type; 98 : data_on_slice(make_not_null(&get<tag_to_slice>(vars_on_face)), 99 : db::get<tag_to_slice>(box), mesh.extents(), 100 : direction.value().dimension(), 101 : index_to_slice_at(mesh.extents(), direction.value())); 102 : }); 103 : 104 : auto& received_data = inbox.at(time_step_id); 105 : get(get<psi_tag>(received_data)) += 106 : get(get<psi_tag>(puncture_field.value())); 107 : 108 : // the advective term transforms the time derivative back into the 109 : // inertial frame 110 : get(get<dt_psi_tag>(received_data)) += 111 : get(get<dt_psi_tag>(puncture_field.value())) - 112 : get(get<Tags::RegularFieldAdvectiveTerm<Dim>>(box)); 113 : 114 : db::mutate<Tags::WorldtubeSolution<Dim>>( 115 : [&received_data, &puncture_field, 116 : &vars_on_face](const gsl::not_null<Variables<evolved_tags_list>*> 117 : worldtube_solution) { 118 : worldtube_solution->initialize( 119 : puncture_field.value().number_of_grid_points()); 120 : const auto& inv_jacobian = get<domain::Tags::InverseJacobian< 121 : Dim, Frame::Grid, Frame::Inertial>>(vars_on_face); 122 : auto& phi_inertial = 123 : get<CurvedScalarWave::Tags::Phi<Dim>>(*worldtube_solution); 124 : for (size_t i = 0; i < Dim; ++i) { 125 : phi_inertial.get(i) = 126 : get<0>(get<di_psi_tag<Frame::Grid>>(received_data)) * 127 : inv_jacobian.get(0, i) + 128 : get<1>(get<di_psi_tag<Frame::Grid>>(received_data)) * 129 : inv_jacobian.get(1, i) + 130 : get<2>(get<di_psi_tag<Frame::Grid>>(received_data)) * 131 : inv_jacobian.get(2, i); 132 : phi_inertial.get(i) += 133 : get<di_psi_tag<Frame::Inertial>>(puncture_field.value()) 134 : .get(i); 135 : } 136 : 137 : get<CurvedScalarWave::Tags::Psi>(*worldtube_solution) = 138 : get<psi_tag>(received_data); 139 : const auto& shift = 140 : get<gr::Tags::Shift<DataVector, Dim>>(vars_on_face); 141 : 142 : const auto& lapse = get<gr::Tags::Lapse<DataVector>>(vars_on_face); 143 : auto& pi = get<CurvedScalarWave::Tags::Pi>(*worldtube_solution); 144 : get(pi) = (-get(get<dt_psi_tag>(received_data)) + 145 : get(dot_product(shift, phi_inertial))) / 146 : get(lapse); 147 : }, 148 : make_not_null(&box)); 149 : inbox.erase(time_step_id); 150 : } 151 : return {Parallel::AlgorithmExecution::Continue, std::nullopt}; 152 : } 153 : }; 154 : } // namespace CurvedScalarWave::Worldtube::Actions