SpECTRE Documentation Coverage Report
Current view: top level - PointwiseFunctions/AnalyticSolutions/Elasticity - HalfSpaceMirror.hpp Hit Total Coverage
Commit: ecb8a275e1aebab77dcce48a5e098ed4e486ab4b Lines: 2 51 3.9 %
Date: 2026-08-22 01:05:40
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.14