SpECTRE  v2024.04.12
evolution::dg::Actions::ComputeTimeDerivative< Dim, EvolutionSystem, DgStepChoosers, LocalTimeStepping > Struct Template Reference

Computes the time derivative for a DG time step. More...

#include <ComputeTimeDerivative.hpp>

Public Types

using inbox_tags = tmpl::list< evolution::dg::Tags::BoundaryCorrectionAndGhostCellsInbox< Dim > >
 
using const_global_cache_tags = tmpl::append< tmpl::list<::dg::Tags::Formulation, evolution::Tags::BoundaryCorrection< EvolutionSystem >, domain::Tags::ExternalBoundaryConditions< Dim > > >
 

Public Member Functions

template<typename ParallelComponent , typename DbTagsList , typename Metavariables >
void send_data_for_fluxes (const gsl::not_null< Parallel::GlobalCache< Metavariables > * > cache, const gsl::not_null< db::DataBox< DbTagsList > * > box, const Variables< db::wrap_tags_in< ::Tags::Flux, typename EvolutionSystem::flux_variables, tmpl::size_t< Dim >, Frame::Inertial > > &volume_fluxes)
 

Static Public Member Functions

template<typename DbTagsList , typename... InboxTags, typename ArrayIndex , typename ActionList , typename ParallelComponent , typename Metavariables >
static Parallel::iterable_action_return_t apply (db::DataBox< DbTagsList > &box, tuples::TaggedTuple< InboxTags... > &, Parallel::GlobalCache< Metavariables > &cache, const ArrayIndex &, ActionList, const ParallelComponent *)
 

Detailed Description

template<size_t Dim, typename EvolutionSystem, typename DgStepChoosers, bool LocalTimeStepping>
struct evolution::dg::Actions::ComputeTimeDerivative< Dim, EvolutionSystem, DgStepChoosers, LocalTimeStepping >

Computes the time derivative for a DG time step.

Computes the volume fluxes, the divergence of the fluxes and all additional interior contributions to the time derivatives (both nonconservative products and source terms). The internal mortar data is also computed.

The general first-order hyperbolic evolution equation solved for conservative systems is:

\begin{align*} \frac{\partial u_\alpha}{\partial \hat{t}} + \partial_{i} \left(F^i_\alpha - v^i_g u_\alpha\right) = S_\alpha-u_\alpha\partial_i v^i_g, \end{align*}

where \(F^i_{\alpha}\) are the fluxes when the mesh isn't moving, \(v^i_g\) is the velocity of the mesh, \(u_{\alpha}\) are the evolved variables, \(S_{\alpha}\) are the source terms, \(\hat{t}\) is the time in the logical frame, \(t\) is the time in the inertial frame, hatted indices correspond to logical frame quantites, and unhatted indices to inertial frame quantities (e.g. \(\partial_i\) is the derivative with respect to the inertial coordinates). For evolution equations that do not have any fluxes and only nonconservative products we evolve:

\begin{align*} \frac{\partial u_\alpha}{\partial \hat{t}} +\left(B^i_{\alpha\beta}-v^i_g \delta_{\alpha\beta} \right)\partial_{i}u_\beta = S_\alpha. \end{align*}

Finally, for equations with both conservative terms and nonconservative products we use:

\begin{align*} \frac{\partial u_\alpha}{\partial \hat{t}} + \partial_{i} \left(F^i_\alpha - v^i_g u_\alpha\right) +B^i_{\alpha\beta}\partial_{i}u_\beta = S_\alpha-u_\alpha\partial_i v^i_g, \end{align*}

where \(B^i_{\alpha\beta}\) is the matrix for the nonconservative products.

Volume Terms

The mesh velocity is added to the flux automatically if the mesh is moving. That is,

\begin{align*} F^i_{\alpha}\to F^i_{\alpha}-v^i_{g} u_{\alpha} \end{align*}

The source terms are also altered automatically by adding:

\begin{align*} -u_\alpha \partial_i v^i_g, \end{align*}

For systems with equations that only contain nonconservative products, the following mesh velocity is automatically added to the time derivative:

\begin{align*} v^i_g \partial_i u_\alpha, \end{align*}

Note
The term is always added in the Frame::Inertial frame, and the plus sign arises because we add it to the time derivative.
Warning
The mesh velocity terms are added to the time derivatives before invoking the boundary conditions. This means that the time derivatives passed to the boundary conditions are with respect to \(\hat{t}\), not \(t\). This is especially important in the TimeDerivative/Bjorhus boundary conditions.

