SpECTRE Documentation Coverage Report
Current view: top level - Domain - DomainHelpers.hpp Coverage Total Hit
Commit: a37d7b3c1803b88b537d2aef1c27ca5e6b499398 Lines: 41.3 % 63 26
Test Date: 2026-11-12 04:47:19
Legend: Lines:     hit not hit

            Line data    Source code
       1            1 : // Distributed under the MIT License.
       2              : // See LICENSE.txt for details.
       3              : 
       4              : /// \file
       5              : /// Defines DomainHelper functions
       6              : 
       7              : #pragma once
       8              : 
       9              : #include <array>
      10              : #include <cstddef>
      11              : #include <iosfwd>
      12              : #include <limits>
      13              : #include <memory>
      14              : #include <vector>
      15              : 
      16              : #include "DataStructures/Index.hpp"
      17              : #include "DataStructures/Tensor/Tensor.hpp"
      18              : #include "Domain/CoordinateMaps/CoordinateMap.hpp"
      19              : #include "Domain/CoordinateMaps/Distribution.hpp"
      20              : #include "Domain/Structure/Direction.hpp"
      21              : #include "Domain/Structure/Side.hpp"
      22              : #include "Utilities/ConstantExpressions.hpp"
      23              : #include "Utilities/Gsl.hpp"
      24              : #include "Utilities/MakeArray.hpp"
      25              : 
      26              : /// \cond
      27              : template <size_t VolumeDim>
      28              : class BlockNeighbors;
      29              : namespace domain {
      30              : template <typename SourceFrame, typename TargetFrame, size_t Dim>
      31              : class CoordinateMapBase;
      32              : }  // namespace domain
      33              : template <size_t VolumeDim, typename T>
      34              : class DirectionMap;
      35              : template <size_t VolumeDim>
      36              : class Domain;
      37              : template <size_t VolumeDim>
      38              : class OrientationMap;
      39              : namespace Options {
      40              : class Option;
      41              : template <typename T>
      42              : struct create_from_yaml;
      43              : }  // namespace Options
      44              : namespace domain::CoordinateMaps {
      45              : template <typename Map1, typename Map2>
      46              : class ProductOf2Maps;
      47              : template <typename Map1, typename Map2, typename Map3>
      48              : class ProductOf3Maps;
      49              : class Affine;
      50              : template <size_t Dim>
      51              : class Identity;
      52              : class Interval;
      53              : class PolarToCartesian;
      54              : template <size_t Dim>
      55              : class Wedge;
      56              : class Frustum;
      57              : }  // namespace domain::CoordinateMaps
      58              : /// \endcond
      59              : 
      60              : /// \ingroup ComputationalDomainGroup
      61              : /// Each member in `PairOfFaces` holds the global corner ids of a block face.
      62              : /// `PairOfFaces` is used in setting up periodic boundary conditions by
      63              : /// identifying the two faces with each other.
      64              : /// \requires The pair of faces must belong to a single block.
      65            1 : struct PairOfFaces {
      66            0 :   std::vector<size_t> first;
      67            0 :   std::vector<size_t> second;
      68              : };
      69              : 
      70              : /// \ingroup ComputationalDomainGroup
      71              : /// Sets up the BlockNeighbors using the corner numbering scheme
      72              : /// provided by the user to deduce the correct neighbors and
      73              : /// orientations. Does not set up periodic boundary conditions.
      74              : template <size_t VolumeDim>
      75            1 : void set_internal_boundaries(
      76              :     gsl::not_null<
      77              :         std::vector<DirectionMap<VolumeDim, BlockNeighbors<VolumeDim>>>*>
      78              :         neighbors_of_all_blocks,
      79              :     const std::vector<std::array<size_t, two_to_the(VolumeDim)>>&
      80              :         corners_of_all_blocks);
      81              : 
      82              : /// \ingroup ComputationalDomainGroup
      83              : /// Sets up the BlockNeighbors using the corner numbering scheme
      84              : /// implied by the maps provided by the user to deduce the correct
      85              : /// neighbors and orientations.
      86              : /// \warning Does not set up periodic boundary conditions.
      87              : template <size_t VolumeDim>
      88            1 : void set_internal_boundaries(
      89              :     gsl::not_null<
      90              :         std::vector<DirectionMap<VolumeDim, BlockNeighbors<VolumeDim>>>*>
      91              :         neighbors_of_all_blocks,
      92              :     const std::vector<std::unique_ptr<domain::CoordinateMapBase<
      93              :         Frame::BlockLogical, Frame::Inertial, VolumeDim>>>& maps);
      94              : 
      95              : /// \ingroup ComputationalDomainGroup
      96              : /// Sets up additional BlockNeighbors corresponding to any
      97              : /// identifications of faces provided by the user. Can be used
      98              : /// for manually setting up periodic boundary conditions.
      99              : template <size_t VolumeDim>
     100            1 : void set_identified_boundaries(
     101              :     const std::vector<PairOfFaces>& identifications,
     102              :     const std::vector<std::array<size_t, two_to_the(VolumeDim)>>&
     103              :         corners_of_all_blocks,
     104              :     gsl::not_null<
     105              :         std::vector<DirectionMap<VolumeDim, BlockNeighbors<VolumeDim>>>*>
     106              :         neighbors_of_all_blocks);
     107              : 
     108              : /// \ingroup ComputationalDomainGroup
     109              : /// \brief The multi-indices that identify the individual Blocks in the lattice
     110              : template <size_t VolumeDim>
     111            1 : auto indices_for_rectilinear_domains(
     112              :     const Index<VolumeDim>& domain_extents,
     113              :     const std::vector<Index<VolumeDim>>& block_indices_to_exclude = {})
     114              :     -> std::vector<Index<VolumeDim>>;
     115              : 
     116              : /// \ingroup ComputationalDomainGroup
     117              : /// \brief The block names for the individual Blocks in the lattice
     118              : template <size_t VolumeDim>
     119            1 : auto block_names_for_rectilinear_domains(
     120              :     const Index<VolumeDim>& domain_extents,
     121              :     const std::vector<Index<VolumeDim>>& block_indices_to_exclude = {})
     122              :     -> std::vector<std::string>;
     123              : 
     124              : /// \ingroup ComputationalDomainGroup
     125              : /// \brief The corners for a rectilinear domain made of n-cubes.
     126              : ///
     127              : /// The `domain_extents` argument holds the number of blocks to have
     128              : /// in each dimension. The blocks all have aligned orientations by
     129              : /// construction. The `block_indices_to_exclude` argument allows the user
     130              : /// to selectively exclude blocks from the resulting domain. This allows
     131              : /// for the creation of non-trivial shapes such as the net for a tesseract.
     132              : template <size_t VolumeDim>
     133            1 : auto corners_for_rectilinear_domains(
     134              :     const Index<VolumeDim>& domain_extents,
     135              :     const std::vector<Index<VolumeDim>>& block_indices_to_exclude = {})
     136              :     -> std::vector<std::array<size_t, two_to_the(VolumeDim)>>;
     137              : 
     138              : /// \ingroup ComputationalDomainGroup
     139              : /// \brief An array of the orientations of the six blocks that make up a Sphere.
     140              : ///
     141              : /// A Block or Blocks can be wrapped in an outer layer of Blocks surrounding
     142              : /// the original Block(s). In the BBH Domain, this occurs several times, using
     143              : /// both Wedges and Frustums. This standardizes the ordering of the orientations
     144              : /// for both.
     145            1 : std::array<OrientationMap<3>, 6> orientations_for_sphere_wrappings();
     146              : 
     147              : /// \ingroup ComputationalDomainGroup
     148              : /// The number of wedges to include in the Sphere domain.
     149            1 : enum class ShellWedges {
     150              :   /// Use the entire shell
     151              :   All,
     152              :   /// Use only the four equatorial wedges
     153              :   FourOnEquator,
     154              :   /// Use only the single wedge along -x
     155              :   OneAlongMinusX
     156              : };
     157              : 
     158              : /// \ingroup ComputationalDomainGroup
     159              : /// The first index in the list "UpperZ", "LowerZ", "UpperY", "LowerY", "UpperX"
     160              : /// "LowerX" that is included in `which_wedges`. It is 0 for `ShellWedges::All`,
     161              : /// 2 for `ShellWedges::FourOnEquator`, and 5 for `ShellWedges::OneAlongMinusX`.
     162            1 : size_t which_wedge_index(const ShellWedges& which_wedges);
     163              : 
     164              : /*!
     165              :  * \ingroup ComputationalDomainGroup
     166              :  * These are the CoordinateMaps of the Wedge<3>s used in the Sphere and
     167              :  * binary compact object DomainCreators. This function can also be used to
     168              :  * wrap the Sphere in a cube made of six Wedge<3>s.
     169              :  *
     170              :  * \param inner_radius Radius of the inner boundary of the shell, or the
     171              :  * radius circumscribing the inner cube of a sphere.
     172              :  * \param outer_radius Outer radius of the shell or sphere.
     173              :  * \param inner_sphericity Specifies if the wedges form a spherical inner
     174              :  * boundary (1.0) or a cubical inner boundary (0.0).
     175              :  * \param outer_sphericity Specifies if the wedges form a spherical outer
     176              :  * boundary (1.0) or a cubical outer boundary (0.0).
     177              :  * \param offset_options A pair of values with the first being half the length
     178              :  * of the cube that would form the outer boundary and the second being the
     179              :  * offset to apply to the wedges.
     180              :  * \param use_equiangular_map Toggles the equiangular map of the Wedge map.
     181              :  * \param use_half_wedges When `true`, the wedges in the +z,-z,+y,-y directions
     182              :  * are cut in half along their xi-axes. The resulting ten CoordinateMaps are
     183              :  * used for the outermost Blocks of the BBH Domain.
     184              :  * \param radial_partitioning Specifies the radial boundaries of sub-shells
     185              :  * between `inner_radius` and `outer_radius`. If the inner and outer
     186              :  * sphericities are different, the innermost shell does the transition.
     187              :  * \param radial_distribution Select the radial distribution of grid points in
     188              :  * the spherical shells.
     189              :  * \param which_wedges Select a subset of wedges.
     190              :  * \param opening_angle sets the combined opening angle of the two half wedges
     191              :  * that open up along the y-z plane. The endcap wedges are then given an angle
     192              :  * of pi minus this opening angle. This parameter only has an effect if
     193              :  * `use_half_wedges` is set to `true`.
     194              :  */
     195            1 : std::vector<domain::CoordinateMaps::Wedge<3>> sph_wedge_coordinate_maps(
     196              :     double inner_radius, double outer_radius, double inner_sphericity,
     197              :     double outer_sphericity, bool use_equiangular_map,
     198              :     const std::optional<std::pair<double, std::array<double, 3>>>&
     199              :         offset_options = std::nullopt,
     200              :     bool use_half_wedges = false,
     201              :     const std::vector<double>& radial_partitioning = {},
     202              :     const std::vector<domain::CoordinateMaps::Distribution>&
     203              :         radial_distribution = {domain::CoordinateMaps::Distribution::Linear},
     204              :     ShellWedges which_wedges = ShellWedges::All, double opening_angle = M_PI_2);
     205              : 
     206              : /*!
     207              :  * \ingroup ComputationalDomainGroup
     208              :  * \brief Redistribute points in the radial ($\zeta$) direction of a domain
     209              :  * layer (e.g. a shell or cube around an object) between the radii
     210              :  * \f$r_\mathrm{in}\f$ and \f$r_\mathrm{out}\f$.
     211              :  *
     212              :  * The map takes a logical coordinate in \f$[-1, 1]\f$ to a
     213              :  * logarithmically-redistributed logical coordinate in \f$[-1, 1]\f$. It is
     214              :  * meant to be applied before a map that is affine along each radial ray, such
     215              :  * as a `domain::CoordinateMaps::Wedge` map. A `log_map_strength` of 1.0 places
     216              :  * the log-map physical origin ("singularity position") at radius 0; larger
     217              :  * values move it toward the inner radius, concentrating grid points near the
     218              :  * object.
     219              :  *
     220              :  * We define three radial coordinates:
     221              :  * - \f$\zeta\f$: input logical coordinate in \f$[-1, 1]\f$;
     222              :  * - \f$\zeta_{\log}\f$: logarithmically-redistributed logical coordinate in
     223              :  *   \f$[-1, 1]\f$;
     224              :  * - \f$r\f$: physical radius in \f$[r_\mathrm{in}, r_\mathrm{out}]\f$.
     225              :  *
     226              :  * Hence, we define two maps:
     227              :  * - Log map \f$\zeta_{\log}(\zeta)\f$:
     228              :  *   \f{align}
     229              :  *   \ln(\zeta_{\log} - \zeta_0)
     230              :  *   &= \frac{1 + \zeta}{2} \ln(1 - \zeta_0) \nonumber \\
     231              :  *   &+ \frac{1 - \zeta}{2} \ln(-1 - \zeta_0),
     232              :  *   \f}
     233              :  *   where \f$\zeta_0 < -1\f$ is the "logical position" of the log map's
     234              :  *   origin.
     235              :  * - Radius map \f$r(\zeta_{\log})\f$, affine along each radial ray:
     236              :  *   \f{align}
     237              :  *   r(\zeta_{\log}) = \frac{1 - \zeta_{\log}}{2} r_\mathrm{in}
     238              :  *   + \frac{1 + \zeta_{\log}}{2} r_\mathrm{out}.
     239              :  *   \f}
     240              :  *   For example, for a `domain::CoordinateMaps::Wedge` map between two
     241              :  *   spherical surfaces, the redistribution is isotropic. With a flat outer
     242              :  *   surface, \f$r_\mathrm{out}\f$ is the distance to the corners, so the
     243              :  *   redistribution varies with direction.
     244              :  *
     245              :  * Composing these two maps, we get \f$r(\zeta) = r(\zeta_{\log}(\zeta))\f$:
     246              :  *
     247              :  * \f{align}
     248              :  * \ln(r - r_0) &= \frac{1 + \zeta}{2} \ln(r_\mathrm{out} - r_0) \nonumber \\
     249              :  * &+ \frac{1 - \zeta}{2} \ln(r_\mathrm{in} - r_0),
     250              :  * \f}
     251              :  *
     252              :  * where \f$r_0 < r_\mathrm{in}\f$ is the "physical position" of the log map's
     253              :  * origin. For the log map \f$\zeta_{\log}(\zeta)\f$, we need to specify
     254              :  * \f$\zeta_0\f$, but it is easier to specify \f$r_0\f$ because the
     255              :  * ratio of the radial Jacobian (\f$J := dr/d\zeta\f$) at the outer
     256              :  * (\f$\zeta=+1\f$) vs inner (\f$\zeta=-1\f$) boundaries is
     257              :  *
     258              :  * \f{align}
     259              :  * \frac{J_\mathrm{out}}{J_\mathrm{in}}
     260              :  * = \frac{r_\mathrm{out} - r_0}{r_\mathrm{in} - r_0}
     261              :  * := \alpha \frac{r_\mathrm{out}}{r_\mathrm{in}},
     262              :  * \f}
     263              :  *
     264              :  * where \f$\alpha \geq 1\f$ is `log_map_strength`, which we use to
     265              :  * parametrize \f$r_0\f$. Once we specify \f$\alpha\f$, we can invert the
     266              :  * Jacobian ratio above to get
     267              :  *
     268              :  * \f{align}
     269              :  * r_0 = \frac{r_\mathrm{in} r_\mathrm{out} (1 - \alpha)}
     270              :  * {r_\mathrm{in} - \alpha r_\mathrm{out}}.
     271              :  * \f}
     272              :  *
     273              :  * Then, we can invert the radius map \f$r(\zeta_{\log})\f$ to get
     274              :  *
     275              :  * \f{align}
     276              :  * \zeta_0 = \frac{2 r_0 - (r_\mathrm{out} + r_\mathrm{in})}
     277              :  * {r_\mathrm{out} - r_\mathrm{in}}.
     278              :  * \f}
     279              :  *
     280              :  * \param inner_radius The inner radius \f$r_\mathrm{in}\f$ of the layer.
     281              :  * \param outer_radius The outer radius \f$r_\mathrm{out}\f$ of the layer.
     282              :  * \param log_map_strength The log-map strength \f$\alpha \geq 1\f$.
     283              :  */
     284            1 : domain::CoordinateMaps::Interval radial_distribution_log_map(
     285              :     double inner_radius, double outer_radius, double log_map_strength);
     286              : 
     287              : /// \ingroup ComputationalDomainGroup
     288              : /// These are the ten Frustums used in the DomainCreators for binary compact
     289              : /// objects. The Frustums partition the volume defined by two bounding
     290              : /// surfaces: The inner surface is the surface of the two joined inner cubes
     291              : /// enveloping the two compact objects, while the outer is the surface of the
     292              : /// outer cube.
     293              : ///
     294              : /// When the sphericity is 0, the \p length_inner_cube must be less than $1/2$
     295              : /// \p length_outer_cube while when the sphericity is 1 it must be less than
     296              : /// $\sqrt{3}/2$ \p length_outer_cube.
     297              : ///
     298              : /// \param length_inner_cube The side length of the cubes enveloping the two
     299              : /// shells.
     300              : /// \param length_outer_cube The side length of the outer cube.
     301              : /// \param equiangular_map_at_outer Whether to apply a tangent map in the
     302              : /// angular directions at the outer boundary.
     303              : /// \param equiangular_map_at_inner Whether to apply a tangent map in the
     304              : /// angular directions at the inner boundary.
     305              : /// \param origin_preimage The center of the two joined inner cubes is moved
     306              : /// away from the origin and to this point, origin_preimage.
     307              : /// \param radial_distribution The gridpoint distribution in the radial
     308              : /// direction, possibly dependent on the value passed to `distribution_value`.
     309              : /// \param distribution_value Used by `radial_distribution`. \see Frustum for
     310              : /// details.
     311              : /// \param sphericity Determines whether the outer surface is a cube
     312              : /// (value of 0), a sphere (value of 1) or somewhere in between.
     313              : /// \param opening_angle determines the gridpoint distribution used
     314              : /// in the Frustums such that they conform to the outer sphere of Wedges with
     315              : /// the same value for `opening_angle`.
     316            1 : std::vector<domain::CoordinateMaps::Frustum> frustum_coordinate_maps(
     317              :     double length_inner_cube, double length_outer_cube,
     318              :     bool equiangular_map_at_outer, bool equiangular_map_at_inner,
     319              :     const std::array<double, 3>& origin_preimage = {{0.0, 0.0, 0.0}},
     320              :     domain::CoordinateMaps::Distribution radial_distribution =
     321              :         domain::CoordinateMaps::Distribution::Linear,
     322              :     std::optional<double> distribution_value = std::nullopt,
     323              :     double sphericity = 0.0, double opening_angle = M_PI_2);
     324              : 
     325              : /// \ingroup ComputationalDomainGroup
     326              : /// \brief The corners for a domain with radial layers.
     327              : ///
     328              : /// Generates the corners for a Domain which is made of one or more layers
     329              : /// of Blocks fully enveloping an interior volume, e.g. Sphere.
     330              : ///
     331              : /// \param number_of_layers specifies how many layers of Blocks to have
     332              : /// in the final domain.
     333              : /// \param include_central_block set to `true` where the interior
     334              : /// volume is filled with a central Block, and `false` where the
     335              : /// interior volume is left empty.
     336              : /// \param central_block_corners are used as seed values to generate the corners
     337              : /// for the surrounding Blocks.
     338              : /// \param which_wedges can be used to exclude a subset of the wedges.
     339            1 : std::vector<std::array<size_t, 8>> corners_for_radially_layered_domains(
     340              :     size_t number_of_layers, bool include_central_block,
     341              :     const std::array<size_t, 8>& central_block_corners = {{1, 2, 3, 4, 5, 6, 7,
     342              :                                                            8}},
     343              :     ShellWedges which_wedges = ShellWedges::All);
     344              : 
     345              : /// \ingroup ComputationalDomainGroup
     346              : /// \brief The corners for a domain with biradial layers.
     347              : ///
     348              : /// Generates the corners for a BBH-like Domain which is made of one or more
     349              : /// layers of Blocks fully enveloping two interior volumes. The
     350              : /// `number_of_radial_layers` gives the number of layers that fully envelop
     351              : /// each interior volume with six Blocks each. The `number_of_biradial_layers`
     352              : /// gives the number of layers that fully envelop both volumes at once, using
     353              : /// ten Blocks per layer as opposed to six. The `central_block_corners_lhs`
     354              : /// are used as seed values to generate the corners for the surrounding
     355              : /// Blocks.
     356            1 : std::vector<std::array<size_t, 8>> corners_for_biradially_layered_domains(
     357              :     size_t number_of_radial_layers, size_t number_of_biradial_layers,
     358              :     bool include_central_block_lhs, bool include_central_block_rhs,
     359              :     const std::array<size_t, 8>& central_block_corners_lhs = {
     360              :         {1, 2, 3, 4, 5, 6, 7, 8}});
     361              : 
     362              : /// \ingroup ComputationalDomainGroup
     363              : /// These are the CoordinateMaps used in the Cylinder DomainCreator for when
     364              : /// cylinders are built using cubes instead of a single cylindrical block.
     365              : ///
     366              : /// The `radial_partitioning` specifies the radial boundaries of sub-shells
     367              : /// between `inner_radius` and `outer_radius`, while `partitioning_in_z`
     368              : /// specifies the z-boundaries, splitting the cylinder into stacked
     369              : /// 3-dimensional disks. The circularity of the shell wedges changes from 0 to 1
     370              : /// within the innermost sub-shell.
     371              : ///
     372              : /// Set the `radial_distribution` to select the radial distribution of grid
     373              : /// points in the cylindrical shells. The innermost shell must have
     374              : /// `domain::CoordinateMaps::Distribution::Linear` because it changes the
     375              : /// circularity. The distribution along the z-axis for each circular
     376              : /// disc is specified through `distribution_in_z`.
     377              : template <typename TargetFrame>
     378            1 : auto cyl_wedge_coordinate_maps(
     379              :     double inner_radius, double outer_radius, double lower_z_bound,
     380              :     double upper_z_bound, bool use_equiangular_map,
     381              :     const std::vector<double>& radial_partitioning = {},
     382              :     const std::vector<double>& partitioning_in_z = {},
     383              :     const std::vector<domain::CoordinateMaps::Distribution>&
     384              :         radial_distribution = {domain::CoordinateMaps::Distribution::Linear},
     385              :     const std::vector<domain::CoordinateMaps::Distribution>& distribution_in_z =
     386              :         {domain::CoordinateMaps::Distribution::Linear})
     387              :     -> std::vector<std::unique_ptr<
     388              :         domain::CoordinateMapBase<Frame::BlockLogical, TargetFrame, 3>>>;
     389              : 
     390            0 : enum class CylindricalDomainParityFlip { none, z_direction };
     391              : 
     392              : /// \ingroup ComputationalDomainGroup
     393              : /// Same as `cyl_wedge_coordinate_maps`, but only the center square blocks,
     394              : ///
     395              : /// If `CylindricalDomainParityFlip::z_direction` is specified, then
     396              : /// the returned maps describe a cylinder with `lower_z_bound`
     397              : /// corresponding to logical coordinate `upper_zeta` and `upper_z_bound`
     398              : /// corresponding to logical coordinate `lower_zeta`, and thus the
     399              : /// resulting maps are left-handed.
     400              : /// `CylindricalDomainParityFlip::z_direction` is therefore useful
     401              : /// only when composing with another map that is also left-handed, so
     402              : /// that the composed coordinate system is right-handed.
     403              : ///
     404              : /// Returned as a vector of the coordinate maps so that they can
     405              : /// be composed with other maps later.
     406            1 : auto cyl_wedge_coord_map_center_blocks(
     407              :     double inner_radius, double lower_z_bound, double upper_z_bound,
     408              :     bool use_equiangular_map, const std::vector<double>& partitioning_in_z = {},
     409              :     const std::vector<domain::CoordinateMaps::Distribution>& distribution_in_z =
     410              :         {domain::CoordinateMaps::Distribution::Linear},
     411              :     CylindricalDomainParityFlip parity_flip = CylindricalDomainParityFlip::none)
     412              :     -> std::vector<domain::CoordinateMaps::ProductOf3Maps<
     413              :         domain::CoordinateMaps::Interval, domain::CoordinateMaps::Interval,
     414              :         domain::CoordinateMaps::Interval>>;
     415              : 
     416              : /// \ingroup ComputationalDomainGroup
     417              : /// Same as cyl_wedge_coordinate_maps, but only the surrounding wedge blocks.
     418              : ///
     419              : /// If `CylindricalDomainParityFlip::z_direction` is specified, then
     420              : /// the returned maps describe a cylinder with `lower_z_bound`
     421              : /// corresponding to logical coordinate `upper_zeta` and `upper_z_bound`
     422              : /// corresponding to logical coordinate `lower_zeta`, and thus the
     423              : /// resulting maps are left-handed.
     424              : /// `CylindricalDomainParityFlip::z_direction` is therefore useful
     425              : /// only when composing with another map that is also left-handed, so
     426              : /// that the composed coordinate system is right-handed.
     427              : ///
     428              : /// Returned as a vector of the coordinate maps so that they can
     429              : /// be composed with other maps later.
     430            1 : auto cyl_wedge_coord_map_surrounding_blocks(
     431              :     double inner_radius, double outer_radius, double lower_z_bound,
     432              :     double upper_z_bound, bool use_equiangular_map, double inner_circularity,
     433              :     const std::vector<double>& radial_partitioning = {},
     434              :     const std::vector<double>& partitioning_in_z = {},
     435              :     const std::vector<domain::CoordinateMaps::Distribution>&
     436              :         radial_distribution = {domain::CoordinateMaps::Distribution::Linear},
     437              :     const std::vector<domain::CoordinateMaps::Distribution>& distribution_in_z =
     438              :         {domain::CoordinateMaps::Distribution::Linear},
     439              :     CylindricalDomainParityFlip parity_flip = CylindricalDomainParityFlip::none)
     440              :     -> std::vector<domain::CoordinateMaps::ProductOf2Maps<
     441              :         domain::CoordinateMaps::Wedge<2>, domain::CoordinateMaps::Interval>>;
     442              : 
     443              : /// \ingroup ComputationalDomainGroup
     444              : /// This is the CoordinateMap used in the Cylinder DomainCreator for when
     445              : /// cylinders are built using a single cylindrical block instead of cubes.
     446              : ///
     447              : /// Returns a unit cylinder with the given `inner_radius`, `outer_radius`,
     448              : /// `lower_z_bound`, and `upper_z_bound`. The returned unit cylinder's
     449              : /// intended use is to compose it with `UniformCylindricalEndCap`,
     450              : /// `UniformCylindricalFlatEndCap`, or `UniformCylindricalSide` to create the
     451              : /// different cylinders needed by `domain::CylindricalBinaryCompactObject`.
     452              : ::domain::CoordinateMap<
     453              :     Frame::BlockLogical, Frame::Inertial,
     454              :     ::domain::CoordinateMaps::ProductOf3Maps<
     455              :         ::domain::CoordinateMaps::Affine, ::domain::CoordinateMaps::Identity<1>,
     456              :         ::domain::CoordinateMaps::Interval>,
     457              :     ::domain::CoordinateMaps::ProductOf2Maps<
     458              :         ::domain::CoordinateMaps::PolarToCartesian,
     459              :         ::domain::CoordinateMaps::Identity<1>>>
     460            1 : cyl_coordinate_map(double inner_radius, double outer_radius,
     461              :                    double lower_z_bound, double upper_z_bound);
     462              : 
     463              : /// \ingroup ComputationalDomainGroup
     464              : /// \brief The corners for a cylindrical domain split into discs with radial
     465              : /// shells.
     466              : ///
     467              : /// Generates the corners for a Domain which is made of one or more stacked
     468              : /// discs consisting of layers of Blocks enveloping an interior square prism.
     469              : /// The `number_of_shells` specifies how many of these layers of Blocks to have
     470              : /// in each disc.
     471              : ///
     472              : /// The `number_of_discs` specifies how many discs make up the domain.
     473              : /// The very basic cylinder with one shell and one layer serves as a base
     474              : /// to generate the corners for subsequent shells first and discs second.
     475            1 : std::vector<std::array<size_t, 8>> corners_for_cylindrical_layered_domains(
     476              :     size_t number_of_shells, size_t number_of_discs);
     477              : 
     478              : /// \ingroup ComputationalDomainGroup
     479              : /// \brief Permutes the corner numbers of an n-cube.
     480              : ///
     481              : /// Returns the correct ordering of global corner numbers for a rotated block
     482              : /// in an otherwise aligned edifice of blocks, given the OrientationMap a
     483              : /// block aligned with the edifice has relative to this one, and given the
     484              : /// corner numbering the rotated block would have if it were aligned.
     485              : /// This is useful in creating domains for testing purposes, e.g.
     486              : /// RotatedIntervals, RotatedRectangles, and RotatedBricks.
     487              : template <size_t VolumeDim>
     488            1 : std::array<size_t, two_to_the(VolumeDim)> discrete_rotation(
     489              :     const OrientationMap<VolumeDim>& orientation,
     490              :     const std::array<size_t, two_to_the(VolumeDim)>& corners_of_aligned);
     491              : 
     492              : /// \ingroup ComputationalDomainGroup
     493              : /// \brief The CoordinateMaps for a rectilinear domain of n-cubes.
     494              : ///
     495              : /// Allows for both Affine and Equiangular maps.
     496              : template <typename TargetFrame, size_t VolumeDim>
     497            1 : auto maps_for_rectilinear_domains(
     498              :     const Index<VolumeDim>& domain_extents,
     499              :     const std::array<std::vector<double>, VolumeDim>& block_demarcations,
     500              :     const std::vector<Index<VolumeDim>>& block_indices_to_exclude = {},
     501              :     const std::vector<OrientationMap<VolumeDim>>& orientations_of_all_blocks =
     502              :         {},
     503              :     const std::array<std::vector<domain::CoordinateMaps::Distribution>,
     504              :                      VolumeDim>& distributions = {},
     505              :     const std::array<std::vector<std::optional<double>>, VolumeDim>&
     506              :         singularity_positions = {},
     507              :     bool use_equiangular_map = false)
     508              :     -> std::vector<std::unique_ptr<domain::CoordinateMapBase<
     509              :         Frame::BlockLogical, TargetFrame, VolumeDim>>>;
     510              : 
     511              : /// \ingroup ComputationalDomainGroup
     512              : /// \brief Create a rectilinear Domain of multicubes.
     513              : ///
     514              : /// \details Useful for constructing domains for testing non-trivially
     515              : /// connected rectilinear domains made up of cubes. We refer to a domain of
     516              : /// this type as an edifice. The `domain_extents` provides the size (in the
     517              : /// number of blocks) of the initial aligned edifice to construct. The
     518              : /// `block_indices_to_exclude` parameter is used in refining the shape of
     519              : /// the edifice from a cube to sometime more non-trivial, such as an L-shape
     520              : /// or the net of a tesseract. The `block_demarcations` and
     521              : /// `use_equiangular_map` parameters determine the CoordinateMaps to be used.
     522              : /// `orientations_of_all_blocks` contains the OrientationMap of the edifice
     523              : /// relative to each block.
     524              : ///
     525              : /// The `identifications` parameter is used when identifying the faces of
     526              : /// blocks in an edifice. This is used to identify the 1D boundaries in the 2D
     527              : /// net for a 3D cube to construct a domain with topology S2. Note: If the user
     528              : /// wishes to rotate the blocks as well as manually identify their faces, the
     529              : /// user must provide the PairOfFaces corresponding to the rotated corners.
     530              : template <size_t VolumeDim>
     531            1 : Domain<VolumeDim> rectilinear_domain(
     532              :     const Index<VolumeDim>& domain_extents,
     533              :     const std::array<std::vector<double>, VolumeDim>& block_demarcations,
     534              :     const std::vector<Index<VolumeDim>>& block_indices_to_exclude = {},
     535              :     const std::vector<OrientationMap<VolumeDim>>& orientations_of_all_blocks =
     536              :         {},
     537              :     const std::array<bool, VolumeDim>& dimension_is_periodic =
     538              :         make_array<VolumeDim>(false),
     539              :     const std::vector<PairOfFaces>& identifications = {},
     540              :     const std::array<std::vector<domain::CoordinateMaps::Distribution>,
     541              :                      VolumeDim>& distributions = {},
     542              :     const std::array<std::vector<std::optional<double>>, VolumeDim>&
     543              :         singularity_positions = {},
     544              :     bool use_equiangular_map = false);
     545              : 
     546              : /// \ingroup ComputationalDomainGroup
     547              : /// Iterates over the corners of a VolumeDim-dimensional cube.
     548              : template <size_t VolumeDim>
     549            1 : class VolumeCornerIterator {
     550              :  public:
     551            0 :   VolumeCornerIterator() { setup_from_local_corner_number(); }
     552              : 
     553            0 :   explicit VolumeCornerIterator(size_t initial_local_corner_number)
     554              :       : local_corner_number_(initial_local_corner_number) {
     555              :     setup_from_local_corner_number();
     556              :   }
     557            0 :   VolumeCornerIterator(
     558              :       // The block index is also global corner
     559              :       // index of the lowest corner of the block.
     560              :       Index<VolumeDim> block_index, Index<VolumeDim> global_corner_extents)
     561              :       : global_corner_number_(
     562              :             collapsed_index(block_index, global_corner_extents)),
     563              :         global_corner_index_(block_index),
     564              :         global_corner_extents_(global_corner_extents) {}
     565              : 
     566            0 :   void operator++() {
     567              :     ++local_corner_number_;
     568              :     setup_from_local_corner_number();
     569              :   }
     570              : 
     571            0 :   explicit operator bool() const {
     572              :     return local_corner_number_ < two_to_the(VolumeDim);
     573              :   }
     574              : 
     575            0 :   size_t local_corner_number() const { return local_corner_number_; }
     576              : 
     577            0 :   size_t global_corner_number() const {
     578              :     std::array<size_t, VolumeDim> new_indices{};
     579              :     for (size_t i = 0; i < VolumeDim; i++) {
     580              :       gsl::at(new_indices, i) =
     581              :           global_corner_index_[i] +
     582              :           (gsl::at(array_sides_, i) == Side::Upper ? 1 : 0);
     583              :     }
     584              :     const Index<VolumeDim> interior_multi_index(new_indices);
     585              :     return collapsed_index(interior_multi_index, global_corner_extents_);
     586              :   }
     587              : 
     588            0 :   const std::array<Side, VolumeDim>& operator()() const { return array_sides_; }
     589              : 
     590            0 :   const std::array<Side, VolumeDim>& operator*() const { return array_sides_; }
     591              : 
     592            0 :   const std::array<double, VolumeDim>& coords_of_corner() const {
     593              :     return coords_of_corner_;
     594              :   }
     595              : 
     596            0 :   const std::array<Direction<VolumeDim>, VolumeDim>& directions_of_corner()
     597              :       const {
     598              :     return array_directions_;
     599              :   }
     600              : 
     601            0 :   void setup_from_local_corner_number() {
     602              :     for (size_t i = 0; i < VolumeDim; i++) {
     603              :       gsl::at(coords_of_corner_, i) =
     604              :           2.0 * get_nth_bit(local_corner_number_, i) - 1.0;
     605              :       gsl::at(array_sides_, i) =
     606              :           2 * get_nth_bit(local_corner_number_, i) - 1 == 1 ? Side::Upper
     607              :                                                             : Side::Lower;
     608              :       gsl::at(array_directions_, i) =
     609              :           Direction<VolumeDim>(i, gsl::at(array_sides_, i));
     610              :     }
     611              :   }
     612              : 
     613              :  private:
     614            0 :   size_t local_corner_number_ = 0;
     615            0 :   size_t global_corner_number_{std::numeric_limits<size_t>::max()};
     616            0 :   Index<VolumeDim> global_corner_index_{};
     617            0 :   Index<VolumeDim> global_corner_extents_{};
     618            0 :   std::array<Side, VolumeDim> array_sides_ = make_array<VolumeDim>(Side::Lower);
     619            0 :   std::array<Direction<VolumeDim>, VolumeDim> array_directions_{};
     620            0 :   std::array<double, VolumeDim> coords_of_corner_ = make_array<VolumeDim>(-1.0);
     621              : };
     622              : 
     623              : /// \ingroup ComputationalDomainGroup
     624              : /// Iterates over the 2^(VolumeDim-1) logical corners of the face of a
     625              : /// VolumeDim-dimensional cube in the given direction.
     626              : template <size_t VolumeDim>
     627            1 : class FaceCornerIterator {
     628              :  public:
     629            0 :   explicit FaceCornerIterator(Direction<VolumeDim> direction);
     630              : 
     631            0 :   void operator++() {
     632              :     face_index_++;
     633              :     do {
     634              :       index_++;
     635              :     } while (get_nth_bit(index_, direction_.dimension()) ==
     636              :              (direction_.side() == Side::Upper ? 0 : 1));
     637              :     for (size_t i = 0; i < VolumeDim; ++i) {
     638              :       corner_[i] = 2 * static_cast<int>(get_nth_bit(index_, i)) - 1;
     639              :     }
     640              :   }
     641              : 
     642            0 :   explicit operator bool() const {
     643              :     return face_index_ < two_to_the(VolumeDim - 1);
     644              :   }
     645              : 
     646            0 :   tnsr::I<double, VolumeDim, Frame::BlockLogical> operator()() const {
     647              :     return corner_;
     648              :   }
     649              : 
     650            0 :   tnsr::I<double, VolumeDim, Frame::BlockLogical> operator*() const {
     651              :     return corner_;
     652              :   }
     653              : 
     654              :   // Returns the value used to construct the logical corner.
     655            0 :   size_t volume_index() const { return index_; }
     656              : 
     657              :   // Returns the number of times operator++ has been called.
     658            0 :   size_t face_index() const { return face_index_; }
     659              : 
     660              :  private:
     661            0 :   const Direction<VolumeDim> direction_;
     662            0 :   size_t index_;
     663            0 :   size_t face_index_ = 0;
     664            0 :   tnsr::I<double, VolumeDim, Frame::BlockLogical> corner_;
     665              : };
     666              : 
     667              : template <size_t VolumeDim>
     668              : FaceCornerIterator<VolumeDim>::FaceCornerIterator(
     669              :     Direction<VolumeDim> direction)
     670              :     : direction_(std::move(direction)),
     671              :       index_(direction_.side() == Side::Upper
     672              :                  ? two_to_the(direction_.dimension())
     673              :                  : 0) {
     674              :   for (size_t i = 0; i < VolumeDim; ++i) {
     675              :     corner_[i] = 2 * static_cast<int>(get_nth_bit(index_, i)) - 1;
     676              :   }
     677              : }
     678              : 
     679            0 : std::ostream& operator<<(std::ostream& os, const ShellWedges& which_wedges);
     680              : 
     681              : template <>
     682            0 : struct Options::create_from_yaml<ShellWedges> {
     683              :   template <typename Metavariables>
     684            0 :   static ShellWedges create(const Options::Option& options) {
     685              :     return create<void>(options);
     686              :   }
     687              : };
     688              : template <>
     689            0 : ShellWedges Options::create_from_yaml<ShellWedges>::create<void>(
     690              :     const Options::Option& options);
        

Generated by: LCOV version 2.0-1