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 <limits> 8 : 9 : #include "DataStructures/CachedTempBuffer.hpp" 10 : #include "DataStructures/DataBox/Prefixes.hpp" 11 : #include "DataStructures/DataBox/Tag.hpp" 12 : #include "DataStructures/DataVector.hpp" 13 : #include "DataStructures/TaggedTuple.hpp" 14 : #include "DataStructures/Tensor/Tensor.hpp" 15 : #include "Elliptic/Systems/Elasticity/Tags.hpp" 16 : #include "NumericalAlgorithms/Spectral/Mesh.hpp" 17 : #include "Options/String.hpp" 18 : #include "PointwiseFunctions/Elasticity/ConstitutiveRelations/IsotropicHomogeneous.hpp" 19 : #include "PointwiseFunctions/InitialDataUtilities/AnalyticSolution.hpp" 20 : #include "Utilities/ContainerHelpers.hpp" 21 : #include "Utilities/ErrorHandling/Error.hpp" 22 : #include "Utilities/Serialization/CharmPupable.hpp" 23 : #include "Utilities/TMPL.hpp" 24 : 25 : namespace Elasticity::Solutions { 26 : 27 : namespace detail { 28 : template <typename DataType> 29 : struct HalfSpaceMirrorVariables { 30 : struct DisplacementR : db::SimpleTag { 31 : using type = Scalar<DataType>; 32 : }; 33 : using Cache = 34 : CachedTempBuffer<DisplacementR, Tags::Displacement<3>, Tags::Strain<3>, 35 : Tags::MinusStress<3>, Tags::PotentialEnergyDensity<3>, 36 : ::Tags::FixedSource<Tags::Displacement<3>>>; 37 : 38 : const tnsr::I<DataType, 3>& x; 39 : const double beam_width; 40 : const ConstitutiveRelations::IsotropicHomogeneous<3>& constitutive_relation; 41 : const size_t integration_intervals; 42 : const double absolute_tolerance; 43 : const double relative_tolerance; 44 : 45 : void operator()(gsl::not_null<Scalar<DataType>*> displacement_r, 46 : gsl::not_null<Cache*> cache, DisplacementR /*meta*/) const; 47 : void operator()(gsl::not_null<tnsr::I<DataType, 3>*> displacement, 48 : gsl::not_null<Cache*> cache, 49 : Tags::Displacement<3> /*meta*/) const; 50 : void operator()(gsl::not_null<tnsr::ii<DataType, 3>*> strain, 51 : gsl::not_null<Cache*> cache, Tags::Strain<3> /*meta*/) const; 52 : void operator()(gsl::not_null<tnsr::II<DataType, 3>*> minus_stress, 53 : gsl::not_null<Cache*> cache, 54 : Tags::MinusStress<3> /*meta*/) const; 55 : void operator()(gsl::not_null<Scalar<DataType>*> potential_energy_density, 56 : gsl::not_null<Cache*> cache, 57 : Tags::PotentialEnergyDensity<3> /*meta*/) const; 58 : void operator()( 59 : gsl::not_null<tnsr::I<DataType, 3>*> fixed_source_for_displacement, 60 : gsl::not_null<Cache*> cache, 61 : ::Tags::FixedSource<Tags::Displacement<3>> /*meta*/) const; 62 : }; 63 : } // namespace detail 64 : 65 : /*! 66 : * \brief The solution for a half-space mirror deformed by a laser beam. 67 : * 68 : * \details This solution is mapping (via the fluctuation dissipation theorem) 69 : * thermal noise to an elasticity problem where a normally incident and 70 : * axisymmetric laser beam with a Gaussian beam profile acts on the face of a 71 : * semi-infinite mirror. Here we assume the face to be at \f$z = 0\f$ and the 72 : * material to extend to \f$+\infty\f$ in the z-direction as well as for the 73 : * mirror diameter to be comparatively large to the `beam width`. The mirror 74 : * material is characterized by an isotropic homogeneous constitutive relation 75 : * \f$Y^{ijkl}\f$ (see 76 : * `Elasticity::ConstitutiveRelations::IsotropicHomogeneous`). In this scenario, 77 : * the auxiliary elastic problem has an applied pressure distribution equal to 78 : * the laser beam intensity profile \f$p(r)\f$ (see Eq. (11.94) and Eq. (11.95) 79 : * in \cite ThorneBlandford2017 with F = 1 and the time dependency dropped) 80 : * 81 : * \f{align} 82 : * T^{zr} &= T^{rz} = 0 \\ 83 : * T^{zz} &= p(r) = \frac{e^{-\frac{r^2}{r_0^2}}}{\pi r_0^2}\text{.} 84 : * \f} 85 : * 86 : * in the form of a Neumann boundary condition to the face of the mirror. We 87 : * find that this stress in cylinder coordinates is produced by the displacement 88 : * field 89 : * 90 : * \f{align} 91 : * \xi_{r} &= \frac{1}{2 \mu} \int_0^{\infty} dk J_1(kr)e^{(-kz)}\left(1 - 92 : * \frac{\lambda + 2\mu}{\lambda + \mu} + kz \right) \tilde{p}(k) \\ 93 : * \xi_{\phi} &= 0 \\ 94 : * \xi_{z} &= \frac{1}{2 \mu} \int_0^{\infty} dk J_0(kr)e^{(-kz)}\left(1 + 95 : * \frac{\mu}{\lambda + \mu} + kz \right) \tilde{p}(k) 96 : * \f} 97 : * 98 : * and the strain 99 : * 100 : * \f{align} 101 : * \Theta &= \frac{1}{2 \mu} \int_0^{\infty} dk 102 : * J_0(kr) k e^{(-kz)}\left(\frac{-2\mu}{\lambda + \mu}\right) \tilde{p}(k) \\ 103 : * S_{rr} &= \Theta - S_{\phi\phi} - S_{zz} \\ 104 : * S_{\phi\phi} &= \frac{\xi_{r}}{r} \\ 105 : * S_{(rz)} &= -\frac{1}{2 \mu} \int_0^{\infty} dk J_1(kr) k e^{(-kz)}\left(kz 106 : * \right) \tilde{p}(k) \\ 107 : * S_{zz} &= \frac{1}{2 \mu} \int_0^{\infty} dk 108 : * J_0(kr) k e^{(-kz)}\left(-\frac{\mu}{\lambda + \mu} - kz \right) \tilde{p}(k) 109 : * \f} 110 : * 111 : * (see Eqs. (11 a) - (11 c) and (13 a) - (13 e), with (13 c) swapped in favor 112 : * of (12 c) in \cite Lovelace2007tn), where \f$\tilde{p}(k)= \frac{1}{2\pi} 113 : * e^{-(\frac{kr_0}{2})^2}\f$ is the Hankel-Transform of the lasers intensity 114 : * profile and \f$ \Theta = \mathrm{Tr}(S)\f$ the materials expansion. 115 : * 116 : */ 117 1 : class HalfSpaceMirror : public elliptic::analytic_data::AnalyticSolution { 118 : public: 119 0 : using constitutive_relation_type = 120 : Elasticity::ConstitutiveRelations::IsotropicHomogeneous<3>; 121 : 122 0 : struct BeamWidth { 123 0 : using type = double; 124 0 : static constexpr Options::String help{ 125 : "The lasers beam width r_0 with FWHM = 2*sqrt(ln 2)*r_0"}; 126 0 : static type lower_bound() { return 0.0; } 127 : }; 128 : 129 0 : struct Material { 130 0 : using type = constitutive_relation_type; 131 0 : static constexpr Options::String help{ 132 : "The material properties of the beam"}; 133 : }; 134 : 135 0 : struct IntegrationIntervals { 136 0 : using type = size_t; 137 0 : static constexpr Options::String help{ 138 : "Workspace size for numerical integrals. Increase if integrals fail to " 139 : "reach the prescribed tolerance at large distances relative to the " 140 : "beam width. The suggested values for workspace size and tolerances " 141 : "should accommodate distances of up to ~100 beam widths."}; 142 0 : static type lower_bound() { return 1; } 143 0 : static type suggested_value() { return 350; } 144 : }; 145 : 146 0 : struct AbsoluteTolerance { 147 0 : using type = double; 148 0 : static constexpr Options::String help{ 149 : "Absolute tolerance for numerical integrals"}; 150 0 : static type lower_bound() { return 0.; } 151 0 : static type suggested_value() { return 1e-12; } 152 : }; 153 : 154 0 : struct RelativeTolerance { 155 0 : using type = double; 156 0 : static constexpr Options::String help{ 157 : "Relative tolerance for numerical integrals"}; 158 0 : static type lower_bound() { return 0.; } 159 0 : static type upper_bound() { return 1.; } 160 0 : static type suggested_value() { return 1e-10; } 161 : }; 162 : 163 0 : using options = tmpl::list<BeamWidth, Material, IntegrationIntervals, 164 : AbsoluteTolerance, RelativeTolerance>; 165 0 : static constexpr Options::String help{ 166 : "A semi-infinite mirror on which a laser introduces stress perpendicular " 167 : "to the mirrors surface."}; 168 : 169 0 : HalfSpaceMirror() = default; 170 0 : HalfSpaceMirror(const HalfSpaceMirror&) = default; 171 0 : HalfSpaceMirror& operator=(const HalfSpaceMirror&) = default; 172 0 : HalfSpaceMirror(HalfSpaceMirror&&) = default; 173 0 : HalfSpaceMirror& operator=(HalfSpaceMirror&&) = default; 174 0 : ~HalfSpaceMirror() override = default; 175 0 : std::unique_ptr<elliptic::analytic_data::AnalyticSolution> get_clone() 176 : const override { 177 : return std::make_unique<HalfSpaceMirror>(*this); 178 : } 179 : 180 : /// \cond 181 : explicit HalfSpaceMirror(CkMigrateMessage* m) 182 : : elliptic::analytic_data::AnalyticSolution(m) {} 183 : using PUP::able::register_constructor; 184 : WRAPPED_PUPable_decl_template(HalfSpaceMirror); // NOLINT 185 : /// \endcond 186 : 187 0 : HalfSpaceMirror(double beam_width, 188 : constitutive_relation_type constitutive_relation, 189 : size_t integration_intervals = 350, 190 : double absolute_tolerance = 1e-12, 191 : double relative_tolerance = 1e-10) 192 : : beam_width_(beam_width), 193 : constitutive_relation_(std::move(constitutive_relation)), 194 : integration_intervals_(integration_intervals), 195 : absolute_tolerance_(absolute_tolerance), 196 : relative_tolerance_(relative_tolerance) {} 197 : 198 0 : double beam_width() const { return beam_width_; } 199 0 : size_t integration_intervals() const { return integration_intervals_; } 200 0 : double absolute_tolerance() const { return absolute_tolerance_; } 201 0 : double relative_tolerance() const { return relative_tolerance_; } 202 : 203 0 : const constitutive_relation_type& constitutive_relation() const { 204 : return constitutive_relation_; 205 : } 206 : 207 : template <typename DataType, typename... RequestedTags> 208 0 : tuples::TaggedTuple<RequestedTags...> variables( 209 : const tnsr::I<DataType, 3>& x, 210 : tmpl::list<RequestedTags...> /*meta*/) const { 211 : for (size_t i = 0; i < get_size(get<2>(x)); i++) { 212 : if (UNLIKELY(get_element(get<2>(x), i) < 0)) { 213 : ERROR( 214 : "The HalfSpaceMirror solution is not defined for negative values " 215 : "of z."); 216 : } 217 : } 218 : using VarsComputer = detail::HalfSpaceMirrorVariables<DataType>; 219 : typename VarsComputer::Cache cache{get_size(*x.begin())}; 220 : const VarsComputer computer{x, 221 : beam_width_, 222 : constitutive_relation_, 223 : integration_intervals_, 224 : absolute_tolerance_, 225 : relative_tolerance_}; 226 : return {cache.get_var(computer, RequestedTags{})...}; 227 : } 228 : 229 : template <typename... RequestedTags> 230 0 : tuples::TaggedTuple<RequestedTags...> variables( 231 : const tnsr::I<DataVector, 3>& x, const Mesh<3>& /*mesh*/, 232 : const InverseJacobian<DataVector, 3, Frame::ElementLogical, 233 : Frame::Inertial>& /*inv_jacobian*/, 234 : tmpl::list<RequestedTags...> meta) const { 235 : return variables(x, meta); 236 : } 237 : 238 : /// NOLINTNEXTLINE(google-runtime-references) 239 1 : void pup(PUP::er& p) override { 240 : elliptic::analytic_data::AnalyticSolution::pup(p); 241 : p | beam_width_; 242 : p | constitutive_relation_; 243 : p | integration_intervals_; 244 : p | absolute_tolerance_; 245 : p | relative_tolerance_; 246 : } 247 : 248 : private: 249 0 : double beam_width_{std::numeric_limits<double>::signaling_NaN()}; 250 0 : constitutive_relation_type constitutive_relation_{}; 251 0 : size_t integration_intervals_{std::numeric_limits<size_t>::max()}; 252 0 : double absolute_tolerance_{std::numeric_limits<double>::signaling_NaN()}; 253 0 : double relative_tolerance_{std::numeric_limits<double>::signaling_NaN()}; 254 : }; 255 : 256 0 : bool operator==(const HalfSpaceMirror& lhs, const HalfSpaceMirror& rhs); 257 0 : bool operator!=(const HalfSpaceMirror& lhs, const HalfSpaceMirror& rhs); 258 : 259 : } // namespace Elasticity::Solutions