Line data Source code
1 0 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : #pragma once 5 : 6 : #include <cstddef> 7 : #include <string> 8 : #include <vector> 9 : 10 : #include "DataStructures/ComplexDataVector.hpp" 11 : #include "DataStructures/Tensor/TypeAliases.hpp" 12 : #include "Domain/Tags.hpp" 13 : #include "Elliptic/BoundaryConditions/BoundaryCondition.hpp" 14 : #include "Elliptic/BoundaryConditions/BoundaryConditionType.hpp" 15 : #include "Elliptic/Systems/SelfForce/Scalar/Tags.hpp" 16 : #include "Options/String.hpp" 17 : #include "Utilities/Gsl.hpp" 18 : #include "Utilities/TMPL.hpp" 19 : 20 : namespace ScalarSelfForce::BoundaryConditions { 21 : 22 : /*! 23 : * \brief Radial Sommerfeld boundary conditions for the m-mode field. 24 : * 25 : * The radial boundary conditions are given in Eq. (4.10-4.11) in 26 : * \cite Osburn:2022bby . They apply both near the Kerr horizon (inner radial 27 : * boundary) and at large distance (outer radial boundary): 28 : * 29 : * \begin{equation} 30 : * n_i F^i = i m \Omega \Psi_m 31 : * \end{equation} 32 : * 33 : * These boundary conditions currently assume a circular equatorial orbit. 34 : */ 35 1 : class Sommerfeld : public elliptic::BoundaryConditions::BoundaryCondition<2> { 36 : private: 37 0 : using Base = elliptic::BoundaryConditions::BoundaryCondition<2>; 38 : 39 : public: 40 0 : struct BlackHoleMass { 41 0 : static constexpr Options::String help = 42 : "Kerr mass parameter 'M' of the black hole"; 43 0 : using type = double; 44 : }; 45 0 : struct BlackHoleSpin { 46 0 : static constexpr Options::String help = 47 : "Kerr dimensionless spin parameter 'chi' of the black hole"; 48 0 : using type = double; 49 : }; 50 0 : struct OrbitalRadius { 51 0 : static constexpr Options::String help = 52 : "Radius 'r_0' of the circular orbit"; 53 0 : using type = double; 54 : }; 55 0 : struct MModeNumber { 56 0 : static constexpr Options::String help = 57 : "Mode number 'm' of the scalar field"; 58 0 : using type = int; 59 : }; 60 0 : struct HyperboloidalSlicing { 61 0 : static constexpr Options::String help = 62 : "Whether hyperboloidal slicing is applied. If true, a simple Neumann " 63 : "boundary condition is applied."; 64 0 : using type = bool; 65 : }; 66 0 : struct Order { 67 0 : static constexpr Options::String help = 68 : "Order of the boundary condition. First order (Order=1) implements " 69 : "just the leading 'i m Omega' term. Second order (Order=2) includes " 70 : "the next-to-leading '1/r' term as well (Robin-type)."; 71 0 : using type = int; 72 : }; 73 : 74 0 : static constexpr Options::String help = 75 : "Radial Sommerfeld boundary condition"; 76 0 : using options = tmpl::list<BlackHoleMass, BlackHoleSpin, OrbitalRadius, 77 : MModeNumber, HyperboloidalSlicing, Order>; 78 : 79 0 : Sommerfeld() = default; 80 0 : Sommerfeld(const Sommerfeld&) = default; 81 0 : Sommerfeld& operator=(const Sommerfeld&) = default; 82 0 : Sommerfeld(Sommerfeld&&) = default; 83 0 : Sommerfeld& operator=(Sommerfeld&&) = default; 84 0 : ~Sommerfeld() override = default; 85 : 86 0 : explicit Sommerfeld(double black_hole_mass, double black_hole_spin, 87 : double orbital_radius, int m_mode_number, 88 : bool hyperboloidal_slicing, int order); 89 : 90 0 : double black_hole_mass() const { return black_hole_mass_; } 91 0 : double black_hole_spin() const { return black_hole_spin_; } 92 0 : double orbital_radius() const { return orbital_radius_; } 93 0 : int m_mode_number() const { return m_mode_number_; } 94 0 : bool hyperboloidal_slicing() const { return hyperboloidal_slicing_; } 95 0 : int order() const { return order_; } 96 : 97 : /// \cond 98 : explicit Sommerfeld(CkMigrateMessage* m); 99 : using PUP::able::register_constructor; 100 : WRAPPED_PUPable_decl_template(Sommerfeld); 101 : /// \endcond 102 : 103 0 : std::unique_ptr<domain::BoundaryConditions::BoundaryCondition> get_clone() 104 : const override; 105 : 106 0 : std::vector<elliptic::BoundaryConditionType> boundary_condition_types() 107 : const override { 108 : return {elliptic::BoundaryConditionType::Neumann}; 109 : } 110 : 111 0 : using argument_tags = 112 : tmpl::list<Tags::Beta, Tags::Gamma>; 113 0 : using volume_tags = tmpl::list<>; 114 : 115 0 : void apply(gsl::not_null<Scalar<ComplexDataVector>*> field, 116 : gsl::not_null<Scalar<ComplexDataVector>*> n_dot_field_gradient, 117 : const tnsr::i<ComplexDataVector, 2>& deriv_field, 118 : const Scalar<ComplexDataVector>& beta, 119 : const tnsr::i<ComplexDataVector, 2>& gamma) const; 120 : 121 0 : using argument_tags_linearized = 122 : tmpl::list<Tags::Beta, Tags::Gamma>; 123 0 : using volume_tags_linearized = tmpl::list<>; 124 : 125 0 : void apply_linearized( 126 : gsl::not_null<Scalar<ComplexDataVector>*> field_correction, 127 : gsl::not_null<Scalar<ComplexDataVector>*> n_dot_field_gradient_correction, 128 : const tnsr::i<ComplexDataVector, 2>& deriv_field_correction, 129 : const Scalar<ComplexDataVector>& beta, 130 : const tnsr::i<ComplexDataVector, 2>& gamma) const; 131 : 132 : // NOLINTNEXTLINE 133 0 : void pup(PUP::er& p) override; 134 : 135 : private: 136 0 : friend bool operator==(const Sommerfeld& lhs, const Sommerfeld& rhs); 137 : 138 0 : double black_hole_mass_{std::numeric_limits<double>::signaling_NaN()}; 139 0 : double black_hole_spin_{std::numeric_limits<double>::signaling_NaN()}; 140 0 : double orbital_radius_{std::numeric_limits<double>::signaling_NaN()}; 141 0 : int m_mode_number_{}; 142 0 : bool hyperboloidal_slicing_{}; 143 0 : int order_{}; 144 : }; 145 : 146 0 : bool operator!=(const Sommerfeld& lhs, const Sommerfeld& rhs); 147 : 148 : } // namespace ScalarSelfForce::BoundaryConditions