SpECTRE Documentation Coverage Report
Current view: top level - Evolution/Systems/Cce - GaugeTransformBoundaryData.hpp Hit Total Coverage
Commit: 817e13c5144619b701c7cd870655d8dbf94ab8ce Lines: 19 74 25.7 %
Date: 2024-07-19 22:17:05
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             : 
       8             : #include "DataStructures/ComplexDataVector.hpp"
       9             : #include "DataStructures/DataBox/Prefixes.hpp"
      10             : #include "DataStructures/SpinWeighted.hpp"
      11             : #include "DataStructures/Tags.hpp"
      12             : #include "DataStructures/Tensor/IndexType.hpp"
      13             : #include "DataStructures/Tensor/Tensor.hpp"
      14             : #include "DataStructures/Tensor/TypeAliases.hpp"
      15             : #include "DataStructures/Variables.hpp"
      16             : #include "Evolution/Systems/Cce/Tags.hpp"
      17             : #include "NumericalAlgorithms/SpinWeightedSphericalHarmonics/SwshCollocation.hpp"
      18             : #include "NumericalAlgorithms/SpinWeightedSphericalHarmonics/SwshDerivatives.hpp"
      19             : #include "NumericalAlgorithms/SpinWeightedSphericalHarmonics/SwshInterpolation.hpp"
      20             : #include "Utilities/Gsl.hpp"
      21             : #include "Utilities/TMPL.hpp"
      22             : 
      23             : namespace Cce {
      24             : 
      25             : namespace Tags {
      26             : /// \cond
      27             : struct LMax;
      28             : /// \endcond
      29             : }  // namespace Tags
      30             : 
      31             : /// The set of tags that should be calculated before the initial data is
      32             : /// computed on the first hypersurface.
      33           1 : using gauge_adjustments_setup_tags =
      34             :     tmpl::list<Tags::BondiR, Tags::BondiJ, Tags::Dr<Tags::BondiJ>>;
      35             : 
      36             : /*!
      37             :  * \brief Computes the gauge-transformed
      38             :  * `Tags::EvolutionGaugeBoundaryValue<Tag>` for any of the boundary tags needed
      39             :  * in the evolution.
      40             :  *
      41             :  * \details Most of these computations involve first interpolating via a
      42             :  * `Spectral::Swsh::SwshInterpolator` to the new angular grid, followed by
      43             :  * manipulations associated with the tensor transformation of the metric and its
      44             :  * derivatives. Individual template specializations contain detailed
      45             :  * explanations about the respective gauge transformations.
      46             :  */
      47             : template <typename Tag>
      48           1 : struct GaugeAdjustedBoundaryValue;
      49             : 
      50             : /*!
      51             :  * \brief Computes the evolution gauge Bondi \f$\hat R\f$ on the worldtube from
      52             :  * Cauchy gauge quantities
      53             :  *
      54             :  * \details The evolution gauge Bondi \f$\hat R\f$ obeys:
      55             :  *
      56             :  * \f{align*}{
      57             :  * \hat R = \hat \omega R(\hat x^{\hat A}),
      58             :  * \f}
      59             :  *
      60             :  * where the evaluation of \f$R\f$ at \f$\hat x^{\hat A}\f$ requires an
      61             :  * interpolation to the evolution coordinates, and \f$\hat \omega\f$ is the
      62             :  * conformal factor associated with the angular part of the gauge
      63             :  * transformation.
      64             :  */
      65             : template <>
      66           1 : struct GaugeAdjustedBoundaryValue<Tags::BondiR> {
      67           0 :   using return_tags =
      68             :       tmpl::list<Tags::EvolutionGaugeBoundaryValue<Tags::BondiR>>;
      69           0 :   using argument_tags = tmpl::list<
      70             :       Tags::BoundaryValue<Tags::BondiR>, Tags::PartiallyFlatGaugeOmega,
      71             :       Spectral::Swsh::Tags::SwshInterpolator<Tags::CauchyAngularCoords>>;
      72             : 
      73           0 :   static void apply(
      74             :       gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, 0>>*>
      75             :           evolution_gauge_r,
      76             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& cauchy_gauge_r,
      77             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& omega,
      78             :       const Spectral::Swsh::SwshInterpolator& interpolator);
      79             : };
      80             : 
      81             : /*!
      82             :  * \brief Computes the evolution gauge \f$\partial_{\hat u} \hat R / \hat R\f$
      83             :  * on the worldtube.
      84             :  *
      85             :  * \details The evolution gauge quantity \f$ \partial_{\hat u} \hat R / \hat
      86             :  * R\f$ obeys
      87             :  *
      88             :  * \f{align*}{
      89             :  *  \frac{\partial_{\hat u} \hat R}{ \hat R}
      90             :  * = \frac{\partial_u R (\hat x^{\hat A})}{R(\hat x^{\hat A})}
      91             :  * + \frac{\partial_{\hat u} \hat \omega}{\hat \omega}
      92             :  * + \frac{\mathcal U^{(0)} \bar \eth R(\hat x^{\hat A})
      93             :  * + \bar{\mathcal U}^{(0)} \eth R(\hat x^{\hat A}) }{2 R(\hat x^{\hat A})}
      94             :  * \f}
      95             :  *
      96             :  * note that the terms proportional to \f$\eth R\f$ or its conjugate arise from
      97             :  * the conversion between \f$\partial_u\f$ and \f$\partial_{\hat u}f\f$. The
      98             :  * right-hand side quantities with explicit \f$\hat x\f$ require interpolation.
      99             :  * \f$\mathcal U^{(0)}\f$ is the asymptotic quantity determined by
     100             :  * `GaugeUpdateTimeDerivatives`.
     101             :  */
     102             : template <>
     103           1 : struct GaugeAdjustedBoundaryValue<Tags::DuRDividedByR> {
     104           0 :   using return_tags =
     105             :       tmpl::list<Tags::EvolutionGaugeBoundaryValue<Tags::DuRDividedByR>>;
     106           0 :   using argument_tags = tmpl::list<
     107             :       Tags::BoundaryValue<Tags::DuRDividedByR>, Tags::BondiUAtScri,
     108             :       Tags::EvolutionGaugeBoundaryValue<Tags::BondiR>,
     109             :       Tags::PartiallyFlatGaugeOmega, Tags::Du<Tags::PartiallyFlatGaugeOmega>,
     110             :       Spectral::Swsh::Tags::SwshInterpolator<Tags::CauchyAngularCoords>,
     111             :       Tags::LMax>;
     112             : 
     113           0 :   static void apply(
     114             :       gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, 0>>*>
     115             :           evolution_gauge_du_r_divided_by_r,
     116             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>&
     117             :           cauchy_gauge_du_r_divided_by_r,
     118             :       const Scalar<SpinWeighted<ComplexDataVector, 1>>& bondi_u_at_scri,
     119             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& evolution_gauge_r,
     120             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& omega,
     121             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& du_omega,
     122             :       const Spectral::Swsh::SwshInterpolator& interpolator, size_t l_max);
     123             : };
     124             : 
     125             : /*!
     126             :  * \brief Computes the evolution gauge quantity \f$\hat J\f$ on the worldtube
     127             :  *
     128             :  * \details The evolution gauge quantity \f$\hat J\f$ obeys
     129             :  *
     130             :  * \f{align*}{
     131             :  * \hat J = \frac{1}{4 \hat{\omega}^2} \left( \bar{\hat d}^2  J(\hat x^{\hat A})
     132             :  * + \hat c^2 \bar J(\hat x^{\hat A})
     133             :  * + 2 \hat c \bar{\hat d} K(\hat x^{\hat A}) \right)
     134             :  * \f}
     135             :  *
     136             :  * Where \f$\hat c\f$ and \f$\hat d\f$ are the spin-weighted angular Jacobian
     137             :  * factors computed by `GaugeUpdateJacobianFromCoords`, and \f$\hat \omega\f$ is
     138             :  * the conformal factor associated with the angular coordinate transformation.
     139             :  * Note that the right-hand sides with explicit \f$\hat x^{\hat A}\f$ dependence
     140             :  * must be interpolated and that \f$K = \sqrt{1 + J \bar J}\f$.
     141             :  */
     142             : template <>
     143           1 : struct GaugeAdjustedBoundaryValue<Tags::BondiJ> {
     144           0 :   using return_tags =
     145             :       tmpl::list<Tags::EvolutionGaugeBoundaryValue<Tags::BondiJ>>;
     146           0 :   using argument_tags = tmpl::list<
     147             :       Tags::BoundaryValue<Tags::BondiJ>, Tags::PartiallyFlatGaugeC,
     148             :       Tags::PartiallyFlatGaugeD, Tags::PartiallyFlatGaugeOmega,
     149             :       Spectral::Swsh::Tags::SwshInterpolator<Tags::CauchyAngularCoords>>;
     150             : 
     151           0 :   static void apply(
     152             :       gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, 2>>*>
     153             :           evolution_gauge_j,
     154             :       const Scalar<SpinWeighted<ComplexDataVector, 2>>& cauchy_gauge_j,
     155             :       const Scalar<SpinWeighted<ComplexDataVector, 2>>& gauge_c,
     156             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& gauge_d,
     157             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& omega,
     158             :       const Spectral::Swsh::SwshInterpolator& interpolator);
     159             : };
     160             : 
     161             : /*!
     162             :  * \brief Computes the evolution gauge quantity \f$\partial_{\hat r} \hat J\f$
     163             :  * on the worldtube
     164             :  *
     165             :  * \details The evolution gauge quantity \f$\partial_{\hat r} \hat J\f$ is
     166             :  * determined from \f$\partial_{\hat r} = \frac{\partial_r}{\hat \omega}\f$ and
     167             :  * the expression for \f$\hat J\f$ given in the documentation for
     168             :  * `GaugeAdjustedBoundaryValue<Tags::BondiJ>`
     169             :  */
     170             : template <>
     171           1 : struct GaugeAdjustedBoundaryValue<Tags::Dr<Tags::BondiJ>> {
     172           0 :   using return_tags =
     173             :       tmpl::list<Tags::EvolutionGaugeBoundaryValue<Tags::Dr<Tags::BondiJ>>>;
     174           0 :   using argument_tags = tmpl::list<
     175             :       Tags::BoundaryValue<Tags::Dr<Tags::BondiJ>>,
     176             :       Tags::BoundaryValue<Tags::BondiJ>, Tags::PartiallyFlatGaugeC,
     177             :       Tags::PartiallyFlatGaugeD, Tags::PartiallyFlatGaugeOmega,
     178             :       Spectral::Swsh::Tags::SwshInterpolator<Tags::CauchyAngularCoords>,
     179             :       Tags::LMax>;
     180             : 
     181           0 :   static void apply(
     182             :       gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, 2>>*>
     183             :           evolution_gauge_dr_j,
     184             :       const Scalar<SpinWeighted<ComplexDataVector, 2>>& cauchy_gauge_dr_j,
     185             :       const Scalar<SpinWeighted<ComplexDataVector, 2>>& cauchy_gauge_j,
     186             :       const Scalar<SpinWeighted<ComplexDataVector, 2>>& gauge_c,
     187             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& gauge_d,
     188             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& omega,
     189             :       const Spectral::Swsh::SwshInterpolator& interpolator, size_t l_max);
     190             : };
     191             : 
     192             : /*!
     193             :  * \brief Computes the evolution gauge quantity \f$\hat \beta\f$ on the
     194             :  * worldtube
     195             :  *
     196             :  * \details The evolution gauge quantity \f$\hat \beta\f$ obeys
     197             :  *
     198             :  * \f{align*}{
     199             :  * e^{2 \hat \beta} = e^{2 \beta(\hat x^{\hat A})} / \hat \omega.
     200             :  * \f}
     201             :  *
     202             :  * The explicit evaluation at \f$\hat x^{\hat A}\f$ on the right-hand side
     203             :  * indicates the requirement of an interpolation step, and \f$\hat \omega\f$ is
     204             :  * the conformal factor associated with the angular transformation.
     205             :  */
     206             : template <>
     207           1 : struct GaugeAdjustedBoundaryValue<Tags::BondiBeta> {
     208           0 :   using return_tags =
     209             :       tmpl::list<Tags::EvolutionGaugeBoundaryValue<Tags::BondiBeta>>;
     210           0 :   using argument_tags = tmpl::list<
     211             :       Tags::BoundaryValue<Tags::BondiBeta>, Tags::PartiallyFlatGaugeOmega,
     212             :       Spectral::Swsh::Tags::SwshInterpolator<Tags::CauchyAngularCoords>>;
     213             : 
     214           0 :   static void apply(
     215             :       gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, 0>>*>
     216             :           evolution_gauge_beta,
     217             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& cauchy_gauge_beta,
     218             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& omega,
     219             :       const Spectral::Swsh::SwshInterpolator& interpolator);
     220             : };
     221             : 
     222             : /*!
     223             :  * \brief Computes the evolution gauge quantity \f$\hat Q\f$ on the worldtube.
     224             :  *
     225             :  * \details The evolution gauge quantity \f$\hat Q\f$ obeys
     226             :  *
     227             :  * \f{align*}{
     228             :  * \hat Q =& \hat r^2 e^{-2 \hat \beta} (\hat K \partial_{\hat r} \hat U
     229             :  * + \hat J \partial_{\hat r} \hat{\bar U}),\\
     230             :  * \partial_{\hat r} \hat U
     231             :  * =& \frac{1}{2 \hat \omega^3}\left(\hat{\bar d} \partial_r U(\hat x^{\hat A})
     232             :  * - \hat c \partial_r \bar U(\hat x^{\hat A})\right)
     233             :  * + \frac{e^{2\hat \beta}}{\hat r^2 \hat \omega}
     234             :  * \left(\hat J \hat{\bar{\eth}} \hat \omega
     235             :  * - \hat K \hat \eth \hat \omega\right)
     236             :  * \left(-1 + \partial_{\hat y} \hat{\bar{J}} \partial_{\hat y} \hat J
     237             :  * - \left[\frac{\partial_{\hat y}(\hat J \hat{\bar{J}})}
     238             :  * {2 \hat K}\right]^2\right) \notag \\
     239             :  * & + 2 \frac{e^{2 \hat \beta}}{\hat \omega \hat r^2}
     240             :  * \left[ \hat{\bar{\eth}} \hat \omega \partial_{\hat y} \hat J
     241             :  * + \hat{\eth} \hat \omega \left(-\frac{\hat J \partial_{\hat y}
     242             :  * \hat{\bar J}
     243             :  * + \hat{\bar J} \partial_{\hat y} \hat J}{2 \hat K}\right) \right].
     244             :  * \f}
     245             :  *
     246             :  * where the explicit argument \f$\hat x^{\hat A}\f$ on the right-hand side
     247             :  * implies the need for an interpolation operation, and
     248             :  * \f$K = \sqrt{1 + J \bar J}\f$.
     249             :  */
     250             : template <>
     251           1 : struct GaugeAdjustedBoundaryValue<Tags::BondiQ> {
     252           0 :   using return_tags =
     253             :       tmpl::list<Tags::EvolutionGaugeBoundaryValue<Tags::BondiQ>>;
     254             : 
     255           0 :   using argument_tags = tmpl::list<
     256             :       Tags::BoundaryValue<Tags::Dr<Tags::BondiU>>, Tags::BondiJ,
     257             :       Tags::Dy<Tags::BondiJ>, Tags::EvolutionGaugeBoundaryValue<Tags::BondiR>,
     258             :       Tags::EvolutionGaugeBoundaryValue<Tags::BondiBeta>,
     259             :       Tags::PartiallyFlatGaugeC, Tags::PartiallyFlatGaugeD,
     260             :       Tags::PartiallyFlatGaugeOmega,
     261             :       Spectral::Swsh::Tags::Derivative<Tags::PartiallyFlatGaugeOmega,
     262             :                                        Spectral::Swsh::Tags::Eth>,
     263             :       Spectral::Swsh::Tags::SwshInterpolator<Tags::CauchyAngularCoords>,
     264             :       Tags::LMax>;
     265             : 
     266           0 :   static void apply(
     267             :       const gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, 1>>*>
     268             :           evolution_gauge_q,
     269             :       const Scalar<SpinWeighted<ComplexDataVector, 1>>& cauchy_gauge_dr_u,
     270             :       const Scalar<SpinWeighted<ComplexDataVector, 2>>& volume_j,
     271             :       const Scalar<SpinWeighted<ComplexDataVector, 2>>& volume_dy_j,
     272             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& evolution_gauge_r,
     273             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& evolution_gauge_beta,
     274             :       const Scalar<SpinWeighted<ComplexDataVector, 2>>& gauge_c,
     275             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& gauge_d,
     276             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& omega,
     277             :       const Scalar<SpinWeighted<ComplexDataVector, 1>>& eth_omega,
     278             :       const Spectral::Swsh::SwshInterpolator& interpolator,
     279             :       const size_t l_max) {
     280             :     apply_impl(make_not_null(&get(*evolution_gauge_q)), get(cauchy_gauge_dr_u),
     281             :                get(volume_j), get(volume_dy_j), get(evolution_gauge_r),
     282             :                get(evolution_gauge_beta), get(gauge_c), get(gauge_d),
     283             :                get(omega), get(eth_omega), interpolator, l_max);
     284             :   }
     285             : 
     286             :  private:
     287           0 :   static void apply_impl(
     288             :       gsl::not_null<SpinWeighted<ComplexDataVector, 1>*> evolution_gauge_q,
     289             :       const SpinWeighted<ComplexDataVector, 1>& cauchy_gauge_dr_u,
     290             :       const SpinWeighted<ComplexDataVector, 2>& volume_j,
     291             :       const SpinWeighted<ComplexDataVector, 2>& volume_dy_j,
     292             :       const SpinWeighted<ComplexDataVector, 0>& evolution_gauge_r,
     293             :       const SpinWeighted<ComplexDataVector, 0>& evolution_gauge_beta,
     294             :       const SpinWeighted<ComplexDataVector, 2>& gauge_c,
     295             :       const SpinWeighted<ComplexDataVector, 0>& gauge_d,
     296             :       const SpinWeighted<ComplexDataVector, 0>& omega,
     297             :       const SpinWeighted<ComplexDataVector, 1>& eth_omega,
     298             :       const Spectral::Swsh::SwshInterpolator& interpolator, size_t l_max);
     299             : };
     300             : 
     301             : /*!
     302             :  * \brief Computes the evolution gauge quantity \f$\mathcal U\f$ on the
     303             :  * worldtube.
     304             :  *
     305             :  * \details Note that the boundary quantity computed by this function is, by
     306             :  * necessity, NOT the evolution gauge bondi \f$\hat U\f$, because there is
     307             :  * insufficient information at the point in the computation this will be
     308             :  * evaluated to completely determine \f$\hat{U}\f$. Instead, this determines
     309             :  * the boundary value of \f$\mathcal U\f$, which satisfies,
     310             :  *
     311             :  * \f{align*}{
     312             :  * \mathcal{U} - \mathcal{U}^{(0)} = \hat U,
     313             :  * \f}
     314             :  *
     315             :  * where the superscript \f$(0)\f$ denotes evaluation at \f$\mathcal I^+\f$. In
     316             :  * particular, the result of this computation may be used with the same
     317             :  * hypersurface equations as the full evolution gauge \f$\hat U\f$, because they
     318             :  * satisfy the same radial differential equation.
     319             :  *
     320             :  * \f$\mathcal U\f$ is computed by,
     321             :  *
     322             :  * \f{align*}{
     323             :  * \mathcal U = \frac{1}{2\hat \omega^2} \left(\hat{\bar d} U(\hat x^{\hat A})
     324             :  * - \hat c \bar U(\hat x^{\hat A}) \right)
     325             :  * - \frac{e^{2 \hat \beta}}{\hat r \hat \omega}
     326             :  * \left(\hat K \hat \eth \hat \omega
     327             :  * -  \hat J\hat{\bar{\eth}} \hat \omega\right),
     328             :  * \f}
     329             :  *
     330             :  * where the explicit argument \f$\hat x^{\hat A}\f$ on the right-hand side
     331             :  * implies the need for an interpolation operation, and
     332             :  * \f$K = \sqrt{1 + J \bar J}\f$.
     333             :  */
     334             : template <>
     335           1 : struct GaugeAdjustedBoundaryValue<Tags::BondiU> {
     336           0 :   using return_tags =
     337             :       tmpl::list<Tags::EvolutionGaugeBoundaryValue<Tags::BondiU>>;
     338           0 :   using argument_tags = tmpl::list<
     339             :       Tags::BoundaryValue<Tags::BondiU>, Tags::BondiJ,
     340             :       Tags::EvolutionGaugeBoundaryValue<Tags::BondiR>,
     341             :       Tags::EvolutionGaugeBoundaryValue<Tags::BondiBeta>,
     342             :       Tags::PartiallyFlatGaugeC, Tags::PartiallyFlatGaugeD,
     343             :       Tags::PartiallyFlatGaugeOmega,
     344             :       Spectral::Swsh::Tags::Derivative<Tags::PartiallyFlatGaugeOmega,
     345             :                                        Spectral::Swsh::Tags::Eth>,
     346             :       Spectral::Swsh::Tags::SwshInterpolator<Tags::CauchyAngularCoords>,
     347             :       Tags::LMax>;
     348             : 
     349           0 :   static void apply(
     350             :       gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, 1>>*>
     351             :           evolution_gauge_u,
     352             :       const Scalar<SpinWeighted<ComplexDataVector, 1>>& cauchy_gauge_u,
     353             :       const Scalar<SpinWeighted<ComplexDataVector, 2>>& volume_j,
     354             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& evolution_gauge_r,
     355             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& evolution_gauge_beta,
     356             :       const Scalar<SpinWeighted<ComplexDataVector, 2>>& gauge_c,
     357             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& gauge_d,
     358             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& omega,
     359             :       const Scalar<SpinWeighted<ComplexDataVector, 1>>& eth_omega,
     360             :       const Spectral::Swsh::SwshInterpolator& interpolator, size_t l_max);
     361             : };
     362             : 
     363             : /*!
     364             :  * \brief Computes the evolution gauge quantity \f$\hat W\f$ on the worldtube.
     365             :  *
     366             :  * \details The evolution gauge value \f$\hat W\f$ obeys
     367             :  *
     368             :  * \f{align*}{
     369             :  * \hat W =& W(\hat x^{\hat A}) + (\hat \omega - 1) / \hat r
     370             :  * + \frac{e^{2 \hat \beta}}{2 \hat \omega^2 \hat r}
     371             :  * \left(\hat J \left(\hat{\bar \eth} \hat \omega\right)^2
     372             :  * + \hat{\bar{J}} \left(\hat \eth \hat \omega\right) ^2
     373             :  * - 2 K \left( \hat \eth \hat \omega\right) \left(\hat{\bar \eth} \hat
     374             :  * \omega\right) \right)
     375             :  * - \frac{2 \partial_{u} \hat \omega}{\hat \omega}
     376             :  * - \frac{ \hat U \bar \eth \hat \omega + \hat{\bar U} \eth \hat \omega }
     377             :  * {\hat \omega},
     378             :  * \f}
     379             :  *
     380             :  * where the explicit argument \f$\hat x^{\hat A}\f$ on the right-hand side
     381             :  * implies the need for an interpolation operation and
     382             :  * \f$K = \sqrt{1 + J \bar J}\f$.
     383             :  */
     384             : template <>
     385           1 : struct GaugeAdjustedBoundaryValue<Tags::BondiW> {
     386           0 :   using return_tags =
     387             :       tmpl::list<Tags::EvolutionGaugeBoundaryValue<Tags::BondiW>>;
     388           0 :   using argument_tags = tmpl::list<
     389             :       Tags::BoundaryValue<Tags::BondiW>, Tags::BondiJ,
     390             :       Tags::EvolutionGaugeBoundaryValue<Tags::BondiU>,
     391             :       Tags::EvolutionGaugeBoundaryValue<Tags::BondiBeta>, Tags::BondiUAtScri,
     392             :       Tags::EvolutionGaugeBoundaryValue<Tags::BondiR>,
     393             :       Tags::PartiallyFlatGaugeOmega, Tags::Du<Tags::PartiallyFlatGaugeOmega>,
     394             :       Spectral::Swsh::Tags::Derivative<Tags::PartiallyFlatGaugeOmega,
     395             :                                        Spectral::Swsh::Tags::Eth>,
     396             :       Spectral::Swsh::Tags::SwshInterpolator<Tags::CauchyAngularCoords>,
     397             :       Tags::LMax>;
     398             : 
     399           0 :   static void apply(
     400             :       const gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, 0>>*>
     401             :           evolution_gauge_w,
     402             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& cauchy_gauge_w,
     403             :       const Scalar<SpinWeighted<ComplexDataVector, 2>>& volume_j,
     404             :       const Scalar<SpinWeighted<ComplexDataVector, 1>>& evolution_gauge_u,
     405             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& evolution_gauge_beta,
     406             :       const Scalar<SpinWeighted<ComplexDataVector, 1>>&
     407             :           evolution_gauge_u_at_scri,
     408             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& evolution_gauge_r,
     409             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& omega,
     410             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& du_omega,
     411             :       const Scalar<SpinWeighted<ComplexDataVector, 1>>& eth_omega,
     412             :       const Spectral::Swsh::SwshInterpolator& interpolator,
     413             :       const size_t l_max) {
     414             :     apply_impl(make_not_null(&get(*evolution_gauge_w)), get(cauchy_gauge_w),
     415             :                get(volume_j), get(evolution_gauge_u), get(evolution_gauge_beta),
     416             :                get(evolution_gauge_u_at_scri), get(evolution_gauge_r),
     417             :                get(omega), get(du_omega), get(eth_omega), interpolator, l_max);
     418             :   }
     419             : 
     420             :  private:
     421           0 :   static void apply_impl(
     422             :       gsl::not_null<SpinWeighted<ComplexDataVector, 0>*> evolution_gauge_w,
     423             :       const SpinWeighted<ComplexDataVector, 0>& cauchy_gauge_w,
     424             :       const SpinWeighted<ComplexDataVector, 2>& volume_j,
     425             :       const SpinWeighted<ComplexDataVector, 1>& evolution_gauge_u,
     426             :       const SpinWeighted<ComplexDataVector, 0>& evolution_gauge_beta,
     427             :       const SpinWeighted<ComplexDataVector, 1>& evolution_gauge_u_at_scri,
     428             :       const SpinWeighted<ComplexDataVector, 0>& evolution_gauge_r,
     429             :       const SpinWeighted<ComplexDataVector, 0>& omega,
     430             :       const SpinWeighted<ComplexDataVector, 0>& du_omega,
     431             :       const SpinWeighted<ComplexDataVector, 1>& eth_omega,
     432             :       const Spectral::Swsh::SwshInterpolator& interpolator, size_t l_max);
     433             : };
     434             : 
     435             : /*!
     436             :  * \brief Computes the evolution gauge quantity \f$\hat H\f$ on the worldtube.
     437             :  *
     438             :  * \details The evolution gauge \f$\hat H\f$ obeys
     439             :  *
     440             :  * \f{align*}{
     441             :  *   \hat H =&
     442             :  * \frac{1}{2} \left(\mathcal{U}^{(0)} \hat{\bar \eth} \hat J
     443             :  * + \bar{\mathcal{U}}^{(0)} \hat{\eth} \hat J\right)
     444             :  * + \frac{\partial_{\hat u} \hat \omega
     445             :  * - \tfrac{1}{2} \left(\mathcal{U}^{(0)} \bar{\hat \eth}\hat \omega
     446             :  * + \bar{\mathcal{U}}^{(0)} \hat \eth \hat \omega \right) }{\hat \omega}
     447             :  * \left(2 \hat J - 2 \partial_{\hat y} \hat J\right)
     448             :  * - \hat J\hat{\bar \eth} \mathcal{U}^{(0)}
     449             :  * + \hat K \hat \eth \bar{\mathcal{U}}^{(0)}  \notag\\
     450             :  * &+ \frac{1}{4 \hat \omega^2} \left(\hat{\bar d}^2 H(\hat x^{\hat A})
     451             :  * + \hat c^2 \bar H(\hat x^{\hat A})
     452             :  * + \hat{\bar d} \hat c \frac{H(\hat x^{\hat A}) \bar J(\hat x^{\hat A})
     453             :  * + J(\hat x^{\hat A}) \bar H(\hat x^{\hat A})}{K}\right)
     454             :  * + 2 \frac{\partial_u R}{R} \partial_{\hat y} J
     455             :  * \f}
     456             :  *
     457             :  * where the superscript \f$(0)\f$ denotes evaluation at \f$\mathcal I^+\f$ and
     458             :  * the explicit \f$\hat x^{\hat A}\f$ arguments on the right-hand side imply
     459             :  * interpolation operations, and \f$K = \sqrt{1 + J \bar J}\f$,
     460             :  * \f$\hat K = \sqrt{1 + \hat J \hat{\bar J}}\f$.
     461             :  */
     462             : template <>
     463           1 : struct GaugeAdjustedBoundaryValue<Tags::BondiH> {
     464           0 :   using return_tags =
     465             :       tmpl::list<Tags::EvolutionGaugeBoundaryValue<Tags::BondiH>>;
     466           0 :   using argument_tags = tmpl::list<
     467             :       Tags::BondiJ, Tags::BoundaryValue<Tags::Du<Tags::BondiJ>>,
     468             :       Tags::Dy<Tags::BondiJ>, Tags::BondiUAtScri,
     469             :       Tags::EvolutionGaugeBoundaryValue<Tags::BondiR>,
     470             :       Tags::PartiallyFlatGaugeC, Tags::PartiallyFlatGaugeD,
     471             :       Tags::PartiallyFlatGaugeOmega, Tags::Du<Tags::PartiallyFlatGaugeOmega>,
     472             :       Spectral::Swsh::Tags::Derivative<Tags::PartiallyFlatGaugeOmega,
     473             :                                        Spectral::Swsh::Tags::Eth>,
     474             :       Tags::EvolutionGaugeBoundaryValue<Tags::DuRDividedByR>,
     475             :       Spectral::Swsh::Tags::SwshInterpolator<Tags::CauchyAngularCoords>,
     476             :       Tags::LMax>;
     477             : 
     478           0 :   static void apply(
     479             :       const gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, 2>>*>
     480             :           evolution_gauge_h,
     481             :       const Scalar<SpinWeighted<ComplexDataVector, 2>>& volume_j,
     482             :       const Scalar<SpinWeighted<ComplexDataVector, 2>>& cauchy_gauge_du_j,
     483             :       const Scalar<SpinWeighted<ComplexDataVector, 2>>& volume_dy_j,
     484             :       const Scalar<SpinWeighted<ComplexDataVector, 1>>&
     485             :           evolution_gauge_u_at_scri,
     486             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& evolution_gauge_r,
     487             :       const Scalar<SpinWeighted<ComplexDataVector, 2>>& gauge_c,
     488             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& gauge_d,
     489             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& omega,
     490             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& du_omega,
     491             :       const Scalar<SpinWeighted<ComplexDataVector, 1>>& eth_omega,
     492             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>&
     493             :           evolution_gauge_du_r_divided_by_r,
     494             :       const Spectral::Swsh::SwshInterpolator& interpolator,
     495             :       const size_t l_max) {
     496             :     apply_impl(make_not_null(&get(*evolution_gauge_h)), get(volume_j),
     497             :                get(cauchy_gauge_du_j), get(volume_dy_j),
     498             :                get(evolution_gauge_u_at_scri), get(evolution_gauge_r),
     499             :                get(gauge_c), get(gauge_d), get(omega), get(du_omega),
     500             :                get(eth_omega), get(evolution_gauge_du_r_divided_by_r),
     501             :                interpolator, l_max);
     502             :   }
     503             : 
     504             :  private:
     505           0 :   static void apply_impl(
     506             :       gsl::not_null<SpinWeighted<ComplexDataVector, 2>*> evolution_gauge_h,
     507             :       const SpinWeighted<ComplexDataVector, 2>& volume_j,
     508             :       const SpinWeighted<ComplexDataVector, 2>& cauchy_gauge_du_j,
     509             :       const SpinWeighted<ComplexDataVector, 2>& volume_dy_j,
     510             :       const SpinWeighted<ComplexDataVector, 1>& evolution_gauge_u_at_scri,
     511             :       const SpinWeighted<ComplexDataVector, 0>& evolution_gauge_r,
     512             :       const SpinWeighted<ComplexDataVector, 2>& gauge_c,
     513             :       const SpinWeighted<ComplexDataVector, 0>& gauge_d,
     514             :       const SpinWeighted<ComplexDataVector, 0>& omega,
     515             :       const SpinWeighted<ComplexDataVector, 0>& du_omega,
     516             :       const SpinWeighted<ComplexDataVector, 1>& eth_omega,
     517             :       const SpinWeighted<ComplexDataVector, 0>&
     518             :           evolution_gauge_du_r_divided_by_r,
     519             :       const Spectral::Swsh::SwshInterpolator& interpolator, size_t l_max);
     520             : };
     521             : 
     522             : /*!
     523             :  * \brief Computes the evolution gauge quantity \f$\hat \Pi\f$ for the scalar
     524             :  * field on the worldtube.
     525             :  *
     526             :  * \details The evolution gauge \f$\hat \Pi\f$ obeys
     527             :  * \f{align*}{
     528             :  *   \hat \Pi = \partial_{t^\prime} \psi + \Re
     529             :  *   \left(\mathcal{U}^{(0)}\bar{\eth}\psi\right)
     530             :  * \f}
     531             :  *
     532             :  * where \f$\partial_{t^\prime} \psi\f$ comes from the Cauchy evolution.
     533             :  */
     534             : template <>
     535           1 : struct GaugeAdjustedBoundaryValue<Tags::KleinGordonPi> {
     536           0 :   using return_tags =
     537             :       tmpl::list<Tags::EvolutionGaugeBoundaryValue<Tags::KleinGordonPi>>;
     538           0 :   using argument_tags = tmpl::list<
     539             :       Tags::BoundaryValue<Tags::KleinGordonPi>, Tags::BondiUAtScri,
     540             :       Spectral::Swsh::Tags::SwshInterpolator<Tags::CauchyAngularCoords>,
     541             :       Tags::LMax, Tags::KleinGordonPsi>;
     542             : 
     543           0 :   static void apply(
     544             :       gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, 0>>*>
     545             :           evolution_kg_pi,
     546             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& cauchy_kg_pi,
     547             :       const Scalar<SpinWeighted<ComplexDataVector, 1>>&
     548             :           evolution_gauge_u_at_scri,
     549             :       const Spectral::Swsh::SwshInterpolator& interpolator, size_t l_max,
     550             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& volume_psi);
     551             : };
     552             : 
     553             : /*!
     554             :  * \brief Update the Cauchy gauge cartesian coordinate derivative \f$\partial_u
     555             :  * x(\hat x)\f$, as well as remaining gauge quantities \f$\mathcal U^{(0)}\f$,
     556             :  * \f$\hat U \equiv \mathcal U - \mathcal U^{(0)}\f$, and \f$\partial_{\hat u}
     557             :  * \hat \omega\f$ to maintain asymptotically inertial angular coordinates.
     558             :  *
     559             :  * \details The constraint we must satisfy to maintain the asymptotically
     560             :  * inertial angular coordinates is
     561             :  *
     562             :  * \f{align*}{
     563             :  * \partial_{\hat u} x^A =  \mathcal U^{(0) \hat A} \partial_{\hat A} x^{A},
     564             :  * \f}
     565             :  *
     566             :  * which we compute for a representative Cartesian coordinate set on the unit
     567             :  * sphere, to maintain representability and ensure that angular transform and
     568             :  * derivative operations keep the desired precision. The equation we use for the
     569             :  * Cartesian analog is:
     570             :  *
     571             :  * \f{align*}{
     572             :  * \partial_{\hat u} x^i &= \frac{1}{2} (\bar{\mathcal U}^{(0)} \hat \eth x^i +
     573             :  * \mathcal U^{(0)} \hat{\bar \eth} x^i ) \\
     574             :  * &= \text{Re}(\bar{\mathcal U}^{(0)} \hat \eth x^i)
     575             :  * \f}
     576             :  *
     577             :  * This computation completes the unfixed degrees of freedom for the coordinate
     578             :  * transformation at the boundary, so also computes the gauge quantities that
     579             :  * rely on this information \f$\mathcal U^{(0)}\f$,
     580             :  * \f$\hat U\f$, and \f$\partial_{\hat u} \hat \omega\f$.
     581             :  *
     582             :  * The time derivative of \f$\hat \omega\f$ is calculated from the equation
     583             :  * \f{align*}{
     584             :  * \partial_{\hat u} \hat \omega
     585             :  * = \frac{\hat \omega}{4} (\hat{\bar \eth} \mathcal U^{(0)}
     586             :  * + \hat \eth \bar{\mathcal U}^{(0)})
     587             :  * + \frac{1}{2} (\mathcal U^{(0)} \hat{\bar \eth} \hat \omega
     588             :  * + \bar{\mathcal U}^{(0)} \hat \eth \hat \omega)
     589             :  * \f}
     590             :  * \warning Before this update call the quantity stored in the tag
     591             :  * `Cce::Tags::BondiU` represents \f$\mathcal U\f$, and after this update call,
     592             :  * it represents \f$\hat U\f$ (the true evolution gauge quantity).
     593             :  */
     594           1 : struct GaugeUpdateTimeDerivatives {
     595           0 :   using return_tags =
     596             :       tmpl::list<::Tags::dt<Tags::CauchyCartesianCoords>, Tags::BondiUAtScri,
     597             :                  Tags::BondiU, Tags::Du<Tags::PartiallyFlatGaugeOmega>>;
     598           0 :   using argument_tags =
     599             :       tmpl::list<Tags::CauchyCartesianCoords, Tags::PartiallyFlatGaugeOmega,
     600             :                  Spectral::Swsh::Tags::Derivative<Tags::PartiallyFlatGaugeOmega,
     601             :                                                   Spectral::Swsh::Tags::Eth>,
     602             :                  Tags::LMax>;
     603             : 
     604           0 :   static void apply(
     605             :       gsl::not_null<tnsr::i<DataVector, 3>*> cartesian_cauchy_du_x,
     606             :       gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, 1>>*>
     607             :           evolution_gauge_u_at_scri,
     608             :       gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, 1>>*> volume_u,
     609             :       gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, 0>>*> du_omega,
     610             :       const tnsr::i<DataVector, 3>& cartesian_cauchy_coordinates,
     611             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& omega,
     612             :       const Scalar<SpinWeighted<ComplexDataVector, 1>>& eth_omega,
     613             :       size_t l_max);
     614             : };
     615             : 
     616             : /*!
     617             :  * \brief Update the inertial gauge cartesian coordinate derivative
     618             :  * \f$\partial_u \hat x(x)\f$.
     619             :  *
     620             :  * \details For the asymptotically inertial angular coordinates
     621             :  * \f$\hat{x}^{\hat{A}}\f$, we have:
     622             :  *
     623             :  * \f{align*}{
     624             :  * \partial_u \hat{x}^{\hat{A}} = -U^{(0)B}\partial_B \hat{x}^{\hat{A}}
     625             :  * \f}
     626             :  *
     627             :  * and the Cartesian version reads
     628             :  *
     629             :  * \f{align*}{
     630             :  * \partial_u \hat{x}^{\hat{i}}= - \text{Re}(\bar{U}^{(0)}
     631             :  * \eth \hat{x}^{\hat{i}})
     632             :  * \f}
     633             :  *
     634             :  * Note that \f$U^{0}\f$ and \f$\mathcal U^{(0)}\f$ are related by
     635             :  *
     636             :  * \f{align*}{
     637             :  * U^{(0)} &= \frac{1}{2\omega^2} \left( \bar{d} \mathcal U^{(0)} -
     638             :  * c \bar{\mathcal U}^{(0)} \right) \\
     639             :  * &= \frac{\hat \omega^2}{2} \left( \bar{d} \mathcal U^{(0)} -
     640             :  * c \bar{\mathcal U}^{(0)} \right)
     641             :  * \f}
     642             :  *
     643             :  * see Eq. (79) of \cite Moxon2020gha.
     644             :  */
     645           1 : struct GaugeUpdateInertialTimeDerivatives {
     646           0 :   using return_tags = tmpl::list<::Tags::dt<Tags::PartiallyFlatCartesianCoords>,
     647             :                                  Tags::BondiUAtScri>;
     648           0 :   using argument_tags = tmpl::list<
     649             :       Tags::PartiallyFlatCartesianCoords, Tags::CauchyGaugeC,
     650             :       Tags::PartiallyFlatGaugeOmega, Tags::CauchyGaugeD, Tags::LMax,
     651             :       Spectral::Swsh::Tags::SwshInterpolator<Tags::PartiallyFlatAngularCoords>>;
     652           0 :   static void apply(
     653             :       gsl::not_null<tnsr::i<DataVector, 3>*> cartesian_inertial_du_x,
     654             :       gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, 1>>*>
     655             :           evolution_gauge_u_at_scri,
     656             :       const tnsr::i<DataVector, 3>& cartesian_inertial_coordinates,
     657             :       const Scalar<SpinWeighted<ComplexDataVector, 2>>& gauge_cauchy_c,
     658             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& omega,
     659             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& gauge_cauchy_d,
     660             :       size_t l_max, const Spectral::Swsh::SwshInterpolator& interpolator);
     661             : };
     662             : 
     663             : /*!
     664             :  * \brief Update the angular coordinates stored in `AngularTag` via
     665             :  * trigonometric operations applied to the Cartesian coordinates stored in
     666             :  * `CartesianTag`.
     667             :  *
     668             :  * \details This function also normalizes the Cartesian coordinates stored in
     669             :  * `CartesianTag`, which is the desired behavior for the CCE boundary
     670             :  * computation.
     671             :  */
     672             : template <typename AngularTag, typename CartesianTag>
     673           1 : struct GaugeUpdateAngularFromCartesian {
     674           0 :   using argument_tags = tmpl::list<>;
     675           0 :   using return_tags = tmpl::list<AngularTag, CartesianTag>;
     676             : 
     677           0 :   static void apply(
     678             :       const gsl::not_null<
     679             :           tnsr::i<DataVector, 2, ::Frame::Spherical<::Frame::Inertial>>*>
     680             :           angular_coordinates,
     681             :       const gsl::not_null<tnsr::i<DataVector, 3>*> cartesian_coordinates) {
     682             :     // normalize the cartesian coordinates
     683             :     const DataVector one_over_cartesian_r =
     684             :         1.0 / sqrt(square(get<0>(*cartesian_coordinates)) +
     685             :                    square(get<1>(*cartesian_coordinates)) +
     686             :                    square(get<2>(*cartesian_coordinates)));
     687             : 
     688             :     get<0>(*cartesian_coordinates) *= one_over_cartesian_r;
     689             :     get<1>(*cartesian_coordinates) *= one_over_cartesian_r;
     690             :     get<2>(*cartesian_coordinates) *= one_over_cartesian_r;
     691             : 
     692             :     const auto& x = get<0>(*cartesian_coordinates);
     693             :     const auto& y = get<1>(*cartesian_coordinates);
     694             :     const auto& z = get<2>(*cartesian_coordinates);
     695             : 
     696             :     get<0>(*angular_coordinates) = atan2(sqrt(square(x) + square(y)), z);
     697             :     get<1>(*angular_coordinates) = atan2(y, x);
     698             :   }
     699             : };
     700             : 
     701             : namespace detail {
     702             : void gauge_update_jacobian_from_coordinates_apply_impl(
     703             :     gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, 2>>*>
     704             :         gauge_factor_spin_2,
     705             :     gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, 0>>*>
     706             :         gauge_factor_spin_0,
     707             :     gsl::not_null<
     708             :         tnsr::i<DataVector, 2, ::Frame::Spherical<::Frame::Inertial>>*>
     709             :         angular_source_coordinates,
     710             :     const tnsr::i<DataVector, 3>& cartesian_source_coordinates, size_t l_max);
     711             : }  // namespace detail
     712             : 
     713             : /*!
     714             :  * \brief From the angular coordinates `AngularCoordinateTag` and the Cartesian
     715             :  * coordinates `CartesianCoordinateTag`, determine the spin-weighted Jacobian
     716             :  * factors `GaugeFactorSpin2` and `GaugeFactorSpin0`.
     717             :  *
     718             :  * \details This is most often used in the context of generating the Jacobians
     719             :  * in the evolution-gauge coordinates from the Cauchy collocation points as a
     720             :  * function of the evolution gauge coordinates. In this concrete case, the
     721             :  * `GaugeFactorSpin2` is the gauge factor \f$\hat c\f$ and takes the value
     722             :  *
     723             :  * \f{align*}{
     724             :  * \hat c = \hat q^{\hat A} \partial_{\hat A}(x^A) q_A,
     725             :  * \f}
     726             :  *
     727             :  * and the `GaugeFactorSpin0` is the gauge factor \f$\hat d\f$ and takes the
     728             :  * value
     729             :  *
     730             :  * \f{align*}{
     731             :  * \hat d = \hat{\bar q}^{\hat A} \partial_{\hat A}(x^A) q_A.
     732             :  * \f}
     733             :  *
     734             :  * The more generic template construction is employed so that the spin-weighted
     735             :  * Jacobians can also be computed between two arbitrary gauges, including the
     736             :  * inverse Jacobians associated with moving from the evolution gauge to the
     737             :  * Cauchy gauge.
     738             :  */
     739             : template <typename GaugeFactorSpin2, typename GaugeFactorSpin0,
     740             :           typename AngularCoordinateTag, typename CartesianCoordinateTag>
     741           1 : struct GaugeUpdateJacobianFromCoordinates {
     742           0 :   using return_tags =
     743             :       tmpl::list<GaugeFactorSpin2, GaugeFactorSpin0, AngularCoordinateTag>;
     744           0 :   using argument_tags = tmpl::list<CartesianCoordinateTag, Tags::LMax>;
     745             : 
     746           0 :   static void apply(
     747             :       const gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, 2>>*>
     748             :           gauge_factor_spin_2,
     749             :       const gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, 0>>*>
     750             :           gauge_factor_spin_0,
     751             :       const gsl::not_null<
     752             :           tnsr::i<DataVector, 2, ::Frame::Spherical<::Frame::Inertial>>*>
     753             :           angular_source_coordinates,
     754             :       const tnsr::i<DataVector, 3>& cartesian_source_coordinates,
     755             :       const size_t l_max) {
     756             :     detail::gauge_update_jacobian_from_coordinates_apply_impl(
     757             :         gauge_factor_spin_2, gauge_factor_spin_0, angular_source_coordinates,
     758             :         cartesian_source_coordinates, l_max);
     759             :   }
     760             : };
     761             : 
     762             : /*!
     763             :  * \brief Update the interpolator stored in
     764             :  * `Spectral::Swsh::Tags::SwshInterpolator<AngularCoordinates>`.
     765             :  *
     766             :  * \details Note that the `AngularCoordinates` associated with the interpolator
     767             :  * should be the source coordinates. For instance, when interpolating a quantity
     768             :  * defined on the Cauchy gauge collocation points to the evolution gauge
     769             :  * collocation points, the interpolator input should be the Cauchy coordinates
     770             :  * points as a function of the evolution gauge coordinates (at the evolution
     771             :  * gauge collocation points).
     772             :  */
     773             : template <typename AngularCoordinates>
     774           1 : struct GaugeUpdateInterpolator {
     775           0 :   using return_tags =
     776             :       tmpl::list<Spectral::Swsh::Tags::SwshInterpolator<AngularCoordinates>>;
     777           0 :   using argument_tags = tmpl::list<AngularCoordinates, Tags::LMax>;
     778             : 
     779           0 :   static void apply(
     780             :       const gsl::not_null<Spectral::Swsh::SwshInterpolator*> interpolator,
     781             :       const tnsr::i<DataVector, 2, ::Frame::Spherical<::Frame::Inertial>>&
     782             :           angular_coordinates,
     783             :       const size_t l_max) {
     784             :     // throw away the old interpolator and generate a new one for the current
     785             :     // grid points.
     786             :     *interpolator = Spectral::Swsh::SwshInterpolator(
     787             :         get<0>(angular_coordinates), get<1>(angular_coordinates), l_max);
     788             :   }
     789             : };
     790             : 
     791             : /*!
     792             :  * \brief Update the quantity \f$\hat \omega\f$ and \f$\hat \eth \hat \omega\f$
     793             :  * for updated spin-weighted Jacobian quantities \f$\hat c\f$ and \f$\hat d\f$.
     794             :  *
     795             :  * \details The conformal factor \f$\hat \omega\f$ can be determined by the
     796             :  * angular determinant from the spin-weighted Jacobian factors as
     797             :  *
     798             :  * \f{align*}{
     799             :  * \hat \omega = \frac{1}{2} \sqrt{\hat d \hat{\bar d} - \hat c \hat{\bar c}}.
     800             :  * \f}
     801             :  */
     802             : template <typename GaugeC, typename GaugeD, typename GaugeOmega>
     803           1 : struct GaugeUpdateOmega {
     804           0 :   using argument_tags = tmpl::list<GaugeC, GaugeD, Tags::LMax>;
     805           0 :   using return_tags = tmpl::list<
     806             :       GaugeOmega,
     807             :       Spectral::Swsh::Tags::Derivative<GaugeOmega, Spectral::Swsh::Tags::Eth>>;
     808             : 
     809           0 :   static void apply(
     810             :       gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, 0>>*> omega,
     811             :       gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, 1>>*> eth_omega,
     812             :       const Scalar<SpinWeighted<ComplexDataVector, 2>>& gauge_c,
     813             :       const Scalar<SpinWeighted<ComplexDataVector, 0>>& gauge_d, size_t l_max);
     814             : };
     815             : 
     816             : /*!
     817             :  * \brief Initialize to default values (identity transform) all of the angular
     818             :  * gauge quantities for the boundary gauge transforms.
     819             :  *
     820             :  * \details The updated quantities are the Cauchy angular and Cartesian
     821             :  * coordinates, as well as the spin-weighted gauge factors and the conformal
     822             :  * factor. All quantities are initialized to the appropriate value for the
     823             :  * identity transform of angular coordinates. Using this initialization function
     824             :  * ensures that the evolution gauge and the Cauchy gauge angular coordinates
     825             :  * agree on the first evaluated time.
     826             :  * - `CauchyAngularCoords` are set to the angular collocation values for the
     827             :  * spin-weighted spherical harmonic library
     828             :  * - `CauchyCartesianCoords` are set to the Cartesian coordinates for the
     829             :  * `CauchyAngularCoords` evaluated on a unit sphere.
     830             :  * - `GaugeC` is set to 0
     831             :  * - `GaugeD` is set to 2
     832             :  * - `GaugeOmega` is set to 1
     833             :  */
     834           1 : struct InitializeGauge {
     835           0 :   using return_tags =
     836             :       tmpl::list<Tags::CauchyAngularCoords, Tags::CauchyCartesianCoords,
     837             :                  Tags::PartiallyFlatGaugeC, Tags::PartiallyFlatGaugeD,
     838             :                  Tags::PartiallyFlatGaugeOmega>;
     839           0 :   using argument_tags = tmpl::list<Tags::LMax>;
     840             : 
     841           0 :   static void apply(
     842             :       gsl::not_null<
     843             :           tnsr::i<DataVector, 2, ::Frame::Spherical<::Frame::Inertial>>*>
     844             :           angular_cauchy_coordinates,
     845             :       gsl::not_null<tnsr::i<DataVector, 3>*> cartesian_cauchy_coordinates,
     846             :       gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, 2>>*> gauge_c,
     847             :       gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, 0>>*> gauge_d,
     848             :       gsl::not_null<Scalar<SpinWeighted<ComplexDataVector, 0>>*> omega,
     849             :       size_t l_max);
     850             : };
     851             : }  // namespace Cce

Generated by: LCOV version 1.14