Path: blob/main/src/time_integration/relaxation_methods/methods_vanderHouwen.jl
5590 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@doc raw"""8vanderHouwenAlgorithm910Abstract type for sub-diagonal Runge-Kutta methods, i.e.,11methods with a Butcher tableau of the form12```math13\begin{array}14{c|c|c c c c c c}15i & \boldsymbol c & & & A & & & \\16\hline171 & 0 & & & & & & \\182 & c_2 & a_{21} & & & & & \\193 & c_3 & b_1 & a_{32} & & & & \\204 & c_4 & b_1 & b_2 & a_{43} & & & \\21\vdots & \vdots & \vdots & \vdots & \ddots & \ddots & & \\22S & c_S & b_1 & b_2 & \dots & b_{S-2} & a_{S, S-1} & \\23\hline24& & b_1 & b_2 & \dots & b_{S-2} & b_{S-1} & b_S25\end{array}26```2728Currently implemented methods are the Carpenter-Kennedy-Lewis 4-stage, 3rd-order method [`CKL43`](@ref)29and the Carpenter-Kennedy-Lewis 5-stage, 4th-order method [`CKL54`](@ref) which are optimized for the30compressible Navier-Stokes equations.31"""32abstract type vanderHouwenAlgorithm <: AbstractTimeIntegrationAlgorithm end3334"""35vanderHouwenRelaxationAlgorithm3637Abstract type for van-der-Houwen type Runge-Kutta algorithms (see [`vanderHouwenAlgorithm`](@ref))38with relaxation to achieve entropy-conservation/stability.39In addition to the standard Runge-Kutta method, these algorithms are equipped with a40relaxation solver [`AbstractRelaxationSolver`](@ref) which is used to compute the relaxation parameter ``\\gamma``.41This allows the relaxation methods to suppress entropy defects due to the time stepping.4243For details on the relaxation procedure, see44- Ketcheson (2019)45Relaxation Runge-Kutta Methods: Conservation and Stability for Inner-Product Norms46[DOI: 10.1137/19M1263662](https://doi.org/10.1137/19M1263662)47- Ranocha et al. (2020)48Relaxation Runge-Kutta Methods: Fully Discrete Explicit Entropy-Stable Schemes for the Compressible Euler and Navier-Stokes Equations49[DOI: 10.1137/19M1263480](https://doi.org/10.1137/19M1263480)5051Currently implemented methods are the Carpenter-Kennedy-Lewis 4-stage, 3rd-order method [`RelaxationCKL43`](@ref)52and the Carpenter-Kennedy-Lewis 5-stage, 4th-order method [`RelaxationCKL54`](@ref) which are optimized for the53compressible Navier-Stokes equations.54"""55abstract type vanderHouwenRelaxationAlgorithm <:56AbstractRelaxationTimeIntegrationAlgorithm end5758"""59CKL43()6061Carpenter-Kennedy-Lewis 4-stage, 3rd-order low-storage Runge-Kutta method,62optimized for the compressible Navier-Stokes equations.63Implemented as a [`vanderHouwenAlgorithm`](@ref).64For the exact coefficients consult the original paper:6566- Kennedy, Carpenter, Lewis (2000)67Low-storage, explicit Runge-Kutta schemes for the compressible Navier-Stokes equations68[DOI: 10.1016/S0168-9274(99)00141-5](https://doi.org/10.1016/S0168-9274(99)00141-5)69"""70struct CKL43 <: vanderHouwenAlgorithm71a::SVector{4, Float64}72b::SVector{4, Float64}73c::SVector{4, Float64}74end75function CKL43()76a = SVector(0.0,7711847461282814 / 36547543011857,783943225443063 / 7078155732230,79-346793006927 / 4029903576067)8081b = SVector(1017324711453 / 9774461848756,828237718856693 / 13685301971492,8357731312506979 / 19404895981398,84-101169746363290 / 37734290219643)85c = SVector(0.0,86a[2],87b[1] + a[3],88b[1] + b[2] + a[4])8990return CKL43(a, b, c)91end9293"""94RelaxationCKL43(; relaxation_solver = RelaxationSolverNewton())9596Relaxation version of the 4-stage, 3rd-order low-storage Runge-Kutta method [`CKL43()`](@ref),97implemented as a [`vanderHouwenRelaxationAlgorithm`](@ref).98The default relaxation solver [`AbstractRelaxationSolver`](@ref) is [`RelaxationSolverNewton`](@ref).99"""100struct RelaxationCKL43{AbstractRelaxationSolver} <: vanderHouwenRelaxationAlgorithm101van_der_houwen_alg::CKL43102relaxation_solver::AbstractRelaxationSolver103end104function RelaxationCKL43(; relaxation_solver = RelaxationSolverNewton())105return RelaxationCKL43{typeof(relaxation_solver)}(CKL43(), relaxation_solver)106end107108"""109CKL54()110111Carpenter-Kennedy-Lewis 5-stage, 4th-order low-storage Runge-Kutta method,112optimized for the compressible Navier-Stokes equations.113Implemented as a [`vanderHouwenAlgorithm`](@ref).114For the exact coefficients consult the original paper:115116- Kennedy, Carpenter, Lewis (2000)117Low-storage, explicit Runge-Kutta schemes for the compressible Navier-Stokes equations118[DOI: 10.1016/S0168-9274(99)00141-5](https://doi.org/10.1016/S0168-9274(99)00141-5)119"""120struct CKL54 <: vanderHouwenAlgorithm121a::SVector{5, Float64}122b::SVector{5, Float64}123c::SVector{5, Float64}124end125function CKL54()126a = SVector(0.0,127970286171893 / 4311952581923,1286584761158862 / 12103376702013,1292251764453980 / 15575788980749,13026877169314380 / 34165994151039)131132b = SVector(1153189308089 / 22510343858157,1331772645290293 / 4653164025191,134-1672844663538 / 4480602732383,1352114624349019 / 3568978502595,1365198255086312 / 14908931495163)137c = SVector(0.0,138a[2],139b[1] + a[3],140b[1] + b[2] + a[4],141b[1] + b[2] + b[3] + a[5])142143return CKL54(a, b, c)144end145146"""147RelaxationCKL54(; relaxation_solver = RelaxationSolverNewton())148149Relaxation version of the 4-stage, 3rd-order low-storage Runge-Kutta method [`CKL54()`](@ref),150implemented as a [`vanderHouwenRelaxationAlgorithm`](@ref).151The default relaxation solver [`AbstractRelaxationSolver`](@ref) is [`RelaxationSolverNewton`](@ref).152"""153struct RelaxationCKL54{AbstractRelaxationSolver} <: vanderHouwenRelaxationAlgorithm154van_der_houwen_alg::CKL54155relaxation_solver::AbstractRelaxationSolver156end157function RelaxationCKL54(; relaxation_solver = RelaxationSolverNewton())158return RelaxationCKL54{typeof(relaxation_solver)}(CKL54(), relaxation_solver)159end160161# This struct is needed to fake https://github.com/SciML/OrdinaryDiffEq.jl/blob/0c2048a502101647ac35faabd80da8a5645beac7/src/integrators/type.jl#L77162# This implements the interface components described at163# https://diffeq.sciml.ai/v6.8/basics/integrator/#Handing-Integrators-1164# which are used in Trixi.jl.165mutable struct vanderHouwenRelaxationIntegrator{RealT <: Real, uType <: AbstractVector,166Params, Sol, F, Alg,167SimpleIntegratorOptions,168AbstractRelaxationSolver} <:169RelaxationIntegrator170u::uType171du::uType172u_tmp::uType173t::RealT174dt::RealT # current time step175dtcache::RealT # ignored176iter::Int # current number of time steps (iteration)177p::Params # will be the semidiscretization from Trixi.jl178sol::Sol # faked179const f::F # `rhs` of the semidiscretization180const alg::Alg # `vanderHouwenRelaxationAlgorithm`181opts::SimpleIntegratorOptions182finalstep::Bool # added for convenience183# Addition for efficient implementation184k_prev::uType185# Addition for Relaxation methodology186direction::uType # RK update, i.e., sum of stages K_i times weights b_i187gamma::RealT # Relaxation parameter188S_old::RealT # Entropy of previous iterate189const relaxation_solver::AbstractRelaxationSolver190# Note: Could add another register which would store the summed-up191# dot products ∑ₖ (wₖ ⋅ kₖ) and then integrate only once and not per stage k192# Could also add option `recompute_entropy` for entropy-conservative problems193# to save redundant computations.194end195196function init(ode::ODEProblem, alg::vanderHouwenRelaxationAlgorithm;197dt, callback::Union{CallbackSet, Nothing} = nothing, kwargs...)198u = copy(ode.u0)199du = similar(u)200u_tmp = copy(u)201k_prev = similar(u)202203t = first(ode.tspan)204iter = 0205206# For entropy relaxation207direction = zero(u)208gamma = one(eltype(u))209semi = ode.p210u_wrap = wrap_array(u, semi)211S_old = integrate(entropy, u_wrap, semi.mesh, semi.equations, semi.solver,212semi.cache)213214integrator = vanderHouwenRelaxationIntegrator(u, du, u_tmp, t, dt, zero(dt), iter,215ode.p, (prob = ode,), ode.f,216alg.van_der_houwen_alg,217SimpleIntegratorOptions(callback,218ode.tspan;219kwargs...),220false,221k_prev, direction, gamma, S_old,222alg.relaxation_solver)223224initialize_callbacks!(callback, integrator)225226return integrator227end228229function step!(integrator::vanderHouwenRelaxationIntegrator)230@unpack prob = integrator.sol231@unpack alg = integrator232t_end = last(prob.tspan)233callbacks = integrator.opts.callback234235@assert !integrator.finalstep236if isnan(integrator.dt)237error("time step size `dt` is NaN")238end239240limit_dt!(integrator, t_end)241242@trixi_timeit timer() "Relaxation vdH RK integration step" begin243num_stages = length(alg.c)244245mesh, equations, dg, cache = mesh_equations_solver_cache(prob.p)246u_wrap = wrap_array(integrator.u, prob.p)247u_tmp_wrap = wrap_array(integrator.u_tmp, prob.p)248249# First stage250integrator.f(integrator.du, integrator.u, prob.p, integrator.t)251# Try to enable optimizations due to `muladd` by computing this factor only once, see252# https://github.com/trixi-framework/Trixi.jl/pull/2480#discussion_r2224529532253b1dt = alg.b[1] * integrator.dt254@threaded for i in eachindex(integrator.u)255integrator.direction[i] = b1dt * integrator.du[i]256257integrator.k_prev[i] = integrator.du[i] # Faster than broadcasted version (with .=)258end259260du_wrap = wrap_array(integrator.du, prob.p)261# Entropy change due to first stage262dS = alg.b[1] * integrator.dt *263integrate_w_dot_stage(du_wrap, u_wrap, mesh, equations, dg, cache)264265a2_dt = alg.a[2] * integrator.dt266@threaded for i in eachindex(integrator.u)267integrator.u_tmp[i] = integrator.u[i] + a2_dt * integrator.du[i]268end269270# Second to last stage271for stage in 2:(num_stages - 1)272integrator.f(integrator.du, integrator.u_tmp, prob.p,273integrator.t + alg.c[stage] * integrator.dt)274275# Entropy change due to current stage276bs_dt = alg.b[stage] * integrator.dt277dS += bs_dt *278integrate_w_dot_stage(du_wrap, u_tmp_wrap, mesh, equations, dg, cache)279280bsminus1_minus_as = alg.b[stage - 1] - alg.a[stage]281@threaded for i in eachindex(integrator.u)282# Try to enable optimizations due to `muladd` by avoiding `+=`283# https://github.com/trixi-framework/Trixi.jl/pull/2480#discussion_r2224531702284integrator.direction[i] = integrator.direction[i] +285bs_dt * integrator.du[i]286287# Subtract previous stage contribution from `u_tmp` and add most recent one288integrator.u_tmp[i] = integrator.u_tmp[i] +289integrator.dt *290(bsminus1_minus_as * integrator.k_prev[i] +291alg.a[stage + 1] * integrator.du[i])292293integrator.k_prev[i] = integrator.du[i] # Faster than broadcasted version (with .=)294end295end296297# Last stage298integrator.f(integrator.du, integrator.u_tmp, prob.p,299integrator.t + alg.c[num_stages] * integrator.dt)300301bs_dt = alg.b[num_stages] * integrator.dt302dS += bs_dt *303integrate_w_dot_stage(du_wrap, u_tmp_wrap, mesh, equations, dg, cache)304305@threaded for i in eachindex(integrator.u)306integrator.direction[i] = integrator.direction[i] + bs_dt * integrator.du[i]307end308309direction_wrap = wrap_array(integrator.direction, prob.p)310311@trixi_timeit timer() "Relaxation solver" relaxation_solver!(integrator,312u_tmp_wrap, u_wrap,313direction_wrap, dS,314mesh, equations,315dg, cache,316integrator.relaxation_solver)317318integrator.iter += 1319update_t_relaxation!(integrator)320321# Do relaxed update322@threaded for i in eachindex(integrator.u)323integrator.u[i] = integrator.u[i] +324integrator.gamma * integrator.direction[i]325end326end327328@trixi_timeit timer() "Step-Callbacks" handle_callbacks!(callbacks, integrator)329330check_max_iter!(integrator)331332return nothing333end334335# used for AMR336function Base.resize!(integrator::vanderHouwenRelaxationIntegrator, new_size)337resize!(integrator.u, new_size)338resize!(integrator.du, new_size)339resize!(integrator.u_tmp, new_size)340resize!(integrator.k_prev, new_size)341# Relaxation addition342resize!(integrator.direction, new_size)343344return nothing345end346end # @muladd347348349