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