Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <array>
7 : #include <cstddef>
8 : #include <memory>
9 : #include <optional>
10 : #include <string>
11 : #include <unordered_map>
12 : #include <variant>
13 : #include <vector>
14 :
15 : #include "Domain/BoundaryConditions/BoundaryCondition.hpp"
16 : #include "Domain/BoundaryConditions/GetBoundaryConditionsBase.hpp"
17 : #include "Domain/CoordinateMaps/Distribution.hpp"
18 : #include "Domain/Creators/DomainCreator.hpp"
19 : #include "Domain/Creators/TimeDependence/TimeDependence.hpp"
20 : #include "Domain/Creators/TimeDependentOptions/Sphere.hpp"
21 : #include "Options/Auto.hpp"
22 : #include "Options/Context.hpp"
23 : #include "Options/String.hpp"
24 : #include "Utilities/TMPL.hpp"
25 :
26 : /// \cond
27 : template <size_t Dim, typename T>
28 : class DirectionMap;
29 : template <size_t Dim>
30 : class Domain;
31 : namespace domain {
32 : namespace CoordinateMaps {
33 : template <size_t Dim>
34 : class Identity;
35 : class Interval;
36 : template <typename Map1, typename Map2>
37 : class ProductOf2Maps;
38 : class SphericalToCartesianPfaffian;
39 : } // namespace CoordinateMaps
40 :
41 : template <typename SourceFrame, typename TargetFrame, typename... Maps>
42 : class CoordinateMap;
43 : } // namespace domain
44 : /// \endcond
45 :
46 : namespace domain::creators {
47 : /// \brief A set of concentric spherical shells
48 : ///
49 : /// \note This domain will use a spherical harmonic basis in the angular
50 : /// directions. It cannot be used with subcell.
51 : ///
52 : /// \see Sphere for a spherical domain compatible with subcell
53 : ///
54 : /// Setting the inner radius to $0$ will set the inner-most element to be a
55 : /// filled sphere.
56 : ///
57 : /// This domain creator offers one grid anchor "Center" at the origin.
58 : ///
59 : /// #### Time dependent maps
60 : /// There are two ways to add time dependent maps to the SphericalShells domain
61 : /// creator. In the input file, these are specified under the
62 : /// `TimeDependentMaps:` block.
63 : ///
64 : /// ##### TimeDependence
65 : /// You can use a simple TimeDependence (e.g.
66 : /// `domain::creators::time_dependence::UniformTranslation` or
67 : /// `domain::creators::time_dependence::RotationAboutZAxis`) to add time
68 : /// dependent maps. This method will add the same maps to all blocks in the
69 : /// domain.
70 : ///
71 : /// ##### Hard-coded time dependent maps
72 : /// The SphericalShells domain creator also has the option to use some hard
73 : /// coded time dependent maps that may be useful in certain scenarios. This
74 : /// method adds the maps in `domain::creators::sphere::TimeDependentMapOptions`
75 : /// to the domain. Currently, the first (inner-most) shell has maps between
76 : /// `Frame::Grid`, `Frame::Distorted`, and `Frame::Inertial` while all
77 : /// subsequent shells only have maps between `Frame::Grid` and
78 : /// `Frame::Inertial`.
79 : ///
80 : /// ##### None
81 : /// To not have any time dependent maps, pass a `std::nullopt` as the
82 : /// appropriate argument in the constructor. In the input file, simply have
83 : /// `TimeDependentMaps: None`.
84 1 : class SphericalShells : public DomainCreator<3> {
85 : public:
86 0 : using maps_list =
87 : tmpl::append<tmpl::list<domain::CoordinateMap<
88 : Frame::BlockLogical, Frame::Inertial,
89 : domain::CoordinateMaps::ProductOf2Maps<
90 : domain::CoordinateMaps::Interval,
91 : domain::CoordinateMaps::Identity<2>>,
92 : domain::CoordinateMaps::SphericalToCartesianPfaffian>>,
93 : typename sphere::TimeDependentMapOptions::maps_list>;
94 :
95 : /*!
96 : * \brief Radius of innermost spherical shell
97 : */
98 1 : struct InnerRadius {
99 0 : using type = double;
100 0 : static constexpr Options::String help = {
101 : "Inner radius of the spherical shells. If set to 0, the innermost "
102 : "element with be a B3 in which case the inner boundary condition is "
103 : "not used"};
104 : };
105 :
106 : /*!
107 : * \brief Radius of outer boundary
108 : */
109 1 : struct OuterRadius {
110 0 : using type = double;
111 0 : static constexpr Options::String help = {
112 : "Outer radius of the spherical shells."};
113 : };
114 :
115 : /*!
116 : * \brief Initial refinement in radial direction
117 : */
118 1 : struct InitialRadialRefinement {
119 0 : using type = size_t;
120 0 : static constexpr Options::String help = {
121 : "Initial radial refinement level."};
122 : };
123 :
124 : /*!
125 : * \brief Initial number of radial grid points
126 : */
127 1 : struct InitialNumberOfRadialGridPoints {
128 0 : using type = size_t;
129 0 : static constexpr Options::String help = {
130 : "Initial number of radial grid points."};
131 : };
132 :
133 : /*!
134 : * \brief Initial spherical harmonic resolution
135 : */
136 1 : struct InitialSphericalHarmonicL {
137 0 : using type = size_t;
138 0 : static size_t lower_bound() { return 6; }
139 0 : static constexpr Options::String help = {
140 : "Initial spherical harmonic resolution specified as the highest "
141 : "spherical harmonic represented on the grid. Minimum value is 6."};
142 : };
143 :
144 : /*!
145 : * \brief Radial coordinates of the boundaries splitting elements
146 : */
147 1 : struct RadialPartitioning {
148 0 : using type = std::vector<double>;
149 0 : static constexpr Options::String help = {
150 : "Radial coordinates of the boundaries splitting the spherical shell "
151 : "between InnerRadius and OuterRadius. They must be given in ascending "
152 : "order. This should be used if boundaries need to be set at specific "
153 : "radii. If the number but not the specific locations of the boundaries "
154 : "are important, use InitialRefinement instead."};
155 : };
156 :
157 : /*!
158 : * \brief Distributions to apply to the radial coordinates
159 : */
160 1 : struct RadialDistribution {
161 0 : using type =
162 : std::variant<domain::CoordinateMaps::Distribution,
163 : std::vector<domain::CoordinateMaps::Distribution>>;
164 0 : static constexpr Options::String help = {
165 : "Select the radial distribution of grid points in each spherical "
166 : "shell. There must be N+1 radial distributions specified for N radial "
167 : "partitions. You can also specify just a single radial distribution "
168 : "(not in a vector) which will use the same distribution for all "
169 : "partitions."};
170 : };
171 :
172 0 : using TimeDepOptionType = std::variant<
173 : sphere::TimeDependentMapOptions,
174 : std::unique_ptr<domain::creators::time_dependence::TimeDependence<3>>>;
175 :
176 : /*!
177 : * \brief Time dependence of the domain
178 : */
179 1 : struct TimeDependentMaps {
180 0 : using type = Options::Auto<TimeDepOptionType, Options::AutoLabel::None>;
181 0 : static constexpr Options::String help = {
182 : "The options for time dependent maps. This can either be a "
183 : "TimeDependence or hard coded time dependent options. Specify `None` "
184 : "for no time dependent maps."};
185 : };
186 :
187 : /*!
188 : * \brief Boundary condition to apply to inner boundary when not filled
189 : */
190 : template <typename BoundaryConditionsBase>
191 1 : struct InnerBoundaryCondition {
192 0 : static constexpr Options::String help =
193 : "Options for the boundary conditions at the inner radius.";
194 0 : using type = Options::Auto<std::unique_ptr<BoundaryConditionsBase>,
195 : Options::AutoLabel::None>;
196 : };
197 :
198 : /*!
199 : * \brief Boundary condition to apply to outer boundary
200 : */
201 : template <typename BoundaryConditionsBase>
202 1 : struct OuterBoundaryCondition {
203 0 : static constexpr Options::String help =
204 : "Options for the boundary conditions at the outer radius.";
205 0 : using type = std::unique_ptr<BoundaryConditionsBase>;
206 : };
207 :
208 0 : using basic_options =
209 : tmpl::list<InnerRadius, OuterRadius, InitialRadialRefinement,
210 : InitialNumberOfRadialGridPoints, InitialSphericalHarmonicL,
211 : RadialPartitioning, RadialDistribution, TimeDependentMaps>;
212 :
213 : template <typename Metavariables>
214 0 : using options = tmpl::conditional_t<
215 : domain::BoundaryConditions::has_boundary_conditions_base_v<
216 : typename Metavariables::system>,
217 : tmpl::push_back<
218 : basic_options,
219 : InnerBoundaryCondition<
220 : domain::BoundaryConditions::get_boundary_conditions_base<
221 : typename Metavariables::system>>,
222 : OuterBoundaryCondition<
223 : domain::BoundaryConditions::get_boundary_conditions_base<
224 : typename Metavariables::system>>>,
225 : basic_options>;
226 :
227 0 : static constexpr Options::String help{
228 : "An optional B3 surrounded by a set of concentric spherical shells "
229 : "centered at the origin."};
230 :
231 0 : SphericalShells(
232 : double inner_radius, double outer_radius,
233 : size_t initial_radial_refinement,
234 : size_t initial_number_of_radial_grid_points,
235 : size_t initial_spherical_harmonic_l,
236 : std::vector<double> radial_partitioning = {},
237 : const typename RadialDistribution::type& radial_distribution =
238 : domain::CoordinateMaps::Distribution::Linear,
239 : std::optional<TimeDepOptionType> time_dependent_options = std::nullopt,
240 : std::optional<
241 : std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>>
242 : inner_boundary_condition = std::nullopt,
243 : std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>
244 : outer_boundary_condition = nullptr,
245 : const Options::Context& context = {});
246 :
247 0 : SphericalShells() = default;
248 0 : SphericalShells(const SphericalShells&) = delete;
249 0 : SphericalShells(SphericalShells&&) = default;
250 0 : SphericalShells& operator=(const SphericalShells&) = delete;
251 0 : SphericalShells& operator=(SphericalShells&&) = default;
252 0 : ~SphericalShells() override = default;
253 :
254 0 : Domain<3> create_domain() const override;
255 :
256 : /// A single grid anchor "Center" at the origin.
257 : std::unordered_map<std::string, tnsr::I<double, 3, Frame::Grid>>
258 1 : grid_anchors() const override;
259 :
260 : std::vector<DirectionMap<
261 : 3, std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>>>
262 1 : external_boundary_conditions() const override;
263 :
264 1 : std::vector<std::array<size_t, 3>> initial_extents() const override;
265 :
266 1 : std::vector<std::array<size_t, 3>> initial_refinement_levels() const override;
267 :
268 : /// The block names are Shell0, Shell1, ..., starting with the innermost
269 : /// Block.
270 1 : std::vector<std::string> block_names() const override;
271 :
272 : /// The block groups are Shell0, Shell1, ..., starting with the innermost
273 : /// Block.
274 : std::unordered_map<std::string, std::unordered_set<std::string>>
275 1 : block_groups() const override;
276 :
277 1 : auto functions_of_time(const std::unordered_map<std::string, double>&
278 : initial_expiration_times = {}) const
279 : -> std::unordered_map<
280 : std::string,
281 : std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>> override;
282 :
283 : private:
284 0 : double inner_radius_{};
285 0 : double outer_radius_{};
286 0 : size_t initial_radial_refinement_{};
287 0 : size_t initial_number_of_radial_grid_points_{};
288 0 : bool excise_center_{};
289 0 : size_t initial_spherical_harmonic_l_{};
290 0 : std::vector<double> radial_partitioning_{};
291 0 : std::vector<domain::CoordinateMaps::Distribution> radial_distribution_{};
292 0 : std::optional<TimeDepOptionType> time_dependent_options_{};
293 0 : bool use_hard_coded_maps_{false};
294 : std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>
295 0 : inner_boundary_condition_{};
296 : std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>
297 0 : outer_boundary_condition_{};
298 0 : size_t num_blocks_{};
299 0 : std::vector<std::string> block_names_{};
300 : std::unordered_map<std::string, std::unordered_set<std::string>>
301 0 : block_groups_{};
302 : std::unordered_map<std::string, tnsr::I<double, 3, Frame::Grid>>
303 0 : grid_anchors_{};
304 : };
305 : } // namespace domain::creators
|