Path: blob/main/src/callbacks_step/glm_speed.jl
2802 views
# By default, Julia/LLVM does not use fused multiply-add operations (FMAs).1# Since these FMAs can increase the performance of many numerical algorithms,2# we need to opt-in explicitly.3# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details.4@muladd begin5#! format: noindent67"""8GlmSpeedCallback(; glm_scale=0.5, cfl, semi_indices=())910Update the divergence cleaning wave speed `c_h` according to the time step11computed in [`StepsizeCallback`](@ref) for the ideal GLM-MHD equations, the multi-component12GLM-MHD equations, and the multi-ion GLM-MHD equations.13The `cfl` number should be set to the same value as for the time step size calculation.14As for standard [`StepsizeCallback`](@ref) `cfl` can be either set to a `Real` number or15a function of time `t` returning a `Real` number.1617The `glm_scale` ensures that the GLM wave speed is lower than the fastest physical waves in the MHD18solution and should thus be set to a value within the interval [0,1]. Note that `glm_scale = 0`19deactivates the divergence cleaning.2021In case of coupled semidiscretizations, specify for which `semi_index`, i.e. index of the22semidiscretization, the divergence cleaning should be applied. See also23[`SemidiscretizationCoupled`](@ref).24Note: `SemidiscretizationCoupled` and all related features are considered experimental and25may change at any time.26"""27struct GlmSpeedCallback{RealT <: Real, CflType}28glm_scale::RealT29cfl::CflType30semi_indices::Vector{Int}31end3233function Base.show(io::IO, cb::DiscreteCallback{<:Any, <:GlmSpeedCallback})34@nospecialize cb # reduce precompilation time3536glm_speed_callback = cb.affect!37@unpack glm_scale, cfl, semi_indices = glm_speed_callback38print(io, "GlmSpeedCallback(glm_scale=", glm_scale, ", cfl=", cfl, "semi_indices=",39semi_indices, ")")40return nothing41end4243function Base.show(io::IO, ::MIME"text/plain",44cb::DiscreteCallback{<:Any, <:GlmSpeedCallback})45@nospecialize cb # reduce precompilation time4647if get(io, :compact, false)48show(io, cb)49else50glm_speed_callback = cb.affect!5152setup = [53"GLM wave speed scaling" => glm_speed_callback.glm_scale,54"Expected CFL number" => glm_speed_callback.cfl,55"Selected semidiscretizations" => glm_speed_callback.semi_indices56]57summary_box(io, "GlmSpeedCallback", setup)58end59end6061function GlmSpeedCallback(; glm_scale = 0.5, cfl, semi_indices = Int[])62@assert 0<=glm_scale<=1 "glm_scale must be between 0 and 1"6364cfl_function = isa(cfl, Real) ? Returns(cfl) : cfl65glm_speed_callback = GlmSpeedCallback{typeof(glm_scale), typeof(cfl_function)}(glm_scale,66cfl_function,67semi_indices)6869return DiscreteCallback(glm_speed_callback, glm_speed_callback, # the first one is the condition, the second the affect!70save_positions = (false, false),71initialize = initialize!)72end7374function initialize!(cb::DiscreteCallback{Condition, Affect!}, u, t,75integrator) where {Condition, Affect! <: GlmSpeedCallback}76return cb.affect!(integrator)77end7879# this method is called to determine whether the callback should be activated80function (glm_speed_callback::GlmSpeedCallback)(u, t, integrator)81return true82end8384function update_cleaning_speed!(semi, glm_speed_callback, dt, t)85@unpack glm_scale, cfl = glm_speed_callback8687mesh, equations, solver, cache = mesh_equations_solver_cache(semi)8889# compute time step for GLM linear advection equation with c_h=1 (redone due to the possible AMR)90c_h_deltat = calc_dt_for_cleaning_speed(cfl(t), mesh, equations, solver, cache)9192# c_h is proportional to its own time step divided by the complete MHD time step93# We use @reset here since the equations are immutable (to work on GPUs etc.).94# Thus, we need to modify the equations field of the semidiscretization.95@reset equations.c_h = glm_scale * c_h_deltat / dt96semi.equations = equations9798return semi99end100101# This method is called as callback after the StepsizeCallback during the time integration.102@inline function (glm_speed_callback::GlmSpeedCallback)(integrator)103dt = get_proposed_dt(integrator)104semi = integrator.p105106# Call the appropriate update function (this indirection allows to specialize on,107# e.g., the semidiscretization type)108update_cleaning_speed!(semi, glm_speed_callback, dt, integrator.t)109110# avoid re-evaluating possible FSAL stages111u_modified!(integrator, false)112113return nothing114end115116include("glm_speed_dg.jl")117end # @muladd118119120