SpECTRE Documentation Coverage Report
Current view: top level - Evolution/Systems/Ccz4/FiniteDifference - SoTimeDerivative.hpp Hit Total Coverage
Commit: 3ffcbc8ecf43797401b60bcca17d6040ee06f013 Lines: 1 4 25.0 %
Date: 2026-03-03 02:01:44
Legend: Lines: hit not hit

          Line data    Source code
       1           0 : // Distributed under the MIT License.
       2             : // See LICENSE.txt for details.
       3             : #pragma once
       4             : 
       5             : #include <cmath>
       6             : #include <cstddef>
       7             : 
       8             : #include "DataStructures/DataBox/AsAccess.hpp"
       9             : #include "DataStructures/DataBox/DataBox.hpp"
      10             : #include "DataStructures/DataBox/PrefixHelpers.hpp"
      11             : #include "DataStructures/DataBox/Prefixes.hpp"
      12             : #include "DataStructures/DataVector.hpp"
      13             : #include "DataStructures/TaggedContainers.hpp"
      14             : #include "DataStructures/Tensor/EagerMath/DeterminantAndInverse.hpp"
      15             : #include "DataStructures/Tensor/Tensor.hpp"
      16             : #include "DataStructures/Variables.hpp"
      17             : #include "DataStructures/VectorImpl.hpp"
      18             : #include "Evolution/DgSubcell/Tags/GhostDataForReconstruction.hpp"
      19             : #include "Evolution/DgSubcell/Tags/Jacobians.hpp"
      20             : #include "Evolution/DgSubcell/Tags/Mesh.hpp"
      21             : #include "Evolution/Systems/Ccz4/BoundaryConditions/BoundaryCondition.hpp"
      22             : #include "Evolution/Systems/Ccz4/BoundaryConditions/Sommerfeld.hpp"
      23             : #include "Evolution/Systems/Ccz4/Christoffel.hpp"
      24             : #include "Evolution/Systems/Ccz4/DerivChristoffel.hpp"
      25             : #include "Evolution/Systems/Ccz4/DerivLapse.hpp"
      26             : #include "Evolution/Systems/Ccz4/DerivZ4Constraint.hpp"
      27             : #include "Evolution/Systems/Ccz4/FiniteDifference/BoundaryConditionGhostData.hpp"
      28             : #include "Evolution/Systems/Ccz4/FiniteDifference/Derivatives.hpp"
      29             : #include "Evolution/Systems/Ccz4/FiniteDifference/Tags.hpp"
      30             : #include "Evolution/Systems/Ccz4/Ricci.hpp"
      31             : #include "Evolution/Systems/Ccz4/RicciScalarPlusDivergenceZ4Constraint.hpp"
      32             : #include "Evolution/Systems/Ccz4/Tags.hpp"
      33             : #include "Evolution/Systems/Ccz4/TagsDeclarations.hpp"
      34             : #include "Evolution/Systems/Ccz4/TempTags.hpp"
      35             : #include "Evolution/Systems/Ccz4/TimeDerivative.hpp"
      36             : #include "Evolution/Systems/Ccz4/Z4Constraint.hpp"
      37             : #include "Utilities/CallWithDynamicType.hpp"
      38             : #include "Utilities/ConstantExpressions.hpp"
      39             : #include "Utilities/ContainerHelpers.hpp"
      40             : #include "Utilities/ErrorHandling/Assert.hpp"
      41             : #include "Utilities/ErrorHandling/Error.hpp"
      42             : #include "Utilities/Gsl.hpp"
      43             : #include "Utilities/TMPL.hpp"
      44             : 
      45             : /*!
      46             :  * \brief The namespace for evolving the second-order Ccz4 system.
      47             :  * Spatial derivatives are computed using 4-th order finite
      48             :  * differencing. Currently this system only works in 3D.
      49             :  */
      50             : namespace Ccz4::fd {
      51           0 : const size_t Dim = 3;
      52             : 
      53             : namespace detail {
      54             : // Calculate the time derivative of the evolved variables for the second-order
      55             : // Ccz4 system. There is quite some overlap between this apply() funcion
      56             : // and the apply() function in the first-order Ccz4 system. However,
      57             : // it is not straightforward to directly reuse the first-order
      58             : // apply() function as the function signatures differ significantly.
      59             : template <size_t Dim>
      60             : static void apply(
      61             :     // LHS time derivatives of evolved variables: eq 4(a) - 4(i)
      62             :     const gsl::not_null<tnsr::ii<DataVector, Dim>*> dt_conformal_spatial_metric,
      63             :     const gsl::not_null<Scalar<DataVector>*> dt_lapse,
      64             :     const gsl::not_null<tnsr::I<DataVector, Dim>*> dt_shift,
      65             :     const gsl::not_null<Scalar<DataVector>*> dt_conformal_factor,
      66             :     const gsl::not_null<tnsr::ii<DataVector, Dim>*> dt_a_tilde,
      67             :     const gsl::not_null<Scalar<DataVector>*> dt_trace_extrinsic_curvature,
      68             :     const gsl::not_null<Scalar<DataVector>*> dt_theta,
      69             :     const gsl::not_null<tnsr::I<DataVector, Dim>*> dt_gamma_hat,
      70             :     const gsl::not_null<tnsr::I<DataVector, Dim>*> dt_b,
      71             : 
      72             :     // quantities we need for computing eq 4, 13-27
      73             :     const gsl::not_null<Scalar<DataVector>*> conformal_factor_squared,
      74             :     const gsl::not_null<Scalar<DataVector>*> det_conformal_spatial_metric,
      75             :     const gsl::not_null<tnsr::II<DataVector, Dim>*>
      76             :         inv_conformal_spatial_metric,
      77             :     const gsl::not_null<tnsr::II<DataVector, Dim>*> inv_spatial_metric,
      78             :     const gsl::not_null<tnsr::II<DataVector, Dim>*> inv_a_tilde,
      79             :     // temporary expressions
      80             :     const gsl::not_null<tnsr::ij<DataVector, Dim>*> a_tilde_times_field_b,
      81             :     const gsl::not_null<tnsr::ii<DataVector, Dim>*>
      82             :         a_tilde_minus_one_third_conformal_metric_times_trace_a_tilde,
      83             :     const gsl::not_null<Scalar<DataVector>*> contracted_field_b,
      84             :     const gsl::not_null<tnsr::ijK<DataVector, Dim>*> symmetrized_d_field_b,
      85             :     const gsl::not_null<tnsr::i<DataVector, Dim>*>
      86             :         contracted_symmetrized_d_field_b,
      87             :     const gsl::not_null<tnsr::i<DataVector, Dim>*> field_d_up_times_a_tilde,
      88             :     const gsl::not_null<tnsr::I<DataVector, Dim>*>
      89             :         contracted_field_d_up,  // temp for eq 18 -20
      90             :     const gsl::not_null<Scalar<DataVector>*>
      91             :         half_conformal_factor_squared,  // temp for eq 25
      92             :     const gsl::not_null<tnsr::ij<DataVector, Dim>*>
      93             :         conformal_metric_times_field_b,
      94             :     const gsl::not_null<tnsr::ii<DataVector, Dim>*>
      95             :         conformal_metric_times_trace_a_tilde,
      96             :     const gsl::not_null<tnsr::i<DataVector, Dim>*>
      97             :         inv_conformal_metric_times_d_a_tilde,
      98             :     const gsl::not_null<tnsr::I<DataVector, Dim>*>
      99             :         gamma_hat_minus_contracted_conformal_christoffel,
     100             :     const gsl::not_null<tnsr::iJ<DataVector, Dim>*>
     101             :         d_gamma_hat_minus_contracted_conformal_christoffel,
     102             :     const gsl::not_null<tnsr::i<DataVector, Dim>*>
     103             :         contracted_christoffel_second_kind,  // temp for eq 18 -20
     104             :     const gsl::not_null<tnsr::ij<DataVector, Dim>*>
     105             :         contracted_d_conformal_christoffel_difference,  // temp for eq 18 -20
     106             :     const gsl::not_null<Scalar<DataVector>*> k_minus_2_theta_c,
     107             :     const gsl::not_null<Scalar<DataVector>*> k_minus_k0_minus_2_theta_c,
     108             :     const gsl::not_null<tnsr::ii<DataVector, Dim>*> lapse_times_a_tilde,
     109             :     const gsl::not_null<tnsr::ijj<DataVector, Dim>*> lapse_times_d_a_tilde,
     110             :     const gsl::not_null<tnsr::i<DataVector, Dim>*> lapse_times_field_a,
     111             :     const gsl::not_null<tnsr::ii<DataVector, Dim>*>
     112             :         lapse_times_conformal_spatial_metric,
     113             :     const gsl::not_null<Scalar<DataVector>*> lapse_times_slicing_condition,
     114             :     const gsl::not_null<Scalar<DataVector>*>
     115             :         lapse_times_ricci_scalar_plus_divergence_z4_constraint,
     116             :     const gsl::not_null<tnsr::I<DataVector, Dim>*> shift_times_deriv_gamma_hat,
     117             :     const gsl::not_null<tnsr::ii<DataVector, Dim>*>
     118             :         inv_tau_times_conformal_metric,
     119             :     // expressions and identities needed for evolution equations: eq 13 - 27
     120             :     const gsl::not_null<Scalar<DataVector>*> trace_a_tilde,       // eq 13
     121             :     const gsl::not_null<tnsr::iJJ<DataVector, Dim>*> field_d_up,  // eq 14
     122             :     const gsl::not_null<tnsr::Ijj<DataVector, Dim>*>
     123             :         conformal_christoffel_second_kind,  // eq 15
     124             :     const gsl::not_null<tnsr::iJkk<DataVector, Dim>*>
     125             :         d_conformal_christoffel_second_kind,  // eq 16
     126             :     const gsl::not_null<tnsr::Ijj<DataVector, Dim>*>
     127             :         christoffel_second_kind,  // eq 17
     128             :     const gsl::not_null<tnsr::ii<DataVector, Dim>*>
     129             :         spatial_ricci_tensor,  // eq 18 - 20
     130             :     const gsl::not_null<tnsr::ij<DataVector, Dim>*> grad_grad_lapse,  // eq 21
     131             :     const gsl::not_null<Scalar<DataVector>*> divergence_lapse,        // eq 22
     132             :     const gsl::not_null<tnsr::I<DataVector, Dim>*>
     133             :         contracted_conformal_christoffel_second_kind,  // eq 23
     134             :     const gsl::not_null<tnsr::iJ<DataVector, Dim>*>
     135             :         d_contracted_conformal_christoffel_second_kind,  // eq 24
     136             :     const gsl::not_null<tnsr::i<DataVector, Dim>*>
     137             :         spatial_z4_constraint,  // eq 25
     138             :     const gsl::not_null<tnsr::I<DataVector, Dim>*>
     139             :         upper_spatial_z4_constraint,  // eq 25
     140             :     const gsl::not_null<tnsr::ij<DataVector, Dim>*>
     141             :         grad_spatial_z4_constraint,  // eq 26
     142             :     const gsl::not_null<Scalar<DataVector>*>
     143             :         ricci_scalar_plus_divergence_z4_constraint,  // eq 27
     144             : 
     145             :     // fixed params for SO-CCZ4
     146             :     // c = 1.0, cleaning_speed = 1.0
     147             :     // one_over_relaxation_time = 0.0
     148             :     const double c, const double cleaning_speed,  // e in the paper
     149             :     const double one_over_relaxation_time,        // \tau^{-1}
     150             : 
     151             :     // free params for SO-CCZ4
     152             :     const Scalar<DataVector>& eta, const double f, const double kappa_1,
     153             :     const double kappa_2, const double kappa_3, const Scalar<DataVector>& k_0,
     154             : 
     155             :     // evolved variables
     156             :     const tnsr::ii<DataVector, Dim>& conformal_spatial_metric,
     157             :     const Scalar<DataVector>& lapse, const tnsr::I<DataVector, Dim>& shift,
     158             :     const Scalar<DataVector>& conformal_factor,
     159             :     const tnsr::ii<DataVector, Dim>& a_tilde,
     160             :     const Scalar<DataVector>& trace_extrinsic_curvature,
     161             :     const Scalar<DataVector>& theta, const tnsr::I<DataVector, Dim>& gamma_hat,
     162             :     const tnsr::I<DataVector, Dim>& b,
     163             : 
     164             :     // auxilliary fields and their derivatives
     165             :     const tnsr::i<DataVector, Dim>& field_a,
     166             :     const tnsr::iJ<DataVector, Dim>& field_b,
     167             :     const tnsr::ijj<DataVector, Dim>& field_d,
     168             :     const tnsr::i<DataVector, Dim>& field_p,
     169             :     const tnsr::ii<DataVector, Dim>& d_field_a,
     170             :     const tnsr::iiJ<DataVector, Dim>& d_field_b,
     171             :     const tnsr::iijj<DataVector, Dim>& d_field_d,
     172             :     const tnsr::ii<DataVector, Dim>& d_field_p,
     173             : 
     174             :     // spatial derivatives of other evolved variables
     175             :     const tnsr::ijj<DataVector, Dim>& d_a_tilde,
     176             :     const tnsr::i<DataVector, Dim>& d_trace_extrinsic_curvature,
     177             :     const tnsr::i<DataVector, Dim>& d_theta,
     178             :     const tnsr::iJ<DataVector, Dim>& d_gamma_hat,
     179             :     const tnsr::iJ<DataVector, Dim>& d_b, const bool shifting_shift,
     180             :     const bool evolve_lapse_and_shift) {
     181             :   constexpr double one_third = 1.0 / 3.0;
     182             :   // quantities we need for computing eq 4, 13 - 27
     183             : 
     184             :   determinant_and_inverse(det_conformal_spatial_metric,
     185             :                           inv_conformal_spatial_metric,
     186             :                           conformal_spatial_metric);
     187             : 
     188             :   get(*conformal_factor_squared) = square(get(conformal_factor));
     189             : 
     190             :   ::tenex::evaluate<ti::I, ti::J>(
     191             :       inv_spatial_metric, (*conformal_factor_squared)() *
     192             :                               (*inv_conformal_spatial_metric)(ti::I, ti::J));
     193             : 
     194             :   ::tenex::evaluate<ti::I, ti::J>(
     195             :       inv_a_tilde, a_tilde(ti::k, ti::l) *
     196             :                        (*inv_conformal_spatial_metric)(ti::I, ti::K) *
     197             :                        (*inv_conformal_spatial_metric)(ti::J, ti::L));
     198             : 
     199             :   ASSERT(min(get(lapse)) > 0.0,
     200             :          "The lapse must be positive when using 1+log slicing but is: "
     201             :              << get(lapse));
     202             : 
     203             :   // slicing_condition and d_slicing_condition is not used in SO-CCZ4
     204             :   // \alpha g(\alpha)  == 2
     205             :   *lapse_times_slicing_condition =
     206             :       make_with_value<Scalar<DataVector>>(lapse, 2.0);
     207             : 
     208             :   // expressions and identities needed for evolution equations: eq 13 - 27
     209             : 
     210             :   // eq 13
     211             :   ::tenex::evaluate(
     212             :       trace_a_tilde,
     213             :       (*inv_conformal_spatial_metric)(ti::I, ti::J) * a_tilde(ti::i, ti::j));
     214             : 
     215             :   // from eq 14: field_d_up is the D_k^{ij} tensor
     216             :   ::tenex::evaluate<ti::k, ti::I, ti::J>(
     217             :       field_d_up, (*inv_conformal_spatial_metric)(ti::I, ti::N) *
     218             :                       (*inv_conformal_spatial_metric)(ti::M, ti::J) *
     219             :                       field_d(ti::k, ti::n, ti::m));
     220             : 
     221             :   // eq 15
     222             :   ::Ccz4::conformal_christoffel_second_kind(conformal_christoffel_second_kind,
     223             :                                             *inv_conformal_spatial_metric,
     224             :                                             field_d);
     225             : 
     226             :   // eq 16
     227             :   ::Ccz4::deriv_conformal_christoffel_second_kind(
     228             :       d_conformal_christoffel_second_kind, *inv_conformal_spatial_metric,
     229             :       field_d, d_field_d, *field_d_up);
     230             : 
     231             :   // eq 17
     232             :   ::Ccz4::christoffel_second_kind(christoffel_second_kind,
     233             :                                   conformal_spatial_metric,
     234             :                                   *inv_conformal_spatial_metric, field_p,
     235             :                                   *conformal_christoffel_second_kind);
     236             : 
     237             :   // temporary expressions needed for eq 18 - 20
     238             :   ::tenex::evaluate<ti::l>(contracted_christoffel_second_kind,
     239             :                            (*christoffel_second_kind)(ti::M, ti::l, ti::m));
     240             : 
     241             :   // comment for the future: we should probably ensure the traces are taken
     242             :   // before computing the differences as the off-diagonal terms are not
     243             :   // needed
     244             :   ::tenex::evaluate<ti::i, ti::j>(
     245             :       contracted_d_conformal_christoffel_difference,
     246             :       (*d_conformal_christoffel_second_kind)(ti::m, ti::M, ti::i, ti::j) -
     247             :           (*d_conformal_christoffel_second_kind)(ti::j, ti::M, ti::i, ti::m));
     248             : 
     249             :   ::tenex::evaluate<ti::L>(contracted_field_d_up,
     250             :                            (*field_d_up)(ti::m, ti::M, ti::L));
     251             : 
     252             :   // eq 18 - 20
     253             :   ::Ccz4::spatial_ricci_tensor(
     254             :       spatial_ricci_tensor, *christoffel_second_kind,
     255             :       *contracted_christoffel_second_kind,
     256             :       *contracted_d_conformal_christoffel_difference, conformal_spatial_metric,
     257             :       *inv_conformal_spatial_metric, field_d, *field_d_up,
     258             :       *contracted_field_d_up, field_p, d_field_p);
     259             : 
     260             :   // eq 21
     261             :   ::Ccz4::grad_grad_lapse(grad_grad_lapse, lapse, *christoffel_second_kind,
     262             :                           field_a, d_field_a);
     263             : 
     264             :   // eq 22
     265             :   ::Ccz4::divergence_lapse(divergence_lapse, *conformal_factor_squared,
     266             :                            *inv_conformal_spatial_metric, *grad_grad_lapse);
     267             : 
     268             :   // eq 23
     269             :   ::Ccz4::contracted_conformal_christoffel_second_kind(
     270             :       contracted_conformal_christoffel_second_kind,
     271             :       *inv_conformal_spatial_metric, *conformal_christoffel_second_kind);
     272             : 
     273             :   // eq 24
     274             :   ::Ccz4::deriv_contracted_conformal_christoffel_second_kind(
     275             :       d_contracted_conformal_christoffel_second_kind,
     276             :       *inv_conformal_spatial_metric, *field_d_up,
     277             :       *conformal_christoffel_second_kind, *d_conformal_christoffel_second_kind);
     278             : 
     279             :   // temp for eq 25
     280             :   ::tenex::evaluate<ti::I>(
     281             :       gamma_hat_minus_contracted_conformal_christoffel,
     282             :       gamma_hat(ti::I) -
     283             :           (*contracted_conformal_christoffel_second_kind)(ti::I));
     284             : 
     285             :   // eq 25
     286             :   ::Ccz4::spatial_z4_constraint(
     287             :       spatial_z4_constraint, conformal_spatial_metric,
     288             :       *gamma_hat_minus_contracted_conformal_christoffel);
     289             : 
     290             :   // temp for eq 25
     291             :   ::tenex::evaluate(half_conformal_factor_squared,
     292             :                     0.5 * (*conformal_factor_squared)());
     293             : 
     294             :   // eq 25
     295             :   ::Ccz4::upper_spatial_z4_constraint(
     296             :       upper_spatial_z4_constraint, *half_conformal_factor_squared,
     297             :       *gamma_hat_minus_contracted_conformal_christoffel);
     298             : 
     299             :   // temp for eq 26
     300             :   ::tenex::evaluate<ti::i, ti::L>(
     301             :       d_gamma_hat_minus_contracted_conformal_christoffel,
     302             :       d_gamma_hat(ti::i, ti::L) -
     303             :           (*d_contracted_conformal_christoffel_second_kind)(ti::i, ti::L));
     304             : 
     305             :   // eq 26
     306             :   ::Ccz4::grad_spatial_z4_constraint(
     307             :       grad_spatial_z4_constraint, *spatial_z4_constraint,
     308             :       conformal_spatial_metric, *christoffel_second_kind, field_d,
     309             :       *gamma_hat_minus_contracted_conformal_christoffel,
     310             :       *d_gamma_hat_minus_contracted_conformal_christoffel);
     311             : 
     312             :   // eq 27
     313             :   ::Ccz4::ricci_scalar_plus_divergence_z4_constraint(
     314             :       ricci_scalar_plus_divergence_z4_constraint, *conformal_factor_squared,
     315             :       *inv_conformal_spatial_metric, *spatial_ricci_tensor,
     316             :       *grad_spatial_z4_constraint);
     317             : 
     318             :   // temporary expressions not already computed above
     319             : 
     320             :   ::tenex::evaluate(contracted_field_b, field_b(ti::k, ti::K));
     321             : 
     322             :   ::tenex::evaluate<ti::k, ti::j, ti::I>(
     323             :       symmetrized_d_field_b,
     324             :       0.5 * (d_field_b(ti::k, ti::j, ti::I) + d_field_b(ti::j, ti::k, ti::I)));
     325             : 
     326             :   ::tenex::evaluate<ti::k>(contracted_symmetrized_d_field_b,
     327             :                            (*symmetrized_d_field_b)(ti::k, ti::i, ti::I));
     328             : 
     329             :   ::tenex::evaluate<ti::k>(
     330             :       field_d_up_times_a_tilde,
     331             :       (*field_d_up)(ti::k, ti::I, ti::J) * a_tilde(ti::i, ti::j));
     332             : 
     333             :   ::tenex::evaluate<ti::i, ti::j>(
     334             :       conformal_metric_times_field_b,
     335             :       conformal_spatial_metric(ti::k, ti::i) * field_b(ti::j, ti::K));
     336             : 
     337             :   ::tenex::evaluate<ti::i, ti::j>(
     338             :       conformal_metric_times_trace_a_tilde,
     339             :       conformal_spatial_metric(ti::i, ti::j) * (*trace_a_tilde)());
     340             : 
     341             :   ::tenex::evaluate<ti::k>(inv_conformal_metric_times_d_a_tilde,
     342             :                            (*inv_conformal_spatial_metric)(ti::I, ti::J) *
     343             :                                d_a_tilde(ti::k, ti::i, ti::j));
     344             : 
     345             :   ::tenex::evaluate<ti::i, ti::j>(
     346             :       a_tilde_times_field_b, a_tilde(ti::k, ti::i) * field_b(ti::j, ti::K));
     347             : 
     348             :   ::tenex::evaluate<ti::i, ti::j>(
     349             :       a_tilde_minus_one_third_conformal_metric_times_trace_a_tilde,
     350             :       a_tilde(ti::i, ti::j) -
     351             :           one_third * (*conformal_metric_times_trace_a_tilde)(ti::i, ti::j));
     352             : 
     353             :   ::tenex::evaluate(k_minus_2_theta_c,
     354             :                     trace_extrinsic_curvature() - 2.0 * c * theta());
     355             : 
     356             :   ::tenex::evaluate(k_minus_k0_minus_2_theta_c, (*k_minus_2_theta_c)() - k_0());
     357             : 
     358             :   ::tenex::evaluate<ti::i, ti::j>(lapse_times_a_tilde,
     359             :                                   (lapse)() * a_tilde(ti::i, ti::j));
     360             : 
     361             :   tenex::evaluate<ti::k, ti::i, ti::j>(
     362             :       lapse_times_d_a_tilde, (lapse)() * d_a_tilde(ti::k, ti::i, ti::j));
     363             : 
     364             :   ::tenex::evaluate<ti::k>(lapse_times_field_a, (lapse)() * field_a(ti::k));
     365             : 
     366             :   ::tenex::evaluate<ti::i, ti::j>(
     367             :       lapse_times_conformal_spatial_metric,
     368             :       (lapse)() * conformal_spatial_metric(ti::i, ti::j));
     369             : 
     370             :   ::tenex::evaluate(
     371             :       lapse_times_ricci_scalar_plus_divergence_z4_constraint,
     372             :       (lapse)() * (*ricci_scalar_plus_divergence_z4_constraint)());
     373             : 
     374             :   ::tenex::evaluate<ti::I>(shift_times_deriv_gamma_hat,
     375             :                            shift(ti::K) * d_gamma_hat(ti::k, ti::I));
     376             : 
     377             :   ::tenex::evaluate<ti::i, ti::j>(
     378             :       inv_tau_times_conformal_metric,
     379             :       one_over_relaxation_time * conformal_spatial_metric(ti::i, ti::j));
     380             : 
     381             :   // time derivative computation: eq 4(a) - 4(i)
     382             :   // The way we evaluate the following may seem weird compared
     383             :   // to 4(a) - 4(i). This is because we try to reuse the first-order
     384             :   // Ccz4 codes as much as possible. Hence, the following is written
     385             :   // based on 12a-12i, with s=1, and red terms canceled.
     386             : 
     387             :   // eq 12a : time derivative of the conformal spatial metric
     388             :   // this reduces to eq 4a for our choice of \tau^{-1}=0.
     389             :   ::tenex::evaluate<ti::i, ti::j>(
     390             :       dt_conformal_spatial_metric,
     391             :       2.0 * shift(ti::K) * field_d(ti::k, ti::i, ti::j) +
     392             :           (*conformal_metric_times_field_b)(ti::i, ti::j) +
     393             :           (*conformal_metric_times_field_b)(ti::j, ti::i) -
     394             :           2.0 * one_third * conformal_spatial_metric(ti::i, ti::j) *
     395             :               (*contracted_field_b)() -
     396             :           2.0 * (lapse)() *
     397             :               (*a_tilde_minus_one_third_conformal_metric_times_trace_a_tilde)(
     398             :                   ti::i, ti::j) -
     399             :           (*inv_tau_times_conformal_metric)(ti::i, ti::j) *
     400             :               ((*det_conformal_spatial_metric)() - 1.0));
     401             : 
     402             :   if (evolve_lapse_and_shift) {
     403             :     // time derivative of the lapse
     404             :     ::tenex::evaluate<>(dt_lapse, (shift(ti::K) * field_a(ti::k) -
     405             :                                    (*lapse_times_slicing_condition)() *
     406             :                                        (*k_minus_k0_minus_2_theta_c)()) *
     407             :                                       lapse());
     408             :     // time derivative of the shift
     409             :     ::tenex::evaluate<ti::I>(dt_shift, f * b(ti::I));
     410             :     if (shifting_shift) {
     411             :       ::tenex::update<ti::I>(
     412             :           dt_shift, (*dt_shift)(ti::I) + shift(ti::K) * field_b(ti::k, ti::I));
     413             :     }
     414             :   } else {
     415             :     *dt_lapse = make_with_value<Scalar<DataVector>>(lapse, 0.0);
     416             :     *dt_shift = make_with_value<tnsr::I<DataVector, Dim>>(shift, 0.0);
     417             :   }
     418             : 
     419             :   // time derivative of the the conformal factor
     420             :   ::tenex::evaluate(dt_conformal_factor,
     421             :                     (shift(ti::K) * field_p(ti::k) +
     422             :                      one_third * ((lapse)() * trace_extrinsic_curvature() -
     423             :                                   (*contracted_field_b)())) *
     424             :                         conformal_factor());
     425             : 
     426             :   // time derivative of the trace-free part of the extrinsic curvature
     427             :   ::tenex::evaluate<ti::i, ti::j>(
     428             :       dt_a_tilde,
     429             :       shift(ti::K) * d_a_tilde(ti::k, ti::i, ti::j) +
     430             :           (*conformal_factor_squared)() *
     431             :               ((lapse)() * ((*spatial_ricci_tensor)(ti::i, ti::j) +
     432             :                             (*grad_spatial_z4_constraint)(ti::i, ti::j) +
     433             :                             (*grad_spatial_z4_constraint)(ti::j, ti::i)) -
     434             :                (*grad_grad_lapse)(ti::i, ti::j)) -
     435             :           one_third * conformal_spatial_metric(ti::i, ti::j) *
     436             :               ((*lapse_times_ricci_scalar_plus_divergence_z4_constraint)() -
     437             :                (*divergence_lapse)()) +
     438             :           (*a_tilde_times_field_b)(ti::i, ti::j) +
     439             :           (*a_tilde_times_field_b)(ti::j, ti::i) -
     440             :           2.0 * one_third * a_tilde(ti::i, ti::j) * (*contracted_field_b)() +
     441             :           (*lapse_times_a_tilde)(ti::i, ti::j) * (*k_minus_2_theta_c)() -
     442             :           2.0 * (*lapse_times_a_tilde)(ti::i, ti::l) *
     443             :               (*inv_conformal_spatial_metric)(ti::L, ti::M) *
     444             :               a_tilde(ti::m, ti::j) -
     445             :           (*inv_tau_times_conformal_metric)(ti::i, ti::j) * (*trace_a_tilde)());
     446             : 
     447             :   // time derivative of the trace of the extrinsic curvature
     448             :   ::tenex::evaluate(
     449             :       dt_trace_extrinsic_curvature,
     450             :       shift(ti::K) * d_trace_extrinsic_curvature(ti::k) -
     451             :           (*divergence_lapse)() +
     452             :           (*lapse_times_ricci_scalar_plus_divergence_z4_constraint)() +
     453             :           (lapse)() * (trace_extrinsic_curvature() * (*k_minus_2_theta_c)() -
     454             :                        3.0 * kappa_1 * (1.0 + kappa_2) * theta()));
     455             : 
     456             :   // time derivative of the projection of the Z4 four-vector along
     457             :   // the normal direction
     458             :   ::tenex::evaluate(
     459             :       dt_theta,
     460             :       shift(ti::K) * d_theta(ti::k) +
     461             :           (lapse)() *
     462             :               (0.5 * square(cleaning_speed) *
     463             :                    ((*ricci_scalar_plus_divergence_z4_constraint)() +
     464             :                     2.0 * one_third * square(trace_extrinsic_curvature()) -
     465             :                     a_tilde(ti::i, ti::j) * (*inv_a_tilde)(ti::I, ti::J)) -
     466             :                c * theta() * trace_extrinsic_curvature() -
     467             :                (*upper_spatial_z4_constraint)(ti::I)*field_a(ti::i) -
     468             :                kappa_1 * (2.0 + kappa_2) * theta()));
     469             : 
     470             :   // time derivative \hat{\Gamma}^i
     471             :   // first, compute terms without s
     472             :   ::tenex::evaluate<ti::I>(
     473             :       dt_gamma_hat,
     474             :       // terms without lapse nor s
     475             :       (*shift_times_deriv_gamma_hat)(ti::I) +
     476             :           2.0 * one_third *
     477             :               (*contracted_conformal_christoffel_second_kind)(ti::I) *
     478             :               (*contracted_field_b)() -
     479             :           (*contracted_conformal_christoffel_second_kind)(ti::K)*field_b(
     480             :               ti::k, ti::I) +
     481             :           2.0 * kappa_3 * (*spatial_z4_constraint)(ti::j) *
     482             :               (2.0 * one_third * (*inv_conformal_spatial_metric)(ti::I, ti::J) *
     483             :                    (*contracted_field_b)() -
     484             :                (*inv_conformal_spatial_metric)(ti::J, ti::K) *
     485             :                    field_b(ti::k, ti::I)) +
     486             :           // terms with lapse but not s
     487             :           2.0 * (lapse)() *
     488             :               (-2.0 * one_third *
     489             :                    (*inv_conformal_spatial_metric)(ti::I, ti::J) *
     490             :                    d_trace_extrinsic_curvature(ti::j) +
     491             :                (*inv_conformal_spatial_metric)(ti::K, ti::I) * d_theta(ti::k) +
     492             :                (*conformal_christoffel_second_kind)(ti::I, ti::j, ti::k) *
     493             :                    (*inv_a_tilde)(ti::J, ti::K) -
     494             :                3.0 * (*inv_a_tilde)(ti::I, ti::J) * field_p(ti::j) -
     495             :                (*inv_conformal_spatial_metric)(ti::K, ti::I) *
     496             :                    (theta() * field_a(ti::k) +
     497             :                     2.0 * one_third * trace_extrinsic_curvature() *
     498             :                         (*spatial_z4_constraint)(ti::k)) -
     499             :                (*inv_a_tilde)(ti::I, ti::J) * field_a(ti::j) -
     500             :                kappa_1 * (*inv_conformal_spatial_metric)(ti::I, ti::J) *
     501             :                    (*spatial_z4_constraint)(ti::j)));
     502             :   // We add the following since s=1 (Gamma-driver gauge) is assumed in SoCcz4
     503             :   ::tenex::update<ti::I>(dt_gamma_hat,
     504             :                          (*dt_gamma_hat)(ti::I) +
     505             :                              // red terms should cancel
     506             :                              // terms with s but not lapse
     507             :                              (*inv_conformal_spatial_metric)(ti::K, ti::L) *
     508             :                                  (*symmetrized_d_field_b)(ti::k, ti::l, ti::I) +
     509             :                              one_third *
     510             :                                  (*inv_conformal_spatial_metric)(ti::I, ti::K) *
     511             :                                  (*contracted_symmetrized_d_field_b)(ti::k));
     512             : 
     513             :   // time derivative b^i
     514             :   if (evolve_lapse_and_shift) {
     515             :     ::tenex::evaluate<ti::I>(dt_b, (*dt_gamma_hat)(ti::I)-eta() * b(ti::I));
     516             :     if (shifting_shift) {
     517             :       ::tenex::update<ti::I>(
     518             :           dt_b, (*dt_b)(ti::I) + shift(ti::K) * (d_b(ti::k, ti::I) -
     519             :                                                  d_gamma_hat(ti::k, ti::I)));
     520             :     }
     521             :   } else {
     522             :     (*dt_b).get(0) = 0.0;
     523             :     (*dt_b).get(1) = 0.0;
     524             :     (*dt_b).get(2) = 0.0;
     525             :   }
     526             : 
     527             :   // Note that, we do not need to evolve the auxiliary variables in SO-CCZ4.
     528             : }
     529             : }  // namespace detail
     530             : 
     531             : /*!
     532             :  * \brief Compute the RHS of the second-order CCZ4 formulation of Einstein's
     533             :  * equations \cite Dumbser2017okk with finite differencing. Also
     534             :  * update the time derivative at outermost interior points in a sphere domain
     535             :  * if Sommerfeld boundary conditions are applied.
     536             :  *
     537             :  * \details The evolution equations are equations 4(a) - 4(i) of
     538             :  * \cite Dumbser2017okk Equations 13 - 27 define identities
     539             :  * used in the evolution equations.
     540             :  *
     541             :  * \note Different from the first-order system, the lapse
     542             :  * and the conformal factor are evolved instead of their natural logs.
     543             :  * The four auxiliary varialbels \f$A_i\f$, \f$B_k{}^{i}\f$,
     544             :  * \f$D_{kij}\f$, and \f$P_i\f$ are NOT evolved.
     545             :  */
     546           1 : struct SoTimeDerivative {
     547             :   template <typename DbTagsList>
     548           0 :   static void apply(const gsl::not_null<db::DataBox<DbTagsList>*> box) {
     549             :     // compute the first spatial derivatives of the evolved variables
     550             :     using evolved_vars_tag = typename System::variables_tag;
     551             :     using gradients_tags = typename System::gradients_tags;
     552             : 
     553             :     // only 4-th order accurate second derivatives have been implemented
     554             :     // To keep the same order of accuracy we use the same order for
     555             :     // both first and second derivatives
     556             :     constexpr size_t fd_order = 4;
     557             :     const auto& evolved_vars = db::get<evolved_vars_tag>(*box);
     558             :     const Mesh<Dim>& subcell_mesh =
     559             :         db::get<evolution::dg::subcell::Tags::Mesh<Dim>>(*box);
     560             :     const size_t num_pts = subcell_mesh.number_of_grid_points();
     561             :     using deriv_var_tag = db::wrap_tags_in<::Tags::deriv, gradients_tags,
     562             :                                            tmpl::size_t<Dim>, Frame::Inertial>;
     563             :     Variables<deriv_var_tag> cell_centered_Ccz4_derivs{num_pts};
     564             :     const auto& cell_centered_logical_to_inertial_inv_jacobian =
     565             :         db::get<evolution::dg::subcell::fd::Tags::
     566             :                     InverseJacobianLogicalToInertial<Dim>>(*box);
     567             : 
     568             :     constexpr bool subcell_enabled_at_external_boundary =
     569             :         std::decay_t<decltype(db::get<Parallel::Tags::Metavariables>(
     570             :             *box))>::SubcellOptions::subcell_enabled_at_external_boundary;
     571             : 
     572             :     const Element<3>& element = db::get<domain::Tags::Element<3>>(*box);
     573             : 
     574             :     const Ccz4::fd::Reconstructor& recons =
     575             :         db::get<Ccz4::fd::Tags::Reconstructor>(*box);
     576             : 
     577             :     // If the element has external boundaries and subcell is enabled for
     578             :     // boundary elements, compute FD ghost data with a given boundary condition.
     579             :     if constexpr (subcell_enabled_at_external_boundary) {
     580             :       if (not element.external_boundaries().empty()) {
     581             :         fd::BoundaryConditionGhostData::apply(box, element, recons);
     582             :       }
     583             :     }
     584             : 
     585             :     const bool evolve_lapse_and_shift =
     586             :         get<::Ccz4::fd::Tags::EvolveLapseAndShift>(*box);
     587             : 
     588             :     ::Ccz4::fd::spacetime_derivatives(
     589             :         make_not_null(&cell_centered_Ccz4_derivs), evolved_vars,
     590             :         db::get<evolution::dg::subcell::Tags::GhostDataForReconstruction<Dim>>(
     591             :             *box),
     592             :         fd_order, subcell_mesh, cell_centered_logical_to_inertial_inv_jacobian);
     593             : 
     594             :     // calculate the four auxiliary fields in eq. 6
     595             :     // auxiliary variables NOT evolved in SO-CCZ4
     596             :     const auto& d_lapse =
     597             :         get<::Tags::deriv<gr::Tags::Lapse<DataVector>, tmpl::size_t<Dim>,
     598             :                           Frame::Inertial>>(cell_centered_Ccz4_derivs);
     599             :     const auto& lapse = get<gr::Tags::Lapse<DataVector>>(evolved_vars);
     600             :     const auto field_a = ::tenex::evaluate<ti::i>(d_lapse(ti::i) / lapse());
     601             : 
     602             :     const auto& field_b =
     603             :         get<::Tags::deriv<gr::Tags::Shift<DataVector, Dim>, tmpl::size_t<Dim>,
     604             :                           Frame::Inertial>>(cell_centered_Ccz4_derivs);
     605             : 
     606             :     const auto& d_spatial_conformal_metric =
     607             :         get<::Tags::deriv<::Ccz4::Tags::ConformalMetric<DataVector, Dim>,
     608             :                           tmpl::size_t<Dim>, Frame::Inertial>>(
     609             :             cell_centered_Ccz4_derivs);
     610             :     tnsr::ijj<DataVector, Dim> field_d;
     611             :     ::tenex::evaluate<ti::i, ti::j, ti::k>(
     612             :         make_not_null(&field_d),
     613             :         0.5 * d_spatial_conformal_metric(ti::i, ti::j, ti::k));
     614             : 
     615             :     const auto& conformal_factor =
     616             :         get<::Ccz4::Tags::ConformalFactor<DataVector>>(evolved_vars);
     617             :     const auto& d_conformal_factor =
     618             :         get<::Tags::deriv<::Ccz4::Tags::ConformalFactor<DataVector>,
     619             :                           tmpl::size_t<Dim>, Frame::Inertial>>(
     620             :             cell_centered_Ccz4_derivs);
     621             :     const auto field_p = ::tenex::evaluate<ti::i>(d_conformal_factor(ti::i) /
     622             :                                                   conformal_factor());
     623             : 
     624             :     // compute second derivatives of the evolved variables
     625             :     Variables<db::wrap_tags_in<::Tags::second_deriv, gradients_tags,
     626             :                                tmpl::size_t<Dim>, Frame::Inertial>>
     627             :         cell_centered_Ccz4_second_derivs{num_pts};
     628             : 
     629             :     Ccz4::fd::second_spacetime_derivatives(
     630             :         make_not_null(&cell_centered_Ccz4_second_derivs), evolved_vars,
     631             :         db::get<evolution::dg::subcell::Tags::GhostDataForReconstruction<Dim>>(
     632             :             *box),
     633             :         fd_order, subcell_mesh, cell_centered_logical_to_inertial_inv_jacobian);
     634             : 
     635             :     // compute spatial derivative of the four auxiliary fields
     636             :     const auto& d_d_lapse =
     637             :         get<::Tags::second_deriv<gr::Tags::Lapse<DataVector>, tmpl::size_t<Dim>,
     638             :                                  Frame::Inertial>>(
     639             :             cell_centered_Ccz4_second_derivs);
     640             :     tnsr::ii<DataVector, Dim> d_field_a;
     641             :     ::tenex::evaluate<ti::i, ti::j>(
     642             :         make_not_null(&d_field_a),
     643             :         (d_d_lapse(ti::i, ti::j) - d_lapse(ti::i) * d_lapse(ti::j) / lapse()) /
     644             :             lapse());
     645             : 
     646             :     const auto& d_field_b =
     647             :         get<::Tags::second_deriv<gr::Tags::Shift<DataVector, Dim>,
     648             :                                  tmpl::size_t<Dim>, Frame::Inertial>>(
     649             :             cell_centered_Ccz4_second_derivs);
     650             : 
     651             :     const auto& d_d_conformal_metric =
     652             :         get<::Tags::second_deriv<::Ccz4::Tags::ConformalMetric<DataVector, Dim>,
     653             :                                  tmpl::size_t<Dim>, Frame::Inertial>>(
     654             :             cell_centered_Ccz4_second_derivs);
     655             : 
     656             :     tnsr::iijj<DataVector, Dim> d_field_d;
     657             :     ::tenex::evaluate<ti::i, ti::j, ti::k, ti::l>(
     658             :         make_not_null(&d_field_d),
     659             :         0.5 * d_d_conformal_metric(ti::i, ti::j, ti::k, ti::l));
     660             : 
     661             :     const auto& d_d_conformal_factor =
     662             :         get<::Tags::second_deriv<::Ccz4::Tags::ConformalFactor<DataVector>,
     663             :                                  tmpl::size_t<Dim>, Frame::Inertial>>(
     664             :             cell_centered_Ccz4_second_derivs);
     665             : 
     666             :     tnsr::ii<DataVector, Dim> d_field_p;
     667             :     ::tenex::evaluate<ti::i, ti::j>(
     668             :         make_not_null(&d_field_p),
     669             :         (d_d_conformal_factor(ti::i, ti::j) - d_conformal_factor(ti::i) *
     670             :                                                   d_conformal_factor(ti::j) /
     671             :                                                   conformal_factor()) /
     672             :             conformal_factor());
     673             : 
     674             :     // intialize containers to be supplied in the SO-CCZ4 TimeDerivative.cpp
     675             :     // apply() function quantities we need for computing eq 4, 13 - 27
     676             :     using TempVars = Variables<tmpl::list<
     677             :         ::Ccz4::Tags::ConformalFactorSquared<DataVector>,
     678             :         ::Ccz4::Tags::DetConformalSpatialMetric<DataVector>,
     679             :         ::Ccz4::Tags::InverseConformalMetric<DataVector, Dim>,
     680             :         gr::Tags::InverseSpatialMetric<DataVector, Dim>,
     681             :         ::Ccz4::Tags::InvATilde<DataVector, Dim>,
     682             :         ::Ccz4::Tags::ATildeTimesFieldB<DataVector, Dim>,
     683             :         ::Ccz4::Tags::ATildeMinusOneThirdConformalMetricTimesTraceATilde<
     684             :             DataVector, Dim>,
     685             :         ::Ccz4::Tags::ContractedFieldB<DataVector>,
     686             :         ::Ccz4::Tags::SymmetrizedDerivFieldB<DataVector, Dim>,
     687             :         ::Ccz4::Tags::ContractedSymmetrizedDerivFieldB<DataVector, Dim>,
     688             :         ::Ccz4::Tags::FieldDUpTimesATilde<DataVector, Dim>,
     689             :         ::Ccz4::Tags::ContractedFieldDUp<DataVector, Dim>,
     690             :         ::Ccz4::Tags::HalfConformalFactorSquared<DataVector>,
     691             :         ::Ccz4::Tags::ConformalMetricTimesFieldB<DataVector, Dim>,
     692             :         ::Ccz4::Tags::ConformalMetricTimesTraceATilde<DataVector, Dim>,
     693             :         ::Ccz4::Tags::InverseConformalMetricTimesDerivATilde<DataVector, Dim>,
     694             :         ::Ccz4::Tags::GammaHatMinusContractedConformalChristoffel<DataVector,
     695             :                                                                   Dim>,
     696             :         ::Ccz4::Tags::DerivGammaHatMinusContractedConformalChristoffel<
     697             :             DataVector, Dim>,
     698             :         ::Ccz4::Tags::ContractedChristoffelSecondKind<DataVector, Dim>,
     699             :         ::Ccz4::Tags::ContractedDerivConformalChristoffelDifference<DataVector,
     700             :                                                                     Dim>,
     701             :         ::Ccz4::Tags::KMinus2ThetaC<DataVector>,
     702             :         ::Ccz4::Tags::KMinusK0Minus2ThetaC<DataVector>,
     703             :         ::Ccz4::Tags::LapseTimesATilde<DataVector, Dim>,
     704             :         ::Ccz4::Tags::LapseTimesDerivATilde<DataVector, Dim>,
     705             :         ::Ccz4::Tags::LapseTimesFieldA<DataVector, Dim>,
     706             :         ::Ccz4::Tags::LapseTimesConformalMetric<DataVector, Dim>,
     707             :         ::Ccz4::Tags::LapseTimesSlicingCondition<DataVector>,
     708             :         ::Ccz4::Tags::LapseTimesRicciScalarPlus2DivergenceZ4Constraint<
     709             :             DataVector>,
     710             :         ::Ccz4::Tags::ShiftTimesDerivGammaHat<DataVector, Dim>,
     711             :         ::Ccz4::Tags::InverseTauTimesConformalMetric<DataVector, Dim>,
     712             :         ::Ccz4::Tags::TraceATilde<DataVector>,
     713             :         ::Ccz4::Tags::FieldDUp<DataVector, Dim>,
     714             :         ::Ccz4::Tags::ConformalChristoffelSecondKind<DataVector, Dim>,
     715             :         ::Ccz4::Tags::DerivConformalChristoffelSecondKind<DataVector, Dim>,
     716             :         ::Ccz4::Tags::ChristoffelSecondKind<DataVector, Dim>,
     717             :         ::Ccz4::Tags::SpatialRicciTensor<DataVector, Dim>,
     718             :         ::Ccz4::Tags::GradGradLapse<DataVector, Dim>,
     719             :         ::Ccz4::Tags::DivergenceLapse<DataVector>,
     720             :         ::Ccz4::Tags::ContractedConformalChristoffelSecondKind<DataVector, Dim>,
     721             :         ::Ccz4::Tags::DerivContractedConformalChristoffelSecondKind<DataVector,
     722             :                                                                     Dim>,
     723             :         ::Ccz4::Tags::SpatialZ4Constraint<DataVector, Dim>,
     724             :         ::Ccz4::Tags::GradSpatialZ4Constraint<DataVector, Dim>,
     725             :         ::Ccz4::Tags::RicciScalarPlusDivergenceZ4Constraint<DataVector>>>;
     726             : 
     727             :     TempVars temp_vars(num_pts);
     728             :     tnsr::I<DataVector, Dim> upper_spatial_z4_constraint(num_pts);
     729             : 
     730             :     // free params
     731             :     const double c = 1.0;               // c = 1.0 in SO-CCZ4
     732             :     const double cleaning_speed = 1.0;  // e in the paper; e = 1.0 for SO-CCZ4
     733             :     const Scalar<DataVector>& eta = get<::Ccz4::Tags::Eta<DataVector>>(*box);
     734             :     const double f = Ccz4::fd::System::f;
     735             :     const Scalar<DataVector>& k_0 = get<::Ccz4::Tags::K0<DataVector>>(*box);
     736             :     const double kappa_1 = get<::Ccz4::Tags::Kappa1>(*box);
     737             :     const double kappa_2 = get<::Ccz4::Tags::Kappa2>(*box);
     738             :     const double kappa_3 = get<::Ccz4::Tags::Kappa3>(*box);
     739             :     const double one_over_relaxation_time = 0.0;  // \tau^{-1} = 0 in SO-CCZ4
     740             :     const bool shifting_shift = Ccz4::fd::System::shifting_shift;
     741             : 
     742             :     // we assume the databox already has tags corresponding to dt of the evolved
     743             :     // variables
     744             :     using dt_variables_tag = db::add_tag_prefix<::Tags::dt, evolved_vars_tag>;
     745             : 
     746             :     db::mutate<dt_variables_tag,
     747             :                ::Ccz4::Tags::SpatialZ4ConstraintUp<DataVector, Dim>>(
     748             :         [&](const auto dt_vars_ptr,
     749             :             const auto upper_spatial_z4_constraint_ptr) {
     750             :           // resize here
     751             :           dt_vars_ptr->initialize(subcell_mesh.number_of_grid_points());
     752             :           auto& [conformal_factor_squared, det_conformal_spatial_metric,
     753             :                  inv_conformal_spatial_metric, inv_spatial_metric, inv_a_tilde,
     754             :                  a_tilde_times_field_b,
     755             :                  a_tilde_minus_one_third_conformal_metric_times_trace_a_tilde,
     756             :                  contracted_field_b, symmetrized_d_field_b,
     757             :                  contracted_symmetrized_d_field_b, field_d_up_times_a_tilde,
     758             :                  contracted_field_d_up, half_conformal_factor_squared,
     759             :                  conformal_metric_times_field_b,
     760             :                  conformal_metric_times_trace_a_tilde,
     761             :                  inv_conformal_metric_times_d_a_tilde,
     762             :                  gamma_hat_minus_contracted_conformal_christoffel,
     763             :                  d_gamma_hat_minus_contracted_conformal_christoffel,
     764             :                  contracted_christoffel_second_kind,
     765             :                  contracted_d_conformal_christoffel_difference,
     766             :                  k_minus_2_theta_c, k_minus_k0_minus_2_theta_c,
     767             :                  lapse_times_a_tilde, lapse_times_d_a_tilde,
     768             :                  lapse_times_field_a, lapse_times_conformal_spatial_metric,
     769             :                  lapse_times_slicing_condition,
     770             :                  lapse_times_ricci_scalar_plus_divergence_z4_constraint,
     771             :                  shift_times_deriv_gamma_hat, inv_tau_times_conformal_metric,
     772             :                  trace_a_tilde, field_d_up, conformal_christoffel_second_kind,
     773             :                  d_conformal_christoffel_second_kind, christoffel_second_kind,
     774             :                  spatial_ricci_tensor, grad_grad_lapse, divergence_lapse,
     775             :                  contracted_conformal_christoffel_second_kind,
     776             :                  d_contracted_conformal_christoffel_second_kind,
     777             :                  spatial_z4_constraint, grad_spatial_z4_constraint,
     778             :                  ricci_scalar_plus_divergence_z4_constraint] = temp_vars;
     779             :           detail::apply(
     780             :               // LHS time derivatives of evolved variables: eq 4a - 4i
     781             :               make_not_null(
     782             :                   &get<::Tags::dt<
     783             :                       ::Ccz4::Tags::ConformalMetric<DataVector, Dim>>>(
     784             :                       *dt_vars_ptr)),  // eq 4a
     785             :               make_not_null(&get<::Tags::dt<gr::Tags::Lapse<DataVector>>>(
     786             :                   *dt_vars_ptr)),  // eq 4g
     787             :               make_not_null(&get<::Tags::dt<gr::Tags::Shift<DataVector, Dim>>>(
     788             :                   *dt_vars_ptr)),  // eq 4h
     789             :               make_not_null(
     790             :                   &get<::Tags::dt<::Ccz4::Tags::ConformalFactor<DataVector>>>(
     791             :                       *dt_vars_ptr)),  // eq 4c
     792             :               make_not_null(
     793             :                   &get<::Tags::dt<::Ccz4::Tags::ATilde<DataVector, Dim>>>(
     794             :                       *dt_vars_ptr)),  // eq 4b
     795             :               make_not_null(&get<::Tags::dt<
     796             :                                 gr::Tags::TraceExtrinsicCurvature<DataVector>>>(
     797             :                   *dt_vars_ptr)),  // eq 4d
     798             :               make_not_null(&get<::Tags::dt<::Ccz4::Tags::Theta<DataVector>>>(
     799             :                   *dt_vars_ptr)),  // eq 4e
     800             :               make_not_null(
     801             :                   &get<::Tags::dt<::Ccz4::Tags::GammaHat<DataVector, Dim>>>(
     802             :                       *dt_vars_ptr)),  // eq 4f
     803             :               make_not_null(
     804             :                   &get<::Tags::dt<
     805             :                       ::Ccz4::Tags::AuxiliaryShiftB<DataVector, Dim>>>(
     806             :                       *dt_vars_ptr)),  // eq 4i
     807             : 
     808             :               // quantities we need for computing eq 4, 13 - 27
     809             :               make_not_null(&conformal_factor_squared),
     810             :               make_not_null(&det_conformal_spatial_metric),
     811             :               make_not_null(&inv_conformal_spatial_metric),
     812             :               make_not_null(&inv_spatial_metric), make_not_null(&inv_a_tilde),
     813             :               // temporary expressions
     814             :               make_not_null(&a_tilde_times_field_b),
     815             :               make_not_null(
     816             :                 &a_tilde_minus_one_third_conformal_metric_times_trace_a_tilde),
     817             :               make_not_null(&contracted_field_b),
     818             :               make_not_null(&symmetrized_d_field_b),
     819             :               make_not_null(&contracted_symmetrized_d_field_b),
     820             :               make_not_null(&field_d_up_times_a_tilde),
     821             :               make_not_null(&contracted_field_d_up),  // temp for eq 18 -20
     822             :               make_not_null(&half_conformal_factor_squared),  // temp for eq 25
     823             :               make_not_null(&conformal_metric_times_field_b),
     824             :               make_not_null(&conformal_metric_times_trace_a_tilde),
     825             :               make_not_null(&inv_conformal_metric_times_d_a_tilde),
     826             :               make_not_null(&gamma_hat_minus_contracted_conformal_christoffel),
     827             :               make_not_null(
     828             :                   &d_gamma_hat_minus_contracted_conformal_christoffel),
     829             :               make_not_null(
     830             :                   &contracted_christoffel_second_kind),  // temp for eq 18 -20
     831             :               make_not_null(
     832             :                   &contracted_d_conformal_christoffel_difference),  // temp for
     833             :                                                                     // eq 18 -20
     834             :               make_not_null(&k_minus_2_theta_c),
     835             :               make_not_null(&k_minus_k0_minus_2_theta_c),
     836             :               make_not_null(&lapse_times_a_tilde),
     837             :               make_not_null(&lapse_times_d_a_tilde),
     838             :               make_not_null(&lapse_times_field_a),
     839             :               make_not_null(&lapse_times_conformal_spatial_metric),
     840             :               make_not_null(&lapse_times_slicing_condition),
     841             :               make_not_null(
     842             :                   &lapse_times_ricci_scalar_plus_divergence_z4_constraint),
     843             :               make_not_null(&shift_times_deriv_gamma_hat),
     844             :               make_not_null(&inv_tau_times_conformal_metric),
     845             :               // expressions and identities needed for evolution equations: eq
     846             :               // 13
     847             :               // - 27
     848             :               make_not_null(&trace_a_tilde),                        // eq 13
     849             :               make_not_null(&field_d_up),                           // eq 14
     850             :               make_not_null(&conformal_christoffel_second_kind),    // eq 15
     851             :               make_not_null(&d_conformal_christoffel_second_kind),  // eq 16
     852             :               make_not_null(&christoffel_second_kind),              // eq 17
     853             :               make_not_null(&spatial_ricci_tensor),  // eq 18 - 20
     854             :               make_not_null(&grad_grad_lapse),       // eq 21
     855             :               make_not_null(&divergence_lapse),      // eq 22
     856             :               make_not_null(
     857             :                   &contracted_conformal_christoffel_second_kind),  // eq 23
     858             :               make_not_null(
     859             :                   &d_contracted_conformal_christoffel_second_kind),  // eq 24
     860             :               make_not_null(&spatial_z4_constraint),                 // eq 25
     861             :               make_not_null(&upper_spatial_z4_constraint),           // eq 25
     862             :               make_not_null(&grad_spatial_z4_constraint),            // eq 26
     863             :               make_not_null(
     864             :                   &ricci_scalar_plus_divergence_z4_constraint),  // eq 27
     865             :               // fixed params
     866             :               c, cleaning_speed,         // e in the paper
     867             :               one_over_relaxation_time,  // \tau^{-1}
     868             :               // free params
     869             :               eta, f, kappa_1, kappa_2, kappa_3, k_0,
     870             :               // evolved variables
     871             :               get<::Ccz4::Tags::ConformalMetric<DataVector, Dim>>(evolved_vars),
     872             :               get<gr::Tags::Lapse<DataVector>>(evolved_vars),
     873             :               get<gr::Tags::Shift<DataVector, Dim>>(evolved_vars),
     874             :               get<::Ccz4::Tags::ConformalFactor<DataVector>>(evolved_vars),
     875             :               get<::Ccz4::Tags::ATilde<DataVector, Dim>>(evolved_vars),
     876             :               get<gr::Tags::TraceExtrinsicCurvature<DataVector>>(evolved_vars),
     877             :               get<::Ccz4::Tags::Theta<DataVector>>(evolved_vars),
     878             :               get<::Ccz4::Tags::GammaHat<DataVector, Dim>>(evolved_vars),
     879             :               get<::Ccz4::Tags::AuxiliaryShiftB<DataVector, Dim>>(evolved_vars),
     880             : 
     881             :               field_a,  // auxiliary variables NOT evolved in SO-CCZ4
     882             :               field_b, field_d, field_p,
     883             :               d_field_a,  // spatial derivative of auxiliary variables
     884             :               d_field_b, d_field_d, d_field_p,
     885             : 
     886             :               // spatial derivatives of other evolved variables
     887             :               get<::Tags::deriv<::Ccz4::Tags::ATilde<DataVector, Dim>,
     888             :                                 tmpl::size_t<Dim>, Frame::Inertial>>(
     889             :                   cell_centered_Ccz4_derivs),
     890             :               get<::Tags::deriv<gr::Tags::TraceExtrinsicCurvature<DataVector>,
     891             :                                 tmpl::size_t<Dim>, Frame::Inertial>>(
     892             :                   cell_centered_Ccz4_derivs),
     893             :               get<::Tags::deriv<::Ccz4::Tags::Theta<DataVector>,
     894             :                                 tmpl::size_t<Dim>, Frame::Inertial>>(
     895             :                   cell_centered_Ccz4_derivs),
     896             :               get<::Tags::deriv<::Ccz4::Tags::GammaHat<DataVector, Dim>,
     897             :                                 tmpl::size_t<Dim>, Frame::Inertial>>(
     898             :                   cell_centered_Ccz4_derivs),
     899             :               get<::Tags::deriv<::Ccz4::Tags::AuxiliaryShiftB<DataVector, Dim>,
     900             :                                 tmpl::size_t<Dim>, Frame::Inertial>>(
     901             :                   cell_centered_Ccz4_derivs),
     902             :               shifting_shift, evolve_lapse_and_shift);
     903             : 
     904             :           *upper_spatial_z4_constraint_ptr =
     905             :               std::move(upper_spatial_z4_constraint);
     906             :         },
     907             :         box);
     908             : 
     909             :     // handling Sommerfeld BCs
     910             :     // WARNING: We assume a complete sphere domain (all wedges)
     911             :     if constexpr (not subcell_enabled_at_external_boundary) {
     912             :       return;
     913             :     }
     914             :     if (element.external_boundaries().empty()) {
     915             :       return;
     916             :     }
     917             : 
     918             :     const auto& external_bcs =
     919             :         db::get<domain::Tags::ExternalBoundaryConditions<Dim>>(*box).at(
     920             :             element.id().block_id());
     921             :     for (const auto& direction : element.external_boundaries()) {
     922             :       ASSERT(direction == Direction<Dim>::upper_zeta(),
     923             :              "external bc direction is not upper_zeta but " << direction);
     924             :       // this is potentially expensive; we should add a boolean flag for
     925             :       // time-dependent bc. This should be done in a future PR.
     926             :       if (dynamic_cast<const Ccz4::BoundaryConditions::Sommerfeld*>(
     927             :               external_bcs.at(direction).get()) == nullptr) {
     928             :         return;  // no need to check more, as we do not allow mixed BCs
     929             :       }
     930             :     }
     931             : 
     932             :     db::mutate<dt_variables_tag>(
     933             :         [&](const auto dt_vars_ptr, const auto& inertial_coords,
     934             :             const auto& evolved_var) {
     935             :           const size_t num_face_pts =
     936             :               subcell_mesh.extents(0) * subcell_mesh.extents(1);
     937             : 
     938             :           ASSERT(inertial_coords.get(0).size() ==
     939             :                      subcell_mesh.number_of_grid_points() and
     940             :                  inertial_coords.get(1).size() ==
     941             :                      subcell_mesh.number_of_grid_points() and
     942             :                  inertial_coords.get(2).size() ==
     943             :                      subcell_mesh.number_of_grid_points(),
     944             :                  "Inertial coords size ["
     945             :                      << inertial_coords.get(0).size()
     946             :                      << ", " << inertial_coords.get(1).size()
     947             :                      << ", " << inertial_coords.get(2).size()
     948             :                      << "] does not match number of subcell points "
     949             :                      << subcell_mesh.number_of_grid_points());
     950             : 
     951             :           std::array<DataVector, Dim> outermost_inertial_coords{};
     952             :           for (size_t i = 0; i < Dim; ++i) {
     953             :             make_const_view<DataVector>(
     954             :                 make_not_null(&outermost_inertial_coords.at(i)),
     955             :                 inertial_coords.get(i),
     956             :                 (subcell_mesh.extents(2) - 1) * num_face_pts, num_face_pts);
     957             :           }
     958             :           const DataVector outermost_radial_coords =
     959             :               sqrt(square(outermost_inertial_coords[0]) +
     960             :                    square(outermost_inertial_coords[1]) +
     961             :                    square(outermost_inertial_coords[2]));
     962             : 
     963             :           // modify the time derivatives at the outermost interior points
     964             :           // per Sommerfeld BCs
     965             :           tmpl::for_each<Ccz4::fd::System::variables_tag_list>(
     966             :               [&]<typename Tag>(tmpl::type_<Tag> /*meta*/) {
     967             :                 const auto& var = get<Tag>(evolved_var);
     968             :                 const auto& d_var =
     969             :                     get<::Tags::deriv<Tag, tmpl::size_t<Dim>, Frame::Inertial>>(
     970             :                         cell_centered_Ccz4_derivs);
     971             :                 auto& dt_var = get<::Tags::dt<Tag>>(*dt_vars_ptr);
     972             : 
     973             :                 for (size_t tensor_index = 0; tensor_index < Tag::type::size();
     974             :                      ++tensor_index) {
     975             :                   DataVector outermost_var{};
     976             :                   make_const_view<DataVector>(
     977             :                       make_not_null(&outermost_var), var[tensor_index],
     978             :                       (subcell_mesh.extents(2) - 1) * num_face_pts,
     979             :                       num_face_pts);
     980             : 
     981             :                   std::array<DataVector, Dim> outermost_d_var{};
     982             :                   for (size_t i = 0; i < Dim; ++i) {
     983             :                     make_const_view<DataVector>(
     984             :                         make_not_null(&outermost_d_var.at(i)),
     985             :                         d_var[Dim * tensor_index + i],
     986             :                         (subcell_mesh.extents(2) - 1) * num_face_pts,
     987             :                         num_face_pts);
     988             :                   }
     989             : 
     990             :                   const DataVector outermost_dr_var =
     991             :                       (outermost_inertial_coords[0] * outermost_d_var[0] +
     992             :                        outermost_inertial_coords[1] * outermost_d_var[1] +
     993             :                        outermost_inertial_coords[2] * outermost_d_var[2]) /
     994             :                       outermost_radial_coords;
     995             :                   DataVector outermost_dt_var{};
     996             :                   outermost_dt_var.set_data_ref(
     997             :                       dt_var[tensor_index].data() +
     998             :                           (subcell_mesh.extents(2) - 1) * num_face_pts,
     999             :                       num_face_pts);
    1000             :                   outermost_dt_var =
    1001             :                       outermost_var * (-1.0 / outermost_radial_coords) -
    1002             :                       outermost_dr_var;
    1003             :                 }
    1004             :               });
    1005             :         },
    1006             :         box,
    1007             :         db::get<evolution::dg::subcell::Tags::Coordinates<
    1008             :             Dim, Frame::Inertial>>(*box),
    1009             :         db::get<evolved_vars_tag>(*box));
    1010             :   }
    1011             : };
    1012             : }  // namespace Ccz4::fd

Generated by: LCOV version 1.14