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 <string>
9 :
10 : #include "DataStructures/DataBox/Tag.hpp"
11 : #include "DataStructures/DataVector.hpp"
12 : #include "DataStructures/Tensor/Tensor.hpp"
13 : #include "Domain/Tags.hpp"
14 : #include "Domain/TagsTimeDependent.hpp"
15 : #include "NumericalAlgorithms/Spectral/Mesh.hpp"
16 : #include "Utilities/GetOutput.hpp"
17 : #include "Utilities/Gsl.hpp"
18 : #include "Utilities/TMPL.hpp"
19 :
20 0 : namespace Events::Tags {
21 : /// \brief The mesh for the observation computational grid. For hybrid methods
22 : /// like DG-FD the observer mesh changes throughout the evolution.
23 : template <size_t Dim>
24 1 : struct ObserverMesh : db::SimpleTag {
25 0 : using type = ::Mesh<Dim>;
26 : };
27 :
28 : /// \brief Sets the `ObserverMesh` to `domain::Tags::Mesh`
29 : ///
30 : /// This is what you would use for a single numerical method simulation. Hybrid
31 : /// methods will supply their own tags.
32 : template <size_t Dim>
33 1 : struct ObserverMeshCompute : ObserverMesh<Dim>, db::ComputeTag {
34 0 : using base = ObserverMesh<Dim>;
35 0 : using return_type = typename base::type;
36 0 : using argument_tags = tmpl::list<::domain::Tags::Mesh<Dim>>;
37 0 : static void function(const gsl::not_null<return_type*> observer_mesh,
38 : const ::Mesh<Dim>& mesh) {
39 : *observer_mesh = mesh;
40 : }
41 : };
42 :
43 : /*!
44 : * \brief The coordinates used for observation.
45 : *
46 : * In methods like DG-FD the mesh and coordinates change throughout the
47 : * simulation, so we need to always grab the right ones.
48 : */
49 : template <size_t Dim, typename Fr>
50 1 : struct ObserverCoordinates : db::SimpleTag {
51 0 : static std::string name() { return get_output(Fr{}) + "Coordinates"; }
52 0 : using type = tnsr::I<DataVector, Dim, Fr>;
53 : };
54 :
55 : /// \brief Sets the `ObserverCoordinates` to `domain::Tags::Coordinates`
56 : ///
57 : /// This is what you would use for a single numerical method simulation. Hybrid
58 : /// methods will supply their own tags.
59 : template <size_t Dim, typename Fr>
60 1 : struct ObserverCoordinatesCompute : ObserverCoordinates<Dim, Fr>,
61 : db::ComputeTag {
62 0 : using base = ObserverCoordinates<Dim, Fr>;
63 0 : using return_type = typename base::type;
64 0 : using argument_tags = tmpl::list<::domain::Tags::Coordinates<Dim, Fr>>;
65 0 : static void function(const gsl::not_null<return_type*> observer_coords,
66 : const return_type& coords) {
67 : for (size_t i = 0; i < Dim; ++i) {
68 : observer_coords->get(i).set_data_ref(
69 : // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
70 : make_not_null(&const_cast<DataVector&>(coords.get(i))));
71 : }
72 : }
73 : };
74 :
75 : /*!
76 : * \brief The inverse Jacobian used for observation.
77 : *
78 : * In methods like DG-FD the mesh and inverse Jacobian change throughout the
79 : * simulation, so we need to always grab the right ones.
80 : */
81 : template <size_t Dim, typename SourceFrame, typename TargetFrame>
82 1 : struct ObserverInverseJacobian : db::SimpleTag {
83 0 : static std::string name() {
84 : return "InverseJacobian(" + get_output(SourceFrame{}) + "," +
85 : get_output(TargetFrame{}) + ")";
86 : }
87 0 : using type = ::InverseJacobian<DataVector, Dim, SourceFrame, TargetFrame>;
88 : };
89 :
90 : /// \brief Sets the `ObserverInverseJacobian` to `domain::Tags::InverseJacobian`
91 : ///
92 : /// This is what you would use for a single numerical method simulation. Hybrid
93 : /// methods will supply their own tags.
94 : template <size_t Dim, typename SourceFrame, typename TargetFrame>
95 1 : struct ObserverInverseJacobianCompute
96 : : ObserverInverseJacobian<Dim, SourceFrame, TargetFrame>,
97 : db::ComputeTag {
98 0 : using base = ObserverInverseJacobian<Dim, SourceFrame, TargetFrame>;
99 0 : using return_type = typename base::type;
100 0 : using argument_tags = tmpl::list<
101 : ::domain::Tags::InverseJacobian<Dim, SourceFrame, TargetFrame>>;
102 0 : static void function(
103 : const gsl::not_null<return_type*> observer_inverse_jacobian,
104 : const return_type& inverse_jacobian) {
105 : for (size_t i = 0; i < inverse_jacobian.size(); ++i) {
106 : (*observer_inverse_jacobian)[i].set_data_ref(
107 : // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
108 : make_not_null(&const_cast<DataVector&>(inverse_jacobian[i])));
109 : }
110 : }
111 : };
112 :
113 : /*!
114 : * \brief The Jacobian used for observation.
115 : *
116 : * In methods like DG-FD the mesh and Jacobian change throughout the
117 : * simulation, so we need to always grab the right ones.
118 : */
119 : template <size_t Dim, typename SourceFrame, typename TargetFrame>
120 1 : struct ObserverJacobian : db::SimpleTag {
121 0 : static std::string name() {
122 : return "Jacobian(" + get_output(SourceFrame{}) + "," +
123 : get_output(TargetFrame{}) + ")";
124 : }
125 0 : using type = ::Jacobian<DataVector, Dim, SourceFrame, TargetFrame>;
126 : };
127 :
128 : /// \brief Sets the `ObserverJacobian` to `domain::Tags::Jacobian`
129 : ///
130 : /// This is what you would use for a single numerical method simulation. Hybrid
131 : /// methods will supply their own tags.
132 : template <size_t Dim, typename SourceFrame, typename TargetFrame>
133 1 : struct ObserverJacobianCompute
134 : : ObserverJacobian<Dim, SourceFrame, TargetFrame>,
135 : db::ComputeTag {
136 0 : using base = ObserverJacobian<Dim, SourceFrame, TargetFrame>;
137 0 : using return_type = typename base::type;
138 0 : using argument_tags =
139 : tmpl::list<::domain::Tags::Jacobian<Dim, SourceFrame, TargetFrame>>;
140 0 : static void function(const gsl::not_null<return_type*> observer_jacobian,
141 : const return_type& jacobian) {
142 : for (size_t i = 0; i < jacobian.size(); ++i) {
143 : (*observer_jacobian)[i].set_data_ref(
144 : // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
145 : make_not_null(&const_cast<DataVector&>(jacobian[i])));
146 : }
147 : }
148 : };
149 :
150 : /*!
151 : * \brief The determinant of the inverse Jacobian used for observation.
152 : *
153 : * In methods like DG-FD the mesh and inverse Jacobian change throughout the
154 : * simulation, so we need to always grab the right ones.
155 : */
156 : template <typename SourceFrame, typename TargetFrame>
157 1 : struct ObserverDetInvJacobian : db::SimpleTag {
158 0 : static std::string name() {
159 : return "DetInvJacobian(" + get_output(SourceFrame{}) + "," +
160 : get_output(TargetFrame{}) + ")";
161 : }
162 0 : using type = Scalar<DataVector>;
163 : };
164 :
165 : /// \brief Sets the `ObserverDetInvJacobian` to `domain::Tags::DetInvJacobian`
166 : ///
167 : /// This is what you would use for a single numerical method simulation. Hybrid
168 : /// methods will supply their own tags.
169 : template <typename SourceFrame, typename TargetFrame>
170 1 : struct ObserverDetInvJacobianCompute
171 : : ObserverDetInvJacobian<SourceFrame, TargetFrame>,
172 : db::ComputeTag {
173 0 : using base = ObserverDetInvJacobian<SourceFrame, TargetFrame>;
174 0 : using return_type = typename base::type;
175 0 : using argument_tags =
176 : tmpl::list<::domain::Tags::DetInvJacobian<SourceFrame, TargetFrame>>;
177 0 : static void function(
178 : const gsl::not_null<return_type*> observer_det_inverse_jacobian,
179 : const return_type& det_inverse_jacobian) {
180 : for (size_t i = 0; i < det_inverse_jacobian.size(); ++i) {
181 : (*observer_det_inverse_jacobian)[i].set_data_ref(
182 : // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
183 : make_not_null(&const_cast<DataVector&>(det_inverse_jacobian[i])));
184 : }
185 : }
186 : };
187 :
188 : /// \brief The mesh velocity used for observations
189 : ///
190 : /// The type is a `std::optional`, which when it is not set indicates that the
191 : /// mesh is not moving.
192 : template <size_t Dim, typename Frame = ::Frame::Inertial>
193 1 : struct ObserverMeshVelocity : db::SimpleTag {
194 0 : static std::string name() { return get_output(Frame{}) + "MeshVelocity"; }
195 0 : using type = std::optional<tnsr::I<DataVector, Dim, Frame>>;
196 : };
197 :
198 : /// \brief Sets the `ObserverMeshVelocty` to `domain::Tags::MeshVelocty`
199 : ///
200 : /// This is what you would use for a single numerical method simulation. Hybrid
201 : /// methods will supply their own tags.
202 : template <size_t Dim, typename Frame = ::Frame::Inertial>
203 1 : struct ObserverMeshVelocityCompute : ObserverMeshVelocity<Dim, Frame>,
204 : db::ComputeTag {
205 0 : using base = ObserverMeshVelocity<Dim, Frame>;
206 0 : using return_type = typename base::type;
207 0 : using argument_tags = tmpl::list<::domain::Tags::MeshVelocity<Dim, Frame>>;
208 0 : static void function(const gsl::not_null<return_type*> observer_mesh_velocity,
209 : const return_type& mesh_velocity) {
210 : if (mesh_velocity.has_value()) {
211 : *observer_mesh_velocity = tnsr::I<DataVector, Dim, Frame>{};
212 : for (size_t i = 0; i < mesh_velocity->size(); ++i) {
213 : observer_mesh_velocity->value()[i].set_data_ref(
214 : // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
215 : make_not_null(&const_cast<DataVector&>(mesh_velocity.value()[i])));
216 : }
217 : } else {
218 : *observer_mesh_velocity = std::nullopt;
219 : }
220 : }
221 : };
222 : } // namespace Events::Tags
|