Line data Source code
1 1 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : /// \file 5 : /// Defines ScalarWave::Solutions::RegularSphericalWave 6 : 7 : #pragma once 8 : 9 : #include <cstddef> 10 : #include <memory> 11 : 12 : #include "DataStructures/Tensor/TypeAliases.hpp" // IWYU pragma: keep 13 : #include "Options/String.hpp" 14 : #include "PointwiseFunctions/AnalyticSolutions/AnalyticSolution.hpp" 15 : #include "PointwiseFunctions/InitialDataUtilities/InitialData.hpp" 16 : #include "PointwiseFunctions/MathFunctions/MathFunction.hpp" 17 : #include "Utilities/Serialization/CharmPupable.hpp" 18 : #include "Utilities/TMPL.hpp" 19 : #include "Utilities/TaggedTuple.hpp" 20 : // IWYU pragma: no_forward_declare Tensor 21 : 22 : /// \cond 23 : class DataVector; 24 : namespace ScalarWave::Tags { 25 : struct Pi; 26 : struct Psi; 27 : template <size_t Dim> 28 : struct Phi; 29 : } // namespace ScalarWave::Tags 30 : namespace Tags { 31 : template <typename Tag> 32 : struct dt; 33 : } // namespace Tags 34 : template <size_t VolumeDim, typename Fr> 35 : class MathFunction; 36 : namespace PUP { 37 : class er; 38 : } // namespace PUP 39 : /// \endcond 40 : 41 : namespace ScalarWave::Solutions { 42 : /*! 43 : * \brief A 3D spherical wave solution to the Euclidean wave equation that is 44 : * regular at the origin 45 : * 46 : * The solution is given by \f$\Psi(\vec{x},t) = \Psi(r,t) = 47 : * \frac{F(r-t)-F(-r-t)}{r}\f$ describing an outgoing and an ingoing wave 48 : * with profile \f$F(u)\f$. For small \f$r\f$ the solution is approximated by 49 : * its Taylor expansion \f$\Psi(r,t)=2 F^\prime(-t) + \mathcal{O}(r^2)\f$. The 50 : * outgoing and ingoing waves meet at the origin (and cancel each other) when 51 : * \f$F^\prime(-t)=0\f$. 52 : * 53 : * The expansion is employed where \f$r\f$ lies within the cubic root of the 54 : * machine epsilon. Inside this radius we expect the error due to the truncation 55 : * of the Taylor expansion to be smaller than the numerical error made when 56 : * evaluating the full \f$\Psi(r,t)\f$. This is because the truncation error 57 : * scales as \f$r^2\f$ (since we keep the zeroth order, and the linear order 58 : * vanishes as all odd orders do) and the numerical error scales as 59 : * \f$\frac{\epsilon}{r}\f$, so they are comparable at 60 : * \f$r\propto\epsilon^\frac{1}{3}\f$. 61 : * 62 : * \requires the profile \f$F(u)\f$ to have a length scale of order unity so 63 : * that "small" \f$r\f$ means \f$r\ll 1\f$. This is without loss of generality 64 : * because of the scale invariance of the wave equation. The profile could be a 65 : * Gausssian centered at 0 with width 1, for instance. 66 : */ 67 1 : class RegularSphericalWave : public evolution::initial_data::InitialData, 68 : public MarkAsAnalyticSolution { 69 : public: 70 0 : static constexpr size_t volume_dim = 3; 71 0 : struct Profile { 72 0 : using type = std::unique_ptr<MathFunction<1, Frame::Inertial>>; 73 0 : static constexpr Options::String help = { 74 : "The radial profile of the spherical wave."}; 75 : }; 76 : 77 0 : using options = tmpl::list<Profile>; 78 : 79 0 : static constexpr Options::String help = { 80 : "A spherical wave solution of the Euclidean wave equation that is " 81 : "regular at the origin"}; 82 : 83 0 : using tags = 84 : tmpl::list<Tags::Psi, Tags::Pi, Tags::Phi<3>, ::Tags::dt<Tags::Psi>, 85 : ::Tags::dt<Tags::Pi>, ::Tags::dt<Tags::Phi<3>>>; 86 : 87 0 : RegularSphericalWave() = default; 88 0 : explicit RegularSphericalWave( 89 : std::unique_ptr<MathFunction<1, Frame::Inertial>> profile); 90 0 : RegularSphericalWave(const RegularSphericalWave& other); 91 0 : RegularSphericalWave& operator=(const RegularSphericalWave& other); 92 0 : RegularSphericalWave(RegularSphericalWave&&) = default; 93 0 : RegularSphericalWave& operator=(RegularSphericalWave&&) = default; 94 0 : ~RegularSphericalWave() override = default; 95 : 96 0 : auto get_clone() const 97 : -> std::unique_ptr<evolution::initial_data::InitialData> override; 98 : 99 : /// \cond 100 : explicit RegularSphericalWave(CkMigrateMessage* msg); 101 : using PUP::able::register_constructor; 102 : WRAPPED_PUPable_decl_template(RegularSphericalWave); 103 : /// \endcond 104 : 105 0 : tuples::TaggedTuple<Tags::Psi, Tags::Pi, Tags::Phi<3>> variables( 106 : const tnsr::I<DataVector, 3>& x, double t, 107 : tmpl::list<Tags::Psi, Tags::Pi, Tags::Phi<3>> /*meta*/) const; 108 : 109 : tuples::TaggedTuple<::Tags::dt<Tags::Psi>, ::Tags::dt<Tags::Pi>, 110 : ::Tags::dt<Tags::Phi<3>>> 111 0 : variables(const tnsr::I<DataVector, 3>& x, double t, 112 : tmpl::list<::Tags::dt<Tags::Psi>, ::Tags::dt<Tags::Pi>, 113 : ::Tags::dt<Tags::Phi<3>>> /*meta*/) const; 114 : 115 : // NOLINTNEXTLINE(google-runtime-references) 116 0 : void pup(PUP::er& p) override; 117 : 118 : private: 119 : // NOLINTNEXTLINE(readability-redundant-declaration) 120 0 : friend bool operator==(const RegularSphericalWave& lhs, 121 : const RegularSphericalWave& rhs); 122 : // NOLINTNEXTLINE(readability-redundant-declaration) 123 0 : friend bool operator!=(const RegularSphericalWave& lhs, 124 : const RegularSphericalWave& rhs); 125 0 : std::unique_ptr<MathFunction<1, Frame::Inertial>> profile_; 126 : }; 127 : } // namespace ScalarWave::Solutions