SpECTRE Documentation Coverage Report
Current view: top level - Domain/Creators - CylindricalBinaryCompactObject.hpp Hit Total Coverage
Commit: c3e43f8d41800b0ecefb9d1393f1de1d5a280c8f Lines: 8 88 9.1 %
Date: 2026-07-24 22:09:25
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 <string>
      10             : #include <unordered_map>
      11             : #include <unordered_set>
      12             : #include <variant>
      13             : #include <vector>
      14             : 
      15             : #include "DataStructures/Tensor/Tensor.hpp"
      16             : #include "Domain/BoundaryConditions/BoundaryCondition.hpp"
      17             : #include "Domain/BoundaryConditions/GetBoundaryConditionsBase.hpp"
      18             : #include "Domain/CoordinateMaps/CoordinateMap.hpp"
      19             : #include "Domain/CoordinateMaps/Identity.hpp"
      20             : #include "Domain/Creators/DomainCreator.hpp"
      21             : #include "Domain/Creators/TimeDependentOptions/BinaryCompactObject.hpp"
      22             : #include "Domain/Domain.hpp"
      23             : #include "Domain/Structure/DirectionMap.hpp"
      24             : #include "Domain/Structure/ObjectLabel.hpp"
      25             : #include "Options/Auto.hpp"
      26             : #include "Options/Context.hpp"
      27             : #include "Options/String.hpp"
      28             : #include "Utilities/GetOutput.hpp"
      29             : #include "Utilities/TMPL.hpp"
      30             : 
      31             : /// \cond
      32             : namespace domain {
      33             : namespace CoordinateMaps {
      34             : class Affine;
      35             : class Interval;
      36             : template <typename Map1, typename Map2>
      37             : class ProductOf2Maps;
      38             : template <typename Map1, typename Map2, typename Map3>
      39             : class ProductOf3Maps;
      40             : class SphericalToCartesianPfaffian;
      41             : template <size_t VolumeDim>
      42             : class Wedge;
      43             : template <size_t VolumeDim>
      44             : class DiscreteRotation;
      45             : class UniformCylindricalEndcap;
      46             : class UniformCylindricalFlatEndcap;
      47             : class UniformCylindricalSide;
      48             : }  // namespace CoordinateMaps
      49             : 
      50             : template <typename SourceFrame, typename TargetFrame, typename... Maps>
      51             : class CoordinateMap;
      52             : 
      53             : template <typename T>
      54             : struct ExpandOverBlocks;
      55             : 
      56             : namespace FunctionsOfTime {
      57             : class FunctionOfTime;
      58             : }  // namespace FunctionsOfTime
      59             : }  // namespace domain
      60             : 
      61             : namespace Frame {
      62             : struct Grid;
      63             : struct Distorted;
      64             : struct Inertial;
      65             : struct BlockLogical;
      66             : }  // namespace Frame
      67             : /// \endcond
      68             : 
      69             : namespace domain::creators {
      70             : 
      71             : /*!
      72             :  * \ingroup ComputationalDomainGroup
      73             :  *
      74             :  * \brief A general domain for two compact objects based on cylinders.
      75             :  *
      76             :  * Creates a 3D Domain that represents a binary compact object
      77             :  * solution.  This domain is described briefly in the Appendix of
      78             :  * \cite Buchman:2012dw, and is illustrated in Figure 20 of that
      79             :  * paper.
      80             :  *
      81             :  * In the code and options below, `ObjectA` and `ObjectB` refer to the
      82             :  * two compact objects. In the grid frame, `ObjectA` is located to the
      83             :  * right of (i.e. a more positive value of the x-coordinate than)
      84             :  * `ObjectB`.  The inner edge of the Blocks surrounding each of
      85             :  * `ObjectA` and `ObjectB` is spherical in grid coordinates; the
      86             :  * user must specify the center and radius of this surface for both
      87             :  * `ObjectA` and `ObjectB`, and the user must specify the outer boundary
      88             :  * radius.  The outer boundary is a sphere centered at the origin.
      89             :  *
      90             :  * This domain offers some grid anchors. See
      91             :  * `domain::creators::bco::create_grid_anchors` for which ones are offered.
      92             :  *
      93             :  * Note that Figure 20 of \cite Buchman:2012dw illustrates additional
      94             :  * spherical shells inside the "EA" and "EB" blocks, and the caption
      95             :  * of Figure 20 indicates that there are additional spherical shells
      96             :  * outside the "CA" and "CB" blocks; `CylindricalBinaryCompactObject`
      97             :  * has these extra shells inside "EA" only if the option `IncludeInnerSphereA`
      98             :  * is true, and it has the extra shells inside "EB" only if the option
      99             :  * `IncludeInnerSphereB` is true. If the shells are absent, then the "EA" and
     100             :  * "EB" blocks extend to the excision boundaries.
     101             :  *
     102             :  * The Blocks are named as follows:
     103             :  * - Each of CAFilledCylinder, EAFilledCylinder, EBFilledCylinder,
     104             :  *   MAFilledCylinder, MBFilledCylinder, and CBFilledCylinder consists
     105             :  *   of 5 blocks, named 'Center', 'East', 'North', 'West', and
     106             :  *   'South', so an example of a valid block name is
     107             :  *   'CAFilledCylinderCenter'.
     108             :  * - Each of CACylinder, EACylinder, EBCylinder, and CBCylinder
     109             :  *   consists of 4 blocks, named 'East', 'North', 'West', and 'South',
     110             :  *   so an example of a valid block name is 'CACylinderEast'.
     111             :  * - The Block group called "Outer" consists of all the CA and CB blocks.
     112             :  * - OuterShell0 is the single shell in a Block group called "OuterSphere" and
     113             :  *   it borders the outer boundary.
     114             :  * - The Block group called "InnerA" consists of all the EA, and MA
     115             :  *   blocks. They all border the inner boundary "A" if
     116             :  *   `IncludeInnerSphereA` is false.
     117             :  * - If `IncludeInnerSphereA` is true, InnerAShell0 is the single shell in a
     118             :  *   Block group called "InnerSphereA" and it borders the inner excision
     119             :  *   boundary "A".
     120             :  * - The Block group called "InnerB" consists of all the EB, and MB
     121             :  *   blocks. They all border the inner boundary "B" if
     122             :  *   `IncludeInnerSphereB` is false.
     123             :  * - If `IncludeInnerSphereB` is true, InnerBShell0 is the single shell in a
     124             :  *   Block group called "InnerSphereB" and it borders the inner excision
     125             :  *   boundary "B".
     126             :  *
     127             :  * If \f$c_A\f$ and \f$c_B\f$ are the input parameters center_A and
     128             :  * center_B, \f$r_A\f$ and \f$r_B\f$ are the input parameters radius_A and
     129             :  * radius_B, and \f$R\f$ is the outer boundary radius, we demand the
     130             :  * following restrictions on parameters:
     131             :  * - \f$c_A^0>0\f$; this is a convention to simplify the code.
     132             :  * - \f$c_B^0<0\f$; this is a convention to simplify the code.
     133             :  * - \f$|c_A^0|\le|c_B^0|\f$. We should roughly have \f$r_A c_A^0 + r_B c_B^0\f$
     134             :  *   close to zero; that is, for BBHs (where \f$r_A\f$ is roughly twice the
     135             :  *   mass of the heavier object A, and \f$r_B\f$ is roughly twice the mass
     136             :  *   of the lighter object B) the center of mass should be roughly
     137             :  *   at the origin.
     138             :  * - \f$0 < r_B < r_A\f$
     139             :  * - \f$R \ge 3(|c_A^0|-|c_B^0|)\f$; otherwise the blocks will be too compressed
     140             :  *   near the outer boundary.
     141             :  *
     142             :  * All time dependent maps are optional to specify. To include a map, specify
     143             :  * its options. Otherwise specify `None` for that map. You can also turn off
     144             :  * time dependent maps all together by specifying `None` for the
     145             :  * `TimeDependentMaps` option. See
     146             :  * `domain::creators::bco::TimeDependentMapOptions`. This class must pass a
     147             :  * template parameter of `true` to
     148             :  * `domain::creators::bco::TimeDependentMapOptions`.
     149             :  */
     150           1 : class CylindricalBinaryCompactObject : public DomainCreator<3> {
     151             :  public:
     152           0 :   using maps_list = tmpl::flatten<
     153             :       tmpl::list<domain::CoordinateMap<
     154             :                      Frame::BlockLogical, Frame::Inertial,
     155             :                      CoordinateMaps::ProductOf3Maps<CoordinateMaps::Interval,
     156             :                                                     CoordinateMaps::Interval,
     157             :                                                     CoordinateMaps::Interval>,
     158             :                      CoordinateMaps::UniformCylindricalEndcap,
     159             :                      CoordinateMaps::DiscreteRotation<3>>,
     160             :                  domain::CoordinateMap<
     161             :                      Frame::BlockLogical, Frame::Inertial,
     162             :                      CoordinateMaps::ProductOf2Maps<CoordinateMaps::Wedge<2>,
     163             :                                                     CoordinateMaps::Interval>,
     164             :                      CoordinateMaps::UniformCylindricalEndcap,
     165             :                      CoordinateMaps::DiscreteRotation<3>>,
     166             :                  domain::CoordinateMap<
     167             :                      Frame::BlockLogical, Frame::Inertial,
     168             :                      CoordinateMaps::ProductOf3Maps<CoordinateMaps::Interval,
     169             :                                                     CoordinateMaps::Interval,
     170             :                                                     CoordinateMaps::Interval>,
     171             :                      CoordinateMaps::UniformCylindricalFlatEndcap,
     172             :                      CoordinateMaps::DiscreteRotation<3>>,
     173             :                  domain::CoordinateMap<
     174             :                      Frame::BlockLogical, Frame::Inertial,
     175             :                      CoordinateMaps::ProductOf2Maps<CoordinateMaps::Wedge<2>,
     176             :                                                     CoordinateMaps::Interval>,
     177             :                      CoordinateMaps::UniformCylindricalFlatEndcap,
     178             :                      CoordinateMaps::DiscreteRotation<3>>,
     179             :                  domain::CoordinateMap<
     180             :                      Frame::BlockLogical, Frame::Inertial,
     181             :                      CoordinateMaps::ProductOf2Maps<CoordinateMaps::Wedge<2>,
     182             :                                                     CoordinateMaps::Interval>,
     183             :                      CoordinateMaps::UniformCylindricalSide,
     184             :                      CoordinateMaps::DiscreteRotation<3>>,
     185             :                  domain::CoordinateMap<
     186             :                      Frame::BlockLogical, Frame::Inertial,
     187             :                      domain::CoordinateMaps::ProductOf2Maps<
     188             :                          CoordinateMaps::Interval, CoordinateMaps::Identity<2>>,
     189             :                      domain::CoordinateMaps::SphericalToCartesianPfaffian,
     190             :                      CoordinateMaps::ProductOf3Maps<CoordinateMaps::Affine,
     191             :                                                     CoordinateMaps::Affine,
     192             :                                                     CoordinateMaps::Affine>>,
     193             :                  bco::TimeDependentMapOptions<true>::maps_list>>;
     194             : 
     195           0 :   struct CenterA {
     196           0 :     using type = std::array<double, 3>;
     197           0 :     static constexpr Options::String help = {
     198             :         "Grid coordinates of center for Object A, which is at x>0."};
     199             :   };
     200           0 :   struct CenterB {
     201           0 :     using type = std::array<double, 3>;
     202           0 :     static constexpr Options::String help = {
     203             :         "Grid coordinates of center for Object B, which is at x<0."};
     204             :   };
     205           0 :   struct RadiusA {
     206           0 :     using type = double;
     207           0 :     static constexpr Options::String help = {
     208             :         "Grid-coordinate radius of grid boundary around Object A."};
     209             :   };
     210           0 :   struct RadiusB {
     211           0 :     using type = double;
     212           0 :     static constexpr Options::String help = {
     213             :         "Grid-coordinate radius of grid boundary around Object B."};
     214             :   };
     215           0 :   struct IncludeInnerSphereA {
     216           0 :     using type = bool;
     217           0 :     static constexpr Options::String help = {
     218             :         "Add an extra spherical layer of Blocks around Object A."};
     219             :   };
     220           0 :   struct IncludeInnerSphereB {
     221           0 :     using type = bool;
     222           0 :     static constexpr Options::String help = {
     223             :         "Add an extra spherical layer of Blocks around Object B."};
     224             :   };
     225           0 :   struct OuterRadius {
     226           0 :     using type = double;
     227           0 :     static constexpr Options::String help = {
     228             :         "Grid-coordinate radius of outer boundary."};
     229             :   };
     230           0 :   struct UseEquiangularMap {
     231           0 :     using type = bool;
     232           0 :     static constexpr Options::String help = {
     233             :         "Distribute grid points equiangularly in 2d wedges."};
     234           0 :     static bool suggested_value() { return false; }
     235             :   };
     236             : 
     237           0 :   struct InitialRefinement {
     238           0 :     using type = std::variant<
     239             :         size_t, std::array<size_t, 3>, std::vector<std::array<size_t, 3>>,
     240             :         std::unordered_map<std::string, std::array<size_t, 3>>,
     241             :         std::unordered_map<std::string,
     242             :                            std::variant<std::array<size_t, 3>, size_t>>>;
     243           0 :     static constexpr Options::String help = {
     244             :         "Initial refinement level. Specify one of: a single number, a list "
     245             :         "representing [r, theta, perp], or such a list for every block in the "
     246             :         "domain. Here 'r' is the radial direction normal to the inner and "
     247             :         "outer boundaries, 'theta' is the periodic direction, and 'perp' is "
     248             :         "the third direction. Note that for spherical shell block groups "
     249             :         "('InnerSphereA', 'InnerSphereB', and 'OuterSphere'), you must instead "
     250             :         "specify refinement as a single value representing radial refinement."};
     251             :   };
     252           0 :   struct InitialGridPoints {
     253           0 :     using type = std::variant<
     254             :         size_t, std::array<size_t, 3>, std::vector<std::array<size_t, 3>>,
     255             :         std::unordered_map<std::string, std::array<size_t, 3>>,
     256             :         std::unordered_map<std::string, std::variant<std::array<size_t, 3>,
     257             :                                                      std::array<size_t, 2>>>>;
     258           0 :     static constexpr Options::String help = {
     259             :         "Initial number of grid points. Specify one of: a single number, a "
     260             :         "list representing [r, theta, perp], or such a list for every block in "
     261             :         "the domain. Here 'r' is the radial direction normal to the inner and "
     262             :         "outer boundaries, 'theta' is the periodic direction, and 'perp' is "
     263             :         "the third direction. The exception to this is that for spherical "
     264             :         "shell blocks groups ('InnerSphereA', 'InnerSphereB', 'OuterSphere'),"
     265             :         "you must instead specify grid points as [r, L_max]. The exception to "
     266             :         "this is if a single number is specified for global initial grid "
     267             :         "points."};
     268             :   };
     269             : 
     270           0 :   struct BoundaryConditions {
     271           0 :     static constexpr Options::String help = "The boundary conditions to apply.";
     272             :   };
     273             :   template <typename BoundaryConditionsBase>
     274           0 :   struct InnerBoundaryCondition {
     275           0 :     static std::string name() { return "InnerBoundary"; }
     276           0 :     static constexpr Options::String help =
     277             :         "Options for the inner boundary conditions.";
     278           0 :     using type = std::unique_ptr<BoundaryConditionsBase>;
     279           0 :     using group = BoundaryConditions;
     280             :   };
     281             : 
     282             :   template <typename BoundaryConditionsBase>
     283           0 :   struct OuterBoundaryCondition {
     284           0 :     static std::string name() { return "OuterBoundary"; }
     285           0 :     static constexpr Options::String help =
     286             :         "Options for the outer boundary conditions.";
     287           0 :     using type = std::unique_ptr<BoundaryConditionsBase>;
     288           0 :     using group = BoundaryConditions;
     289             :   };
     290             : 
     291           0 :   struct TimeDependentMaps {
     292           0 :     using type = Options::Auto<bco::TimeDependentMapOptions<true>,
     293             :                                Options::AutoLabel::None>;
     294           0 :     static constexpr Options::String help =
     295             :         bco::TimeDependentMapOptions<true>::help;
     296             :   };
     297             : 
     298             :   template <typename Metavariables>
     299           0 :   using options = tmpl::append<
     300             :       tmpl::list<CenterA, CenterB, RadiusA, RadiusB, IncludeInnerSphereA,
     301             :                  IncludeInnerSphereB, OuterRadius, UseEquiangularMap,
     302             :                  InitialRefinement, InitialGridPoints, TimeDependentMaps>,
     303             :       tmpl::conditional_t<
     304             :           domain::BoundaryConditions::has_boundary_conditions_base_v<
     305             :               typename Metavariables::system>,
     306             :           tmpl::list<
     307             :               InnerBoundaryCondition<
     308             :                   domain::BoundaryConditions::get_boundary_conditions_base<
     309             :                       typename Metavariables::system>>,
     310             :               OuterBoundaryCondition<
     311             :                   domain::BoundaryConditions::get_boundary_conditions_base<
     312             :                       typename Metavariables::system>>>,
     313             :           tmpl::list<>>>;
     314             : 
     315           0 :   static constexpr Options::String help{
     316             :       "The CylindricalBinaryCompactObject domain is a general domain for "
     317             :       "two compact objects. The user must provide the (grid-frame) "
     318             :       "centers and radii of the spherical inner edge of the grid surrounding "
     319             :       "each of the two compact objects A and B."};
     320             : 
     321           0 :   CylindricalBinaryCompactObject(
     322             :       std::array<double, 3> center_A, std::array<double, 3> center_B,
     323             :       double radius_A, double radius_B, bool include_inner_sphere_A,
     324             :       bool include_inner_sphere_B, double outer_radius,
     325             :       bool use_equiangular_map,
     326             :       const typename InitialRefinement::type& initial_refinement,
     327             :       const typename InitialGridPoints::type& initial_grid_points,
     328             :       std::optional<bco::TimeDependentMapOptions<true>> time_dependent_options =
     329             :           std::nullopt,
     330             :       std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>
     331             :           inner_boundary_condition = nullptr,
     332             :       std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>
     333             :           outer_boundary_condition = nullptr,
     334             :       const Options::Context& context = {});
     335             : 
     336           0 :   CylindricalBinaryCompactObject() = default;
     337           0 :   CylindricalBinaryCompactObject(const CylindricalBinaryCompactObject&) =
     338             :       delete;
     339           0 :   CylindricalBinaryCompactObject(CylindricalBinaryCompactObject&&) = default;
     340           0 :   CylindricalBinaryCompactObject& operator=(
     341             :       const CylindricalBinaryCompactObject&) = delete;
     342           0 :   CylindricalBinaryCompactObject& operator=(CylindricalBinaryCompactObject&&) =
     343             :       default;
     344           0 :   ~CylindricalBinaryCompactObject() override = default;
     345             : 
     346           0 :   Domain<3> create_domain() const override;
     347             : 
     348             :   std::unordered_map<std::string, tnsr::I<double, 3, Frame::Grid>>
     349           1 :   grid_anchors() const override {
     350             :     return grid_anchors_;
     351             :   }
     352             : 
     353             :   std::vector<DirectionMap<
     354             :       3, std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>>>
     355           1 :   external_boundary_conditions() const override;
     356             : 
     357           1 :   std::vector<std::array<size_t, 3>> initial_extents() const override;
     358             : 
     359           1 :   std::vector<std::array<size_t, 3>> initial_refinement_levels() const override;
     360             : 
     361           1 :   auto functions_of_time(const std::unordered_map<std::string, double>&
     362             :                              initial_expiration_times = {}) const
     363             :       -> std::unordered_map<
     364             :           std::string,
     365             :           std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>> override;
     366             : 
     367           1 :   std::vector<std::string> block_names() const override { return block_names_; }
     368             : 
     369             :   std::unordered_map<std::string, std::unordered_set<std::string>>
     370           1 :   block_groups() const override {
     371             :     return block_groups_;
     372             :   }
     373             : 
     374             :  private:
     375             :   // Note that center_A_ and center_B_ are rotated with respect to the
     376             :   // input centers (which are in the grid frame), so that we can
     377             :   // construct the map in a frame where the centers are offset in the
     378             :   // z direction.  At the end, there will be another rotation back to
     379             :   // the grid frame (where the centers are offset in the x direction).
     380           0 :   std::array<double, 3> center_A_{};
     381           0 :   std::array<double, 3> center_B_{};
     382           0 :   double radius_A_{};
     383           0 :   double radius_B_{};
     384           0 :   double outer_radius_A_{};
     385           0 :   double outer_radius_B_{};
     386           0 :   bool include_inner_sphere_A_{};
     387           0 :   bool include_inner_sphere_B_{};
     388           0 :   double outer_radius_{};
     389           0 :   bool use_equiangular_map_{false};
     390           0 :   typename std::vector<std::array<size_t, 3>> initial_refinement_{};
     391           0 :   typename std::vector<std::array<size_t, 3>> initial_grid_points_{};
     392             :   // cut_spheres_offset_factor_ is eta in Eq. (A.9) of
     393             :   // https://arxiv.org/abs/1206.3015.  cut_spheres_offset_factor_
     394             :   // could be set to unity to simplify the equations.  Here we fix it
     395             :   // to the value 0.99 used in SpEC, so that we reproduce SpEC's
     396             :   // domain decomposition.
     397           0 :   double cut_spheres_offset_factor_{0.99};
     398             :   // z_cutting_plane_ is x_C in Eq. (A.9) of
     399             :   // https://arxiv.org/abs/1206.3015 (but rotated to the z-axis).
     400           0 :   double z_cutting_plane_{};
     401           0 :   size_t number_of_blocks_{};
     402           0 :   size_t first_outer_shell_block{};
     403             :   std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>
     404           0 :       inner_boundary_condition_;
     405             :   std::unique_ptr<domain::BoundaryConditions::BoundaryCondition>
     406           0 :       outer_boundary_condition_;
     407           0 :   std::vector<std::string> block_names_{};
     408             :   std::unordered_map<std::string, std::unordered_set<std::string>>
     409           0 :       block_groups_{};
     410             :   std::unordered_map<std::string, tnsr::I<double, 3, Frame::Grid>>
     411           0 :       grid_anchors_{};
     412             :   // FunctionsOfTime options
     413           0 :   std::optional<bco::TimeDependentMapOptions<true>> time_dependent_options_{};
     414             : };
     415             : }  // namespace domain::creators

Generated by: LCOV version 1.14