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 <string>
10 : #include <unordered_map>
11 : #include <vector>
12 :
13 : #include "Domain/BoundaryConditions/BoundaryCondition.hpp"
14 : #include "Domain/BoundaryConditions/Cartoon.hpp"
15 : #include "Domain/BoundaryConditions/GetBoundaryConditionsBase.hpp"
16 : #include "Domain/CoordinateMaps/Distribution.hpp"
17 : #include "Domain/Creators/DomainCreator.hpp"
18 : #include "Domain/Creators/TimeDependence/TimeDependence.hpp"
19 : #include "Domain/Domain.hpp"
20 : #include "Domain/Structure/DirectionMap.hpp"
21 : #include "Options/Context.hpp"
22 : #include "Options/String.hpp"
23 : #include "Utilities/TMPL.hpp"
24 :
25 : /// \cond
26 : namespace domain {
27 : namespace CoordinateMaps {
28 : class Interval;
29 : template <typename Map1, typename Map2, typename Map3>
30 : class ProductOf3Maps;
31 : } // namespace CoordinateMaps
32 :
33 : template <typename SourceFrame, typename TargetFrame, typename... Maps>
34 : class CoordinateMap;
35 : } // namespace domain
36 : /// \endcond
37 :
38 : namespace domain::creators {
39 : /// Create a 3D Domain with its computational domain being the\f$x-y\f$
40 : /// plane. The third dimension uses a Cartoon basis with Killing vector along
41 : /// the \f$\phi\f$ direction.
42 1 : class CartoonCylinder : public DomainCreator<3> {
43 : public:
44 0 : using maps_list = tmpl::list<domain::CoordinateMap<
45 : Frame::BlockLogical, Frame::Inertial,
46 : CoordinateMaps::ProductOf3Maps<CoordinateMaps::Interval,
47 : CoordinateMaps::Interval,
48 : CoordinateMaps::Identity<1>>>>;
49 :
50 0 : static std::string name() { return "CartoonCylinder"; }
51 :
52 0 : struct LowerBounds {
53 0 : using type = std::array<double, 2>;
54 0 : static constexpr Options::String help = {
55 : "Lower bound in the [x,y] dimensions. The lower x must be greater than "
56 : "or equal to 0. If x=0 is included, the innermost elements use a 1D "
57 : "Zernike basis, otherwise the domain will be a cylindrical shell."};
58 : };
59 :
60 0 : struct UpperBounds {
61 0 : using type = std::array<double, 2>;
62 0 : static constexpr Options::String help = {
63 : "Upper bound in the [x,y] dimensions."};
64 : };
65 :
66 0 : struct InitialRefinement {
67 0 : using type = std::array<size_t, 2>;
68 0 : static constexpr Options::String help = {
69 : "Initial refinement level for the [x,y] dimensions."};
70 : };
71 :
72 0 : struct InitialGridPoints {
73 0 : using type = std::array<size_t, 2>;
74 0 : static constexpr Options::String help = {
75 : "Initial number of grid points in the [x,y] dimensions."};
76 : };
77 :
78 0 : struct Distributions {
79 0 : using type = std::array<CoordinateMaps::Distribution, 2>;
80 0 : static constexpr Options::String help = {
81 : "Distribution of grid points in the [x,y] dimensions."};
82 : };
83 :
84 : template <typename BoundaryConditionsBase>
85 0 : struct LowerUpperBoundaryCondition {
86 0 : static constexpr Options::String help =
87 : "Lower and upper Boundary Conditions";
88 0 : struct LowerBC {
89 0 : using type = std::unique_ptr<BoundaryConditionsBase>;
90 0 : static constexpr Options::String help = "Lower Boundary Condition";
91 0 : static std::string name() { return "Lower"; };
92 : };
93 0 : struct UpperBC {
94 0 : using type = std::unique_ptr<BoundaryConditionsBase>;
95 0 : static constexpr Options::String help = "Upper Boundary Condition";
96 0 : static std::string name() { return "Upper"; };
97 : };
98 0 : LowerUpperBoundaryCondition(typename LowerBC::type lower_bc,
99 : typename UpperBC::type upper_bc)
100 : : lower(std::move(lower_bc)), upper(std::move(upper_bc)){};
101 0 : LowerUpperBoundaryCondition() = default;
102 0 : std::unique_ptr<BoundaryConditionsBase> lower;
103 0 : std::unique_ptr<BoundaryConditionsBase> upper;
104 0 : using options = tmpl::list<LowerBC, UpperBC>;
105 : };
106 :
107 : template <typename BoundaryConditionsBase>
108 0 : struct BoundaryConditions {
109 0 : static constexpr Options::String help = {
110 : "The boundary conditions to be imposed in the x & y dimensions. "
111 : "Either specify one B.C. to be imposed for both "
112 : "lower and upper boundary or a pair 'Lower:' and 'Upper:'."};
113 0 : using type = std::array<
114 : std::variant<std::unique_ptr<BoundaryConditionsBase>,
115 : LowerUpperBoundaryCondition<BoundaryConditionsBase>>,
116 : 2>;
117 : };
118 :
119 0 : struct TimeDependence {
120 0 : using type =
121 : std::unique_ptr<domain::creators::time_dependence::TimeDependence<3>>;
122 0 : static constexpr Options::String help = {
123 : "The time dependence of the moving mesh domain. Specify `None` for no "
124 : "time dependant maps."};
125 : };
126 :
127 0 : using basic_options =
128 : tmpl::list<LowerBounds, UpperBounds, InitialRefinement, InitialGridPoints,
129 : Distributions, TimeDependence>;
130 :
131 : template <typename Metavariables>
132 0 : using options = tmpl::conditional_t<
133 : domain::BoundaryConditions::has_boundary_conditions_base_v<
134 : typename Metavariables::system>,
135 : tmpl::push_back<
136 : basic_options,
137 : BoundaryConditions<
138 : domain::BoundaryConditions::get_boundary_conditions_base<
139 : typename Metavariables::system>>>,
140 : basic_options>;
141 :
142 0 : static constexpr Options::String help{
143 : "A cylinder domain that requires/enforces axial symmetry. The "
144 : "computational domain is the x-y plane, with Cartoon partial derivatives "
145 : "being used for the z direction. Elements touching the x=0 axis use "
146 : "ZernikeB1 bases in the x direction and automatically apply a system's "
147 : "Cartoon-type boundary condition."};
148 :
149 0 : CartoonCylinder(
150 : std::array<double, 2> lower_bounds, std::array<double, 2> upper_bounds,
151 : std::array<size_t, 2> initial_refinement_levels,
152 : std::array<size_t, 2> initial_num_points,
153 : std::array<CoordinateMaps::Distribution, 2> distributions = {},
154 : std::unique_ptr<domain::creators::time_dependence::TimeDependence<3>>
155 : time_dependence = nullptr,
156 : std::array<std::array<std::unique_ptr<
157 : domain::BoundaryConditions::BoundaryCondition>,
158 : 2>,
159 : 2>
160 : boundary_conditions = {},
161 : std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>
162 : cartoon_boundary_condition = nullptr,
163 : const Options::Context& context = {});
164 :
165 0 : CartoonCylinder() = default;
166 0 : CartoonCylinder(const CartoonCylinder&) = delete;
167 0 : CartoonCylinder(CartoonCylinder&&) = default;
168 0 : CartoonCylinder& operator=(const CartoonCylinder&) = delete;
169 0 : CartoonCylinder& operator=(CartoonCylinder&&) = default;
170 0 : ~CartoonCylinder() override = default;
171 :
172 0 : Domain<3> create_domain() const override;
173 :
174 : std::vector<DirectionMap<
175 : 3, std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>>>
176 1 : external_boundary_conditions() const override;
177 :
178 1 : std::vector<std::array<size_t, 3>> initial_extents() const override;
179 :
180 1 : std::vector<std::array<size_t, 3>> initial_refinement_levels() const override;
181 :
182 : /// The only block is Block0
183 1 : std::vector<std::string> block_names() const override;
184 :
185 : /// The only group is CartoonCylinder
186 : std::unordered_map<std::string, std::unordered_set<std::string>>
187 1 : block_groups() const override;
188 :
189 1 : auto functions_of_time(const std::unordered_map<std::string, double>&
190 : initial_expiration_times = {}) const
191 : -> std::unordered_map<
192 : std::string,
193 : std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>> override;
194 :
195 : // Transforms from option-created boundary conditions to the type used in the
196 : // constructor
197 : template <typename BoundaryConditionsBase>
198 0 : static auto transform_boundary_conditions(
199 : std::array<
200 : std::variant<std::unique_ptr<BoundaryConditionsBase>,
201 : LowerUpperBoundaryCondition<BoundaryConditionsBase>>,
202 : 2>
203 : boundary_conditions)
204 : -> std::array<
205 : std::array<
206 : std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>,
207 : 2>,
208 : 2>;
209 :
210 : private:
211 0 : std::array<double, 2> lower_bounds_{};
212 0 : std::array<double, 2> upper_bounds_{};
213 0 : std::array<size_t, 2> initial_refinement_levels_{};
214 0 : std::array<size_t, 2> initial_num_points_{};
215 0 : bool is_periodic_in_y_{};
216 0 : std::array<CoordinateMaps::Distribution, 2> distributions_{};
217 0 : bool using_zernike_{};
218 : std::array<
219 : std::array<std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>,
220 : 2>,
221 : 2>
222 0 : boundary_conditions_{};
223 : std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>
224 0 : cartoon_boundary_condition_{};
225 : std::unique_ptr<domain::creators::time_dependence::TimeDependence<3>>
226 0 : time_dependence_;
227 0 : size_t num_blocks_{};
228 0 : std::vector<std::string> block_names_{};
229 : std::unordered_map<std::string, std::unordered_set<std::string>>
230 0 : block_groups_{};
231 : };
232 :
233 : template <typename BoundaryConditionsBase>
234 : auto CartoonCylinder::transform_boundary_conditions(
235 : std::array<
236 : std::variant<std::unique_ptr<BoundaryConditionsBase>,
237 : LowerUpperBoundaryCondition<BoundaryConditionsBase>>,
238 : 2>
239 : boundary_conditions)
240 : -> std::array<
241 : std::array<
242 : std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>, 2>,
243 : 2> {
244 : std::array<
245 : std::array<std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>,
246 : 2>,
247 : 2>
248 : result{};
249 : for (size_t d = 0; d < 2; ++d) {
250 : if (std::holds_alternative<std::unique_ptr<BoundaryConditionsBase>>(
251 : boundary_conditions[d])) {
252 : auto bc = std::move(std::get<std::unique_ptr<BoundaryConditionsBase>>(
253 : boundary_conditions[d]));
254 : gsl::at(gsl::at(result, d), 0) = bc->get_clone();
255 : gsl::at(gsl::at(result, d), 1) = std::move(bc);
256 : } else {
257 : auto& bc = std::get<LowerUpperBoundaryCondition<BoundaryConditionsBase>>(
258 : boundary_conditions[d]);
259 : gsl::at(gsl::at(result, d), 0) = std::move(bc.lower);
260 : gsl::at(gsl::at(result, d), 1) = std::move(bc.upper);
261 : }
262 : }
263 : return result;
264 : }
265 :
266 : } // namespace domain::creators
267 :
268 : namespace domain::creators::detail {
269 : /// \brief Helper struct for CartoonCylinder options parsing so the internal
270 : /// cartoon boundary condition at $x = 0$ is not a required argument.
271 : ///
272 : /// \details To get the cartoon-type boundary condition from a system we need
273 : /// access to the system's metavariables, which is only present when parsing
274 : /// options. The point of this design is so that the input file does not
275 : /// require a dummy value for an InnerBoundaryCondition that is always the
276 : /// same for a given system.
277 : ///
278 : /// This helper's constructor does not take an InnerBoundaryCondition, which
279 : /// means if we parse a CartoonCylinder as a CartonSphere2DOptionsHelper
280 : /// by having an options parsing specialization (so the input file values are
281 : /// the helper's construtor, not CartoonCylinder's), we can detect the
282 : /// cartoon-type boundary condition for the given system and only then call
283 : /// the CartoonCylinder constructor with the extra information.
284 : struct CartoonCylinderOptionsHelper {
285 : template <typename Metavariables>
286 : using options = typename domain::creators::CartoonCylinder::template options<
287 : Metavariables>;
288 :
289 : template <typename BoundaryConditionsBase>
290 : using LowerUpperBoundaryCondition =
291 : domain::creators::CartoonCylinder::LowerUpperBoundaryCondition<
292 : BoundaryConditionsBase>;
293 :
294 : static constexpr Options::String help = {"CartoonCylinderOptionsHelper"};
295 :
296 : // Default constructor required by Options system
297 : CartoonCylinderOptionsHelper() = default;
298 :
299 : // Does not take cartoon BC
300 : CartoonCylinderOptionsHelper(
301 : std::array<double, 2> lower_bounds, std::array<double, 2> upper_bounds,
302 : std::array<size_t, 2> initial_refinement_levels,
303 : std::array<size_t, 2> initial_num_points,
304 : std::array<CoordinateMaps::Distribution, 2> distributions,
305 : std::unique_ptr<domain::creators::time_dependence::TimeDependence<3>>
306 : time_dependence = nullptr,
307 : std::array<std::array<std::unique_ptr<
308 : domain::BoundaryConditions::BoundaryCondition>,
309 : 2>,
310 : 2>
311 : boundary_conditions = {},
312 : Options::Context context = {});
313 :
314 : template <typename BoundaryConditionsBase>
315 : CartoonCylinderOptionsHelper(
316 : std::array<double, 2> lower_bounds, std::array<double, 2> upper_bounds,
317 : std::array<size_t, 2> initial_refinement_levels,
318 : std::array<size_t, 2> initial_num_points,
319 : std::array<CoordinateMaps::Distribution, 2> distributions,
320 : std::unique_ptr<domain::creators::time_dependence::TimeDependence<3>>
321 : time_dependence = nullptr,
322 : std::array<
323 : std::variant<std::unique_ptr<BoundaryConditionsBase>,
324 : LowerUpperBoundaryCondition<BoundaryConditionsBase>>,
325 : 2>
326 : boundary_conditions = {},
327 : Options::Context context = {})
328 : : CartoonCylinderOptionsHelper(
329 : std::move(lower_bounds), std::move(upper_bounds),
330 : std::move(initial_refinement_levels), std::move(initial_num_points),
331 : std::move(distributions), std::move(time_dependence),
332 : domain::creators::CartoonCylinder::transform_boundary_conditions(
333 : std::move(boundary_conditions)),
334 : std::move(context)) {}
335 : // Same members as in CartoonCylinder; public, to be extracted
336 : std::array<double, 2> lower_bounds_{};
337 : std::array<double, 2> upper_bounds_{};
338 : std::array<size_t, 2> initial_refinement_levels_{};
339 : std::array<size_t, 2> initial_num_points_{};
340 : std::array<CoordinateMaps::Distribution, 2> distributions_{};
341 : std::unique_ptr<domain::creators::time_dependence::TimeDependence<3>>
342 : time_dependence_{nullptr};
343 : std::array<
344 : std::array<std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>,
345 : 2>,
346 : 2>
347 : boundary_conditions_{};
348 : Options::Context context_{};
349 : };
350 : } // namespace domain::creators::detail
351 :
352 : // Options parsing specialization to automate CartoonCylinder's cartoon
353 : // boundary condition
354 : template <>
355 0 : struct Options::create_from_yaml<domain::creators::CartoonCylinder> {
356 : template <typename Metavariables>
357 0 : static domain::creators::CartoonCylinder create(
358 : const Options::Option& options) {
359 : auto helper =
360 : options.parse_as<domain::creators::detail::CartoonCylinderOptionsHelper,
361 : Metavariables>();
362 :
363 : // Create cartoon BC if system supports it, if not will throw parse error in
364 : // real constructor
365 : std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>
366 : cartoon_boundary_condition = nullptr;
367 : if constexpr (domain::BoundaryConditions::has_boundary_conditions_base_v<
368 : typename Metavariables::system>) {
369 : if constexpr (domain::BoundaryConditions::system_has_cartoon_bc_v<
370 : Metavariables>) {
371 : cartoon_boundary_condition =
372 : domain::BoundaryConditions::make_cartoon_boundary_condition<
373 : Metavariables>();
374 : }
375 : }
376 :
377 : // Construct CartoonCylinder using the helper's parsed data + cartoon BC
378 : return domain::creators::CartoonCylinder(
379 : helper.lower_bounds_, helper.upper_bounds_,
380 : helper.initial_refinement_levels_, helper.initial_num_points_,
381 : helper.distributions_, std::move(helper.time_dependence_),
382 : std::move(helper.boundary_conditions_),
383 : std::move(cartoon_boundary_condition), helper.context_);
384 : }
385 : };
|