Here are examples of the TimeDerivative struct used to compute the volume time derivative. This struct is what the type alias System::compute_volume_time_derivative points to. The time derivatives are as gsl::not_null first, then the temporary tags as gsl::not_null, followed by the argument_tags. These type aliases are given by

using temporary_tags = tmpl::list<Var3Squared>;
using common_argument_tags = tmpl::list<Var1, Var2<Dim>, Var3>;
using argument_tags =
tmpl::conditional_t<HasPrimitiveVars,
tmpl::push_back<common_argument_tags, PrimVar1>,
common_argument_tags>;

for the examples. For a conservative system without primitives the apply function would look like

static void apply(
// Time derivatives returned by reference. All the tags in the
// variables_tag in the system struct.
const gsl::not_null<Scalar<DataVector>*> dt_var1,
const gsl::not_null<tnsr::I<DataVector, Dim, Frame::Inertial>*> dt_var2,
// Fluxes returned by reference. Listed in the system struct as
// flux_variables.
const gsl::not_null<tnsr::I<DataVector, Dim, Frame::Inertial>*> flux_var1,
const gsl::not_null<tnsr::IJ<DataVector, Dim, Frame::Inertial>*>
flux_var2,
// Temporaries returned by reference. Listed in temporary_tags above.
const gsl::not_null<Scalar<DataVector>*> square_var3,
// Arguments listed in argument_tags above
const Scalar<DataVector>& var1,
const tnsr::I<DataVector, Dim, Frame::Inertial>& var2,
const Scalar<DataVector>& var3) {
get(*square_var3) = square(get(var3));
// Set source terms
get(*dt_var1) = get(*square_var3);
for (size_t d = 0; d < Dim; ++d) {
dt_var2->get(d) = get(var3) * d;
}
// Set fluxes
for (size_t i = 0; i < Dim; ++i) {
flux_var1->get(i) = square(get(var1)) * var2.get(i);
for (size_t j = 0; j < Dim; ++j) {
flux_var2->get(i, j) = var2.get(i) * var2.get(j) * get(var1);
if (i == j) {
flux_var2->get(i, j) += cube(get(var1));
}
}
}
}

For a nonconservative system it would be

static void apply(
// Time derivatives returned by reference. All the tags in the
// variables_tag in the system struct.
const gsl::not_null<Scalar<DataVector>*> dt_var1,
const gsl::not_null<tnsr::I<DataVector, Dim, Frame::Inertial>*> dt_var2,
// Temporaries returned by reference. Listed in temporary_tags above.
const gsl::not_null<Scalar<DataVector>*> square_var3,
// Partial derivative arguments. Listed in the system struct as
// gradient_variables.
const tnsr::i<DataVector, Dim, Frame::Inertial>& d_var1,
const tnsr::iJ<DataVector, Dim, Frame::Inertial>& d_var2,
// Arguments listed in argument_tags above
const Scalar<DataVector>& var1,
const tnsr::I<DataVector, Dim, Frame::Inertial>& var2,
const Scalar<DataVector>& var3) {
get(*square_var3) = square(get(var3));
// Set source terms and nonconservative products
get(*dt_var1) = get(*square_var3);
for (size_t d = 0; d < Dim; ++d) {
get(*dt_var1) -= var2.get(d) * d_var1.get(d);
dt_var2->get(d) = get(var3) * d;
for (size_t i = 0; i < Dim; ++i) {
dt_var2->get(d) -= get(var1) * var2.get(i) * d_var2.get(i, d);
}
}
}

And finally, for a mixed conservative-nonconservative system with primitive variables

static void apply(
const gsl::not_null<Scalar<DataVector>*> dt_var1,
const gsl::not_null<tnsr::I<DataVector, Dim, Frame::Inertial>*> dt_var2,
const gsl::not_null<tnsr::IJ<DataVector, Dim, Frame::Inertial>*>
flux_var2,
const gsl::not_null<Scalar<DataVector>*> square_var3,
const tnsr::i<DataVector, Dim, Frame::Inertial>& d_var1,
const Scalar<DataVector>& var1,
const tnsr::I<DataVector, Dim, Frame::Inertial>& var2,
const Scalar<DataVector>& var3, const Scalar<DataVector>& prim_var1) {
apply(dt_var1, dt_var2, flux_var2, square_var3, d_var1, var1, var2, var3);
get(*dt_var1) += get(prim_var1);
}

In addition to each variable being passed individually, if the time derivative struct inherits from evolution::PassVariables, then the time derivatives, fluxes, and temporaries are passed as gsl::not_null<Variables<...>>. This is useful for systems where additional quantities are sometimes evolved, and just generally nice for keeping the number of arguments reasonable. Below are the above examples but with Variables being passed.

