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

Generated by: LCOV version 1.14