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::GeodesicPunctureField<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
|