static void apply(
// Time derivatives returned by reference. All the tags in the
// variables_tag in the system struct.
const gsl::not_null<Variables<tmpl::list<dt_var1, dt_var2>>*> dt_vars,
// Fluxes returned by reference. Listed in the system struct as
// flux_variables.
const gsl::not_null<Variables<tmpl::list<flux_var1, flux_var2>>*>
flux_vars,
// Temporaries returned by reference. Listed in temporary_tags above.
const gsl::not_null<Variables<tmpl::list<Var3Squared>>*> temporaries,
// Arguments listed in argument_tags above
const Scalar<DataVector>& var1,
const tnsr::I<DataVector, Dim, Frame::Inertial>& var2,
const Scalar<DataVector>& var3) {
// just forward to other implementation to reduce code duplication
base::apply(get<dt_var1>(dt_vars), get<dt_var2>(dt_vars),
get<flux_var1>(flux_vars), get<flux_var2>(flux_vars),
get<Var3Squared>(temporaries), var1, var2, var3);
}
static void apply(
// Time derivatives returned by reference. All the tags in the
// variables_tag in the system struct.
const gsl::not_null<Variables<tmpl::list<dt_var1, dt_var2>>*> dt_vars,
// Temporaries returned by reference. Listed in temporary_tags above.
const gsl::not_null<Variables<tmpl::list<Var3Squared>>*> temporaries,
// Partial derivative arguments. Listed in the system struct as
// gradient_variables.
const tnsr::i<DataVector, Dim, Frame::Inertial>& d_var1,
const tnsr::iJ<DataVector, Dim, Frame::Inertial>& d_var2,
// Arguments listed in argument_tags above
const Scalar<DataVector>& var1,
const tnsr::I<DataVector, Dim, Frame::Inertial>& var2,
const Scalar<DataVector>& var3) {
// just forward to other implementation to reduce code duplication
base::apply(get<dt_var1>(dt_vars), get<dt_var2>(dt_vars),
get<Var3Squared>(temporaries), d_var1, d_var2, var1, var2,
var3);
}
static void apply(
const gsl::not_null<Variables<tmpl::list<dt_var1, dt_var2>>*> dt_vars,
const gsl::not_null<Variables<tmpl::list<flux_var2>>*> flux_vars,
const gsl::not_null<Variables<tmpl::list<Var3Squared>>*> temporaries,
const tnsr::i<DataVector, Dim, Frame::Inertial>& d_var1,
const Scalar<DataVector>& var1,
const tnsr::I<DataVector, Dim, Frame::Inertial>& var2,
const Scalar<DataVector>& var3, const Scalar<DataVector>& prim_var1) {
// just forward to other implementation to reduce code duplication
base::apply(get<dt_var1>(dt_vars), get<dt_var2>(dt_vars),
get<flux_var2>(flux_vars), get<Var3Squared>(temporaries),
d_var1, var1, var2, var3, prim_var1);
}

Uses:

  • System:
    • variables_tag
    • flux_variables
    • gradient_variables
    • compute_volume_time_derivative_terms
  • DataBox:
    • Items in system::compute_volume_time_derivative_terms::argument_tags
    • domain::Tags::MeshVelocity<Metavariables::volume_dim>
    • Metavariables::system::variables_tag
    • Metavariables::system::flux_variables
    • Metavariables::system::gradient_variables
    • domain::Tags::DivMeshVelocity
    • DirectionsTag,
    • Required interface items for Metavariables::system::normal_dot_fluxes

DataBox changes:

Internal Boundary Terms

Internal boundary terms are computed from the System::boundary_correction_base type alias. This type alias must point to a base class with creatable_classes. Each concrete boundary correction must specify:

  • type alias template dg_package_field_tags. These are what will be returned by gsl::not_null from the dg_package_data member function.
  • type alias template dg_package_temporary_tags. These are temporary tags that are projected to the face and then passed to the dg_package_data function.
  • type alias template dg_package_primitive_tags. These are the primitive variables (if any) that are projected to the face and then passed to dg_package_data.
  • type alias template dg_package_volume_tags. These are tags that are not projected to the interface and are retrieved directly from the DataBox. The equation of state for hydrodynamics systems is an example of what would be a "volume tag".

A static constexpr bool need_normal_vector must be specified. If true then the normal vector is computed from the normal covector. This is currently not implemented.

