SpECTRE Documentation Coverage Report
Current view: top level - Domain/Creators - Sphere.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 9.1 % 99 9
Test Date: 2026-10-22 17:29:42
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 2.0-1