Line data Source code
1 1 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : /// \file 5 : /// Defines the class CylindricalSide. 6 : 7 : #pragma once 8 : 9 : #include <array> 10 : #include <cstddef> 11 : #include <limits> 12 : #include <optional> 13 : 14 : #include "DataStructures/Tensor/TypeAliases.hpp" 15 : #include "Domain/CoordinateMaps/FocallyLiftedMap.hpp" 16 : #include "Domain/CoordinateMaps/FocallyLiftedSide.hpp" 17 : 18 : /// \cond 19 : namespace PUP { 20 : class er; 21 : } // namespace PUP 22 : /// \endcond 23 : 24 : namespace domain::CoordinateMaps { 25 : 26 : /*! 27 : * \ingroup CoordinateMapsGroup 28 : * 29 : * \brief Map from a 3D unit right cylindrical shell to a volume that connects 30 : * portions of two spherical surfaces. 31 : * 32 : * \image html CylindricalSide.svg "2D slice showing mapped (shaded) region." 33 : * 34 : * \details Consider two spheres with centers \f$C_1\f$ and \f$C_2\f$, 35 : * and radii \f$R_1\f$ and \f$R_2\f$. Let sphere 1 be intersected by two 36 : * planes normal to the \f$z\f$ axis and located at \f$z = z_\mathrm{L}\f$ 37 : * and \f$z = z_\mathrm{U}\f$, with \f$z_\mathrm{L} < z_\mathrm{U}\f$. 38 : * Also let there be a projection point \f$P\f$. 39 : * 40 : * Note that Sphere 1 and Sphere 2 are not equivalent, because the 41 : * mapped portion of Sphere 1 is bounded by planes of constant 42 : * \f$z\f$ but the mapped portion of Sphere 2 is not (except for 43 : * special choices of \f$C_1\f$, \f$C_2\f$, and \f$P\f$). 44 : * 45 : * CylindricalSide maps a 3D unit right cylindrical shell (with 46 : * coordinates \f$(\bar{x},\bar{y},\bar{z})\f$ such that 47 : * \f$-1\leq\bar{z}\leq 1\f$ and \f$1 \leq \bar{x}^2+\bar{y}^2 \leq 48 : * 4\f$) to the shaded area in each panel of the figure above (with 49 : * coordinates \f$(x,y,z)\f$). The figure shows two different allowed 50 : * possibilities: \f$R_1 > R_2\f$ and \f$R_2 > R_1\f$. Note that the 51 : * two portions of the shaded region in each panel of the figure 52 : * represent different portions of the same block; each panel of the 53 : * figure is to be understood as rotated around the \f$z\f$ axis. The 54 : * inner boundary of the cylindrical shell \f$\bar{x}^2+\bar{y}^2=1\f$ 55 : * is mapped to the portion of sphere 1 that has \f$z_\mathrm{L} \leq 56 : * z \leq z_\mathrm{U}\f$. Curves of constant \f$(\bar{z})\f$ along 57 : * the vector \f$(\bar{x},\bar{y})\f$ are mapped to portions of lines 58 : * that pass through \f$P\f$. Along each of these curves, 59 : * \f$\bar{x}^2+\bar{y}^2=1\f$ is mapped to a point on sphere 1 and 60 : * \f$\bar{x}^2+\bar{y}^2=4\f$ is mapped to a point on sphere 2. 61 : * 62 : * CylindricalSide is described briefly in the Appendix of 63 : * \cite Buchman:2012dw. CylindricalSide is used to construct the blocks 64 : * labeled 'CA cylinder', 'EA cylinder', 'CB cylinder', 'EE cylinder', 65 : * and 'EB cylinder' in Figure 20 of that paper. Note that 'CA 66 : * cylinder', 'CB cylinder', and 'EE cylinder' have Sphere 1 contained 67 : * in Sphere2, and 'EA cylinder' and 'EB cylinder' have Sphere 2 68 : * contained in Sphere 1. 69 : * 70 : * CylindricalSide is implemented using `FocallyLiftedMap` 71 : * and `FocallyLiftedInnerMaps::Side`; see those classes for 72 : * details. 73 : * 74 : * ### Restrictions on map parameters. 75 : * 76 : * We demand that: 77 : * - Either Sphere 1 is fully contained inside Sphere 2, or 78 : * Sphere 2 is fully contained inside Sphere 1. 79 : * - \f$P\f$ is contained inside the smaller sphere, and 80 : * between (or on) the planes defined by \f$z_\mathrm{L}\f$ and 81 : * \f$z_\mathrm{U}\f$. 82 : * - If sphere 1 is contained in sphere 2: 83 : * - \f$C_1^z - 0.95 R_1 \leq z_\mathrm{L}\f$ 84 : * - \f$z_\mathrm{U} \leq C_1^z + 0.95 R_1\f$ 85 : * - If sphere 2 is contained in sphere 1: 86 : * - \f$C_1^z - 0.95 R_1 \leq z_\mathrm{L} \leq C_1^z - 0.2 R_1\f$ 87 : * - \f$C_1^z + 0.2 R_1 \leq z_\mathrm{U} \leq C_1^z + 0.95 R_1\f$ 88 : * 89 : */ 90 1 : class CylindricalSide { 91 : public: 92 0 : static constexpr size_t dim = 3; 93 0 : CylindricalSide(const std::array<double, 3>& center_one, 94 : const std::array<double, 3>& center_two, 95 : const std::array<double, 3>& proj_center, double radius_one, 96 : double radius_two, double z_lower, double z_upper); 97 : 98 0 : CylindricalSide() = default; 99 0 : ~CylindricalSide() = default; 100 0 : CylindricalSide(CylindricalSide&&) = default; 101 0 : CylindricalSide(const CylindricalSide&) = default; 102 0 : CylindricalSide& operator=(const CylindricalSide&) = default; 103 0 : CylindricalSide& operator=(CylindricalSide&&) = default; 104 : 105 : template <typename T> 106 0 : std::array<T, 3> operator()(const std::array<T, 3>& source_coords) const; 107 : 108 0 : std::optional<std::array<double, 3>> inverse( 109 : const std::array<double, 3>& target_coords) const; 110 : 111 : template <typename T> 112 0 : tnsr::Ij<T, 3, Frame::NoFrame> jacobian( 113 : const std::array<T, 3>& source_coords) const; 114 : 115 : template <typename T> 116 0 : tnsr::Ij<T, 3, Frame::NoFrame> inv_jacobian( 117 : const std::array<T, 3>& source_coords) const; 118 : 119 : // NOLINTNEXTLINE(google-runtime-references) 120 0 : void pup(PUP::er& p); 121 : 122 0 : static bool is_identity() { return false; } 123 : 124 0 : static constexpr bool supports_hessian{false}; 125 : 126 : private: 127 0 : friend bool operator==(const CylindricalSide& lhs, 128 : const CylindricalSide& rhs); 129 0 : FocallyLiftedMap<FocallyLiftedInnerMaps::Side> impl_; 130 : }; 131 0 : bool operator!=(const CylindricalSide& lhs, const CylindricalSide& rhs); 132 : 133 : } // namespace domain::CoordinateMaps