The dg_package_data function takes as arguments gsl::not_null of the dg_package_data_field_tags, then the projected evolved variables, the projected fluxes, the projected temporaries, the projected primitives, the unit normal covector, mesh velocity, normal dotted into the mesh velocity, the volume_tags, and finally the dg::Formulation. The dg_package_data function must compute all ingredients for the boundary correction, including mesh-velocity-corrected characteristic speeds. However, the projected fluxes passed in are \(F^i - u v^i_g\) (the mesh velocity term is already included). The dg_package_data function must also return a double that is the maximum absolute characteristic speed over the entire face. This will be used for checking that the time step doesn't violate the CFL condition.

Here is an example of the type aliases and bool:

using dg_package_field_tags = tmpl::push_back<
tmpl::append<db::wrap_tags_in<::Tags::NormalDotFlux, variables_tags>,
variables_tags>,
MaxAbsCharSpeed>;
using dg_package_data_temporary_tags = tmpl::list<Var3Squared>;
using dg_package_data_primitive_tags =
tmpl::conditional_t<HasPrims, tmpl::list<PrimVar1>, tmpl::list<>>;
using dg_package_data_volume_tags =
tmpl::conditional_t<HasPrims, tmpl::list<Tags::TimeStepId>, tmpl::list<>>;
using dg_boundary_terms_volume_tags =
tmpl::conditional_t<HasPrims, tmpl::list<Tags::TimeStepId>, tmpl::list<>>;

The normal vector requirement is:

static constexpr bool need_normal_vector = false;

For a conservative system with primitive variables and using the TimeStepId as a volume tag the dg_package_data function looks like:

double dg_package_data(
const gsl::not_null<Scalar<DataVector>*> out_normal_dot_flux_var1,
const gsl::not_null<tnsr::I<DataVector, Dim, Frame::Inertial>*>
out_normal_dot_flux_var2,
const gsl::not_null<Scalar<DataVector>*> out_var1,
const gsl::not_null<tnsr::I<DataVector, Dim, Frame::Inertial>*> out_var2,
const gsl::not_null<Scalar<DataVector>*> max_abs_char_speed,
const Scalar<DataVector>& var1,
const tnsr::I<DataVector, Dim, Frame::Inertial>& var2,
const tnsr::I<DataVector, Dim, Frame::Inertial>& flux_var1,
const tnsr::IJ<DataVector, Dim, Frame::Inertial>& flux_var2,
const Scalar<DataVector>& var3_squared,
const Scalar<DataVector>& prim_var1,
const tnsr::i<DataVector, Dim, Frame::Inertial>& normal_covector,
const std::optional<tnsr::I<DataVector, Dim, Frame::Inertial>>&
mesh_velocity,
const std::optional<Scalar<DataVector>>& normal_dot_mesh_velocity,
const TimeStepId& time_step_id) const {
dg_package_data(out_normal_dot_flux_var1, out_normal_dot_flux_var2,
out_var1, out_var2, max_abs_char_speed, var1, var2,
flux_var1, flux_var2, var3_squared, normal_covector,
mesh_velocity, normal_dot_mesh_velocity);
get(*out_var1) += get(prim_var1) + time_step_id.step_time().value();
return max(get(*max_abs_char_speed));
}

For a mixed conservative-nonconservative system with primitive variables and using the TimeStepId as a volume tag the dg_package_data function looks like:

double dg_package_data(
const gsl::not_null<Scalar<DataVector>*> out_normal_dot_flux_var1,
const gsl::not_null<tnsr::I<DataVector, Dim, Frame::Inertial>*>
out_normal_dot_flux_var2,
const gsl::not_null<Scalar<DataVector>*> out_var1,
const gsl::not_null<tnsr::I<DataVector, Dim, Frame::Inertial>*> out_var2,
const gsl::not_null<Scalar<DataVector>*> max_abs_char_speed,
const Scalar<DataVector>& var1,
const tnsr::I<DataVector, Dim, Frame::Inertial>& var2,
const tnsr::IJ<DataVector, Dim, Frame::Inertial>& flux_var2,
const Scalar<DataVector>& var3_squared,
const Scalar<DataVector>& prim_var1,
const tnsr::i<DataVector, Dim, Frame::Inertial>& normal_covector,
const std::optional<tnsr::I<DataVector, Dim, Frame::Inertial>>&
mesh_velocity,
const std::optional<Scalar<DataVector>>& normal_dot_mesh_velocity,
const TimeStepId& time_step_id) const {
dg_package_data(out_normal_dot_flux_var1, out_normal_dot_flux_var2,
out_var1, out_var2, max_abs_char_speed, var1, var2,
flux_var2, var3_squared, normal_covector, mesh_velocity,
normal_dot_mesh_velocity);
get(*out_var1) += get(prim_var1) + time_step_id.step_time().value();
return max(get(*max_abs_char_speed));
}

Uses:

DataBox changes:


The documentation for this struct was generated from the following file: