SpECTRE Documentation Coverage Report
Current view: top level - Domain/Creators - Sphere.hpp Hit Total Coverage
Commit: ecb8a275e1aebab77dcce48a5e098ed4e486ab4b Lines: 9 99 9.1 %
Date: 2026-08-22 01:05:40
Legend: Lines: hit not hit

          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 "Domain/Domain.hpp"
      22             : #include "Domain/Structure/DirectionMap.hpp"
      23             : #include "Options/Auto.hpp"
      24             : #include "Options/Context.hpp"
      25             : #include "Options/Options.hpp"
      26             : #include "Options/ParseError.hpp"
      27             : #include "Options/String.hpp"
      28             : #include "Utilities/TMPL.hpp"
      29             : 
      30             : /// \cond
      31             : namespace domain {
      32             : namespace CoordinateMaps {
      33             : class Affine;
      34             : class BulgedCube;
      35             : class EquatorialCompression;
      36             : class Equiangular;
      37             : template <typename Map1, typename Map2, typename Map3>
      38             : class ProductOf3Maps;
      39             : template <size_t Dim>
      40             : class Wedge;
      41             : }  // namespace CoordinateMaps
      42             : 
      43             : template <typename SourceFrame, typename TargetFrame, typename... Maps>
      44             : class CoordinateMap;
      45             : }  // namespace domain
      46             : /// \endcond
      47             : 
      48             : namespace domain::creators::detail {
      49             : 
      50             : /// Options for excising the interior of the sphere. This class parses as the
      51             : /// `ExcisionFromOptions` subclass if boundary conditions are enabled, and as a
      52             : /// plain string if boundary conditions are disabled.
      53             : struct Excision {
      54             :   Excision() = default;
      55             :   Excision(std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>
      56             :                boundary_condition);
      57             :   std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>
      58             :       boundary_condition = nullptr;
      59             : };
      60             : 
      61             : struct ExcisionFromOptions : Excision {
      62             :   static constexpr Options::String help = {
      63             :       "Excise the interior of the sphere, leaving a spherical shell."};
      64             :   template <typename BoundaryConditionsBase>
      65             :   struct BoundaryCondition {
      66             :     static std::string name() { return "ExciseWithBoundaryCondition"; }
      67             :     using type = std::unique_ptr<BoundaryConditionsBase>;
      68             :     static constexpr Options::String help = {
      69             :         "The boundary condition to impose on the excision surface."};
      70             :   };
      71             :   template <typename Metavariables>
      72             :   using options = tmpl::list<BoundaryCondition<
      73             :       domain::BoundaryConditions::get_boundary_conditions_base<
      74             :           typename Metavariables::system>>>;
      75             :   using Excision::Excision;
      76             : };
      77             : 
      78             : /// Options for filling the interior of the sphere with a cube
      79             : struct InnerCube {
      80             :   static constexpr Options::String help = {
      81             :       "Fill the interior of the sphere with a cube."};
      82             :   struct Sphericity {
      83             :     static std::string name() { return "FillWithSphericity"; }
      84             :     using type = double;
      85             :     static constexpr Options::String help = {
      86             :         "Sphericity of the inner cube. A sphericity of 0 uses a product "
      87             :         "of 1D maps as the map in the center. A sphericity > 0 uses a "
      88             :         "BulgedCube. A sphericity of exactly 1 is not allowed. See "
      89             :         "BulgedCube docs for why."};
      90             :     static double lower_bound() { return 0.0; }
      91             :     static double upper_bound() { return 1.0; }
      92             :   };
      93             :   using options = tmpl::list<Sphericity>;
      94             :   InnerCube() = default;
      95             :   explicit InnerCube(double sphericity_in) : sphericity(sphericity_in) {}
      96             :   double sphericity = std::numeric_limits<double>::signaling_NaN();
      97             : };
      98             : 
      99             : }  // namespace domain::creators::detail
     100             : 
     101             : template <>
     102             : struct Options::create_from_yaml<domain::creators::detail::Excision> {
     103             :   template <typename Metavariables>
     104             :   static domain::creators::detail::Excision create(
     105             :       const Options::Option& options) {
     106             :     if constexpr (domain::BoundaryConditions::has_boundary_conditions_base_v<
     107             :                       typename Metavariables::system>) {
     108             :       // Boundary conditions are enabled. Parse with a nested option.
     109             :       return options.parse_as<domain::creators::detail::ExcisionFromOptions,
     110             :                               Metavariables>();
     111             :     } else {
     112             :       // Boundary conditions are disabled. Parse as a plain string.
     113             :       if (options.parse_as<std::string>() == "Excise") {
     114             :         return domain::creators::detail::Excision{};
     115             :       } else {
     116             :         PARSE_ERROR(options.context(), "Parse error");
     117             :       }
     118             :     }
     119             :   }
     120             : };
     121             : 
     122             : namespace domain::creators {
     123             : 
     124             : /*!
     125             :  * \brief A 3D cubed sphere.
     126             :  *
     127             :  * Six wedges surround an interior region, which is either excised or filled in
     128             :  * with a seventh block. The interior region is a (possibly deformed) sphere
     129             :  * when excised, or a (possibly deformed) cube when filled in. Additional
     130             :  * spherical shells, each composed of six wedges, can be added with the
     131             :  * 'RadialPartitioning' option.
     132             :  *
     133             :  * \image html WedgeOrientations.png "The orientation of each wedge in a cubed
     134             :  * sphere."
     135             :  *
     136             :  * This domain creator offers one grid anchor "Center" at the origin.
     137             :  *
     138             :  * #### Inner cube sphericity
     139             :  * The inner cube is a BulgedCube except if the inner cube sphericity is
     140             :  * exactly 0. Then an Equiangular or Affine map is used (depending on if it's
     141             :  * equiangular or not) to avoid a root find in the BulgedCube map.
     142             :  *
     143             :  * #### Time dependent maps
     144             :  * There are two ways to add time dependent maps to the Sphere domain
     145             :  * creator. In the input file, these are specified under the
     146             :  * `TimeDependentMaps:` block.
     147             :  *
     148             :  * ##### TimeDependence
     149             :  * You can use a simple TimeDependence (e.g.
     150             :  * `domain::creators::time_dependence::UniformTranslation` or
     151             :  * `domain::creators::time_dependence::RotationAboutZAxis`) to add time
     152             :  * dependent maps. This method will add the same maps to all blocks in the
     153             :  * domain. This method can be used with an inner cube or with an excision
     154             :  * surface.
     155             :  *
     156             :  * ##### Hard-coded time dependent maps
     157             :  * The Sphere domain creator also has the option to use some hard coded time
     158             :  * dependent maps that may be useful in certain scenarios. This method adds the
     159             :  * maps in `domain::creators::sphere::TimeDependentMapOptions` to the domain.
     160             :  * When a shape map is specified, an excised sphere uses it on the innermost
     161             :  * radial shell by default. A filled sphere with multiple radial shells uses it
     162             :  * on at least the two innermost shells: the first shell turns on the
     163             :  * deformation away from the central cube, and the subsequent selected shells
     164             :  * roll it off. At least one outer shell must remain without a shape map, so
     165             :  * this filled configuration requires at least three radial shells. The
     166             :  * `NumberOfRadialShellsWithShapeMap` option can be used to choose more inner
     167             :  * shells. With only one radial shell, a filled sphere does not roll off the
     168             :  * shape map, while an excised sphere rolls it off at the outer boundary.
     169             :  *
     170             :  * ##### None
     171             :  * To not have any time dependent maps, pass a `std::nullopt` to the appropriate
     172             :  * argument in the constructor. In the input file, simply have
     173             :  * `TimeDependentMaps: None`.
     174             :  *
     175             :  */
     176           1 : class Sphere : public DomainCreator<3> {
     177             :  private:
     178           0 :   using Affine = CoordinateMaps::Affine;
     179           0 :   using Affine3D = CoordinateMaps::ProductOf3Maps<Affine, Affine, Affine>;
     180           0 :   using Equiangular = CoordinateMaps::Equiangular;
     181           0 :   using Equiangular3D =
     182             :       CoordinateMaps::ProductOf3Maps<Equiangular, Equiangular, Equiangular>;
     183           0 :   using BulgedCube = CoordinateMaps::BulgedCube;
     184             : 
     185             :  public:
     186           0 :   using maps_list = tmpl::append<
     187             :       tmpl::list<
     188             :           // Inner cube
     189             :           domain::CoordinateMap<Frame::BlockLogical, Frame::Inertial,
     190             :                                 BulgedCube>,
     191             :           domain::CoordinateMap<Frame::BlockLogical, Frame::Inertial, Affine3D>,
     192             :           domain::CoordinateMap<Frame::BlockLogical, Frame::Inertial,
     193             :                                 Equiangular3D>,
     194             :           // Wedges
     195             :           domain::CoordinateMap<Frame::BlockLogical, Frame::Inertial,
     196             :                                 CoordinateMaps::Wedge<3>>,
     197             :           domain::CoordinateMap<Frame::BlockLogical, Frame::Inertial,
     198             :                                 CoordinateMaps::Wedge<3>,
     199             :                                 CoordinateMaps::EquatorialCompression>>,
     200             :       typename sphere::TimeDependentMapOptions::maps_list>;
     201             : 
     202           0 :   struct InnerRadius {
     203           0 :     using type = double;
     204           0 :     static constexpr Options::String help = {
     205             :         "Radius circumscribing the inner cube or the excision."};
     206             :   };
     207             : 
     208           0 :   struct OuterRadius {
     209           0 :     using type = double;
     210           0 :     static constexpr Options::String help = {"Radius of the sphere."};
     211             :   };
     212             : 
     213           0 :   using Excision = detail::Excision;
     214           0 :   using InnerCube = detail::InnerCube;
     215             : 
     216           0 :   struct Interior {
     217           0 :     using type = std::variant<Excision, InnerCube>;
     218           0 :     static constexpr Options::String help = {
     219             :         "Specify 'ExciseWithBoundaryCondition' and a boundary condition to "
     220             :         "excise the interior of the sphere, leaving a spherical shell "
     221             :         "(or just 'Excise' if boundary conditions are disabled). "
     222             :         "Or specify 'CubeWithSphericity' to fill the interior."};
     223             :   };
     224             : 
     225           0 :   struct InitialRefinement {
     226           0 :     using type =
     227             :         std::variant<size_t, std::array<size_t, 3>,
     228             :                      std::vector<std::array<size_t, 3>>,
     229             :                      std::unordered_map<std::string, std::array<size_t, 3>>>;
     230           0 :     static constexpr Options::String help = {
     231             :         "Initial refinement level. Specify one of: a single number, a "
     232             :         "list representing [phi, theta, r], or such a list for every block "
     233             :         "in the domain. The central cube always uses the value for 'theta' "
     234             :         "in both y- and z-direction."};
     235             :   };
     236             : 
     237           0 :   struct InitialGridPoints {
     238           0 :     using type =
     239             :         std::variant<size_t, std::array<size_t, 3>,
     240             :                      std::vector<std::array<size_t, 3>>,
     241             :                      std::unordered_map<std::string, std::array<size_t, 3>>>;
     242           0 :     static constexpr Options::String help = {
     243             :         "Initial number of grid points. Specify one of: a single number, a "
     244             :         "list representing [phi, theta, r], or such a list for every block "
     245             :         "in the domain. The central cube always uses the value for 'theta' "
     246             :         "in both y- and z-direction."};
     247             :   };
     248             : 
     249           0 :   struct UseEquiangularMap {
     250           0 :     using type = bool;
     251           0 :     static constexpr Options::String help = {
     252             :         "Use equiangular instead of equidistant coordinates. Equiangular "
     253             :         "coordinates give better gridpoint spacings in the angular "
     254             :         "directions, while equidistant coordinates give better gridpoint "
     255             :         "spacings in the inner cube."};
     256             :   };
     257             : 
     258             :   /// Options for the EquatorialCompression map
     259           1 :   struct EquatorialCompressionOptions {
     260           0 :     static constexpr Options::String help = {
     261             :         "Options for the EquatorialCompression map."};
     262           0 :     struct AspectRatio {
     263           0 :       using type = double;
     264           0 :       static constexpr Options::String help = {
     265             :           "An aspect ratio greater than 1 moves grid points toward the "
     266             :           "equator, and an aspect ratio smaller than 1 moves grid points "
     267             :           "toward the poles."};
     268           0 :       static double lower_bound() { return 0.0; }
     269             :     };
     270           0 :     struct IndexPolarAxis {
     271           0 :       using type = size_t;
     272           0 :       static constexpr Options::String help = {
     273             :           "The index (0, 1, or 2) of the axis along which equatorial "
     274             :           "compression is applied, where 0 is x, 1 is y, and 2 is z."};
     275           0 :       static size_t upper_bound() { return 2; }
     276             :     };
     277           0 :     using options = tmpl::list<AspectRatio, IndexPolarAxis>;
     278             : 
     279           0 :     double aspect_ratio;
     280           0 :     size_t index_polar_axis;
     281             :   };
     282             : 
     283           0 :   struct EquatorialCompression {
     284           0 :     using type =
     285             :         Options::Auto<EquatorialCompressionOptions, Options::AutoLabel::None>;
     286           0 :     static constexpr Options::String help = {
     287             :         "Apply an equatorial compression map to focus resolution on the "
     288             :         "equator or on the poles. The equatorial compression is an angular "
     289             :         "redistribution of grid points and will preserve the spherical shape "
     290             :         "of the inner and outer boundaries."};
     291             :   };
     292             : 
     293           0 :   struct RadialPartitioning {
     294           0 :     using type = std::vector<double>;
     295           0 :     static constexpr Options::String help = {
     296             :         "Radial coordinates of the boundaries splitting the spherical shell "
     297             :         "between InnerRadius and OuterRadius. They must be given in ascending "
     298             :         "order. This should be used if boundaries need to be set at specific "
     299             :         "radii. If the number but not the specific locations of the boundaries "
     300             :         "are important, use InitialRefinement instead."};
     301             :   };
     302             : 
     303           0 :   struct RadialDistribution {
     304           0 :     using type =
     305             :         std::variant<domain::CoordinateMaps::Distribution,
     306             :                      std::vector<domain::CoordinateMaps::Distribution>>;
     307           0 :     static constexpr Options::String help = {
     308             :         "Select the radial distribution of grid points in each spherical "
     309             :         "shell. There must be N+1 radial distributions specified for N radial "
     310             :         "partitions. If the interior of the sphere is filled with a cube, the "
     311             :         "innermost shell must have a 'Linear' distribution because it changes "
     312             :         "in sphericity. You can also specify just a single radial distribution "
     313             :         "(not in a vector) which will use the same distribution for all "
     314             :         "partitions."};
     315             :   };
     316             : 
     317           0 :   struct WhichWedges {
     318           0 :     using type = ShellWedges;
     319           0 :     static constexpr Options::String help = {
     320             :         "Which wedges to include in the shell."};
     321           0 :     static constexpr type suggested_value() { return ShellWedges::All; }
     322             :   };
     323             : 
     324           0 :   using TimeDepOptionType = std::variant<
     325             :       sphere::TimeDependentMapOptions,
     326             :       std::unique_ptr<domain::creators::time_dependence::TimeDependence<3>>>;
     327             : 
     328           0 :   struct TimeDependentMaps {
     329           0 :     using type = Options::Auto<TimeDepOptionType, Options::AutoLabel::None>;
     330           0 :     static constexpr Options::String help = {
     331             :         "The options for time dependent maps. This can either be a "
     332             :         "TimeDependence or hard coded time dependent options. Specify `None` "
     333             :         "for no time dependent maps."};
     334             :   };
     335             : 
     336             :   template <typename BoundaryConditionsBase>
     337           0 :   struct OuterBoundaryCondition {
     338           0 :     static constexpr Options::String help =
     339             :         "Options for the boundary conditions at the outer radius.";
     340           0 :     using type = std::unique_ptr<BoundaryConditionsBase>;
     341             :   };
     342             : 
     343           0 :   using basic_options =
     344             :       tmpl::list<InnerRadius, OuterRadius, Interior, InitialRefinement,
     345             :                  InitialGridPoints, UseEquiangularMap, EquatorialCompression,
     346             :                  RadialPartitioning, RadialDistribution, WhichWedges,
     347             :                  TimeDependentMaps>;
     348             : 
     349             :   template <typename Metavariables>
     350           0 :   using options = tmpl::conditional_t<
     351             :       domain::BoundaryConditions::has_boundary_conditions_base_v<
     352             :           typename Metavariables::system>,
     353             :       tmpl::push_back<
     354             :           basic_options,
     355             :           OuterBoundaryCondition<
     356             :               domain::BoundaryConditions::get_boundary_conditions_base<
     357             :                   typename Metavariables::system>>>,
     358             :       basic_options>;
     359             : 
     360           0 :   static constexpr Options::String help{
     361             :       "A 3D cubed sphere. Six wedges surround an interior region, which is "
     362             :       "either excised or filled in with a seventh block. The interior region "
     363             :       "is a (possibly deformed) sphere when excised, or a (possibly deformed) "
     364             :       "cube when filled in. Additional spherical shells, each composed of six "
     365             :       "wedges, can be added with the 'RadialPartitioning' option."};
     366             : 
     367           0 :   Sphere(
     368             :       double inner_radius, double outer_radius,
     369             :       std::variant<Excision, InnerCube> interior,
     370             :       const typename InitialRefinement::type& initial_refinement,
     371             :       const typename InitialGridPoints::type& initial_number_of_grid_points,
     372             :       bool use_equiangular_map,
     373             :       std::optional<EquatorialCompressionOptions> equatorial_compression = {},
     374             :       std::vector<double> radial_partitioning = {},
     375             :       const typename RadialDistribution::type& radial_distribution =
     376             :           domain::CoordinateMaps::Distribution::Linear,
     377             :       ShellWedges which_wedges = ShellWedges::All,
     378             :       std::optional<TimeDepOptionType> time_dependent_options = std::nullopt,
     379             :       std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>
     380             :           outer_boundary_condition = nullptr,
     381             :       const Options::Context& context = {});
     382             : 
     383           0 :   Sphere() = default;
     384           0 :   Sphere(const Sphere&) = delete;
     385           0 :   Sphere(Sphere&&) = default;
     386           0 :   Sphere& operator=(const Sphere&) = delete;
     387           0 :   Sphere& operator=(Sphere&&) = default;
     388           0 :   ~Sphere() override = default;
     389             : 
     390           0 :   Domain<3> create_domain() const override;
     391             : 
     392             :   std::unordered_map<std::string, tnsr::I<double, 3, Frame::Grid>>
     393           1 :   grid_anchors() const override {
     394             :     return grid_anchors_;
     395             :   }
     396             : 
     397             :   std::vector<DirectionMap<
     398             :       3, std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>>>
     399           1 :   external_boundary_conditions() const override;
     400             : 
     401           1 :   std::vector<std::array<size_t, 3>> initial_extents() const override {
     402             :     return initial_number_of_grid_points_;
     403             :   }
     404             : 
     405           1 :   std::vector<std::array<size_t, 3>> initial_refinement_levels()
     406             :       const override {
     407             :     return initial_refinement_;
     408             :   }
     409             : 
     410           1 :   std::vector<std::string> block_names() const override { return block_names_; }
     411             : 
     412             :   std::unordered_map<std::string, std::unordered_set<std::string>>
     413           1 :   block_groups() const override {
     414             :     return block_groups_;
     415             :   }
     416             : 
     417           1 :   auto functions_of_time(const std::unordered_map<std::string, double>&
     418             :                              initial_expiration_times = {}) const
     419             :       -> std::unordered_map<
     420             :           std::string,
     421             :           std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>> override;
     422             : 
     423             :  private:
     424           0 :   double inner_radius_{};
     425           0 :   double outer_radius_{};
     426           0 :   std::variant<Excision, InnerCube> interior_{};
     427           0 :   bool fill_interior_ = false;
     428           0 :   std::vector<std::array<size_t, 3>> initial_refinement_{};
     429           0 :   std::vector<std::array<size_t, 3>> initial_number_of_grid_points_{};
     430           0 :   bool use_equiangular_map_ = false;
     431           0 :   std::optional<EquatorialCompressionOptions> equatorial_compression_{};
     432           0 :   std::vector<double> radial_partitioning_{};
     433           0 :   std::vector<domain::CoordinateMaps::Distribution> radial_distribution_{};
     434           0 :   ShellWedges which_wedges_ = ShellWedges::All;
     435           0 :   std::optional<TimeDepOptionType> time_dependent_options_{};
     436           0 :   bool use_hard_coded_maps_{false};
     437             :   std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>
     438           0 :       outer_boundary_condition_;
     439           0 :   size_t num_shells_{};
     440           0 :   size_t num_blocks_;
     441           0 :   size_t num_blocks_per_shell_;
     442           0 :   std::vector<std::string> block_names_{};
     443             :   std::unordered_map<std::string, std::unordered_set<std::string>>
     444           0 :       block_groups_{};
     445             :   std::unordered_map<std::string, tnsr::I<double, 3, Frame::Grid>>
     446           0 :       grid_anchors_{};
     447             : };
     448             : 
     449             : }  // namespace domain::creators

Generated by: LCOV version 1.14